diff --git a/src/animation/foldhaus_animation.h b/src/animation/foldhaus_animation.h new file mode 100644 index 0000000..3b00f99 --- /dev/null +++ b/src/animation/foldhaus_animation.h @@ -0,0 +1,11 @@ +struct animation_block +{ + r32 StartTime; + r32 EndTime; + animation_block* Next; +}; + +struct animation_layer +{ + animation_block* Blocks; +}; \ No newline at end of file diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index b54eb35..8b0858c 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -137,7 +137,6 @@ LoadAssembly (app_state* State, context Context, char* Path) string FileName = Substring(PathString, IndexOfLastSlash + 1); r32 Scale = 100; - Assert(State->AssembliesCount < ASSEMBLY_LIST_LENGTH); s32 AssemblyMemorySize = GetAssemblyMemorySizeFromDefinition(AssemblyDefinition, FileName); u8* AssemblyMemory = Context.PlatformAlloc(AssemblyMemorySize); @@ -147,7 +146,9 @@ LoadAssembly (app_state* State, context Context, char* Path) Scale, AssemblyMemory, AssemblyMemorySize); - State->AssemblyList[State->AssembliesCount++] = NewAssembly; + array_entry_handle NewAssemblyHandle = PushElement(NewAssembly, &State->AssemblyList); + PushElement(NewAssemblyHandle, &State->ActiveAssemblyIndecies); + State->TotalLEDsCount += NewAssembly.LEDCount; ClearArenaToSnapshot(State->Transient, TempMemorySnapshot); @@ -156,19 +157,20 @@ LoadAssembly (app_state* State, context Context, char* Path) internal void UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context) { - assembly* Assembly = State->AssemblyList + AssemblyIndex; + assembly* Assembly = GetElementAtIndex(AssemblyIndex, State->AssemblyList); State->TotalLEDsCount -= Assembly->LEDCount; Context.PlatformFree(Assembly->Arena.Base, Assembly->Arena.Size); - if (AssemblyIndex != (State->AssembliesCount - 1)) + RemoveElementAtIndex(AssemblyIndex, &State->AssemblyList); + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - State->AssemblyList[AssemblyIndex] = State->AssemblyList[State->AssembliesCount - 1]; + array_entry_handle Handle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + if (Handle.Index == AssemblyIndex) + { + RemoveElementAtIndex(i, &State->ActiveAssemblyIndecies); + break; + } } - else - { - *Assembly = {}; - } - State->AssembliesCount -= 1; } //////////////////////////////////////////////////////////////////////// @@ -287,6 +289,9 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Camera.Position = v3{0, 0, -250}; State->Camera.LookAt = v3{0, 0, 0}; + State->AssemblyList.BucketSize = 32; + State->AssemblyList.FreeList.Next = &State->AssemblyList.FreeList; + State->ActiveAssemblyIndecies.BucketSize = 32; #if 1 char Path[] = "radialumia.fold"; LoadAssembly(State, Context, Path); @@ -409,9 +414,10 @@ UPDATE_AND_RENDER(UpdateAndRender) s32 HeaderSize = State->NetworkProtocolHeaderSize; dmx_buffer_list* DMXBuffers = 0; - for (s32 i = 0; i < State->AssembliesCount; i++) + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - assembly Assembly = State->AssemblyList[i]; + array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList); dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(Assembly, HeaderSize, State->Transient); DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers); } @@ -475,9 +481,10 @@ UPDATE_AND_RENDER(UpdateAndRender) s32 MaxLEDsPerJob = 2048; render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount); - for (s32 AssemblyIdx = 0; AssemblyIdx < State->AssembliesCount; AssemblyIdx++) + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - assembly Assembly = State->AssemblyList[AssemblyIdx]; + array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList); s32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDCount, MaxLEDsPerJob); for (s32 Job = 0; Job < JobsNeeded; Job++) @@ -529,9 +536,11 @@ UPDATE_AND_RENDER(UpdateAndRender) State->Interface, Mouse); string InterfaceString = MakeString(PushArray(State->Transient, char, 256), 256); - for (int i = 0; i < State->AssembliesCount; i++) + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - PrintF(&InterfaceString, "Unload %.*s", State->AssemblyList[i].Name.Length, State->AssemblyList[i].Name.Memory); + array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList); + PrintF(&InterfaceString, "Unload %.*s", Assembly.Name.Length, Assembly.Name.Memory); ButtonPos.x += ButtonDim.x + 10; button_result UnloadAssemblyBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index 1874697..2b354f4 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -46,12 +46,8 @@ struct app_state s32 TotalLEDsCount; - // TODO(Peter): Make this dynamic. We want them contiguous in memory since we'll be accessing them - // mostly by looping through them. On the other hand, I don't expect there to ever be more than 100 - // of them at once. -#define ASSEMBLY_LIST_LENGTH 32 - assembly AssemblyList[ASSEMBLY_LIST_LENGTH]; - s32 AssembliesCount; + assembly_array AssemblyList; + array_entry_handle_contiguous_array ActiveAssemblyIndecies; camera Camera; r32 PixelsToWorldScale; diff --git a/src/foldhaus_assembly.h b/src/foldhaus_assembly.h index ea945f7..e413bbe 100644 --- a/src/foldhaus_assembly.h +++ b/src/foldhaus_assembly.h @@ -36,3 +36,5 @@ struct assembly s32 LEDUniverseMapCount; leds_in_universe_range* LEDUniverseMap; }; + +TYPEDEF_ARRAY(assembly); diff --git a/src/foldhaus_debug_visuals.h b/src/foldhaus_debug_visuals.h index a98770e..8ce9557 100644 --- a/src/foldhaus_debug_visuals.h +++ b/src/foldhaus_debug_visuals.h @@ -211,7 +211,7 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c r32 FramesPerSecond = 1.0f / DeltaTime; - PrintF(&DebugString, "Framerate: %.*f s %d fps | Modes: %d Memory Used: %d / %d | Commands: %d", + PrintF(&DebugString, "Framerate: %.*f s %d fps | Modes: %d Memory Used: %d / %d | Commands: %d | HI SAM!!!! ", 5, DeltaTime, (u32)FramesPerSecond, State->Modes.ActiveModesCount, diff --git a/src/foldhaus_platform.h b/src/foldhaus_platform.h index f927a2a..79d8c88 100644 --- a/src/foldhaus_platform.h +++ b/src/foldhaus_platform.h @@ -1,5 +1,6 @@ #include "gs_language.h" #include "gs_platform.h" +#include "gs_array.h" #include "foldhaus_memory.h" #include "gs_string.h" diff --git a/src/gs_array.h b/src/gs_array.h new file mode 100644 index 0000000..6fd0b47 --- /dev/null +++ b/src/gs_array.h @@ -0,0 +1,226 @@ +struct free_list +{ + free_list* Next; + s32 Index; +}; + +struct bucket_index +{ + s32 Bucket; + s32 IndexInBucket; +}; + +inline bucket_index +GetBucketIndexForIndex (s32 Index, s32 BucketSize) +{ + bucket_index Result = {}; + Result.Bucket = Index / BucketSize; + Result.IndexInBucket = Index % BucketSize; + return Result; +}; + +struct array_entry_handle +{ + s32 Generation; + s32 Index; +}; + +// NOTE(Peter): This is a total bastardization of the preprocessor but it works and is +// easier than writing a metaprogramming system at the moment. +// TODO(Peter): Write a metaprogramming version of this that is actually easy to debug + +#define TYPEDEF_ARRAY(element_type) \ +struct element_type##_array_entry { \ + s32 Generation; \ + union \ + { \ + element_type Entry; \ + free_list Free; \ + }; \ +}; \ +\ +struct element_type##_array \ +{ \ + element_type##_array_entry** Buckets; \ + s32 BucketSize; \ + s32 BucketCount; \ + s32 Used; \ + free_list FreeList; \ +}; \ +\ +internal void \ +GrowBuffer(element_type##_array* Buffer) \ +{ \ + s32 NewBucketSize = sizeof(element_type##_array_entry) * Buffer->BucketSize; \ + element_type##_array_entry* NewBucket = (element_type##_array_entry*)malloc(NewBucketSize); \ + GSZeroMemory((u8*)NewBucket, NewBucketSize); \ + \ + s32 NewBucketIndex = Buffer->BucketCount++; \ + if (!Buffer->Buckets) \ + { \ + Buffer->Buckets = (element_type##_array_entry**)malloc(sizeof(element_type##_array_entry*)); \ + } \ + else \ + { \ + Buffer->Buckets = (element_type##_array_entry**)realloc(Buffer->Buckets, sizeof(element_type##_array_entry*) * Buffer->BucketCount); \ + } \ + Buffer->Buckets[NewBucketIndex] = NewBucket; \ +} \ +\ +internal element_type##_array_entry* \ +GetEntryAtIndex (s32 Index, element_type##_array Buffer) \ +{ \ + bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \ + element_type##_array_entry* Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \ + return Entry; \ +} \ +\ +internal array_entry_handle \ +PushElement (element_type Data, element_type##_array* Buffer) \ +{ \ + array_entry_handle Result = {}; \ + \ + if (Buffer->FreeList.Next != &Buffer->FreeList) \ + { \ + free_list* FreeList = Buffer->FreeList.Next; \ + element_type##_array_entry* Entry = GetEntryAtIndex(FreeList->Index, *Buffer); \ + Buffer->FreeList.Next = Entry->Free.Next; \ + \ + Result.Index = Entry->Free.Index; \ + Result.Generation = Entry->Generation; \ + Entry->Entry = Data; \ + \ + ++Buffer->Used; \ + } \ + else \ + { \ + if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \ + { \ + GrowBuffer(Buffer); \ + } \ + \ + s32 Index = Buffer->Used++; \ + s32 BucketIndex = Index / Buffer->BucketSize; \ + s32 IndexInBucket = Index % Buffer->BucketSize; \ + \ + Buffer->Buckets[BucketIndex][IndexInBucket].Entry = Data; \ + Result.Index = Index; \ + Result.Generation = Buffer->Buckets[BucketIndex][IndexInBucket].Generation; \ + } \ + \ + return Result; \ +} \ +\ +internal element_type* \ +GetElementAtIndex (s32 Index, element_type##_array Buffer) \ +{ \ + Assert(Index < Buffer.Used); \ + element_type##_array_entry* Entry = GetEntryAtIndex(Index, Buffer); \ + element_type* Result = &Entry->Entry; \ + return Result; \ +} \ +\ +internal element_type* \ +GetElementWithHandle (array_entry_handle Handle, element_type##_array Buffer) \ +{ \ + element_type* Result = 0; \ + \ + element_type##_array_entry* Entry = GetEntryAtIndex(Handle.Index, Buffer); \ + \ + if (Entry->Generation == Handle.Generation) \ + { \ + Result = &Entry->Entry; \ + } \ + \ + return Result; \ +} \ +\ +internal void \ +RemoveElementAtIndex (s32 Index, element_type##_array* Buffer) \ +{ \ + Assert(Index < Buffer->Used); \ + \ + element_type##_array_entry* Entry = GetEntryAtIndex(Index, *Buffer); \ + ++Entry->Generation; \ + Entry->Free.Index = Index; \ + \ + Entry->Free.Next = Buffer->FreeList.Next; \ + Buffer->FreeList.Next = &Entry->Free; \ + \ + --Buffer->Used; \ +} \ + +// END OF CRAZY MACRO + + +#define TYPEDEF_CONTIGUOUS_ARRAY(element_type) \ +struct element_type##_contiguous_array \ +{ \ + element_type** Buckets; \ + s32 BucketSize; \ + s32 BucketCount; \ + s32 Used; \ +}; \ +\ +internal void \ +GrowBuffer(element_type##_contiguous_array* Buffer) \ +{ \ + s32 NewBucketSize = sizeof(element_type) * Buffer->BucketSize; \ + element_type* NewBucket = (element_type*)malloc(NewBucketSize); \ + GSZeroMemory((u8*)NewBucket, NewBucketSize); \ + \ + s32 NewBucketIndex = Buffer->BucketCount++; \ + if (!Buffer->Buckets) \ + { \ + Buffer->Buckets = (element_type**)malloc(sizeof(element_type*)); \ + } \ + else \ + { \ + Buffer->Buckets = (element_type**)realloc(Buffer->Buckets, sizeof(element_type*) * Buffer->BucketCount); \ + } \ + Buffer->Buckets[NewBucketIndex] = NewBucket; \ +} \ +\ +internal element_type* \ +GetElementAtIndex (s32 Index, element_type##_contiguous_array Buffer) \ +{ \ + bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \ + element_type* Entry = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; \ + return Entry; \ +} \ +\ +internal s32 \ +PushElement (element_type Data, element_type##_contiguous_array* Buffer) \ +{ \ + s32 Result = -1; \ + \ + if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) \ + { \ + GrowBuffer(Buffer); \ + } \ + \ + s32 Index = Buffer->Used++; \ + s32 BucketIndex = Index / Buffer->BucketSize; \ + s32 IndexInBucket = Index % Buffer->BucketSize; \ + \ + Buffer->Buckets[BucketIndex][IndexInBucket] = Data; \ + Result = Index; \ + return Result; \ +} \ +\ +internal void \ +RemoveElementAtIndex (s32 Index, element_type##_contiguous_array* Buffer) \ +{ \ + Assert(Index < Buffer->Used); \ + \ + bucket_index IndexToRemove = GetBucketIndexForIndex(Index, Buffer->BucketSize); \ + bucket_index LastIndex = GetBucketIndexForIndex(Buffer->Used - 1, Buffer->BucketSize); \ + element_type ValueAtLastIndex = Buffer->Buckets[LastIndex.Bucket][LastIndex.IndexInBucket]; \ + Buffer->Buckets[IndexToRemove.Bucket][IndexToRemove.IndexInBucket] = ValueAtLastIndex; \ + --Buffer->Used; \ +} \ + +// END OF CRAZY MACRO + +TYPEDEF_ARRAY(array_entry_handle); +TYPEDEF_CONTIGUOUS_ARRAY(array_entry_handle); \ No newline at end of file