diff --git a/build.bat b/build.bat index 514d5e8..744f502 100644 --- a/build.bat +++ b/build.bat @@ -10,7 +10,7 @@ IF NOT EXIST .\build\ mkdir .\build C:\programs\ctime\ctime.exe -begin %ProjectDevPath%\build\win32_foldhaus_build_time.ctm -set CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- +set CommonCompilerFlags=-nologo -DDEBUG=1 -DPLATFORM_WINDOWS -FC -WX -W4 -Z7 -Oi -GR- -EHsc -EHa- -MTd -fp:fast -fp:except- -IC:\programs-dev\gs_libs\src set CommonCompilerFlags=-wd4127 -wd4702 -wd4101 -wd4505 -wd4100 -wd4189 -wd4244 -wd4201 -wd4996 -I%CommonLibs% -O2 %CommonCompilerFlags% set CommonLinkerFlags= -opt:ref diff --git a/data/blumen_lumen.fold b/data/blumen_lumen.fold new file mode 100644 index 0000000..6340e2d --- /dev/null +++ b/data/blumen_lumen.fold @@ -0,0 +1,15 @@ +led_strip_count 12 + +led_strip { 0, 0, 0, INTERPOLATE_POINTS, (0.000000, 1.000000, 0.000000), (0.000000, 0.050000, 1.000000), 70 } +led_strip { 0, 1, 0, INTERPOLATE_POINTS, (0.500000, 0.866025, 0.000000), (0.025000, 0.043301, 1.000000), 70 } +led_strip { 0, 2, 0, INTERPOLATE_POINTS, (0.866025, 0.499999, 0.000000), (0.043301, 0.024999, 1.000000), 70 } +led_strip { 0, 3, 0, INTERPOLATE_POINTS, (1.000000, -0.000000, 0.000000), (0.050000, -0.000000, 1.000000), 70 } +led_strip { 0, 4, 0, INTERPOLATE_POINTS, (0.866025, -0.500000, 0.000000), (0.043301, -0.025000, 1.000000), 70 } +led_strip { 0, 5, 0, INTERPOLATE_POINTS, (0.500000, -0.866025, 0.000000), (0.025000, -0.043301, 1.000000), 70 } +led_strip { 0, 6, 0, INTERPOLATE_POINTS, (-0.000000, -1.000000, 0.000000), (-0.000000, -0.050000, 1.000000), 70 } +led_strip { 0, 7, 0, INTERPOLATE_POINTS, (-0.500000, -0.866025, 0.000000), (-0.025000, -0.043301, 1.000000), 70 } +led_strip { 0, 8, 0, INTERPOLATE_POINTS, (-0.866025, -0.499999, 0.000000), (-0.043301, -0.024999, 1.000000), 70 } +led_strip { 0, 9, 0, INTERPOLATE_POINTS, (-1.000000, 0.000000, 0.000000), (-0.050000, 0.000000, 1.000000), 70 } +led_strip { 0, 10, 0, INTERPOLATE_POINTS, (-0.866025, 0.499999, 0.000000), (-0.043301, 0.024999, 1.000000), 70 } +led_strip { 0, 11, 0, INTERPOLATE_POINTS, (-0.499999, 0.866025, 0.000000), (-0.024999, 0.043301, 1.000000), 70 } +END_OF_ASSEMBLY_FILE \ No newline at end of file diff --git a/data/generate_blumen_code.h b/data/generate_blumen_code.h new file mode 100644 index 0000000..e4acd76 --- /dev/null +++ b/data/generate_blumen_code.h @@ -0,0 +1,21 @@ +// NOTE(Peter): stuff this in a function and itll print out the code needed to generate a blumen +// TODO(Peter): Modify this when you get actual blumen measurements +MakeStringBuffer(Buffer, 256); +v3 InnerVectors[12]; +v3 OuterVectors[12]; +for (s32 i = 0; i < 12; i++) +{ + r32 Theta = ((r32)i / 12.0f) * 2 * PI; + + v3 Direction = v3{GSSin(Theta), GSCos(Theta), 0}; + + InnerVectors[i] = Direction; + OuterVectors[i] = v3{Direction.x * 0.05f, Direction.y * 0.05f, 1}; + + PrintF(&Buffer, "led_strip { 0, %d, 0, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 70 }\n", + i, + InnerVectors[i].x, InnerVectors[i].y, InnerVectors[i].z, + OuterVectors[i].x, OuterVectors[i].y, OuterVectors[i].z); + NullTerminate(&Buffer); + OutputDebugStringA(Buffer.Memory); +} diff --git a/data/splash.png b/data/splash.png index 02bb10a..689248b 100644 Binary files a/data/splash.png and b/data/splash.png differ diff --git a/meta/gs_string_builder.h b/meta/gs_string_builder.h new file mode 100644 index 0000000..519ed0c --- /dev/null +++ b/meta/gs_string_builder.h @@ -0,0 +1,99 @@ +#define STRING_BUILDER_ARRAY_BUFFER_SIZE 32 + +struct string_array +{ + string** Buckets; + s32 BucketSize; + s32 BucketCount; + s32 Used; + free_list FreeList; +}; + +internal string* +GetEntryAtIndex (s32 Index, string_array Buffer) +{ + string* Result = 0; + if (Buffer.Buckets) + { + bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); + Result = Buffer.Buckets[BucketIndex.Bucket] + BucketIndex.IndexInBucket; + } + return Result; +} + +internal s32 +PushElement (string Data, string_array* Buffer) +{ + s32 Result = -1; + + if (Buffer->Used >= Buffer->BucketSize * Buffer->BucketCount) + { + Buffer->Buckets = (string**)GrowBuffer(Buffer->BucketSize, sizeof(string), &Buffer->BucketCount, (void**)Buffer->Buckets); + } + + s32 Index = Buffer->Used++; + s32 BucketIndex = Index / Buffer->BucketSize; + s32 IndexInBucket = Index % Buffer->BucketSize; + + Buffer->Buckets[BucketIndex][IndexInBucket] = Data; + Result = Index; + return Result; +} + +struct string_builder +{ + string_array Buffer; + s32 BufferElementSize; +}; + +internal string_builder +InitStringBuilder(s32 BufferSize) +{ + string_builder Result = {}; + Result.BufferElementSize = BufferSize; + Result.Buffer.BucketSize = STRING_BUILDER_ARRAY_BUFFER_SIZE; + Result.Buffer.FreeList.Next = &Result.Buffer.FreeList; + return Result; +} + +internal void +GrowStringBuilder (string_builder* StringBuilder) +{ + string NewSegment = {}; + NewSegment.Memory = (char*)malloc(StringBuilder->BufferElementSize * sizeof(char)); + NewSegment.Max = StringBuilder->BufferElementSize; + + PushElement(NewSegment, &StringBuilder->Buffer); +} + +internal void +StringBuilderPrintF (string_builder* StringBuilder, char* Format, ...) +{ + string Addition = {}; + Addition.Max = 2048; + Addition.Memory = (char*)malloc(Addition.Max * sizeof(char)); + + va_list Args; + va_start(Args, Format); + Addition.Length = PrintFArgsList(Addition.Memory, Addition.Max, Format, Args); + + s32 CharsCopied = 0; + while (CharsCopied < Addition.Length) + { + s32 StringBuilderTailIndex = StringBuilder->Buffer.Used - 1; + string* LastString = GetEntryAtIndex(StringBuilderTailIndex, StringBuilder->Buffer); + if (!LastString || LastString->Length >= LastString->Max) + { + GrowStringBuilder(StringBuilder); + StringBuilderTailIndex = StringBuilder->Buffer.Used - 1; + LastString = GetEntryAtIndex(StringBuilderTailIndex, StringBuilder->Buffer); + } + + while (CharsCopied < Addition.Length && LastString->Length < LastString->Max) + { + LastString->Memory[LastString->Length++] = Addition.Memory[CharsCopied++]; + } + } + + free(Addition.Memory); +} \ No newline at end of file diff --git a/src/animation/foldhaus_animation.h b/src/animation/foldhaus_animation.h new file mode 100644 index 0000000..064402b --- /dev/null +++ b/src/animation/foldhaus_animation.h @@ -0,0 +1,147 @@ +// TODO +// [] - animation blending +// [] - delete a layer +// [] - will need a way to create an empty layer +// [] - get a list of all animation procs + +#define ANIMATION_PROC(name) void name(assembly* Assembly, r32 Time) +typedef ANIMATION_PROC(animation_proc); + +struct animation_block +{ + // TODO(Peter): Should we change this to frames?? + r32 StartTime; + r32 EndTime; + animation_proc* Proc; + + u32 Layer; +}; + +struct animation_block_handle +{ + s32 Index; + // NOTE(Peter): Zero is invalid + u32 Generation; +}; + +struct animation_block_entry +{ + u32 Generation; + animation_block Block; + free_list Free; +}; + +#define ANIMATION_SYSTEM_LAYERS_MAX 128 +#define ANIMATION_SYSTEM_BLOCKS_MAX 128 +struct animation_system +{ + animation_block_entry Blocks[ANIMATION_SYSTEM_BLOCKS_MAX]; + free_list FreeList; + u32 BlocksCount; + + r32 Time; + s32 LastUpdatedFrame; + r32 SecondsPerFrame; + + b32 TimelineShouldAdvance; + + // :Temporary + r32 AnimationStart; + r32 AnimationEnd; +}; + +internal b32 +AnimationBlockHandlesAreEqual(animation_block_handle A, animation_block_handle B) +{ + b32 Result = ((A.Index == B.Index) && (A.Generation == B.Generation)); + return Result; +} + +internal b32 +AnimationBlockHandleIsValid(animation_block_handle Handle) +{ + b32 Result = Handle.Generation != 0; + return Result; +} + +internal void +InitializeAnimationSystem(animation_system* System) +{ + *System = {0}; + System->FreeList.Next = &System->FreeList; +} + +inline b32 +AnimationBlockIsFree(animation_block_entry Entry) +{ + // NOTE(Peter): If we've set Free.Next to zero, we've removed it from the + // free list. + b32 Result = Entry.Free.Next != 0; + return Result; +} + +internal animation_block_entry* +GetEntryAtIndex(u32 Index, animation_system* System) +{ + Assert(Index < System->BlocksCount); + animation_block_entry* Result = System->Blocks + Index; + return Result; +} + +internal animation_block* +GetAnimationBlockWithHandle(animation_block_handle Handle, animation_system* System) +{ + animation_block* Result = 0; + animation_block_entry* Entry = GetEntryAtIndex(Handle.Index, System); + if (Entry && Entry->Generation == Handle.Generation) + { + Result = &Entry->Block; + } + return Result; +} + +internal animation_block_handle +AddAnimationBlock(animation_block Block, animation_system* System) +{ + animation_block_handle Result = {0}; + + if (System->FreeList.Next != 0 + && System->FreeList.Next != &System->FreeList) + { + free_list* FreeEntry = System->FreeList.Next; + Result.Index = FreeEntry->Index; + System->FreeList.Next = FreeEntry->Next; + } + else + { + Assert(System->BlocksCount < ANIMATION_SYSTEM_BLOCKS_MAX); + Result.Index = System->BlocksCount++; + } + + animation_block_entry* Entry = GetEntryAtIndex(Result.Index, System); + Entry->Generation += 1; + Result.Generation = Entry->Generation; + System->Blocks[Result.Index].Block = Block; + System->Blocks[Result.Index].Free.Next = 0; + + return Result; +} + +internal void +RemoveAnimationBlock(animation_block_handle Handle, animation_system* System) +{ + animation_block_entry* Entry = GetEntryAtIndex(Handle.Index, System); + + // NOTE(Peter): I'm pretty sure this doesn't need to be an assert but at the moment, there + // is no reason why we shouldn't always be able to remove an entry when we request it. + // For now, I'm putting this assert here so we deal with this intentionally when the first + // case comes up. + // TODO: When we do deal with the above note, I'm guessing we want to return true or false + // to signal if we were able to remove the entry or not so that the calling site can deal + // with the removed reference + Assert(Handle.Generation == Entry->Generation); + + Entry->Free.Index = Handle.Index; + Entry->Free.Next = System->FreeList.Next; + System->FreeList.Next = &Entry->Free; +} diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index a9f3f2b..407082c 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -1,12 +1,22 @@ #include "foldhaus_platform.h" #include "foldhaus_app.h" +internal void +SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex) +{ + if(OldPanelDefinitionIndex >= 0) + { + GlobalPanelDefs[OldPanelDefinitionIndex].Cleanup(Panel); + } + GlobalPanelDefs[NewPanelDefinitionIndex].Init(Panel); +} + internal v4 -MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 WindowHeight) +MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, rect WindowBounds) { DEBUG_TRACK_SCOPE(MouseToWorldRay); - r32 X = ((2.0f * MouseX) / WindowWidth) - 1; - r32 Y = ((2.0f * MouseY) / WindowHeight) - 1; + r32 X = ((2.0f * MouseX) / Width(WindowBounds)) - 1; + r32 Y = ((2.0f * MouseY) / Height(WindowBounds)) - 1; v4 ScreenPos = v4{X, Y, -1, 1}; @@ -22,73 +32,10 @@ MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 Win return WorldPosition; } -struct draw_leds_job_data -{ - led* LEDs; - pixel* Colors; - s32 StartIndex; - s32 OnePastLastIndex; - - render_quad_batch_constructor* Batch; - - m44 FaceCameraMatrix; - m44 ModelViewMatrix; - r32 LEDHalfWidth; -}; - -internal void -DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData) -{ - DEBUG_TRACK_FUNCTION; - - draw_leds_job_data* Data = (draw_leds_job_data*)JobData; - - s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex; - - quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2); - s32 TrisUsed = 0; - - r32 HalfWidth = Data->LEDHalfWidth; - - v4 P0_In = v4{-HalfWidth, -HalfWidth, 0, 1}; - v4 P1_In = v4{HalfWidth, -HalfWidth, 0, 1}; - v4 P2_In = v4{HalfWidth, HalfWidth, 0, 1}; - v4 P3_In = v4{-HalfWidth, HalfWidth, 0, 1}; - - v2 UV0 = v2{0, 0}; - v2 UV1 = v2{1, 0}; - v2 UV2 = v2{1, 1}; - v2 UV3 = v2{0, 1}; - - led* LED = Data->LEDs + Data->StartIndex; - for (s32 LEDIdx = 0; - LEDIdx < LEDCount; - LEDIdx++) - { - pixel PixelColor = Data->Colors[LED->Index]; - v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f}; - - v4 V4Position = LED->Position; - V4Position.w = 0; - v4 P0 = P0_In + V4Position; - v4 P1 = P1_In + V4Position; - v4 P2 = P2_In + V4Position; - v4 P3 = P3_In + V4Position; - - SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++, - P0, P1, P2, UV0, UV1, UV2, Color, Color, Color); - SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++, - P0, P2, P3, UV0, UV2, UV3, Color, Color, Color); - - LED++; - } -} - struct send_sacn_job_data { platform_socket_handle SendSocket; - platform_get_send_address* GetSendAddress; platform_send_to* SendTo; dmx_buffer_list* DMXBuffers; }; @@ -99,7 +46,6 @@ SACNSendDMXBufferListJob (s32 ThreadID, void* JobData) DEBUG_TRACK_FUNCTION; send_sacn_job_data* Data = (send_sacn_job_data*)JobData; - platform_get_send_address* GetSendAddress = Data->GetSendAddress; platform_socket_handle SendSocket = Data->SendSocket; platform_send_to* SendTo = Data->SendTo; @@ -109,10 +55,11 @@ SACNSendDMXBufferListJob (s32 ThreadID, void* JobData) dmx_buffer Buffer = DMXBufferAt->Buffer; u_long V4SendAddress = SACNGetUniverseSendAddress(Buffer.Universe); - platform_network_address_handle SendAddress = GetSendAddress( - AF_INET, - HostToNetU16(DEFAULT_STREAMING_ACN_PORT), - HostToNetU32(V4SendAddress)); + + platform_network_address SendAddress = {}; + SendAddress.Family = AF_INET; + SendAddress.Port = DEFAULT_STREAMING_ACN_PORT; + SendAddress.Address = V4SendAddress; SendTo(SendSocket, SendAddress, (const char*)Buffer.Base, Buffer.TotalSize, 0); @@ -120,57 +67,6 @@ SACNSendDMXBufferListJob (s32 ThreadID, void* JobData) } } -internal void -LoadAssembly (app_state* State, context Context, char* Path) -{ - arena_snapshot TempMemorySnapshot = TakeSnapshotOfArena(*State->Transient); - - platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path); - Assert(TestAssemblyFile.Size > 0); - - assembly_definition AssemblyDefinition = ParseAssemblyFile(TestAssemblyFile.Base, TestAssemblyFile.Size, State->Transient); - - Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size); - - string PathString = MakeStringLiteral(Path); - s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\'); - 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); - - assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, - FileName, - v3{0, 0, 0}, - Scale, - AssemblyMemory, - AssemblyMemorySize); - State->AssemblyList[State->AssembliesCount++] = NewAssembly; - State->TotalLEDsCount += NewAssembly.LEDCount; - - ClearArenaToSnapshot(State->Transient, TempMemorySnapshot); -} - -internal void -UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context) -{ - assembly* Assembly = State->AssemblyList + AssemblyIndex; - State->TotalLEDsCount -= Assembly->LEDCount; - Context.PlatformFree(Assembly->Arena.Base, Assembly->Arena.Size); - - if (AssemblyIndex != (State->AssembliesCount - 1)) - { - State->AssemblyList[AssemblyIndex] = State->AssemblyList[State->AssembliesCount - 1]; - } - else - { - *Assembly = {}; - } - State->AssembliesCount -= 1; -} - //////////////////////////////////////////////////////////////////////// RELOAD_STATIC_DATA(ReloadStaticData) @@ -180,36 +76,25 @@ RELOAD_STATIC_DATA(ReloadStaticData) GlobalDebugServices = DebugServices; GSAlloc = Alloc; GSFree = Free; - - if (State->DefaultInputCommandRegistry.Size > 0) - { - RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_MouseLeftButton, Command_Began, KeyCode_Invalid, - Begin3DViewMouseRotate); - RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_U, Command_Began, KeyCode_Invalid, OpenUniverseView); - RegisterKeyPressCommand(&State->DefaultInputCommandRegistry, KeyCode_Tab, Command_Began, KeyCode_Invalid, OpenNodeView); - } } INITIALIZE_APPLICATION(InitializeApplication) { app_state* State = (app_state*)Context.MemoryBase; - u8* MemoryCursor = Context.MemoryBase + sizeof(app_state); - s32 PermanentStorageSize = Megabytes(32); - s32 TransientStorageSize = Context.MemorySize - PermanentStorageSize; - State->Permanent = BootstrapArenaIntoMemory(MemoryCursor, PermanentStorageSize); - State->Transient = BootstrapArenaIntoMemory(MemoryCursor + PermanentStorageSize, TransientStorageSize); - - InitMemoryArena(&State->SACNMemory, 0, 0, Context.PlatformAlloc); - - InitializeInputCommandRegistry(&State->DefaultInputCommandRegistry, 32, State->Permanent); + State->Permanent = {}; + State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; + State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + State->Transient = {}; + State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; + State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; s32 CommandQueueSize = 32; - command_queue_entry* CommandQueueMemory = PushArray(State->Permanent, + command_queue_entry* CommandQueueMemory = PushArray(&State->Permanent, command_queue_entry, CommandQueueSize); State->CommandQueue = InitializeCommandQueue(CommandQueueMemory, CommandQueueSize); - State->ActiveTextEntry.Buffer = MakeString(PushArray(State->Permanent, char, 256), 0, 256); + State->ActiveTextEntry.Buffer = MakeString(PushArray(&State->Permanent, char, 256), 0, 256); // TODO(Peter): put in InitializeInterface? r32 FontSize = 14; @@ -217,12 +102,12 @@ INITIALIZE_APPLICATION(InitializeApplication) platform_memory_result FontFile = Context.PlatformReadEntireFile("Anonymous Pro.ttf"); if (FontFile.Size) { - bitmap_font* Font = PushStruct(State->Permanent, bitmap_font); + bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font); Font->BitmapWidth = 512; Font->BitmapHeight = 512; Font->BitmapBytesPerPixel = 4; - Font->BitmapMemory = PushArray(State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel); + Font->BitmapMemory = PushArray(&State->Permanent, u8, Font->BitmapWidth * Font->BitmapHeight * Font->BitmapBytesPerPixel); Font->BitmapStride = Font->BitmapWidth * Font->BitmapBytesPerPixel; GSMemSet(Font->BitmapMemory, 0, Font->BitmapStride * Font->BitmapHeight); @@ -235,8 +120,8 @@ INITIALIZE_APPLICATION(InitializeApplication) Font->CodepointDictionarySize = (FontInfo.CodepointOnePastLast - FontInfo.CodepointStart); Font->CodepointDictionaryCount = 0; - Font->CodepointKeys = PushArray(State->Permanent, char, Font->CodepointDictionarySize); - Font->CodepointValues = PushArray(State->Permanent, codepoint_bitmap, Font->CodepointDictionarySize); + Font->CodepointKeys = PushArray(&State->Permanent, char, Font->CodepointDictionarySize); + Font->CodepointValues = PushArray(&State->Permanent, codepoint_bitmap, Font->CodepointDictionarySize); for (s32 Codepoint = FontInfo.CodepointStart; Codepoint < FontInfo.CodepointOnePastLast; @@ -248,18 +133,17 @@ INITIALIZE_APPLICATION(InitializeApplication) u32 CodepointW, CodepointH; Context.PlatformDrawFontCodepoint( - Font->BitmapMemory, - Font->BitmapWidth, - Font->BitmapHeight, - CodepointX, CodepointY, - Codepoint, FontInfo, - &CodepointW, &CodepointH); + Font->BitmapMemory, + Font->BitmapWidth, + Font->BitmapHeight, + CodepointX, CodepointY, + Codepoint, FontInfo, + &CodepointW, &CodepointH); AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); } State->Interface.Font = Font; - State->Font = Font; Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory, Font->BitmapWidth, Font->BitmapHeight); @@ -282,12 +166,15 @@ INITIALIZE_APPLICATION(InitializeApplication) State->NetworkProtocolHeaderSize = STREAM_HEADER_SIZE; State->Camera.FieldOfView = DegreesToRadians(45.0f); - State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight; + State->Camera.AspectRatio = AspectRatio(State->WindowBounds); State->Camera.Near = 1.0f; State->Camera.Far = 100.0f; 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); @@ -297,54 +184,73 @@ INITIALIZE_APPLICATION(InitializeApplication) GlobalDebugServices->Interface.RenderSculpture = true; - State->NodeList = AllocateNodeList(State->Permanent, 128); - State->OutputNode = PushOutputNodeOnList(State->NodeList, v2{500, 250}, State->Permanent); - { - State->NodeRenderSettings.PortColors[MemberType_r32] = RedV4; - State->NodeRenderSettings.PortColors[MemberType_s32] = GreenV4; - State->NodeRenderSettings.PortColors[MemberType_v4] = BlueV4; - State->NodeRenderSettings.Font = State->Font; - } ReloadStaticData(Context, GlobalDebugServices, Alloc, Free); - { // MODES PLAYGROUND - State->Modes.ActiveModesCount = 0; - - s32 ModesMemorySize = Kilobytes(32); - u8* ModesMemory = PushSize(State->Permanent, ModesMemorySize); - InitMemoryArena(&State->Modes.Arena, ModesMemory, ModesMemorySize, 0); - } + // Setup Operation Modes + State->Modes.ActiveModesCount = 0; + State->Modes.Arena = {}; + State->Modes.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; + State->Modes.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + State->Modes.Arena.FindAddressRule = FindAddress_InLastBufferOnly; + + { // Animation PLAYGROUND + InitializeAnimationSystem(&State->AnimationSystem); + State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; + State->AnimationSystem.AnimationStart = 0; + State->AnimationSystem.AnimationEnd = 15; + } // End Animation Playground + + + InitializePanelSystem(&State->PanelSystem); + panel* Panel = TakeNewPanel(&State->PanelSystem); + SetPanelDefinition(Panel, 0); } internal void -HandleInput (app_state* State, input_queue InputQueue, mouse_state Mouse) +HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_state Mouse) { DEBUG_TRACK_FUNCTION; - input_command_registry ActiveCommands = State->DefaultInputCommandRegistry; - if (State->Modes.ActiveModesCount > 0) + b32 PanelSystemHandledInput = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + if (!PanelSystemHandledInput) { - ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; - } - - for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) - { - input_entry Event = InputQueue.Entries[EventIdx]; + input_command_registry ActiveCommands = {}; + if (State->Modes.ActiveModesCount > 0) + { + ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; + } + else + { + panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); + if (!PanelWithMouseOverIt.Panel) { return; } + + panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; + if (!PanelDefinition.InputCommands) { return; } + + ActiveCommands.Commands = PanelDefinition.InputCommands; + ActiveCommands.Size = sizeof(*PanelDefinition.InputCommands) / sizeof(PanelDefinition.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; + } - // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege - // Down and Up over Held. In other words, we don't want to call a Held command on the - // frame when the button was released, even if the command is registered to both events - if (KeyTransitionedDown(Event)) + for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); - } - else if (KeyTransitionedUp(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); - } - else if (KeyHeldDown(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + input_entry Event = InputQueue.Entries[EventIdx]; + + // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege + // Down and Up over Held. In other words, we don't want to call a Held command on the + // frame when the button was released, even if the command is registered to both events + if (KeyTransitionedDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue); + } + else if (KeyTransitionedUp(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); + } + else if (KeyHeldDown(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue); + } } } @@ -377,6 +283,7 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) NewBuffer->Buffer.Base = PushArray(Arena, u8, BufferSize); NewBuffer->Buffer.TotalSize = BufferSize; NewBuffer->Buffer.HeaderSize = BufferHeaderSize; + NewBuffer->Next = 0; // Append if (!Result) { @@ -386,6 +293,7 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) Head->Next = NewBuffer; Head = NewBuffer; + u8* DestChannel = Head->Buffer.Base + BufferHeaderSize; for (s32 LEDIdx = LEDUniverseRange.RangeStart; LEDIdx < LEDUniverseRange.RangeOnePastLast; LEDIdx++) @@ -393,8 +301,11 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) led LED = Assembly.LEDs[LEDIdx]; pixel Color = Assembly.Colors[LED.Index]; - s32 DestinationStartChannel = LEDIdx * 3; - *((pixel*)(Head->Buffer.Base + DestinationStartChannel)) = Color; + + DestChannel[0] = Color.R; + DestChannel[1] = Color.G; + DestChannel[2] = Color.B; + DestChannel += 3; } } @@ -405,40 +316,62 @@ UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; app_state* State = (app_state*)Context.MemoryBase; + State->WindowBounds = Context.WindowBounds; // NOTE(Peter): We do this at the beginning because all the render commands are stored in Transient, // and need to persist beyond the end of the UpdateAndRender call. In the release version, we won't // zero the Transient arena when we clear it so it wouldn't be a problem, but it is technically // incorrect to clear the arena, and then access the memory later. - ClearArena(State->Transient); + ClearArena(&State->Transient); - HandleInput(State, InputQueue, Mouse); + HandleInput(State, State->WindowBounds, InputQueue, Mouse); - for (s32 AssemblyIndex = 0; AssemblyIndex < State->AssembliesCount; AssemblyIndex++) - { - assembly Assembly = State->AssemblyList[AssemblyIndex]; - UpdateOutputNodeCalculations(State->OutputNode, State->NodeList, - State->Permanent, State->Transient, - Assembly.LEDs, - Assembly.Colors, - Assembly.LEDCount, - Context.DeltaTime); - ResetNodesUpdateState(State->NodeList); + if (State->AnimationSystem.TimelineShouldAdvance) { + State->AnimationSystem.Time += Context.DeltaTime; + if (State->AnimationSystem.Time > State->AnimationSystem.AnimationEnd) + { + State->AnimationSystem.Time -= State->AnimationSystem.AnimationEnd; + } + } + + s32 CurrentFrame = (s32)(State->AnimationSystem.Time / State->AnimationSystem.SecondsPerFrame); + if (CurrentFrame != State->AnimationSystem.LastUpdatedFrame) + { + State->AnimationSystem.LastUpdatedFrame = CurrentFrame; + r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame; + + for (u32 i = 0; i < State->AnimationSystem.BlocksCount; i++) + { + animation_block_entry BlockEntry = State->AnimationSystem.Blocks[i]; + if (!AnimationBlockIsFree(BlockEntry)) + { + animation_block Block = BlockEntry.Block; + if (State->AnimationSystem.Time >= Block.StartTime + && State->AnimationSystem.Time <= Block.EndTime) + { + for (s32 j = 0; j < State->ActiveAssemblyIndecies.Used; j++) + { + array_entry_handle* AssemblyHandle = GetElementAtIndex(j, State->ActiveAssemblyIndecies); + assembly* Assembly = GetElementWithHandle(*AssemblyHandle, State->AssemblyList); + Block.Proc(Assembly, FrameTime - Block.StartTime); + } + } + } + } } - ClearTransientNodeColorBuffers(State->NodeList); 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]; - dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(Assembly, HeaderSize, State->Transient); + 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); } DEBUG_IF(GlobalDebugServices->Interface.SendSACNData) { - switch (State->NetworkProtocol) { case NetworkProtocol_SACN: @@ -453,139 +386,46 @@ UPDATE_AND_RENDER(UpdateAndRender) CurrentDMXBuffer = CurrentDMXBuffer->Next; } - send_sacn_job_data* Job = PushStruct(State->Transient, send_sacn_job_data); + send_sacn_job_data* Job = PushStruct(&State->Transient, send_sacn_job_data); Job->SendSocket = State->SACN.SendSocket; - Job->GetSendAddress = Context.PlatformGetSendAddress; Job->SendTo = Context.PlatformSendTo; Job->DMXBuffers = DMXBuffers; Context.GeneralWorkQueue->PushWorkOnQueue( - Context.GeneralWorkQueue, - SACNSendDMXBufferListJob, - Job); + Context.GeneralWorkQueue, + SACNSendDMXBufferListJob, + Job); }break; InvalidDefaultCase; } } - //////////////////////////////// - // Render Assembly - /////////////////////////////// - if (Context.WindowIsVisible) + PushRenderOrthographic(RenderBuffer, 0, 0, Width(State->WindowBounds), Height(State->WindowBounds)); + PushRenderClearScreen(RenderBuffer); + + panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); + DrawAllPanels(PanelsToRender, RenderBuffer, Mouse, State, Context); + + for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) { - State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight; - - m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera); - m44 ProjectionMatrix = GetCameraPerspectiveProjectionMatrix(State->Camera); - - r32 LEDHalfWidth = .5f; - - PushRenderPerspective(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHeight, State->Camera); - PushRenderClearScreen(RenderBuffer); - - // TODO(Peter): Pretty sure this isn't working right now - m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1)); - FaceCameraMatrix = FaceCameraMatrix; - - DEBUG_IF(GlobalDebugServices->Interface.RenderSculpture) // DebugServices RenderSculpture Toggle + operation_mode OperationMode = State->Modes.ActiveModes[m]; + if (OperationMode.Render != 0) { - DEBUG_TRACK_SCOPE(RenderSculpture); - - s32 MaxLEDsPerJob = 2048; - render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount); - - for (s32 AssemblyIdx = 0; AssemblyIdx < State->AssembliesCount; AssemblyIdx++) - { - assembly Assembly = State->AssemblyList[AssemblyIdx]; - s32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDCount, MaxLEDsPerJob); - - for (s32 Job = 0; Job < JobsNeeded; Job++) - { - draw_leds_job_data* JobData = PushStruct(State->Transient, draw_leds_job_data); - JobData->LEDs = Assembly.LEDs; - JobData->Colors = Assembly.Colors; - JobData->StartIndex = Job * MaxLEDsPerJob; - JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDCount); - JobData->Batch = &RenderLEDsBatch; - JobData->FaceCameraMatrix; - JobData->ModelViewMatrix = ModelViewMatrix; - JobData->LEDHalfWidth = LEDHalfWidth; - - Context.GeneralWorkQueue->PushWorkOnQueue( - Context.GeneralWorkQueue, - DrawLEDsInBufferRangeJob, - JobData); - } - } - - Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0); - Context.GeneralWorkQueue->ResetWorkQueue(Context.GeneralWorkQueue); + OperationMode.Render(State, RenderBuffer, OperationMode, Mouse); } - - /////////////////////////////////////// - // Interface - ////////////////////////////////////// - - DEBUG_TRACK_SCOPE(DrawInterface); - - PushRenderOrthographic(RenderBuffer, 0, 0, Context.WindowWidth, Context.WindowHeight); - - /////////////////////////////////////// - // Menu Bar - ////////////////////////////////////// - - r32 TopBarHeight = 40; + } + + // Checking for overflows + { + DEBUG_TRACK_SCOPE(OverflowChecks); + AssertAllocationsNoOverflow(State->Permanent); + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - panel_result TopBarPanel = EvaluatePanel(RenderBuffer, - v2{0, Context.WindowHeight - TopBarHeight}, - v2{Context.WindowWidth, Context.WindowHeight}, - 0, State->Interface); - - v2 ButtonDim = v2{200, (r32)NewLineYOffset(*State->Interface.Font) + 10}; - v2 ButtonPos = v2{State->Interface.Margin.x, Context.WindowHeight - (ButtonDim.y + 10)}; - button_result LoadAssemblyBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - MakeStringLiteral("Load Assembly"), - State->Interface, Mouse); - - string InterfaceString = MakeString(PushArray(State->Transient, char, 256), 256); - for (int i = 0; i < State->AssembliesCount; i++) - { - PrintF(&InterfaceString, "Unload %.*s", State->AssemblyList[i].Name.Length, State->AssemblyList[i].Name.Memory); - - ButtonPos.x += ButtonDim.x + 10; - button_result UnloadAssemblyBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - InterfaceString, State->Interface, Mouse); - - if (UnloadAssemblyBtn.Pressed) - { - UnloadAssembly(i, State, Context); - } - } - - if (LoadAssemblyBtn.Pressed) - { - char FilePath[256]; - b32 Success = Context.PlatformGetFilePath(FilePath, 256, "Foldhaus Files\0*.fold\0\0"); - if (Success) - { - LoadAssembly(State, Context, FilePath); - } - } + array_entry_handle* AssemblyHandle = GetElementAtIndex(i, State->ActiveAssemblyIndecies); + assembly* Assembly = GetElementWithHandle(*AssemblyHandle, State->AssemblyList); + AssertAllocationsNoOverflow(Assembly->Arena); } - - for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) - { - operation_mode OperationMode = State->Modes.ActiveModes[m]; - if (OperationMode.Render != 0) - { - OperationMode.Render(State, RenderBuffer, OperationMode, Mouse); - } - } - - DrawDebugInterface(RenderBuffer, 25, - State->Interface, Context.WindowWidth, Context.WindowHeight - TopBarHeight, - Context.DeltaTime, State, State->Camera, Mouse, State->Transient); } } diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index b8a723b..3c60263 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -13,18 +13,21 @@ #include "foldhaus_node.h" #include "assembly_parser.cpp" #include "test_patterns.h" -#include "foldhaus_interface.h" + +// TODO(Peter): something we can do later is to remove all reliance on app_state and context +// from foldhaus_pane.h. It should just emit lists of things that the app can iterate over and +// perform operations on, like panel_draw_requests = { bounds, panel* } etc. +#include "foldhaus_panel.h" typedef struct app_state app_state; #include "foldhaus_command_dispatch.h" -#include "foldhaus_command_dispatch.cpp" #include "foldhaus_operation_mode.h" +#include "animation/foldhaus_animation.h" + #include "foldhaus_text_entry.h" -#include "foldhaus_default_nodes.h" -#include "generated/foldhaus_nodes_generated.cpp" #include "foldhaus_search_lister.h" enum network_protocol @@ -37,9 +40,10 @@ enum network_protocol struct app_state { - memory_arena* Permanent; - memory_arena* Transient; - memory_arena SACNMemory; + rect WindowBounds; + + memory_arena Permanent; + memory_arena Transient; s32 NetworkProtocolHeaderSize; network_protocol NetworkProtocol; @@ -47,37 +51,168 @@ struct app_state streaming_acn SACN; 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; operation_mode_system Modes; - input_command_registry DefaultInputCommandRegistry; input_command_queue CommandQueue; text_entry ActiveTextEntry; - node_list* NodeList; - node_header* OutputNode; - - node_render_settings NodeRenderSettings; - bitmap_font* Font; interface_config Interface; + + animation_system AnimationSystem; + animation_block_handle SelectedAnimationBlockHandle; + + panel_system PanelSystem; }; internal void OpenColorPicker(app_state* State, v4* Address); +// BEGIN TEMPORARY PATTERNS +internal void +TestPatternOne(assembly* Assembly, r32 Time) +{ + for (s32 Range = 0; Range < Assembly->LEDUniverseMapCount; Range++) + { + leds_in_universe_range LEDUniverseRange = Assembly->LEDUniverseMap[Range]; + for (s32 LEDIdx = LEDUniverseRange.RangeStart; + LEDIdx < LEDUniverseRange.RangeOnePastLast; + LEDIdx++) + { + led LED = Assembly->LEDs[LEDIdx]; + Assembly->Colors[LED.Index].R = 255; + Assembly->Colors[LED.Index].B = 255; + Assembly->Colors[LED.Index].G = 255; + } + } +} + +internal void +TestPatternTwo(assembly* Assembly, r32 Time) +{ + r32 PeriodicTime = (Time / PI) * 2; + + r32 ZeroOneSin = (GSSin(PeriodicTime) * .5f) + .5f; + r32 ZeroOneCos = (GSCos(PeriodicTime) * .5f) + .5f; + pixel Color = { (u8)(ZeroOneSin * 255), 0, (u8)(ZeroOneCos * 255) }; + + v4 Center = v4{0, 0, 0, 1}; + r32 ThetaZ = Time / 2; + v4 Normal = v4{GSCos(ThetaZ), 0, GSSin(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 + v4 Right = Cross(Normal, v4{0, 1, 0, 0}); + + v4 FrontCenter = Center + (Normal * 25); + v4 BackCenter = Center - (Normal * 25); + + r32 OuterRadiusSquared = 1000000; + r32 InnerRadiusSquared = 0; + + for (s32 Range = 0; Range < Assembly->LEDUniverseMapCount; Range++) + { + leds_in_universe_range LEDUniverseRange = Assembly->LEDUniverseMap[Range]; + for (s32 LEDIdx = LEDUniverseRange.RangeStart; + LEDIdx < LEDUniverseRange.RangeOnePastLast; + LEDIdx++) + { + led LED = Assembly->LEDs[LEDIdx]; + + v4 Position = LED.Position; + + v4 ToFront = Position + FrontCenter; + v4 ToBack = Position + BackCenter; + + r32 ToFrontDotNormal = Dot(ToFront, Normal); + r32 ToBackDotNormal = Dot(ToBack, Normal); + + ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000); + ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000); + + r32 SqDistToCenter = MagSqr(Position); + if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) + { + if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) + { + Assembly->Colors[LED.Index] = Color; + } + else + { + Assembly->Colors[LED.Index] = {}; + } + } + else + { + Assembly->Colors[LED.Index] = {}; + } + } + } +} + +internal void +TestPatternThree(assembly* Assembly, r32 Time) +{ + r32 GreenSize = 20.0f; + r32 BlueSize = 25.0f; + r32 RedSize = 25.0f; + + r32 GreenPosition = -GreenSize + (Time * 45); + r32 BluePosition = -BlueSize + (Time * 25); + r32 RedPosition = (100 + RedSize) + (Time * -35); + + for (s32 Range = 0; Range < Assembly->LEDUniverseMapCount; Range++) + { + leds_in_universe_range LEDUniverseRange = Assembly->LEDUniverseMap[Range]; + for (s32 LEDIdx = LEDUniverseRange.RangeStart; + LEDIdx < LEDUniverseRange.RangeOnePastLast; + LEDIdx++) + { + led LED = Assembly->LEDs[LEDIdx]; + u8 Red = 0; + u8 Green = 0; + u8 Blue = 0; + + r32 GreenDistance = GSAbs(LED.Position.z - GreenPosition); + r32 GreenBrightness = GSClamp(0.0f, GreenSize - GreenDistance, GreenSize) / GreenSize; + Green = (u8)(GreenBrightness * 255); + + r32 BlueDistance = GSAbs(LED.Position.z - BluePosition); + r32 BlueBrightness = GSClamp(0.0f, BlueSize - BlueDistance, BlueSize) / BlueSize; + Blue = (u8)(BlueBrightness * 255); + + r32 RedDistance = GSAbs(LED.Position.z - RedPosition); + r32 RedBrightness = GSClamp(0.0f, RedSize - RedDistance, RedSize) / RedSize; + Red = (u8)(RedBrightness * 255); + + Assembly->Colors[LED.Index].R = Red; + Assembly->Colors[LED.Index].B = Blue; + Assembly->Colors[LED.Index].G = Green; + } + } +} +// END TEMPORARY PATTERNS + #include "foldhaus_assembly.cpp" -#include "foldhaus_node.cpp" -#include "foldhaus_debug_visuals.h" -//#include "foldhaus_sacn_view.cpp" + #include "foldhaus_text_entry.cpp" #include "foldhaus_search_lister.cpp" -#include "foldhaus_interface.cpp" \ No newline at end of file +#define PANEL_INIT_PROC(name) void name(panel* Panel) +typedef PANEL_INIT_PROC(panel_init_proc); + +#define PANEL_CLEANUP_PROC(name) void name(panel* Panel) +typedef PANEL_CLEANUP_PROC(panel_cleanup_proc); + +#define PANEL_RENDER_PROC(name) void name(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +typedef PANEL_RENDER_PROC(panel_render_proc); + +#include "panels/foldhaus_panel_sculpture_view.h" +#include "panels/foldhaus_panel_profiler.h" +#include "panels/foldhaus_panel_dmx_view.h" +#include "panels/foldhaus_panel_animation_timeline.h" +#include "panels/foldhaus_panel_hierarchy.h" + +#include "generated/foldhaus_panels_generated.h" + +#include "foldhaus_interface.cpp" diff --git a/src/foldhaus_assembly.cpp b/src/foldhaus_assembly.cpp index 418b169..4a39d04 100644 --- a/src/foldhaus_assembly.cpp +++ b/src/foldhaus_assembly.cpp @@ -10,13 +10,12 @@ GetAssemblyMemorySizeFromDefinition(assembly_definition Definition, string Name) internal assembly ConstructAssemblyFromDefinition (assembly_definition Definition, string AssemblyName, - v3 RootPosition, + v4 RootPosition, r32 Scale, - u8* MemoryBase, - s32 MemorySize) + memory_arena Arena) { assembly Assembly = {}; - Assembly.Arena = CreateMemoryArena(MemoryBase, MemorySize); + Assembly.Arena = Arena; Assembly.Name = MakeString(PushArray(&Assembly.Arena, char, AssemblyName.Length), AssemblyName.Length); CopyStringTo(AssemblyName, &Assembly.Name); @@ -44,8 +43,8 @@ ConstructAssemblyFromDefinition (assembly_definition Definition, // now. The assert is to remind you to create more cases when necessary Assert(StripDef.InterpolationType == StripInterpolate_Points); - v4 WS_StripStart = V4(StripDef.InterpolatePositionStart * Scale, 1); - v4 WS_StripEnd = V4(StripDef.InterpolatePositionEnd * Scale, 1); + v4 WS_StripStart = RootPosition + V4(StripDef.InterpolatePositionStart * Scale, 1); + v4 WS_StripEnd = RootPosition + V4(StripDef.InterpolatePositionEnd * Scale, 1); s32 LEDsInStripCount = StripDef.LEDsPerStrip; Assert(Assembly.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount); @@ -63,3 +62,56 @@ ConstructAssemblyFromDefinition (assembly_definition Definition, Assert(Assembly.LEDCount == Definition.TotalLEDCount); return Assembly; } + +static v4 TempAssemblyOffsets[] = { v4{0, 0, 0, 0}, v4{250, 0, 75, 0}, v4{-250, 0, 75, 0} }; +s32 TempAssemblyOffsetsCount = 3; + +internal void +LoadAssembly (app_state* State, context Context, char* Path) +{ + platform_memory_result TestAssemblyFile = Context.PlatformReadEntireFile(Path); + Assert(TestAssemblyFile.Size > 0); + + assembly_definition AssemblyDefinition = ParseAssemblyFile(TestAssemblyFile.Base, TestAssemblyFile.Size, &State->Transient); + + Context.PlatformFree(TestAssemblyFile.Base, TestAssemblyFile.Size); + + string PathString = MakeStringLiteral(Path); + s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\'); + string FileName = Substring(PathString, IndexOfLastSlash + 1); + + r32 Scale = 100; + memory_arena AssemblyArena = {}; + AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; + AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + + v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount]; + assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, + FileName, + Offset, + Scale, + AssemblyArena); + array_entry_handle NewAssemblyHandle = PushElement(NewAssembly, &State->AssemblyList); + PushElement(NewAssemblyHandle, &State->ActiveAssemblyIndecies); + + State->TotalLEDsCount += NewAssembly.LEDCount; +} + +internal void +UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context) +{ + assembly* Assembly = GetElementAtIndex(AssemblyIndex, State->AssemblyList); + State->TotalLEDsCount -= Assembly->LEDCount; + FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree); + + RemoveElementAtIndex(AssemblyIndex, &State->AssemblyList); + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) + { + array_entry_handle Handle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + if (Handle.Index == AssemblyIndex) + { + RemoveElementAtIndex(i, &State->ActiveAssemblyIndecies); + break; + } + } +} diff --git a/src/foldhaus_assembly.h b/src/foldhaus_assembly.h index ea945f7..637ae5f 100644 --- a/src/foldhaus_assembly.h +++ b/src/foldhaus_assembly.h @@ -24,7 +24,7 @@ struct leds_in_universe_range struct assembly { - static_memory_arena Arena; + memory_arena Arena; string Name; string FilePath; @@ -36,3 +36,5 @@ struct assembly s32 LEDUniverseMapCount; leds_in_universe_range* LEDUniverseMap; }; + +TYPEDEF_ARRAY(assembly); diff --git a/src/foldhaus_command_dispatch.cpp b/src/foldhaus_command_dispatch.cpp deleted file mode 100644 index 325df75..0000000 --- a/src/foldhaus_command_dispatch.cpp +++ /dev/null @@ -1,149 +0,0 @@ -internal void -InitializeInputCommandRegistry (input_command_registry* CommandRegistry, - s32 Size, - memory_arena* Storage) -{ - CommandRegistry->Commands = PushArray(Storage, input_command, Size); - CommandRegistry->Size = Size; - CommandRegistry->Used = 0; -} - -internal void -RegisterMouseWheelCommand (input_command_registry* CommandRegistry, - input_command_proc* Proc) -{ - CommandRegistry->MouseWheelCommand = Proc; -} - -internal s32 -GetCommandIndexInQueue(input_command_queue* Queue, input_command Command, input_entry Event) -{ - s32 Result = -1; - for (s32 CommandIndex = 0; CommandIndex < Queue->Used; CommandIndex++) - { - command_queue_entry* Entry = Queue->Commands + CommandIndex; - if(Entry->Event.Key == Event.Key) - { - Result = CommandIndex; - break; - } - } - return Result; -} - -internal input_command_queue -InitializeCommandQueue(command_queue_entry* Memory, s32 MemorySize) -{ - input_command_queue Result = {}; - Result.Size = MemorySize; - Result.Used = 0; - Result.Commands = Memory; - return Result; -} - -internal void -ClearCommandQueue(input_command_queue* Queue) -{ - Queue->Used = 0; -} - -internal void -PushCommandOnQueue(input_command_queue* Queue, input_command Command, input_entry Event) -{ - Assert(Queue->Used < Queue->Size); - command_queue_entry Entry = {}; - Entry.Command = Command; - Entry.Event = Event; - Queue->Commands[Queue->Used++] = Entry; -} - -internal void -RemoveCommandFromQueue(input_command_queue* Queue, s32 Index) -{ - s32 CommandIndex = Index; - if (CommandIndex < Queue->Used) - { - Queue->Used -= 1; - - for (; CommandIndex < Queue->Used; CommandIndex++) - { - Queue->Commands[CommandIndex] = Queue->Commands[CommandIndex + 1]; - } - } -} - -internal void -RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_entry Event) -{ - s32 CommandIndex = GetCommandIndexInQueue(Queue, Command, Event); - - // NOTE(Peter): If we made it through the queue without finding an event, there wasn't one - // to remove. This happens when we've changed command registries as a result of an input command, - // and the command exists in the new registry. - // For example: - // clicking a mouse button triggers a command to switch registries - // the new registry tracks mouse drag (persist until release) - // when the mouse is released, the event fires, but there is no mouse down event to remove - // For this reason, I'm allowing the case where we try and remove a command where non exists - // I don't think this is a great solution but Im not super familiar with the codebase right now - // so leaving it as is. revisit if it becomes a problem. - RemoveCommandFromQueue(Queue, CommandIndex); -} - -internal input_command* -FindExistingCommand (input_command_registry CommandRegistry, key_code Key, key_code Mdfr, b32 Flags) -{ - input_command* Result = 0; - - for (s32 Cmd = 0; Cmd < CommandRegistry.Used; Cmd++) - { - input_command* Command = CommandRegistry.Commands + Cmd; - if (Command->Key == Key && Command->Mdfr == Mdfr) - { - b32 FlagsOverlap = Flags & Command->Flags; - if (FlagsOverlap) - { - Result = Command; - break; - } - } - } - - return Result; -} - -internal b32 -FindAndPushExistingCommand(input_command_registry CommandRegistry, input_entry Event, b32 Flags, input_command_queue* CommandQueue) -{ - b32 CommandFound = false; - input_command* Command = FindExistingCommand(CommandRegistry, Event.Key, (key_code)0, Flags); - if (Command) - { - PushCommandOnQueue(CommandQueue, *Command, Event); - CommandFound = true; - } - return CommandFound; -} - -internal void -RegisterKeyPressCommand (input_command_registry* CommandRegistry, - key_code Key, - b32 Flags, - key_code Mdfr, - input_command_proc* Proc) -{ - input_command* Command = FindExistingCommand(*CommandRegistry, Key, Mdfr, Flags); - - if (!Command) - { - Assert(CommandRegistry->Size > CommandRegistry->Used); - Assert(Mdfr == KeyCode_Invalid || Mdfr == KeyCode_LeftShift || Mdfr == KeyCode_RightShift || - Mdfr == KeyCode_LeftCtrl || Mdfr == KeyCode_RightCtrl || Mdfr == KeyCode_Alt); - Command = CommandRegistry->Commands + CommandRegistry->Used++; - } - - Command->Key = Key; - Command->Flags = Flags; - Command->Mdfr = Mdfr; - Command->Proc = Proc; -} \ No newline at end of file diff --git a/src/foldhaus_command_dispatch.h b/src/foldhaus_command_dispatch.h index 6f5fd08..e038e68 100644 --- a/src/foldhaus_command_dispatch.h +++ b/src/foldhaus_command_dispatch.h @@ -43,4 +43,154 @@ struct input_command_queue s32 Size; s32 Used; command_queue_entry* Commands; -}; \ No newline at end of file +}; + +internal void +InitializeInputCommandRegistry (input_command_registry* CommandRegistry, + s32 Size, + memory_arena* Storage) +{ + CommandRegistry->Commands = PushArray(Storage, input_command, Size); + CommandRegistry->Size = Size; + CommandRegistry->Used = 0; +} + +internal void +RegisterMouseWheelCommand (input_command_registry* CommandRegistry, + input_command_proc* Proc) +{ + CommandRegistry->MouseWheelCommand = Proc; +} + +internal s32 +GetCommandIndexInQueue(input_command_queue* Queue, input_command Command, input_entry Event) +{ + s32 Result = -1; + for (s32 CommandIndex = 0; CommandIndex < Queue->Used; CommandIndex++) + { + command_queue_entry* Entry = Queue->Commands + CommandIndex; + if(Entry->Event.Key == Event.Key) + { + Result = CommandIndex; + break; + } + } + return Result; +} + +internal input_command_queue +InitializeCommandQueue(command_queue_entry* Memory, s32 MemorySize) +{ + input_command_queue Result = {}; + Result.Size = MemorySize; + Result.Used = 0; + Result.Commands = Memory; + return Result; +} + +internal void +ClearCommandQueue(input_command_queue* Queue) +{ + Queue->Used = 0; +} + +internal void +PushCommandOnQueue(input_command_queue* Queue, input_command Command, input_entry Event) +{ + Assert(Queue->Used < Queue->Size); + command_queue_entry Entry = {}; + Entry.Command = Command; + Entry.Event = Event; + Queue->Commands[Queue->Used++] = Entry; +} + +internal void +RemoveCommandFromQueue(input_command_queue* Queue, s32 Index) +{ + s32 CommandIndex = Index; + if (CommandIndex < Queue->Used) + { + Queue->Used -= 1; + + for (; CommandIndex < Queue->Used; CommandIndex++) + { + Queue->Commands[CommandIndex] = Queue->Commands[CommandIndex + 1]; + } + } +} + +internal void +RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_entry Event) +{ + s32 CommandIndex = GetCommandIndexInQueue(Queue, Command, Event); + + // NOTE(Peter): If we made it through the queue without finding an event, there wasn't one + // to remove. This happens when we've changed command registries as a result of an input command, + // and the command exists in the new registry. + // For example: + // clicking a mouse button triggers a command to switch registries + // the new registry tracks mouse drag (persist until release) + // when the mouse is released, the event fires, but there is no mouse down event to remove + // For this reason, I'm allowing the case where we try and remove a command where non exists + // I don't think this is a great solution but Im not super familiar with the codebase right now + // so leaving it as is. revisit if it becomes a problem. + RemoveCommandFromQueue(Queue, CommandIndex); +} + +internal input_command* +FindExistingCommand (input_command_registry CommandRegistry, key_code Key, key_code Mdfr, b32 Flags) +{ + input_command* Result = 0; + + for (s32 Cmd = 0; Cmd < CommandRegistry.Used; Cmd++) + { + input_command* Command = CommandRegistry.Commands + Cmd; + if (Command->Key == Key && Command->Mdfr == Mdfr) + { + b32 FlagsOverlap = Flags & Command->Flags; + if (FlagsOverlap) + { + Result = Command; + break; + } + } + } + + return Result; +} + +internal b32 +FindAndPushExistingCommand(input_command_registry CommandRegistry, input_entry Event, b32 Flags, input_command_queue* CommandQueue) +{ + b32 CommandFound = false; + input_command* Command = FindExistingCommand(CommandRegistry, Event.Key, (key_code)0, Flags); + if (Command) + { + PushCommandOnQueue(CommandQueue, *Command, Event); + CommandFound = true; + } + return CommandFound; +} + +internal void +RegisterKeyPressCommand (input_command_registry* CommandRegistry, + key_code Key, + b32 Flags, + key_code Mdfr, + input_command_proc* Proc) +{ + input_command* Command = FindExistingCommand(*CommandRegistry, Key, Mdfr, Flags); + + if (!Command) + { + Assert(CommandRegistry->Size > CommandRegistry->Used); + Assert(Mdfr == KeyCode_Invalid || Mdfr == KeyCode_LeftShift || Mdfr == KeyCode_RightShift || + Mdfr == KeyCode_LeftCtrl || Mdfr == KeyCode_RightCtrl || Mdfr == KeyCode_Alt); + Command = CommandRegistry->Commands + CommandRegistry->Used++; + } + + Command->Key = Key; + Command->Flags = Flags; + Command->Mdfr = Mdfr; + Command->Proc = Proc; +} \ No newline at end of file diff --git a/src/foldhaus_debug_visuals.h b/src/foldhaus_debug_visuals.h index e9e313a..7242ef9 100644 --- a/src/foldhaus_debug_visuals.h +++ b/src/foldhaus_debug_visuals.h @@ -1,194 +1,3 @@ - -internal void -RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer, - interface_config Interface, mouse_state Mouse, - v2 Min, v2 Max, - debug_frame* VisibleFrame, memory_arena* Memory) -{ - v4 ThreadColors[] = { - v4{.73f, .33f, .83f, 1}, - v4{0, .50f, .50f, 1}, - v4{.83f, 0, 0, 1}, - v4{.33f, .49f, .83f, 1}, - v4{.74f, .40f, .25f, 1}, - }; - - r32 Width = Max.x - Min.x; - r32 DepthHeight = 64; - - s64 FrameStartCycles = VisibleFrame->FrameStartCycles; - s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; - - debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices, - VisibleFrame); - - MakeStringBuffer(String, 256); - for (s32 i = 0; i < ThreadScopeCalls->Count; i++) - { - scope_record* Record = ThreadScopeCalls->Calls + i; - scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash); - r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles; - r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles; - - v2 ScopeMin = v2{Min.x + (Width * PercentStart), Max.y - ((Record->CallDepth + 1) * DepthHeight)}; - v2 ScopeMax = v2{Min.x + (Width * PercentEnd), ScopeMin.y + (DepthHeight - 4)}; - - if ((ScopeMax.x - ScopeMin.x) >= 1) - { - v4 Color = ThreadColors[0]; - if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax)) - { - Color = GreenV4; - } - - PushRenderQuad2D(RenderBuffer, ScopeMin, ScopeMax, Color); - PushRenderBoundingBox2D(RenderBuffer, ScopeMin, ScopeMax, 1, BlackV4); - - if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax)) - { - PushRenderQuad2D(RenderBuffer, Mouse.Pos, Mouse.Pos + v2{256, 32}, BlackV4); - PrintF(&String, "%.*s : %d - %d", Name->Name.Length, Name->Name.Memory, Record->StartCycles, Record->EndCycles); - DrawString(RenderBuffer, String, Interface.Font, Mouse.Pos, WhiteV4); - } - } - } -} - -internal void -RenderProfiler_ListVisualization(render_command_buffer* RenderBuffer, - interface_config Interface, mouse_state Mouse, - v2 Min, v2 Max, - debug_frame* VisibleFrame, memory_arena* Memory) -{ - MakeStringBuffer(String, 256); - - r32 YAt = Max.y - Interface.Font->PixelHeight; - r32 Column0X = Min.x; - r32 Column1X = Column0X + 256; - r32 Column2X = Column1X + 128; - r32 Column3X = Column2X + 128; - r32 Column4X = Column3X + 100; - - for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) - { - scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; - if (NameEntry.Hash != 0) - { - collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; - - PrintF(&String, "%.*s", NameEntry.Name.Length, NameEntry.Name.Memory); - DrawString(RenderBuffer, String, Interface.Font, v2{Column0X, YAt}, WhiteV4); - - PrintF(&String, "%f", CollatedRecord->PercentFrameTime); - DrawString(RenderBuffer, String, Interface.Font, v2{Column1X, YAt}, WhiteV4); - - PrintF(&String, "%fs", CollatedRecord->TotalSeconds); - DrawString(RenderBuffer, String, Interface.Font, v2{Column2X, YAt}, WhiteV4); - - PrintF(&String, "%dcy", CollatedRecord->TotalCycles); - DrawString(RenderBuffer, String, Interface.Font, v2{Column3X, YAt}, WhiteV4); - - PrintF(&String, "%d calls", CollatedRecord->CallCount); - DrawString(RenderBuffer, String, Interface.Font, v2{Column4X, YAt}, WhiteV4); - - YAt -= Interface.Font->PixelHeight + 4; - - if (YAt < Min.y) { break; } - } - } -} - -internal void -DrawDebugFrameList (render_command_buffer* RenderBuffer, interface_config Interface, mouse_state Mouse, v2 BoundsMin, v2 BoundsMax, memory_arena* Memory) -{ - string String = InitializeEmptyString(PushArray(Memory, char, 256), 256); - - v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 }; - - r32 FrameListHeight = 64; - v2 FrameListMin = v2{BoundsMin.x + 16, BoundsMax.y - (16 + FrameListHeight)}; - v2 FrameListMax = v2{BoundsMax.x - 16, BoundsMax.y - 16}; - - r32 FrameListPadding = 4; - r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2); - - r32 SingleFrameStep = FrameListInnerWidth / DEBUG_FRAME_COUNT; - r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2); - - PushRenderBoundingBox2D(RenderBuffer, FrameListMin, FrameListMax, 2, WhiteV4); - - if (PointIsInRange(Mouse.Pos, FrameListMin, FrameListMax) && - MouseButtonHeldDown(Mouse.LeftButtonState)) - { - r32 LocalMouseX = (Mouse.Pos.x - FrameListMin.x) + FrameListPadding; - s32 ClosestFrameIndex = (LocalMouseX / SingleFrameStep); - - if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT) - { - GlobalDebugServices->RecordFrames = false; - GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex; - } - } - - for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++) - { - v2 Min = v2{FrameListMin.x + FrameListPadding + (F * SingleFrameStep), FrameListMin.y + 4}; - v2 Max = v2{Min.x + SingleFrameWidth, FrameListMax.y - 4}; - - s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F); - if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; } - v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)]; - PushRenderQuad2D(RenderBuffer, Min, Max, Color); - } - - debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - s64 FrameStartCycles = VisibleFrame->FrameStartCycles; - s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; - - PrintF(&String, "Frame %d - Total Cycles: %lld", - GlobalDebugServices->CurrentDebugFrame - 1, - FrameTotalCycles); - DrawString(RenderBuffer, String, Interface.Font, FrameListMin - v2{0, 32}, WhiteV4); - - v2 ButtonMin = v2{FrameListMax.x - 128, FrameListMin.y - 32}; - v2 ButtonMax = ButtonMin + v2{128, 28}; - button_result ShouldResumeRecording = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("Resume Recording"), Interface, Mouse); - if (ShouldResumeRecording.Pressed) - { - GlobalDebugServices->RecordFrames = true; - } - - ButtonMin = v2{FrameListMin.x, FrameListMin.y - 60}; - ButtonMax = v2{FrameListMin.x + 128, FrameListMin.y - 42}; - button_result ActivateScopeView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("Scope View"), Interface, Mouse); - - ButtonMin.x += 152; - ButtonMax.x += 152; - button_result ActivateListView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - MakeString("List View"), Interface, Mouse); - - if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; } - if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; } - - v2 ViewModeMin = v2{FrameListMin.x, BoundsMin.y}; - v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96}; - - if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) - { - RenderProfiler_ScopeVisualization(RenderBuffer, Interface, Mouse, - ViewModeMin, ViewModeMax, - VisibleFrame, Memory); - } - else - { - RenderProfiler_ListVisualization(RenderBuffer, Interface, Mouse, - ViewModeMin, ViewModeMax, - VisibleFrame, Memory); - } -} - internal void DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_config Interface, r32 WindowWidth, r32 WindowHeight, r32 DeltaTime, app_state* State, camera Camera, mouse_state Mouse, memory_arena* Transient) { @@ -197,8 +6,6 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c v2 TopOfDebugView = v2{StartX, WindowHeight - (NewLineYOffset(*Interface.Font) + 5)}; v2 TopOfScreenLinePos = TopOfDebugView; - arena_snapshot StartTempMemory = TakeSnapshotOfArena(*Transient); - string DebugString = InitializeEmptyString(PushArray(Transient, char, 256), 256); if (GlobalDebugServices->Interface.ShowCameraMouse) @@ -211,12 +18,12 @@ 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, - State->Modes.Arena.CurrentRegion->Used, - State->Modes.Arena.CurrentRegion->Size, + State->Modes.Arena.TotalUsed, + State->Modes.Arena.TotalSize, State->CommandQueue.Used); DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, WhiteV4); @@ -298,13 +105,6 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c TopOfScreenLinePos, WhiteV4); TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - PrintF(&DebugString, "Nodes Memory: %d / %d", - State->NodeList->TotalUsed, - State->NodeList->TotalMax); - DrawString(RenderBuffer, DebugString, Interface.Font, - TopOfScreenLinePos, WhiteV4); - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - PrintF(&DebugString, "Render Buffer: %d / %d (at this point)", RenderBuffer->CommandMemoryUsed, RenderBuffer->CommandMemorySize); @@ -312,58 +112,4 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c TopOfScreenLinePos, WhiteV4); TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); } - - if (GlobalDebugServices->Interface.ShowTrackedScopes) - { - v2 ProfilerMin = v2{TopOfDebugView.x, TopOfDebugView.y - 500}; - v2 ProfilerMax = v2{TopOfDebugView.x + 700, TopOfDebugView.y - 64}; - PushRenderQuad2D(RenderBuffer, ProfilerMin, ProfilerMax, v4{0, 0, 0, .8f}); - DrawDebugFrameList(RenderBuffer, Interface, Mouse, ProfilerMin, ProfilerMax, Transient); - -#if 0 - r32 ColumnsStartX = TopOfScreenLinePos.x; - for (s32 i = 0; i < GlobalDebugServices->ScopeHistogramUsed; i++) - { - v2 Register = v2{ColumnsStartX, TopOfScreenLinePos.y}; - - s32 CurrentFrame = GlobalDebugServices->ScopeHistogramSorted[i].CurrentFrame - 1; - if (CurrentFrame < 0) { CurrentFrame = HISTOGRAM_DEPTH - 1; } - - u64 CyclesPerHit = GlobalDebugServices->ScopeHistogramSorted[i].PerFrame_Cycles[CurrentFrame]; - r32 SecondsPerHit = (r32)CyclesPerHit / (r32)GlobalDebugServices->PerformanceCountFrequency; - - // Column 1 - PrintF(&DebugString, "%.*s", - GlobalDebugServices->ScopeHistogramSorted[i].ScopeName.Length, - GlobalDebugServices->ScopeHistogramSorted[i].ScopeName.Memory); - r32 ColumnOneX = DrawString(RenderBuffer, DebugString, Interface.Font, - Register, WhiteV4).x; - Register.x += GSMax(ColumnOneX - Register.x, 250.f); - - // Column 2 - PrintF(&DebugString, "%d hits", GlobalDebugServices->ScopeHistogramSorted[i].PerFrame_CallCount[CurrentFrame]); - r32 ColumnTwoX = DrawString(RenderBuffer, DebugString, Interface.Font, - Register, WhiteV4).x; - Register.x += GSMax(ColumnTwoX - Register.x, 150.f); - - // Column 3 - PrintF(&DebugString, "%lld cycles", CyclesPerHit); - r32 ColumnThreeX = DrawString(RenderBuffer, DebugString, Interface.Font, - Register, WhiteV4).x; - Register.x += GSMax(ColumnThreeX - Register.x, 200.f); - - PrintF(&DebugString, "%f sec", SecondsPerHit); - r32 ColumnFourX = DrawString(RenderBuffer, DebugString, Interface.Font, - Register, WhiteV4).x; - Register.x += GSMax(ColumnFourX - Register.x, 200.f); - - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - - - } -#endif - } - - ZeroArenaToSnapshot(Transient, StartTempMemory); - ClearArenaToSnapshot(Transient, StartTempMemory); } diff --git a/src/foldhaus_interface.cpp b/src/foldhaus_interface.cpp index cc1c53a..1454635 100644 --- a/src/foldhaus_interface.cpp +++ b/src/foldhaus_interface.cpp @@ -117,8 +117,7 @@ input_command UniverseViewCommands [] = { FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView) { - operation_mode* UniverseViewMode = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommands); - UniverseViewMode->Render = RenderUniverseView; + operation_mode* UniverseViewMode = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommands, RenderUniverseView); // State Setup universe_view_operation_state* OpState = CreateOperationState(UniverseViewMode, @@ -130,542 +129,458 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView) //////////////////////////////////////// // -// Node Lister +// Panels // /////////////////////////////////////// -struct node_lister_operation_state +enum panel_edit_mode { - search_lister SearchLister; - v2 ListPosition; + PanelEdit_Modify, + PanelEdit_Destroy, + + PanelEdit_Count, }; -OPERATION_RENDER_PROC(RenderNodeLister) +// +// Drag Panel Border Operation Mode + +OPERATION_STATE_DEF(drag_panel_border_operation_state) { - node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory; + panel* Panel; - v2 TopLeft = OpState->ListPosition; - v2 Dimension = v2{300, 30}; - - // Filter the lister - OpState->SearchLister.Filter = State->ActiveTextEntry.Buffer; - FilterSearchLister(&OpState->SearchLister); - - // Display Search Lister - search_lister_result NodeListerResult = EvaluateSearchLister (RenderBuffer, TopLeft, Dimension, - MakeStringLiteral("Nodes List"), - OpState->SearchLister.SourceList, - OpState->SearchLister.FilteredIndexLUT, - OpState->SearchLister.FilteredListCount, - OpState->SearchLister.HotItem, - &State->ActiveTextEntry.Buffer, - State->ActiveTextEntry.CursorPosition, - State->Font, State->Interface, Mouse); -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - OpState->SearchLister.HotItem = GetNextFilteredItem(OpState->SearchLister); -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeListerPrevItem) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - OpState->SearchLister.HotItem = GetPrevFilteredItem(OpState->SearchLister); -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeLister) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -FOLDHAUS_INPUT_COMMAND_PROC(SelectAndCloseNodeLister) -{ - node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); - s32 FilteredNodeIndex = OpState->SearchLister.HotItem; - if (FilteredNodeIndex >= 0) - { - s32 NodeIndex = OpState->SearchLister.FilteredIndexLUT[FilteredNodeIndex]; - PushNodeOnListFromSpecification(State->NodeList, (node_type)NodeIndex, - Mouse.Pos, State->Permanent); - } - CloseNodeLister(State, Event, Mouse); -} - -input_command UniverseViewCommads [] = { - { KeyCode_DownArrow, KeyCode_Invalid, Command_Began, NodeListerNextItem }, - { KeyCode_UpArrow, KeyCode_Invalid, Command_Began, NodeListerPrevItem }, - { KeyCode_Enter, KeyCode_Invalid, Command_Began, SelectAndCloseNodeLister }, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, CloseNodeLister }, - { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseNodeLister }, - DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, + // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, + // it stores the value calculated when the operation mode is kicked off. + rect InitialPanelBounds; + panel_split_direction PanelEdgeDirection; + panel_edit_mode PanelEditMode; }; -FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) +OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) { - operation_mode* AddNodeOperation = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommads); + drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory; + rect PanelBounds = OpState->InitialPanelBounds; - AddNodeOperation->Render = RenderNodeLister; - - node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation, - &State->Modes, - node_lister_operation_state); + if (OpState->PanelEditMode == PanelEdit_Modify) { - OpState->SearchLister.SourceListCount = NodeSpecificationsCount; - OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, string, OpState->SearchLister.SourceListCount); + v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f}; + + v2 EdgePreviewMin = {}; + v2 EdgePreviewMax = {}; + if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) { - for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) + EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y}; + EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1}; + } + else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) + { + EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y}; + EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y}; + } + + PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor); + } + else if (OpState->PanelEditMode == PanelEdit_Destroy) + { + rect PanelToDeleteBounds = {}; + if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) + { + r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); + if (Mouse.Pos.y > SplitY) { - OpState->SearchLister.SourceList[i] = MakeString( - NodeSpecifications[i].Name, - NodeSpecifications[i].NameLength); + PanelToDeleteBounds = GetTopPanelBounds(OpState->Panel, PanelBounds); + } + else + { + PanelToDeleteBounds = GetBottomPanelBounds(OpState->Panel, PanelBounds); } } - OpState->SearchLister.Filter = MakeString(PushArray(&State->Modes.Arena, char, 64), 0, 64); - - OpState->SearchLister.FilteredListMax = OpState->SearchLister.SourceListCount; - OpState->SearchLister.FilteredListCount = 0; - OpState->SearchLister.FilteredIndexLUT = PushArray(&State->Modes.Arena, s32, OpState->SearchLister.SourceListCount); - } - - OpState->ListPosition = Mouse.Pos; - SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); -} - -//////////////////////////////////////// -// -// Node Color Picker -// -/////////////////////////////////////// - -struct color_picker_operation_state -{ - v4* ValueAddr; -}; - -internal void -CloseColorPicker(app_state* State) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand) -{ - CloseColorPicker(State); -} - -OPERATION_RENDER_PROC(RenderColorPicker) -{ - color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory; - - - b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, - v2{200, 200}, State->Interface, Mouse); - - if (ShouldClose) - { - CloseColorPicker(State); + else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) + { + r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); + if (Mouse.Pos.x > SplitX) + { + PanelToDeleteBounds = GetRightPanelBounds(OpState->Panel, PanelBounds); + } + else + { + PanelToDeleteBounds = GetLeftPanelBounds(OpState->Panel, PanelBounds); + } + } + v4 OverlayColor = v4{0, 0, 0, .3f}; + PushRenderQuad2D(RenderBuffer, PanelToDeleteBounds.Min, PanelToDeleteBounds.Max, OverlayColor); } } -input_command ColorPickerCommands [] = { - { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseColorPickerCommand }, -}; - -internal void -OpenColorPicker(app_state* State, node_connection* Connection) +FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) { - operation_mode* ColorPickerMode = ActivateOperationModeWithCommands(&State->Modes, ColorPickerCommands); - ColorPickerMode->Render = RenderColorPicker; + drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state); + panel* Panel = OpState->Panel; + rect PanelBounds = OpState->InitialPanelBounds; - color_picker_operation_state* OpState = CreateOperationState(ColorPickerMode, - &State->Modes, - color_picker_operation_state); - OpState->ValueAddr = Connection->V4ValuePtr; -} - - -//////////////////////////////////////// -// -// Node Field Text Edit -// -/////////////////////////////////////// - -FOLDHAUS_INPUT_COMMAND_PROC(EndNodeFieldTextEdit) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command NodeFieldTextEditCommands [] = { - { KeyCode_Enter, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, - DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, -}; - -internal void -BeginNodeFieldTextEdit(app_state* State, node_connection* Connection) -{ - operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, - NodeFieldTextEditCommands); - - SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr); -} - -//////////////////////////////////////// -// -// Node Port Mouse Drag -// -/////////////////////////////////////// - -struct drag_node_port_operation_state -{ - node_interaction Interaction; -}; - -OPERATION_RENDER_PROC(RenderDraggingNodePort) -{ - drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory; - UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, - State->NodeRenderSettings, RenderBuffer); -} - -FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNodePort) -{ - drag_node_port_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_port_operation_state); - - TryConnectNodes(OpState->Interaction, Mouse.Pos, State->NodeList, State->NodeRenderSettings); - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command DragNodePortInputCommands[] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNodePort }, -}; - -internal void -BeginDraggingNodePort(app_state* State, node_interaction Interaction) -{ - operation_mode* DragNodePortMode = ActivateOperationModeWithCommands( - &State->Modes, - DragNodePortInputCommands); - DragNodePortMode->Render = RenderDraggingNodePort; - - drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, - &State->Modes, - drag_node_port_operation_state); - OpState->Interaction = Interaction; -} - -//////////////////////////////////////// -// -// Node Field Mouse Drag -// -/////////////////////////////////////// - -OPERATION_RENDER_PROC(RenderDragNodeField) -{ - // TODO(Peter): - //UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State); -} - -internal void -BeginInteractWithNodeField(app_state* State, node_interaction Interaction) -{ - // TODO(Peter): -} - -//////////////////////////////////////// -// -// Node Mouse Drag -// -/////////////////////////////////////// - -struct drag_node_operation_state -{ - node_interaction Interaction; -}; - -OPERATION_RENDER_PROC(RenderDraggingNode) -{ - drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state); - UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, - State->NodeRenderSettings); -} - -FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNode) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command DragNodeInputCommands[] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNode }, -}; - -internal void -BeginDraggingNode(app_state* State, node_interaction Interaction) -{ - operation_mode* DragNodeMode = ActivateOperationModeWithCommands( - &State->Modes, - DragNodeInputCommands); - DragNodeMode->Render = RenderDraggingNode; - - drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, - &State->Modes, - drag_node_operation_state); - OpState->Interaction = Interaction; -} - -//////////////////////////////////////// -// -// Node View -// -/////////////////////////////////////// - -struct node_view_operation_state -{ - s32 SelectedNodeHandle; -}; - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - - node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings); - if (Node) + if (OpState->PanelEditMode == PanelEdit_Modify) { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, - State->NodeRenderSettings); - if (IsDraggingNodePort(NewInteraction)) + if (Panel->SplitDirection == PanelSplit_Horizontal) { - BeginDraggingNodePort(State, NewInteraction); + r32 NewSplitY = Mouse.Pos.y; + if (NewSplitY <= PanelBounds.Min.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem); + } + else if (NewSplitY >= PanelBounds.Max.y) + { + ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); + } + else + { + Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Height(PanelBounds); + } } - else if(IsDraggingNodeValue(NewInteraction)) + else if (Panel->SplitDirection == PanelSplit_Vertical) { - // TODO(Peter): This probably wants to live in a mouse held action - // the first frame we realize we're held over a field, just transition to - // drag node field - //BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings); + r32 NewSplitX = Mouse.Pos.x; + if (NewSplitX <= PanelBounds.Min.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem); + } + else if (NewSplitX >= PanelBounds.Max.x) + { + ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); + } + else + { + Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Width(PanelBounds); + } } - else // IsDraggingNode + } + else // PanelEdit_Destroy + { + if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) { - OpState->SelectedNodeHandle = Node->Handle; - BeginDraggingNode(State, NewInteraction); + r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); + if (Mouse.Pos.y > SplitY) + { + ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); + } + else + { + ConsolidatePanelsKeepOne(Panel, Panel->Top, &State->PanelSystem); + } } + else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) + { + r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); + if (Mouse.Pos.x > SplitX) + { + ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); + } + else + { + ConsolidatePanelsKeepOne(Panel, Panel->Right, &State->PanelSystem); + } + } + } + + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragPanelBorderCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragPanelBorderOperation }, + { KeyCode_MouseRightButton, KeyCode_Invalid, Command_Ended, EndDragPanelBorderOperation }, +}; + +internal void +BeginDragPanelBorder(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, panel_split_direction PanelEdgeDirection, mouse_state Mouse, app_state* State) +{ + operation_mode* DragPanelBorder = ActivateOperationModeWithCommands(&State->Modes, DragPanelBorderCommands, UpdateAndRenderDragPanelBorder); + drag_panel_border_operation_state* OpState = CreateOperationState(DragPanelBorder, &State->Modes, drag_panel_border_operation_state); + OpState->Panel = Panel; + OpState->InitialPanelBounds = PanelBounds; + OpState->PanelEdgeDirection = PanelEdgeDirection; + OpState->PanelEditMode = PanelEditMode; +} + +// ---------------- + +// +// Drag To Split Panel Operation + + +OPERATION_STATE_DEF(split_panel_operation_state) +{ + panel* Panel; + + // NOTE(Peter): InitialPanelBounds is the bounds of the panel we are modifying, + // it stores the value calculated when the operation mode is kicked off. + rect InitialPanelBounds; +}; + +OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel) +{ + split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory; + rect PanelBounds = OpState->InitialPanelBounds; + v4 EdgePreviewColor = v4{.3f, .3f, .3f, 1.f}; + + r32 MouseDeltaX = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); + r32 MouseDeltaY = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + + v2 EdgePreviewMin = {}; + v2 EdgePreviewMax = {}; + if (MouseDeltaY > MouseDeltaX) // Horizontal Split + { + EdgePreviewMin = v2{PanelBounds.Min.x, Mouse.Pos.y}; + EdgePreviewMax = v2{PanelBounds.Max.x, Mouse.Pos.y + 1}; + } + else // Vertical Split + { + EdgePreviewMin = v2{Mouse.Pos.x, PanelBounds.Min.y}; + EdgePreviewMax = v2{Mouse.Pos.x + 1, PanelBounds.Max.y}; + } + + PushRenderQuad2D(RenderBuffer, EdgePreviewMin, EdgePreviewMax, EdgePreviewColor); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) +{ + split_panel_operation_state* OpState = GetCurrentOperationState(State->Modes, split_panel_operation_state); + panel* Panel = OpState->Panel; + rect PanelBounds = OpState->InitialPanelBounds; + + r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); + r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + + if (XDistance > YDistance) + { + r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Width(PanelBounds); + SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); } else { - OpState->SelectedNodeHandle = 0; + r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Height(PanelBounds); + SplitPanelHorizontally(Panel, YPercent, PanelBounds, &State->PanelSystem); } -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings); - if (Node) - { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, - State->NodeRenderSettings); - if(IsDraggingNodeValue(NewInteraction)) - { - node_connection* Connection = Node->Connections + NewInteraction.InputValue; - struct_member_type InputType = Connection->Type; - - if (InputType == MemberType_r32) - { - BeginNodeFieldTextEdit(State, Connection); - } - else if (InputType == MemberType_v4) - { - OpenColorPicker(State, Connection); - } - } - } -} - -OPERATION_RENDER_PROC(RenderNodeView) -{ - node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory; - - DEBUG_TRACK_FUNCTION; - - MakeStringBuffer(NodeHeaderBuffer, 128); - - node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); - - node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList); - while (NodeIteratorIsValid(NodeIter)) - { - node_header* Node = NodeIter.At; - - rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); - b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); - - if (Node == SelectedNode) - { - PushRenderQuad2D(RenderBuffer, NodeBounds.Min - v2{2, 2}, NodeBounds.Max + v2{2, 2}, WhiteV4); - } - - PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f}); - - // TODO(Peter): This is just for debug purposes. We can remove and go back to just having - // Node->Name in DrawString - string NodeName = GetNodeName(*Node); - PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle); - DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font, - v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)}, - WhiteV4); - - for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++) - { - v4 PortColor = State->NodeRenderSettings.PortColors[Node->Connections[Connection].Type]; - - // Inputs - if (ConnectionIsInput(Node, Connection)) - { - rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); - DrawPort(RenderBuffer, PortBounds, PortColor); - - // - // TODO(Peter): I don't like excluding OutputNode, feels too much like a special case - // but I don't want to get in to the meta programming right now. - // We should just generate a spec and struct member types for NodeType_OutputNode - // - // :ExcludingOutputNodeSpecialCase - // - if (Node->Type != NodeType_OutputNode && DrawFields) - { - node_specification Spec = NodeSpecifications[Node->Type]; - node_struct_member Member = Spec.MemberList[Connection]; - DrawString(RenderBuffer, MakeString(Member.Name), - State->NodeRenderSettings.Font, - v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right); - } - - rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings); - DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); - - // NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship, - // whereas output ports might have many connections, they really only know about the most recent one - // Not sure if this is a problem. We mostly do everything backwards here, starting at the - // most downstream node and working back up to find dependencies. - if (ConnectionHasUpstreamConnection(Node, Connection)) - { - rect ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); - v2 InputCenter = CalculateRectCenter(PortBounds); - v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); - PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); - } - } - - // Outputs - if (ConnectionIsOutput(Node, Connection)) - { - rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); - DrawPort(RenderBuffer, PortBounds, PortColor); - - if (DrawFields) - { - node_specification Spec = NodeSpecifications[Node->Type]; - node_struct_member Member = Spec.MemberList[Connection]; - DrawString(RenderBuffer, MakeString(Member.Name), - State->NodeRenderSettings.Font, - v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); - } - - rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); - DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); - } - - for (s32 Button = 0; Button < 3; Button++) - { - rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); - PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); - } - } - - Next(&NodeIter); - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(NodeViewDeleteNode) -{ - node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); - if (OpState->SelectedNodeHandle > 0) - { - node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); - FreeNodeOnList(State->NodeList, SelectedNode); - } -} - -FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView) -{ DeactivateCurrentOperationMode(&State->Modes); } -input_command NodeViewCommands [] = { - { KeyCode_Tab, KeyCode_Invalid, Command_Began, CloseNodeView}, - { KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister}, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction}, - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction}, - { KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode}, +input_command SplitPanelCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndSplitPanelOperation }, }; -FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView) +internal void +BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_state* State) { - operation_mode* NodeViewMode = ActivateOperationModeWithCommands(&State->Modes, NodeViewCommands); - NodeViewMode->Render = RenderNodeView; - - node_view_operation_state* OpState = CreateOperationState(NodeViewMode, - &State->Modes, - node_view_operation_state); - - OpState->SelectedNodeHandle = 0; + operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); + split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); + OpState->Panel = Panel; + OpState->InitialPanelBounds = PanelBounds; } -//////////////////////////////////////// -// -// 3D View Mouse Rotate -// -/////////////////////////////////////// -struct mouse_rotate_view_operation_state -{ - v4 CameraStartPos; -}; +// ---------------- -OPERATION_RENDER_PROC(Update3DViewMouseRotate) +#define PANEL_EDGE_CLICK_MAX_DISTANCE 6 + +internal b32 +HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, mouse_state Mouse, app_state* State) { - mouse_rotate_view_operation_state* OpState = (mouse_rotate_view_operation_state*)Operation.OpStateMemory; + b32 HandledMouseInput = false; - v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos; + if (Panel->SplitDirection == PanelSplit_NoSplit + && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) + { + BeginSplitPanelOperation(Panel, PanelBounds, Mouse, State); + HandledMouseInput = true; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.y - SplitY); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State); + HandledMouseInput = true; + } + else + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + if (PointIsInRect(Mouse.DownPos, BottomPanelBounds)) + { + HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State); + } + if (PointIsInRect(Mouse.DownPos, TopPanelBounds)) + { + HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State); + } + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); + r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); + if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State); + HandledMouseInput = true; + } + else + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + if (PointIsInRect(Mouse.DownPos, LeftPanelBounds)) + { + HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State); + } + if (PointIsInRect(Mouse.DownPos, RightPanelBounds)) + { + HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State); + } + } + } - m44 XRotation = GetXRotation(-TotalDeltaPos.y * State->PixelsToWorldScale); - m44 YRotation = GetYRotation(TotalDeltaPos.x * State->PixelsToWorldScale); - m44 Combined = XRotation * YRotation; - - State->Camera.Position = V3(Combined * OpState->CameraStartPos); + return HandledMouseInput; } -FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate) +internal b32 +HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_state Mouse, app_state* State) { - DeactivateCurrentOperationMode(&State->Modes); + b32 HandledMouseInput = false; + + panel* FirstPanel = &PanelSystem->Panels[0].Panel; + if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) + { + HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Modify, WindowBounds, Mouse, State); + } + else if (MouseButtonTransitionedDown(Mouse.RightButtonState)) + { + HandledMouseInput = HandleMouseDownPanelInteractionOrRecurse(FirstPanel, PanelEdit_Destroy, WindowBounds, Mouse, State); + } + + return HandledMouseInput; } -input_command MouseRotateViewCommands [] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate}, -}; - -FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate) +internal void +DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state Mouse, render_command_buffer* RenderBuffer) { - operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands); - RotateViewMode->Render = Update3DViewMouseRotate; + r32 MouseLeftEdgeDistance = GSAbs(Mouse.Pos.x - PanelMin.x); + r32 MouseRightEdgeDistance = GSAbs(Mouse.Pos.x - PanelMax.x); + r32 MouseTopEdgeDistance = GSAbs(Mouse.Pos.y - PanelMax.y); + r32 MouseBottomEdgeDistance = GSAbs(Mouse.Pos.y - PanelMin.y); - mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode, - &State->Modes, - mouse_rotate_view_operation_state); - OpState->CameraStartPos = V4(State->Camera.Position, 1); -} \ No newline at end of file + PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); + v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; + r32 HighlightThickness = 1; + if (MouseLeftEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 LeftEdgeMin = PanelMin; + v2 LeftEdgeMax = v2{PanelMin.x + HighlightThickness, PanelMax.y}; + PushRenderQuad2D(RenderBuffer, LeftEdgeMin, LeftEdgeMax, HighlightColor); + } + else if (MouseRightEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 RightEdgeMin = v2{PanelMax.x - HighlightThickness, PanelMin.y}; + v2 RightEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, RightEdgeMin, RightEdgeMax, HighlightColor); + } + else if (MouseTopEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 TopEdgeMin = v2{PanelMin.x, PanelMax.y - HighlightThickness}; + v2 TopEdgeMax = PanelMax; + PushRenderQuad2D(RenderBuffer, TopEdgeMin, TopEdgeMax, HighlightColor); + } + else if (MouseBottomEdgeDistance < PANEL_EDGE_CLICK_MAX_DISTANCE) + { + v2 BottomEdgeMin = PanelMin; + v2 BottomEdgeMax = v2{PanelMax.x, PanelMin.y + HighlightThickness}; + PushRenderQuad2D(RenderBuffer, BottomEdgeMin, BottomEdgeMax, HighlightColor); + } +} + +internal void +DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, interface_config Interface, mouse_state Mouse) +{ + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, v2{FooterBounds.Max.x, FooterBounds.Min.y + 25}, v4{.5f, .5f, .5f, 1.f}); + PushRenderQuad2D(RenderBuffer, FooterBounds.Min, FooterBounds.Min + v2{25, 25}, WhiteV4); + + v2 PanelSelectButtonMin = FooterBounds.Min + v2{30, 1}; + v2 PanelSelectButtonMax = PanelSelectButtonMin + v2{100, 23}; + + if (Panel->PanelSelectionMenuOpen) + { + v2 ButtonDimension = v2{100, 25}; + v2 ButtonMin = v2{PanelSelectButtonMin.x, FooterBounds.Max.y}; + + v2 MenuMin = ButtonMin; + v2 MenuMax = v2{ButtonMin.x + ButtonDimension.x, ButtonMin.y + (ButtonDimension.y * GlobalPanelDefsCount)}; + if (MouseButtonTransitionedDown(Mouse.LeftButtonState) + && !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) + { + Panel->PanelSelectionMenuOpen = false; + } + + + for (s32 i = 0; i < GlobalPanelDefsCount; i++) + { + panel_definition Def = GlobalPanelDefs[i]; + string DefName = MakeString(Def.PanelName, Def.PanelNameLength); + button_result DefinitionButton = EvaluateButton(RenderBuffer, + ButtonMin, ButtonMin + ButtonDimension, + DefName, Interface, Mouse); + if (DefinitionButton.Pressed) + { + SetPanelDefinition(Panel, i); + Panel->PanelSelectionMenuOpen = false; + } + + ButtonMin.y += ButtonDimension.y; + } + } + + button_result ButtonResult = EvaluateButton(RenderBuffer, + PanelSelectButtonMin, + PanelSelectButtonMax, + MakeStringLiteral("Select"), Interface, Mouse); + if (ButtonResult.Pressed) + { + Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; + } + +} + +internal void +RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +{ + Assert(Panel->PanelDefinitionIndex >= 0); + + rect FooterBounds = rect{ + PanelBounds.Min, + v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, + }; + rect PanelViewBounds = rect{ + v2{PanelBounds.Min.x, FooterBounds.Max.y}, + PanelBounds.Max, + }; + + panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; + Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); + + PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); + DrawPanelFooter(Panel, RenderBuffer, FooterBounds, State->Interface, Mouse); +} + +internal void +DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mouse_state Mouse, app_state* State, context Context) +{ + for (u32 i = 0; i < PanelLayout.PanelsCount; i++) + { + panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; + panel* Panel = PanelWithLayout.Panel; + rect PanelBounds = PanelWithLayout.Bounds; + + RenderPanel(Panel, PanelBounds, State->WindowBounds, RenderBuffer, State, Context, Mouse); + v4 BorderColor = v4{0, 0, 0, 1}; + + PushRenderOrthographic(RenderBuffer, State->WindowBounds.Min.x, State->WindowBounds.Min.y, State->WindowBounds.Max.x, State->WindowBounds.Max.y); + DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); + } +} diff --git a/src/foldhaus_interface.h b/src/foldhaus_interface.h deleted file mode 100644 index e69de29..0000000 diff --git a/src/foldhaus_memory.h b/src/foldhaus_memory.h index 16e2378..cdbc2db 100644 --- a/src/foldhaus_memory.h +++ b/src/foldhaus_memory.h @@ -1,5 +1,6 @@ #ifndef GS_MEMORY_H +#if 0 #ifndef GS_LANGUAGE_H typedef uint8_t u8; @@ -230,6 +231,7 @@ ClearArenaToSnapshot (memory_arena* Arena, arena_snapshot Snapshot) Assert(RegionCursor == Snapshot.CurrentRegion); RegionCursor->Used = Snapshot.UsedAtSnapshot; } +#endif // // Basic Memory Arena @@ -253,6 +255,7 @@ CreateMemoryArena (u8* Base, u32 Size) return Result; } +#define PushArrayOnStaticArena(arena, type, length) (type*)PushSize_((arena), sizeof(type) * length) static u8* PushSize_ (static_memory_arena* Arena, u32 Size) { @@ -262,80 +265,5 @@ PushSize_ (static_memory_arena* Arena, u32 Size) return Result; } -// -// Tracked Array Implementation -// - -#define ARRAY_CHECKSUM 0x51bada7b -struct array_header_ -{ - u32 Size; - s32 ElementMax; - s32 ElementCount; - s32 ElementSize; - u32 Checksum; -}; - -#define gs_PushArray(arena, type, size) (type*)gs_PushArray_(arena, sizeof(type), size) - -static u8* -gs_PushArray_ (memory_arena* Arena, u32 StepSize, u32 Count) -{ - u32 ArrayFootprint = sizeof(array_header_) + (StepSize * Count); - array_header_* Header = (array_header_*)PushSize_(Arena, ArrayFootprint); - - array_header_* Body = Header + 1; - u8* Result = (u8*)(Body); - - Header->Size = Count * StepSize; - Header->ElementMax = Count; - Header->ElementSize = StepSize; - Header->ElementCount = 0; - Header->Checksum = ARRAY_CHECKSUM; - - return Result; -} - -#define gs_ArrayHeader_(array) (((array_header_*)array) - 1) - -#ifdef DEBUG -#define gs_ArrayCheck(array) Assert(!array || gs_ArrayHeader_(array)->Checksum == ARRAY_CHECKSUM) -#else -#define gs_ArrayCheck(array) -#endif - -#define gs_ArrayCount(array) gs_ArrayCount_((u8*)array) -static s32 -gs_ArrayCount_ (u8* Base) -{ - gs_ArrayCheck(Base); - return gs_ArrayHeader_(Base)->ElementCount; -} - -#define gs_ArrayMax(array) gs_ArrayMax_((u8*)array) -static s32 -gs_ArrayMax_ (u8* Base) -{ - gs_ArrayCheck(Base); - return gs_ArrayHeader_(Base)->ElementMax; -} - -#define gs_ArrayAdd(array) ( gs_PushArrayElement_((u8*)array), (array) + (gs_ArrayCount(array) - 1) ) -#define gs_ArrayPush(array, ele) *( gs_ArrayAdd(array) ) = (ele) - -static void* -gs_PushArrayElement_ (u8* Base) -{ - gs_ArrayCheck(Base); - Assert(gs_ArrayHeader_(Base)->ElementCount + 1 <= gs_ArrayHeader_(Base)->ElementMax); - - void* Result = (void*)(Base + (gs_ArrayHeader_(Base)->ElementCount * gs_ArrayHeader_(Base)->ElementSize)); - gs_ArrayHeader_(Base)->ElementCount++; - - return Result; -} - - - #define GS_MEMORY_H #endif // GS_MEMORY_H \ No newline at end of file diff --git a/src/foldhaus_operation_mode.h b/src/foldhaus_operation_mode.h index ef7d043..6c9b490 100644 --- a/src/foldhaus_operation_mode.h +++ b/src/foldhaus_operation_mode.h @@ -1,5 +1,7 @@ typedef struct operation_mode operation_mode; +#define OPERATION_STATE_DEF(name) struct name + #define OPERATION_RENDER_PROC(name) void name(app_state* State, render_command_buffer* RenderBuffer, operation_mode Operation, mouse_state Mouse) typedef OPERATION_RENDER_PROC(operation_render_proc); @@ -23,26 +25,30 @@ struct operation_mode_system }; internal operation_mode* -ActivateOperationMode (operation_mode_system* System) +ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc) { + operation_mode* Result = 0; + Assert(System->ActiveModesCount < OPERATION_MODES_MAX); s32 ModeIndex = System->ActiveModesCount++; - System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(System->Arena); + System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena); operation_mode NewMode = {}; System->ActiveModes[ModeIndex] = NewMode; - return &System->ActiveModes[ModeIndex]; + Result = &System->ActiveModes[ModeIndex]; + Result->Render = RenderProc; + return Result; } -#define ActivateOperationModeWithCommands(sys, cmds) \ -ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0]))); +#define ActivateOperationModeWithCommands(sys, cmds, render) \ +ActivateOperationModeWithCommands_(sys, cmds, (s32)(sizeof(cmds) / sizeof(cmds[0])), render); internal operation_mode* -ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount) +ActivateOperationModeWithCommands_(operation_mode_system* System, input_command* Commands, s32 CommandsCount, operation_render_proc* RenderProc) { - operation_mode* NewMode = ActivateOperationMode(System); + operation_mode* NewMode = ActivateOperationMode(System, RenderProc); InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena); for (s32 i = 0; i < CommandsCount; i++) @@ -66,7 +72,7 @@ DeactivateCurrentOperationMode (operation_mode_system* System) (stateType*)CreateOperationState_(mode, modeSystem, sizeof(stateType)) #define GetCurrentOperationState(modeSystem, stateType) \ -(stateType*)State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].OpStateMemory; +(stateType*)(modeSystem).ActiveModes[(modeSystem).ActiveModesCount - 1].OpStateMemory; internal u8* diff --git a/src/foldhaus_panel.h b/src/foldhaus_panel.h new file mode 100644 index 0000000..06fb431 --- /dev/null +++ b/src/foldhaus_panel.h @@ -0,0 +1,360 @@ +/* +File: foldhaus_panel.cpp +Description: a system for laying out panels on a screen +Author: Peter Slattery +Creation Date: 2019-12-26 + +Usage: +Include this file in ONE file in your project. +Define SetPanelDefinitionExternal + +*/ + +typedef struct panel panel; + +enum panel_split_direction +{ + PanelSplit_NoSplit, + PanelSplit_Horizontal, + PanelSplit_Vertical, + + PanelSplit_Count, +}; + +typedef struct panel_entry panel_entry; + +struct panel +{ + s32 PanelDefinitionIndex; + + panel_split_direction SplitDirection; + r32 SplitPercent; + + // TODO(Peter): This REALLY doesn't want to live here + // Probably belongs in a more generalized PanelInterfaceState or something + b32 PanelSelectionMenuOpen; + + union{ + panel_entry* Left; + panel_entry* Top; + }; + union{ + panel_entry* Right; + panel_entry* Bottom; + }; +}; + +struct free_panel +{ + panel_entry* Next; +}; + +struct panel_entry +{ + panel Panel; + free_panel Free; +}; + +#define PANELS_MAX 16 +struct panel_system +{ + panel_entry Panels[PANELS_MAX]; + u32 PanelsUsed; + + panel_entry FreeList; +}; + +// NOTE(Peter): This representation is used to let external code render and interact +// with panels. It shouldn't be stored across frame boundaries as the pointers to +// Panel's are liable to change. +struct panel_with_layout +{ + panel* Panel; + rect Bounds; +}; + +struct panel_layout +{ + panel_with_layout* Panels; + u32 PanelsCount; + u32 PanelsMax; +}; + +internal void SetPanelDefinitionExternal(panel* Panel, s32 OldPanelDefinitionIndex, s32 NewPanelDefinitionIndex); + +///////////////////////////////// +// +// Book-Keeping +// +///////////////////////////////// + +internal void +InitializePanelSystem(panel_system* PanelSystem) +{ + PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList; +} + +internal panel_entry* +TakeNewPanelEntry(panel_system* PanelSystem) +{ + panel_entry* FreeEntry = 0; + if (PanelSystem->FreeList.Free.Next != &PanelSystem->FreeList) + { + FreeEntry = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = FreeEntry->Free.Next; + } + else + { + Assert(PanelSystem->PanelsUsed < PANELS_MAX); + FreeEntry = PanelSystem->Panels + PanelSystem->PanelsUsed++; + } + return FreeEntry; +} + +internal panel* +TakeNewPanel(panel_system* PanelSystem) +{ + panel* Result = 0; + panel_entry* FreeEntry = TakeNewPanelEntry(PanelSystem); + Result = &FreeEntry->Panel; + + *Result = {0}; + Result->PanelDefinitionIndex = -1; + + return Result; +} + +internal void +FreePanelEntry(panel_entry* Entry, panel_system* PanelSystem) +{ + Assert(Entry >= PanelSystem->Panels && Entry <= PanelSystem->Panels + PANELS_MAX); + Entry->Panel = {0}; + Entry->Free.Next = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = Entry; +} + +internal void +FreePanelEntryRecursive(panel_entry* Entry, panel_system* PanelSystem) +{ + if (Entry->Panel.SplitDirection != PanelSplit_NoSplit) + { + FreePanelEntryRecursive(Entry->Panel.Left, PanelSystem); + FreePanelEntryRecursive(Entry->Panel.Right, PanelSystem); + } + FreePanelEntry(Entry, PanelSystem); +} + +internal void +FreePanelAtIndex(s32 Index, panel_system* PanelSystem) +{ + Assert(Index > 0 && Index < (s32)PanelSystem->PanelsUsed); + panel_entry* EntryToFree = PanelSystem->Panels + Index; + EntryToFree->Free.Next = PanelSystem->FreeList.Free.Next; + PanelSystem->FreeList.Free.Next = EntryToFree; +} + +internal void +SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) +{ + r32 SplitX = GSLerp(ParentBounds.Min.x, ParentBounds.Max.x, Percent); + if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x) + { + Parent->SplitDirection = PanelSplit_Vertical; + Parent->SplitPercent = Percent; + + Parent->Left = TakeNewPanelEntry(PanelSystem); + Parent->Left->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; + + Parent->Right = TakeNewPanelEntry(PanelSystem); + Parent->Right->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; + } +} + +internal void +SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) +{ + r32 SplitY = GSLerp(ParentBounds.Min.y, ParentBounds.Max.y, Percent); + if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y) + { + Parent->SplitDirection = PanelSplit_Horizontal; + Parent->SplitPercent = Percent; + + Parent->Bottom = TakeNewPanelEntry(PanelSystem); + Parent->Bottom->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; + + Parent->Top = TakeNewPanelEntry(PanelSystem); + Parent->Top->Panel.PanelDefinitionIndex = Parent->PanelDefinitionIndex; + } +} + +internal void +ConsolidatePanelsKeepOne(panel* Parent, panel_entry* PanelEntryToKeep, panel_system* PanelSystem) +{ + panel_entry* LeftChild = Parent->Left; + panel_entry* RightChild = Parent->Right; + + panel_entry* PanelEntryToDestroy = PanelEntryToKeep == LeftChild ? RightChild : LeftChild; + + *Parent = PanelEntryToKeep->Panel; + + FreePanelEntry(PanelEntryToKeep, PanelSystem); + FreePanelEntryRecursive(PanelEntryToDestroy, PanelSystem); +} + +internal void +SetPanelDefinition(panel* Panel, s32 NewDefinitionIndex) +{ + s32 OldDefinitionIndex = Panel->PanelDefinitionIndex; + Panel->PanelDefinitionIndex = NewDefinitionIndex; + SetPanelDefinitionExternal(Panel, OldDefinitionIndex, NewDefinitionIndex); +} + +///////////////////////////////// +// +// Rendering And Interaction +// +///////////////////////////////// + +internal rect +GetTopPanelBounds(panel* Panel, rect PanelBounds) +{ + rect Result = {}; + Result.Min = v2{ + PanelBounds.Min.x, + GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent) + }; + Result.Max = PanelBounds.Max; + return Result; +} + +internal rect +GetBottomPanelBounds(panel* Panel, rect PanelBounds) +{ + rect Result = {}; + Result.Min = PanelBounds.Min; + Result.Max = v2{ + PanelBounds.Max.x, + GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, Panel->SplitPercent) + }; + return Result; +} + +internal rect +GetRightPanelBounds(panel* Panel, rect PanelBounds) +{ + rect Result = {}; + Result.Min = v2{ + GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent), + PanelBounds.Min.y + }; + Result.Max = PanelBounds.Max; + return Result; +} + +internal rect +GetLeftPanelBounds(panel* Panel, rect PanelBounds) +{ + rect Result = {}; + Result.Min = PanelBounds.Min; + Result.Max = v2{ + GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent), + PanelBounds.Max.y + }; + return Result; +} + +internal void +LayoutPanel(panel* Panel, rect PanelBounds, panel_layout* Layout) +{ + if (Panel->SplitDirection == PanelSplit_NoSplit) + { + panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++; + WithLayout->Panel = Panel; + WithLayout->Bounds = PanelBounds; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout); + LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout); + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout); + LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout); + } +} + +internal panel_layout +GetPanelLayout(panel_system* System, rect WindowBounds, memory_arena* Storage) +{ + panel_layout Result = {}; + Result.PanelsMax = System->PanelsUsed; + Result.Panels = PushArray(Storage, panel_with_layout, Result.PanelsMax); + + LayoutPanel(&System->Panels[0].Panel, WindowBounds, &Result); + + return Result; +} + +struct panel_and_bounds +{ + panel* Panel; + rect Bounds; +}; + +internal panel_and_bounds +GetPanelContainingPoint(v2 Point, panel* Panel, rect PanelBounds) +{ + panel_and_bounds Result = {0}; + + if (Panel->SplitDirection == PanelSplit_NoSplit) + { + Result.Panel = Panel; + Result.Bounds = PanelBounds; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + + if (PointIsInRange(Point, TopPanelBounds.Min, TopPanelBounds.Max)) + { + Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds); + } + else if (PointIsInRange(Point, BottomPanelBounds.Min, BottomPanelBounds.Max)) + { + Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds); + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + + if (PointIsInRange(Point, LeftPanelBounds.Min, LeftPanelBounds.Max)) + { + Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds); + } + else if (PointIsInRange(Point, RightPanelBounds.Min, RightPanelBounds.Max)) + { + Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds); + } + } + + return Result; +} + +internal panel_and_bounds +GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect WindowBounds) +{ + panel_and_bounds Result = {0}; + if (PanelSystem->PanelsUsed > 0) + { + Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds); + } + return Result; +} diff --git a/src/foldhaus_platform.h b/src/foldhaus_platform.h index f927a2a..58e4d16 100644 --- a/src/foldhaus_platform.h +++ b/src/foldhaus_platform.h @@ -1,8 +1,13 @@ -#include "gs_language.h" +#define GS_LANGUAGE_NO_PROFILER_DEFINES +#include #include "gs_platform.h" +#include "gs_array.h" -#include "foldhaus_memory.h" -#include "gs_string.h" +#define GS_MEMORY_TRACK_ALLOCATIONS +#define GS_MEMORY_NO_STD_LIBS +#include + +#include #include "foldhaus_debug.h" global_variable debug_services* GlobalDebugServices; @@ -10,7 +15,7 @@ global_variable debug_services* GlobalDebugServices; global_variable platform_alloc* GSAlloc; global_variable platform_free* GSFree; -#include "gs_vector_matrix.h" +#include #include "gs_input.h" @@ -117,8 +122,7 @@ struct context u32 MemorySize; b32 WindowIsVisible; - r32 WindowWidth; - r32 WindowHeight; + rect WindowBounds; r32 DeltaTime; // Application Services @@ -132,6 +136,7 @@ struct context platform_alloc* PlatformAlloc; platform_free* PlatformFree; + platform_realloc* PlatformRealloc; platform_read_entire_file* PlatformReadEntireFile; platform_write_entire_file* PlatformWriteEntireFile; platform_get_file_path* PlatformGetFilePath; @@ -139,7 +144,6 @@ struct context platform_get_font_info* PlatformGetFontInfo; platform_draw_font_codepoint* PlatformDrawFontCodepoint; platform_get_socket_handle* PlatformGetSocketHandle; - platform_get_send_address* PlatformGetSendAddress; platform_set_socket_option* PlatformSetSocketOption; platform_send_to* PlatformSendTo; platform_close_socket* PlatformCloseSocket; diff --git a/src/foldhaus_search_lister.cpp b/src/foldhaus_search_lister.cpp index 6e7ca98..ee42843 100644 --- a/src/foldhaus_search_lister.cpp +++ b/src/foldhaus_search_lister.cpp @@ -1,3 +1,9 @@ +internal b32 +NamePassesFilter (string Target, string Filter) +{ + return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter)); +} + internal void FilterSearchLister (search_lister* SearchLister) { @@ -9,7 +15,7 @@ FilterSearchLister (search_lister* SearchLister) for (s32 i = 0; i < SearchLister->SourceListCount; i++) { string* NameString = SearchLister->SourceList + i; - if (SpecificationPassesFilter(*NameString, SearchLister->Filter)) + if (NamePassesFilter(*NameString, SearchLister->Filter)) { SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i; } diff --git a/src/generated/foldhaus_nodes_generated.cpp b/src/generated/foldhaus_nodes_generated.cpp index 25fa0d0..2543f5b 100644 --- a/src/generated/foldhaus_nodes_generated.cpp +++ b/src/generated/foldhaus_nodes_generated.cpp @@ -47,7 +47,6 @@ node_struct_member MemberList_sin_wave_data[] = { node_struct_member MemberList_multiply_patterns_data[] = { { MemberType_NODE_COLOR_BUFFER, "ALEDs", (u64)&((multiply_patterns_data*)0)->ALEDs, IsInputMember }, -{ MemberType_NODE_COLOR_BUFFER, "BLEDs", (u64)&((multiply_patterns_data*)0)->BLEDs, IsInputMember }, { MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((multiply_patterns_data*)0)->ResultLEDs, IsOutputMember}, }; @@ -83,8 +82,8 @@ node_specification NodeSpecifications[] = { { NodeType_VectorValue, "VectorValue", 11, MemberList_vector_data, 32, 5, false}, { NodeType_MultiplyNodeProc, "MultiplyNodeProc", 16, MemberList_multiply_data, 12, 3, false}, { NodeType_AddNodeProc, "AddNodeProc", 11, MemberList_add_data, 48, 3, false}, -{ NodeType_SinWave, "SinWave", 7, MemberList_sin_wave_data, 20, 4, false}, -{ NodeType_MultiplyPatterns, "MultiplyPatterns", 16, MemberList_multiply_patterns_data, 60, 3, false}, +{ NodeType_SinWave, "SinWave", 7, MemberList_sin_wave_data, 16, 4, false}, +{ NodeType_MultiplyPatterns, "MultiplyPatterns", 16, MemberList_multiply_patterns_data, 40, 2, false}, { NodeType_OutputNode, "OutputNode", 10, MemberList_output_node_data, 20, 1, false}, { NodeType_SolidColorProc, "SolidColorProc", 14, MemberList_solid_color_data, 36, 2, false}, { NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 44, 4, false}, @@ -93,11 +92,11 @@ node_specification NodeSpecifications[] = { s32 NodeSpecificationsCount = 10; internal void CallNodeProc(node_header* Node, u8* Data, led* LEDs, s32 LEDsCount, r32 DeltaTime) -{ -node_specification Spec = NodeSpecifications[Node->Type]; -switch (Spec.Type) -{ -case NodeType_FloatValue: { FloatValue((float_value_data*)Data, DeltaTime); } break; + { + node_specification Spec = NodeSpecifications[Node->Type]; + switch (Spec.Type) + { + case NodeType_FloatValue: { FloatValue((float_value_data*)Data, DeltaTime); } break; case NodeType_VectorValue: { VectorValue((vector_data*)Data, DeltaTime); } break; case NodeType_MultiplyNodeProc: { MultiplyNodeProc((multiply_data*)Data, DeltaTime); } break; case NodeType_AddNodeProc: { AddNodeProc((add_data*)Data, DeltaTime); } break; diff --git a/src/generated/foldhaus_panels_generated.h b/src/generated/foldhaus_panels_generated.h new file mode 100644 index 0000000..75cd072 --- /dev/null +++ b/src/generated/foldhaus_panels_generated.h @@ -0,0 +1,18 @@ +struct panel_definition +{ + char* PanelName; + s32 PanelNameLength; + panel_init_proc* Init; + panel_cleanup_proc* Cleanup; + panel_render_proc* Render; + input_command* InputCommands; +}; + +global_variable s32 GlobalPanelDefsCount = 5; +global_variable panel_definition GlobalPanelDefs[] = { + { "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands}, + { "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render, AnimationTimeline_Commands }, + { "DMX View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, 0 }, + { "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, 0 }, + { "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, 0 }, +}; \ No newline at end of file diff --git a/src/gs_array.h b/src/gs_array.h new file mode 100644 index 0000000..37c9855 --- /dev/null +++ b/src/gs_array.h @@ -0,0 +1,229 @@ +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; \ + \ +} \ + +// 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) \ + { \ + element_type* Entry = 0; \ + if (Index <= Buffer.Used) \ + { \ +bucket_index BucketIndex = GetBucketIndexForIndex(Index, Buffer.BucketSize); \ + 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 diff --git a/src/gs_hashtable.h b/src/gs_hashtable.h new file mode 100644 index 0000000..ab0c014 --- /dev/null +++ b/src/gs_hashtable.h @@ -0,0 +1 @@ +// \ No newline at end of file diff --git a/src/gs_input.h b/src/gs_input.h index d77d12a..30bebb5 100644 --- a/src/gs_input.h +++ b/src/gs_input.h @@ -105,5 +105,7 @@ MouseButtonTransitionedUp (b32 MouseButtonState) internal b32 MouseButtonHeldDown (b32 MouseButtonState) { - return (KeyWasDown(MouseButtonState) && KeyIsDown(MouseButtonState)); + b32 WasDown = KeyWasDown(MouseButtonState); + b32 IsDown = KeyIsDown(MouseButtonState); + return (WasDown && IsDown); } \ No newline at end of file diff --git a/src/gs_language.h b/src/gs_language.h deleted file mode 100644 index d1b233a..0000000 --- a/src/gs_language.h +++ /dev/null @@ -1,423 +0,0 @@ -#ifndef GS_LANGUAGE_H - -#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) -#include -#include - -// TODO(Peter): Get rid of stdio and math.h -#include -#include - -#elif defined(__APPLE__) && defined(__MAC__) -// TODO(Peter): - -#else // Std lib -#include - -#endif - -#define internal static -#define local_persist static -#define global_variable static - - -#if !defined(GS_TYPES) - -#define GSINT64(s) (s) ## L -#define GSUINT64(s) (s) ## UL - -typedef signed char b8; -typedef short int b16; -typedef int b32; -typedef long long int b64; - -typedef unsigned char u8; -typedef unsigned short int u16; -typedef unsigned int u32; -typedef unsigned long long int u64; - -typedef signed char s8; -typedef short int s16; -typedef int s32; -typedef long long int s64; - -typedef float r32; -typedef double r64; - -#define INT8_MIN (-128) -#define INT16_MIN (-32767-1) -#define INT32_MIN (-2147483647-1) -#define INT64_MIN (-GSINT64(9223372036854775807)-1) - -#define INT8_MAX (127) -#define INT16_MAX (32767) -#define INT32_MAX (2147483647) -#define INT64_MAX (GSINT64(9223372036854775807)) - -#define UINT8_MAX (255) -#define UINT16_MAX (65535) -#define UINT32_MAX (4294967295U) -#define UINT64_MAX (GSUINT64(18446744073709551615)) - -#define FLOAT_MIN (1.175494351e-38F) -#define FLOAT_MAX (3.402823466e+38F) -#define DOUBLE_MIN (2.2250738585072014e-308) -#define DOUBLE_MAX (1.7976931348623158e+308) - -#define Kilobytes(Value) ((Value) * 1024) -#define Megabytes(Value) (Kilobytes(Value) * 1024) -#define Gigabytes(Value) (Megabytes(Value) * 1024) -#define Terabytes(Value) (Gigabytes(Value) * 1024) - -#define PI 3.14159265359 -#define PI_OVER_180 0.01745329251f - -#define GS_TYPES -#endif - - -#ifdef DEBUG - -static void DebugPrint(char* Format, ...); - -#if !defined(Assert) -// NOTE(peter): this writes to address 0 which is always illegal and will cause a crash -#define Assert(expression) if(!(expression)){ *((int *)0) = 5; } -#endif - -#define DEBUG_IF(condition) if (condition) - -#define InvalidCodePath Assert(0) -#define InvalidDefaultCase default: { Assert(0); } -#define DebugBreak __debugbreak() - -#define STBI_ASSERT(x) Assert(x) - -#ifdef GS_TEST_SUTE -#define TestClean(v, c) SuccessCount += Test(v, c, &TestCount) -internal s32 -Test(b32 Result, char* Description, s32* Count) -{ - char* Passed = (Result ? "Success" : "Failed"); - if (!Result) - DebugPrint("%s:\n................................................%s\n\n", Description, Passed); - - *Count = *Count + 1; - return (Result ? 1 : 0); -} -#endif // GS_TEST_SUTE - -#else - -#define Assert(expression) -#define InvalidCodePath -#define DEBUG_IF(condition) - -//#define DEBUG_TRACK_SCOPE(a) - -#endif // DEBUG - -#ifndef GS_LANGUAGE_MATH - -#define GSZeroStruct(data) GSZeroMemory_((u8*)(&(data)), sizeof(data)) -#define GSZeroMemory(mem, size) GSZeroMemory_((u8*)(mem), (size)) -static void -GSZeroMemory_ (u8* Memory, s32 Size) -{ - for (int i = 0; i < Size; i++) { Memory[i] = 0; } -} - -#define GSMemCopy(from, to, size) GSMemCopy_((u8*)from, (u8*)to, size) -static void -GSMemCopy_ (u8* From, u8* To, s32 Size) -{ - for (int i = 0; i < Size; i++) { To[i] = From[i]; } -} - -#define GSMemSet(buffer, value, size) GSMemSet_((u8*)buffer, value, size) -internal void -GSMemSet_ (u8* Buffer, u8 Value, s32 Length) -{ - u8* Cursor = Buffer; - for (s32 i = 0; i < Length; i++) - { - *Cursor++ = Value; - } -} - -#define GSMinDef(type) static type GSMin(type A, type B) { return (A < B ? A : B); } -GSMinDef(s8) -GSMinDef(s16) -GSMinDef(s32) -GSMinDef(s64) -GSMinDef(u8) -GSMinDef(u16) -GSMinDef(u32) -GSMinDef(u64) -GSMinDef(r32) -GSMinDef(r64) -#undef GSMinDef - -#define GSMaxDef(type) static type GSMax(type A, type B) { return (A > B ? A : B); } -GSMaxDef(s8) -GSMaxDef(s16) -GSMaxDef(s32) -GSMaxDef(s64) -GSMaxDef(u8) -GSMaxDef(u16) -GSMaxDef(u32) -GSMaxDef(u64) -GSMaxDef(r32) -GSMaxDef(r64) -#undef GSMaxDef - -inline b32 XOR(b32 A, b32 B) -{ - b32 Result = (A == !B); - return Result; -} -#define GSClampDef(type) static type GSClamp(type Min, type V, type Max) { \ - type Result = V; \ - if (V < Min) { Result = Min; } \ - if (V > Max) { Result = Max; } \ - return Result; \ -} -GSClampDef(s8) -GSClampDef(s16) -GSClampDef(s32) -GSClampDef(s64) -GSClampDef(u8) -GSClampDef(u16) -GSClampDef(u32) -GSClampDef(u64) -GSClampDef(r32) -GSClampDef(r64) -#undef GSClampDef - -#define GSClamp01Def(type) static type GSClamp01(type V) { \ - type Min = 0; type Max = 1; \ - type Result = V; \ - if (V < Min) { Result = Min; } \ - if (V > Max) { Result = Max; } \ - return Result; \ -} -GSClamp01Def(r32) -GSClamp01Def(r64) -#undef GSClamp01Def - -#define GSAbsDef(type) static type GSAbs(type A) { return (A < 0 ? -A : A); } -GSAbsDef(s8) -GSAbsDef(s16) -GSAbsDef(s32) -GSAbsDef(s64) -GSAbsDef(r32) -GSAbsDef(r64) -#undef GSAbsDef - -#define GSPowDef(type) static type GSPow(type N, s32 Power) { \ - type Result = N; \ - for(s32 i = 1; i < Power; i++) { Result *= N; } \ - return Result; \ -} -GSPowDef(s8) -GSPowDef(s16) -GSPowDef(s32) -GSPowDef(s64) -GSPowDef(u8) -GSPowDef(u16) -GSPowDef(u32) -GSPowDef(u64) -GSPowDef(r32) -GSPowDef(r64) -#undef GSPowDef - - -#define GSLerpDef(type) type GSLerp(type A, type B, type Percent) { return (A * (1.0f - Percent))+(B * Percent);} -GSLerpDef(r32) -GSLerpDef(r64) -#undef GSLerpDef - -static r32 GSSqrt(r32 V) -{ - r32 Result = _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V))); - return Result; -} -#if 0 -// TODO(Peter): Need a way to split the input into two f32's to supply to _mm_sqrt_sd -static r64 GSSqrt(r64 V) -{ - r64 Result = _mm_cvtsd_f64(_mm_sqrt_sd(_mm_set_sd(V))); - return Result; -} -#endif - -static r32 DegreesToRadians (r32 Degrees) { return Degrees * PI_OVER_180; } -static r64 DegreesToRadians (r64 Degrees) { return Degrees * PI_OVER_180; } - -#define GSIsPowerOfTwoDef(type) static type IsPowerOfTwo(type V) { return (V & (V - 1)) == 0; } -GSIsPowerOfTwoDef(u8); -GSIsPowerOfTwoDef(u16); -GSIsPowerOfTwoDef(u32); -GSIsPowerOfTwoDef(u64); -#undef GSIsPowerOfTwoDef - -#define GSIsOddDef(type) inline type IsOdd(type V) { return (V & 1); } -GSIsOddDef(u8); -GSIsOddDef(u16); -GSIsOddDef(u32); -GSIsOddDef(u64); -GSIsOddDef(s8); -GSIsOddDef(s16); -GSIsOddDef(s32); -GSIsOddDef(s64); -#undef GSIsOddDef - -#define GSIntDivideRoundUpDef(type) static type IntegerDivideRoundUp (type A, type B) { r32 Result = (r32)A / (r32)B; Result += .99999f; return (type)Result; } -GSIntDivideRoundUpDef(u8); -GSIntDivideRoundUpDef(u16); -GSIntDivideRoundUpDef(u32); -GSIntDivideRoundUpDef(u64); -GSIntDivideRoundUpDef(s8); -GSIntDivideRoundUpDef(s16); -GSIntDivideRoundUpDef(s32); -GSIntDivideRoundUpDef(s64); -#undef GSIntDivideRoundUpDef - -#define GSRemapDef(type) \ -static type GSRemap(type Value, type OldMin, type OldMax, type NewMin, type NewMax) { \ - type Result = (Value - OldMin) / (OldMax - OldMin); \ - Result = (Result * (NewMax - NewMin)) + NewMin; \ - return Result; \ -} -GSRemapDef(u8); -GSRemapDef(u16); -GSRemapDef(u32); -GSRemapDef(u64); -GSRemapDef(s8); -GSRemapDef(s16); -GSRemapDef(s32); -GSRemapDef(s64); -GSRemapDef(r32); -GSRemapDef(r64); -#undef GSRemapDef - -#define GSTrigFunctionDef(name, type, func) static type name(type V) { return func(V); } -GSTrigFunctionDef(GSSin, r32, sinf); -GSTrigFunctionDef(GSSin, r64, sin); -GSTrigFunctionDef(GSCos, r32, cosf); -GSTrigFunctionDef(GSCos, r64, cos); -GSTrigFunctionDef(GSTan, r32, tanf); -GSTrigFunctionDef(GSTan, r64, tan); -#undef GSTrigFunctionDef - -static u8 -RoundToNearestPowerOfTwo (u8 V) -{ - u8 Result = 0; - - if (IsPowerOfTwo(V)) - { - Result = V; - } - else - { - Result = V - 1; - Result |= Result >> 1; - Result |= Result >> 2; - Result |= Result >> 4; - Result += 1; - } - - return Result; -} - -static u16 -RoundToNearestPowerOfTwo (u16 V) -{ - u16 Result = 0; - - if (IsPowerOfTwo(V)) - { - Result = V; - } - else - { - Result = V - 1; - Result |= Result >> 1; - Result |= Result >> 2; - Result |= Result >> 4; - Result |= Result >> 8; - Result += 1; - } - - return Result; -} - -static u32 -RoundToNearestPowerOfTwo (u32 V) -{ - u32 Result = 0; - - if (IsPowerOfTwo(V)) - { - Result = V; - } - else - { - Result = V - 1; - Result |= Result >> 1; - Result |= Result >> 2; - Result |= Result >> 4; - Result |= Result >> 8; - Result |= Result >> 16; - Result += 1; - } - - return Result; -} - -static u64 -RoundToNearestPowerOfTwo (u64 V) -{ - u64 Result = 0; - - if (IsPowerOfTwo(V)) - { - Result = V; - } - else - { - Result = V - 1; - Result |= Result >> 1; - Result |= Result >> 2; - Result |= Result >> 4; - Result |= Result >> 8; - Result |= Result >> 16; - Result |= Result >> 32; - Result += 1; - } - - return Result; -} - -#define GS_LANGUAGE_MATH -#endif // GS_LANGUAGE_MATH - -static u32 -HostToNetU32(u32 In) -{ - unsigned char *s = (unsigned char *)&In; - u32 Result = (u32)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); - return Result; -} - -static u16 -HostToNetU16(u16 In) -{ - unsigned char *s = (unsigned char *)&In; - u16 Result = (u16)(s[0] << 8 | s[1]); - return Result; -} - -#define GS_LANGUAGE_H -#endif diff --git a/src/gs_memory.h b/src/gs_memory.h deleted file mode 100644 index 9d1541d..0000000 --- a/src/gs_memory.h +++ /dev/null @@ -1,461 +0,0 @@ -#ifndef GS_MEMORY_H - -#define ArenaZeroStruct(data_ptr) ArenaZeroStruct_((u8*)data_ptr, sizeof(*data_ptr)) -inline void -ArenaZeroStruct_ (u8* Base, s32 Size) -{ - u8* Iter = Base; - for (s32 i = 0; i < Size; i++) { *Iter++ = 0; } -} - -struct grow_arena_result -{ - u8* Base; - s32 Size; -}; - -#define GROW_ARENA_MEMORY(name) grow_arena_result name(s32 Size) -typedef GROW_ARENA_MEMORY(grow_arena_memory); - -#define FREE_ARENA_MEMORY(name) b32 name(u8* Base, s32 Size) -typedef FREE_ARENA_MEMORY(free_arena_memory); - -struct memory_region_header -{ - memory_region_header* Prev; - s32 Size; - s32 Used; - u8* Base; -}; - -inline b32 -RegionCanFitSize (memory_region_header* Header, s32 Size) -{ - b32 Result = (Header->Used + Size) <= Header->Size; - return Result; -} - -inline b32 -AddressIsInRegion (memory_region_header* Header, u8* Address) -{ - b32 Result = (Header->Base <= Address) && (Header->Base + Header->Used > Address); - return Result; -} - -#ifndef DEFAULT_MEMORY_ALIGNMENT -#define DEFAULT_MEMORY_ALIGNMENT (2 * sizeof(void*)) -#endif - -b32 GSMemIsPowerOfTwo (u64 Address) -{ - return (Address & (Address - 1)) == 0; -} - -u64 AlignForward (u64 Base, u64 Align) -{ - u64 P, A, Modulo; - - Assert(GSMemIsPowerOfTwo(Align)); - - P = Base; - A = Align; - Modulo = P & (A - 1); - - if (Modulo != 0) - { - P = P + (A - Modulo); - } - - return P; -} - -////////////////////////////// -// Heap Memory -////////////////////////////// - -// heap_memory_arena -// a growable memory arena that has two ways to interact with it: push and clear. -// Push: returns a free region of continguous memory. If the arenas GrowArenaProc function is set, this may -// get called in order to obtain enough free memory to fulfil the push request -// Clear: clears the entire memory arena. If the arena has been grown at any point, those subsequent -// regions of memory will be freed back to the system. -struct heap_memory_arena -{ - memory_region_header* CurrentRegion; - - s32 RegionMemorySize; - grow_arena_memory* GrowArenaProc; - free_arena_memory* FreeArenaMemoryProc; -}; - -static void -GrowHeapArena (heap_memory_arena* Arena, s32 RequestedSize) -{ - if (Arena->GrowArenaProc) - { - Assert(Arena->RegionMemorySize > 0); - - s32 GrowthSize = GSMax(RequestedSize, Arena->RegionMemorySize); - grow_arena_result NewMemory = Arena->GrowArenaProc(GrowthSize + sizeof(memory_region_header)); - Assert(NewMemory.Size > 0); - - memory_region_header* Header = (memory_region_header*)NewMemory.Base; - Header->Base = (u8*)NewMemory.Base + sizeof(memory_region_header); - Header->Size = NewMemory.Size - sizeof(memory_region_header); - Header->Used = 0; - Header->Prev = Arena->CurrentRegion; - Arena->CurrentRegion = Header; - } - else - { - InvalidCodePath; - } -} - -#define PushStruct(arena, type) (type*)PushSize_(arena, sizeof(type)) -#define PushArray(arena, type, count) (type*)PushSize_(arena, sizeof(type)*count) -static u8* -PushSize_ (heap_memory_arena* Arena, s32 Size) -{ - if (!Arena->CurrentRegion) { GrowHeapArena(Arena, Size); } - - u8* CurrPointer = Arena->CurrentRegion->Base + Arena->CurrentRegion->Used; - u64 Offset = AlignForward((u64)CurrPointer, DEFAULT_MEMORY_ALIGNMENT); - Offset -= (u64)(Arena->CurrentRegion->Base + Arena->CurrentRegion->Used); - - if (!RegionCanFitSize(Arena->CurrentRegion, Size + Offset)) - { - // TODO(Peter): There might be empty space in the current region, its just not big enough for the - // requested size. We should search backwards to see if there is enough space in a previous region - // before growing the arena. - - GrowHeapArena(Arena, Size + Offset); - } - - u8* Result = Arena->CurrentRegion->Base + Arena->CurrentRegion->Used + Offset; - Arena->CurrentRegion->Used += Size + Offset; - - GSZeroMemory(Result, Size); - - return Result; -} - -static void -InitHeapMemoryArena (heap_memory_arena* Arena, s32 RegionMemorySize, - grow_arena_memory* GrowProc, free_arena_memory* FreeProc) -{ - ArenaZeroStruct(Arena); - Arena->RegionMemorySize = RegionMemorySize; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -static void -InitHeapMemoryArena (heap_memory_arena* Arena, u8* Base, s32 Size, - s32 RegionMemorySize = 0, - grow_arena_memory* GrowProc = 0, - free_arena_memory* FreeProc = 0) -{ - Assert(Size > sizeof(memory_region_header)); - - Arena->CurrentRegion = (memory_region_header*)Base; - Arena->CurrentRegion->Base = Base + sizeof(memory_region_header); - Arena->CurrentRegion->Size = Size - sizeof(memory_region_header); - Arena->CurrentRegion->Used = 0; - Arena->CurrentRegion->Prev = 0; - - Arena->RegionMemorySize = RegionMemorySize; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -static void -ClearHeapMemoryArena (heap_memory_arena* Arena) -{ - if (!Arena->CurrentRegion) { return; } - - memory_region_header* CurrentHead = Arena->CurrentRegion; - - if (CurrentHead->Prev) - { - Assert(Arena->FreeArenaMemoryProc); - while(CurrentHead->Prev) - { - memory_region_header* PrevHead = CurrentHead->Prev; - Arena->FreeArenaMemoryProc((u8*)CurrentHead, CurrentHead->Size + sizeof(memory_region_header)); - CurrentHead = PrevHead; - } - - Arena->CurrentRegion = CurrentHead; - } - - Arena->CurrentRegion->Used = 0; -} - - -////////////////////////////// -// Stack Memory -////////////////////////////// - -struct stack_memory_region -{ - stack_memory_region* Prev; -}; - -// stack_memory_arena -// Push: returns a free region of continguous memory. If the arenas GrowArenaProc function is set, this may -// get called in order to obtain enough free memory to fulfil the push request -// Pop: frees the last region allocated on the stack, returning it to the region of memory available to -// be used. -// Clear: clears the entire memory arena. If the arena has been grown at any point, those subsequent -// regions of memory will be freed back to the system. -struct stack_memory_arena -{ - memory_region_header* CurrentRegion; - stack_memory_region* UsedList; - - s32 RegionMemorySize; - grow_arena_memory* GrowArenaProc; - free_arena_memory* FreeArenaMemoryProc; -}; - -static u8* -PushSize_ (stack_memory_arena* Arena, s32 Size) -{ - if (!Arena->CurrentRegion || - !RegionCanFitSize(Arena->CurrentRegion, Size)) - { - if (Arena->GrowArenaProc) - { - Assert(Arena->RegionMemorySize > 0); - - grow_arena_result NewMemory = Arena->GrowArenaProc(Arena->RegionMemorySize + sizeof(memory_region_header)); - Assert(NewMemory.Size > 0); - - memory_region_header* Header = (memory_region_header*)NewMemory.Base; - Header->Base = (u8*)NewMemory.Base + sizeof(memory_region_header); - Header->Size = NewMemory.Size - sizeof(memory_region_header); - Header->Used = 0; - Header->Prev = Arena->CurrentRegion; - Arena->CurrentRegion = Header; - } - else - { - InvalidCodePath; - } - } - - u8* Region = Arena->CurrentRegion->Base + Arena->CurrentRegion->Used; - stack_memory_region* UsedListHeader = (stack_memory_region*)Region; - UsedListHeader->Prev = Arena->UsedList; - Arena->UsedList = UsedListHeader; - - u8* Result = Region + sizeof(stack_memory_region); - Arena->CurrentRegion->Used += Size + sizeof(stack_memory_region); - - return Result; -} - -// NOTE(Peter): Returns size available after the Pop operation -static s32 -PopLast (stack_memory_arena* Arena) -{ - s32 Result = Arena->CurrentRegion->Size - Arena->CurrentRegion->Used; - - if (Arena->UsedList) - { - u8* LastHead = (u8*)Arena->UsedList; - - if (!AddressIsInRegion(Arena->CurrentRegion, LastHead) && - Arena->FreeArenaMemoryProc) - { - memory_region_header* PrevHeader = Arena->CurrentRegion->Prev; - Arena->FreeArenaMemoryProc((u8*)Arena->CurrentRegion, - Arena->CurrentRegion->Size + sizeof(memory_region_header)); - Arena->CurrentRegion = PrevHeader; - - } - - Assert(LastHead >= Arena->CurrentRegion->Base && - LastHead <= Arena->CurrentRegion->Base + Arena->CurrentRegion->Size); - - stack_memory_region* PrevAlloc = Arena->UsedList->Prev; - - s32 SizeUsed = LastHead - Arena->CurrentRegion->Base; - Arena->CurrentRegion->Used = SizeUsed; - Result = Arena->CurrentRegion->Size - Arena->CurrentRegion->Used; - - Arena->UsedList = PrevAlloc; - } - - return Result; -} - -static void -InitStackMemoryArena (stack_memory_arena* Arena, s32 RegionMemorySize, - grow_arena_memory* GrowProc, free_arena_memory* FreeProc) -{ - ArenaZeroStruct(Arena); - Arena->RegionMemorySize = RegionMemorySize; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -static void -InitStackMemoryArena (stack_memory_arena* Arena, u8* Base, s32 Size, - s32 RegionMemorySize = 0, - grow_arena_memory* GrowProc = 0, - free_arena_memory* FreeProc = 0) -{ - Assert(Size > sizeof(memory_region_header)); - - Arena->CurrentRegion = (memory_region_header*)Base; - Arena->CurrentRegion->Base = Base + sizeof(memory_region_header); - Arena->CurrentRegion->Size = Size - sizeof(memory_region_header); - Arena->CurrentRegion->Used = 0; - Arena->CurrentRegion->Prev = 0; - - Arena->RegionMemorySize = RegionMemorySize; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -static void -ClearStackMemoryArena (stack_memory_arena* Arena) -{ - if (!Arena->CurrentRegion) { return; } - - memory_region_header* CurrentHead = Arena->CurrentRegion; - - if (CurrentHead->Prev) - { - Assert(Arena->FreeArenaMemoryProc); - while(CurrentHead->Prev) - { - memory_region_header* PrevHead = CurrentHead->Prev; - Arena->FreeArenaMemoryProc((u8*)CurrentHead, CurrentHead->Size + sizeof(memory_region_header)); - CurrentHead = PrevHead; - } - - Arena->CurrentRegion = CurrentHead; - } - - Arena->CurrentRegion->Used = 0; - Arena->UsedList = 0; -} - -////////////////////////////// -// Pool Memory -////////////////////////////// - -struct chunk_header -{ - chunk_header* Prev; -}; - -struct pool_memory_arena -{ - memory_region_header* CurrentRegion; - s32 ChunkSize; - chunk_header* FreeList; - - s32 RegionMemorySize; - grow_arena_memory* GrowArenaProc; - free_arena_memory* FreeArenaMemoryProc; -}; - -struct chunk_result -{ - s32 Size; - u8* Base; -}; - -static chunk_result -PushChunk (pool_memory_arena* Arena) -{ - chunk_result Result = {}; - - if (Arena->FreeList) - { - Result.Base = (u8*)Arena->FreeList; - Result.Size = Arena->ChunkSize; - - Arena->FreeList = Arena->FreeList->Prev; - } - else - { - if (!RegionCanFitSize(Arena->CurrentRegion, Arena->ChunkSize)) - { - if (Arena->GrowArenaProc) - { - grow_arena_result NewMemory = Arena->GrowArenaProc(Arena->RegionMemorySize + sizeof(memory_region_header)); - Assert(NewMemory.Size > 0); - - memory_region_header* Header = (memory_region_header*)NewMemory.Base; - Header->Base = (u8*)NewMemory.Base + sizeof(memory_region_header); - Header->Size = NewMemory.Size - sizeof(memory_region_header); - Header->Used = 0; - Header->Prev = Arena->CurrentRegion; - Arena->CurrentRegion = Header; - } - else - { - InvalidCodePath; - } - } - - Result.Base = Arena->CurrentRegion->Base + Arena->CurrentRegion->Used; - Result.Size = Arena->ChunkSize; - - Arena->CurrentRegion->Used += Arena->ChunkSize; - } - - return Result; -} - -static void -FreeChunk (pool_memory_arena* Arena, u8* Base, s32 Size) -{ - Assert(Arena->ChunkSize == Size); - - chunk_header* Header = (chunk_header*)Base; - Header->Prev = Arena->FreeList; - Arena->FreeList = Header; -} - -static void -InitPoolMemoryArena (pool_memory_arena* Arena, s32 ChunkSize, s32 ChunksPerRegion, - grow_arena_memory* GrowProc, free_arena_memory* FreeProc) -{ - Assert(ChunkSize > sizeof(chunk_header)); - - ArenaZeroStruct(Arena); - Arena->ChunkSize = ChunkSize; - Arena->RegionMemorySize = ChunkSize * ChunksPerRegion; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -static void -InitStackMemoryArena (pool_memory_arena* Arena, u8* Base, s32 Size, - s32 ChunkSize, s32 ChunksPerRegion, - grow_arena_memory* GrowProc = 0, - free_arena_memory* FreeProc = 0) -{ - Assert(Size > sizeof(memory_region_header)); - Assert(Size % ChunkSize == ChunksPerRegion); - - Arena->CurrentRegion = (memory_region_header*)Base; - Arena->CurrentRegion->Base = Base + sizeof(memory_region_header); - Arena->CurrentRegion->Size = Size - sizeof(memory_region_header); - Arena->CurrentRegion->Used = 0; - Arena->CurrentRegion->Prev = 0; - - Arena->ChunkSize = ChunkSize; - Arena->RegionMemorySize = ChunkSize * ChunksPerRegion; - Arena->GrowArenaProc = GrowProc; - Arena->FreeArenaMemoryProc = FreeProc; -} - -#define GS_MEMORY_H -#endif // GS_MEMORY_H diff --git a/src/gs_platform.h b/src/gs_platform.h index 332d349..9f1b5a7 100644 --- a/src/gs_platform.h +++ b/src/gs_platform.h @@ -75,6 +75,9 @@ typedef PLATFORM_ALLOC(platform_alloc); #define PLATFORM_FREE(name) b32 name(u8* Base, s32 Size) typedef PLATFORM_FREE(platform_free); +#define PLATFORM_REALLOC(name) u8* name(u8* Base, u32 OldSize, u32 NewSize) +typedef PLATFORM_REALLOC(platform_realloc); + #define PLATFORM_READ_ENTIRE_FILE(name) platform_memory_result name(char* Path) typedef PLATFORM_READ_ENTIRE_FILE(platform_read_entire_file); @@ -87,6 +90,13 @@ typedef PLATFORM_GET_FILE_PATH(platform_get_file_path); #define PLATFORM_GET_GPU_TEXTURE_HANDLE(name) s32 name(u8* Memory, s32 Width, s32 Height) typedef PLATFORM_GET_GPU_TEXTURE_HANDLE(platform_get_gpu_texture_handle); +struct platform_network_address +{ + s32 Family; + u16 Port; + u32 Address; +}; + typedef s32 platform_socket_handle; typedef s32 platform_network_address_handle; @@ -99,7 +109,7 @@ typedef PLATFORM_GET_SEND_ADDRESS_HANDLE(platform_get_send_address); #define PLATFORM_SET_SOCKET_OPTION(name) s32 name(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) typedef PLATFORM_SET_SOCKET_OPTION(platform_set_socket_option); -#define PLATFORM_SEND_TO(name) s32 name(platform_socket_handle SocketHandle, platform_network_address_handle AddressHandle, const char* Buffer, s32 BufferLength, s32 Flags) +#define PLATFORM_SEND_TO(name) s32 name(platform_socket_handle SocketHandle, platform_network_address Address, const char* Buffer, s32 BufferLength, s32 Flags) typedef PLATFORM_SEND_TO(platform_send_to); #define PLATFORM_CLOSE_SOCKET(name) void name(platform_socket_handle SocketHandle) diff --git a/src/gs_string.h b/src/gs_string.h deleted file mode 100644 index 2cd8158..0000000 --- a/src/gs_string.h +++ /dev/null @@ -1,2206 +0,0 @@ -#ifndef GS_STRING_H -//////////////////////////////////////////////////////////////// -// String -//////////////////////////////////////////////////////////////// - -struct string -{ - char* Memory; - s32 Length; - s32 Max; -}; - -//////////////////////////////////////////////////////////////// -// String Tokenizing -//////////////////////////////////////////////////////////////// - -struct tokenizer -{ - char* At; - char* Memory; - s32 MemoryLength; -}; - - -enum token_type -{ - Token_Error, - - Token_LeftParen, - Token_RightParen, - Token_LeftSquareBracket, - Token_RightSquareBracket, - Token_LeftCurlyBracket, - Token_RightCurlyBracket, - Token_Semicolon, - Token_Operator, - Token_Comma, - Token_Period, - Token_PointerReference, - - Token_PoundDefine, - Token_PoundUndef, - Token_PoundInclude, - Token_PoundIfDef, - Token_PoundIfNDef, - Token_PoundIf, - Token_PoundElif, - Token_PoundElse, - Token_PoundEndif, - Token_PoundError, - Token_PoundPragma, - - Token_Number, - Token_Char, - Token_String, - Token_Identifier, - - Token_Comment, - Token_MultilineComment, - - Token_Unknown, - Token_EndOfStream, -}; - -char* TokenNames[] = { - "Token_Error ", - "Token_LeftParen ", - "Token_RightParen ", - "Token_LeftSquareBracket ", - "Token_RightSquareBracket ", - "Token_LeftCurlyBracket ", - "Token_RightCurlyBracket ", - "Token_Semicolon ", - "Token_Operator ", - "Token_Comma ", - "Token_Period ", - "Token_PointerReference ", - "Token_PoundDefine ", - "Token_PoundUndef ", - "Token_PoundInclude ", - "Token_PoundIfDef ", - "Token_PoundIfNDef ", - "Token_PoundIf ", - "Token_PoundElif ", - "Token_PoundElse ", - "Token_PoundEndif ", - "Token_PoundError ", - "Token_PoundPragma ", - "Token_Number ", - "Token_Char ", - "Token_String ", - "Token_Identifier ", - "Token_Comment ", - "Token_MultilineComment ", - "Token_Unknown ", - "Token_EndOfStream ", -}; - -struct token -{ - token_type Type; - string Text; - token* Next; -}; - -//////////////////////////////////////////////////////////////// -// String Memory -//////////////////////////////////////////////////////////////// - -struct slot_header -{ - slot_header* Next; - s32 Size; -}; - -struct slot_arena -{ - u8* Memory; - s32 SlotSize; - s32 SlotCount; - slot_header* FreeList; -}; - -struct contiguous_slot_count_result -{ - s32 Count; - slot_header* LastContiguousSlot; -}; - - -//////////////////////////////////////////////////////////////// -// String Function Declarations -//////////////////////////////////////////////////////////////// - -// Utility -#if !defined GS_LANGUAGE_H - -static void GSZeroMemory (u8* Memory, s32 Size); -static s32 GSMin (s32 A, s32 B); -static s32 GSAbs (s32 A); -static float GSAbsF (float A); -static float GSPowF (float N, s32 Power); - -#endif - -// Setup - -#ifdef GS_MEMORY_H -#define PushString(str, arena, size) (str)->Memory = PushArray(arena, char, size); (str)->Length = 0; (str)->Max = size; -#endif - -static void InitializeEmptyString (string* String, char* Data, s32 DataSize); -static void InitializeString(string* String, char* Data, s32 Used, s32 Max); -static string InitializeEmptyString (char* Data, s32 DataSize); -static string InitializeString (char* Data, s32 Used, s32 Max); -static void ClearString (string* String); - -// Character Values -static bool IsSlash (char C); -static bool IsNewline (char C); -static bool IsWhitespace (char C); -static bool IsAlpha (char C); -static bool IsUpper (char C); -static bool IsLower (char C); -static char ToUpper (char C); -static char ToLower (char C); -static bool IsNumeric (char C); -static bool IsNumericExtended (char C); -static bool IsAlphaNumeric (char C); -static bool IsOperator (char C); -static bool CharsEqualCaseInsensitive(char A, char B); - -// Tokenizing -static b32 AtValidPosition(tokenizer Tokenizer); -static b32 AtValidToken(tokenizer Tokenizer); -static char* EatToNewLine(char* C); -static void EatToNewLine(tokenizer* T); -static char* EatWhitespace(char* C); -static void EatWhitespace(tokenizer* T); -static char* EatToWhitespace(char* C); -static void EatToWhitespace(tokenizer* T); -static char* EatToCharacter(char* C, char Char); -static void EatToCharacter(tokenizer* T, char Char); -static char* EatPastCharacter(char* C, char Char); -static void EatPastCharacter(tokenizer* T, char Char); -static char* EatNumber(char* C); -static void EatNumber(tokenizer* T); - -// Char/Char Array -static u32 CharToUInt (char C); -static s32 CharArrayLength (char* CharArray); -static bool CharArraysEqual (char* A, s32 ALength, char* B, s32 BLength); -static bool CharArraysEqualUnsafe (char* A, char* B); -static void ReverseCharArray (char* Array, s32 Length); -#define FirstIndexOfCharInCharArray(array, find) IndexOfChar(array, 0, find) -static s32 IndexOfChar (char* Array, s32 Start, char Find); -#define FastLastIndexOfCharInCharArray(array, len, find) FastReverseIndexOfChar(array, len, 0, find) -static s32 FastReverseIndexOfChar (char* Array, s32 Length, s32 OffsetFromEnd, char Find); -#define LastIndexOfCharInCharArray(array, find) ReverseIndexOfChar(array, 0, find) -static s32 ReverseIndexOfChar (char* Array, s32 OffsetFromEnd, char Find); -static b32 CharArrayContains(char* Array, char* CheckFor); -static b32 CharArrayContainsSafe(char* Array, s32 ArrayLength, char* CheckFor, s32 CheckForLength); - -// String - -#define MakeStringBuffer(name, size) \ -char name##Backbuffer[(size)]; \ -string name = MakeString(name##Backbuffer, size); - -static string MakeString (char* Array, s32 Length, s32 Max); -static string MakeString (char* Array, s32 Length); -static string MakeString (char* Array); -static string MakeStringLiteral(char* Data); - -static bool StringsEqual (string A, string B); -static bool StringEqualsCharArray (string String, char* CharArray); -static bool StringEqualsCharArray (string String, char* CharArray, s32 CharArrayLength); -static s32 FindFirstChar (string String, char C); - -static void SetStringToChar (string* Dest, char C, s32 Count); -static void SetStringToCharArray (string* Dest, char* Source); - -static void ConcatString (string Source, string* Dest); -static void ConcatString (string Source, s32 Length, string* Dest); -static void ConcatCharToString(string* Dest, char C); -static void ConcatCharArrayToString (char* Source, string* Dest); -static void ConcatCharArrayToString (char* Source, s32 SourceLength, string* Dest); - -static void CopyStringTo (string Source, string* Dest); -static s32 CopyStringToCharArray (string Source, char* Dest, s32 DestLength); -static void CopyCharArrayToString (char* Src, string* Dest); -static void CopyCharArrayToString (char* Src, s32 SrcLength, string* Dest); -static s32 CopyCharArray (char* Source, char* Dest, s32 DestLength); -static s32 CopyCharArrayAt (char* Source, char* Dest, s32 DestLength, s32 Offset); - -static void InsertChar (string* String, char Char, s32 Index); -static void InsertStringAt (string* Dest, string Source, s32 At); -static void RemoveCharAt (string* String, s32 Index); - -static s32 IndexOfChar(string String, char C); -static s32 LastIndexOfChar(string String, char C); -static string Substring (string* String, s32 Start, s32 End); -static string Substring (string* String, s32 Start); - -static b32 StringContainsCharArray(string SearchIn, char* SearchFor, s32 SearchForLength); -static b32 StringContainsString(string SearchIn, string SearchFor); -static b32 StringContainsCharArrayCaseInsensitive(string SearchIn, char* SearchFor, s32 SearchForLength); -static b32 StringContainsStringCaseInsensitive(string SearchIn, string SearchFor); - -static void NullTerminate (string* String); - - -// Parsing -enum parse_type -{ - ParseType_UnsignedInt, - ParseType_SignedInt, - ParseType_Float, -}; - -struct parse_result -{ - parse_type Type; - char* OnePastLast; - union - { - u32 UnsignedIntValue; - s32 SignedIntValue; - r32 FloatValue; - }; -}; - -enum format_flags -{ - FormatFlags_LeftJustify = 0x1, - FormatFlags_ForceSign = 0x2, - FormatFlags_ForceSpaceInsteadOfSign = 0x4, - FormatFlags_ForceDecimalOrPrependOx = 0x8, - FormatFlags_PadWithZeroesInsteadOfSpaces = 0x16, -}; - -static parse_result ParseUnsignedInt (char* String, s32 Length); -static parse_result ParseSignedInt (char* String, s32 Length); -static parse_result ParseFloat (char* String, s32 Length); - -// PrintF -static void PrintFArgList(char* Dest, s32 DestMax, char* Format, va_list Args); -static void PrintF(string* String, char* Format, ...); - -//////////////////////////////////////////////////////////////// -// String Memory Function Declarations -//////////////////////////////////////////////////////////////// - -static s32 CalculateSlotCountFromSize (s32 RequestedSize, s32 SlotSize); -static bool SlotsAreContiguous (slot_header* First, slot_header* Second); -static contiguous_slot_count_result CountContiguousSlots (slot_header* First); -static slot_header* GetSlotAtOffset(slot_header* First, s32 Offset); -static slot_header* InsertSlotIntoList (slot_header* NewSlot, slot_header* ListStart); -static void AllocStringFromStringArena (string* String, s32 Size, slot_arena* Storage); -static string AllocStringFromStringArena (s32 Size, slot_arena* Storage); -static void FreeToStringArena (string* String, slot_arena* Storage); -static void ReallocFromStringArena (string* String, s32 NewSize, slot_arena* Storage); - -//////////////////////////////////////////////////////////////// -// String Utility Functions -//////////////////////////////////////////////////////////////// - -#if !defined GS_LANGUAGE_H - -static void -GSZeroMemory (u8* Memory, s32 Size) -{ - for (int i = 0; i < Size; i++) { Memory[i] = 0; } -} - -static s32 -GSMin (s32 A, s32 B) -{ - return (A < B ? A : B); -} - -static s32 -GSAbs (s32 A) -{ - return (A < 0 ? -A : A); -} - -static float -GSAbs (float A) -{ - return (A < 0 ? -A : A); -} - -static float -GSPow (float N, s32 Power) -{ - float Result = N; - for(s32 i = 1; i < Power; i++) { Result *= N; } - return Result; -} - -#endif - -//////////////////////////////////////////////////////////////// -// Init and Clear -//////////////////////////////////////////////////////////////// - -static void -InitializeEmptyString (string* String, char* Data, s32 DataSize) -{ - String->Memory = Data; - String->Max = DataSize; - String->Length = 0; -} - -static void -InitializeString(string* String, char* Data, s32 Used, s32 Max) -{ - String->Memory = Data; - String->Max = Max; - String->Length = Used; -} - -static string -InitializeEmptyString (char* Data, s32 DataSize) -{ - string Result = {}; - Result.Memory = Data; - Result.Max = DataSize; - Result.Length = 0; - return Result; -} - -static string -InitializeString (char* Data, s32 Used, s32 Max) -{ - string Result = {}; - Result.Memory = Data; - Result.Max = Max; - Result.Length = Used; - return Result; -} - -static void -ClearString (string* String) -{ - String->Memory = 0; - String->Max = 0; - String->Length = 0; -} - -//////////////////////////////////////////////////////////////// -// Char Value Types -//////////////////////////////////////////////////////////////// - -static bool IsSlash (char C) { return ((C == '\\') || (C == '/')); } -static bool IsNewline (char C) { return (C == '\n') || (C == '\r'); } -static bool IsWhitespace (char C) { return (C == ' ') || (C == '\t') || IsNewline(C); } -static bool IsAlpha (char C) -{ - // TODO(Peter): support UTF8 chars - return ((C >= 'A') && (C <= 'Z')) || ((C >= 'a') && (C <= 'z')) || (C == '_'); -} -static bool IsUpper (char C) -{ - return ((C >= 'A') && (C <= 'Z')); -} -static bool IsLower (char C) -{ - return ((C >= 'a') && (C <= 'z')); -} -static bool IsNumeric (char C) -{ - return (C >= '0') && (C <= '9'); -} -static bool IsNumericExtended (char C) -{ - return (IsNumeric(C) || (C == 'x') || (C == 'f') || (C == '.')); -} -static bool IsAlphaNumeric (char C) -{ - return IsAlpha(C) || IsNumeric(C); -} -static bool IsOperator (char C) -{ - return ((C == '+') || - (C == '-') || - (C == '*') || - (C == '/') || - (C == '=') || - (C == '%') || - (C == '<') || - (C == '>')); -} -static char ToUpper (char A) -{ - char Result = A; - if (IsLower(A)) - { - Result += 'A' - 'a'; - } - return Result; -} -static char ToLower (char A) -{ - char Result = A; - if (IsUpper(A)) - { - Result -= 'A' - 'a'; - } - return Result; -} -static bool CharsEqualCaseInsensitive (char A, char B) -{ - b32 Result = (ToLower(A) == ToLower(B)); - return Result; -} - -//////////////////////////////////////////////////////////////// -// Tokenizing -//////////////////////////////////////////////////////////////// - -static b32 -AtValidPosition (tokenizer Tokenizer) -{ - b32 Result = (Tokenizer.At - Tokenizer.Memory) <= Tokenizer.MemoryLength; - return Result; -} - -static b32 -AtValidToken(tokenizer Tokenizer) -{ - b32 Result = *Tokenizer.At && Tokenizer.At < (Tokenizer.Memory + Tokenizer.MemoryLength); - return Result; -} - -static char* -EatToNewLine(char* C) -{ - char* Result = C; - while (*Result && !IsNewline(*Result)) { Result++; } - if (*Result) { Result++; } // NOTE(Peter): eat past the newline character - return Result; -} - -static void -EatToNewLine(tokenizer* T) -{ - while (*T->At && !IsNewline(*T->At)) { T->At++; } - if (*T->At) { T->At++; } // NOTE(Peter): eat past the newline character -} - -static char* -EatWhitespace(char* C) -{ - char* Result = C; - while (*Result && IsWhitespace(*Result)) { Result++; } - return Result; -} - -static void -EatWhitespace(tokenizer* T) -{ - while (*T->At && IsWhitespace(*T->At)) { T->At++; } -} - -static char* -EatToWhitespace(char* C) -{ - char* Result = C; - while (*Result && !IsWhitespace(*Result)) { Result++; } - return Result; -} - -static void -EatToWhitespace(tokenizer* T) -{ - while (*T->At && !IsWhitespace(*T->At)) { T->At++; } -} - -static char* -EatToCharacter(char* C, char Char) -{ - char* Result = C; - while (*Result && *Result != Char) { Result++; } - return Result; -} - -static void -EatToCharacter(tokenizer* T, char Char) -{ - while (*T->At && *T->At != Char) { T->At++; } -} - -static char* -EatPastCharacter(char* C, char Char) -{ - char* Result = EatToCharacter(C, Char); - if (*Result && *Result == Char) { Result++; } - return Result; -} - -static void -EatPastCharacter(tokenizer* T, char Char) -{ - EatToCharacter(T, Char); - if (*T->At && *T->At == Char) { T->At++; } -} - -static char* -EatNumber(char* C) -{ - char* Result = C; - while (*Result && IsNumericExtended(*Result)) { Result++; } - return Result; -} - -static void -EatNumber(tokenizer* T) -{ - while (*T->At && IsNumericExtended(*T->At)) { T->At++; } -} - -//////////////////////////////////////////////////////////////// -// Basic Char Operations -//////////////////////////////////////////////////////////////// - -static u32 CharToUInt (char C) { - u32 Result = (C - '0'); - return Result; -} - -static s32 -CharArrayLength (char* Array) -{ - char* C = Array; - s32 Result = 0; - while (*C) - { - *C++; - Result++; - } - return Result; -} - -static s32 -NullTerminatedCharArrayLength (char* CharArray) -{ - char* Iter = CharArray; - while (*Iter) - { - *Iter++; - } - return (Iter - CharArray); -} - -static bool -CharArraysEqual (char* A, s32 ALength, char* B, s32 BLength) -{ - bool Result = false; - if (ALength == BLength) - { - Result = true; - char* AIter = A; - char* BIter = B; - for (s32 i = 0; i < ALength; i++) - { - if(*AIter++ != *BIter++) - { - Result = false; - break; - } - } - } - return Result; -} - -static bool -CharArraysEqualUnsafe (char* A, char* B) -{ - bool Result = true; - - char* AIter = A; - char* BIter = B; - while(*AIter && *BIter) - { - if(*AIter++ != *BIter++) - { - Result = false; - break; - } - } - - if((*AIter && !*BIter) || (!*AIter && *BIter)) - { - Result = false; - } - - return Result; -} - -static bool -CharArraysEqualUpToLength (char* A, char* B, s32 Length) -{ - bool Result = true; - - char* AIter = A; - char* BIter = B; - for (s32 i = 0; i < Length; i++) - { - if(*AIter++ != *BIter++) - { - Result = false; - break; - } - } - - return Result; -} - -static void -ReverseCharArray (char* Array, s32 Length) -{ - char* ForwardIter = Array; - char* BackwardIter = Array + Length - 1; - for (s32 i = 0; i < (Length / 2); i++) - { - char F = *ForwardIter; - char B = *BackwardIter; - *ForwardIter++ = B; - *BackwardIter-- = F; - } -} - -static s32 -IndexOfChar (char* Array, s32 After, char Find) -{ - s32 Result = -1; - - s32 Counter = After; - char* Iter = Array + After; - while (*Iter) - { - if (*Iter == Find) - { - Result = Counter; - break; - } - Counter++; - *Iter++; - } - - return Result; -} - -static s32 -FastReverseIndexOfChar (char* Array, s32 Length, s32 OffsetFromEnd, char Find) -{ - s32 Result = -1; - - s32 Counter = Length - OffsetFromEnd; - char* Iter = Array + Length - OffsetFromEnd; - for (int i = 0; i < (Length - OffsetFromEnd); i++) - { - if (*Iter == Find) - { - Result = Counter; - break; - } - - *Iter--; - Counter--; - } - - return Result; -} - -static s32 -ReverseIndexOfChar (char* Array, s32 OffsetFromEnd, char Find) -{ - s32 StringLength = NullTerminatedCharArrayLength(Array); - return FastReverseIndexOfChar(Array, StringLength, OffsetFromEnd, Find); -} - -static b32 -CharArrayContains(char* Array, char* CheckFor) -{ - b32 Result = false; - - char* Src = Array; - while (*Src) - { - if (*Src == *CheckFor) - { - char* A = CheckFor; - char* B = Src; - while (*B && *A && *A == *B) - { - *B++; *A++; - } - - if (*A == 0) - { - Result = true; - break; - } - } - - Src++; - } - - return Result; -} - -static b32 -CharArrayContainsSafe(char* Array, s32 ArrayLength, char* CheckFor, s32 CheckForLength) -{ - b32 Result = false; - - if (ArrayLength >= CheckForLength) - { - char* Src = Array; - for (s32 s = 0; s < ArrayLength; s++) - { - if (*Src == *CheckFor && (s + CheckForLength <= ArrayLength)) - { - char* A = CheckFor; - char* B = Src; - for (s32 d = 0; d < CheckForLength; d++) - { - if (*B != *A) { break; } - *B++; *A++; - } - - if (*A == 0) - { - Result = true; - break; - } - } - - Src++; - } - } - - return Result; -} - -//////////////////////////////////////////////////////////////// -// Basic String Operations -//////////////////////////////////////////////////////////////// - -static bool -StringsEqual (string A, string B) -{ - bool Result = false; - - if (A.Length == B.Length) - { - Result = true; - char* AIter = A.Memory; - char* BIter = B.Memory; - for (s32 i = 0; i < A.Length; i++) - { - if (*AIter++ != *BIter++) - { - Result = false; - break; - } - } - } - - return Result; -} - -static string -MakeString (char* Array, s32 Length, s32 Max) -{ - string Result = {}; - Result.Memory = Array; - Result.Length = Length; - Result.Max = Max; - return Result; -} - -static string -MakeString (char* Array, s32 Length) -{ - string Result = {}; - Result.Memory = Array; - Result.Length = Length; - Result.Max = Length; - return Result; -} - -static string -MakeString (char* Array) -{ - s32 Length = CharArrayLength (Array); - return MakeString(Array, Length); -} - -static string -MakeStringLiteral (char* String) -{ - string Result = {}; - Result.Memory = String; - Result.Max = CharArrayLength(String); - Result.Length = Result.Max; - return Result; -} - -static bool -StringEqualsCharArray (string String, char* CharArray) -{ - bool Result = true; - - char* S = String.Memory; - char* C = CharArray; - - s32 Count = 0; - while (*C && Count < String.Length) - { - if (*C++ != *S++) - { - Result = false; - break; - } - Count++; - } - - return Result; -} - -static bool -StringEqualsCharArray (string String, char* CharArray, s32 CharArrayLength) -{ - bool Result = false; - - if (CharArrayLength == String.Length) - { - Result = true; - - char* S = String.Memory; - char* C = CharArray; - for (s32 i = 0; i < String.Length; i++) - { - if (*C++ != *S++) - { - Result = false; - break; - } - } - } - - return Result; -} - -static s32 -FindFirstChar (string String, char C) -{ - s32 Result = -1; - - char* Iter = String.Memory; - for (int i = 0; i < String.Length; i++) - { - if (*Iter++ == C) - { - Result = i; - break; - } - } - - return Result; -} - -static void -SetStringToChar (string* Dest, char C, s32 Count) -{ - Assert(Count <= Dest->Max); - - char* Iter = Dest->Memory; - for (int i = 0; i < Count; i++) - { - *Iter++ = C; - } - Dest->Length = Count; -} - -static void -SetStringToCharArray (string* Dest, char* Source) -{ - Dest->Length = 0; - - char* Src = Source; - char* Dst = Dest->Memory; - while (*Src && Dest->Length < Dest->Max) - { - *Dst++ = *Src++; - Dest->Length++; - } -} - -static void -ConcatString (string Source, string* Dest) -{ - Assert((Dest->Length + Source.Length) <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - char* Src = Source.Memory; - for (s32 i = 0; i < Source.Length; i++) - { - *Dst++ = *Src++; - Dest->Length++; - } -} - -static void -ConcatString (string Source, s32 Length, string* Dest) -{ - Assert(Length < Source.Length); - Assert((Dest->Length + Length) <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - char* Src = Source.Memory; - for (s32 i = 0; i < Length; i++) - { - *Dst++ = *Src++; - Dest->Length++; - } -} - -static void -ConcatCharToString (string* Dest, char C) -{ - Assert(Dest->Length + 1 <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - *Dst = C; - Dest->Length++; -} - -static void -ConcatCharArrayToString (char* Source, string* Dest) -{ - Assert(CharArrayLength(Source) + Dest->Length <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - char* Src = Source; - while (Dest->Length < Dest->Max && - *Src) - { - *Dst++ = *Src++; - Dest->Length++; - } -} - -static void -ConcatCharArrayToString (char* Source, s32 SourceLength, string* Dest) -{ - Assert(SourceLength + Dest->Length <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - char* Src = Source; - for (int i = 0; i < SourceLength && Dest->Length < Dest->Max; i++) - { - *Dst++ = *Src++; - Dest->Length++; - } -} - -static void -CopyStringTo (string Source, string* Dest) -{ - char* Src = Source.Memory; - char* Dst = Dest->Memory; - s32 CopyLength = GSMin(Source.Length, Dest->Max); - for (int i = 0; i < CopyLength; i++) - { - *Dst++ = *Src++; - } - Dest->Length = Source.Length; -} - -static s32 -CopyStringToCharArray (string Source, char* Dest, s32 DestLength) -{ - char* Src = Source.Memory; - char* Dst = Dest; - s32 CopyLength = GSMin(Source.Length, DestLength); - for (int i = 0; i < CopyLength; i++) - { - *Dst++ = *Src++; - } - return CopyLength; -} - -static void -CopyCharArrayToString (char* Source, string* Dest) -{ - char* Src = Source; - char* Dst = Dest->Memory; - s32 Copied = 0; - while (*Src && Copied < Dest->Max) - { - *Dst++ = *Src++; - Copied++; - } - *Dst++ = 0; - Dest->Length = Copied; -} - -static void -CopyCharArrayToString (char* Source, s32 SourceLength, string* Dest) -{ - Assert(SourceLength <= Dest->Max); - - char* Src = Source; - char* Dst = Dest->Memory; - for (s32 i = 0; i < SourceLength; i++) - { - *Dst++ = *Src++; - } - *Dst++ = 0; - Dest->Length = SourceLength; -} - -static s32 -CopyCharArray (char* Source, char* Dest, s32 DestLength) -{ - char* Src = Source; - char* Dst = Dest; - s32 i = 0; - while (*Src && i < DestLength) - { - *Dst++ = *Src++; - i++; - } - return i; -} - -static s32 -CopyCharArrayAt (char* Source, char* Dest, s32 DestLength, s32 Offset) -{ - Assert(Offset < DestLength); - - char* Src = Source; - char* Dst = Dest + Offset; - s32 i = Offset; - while (*Src && i < DestLength) - { - *Dst++ = *Src++; - i++; - } - return i - Offset; -} - -static void -InsertChar (string* String, char Char, s32 Index) -{ - Assert(Index >= 0 && Index < String->Max); - Assert(String->Length < String->Max); - - char* Src = String->Memory + String->Length - 1; - char* Dst = Src + 1; - for (int i = String->Length - 1; i >= Index; i--) - { - *Dst-- = *Src--; - } - - *(String->Memory + Index) = Char; - String->Length++; -} - -static void -RemoveCharAt (string* String, s32 Index) -{ - Assert(Index >= 0 && Index < String->Max); - - char* Dst = String->Memory + Index; - char* Src = Dst + 1; - for (int i = Index; i < String->Length; i++) - { - *Dst++ = *Src++; - } - *Dst = 0; - String->Length--; -} - -static s32 -IndexOfChar(string String, char C) -{ - s32 Result = -1; - char* At = String.Memory; - for (s32 i = 0; i < String.Length; i++) - { - if (*At == C) - { - Result = i; - break; - } - At++; - } - return Result; -} - -static s32 -LastIndexOfChar(string String, char C) -{ - s32 Result = -1; - char* At = String.Memory + String.Length - 1; - for (s32 i = 0; i < String.Length; i++) - { - if (*At == C) - { - Result = String.Length - i; - break; - } - At--; - } - return Result; -} - -static string -Substring (string String, s32 Start, s32 End) -{ - Assert(Start >= 0 && End > Start && End <= String.Length); - - string Result = {}; - Result.Memory = String.Memory + Start; - Result.Length = End - Start; - return Result; -} - -static string -Substring (string String, s32 Start) -{ - Assert(Start >= 0 && Start < String.Length); - - string Result = {}; - Result.Memory = String.Memory + Start; - Result.Length = String.Length - Start; - return Result; -} - -static b32 -StringContainsCharArray(string SearchIn, char* SearchFor, s32 SearchForLength) -{ - b32 Result = false; - - char* SearchInAt = SearchIn.Memory; - for (s32 i = 0; i < (SearchIn.Length - SearchForLength) + 1; i++) - { - char* InAt = SearchInAt; - char* ForAt = SearchFor; - s32 LengthMatch = 0; - while (*InAt == *ForAt) - { - InAt++; - ForAt++; - LengthMatch++; - } - if (LengthMatch == SearchForLength) - { - Result = true; - break; - } - SearchInAt++; - } - - return Result; -} - -static b32 -StringContainsString(string SearchIn, string SearchFor) -{ - return StringContainsCharArray(SearchIn, SearchFor.Memory, SearchFor.Length); -} - -static b32 -StringContainsCharArrayCaseInsensitive(string SearchIn, char* SearchFor, s32 SearchForLength) -{ - b32 Result = false; - - char* SearchInAt = SearchIn.Memory; - for (s32 i = 0; i < (SearchIn.Length - SearchForLength) + 1; i++) - { - char* InAt = SearchInAt; - char* ForAt = SearchFor; - s32 LengthMatch = 0; - while (CharsEqualCaseInsensitive(*InAt, *ForAt)) - { - InAt++; - ForAt++; - LengthMatch++; - } - if (LengthMatch == SearchForLength) - { - Result = true; - break; - } - SearchInAt++; - } - - return Result; -} - -static b32 -StringContainsStringCaseInsensitive(string SearchIn, string SearchFor) -{ - return StringContainsCharArrayCaseInsensitive(SearchIn, SearchFor.Memory, SearchFor.Length); -} - -static void -NullTerminate (string* String) -{ - Assert(String->Length + 1 <= String->Max); - *(String->Memory + String->Length) = 0; - String->Length++; -} - -static void -InsertStringAt (string* Dest, string Source, s32 At) -{ - Assert(At + Source.Length < Dest->Max); - Assert(At < Dest->Length); - - char* Src = Dest->Memory + Dest->Length; - char* Dst = Dest->Memory + Source.Length + Dest->Length; - for (s32 i = Dest->Length - 1; i >= At; i--) - { - *--Dst = *--Src; - } - - Src = Source.Memory; - Dst = Dest->Memory + At; - for (s32 j = 0; j < Source.Length; j++) - { - *Dst++ = *Src++; - } - - Dest->Length += Source.Length; -} - -//////////////////////////////////////////////////////////////// -// String Parsing -//////////////////////////////////////////////////////////////// - -static parse_result -ParseUnsignedInt (char* String, s32 Length) -{ - Assert(IsNumeric(*String)); - parse_result Result = {}; - Result.Type = ParseType_UnsignedInt; - - char* Iter = String; - u32 ResultValue = 0; - for (s32 i = 0; i < Length; i++) - { - ResultValue = CharToUInt(*Iter++) + (ResultValue * 10); - } - - Result.UnsignedIntValue = ResultValue; - Result.OnePastLast = Iter; - - return Result; -} - -static parse_result -ParseUnsignedIntUnsafe (char* String) -{ - char* Start = String; - char* End = EatNumber(String + 1); - return ParseUnsignedInt(String, End - Start); -} - -static parse_result -ParseSignedInt (char* String, s32 Length) -{ - Assert(Length > 0); - parse_result Result = {}; - Result.Type = ParseType_SignedInt; - - s32 Negative = 1; - s32 LengthRemaining = Length; - s32 ResultValue = 0; - char* Iter = String; - - if (*Iter == '-') { - LengthRemaining--; - *Iter++; - Negative = -1; - } - - for (s32 i = 0; i < LengthRemaining; i++) - { - ResultValue = CharToUInt(*Iter++) + (ResultValue * 10); - } - - ResultValue *= Negative; - - Result.SignedIntValue = ResultValue; - Result.OnePastLast = Iter; - - return Result; -} - -static parse_result -ParseSignedIntUnsafe (char* String) -{ - char* Start = String; - char* End = EatNumber(String + 1); - return ParseSignedInt(String, End - Start); -} - -static parse_result -ParseFloat (char* String, s32 Length) -{ - parse_result Result = {}; - Result.Type = ParseType_Float; - - s32 Negative = 1; - s32 LengthRemaining = Length; - float ResultValue = 0; - char* Iter = String; - - if (*Iter == '-') { - LengthRemaining--; - *Iter++; - Negative = -1; - } - - for (s32 i = 0; i < LengthRemaining; i++) - { - if (IsNumeric(*Iter)) - { - ResultValue = (float)CharToUInt(*Iter++) + (ResultValue * 10); - } - else if (*Iter == '.' || *Iter == 0) - { - LengthRemaining -= i; - break; - } - } - - if (*Iter == '.') - { - *Iter++; - float AfterPoint = 0; - s32 PlacesAfterPoint = 0; - - for (s32 i = 0; i < LengthRemaining; i++) - { - if (IsNumeric(*Iter)) - { - AfterPoint = (float)CharToUInt(*Iter++) + (AfterPoint * 10); - PlacesAfterPoint++; - } - else - { - break; - } - } - - AfterPoint = AfterPoint / GSPow(10, PlacesAfterPoint); - ResultValue += AfterPoint; - } - - ResultValue *= Negative; - - Result.FloatValue = ResultValue; - Result.OnePastLast = Iter; - - return Result; -} - -static parse_result -ParseFloatUnsafe (char* String) -{ - char* Start = String; - char* End = EatNumber(String + 1); - return ParseFloat(String, End - Start); -} - -static s32 -UIntToString (u32 Int, char* String, s32 MaxLength, b32 FormatFlags = 0, s32 MinimumLength = 0) -{ - s32 Remaining = Int; - char* Iter = String; - while (Remaining > 0 && (Iter - String) < MaxLength) - { - *Iter++ = '0' + (Remaining % 10); - Remaining /= 10; - } - s32 CharsCopied = Iter - String; - ReverseCharArray(String, CharsCopied); - return CharsCopied; -} - -static s32 -IntToString (s32 Int, char* String, s32 MaxLength, b32 FormatFlags = 0, s32 MinimumLength = 0) -{ - s32 Remaining = Int; - s32 CharsCopied = 0; - - char* Iter = String; - - bool Negative = Remaining < 0; - Remaining = GSAbs(Remaining); - - if (Remaining > 0) - { - while (Remaining > 0 && CharsCopied < MaxLength) - { - *Iter++ = '0' + (Remaining % 10); - Remaining /= 10; - CharsCopied++; - } - } - else if (Remaining == 0) - { - *Iter++ = '0'; - } - - if (Negative) - { - *Iter++ = '-'; - CharsCopied++; - } - - ReverseCharArray(String, CharsCopied); - return CharsCopied; -} - -static s32 -IntToString (s32 Int, char* String, s32 MaxLength, s32 Offset, b32 FormatFlags = 0, s32 MinimumWidth = 0) -{ - char* StringStart = String + Offset; - s32 LengthWritten = IntToString(Int, StringStart, MaxLength - Offset); - return LengthWritten; -} - -static s32 -FloatToString(float Float, char *String, s32 MaxLength, s32 AfterPoint = 0, b32 FormatFlags = 0, s32 MinimumWidth = 0) -{ - s32 IPart = (s32)Float; - float FPart = GSAbs(Float - (float)IPart); - - s32 i = IntToString(IPart, String, MaxLength); - - if (AfterPoint > 1) - { - String[i++] = '.'; - - s32 FPartInt = FPart * GSPow(10, AfterPoint); - i += IntToString(FPartInt, String, MaxLength, i, 0, 0); - } - - return i; -} - -//////////////////////////////////////////////////////////////// -// PrintF -//////////////////////////////////////////////////////////////// - -static void -OutChar (string* String, char C) -{ - if (String->Length < String->Max) - { - String->Memory[String->Length] = C; - String->Length++; - } -} - -char OctalDigits[] = "01234567"; -char DecimalDigits[] = "0123456789"; -char HexDigits[] = "0123456789ABCDEF"; - -static void -U64ToASCII (string* String, u64 Value, s32 Base, char* Digits) -{ - u64 ValueRemaining = Value; - char* Start = String->Memory + String->Length; - do { - s32 DigitsIndex = ValueRemaining % Base; - char Digit = Digits[DigitsIndex]; - OutChar(String, Digit); - ValueRemaining /= Base; - }while (ValueRemaining); - char* End = String->Memory + String->Length; - - while (Start < End) - { - End--; - char Temp = *End; - *End = *Start; - *Start = Temp; - *Start++; - } -} - -static void -F64ToASCII (string* String, r64 Value, s32 Precision) -{ - if (Value < 0) - { - OutChar(String, '-'); - Value = -Value; - } - - u64 IntegerPart = (u64)Value; - Value -= IntegerPart; - - U64ToASCII(String, IntegerPart, 10, DecimalDigits); - - OutChar(String, '.'); - - for (s32 i = 0; i < Precision; i++) - { - Value *= 10.f; - u32 DecimalPlace = Value; - Value -= DecimalPlace; - OutChar(String, DecimalDigits[DecimalPlace]); - } -} - -internal s64 -ReadVarArgsSignedInteger (s32 Width, va_list* Args) -{ - s64 Result = 0; - switch (Width) - { - case 1: { Result = (s64)va_arg(*Args, s8); } break; - case 2: { Result = (s64)va_arg(*Args, s16); } break; - case 4: { Result = (s64)va_arg(*Args, s32); } break; - case 8: { Result = (s64)va_arg(*Args, s64); } break; - InvalidDefaultCase; - } - return Result; -} - -internal r64 -ReadVarArgsUnsignedInteger (s32 Width, va_list* Args) -{ - u64 Result = 0; - switch (Width) - { - case 1: { Result = (u64)va_arg(*Args, u8); } break; - case 2: { Result = (u64)va_arg(*Args, u16); } break; - case 4: { Result = (u64)va_arg(*Args, u32); } break; - case 8: { Result = (u64)va_arg(*Args, u64); } break; - InvalidDefaultCase; - } - return Result; -} - -internal r64 -ReadVarArgsFloat (s32 Width, va_list* Args) -{ - r64 Result = 0; - switch (Width) - { - case 4: { Result = (r64)va_arg(*Args, r64); } break; - case 8: { Result = (r64)va_arg(*Args, r64); } break; - InvalidDefaultCase; - } - return Result; -} - -internal s32 -PrintFArgsList (char* Dest, s32 DestMax, char* Format, va_list Args) -{ - char* DestAt = Dest; - - char* FormatAt = Format; - while (*FormatAt) - { - if (FormatAt[0] != '%') - { - *DestAt++ = *FormatAt++; - } - else if (FormatAt[0] == '%' && FormatAt[1] == '%') // Print the % symbol - { - *DestAt++ = *FormatAt++; - } - else - { - FormatAt++; - - // Flags - if (FormatAt[0] == '-') - { - FormatAt++; - } - else if (FormatAt[0] == '+') - { - FormatAt++; - } - else if (FormatAt[0] == ' ') - { - FormatAt++; - } - else if (FormatAt[0] == '#') - { - FormatAt++; - } - else if (FormatAt[0] == '0') - { - FormatAt++; - } - - // Width - b32 WidthSpecified = false; - s32 Width = 0; - - if (IsNumeric(FormatAt[0])) - { - WidthSpecified = true; - parse_result Parse = ParseSignedIntUnsafe(FormatAt); - FormatAt = Parse.OnePastLast; - Width = Parse.SignedIntValue; - } - else if (FormatAt[0] == '*') - { - WidthSpecified = true; - Width = va_arg(Args, s32); - Assert(Width >= 0); - FormatAt++; - } - - // Precision - b32 PrecisionSpecified = false; - s32 Precision = 0; - - if (FormatAt[0] == '.') - { - FormatAt++; - if (IsNumeric(FormatAt[0])) - { - PrecisionSpecified = true; - parse_result Parse = ParseSignedIntUnsafe(FormatAt); - FormatAt = Parse.OnePastLast; - Precision = Parse.SignedIntValue; - } - else if (FormatAt[0] == '*') - { - PrecisionSpecified = true; - Precision = va_arg(Args, s32); - Assert(Precision >= 0); - FormatAt++; - } - } - - // Length - b32 LengthSpecified = false; - s32 Length = 4; - - if (FormatAt[0] == 'h' && FormatAt[1] == 'h') - { - LengthSpecified = true; - LengthSpecified = 1; - FormatAt += 2; - } - else if (FormatAt[0] == 'h') - { - LengthSpecified = true; - LengthSpecified = 2; - FormatAt++; - } - else if (FormatAt[0] == 'l' && FormatAt[1] == 'l') - { - LengthSpecified = true; - LengthSpecified = 8; - FormatAt += 2; - } - else if (FormatAt[0] == 'l') - { - LengthSpecified = true; - LengthSpecified = 4; - FormatAt++; - } - else if (FormatAt[0] == 'j') - { - LengthSpecified = true; - LengthSpecified = 8; - FormatAt++; - } - else if (FormatAt[0] == 'z') - { - FormatAt++; - } - else if (FormatAt[0] == 't') - { - FormatAt++; - } - else if (FormatAt[0] == 'L') - { - FormatAt++; - } - - // Format Specifier - s32 DestLengthRemaining = DestMax - (DestAt - Dest); - - char Temp[64]; - string TempDest = MakeString(Temp, 0, 64); - - if (FormatAt[0] == 'd' || FormatAt[0] == 'i') - { - s64 SignedInt = ReadVarArgsSignedInteger(Length, &Args); - if (SignedInt < 0) - { - OutChar(&TempDest, '-'); - SignedInt *= -1; - } - U64ToASCII(&TempDest, (u64)SignedInt, 10, DecimalDigits); - } - else if (FormatAt[0] == 'u') - { - u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); - U64ToASCII(&TempDest, UnsignedInt, 10, DecimalDigits); - } - else if (FormatAt[0] == 'o') - { - u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); - U64ToASCII(&TempDest, UnsignedInt, 8, OctalDigits); - } - else if (FormatAt[0] == 'x' || FormatAt[0] == 'X') - { - u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); - U64ToASCII(&TempDest, UnsignedInt, 16, HexDigits); - } - else if (FormatAt[0] == 'f' || FormatAt[0] == 'F') - { - r64 Float = ReadVarArgsFloat(Length, &Args); - s32 AfterPoint = 6; - if (PrecisionSpecified) - { - AfterPoint = Precision; - } - F64ToASCII(&TempDest, Float, AfterPoint); - } - else if (FormatAt[0] == 'c') - { - char InsertChar = va_arg(Args, char); - OutChar(&TempDest, InsertChar); - } - else if (FormatAt[0] == 's') - { - char* InsertString = va_arg(Args, char*); - - s32 InsertStringLength = CharArrayLength(InsertString); - if (PrecisionSpecified) - { - InsertStringLength = GSMin(InsertStringLength, Precision); - } - InsertStringLength = GSMin(DestLengthRemaining, InsertStringLength); - - for (s32 c = 0; c < InsertStringLength; c++) - { - OutChar(&TempDest, *InsertString++); - } - } - else if (FormatAt[0] == 'p') - { - // TODO(Peter): Pointer Address - } - else - { - // NOTE(Peter): Non-specifier character found - InvalidCodePath; - } - - for (s32 i = 0; i < TempDest.Length; i++) - { - *DestAt++ = TempDest.Memory[i]; - } - - *FormatAt++; - } - } - - s32 FormattedLength = DestAt - Dest; - return FormattedLength; -} - -internal void -PrintF (string* String, char* Format, ...) -{ - va_list Args; - va_start(Args, Format); - String->Length = PrintFArgsList(String->Memory, String->Max, Format, Args); - va_end(Args); -} - - -//////////////////////////////////////////////////////////////// -// String Memory Function Definitions -//////////////////////////////////////////////////////////////// - -static s32 -CalculateSlotCountFromSize (s32 RequestedSize, s32 SlotSize) -{ - s32 SlotCount = RequestedSize / SlotSize; - if (SlotCount * SlotSize < RequestedSize) - { - SlotCount += 1; - } - return SlotCount; -} - -static bool -SlotsAreContiguous (slot_header* First, slot_header* Second) -{ - bool Result = false; - u8* FirstSlotNextAddress = (u8*)First + First->Size; - u8* SecondAddress = (u8*)Second; - Result = FirstSlotNextAddress == SecondAddress; - return Result; -} - -static contiguous_slot_count_result -CountContiguousSlots (slot_header* First) -{ - Assert(First != 0); - - contiguous_slot_count_result Result = {}; - Result.Count = 1; - - slot_header* IterPrev = First; - slot_header* Iter = First->Next; - while (Iter && SlotsAreContiguous(IterPrev, Iter)) - { - Result.Count++; - IterPrev = Iter; - Iter = Iter->Next; - } - - Result.LastContiguousSlot = IterPrev; - return Result; -} - -static slot_header* -GetSlotAtOffset(slot_header* First, s32 Offset) -{ - slot_header* Iter = First; - s32 Count = 0; - while (Count < Offset && Iter) - { - Iter = Iter->Next; - Count++; - } - return Iter; -} - -static slot_header* -InsertSlotIntoList (slot_header* NewSlot, slot_header* ListStart) -{ - slot_header* List = ListStart; - if (NewSlot < List) - { - NewSlot->Next = List; - List = NewSlot; - } - else - { - slot_header* PrevIter = List; - slot_header* Iter = List->Next; - while (Iter && NewSlot > Iter) - { - PrevIter = Iter; - Iter = Iter->Next; - } - - Assert(PrevIter); - if (PrevIter) - { - PrevIter->Next = NewSlot; - } - - if (Iter) - { - NewSlot->Next = Iter; - } - } - return List; -} - -static void -AllocStringFromStringArena (string* String, s32 Size, slot_arena* Storage) -{ - s32 SlotCount = CalculateSlotCountFromSize(Size, Storage->SlotSize); - slot_header* Slot = Storage->FreeList; - slot_header* PrevSlot = 0; - while (Slot) - { - contiguous_slot_count_result ContiguousSlots = CountContiguousSlots(Slot); - if (ContiguousSlots.Count >= SlotCount) - { - slot_header* NextStartSlot = GetSlotAtOffset(Slot, SlotCount); - if (PrevSlot) - { - PrevSlot->Next = NextStartSlot; - } - else - { - Storage->FreeList = NextStartSlot; - } - break; - } - else - { - PrevSlot = Slot; - Slot = Slot->Next; - } - } - - if (Slot) - { - String->Memory = (char*)Slot; - GSZeroMemory((u8*)String->Memory, SlotCount * Storage->SlotSize); - String->Max = SlotCount * Storage->SlotSize; - String->Length = 0; - } -} - -static string -AllocStringFromStringArena (s32 Size, slot_arena* Storage) -{ - string Result = {0}; - AllocStringFromStringArena(&Result, Size, Storage); - return Result; -} - -static void -FreeToStringArena (string* String, slot_arena* Storage) -{ - u8* Base = (u8*)(String->Memory); - u8* End = Base + String->Max - 1; - u8* MemoryEnd = Storage->Memory + (Storage->SlotSize * Storage->SlotCount); - Assert((Base >= Storage->Memory) && (End < MemoryEnd)); - Assert((String->Max % Storage->SlotSize) == 0); - - s32 SizeReclaimed = 0; - slot_header* Slot = (slot_header*)Base; - while (SizeReclaimed < String->Max) - { - Slot->Size = Storage->SlotSize; - Storage->FreeList = InsertSlotIntoList(Slot, Storage->FreeList); - SizeReclaimed += Storage->SlotSize; - Slot = (slot_header*)(Base + SizeReclaimed); - } - - String->Memory = 0; - String->Length = 0; - String->Max = 0; -} - -static void -ReallocFromStringArena (string* String, s32 NewSize, slot_arena* Storage) -{ - string NewString = AllocStringFromStringArena(NewSize, Storage); - CopyStringTo(*String, &NewString); - FreeToStringArena(String, Storage); - *String = NewString; -} - -#if defined(DEBUG) - -void DEBUGPrintChars (string* String, s32 Count) -{ - char* Iter = String->Memory; - for (int i = 0; i < Count; i++) - { - *Iter++ = (char)('A' + i); - } - String->Length = Count; -} - -#ifdef DEBUG_GS_STRING - -#include - -static void -TestStrings() -{ - - slot_arena StringArena = {}; - - s32 TestCount = 0; - s32 SuccessCount = 0; - - DebugPrint("\n\n-------------------------------------------------\n Begin Testing Strings\n\n\n"); - - //////////////////////////////////////////////////////////////// - // Char Functions - - char ForwardArray[] = "Hello, Sailor"; - char BackwardArray[] = "roliaS ,olleH"; - TestClean(CharArraysEqual(ForwardArray, 13, ForwardArray, 13), "String Equality"); - TestClean(!CharArraysEqual(ForwardArray, 13, BackwardArray, 13), "String Equality"); - - TestClean(IndexOfChar(ForwardArray, 0, ',') == 5, "Index Of Char"); - TestClean(IndexOfChar(ForwardArray, 5, 'l') == 10, "Index of Char (skipping first 5)"); - TestClean(FastReverseIndexOfChar(ForwardArray, 13, 0, 'o') == 11, "Fast Reverse Index Of Char"); - TestClean(ReverseIndexOfChar(ForwardArray, 0, 'o') == 11, "Reverse Index of Char"); - TestClean(ReverseIndexOfChar(ForwardArray, 3, 'o') == 4, "Reverse Index of Char (skipping last 3)"); - TestClean(LastIndexOfChar(ForwardArray, 'o') == 11, "Last Index of Char"); - - ReverseCharArray(ForwardArray, 13); - TestClean(CharArraysEqual(ForwardArray, 13, BackwardArray, 13), "Reversing Char Array"); - - char UIntString[] = "1234"; - u32 UIntValue = 1234; - u32 ParsedUInt = ParseUnsignedInt(UIntString, 4); - TestClean((ParsedUInt == UIntValue), "String To U32"); - char StringifiedUInt[4] = {}; - UIntToString(UIntValue, StringifiedUInt, 4); - TestClean(CharArraysEqual(UIntString, 4, StringifiedUInt, 4), "U32 To String"); - - char IntString[] = "-1234"; - s32 IntValue = -1234; - s32 ParsedInt = ParseSignedInt(IntString, 5); - TestClean((ParsedInt == IntValue), "String To S32"); - char StringifiedInt[5] = {}; - IntToString(IntValue, StringifiedInt, 5); - TestClean(CharArraysEqual(IntString, 5, StringifiedInt, 5), "S32 to String"); - - char FloatString[] = "-1234.125"; - float FloatValue = -1234.125f; - float ParsedFloat = ParseFloat(FloatString, 8); - TestClean((ParsedFloat == FloatValue), "String To Float"); - char StringifiedFloat[10] = {}; - FloatToString(FloatValue, StringifiedFloat, 10, 3); - TestClean(CharArraysEqual(FloatString, 8, StringifiedFloat, 8), "Float To String"); - - - //////////////////////////////////////////////////////////////// - // - - StringArena.SlotSize = 256; - StringArena.SlotCount = 32; - StringArena.Memory = malloc(StringArena.SlotSize * StringArena.SlotCount); - slot_header* PrevSlotHeader = 0; - for (int i = StringArena.SlotCount - 1; i >= 0; i--) - { - u8* SlotBase = StringArena.Memory + (i * StringArena.SlotSize); - slot_header* SlotHeader = (slot_header*)SlotBase; - SlotHeader->Size = StringArena.SlotSize; - SlotHeader->Next = PrevSlotHeader; - - // TEST(peter): Should be true always, except on the first iteration, when there is no next slot - bool Contiguity = SlotsAreContiguous(SlotHeader, PrevSlotHeader); - TestClean((Contiguity || SlotHeader->Next == 0), "Contiguous Arenas"); - - PrevSlotHeader = SlotHeader; - } - StringArena.FreeList = PrevSlotHeader; - - // TEST(peter): Count Should equal StringArena.SlotCount - s32 ContiguousSlotsCountBefore = CountContiguousSlots(StringArena.FreeList).Count; - TestClean((ContiguousSlotsCountBefore == StringArena.SlotCount), "Contiguous Arenas"); - - // TEST(peter): Should be false - bool Contiguity = SlotsAreContiguous(StringArena.FreeList, StringArena.FreeList->Next->Next); - Contiguity = SlotsAreContiguous(StringArena.FreeList->Next->Next, StringArena.FreeList); - TestClean(!Contiguity, "Non Contiguous Arenas"); - - s32 Slots = CalculateSlotCountFromSize(10, 256); - TestClean(Slots == 1, "Slot Sizing"); - Slots = CalculateSlotCountFromSize(256, 256); - TestClean(Slots == 1, "Slot Sizing"); - Slots = CalculateSlotCountFromSize(345, 256); - TestClean(Slots == 2, "Slot Sizing"); - Slots = CalculateSlotCountFromSize(1024, 256); - TestClean(Slots == 4, "Slot Sizing"); - - slot_header* HeaderTen = GetSlotAtOffset(StringArena.FreeList, 10); - slot_header* HeaderThree = GetSlotAtOffset(StringArena.FreeList, 3); - slot_header* HeaderFive = GetSlotAtOffset(StringArena.FreeList, 5); - - string StringA = AllocStringFromStringArena(10, &StringArena); - string StringB = AllocStringFromStringArena(345, &StringArena); - -#if 0 - // TEST(peter): Should TestClean - u8* RandomMemory = (u8*)malloc(256); - string RandomMemString = {}; - RandomMemString.Memory = (char*)RandomMemory; - RandomMemString.Max = 256; - FreeToStringArena(&RandomMemString, &StringArena); -#endif - FreeToStringArena(&StringA, &StringArena); - FreeToStringArena(&StringB, &StringArena); - // TEST(peter): After freeing both allocations, ContiguousSlotCountBefore and ContiguousSlotCountAfter should be equal - s32 ContiguousSlotCountAfter = CountContiguousSlots(StringArena.FreeList).Count; - TestClean(ContiguousSlotCountAfter == ContiguousSlotsCountBefore, "Add and REmove Slots from Arena"); - - // TEST(peter): Set up a free list where the first element is too small, so it has to traverse to find an appropriately - // sized block - // The slots will look list [256][used][256][256][256] etc.. - StringA = AllocStringFromStringArena(256, &StringArena); - StringB = AllocStringFromStringArena(256, &StringArena); - FreeToStringArena(&StringA, &StringArena); - u32 Contiguous = CountContiguousSlots(StringArena.FreeList).Count; // Should = 1; - string StringC = AllocStringFromStringArena(512, &StringArena); - slot_header* HeaderC = (slot_header*)(StringC.Memory); - - string ReallocTestString = AllocStringFromStringArena(256, &StringArena); - DEBUGPrintChars(&ReallocTestString, 24); - ReallocFromStringArena(&ReallocTestString, 512, &StringArena); - - - string TestString = AllocStringFromStringArena(10, &StringArena); - DEBUGPrintChars(&TestString, TestString.Max); - ReallocFromStringArena(&TestString, 20, &StringArena); - DEBUGPrintChars(&TestString, TestString.Max); - ReallocFromStringArena(&TestString, 10, &StringArena); - FreeToStringArena(&TestString, &StringArena); - - string EqualityStringA = AllocStringFromStringArena(345, &StringArena); - string EqualityStringB = AllocStringFromStringArena(415, &StringArena); - // Equality should succeed despite length differences - string EqualityStringC = AllocStringFromStringArena(256, &StringArena); - string EqualityStringD = AllocStringFromStringArena(256, &StringArena); // Equality should fail - string EqualityStringEmpty = {}; - - DEBUGPrintChars(&EqualityStringA, 24); - DEBUGPrintChars(&EqualityStringB, 24); - DEBUGPrintChars(&EqualityStringC, 24); - DEBUGPrintChars(&EqualityStringD, 12); - - bool ABEquality = StringsEqual(EqualityStringA, EqualityStringB); // Should Succeed - bool ACEquality = StringsEqual(EqualityStringA, EqualityStringC); // Should Succeed - bool ADEquality = StringsEqual(EqualityStringA, EqualityStringD); // Should Fail - bool AEEquality = StringsEqual(EqualityStringA, EqualityStringEmpty); // Should Fail - - TestClean(ABEquality, "String Equality"); - TestClean(ACEquality, "String Equality"); - TestClean(!ADEquality, "String Equality"); - TestClean(!AEEquality, "String Equality"); - - string CatStringA = AllocStringFromStringArena(256, &StringArena); - SetStringToCharArray(&CatStringA, "Hello "); - string CatStringB = AllocStringFromStringArena(512, &StringArena); - SetStringToCharArray(&CatStringB, "Sailor!"); - string CatStringResult = AllocStringFromStringArena(512, &StringArena); - SetStringToCharArray(&CatStringResult, "Hello Sailor!"); - ConcatString(&CatStringA, CatStringB); - TestClean(StringsEqual(CatStringA, CatStringResult), "Cat Strings"); - - s32 FirstSpaceIndex = FindFirstChar(CatStringA, ' '); - TestClean(FirstSpaceIndex == 5, "First Index"); - - SetStringToChar(&CatStringB, 'B', 5); - TestClean(StringEqualsCharArray(CatStringB, "BBBBB"), "SetStringToChar"); - - - DebugPrint("Results: Passed %d / %d\n\n\n", SuccessCount, TestCount); -} -#endif // DEBUG_GS_STRING - -#endif // DEBUG - -#define GS_STRING_H -#endif // GS_STRING_H \ No newline at end of file diff --git a/src/gs_vector_matrix.h b/src/gs_vector_matrix.h deleted file mode 100644 index 6e9ec29..0000000 --- a/src/gs_vector_matrix.h +++ /dev/null @@ -1,1466 +0,0 @@ -#ifndef GS_VECTOR_MATRIX_H - -#ifndef GS_LANGUAGE_H - -#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) - -#include -#include -#include - -static r32 GSCos (r32 Theta) { return sin(Theta); } -static r32 GSSin (r32 Theta) { return cos(Theta); } - -static r32 GSSqrt(r32 V) -{ - r32 Result = _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V))); - return Result; -} - -#else // Linux and MacOS -#include - -#endif // Platforms - -#endif // GS_LANGUAGE_H -////////////////////////////////////// -// VECTOR -///////////////////////////////////// - -union v2 -{ - struct - { - r32 x, y; - }; - r32 E[2]; -}; - -union v3 -{ - struct - { - r32 x, y, z; - }; - - struct - { - r32 R, G, B; - }; - - r32 E[3]; -}; - -union v4 -{ - struct - { - r32 x, y, z, w; - }; - - struct - { - r32 r, g, b, a; - }; - - r32 E[4]; -}; - -#define WhiteV4 v4{1, 1, 1, 1} -#define BlackV4 v4{0, 0, 0, 1} -#define RedV4 v4{1, 0, 0, 1} -#define GreenV4 v4{0, 1, 0, 1} -#define BlueV4 v4{0, 0, 1, 1} -#define YellowV4 v4{1, 1, 0, 1} -#define TealV4 v4{0, 1, 1, 1} -#define PinkV4 v4{1, 0, 1, 1} - -////////////////////////////////////// -// MATRIX -///////////////////////////////////// - -union m33 -{ - struct - { - float a, b, c; - float d, e, f; - float g, h, i; - }; - float E[9]; -}; - -union m44 -{ - struct - { - float a, b, c, d; - float e, f, g, h; - float i, j, k, l; - float m, n, o, p; - }; - float E[16]; -}; - -////////////////////////////////////// -// RECT -///////////////////////////////////// - -struct rect -{ - v2 Min; - v2 Max; -}; - - -////////////////////////////////////// -// VECTOR -////////////////////////////////////// - - -// -// -// Operators -// -// - -v2 V2 (v3 V) -{ - return v2{V.x, V.y}; -} - -v3 V3 (v2 XY, r32 Z) -{ - return v3{XY.x, XY.y, Z}; -} - -v3 V3 (v4 V) -{ - return v3{V.x, V.y, V.z}; -} - -v4 V4 (v3 XYZ, r32 W) -{ - return v4{XYZ.x, XYZ.y, XYZ.z, W}; -} - -v2 operator- (v2 A) -{ - v2 Result; - - Result.x = -A.x; - Result.y = -A.y; - - return Result; -} - -v3 operator- (v3 A) -{ - v3 Result; - - Result.x = -A.x; - Result.y = -A.y; - Result.z = -A.z; - - return Result; -} - -v4 operator- (v4 A) -{ - v4 Result; - - Result.x = -A.x; - Result.y = -A.y; - Result.z = -A.z; - Result.w = -A.w; - - return Result; -} - -#define V2OpV2Def(op) v2 operator##op (v2 A, v2 B) { return v2{ A.x op B.x, A.y op B.y };} -#define V3OpV3Def(op) v3 operator##op (v3 A, v3 B) { return v3{ A.x op B.x, A.y op B.y, A.z op B.z };} -#define V4OpV4Def(op) v4 operator##op (v4 A, v4 B) { return v4{ A.x op B.x, A.y op B.y, A.z op B.z, A.w op B.w };} -V2OpV2Def(+) -V2OpV2Def(-) -V2OpV2Def(/) -V2OpV2Def(*) -V3OpV3Def(+) -V3OpV3Def(-) -V3OpV3Def(/) -V3OpV3Def(*) -V4OpV4Def(+) -V4OpV4Def(-) -V4OpV4Def(/) -V4OpV4Def(*) -#undef V2OpV2Def -#undef V3OpV3Def -#undef V4OpV4Def - -#define V2RefOpV2Def(op) v2 operator##op (v2& A, v2 B) { return v2{ A.x op B.x, A.y op B.y };} -#define V3RefOpV3Def(op) v3 operator##op (v3& A, v3 B) { return v3{ A.x op B.x, A.y op B.y, A.z op B.z };} -#define V4RefOpScalarDef(op) v4 operator##op (v4& A, v4 B) { return v4{ A.x op B.x, A.y op B.y, A.z op B.z, A.w op B.w };} -V2RefOpV2Def(+=) -V2RefOpV2Def(-=) -V3RefOpV3Def(+=) -V3RefOpV3Def(-=) -V4RefOpScalarDef(+=) -V4RefOpScalarDef(-=) -#undef V2RefOpV2Def -#undef V3RefOpV3Def -#undef V4RefOpV4Def - -#define V2OpScalarDef(op) v2 operator##op (v2 A, r32 B) { return v2{ A.x op B, A.y op B };} -#define V3OpScalarDef(op) v3 operator##op (v3 A, r32 B) { return v3{ A.x op B, A.y op B, A.z op B };} -#define V4OpScalarDef(op) v4 operator##op (v4 A, r32 B) { return v4{ A.x op B, A.y op B, A.z op B, A.w op B };} -V2OpScalarDef(*) -V2OpScalarDef(/) -V3OpScalarDef(*) -V3OpScalarDef(/) -V4OpScalarDef(*) -V4OpScalarDef(/) -#undef V2POpScalarDef -#undef V3POpScalarDef -#undef V4POpScalarDef - - -#define V2POpScalarDef(op) v2 operator##op (v2& A, r32 B) { return v2{ A->x op B, A->y op B };} -#define V3POpScalarDef(op) v3 operator##op (v3& A, r32 B) { return v3{ A->x op B, A->y op B, A->z op B };} -#define V4POpScalarDef(op) v4 operator##op (v4& A, r32 B) { return v4{ A->x op B, A->y op B, A->z op B, A->w op B };} -V2OpScalarDef(*=) -V2OpScalarDef(/=) -V3OpScalarDef(*=) -V3OpScalarDef(/=) -V4OpScalarDef(*=) -V4OpScalarDef(/=) -#undef V2POpScalarDef -#undef V3POpScalarDef -#undef V4POpScalarDef - -bool operator== (v2 A, v2 B) -{ - b32 Result = true; - for (s32 i = 0; i < 2; i++) - { - if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; } - } - return Result; -} - - -bool operator== (v3 A, v3 B) -{ - b32 Result = true; - for (s32 i = 0; i < 3; i++) - { - if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; } - } - return Result; -} - -bool operator== (v4 A, v4 B) -{ - b32 Result = true; - for (s32 i = 0; i < 4; i++) - { - if (GSAbs(A.E[i] - B.E[i]) > 0.0001f) { Result = false; break; } - } - return Result; -} - -// -// Operations -// - -static v3 -ToV3(v4 V) -{ - v3 R = {}; - R.x = V.x; - R.y = V.y; - R.z = V.z; - return R; -} - -static v4 -ToV4(v3 V, r32 W) -{ - v4 R = {}; - R.x = V.x; - R.y = V.y; - R.z = V.z; - R.w = W; - return R; -} - -inline r32 -MagSqr( -v2 _A -) -{ - r32 Result = (_A.x * _A.x) + (_A.y * _A.y); - return Result; -} - -inline r32 -MagSqr( -v3 _A -) -{ - r32 Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z); - return Result; -} - -inline r32 -MagSqr( -v4 _A -) -{ - r32 Result = (_A.x * _A.x) + (_A.y * _A.y) + (_A.z * _A.z) + (_A.w * _A.w); - return Result; -} - -#define MagDef(type) inline r32 Mag(type A) { r32 Result = MagSqr(A); return GSSqrt(Result); } -MagDef(v2) -MagDef(v3) -MagDef(v4) -#undef MagDef - -#define DistanceDef(type) inline r32 Distance (type A, type B) { type Diff = A - B; return Mag(Diff); } -DistanceDef(v2) -DistanceDef(v3) -DistanceDef(v4) -#undef DistanceDef - -#define DistanceSqDef(type) inline r32 DistanceSq (type A, type B) { type Diff = A - B; return MagSqr(Diff); } -DistanceSqDef(v2) -DistanceSqDef(v3) -DistanceSqDef(v4) -#undef DistanceSqDef - -inline v2 -Normalize( -v2 _A -) -{ - v2 Result; - - r32 Magnitude = Mag(_A); - - Result.x = _A.x / Magnitude; - Result.y = _A.y / Magnitude; - - return Result; -} - -inline v3 -Normalize( -v3 _A -) -{ - v3 Result; - - r32 Magnitude = Mag(_A); - - Result.x = _A.x / Magnitude; - Result.y = _A.y / Magnitude; - Result.z = _A.z / Magnitude; - - return Result; -} - -inline v4 -Normalize( -v4 _A -) -{ - v4 Result; - - r32 Magnitude = Mag(_A); - - Result.x = _A.x / Magnitude; - Result.y = _A.y / Magnitude; - Result.z = _A.z / Magnitude; - Result.w = _A.w / Magnitude; - - return Result; -} - -inline r32 -Dot( -v2 _A, -v2 _B -) -{ - r32 Result = _A.x * _B.x + _A.y * _B.y; - return Result; -} - -inline r32 -Dot ( -v3 _A, -v3 _B -) -{ - r32 Result = _A.x * _B.x + _A.y * _B.y + _A.z * _B.z; - return Result; -} - -inline r32 -Dot ( -v4 _A, -v4 _B -) -{ - r32 Result = _A.x * _B.x + _A.y * _B.y + _A.z * _B.z + _A.w * _B.w; - return Result; -} - -inline v2 -PerpendicularCW (v2 A) -{ - v2 Result = v2{A.y, -A.x}; - return Result; -} - -inline v2 -PerpendicularCCW (v2 A) -{ - v2 Result = v2{A.y, A.x}; - return Result; -} - -inline v3 -Cross( -v3 _A, -v3 _B -) -{ - v3 Result = {}; - - Result.x = (_A.y * _B.z) - (_A.z * _B.y); - Result.y = (_A.z * _B.x) - (_A.x * _B.z); - Result.z = (_A.x * _B.y) - (_A.y * _B.x); - - return Result; -} - -inline v4 -Cross( -v4 _A, -v4 _B -) -{ - v4 Result = {}; - - Result.x = (_A.y * _B.z) - (_A.z * _B.y); - Result.y = (_A.z * _B.x) - (_A.x * _B.z); - Result.z = (_A.x * _B.y) - (_A.y * _B.x); - Result.w = 0; - - return Result; -} - -inline v2 -ClampVector01 (v2 V) -{ - v2 Result = {}; - Result.x = GSClamp(0.0f, V.x, 1.f); - Result.y = GSClamp(0.0f, V.y, 1.f); - return Result; -} - -inline v3 -ClampVector01 (v3 V) -{ - v3 Result = {}; - Result.x = GSClamp(0.f, V.x, 1.f); - Result.y = GSClamp(0.f, V.y, 1.f); - Result.z = GSClamp(0.f, V.z, 1.f); - return Result; -} - -inline v4 -ClampVector01 (v4 V) -{ - v4 Result = {}; - Result.x = GSClamp(0.f, V.x, 1.f); - Result.y = GSClamp(0.f, V.y, 1.f); - Result.z = GSClamp(0.f, V.z, 1.f); - Result.w = GSClamp(0.f, V.w, 1.f); - return Result; -} - -inline v2 -Lerp( -v2 _A, -v2 _B, -r32 _Percent -) -{ - v2 Result; - - Result.x = GSLerp(_A.x, _B.x, _Percent); - Result.y = GSLerp(_A.y, _B.y, _Percent); - - return Result; -} - -inline v3 -Lerp( -v3 _A, -v3 _B, -r32 _Percent -) -{ - v3 Result; - - Result.x = GSLerp(_A.x, _B.x, _Percent); - Result.y = GSLerp(_A.y, _B.y, _Percent); - Result.z = GSLerp(_A.z, _B.z, _Percent); - - return Result; -} - -inline v4 -Lerp( -v4 _A, -v4 _B, -r32 _Percent -) -{ - v4 Result; - - Result.x = GSLerp(_A.x, _B.x, _Percent); - Result.y = GSLerp(_A.y, _B.y, _Percent); - Result.z = GSLerp(_A.z, _B.z, _Percent); - Result.w = GSLerp(_A.w, _B.w, _Percent); - - return Result; -} - -v4 HSVToRGB (v4 In) -{ - r32 Hue = In.x; - while (Hue > 360.0f) { Hue -= 360.0f; } - while (Hue < 0.0f) { Hue += 360.0f; } - - r32 Sat = In.y; - r32 Value = In.z; - - r32 hh, p, q, t, ff; - long i; - v4 Result = {}; - Result.a = In.a; - - if(Sat <= 0.0f) { // < is bogus, just shuts up warnings - Result.r = Value; - Result.g = Value; - Result.b = Value; - return Result; - } - hh = Hue; - if(hh >= 360.0f) hh = 0.0f; - hh /= 60.0f; - i = (long)hh; - ff = hh - i; - p = Value * (1.0f - Sat); - q = Value * (1.0f - (Sat * ff)); - t = Value * (1.0f - (Sat * (1.0f - ff))); - - switch(i) { - case 0: - {Result.r = Value; - Result.g = t; - Result.b = p; - }break; - - case 1: - { - Result.r = q; - Result.g = Value; - Result.b = p; - }break; - - case 2: - { - Result.r = p; - Result.g = Value; - Result.b = t; - }break; - - case 3: - { - Result.r = p; - Result.g = q; - Result.b = Value; - }break; - - case 4: - { - Result.r = t; - Result.g = p; - Result.b = Value; - }break; - - case 5: - default: - { - Result.r = Value; - Result.g = p; - Result.b = q; - }break; - } - - return Result; -} - -static bool -PointIsInRange ( -v2 _P, -v2 _Min, v2 _Max -) -{ - return (_P.x >= _Min.x && _P.x <= _Max.x && - _P.y >= _Min.y && _P.y <= _Max.y); -} - -static bool -PointIsInRangeSafe ( -v2 _P, -v2 _Min, v2 _Max -) -{ - s32 MinX = GSMin(_Min.x, _Max.x); - s32 MinY = GSMin(_Min.y, _Max.y); - s32 MaxX = GSMax(_Min.x, _Max.x); - s32 MaxY = GSMax(_Min.y, _Max.y); - - return (_P.x >= MinX && _P.x <= MaxX && - _P.y >= MinY && _P.y <= MaxY); -} - -inline v2 -PointToPercentRange (v2 P, v2 Min, v2 Max) -{ - v2 Result = {}; - - Result.x = GSClamp(0.f, (P.x - Min.x) / (Max.x - Min.x), 1.f); - Result.y = GSClamp(0.f, (P.y - Min.y) / (Max.y - Min.y), 1.f); - - return Result; -} - -////////////////////////////////////// -// RECT -////////////////////////////////////// - -inline r32 -Width (rect Rect) -{ - s32 Result = Rect.Max.x - Rect.Min.x; - return Result; -} - -inline r32 -Height (rect Rect) -{ - s32 Result = Rect.Max.y - Rect.Min.y; - return Result; -} - -inline v2 -CalculateRectCenter (rect Rect) -{ - v2 Result = (Rect.Min + Rect.Max) / 2.0f; - return Result; -} - -inline b32 -PointIsInRect (v2 Point, rect Rect) -{ - b32 Result = ((Point.x >= Rect.Min.x && Point.x <= Rect.Max.x) && - (Point.y >= Rect.Min.y && Point.y <= Rect.Max.y)); - return Result; -} - -////////////////////////////////////// -// MATRIX -////////////////////////////////////// - -static m33 -M33(r32 a, r32 b, r32 c, - r32 d, r32 e, r32 f, - r32 g, r32 h, r32 i) -{ - m33 M = {}; - M.a = a; M.b = b; M.c = c; - M.d = d; M.e = e; M.f = f; - M.g = g; M.h = h; M.i = i; - return M; -} - -static m44 -M44(r32 a, r32 b, r32 c, r32 d, - r32 e, r32 f, r32 g, r32 h, - r32 i, r32 j, r32 k, r32 l, - r32 m, r32 n, r32 o, r32 p) -{ - m44 M = {}; - M.a = a; M.b = b; M.c = c; M.d = d; - M.e = e; M.f = f; M.g = g; M.h = h; - M.i = i; M.j = j; M.k = k; M.l = l; - M.m = m; M.n = n; M.o = o; M.p = p; - return M; -} - -static m33 -M33Empty () -{ - m33 M = {}; - M.a = 0; M.b = 0; M.c = 0; - M.d = 0; M.e = 0; M.f = 0; - M.g = 0; M.h = 0; M.i = 0; - return M; -} - -static m44 -M44Empty() -{ - m44 M = {}; - M.a = 0; M.b = 0; M.c = 0; M.d = 0; - M.e = 0; M.f = 0; M.g = 0; M.h = 0; - M.i = 0; M.j = 0; M.k = 0; M.l = 0; - M.m = 0; M.n = 0; M.o = 0; M.p = 0; - return M; -} - -static m33 -M33Identity () -{ - m33 M = {}; - M.a = 1; M.b = 0; M.c = 0; - M.d = 0; M.e = 1; M.f = 0; - M.g = 0; M.h = 0; M.i = 1; - return M; -} - -static m44 -M44Identity() -{ - m44 M = {}; - M.a = 1; M.b = 0; M.c = 0; M.d = 0; - M.e = 0; M.f = 1; M.g = 0; M.h = 0; - M.i = 0; M.j = 0; M.k = 1; M.l = 0; - M.m = 0; M.n = 0; M.o = 0; M.p = 1; - return M; -} - -static m44 -GetXRotation (r32 Angle) -{ - r32 CosAngle = GSCos(Angle); - r32 SinAngle = GSSin(Angle); - m44 M = { - 1, 0, 0, 0, - 0, CosAngle, SinAngle, 0, - 0, -SinAngle, CosAngle, 0, - 0, 0, 0, 1 - }; - return M; -} - - -static m44 -GetYRotation (r32 Angle) -{ - r32 CosAngle = GSCos(Angle); - r32 SinAngle = GSSin(Angle); - m44 M = { - CosAngle, 0, -SinAngle, 0, - 0, 1, 0, 0, - SinAngle, 0, CosAngle, 0, - 0, 0, 0, 1 - }; - return M; -} - -static m44 -GetZRotation (r32 Angle) -{ - r32 CosAngle = GSCos(Angle); - r32 SinAngle = GSSin(Angle); - m44 M = { - CosAngle, SinAngle, 0, 0, - -SinAngle, CosAngle, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - return M; -} - - -static m33 -Transpose (m33 M) -{ - m33 Result = {}; - - for (s32 x = 0; x < 3; x++) - { - for (s32 y = 0; y < 3; y++) - { - Result.E[x + (y * 3)] = M.E[y + (x * 3)]; - } - } - - return Result; -} - -inline m44 -Transpose (m44 M) -{ - DEBUG_TRACK_SCOPE(Transpose); - - m44 Result = {}; - - Result.E[0] = M.E[0]; - Result.E[1] = M.E[4]; - Result.E[2] = M.E[8]; - Result.E[3] = M.E[12]; - - Result.E[4] = M.E[1]; - Result.E[5] = M.E[5]; - Result.E[6] = M.E[9]; - Result.E[7] = M.E[13]; - - Result.E[8] = M.E[2]; - Result.E[9] = M.E[6]; - Result.E[10] = M.E[10]; - Result.E[11] = M.E[14]; - - Result.E[12] = M.E[3]; - Result.E[13] = M.E[7]; - Result.E[14] = M.E[11]; - Result.E[15] = M.E[15]; - - return Result; -} - -static m44 -GetPositionM44 (v4 Position) -{ -#if 1 - return m44{ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - Position.x, Position.y, Position.z, Position.w - }; -#else - return m44{ - 1, 0, 0, Position.x, - 0, 1, 0, Position.y, - 0, 0, 1, Position.z, - 0, 0, 0, Position.w}; -#endif -} - -static m44 -GetLookAtMatrix (v4 Position, v4 Target) -{ - // Forward - v4 Forward = Normalize(Target - Position); - // Right - v4 Right = Normalize(Cross(v4{0, 1, 0, 0}, Forward)); - // Up - v4 Up = Normalize(Cross(Forward, Right)); - - m44 RotationMatrix = M44( - Right.x, Up.x, Forward.x, 0, - Right.y, Up.y, Forward.y, 0, - Right.z, Up.z, Forward.z, 0, - 0, 0, 0, 1); - - return RotationMatrix; -} - -b32 operator== (m33 A, m33 B) -{ - b32 Result = true; - for (int e = 0; e < 9; e++) { if (GSAbs(A.E[e] - B.E[e]) > 0.0001f) { Result = false; break; } } - return Result; -} - -b32 operator== (m44 A, m44 B) -{ - b32 Result = true; - for (int e = 0; e < 16; e++) { if (GSAbs(A.E[e] - B.E[e]) > 0.0001f) { Result = false; break; } } - return Result; -} - -m33 operator+ (m33 A, m33 B) -{ - m33 M = {}; - for (int e = 0; e < 9; e++) { M.E[e] = A.E[e] + B.E[e]; } - return M; -} - -m44 operator+ (m44 A, m44 B) -{ - m44 M = {}; - for (int e = 0; e < 16; e++) { M.E[e] = A.E[e] + B.E[e]; } - return M; -} - -m33 operator- (m33 A, m33 B) -{ - m33 M = {}; - for (int e = 0; e < 9; e++) { M.E[e] = A.E[e] - B.E[e]; } - return M; -} - -m44 operator- (m44 A, m44 B) -{ - m44 M = {}; - for (int e = 0; e < 16; e++) { M.E[e] = A.E[e] - B.E[e]; } - return M; -} - -m33 operator* (m33 A, m33 B) -{ - m33 M = {}; - for (int rx = 0; rx < 3; rx++) - { - for (int ry = 0; ry < 3; ry++) - { - int RIndex = (ry * 3) + rx; - M.E[RIndex] = 0; - for (int i = 0; i < 3; i++) - { - M.E[RIndex] += B.E[(ry * 3) + i] * A.E[(i * 3) + rx]; - } - } - } - return M; -} - -m44 operator* (m44 A, m44 B) -{ - m44 M = {}; - - r32 A00=A.E[0+4*0]; - r32 A01=A.E[0+4*1]; - r32 A02=A.E[0+4*2]; - r32 A03=A.E[0+4*3]; - - r32 A10=A.E[1+4*0]; - r32 A11=A.E[1+4*1]; - r32 A12=A.E[1+4*2]; - r32 A13=A.E[1+4*3]; - - r32 A20=A.E[2+4*0]; - r32 A21=A.E[2+4*1]; - r32 A22=A.E[2+4*2]; - r32 A23=A.E[2+4*3]; - - r32 A30=A.E[3+4*0]; - r32 A31=A.E[3+4*1]; - r32 A32=A.E[3+4*2]; - r32 A33=A.E[3+4*3]; - - r32 B00=B.E[0+4*0]; - r32 B01=B.E[0+4*1]; - r32 B02=B.E[0+4*2]; - r32 B03=B.E[0+4*3]; - - r32 B10=B.E[1+4*0]; - r32 B11=B.E[1+4*1]; - r32 B12=B.E[1+4*2]; - r32 B13=B.E[1+4*3]; - - r32 B20=B.E[2+4*0]; - r32 B21=B.E[2+4*1]; - r32 B22=B.E[2+4*2]; - r32 B23=B.E[2+4*3]; - - r32 B30=B.E[3+4*0]; - r32 B31=B.E[3+4*1]; - r32 B32=B.E[3+4*2]; - r32 B33=B.E[3+4*3]; - - M.E[0+4*0] = A00*B00+A10*B01+A20*B02+A30*B03; - M.E[0+4*1] = A01*B00+A11*B01+A21*B02+A31*B03; - M.E[0+4*2] = A02*B00+A12*B01+A22*B02+A32*B03; - M.E[0+4*3] = A03*B00+A13*B01+A23*B02+A33*B03; - - M.E[1+4*0] = A00*B10+A10*B11+A20*B12+A30*B13; - M.E[1+4*1] = A01*B10+A11*B11+A21*B12+A31*B13; - M.E[1+4*2] = A02*B10+A12*B11+A22*B12+A32*B13; - M.E[1+4*3] = A03*B10+A13*B11+A23*B12+A33*B13; - - M.E[2+4*0] = A00*B20+A10*B21+A20*B22+A30*B23; - M.E[2+4*1] = A01*B20+A11*B21+A21*B22+A31*B23; - M.E[2+4*2] = A02*B20+A12*B21+A22*B22+A32*B23; - M.E[2+4*3] = A03*B20+A13*B21+A23*B22+A33*B23; - - M.E[3+4*0] = A00*B30+A10*B31+A20*B32+A30*B33; - M.E[3+4*1] = A01*B30+A11*B31+A21*B32+A31*B33; - M.E[3+4*2] = A02*B30+A12*B31+A22*B32+A32*B33; - M.E[3+4*3] = A03*B30+A13*B31+A23*B32+A33*B33; - - return M; -} - -v3 operator* (m33 M, v3 V) -{ - v3 Result = {}; - int i = 0; - for (int y = 0; y < 3; y++) - { - Result.E[y] = 0; - for (int x = 0; x < 3; x++) - { - Result.E[y] += M.E[(y * 3) + x] * V.E[x]; - } - } - return Result; -} - -v4 operator* (m44 M, v4 V) -{ - v4 Result = {}; -#if 1 - Result.x = V.x*M.a + V.y*M.e + V.z*M.i + V.w*M.m; - Result.y = V.x*M.b + V.y*M.f + V.z*M.j + V.w*M.n; - Result.z = V.x*M.c + V.y*M.g + V.z*M.k + V.w*M.o; - Result.w = V.x*M.d + V.y*M.h + V.z*M.l + V.w*M.p; -#else - for (int y = 0; y < 4; y++) - { - Result.E[y] = 0; - for (int x = 0; x < 4; x++) - { - Result.E[y] += M.E[(y * 4) + x] * V.E[x]; - } - } -#endif - return Result; -} - -b32 Inverse(m44 M_In, m44* M_Out) -{ - b32 Result = false; - - r32 det; - s32 i; - - - M_Out->E[0] = M_In.E[5] * M_In.E[10] * M_In.E[15] - - M_In.E[5] * M_In.E[11] * M_In.E[14] - - M_In.E[9] * M_In.E[6] * M_In.E[15] + - M_In.E[9] * M_In.E[7] * M_In.E[14] + - M_In.E[13] * M_In.E[6] * M_In.E[11] - - M_In.E[13] * M_In.E[7] * M_In.E[10]; - - M_Out->E[4] = -M_In.E[4] * M_In.E[10] * M_In.E[15] + - M_In.E[4] * M_In.E[11] * M_In.E[14] + - M_In.E[8] * M_In.E[6] * M_In.E[15] - - M_In.E[8] * M_In.E[7] * M_In.E[14] - - M_In.E[12] * M_In.E[6] * M_In.E[11] + - M_In.E[12] * M_In.E[7] * M_In.E[10]; - - M_Out->E[8] = M_In.E[4] * M_In.E[9] * M_In.E[15] - - M_In.E[4] * M_In.E[11] * M_In.E[13] - - M_In.E[8] * M_In.E[5] * M_In.E[15] + - M_In.E[8] * M_In.E[7] * M_In.E[13] + - M_In.E[12] * M_In.E[5] * M_In.E[11] - - M_In.E[12] * M_In.E[7] * M_In.E[9]; - - M_Out->E[12] = -M_In.E[4] * M_In.E[9] * M_In.E[14] + - M_In.E[4] * M_In.E[10] * M_In.E[13] + - M_In.E[8] * M_In.E[5] * M_In.E[14] - - M_In.E[8] * M_In.E[6] * M_In.E[13] - - M_In.E[12] * M_In.E[5] * M_In.E[10] + - M_In.E[12] * M_In.E[6] * M_In.E[9]; - - M_Out->E[1] = -M_In.E[1] * M_In.E[10] * M_In.E[15] + - M_In.E[1] * M_In.E[11] * M_In.E[14] + - M_In.E[9] * M_In.E[2] * M_In.E[15] - - M_In.E[9] * M_In.E[3] * M_In.E[14] - - M_In.E[13] * M_In.E[2] * M_In.E[11] + - M_In.E[13] * M_In.E[3] * M_In.E[10]; - - M_Out->E[5] = M_In.E[0] * M_In.E[10] * M_In.E[15] - - M_In.E[0] * M_In.E[11] * M_In.E[14] - - M_In.E[8] * M_In.E[2] * M_In.E[15] + - M_In.E[8] * M_In.E[3] * M_In.E[14] + - M_In.E[12] * M_In.E[2] * M_In.E[11] - - M_In.E[12] * M_In.E[3] * M_In.E[10]; - - M_Out->E[9] = -M_In.E[0] * M_In.E[9] * M_In.E[15] + - M_In.E[0] * M_In.E[11] * M_In.E[13] + - M_In.E[8] * M_In.E[1] * M_In.E[15] - - M_In.E[8] * M_In.E[3] * M_In.E[13] - - M_In.E[12] * M_In.E[1] * M_In.E[11] + - M_In.E[12] * M_In.E[3] * M_In.E[9]; - - M_Out->E[13] = M_In.E[0] * M_In.E[9] * M_In.E[14] - - M_In.E[0] * M_In.E[10] * M_In.E[13] - - M_In.E[8] * M_In.E[1] * M_In.E[14] + - M_In.E[8] * M_In.E[2] * M_In.E[13] + - M_In.E[12] * M_In.E[1] * M_In.E[10] - - M_In.E[12] * M_In.E[2] * M_In.E[9]; - - M_Out->E[2] = M_In.E[1] * M_In.E[6] * M_In.E[15] - - M_In.E[1] * M_In.E[7] * M_In.E[14] - - M_In.E[5] * M_In.E[2] * M_In.E[15] + - M_In.E[5] * M_In.E[3] * M_In.E[14] + - M_In.E[13] * M_In.E[2] * M_In.E[7] - - M_In.E[13] * M_In.E[3] * M_In.E[6]; - - M_Out->E[6] = -M_In.E[0] * M_In.E[6] * M_In.E[15] + - M_In.E[0] * M_In.E[7] * M_In.E[14] + - M_In.E[4] * M_In.E[2] * M_In.E[15] - - M_In.E[4] * M_In.E[3] * M_In.E[14] - - M_In.E[12] * M_In.E[2] * M_In.E[7] + - M_In.E[12] * M_In.E[3] * M_In.E[6]; - - M_Out->E[10] = M_In.E[0] * M_In.E[5] * M_In.E[15] - - M_In.E[0] * M_In.E[7] * M_In.E[13] - - M_In.E[4] * M_In.E[1] * M_In.E[15] + - M_In.E[4] * M_In.E[3] * M_In.E[13] + - M_In.E[12] * M_In.E[1] * M_In.E[7] - - M_In.E[12] * M_In.E[3] * M_In.E[5]; - - M_Out->E[14] = -M_In.E[0] * M_In.E[5] * M_In.E[14] + - M_In.E[0] * M_In.E[6] * M_In.E[13] + - M_In.E[4] * M_In.E[1] * M_In.E[14] - - M_In.E[4] * M_In.E[2] * M_In.E[13] - - M_In.E[12] * M_In.E[1] * M_In.E[6] + - M_In.E[12] * M_In.E[2] * M_In.E[5]; - - M_Out->E[3] = -M_In.E[1] * M_In.E[6] * M_In.E[11] + - M_In.E[1] * M_In.E[7] * M_In.E[10] + - M_In.E[5] * M_In.E[2] * M_In.E[11] - - M_In.E[5] * M_In.E[3] * M_In.E[10] - - M_In.E[9] * M_In.E[2] * M_In.E[7] + - M_In.E[9] * M_In.E[3] * M_In.E[6]; - - M_Out->E[7] = M_In.E[0] * M_In.E[6] * M_In.E[11] - - M_In.E[0] * M_In.E[7] * M_In.E[10] - - M_In.E[4] * M_In.E[2] * M_In.E[11] + - M_In.E[4] * M_In.E[3] * M_In.E[10] + - M_In.E[8] * M_In.E[2] * M_In.E[7] - - M_In.E[8] * M_In.E[3] * M_In.E[6]; - - M_Out->E[11] = -M_In.E[0] * M_In.E[5] * M_In.E[11] + - M_In.E[0] * M_In.E[7] * M_In.E[9] + - M_In.E[4] * M_In.E[1] * M_In.E[11] - - M_In.E[4] * M_In.E[3] * M_In.E[9] - - M_In.E[8] * M_In.E[1] * M_In.E[7] + - M_In.E[8] * M_In.E[3] * M_In.E[5]; - - M_Out->E[15] = M_In.E[0] * M_In.E[5] * M_In.E[10] - - M_In.E[0] * M_In.E[6] * M_In.E[9] - - M_In.E[4] * M_In.E[1] * M_In.E[10] + - M_In.E[4] * M_In.E[2] * M_In.E[9] + - M_In.E[8] * M_In.E[1] * M_In.E[6] - - M_In.E[8] * M_In.E[2] * M_In.E[5]; - - det = M_In.E[0] * M_Out->E[0] + M_In.E[1] * M_Out->E[4] + M_In.E[2] * M_Out->E[8] + M_In.E[3] * M_Out->E[12]; - - if (det == 0) - { - return false; - } - - det = 1.0 / det; - - for (i = 0; i < 16; i++) - { - M_Out->E[i] = M_Out->E[i] * det; - } - - return true; -} - -#if defined(VECTOR_MATRIX_TEST_SUITE) - -void TestVectorMatrixMultiplication () -{ - s32 TestCount = 0; - s32 SuccessCount = 0; - - DebugPrint("\n\n-------------------------------------------------\n Begin Testing Vector/Matrix\n\n\n"); - - // Utility Functions - TestClean((GSSqrt(4.f) == 2.f), "Vector Square Root"); - TestClean((GSLerp(0.f, 1.f, .5f) == .5f), "Vector Lerp"); - TestClean((GSMin(-.25f, 5.f) == -.25f), "Vector Min"); - TestClean((GSMax(-.25f, 5.f) == 5.f), "Vector Max"); - TestClean((GSClamp(-2.f, -3.f, 5.f) == -2.f), "Vector Clamp, Lower Than Range"); - TestClean((GSClamp(-2.f, 6.f, 5.f) == 5.f), "Vector Clamp, Higher Than Range"); - - ////////////////////////////// - // Vector Functions - ///////////////////////////// - - v2 V2Unit = v2{1, 0}; - v3 V3Unit = v3{1, 0, 0}; - v4 V4Unit = v4{1, 0, 0, 0}; - - v2 TestV2 = v2{1, 2}; - r32 TestV2MagSq = (TestV2.x * TestV2.x) + (TestV2.y * TestV2.y); - r32 TestV2Mag = GSSqrt(TestV2MagSq); - v2 TestV2Norm = v2{TestV2.x / TestV2Mag, TestV2.y / TestV2Mag}; - r32 TestV2DotR = (TestV2.x * V2Unit.x) + (TestV2.y * V2Unit.y); - - v3 TestV3 = v3{1, 2, 3}; - r32 TestV3MagSq = (TestV3.x * TestV3.x) + (TestV3.y * TestV3.y) + (TestV3.z * TestV3.z); - r32 TestV3Mag = GSSqrt(TestV3MagSq); - v3 TestV3Norm = v3{TestV3.x / TestV3Mag, TestV3.y / TestV3Mag, TestV3.z / TestV3Mag}; - r32 TestV3DotR = (TestV3.x * V3Unit.x) + (TestV3.y * V3Unit.y) + (TestV3.z * V3Unit.z); - - v4 TestV4 = v4{1, 2, 3, 4}; - r32 TestV4MagSq = (TestV4.x * TestV4.x) + (TestV4.y * TestV4.y) + (TestV4.z * TestV4.z) + (TestV4.w * TestV4.w); - r32 TestV4Mag = GSSqrt(TestV4MagSq); - v4 TestV4Norm = v4{ - TestV4.x / TestV4Mag, TestV4.y / TestV4Mag, TestV4.z / TestV4Mag, TestV4.w / TestV4Mag - }; - r32 TestV4DotR = (TestV4.x * V4Unit.x) + (TestV4.y * V4Unit.y) + (TestV4.z * V4Unit.z) + (TestV4.w * V4Unit.w); - - v2 DownCastV3 = V2(TestV3); - v3 DownCastV4 = V3(TestV4); - - v2 EqualityV2 = v2{TestV2.x, TestV2.y}; - v2 ZeroV2 = v2{0, 0}; - v3 EqualityV3 = v3{TestV3.x, TestV3.y, TestV3.z}; - v3 ZeroV3 = v3{0, 0, 0}; - v4 EqualityV4 = v4{TestV4.x, TestV4.y, TestV4.z, TestV4.w}; - v4 ZeroV4 = v4{0, 0, 0, 0}; - - TestClean((TestV2.x == 1 && TestV2.y == 2), "V2 Assignment"); - TestClean((TestV3.x == 1 && TestV3.y == 2 && TestV3.z == 3), "V3 Assignment"); - TestClean((TestV4.x == 1 && TestV4.y == 2 && TestV4.z == 3 && TestV4.w == 4), "V3 Assignment"); - - TestClean((DownCastV3.x == 1 && DownCastV3.y == 2), "V3 -> V2 Downcast"); - TestClean((DownCastV4.x == 1 && DownCastV4.y == 2 && DownCastV4.z == 3), "V4 -> V3 Downcast"); - - // Vector Operators - - TestClean((TestV2 == EqualityV2 && !(TestV2 == ZeroV2)), "V2 Equality"); - TestClean((TestV3 == EqualityV3 && !(TestV3 == ZeroV3)), "V3 Equality"); - TestClean((TestV4 == EqualityV4 && !(TestV4 == ZeroV4)), "V4 Equality"); - - TestClean(((TestV2 - TestV2) == ZeroV2), "V2 Subtraction"); - TestClean(((TestV3 - TestV3) == ZeroV3), "V3 Subtraction"); - TestClean(((TestV4 - TestV4) == ZeroV4), "V4 Subtraction"); - - TestClean(((TestV2 + TestV2) == v2{TestV2.x * 2, TestV2.y * 2}), "V2 Addition"); - TestClean(((TestV3 + TestV3) == v3{TestV3.x * 2, TestV3.y * 2, TestV3.z * 2}), "V3 Addition"); - TestClean(((TestV4 + TestV4) == v4{TestV4.x * 2, TestV4.y * 2, TestV4.z * 2, TestV4.w * 2}), "V4 Addition"); - - TestClean(((TestV2 * 2.0f) == v2{TestV2.x * 2, TestV2.y * 2}), "V2 Multiplication"); - TestClean(((TestV3 * 2.0f) == v3{TestV3.x * 2, TestV3.y * 2, TestV3.z * 2}), "V3 Multiplication"); - TestClean(((TestV4 * 2.0f) == v4{TestV4.x * 2, TestV4.y * 2, TestV4.z * 2, TestV4.w * 2}), "V4 Multiplication"); - - TestClean(((TestV2 * TestV2) == v2{TestV2.x * TestV2.x, TestV2.y * TestV2.y}), "V2 Piecewise Mult"); - TestClean(((TestV3 * TestV3) == v3{ - TestV3.x * TestV3.x, - TestV3.y * TestV3.y, - TestV3.z * TestV3.z}), "V3 Piecewise Mult"); - TestClean(((TestV4 * TestV4) == v4{ - TestV4.x * TestV4.x, - TestV4.y * TestV4.y, - TestV4.z * TestV4.z, - TestV4.w * TestV4.w}), "V4 Piecewise Mult"); - - - TestClean(((TestV2 / 2.0f) == v2{TestV2.x / 2, TestV2.y / 2}), "V2 Division"); - TestClean(((TestV3 / 2.0f) == v3{TestV3.x / 2, TestV3.y / 2, TestV3.z / 2}), "V3 Division"); - TestClean(((TestV4 / 2.0f) == v4{TestV4.x / 2, TestV4.y / 2, TestV4.z / 2, TestV4.w / 2}), "V4 Division"); - - TestClean(((TestV2 / TestV2) == v2{TestV2.x / TestV2.x, TestV2.y / TestV2.y}), "V2 Piecewise Div"); - TestClean(((TestV3 / TestV3) == v3{ - TestV3.x / TestV3.x, - TestV3.y / TestV3.y, - TestV3.z / TestV3.z}), "V3 Piecewise Div"); - TestClean(((TestV4 / TestV4) == v4{ - TestV4.x / TestV4.x, - TestV4.y / TestV4.y, - TestV4.z / TestV4.z, - TestV4.w / TestV4.w}), "V4 Piecewise Div"); - - TestClean(((MagSqr(V2Unit) == 1) && (MagSqr(TestV2) == TestV2MagSq)), "V2 Square Mag"); - TestClean(((MagSqr(V3Unit) == 1) && (MagSqr(TestV3) == TestV3MagSq)), "V3 Square Mag"); - TestClean(((MagSqr(V4Unit) == 1) && (MagSqr(TestV4) == TestV4MagSq)), "V4 Square Mag"); - TestClean(((Mag(V2Unit) == 1) && (Mag(TestV2) == TestV2Mag)), "V2 Mag"); - TestClean(((Mag(V3Unit) == 1) && (Mag(TestV3) == TestV3Mag)), "V3 Mag"); - TestClean(((Mag(V4Unit) == 1) && (Mag(TestV4) == TestV4Mag)), "V4 Mag"); - - TestClean((DistanceSq(ZeroV2, TestV2) == TestV2MagSq), "V2 Distance Sq"); - TestClean((DistanceSq(ZeroV3, TestV3) == TestV3MagSq), "V3 Distance Sq"); - TestClean((DistanceSq(ZeroV4, TestV4) == TestV4MagSq), "V4 Distance Sq"); - TestClean((Distance(ZeroV2, TestV2) == TestV2Mag), "V2 Distance"); - TestClean((Distance(ZeroV3, TestV3) == TestV3Mag), "V3 Distance"); - TestClean((Distance(ZeroV4, TestV4) == TestV4Mag), "V4 Distance"); - - TestClean((Normalize(TestV2) == TestV2Norm), "V2 Normalize"); - TestClean((Normalize(TestV3) == TestV3Norm), "V3 Normalize"); - TestClean((Normalize(TestV4) == TestV4Norm), "V4 Normalize"); - - TestClean(((Dot(V2Unit, V2Unit) == 1) && (Dot(TestV2, V2Unit) == TestV2DotR)), "V2 Dot"); - TestClean(((Dot(V3Unit, V3Unit) == 1) && (Dot(TestV3, V3Unit) == TestV3DotR)), "V3 Dot"); - TestClean(((Dot(V4Unit, V4Unit) == 1) && (Dot(TestV4, V4Unit) == TestV4DotR)), "V4 Dot"); - - // Skipping Cross For Now - - TestClean((Lerp(v2{0, 0}, v2{1, 1}, .5f) == v2{.5f, .5f}), "V2 Lerp"); - TestClean((Lerp(v3{0, 0, 0}, v3{1, 1, 1}, .5f) == v3{.5f, .5f, .5f}), "V3 Lerp"); - TestClean((Lerp(v4{0, 0, 0, 0}, v4{1, 1, 1, 1}, .5f) == v4{.5f, .5f, .5f, .5f}), "V4 Lerp"); - - ///////////////////////////// - // Matrix - //////////////////////////// - - m33 TestM33 = m33{ - 0, 1, 2, - 3, 4, 5, - 6, 7, 8}; - - m33 EqualityM33 = {}; - for (s32 i = 0; i < 16; i++) { EqualityM33.E[i] = TestM33.E[i]; } - - m33 TransposeM33 = m33{ - 0, 3, 6, - 1, 4, 7, - 2, 5, 8}; - - m33 IdentityM33 = m33{ - 1, 0, 0, - 0, 1, 0, - 0, 0, 1}; - - m33 TestM33Squared = m33{ - 15, 18, 21, - 42, 54, 66, - 69, 90, 111 - }; - - m44 TestM44 = m44{ - 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 - }; - - m44 EqualityM44 = {}; - for (s32 i = 0; i < 16; i++) { EqualityM44.E[i] = TestM44.E[i]; } - - m44 TransposeM44 = m44{ - 0, 4, 8, 12, - 1, 5, 9, 13, - 2, 6, 10, 14, - 3, 7, 11, 15 - }; - - m44 IdentityM44 = m44{ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - - m44 TestM44Squared = m44{ - 56, 62, 68, 74, - 152, 174, 196, 218, - 248, 286, 324, 362, - 344, 398, 452, 506, - }; - - TestClean(((IdentityM33 == IdentityM33) && (TestM33 == EqualityM33)), "M33 Equality"); - TestClean(((IdentityM44 == IdentityM44) && (TestM44 == EqualityM44)), "M44 Equality"); - - TestClean(((Transpose(IdentityM33) == IdentityM33) && - (Transpose(TestM33) == TransposeM33)), "M33 Transpose"); - TestClean(((Transpose(IdentityM44) == IdentityM44) && - (Transpose(TestM44) == TransposeM44)), "M44 Transpose"); - - TestClean(((TestM33 * IdentityM33) == TestM33), "M33 Identity Mult"); - TestClean(((TestM44 * IdentityM44) == TestM44), "M44 Identity Mult"); - TestClean(((TestM33 * TestM33) == TestM33Squared), "M33 Mult"); - TestClean(((TestM44 * TestM44) == TestM44Squared), "M44 Mult"); - - - // Useful Tests - v4 Right = v4{1, 0, 0, 0}; - v4 Forward = v4{0, 0, 1, 0}; - v4 Up = v4{0, 1, 0, 0}; - v4 Left = v4{-1, 0, 0, 0}; - v4 Back = v4{0, 0, -1, 0}; - v4 Down = v4{0, -1, 0, 0}; - - m44 NinetyDegreesAboutX = GetXRotation(M_PI / 2); - v4 Rotated = NinetyDegreesAboutX * Forward; - TestClean((Rotated == Up), "Rotation About X"); - - m44 NinetyDegreesAboutY = GetYRotation(M_PI / 2); - Rotated = NinetyDegreesAboutY * Right; - TestClean((Rotated == Forward), "Rotation About Y"); - - m44 NinetyDegreesAboutZ = GetZRotation(M_PI / 2); - Rotated = NinetyDegreesAboutZ * Right; - TestClean((Rotated == Down), "Rotation About Z"); - - - v4 A = v4{1, 2, 3, 4}; - m44 B = m44{ - 1, 2, 3, 4, - 5, 6, 7, 8, - 9, 1, 2, 3, - 4, 5, 6, 7}; - v4 VTest = v4{30, 70, 29, 60}; - TestClean(((B * A) == VTest), "V4 M44 Multiplication"); - - m44 C = m44{ - 9, 8, 7, 6, - 5, 4, 3, 2, - 1, 0, 9, 8, - 7, 6, 5, 4 - }; - m44 MResult = B * C; - m44 MTest = m44{ - 50, 40, 60, 50, - 138, 112, 156, 130, - 109, 94, 99, 84, - 116, 94, 132, 110 - }; - TestClean(((B * C) == MTest), "M44 Mult Test 2"); - - m44 Identity = M44Identity(); - m44 InvIdentity = {}; - Inverse(Identity, &InvIdentity); - TestClean((Identity == InvIdentity), "Inverse Identity"); - - m44 Test = m44{ - 2, 4, 6, 7, - 5, 1, 8, 8, - 1, 7, 3, 1, - 3, 9, 2, 4 - }; - m44 PreCalcTestInv = m44{ - -0.3904761904761904762f, 0.26190476190476190475f, -0.02857142857142857139f, 0.16666666666666666668f, - 0.022222222222222222212f, -0.055555555555555555549f, 0.06666666666666666667f, 0.055555555555555555547f, - -0.00317460317460317458f, 0.07936507936507936506f, 0.27619047619047619045f, -0.2222222222222222222f, - 0.24444444444444444444f, -0.1111111111111111111f, -0.26666666666666666667f, 0.1111111111111111111f - }; - m44 InvTest = {}; - Inverse(Test, &InvTest); - //TestClean((PreCalcTestInv == InvTest), "Inverse M44"); - - DebugPrint("Results: Passed %d / %d\n\n\no", SuccessCount, TestCount); -} - -#endif - -#define GS_VECTOR_MATRIX_H -#endif \ No newline at end of file diff --git a/src/gs_win32.cpp b/src/gs_win32.cpp index 277b1aa..fd89867 100644 --- a/src/gs_win32.cpp +++ b/src/gs_win32.cpp @@ -61,6 +61,7 @@ internal void Win32DisplayBufferInWindow(win32_offscreen_buffer* Buffer internal PLATFORM_ALLOC(Win32Alloc); internal PLATFORM_FREE(Win32Free); +internal PLATFORM_REALLOC(Win32Realloc); // File IO internal PLATFORM_READ_ENTIRE_FILE(Win32ReadEntireFile); @@ -610,6 +611,17 @@ PLATFORM_FREE(Win32Free) return Result; } +PLATFORM_REALLOC(Win32Realloc) +{ + u8* NewMemory = Win32BasicAlloc(NewSize); + if (Base) + { + GSMemCopy(Base, NewMemory, OldSize); + Win32Free(Base, OldSize); + } + return NewMemory; +} + // File IO PLATFORM_READ_ENTIRE_FILE(Win32ReadEntireFile) { diff --git a/src/interface.h b/src/interface.h index 32acbae..52265ba 100644 --- a/src/interface.h +++ b/src/interface.h @@ -8,12 +8,14 @@ enum string_alignment internal void DrawCharacter_ (render_quad_batch_constructor* BatchConstructor, r32 MinX, r32 MinY, codepoint_bitmap CodepointInfo, v4 Color) { - r32 MaxX = MinX + (CodepointInfo.Width); - r32 MaxY = MinY + (CodepointInfo.Height); + s32 AlignedMinX = (s32)(MinX); + s32 AlignedMinY = (s32)(MinY); + s32 AlignedMaxX = AlignedMinX + (CodepointInfo.Width); + s32 AlignedMaxY = AlignedMinY + (CodepointInfo.Height); PushQuad2DOnBatch(BatchConstructor, - v2{MinX, MinY}, v2{MaxX, MinY}, - v2{MaxX, MaxY}, v2{MinX, MaxY}, + v2{(r32)AlignedMinX, (r32)AlignedMinY}, v2{(r32)AlignedMaxX, (r32)AlignedMinY}, + v2{(r32)AlignedMaxX, (r32)AlignedMaxY}, v2{(r32)AlignedMinX, (r32)AlignedMaxY}, CodepointInfo.UVMin, CodepointInfo.UVMax, Color); } @@ -432,140 +434,54 @@ enum selection_state Selection_Deselected, }; -struct scroll_list_result +struct interface_list { - s32 IndexSelected; - s32 StartIndex; - selection_state Selection; + rect ListBounds; + + v2 ListElementDimensions; + v2 ElementLabelIndent; + + v4 TextColor; + v4* LineBGColors; + s32 LineBGColorsCount; + v4 LineBGHoverColor; + + s32 ListElementsCount; }; -internal scroll_list_result -DrawOptionsList(render_command_buffer* RenderBuffer, v2 Min, v2 Max, - string* Options, s32 OptionsCount, - s32 Start, interface_config Config, mouse_state Mouse) +internal rect +DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer) { - scroll_list_result Result = {}; - Result.IndexSelected = -1; - Result.StartIndex = Start; - Result.Selection = Selection_None; + rect LineBounds = {}; + LineBounds.Min = v2{ + List->ListBounds.Min.x, + List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1)) + }; + LineBounds.Max = LineBounds.Min + List->ListElementDimensions; - r32 OptionHeight = NewLineYOffset(*Config.Font) + (2 * Config.Margin.y); - r32 OptionOffset = OptionHeight + Config.Margin.y; - - s32 OptionsToDisplay = ((Max.y - Min.y) / OptionHeight) - 2; - OptionsToDisplay = GSMin(OptionsToDisplay, (OptionsCount - Start)); - - v2 ButtonMin = v2{Min.x, Max.y - OptionHeight}; - v2 ButtonMax = v2{Max.x, Max.y}; - - string* OptionCursor = Options + Start; - for (s32 i = 0; i < OptionsToDisplay; i++) + v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount]; + if (PointIsInRange(Mouse.Pos, LineBounds.Min, LineBounds.Max)) { - button_result Button = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, - *OptionCursor, - Config, Mouse); - if (Button.Pressed) - { - Result.IndexSelected = Start + i; - Result.Selection = Selection_Selected; - } - OptionCursor++; - ButtonMin.y -= OptionOffset; - ButtonMax.y -= OptionOffset; + Color = List->LineBGHoverColor; } - r32 HalfWidthWithMargin = ((Max.x - Min.x) / 2.0f) - Config.Margin.x; - string DownArrowString = MakeStringLiteral(" v "); - string UpArrowString = MakeStringLiteral(" ^ "); - button_result Down = EvaluateButton(RenderBuffer, Min, v2{Min.x + HalfWidthWithMargin, Min.y + OptionHeight}, - DownArrowString, Config, Mouse); - button_result Up = EvaluateButton(RenderBuffer, v2{Min.x + HalfWidthWithMargin + Config.Margin.x, Min.y}, - v2{Max.x, Min.y + OptionHeight}, - UpArrowString, Config, Mouse); - if (Down.Pressed) - { - Result.StartIndex += 1; - } - if (Up.Pressed) - { - Result.StartIndex -= 1; - } - - Result.StartIndex = GSClamp(0, Result.StartIndex, OptionsCount); - - return Result; + PushRenderQuad2D(RenderBuffer, LineBounds.Min, LineBounds.Max, Color); + return LineBounds; } -internal scroll_list_result -DrawSelectableOptionsList(render_command_buffer* RenderBuffer, v2 Min, v2 Max, - string* Options, s32 OptionsCount, - s32 Start, s32 Selected, interface_config Config, mouse_state Mouse) +internal rect +DrawListElement(string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) { - scroll_list_result Result = {}; - Result.IndexSelected = Selected; - Result.StartIndex = Start; - Result.Selection = Selection_None; + rect Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); - r32 OptionHeight = NewLineYOffset(*Config.Font) + (2 * Config.Margin.y); - r32 OptionOffset = OptionHeight + Config.Margin.y; + v2 LabelPosition = Bounds.Min + List->ElementLabelIndent; + DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor); - s32 OptionsToDisplay = ((Max.y - Min.y) / OptionHeight) - 2; - OptionsToDisplay = GSMin(OptionsToDisplay, (OptionsCount - Start)); - - string* OptionCursor = 0; - OptionCursor = Options + Start; - - v2 ButtonMin = v2{Min.x, Max.y - OptionHeight}; - v2 ButtonMax = v2{Max.x, Max.y}; - - for (s32 i = 0; i < OptionsToDisplay; i++) - { - button_result Button = EvaluateSelectableButton(RenderBuffer, ButtonMin, ButtonMax, - *OptionCursor, - Config, Mouse, (Selected == Start + i)); - if (Button.Pressed) - { - s32 SelectedIndex = Start + i; - if (SelectedIndex == Result.IndexSelected) - { - Result.Selection = Selection_Deselected; - Result.IndexSelected = -1; - } - else - { - Result.Selection = Selection_Selected; - Result.IndexSelected = Start + i; - } - } - - OptionCursor++; - - ButtonMin.y -= OptionOffset; - ButtonMax.y -= OptionOffset; - } - - r32 HalfWidthWithMargin = ((Max.x - Min.x) / 2.0f) - Config.Margin.x; - string DownArrowString = MakeStringLiteral(" v "); - string UpArrowString = MakeStringLiteral(" ^ "); - button_result Down = EvaluateButton(RenderBuffer, Min, v2{Min.x + HalfWidthWithMargin, Min.y + OptionHeight}, - DownArrowString, Config, Mouse); - button_result Up = EvaluateButton(RenderBuffer, v2{Min.x + HalfWidthWithMargin + Config.Margin.x, Min.y}, - v2{Max.x, Min.y + OptionHeight}, - UpArrowString, Config, Mouse); - if (Down.Pressed) - { - Result.StartIndex += 1; - } - if (Up.Pressed) - { - Result.StartIndex -= 1; - } - - Result.StartIndex = GSClamp(0, Result.StartIndex, OptionsCount); - - return Result; + List->ListElementsCount++; + return Bounds; } + internal r32 EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, v2 Min, v2 Max, r32 Current, mouse_state Mouse) { diff --git a/src/node/foldhaus_node_interface.cpp b/src/node/foldhaus_node_interface.cpp new file mode 100644 index 0000000..2e44c67 --- /dev/null +++ b/src/node/foldhaus_node_interface.cpp @@ -0,0 +1,498 @@ + +//////////////////////////////////////// +// +// Node Lister +// +/////////////////////////////////////// + +struct node_lister_operation_state +{ + search_lister SearchLister; + v2 ListPosition; +}; + +OPERATION_RENDER_PROC(RenderNodeLister) +{ + node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory; + + v2 TopLeft = OpState->ListPosition; + v2 Dimension = v2{300, 30}; + + // Filter the lister + OpState->SearchLister.Filter = State->ActiveTextEntry.Buffer; + FilterSearchLister(&OpState->SearchLister); + + // Display Search Lister + search_lister_result NodeListerResult = EvaluateSearchLister (RenderBuffer, TopLeft, Dimension, + MakeStringLiteral("Nodes List"), + OpState->SearchLister.SourceList, + OpState->SearchLister.FilteredIndexLUT, + OpState->SearchLister.FilteredListCount, + OpState->SearchLister.HotItem, + &State->ActiveTextEntry.Buffer, + State->ActiveTextEntry.CursorPosition, + State->Font, State->Interface, Mouse); +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeListerNextItem) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + OpState->SearchLister.HotItem = GetNextFilteredItem(OpState->SearchLister); +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeListerPrevItem) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + OpState->SearchLister.HotItem = GetPrevFilteredItem(OpState->SearchLister); +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeLister) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +FOLDHAUS_INPUT_COMMAND_PROC(SelectAndCloseNodeLister) +{ + node_lister_operation_state* OpState = GetCurrentOperationState(State->Modes, node_lister_operation_state); + s32 FilteredNodeIndex = OpState->SearchLister.HotItem; + if (FilteredNodeIndex >= 0) + { + s32 NodeIndex = OpState->SearchLister.FilteredIndexLUT[FilteredNodeIndex]; + PushNodeOnListFromSpecification(State->NodeList, (node_type)NodeIndex, + Mouse.Pos, State->Permanent); + } + CloseNodeLister(State, Event, Mouse); +} + +input_command UniverseViewCommads [] = { + { KeyCode_DownArrow, KeyCode_Invalid, Command_Began, NodeListerNextItem }, + { KeyCode_UpArrow, KeyCode_Invalid, Command_Began, NodeListerPrevItem }, + { KeyCode_Enter, KeyCode_Invalid, Command_Began, SelectAndCloseNodeLister }, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, CloseNodeLister }, + { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseNodeLister }, + DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, +}; + +FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) +{ + operation_mode* AddNodeOperation = ActivateOperationModeWithCommands(&State->Modes, UniverseViewCommads); + + AddNodeOperation->Render = RenderNodeLister; + + node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation, + &State->Modes, + node_lister_operation_state); + { + OpState->SearchLister.SourceListCount = NodeSpecificationsCount; + OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, string, OpState->SearchLister.SourceListCount); + { + for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) + { + OpState->SearchLister.SourceList[i] = MakeString( + NodeSpecifications[i].Name, + NodeSpecifications[i].NameLength); + } + } + OpState->SearchLister.Filter = MakeString(PushArray(&State->Modes.Arena, char, 64), 0, 64); + + OpState->SearchLister.FilteredListMax = OpState->SearchLister.SourceListCount; + OpState->SearchLister.FilteredListCount = 0; + OpState->SearchLister.FilteredIndexLUT = PushArray(&State->Modes.Arena, s32, OpState->SearchLister.SourceListCount); + } + + OpState->ListPosition = Mouse.Pos; + SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); +} + +//////////////////////////////////////// +// +// Node Color Picker +// +/////////////////////////////////////// + +struct color_picker_operation_state +{ + v4* ValueAddr; +}; + +internal void +CloseColorPicker(app_state* State) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand) +{ + CloseColorPicker(State); +} + +OPERATION_RENDER_PROC(RenderColorPicker) +{ + color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory; + + + b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, + v2{200, 200}, State->Interface, Mouse); + + if (ShouldClose) + { + CloseColorPicker(State); + } +} + +input_command ColorPickerCommands [] = { + { KeyCode_Esc, KeyCode_Invalid, Command_Began, CloseColorPickerCommand }, +}; + +internal void +OpenColorPicker(app_state* State, node_connection* Connection) +{ + operation_mode* ColorPickerMode = ActivateOperationModeWithCommands(&State->Modes, ColorPickerCommands); + ColorPickerMode->Render = RenderColorPicker; + + color_picker_operation_state* OpState = CreateOperationState(ColorPickerMode, + &State->Modes, + color_picker_operation_state); + OpState->ValueAddr = Connection->V4ValuePtr; +} + + +//////////////////////////////////////// +// +// Node Field Text Edit +// +/////////////////////////////////////// + +FOLDHAUS_INPUT_COMMAND_PROC(EndNodeFieldTextEdit) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command NodeFieldTextEditCommands [] = { + { KeyCode_Enter, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, EndNodeFieldTextEdit }, + DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY, +}; + +internal void +BeginNodeFieldTextEdit(app_state* State, node_connection* Connection) +{ + operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, + NodeFieldTextEditCommands); + + SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr); +} + +//////////////////////////////////////// +// +// Node Port Mouse Drag +// +/////////////////////////////////////// + +struct drag_node_port_operation_state +{ + node_interaction Interaction; +}; + +OPERATION_RENDER_PROC(RenderDraggingNodePort) +{ + drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory; + UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, + State->NodeRenderSettings, RenderBuffer); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNodePort) +{ + drag_node_port_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_port_operation_state); + + TryConnectNodes(OpState->Interaction, Mouse.Pos, State->NodeList, State->NodeRenderSettings); + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragNodePortInputCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNodePort }, +}; + +internal void +BeginDraggingNodePort(app_state* State, node_interaction Interaction) +{ + operation_mode* DragNodePortMode = ActivateOperationModeWithCommands( + &State->Modes, + DragNodePortInputCommands); + DragNodePortMode->Render = RenderDraggingNodePort; + + drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, + &State->Modes, + drag_node_port_operation_state); + OpState->Interaction = Interaction; +} + +//////////////////////////////////////// +// +// Node Field Mouse Drag +// +/////////////////////////////////////// + +OPERATION_RENDER_PROC(RenderDragNodeField) +{ + // TODO(Peter): + //UpdateDraggingNodeValue(Mouse.Pos, Mouse.OldPos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, State); +} + +internal void +BeginInteractWithNodeField(app_state* State, node_interaction Interaction) +{ + // TODO(Peter): +} + +//////////////////////////////////////// +// +// Node Mouse Drag +// +/////////////////////////////////////// + +struct drag_node_operation_state +{ + node_interaction Interaction; +}; + +OPERATION_RENDER_PROC(RenderDraggingNode) +{ + drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state); + UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, + State->NodeRenderSettings); +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDraggingNode) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragNodeInputCommands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDraggingNode }, +}; + +internal void +BeginDraggingNode(app_state* State, node_interaction Interaction) +{ + operation_mode* DragNodeMode = ActivateOperationModeWithCommands( + &State->Modes, + DragNodeInputCommands); + DragNodeMode->Render = RenderDraggingNode; + + drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, + &State->Modes, + drag_node_operation_state); + OpState->Interaction = Interaction; +} + +//////////////////////////////////////// +// +// Node View +// +/////////////////////////////////////// + +struct node_view_operation_state +{ + s32 SelectedNodeHandle; +}; + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + + node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings); + if (Node) + { + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, + State->NodeRenderSettings); + if (IsDraggingNodePort(NewInteraction)) + { + BeginDraggingNodePort(State, NewInteraction); + } + else if(IsDraggingNodeValue(NewInteraction)) + { + // TODO(Peter): This probably wants to live in a mouse held action + // the first frame we realize we're held over a field, just transition to + // drag node field + //BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings); + } + else // IsDraggingNode + { + OpState->SelectedNodeHandle = Node->Handle; + BeginDraggingNode(State, NewInteraction); + } + } + else + { + OpState->SelectedNodeHandle = 0; + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + + node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings); + if (Node) + { + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, + State->NodeRenderSettings); + if(IsDraggingNodeValue(NewInteraction)) + { + node_connection* Connection = Node->Connections + NewInteraction.InputValue; + struct_member_type InputType = Connection->Type; + + if (InputType == MemberType_r32) + { + BeginNodeFieldTextEdit(State, Connection); + } + else if (InputType == MemberType_v4) + { + OpenColorPicker(State, Connection); + } + } + } +} + +OPERATION_RENDER_PROC(RenderNodeView) +{ + node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory; + + DEBUG_TRACK_FUNCTION; + + MakeStringBuffer(NodeHeaderBuffer, 128); + + node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); + + node_list_iterator NodeIter = GetNodeListIterator(*State->NodeList); + while (NodeIteratorIsValid(NodeIter)) + { + node_header* Node = NodeIter.At; + + rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); + b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); + + if (Node == SelectedNode) + { + PushRenderQuad2D(RenderBuffer, NodeBounds.Min - v2{2, 2}, NodeBounds.Max + v2{2, 2}, WhiteV4); + } + + PushRenderQuad2D(RenderBuffer, NodeBounds.Min, NodeBounds.Max, v4{.5f, .5f, .5f, 1.f}); + + // TODO(Peter): This is just for debug purposes. We can remove and go back to just having + // Node->Name in DrawString + string NodeName = GetNodeName(*Node); + PrintF(&NodeHeaderBuffer, "%.*s: %d", NodeName.Length, NodeName.Memory, Node->Handle); + DrawString(RenderBuffer, NodeHeaderBuffer, State->NodeRenderSettings.Font, + v2{NodeBounds.Min.x + 5, NodeBounds.Max.y - (State->NodeRenderSettings.Font->PixelHeight + NODE_HEADER_HEIGHT + 5)}, + WhiteV4); + + for (s32 Connection = 0; Connection < Node->ConnectionsCount; Connection++) + { + v4 PortColor = State->NodeRenderSettings.PortColors[Node->Connections[Connection].Type]; + + // Inputs + if (ConnectionIsInput(Node, Connection)) + { + rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); + DrawPort(RenderBuffer, PortBounds, PortColor); + + // + // TODO(Peter): I don't like excluding OutputNode, feels too much like a special case + // but I don't want to get in to the meta programming right now. + // We should just generate a spec and struct member types for NodeType_OutputNode + // + // :ExcludingOutputNodeSpecialCase + // + if (Node->Type != NodeType_OutputNode && DrawFields) + { + node_specification Spec = NodeSpecifications[Node->Type]; + node_struct_member Member = Spec.MemberList[Connection]; + DrawString(RenderBuffer, MakeString(Member.Name), + State->NodeRenderSettings.Font, + v2{PortBounds.Min.x - 8, PortBounds.Min.y}, WhiteV4, Align_Right); + } + + rect ValueBounds = CalculateNodeInputValueBounds(Node, Connection, State->NodeRenderSettings); + DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); + + // NOTE(Peter): its way easier to draw the connection on the input port b/c its a 1:1 relationship, + // whereas output ports might have many connections, they really only know about the most recent one + // Not sure if this is a problem. We mostly do everything backwards here, starting at the + // most downstream node and working back up to find dependencies. + if (ConnectionHasUpstreamConnection(Node, Connection)) + { + rect ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); + v2 InputCenter = CalculateRectCenter(PortBounds); + v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); + PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); + } + } + + // Outputs + if (ConnectionIsOutput(Node, Connection)) + { + rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); + DrawPort(RenderBuffer, PortBounds, PortColor); + + if (DrawFields) + { + node_specification Spec = NodeSpecifications[Node->Type]; + node_struct_member Member = Spec.MemberList[Connection]; + DrawString(RenderBuffer, MakeString(Member.Name), + State->NodeRenderSettings.Font, + v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); + } + + rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); + DrawValueDisplay(RenderBuffer, ValueBounds, Node->Connections[Connection], State->NodeRenderSettings.Font); + } + + for (s32 Button = 0; Button < 3; Button++) + { + rect ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); + PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); + } + } + + Next(&NodeIter); + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(NodeViewDeleteNode) +{ + node_view_operation_state* OpState = GetCurrentOperationState(State->Modes, node_view_operation_state); + if (OpState->SelectedNodeHandle > 0) + { + node_header* SelectedNode = GetNodeWithHandle(State->NodeList, OpState->SelectedNodeHandle); + FreeNodeOnList(State->NodeList, SelectedNode); + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(CloseNodeView) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command NodeViewCommands [] = { + { KeyCode_Tab, KeyCode_Invalid, Command_Began, CloseNodeView}, + { KeyCode_A, KeyCode_Invalid, Command_Began, OpenNodeLister}, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, NodeViewBeginMouseDragInteraction}, + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, NodeViewBeginMouseSelectInteraction}, + { KeyCode_X, KeyCode_Invalid, Command_Began, NodeViewDeleteNode}, +}; + +FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView) +{ + operation_mode* NodeViewMode = ActivateOperationModeWithCommands(&State->Modes, NodeViewCommands); + NodeViewMode->Render = RenderNodeView; + + node_view_operation_state* OpState = CreateOperationState(NodeViewMode, + &State->Modes, + node_view_operation_state); + + OpState->SelectedNodeHandle = 0; +} diff --git a/src/panels/foldhaus_panel_animation_timeline.h b/src/panels/foldhaus_panel_animation_timeline.h new file mode 100644 index 0000000..1e496b0 --- /dev/null +++ b/src/panels/foldhaus_panel_animation_timeline.h @@ -0,0 +1,492 @@ +// TODO +// [x] - Moving animation blocks +// [x] - dragging beginning and end of time blocks +// [] - creating a timeblock with a specific animation +// [x] - play, pause, stop, +// [] - setting the start and end of the animation system +// [] - displaying multiple layers + +inline r32 +GetTimeFromPointInAnimationPanel(v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) +{ + r32 StartFrameTime = (r32)StartFrame * SecondsPerFrame; + r32 EndFrameTime = (r32)EndFrame * SecondsPerFrame; + r32 TimeAtPoint = GSRemap(Point.x, PanelBounds.Min.x, PanelBounds.Max.x, StartFrameTime, EndFrameTime); + return TimeAtPoint; +} + +inline s32 +GetFrameFromPointInAnimationPanel (v2 Point, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) +{ + r32 TimeAtPoint = GetTimeFromPointInAnimationPanel(Point, PanelBounds, StartFrame, EndFrame, SecondsPerFrame); + s32 FrameAtPoint = (s32)(TimeAtPoint * SecondsPerFrame); + return FrameAtPoint; +} + +inline s32 +GetXPositionFromTimeInAnimationPanel (r32 Time, rect PanelBounds, s32 StartFrame, s32 EndFrame, r32 SecondsPerFrame) +{ + r32 StartFrameTime = (r32)StartFrame * SecondsPerFrame; + r32 EndFrameTime = (r32)EndFrame * SecondsPerFrame; + s32 XPositionAtTime = GSRemap(Time, StartFrameTime, EndFrameTime, PanelBounds.Min.x, PanelBounds.Max.x); + return XPositionAtTime; +} + +internal void +AddAnimationBlock(r32 StartTime, r32 EndTime, animation_proc* Proc, animation_system* AnimationSystem) +{ + animation_block NewBlock = {0}; + NewBlock.StartTime = StartTime; + NewBlock.EndTime = EndTime; + NewBlock.Proc = Proc; + AddAnimationBlock(NewBlock, AnimationSystem); +} + +#define NEW_ANIMATION_BLOCK_DURATION 3 +internal void +AddAnimationBlockAtCurrentTime (animation_proc* Proc, animation_system* System) +{ + r32 CurrentTime = System->Time; + AddAnimationBlock(CurrentTime, CurrentTime + NEW_ANIMATION_BLOCK_DURATION, Proc, System); +} + +internal void +DeleteAnimationBlock(animation_block_handle AnimationBlockHandle, app_state* State) +{ + RemoveAnimationBlock(State->SelectedAnimationBlockHandle, &State->AnimationSystem); + State->SelectedAnimationBlockHandle = {0}; +} + +internal void +SelectAnimationBlock(animation_block_handle BlockHandle, app_state* State) +{ + State->SelectedAnimationBlockHandle = BlockHandle; +} + +internal void +DeselectCurrentAnimationBlock(app_state* State) +{ + State->SelectedAnimationBlockHandle = {}; +} + +FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) +{ + if (AnimationBlockHandleIsValid(State->SelectedAnimationBlockHandle)) + { + DeleteAnimationBlock(State->SelectedAnimationBlockHandle, State); + } +} + +// +// Drag Time Marker +// + +OPERATION_STATE_DEF(drag_time_marker_operation_state) +{ + rect TimelineBounds; + s32 StartFrame; + s32 EndFrame; +}; + +OPERATION_RENDER_PROC(UpdateDragTimeMarker) +{ + drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory; + r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->StartFrame, OpState->EndFrame, State->AnimationSystem.SecondsPerFrame); + State->AnimationSystem.Time = TimeAtMouseX; +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragTimeMarkerCommands [] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragTimeMarker }, +}; + +internal void +StartDragTimeMarker(rect TimelineBounds, s32 PanelStartFrame, s32 PanelEndFrame, app_state* State) +{ + operation_mode* DragTimeMarkerMode = ActivateOperationModeWithCommands(&State->Modes, DragTimeMarkerCommands, UpdateDragTimeMarker); + + drag_time_marker_operation_state* OpState = CreateOperationState(DragTimeMarkerMode, + &State->Modes, + drag_time_marker_operation_state); + OpState->StartFrame = PanelStartFrame; + OpState->EndFrame = PanelEndFrame ; + OpState->TimelineBounds = TimelineBounds; +} + +// -------------------- + +// +// Drag Animation Clip +// + +#define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10 + +OPERATION_STATE_DEF(drag_animation_clip_state) +{ + rect TimelineBounds; + r32 AnimationPanel_StartFrame; + r32 AnimationPanel_EndFrame; + r32 SelectedClip_InitialStartTime; + r32 SelectedClip_InitialEndTime; +}; + +OPERATION_RENDER_PROC(UpdateDragAnimationClip) +{ + drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; + + s32 ClipInitialStartTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialStartTime, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); + s32 ClipInitialEndTimeXPosition = GetXPositionFromTimeInAnimationPanel(OpState->SelectedClip_InitialEndTime, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); + + r32 TimeAtMouseDownX = GetTimeFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); + r32 TimeAtMouseX = GetTimeFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->AnimationPanel_StartFrame, OpState->AnimationPanel_EndFrame, State->AnimationSystem.SecondsPerFrame); + r32 TimeOffset = TimeAtMouseX - TimeAtMouseDownX; + + animation_block* AnimationBlock = GetAnimationBlockWithHandle(State->SelectedAnimationBlockHandle, &State->AnimationSystem); + + if (GSAbs(Mouse.DownPos.x - ClipInitialStartTimeXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) + { + AnimationBlock->StartTime = OpState->SelectedClip_InitialStartTime + TimeOffset; + } + else if (GSAbs(Mouse.DownPos.x - ClipInitialEndTimeXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) + { + AnimationBlock->EndTime = OpState->SelectedClip_InitialEndTime + TimeOffset; + } + else + { + AnimationBlock->StartTime = OpState->SelectedClip_InitialStartTime + TimeOffset; + AnimationBlock->EndTime = OpState->SelectedClip_InitialEndTime + TimeOffset; + } +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDragAnimationClip) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragAnimationClipCommands [] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragAnimationClip }, +}; + +internal void +SelectAndBeginDragAnimationBlock(animation_block_handle BlockHandle, s32 PanelStartFrame, s32 PanelEndFrame, rect TimelineBounds, app_state* State) +{ + SelectAnimationBlock(BlockHandle, State); + + operation_mode* DragAnimationClipMode = ActivateOperationModeWithCommands(&State->Modes, DragAnimationClipCommands, UpdateDragAnimationClip); + + drag_animation_clip_state* OpState = CreateOperationState(DragAnimationClipMode, + &State->Modes, + drag_animation_clip_state); + OpState->TimelineBounds = TimelineBounds; + OpState->AnimationPanel_StartFrame = PanelStartFrame; + OpState->AnimationPanel_EndFrame = PanelEndFrame ; + + animation_block* SelectedBlock = GetAnimationBlockWithHandle(BlockHandle, &State->AnimationSystem); + OpState->SelectedClip_InitialStartTime = SelectedBlock->StartTime; + OpState->SelectedClip_InitialEndTime = SelectedBlock->EndTime; +} + +// ------------------- + +FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) +{ + panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); + r32 MouseDownPositionPercent = (Mouse.Pos.x - ActivePanel.Bounds.Min.x) / Width(ActivePanel.Bounds); + r32 NewBlockTimeStart = MouseDownPositionPercent * State->AnimationSystem.AnimationEnd; +#define NEW_BLOCK_DURATION 1 + r32 NewBlockTimeEnd = NewBlockTimeStart + NEW_BLOCK_DURATION; + + animation_block Block = {0}; + Block.StartTime = NewBlockTimeStart; + Block.EndTime = NewBlockTimeEnd; + Block.Proc = TestPatternThree; + + animation_block_handle NewBlockHandle = AddAnimationBlock(Block, &State->AnimationSystem); + SelectAnimationBlock(NewBlockHandle, State); +} + +input_command AnimationTimeline_Commands[] = { + { KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand }, + { KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand }, +}; + +PANEL_INIT_PROC(AnimationTimeline_Init) +{ + +} + +PANEL_CLEANUP_PROC(AnimationTimeline_Cleanup) +{ + +} + +internal r32 +DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBuffer, s32 StartFrame, s32 EndFrame, rect PanelBounds, mouse_state Mouse, app_state* State) +{ + MakeStringBuffer(TempString, 256); + + s32 FrameCount = EndFrame - StartFrame; + + r32 FrameBarHeight = 24; + v2 FrameBarMin = v2{PanelBounds.Min.x, PanelBounds.Max.y - FrameBarHeight}; + v2 FrameBarMax = PanelBounds.Max; + + PushRenderQuad2D(RenderBuffer, FrameBarMin, FrameBarMax, v4{.16f, .16f, .16f, 1.f}); + + // Mouse clicked inside frame nubmer bar -> change current frame on timeline + if (MouseButtonTransitionedDown(Mouse.LeftButtonState) + && PointIsInRange(Mouse.DownPos, FrameBarMin, FrameBarMax)) + { + StartDragTimeMarker(rect{FrameBarMin, FrameBarMax}, StartFrame, EndFrame, State); + } + + // Frame Ticks + for (s32 f = 0; f < FrameCount; f += 10) + { + s32 Frame = StartFrame + f; + PrintF(&TempString, "%d", Frame); + + r32 FramePercent = (r32)f / (r32)FrameCount; + r32 FrameX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, FramePercent); + v2 FrameTextPos = v2{FrameX, FrameBarMin.y + 2}; + DrawString(RenderBuffer, TempString, State->Interface.Font, FrameTextPos, WhiteV4); + + // Frame Vertical Slices + v2 LineTop = v2{FrameX, FrameBarMin.y}; + v2 LineBottom = v2{FrameX + 1, PanelBounds.Min.y}; + PushRenderQuad2D(RenderBuffer, LineTop, LineBottom, v4{.16f, .16f, .16f, 1.f}); + } + + return FrameBarMin.y; +} + +internal rect +DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, r32 SecondsPerFrame, s32 FrameCount, s32 StartFrame, rect TimelineBounds, render_command_buffer* RenderBuffer) +{ + rect BlockBounds = {}; + + r32 TimelineWidth = Width(TimelineBounds); + + s32 BlockStartFrame = AnimationBlock.StartTime / SecondsPerFrame; + r32 StartFramePercent = (r32)(BlockStartFrame - StartFrame) / (r32)FrameCount; + r32 StartPosition = TimelineWidth * StartFramePercent; + + s32 BlockEndFrame = AnimationBlock.EndTime / SecondsPerFrame; + r32 EndFramePercent = (r32)(BlockEndFrame - StartFrame) / (r32)FrameCount; + r32 EndPosition = TimelineWidth * EndFramePercent; + + BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, 25}; + BlockBounds.Max = TimelineBounds.Min + v2{EndPosition, 75}; + + PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor); + PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4); + + return BlockBounds; +} + +internal animation_block_handle +DrawAnimationTimeline (animation_system* AnimationSystem, s32 StartFrame, s32 EndFrame, rect PanelBounds, animation_block_handle SelectedBlockHandle, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse) +{ + string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); + s32 FrameCount = EndFrame - StartFrame; + + animation_block_handle Result = SelectedBlockHandle; + + r32 AnimationPanelHeight = PanelBounds.Max.y - PanelBounds.Min.y; + r32 AnimationPanelWidth = PanelBounds.Max.x - PanelBounds.Min.x; + + { + s32 FirstPlayableFrame = (AnimationSystem->AnimationStart / AnimationSystem->SecondsPerFrame); + s32 LastPlayableFrame = (AnimationSystem->AnimationEnd / AnimationSystem->SecondsPerFrame); + + r32 FirstPlayablePercentX = ((r32)(FirstPlayableFrame - StartFrame) / (r32)FrameCount); + r32 LastPlayablePercentX = ((r32)(LastPlayableFrame - StartFrame) / (r32)FrameCount); + + v2 PlayableMin = v2{(FirstPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Min.y }; + v2 PlayableMax = v2{(LastPlayablePercentX * AnimationPanelWidth) + PanelBounds.Min.x, PanelBounds.Max.y }; + + PushRenderQuad2D(RenderBuffer, PanelBounds.Min, PanelBounds.Max, v4{.16f, .16f, .16f, 1.f}); + PushRenderQuad2D(RenderBuffer, PlayableMin, PlayableMax, v4{.22f, .22f, .22f, 1.f}); + } + + r32 FrameBarBottom = DrawFrameBar(AnimationSystem, RenderBuffer, StartFrame, EndFrame, PanelBounds, Mouse, State); + + // Animation Blocks + rect TimelineBounds = rect{ PanelBounds.Min, v2{PanelBounds.Max.x, FrameBarBottom} }; + b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Mouse.LeftButtonState); + for (u32 i = 0; i < AnimationSystem->BlocksCount; i++) + { + animation_block_entry* AnimationBlockEntry = GetEntryAtIndex(i, AnimationSystem); + if (AnimationBlockIsFree(*AnimationBlockEntry)) { continue; } + + animation_block_handle CurrentBlockHandle = {}; + CurrentBlockHandle.Index = i; + CurrentBlockHandle.Generation = AnimationBlockEntry->Generation; + + animation_block AnimationBlockAt = AnimationBlockEntry->Block; + + v4 BlockColor = BlackV4; + if (AnimationBlockHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle)) + { + BlockColor = PinkV4; + } + + rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AnimationSystem->SecondsPerFrame, FrameCount, StartFrame, TimelineBounds, RenderBuffer); + + if (PointIsInRange(Mouse.Pos, BlockBounds.Min, BlockBounds.Max) + && MouseButtonTransitionedDown(Mouse.LeftButtonState)) + { + MouseDownAndNotHandled = false; + SelectAndBeginDragAnimationBlock(CurrentBlockHandle, StartFrame, EndFrame, TimelineBounds, State); + } + } + + // Time Slider + s32 SliderFrame = AnimationSystem->Time / AnimationSystem->SecondsPerFrame; + r32 TimePercent = (r32)(SliderFrame - StartFrame) / (r32)FrameCount; + r32 SliderX = PanelBounds.Min.x + (AnimationPanelWidth * TimePercent); + v2 SliderMin = v2{SliderX, PanelBounds.Min.y}; + v2 SliderMax = v2{SliderX + 1, PanelBounds.Max.y - 25}; + v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f}; + + PushRenderQuad2D(RenderBuffer, SliderMin, SliderMax, TimeSliderColor); + + r32 SliderHalfWidth = 10; + v2 HeadMin = v2{SliderX - SliderHalfWidth, SliderMax.y}; + v2 HeadMax = v2{SliderX + SliderHalfWidth, PanelBounds.Max.y}; + PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor); + + PrintF(&TempString, "%d", SliderFrame); + DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{4, 4}, WhiteV4); + + if (MouseDownAndNotHandled && PointIsInRect(Mouse.Pos, TimelineBounds)) + { + DeselectCurrentAnimationBlock(State); + } + return Result; +} + +struct animation_clip +{ + char* Name; + s32 NameLength; + animation_proc* Proc; +}; + +s32 GlobalAnimationClipsCount = 3; +animation_clip GlobalAnimationClips[] = { + { "Test Pattern One", 16, TestPatternOne }, + { "Test Pattern Two", 16, TestPatternTwo }, + { "Test Pattern Three", 18, TestPatternThree }, +}; + +internal void +DrawAnimationClipsList(rect PanelBounds, mouse_state Mouse, render_command_buffer* RenderBuffer, app_state* State) +{ + v4 LineBGColors[] = { + { .16f, .16f, .16f, 1.f }, + { .18f, .18f, .18f, 1.f }, + }; + + interface_list List = {}; + + List.LineBGColors = LineBGColors; + List.LineBGColorsCount = sizeof(LineBGColors) / sizeof(LineBGColors[0]); + List.LineBGHoverColor = v4{ .22f, .22f, .22f, 1.f }; + List.TextColor = WhiteV4; + List.ListBounds = PanelBounds; + List.ListElementDimensions = v2{ + Width(PanelBounds), + (r32)(State->Interface.Font->PixelHeight + 8), + }; + List.ElementLabelIndent = v2{10, 4}; + + string TitleString = MakeStringLiteral("Animation Clips"); + DrawListElement(TitleString, &List, Mouse, RenderBuffer, State->Interface); + + for (s32 i = 0; i < GlobalAnimationClipsCount; i++) + { + animation_clip Clip = GlobalAnimationClips[i]; + string ClipName = MakeString(Clip.Name, Clip.NameLength); + rect ElementBounds = DrawListElement(ClipName, &List, Mouse, RenderBuffer, State->Interface); + + if (MouseButtonTransitionedDown(Mouse.LeftButtonState) + && PointIsInRect(Mouse.DownPos, ElementBounds)) + { + AddAnimationBlockAtCurrentTime(Clip.Proc, &State->AnimationSystem); + } + } + +} + +PANEL_RENDER_PROC(AnimationTimeline_Render) +{ + animation_block_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; + + r32 OptionsRowHeight = 25; + rect AnimationClipListBounds = rect{ + PanelBounds.Min, + v2{PanelBounds.Min.x + 300, PanelBounds.Max.y - OptionsRowHeight}, + }; + rect TimelineBounds = rect{ + v2{AnimationClipListBounds.Max.x, PanelBounds.Min.y}, + v2{PanelBounds.Max.x, PanelBounds.Max.y - OptionsRowHeight}, + }; + if (Height(TimelineBounds) > 0) + { + DrawAnimationClipsList(AnimationClipListBounds, Mouse, RenderBuffer, State); + + s32 FrameStart = (s32)(State->AnimationSystem.AnimationStart / State->AnimationSystem.SecondsPerFrame); + s32 FrameEnd = (s32)(State->AnimationSystem.AnimationEnd / State->AnimationSystem.SecondsPerFrame); + SelectedBlockHandle = DrawAnimationTimeline(&State->AnimationSystem, + FrameStart - 20, FrameEnd + 20, + TimelineBounds, + SelectedBlockHandle, + RenderBuffer, State, Mouse); + } + + v2 OptionsRowMin = v2{ PanelBounds.Min.x, TimelineBounds.Max.y }; + v2 OptionsRowMax = PanelBounds.Max; + panel_result AnimationPanel = EvaluatePanel(RenderBuffer, OptionsRowMin, OptionsRowMax, + 0, State->Interface); + + r32 ButtonWidth = 35; + v2 ButtonMin = v2{0, 0}; + v2 ButtonMax = v2{35, OptionsRowHeight - 2}; + v2 ButtonAt = v2{OptionsRowMin.x + 1, OptionsRowMin.y + 1}; + + button_result PauseResult = EvaluateButton(RenderBuffer, + ButtonAt + ButtonMin, ButtonAt + ButtonMax, + MakeStringLiteral("Pause"), + State->Interface, Mouse); + ButtonAt.x += ButtonWidth + 2; + button_result PlayResult = EvaluateButton(RenderBuffer, + ButtonAt + ButtonMin, ButtonAt + ButtonMax, + MakeStringLiteral("Play"), + State->Interface, Mouse); + ButtonAt.x += ButtonWidth + 2; + button_result StopResult = EvaluateButton(RenderBuffer, + ButtonAt + ButtonMin, ButtonAt + ButtonMax, + MakeStringLiteral("Stop"), + State->Interface, Mouse); + + if (PauseResult.Pressed) + { + State->AnimationSystem.TimelineShouldAdvance = false; + } + + if (PlayResult.Pressed) + { + State->AnimationSystem.TimelineShouldAdvance = true; + } + + if (StopResult.Pressed) + { + State->AnimationSystem.TimelineShouldAdvance = false; + State->AnimationSystem.Time = 0; + } +} diff --git a/src/panels/foldhaus_panel_dmx_view.h b/src/panels/foldhaus_panel_dmx_view.h new file mode 100644 index 0000000..1986403 --- /dev/null +++ b/src/panels/foldhaus_panel_dmx_view.h @@ -0,0 +1,77 @@ +PANEL_INIT_PROC(DMXView_Init) +{ + +} + +PANEL_CLEANUP_PROC(DMXView_Cleanup) +{ + +} + +PANEL_RENDER_PROC(DMXView_Render) +{ +#if 0 + DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay); + + universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory; + + string TitleBarString = InitializeEmptyString(PushArray(State->Transient, char, 64), 64); + + v2 DisplayArea_Dimension = v2{600, 600}; + + v2 DisplayContents_Offset = OpState->DisplayOffset; + + // + // TODO(Peter): I don't like this. Dragging the Universe view should be an operation mode, just + // like rotating the 3D view, but modes don't have access to the state of modes above them in the stack + // (and attempting to cast those states to the appropriate type seems risky) + // + // :NeedToPassStateDownModeChain + // + if (OpState->MouseDown) + { + DisplayContents_Offset += (Mouse.Pos - Mouse.DownPos); + } + + v2 DisplayArea_TopLeft = v2{300, (r32)RenderBuffer->ViewHeight - 50} + DisplayContents_Offset; + v2 UniverseDisplayDimension = v2{100, 100} * OpState->Zoom; + v2 Padding = v2{25, 50} * OpState->Zoom; + + v2 UniverseDisplayTopLeft = DisplayArea_TopLeft; + + sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer; + while(UniverseList) + { + for (s32 UniverseIdx = 0; + UniverseIdx < UniverseList->Used; + UniverseIdx++) + { + sacn_universe* Universe = UniverseList->Universes + UniverseIdx; + DrawSACNUniversePixels(RenderBuffer, Universe, UniverseDisplayTopLeft, UniverseDisplayDimension); + + + if (OpState->Zoom > .5f) + { + v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12}; + PrintF(&TitleBarString, "Universe %d", Universe->Universe); + DrawString(RenderBuffer, TitleBarString, State->Interface.Font, + TitleDisplayStart, WhiteV4); + } + + UniverseDisplayTopLeft.x += UniverseDisplayDimension.x + Padding.x; + if (UniverseDisplayTopLeft.x > DisplayArea_TopLeft.x + DisplayArea_Dimension.x) + { + UniverseDisplayTopLeft.x = DisplayArea_TopLeft.x; + UniverseDisplayTopLeft.y -= UniverseDisplayDimension.y + Padding.y; + } + + if (UniverseDisplayTopLeft.y < DisplayArea_TopLeft.y - DisplayArea_Dimension.y) + { + break; + } + + } + UniverseList = UniverseList->Next; + } +#endif +} \ No newline at end of file diff --git a/src/panels/foldhaus_panel_hierarchy.h b/src/panels/foldhaus_panel_hierarchy.h new file mode 100644 index 0000000..529d3c7 --- /dev/null +++ b/src/panels/foldhaus_panel_hierarchy.h @@ -0,0 +1,78 @@ +PANEL_INIT_PROC(HierarchyView_Init) +{ + +} + +PANEL_CLEANUP_PROC(HierarchyView_Cleanup) +{ + +} + +PANEL_RENDER_PROC(HierarchyView_Render) +{ + r32 PanelWidth = PanelBounds.Max.x - PanelBounds.Min.x; + r32 PanelHeight = PanelBounds.Max.y - PanelBounds.Min.y; + + v4 LineBGColors[] = { + { .16f, .16f, .16f, 1.f }, + { .18f, .18f, .18f, 1.f }, + }; + + interface_list List = {}; + List.LineBGColors = LineBGColors; + List.LineBGColorsCount = sizeof(LineBGColors) / sizeof(LineBGColors[0]); + List.LineBGHoverColor = v4{ .22f, .22f, .22f, 1.f }; + List.ListBounds = PanelBounds; + List.ListElementDimensions = v2{ + Width(PanelBounds), + (r32)(State->Interface.Font->PixelHeight + 8), + }; + + v2 TextOffset = v2{10, 4}; + string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); + + s32 LineCount = (s32)(PanelHeight / List.ListElementDimensions.y) + 1; + for (s32 i = 0; i < LineCount; i++) + { + rect ElementBounds = DrawListElementBackground(&List, Mouse, RenderBuffer); + + if (i < State->ActiveAssemblyIndecies.Used) + { + array_entry_handle AssemblyHandle = *GetElementAtIndex(i, State->ActiveAssemblyIndecies); + assembly Assembly = *GetElementWithHandle(AssemblyHandle, State->AssemblyList); + PrintF(&TempString, "%S", Assembly.Name); + + DrawString(RenderBuffer, TempString, State->Interface.Font, ElementBounds.Min + TextOffset, WhiteV4); + + PrintF(&TempString, "X"); + + v2 XLowerRight = v2{ElementBounds.Max.x - 25, ElementBounds.Min.y + TextOffset.y}; + v2 XLowerLeft = DrawString(RenderBuffer, TempString, State->Interface.Font, XLowerRight, WhiteV4, Align_Right); + + if (MouseButtonTransitionedUp(Mouse.LeftButtonState) + && PointIsInRange(Mouse.Pos, XLowerLeft, ElementBounds.Max)) + { + UnloadAssembly(AssemblyHandle.Index, State, Context); + } + } + else if (i == State->ActiveAssemblyIndecies.Used) + { + PrintF(&TempString, "+ Add Assembly"); + v2 TextMinX = ElementBounds.Min + TextOffset; + DrawString(RenderBuffer, TempString, State->Interface.Font, TextMinX, WhiteV4); + + if (MouseButtonTransitionedUp(Mouse.LeftButtonState) + && PointIsInRange(Mouse.Pos, ElementBounds.Min, ElementBounds.Max)) + { + char FilePath[256]; + b32 Success = Context.PlatformGetFilePath(FilePath, 256, "Foldhaus Files\0*.fold\0\0"); + if (Success) + { + LoadAssembly(State, Context, FilePath); + } + } + } + + List.ListElementsCount++; + } +} \ No newline at end of file diff --git a/src/panels/foldhaus_panel_profiler.h b/src/panels/foldhaus_panel_profiler.h new file mode 100644 index 0000000..29f27ab --- /dev/null +++ b/src/panels/foldhaus_panel_profiler.h @@ -0,0 +1,199 @@ +PANEL_INIT_PROC(ProfilerView_Init) +{ + +} + +PANEL_CLEANUP_PROC(ProfilerView_Cleanup) +{ + +} + +internal void +RenderProfiler_ScopeVisualization(render_command_buffer* RenderBuffer, + interface_config Interface, mouse_state Mouse, + v2 Min, v2 Max, + debug_frame* VisibleFrame, memory_arena* Memory) +{ + v4 ThreadColors[] = { + v4{.73f, .33f, .83f, 1}, + v4{0, .50f, .50f, 1}, + v4{.83f, 0, 0, 1}, + v4{.33f, .49f, .83f, 1}, + v4{.74f, .40f, .25f, 1}, + }; + + r32 Width = Max.x - Min.x; + r32 DepthHeight = 64; + + s64 FrameStartCycles = VisibleFrame->FrameStartCycles; + s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; + + debug_scope_record_list* ThreadScopeCalls = GetScopeListForThreadInFrame(GlobalDebugServices, + VisibleFrame); + + MakeStringBuffer(String, 256); + for (s32 i = 0; i < ThreadScopeCalls->Count; i++) + { + scope_record* Record = ThreadScopeCalls->Calls + i; + scope_name* Name = GetOrAddNameHashEntry(VisibleFrame, Record->NameHash); + r32 PercentStart = (r32)(Record->StartCycles - FrameStartCycles) / (r32)FrameTotalCycles; + r32 PercentEnd = (r32)(Record->EndCycles - FrameStartCycles) / (r32)FrameTotalCycles; + + v2 ScopeMin = v2{Min.x + (Width * PercentStart), Max.y - ((Record->CallDepth + 1) * DepthHeight)}; + v2 ScopeMax = v2{Min.x + (Width * PercentEnd), ScopeMin.y + (DepthHeight - 4)}; + + if ((ScopeMax.x - ScopeMin.x) >= 1) + { + v4 Color = ThreadColors[0]; + if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax)) + { + Color = GreenV4; + } + + PushRenderQuad2D(RenderBuffer, ScopeMin, ScopeMax, Color); + PushRenderBoundingBox2D(RenderBuffer, ScopeMin, ScopeMax, 1, BlackV4); + + if (PointIsInRange(Mouse.Pos, ScopeMin, ScopeMax)) + { + PushRenderQuad2D(RenderBuffer, Mouse.Pos, Mouse.Pos + v2{256, 32}, BlackV4); + PrintF(&String, "%.*s : %d - %d", Name->Name.Length, Name->Name.Memory, Record->StartCycles, Record->EndCycles); + DrawString(RenderBuffer, String, Interface.Font, Mouse.Pos, WhiteV4); + } + } + } +} + +internal void +RenderProfiler_ListVisualization(render_command_buffer* RenderBuffer, + interface_config Interface, mouse_state Mouse, + v2 Min, v2 Max, + debug_frame* VisibleFrame, memory_arena* Memory) +{ + MakeStringBuffer(String, 256); + + r32 YAt = Max.y - Interface.Font->PixelHeight; + r32 Column0X = Min.x; + r32 Column1X = Column0X + 256; + r32 Column2X = Column1X + 128; + r32 Column3X = Column2X + 128; + r32 Column4X = Column3X + 100; + + for (s32 n = 0; n < VisibleFrame->ScopeNamesMax; n++) + { + scope_name NameEntry = VisibleFrame->ScopeNamesHash[n]; + if (NameEntry.Hash != 0) + { + collated_scope_record* CollatedRecord = VisibleFrame->CollatedScopes + n; + + PrintF(&String, "%.*s", NameEntry.Name.Length, NameEntry.Name.Memory); + DrawString(RenderBuffer, String, Interface.Font, v2{Column0X, YAt}, WhiteV4); + + PrintF(&String, "%f", CollatedRecord->PercentFrameTime); + DrawString(RenderBuffer, String, Interface.Font, v2{Column1X, YAt}, WhiteV4); + + PrintF(&String, "%fs", CollatedRecord->TotalSeconds); + DrawString(RenderBuffer, String, Interface.Font, v2{Column2X, YAt}, WhiteV4); + + PrintF(&String, "%dcy", CollatedRecord->TotalCycles); + DrawString(RenderBuffer, String, Interface.Font, v2{Column3X, YAt}, WhiteV4); + + PrintF(&String, "%d calls", CollatedRecord->CallCount); + DrawString(RenderBuffer, String, Interface.Font, v2{Column4X, YAt}, WhiteV4); + + YAt -= Interface.Font->PixelHeight + 4; + + if (YAt < Min.y) { break; } + } + } +} + +PANEL_RENDER_PROC(ProfilerView_Render) +{ + memory_arena* Memory = &State->Transient; + string String = InitializeEmptyString(PushArray(Memory, char, 256), 256); + + v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 }; + + r32 FrameListHeight = 64; + v2 FrameListMin = v2{PanelBounds.Min.x + 16, PanelBounds.Max.y - (16 + FrameListHeight)}; + v2 FrameListMax = v2{PanelBounds.Max.x - 16, PanelBounds.Max.y - 16}; + + r32 FrameListPadding = 4; + r32 FrameListInnerWidth = (FrameListMax.x - FrameListMin.x) - (FrameListPadding * 2); + + r32 SingleFrameStep = FrameListInnerWidth / DEBUG_FRAME_COUNT; + r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2); + + PushRenderBoundingBox2D(RenderBuffer, FrameListMin, FrameListMax, 2, WhiteV4); + + if (PointIsInRange(Mouse.Pos, FrameListMin, FrameListMax) && + MouseButtonHeldDown(Mouse.LeftButtonState)) + { + r32 LocalMouseX = (Mouse.Pos.x - FrameListMin.x) + FrameListPadding; + s32 ClosestFrameIndex = (LocalMouseX / SingleFrameStep); + + if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT) + { + GlobalDebugServices->RecordFrames = false; + GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex; + } + } + + for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++) + { + v2 Min = v2{FrameListMin.x + FrameListPadding + (F * SingleFrameStep), FrameListMin.y + 4}; + v2 Max = v2{Min.x + SingleFrameWidth, FrameListMax.y - 4}; + + s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F); + if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; } + v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)]; + PushRenderQuad2D(RenderBuffer, Min, Max, Color); + } + + debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); + s64 FrameStartCycles = VisibleFrame->FrameStartCycles; + s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; + + PrintF(&String, "Frame %d - Total Cycles: %lld", + GlobalDebugServices->CurrentDebugFrame - 1, + FrameTotalCycles); + DrawString(RenderBuffer, String, State->Interface.Font, FrameListMin - v2{0, 32}, WhiteV4); + + v2 ButtonMin = v2{FrameListMax.x - 128, FrameListMin.y - 32}; + v2 ButtonMax = ButtonMin + v2{128, 28}; + button_result ShouldResumeRecording = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, + MakeString("Resume Recording"), State->Interface, Mouse); + if (ShouldResumeRecording.Pressed) + { + GlobalDebugServices->RecordFrames = true; + } + + ButtonMin = v2{FrameListMin.x, FrameListMin.y - 60}; + ButtonMax = v2{FrameListMin.x + 128, FrameListMin.y - 42}; + button_result ActivateScopeView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, + MakeString("Scope View"), State->Interface, Mouse); + + ButtonMin.x += 152; + ButtonMax.x += 152; + button_result ActivateListView = EvaluateButton(RenderBuffer, ButtonMin, ButtonMax, + MakeString("List View"), State->Interface, Mouse); + + if (ActivateScopeView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; } + if (ActivateListView.Pressed) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; } + + v2 ViewModeMin = v2{FrameListMin.x, PanelBounds.Min.y}; + v2 ViewModeMax = v2{FrameListMax.x, FrameListMin.y - 96}; + + if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) + { + RenderProfiler_ScopeVisualization(RenderBuffer, State->Interface, Mouse, + ViewModeMin, ViewModeMax, + VisibleFrame, Memory); + } + else + { + RenderProfiler_ListVisualization(RenderBuffer, State->Interface, Mouse, + ViewModeMin, ViewModeMax, + VisibleFrame, Memory); + } +} \ No newline at end of file diff --git a/src/panels/foldhaus_panel_sculpture_view.h b/src/panels/foldhaus_panel_sculpture_view.h new file mode 100644 index 0000000..c9dc032 --- /dev/null +++ b/src/panels/foldhaus_panel_sculpture_view.h @@ -0,0 +1,168 @@ + +// 3D Mouse View + +OPERATION_STATE_DEF(mouse_rotate_view_operation_state) +{ + v4 CameraStartPos; +}; + +OPERATION_RENDER_PROC(Update3DViewMouseRotate) +{ + mouse_rotate_view_operation_state* OpState = (mouse_rotate_view_operation_state*)Operation.OpStateMemory; + + v2 TotalDeltaPos = Mouse.Pos - Mouse.DownPos; + + m44 XRotation = GetXRotation(-TotalDeltaPos.y * State->PixelsToWorldScale); + m44 YRotation = GetYRotation(TotalDeltaPos.x * State->PixelsToWorldScale); + m44 Combined = XRotation * YRotation; + + State->Camera.Position = V3(Combined * OpState->CameraStartPos); +} + +FOLDHAUS_INPUT_COMMAND_PROC(End3DViewMouseRotate) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command MouseRotateViewCommands [] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, End3DViewMouseRotate}, +}; + +FOLDHAUS_INPUT_COMMAND_PROC(Begin3DViewMouseRotate) +{ + operation_mode* RotateViewMode = ActivateOperationModeWithCommands(&State->Modes, MouseRotateViewCommands, Update3DViewMouseRotate); + mouse_rotate_view_operation_state* OpState = CreateOperationState(RotateViewMode, + &State->Modes, + mouse_rotate_view_operation_state); + OpState->CameraStartPos = V4(State->Camera.Position, 1); +} + +// ---------------- + +input_command SculptureView_Commands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate }, +}; + +PANEL_INIT_PROC(SculptureView_Init) +{ + +} + +PANEL_CLEANUP_PROC(SculptureView_Cleanup) +{ + +} + + +struct draw_leds_job_data +{ + led* LEDs; + pixel* Colors; + s32 StartIndex; + s32 OnePastLastIndex; + + render_quad_batch_constructor* Batch; + + m44 FaceCameraMatrix; + m44 ModelViewMatrix; + r32 LEDHalfWidth; +}; + +internal void +DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData) +{ + DEBUG_TRACK_FUNCTION; + + draw_leds_job_data* Data = (draw_leds_job_data*)JobData; + + s32 LEDCount = Data->OnePastLastIndex - Data->StartIndex; + + quad_batch_constructor_reserved_range BatchReservedRange = ThreadSafeReserveRangeInQuadConstructor(Data->Batch, LEDCount * 2); + s32 TrisUsed = 0; + + r32 HalfWidth = Data->LEDHalfWidth; + + v4 P0_In = v4{-HalfWidth, -HalfWidth, 0, 1}; + v4 P1_In = v4{HalfWidth, -HalfWidth, 0, 1}; + v4 P2_In = v4{HalfWidth, HalfWidth, 0, 1}; + v4 P3_In = v4{-HalfWidth, HalfWidth, 0, 1}; + + v2 UV0 = v2{0, 0}; + v2 UV1 = v2{1, 0}; + v2 UV2 = v2{1, 1}; + v2 UV3 = v2{0, 1}; + + led* LED = Data->LEDs + Data->StartIndex; + for (s32 LEDIdx = 0; + LEDIdx < LEDCount; + LEDIdx++) + { + pixel PixelColor = Data->Colors[LED->Index]; + v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f}; + + v4 V4Position = LED->Position; + V4Position.w = 0; + v4 P0 = P0_In + V4Position; + v4 P1 = P1_In + V4Position; + v4 P2 = P2_In + V4Position; + v4 P3 = P3_In + V4Position; + + SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++, + P0, P1, P2, UV0, UV1, UV2, Color, Color, Color); + SetTri3DInBatch(Data->Batch, BatchReservedRange.Start + TrisUsed++, + P0, P2, P3, UV0, UV2, UV3, Color, Color, Color); + + LED++; + } +} + +PANEL_RENDER_PROC(SculptureView_Render) +{ + DEBUG_TRACK_SCOPE(RenderSculpture); + + r32 PanelWidth = PanelBounds.Max.x - PanelBounds.Min.x; + r32 PanelHeight = PanelBounds.Max.y - PanelBounds.Min.y; + State->Camera.AspectRatio = PanelWidth / PanelHeight; + + m44 ModelViewMatrix = GetCameraModelViewMatrix(State->Camera); + m44 ProjectionMatrix = GetCameraPerspectiveProjectionMatrix(State->Camera); + + r32 LEDHalfWidth = .5f; + + PushRenderPerspective(RenderBuffer, PanelBounds.Min.x, PanelBounds.Min.y, PanelWidth, PanelHeight, State->Camera); + + // TODO(Peter): Pretty sure this isn't working right now + m44 FaceCameraMatrix = GetLookAtMatrix(v4{0, 0, 0, 1}, V4(State->Camera.Position, 1)); + FaceCameraMatrix = FaceCameraMatrix; + + s32 MaxLEDsPerJob = 2048; + render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount); + + for (s32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) + { + 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++) + { + draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data); + JobData->LEDs = Assembly.LEDs; + JobData->Colors = Assembly.Colors; + JobData->StartIndex = Job * MaxLEDsPerJob; + JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDCount); + JobData->Batch = &RenderLEDsBatch; + JobData->FaceCameraMatrix; + JobData->ModelViewMatrix = ModelViewMatrix; + JobData->LEDHalfWidth = LEDHalfWidth; + + Context.GeneralWorkQueue->PushWorkOnQueue( + Context.GeneralWorkQueue, + DrawLEDsInBufferRangeJob, + JobData); + } + } + + Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0); + Context.GeneralWorkQueue->ResetWorkQueue(Context.GeneralWorkQueue); +} diff --git a/src/sacn/sacn.h b/src/sacn/sacn.h index cb18e0e..7e406dc 100644 --- a/src/sacn/sacn.h +++ b/src/sacn/sacn.h @@ -330,8 +330,8 @@ SACNGetUniverseSendAddress(s32 Universe) u8 MulticastAddressBuffer[4] = {}; MulticastAddressBuffer[0] = 239; MulticastAddressBuffer[1] = 255; - MulticastAddressBuffer[2] = (u8)(Universe & 0xff00); // high bit - MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff) >> 8); // low bit + MulticastAddressBuffer[2] = (u8)((Universe & 0xff00) >> 8); // high bit + MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff)); // low bit u_long V4Address = (u_long)UpackB4(MulticastAddressBuffer); return V4Address; diff --git a/src/win32_foldhaus.cpp b/src/win32_foldhaus.cpp index e3d53d1..92c39d7 100644 --- a/src/win32_foldhaus.cpp +++ b/src/win32_foldhaus.cpp @@ -158,41 +158,6 @@ PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) return (platform_socket_handle)NewSocketIndex; } -#define NETWORK_ADDRESS_DICTIONARY_GROW_SIZE 32 -s32 Win32NetworkAddressHandleMax; -s32 Win32NetworkAddressHandleCount; -sockaddr_in* NetworkAddressValues; - -PLATFORM_GET_SEND_ADDRESS_HANDLE(Win32GetSendAddress) -{ - if (Win32NetworkAddressHandleCount >= Win32NetworkAddressHandleMax) - { - s32 NewDictionaryMax = Win32NetworkAddressHandleMax + NETWORK_ADDRESS_DICTIONARY_GROW_SIZE; - s32 NewDictionaryDataSize = NewDictionaryMax * sizeof(sockaddr_in); - u8* DictionaryMemory = Win32Alloc(NewDictionaryDataSize); - Assert(DictionaryMemory); - - sockaddr_in* NewValues = (sockaddr_in*)(DictionaryMemory); - if (NetworkAddressValues) - { - GSMemCopy(NetworkAddressValues, NewValues, sizeof(win32_socket) * NewDictionaryMax); - Win32Free((u8*)NetworkAddressValues, sizeof(win32_socket) * Win32NetworkAddressHandleCount); - } - NetworkAddressValues = NewValues; - - Win32NetworkAddressHandleMax = NewDictionaryMax; - } - - Assert(Win32NetworkAddressHandleCount < Win32NetworkAddressHandleMax); - s32 NewAddressIndex = Win32NetworkAddressHandleCount++; - - NetworkAddressValues[NewAddressIndex].sin_family = AddressFamily; - NetworkAddressValues[NewAddressIndex].sin_port = HostToNetU16(Port); - NetworkAddressValues[NewAddressIndex].sin_addr.s_addr = HostToNetU32(Address); - - return (platform_network_address_handle)NewAddressIndex; -} - PLATFORM_SET_SOCKET_OPTION(Win32SetSocketOption) { s32 SocketIndex = (s32)SocketHandle; @@ -211,10 +176,12 @@ PLATFORM_SEND_TO(Win32SendTo) s32 SocketIndex = (s32)SocketHandle; Assert(SocketIndex < Win32SocketHandleCount); - s32 AddressIndex = (s32)AddressHandle; - Assert(AddressIndex < Win32NetworkAddressHandleCount); + sockaddr_in SockAddress = {}; + SockAddress.sin_family = Address.Family; + SockAddress.sin_port = HostToNetU16(Address.Port); + SockAddress.sin_addr.s_addr = HostToNetU32(Address.Address); - s32 LengthSent = sendto(SocketValues[SocketIndex].Socket, Buffer, BufferLength, Flags, (sockaddr*)&NetworkAddressValues[AddressIndex], sizeof(sockaddr_in)); + s32 LengthSent = sendto(SocketValues[SocketIndex].Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in)); if (LengthSent == SOCKET_ERROR) { @@ -233,7 +200,6 @@ PLATFORM_CLOSE_SOCKET(Win32CloseSocket) closesocket(SocketValues[SocketIndex].Socket); } - HDC FontDrawingDC; HBITMAP FontBitmap; HFONT CurrentFont; @@ -404,6 +370,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, false, true, ShiftDown, AltDown, CtrlDown, false); Mouse->RightButtonState = KeyState_IsDown & ~KeyState_WasDown; + Mouse->DownPos = Mouse->Pos; }break; case WM_LBUTTONUP: @@ -522,11 +489,11 @@ Win32GetThreadId() int WINAPI WinMain ( -HINSTANCE HInstance, -HINSTANCE HPrevInstance, -PSTR CmdLineArgs, -INT NCmdShow -) + HINSTANCE HInstance, + HINSTANCE HPrevInstance, + PSTR CmdLineArgs, + INT NCmdShow + ) { MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); Win32UpdateWindowDimension(&MainWindow); @@ -594,19 +561,18 @@ INT NCmdShow context Context = {}; Context.MemorySize = InitialMemorySize; Context.MemoryBase = InitialMemory; - Context.WindowWidth = MainWindow.Width; - Context.WindowHeight = MainWindow.Height; + Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; // Platform functions Context.GeneralWorkQueue = &WorkQueue; Context.PlatformAlloc = Win32Alloc; Context.PlatformFree = Win32Free; + Context.PlatformRealloc = Win32Realloc; Context.PlatformReadEntireFile = Win32ReadEntireFile; Context.PlatformWriteEntireFile = Win32WriteEntireFile; Context.PlatformGetFilePath = Win32SystemDialogueOpenFile; Context.PlatformGetGPUTextureHandle = Win32GetGPUTextureHandle; Context.PlatformGetSocketHandle = Win32GetSocketHandle; - Context.PlatformGetSendAddress = Win32GetSendAddress; Context.PlatformSetSocketOption = Win32SetSocketOption; Context.PlatformSendTo = Win32SendTo; Context.PlatformCloseSocket = Win32CloseSocket; @@ -668,11 +634,7 @@ INT NCmdShow HandleWindowMessage(Message, &MainWindow, &InputQueue, &Mouse); } - // TODO(Peter): We shouldn't need to do this translation. the platform layer knows about win32_windows. We should just make that the interface - // to all windows. - // TODO(Peter): Decide which we want to use, context or renderbuffer. Should only be one - Context.WindowWidth = MainWindow.Width; - Context.WindowHeight = MainWindow.Height; + Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; RenderBuffer.ViewWidth = MainWindow.Width; RenderBuffer.ViewHeight = MainWindow.Height; Context.DeltaTime = LastFrameSecondsElapsed; diff --git a/todo.txt b/todo.txt index d48682e..19cab15 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,7 @@ TODO FOLDHAUS -YOU WERE IN THE MIDDLE OF - +Reimplement Node View +- probably want to take a fresh pass at nodes all together Assembly -> SACN interface x you need to rebuild the map from leds -> universes @@ -36,14 +36,13 @@ Switch To Nodes - evaluation step (one node at a time) Hardening -- turn the default sculpture view into an operation mode ? (have to think about this) +x turn the default sculpture view into an operation mode ? (have to think about this) - Then we want to think about separating out mode render functions from mode update functions. Not sure its necessary but having something that operates like an update funciton but is called render is weird. Might want some sort of coroutine functionality in place, where modes can add and remove optional, parallel update functions - memory visualization -- - Log memory allocations +- x Log memory allocations - separate rendering thread - cache led positions. Only update if they are moving -- :HotCodeReloading UI Improvements - highlight node field under active edit @@ -89,16 +88,9 @@ Resource Management - Icons Animation -- timeline -- create clips that play +x timeline +x create clips that play - clips can have parameters that drive them? -- clips should have prerequesites -- - channels active -- - patterns active in the channel -- - when a clip is playing, it should just take over the whole structure - -Command Line -- select a channel/pattern Optimization - investigate the memory access pattern of the SACN / LED systems. Guessing they are very slow diff --git a/todo_done.txt b/todo_done.txt index 3b23e55..b957c7c 100644 --- a/todo_done.txt +++ b/todo_done.txt @@ -43,4 +43,8 @@ x go back to calling SpecificationIndex Type - x connections shouldn't store their own values, they should just point into permanent storage Hardening -x input context changes \ No newline at end of file +x input context changes + +Animation Timeline +x drag ends of animation clips to change start and end times +x click to drag time marker \ No newline at end of file