diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index d29b0b1..673a299 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -15,7 +15,7 @@ pushd %BuildPath% del *.pdb > NUL 2> NUL REM Run the Preprocessor -%MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp +REM %MetaProgramPath%\foldhaus_meta.exe %SourceCodePath%\foldhaus_app.cpp echo WAITING FOR PDB TO WRITE > lock.tmp @@ -24,7 +24,9 @@ set LastError=%ERRORLEVEL% del lock.tmp -cl %CommonCompilerFlags% %SourceCodePath%\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib +cl %CommonCompilerFlags% %SourceCodePath%\platform_win32\win32_foldhaus.cpp /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib opengl32.lib dsound.lib Ws2_32.lib Comdlg32.lib + +cl %CommonCompilerFlags% %ProjectDevPath%\src\serial_monitor\first.cpp /Feserial_monitor.exe /link %CommonLinkerFlags% user32.lib winmm.lib gdi32.lib popd diff --git a/src/app/animation/foldhaus_animation.h b/src/app/animation/foldhaus_animation.h deleted file mode 100644 index c5b0434..0000000 --- a/src/app/animation/foldhaus_animation.h +++ /dev/null @@ -1,178 +0,0 @@ -// -// File: foldhaus_animation.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_ANIMATION - -#define ANIMATION_PROC(name) void name(assembly_led_buffer* Assembly, r32 Time) -typedef ANIMATION_PROC(animation_proc); - -struct frame_range -{ - s32 Min; - s32 Max; -}; - -struct animation_block -{ - frame_range Range; - u32 AnimationProcHandle; - u32 Layer; -}; - -enum blend_mode -{ - BlendMode_Overwrite, - BlendMode_Add, - BlendMode_Multiply, - BlendMode_Count, -}; - -struct anim_layer -{ - string Name; - blend_mode BlendMode; -}; - -#define ANIMATION_SYSTEM_LAYERS_MAX 128 -#define ANIMATION_SYSTEM_BLOCKS_MAX 128 -struct animation_system -{ - memory_arena Storage; - - gs_list Blocks; - anim_layer* Layers; - u32 LayersCount; - u32 LayersMax; - - // NOTE(Peter): The frame currently being displayed/processed. you - // can see which frame you're on by looking at the time slider on the timeline - // panel - s32 CurrentFrame; - s32 LastUpdatedFrame; - r32 SecondsPerFrame; - b32 TimelineShouldAdvance; - - // Timeline - frame_range PlayableRange; -}; - -internal u32 -SecondsToFrames(r32 Seconds, animation_system System) -{ - u32 Result = Seconds * (1.0f / System.SecondsPerFrame); - return Result; -} - -inline b32 -FrameIsInRange(s32 Frame, frame_range Range) -{ - b32 Result = (Frame >= Range.Min) && (Frame <= Range.Max); - return Result; -} - -internal u32 -GetFrameCount(frame_range Range) -{ - u32 Result = (u32)GSMax(0, Range.Max - Range.Min); - return Result; -} - -internal r32 -FrameToPercentRange(s32 Frame, frame_range Range) -{ - r32 Result = (r32)(Frame - Range.Min); - Result = Result / GetFrameCount(Range); - return Result; -} - -internal s32 -PercentToFrameInRange(r32 Percent, frame_range Range) -{ - s32 Result = Range.Min + (s32)(Percent * GetFrameCount(Range)); - return Result; -} - -internal s32 -ClampFrameToRange(s32 Frame, frame_range Range) -{ - s32 Result = Frame; - if (Result < Range.Min) - { - Result = Range.Min; - } - else if (Result > Range.Max) - { - Result = Range.Max; - } - return Result; -} - -// Blocks - -internal gs_list_handle -AddAnimationBlock(u32 StartFrame, s32 EndFrame, u32 AnimationProcHandle, u32 Layer, animation_system* AnimationSystem) -{ - gs_list_handle Result = {0}; - animation_block NewBlock = {0}; - NewBlock.Range.Min = StartFrame; - NewBlock.Range.Max = EndFrame; - NewBlock.AnimationProcHandle = AnimationProcHandle; - NewBlock.Layer = Layer; - Result = AnimationSystem->Blocks.PushElementOnList(NewBlock); - return Result; -} - -internal void -RemoveAnimationBlock(gs_list_handle AnimationBlockHandle, animation_system* AnimationSystem) -{ - Assert(ListHandleIsValid(AnimationBlockHandle)); - AnimationSystem->Blocks.FreeElementWithHandle(AnimationBlockHandle); -} - -// Layers -internal u32 -AddLayer (string Name, animation_system* AnimationSystem, blend_mode BlendMode = BlendMode_Overwrite) -{ - // TODO(Peter): If this assert fires its time to make the layer buffer system - // resizable. - Assert(AnimationSystem->LayersCount < AnimationSystem->LayersMax); - - u32 Result = 0; - Result = AnimationSystem->LayersCount++; - anim_layer* NewLayer = AnimationSystem->Layers + Result; - *NewLayer = {0}; - NewLayer->Name = MakeString(PushArray(&AnimationSystem->Storage, char, Name.Length), Name.Length); - CopyStringTo(Name, &NewLayer->Name); - NewLayer->BlendMode = BlendMode; - return Result; -} - -internal void -RemoveLayer (u32 LayerIndex, animation_system* AnimationSystem) -{ - Assert(LayerIndex < AnimationSystem->LayersMax); - Assert(LayerIndex < AnimationSystem->LayersCount); - for (u32 i = LayerIndex; i < AnimationSystem->LayersCount - 1; i++) - { - AnimationSystem->Layers[i] = AnimationSystem->Layers[i + 1]; - } - for (u32 i = AnimationSystem->Blocks.Used -= 1; i >= 0; i--) - { - gs_list_entry* Entry = AnimationSystem->Blocks.GetEntryAtIndex(i); - if (EntryIsFree(Entry)) { continue; } - animation_block* Block = &Entry->Value; - if (Block->Layer > LayerIndex) - { - Block->Layer -= 1; - } - else if (Block->Layer == LayerIndex) - { - AnimationSystem->Blocks.FreeElementAtIndex(i); - } - } - AnimationSystem->LayersCount -= 1; -} -#define FOLDHAUS_ANIMATION -#endif // FOLDHAUS_ANIMATION \ No newline at end of file diff --git a/src/app/assembly_parser.cpp b/src/app/assembly_parser.cpp deleted file mode 100644 index 459f644..0000000 --- a/src/app/assembly_parser.cpp +++ /dev/null @@ -1,445 +0,0 @@ -// -// File: assembly_parser.cpp -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef ASSEMBLY_PARSER_CPP - -internal assembly_token -ParseToken (tokenizer* Tokenizer) -{ - assembly_token Result = {}; - Result.Token = Tokenizer->At; - Result.Length = 1; - EatChar(Tokenizer); - - if (*Result.Token == ':'){ Result.Type = AssemblyToken_Colon; } - else if (*Result.Token == ';'){ Result.Type = AssemblyToken_SemiColon; } - else if (*Result.Token =='{'){ Result.Type = AssemblyToken_LeftCurlyBrace; } - else if (*Result.Token =='}'){ Result.Type = AssemblyToken_RightCurlyBrace; } - else if (*Result.Token ==','){ Result.Type = AssemblyToken_Comma; } - else if (IsNumericExtended(*Result.Token)) - { - while(*Tokenizer->At && IsNumericExtended(*Tokenizer->At)) { EatChar(Tokenizer); } - Result.Type = AssemblyToken_Number; - Result.Length = Tokenizer->At - Result.Token; - } - else if (*Result.Token =='\"') - { - while(*Tokenizer->At && *Tokenizer->At != '\"') { EatChar(Tokenizer); } - Result.Token++; // Skip the quote - Result.Type = AssemblyToken_String; - Result.Length = (Tokenizer->At - Result.Token) - 1; - } - else if (*Result.Token == '(') - { - while(*Tokenizer->At && *Tokenizer->At != ')') { EatChar(Tokenizer); } - Result.Token++; // Skip the paren - Result.Type = AssemblyToken_Vector; - Result.Length = (Tokenizer->At - Result.Token) - 1; - } - else if (CharArraysEqualUpToLength(Result.Token, LED_STRIP_IDENTIFIER, CharArrayLength(LED_STRIP_IDENTIFIER))) - { - Result.Type = AssemblyToken_LEDStrip; - Result.Length = CharArrayLength(LED_STRIP_IDENTIFIER); - Tokenizer->At += Result.Length - 1; - } - else if (CharArraysEqualUpToLength(Result.Token, END_ASSEMBLY_FILE_IDENTIFIER, CharArrayLength(END_ASSEMBLY_FILE_IDENTIFIER))) - { - Result.Type = AssemblyToken_EndOfFile; - Result.Length = CharArrayLength(END_ASSEMBLY_FILE_IDENTIFIER); - Tokenizer->At += Result.Length - 1; - } - else - { - Result.Type = AssemblyToken_Identifier; - while(*Tokenizer->At && !IsWhitespace(*Tokenizer->At)) { EatChar(Tokenizer); } - } - - return Result; -} - -internal v3 -ParseAssemblyVector (char* String) -{ - v3 Result = {}; - - tokenizer Tokenizer = {}; - Tokenizer.At = String; - - EatWhitespace(&Tokenizer); - Result.x = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); - - EatWhitespace(&Tokenizer); - Result.y = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); - - EatWhitespace(&Tokenizer); - Result.z = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); - - return Result; -} - -internal b32 -ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer) -{ - b32 HeaderIsValid = false; - - if (CharArraysEqualUpToLength(Tokenizer->At, LED_STRIP_COUNT_IDENTIFIER, CharArrayLength(LED_STRIP_COUNT_IDENTIFIER))) - { - Tokenizer->At += CharArrayLength(LED_STRIP_COUNT_IDENTIFIER); - EatWhitespace(Tokenizer); - assembly_token CountToken = ParseToken(Tokenizer); - if (CountToken.Type == AssemblyToken_Number) - { - Assembly->LEDStripSize = ParseSignedIntUnsafe(CountToken.Token).SignedIntValue; - HeaderIsValid = true; - } - EatWhitespace(Tokenizer); - } - return HeaderIsValid; -} - -internal led_strip_definition -ParseLEDStrip (tokenizer* Tokenizer) -{ - led_strip_definition Result = {}; - - // Control Box Index - while (*Tokenizer->At && !IsNumericExtended(*Tokenizer->At)) { EatChar(Tokenizer); } - assembly_token BoxIDToken = ParseToken(Tokenizer); - Assert(BoxIDToken.Type == AssemblyToken_Number); - Result.ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue; - - // Start Universe - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - assembly_token StartUniverseToken = ParseToken(Tokenizer); - Assert(BoxIDToken.Type == AssemblyToken_Number); - Result.StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue; - - // Start Channel - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - assembly_token StartChannelToken = ParseToken(Tokenizer); - Assert(BoxIDToken.Type == AssemblyToken_Number); - Result.StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue; - - // Strip Type - // TODO(Peter): This is unused for now, and would be a branch point for parsing - // the rest of the info. Fix this. - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - if (CharArraysEqualUpToLength(Tokenizer->At, INTERPOLATE_POINTS_IDENTIFIER, CharArrayLength(INTERPOLATE_POINTS_IDENTIFIER))) - { - Result.InterpolationType = StripInterpolate_Points; - - // Start Position - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - assembly_token StartPositionToken = ParseToken(Tokenizer); - Assert(StartPositionToken.Type == AssemblyToken_Vector); - Result.InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token); - - // End Position - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - assembly_token EndPositionToken = ParseToken(Tokenizer); - Assert(EndPositionToken.Type == AssemblyToken_Vector); - Result.InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token); - - // LEDs Per Strip - EatPastCharacter(Tokenizer, ','); - EatWhitespace(Tokenizer); - assembly_token LEDsPerStripToken = ParseToken(Tokenizer); - Assert(BoxIDToken.Type == AssemblyToken_Number); - Result.LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue; - } - - EatPastCharacter(Tokenizer, '}'); - EatWhitespace(Tokenizer); - - return Result; -} - -internal void -ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer) -{ - EatWhitespace(Tokenizer); - - while(*Tokenizer->At) - { - EatWhitespace(Tokenizer); - assembly_token Token = ParseToken(Tokenizer); - - if (Token.Type != AssemblyToken_EndOfFile) - { - switch (Token.Type) - { - case AssemblyToken_LEDStrip: - { - led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount; - Assert(Assembly->LEDStripCount < Assembly->LEDStripSize); - - *LEDStripDef = ParseLEDStrip(Tokenizer); - Assembly->TotalLEDCount += LEDStripDef->LEDsPerStrip; - - Assembly->LEDStripCount++; - } break; - - // TODO(Peter): Other cases? What else would need to be in the assembly body? - - InvalidDefaultCase; - } - } - else - { - break; - } - } - - // NOTE(Peter): Ensure the validity of the assembly file. We probably don't want an assert here, - // more likely we want to load a valid assembly anyways, and just raise this as an error to the user - // so they can fix it. - Assert(Assembly->LEDStripCount == Assembly->LEDStripSize); -} - -inline b32 -ParseTokenEquals (tokenizer* T, char* Validate) -{ - b32 Result = true; - - char* TAt = T->At; - char* VAt = Validate; - while (((TAt - T->Memory) < T->MemoryLength) && *VAt) - { - if (*VAt != *TAt) - { - Result = false; - break; - } - TAt++; - *VAt++; - } - - if (Result) - { - T->At = TAt; - EatWhitespace(T); - } - - return Result; -} - -internal b32 -ParseComma(tokenizer* T) -{ - b32 Result = ParseTokenEquals(T, ","); - return Result; -} - -internal b32 -ParseOpenCurlyBrace(tokenizer* T) -{ - b32 Result = ParseTokenEquals(T, "{"); - return Result; -} - -internal b32 -ParseCloseCurlyBrace(tokenizer* T) -{ - b32 Result = ParseTokenEquals(T, "}"); - return Result; -} - -internal b32 -ParseOpenParen(tokenizer* T) -{ - b32 Result = ParseTokenEquals(T, "("); - return Result; -} - -internal b32 -ParseCloseParen(tokenizer* T) -{ - b32 Result = ParseTokenEquals(T, ")"); - return Result; -} - -internal b32 -ParseUnsignedInteger(tokenizer* T, u32* Value) -{ - parse_result Result = ParseUnsignedIntUnsafe(T->At); - *Value = Result.UnsignedIntValue; - T->At = Result.OnePastLast; - - // TODO(Peter): Parse functions in gs_string don't actually check for errors or - // whether or not they actually parsed an int. - // :GSStringParseErrors - return true; -} - -internal b32 -ParseFloat(tokenizer* T, r32* Value) -{ - parse_result ParseResult = ParseFloatUnsafe(T->At); - *Value = ParseResult.FloatValue; - T->At = ParseResult.OnePastLast; - - // TODO(Peter): - // :GSStringParseErrors - return true; -} - -internal b32 -ParseVector(tokenizer* T, v3* Value) -{ - b32 Result = true; - - if (ParseOpenParen(T)) - { - for (u32 i = 0; i < 3; i++) - { - b32 ValueSuccess = ParseFloat(T, &(Value->E[i])); - if (!ValueSuccess) - { - Result = false; - break; - } - - b32 CommaSuccess = ParseComma(T); - if (!CommaSuccess) - { - break; - } - } - - if (!ParseCloseParen(T)) - { - Result = false; - } - } - else - { - Result = false; - } - - return Result; -} - -// TODO(Peter): :ErrorLogging -#define ParseLEDStripToken(tokenizer, parse_expr, error_msg) \ -(parse_expr) && (ParseComma(tokenizer)) - -internal b32 -ParseLEDStripCount (tokenizer* T, u32* Value) -{ - b32 Result = false; - - if (ParseTokenEquals(T, LED_STRIP_COUNT_IDENTIFIER)) - { - EatWhitespace(T); - if (ParseUnsignedInteger(T, Value)) - { - Result = true; - } - } - - return Result; -} - -internal b32 -ParseLEDStrip (led_strip_definition* Strip, tokenizer* T, memory_arena* Arena) -{ - b32 Result = false; - - if (ParseTokenEquals(T, LED_STRIP_IDENTIFIER) && - ParseOpenCurlyBrace(T)) - { - Result = true; - - u32 ControlBoxIndex, StartUniverse, StartChannel; - ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->ControlBoxID), "Control Box Error"); - ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->StartUniverse), "Start Universe Error"); - ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->StartChannel), "Start Channel Error"); - - if (ParseTokenEquals(T, INTERPOLATE_POINTS_IDENTIFIER) && - ParseComma(T)) - { - Strip->InterpolationType = StripInterpolate_Points; - - ParseLEDStripToken(T, ParseVector(T, &Strip->InterpolatePositionStart), "Position Start Error"); - ParseLEDStripToken(T, ParseVector(T, &Strip->InterpolatePositionEnd), "Position End Error"); - } - - ParseLEDStripToken(T, ParseUnsignedInteger(T, &Strip->LEDsPerStrip), "LEDs Per Strip Error"); - - EatWhitespace(T); - if (!ParseCloseCurlyBrace(T)) - { - Result = false; - } - } - - return Result; -} - -internal assembly_definition -ParseAssemblyFile (u8* FileBase, s32 FileSize, memory_arena* Arena, event_log* EventLog) -{ - assembly_definition Assembly = {}; - - tokenizer Tokenizer = {}; - Tokenizer.At = (char*)FileBase; - Tokenizer.Memory = (char*)FileBase; - Tokenizer.MemoryLength = FileSize; - - if (ParseLEDStripCount(&Tokenizer, &Assembly.LEDStripSize)) - { - Assembly.LEDStrips = PushArray(Arena, led_strip_definition, Assembly.LEDStripSize); - - while (AtValidPosition(Tokenizer)) - { - EatWhitespace(&Tokenizer); - - if (Assembly.LEDStripCount < Assembly.LEDStripSize) - { - led_strip_definition* LEDStrip = Assembly.LEDStrips + Assembly.LEDStripCount++; - - if (ParseLEDStrip(LEDStrip, &Tokenizer, Arena)) - { - Assembly.TotalLEDCount += LEDStrip->LEDsPerStrip; - } - else - { - LogError(EventLog, "Unable to parse LED strip in assembly file"); - break; - } - } - else - { - if (ParseTokenEquals(&Tokenizer, END_ASSEMBLY_FILE_IDENTIFIER)) - { - break; - } - else - { - LogError(EventLog, "Did not find ent of file identifier in assembly file"); - break; - } - } - } - } - else - { - // TODO(Peter): :ErrorLoggong - InvalidCodePath; - } - - return Assembly; -} - -#define ASSEMBLY_PARSER_CPP -#endif // ASSEMBLY_PARSER_CPP \ No newline at end of file diff --git a/src/app/assembly_parser.h b/src/app/assembly_parser.h deleted file mode 100644 index eee4c9d..0000000 --- a/src/app/assembly_parser.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// File: assembly_parser.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef ASSEMBLY_PARSER_H - -#define LED_STRIP_COUNT_IDENTIFIER "led_strip_count" - -#define LED_STRIP_IDENTIFIER "led_strip" - -#define INTERPOLATE_POINTS_IDENTIFIER "INTERPOLATE_POINTS" - -#define END_ASSEMBLY_FILE_IDENTIFIER "END_OF_ASSEMBLY_FILE" - -enum assembly_token_type -{ - AssemblyToken_Colon, - AssemblyToken_SemiColon, - AssemblyToken_LeftCurlyBrace, - AssemblyToken_RightCurlyBrace, - AssemblyToken_Comma, - - AssemblyToken_Number, - AssemblyToken_String, - AssemblyToken_Vector, - - AssemblyToken_LEDStrip, - - AssemblyToken_Identifier, - - AssemblyToken_EndOfFile -}; - -struct assembly_token -{ - char* Token; - s32 Length; - assembly_token_type Type; -}; - -enum strip_interpolation_type -{ - StripInterpolate_Boxes, - StripInterpolate_Points, -}; - -struct led_strip_definition -{ - u32 ControlBoxID; - u32 StartUniverse; - u32 StartChannel; - - strip_interpolation_type InterpolationType; - // Interpolate Boxes - u32 StartBoxIndex; - u32 EndBoxIndex; - - // Interpolate Positions - v3 InterpolatePositionStart; - v3 InterpolatePositionEnd; - - // Universal Interpolation - u32 LEDsPerStrip; -}; - -struct assembly_definition -{ - u32 LEDStripSize; - u32 LEDStripCount; - u32 TotalLEDCount; - led_strip_definition* LEDStrips; -}; - -#define ASSEMBLY_PARSER_H -#endif // ASSEMBLY_PARSER_H \ No newline at end of file diff --git a/src/app/foldhaus_default_nodes.h b/src/app/deprecated/foldhaus_default_nodes.h similarity index 70% rename from src/app/foldhaus_default_nodes.h rename to src/app/deprecated/foldhaus_default_nodes.h index fd68674..3fddaa0 100644 --- a/src/app/foldhaus_default_nodes.h +++ b/src/app/deprecated/foldhaus_default_nodes.h @@ -100,10 +100,10 @@ NODE_PROC(SinWave, sin_wave_data) Data->Accumulator -= Data->Period; } - r32 ActualMin = GSMin(Data->Min, Data->Max); - r32 ActualMax = GSMax(Data->Min, Data->Max); - r32 SinResult = GSSin((Data->Accumulator / Data->Period) * PI * 2); - Data->Result = GSRemap(SinResult, -1.f, 1.f, ActualMin, ActualMax); + r32 ActualMin = Min(Data->Min, Data->Max); + r32 ActualMax = Max(Data->Min, Data->Max); + r32 SinResult = SinR32((Data->Accumulator / Data->Period) * PiR32 * 2); + Data->Result = RemapR32(SinResult, -1.f, 1.f, ActualMin, ActualMax); } else { @@ -117,7 +117,7 @@ NODE_PROC(SinWave, sin_wave_data) // ///////////////////////////////// -GSMetaTag(node_struct); +GSMetaTag(node_struct); struct multiply_patterns_data { GSMetaTag(node_input); @@ -132,28 +132,25 @@ struct multiply_patterns_data NODE_PROC(MultiplyPatterns, multiply_patterns_data) { - led* LED = Data->Result.LEDs; - for (s32 l = 0; l < Data->Result.LEDCount; l++) + for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++) { - Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); + Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount); - s32 AR = Data->A.Colors[LED->Index].R; - s32 AG = Data->A.Colors[LED->Index].G; - s32 AB = Data->A.Colors[LED->Index].B; + s32 AR = Data->A.Colors[LedIndex].R; + s32 AG = Data->A.Colors[LedIndex].G; + s32 AB = Data->A.Colors[LedIndex].B; - s32 BR = Data->B.Colors[LED->Index].R; - s32 BG = Data->B.Colors[LED->Index].G; - s32 BB = Data->B.Colors[LED->Index].B; + s32 BR = Data->B.Colors[LedIndex].R; + s32 BG = Data->B.Colors[LedIndex].G; + s32 BB = Data->B.Colors[LedIndex].B; s32 RCombined = (AR * BR) / 255; s32 GCombined = (AG * BG) / 255; s32 BCombined = (AB * BB) / 255; - Data->Result.Colors[LED->Index].R = (u8)RCombined; - Data->Result.Colors[LED->Index].G = (u8)GCombined; - Data->Result.Colors[LED->Index].B = (u8)BCombined; - - LED++; + Data->Result.Colors[LedIndex].R = (u8)RCombined; + Data->Result.Colors[LedIndex].G = (u8)GCombined; + Data->Result.Colors[LedIndex].B = (u8)BCombined; } } diff --git a/src/app/foldhaus_node.cpp b/src/app/deprecated/foldhaus_node.cpp similarity index 86% rename from src/app/foldhaus_node.cpp rename to src/app/deprecated/foldhaus_node.cpp index 29e93a9..092d55f 100644 --- a/src/app/foldhaus_node.cpp +++ b/src/app/deprecated/foldhaus_node.cpp @@ -45,7 +45,7 @@ SortNodeNeighbors(u32 ContiguousNodeIndex, gs_list_handle NodeHandle, adjacency_ u32 ContiguousNeighborNodeIndex = SparseToContiguousNodeMap[Neighbor->NodeHandle.Index]; if (!NodesVisited[ContiguousNeighborNodeIndex]) { - SortedNodesCount = SortNodeNeighbors(ContiguousNeighborNodeIndex, Neighbor->NodeHandle, NeighborsLists, NodesVisited, SortedNodeHandles, SortedNodesCount, SparseToContiguousNodeMap); + SortedNodesCount = SortNodeNeighbors(ContiguousNeighborNodeIndex, Neighbor->NodeHandle, NeighborsLists, NodesVisited, SortedNodeHandles, SortedNodesCount, SparseToContiguousNodeMap); } Neighbor = Neighbor->Next; } @@ -55,7 +55,7 @@ SortNodeNeighbors(u32 ContiguousNodeIndex, gs_list_handle NodeHandle, adjacency_ } internal s32* -CreateSparseToContiguousMap (pattern_node_workspace Workspace, memory_arena* Scratch) +CreateSparseToContiguousMap (pattern_node_workspace Workspace, gs_memory_arena* Scratch) { s32* Result = PushArray(Scratch, s32, Workspace.Nodes.OnePastLastUsed); s32 ContiguousIndex = 0; @@ -71,7 +71,7 @@ CreateSparseToContiguousMap (pattern_node_workspace Workspace, memory_arena* Scr } internal void -UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch) +UpdateSortedNodes(pattern_node_workspace* Workspace, gs_memory_arena* Scratch) { ClearNodeWorkspaceStorage(Workspace); @@ -81,7 +81,7 @@ UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch) s32* SparseToContiguousNodeMap = CreateSparseToContiguousMap(*Workspace, &Workspace->Storage); // NOTE(Peter): We need to sort this later on so I'm just storing list lengths in this format - // to begin with. + // to begin with. // NeighborsListLengths[n].Radix = the number of neighbors for the node // NeighborsListLengths[n].ID = the sparse array index of the node gs_radix_entry* NeighborsListLengths = PushArray(Scratch, gs_radix_entry, NodeCount); @@ -119,24 +119,24 @@ UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch) RadixSortInPlace(NeighborsListLengths, Workspace->Nodes.Used); char* OutputCharArray = PushArray(Scratch, char, 1024); - string OutputString = MakeString(OutputCharArray, 0, 1024); + gs_string Outputgs_string = MakeString(OutputCharArray, 0, 1024); - PrintF(&OutputString, "Neighbors Lists: \n"); + PrintF(&Outputgs_string, "Neighbors Lists: \n"); for (u32 d = 0; d < Workspace->Nodes.Used; d++) { - PrintF(&OutputString, " %d: Node [ %d ] : neighbors { ", d, NeighborsListLengths[d].ID); + PrintF(&Outputgs_string, " %d: Node [ %d ] : neighbors { ", d, NeighborsListLengths[d].ID); adjacency_list* Neighbors = NeighborsLists[d]; while (Neighbors) { - PrintF(&OutputString, "%d, ", Neighbors->NodeHandle.Index); + PrintF(&Outputgs_string, "%d, ", Neighbors->NodeHandle.Index); Neighbors = Neighbors->Next; } - PrintF(&OutputString, " }\n"); + PrintF(&Outputgs_string, " }\n"); } - NullTerminate(&OutputString); + NullTerminate(&Outputgs_string); - // This is a contiguous array. + // This is a contiguous array. b8* NodesVisited = PushArray(Scratch, b8, NodeCount); GSZeroArray(NodesVisited, b8, NodeCount); @@ -163,7 +163,7 @@ UpdateSortedNodes(pattern_node_workspace* Workspace, memory_arena* Scratch) } internal void -PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspace, memory_arena* Scratch) +PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspace, gs_memory_arena* Scratch) { pattern_node* NewNode = Workspace->Nodes.TakeElement(); NewNode->SpecificationIndex = NodeSpecificationIndex; @@ -172,13 +172,13 @@ PushNodeOnWorkspace(s32 NodeSpecificationIndex, pattern_node_workspace* Workspac } internal void -PushNodeConnectionOnWorkspace(gs_list_handle UpstreamNodeHandle, u32 UpstreamPortIndex, gs_list_handle DownstreamNodeHandle, u32 DownstreamPortIndex, pattern_node_workspace* Workspace, memory_arena* Scratch) +PushNodeConnectionOnWorkspace(gs_list_handle UpstreamNodeHandle, u32 UpstreamPortIndex, gs_list_handle DownstreamNodeHandle, u32 DownstreamPortIndex, pattern_node_workspace* Workspace, gs_memory_arena* Scratch) { pattern_node_connection Connection = {}; - Connection.UpstreamNodeHandle = UpstreamNodeHandle; - Connection.DownstreamNodeHandle = DownstreamNodeHandle; - Connection.UpstreamPortIndex = UpstreamPortIndex; - Connection.DownstreamPortIndex = DownstreamPortIndex; + Connection.UpstreamNodeHandle = UpstreamNodeHandle; + Connection.DownstreamNodeHandle = DownstreamNodeHandle; + Connection.UpstreamPortIndex = UpstreamPortIndex; + Connection.DownstreamPortIndex = DownstreamPortIndex; Workspace->Connections.PushElementOnBucket(Connection); UpdateSortedNodes(Workspace, Scratch); diff --git a/src/app/foldhaus_node.h b/src/app/deprecated/foldhaus_node.h similarity index 91% rename from src/app/foldhaus_node.h rename to src/app/deprecated/foldhaus_node.h index b51b9ca..b286b28 100644 --- a/src/app/foldhaus_node.h +++ b/src/app/deprecated/foldhaus_node.h @@ -14,7 +14,7 @@ typedef enum node_type node_type; struct color_buffer { - led* LEDs; + v4* LedPositions; pixel* Colors; s32 LEDCount; }; @@ -59,14 +59,14 @@ struct node_specification struct node_specification_ { node_type Type; - string Identifier; + gs_string Identifier; gsm_struct_type DataType; }; struct pattern_node { // TODO(Peter): Something to think about further down the line is the fact that - // SpecificationIndex doesn't have to stay static throughout a single instance of + // SpecificationIndex doesn't have to stay static throughout a single instance of // an application, let alone across separate runs. If you recompile (hot load or not) // with a new specification, the indecies all get thrown off. Should we hash the spec // names or something? @@ -90,9 +90,9 @@ struct pattern_node_workspace gs_bucket Connections; // This is storage for all the structures which follow. - // It is cleared when new nodes are added so that the + // It is cleared when new nodes are added so that the // acceleration structures can be recalculated - memory_arena Storage; + gs_memory_arena Storage; s32* SparseToSortedNodeMap; gs_list_handle* SortedNodeHandles; }; @@ -109,7 +109,7 @@ struct data_name struct data_name #define NODE_PROC(proc_name, input_type) \ -void proc_name(input_type* Data, r32 DeltaTime) +void proc_name(input_type* Data, r32 DeltaTime) #define NODE_IN(type, name) type name #define NODE_OUT(type, name) type name diff --git a/src/app/foldhaus_node_gui.h b/src/app/deprecated/foldhaus_node_gui.h similarity index 100% rename from src/app/foldhaus_node_gui.h rename to src/app/deprecated/foldhaus_node_gui.h diff --git a/src/app/panels/foldhaus_panel_node_graph.h b/src/app/deprecated/foldhaus_panel_node_graph.h similarity index 87% rename from src/app/panels/foldhaus_panel_node_graph.h rename to src/app/deprecated/foldhaus_panel_node_graph.h index 12ae92d..fceb052 100644 --- a/src/app/panels/foldhaus_panel_node_graph.h +++ b/src/app/deprecated/foldhaus_panel_node_graph.h @@ -15,7 +15,7 @@ struct visual_port { gs_list_handle SparseNodeHandle; u32 PortIndex; - rect PortBounds; + rect2 PortBounds; }; struct visual_connection @@ -57,7 +57,7 @@ struct node_graph_state { v2 ViewOffset; - memory_arena LayoutMemory; + gs_memory_arena LayoutMemory; node_layout Layout; b32 LayoutIsDirty; @@ -111,7 +111,7 @@ OPERATION_STATE_DEF(connect_nodes_operation_state) OPERATION_RENDER_PROC(UpdateConnectNodeOperation) { - panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); + panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; GraphState->Layout.InProgressConnectionEnd = Mouse.Pos; @@ -121,14 +121,14 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndConnectNodesOperation) { connect_nodes_operation_state* OpState = GetCurrentOperationState(State->Modes, connect_nodes_operation_state); - panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); + panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; GraphState->Layout.ConnectionIsInProgress = false; for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++) { visual_port VisualPort = GraphState->Layout.VisualPorts[p]; - rect ViewAdjustedBounds = gs_RectOffsetByVector(VisualPort.PortBounds, GraphState->ViewOffset); + rect2 ViewAdjustedBounds = gs_RectOffsetByVector(VisualPort.PortBounds, GraphState->ViewOffset); if (gs_PointIsInRect(Mouse.Pos, ViewAdjustedBounds)) { visual_port UpstreamPort = (OpState->IsInput & IsInputMember) ? VisualPort : OpState->VisualPort; @@ -157,7 +157,7 @@ BeginConnectNodesOperation(visual_port VisualPort, u32 VisualPortIndex, mouse_st OpState->VisualPort = VisualPort; OpState->VisualPortIndex = VisualPortIndex; - panel_and_bounds NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); + panel_with_layout NodeGraphPanel = GetPanelContainingPoint(Mouse.DownPos, &State->PanelSystem, State->WindowBounds); node_graph_state* GraphState = (node_graph_state*)NodeGraphPanel.Panel->PanelStateMemory; GraphState->Layout.ConnectionIsInProgress = true; @@ -196,7 +196,7 @@ NodeGraph_Cleanup(panel* Panel, app_state* State) } internal void -DrawGrid (v2 Offset, v2 GridSquareDim, rect PanelBounds, render_command_buffer* RenderBuffer) +DrawGrid (v2 Offset, v2 GridSquareDim, rect2 PanelBounds, render_command_buffer* RenderBuffer) { r32 LineValue = .16f; v4 LineColor = v4{LineValue, LineValue, LineValue, 1.f}; @@ -232,9 +232,9 @@ DrawGrid (v2 Offset, v2 GridSquareDim, rect PanelBounds, render_command_buffer* } internal void -DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, r32 LineHeight, string_alignment TextAlign, v2 TextOffset, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse) +DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, r32 LineHeight, gs_string_alignment TextAlign, v2 TextOffset, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse) { - rect PortBounds = rect{v2{0, 0}, v2{6, 6}}; + rect2 PortBounds = rect2{v2{0, 0}, v2{6, 6}}; v2 LinePosition = Position; for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++) @@ -244,7 +244,7 @@ DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, { // TODO(Peter): Can we make this rely on the same data that we use to // render the actual connection points? - string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); + gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); DrawString(RenderBuffer, MemberName, Interface.Font, LinePosition + TextOffset, WhiteV4, TextAlign); LinePosition.y -= LineHeight; } @@ -252,7 +252,7 @@ DrawNodePorts(gsm_struct_type_info NodeDataTypeInfo, b32 InputMask, v2 Position, } internal void -DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle NodeHandle, r32 NodeWidth, r32 LineHeight, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse, memory_arena* Scratch) +DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle NodeHandle, r32 NodeWidth, r32 LineHeight, interface_config Interface, render_command_buffer* RenderBuffer, mouse_state Mouse, gs_memory_arena* Scratch) { gsm_struct_type_info NodeDataTypeInfo = StructTypes[NodeSpecification.DataType]; @@ -264,13 +264,13 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod if (MemberIsInput(Member)) { InputMembers++; } if (MemberIsOutput(Member)) { OutputMembers++; } } - u32 LineCount = 1 + GSMax(InputMembers, OutputMembers); + u32 LineCount = 1 + Max(InputMembers, OutputMembers); v2 NodeDim = v2{ NodeWidth, (LineHeight * LineCount) + Interface.Margin.y, }; - rect NodeBounds = rect{ + rect2 NodeBounds = rect2{ v2{ Position.x, Position.y - NodeDim.y }, v2{ Position.x + NodeDim.x, Position.y }, }; @@ -282,7 +282,7 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod PushRenderQuad2D(RenderBuffer, LinePosition, LinePosition + v2{NodeWidth, LineHeight}, v4{1.f, .24f, .39f, 1.f}); - string NodePrintName = MakeString(PushArray(Scratch, char, 256), 0, 256); + gs_string NodePrintName = MakeString(PushArray(Scratch, char, 256), 0, 256); PrintF(&NodePrintName, "%S [%d]", NodeSpecification.Identifier, NodeHandle.Index); DrawString(RenderBuffer, NodePrintName, Interface.Font, LinePosition + TextOffset, WhiteV4); LinePosition.y -= LineHeight; @@ -293,7 +293,7 @@ DrawNode (v2 Position, node_specification_ NodeSpecification, gs_list_handle Nod for (u32 i = 0; i < NodeDataTypeInfo.MembersCount; i++) { gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[i]; - string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); + gs_string MemberName = MakeString(Member.Identifier, Member.IdentifierLength); // TODO(Peter): Can we make this rely on the same data that we use to // render the actual connection points? @@ -329,7 +329,7 @@ GetVisualPortIndexForNode(gs_list_handle SparseNodeHandle, u32 PortIndex, node_l } internal node_layout -ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, r32 LineHeight, memory_arena* Storage, app_state* State) +ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, r32 LineHeight, gs_memory_arena* Storage, app_state* State) { node_layout Result = {}; @@ -373,7 +373,7 @@ ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, { gsm_struct_member_type_info Member = NodeDataTypeInfo.Members[p]; - rect PortBounds = {0}; + rect2 PortBounds = {0}; v2 PortDim = v2{8, 8}; PortBounds.Min = VisualNode->Position + v2{0, PortDim.y / 2}; if (MemberIsInput(Member)) @@ -420,23 +420,23 @@ ArrangeNodes(pattern_node_workspace Workspace, r32 NodeWidth, r32 LayerDistance, GSMetaTag(panel_render); GSMetaTag(panel_type_node_graph); internal void -NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +NodeGraph_Render(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { node_graph_state* GraphState = (node_graph_state*)Panel.PanelStateMemory; b32 MouseHandled = false; - rect NodeSelectionWindowBounds = rect{ + rect2 NodeSelectionWindowBounds = rect2{ PanelBounds.Min, v2{PanelBounds.Min.x + 300, PanelBounds.Max.y}, }; - rect GraphBounds = rect{ + rect2 GraphBounds = rect2{ v2{NodeSelectionWindowBounds.Max.x, PanelBounds.Min.y}, PanelBounds.Max, }; r32 NodeWidth = 150; r32 LayerDistance = 100; - r32 LineHeight = (State->Interface.Font->PixelHeight + (2 * State->Interface.Margin.y)); + r32 LineHeight = ui_GetTextLineHeight(State->Interface); if (GraphState->LayoutIsDirty) { @@ -477,7 +477,7 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf { visual_node VisualNode = GraphState->Layout.VisualNodes[i]; gs_list_handle NodeHandle = State->NodeWorkspace.SortedNodeHandles[i]; - DrawNode(VisualNode.Position + GraphState->ViewOffset, VisualNode.Spec, NodeHandle, NodeWidth, LineHeight, State->Interface, RenderBuffer, Mouse, &State->Transient); + DrawNode(VisualNode.Position + GraphState->ViewOffset, VisualNode.Spec, NodeHandle, NodeWidth, LineHeight, State->Interface.Style, RenderBuffer, Context.Mouse, &State->Transient); } for (u32 p = 0; p < GraphState->Layout.VisualPortsCount; p++) @@ -487,12 +487,12 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf VisualPort.PortBounds.Max += GraphState->ViewOffset; v4 PortColor = WhiteV4; - if (PointIsInRange(Mouse.Pos, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max)) + if (PointIsInRange(Context.Mouse.Pos, VisualPort.PortBounds.Min, VisualPort.PortBounds.Max)) { PortColor = PinkV4; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) + if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState)) { - BeginConnectNodesOperation(VisualPort, p, Mouse, State); + BeginConnectNodesOperation(VisualPort, p, Context.Mouse, State); MouseHandled = true; } } @@ -513,21 +513,21 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf List.TextColor = WhiteV4; List.ListBounds = NodeSelectionWindowBounds; List.ListElementDimensions = v2{ - gs_Width(NodeSelectionWindowBounds), - (r32)(State->Interface.Font->PixelHeight + 8), + Rect2Width(NodeSelectionWindowBounds), + ui_GetTextLineHeight(State->Interface) }; List.ElementLabelIndent = v2{10, 4}; - string TitleString = MakeStringLiteral("Available Nodes"); - DrawListElement(TitleString, &List, Mouse, RenderBuffer, State->Interface); + gs_string Titlegs_string = MakeStringLiteral("Available Nodes"); + DrawListElement(Titlegs_string, &List, Context.Mouse, RenderBuffer, State->Interface.Style); for (u32 i = 0; i < NodeType_Count; i++) { node_specification_ Spec = NodeSpecifications[i]; - rect ElementBounds = DrawListElement(Spec.Identifier, &List, Mouse, RenderBuffer, State->Interface); + rect2 ElementBounds = DrawListElement(Spec.Identifier, &List, Context.Mouse, RenderBuffer, State->Interface.Style); - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) - && gs_PointIsInRect(Mouse.DownPos, ElementBounds)) + if (MouseButtonTransitionedDown(Context.Mouse.LeftButtonState) + && gs_PointIsInRect(Context.Mouse.DownPos, ElementBounds)) { PushNodeOnWorkspace(i, &State->NodeWorkspace, &State->Transient); GraphState->LayoutIsDirty = true; @@ -535,9 +535,9 @@ NodeGraph_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf } } - if (!MouseHandled && MouseButtonTransitionedDown(Mouse.LeftButtonState)) + if (!MouseHandled && MouseButtonTransitionedDown(Context.Mouse.LeftButtonState)) { - BeginPanNodeGraph(State, {}, Mouse); + BeginPanNodeGraph(State, {}, Context.Mouse); } } diff --git a/src/app/foldhaus_search_lister.cpp b/src/app/deprecated/foldhaus_search_lister.cpp similarity index 68% rename from src/app/foldhaus_search_lister.cpp rename to src/app/deprecated/foldhaus_search_lister.cpp index 78734b5..cb0725b 100644 --- a/src/app/foldhaus_search_lister.cpp +++ b/src/app/deprecated/foldhaus_search_lister.cpp @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_SEARCH_LISTER_CPP internal b32 -NamePassesFilter (string Target, string Filter) +NamePassesFilter (gs_string Target, gs_string Filter) { return (Filter.Length == 0 || StringContainsStringCaseInsensitive(Target, Filter)); } @@ -21,14 +21,14 @@ FilterSearchLister (search_lister* SearchLister) for (s32 i = 0; i < SearchLister->SourceListCount; i++) { - string* NameString = SearchLister->SourceList + i; - if (NamePassesFilter(*NameString, SearchLister->Filter)) + gs_string* Namegs_string = SearchLister->SourceList + i; + if (NamePassesFilter(*Namegs_string, SearchLister->Filter)) { SearchLister->FilteredIndexLUT[SearchLister->FilteredListCount++] = i; } } - SearchLister->HotItem = GSClamp(0, SearchLister->HotItem, SearchLister->FilteredListCount - 1); + SearchLister->HotItem = Clamp(0, SearchLister->HotItem, SearchLister->FilteredListCount - 1); if (SearchLister->FilteredListCount == 0) { @@ -39,14 +39,14 @@ FilterSearchLister (search_lister* SearchLister) internal s32 GetNextFilteredItem (search_lister SearchLister) { - s32 Result = GSMin(SearchLister.HotItem + 1, SearchLister.FilteredListCount - 1); + s32 Result = Min(SearchLister.HotItem + 1, SearchLister.FilteredListCount - 1); return Result; } internal s32 GetPrevFilteredItem (search_lister SearchLister) { - s32 Result = GSMax(SearchLister.HotItem - 1, 0); + s32 Result = Max(SearchLister.HotItem - 1, 0); return Result; } diff --git a/src/app/foldhaus_search_lister.h b/src/app/deprecated/foldhaus_search_lister.h similarity index 81% rename from src/app/foldhaus_search_lister.h rename to src/app/deprecated/foldhaus_search_lister.h index 8cc4d15..e2d502e 100644 --- a/src/app/foldhaus_search_lister.h +++ b/src/app/deprecated/foldhaus_search_lister.h @@ -8,11 +8,11 @@ struct search_lister { // TODO(Peter): Giving up trying to just use the source list for now. At the moment - // we are copying the strings you want to filter from and storing them here. Come back + // we are copying the gs_strings you want to filter from and storing them here. Come back // once its working and make the memory efficient version (ie store the existing memory // location, the element stride and the offset to the char*) s32 SourceListCount; - string* SourceList; + gs_string* SourceList; // NOTE(Peter): stores the source indecies of each filtered item // For example: @@ -23,7 +23,7 @@ struct search_lister s32* FilteredIndexLUT; s32 HotItem; - string Filter; + gs_string Filter; }; diff --git a/src/app/foldhaus_text_entry.cpp b/src/app/deprecated/foldhaus_text_entry.cpp similarity index 88% rename from src/app/foldhaus_text_entry.cpp rename to src/app/deprecated/foldhaus_text_entry.cpp index 1d59e10..7deb830 100644 --- a/src/app/foldhaus_text_entry.cpp +++ b/src/app/deprecated/foldhaus_text_entry.cpp @@ -17,15 +17,14 @@ PipeSearchStringToDestination (text_entry* Input) { switch (Input->Destination.Type) { - case TextTranslateTo_String: + case TextTranslateTo_gs_string: { - CopyStringTo(Input->Buffer, Input->Destination.StringDest); + PrintF(Input->Destination.StringDest, "%S", Input->Buffer); }break; case TextTranslateTo_R32: { - parse_result FloatParseResult = ParseFloat(StringExpand(Input->Buffer)); - *Input->Destination.FloatDest = FloatParseResult.FloatValue; + *Input->Destination.FloatDest = (r32)ParseFloat(Input->Buffer.ConstString); }break; InvalidDefaultCase; @@ -37,19 +36,22 @@ RemoveCharacterAtCursor (text_entry* TextEntry) { if (TextEntry->CursorPosition > 0) { - RemoveCharAt(&TextEntry->Buffer, - TextEntry->CursorPosition - 1); + for (u32 i = TextEntry->CursorPosition - 1; i < TextEntry->Buffer.Length; i++) + { + Assert(i + 1 < TextEntry->Buffer.Size); + TextEntry->Buffer.Str[i] = TextEntry->Buffer.Str[i + 1]; + } TextEntry->CursorPosition--; } } -internal void -SetTextInputDestinationToString (text_entry* TextInput, string* DestinationString) +internal void +SetTextInputDestinationToString (text_entry* TextInput, gs_string* DestinationString) { ResetTextInput(TextInput); - TextInput->Destination.Type = TextTranslateTo_String; + TextInput->Destination.Type = TextTranslateTo_gs_string; TextInput->Destination.StringDest = DestinationString; - CopyStringTo(*DestinationString, &TextInput->Buffer); + PrintF(&TextInput->Buffer, "%S", *DestinationString); } internal void @@ -69,14 +71,13 @@ SetTextInputDestinationToFloat (text_entry* TextInput, r32* DestinationFloat) internal void MoveCursorRight (text_entry* TextEntry) { - TextEntry->CursorPosition = GSMin(TextEntry->Buffer.Length, - TextEntry->CursorPosition + 1); + TextEntry->CursorPosition = Min(TextEntry->Buffer.Length, TextEntry->CursorPosition + 1); } internal void MoveCursorLeft (text_entry* TextEntry) { - TextEntry->CursorPosition = GSMax(0, TextEntry->CursorPosition - 1); + TextEntry->CursorPosition = Max(0, TextEntry->CursorPosition - 1); } FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar) @@ -88,12 +89,21 @@ FOLDHAUS_INPUT_COMMAND_PROC(TextEntryInsertChar) Char += ('a' - 'A'); } - InsertChar(&State->ActiveTextEntry.Buffer, Char, State->ActiveTextEntry.CursorPosition); + // Shift string forward + Assert(State->ActiveTextEntry.Buffer.Length < State->ActiveTextEntry.Buffer.Size); + for (u32 i = State->ActiveTextEntry.Buffer.Length; + i > (u32)State->ActiveTextEntry.CursorPosition; + i--) + { + State->ActiveTextEntry.Buffer.Str[i] = State->ActiveTextEntry.Buffer.Str[i - 1]; + } + // Insert new Character + State->ActiveTextEntry.Buffer.Str[State->ActiveTextEntry.CursorPosition] = Char; State->ActiveTextEntry.CursorPosition++; PipeSearchStringToDestination(&State->ActiveTextEntry); } -FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntryString) +FOLDHAUS_INPUT_COMMAND_PROC(RemoveCharacterFromEntrygs_string) { RemoveCharacterAtCursor(&State->ActiveTextEntry); } @@ -109,11 +119,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(TextEntryMoveCursorLeft) } internal void -InitializeTextInputCommands (input_command_registry* Commands, memory_arena* PermanentStorage) +InitializeTextInputCommands (input_command_registry* Commands, gs_memory_arena* PermanentStorage) { if (Commands->Size > 0) { - RegisterKeyPressCommand(Commands, KeyCode_Backspace, Command_Began | Command_Held, KeyCode_Invalid, RemoveCharacterFromEntryString); + RegisterKeyPressCommand(Commands, KeyCode_Backspace, Command_Began | Command_Held, KeyCode_Invalid, RemoveCharacterFromEntrygs_string); RegisterKeyPressCommand(Commands, KeyCode_LeftArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorLeft); RegisterKeyPressCommand(Commands, KeyCode_RightArrow, Command_Began | Command_Held, KeyCode_Invalid, TextEntryMoveCursorRight); @@ -126,7 +136,7 @@ InitializeTextInputCommands (input_command_registry* Commands, memory_arena* Per } #define DEFAULT_TEXT_ENTRY_INPUT_COMMANDS_ARRAY_ENTRY \ -{ KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, RemoveCharacterFromEntryString }, \ +{ KeyCode_Backspace, KeyCode_Invalid, Command_Began | Command_Held, RemoveCharacterFromEntrygs_string }, \ { KeyCode_LeftArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorLeft }, \ { KeyCode_RightArrow, KeyCode_Invalid, Command_Began | Command_Held, TextEntryMoveCursorRight }, \ { KeyCode_a, KeyCode_Invalid, Command_Began | Command_Held, TextEntryInsertChar }, \ diff --git a/src/app/foldhaus_text_entry.h b/src/app/deprecated/foldhaus_text_entry.h similarity index 81% rename from src/app/foldhaus_text_entry.h rename to src/app/deprecated/foldhaus_text_entry.h index dd8ba00..e25608f 100644 --- a/src/app/foldhaus_text_entry.h +++ b/src/app/deprecated/foldhaus_text_entry.h @@ -7,7 +7,7 @@ enum text_translation_type { - TextTranslateTo_String, + TextTranslateTo_gs_string, TextTranslateTo_R32, TextTranslateTo_S32, TextTranslateTo_U32, @@ -17,7 +17,7 @@ struct text_entry_destination { text_translation_type Type; union { - string* StringDest; + gs_string* StringDest; r32* FloatDest; s32* SignedIntDest; u32* UnsignedIntDest; @@ -26,7 +26,7 @@ struct text_entry_destination struct text_entry { - string Buffer; + gs_string Buffer; s32 CursorPosition; text_entry_destination Destination; diff --git a/src/app/foldhaus_util_radialumia_file_converter.cpp b/src/app/deprecated/foldhaus_util_radialumia_file_converter.cpp similarity index 72% rename from src/app/foldhaus_util_radialumia_file_converter.cpp rename to src/app/deprecated/foldhaus_util_radialumia_file_converter.cpp index 32945dd..d03074f 100644 --- a/src/app/foldhaus_util_radialumia_file_converter.cpp +++ b/src/app/deprecated/foldhaus_util_radialumia_file_converter.cpp @@ -10,42 +10,42 @@ #include #include -#include +#include #include "gs/gs_language.h" #include "gs/gs_string.h" #include "../meta/gs_meta_lexer.h" #include "gs/gs_vector.h" -#define STRING_BUFFER_SIZE 512 -struct string_buffer +#define gs_string_BUFFER_SIZE 512 +struct gs_string_buffer { char* Memory; s32 Size; - string_buffer* Next; + gs_string_buffer* Next; }; -struct string_writer +struct gs_string_writer { char* Cursor; - s32 UsedInString; - string_buffer* Buffer; + s32 UsedIngs_string; + gs_string_buffer* Buffer; }; -internal string_buffer* -GrowStringBuffer (string_buffer* Buffer) +internal gs_string_buffer* +Growgs_stringBuffer (gs_string_buffer* Buffer) { - string_buffer* Result; + gs_string_buffer* Result; if (Buffer->Next) { - Result = GrowStringBuffer(Buffer->Next); + Result = Growgs_stringBuffer(Buffer->Next); } else { - Result = (string_buffer*)malloc(sizeof(string_buffer)); - Result->Memory = (char*)malloc(sizeof(char) * STRING_BUFFER_SIZE); - memset(Result->Memory, 0, STRING_BUFFER_SIZE); - Result->Size = STRING_BUFFER_SIZE; + Result = (gs_string_buffer*)malloc(sizeof(gs_string_buffer)); + Result->Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE); + memset(Result->Memory, 0, gs_string_BUFFER_SIZE); + Result->Size = gs_string_BUFFER_SIZE; Result->Next = 0; Buffer->Next = Result; @@ -54,28 +54,28 @@ GrowStringBuffer (string_buffer* Buffer) } internal void -WriteString(string_writer* Writer, char* String, s32 Length) +Writegs_string(gs_string_writer* Writer, char* gs_string, s32 Length) { - char* Src = String; + char* Src = gs_string; char* Dst = Writer->Cursor; s32 LengthWritten = 0; - while (*Src && Writer->UsedInString < Writer->Buffer->Size &&LengthWritten < Length) + while (*Src && Writer->UsedIngs_string < Writer->Buffer->Size &&LengthWritten < Length) { LengthWritten++; *Dst++ = *Src++; - Writer->UsedInString++; + Writer->UsedIngs_string++; } Writer->Cursor = Dst; - if (*Src && Writer->UsedInString == Writer->Buffer->Size) + if (*Src && Writer->UsedIngs_string == Writer->Buffer->Size) { *(Dst - 1) = 0; // Null terminate the buffer - Writer->Buffer = GrowStringBuffer(Writer->Buffer); + Writer->Buffer = Growgs_stringBuffer(Writer->Buffer); Writer->Cursor = Writer->Buffer->Memory; - Writer->UsedInString = 0; - WriteString(Writer, (Src - 1), (Length - LengthWritten) + 1); + Writer->UsedIngs_string = 0; + Writegs_string(Writer, (Src - 1), (Length - LengthWritten) + 1); } } @@ -141,15 +141,15 @@ int main(int ArgCount, char* Args[]) control_box_pairs* StartPair = NextControlBoxPair; s32 PairsCount = 0; - if (StringsEqual(Tokenizer.At, "EOF")) + if (gs_stringsEqual(Tokenizer.At, "EOF")) { break; } EatToCharacterInclusive(&Tokenizer, '{'); EatWhitespace(&Tokenizer); - Assert(StringsEqual(Tokenizer.At, "neighbors: [")); - Tokenizer.At += StringLength("neighbors: ["); + Assert(gs_stringsEqual(Tokenizer.At, "neighbors: [")); + Tokenizer.At += gs_stringLength("neighbors: ["); // Parse Neighbors while(*Tokenizer.At && *Tokenizer.At != ']') @@ -177,8 +177,8 @@ int main(int ArgCount, char* Args[]) EatWhitespace(&Tokenizer); //Parse IP - Assert(StringsEqual(Tokenizer.At, "ip: ")); - Tokenizer.At += StringLength("ip: "); + Assert(gs_stringsEqual(Tokenizer.At, "ip: ")); + Tokenizer.At += gs_stringLength("ip: "); NextControlBox->Address = (char*)malloc(sizeof(char) * 13); memcpy(NextControlBox->Address, Tokenizer.At, 13); Tokenizer.At += 13; @@ -186,27 +186,27 @@ int main(int ArgCount, char* Args[]) // Parse X EatWhitespace(&Tokenizer); - Assert(StringsEqual(Tokenizer.At, "x: ")); - Tokenizer.At += StringLength("x: "); + Assert(gs_stringsEqual(Tokenizer.At, "x: ")); + Tokenizer.At += gs_stringLength("x: "); NextControlBox->X = ParseFloat(Tokenizer.At); EatToCharacterInclusive(&Tokenizer, ';'); // Parse Y EatWhitespace(&Tokenizer); - Assert(StringsEqual(Tokenizer.At, "y: ")); - Tokenizer.At += StringLength("y: "); + Assert(gs_stringsEqual(Tokenizer.At, "y: ")); + Tokenizer.At += gs_stringLength("y: "); NextControlBox->Y = ParseFloat(Tokenizer.At); EatToCharacterInclusive(&Tokenizer, ';'); // Parse Z EatWhitespace(&Tokenizer); - Assert(StringsEqual(Tokenizer.At, "z: ")); - Tokenizer.At += StringLength("z: "); + Assert(gs_stringsEqual(Tokenizer.At, "z: ")); + Tokenizer.At += gs_stringLength("z: "); NextControlBox->Z = ParseFloat(Tokenizer.At); EatToCharacterInclusive(&Tokenizer, ';'); // Parse ID EatWhitespace(&Tokenizer); - Assert(StringsEqual(Tokenizer.At, "id: ")); - Tokenizer.At += StringLength("id: "); + Assert(gs_stringsEqual(Tokenizer.At, "id: ")); + Tokenizer.At += gs_stringLength("id: "); NextControlBox->ID = ParseSignedInt(Tokenizer.At); EatToCharacterInclusive(&Tokenizer, ';'); @@ -278,36 +278,36 @@ int main(int ArgCount, char* Args[]) } - string_buffer OutputFileBuffer = {}; - OutputFileBuffer.Memory = (char*)malloc(sizeof(char) * STRING_BUFFER_SIZE); - OutputFileBuffer.Size = STRING_BUFFER_SIZE; + gs_string_buffer OutputFileBuffer = {}; + OutputFileBuffer.Memory = (char*)malloc(sizeof(char) * gs_string_BUFFER_SIZE); + OutputFileBuffer.Size = gs_string_BUFFER_SIZE; OutputFileBuffer.Next = 0; - string_writer RefWriter = {}; + gs_string_writer RefWriter = {}; RefWriter.Cursor = OutputFileBuffer.Memory; - RefWriter.UsedInString = 0; + RefWriter.UsedIngs_string = 0; RefWriter.Buffer = &OutputFileBuffer; - string_writer* Writer = &RefWriter; + gs_string_writer* Writer = &RefWriter; - char StringBuffer[512]; + char gs_stringBuffer[512]; s32 Len = 0; - Len = sprintf_s(StringBuffer, 512, "control_box_count %d\n", ControlBoxesUsed); - WriteString(Writer, StringBuffer, Len); - Len = sprintf_s(StringBuffer, 512, "led_strip_count %d\n\n", ControlBoxPairsUsed); - WriteString(Writer, StringBuffer, Len); + Len = sprintf_s(gs_stringBuffer, 512, "control_box_count %d\n", ControlBoxesUsed); + Writegs_string(Writer, gs_stringBuffer, Len); + Len = sprintf_s(gs_stringBuffer, 512, "led_strip_count %d\n\n", ControlBoxPairsUsed); + Writegs_string(Writer, gs_stringBuffer, Len); for (s32 c = 0; c < ControlBoxesUsed; c++) { control_box* Box = ControlBoxes + c; - Len = sprintf_s(StringBuffer, 512, + Len = sprintf_s(gs_stringBuffer, 512, "control_box { %d, \"%s\", (%f, %f, %f) }\n", Box->ID, Box->Address, Box->X, Box->Y, Box->Z); - WriteString(Writer, StringBuffer, Len); + Writegs_string(Writer, gs_stringBuffer, Len); } - WriteString(Writer, "\n", 1); + Writegs_string(Writer, "\n", 1); #define UNIVERSES_PER_BOX 25 s32 UniversesPerBox[64]; @@ -316,7 +316,7 @@ int main(int ArgCount, char* Args[]) UniversesPerBox[u] = UNIVERSES_PER_BOX * u; } - char LEDStripFormatString[] = "led_strip { %d, %d, %d, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 144 } \n"; + char LEDStripFormatgs_string[] = "led_strip { %d, %d, %d, INTERPOLATE_POINTS, (%f, %f, %f), (%f, %f, %f), 144 } \n"; for (s32 s = 0; s < ControlBoxPairsUsed; s++) { control_box_pairs* Pair = ControlBoxPairs + s; @@ -332,15 +332,15 @@ int main(int ArgCount, char* Args[]) r32 EndY = ControlBoxes[Pair->End].Y; r32 EndZ = ControlBoxes[Pair->End].Z; - Len = sprintf_s(StringBuffer, 512, - LEDStripFormatString, + Len = sprintf_s(gs_stringBuffer, 512, + LEDStripFormatgs_string, Pair->Start, Universe, 0, StartX, StartY, StartZ, EndX, EndY, EndZ); - WriteString(Writer, StringBuffer, Len); + Writegs_string(Writer, gs_stringBuffer, Len); } - WriteString(Writer, "\n", 1); + Writegs_string(Writer, "\n", 1); for (s32 sp = 0; sp < ExtraStripsUsed; sp++) { @@ -349,20 +349,20 @@ int main(int ArgCount, char* Args[]) s32 Universe = UniversesPerBox[Strip->BoxID]; UniversesPerBox[Strip->BoxID]++; - Len = sprintf_s(StringBuffer, 512, - LEDStripFormatString, + Len = sprintf_s(gs_stringBuffer, 512, + LEDStripFormatgs_string, Strip->BoxID, Universe, 0, Strip->Start.x, Strip->Start.y, Strip->Start.z, Strip->End.x, Strip->End.y, Strip->End.z); - WriteString(Writer, StringBuffer, Len); + Writegs_string(Writer, gs_stringBuffer, Len); } - WriteString(Writer, "END_OF_ASSEMBLY_FILE", StringLength("END_OF_ASSEMBLY_FILE")); + Writegs_string(Writer, "END_OF_ASSEMBLY_FILE", gs_stringLength("END_OF_ASSEMBLY_FILE")); *Writer->Cursor = 0; FILE* OutputFile = fopen("F:/data/radialumia.fold", "w"); - string_buffer* BufferCursor = &OutputFileBuffer; + gs_string_buffer* BufferCursor = &OutputFileBuffer; while(BufferCursor) { fprintf(OutputFile, BufferCursor->Memory); diff --git a/src/app/node/foldhaus_node_interface.cpp b/src/app/deprecated/node/foldhaus_node_interface.cpp similarity index 90% rename from src/app/node/foldhaus_node_interface.cpp rename to src/app/deprecated/node/foldhaus_node_interface.cpp index 0b4c3e4..f4e3b39 100644 --- a/src/app/node/foldhaus_node_interface.cpp +++ b/src/app/deprecated/node/foldhaus_node_interface.cpp @@ -18,7 +18,7 @@ struct node_lister_operation_state }; internal void -RenderNodeLister(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderNodeLister(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { node_lister_operation_state* OpState = (node_lister_operation_state*)Operation.OpStateMemory; @@ -30,7 +30,7 @@ RenderNodeLister(panel Panel, rect PanelBounds, render_command_buffer* RenderBuf FilterSearchLister(&OpState->SearchLister); // Display Search Lister - search_lister_result NodeListerResult = EvaluateSearchLister (&State->Interface_, TopLeft, Dimension, + search_lister_result NodeListerResult = EvaluateSearchLister (&State->Interface_, TopLeft, Dimension, MakeStringLiteral("Nodes List"), OpState->SearchLister.SourceList, OpState->SearchLister.FilteredIndexLUT, @@ -85,12 +85,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) AddNodeOperation->Render = RenderNodeLister; - node_lister_operation_state* OpState = CreateOperationState(AddNodeOperation, - &State->Modes, + 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); + OpState->SearchLister.SourceList = PushArray(&State->Modes.Arena, gs_string, OpState->SearchLister.SourceListCount); { for (s32 i = 0; i < OpState->SearchLister.SourceListCount; i++) { @@ -107,7 +107,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister) } OpState->ListPosition = Mouse.Pos; - SetTextInputDestinationToString(&State->ActiveTextEntry, &OpState->SearchLister.Filter); + SetTextInputDestinationTogs_string(&State->ActiveTextEntry, &OpState->SearchLister.Filter); } //////////////////////////////////////// @@ -133,12 +133,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(CloseColorPickerCommand) } internal void -RenderColorPicker(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderColorPicker(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { color_picker_operation_state* OpState = (color_picker_operation_state*)Operation.OpStateMemory; - b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, + b32 ShouldClose = EvaluateColorPicker(RenderBuffer, OpState->ValueAddr, v2{200, 200}, State->Interface, Mouse); if (ShouldClose) @@ -157,8 +157,8 @@ 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 = CreateOperationState(ColorPickerMode, + &State->Modes, color_picker_operation_state); OpState->ValueAddr = Connection->V4ValuePtr; } @@ -184,7 +184,7 @@ input_command NodeFieldTextEditCommands [] = { internal void BeginNodeFieldTextEdit(app_state* State, node_connection* Connection) { - operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, + operation_mode* NodeFieldTextEditMode = ActivateOperationModeWithCommands(&State->Modes, NodeFieldTextEditCommands); SetTextInputDestinationToFloat(&State->ActiveTextEntry, Connection->R32ValuePtr); @@ -202,10 +202,10 @@ struct drag_node_port_operation_state }; internal void -RenderDraggingNodePort(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderDraggingNodePort(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { drag_node_port_operation_state* OpState = (drag_node_port_operation_state*)Operation.OpStateMemory; - UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, + UpdateDraggingNodePort(Mouse.Pos, OpState->Interaction, State->NodeList, State->NodeRenderSettings, RenderBuffer); } @@ -225,12 +225,12 @@ internal void BeginDraggingNodePort(app_state* State, node_interaction Interaction) { operation_mode* DragNodePortMode = ActivateOperationModeWithCommands( - &State->Modes, + &State->Modes, DragNodePortInputCommands); DragNodePortMode->Render = RenderDraggingNodePort; - drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, - &State->Modes, + drag_node_port_operation_state* OpState = CreateOperationState(DragNodePortMode, + &State->Modes, drag_node_port_operation_state); OpState->Interaction = Interaction; } @@ -242,16 +242,16 @@ BeginDraggingNodePort(app_state* State, node_interaction Interaction) /////////////////////////////////////// internal void -RenderDragNodeField(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderDragNodeField(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { - // TODO(Peter): + // 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): + // TODO(Peter): } //////////////////////////////////////// @@ -266,10 +266,10 @@ struct drag_node_operation_state }; internal void -RenderDraggingNode(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderDraggingNode(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { drag_node_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_node_operation_state); - UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, + UpdateDraggingNode(Mouse.Pos, OpState->Interaction, State->NodeList, State->NodeRenderSettings); } @@ -286,12 +286,12 @@ internal void BeginDraggingNode(app_state* State, node_interaction Interaction) { operation_mode* DragNodeMode = ActivateOperationModeWithCommands( - &State->Modes, + &State->Modes, DragNodeInputCommands); DragNodeMode->Render = RenderDraggingNode; - drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, - &State->Modes, + drag_node_operation_state* OpState = CreateOperationState(DragNodeMode, + &State->Modes, drag_node_operation_state); OpState->Interaction = Interaction; } @@ -314,8 +314,8 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.DownPos, State->NodeRenderSettings); if (Node) { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, State->NodeRenderSettings); if (IsDraggingNodePort(NewInteraction)) { @@ -324,7 +324,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseDragInteraction) 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 + // the first frame we realize we're held over a field, just transition to // drag node field //BeginInteractWithNodeField(State, NewInteraction, State->NodeRenderSettings); } @@ -347,8 +347,8 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) node_header* Node = GetNodeUnderPoint(State->NodeList, Mouse.Pos, State->NodeRenderSettings); if (Node) { - node_interaction NewInteraction = GetNodeInteractionType(Node, - Mouse.Pos, + node_interaction NewInteraction = GetNodeInteractionType(Node, + Mouse.Pos, State->NodeRenderSettings); if(IsDraggingNodeValue(NewInteraction)) { @@ -368,7 +368,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(NodeViewBeginMouseSelectInteraction) } internal void -RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) +RenderNodeView(panel Panel, rect2 PanelBounds, render_command_buffer* RenderBufer, app_state* State, context Context, mouse_state Mouse) { node_view_operation_state* OpState = (node_view_operation_state*)Operation.OpStateMemory; @@ -383,7 +383,7 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer { node_header* Node = NodeIter.At; - rect NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); + rect2 NodeBounds = CalculateNodeBounds(Node, State->NodeRenderSettings); b32 DrawFields = PointIsInRect(Mouse.Pos, NodeBounds); if (Node == SelectedNode) @@ -394,8 +394,8 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer 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); + // Node->Name in Drawgs_string + gs_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)}, @@ -408,12 +408,12 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer // Inputs if (ConnectionIsInput(Node, Connection)) { - rect PortBounds = CalculateNodeInputPortBounds(Node, Connection, State->NodeRenderSettings); + rect2 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. + // 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 @@ -422,21 +422,21 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer { node_specification Spec = NodeSpecifications[Node->Type]; node_struct_member Member = Spec.MemberList[Connection]; - DrawString(RenderBuffer, MakeString(Member.Name), + 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); + rect2 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 + // 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); + rect2 ConnectedPortBounds = GetBoundsOfPortConnectedToInput(Node, Connection, State->NodeList, State->NodeRenderSettings); v2 InputCenter = CalculateRectCenter(PortBounds); v2 OutputCenter = CalculateRectCenter(ConnectedPortBounds); PushRenderLine2D(RenderBuffer, OutputCenter, InputCenter, 1, WhiteV4); @@ -446,25 +446,25 @@ RenderNodeView(panel Panel, rect PanelBounds, render_command_buffer* RenderBufer // Outputs if (ConnectionIsOutput(Node, Connection)) { - rect PortBounds = CalculateNodeOutputPortBounds(Node, Connection, State->NodeRenderSettings); + rect2 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), + DrawString(RenderBuffer, MakeString(Member.Name), State->NodeRenderSettings.Font, v2{PortBounds.Max.x + 8, PortBounds.Min.y}, WhiteV4); } - rect ValueBounds = CalculateNodeOutputValueBounds(Node, Connection, State->NodeRenderSettings); + rect2 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); + rect2 ButtonRect = CalculateNodeDragHandleBounds(NodeBounds, Button, State->NodeRenderSettings); PushRenderQuad2D(RenderBuffer, ButtonRect.Min, ButtonRect.Max, DragButtonColors[Button]); } } @@ -501,8 +501,8 @@ 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 = CreateOperationState(NodeViewMode, + &State->Modes, node_view_operation_state); OpState->SelectedNodeHandle = 0; diff --git a/src/app/dmx/dmx.h b/src/app/dmx/dmx.h deleted file mode 100644 index ed8e8b7..0000000 --- a/src/app/dmx/dmx.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// File: DMX_H -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef DMX_H - -struct dmx_buffer -{ - s32 Universe; - u8* Base; - s32 TotalSize; - s32 HeaderSize; -}; - -struct dmx_buffer_list -{ - dmx_buffer Buffer; - dmx_buffer_list* Next; -}; - -internal dmx_buffer_list* -DMXBufferListGetTail (dmx_buffer_list* List) -{ - dmx_buffer_list* Result = 0; - if (List->Next == 0) - { - Result = List; - } - else - { - Result = DMXBufferListGetTail(List->Next); - } - return Result; -} - -internal dmx_buffer_list* -DMXBufferListAppend (dmx_buffer_list* AppendTo, dmx_buffer_list* Append) -{ - dmx_buffer_list* Result = 0; - - if (AppendTo) - { - dmx_buffer_list* Tail = DMXBufferListGetTail(AppendTo); - Tail->Next = Append; - Result = AppendTo; - } - else - { - Result = Append; - } - - return Result; -} - -#define DMX_H -#endif // DMX_H \ No newline at end of file diff --git a/src/app/foldhaus_command_dispatch.h b/src/app/editor/foldhaus_command_dispatch.h similarity index 95% rename from src/app/foldhaus_command_dispatch.h rename to src/app/editor/foldhaus_command_dispatch.h index 2a7fc1e..e9db217 100644 --- a/src/app/foldhaus_command_dispatch.h +++ b/src/app/editor/foldhaus_command_dispatch.h @@ -5,10 +5,10 @@ // #ifndef FOLDHAUS_COMMAND_DISPATCH_H -#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse) +#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse, context Context) typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc); -// NOTE(Peter): Helper function so I don't have to remember the parameters to this define +// NOTE(Peter): Helper function so I don't have to remember the parameters to this define #define ExecFoldhausCommand(cmd) cmd(State, Event, Mouse) enum input_command_flags @@ -55,7 +55,7 @@ struct input_command_queue internal void InitializeInputCommandRegistry (input_command_registry* CommandRegistry, s32 Size, - memory_arena* Storage) + gs_memory_arena* Storage) { CommandRegistry->Commands = PushArray(Storage, input_command, Size); CommandRegistry->Size = Size; @@ -115,8 +115,8 @@ internal void RemoveCommandFromQueue(input_command_queue* Queue, s32 Index) { s32 CommandIndex = Index; - if (CommandIndex < Queue->Used) - { + if (CommandIndex < Queue->Used) + { Queue->Used -= 1; for (; CommandIndex < Queue->Used; CommandIndex++) @@ -132,9 +132,9 @@ RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_ 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, + // 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: + // 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 diff --git a/src/app/foldhaus_interface.cpp b/src/app/editor/foldhaus_interface.cpp similarity index 71% rename from src/app/foldhaus_interface.cpp rename to src/app/editor/foldhaus_interface.cpp index 86684f5..28a24c2 100644 --- a/src/app/foldhaus_interface.cpp +++ b/src/app/editor/foldhaus_interface.cpp @@ -19,19 +19,6 @@ enum panel_edit_mode PanelEdit_Count, }; -internal void -SetPanelDefinition(panel* Panel, s32 NewPanelDefinitionIndex, app_state* State) -{ - s32 OldPanelDefinitionIndex = Panel->PanelDefinitionIndex; - Panel->PanelDefinitionIndex = NewPanelDefinitionIndex; - - if(OldPanelDefinitionIndex >= 0) - { - GlobalPanelDefs[OldPanelDefinitionIndex].Cleanup(Panel, State); - } - GlobalPanelDefs[NewPanelDefinitionIndex].Init(Panel, State); -} - // // Drag Panel Border Operation Mode @@ -41,7 +28,7 @@ OPERATION_STATE_DEF(drag_panel_border_operation_state) // 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; + rect2 InitialPanelBounds; panel_split_direction PanelEdgeDirection; panel_edit_mode PanelEditMode; }; @@ -49,7 +36,7 @@ OPERATION_STATE_DEF(drag_panel_border_operation_state) OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) { drag_panel_border_operation_state* OpState = (drag_panel_border_operation_state*)Operation.OpStateMemory; - rect PanelBounds = OpState->InitialPanelBounds; + rect2 PanelBounds = OpState->InitialPanelBounds; if (OpState->PanelEditMode == PanelEdit_Modify) { @@ -72,10 +59,10 @@ OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) } else if (OpState->PanelEditMode == PanelEdit_Destroy) { - rect PanelToDeleteBounds = {}; + rect2 PanelToDeleteBounds = {}; if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) { - r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); + r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); if (Mouse.Pos.y > SplitY) { PanelToDeleteBounds = GetTopPanelBounds(OpState->Panel, PanelBounds); @@ -87,7 +74,7 @@ OPERATION_RENDER_PROC(UpdateAndRenderDragPanelBorder) } else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) { - r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); + r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x); if (Mouse.Pos.x > SplitX) { PanelToDeleteBounds = GetRightPanelBounds(OpState->Panel, PanelBounds); @@ -106,7 +93,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) { drag_panel_border_operation_state* OpState = GetCurrentOperationState(State->Modes, drag_panel_border_operation_state); panel* Panel = OpState->Panel; - rect PanelBounds = OpState->InitialPanelBounds; + rect2 PanelBounds = OpState->InitialPanelBounds; if (OpState->PanelEditMode == PanelEdit_Modify) { @@ -123,7 +110,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) } else { - Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / gs_Height(PanelBounds); + Panel->SplitPercent = (NewSplitY - PanelBounds.Min.y) / Rect2Height(PanelBounds); } } else if (Panel->SplitDirection == PanelSplit_Vertical) @@ -139,7 +126,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) } else { - Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / gs_Width(PanelBounds); + Panel->SplitPercent = (NewSplitX - PanelBounds.Min.x) / Rect2Width(PanelBounds); } } } @@ -147,7 +134,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) { if (OpState->PanelEdgeDirection == PanelSplit_Horizontal) { - r32 SplitY = GSLerp(PanelBounds.Min.y, PanelBounds.Max.y, OpState->Panel->SplitPercent); + r32 SplitY = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); if (Mouse.Pos.y > SplitY) { ConsolidatePanelsKeepOne(Panel, Panel->Bottom, &State->PanelSystem); @@ -159,7 +146,7 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndDragPanelBorderOperation) } else if (OpState->PanelEdgeDirection == PanelSplit_Vertical) { - r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, OpState->Panel->SplitPercent); + r32 SplitX = LerpR32(OpState->Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x); if (Mouse.Pos.x > SplitX) { ConsolidatePanelsKeepOne(Panel, Panel->Left, &State->PanelSystem); @@ -180,7 +167,7 @@ input_command DragPanelBorderCommands[] = { }; internal void -BeginDragPanelBorder(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, panel_split_direction PanelEdgeDirection, mouse_state Mouse, app_state* State) +BeginDragPanelBorder(panel* Panel, panel_edit_mode PanelEditMode, rect2 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); @@ -202,17 +189,17 @@ OPERATION_STATE_DEF(split_panel_operation_state) // 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; + rect2 InitialPanelBounds; }; OPERATION_RENDER_PROC(UpdateAndRenderSplitPanel) { split_panel_operation_state* OpState = (split_panel_operation_state*)Operation.OpStateMemory; - rect PanelBounds = OpState->InitialPanelBounds; + rect2 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); + r32 MouseDeltaX = Abs(Mouse.Pos.x - Mouse.DownPos.x); + r32 MouseDeltaY = Abs(Mouse.Pos.y - Mouse.DownPos.y); v2 EdgePreviewMin = {}; v2 EdgePreviewMax = {}; @@ -234,27 +221,27 @@ 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; + rect2 PanelBounds = OpState->InitialPanelBounds; - r32 XDistance = GSAbs(Mouse.Pos.x - Mouse.DownPos.x); - r32 YDistance = GSAbs(Mouse.Pos.y - Mouse.DownPos.y); + r32 XDistance = Abs(Mouse.Pos.x - Mouse.DownPos.x); + r32 YDistance = Abs(Mouse.Pos.y - Mouse.DownPos.y); if (XDistance > YDistance) { - r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / gs_Width(PanelBounds); - SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); + r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / Rect2Width(PanelBounds); + SplitPanelVertically(Panel, XPercent, &State->PanelSystem, State, Context); } else { - r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / gs_Height(PanelBounds); - SplitPanelHorizontally(Panel, YPercent, PanelBounds, &State->PanelSystem); + r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / Rect2Height(PanelBounds); + SplitPanelHorizontally(Panel, YPercent, &State->PanelSystem, State, Context); } - Panel->Left->Panel.PanelDefinitionIndex = Panel->PanelDefinitionIndex; - Panel->Left->Panel.PanelStateMemory = Panel->PanelStateMemory; - Panel->Left->Panel.PanelStateMemorySize = Panel->PanelStateMemorySize; + s32 PanelTypeIndex = Panel->TypeIndex; + gs_data PanelStateMemory = Panel->StateMemory; + Panel_SetCurrentType(&Panel->Left->Panel, &State->PanelSystem, PanelTypeIndex, PanelStateMemory, State, Context); - SetPanelDefinition(&Panel->Right->Panel, Panel->PanelDefinitionIndex, State); + SetAndInitPanelType(&Panel->Right->Panel, &State->PanelSystem, PanelTypeIndex, State, Context); DeactivateCurrentOperationMode(&State->Modes); } @@ -264,7 +251,7 @@ input_command SplitPanelCommands[] = { }; internal void -BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_state* State) +BeginSplitPanelOperation(panel* Panel, rect2 PanelBounds, mouse_state Mouse, app_state* State) { operation_mode* SplitPanel = ActivateOperationModeWithCommands(&State->Modes, SplitPanelCommands, UpdateAndRenderSplitPanel); split_panel_operation_state* OpState = CreateOperationState(SplitPanel, &State->Modes, split_panel_operation_state); @@ -278,20 +265,22 @@ BeginSplitPanelOperation(panel* Panel, rect PanelBounds, mouse_state Mouse, app_ #define PANEL_EDGE_CLICK_MAX_DISTANCE 6 internal b32 -HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect PanelBounds, mouse_state Mouse, app_state* State) +HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEditMode, rect2 PanelBounds, mouse_state Mouse, app_state* State) { b32 HandledMouseInput = false; + rect2 PanelSplitButtonBounds = rect2{ PanelBounds.Min, PanelBounds.Min + v2{25, 25} }; + if (Panel->SplitDirection == PanelSplit_NoSplit - && PointIsInRange(Mouse.DownPos, PanelBounds.Min, PanelBounds.Min + v2{25, 25})) + && PointIsInRect(PanelSplitButtonBounds, Mouse.DownPos)) { 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); + r32 SplitY = LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y); + r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.y - SplitY); if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) { BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Horizontal, Mouse, State); @@ -299,13 +288,13 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit } else { - rect TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); - rect BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); - if (gs_PointIsInRect(Mouse.DownPos, BottomPanelBounds)) + rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + if (PointIsInRect(BottomPanelBounds, Mouse.DownPos)) { HandleMouseDownPanelInteractionOrRecurse(&Panel->Bottom->Panel, PanelEditMode, BottomPanelBounds, Mouse, State); } - if (gs_PointIsInRect(Mouse.DownPos, TopPanelBounds)) + if (PointIsInRect(TopPanelBounds, Mouse.DownPos)) { HandleMouseDownPanelInteractionOrRecurse(&Panel->Top->Panel, PanelEditMode, TopPanelBounds, Mouse, State); } @@ -313,8 +302,8 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit } else if (Panel->SplitDirection == PanelSplit_Vertical) { - r32 SplitX = GSLerp(PanelBounds.Min.x, PanelBounds.Max.x, Panel->SplitPercent); - r32 ClickDistanceFromSplit = GSAbs(Mouse.DownPos.x - SplitX); + r32 SplitX = LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x); + r32 ClickDistanceFromSplit = Abs(Mouse.DownPos.x - SplitX); if (ClickDistanceFromSplit < PANEL_EDGE_CLICK_MAX_DISTANCE) { BeginDragPanelBorder(Panel, PanelEditMode, PanelBounds, PanelSplit_Vertical, Mouse, State); @@ -322,13 +311,13 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit } else { - rect LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); - rect RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); - if (gs_PointIsInRect(Mouse.DownPos, LeftPanelBounds)) + rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + if (PointIsInRect(LeftPanelBounds, Mouse.DownPos)) { HandleMouseDownPanelInteractionOrRecurse(&Panel->Left->Panel, PanelEditMode, LeftPanelBounds, Mouse, State); } - if (gs_PointIsInRect(Mouse.DownPos, RightPanelBounds)) + if (PointIsInRect(RightPanelBounds, Mouse.DownPos)) { HandleMouseDownPanelInteractionOrRecurse(&Panel->Right->Panel, PanelEditMode, RightPanelBounds, Mouse, State); } @@ -339,7 +328,7 @@ HandleMouseDownPanelInteractionOrRecurse(panel* Panel, panel_edit_mode PanelEdit } internal b32 -HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_state Mouse, app_state* State) +HandleMousePanelInteraction(panel_system* PanelSystem, rect2 WindowBounds, mouse_state Mouse, app_state* State) { b32 HandledMouseInput = false; @@ -359,10 +348,10 @@ HandleMousePanelInteraction(panel_system* PanelSystem, rect WindowBounds, mouse_ internal void DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mouse, render_command_buffer* RenderBuffer) { - 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); + r32 MouseLeftEdgeDistance = Abs(Mouse->Pos.x - PanelMin.x); + r32 MouseRightEdgeDistance = Abs(Mouse->Pos.x - PanelMax.x); + r32 MouseTopEdgeDistance = Abs(Mouse->Pos.y - PanelMax.y); + r32 MouseBottomEdgeDistance = Abs(Mouse->Pos.y - PanelMin.y); PushRenderBoundingBox2D(RenderBuffer, PanelMin, PanelMax, 1, Color); v4 HighlightColor = v4{.3f, .3f, .3f, 1.f}; @@ -398,41 +387,46 @@ DrawPanelBorder(panel Panel, v2 PanelMin, v2 PanelMax, v4 Color, mouse_state* Mo } internal void -DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBounds, mouse_state Mouse, app_state* State) +DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect2 FooterBounds, mouse_state Mouse, app_state* State, context Context) { 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); - rect PanelSelectBtnBounds = gs_MakeRectMinWidth(FooterBounds.Min + v2{30, 1}, v2{100, 23}); + rect2 PanelSelectBtnBounds = MakeRect2MinDim(FooterBounds.Min + v2{30, 1}, v2{100, 23}); if (Panel->PanelSelectionMenuOpen) { - rect ButtonBounds = gs_MakeRectMinWidth(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 }); + rect2 ButtonBounds = MakeRect2MinDim(v2{ PanelSelectBtnBounds.Min.x, FooterBounds.Max.y }, v2{ 100, 25 }); + + rect2 MenuBounds = rect2 + { + ButtonBounds.Min, + v2{ + ButtonBounds.Min.x + Rect2Width(ButtonBounds), ButtonBounds.Min.y + (Rect2Height(ButtonBounds) * GlobalPanelDefsCount) + }, + }; - v2 MenuMin = ButtonBounds.Min; - v2 MenuMax = v2{ButtonBounds.Min.x + gs_Width(ButtonBounds), ButtonBounds.Min.y + (gs_Height(ButtonBounds) * GlobalPanelDefsCount)}; if (MouseButtonTransitionedDown(Mouse.LeftButtonState) - && !PointIsInRange(Mouse.DownPos, MenuMin, MenuMax)) + && !PointIsInRect(MenuBounds, Mouse.DownPos)) { Panel->PanelSelectionMenuOpen = false; } - for (s32 i = 0; i < GlobalPanelDefsCount; i++) { panel_definition Def = GlobalPanelDefs[i]; - string DefName = MakeString(Def.PanelName, Def.PanelNameLength); - if (ui_Button(&State->Interface_, DefName, ButtonBounds)) + gs_string DefName = MakeString(Def.PanelName, Def.PanelNameLength); + if (ui_Button(&State->Interface, DefName, ButtonBounds)) { - SetPanelDefinition(Panel, i, State); + SetAndInitPanelType(Panel, &State->PanelSystem, i, State, Context); Panel->PanelSelectionMenuOpen = false; } - ButtonBounds = gs_TranslateRectY(ButtonBounds, gs_Height(ButtonBounds)); + ButtonBounds = Rect2TranslateY(ButtonBounds, Rect2Height(ButtonBounds)); } } - if (ui_Button(&State->Interface_, MakeStringLiteral("Select"), PanelSelectBtnBounds)) + if (ui_Button(&State->Interface, MakeString("Select"), PanelSelectBtnBounds)) { Panel->PanelSelectionMenuOpen = !Panel->PanelSelectionMenuOpen; } @@ -440,24 +434,25 @@ DrawPanelFooter(panel* Panel, render_command_buffer* RenderBuffer, rect FooterBo } internal void -RenderPanel(panel* Panel, rect PanelBounds, rect WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +RenderPanel(panel* Panel, rect2 PanelBounds, rect2 WindowBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) { - Assert(Panel->PanelDefinitionIndex >= 0); + s32 PanelType = Panel->TypeIndex; + Assert(PanelType >= 0); - rect FooterBounds = rect{ + rect2 FooterBounds = rect2{ PanelBounds.Min, v2{PanelBounds.Max.x, PanelBounds.Min.y + 25}, }; - rect PanelViewBounds = rect{ + rect2 PanelViewBounds = rect2{ v2{PanelBounds.Min.x, FooterBounds.Max.y}, PanelBounds.Max, }; - panel_definition Definition = GlobalPanelDefs[Panel->PanelDefinitionIndex]; - Definition.Render(*Panel, PanelViewBounds, RenderBuffer, State, Context, Mouse); + panel_definition Definition = GlobalPanelDefs[PanelType]; + Definition.Render(Panel, PanelViewBounds, RenderBuffer, State, Context); - PushRenderOrthographic(RenderBuffer, WindowBounds.Min.x, WindowBounds.Min.y, WindowBounds.Max.x, WindowBounds.Max.y); - DrawPanelFooter(Panel, RenderBuffer, FooterBounds, Mouse, State); + PushRenderOrthographic(RenderBuffer, WindowBounds); + DrawPanelFooter(Panel, RenderBuffer, FooterBounds, Mouse, State, Context); } internal void @@ -467,16 +462,15 @@ DrawAllPanels(panel_layout PanelLayout, render_command_buffer* RenderBuffer, mou { panel_with_layout PanelWithLayout = PanelLayout.Panels[i]; panel* Panel = PanelWithLayout.Panel; - rect PanelBounds = PanelWithLayout.Bounds; + rect2 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); + PushRenderOrthographic(RenderBuffer, State->WindowBounds); DrawPanelBorder(*Panel, PanelBounds.Min, PanelBounds.Max, BorderColor, Mouse, RenderBuffer); } } - #define FOLDHAUS_INTERFACE_CPP #endif // FOLDHAUS_INTERFACE_CPP \ No newline at end of file diff --git a/src/app/editor/foldhaus_operation_mode.h b/src/app/editor/foldhaus_operation_mode.h new file mode 100644 index 0000000..e45606a --- /dev/null +++ b/src/app/editor/foldhaus_operation_mode.h @@ -0,0 +1,143 @@ +// +// File: foldhaus_operation_mode.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_OPERATION_MODE_H + +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, context Context) +typedef OPERATION_RENDER_PROC(operation_render_proc); + +struct operation_mode +{ + input_command_registry Commands; + operation_render_proc* Render; + gs_memory_cursor Memory; + u8* OpStateMemory; +}; + +#define OPERATION_MODES_MAX 32 +struct operation_mode_system +{ + s32 ActiveModesCount; + operation_mode ActiveModes[OPERATION_MODES_MAX]; + //arena_snapshot ModeMemorySnapshots[OPERATION_MODES_MAX]; + gs_data_array ModeMemoryPagesFreeList; + + // NOTE(Peter): This acts as mode scoped memory. When a mode gets activated, it can allocate + // temporary memory which then gets freed when the mode is deactivated + gs_memory_arena Arena; +}; + +internal operation_mode_system +OperationModeSystemInit(gs_memory_arena* Storage, gs_thread_context ThreadContext) +{ + operation_mode_system Result = {0}; + // TODO(Peter): Do we really need an arena? Can this just operate in constant memory footprint? + Result.Arena.Allocator = ThreadContext.Allocator; + + Result.ModeMemoryPagesFreeList.CountMax = 16; // TODO(Peter): Static number of modes that can be active simultaneously + Result.ModeMemoryPagesFreeList.Data = PushArray(Storage, gs_data, Result.ModeMemoryPagesFreeList.CountMax); + for (u32 Page = 0; Page < Result.ModeMemoryPagesFreeList.CountMax; Page++) + { + // TODO(Peter): 4k pages = page size on windows + Result.ModeMemoryPagesFreeList.Data[Page] = PushSizeToData(Storage, KB(4)); + } + Result.ModeMemoryPagesFreeList.Count = Result.ModeMemoryPagesFreeList.CountMax; + + return Result; +} + +internal gs_data +OperationModeTakeMemoryPage(operation_mode_system* System) +{ + Assert(System->ModeMemoryPagesFreeList.Count > 0); + gs_data Result = {0}; + System->ModeMemoryPagesFreeList.Count -= 1; + u64 LastIndex = System->ModeMemoryPagesFreeList.Count; + Result = System->ModeMemoryPagesFreeList.Data[LastIndex]; + return Result; +} + +internal void +OperationModeFreeMemoryPage(operation_mode_system* System, gs_data Data) +{ + Assert(System->ModeMemoryPagesFreeList.Count < System->ModeMemoryPagesFreeList.CountMax); + u64 LastIndex = System->ModeMemoryPagesFreeList.Count; + System->ModeMemoryPagesFreeList.Count += 1; + System->ModeMemoryPagesFreeList.Data[LastIndex] = Data; +} + +internal operation_mode* +ActivateOperationMode (operation_mode_system* System, operation_render_proc* RenderProc) +{ + Assert(System->ActiveModesCount < OPERATION_MODES_MAX); + operation_mode* Result = 0; + s32 ModeIndex = System->ActiveModesCount++; + + //System->ModeMemorySnapshots[ModeIndex] = TakeSnapshotOfArena(&System->Arena); + + Result = &System->ActiveModes[ModeIndex]; + Result->Memory = CreateMemoryCursor(OperationModeTakeMemoryPage(System)); + Result->Render = RenderProc; + + return Result; +} + +#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, operation_render_proc* RenderProc) +{ + operation_mode* NewMode = ActivateOperationMode(System, RenderProc); + +#if 0 + InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena); + for (s32 i = 0; i < CommandsCount; i++) + { + input_command Command = Commands[i]; + RegisterKeyPressCommand(&NewMode->Commands, Command.Key, Command.Flags, Command.Mdfr, Command.Proc); + } +#else + NewMode->Commands.Commands = Commands; + NewMode->Commands.Size = CommandsCount; + NewMode->Commands.Used = CommandsCount; +#endif + return NewMode; +} + +internal void +DeactivateCurrentOperationMode (operation_mode_system* System) +{ + Assert(System->ActiveModesCount > 0); + s32 ModeIndex = --System->ActiveModesCount; + OperationModeFreeMemoryPage(System, System->ActiveModes[ModeIndex].Memory.Data); + //ClearArenaToSnapshot(&System->Arena, System->ModeMemorySnapshots[ModeIndex]); +} + +#define CreateOperationState(mode, modeSystem, stateType) \ +(stateType*)CreateOperationState_(mode, modeSystem, sizeof(stateType)) + +#define GetCurrentOperationState(modeSystem, stateType) \ +(stateType*)(modeSystem).ActiveModes[(modeSystem).ActiveModesCount - 1].OpStateMemory; + + +internal u8* +CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32 StateSize) +{ + // NOTE(Peter): This isn't a problem if this fires, it just means our page size is too small, + // and its time to make the pages dynamically sized + Assert(Mode->Memory.Data.Size >= StateSize); + u8* Result = PushSizeOnCursor(&Mode->Memory, StateSize).Memory; + Mode->OpStateMemory = Result; + return Result; +} + + +#define FOLDHAUS_OPERATION_MODE_H +#endif // FOLDHAUS_OPERATION_MODE_H \ No newline at end of file diff --git a/src/app/editor/foldhaus_panel.h b/src/app/editor/foldhaus_panel.h new file mode 100644 index 0000000..658a8a3 --- /dev/null +++ b/src/app/editor/foldhaus_panel.h @@ -0,0 +1,448 @@ +// +// File: foldhaus_panel.h +// Author: Peter Slattery +// Creation Date: 2019-12-26 +// +// Usage: +// Include this file in ONE file in your project. +// Define SetPanelDefinitionExternal +// +#ifndef FOLDHAUS_PANEL_H + +enum panel_split_direction +{ + PanelSplit_NoSplit, + PanelSplit_Horizontal, + PanelSplit_Vertical, + + PanelSplit_Count, +}; + +typedef struct panel_entry panel_entry; +typedef struct panel panel; + +#define PANEL_MODAL_OVERRIDE_CALLBACK(name) void name(panel* ReturningFrom, app_state* State, context Context) +typedef PANEL_MODAL_OVERRIDE_CALLBACK(panel_modal_override_callback); + +struct panel +{ + s32 TypeIndex; + gs_data StateMemory; + + panel_entry* ModalOverride; + panel* IsModalOverrideFor; // TODO(pjs): I don't like that this is panel* but ModalOverride is panel_entry* + panel_modal_override_callback* ModalOverrideCB; + + 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 PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State, context Context) +typedef PANEL_INIT_PROC(panel_init_proc); + +#define PANEL_CLEANUP_PROC(name) void name(panel* Panel, app_state* State) +typedef PANEL_CLEANUP_PROC(panel_cleanup_proc); + +#define PANEL_RENDER_PROC(name) void name(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +typedef PANEL_RENDER_PROC(panel_render_proc); + +// NOTE(Peter): This is used by the meta system to generate panel type info +struct panel_definition +{ + char* PanelName; + s32 PanelNameLength; + panel_init_proc* Init; + panel_cleanup_proc* Cleanup; + panel_render_proc* Render; + input_command* InputCommands; + s32 InputCommandsCount; +}; + +#define PANELS_MAX 16 +struct panel_system +{ + panel_definition* PanelDefs; + u32 PanelDefsCount; + + 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; + rect2 Bounds; +}; + +struct panel_layout +{ + panel_with_layout* Panels; + u32 PanelsCount; + u32 PanelsMax; +}; + +///////////////////////////////// +// +// Book-Keeping +// +///////////////////////////////// + +internal void +InitializePanelSystem(panel_system* PanelSystem, panel_definition* PanelDefs, u32 PanelDefsCount) +{ + PanelSystem->FreeList.Free.Next = &PanelSystem->FreeList; + PanelSystem->PanelDefs = PanelDefs; + PanelSystem->PanelDefsCount = PanelDefsCount; +} + +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 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 panel_entry* +Panel_GetModalOverride(panel_entry* PanelEntry) +{ + panel_entry* Result = PanelEntry; + if (PanelEntry->Panel.ModalOverride != 0) + { + Result = Panel_GetModalOverride(PanelEntry->Panel.ModalOverride); + } + return Result; +} + +internal panel* +Panel_GetModalOverride(panel* Panel) +{ + panel* Result = Panel; + if (Panel->ModalOverride != 0) + { + Result = &Panel_GetModalOverride(Panel->ModalOverride)->Panel; + } + return Result; +} + +internal void +Panel_PushModalOverride(panel* Root, panel_entry* Override, panel_modal_override_callback* Callback) +{ + Root->ModalOverride = Override; + Root->ModalOverrideCB = Callback; + Override->Panel.IsModalOverrideFor = Root; +} + +internal void +Panel_PopModalOverride(panel* Parent, panel_system* System) +{ + // TODO(pjs): Free the overrided panel + FreePanelEntry(Parent->ModalOverride, System); + Parent->ModalOverride = 0; +} + +internal void +Panel_SetCurrentType(panel* Panel, panel_system* System, s32 NewPanelType, gs_data TypeStateMemory, app_state* State, context Context) +{ + s32 OldTypeIndex = Panel->TypeIndex; + + Panel->TypeIndex = NewPanelType; + Panel->StateMemory = TypeStateMemory; + + if(OldTypeIndex >= 0) + { + System->PanelDefs[OldTypeIndex].Cleanup(Panel, State); + } +} + +internal void +SetAndInitPanelType(panel* Panel, panel_system* System, s32 NewPanelTypeIndex, app_state* State, context Context) +{ + gs_data EmptyStateData = {0}; + Panel_SetCurrentType(Panel, System, NewPanelTypeIndex, EmptyStateData, State, Context); + System->PanelDefs[NewPanelTypeIndex].Init(Panel, State, Context); +} + +#define Panel_GetStateStruct(p, type) (type*)Panel_GetStateMemory((p), sizeof(type)).Memory +internal gs_data +Panel_GetStateMemory(panel* Panel, u64 Size) +{ + Assert(Panel->StateMemory.Size == Size); + gs_data Result = Panel->StateMemory; + return Result; +} + +internal panel_entry* +PanelSystem_PushPanel(panel_system* PanelSystem, s32 PanelTypeIndex, app_state* State, context Context) +{ + panel_entry* PanelEntry = TakeNewPanelEntry(PanelSystem); + SetAndInitPanelType(&PanelEntry->Panel, PanelSystem, PanelTypeIndex, State, Context); + return PanelEntry; +} + +internal void +SplitPanel(panel* Parent, r32 Percent, panel_split_direction SplitDirection, panel_system* PanelSystem, app_state* State, context Context) +{ + if (Percent >= 0.0f && Percent <= 1.0f) + { + Parent->SplitDirection = SplitDirection; + Parent->SplitPercent = Percent; + + s32 ParentTypeIndex = Parent->TypeIndex; + gs_data ParentStateMemory = Parent->StateMemory; + Parent->Left = TakeNewPanelEntry(PanelSystem); + Panel_SetCurrentType(&Parent->Left->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + + Parent->Right = TakeNewPanelEntry(PanelSystem); + Panel_SetCurrentType(&Parent->Right->Panel, PanelSystem, ParentTypeIndex, ParentStateMemory, State, Context); + } +} + +internal void +SplitPanelVertically(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context) +{ + SplitPanel(Parent, Percent, PanelSplit_Vertical, PanelSystem, State, Context); +} + +internal void +SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem, app_state* State, context Context) +{ + SplitPanel(Parent, Percent, PanelSplit_Horizontal, PanelSystem, State, Context); +} + +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); +} + +///////////////////////////////// +// +// Rendering And Interaction +// +///////////////////////////////// + +internal rect2 +GetTopPanelBounds(panel* Panel, rect2 PanelBounds) +{ + rect2 Result = {}; + Result.Min = v2{ + PanelBounds.Min.x, + LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y) + }; + Result.Max = PanelBounds.Max; + return Result; +} + +internal rect2 +GetBottomPanelBounds(panel* Panel, rect2 PanelBounds) +{ + rect2 Result = {}; + Result.Min = PanelBounds.Min; + Result.Max = v2{ + PanelBounds.Max.x, + LerpR32(Panel->SplitPercent, PanelBounds.Min.y, PanelBounds.Max.y) + }; + return Result; +} + +internal rect2 +GetRightPanelBounds(panel* Panel, rect2 PanelBounds) +{ + rect2 Result = {}; + Result.Min = v2{ + LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x), + PanelBounds.Min.y + }; + Result.Max = PanelBounds.Max; + return Result; +} + +internal rect2 +GetLeftPanelBounds(panel* Panel, rect2 PanelBounds) +{ + rect2 Result = {}; + Result.Min = PanelBounds.Min; + Result.Max = v2{ + LerpR32(Panel->SplitPercent, PanelBounds.Min.x, PanelBounds.Max.x), + PanelBounds.Max.y + }; + return Result; +} + +internal void +LayoutPanel(panel* Panel, rect2 PanelBounds, panel_layout* Layout) +{ + if (Panel->SplitDirection == PanelSplit_NoSplit) + { + panel_with_layout* WithLayout = Layout->Panels + Layout->PanelsCount++; + WithLayout->Panel = Panel_GetModalOverride(Panel); + WithLayout->Bounds = PanelBounds; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + + panel* TopPanel = Panel_GetModalOverride(&Panel->Top->Panel); + panel* BottomPanel = Panel_GetModalOverride(&Panel->Bottom->Panel); + + LayoutPanel(&Panel->Top->Panel, TopPanelBounds, Layout); + LayoutPanel(&Panel->Bottom->Panel, BottomPanelBounds, Layout); + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + + panel* LeftPanel = Panel_GetModalOverride(&Panel->Top->Panel); + panel* RightPanel = Panel_GetModalOverride(&Panel->Bottom->Panel); + + LayoutPanel(&Panel->Left->Panel, LeftPanelBounds, Layout); + LayoutPanel(&Panel->Right->Panel, RightPanelBounds, Layout); + } +} + +internal panel_layout +GetPanelLayout(panel_system* System, rect2 WindowBounds, gs_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; +} + +internal panel_with_layout +GetPanelContainingPoint(v2 Point, panel* Panel, rect2 PanelBounds) +{ + panel_with_layout Result = {0}; + + if (Panel->SplitDirection == PanelSplit_NoSplit) + { + Result.Panel = Panel; + Result.Bounds = PanelBounds; + } + else if (Panel->SplitDirection == PanelSplit_Horizontal) + { + rect2 TopPanelBounds = GetTopPanelBounds(Panel, PanelBounds); + rect2 BottomPanelBounds = GetBottomPanelBounds(Panel, PanelBounds); + + if (PointIsInRect(TopPanelBounds, Point)) + { + Result = GetPanelContainingPoint(Point, &Panel->Top->Panel, TopPanelBounds); + } + else if (PointIsInRect(BottomPanelBounds, Point)) + { + Result = GetPanelContainingPoint(Point, &Panel->Bottom->Panel, BottomPanelBounds); + } + } + else if (Panel->SplitDirection == PanelSplit_Vertical) + { + rect2 LeftPanelBounds = GetLeftPanelBounds(Panel, PanelBounds); + rect2 RightPanelBounds = GetRightPanelBounds(Panel, PanelBounds); + + if (PointIsInRect(LeftPanelBounds, Point)) + { + Result = GetPanelContainingPoint(Point, &Panel->Left->Panel, LeftPanelBounds); + } + else if (PointIsInRect(RightPanelBounds, Point)) + { + Result = GetPanelContainingPoint(Point, &Panel->Right->Panel, RightPanelBounds); + } + } + + return Result; +} + +internal panel_with_layout +GetPanelContainingPoint(v2 Point, panel_system* PanelSystem, rect2 WindowBounds) +{ + panel_with_layout Result = {0}; + if (PanelSystem->PanelsUsed > 0) + { + Result = GetPanelContainingPoint(Point, &PanelSystem->Panels[0].Panel, WindowBounds); + } + return Result; +} + + +#define FOLDHAUS_PANEL_H +#endif // FOLDHAUS_PANEL_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_animation_timeline.h b/src/app/editor/panels/foldhaus_panel_animation_timeline.h new file mode 100644 index 0000000..a37dc78 --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_animation_timeline.h @@ -0,0 +1,658 @@ +// +// File: foldhaus_panel_animation_timeline.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H + +// Colors +global v4 TimeSliderColor = GreenV4; //v4{.36f, .52f, .78f, 1.f}; + +// +struct animation_timeline_state +{ + frame_range VisibleRange; + handle SelectedAnimationBlockHandle; + u32 SelectedAnimationLayer; +}; + +inline u32 +GetFrameFromPointInAnimationPanel(v2 Point, rect2 PanelBounds, frame_range VisibleRange) +{ + r32 HorizontalPercentOfBounds = (Point.x - PanelBounds.Min.x) / (PanelBounds.Max.x - PanelBounds.Min.x); + u32 VisibleFramesCount = GetFrameCount(VisibleRange); + u32 TimeAtPoint = (u32)(HorizontalPercentOfBounds * VisibleFramesCount) + VisibleRange.Min; + return TimeAtPoint; +} + +inline s32 +GetXPositionFromFrameInAnimationPanel (u32 Frame, rect2 PanelBounds, frame_range VisibleRange) +{ + r32 PercentOfTimeline = (r32)(Frame - VisibleRange.Min) / (r32)GetFrameCount(VisibleRange); + s32 XPositionAtFrame = (PercentOfTimeline * Rect2Width(PanelBounds)) + PanelBounds.Min.x; + return XPositionAtFrame; +} + +internal handle +AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 LayerHandle, animation_system* System) +{ + u32 NewBlockStart = System->CurrentFrame; + u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System); + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); + handle AnimHandle = Animation_AddBlock(ActiveAnim, NewBlockStart, NewBlockEnd, AnimationProcHandle, LayerHandle); + return AnimHandle; +} + +internal void +SelectAnimationBlock(handle BlockHandle, app_state* State) +{ + State->SelectedAnimationBlockHandle = BlockHandle; +} + +internal void +DeselectCurrentAnimationBlock(app_state* State) +{ + State->SelectedAnimationBlockHandle = {}; +} + +FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) +{ + handle SelectedAnimHandle = State->SelectedAnimationBlockHandle; + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + if(SelectedAnimHandle.Index < ActiveAnim->Blocks_.Count && + ActiveAnim->Blocks_.Generations[SelectedAnimHandle.Index] == SelectedAnimHandle.Generation) + { + Animation_RemoveBlock(ActiveAnim, State->SelectedAnimationBlockHandle); + State->SelectedAnimationBlockHandle = {0}; + // TODO(pjs): Introduce an animation_block_selection in this file + // it should have a handle to the animation, block, and a HasSelection flag + // as it is now, you kind of always have the first block selected + } +} + +// +// Drag Time Marker +// + +OPERATION_STATE_DEF(drag_time_marker_operation_state) +{ + rect2 TimelineBounds; + s32 StartFrame; + s32 EndFrame; +}; + +OPERATION_RENDER_PROC(UpdateDragTimeMarker) +{ + drag_time_marker_operation_state* OpState = (drag_time_marker_operation_state*)Operation.OpStateMemory; + frame_range Range = { OpState->StartFrame, OpState->EndFrame }; + u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, Range); + State->AnimationSystem.CurrentFrame = FrameAtMouseX; +} + +FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker) +{ + DeactivateCurrentOperationMode(&State->Modes); +} + +input_command DragTimeMarkerCommands [] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragTimeMarker }, +}; + +internal void +StartDragTimeMarker(rect2 TimelineBounds, frame_range VisibleFrames, 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 = VisibleFrames.Min; + OpState->EndFrame = VisibleFrames.Max; + OpState->TimelineBounds = TimelineBounds; +} + +// -------------------- + +// +// Drag Animation Clip +// + +#define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10 + +OPERATION_STATE_DEF(drag_animation_clip_state) +{ + rect2 TimelineBounds; + frame_range VisibleRange; + frame_range ClipRange; +}; + +internal u32 +AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame) +{ + u32 Result = SnappingFrame; + s32 SnapDistance = 5; + if (Abs((s32)SnappingFrame - (s32)SnapToFrame) <= SnapDistance) + { + Result = SnapToFrame; + } + return Result; +} + +OPERATION_RENDER_PROC(UpdateDragAnimationClip) +{ + drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; + + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + + r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange); + u32 ClipInitialStartFrameXPosition = LerpR32(ClipInitialStartFrameXPercent, + OpState->TimelineBounds.Min.x, + OpState->TimelineBounds.Max.x); + r32 ClipInitialEndFrameXPercent = FrameToPercentRange(OpState->ClipRange.Max, OpState->VisibleRange); + u32 ClipInitialEndFrameXPosition = LerpR32(ClipInitialEndFrameXPercent, + OpState->TimelineBounds.Min.x, + OpState->TimelineBounds.Max.x); + + u32 FrameAtMouseDownX = GetFrameFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->VisibleRange); + + u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange); + s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX; + + animation_block* AnimationBlock = Animation_GetBlockFromHandle(ActiveAnim, State->SelectedAnimationBlockHandle); + if (!AnimationBlock) + { + EndCurrentOperationMode(State, {}, Mouse, Context); + return; + } + + if (Abs(Mouse.DownPos.x - ClipInitialStartFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) + { + s32 NewStartFrame = OpState->ClipRange.Min + FrameOffset; + if (FrameOffset < 0) + { + for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++) + { + animation_block OtherBlock = ActiveAnim->Blocks_.Values[i]; + NewStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max); + } + } + else + { + if (NewStartFrame >= AnimationBlock->Range.Max) + { + NewStartFrame = AnimationBlock->Range.Max - 1; + } + } + AnimationBlock->Range.Min = NewStartFrame; + } + else if (Abs(Mouse.DownPos.x - ClipInitialEndFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) + { + r32 NewEndFrame = OpState->ClipRange.Max + FrameOffset; + if (FrameOffset > 0) + { + for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++) + { + animation_block OtherBlock = ActiveAnim->Blocks_.Values[i]; + NewEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min); + } + } + else + { + if(NewEndFrame <= AnimationBlock->Range.Min) + { + NewEndFrame = AnimationBlock->Range.Min + 1; + } + } + AnimationBlock->Range.Max = NewEndFrame; + } + else + { + u32 NewStartFrame = OpState->ClipRange.Min + FrameOffset; + u32 NewEndFrame = OpState->ClipRange.Max + FrameOffset; + for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++) + { + animation_block OtherBlock = ActiveAnim->Blocks_.Values[i];; + + u32 SnapFramesAmount = 0; + if (FrameOffset > 0) + { + u32 FinalEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min); + SnapFramesAmount = FinalEndFrame - NewEndFrame; + } + else if (FrameOffset < 0) + { + u32 FinalStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max); + SnapFramesAmount = FinalStartFrame - NewStartFrame; + } + NewEndFrame += SnapFramesAmount; + NewStartFrame += SnapFramesAmount; + } + AnimationBlock->Range.Min = NewStartFrame; + AnimationBlock->Range.Max = NewEndFrame; + } + + s32 PlayableStartFrame = ActiveAnim->PlayableRange.Min; + s32 PlayableEndFrame = ActiveAnim->PlayableRange.Max; + AnimationBlock->Range.Min = (u32)Clamp(PlayableStartFrame, (s32)AnimationBlock->Range.Min, PlayableEndFrame); + AnimationBlock->Range.Max = (u32)Clamp(PlayableStartFrame, (s32)AnimationBlock->Range.Max, PlayableEndFrame); +} + +input_command DragAnimationClipCommands [] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode }, +}; + +internal void +SelectAndBeginDragAnimationBlock(handle BlockHandle, frame_range VisibleRange, rect2 TimelineBounds, app_state* State) +{ + SelectAnimationBlock(BlockHandle, State); + + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + 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->VisibleRange = VisibleRange; + + animation_block* SelectedBlock = Animation_GetBlockFromHandle(ActiveAnim, BlockHandle); + OpState->ClipRange = SelectedBlock->Range; +} +// ------------------- + +FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) +{ + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + + panel_with_layout ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); + frame_range Range = ActiveAnim->PlayableRange; + u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range); + + handle NewBlockHandle = Animation_AddBlock(ActiveAnim, MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer); + SelectAnimationBlock(NewBlockHandle, State); +} + +input_command AnimationTimeline_Commands[] = { + { KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand }, + { KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand }, +}; +s32 AnimationTimeline_CommandsCount = 2; + +GSMetaTag(panel_init); +GSMetaTag(panel_type_animation_timeline); +internal void +AnimationTimeline_Init(panel* Panel, app_state* State, context Context) +{ + // TODO: :FreePanelMemory + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state); + TimelineState->VisibleRange = ActiveAnim->PlayableRange; + + Panel->StateMemory = StructToData(TimelineState, animation_timeline_state); +} + +GSMetaTag(panel_cleanup); +GSMetaTag(panel_type_animation_timeline); +internal void +AnimationTimeline_Cleanup(panel* Panel, app_state* State) +{ + +} + +internal void +DrawFrameBar (animation_system* AnimationSystem, ui_interface Interface, frame_range VisibleFrames, rect2 BarBounds, app_state* State) +{ + gs_string TempString = PushString(State->Transient, 256); + + s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min; + + r32 BarHeight = Rect2Height(BarBounds); + r32 BarWidth = Rect2Width(BarBounds); + + // Mouse clicked inside frame nubmer bar -> change current frame on timeline + if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) && + PointIsInRect(BarBounds, Interface.Mouse.DownPos)) + { + StartDragTimeMarker(BarBounds, VisibleFrames, State); + } + + PushRenderQuad2D(Interface.RenderBuffer, BarBounds.Min, BarBounds.Max, v4{.16f, .16f, .16f, 1.f}); + + // Frame Ticks + u32 TickCount = 10; + for (u32 Tick = 0; Tick < TickCount; Tick++) + { + r32 Percent = (r32)Tick / (r32)TickCount; + u32 Frame = PercentToFrameInRange(Percent, VisibleFrames); + PrintF(&TempString, "%d", Frame); + r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames); + r32 FrameX = LerpR32(FramePercent, BarBounds.Min.x, BarBounds.Max.x); + v2 FrameTextPos = v2{FrameX, BarBounds.Min.y + 2}; + DrawString(Interface.RenderBuffer, TempString, Interface.Style.Font, FrameTextPos, WhiteV4); + } + + // Time Slider + if (FrameIsInRange(VisibleFrames, AnimationSystem->CurrentFrame)) + { + r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, VisibleFrames); + r32 SliderX = LerpR32(FrameAtPercentVisibleRange, BarBounds.Min.x, BarBounds.Max.x); + + PrintF(&TempString, "%d", AnimationSystem->CurrentFrame); + + // space for each character + a margin on either side + r32 SliderWidth = (8 * TempString.Length) + 8; + r32 SliderHalfWidth = SliderWidth / 2.f; + v2 HeadMin = v2{SliderX - SliderHalfWidth, BarBounds.Min.y}; + v2 HeadMax = v2{SliderX + SliderHalfWidth, BarBounds.Max.y}; + PushRenderQuad2D(Interface.RenderBuffer, HeadMin, HeadMax, TimeSliderColor); + DrawString(Interface.RenderBuffer, TempString, Interface.Style.Font, HeadMin + v2{6, 4}, WhiteV4); + } +} + +internal bool +MinMaxRangeSlider(v2 HandleValues, rect2 SliderBounds, r32 MinValue, r32 MaxValue, ui_interface Interface, v2* OutHandleValues) +{ + // Should Update only gets set to true when the user is finished interacting (ie. on mouse up) + // this allows the continuous use of the value of a handle while it is being dragged, and allows + // for you to know when exactly to update the stored value + + bool ShouldUpdate = false; + *OutHandleValues = HandleValues; + + v4 BGColor = v4{.16f, .16f, .16f, 1.f}; + v4 HandleColor = v4{.8f, .8f, .8f, 1.f}; + + v2 HandleDim = v2{25, Rect2Height(SliderBounds)}; + r32 MinHandleX = RemapR32(HandleValues.x, MinValue, MaxValue, SliderBounds.Min.x, SliderBounds.Max.x); + r32 MaxHandleX = RemapR32(HandleValues.y, MinValue, MaxValue, SliderBounds.Min.x, SliderBounds.Max.x); + rect2 MinHandleBounds = MakeRect2CenterDim(v2{ MinHandleX, Rect2Center(SliderBounds).y }, HandleDim); + rect2 MaxHandleBounds = MakeRect2CenterDim(v2{ MaxHandleX, Rect2Center(SliderBounds).y }, HandleDim); + + // Drag the handles + if (MouseButtonHeldDown(Interface.Mouse.LeftButtonState) || + MouseButtonTransitionedUp(Interface.Mouse.LeftButtonState)) + { + v2 MouseDragOffset = Interface.Mouse.Pos - Interface.Mouse.DownPos; + + // TODO(pjs): We need to make sure that the min handle is always the lower one, etc. + // TODO(pjs): We need to range clamp the handles + if (PointIsInRect(MinHandleBounds, Interface.Mouse.DownPos)) + { + MinHandleBounds = Rect2TranslateX(MinHandleBounds, MouseDragOffset.x); + } + else if (PointIsInRect(MaxHandleBounds, Interface.Mouse.DownPos)) + { + MaxHandleBounds = Rect2TranslateX(MaxHandleBounds, MouseDragOffset.x); + } + } + + // Draw Background + PushRenderQuad2D(Interface.RenderBuffer, SliderBounds.Min, SliderBounds.Max, BGColor); + + // Draw Handles + PushRenderQuad2D(Interface.RenderBuffer, MinHandleBounds.Min, MinHandleBounds.Max, HandleColor); + PushRenderQuad2D(Interface.RenderBuffer, MaxHandleBounds.Min, MaxHandleBounds.Max, HandleColor); + + // Update the output range value + r32 MinHandleXOut = Rect2Center(MinHandleBounds).x; + r32 MaxHandleXOut = Rect2Center(MaxHandleBounds).x; + + r32 MinHandleValue = RemapR32(MinHandleXOut, SliderBounds.Min.x, SliderBounds.Max.x, MinValue, MaxValue); + r32 MaxHandleValue = RemapR32(MaxHandleXOut, SliderBounds.Min.x, SliderBounds.Max.x, MinValue, MaxValue); + + *OutHandleValues = v2{ Min(MinHandleValue, MaxHandleValue), Max(MinHandleValue, MaxHandleValue) }; + + if (MouseButtonTransitionedUp(Interface.Mouse.LeftButtonState)) + { + ShouldUpdate = true; + } + + return ShouldUpdate; +} + + +internal frame_range +DrawTimelineRangeBar (animation_system* AnimationSystem, animation Animation, animation_timeline_state* TimelineState, ui_interface Interface, rect2 BarBounds) +{ + frame_range VisibleRangeAfterInteraction = {}; + r32 MinFrame = (r32)Animation.PlayableRange.Min; + r32 MaxFrame = (r32)Animation.PlayableRange.Max; + + v2 RangeHandles = v2{ (r32)TimelineState->VisibleRange.Min, (r32)TimelineState->VisibleRange.Max }; + + bool ApplyUpdate = MinMaxRangeSlider(RangeHandles, BarBounds, MinFrame, MaxFrame, Interface, &RangeHandles); + VisibleRangeAfterInteraction.Min = (s32)RangeHandles.x; + VisibleRangeAfterInteraction.Max = (s32)RangeHandles.y; + + if (ApplyUpdate) + { + TimelineState->VisibleRange = VisibleRangeAfterInteraction; + } + + return VisibleRangeAfterInteraction; +} + +#define LAYER_HEIGHT 52 + +internal void +DrawLayerMenu(animation_system* AnimationSystem, animation ActiveAnim, ui_interface Interface, rect2 PanelDim, u32* SelectedAnimationLayer) +{ + v2 LayerDim = { Rect2Width(PanelDim), LAYER_HEIGHT }; + v2 LayerListMin = PanelDim.Min + v2{0, 24}; + for (u32 i = 0; i < ActiveAnim.Layers.Count; i++) + { + anim_layer* Layer = ActiveAnim.Layers.Values + i; + + rect2 LayerBounds = {0}; + LayerBounds.Min = { LayerListMin.x, LayerListMin.y + (LayerDim.y * i) }; + LayerBounds.Max = LayerBounds.Min + LayerDim; + + if (MouseButtonTransitionedDown(Interface.Mouse.LeftButtonState) && + PointIsInRect(LayerBounds, Interface.Mouse.Pos)) + { + *SelectedAnimationLayer = i; + } + + v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16}; + if (*SelectedAnimationLayer == i) + { + PushRenderBoundingBox2D(Interface.RenderBuffer, LayerBounds.Min, LayerBounds.Max, 1, WhiteV4); + } + DrawString(Interface.RenderBuffer, Layer->Name, Interface.Style.Font, LayerTextPos, WhiteV4); + } +} + +internal rect2 +DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range VisibleFrames, rect2 TimelineBounds, render_command_buffer* RenderBuffer) +{ + rect2 BlockBounds = {}; + + r32 TimelineWidth = Rect2Width(TimelineBounds); + + u32 ClampedBlockStartFrame = ClampFrameToRange(AnimationBlock.Range.Min, VisibleFrames); + r32 StartFramePercent = FrameToPercentRange(ClampedBlockStartFrame, VisibleFrames); + r32 StartPosition = TimelineWidth * StartFramePercent; + + u32 ClampedBlockEndFrame = ClampFrameToRange(AnimationBlock.Range.Max, VisibleFrames); + r32 EndFramePercent = FrameToPercentRange(ClampedBlockEndFrame, VisibleFrames); + r32 EndPosition = TimelineWidth * EndFramePercent; + + r32 LayerYOffset = LAYER_HEIGHT * AnimationBlock.Layer; + BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, LayerYOffset}; + BlockBounds.Max = TimelineBounds.Min + v2{EndPosition, LayerYOffset + LAYER_HEIGHT}; + + PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor); + PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4); + + return BlockBounds; +} + +internal handle +DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect2 PanelBounds, handle SelectedBlockHandle, ui_interface* Interface, app_state* State) +{ + gs_string Tempgs_string = PushString(State->Transient, 256); + handle Result = SelectedBlockHandle; + + animation CurrAnimation = *AnimationSystem_GetActiveAnimation(AnimationSystem); + + rect2 LayerMenuBounds, TimelineBounds; + RectVSplitAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds); + + // In Top To Bottom Order + rect2 TimelineFrameBarBounds; + rect2 TimelineBlockDisplayBounds; + rect2 TimelineRangeBarBounds; + RectHSplitAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds); + RectHSplitAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds); + + DrawLayerMenu(AnimationSystem, CurrAnimation, *Interface, LayerMenuBounds, &State->SelectedAnimationLayer); + + frame_range AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, CurrAnimation, TimelineState, *Interface, TimelineRangeBarBounds); + + DrawFrameBar(AnimationSystem, *Interface, AdjustedViewRange, TimelineFrameBarBounds, State); + + ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f}); + + // Animation Blocks + b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState); + handle DragBlockHandle = {0}; + for (u32 i = 0; i < CurrAnimation.Blocks_.Count; i++) + { + animation_block* AnimationBlockAt = CurrAnimation.Blocks_.Values + i; + + // If either end is in the range, we should draw it + b32 RangeIsVisible = (FrameIsInRange(AdjustedViewRange, AnimationBlockAt->Range.Min) || + FrameIsInRange(AdjustedViewRange, AnimationBlockAt->Range.Max)); + // If neither end is in the range, but the ends surround the visible range, + // we should still draw it. + RangeIsVisible |= (AnimationBlockAt->Range.Min <= AdjustedViewRange.Min && + AnimationBlockAt->Range.Max>= AdjustedViewRange.Max); + if (RangeIsVisible) + { + v4 BlockColor = BlackV4; + if (SelectedBlockHandle.Index == i && SelectedBlockHandle.Generation == CurrAnimation.Blocks_.Generations[i]) + { + BlockColor = PinkV4; + } + rect2 BlockBounds = DrawAnimationBlock(*AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer); + if (PointIsInRect(BlockBounds, Interface->Mouse.Pos)) + { + DragBlockHandle.Index = i; + DragBlockHandle.Generation = CurrAnimation.Blocks_.Generations[i]; + } + } + } + + if (MouseDownAndNotHandled && Handle_IsValid(DragBlockHandle)) + { + MouseDownAndNotHandled = false; + SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State); + } + + // Time Slider + if (FrameIsInRange(AdjustedViewRange, AnimationSystem->CurrentFrame)) + { + r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange); + r32 SliderX = LerpR32(FrameAtPercentVisibleRange, TimelineBounds.Min.x, TimelineBounds.Max.x); + rect2 SliderBounds = { + v2{ SliderX, TimelineBounds.Min.y }, + v2{ SliderX + 1, TimelineBounds.Max.y } + }; + ui_FillRect(Interface, SliderBounds, TimeSliderColor); + } + + ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4); + ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4); + ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4); + + if (MouseDownAndNotHandled && PointIsInRect(TimelineBounds, Interface->Mouse.Pos)) + { + DeselectCurrentAnimationBlock(State); + } + + return Result; +} + +PANEL_MODAL_OVERRIDE_CALLBACK(LoadAnimationFileCallback) +{ + Assert(ReturningFrom->TypeIndex == PanelType_FileView); + file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state); + gs_file_info FileInfo = FileViewState->SelectedFile; + + gs_file AnimFile = ReadEntireFile(Context.ThreadContext.FileHandler, FileInfo.Path); + gs_string AnimFileString = MakeString((char*)AnimFile.Data.Memory, AnimFile.Data.Size); + animation NewAnim = AnimParser_Parse(AnimFileString, State->AnimationSystem.Storage, GlobalAnimationClipsCount, GlobalAnimationClips); + + u32 NewAnimIndex = AnimationArray_Push(&State->AnimationSystem.Animations, NewAnim); + State->AnimationSystem.ActiveAnimationIndex = NewAnimIndex; +} + +internal void +DrawAnimationClipsList(rect2 PanelBounds, ui_interface* Interface, u32 SelectedAnimationLayerHandle, animation_system* AnimationSystem) +{ + ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds); + for (s32 i = 0; i < GlobalAnimationClipsCount; i++) + { + animation_clip Clip = GlobalAnimationClips[i]; + gs_string ClipName = MakeString(Clip.Name, Clip.NameLength); + if (ui_LayoutListEntry(Interface, &Layout, ClipName, i)) + { + AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayerHandle, AnimationSystem); + } + } +} + +GSMetaTag(panel_render); +GSMetaTag(panel_type_animation_timeline); +internal void +AnimationTimeline_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + animation_timeline_state* TimelineState = Panel_GetStateStruct(Panel, animation_timeline_state); + // TODO(pjs): SelectedAnimationBlockHandle should be a property of animation_timeline_state + // unless its used elsewhere. Audit later + handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; + ui_interface* Interface = &State->Interface; + animation_system* AnimationSystem = &State->AnimationSystem; + + rect2 TitleBarBounds, PanelContentsBounds; + rect2 AnimationListBounds, TimelineBounds; + RectHSplitAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds); + RectVSplitAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds); + + ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]); + ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds); + ui_StartRow(&TitleBarLayout, 4); + { + if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Pause"))) + { + State->AnimationSystem.TimelineShouldAdvance = false; + } + + if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Play"), (State->AnimationSystem.TimelineShouldAdvance ? PinkV4 : BlackV4), v4{.3f, .3f, .3f, 1.0f}, TealV4)) + { + State->AnimationSystem.TimelineShouldAdvance = true; + } + + if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Stop"))) + { + State->AnimationSystem.TimelineShouldAdvance = false; + State->AnimationSystem.CurrentFrame = 0; + } + + if (ui_LayoutButton(Interface, &TitleBarLayout, MakeString("Load"))) + { + panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + Panel_PushModalOverride(Panel, FileBrowser, LoadAnimationFileCallback); + } + } + ui_EndRow(&TitleBarLayout); + + if (Rect2Height(TimelineBounds) > 0) + { + SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State); + DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem); + } +} + +#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H +#endif // FOLDHAUS_PANEL_ANIMATION_TIMELINE_H \ No newline at end of file diff --git a/src/app/panels/foldhaus_panel_dmx_view.h b/src/app/editor/panels/foldhaus_panel_dmx_view.h similarity index 89% rename from src/app/panels/foldhaus_panel_dmx_view.h rename to src/app/editor/panels/foldhaus_panel_dmx_view.h index b4b5ea4..d7213ee 100644 --- a/src/app/panels/foldhaus_panel_dmx_view.h +++ b/src/app/editor/panels/foldhaus_panel_dmx_view.h @@ -18,7 +18,7 @@ s32 DMXView_CommandsCount = 0; GSMetaTag(panel_init); GSMetaTag(panel_type_dmx_view); internal void -DMXView_Init(panel* Panel, app_state* State) +DMXView_Init(panel* Panel, app_state* State, context Context) { } @@ -37,7 +37,7 @@ DMXView_Cleanup(panel* Panel, app_state* State) // This won't actually function // :NoLongerFunctionalSACNCodeButThatsOk internal void -DrawSACNUniversePixels (render_command_buffer* RenderBuffer, sacn_universe* ToDraw, +DrawSACNUniversePixels (render_command_buffer* RenderBuffer, sacn_universe* ToDraw, v2 TopLeft, v2 Dimension) { Assert(ToDraw); @@ -69,12 +69,12 @@ DrawSACNUniversePixels (render_command_buffer* RenderBuffer, sacn_universe* ToDr ++PixelsDrawn; } } -#endif +#endif GSMetaTag(panel_render); GSMetaTag(panel_type_dmx_view); internal void -DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +DMXView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { #if 0 // :NoLongerFunctionalSACNCodeButThatsOk @@ -82,7 +82,7 @@ DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffe universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory; - string TitleBarString = InitializeEmptyString(PushArray(State->Transient, char, 64), 64); + gs_string TitleBargs_string = InitializeEmptygs_string(PushArray(State->Transient, char, 64), 64); v2 DisplayArea_Dimension = v2{600, 600}; @@ -120,8 +120,8 @@ DMXView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffe if (OpState->Zoom > .5f) { v2 TitleDisplayStart = UniverseDisplayTopLeft + v2{0, 12}; - PrintF(&TitleBarString, "Universe %d", Universe->Universe); - DrawString(RenderBuffer, TitleBarString, State->Interface.Font, + PrintF(&TitleBargs_string, "Universe %d", Universe->Universe); + DrawString(RenderBuffer, TitleBargs_string, State->Interface.Font, TitleDisplayStart, WhiteV4); } diff --git a/src/app/editor/panels/foldhaus_panel_file_view.h b/src/app/editor/panels/foldhaus_panel_file_view.h new file mode 100644 index 0000000..e369e7f --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_file_view.h @@ -0,0 +1,129 @@ +// +// File: foldhaus_panel_file_view.h +// Author: Peter Slattery +// Creation Date: 2020-03-08 +// +#ifndef FOLDHAUS_PANEL_FILE_VIEW_H + +struct file_view_state +{ + gs_string WorkingDirectory; + gs_memory_arena FileNamesArena; + gs_file_info_array FileNames; + + gs_file_info SelectedFile; +}; + +internal void +FileView_Exit_(panel* FileViewPanel, app_state* State, context Context) +{ + Assert(FileViewPanel->IsModalOverrideFor != 0); + panel* ReturnTo = FileViewPanel->IsModalOverrideFor; + if (ReturnTo->ModalOverrideCB) + { + ReturnTo->ModalOverrideCB(FileViewPanel, State, Context); + } + Panel_PopModalOverride(ReturnTo, &State->PanelSystem); +} + +global input_command* FileView_Commands = 0; +s32 FileView_CommandsCount = 0; + +internal void +FileViewUpdateWorkingDirectory(gs_const_string WorkingDirectory, file_view_state* State, context Context) +{ + ClearArena(&State->FileNamesArena); + + gs_const_string SanitizedDirectory = WorkingDirectory; + + u32 LastSlashIndex = FindLast(SanitizedDirectory, '\\'); + gs_const_string LastDir = Substring(SanitizedDirectory, LastSlashIndex + 1, SanitizedDirectory.Length); + if (StringsEqual(LastDir, ConstString(".."))) + { + u32 SecondLastSlashIndex = FindLast(SanitizedDirectory, LastSlashIndex - 1, '\\'); + SanitizedDirectory = Substring(SanitizedDirectory, 0, SecondLastSlashIndex); + } + else if (StringsEqual(LastDir, ConstString("."))) + { + SanitizedDirectory = Substring(SanitizedDirectory, 0, LastSlashIndex); + } + + State->WorkingDirectory = PushString(&State->FileNamesArena, WorkingDirectory.Length + 2); + PrintF(&State->WorkingDirectory, "%S", SanitizedDirectory); + if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '\\') + { + AppendPrintF(&State->WorkingDirectory, "\\"); + } + if (State->WorkingDirectory.Str[State->WorkingDirectory.Length - 1] != '*') + { + AppendPrintF(&State->WorkingDirectory, "*"); + } + + State->FileNames = EnumerateDirectory(Context.ThreadContext.FileHandler, &State->FileNamesArena, State->WorkingDirectory.ConstString, EnumerateDirectory_IncludeDirectories); +} + +GSMetaTag(panel_init); +GSMetaTag(panel_type_file_view); +internal void +FileView_Init(panel* Panel, app_state* State, context Context) +{ + // TODO: :FreePanelMemory + file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state); + Panel->StateMemory = StructToData(FileViewState, file_view_state); + FileViewState->FileNamesArena = CreateMemoryArena(Context.ThreadContext.Allocator); + FileViewUpdateWorkingDirectory(ConstString("."), FileViewState, Context); +} + +GSMetaTag(panel_cleanup); +GSMetaTag(panel_type_file_view); +internal void +FileView_Cleanup(panel* Panel, app_state* State) +{ + +} + +GSMetaTag(panel_render); +GSMetaTag(panel_type_file_view); +internal void +FileView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + file_view_state* FileViewState = Panel_GetStateStruct(Panel, file_view_state); + ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); + + if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Exit"))) + { + FileView_Exit_(Panel, State, Context); + } + + // Header + ui_LayoutDrawString(&State->Interface, &Layout, FileViewState->WorkingDirectory, v4{0, 1, 0, 1}); + + // File Display + for (u32 i = 0; i < FileViewState->FileNames.Count; i++) + { + gs_file_info File = FileViewState->FileNames.Values[i]; + + u32 LastSlashIndex = FindLast(File.Path, '\\'); + gs_const_string FileName = Substring(File.Path, LastSlashIndex + 1, File.Path.Length); + gs_string PathString = PushString(State->Transient, FileName.Length); + PrintF(&PathString, "%S", FileName); + if (ui_LayoutListButton(&State->Interface, &Layout, PathString, i)) + { + if (File.IsDirectory) + { + FileViewUpdateWorkingDirectory(File.Path, FileViewState, Context); + } + else + { + FileViewState->SelectedFile = File; + FileView_Exit_(Panel, State, Context); + } + } + } + +} + + + +#define FOLDHAUS_PANEL_FILE_VIEW_H +#endif // FOLDHAUS_PANEL_FILE_VIEW_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_hierarchy.h b/src/app/editor/panels/foldhaus_panel_hierarchy.h new file mode 100644 index 0000000..fdecc36 --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_hierarchy.h @@ -0,0 +1,86 @@ +// +// File: foldhaus_panel_hierarchy.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_PANEL_HIERARCHY_H + +input_command HierarchyView_Commands[] = {{}}; +s32 HierarchyView_CommandsCount = 0; + +GSMetaTag(panel_init); +GSMetaTag(panel_type_hierarchy); +internal void +HierarchyView_Init(panel* Panel, app_state* State, context Context) +{ + +} + +GSMetaTag(panel_cleanup); +GSMetaTag(panel_type_hierarchy); +internal void +HierarchyView_Cleanup(panel* Panel, app_state* State) +{ + +} + +PANEL_MODAL_OVERRIDE_CALLBACK(LoadAssemblyCallback) +{ + Assert(ReturningFrom->TypeIndex == PanelType_FileView); + file_view_state* FileViewState = Panel_GetStateStruct(ReturningFrom, file_view_state); + gs_file_info FileInfo = FileViewState->SelectedFile; + + LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, FileInfo.Path, State->GlobalLog); +} + +GSMetaTag(panel_render); +GSMetaTag(panel_type_hierarchy); +internal void +HierarchyView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + ui_layout Layout = ui_CreateLayout(State->Interface, PanelBounds); + gs_string TempString = PushString(State->Transient, 256); + u32 LineCount = (u32)(Rect2Height(PanelBounds) / Layout.RowHeight) + 1; + u32 AssembliesToDraw = Min(LineCount, State->Assemblies.Count); + rect2* LineBounds = PushArray(State->Transient, rect2, LineCount); + + // Fill in alternating color rows for the backgrounds + for (u32 Line = 0; Line < LineCount; Line++) + { + LineBounds[Line] = ui_ReserveElementBounds(&Layout); + v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface.Style, Line); + ui_FillRect(&State->Interface, LineBounds[Line], ListItemBGColor); + } + + for (u32 AssemblyIndex = 0; AssemblyIndex < AssembliesToDraw; AssemblyIndex++) + { + assembly Assembly = State->Assemblies.Values[AssemblyIndex]; + PrintF(&TempString, "%S", Assembly.Name); + + ui_layout ItemLayout = ui_CreateLayout(State->Interface, LineBounds[AssemblyIndex]); + ui_StartRow(&ItemLayout, 2); + { + ui_LayoutDrawString(&State->Interface, &ItemLayout, TempString, State->Interface.Style.TextColor); + if (ui_LayoutListButton(&State->Interface, &ItemLayout, MakeString("X"), AssemblyIndex)) + { + UnloadAssembly(AssemblyIndex, State, Context); + } + } + ui_EndRow(&ItemLayout); + } + + if (AssembliesToDraw < LineCount) + { + // NOTE(Peter): Add assembly button + PrintF(&TempString, "+ Add Assembly"); + if (ui_ListButton(&State->Interface, TempString, LineBounds[AssembliesToDraw], AssembliesToDraw)) + { + panel_entry* FileBrowser = PanelSystem_PushPanel(&State->PanelSystem, PanelType_FileView, State, Context); + Panel_PushModalOverride(Panel, FileBrowser, LoadAssemblyCallback); + } + } +} + + +#define FOLDHAUS_PANEL_HIERARCHY_H +#endif // FOLDHAUS_PANEL_HIERARCHY_H diff --git a/src/app/panels/foldhaus_panel_profiler.h b/src/app/editor/panels/foldhaus_panel_profiler.h similarity index 63% rename from src/app/panels/foldhaus_panel_profiler.h rename to src/app/editor/panels/foldhaus_panel_profiler.h index d4e25aa..90fbafa 100644 --- a/src/app/panels/foldhaus_panel_profiler.h +++ b/src/app/editor/panels/foldhaus_panel_profiler.h @@ -11,7 +11,7 @@ s32 ProfilerView_CommandsCount = 0; GSMetaTag(panel_init); GSMetaTag(panel_type_profiler); internal void -ProfilerView_Init(panel* Panel, app_state* State) +ProfilerView_Init(panel* Panel, app_state* State, context Context) { } @@ -25,7 +25,7 @@ ProfilerView_Cleanup(panel* Panel, app_state* State) } internal void -RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, memory_arena* Memory) +RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) { v4 ThreadColors[] = { v4{.73f, .33f, .83f, 1}, @@ -35,8 +35,8 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb v4{.74f, .40f, .25f, 1}, }; - rect Bounds = ui_LayoutRemaining(Layout); - r32 Width = gs_Width(Bounds); + rect2 Bounds = ui_LayoutRemaining(Layout); + r32 Width = Rect2Width(Bounds); r32 DepthHeight = 64; s64 FrameStartCycles = VisibleFrame->FrameStartCycles; @@ -48,7 +48,8 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb scope_record* HotRecord = 0; scope_name* HotRecordName = 0; - MakeStringBuffer(String, 256); + char Backbuffer[256]; + gs_string String = MakeString(Backbuffer, 0, 256); for (s32 i = 0; i < ThreadScopeCalls->Count; i++) { scope_record* Record = ThreadScopeCalls->Calls + i; @@ -59,14 +60,14 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb r32 PixelStart = Bounds.Min.x + (Width * PercentStart); r32 PixelEnd = Bounds.Min.x + (Width * PercentEnd); r32 MinY = Bounds.Max.y - ((Record->CallDepth + 1) * DepthHeight); - rect ScopeBounds = { + rect2 ScopeBounds = { v2{ PixelStart, MinY }, v2{ PixelEnd, MinY + (DepthHeight - 4) } }; - if (gs_Width(ScopeBounds) >= 1) + if (Rect2Width(ScopeBounds) >= 1) { v4 Color = ThreadColors[0]; - if (gs_PointIsInRect(Interface->Mouse.Pos, ScopeBounds)) + if (PointIsInRect(ScopeBounds, Interface->Mouse.Pos)) { Color = GreenV4; HotRecord = Record; @@ -81,23 +82,26 @@ RenderProfiler_ScopeVisualization(ui_interface* Interface, ui_layout Layout, deb if (HotRecord != 0) { PrintF(&String, "%S : %d - %d", HotRecordName->Name, HotRecord->StartCycles, HotRecord->EndCycles); - ui_TextBox(Interface, gs_MakeRectMinWidth(Interface->Mouse.Pos, v2{256, 32}), String, BlackV4, WhiteV4); + + rect2 TextBounds = MakeRect2MinDim(Interface->Mouse.Pos, v2{256, 32}); + ui_TextBox(Interface, TextBounds, String, BlackV4, WhiteV4); } } internal void -RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, memory_arena* Memory) +RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debug_frame* VisibleFrame, gs_memory_arena* Memory) { - MakeStringBuffer(String, 256); + char Backbuffer[256]; + gs_string String = MakeString(Backbuffer, 0, 256); r32 ColumnWidths[] = {256, 128, 128, 128, 128}; ui_StartRow(&Layout, 5, &ColumnWidths[0]); { - ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Procedure"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("% Frame"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Seconds"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Cycles"), Interface->Style.TextColor); - ui_LayoutDrawString(Interface, &Layout, MakeStringLiteral("Calls"), Interface->Style.TextColor); + ui_LayoutDrawString(Interface, &Layout, MakeString("Procedure"), Interface->Style.TextColor); + ui_LayoutDrawString(Interface, &Layout, MakeString("% Frame"), Interface->Style.TextColor); + ui_LayoutDrawString(Interface, &Layout, MakeString("Seconds"), Interface->Style.TextColor); + ui_LayoutDrawString(Interface, &Layout, MakeString("Cycles"), Interface->Style.TextColor); + ui_LayoutDrawString(Interface, &Layout, MakeString("Calls"), Interface->Style.TextColor); } ui_EndRow(&Layout); @@ -133,62 +137,65 @@ RenderProfiler_ListVisualization(ui_interface* Interface, ui_layout Layout, debu GSMetaTag(panel_render); GSMetaTag(panel_type_profiler); internal void -ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) +ProfilerView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) { - memory_arena* Memory = &State->Transient; - string String = InitializeEmptyString(PushArray(Memory, char, 256), 256); + gs_memory_arena* Memory = State->Transient; + gs_string String = PushString(Memory, 256); v4 FrameColors[] = { GreenV4, YellowV4, RedV4, WhiteV4 }; r32 FrameListHeight = 64; - rect FrameListBounds, ProcListBounds; - gs_HSplitRectAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds); - rect FrameListInner = gs_InsetRect(FrameListBounds, 4); + rect2 FrameListBounds, ProcListBounds; + RectHSplitAtDistanceFromTop(PanelBounds, FrameListHeight, &FrameListBounds, &ProcListBounds); + rect2 FrameListInner = RectInset(FrameListBounds, 4); - r32 SingleFrameStep = gs_Width(FrameListInner) / DEBUG_FRAME_COUNT; + r32 SingleFrameStep = Rect2Width(FrameListInner) / DEBUG_FRAME_COUNT; r32 SingleFrameWidth = (r32)((s32)SingleFrameStep - 2); - ui_OutlineRect(&State->Interface_, FrameListBounds, 2, WhiteV4); - if (gs_PointIsInRect(Mouse.Pos, FrameListBounds) && MouseButtonHeldDown(Mouse.LeftButtonState)) + ui_OutlineRect(&State->Interface, FrameListBounds, 2, WhiteV4); + if (MouseButtonHeldDown(Context.Mouse.LeftButtonState)) { - v2 LocalMouse = gs_TransformPointIntoRectSpace(Mouse.Pos, FrameListBounds); - s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep); - if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT) + if (PointIsInRect(FrameListBounds, Context.Mouse.Pos)) { - GlobalDebugServices->RecordFrames = false; - GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex; + v2 LocalMouse = Rect2GetRectLocalPoint(FrameListBounds, Context.Mouse.Pos); + s32 ClosestFrameIndex = (LocalMouse.x / SingleFrameStep); + if (ClosestFrameIndex >= 0 && ClosestFrameIndex < DEBUG_FRAME_COUNT) + { + GlobalDebugServices->RecordFrames = false; + GlobalDebugServices->CurrentDebugFrame = ClosestFrameIndex; + } } } - rect FrameBounds = gs_MakeRectMinWidth(FrameListInner.Min, v2{SingleFrameWidth, gs_Height(FrameListInner)}); + rect2 FrameBounds = MakeRect2MinDim(FrameListInner.Min, v2{SingleFrameWidth, Rect2Height(FrameListInner)}); for (s32 F = 0; F < DEBUG_FRAME_COUNT; F++) { - rect PositionedFrameBounds = gs_TranslateRectX(FrameBounds, F * SingleFrameStep); + rect2 PositionedFrameBounds = Rect2TranslateX(FrameBounds, F * SingleFrameStep); s32 FramesAgo = (GlobalDebugServices->CurrentDebugFrame - F); if (FramesAgo < 0) { FramesAgo += DEBUG_FRAME_COUNT; } - v4 Color = FrameColors[GSClamp(0, FramesAgo, 3)]; - ui_FillRect(&State->Interface_, PositionedFrameBounds, Color); + v4 Color = FrameColors[Clamp(0, FramesAgo, 3)]; + ui_FillRect(&State->Interface, PositionedFrameBounds, Color); } debug_frame* VisibleFrame = GetLastDebugFrame(GlobalDebugServices); - ui_layout Layout = ui_CreateLayout(State->Interface_, ProcListBounds); + ui_layout Layout = ui_CreateLayout(State->Interface, ProcListBounds); ui_StartRow(&Layout, 4); { s64 FrameStartCycles = VisibleFrame->FrameStartCycles; s64 FrameTotalCycles = VisibleFrame->FrameEndCycles - VisibleFrame->FrameStartCycles; u32 CurrentDebugFrame = GlobalDebugServices->CurrentDebugFrame - 1; PrintF(&String, "Frame %d", CurrentDebugFrame); - ui_LayoutDrawString(&State->Interface_, &Layout, String, WhiteV4); + ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); PrintF(&String, "Total Cycles: %lld", FrameTotalCycles); - ui_LayoutDrawString(&State->Interface_, &Layout, String, WhiteV4); + ui_LayoutDrawString(&State->Interface, &Layout, String, WhiteV4); // NOTE(NAME): Skipping a space for aesthetic reasons, not functional, and could // be removed, or used for something else ui_ReserveElementBounds(&Layout); - if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("Resume Recording"))) + if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Resume Recording"))) { GlobalDebugServices->RecordFrames = true; } @@ -197,11 +204,11 @@ ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* Render ui_StartRow(&Layout, 8); { - if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("Scope View"))) + if (ui_LayoutButton(&State->Interface, &Layout, MakeString("Scope View"))) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_PROFILER; } - if (ui_LayoutButton(&State->Interface_, &Layout, MakeString("List View"))) + if (ui_LayoutButton(&State->Interface, &Layout, MakeString("List View"))) { GlobalDebugServices->Interface.FrameView = FRAME_VIEW_SCOPE_LIST; } @@ -210,11 +217,11 @@ ProfilerView_Render(panel Panel, rect PanelBounds, render_command_buffer* Render if (GlobalDebugServices->Interface.FrameView == FRAME_VIEW_PROFILER) { - RenderProfiler_ScopeVisualization(&State->Interface_, Layout, VisibleFrame, Memory); + RenderProfiler_ScopeVisualization(&State->Interface, Layout, VisibleFrame, Memory); } else { - RenderProfiler_ListVisualization(&State->Interface_, Layout, VisibleFrame, Memory); + RenderProfiler_ListVisualization(&State->Interface, Layout, VisibleFrame, Memory); } } diff --git a/src/app/editor/panels/foldhaus_panel_sculpture_view.h b/src/app/editor/panels/foldhaus_panel_sculpture_view.h new file mode 100644 index 0000000..6bc24a5 --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_sculpture_view.h @@ -0,0 +1,223 @@ +// +// File: foldhaus_panel_sculpture_view.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H + +// 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 = M44RotationX(-TotalDeltaPos.y * State->PixelsToWorldScale); + m44 YRotation = M44RotationY(TotalDeltaPos.x * State->PixelsToWorldScale); + m44 Combined = XRotation * YRotation; + + State->Camera.Position = (Combined * OpState->CameraStartPos).xyz; +} + +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 = ToV4Point(State->Camera.Position); +} + +// ---------------- + +GSMetaTag(panel_commands); +GSMetaTag(panel_type_sculpture_view); +global input_command SculptureView_Commands[] = { + { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate }, +}; +global s32 SculptureView_CommandsCount = 1; + +GSMetaTag(panel_init); +GSMetaTag(panel_type_sculpture_view); +internal void +SculptureView_Init(panel* Panel, app_state* State, context Context) +{ + +} + +GSMetaTag(panel_cleanup); +GSMetaTag(panel_type_sculpture_view); +internal void +SculptureView_Cleanup(panel* Panel, app_state* State) +{ + +} + + +struct draw_leds_job_data +{ + v4 CameraPosition; + led_buffer LedBuffer; + s32 StartIndex; + s32 OnePastLastIndex; + render_quad_batch_constructor* Batch; + quad_batch_constructor_reserved_range BatchReservedRange; + r32 LEDHalfWidth; +}; + +internal void +DrawLedsInBuffer(led_buffer LedBuffer, s32 StartIndex, s32 OnePastLastIndex, render_quad_batch_constructor* Batch, quad_batch_constructor_reserved_range ReservedRange, r32 LedHalfWidth) +{ + s32 TrisUsed = 0; + + v4 P0_In = v4{-LedHalfWidth, -LedHalfWidth, 0, 1}; + v4 P1_In = v4{LedHalfWidth, -LedHalfWidth, 0, 1}; + v4 P2_In = v4{LedHalfWidth, LedHalfWidth, 0, 1}; + v4 P3_In = v4{-LedHalfWidth, LedHalfWidth, 0, 1}; + + v2 UV0 = v2{0, 0}; + v2 UV1 = v2{1, 0}; + v2 UV2 = v2{1, 1}; + v2 UV3 = v2{0, 1}; + + Assert(OnePastLastIndex <= (s32)LedBuffer.LedCount); + for (s32 LedIndex = StartIndex; LedIndex < OnePastLastIndex; LedIndex++) + { + pixel PixelColor = LedBuffer.Colors[LedIndex]; + v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f}; + + v4 Position = LedBuffer.Positions[LedIndex]; + v4 PositionOffset = ToV4Vec(Position.xyz); + v4 P0 = P0_In + PositionOffset; + v4 P1 = P1_In + PositionOffset; + v4 P2 = P2_In + PositionOffset; + v4 P3 = P3_In + PositionOffset; + + SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P1, P2, UV0, UV1, UV2, Color, Color, Color); + SetTri3DInBatch(Batch, ReservedRange.Start + TrisUsed++, P0, P2, P3, UV0, UV2, UV3, Color, Color, Color); + } +} + +internal void +DrawLEDsInBufferRangeJob (gs_thread_context Context, gs_data JobData) +{ + DEBUG_TRACK_FUNCTION; + draw_leds_job_data* Data = (draw_leds_job_data*)JobData.Memory; + DrawLedsInBuffer(Data->LedBuffer, Data->StartIndex, Data->OnePastLastIndex, Data->Batch, Data->BatchReservedRange, Data->LEDHalfWidth); +} + +internal void +DrawQuad(render_command_buffer* RenderBuffer, v4 C, r32 Rad, v4 Color) +{ + v4 P0 = C + v4{-Rad,-Rad,0,0}; + v4 P1 = C + v4{ Rad,-Rad,0,0}; + v4 P2 = C + v4{ Rad,Rad,0,0}; + v4 P3 = C + v4{ -Rad,Rad,0,0}; + PushRenderQuad3D(RenderBuffer, P0, P1, P2, P3, Color); +} + +internal v2 +SculptureView_WorldToScreenPosition(v4 WorldPosition, camera Camera, rect2 PanelBounds) +{ + v2 Result = {0}; + + r32 PanelW = Rect2Width(PanelBounds); + r32 PanelH = Rect2Height(PanelBounds); + + m44 Matrix = GetCameraPerspectiveProjectionMatrix(Camera) * GetCameraModelViewMatrix(Camera); + v4 WorldPos = Matrix * WorldPosition; + + // this is the Perspective Divide + v2 ProjectedPos = WorldPos.xy / WorldPos.w; + + // Projection gets us in a range [-1, 1], and we want [0, width] + ProjectedPos.x = ((ProjectedPos.x / 2) * PanelW) + (PanelW / 2); + ProjectedPos.y = ((ProjectedPos.y / 2) * PanelH) + (PanelH / 2); + + Result = ProjectedPos + PanelBounds.Min; + return Result; +} + +GSMetaTag(panel_render); +GSMetaTag(panel_type_sculpture_view); +internal void +SculptureView_Render(panel* Panel, rect2 PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context) +{ + DEBUG_TRACK_SCOPE(RenderSculpture); + State->Camera.AspectRatio = RectAspectRatio(PanelBounds); + + PushRenderPerspective(RenderBuffer, PanelBounds, State->Camera); + + u32 MaxLEDsPerJob = 2048; + render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal); + + u32 FocusPixel = 100; + + for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++) + { + led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, BufferIndex); + u32 JobsNeeded = U32DivideRoundUp(LedBuffer->LedCount, MaxLEDsPerJob); + u32 NextLEDIndex = 0; + for (u32 Job = 0; Job < JobsNeeded; Job++) + { + gs_data Data = PushSizeToData(State->Transient, sizeof(draw_leds_job_data)); + draw_leds_job_data* JobData = (draw_leds_job_data*)Data.Memory; + JobData->LedBuffer = *LedBuffer; + JobData->StartIndex = NextLEDIndex; + JobData->OnePastLastIndex = Min(JobData->StartIndex + MaxLEDsPerJob, LedBuffer->LedCount); + s32 JobLedCount = JobData->OnePastLastIndex - JobData->StartIndex; + JobData->Batch = &RenderLEDsBatch; + JobData->BatchReservedRange = ReserveRangeInQuadConstructor(JobData->Batch, JobLedCount * 2); + JobData->LEDHalfWidth = .5f; + JobData->CameraPosition = ToV4Point(State->Camera.Position); +#if 1 + Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, (thread_proc*)DrawLEDsInBufferRangeJob, Data, ConstString("Sculpture Draw LEDS")); +#else + DrawLedsInBuffer(JobData->LedBuffer, JobData->StartIndex, JobData->OnePastLastIndex, JobData->Batch, JobData->BatchReservedRange, JobData->LEDHalfWidth); +#endif + NextLEDIndex = JobData->OnePastLastIndex; + } + } + + // TODO(Peter): I don't like the fact that setting an orthographic view inside a panel render function + // needs to relyon the window bounds rather than the panel bounds. Ideally the panel only needs to know where + // itself is, and nothing else. + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + if (State->Assemblies.Count > 0) + { + assembly Assembly = State->Assemblies.Values[0]; + led_buffer* LedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly.LedBufferIndex); + + v4 LedPosition = LedBuffer->Positions[FocusPixel]; + v2 LedOnScreenPosition = SculptureView_WorldToScreenPosition(LedPosition, State->Camera, PanelBounds); + + gs_string Tempgs_string = PushString(State->Transient, 256); + PrintF(&Tempgs_string, "%f %f", LedOnScreenPosition.x, LedOnScreenPosition.y); + DrawString(RenderBuffer, Tempgs_string, State->Interface.Style.Font, v2{PanelBounds.Min.x + 100, PanelBounds.Max.y - 200}, WhiteV4); + + + v2 BoxHalfDim = v2{ 25, 25 }; + v2 BoxMin = LedOnScreenPosition - BoxHalfDim; + v2 BoxMax = LedOnScreenPosition + BoxHalfDim; + PushRenderBoundingBox2D(RenderBuffer, BoxMin, BoxMax, 2.0f, TealV4); + } + Context.GeneralWorkQueue->CompleteQueueWork(Context.GeneralWorkQueue, Context.ThreadContext); +} + +#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H +#endif // FOLDHAUS_PANEL_SCULPTURE_VIEW_H \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_types.cpp b/src/app/editor/panels/foldhaus_panel_types.cpp new file mode 100644 index 0000000..9c006fa --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_types.cpp @@ -0,0 +1,17 @@ +// +// File: foldhaus_panel_types.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-17 +// +#ifndef FOLDHAUS_PANEL_TYPES_CPP +global s32 GlobalPanelDefsCount = 6; +global panel_definition GlobalPanelDefs[] = { + { "File View", 9, FileView_Init, FileView_Cleanup, FileView_Render, FileView_Commands, FileView_CommandsCount }, + { "Sculpture View", 14, SculptureView_Init, SculptureView_Cleanup, SculptureView_Render, SculptureView_Commands, SculptureView_CommandsCount }, + { "Animation Timeline", 18, AnimationTimeline_Init, AnimationTimeline_Cleanup, AnimationTimeline_Render, AnimationTimeline_Commands, AnimationTimeline_CommandsCount }, + { "Dmx View", 8, DMXView_Init, DMXView_Cleanup, DMXView_Render, DMXView_Commands, DMXView_CommandsCount }, + { "Hierarchy", 9, HierarchyView_Init, HierarchyView_Cleanup, HierarchyView_Render, HierarchyView_Commands, HierarchyView_CommandsCount }, + { "Profiler", 8, ProfilerView_Init, ProfilerView_Cleanup, ProfilerView_Render, ProfilerView_Commands, ProfilerView_CommandsCount }, +}; +#define FOLDHAUS_PANEL_TYPES_CPP +#endif // FOLDHAUS_PANEL_TYPES_CPP \ No newline at end of file diff --git a/src/app/editor/panels/foldhaus_panel_types.h b/src/app/editor/panels/foldhaus_panel_types.h new file mode 100644 index 0000000..7b1164b --- /dev/null +++ b/src/app/editor/panels/foldhaus_panel_types.h @@ -0,0 +1,17 @@ +// +// File: foldhaus_panel_types.h +// Author: Peter Slattery +// Creation Date: 2020-10-17 +// +#ifndef FOLDHAUS_PANEL_TYPES_H +enum panel_type { + PanelType_FileView, + PanelType_SculptureView, + PanelType_AnimationTimeline, + PanelType_DMXView, + PanelType_HierarchyView, + PanelType_NodeGraph, + PanelType_ProfilerView, +}; +#define FOLDHAUS_PANEL_TYPES_H +#endif // FOLDHAUS_PANEL_TYPES_H \ No newline at end of file diff --git a/src/app/engine/animation/foldhaus_animation.h b/src/app/engine/animation/foldhaus_animation.h new file mode 100644 index 0000000..81e2080 --- /dev/null +++ b/src/app/engine/animation/foldhaus_animation.h @@ -0,0 +1,435 @@ +// +// File: foldhaus_animation.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_ANIMATION + +#define ANIMATION_PROC(name) void name(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) +typedef ANIMATION_PROC(animation_proc); + +struct frame_range +{ + s32 Min; + s32 Max; +}; + +struct animation_block +{ + frame_range Range; + u32 AnimationProcHandle; + u32 Layer; +}; + +struct animation_block_array +{ + u32* Generations; + animation_block* Values; + u32 Count; + u32 CountMax; +}; + +enum blend_mode +{ + BlendMode_Overwrite, + BlendMode_Add, + BlendMode_Multiply, + BlendMode_Count, +}; + +global gs_const_string BlendModeStrings[] = { + ConstString("Overwrite"), + ConstString("Add"), + ConstString("Multiply"), + ConstString("Count"), +}; + +struct anim_layer +{ + gs_string Name; + blend_mode BlendMode; +}; + +struct anim_layer_array +{ + anim_layer* Values; + u32 Count; + u32 CountMax; +}; + +struct animation +{ + gs_string Name; + + anim_layer_array Layers; + animation_block_array Blocks_; + + frame_range PlayableRange; +}; + +struct animation_array +{ + animation* Values; + u32 Count; + u32 CountMax; +}; + +struct animation_frame +{ + // NOTE(pjs): These are all parallel arrays of equal length + animation_block* Blocks; + b8* BlocksFilled; + + u32 BlocksCountMax; + u32 BlocksCount; +}; + +#define ANIMATION_SYSTEM_LAYERS_MAX 128 +#define ANIMATION_SYSTEM_BLOCKS_MAX 128 +struct animation_system +{ + gs_memory_arena* Storage; + animation_array Animations; + + // NOTE(Peter): The frame currently being displayed/processed. you + // can see which frame you're on by looking at the time slider on the timeline + // panel + u32 ActiveAnimationIndex; + s32 CurrentFrame; + s32 LastUpdatedFrame; + r32 SecondsPerFrame; + b32 TimelineShouldAdvance; + +}; + +// TODO(pjs): Better name - something like animation_prototype +struct animation_clip +{ + char* Name; + s32 NameLength; + animation_proc* Proc; +}; + +// Serialization + +enum animation_field +{ + AnimField_FileIdent, + AnimField_AnimName, + AnimField_LayersCount, + AnimField_BlocksCount, + + AnimField_PlayableRange, + AnimField_PlayableRangeMin, + AnimField_PlayableRangeMax, + + AnimField_LayersArray, + AnimField_Layer, + AnimField_LayerName, + AnimField_LayerBlendMode, + + AnimField_BlocksArray, + AnimField_Block, + AnimField_BlockFrameRange, + AnimField_BlockFrameRangeMin, + AnimField_BlockFrameRangeMax, + AnimField_BlockLayerIndex, + AnimField_BlockAnimName, + + AnimField_Count, +}; + +global gs_const_string AnimationFieldStrings[] = { + ConstString("lumenarium_animation_file"), // AnimField_FileIdent + ConstString("animation_name"),// AnimField_AnimName + ConstString("layers_count"),// AnimField_LayersCount + ConstString("blocks_count"),// AnimField_BlocksCount + + ConstString("playable_range"),// AnimField_PlayableRange + ConstString("min"),// AnimField_PlayableRangeMin + ConstString("max"),// AnimField_PlayableRangeMax + + ConstString("layers"),// AnimField_LayersArray + ConstString("layer"),// AnimField_Layer + ConstString("name"),// AnimField_LayerName + ConstString("blend"),// AnimField_LayerBlendMode + + ConstString("blocks"),// AnimField_BlocksArray + ConstString("block"),// AnimField_Block + ConstString("frame_range"),// AnimField_BlockFrameRange + ConstString("min"),// AnimField_BlockFrameRangeMin + ConstString("max"),// AnimField_BlockFrameRangeMax + ConstString("layer_index"),// AnimField_BlockLayerIndex + ConstString("animation_name"),// AnimField_BlockAnimName +}; + +////////////////////////// +// +// Anim Block Array + +internal animation_block_array +AnimBlockArray_Create(gs_memory_arena* Storage, u32 CountMax) +{ + animation_block_array Result = {0}; + Result.CountMax = CountMax; + Result.Values = PushArray(Storage, animation_block, Result.CountMax); + Result.Generations = PushArray(Storage, u32, Result.CountMax); + return Result; +} + +internal handle +AnimBlockArray_Push(animation_block_array* Array, animation_block Value) +{ + Assert(Array->Count < Array->CountMax); + handle Result = {0}; + Result.Index = Array->Count++; + // NOTE(pjs): pre-increment so that generation 0 is always invalid + Result.Generation = ++Array->Generations[Result.Index]; + + Array->Values[Result.Index] = Value; + + return Result; +} + +internal void +AnimBlockArray_Remove(animation_block_array* Array, handle Handle) +{ + Assert(Handle.Index < Array->Count); + Assert(Handle_IsValid(Handle)); + Array->Generations[Handle.Index]++; +} + +internal void +AnimBlockArray_RemoveAt(animation_block_array* Array, u32 Index) +{ + Assert(Index < Array->Count); + + handle Handle = {}; + Handle.Index = Index; + Handle.Generation = Array->Generations[Index]; + AnimBlockArray_Remove(Array, Handle); +} + +////////////////////////// +// +// Anim Layers Array + +internal anim_layer_array +AnimLayerArray_Create(gs_memory_arena* Storage, u32 CountMax) +{ + anim_layer_array Result = {0}; + Result.CountMax = CountMax; + Result.Values = PushArray(Storage, anim_layer, Result.CountMax); + return Result; +} + +internal u32 +AnimLayerArray_Push(anim_layer_array* Array, anim_layer Value) +{ + Assert(Array->Count < Array->CountMax); + u32 Index = Array->Count++; + Array->Values[Index] = Value; + return Index; +} + +internal void +AnimLayerArray_Remove(anim_layer_array* Array, u32 Index) +{ + Assert(Index < Array->Count); + for (u32 i = Index; i < Array->Count - 1; i++) + { + Array->Values[i] = Array->Values[i + 1]; + } +} + +////////////////////////// +// +// Animation Array + +internal animation_array +AnimationArray_Create(gs_memory_arena* Storage, u32 CountMax) +{ + animation_array Result = {0}; + Result.CountMax = CountMax; + Result.Values = PushArray(Storage, animation, Result.CountMax); + return Result; +} + +internal u32 +AnimationArray_Push(animation_array* Array, animation Value) +{ + Assert(Array->Count < Array->CountMax); + u32 Index = Array->Count++; + Array->Values[Index] = Value; + return Index; +} + +////////////////////////// +// +// Animation + +internal handle +Animation_AddBlock(animation* Animation, u32 StartFrame, s32 EndFrame, u32 AnimationProcHandle, u32 LayerIndex) +{ + Assert(LayerIndex < Animation->Layers.Count); + + animation_block NewBlock = {0}; + NewBlock.Range.Min = StartFrame; + NewBlock.Range.Max = EndFrame; + NewBlock.AnimationProcHandle = AnimationProcHandle; + NewBlock.Layer = LayerIndex; + + handle Handle = AnimBlockArray_Push(&Animation->Blocks_, NewBlock); + return Handle; +} + +internal void +Animation_RemoveBlock(animation* Animation, handle AnimHandle) +{ + AnimBlockArray_Remove(&Animation->Blocks_, AnimHandle); +} + +internal animation_block* +Animation_GetBlockFromHandle(animation* Animation, handle AnimHandle) +{ + animation_block* Result = 0; + + if (AnimHandle.Generation != 0 && + Animation->Blocks_.Generations[AnimHandle.Index] == AnimHandle.Generation) + { + Result = Animation->Blocks_.Values + AnimHandle.Index; + } + + return Result; +} + +internal u32 +Animation_AddLayer(animation* Animation, anim_layer Layer) +{ + return AnimLayerArray_Push(&Animation->Layers, Layer); +} + +internal u32 +Animation_AddLayer (animation* Animation, gs_string Name, blend_mode BlendMode, animation_system* System) +{ + anim_layer NewLayer = {0}; + NewLayer.Name = PushStringF(System->Storage, 256, "%S", Name); + NewLayer.BlendMode = BlendMode; + + return Animation_AddLayer(Animation, NewLayer); +} + +internal void +Animation_RemoveLayer (animation* Animation, u32 LayerIndex) +{ + AnimLayerArray_Remove(&Animation->Layers, LayerIndex); + for (u32 i = Animation->Blocks_.Count - 1; i >= 0; i--) + { + animation_block* Block = Animation->Blocks_.Values + i; + if (Block->Layer > LayerIndex) + { + Block->Layer -= 1; + } + else if (Block->Layer == LayerIndex) + { + AnimBlockArray_RemoveAt(&Animation->Blocks_, i); + } + } +} + +////////////////////////// +// +// + +internal u32 +SecondsToFrames(r32 Seconds, animation_system System) +{ + u32 Result = Seconds * (1.0f / System.SecondsPerFrame); + return Result; +} + +inline bool +FrameIsInRange(frame_range Range, s32 Frame) +{ + bool Result = (Frame >= Range.Min) && (Frame <= Range.Max); + return Result; +} + +internal u32 +GetFrameCount(frame_range Range) +{ + u32 Result = (u32)Max(0, Range.Max - Range.Min); + return Result; +} + +internal r32 +FrameToPercentRange(s32 Frame, frame_range Range) +{ + r32 Result = (r32)(Frame - Range.Min); + Result = Result / GetFrameCount(Range); + return Result; +} + +internal s32 +PercentToFrameInRange(r32 Percent, frame_range Range) +{ + s32 Result = Range.Min + (s32)(Percent * GetFrameCount(Range)); + return Result; +} + +internal s32 +ClampFrameToRange(s32 Frame, frame_range Range) +{ + s32 Result = Frame; + if (Result < Range.Min) + { + Result = Range.Min; + } + else if (Result > Range.Max) + { + Result = Range.Max; + } + return Result; +} + +// Blocks + +// Layers + +// System + +internal animation* +AnimationSystem_GetActiveAnimation(animation_system* System) +{ + // TODO(pjs): need a way to specify the active animation + return System->Animations.Values + System->ActiveAnimationIndex; +} + +internal animation_frame +AnimationSystem_CalculateAnimationFrame(animation_system* System, gs_memory_arena* Arena) +{ + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(System); + + animation_frame Result = {0}; + Result.BlocksCountMax = ActiveAnim->Layers.Count; + Result.Blocks = PushArray(Arena, animation_block, Result.BlocksCountMax); + Result.BlocksFilled = PushArray(Arena, b8, Result.BlocksCountMax); + ZeroArray(Result.BlocksFilled, b8, Result.BlocksCountMax); + + for (u32 i = 0; i < ActiveAnim->Blocks_.Count; i++) + { + animation_block Block = ActiveAnim->Blocks_.Values[i]; + + if (FrameIsInRange(Block.Range, System->CurrentFrame)) + { + Result.BlocksFilled[Block.Layer] = true; + Result.Blocks[Block.Layer] = Block; + Result.BlocksCount++; + } + } + + return Result; +} + +#define FOLDHAUS_ANIMATION +#endif // FOLDHAUS_ANIMATION \ No newline at end of file diff --git a/src/app/engine/animation/foldhaus_animation_serializer.cpp b/src/app/engine/animation/foldhaus_animation_serializer.cpp new file mode 100644 index 0000000..ac9954e --- /dev/null +++ b/src/app/engine/animation/foldhaus_animation_serializer.cpp @@ -0,0 +1,192 @@ +// +// File: foldhaus_animation_serializer.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-04 +// +#ifndef FOLDHAUS_ANIMATION_SERIALIZER_CPP + +internal gs_string +AnimSerializer_Serialize(animation Anim, animation_clip* GlobalClips, gs_memory_arena* Arena) +{ + serializer Serializer = {0}; + Serializer.String = PushString(Arena, 4096); + Serializer.Identifiers = AnimationFieldStrings; + Serializer.IdentifiersCount = AnimField_Count; + + Serializer_WriteF(&Serializer, "%S;\n", AnimationFieldStrings[AnimField_FileIdent]); + Serializer_WriteStringValue(&Serializer, AnimField_AnimName, Anim.Name.ConstString); + Serializer_WriteValue(&Serializer, AnimField_LayersCount, Anim.Layers.Count); + Serializer_WriteValue(&Serializer, AnimField_BlocksCount, Anim.Blocks_.Count); + + Serializer_OpenStruct(&Serializer, AnimField_PlayableRange); + { + Serializer_WriteValue(&Serializer, AnimField_PlayableRangeMin, (u32)Anim.PlayableRange.Min); + Serializer_WriteValue(&Serializer, AnimField_PlayableRangeMax, (u32)Anim.PlayableRange.Max); + } + Serializer_CloseStruct(&Serializer); + + Serializer_OpenStruct(&Serializer, AnimField_LayersArray); + for (u32 i = 0; i < Anim.Layers.Count; i++) + { + anim_layer LayerAt = Anim.Layers.Values[i]; + Serializer_OpenStruct(&Serializer, AnimField_Layer); + { + Serializer_WriteStringValue(&Serializer, AnimField_LayerName, LayerAt.Name.ConstString); + Serializer_WriteStringValue(&Serializer, AnimField_LayerBlendMode, BlendModeStrings[LayerAt.BlendMode]); + } + Serializer_CloseStruct(&Serializer); + } + Serializer_CloseStruct(&Serializer); + + + Serializer_OpenStruct(&Serializer, AnimField_BlocksArray); + for (u32 i = 0; i < Anim.Blocks_.Count; i++) + { + // TODO(pjs): Handle free'd animation blocks + animation_block AnimationBlockAt = Anim.Blocks_.Values[i]; + + // TODO(pjs): Systematize the AnimationProcHandle + // :AnimProcHandle + u32 AnimationProcIndex = AnimationBlockAt.AnimationProcHandle - 1; + animation_clip Animation = GlobalClips[AnimationProcIndex]; + + Serializer_OpenStruct(&Serializer, AnimField_Block); + { + Serializer_OpenStruct(&Serializer, AnimField_BlockFrameRange); + { + Serializer_WriteValue(&Serializer, AnimField_BlockFrameRangeMin, (u32)AnimationBlockAt.Range.Min); + Serializer_WriteValue(&Serializer, AnimField_BlockFrameRangeMax, (u32)AnimationBlockAt.Range.Max); + } + Serializer_CloseStruct(&Serializer); + + Serializer_WriteValue(&Serializer, AnimField_BlockLayerIndex, AnimationBlockAt.Layer); + Serializer_WriteStringValue(&Serializer, AnimField_BlockAnimName, ConstString(Animation.Name)); + } + Serializer_CloseStruct(&Serializer); + } + Serializer_CloseStruct(&Serializer); + + return Serializer.String; +} + +internal animation +AnimParser_Parse(gs_string File, gs_memory_arena* Arena, u32 AnimClipsCount, animation_clip* AnimClips) +{ + animation Result = {0}; + + parser Parser = {0}; + Parser.String = File; + Parser.At = Parser.String.Str; + Parser.Identifiers = AnimationFieldStrings; + Parser.IdentifiersCount = AnimField_Count; + Parser.Arena = Arena; + + if (Parser_ReadString(&Parser, AnimationFieldStrings[AnimField_FileIdent])) + { + Result.Name = Parser_ReadStringValue(&Parser, AnimField_AnimName); + + Result.Layers.CountMax = Parser_ReadU32Value(&Parser, AnimField_LayersCount); + Result.Layers.Values = PushArray(Arena, anim_layer, Result.Layers.CountMax); + + Result.Blocks_.CountMax = Parser_ReadU32Value(&Parser, AnimField_BlocksCount); + Result.Blocks_.Generations = PushArray(Arena, u32, Result.Blocks_.CountMax); + Result.Blocks_.Values = PushArray(Arena, animation_block, Result.Blocks_.CountMax); + + if (Parser_ReadOpenStruct(&Parser, AnimField_PlayableRange)) + { + Result.PlayableRange.Min = Parser_ReadU32Value(&Parser, AnimField_PlayableRangeMin); + Result.PlayableRange.Max = Parser_ReadU32Value(&Parser, AnimField_PlayableRangeMax); + + if (Parser_ReadCloseStruct(&Parser)) + { + // TODO(pjs): Error + } + } + else + { + // TODO(pjs): Error + } + + if (Parser_ReadOpenStruct(&Parser, AnimField_LayersArray)) + { + while (!Parser_ReadCloseStruct(&Parser)) + { + anim_layer Layer = {0}; + if (Parser_ReadOpenStruct(&Parser, AnimField_Layer)) + { + Layer.Name = Parser_ReadStringValue(&Parser, AnimField_LayerName); + + gs_string BlendModeName = Parser_ReadStringValue(&Parser, AnimField_LayerBlendMode); + for (u32 i = 0; i < BlendMode_Count; i++) + { + if (StringsEqual(BlendModeName.ConstString, BlendModeStrings[i])) + { + Layer.BlendMode = (blend_mode)i; + break; + } + } + + if (Parser_ReadCloseStruct(&Parser)) + { + Animation_AddLayer(&Result, Layer); + } + else + { + // TODO(pjs): Error + } + } + } + } + + if (Parser_ReadOpenStruct(&Parser, AnimField_BlocksArray)) + { + while(!Parser_ReadCloseStruct(&Parser)) + { + animation_block Block = {0}; + + if (Parser_ReadOpenStruct(&Parser, AnimField_Block)) + { + if (Parser_ReadOpenStruct(&Parser, AnimField_BlockFrameRange)) + { + Block.Range.Min = Parser_ReadU32Value(&Parser, AnimField_BlockFrameRangeMin); + Block.Range.Max = Parser_ReadU32Value(&Parser, AnimField_BlockFrameRangeMax); + + Parser_ReadCloseStruct(&Parser); + } + else + { + // TODO(pjs): Error + } + + Block.Layer = Parser_ReadU32Value(&Parser, AnimField_BlockLayerIndex); + + // TODO(pjs): AnimName -> Animation Proc Handle + gs_string AnimName = Parser_ReadStringValue(&Parser, AnimField_BlockAnimName); + Block.AnimationProcHandle = 0; + for (u32 i = 0; i < AnimClipsCount; i++) + { + if (StringEqualsCharArray(AnimName.ConstString, AnimClips[i].Name, CStringLength(AnimClips[i].Name))) + { + Block.AnimationProcHandle = i + 1; + break; + } + } + + if (Parser_ReadCloseStruct(&Parser)) + { + AnimBlockArray_Push(&Result.Blocks_, Block); + } + else + { + // TODO(pjs): Error + } + } + } + } + } + + return Result; +} + +#define FOLDHAUS_ANIMATION_SERIALIZER_CPP +#endif // FOLDHAUS_ANIMATION_SERIALIZER_CPP \ No newline at end of file diff --git a/src/app/artnet/artnet.h b/src/app/engine/artnet/artnet.h similarity index 100% rename from src/app/artnet/artnet.h rename to src/app/engine/artnet/artnet.h diff --git a/src/app/engine/assembly/foldhaus_assembly.cpp b/src/app/engine/assembly/foldhaus_assembly.cpp new file mode 100644 index 0000000..1d68fdb --- /dev/null +++ b/src/app/engine/assembly/foldhaus_assembly.cpp @@ -0,0 +1,278 @@ +// +// File: foldhaus_assembly.cpp +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_ASSEMBLY_CPP + +/////////////////////////// +// +// Assembly Array +// +/////////////////////////// + +internal assembly_array +AssemblyArray_Create(u32 CountMax, gs_memory_arena* Storage) +{ + assembly_array Result = {0}; + Result.CountMax = CountMax; + Result.Values = PushArray(Storage, assembly, Result.CountMax); + return Result; +} + +internal u32 +AssemblyArray_Push(assembly_array* Array, assembly Assembly) +{ + Assert(Array->Count < Array->CountMax); + u32 Index = Array->Count++; + Array->Values[Index] = Assembly; + return Index; +} + +internal assembly* +AssemblyArray_Take(assembly_array* Array) +{ + u32 Index = AssemblyArray_Push(Array, {}); + assembly* Result = Array->Values + Index; + return Result; +} + +internal void +AssemblyArray_RemoveAt(assembly_array* Array, u32 Index) +{ + u32 LastAssemblyIndex = --Array->Count; + Array->Values[Index] = Array->Values[LastAssemblyIndex]; +} + +typedef bool assembly_array_filter_proc(assembly A); +bool AssemblyFilter_OutputsViaSACN(assembly A) { return A.OutputMode == NetworkProtocol_SACN; } +bool AssemblyFilter_OutputsViaUART(assembly A) { return A.OutputMode == NetworkProtocol_UART; } + +internal assembly_array +AssemblyArray_Filter(assembly_array Array, assembly_array_filter_proc* Filter, gs_memory_arena* Storage) +{ + assembly_array Result = AssemblyArray_Create(Array.Count, Storage); + + for (u32 i = 0; i < Array.Count; i++) + { + assembly At = Array.Values[i]; + if (Filter(At)) + { + AssemblyArray_Push(&Result, At); + } + } + + return Result; +} + +/////////////////////////// +// +// LedSystem +// +/////////////////////////// + +internal led_system +LedSystemInitialize(gs_allocator PlatformMemory, u32 BuffersMax) +{ + led_system Result = {}; + Result.PlatformMemory = PlatformMemory; + // TODO(Peter): Since we have access to PlatformMemory, just realloc Buffers when we fill it up + Result.BuffersCountMax = BuffersMax; + Result.Buffers = AllocatorAllocArray(PlatformMemory, led_buffer, Result.BuffersCountMax); + return Result; +} + +internal u32 +LedSystemTakeFreeBuffer(led_system* System, u32 LedCount) +{ + s32 Result = -1; + + if (System->BuffersCount < System->BuffersCountMax) + { + Result = System->BuffersCount++; + } + else + { + // NOTE(Peter): Look for a buffer that's flagged as empty + for (u32 i = 0; i < System->BuffersCount; i++) + { + if (System->Buffers[i].LedCount == 0 + && System->Buffers[i].Colors == 0 + && System->Buffers[i].Positions == 0) + { + Result = i; + break; + } + } + Assert(Result >= 0); // NOTE(Peter): We ran out of room for led buffers + } + + led_buffer* Buffer = &System->Buffers[Result]; + Buffer->LedCount = LedCount; + Buffer->Colors = AllocatorAllocArray(System->PlatformMemory, pixel, Buffer->LedCount); + Buffer->Positions = AllocatorAllocArray(System->PlatformMemory, v4, Buffer->LedCount); + + System->LedsCountTotal += LedCount; + + return (u32)Result; +} + +internal void +LedSystemFreeBuffer(led_system* System, u32 BufferIndex) +{ + Assert(BufferIndex < System->BuffersCountMax); + led_buffer* Buffer = &System->Buffers[BufferIndex]; + AllocatorFreeArray(System->PlatformMemory, Buffer->Colors, pixel, Buffer->LedCount); + AllocatorFreeArray(System->PlatformMemory, Buffer->Positions, v4, Buffer->LedCount); + System->LedsCountTotal -= Buffer->LedCount; + *Buffer = {}; +} + +internal void +LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position) +{ + Assert(Led < Buffer->LedCount); + Buffer->Positions[Led] = Position; +} + +internal u32 +Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex) +{ + u32 LedsAdded = 0; + + switch (GenData.Method) + { + case StripGeneration_InterpolatePoints: + { + strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints; + v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale); + v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale); + + v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount; + for (u32 Step = 0; Step < InterpPoints.LedCount; Step++) + { + s32 LedIndex = LedStartIndex + LedsAdded++; + v4 LedPosition = WS_StripStart + (SingleStep * Step); + LedBufferSetLed(LedBuffer, LedIndex, LedPosition); + StripAt->LedLUT[Step] = LedIndex; + } + }break; + + case StripGeneration_Sequence: + { + strip_gen_sequence Sequence = GenData.Sequence; + for (u32 i = 0; i < Sequence.ElementsCount; i++) + { + strip_gen_data SegmentGenData = Sequence.Elements[i]; + LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded); + } + }break; + + InvalidDefaultCase; + } + + return LedsAdded; +} + +internal void +ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem) +{ + Assembly->LedBufferIndex = LedSystemTakeFreeBuffer(LedSystem, Assembly->LedCountTotal); + led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly->LedBufferIndex); + + v4 RootPosition = ToV4Vec(Assembly->Center); + + // Add Leds + u32 LedsAdded = 0; + for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++) + { + v2_strip* StripAt = &Assembly->Strips[StripIdx]; + StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount); + + strip_gen_data GenData = StripAt->GenerationData; + LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded); + } +} + +internal void +LoadAssembly (assembly_array* Assemblies, led_system* LedSystem, gs_memory_arena* Scratch, context Context, gs_const_string Path, event_log* GlobalLog) +{ + gs_file AssemblyFile = ReadEntireFile(Context.ThreadContext.FileHandler, Path); + if (FileNoError(AssemblyFile)) + { + gs_string AssemblyFileText = MakeString((char*)AssemblyFile.Memory); + + s32 IndexOfLastSlash = FindLast(Path, '\\'); + gs_const_string FileName = Substring(Path, IndexOfLastSlash + 1, Path.Length); + + assembly* NewAssembly = AssemblyArray_Take(Assemblies); + NewAssembly->Arena = CreateMemoryArena(Context.ThreadContext.Allocator); + + if (ParseAssemblyFile(NewAssembly, FileName, AssemblyFileText, Scratch)) + { + ConstructAssemblyFromDefinition(NewAssembly, LedSystem); + } + else + { + FreeMemoryArena(&NewAssembly->Arena); + Assemblies->Count -= 1; + } + } + else + { + LogError(GlobalLog, "Unable to load assembly file"); + } +} + +internal void +UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context) +{ + Assert(AssemblyIndex < State->Assemblies.Count); + assembly* Assembly = &State->Assemblies.Values[AssemblyIndex]; + LedSystemFreeBuffer(&State->LedSystem, Assembly->LedBufferIndex); + FreeMemoryArena(&Assembly->Arena); + AssemblyArray_RemoveAt(&State->Assemblies, AssemblyIndex); +} + +// Querying Assemblies + +internal led_strip_list +AssemblyStripsGetWithTagValue(assembly Assembly, gs_const_string TagName, gs_const_string TagValue, gs_memory_arena* Storage) +{ + led_strip_list Result = {0}; + // TODO(pjs): @Optimization + // We can probably come back here and do this allocation procedurally, or in buckets, or with + // a linked list. But for now, I just want to get this up and running + Result.CountMax = Assembly.StripCount; + Result.StripIndices = PushArray(Storage, u32, Result.CountMax); + + u64 NameHash = HashDJB2ToU32(StringExpand(TagName)); + u64 ValueHash = 0; + if (TagValue.Length > 0) + { + ValueHash = HashDJB2ToU32(StringExpand(TagValue)); + } + + for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++) + { + v2_strip StripAt = Assembly.Strips[StripIndex]; + for (u32 j = 0; j < StripAt.TagsCount; j++) + { + v2_tag TagAt = StripAt.Tags[j]; + if (TagAt.NameHash == NameHash) + { + // NOTE(pjs): We can pass an empty string to the Value parameter, + // and it will match all values of Tag + if (ValueHash == 0 || ValueHash == TagAt.ValueHash) + { + Result.StripIndices[Result.Count++] = StripIndex; + } + } + } + } + + return Result; +} + +#define FOLDHAUS_ASSEMBLY_CPP +#endif // FOLDHAUS_ASSEMBLY_CPP \ No newline at end of file diff --git a/src/app/engine/assembly/foldhaus_assembly.h b/src/app/engine/assembly/foldhaus_assembly.h new file mode 100644 index 0000000..94982a5 --- /dev/null +++ b/src/app/engine/assembly/foldhaus_assembly.h @@ -0,0 +1,198 @@ +// +// File: foldhaus_assembly.h +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_ASSEMBLY_H + +enum network_protocol +{ + NetworkProtocol_SACN, + NetworkProtocol_ArtNet, + NetworkProtocol_UART, + + NetworkProtocol_Count, +}; + +union pixel +{ + struct + { + u8 R; + u8 G; + u8 B; + }; + u8 Channels[3]; +}; + +struct led_buffer +{ + u32 LedCount; + pixel* Colors; + v4* Positions; +}; + +struct led_system +{ + gs_allocator PlatformMemory; + + u32 BuffersCountMax; + u32 BuffersCount; + led_buffer* Buffers; + + u32 LedsCountTotal; +}; + +struct v2_tag +{ + u64 NameHash; + u64 ValueHash; +}; + +struct strip_sacn_addr +{ + s32 StartUniverse; + s32 StartChannel; +}; + +struct strip_uart_addr +{ + u8 Channel; + + gs_string ComPort; + // This may not be used based on the value of the parent + // assembly's NetworkPortMode field +}; + +enum strip_gen_method +{ + StripGeneration_InterpolatePoints, + StripGeneration_Sequence, + + StripGeneration_Count, +}; + +typedef struct strip_gen_data strip_gen_data; + +struct strip_gen_interpolate_points +{ + v3 StartPosition; + v3 EndPosition; + u32 LedCount; +}; + +struct strip_gen_sequence +{ + strip_gen_data* Elements; + u32 ElementsCount; +}; + +struct strip_gen_data +{ + strip_gen_method Method; + + strip_gen_interpolate_points InterpolatePoints; + strip_gen_sequence Sequence; +}; + +struct v2_strip +{ + s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore + + strip_sacn_addr SACNAddr; + strip_uart_addr UARTAddr; + + strip_gen_data GenerationData; + + u32 LedCount; + u32* LedLUT; + + u32 TagsCount; + v2_tag* Tags; +}; + +struct led_strip_list +{ + u32 Count; + u32 CountMax; + u32* StripIndices; +}; + +enum network_port_mode +{ + // This enum defines the scope which contains what network + // port each address should be sent over. + + NetworkPortMode_GlobalPort, + // GlobalPort means that the port is defined in the assembly structure + + NetworkPortMode_PortPerStrip, + // PortPerStrip means that the address stored in the strip structure + // should be used, and each strip might have a different port + + NetworkPortMode_Count, +}; + +struct assembly +{ + gs_memory_arena Arena; + + gs_string Name; + gs_string FilePath; + + r32 Scale; + v3 Center; + s32 LedCountTotal; + u32 LedBufferIndex; + + u32 StripCount; + v2_strip* Strips; + + network_protocol OutputMode; + network_port_mode NetPortMode; + gs_string UARTComPort; +}; + +struct assembly_array +{ + u32 CountMax; + u32 Count; + assembly* Values; +}; + + +internal led_buffer* +LedSystemGetBuffer(led_system* System, u32 Index) +{ + led_buffer* Result = &System->Buffers[Index]; + return Result; +} + +internal u32 +StripGenData_CountLeds(strip_gen_data Data) +{ + u32 Result = 0; + + switch (Data.Method) + { + case StripGeneration_InterpolatePoints: + { + Result += Data.InterpolatePoints.LedCount; + }break; + + case StripGeneration_Sequence: + { + for (u32 i = 0; i < Data.Sequence.ElementsCount; i++) + { + Result += StripGenData_CountLeds(Data.Sequence.Elements[i]); + } + }break; + + InvalidDefaultCase; + } + + return Result; +} + +#define FOLDHAUS_ASSEMBLY_H +#endif // FOLDHAUS_ASSEMBLY_H \ No newline at end of file diff --git a/src/app/engine/assembly/foldhaus_assembly_parser.cpp b/src/app/engine/assembly/foldhaus_assembly_parser.cpp new file mode 100644 index 0000000..ff2cbc0 --- /dev/null +++ b/src/app/engine/assembly/foldhaus_assembly_parser.cpp @@ -0,0 +1,332 @@ +// +// File: foldhaus_assembly_parser.cpp +// Author: Peter Slattery +// Creation Date: 2020-01-01 +// +#ifndef FOLDHAUS_ASSEMBLY_PARSER_CPP + +// TODO(pjs): This is good for meta generation +// ie. It would be great to have +// // enum ident enum prefix +// BEGIN_GEN_ENUM(assembly_field, AssemblyField_) +// // value name gen string of the value name the paired string identifier +// ADD_ENUM_VALUE(AssemblyName, DO_GEN_STRING, "assembly_name") +// ADD_ENUM_VALUE(AssemblyScale, DO_GEN_STRING, "assembly_scale") +// END_GEN_ENUM(assembly_field) + +enum assembly_field +{ + AssemblyField_AssemblyName, + AssemblyField_AssemblyScale, + AssemblyField_AssemblyCenter, + AssemblyField_LedStripCount, + AssemblyField_OutputMode, + + AssemblyField_LedStrip, + + AssemblyField_OutputSACN, + AssemblyField_SACN_StartUniverse, + AssemblyField_SACN_StartChannel, + + AssemblyField_OutputUART, + AssemblyField_UART_Channel, + AssemblyField_UART_ComPort, + + AssemblyField_PointPlacementType, + + AssemblyField_InterpolatePoints, + AssemblyField_Start, + AssemblyField_End, + AssemblyField_LedCount, + + AssemblyField_SegmentSequence, + AssemblyField_SegmentSequenceLength, + AssemblyField_Segment, + + AssemblyField_TagsCount, + AssemblyField_Tag, + AssemblyField_Name, + AssemblyField_Value, + + AssemblyField_Count, +}; + +global gs_const_string AssemblyFieldIdentifiers[] = { + ConstString("assembly_name"), // AssemblyField_AssemblyName + ConstString("assembly_scale"), // AssemblyField_AssemblyScale + ConstString("assembly_center"), // AssemblyField_AssemblyCenter + ConstString("led_strip_count"), // AssemblyField_LedStripCount + ConstString("output_mode"), // AssemblyField_OutputMode + + ConstString("led_strip"), // AssemblyField_LedStrip + + ConstString("output_sacn"), // AssemblyField_OutputSACN + ConstString("start_universe"), // AssemblyField_SACN_StartUniverse + ConstString("start_channel"), // AssemblyField_SACN_StartChannel + + ConstString("output_uart"), // AssemblyField_OutputUART + ConstString("channel"), // AssemblyField_UART_Channel + ConstString("com_port"), // AssemblyField_UART_ComPort + + ConstString("point_placement_type"), // AssemblyField_PointPlacementType + + ConstString("interpolate_points"), // AssemblyField_InterpolatePoints + ConstString("start"), // AssemblyField_Start + ConstString("end"), // AssemblyField_End + ConstString("led_count"), // AssemblyField_LedCount + + ConstString("segment_sequence"), // AssemblyField_SegmentSequence + ConstString("segment_count"), // AssemblyField_SegmentSequenceLength + ConstString("segment"), // AssemblyField_Segment + + ConstString("tags_count"), // AssemblyField_TagCount + ConstString("tag"), // AssemblyField_Tag + ConstString("name"), // AssemblyField_Name + ConstString("value"), // AssemblyField_Value +}; + +internal void +StripSetTag(v2_strip* Strip, u32 TagIndex, gs_const_string TagName, gs_const_string TagValue) +{ + Assert(TagIndex < Strip->TagsCount); + v2_tag* TagAt = &Strip->Tags[TagIndex]; + TagAt->NameHash = HashDJB2ToU32(StringExpand(TagName)); + TagAt->ValueHash = HashDJB2ToU32(StringExpand(TagValue)); +} + +internal strip_sacn_addr +AssemblyParser_ReadSACNAddr(parser* Parser, assembly Assembly) +{ + strip_sacn_addr Result = {0}; + + if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputSACN)) + { + Result.StartUniverse = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartUniverse); + Result.StartChannel = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartChannel); + + if (!Parser_ReadCloseStruct(Parser)) + { + //TokenizerPushError(&Tokenizer, "Struct doesn't close where expected"); + } + } + + return Result; +} + +internal strip_uart_addr +AssemblyParser_ReadUARTAddr(parser* Parser, assembly Assembly) +{ + strip_uart_addr Result = {0}; + + if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputUART)) + { + Result.Channel = (u8)Parser_ReadU32Value(Parser, AssemblyField_UART_Channel); + + bool HasNetPort = Parser_ReadStringValue(Parser, AssemblyField_UART_ComPort, &Result.ComPort, true); + if (Assembly.NetPortMode == NetworkPortMode_PortPerStrip && !HasNetPort) + { + Parser_PushErrorF(Parser, "NetPortMode for assembly is PortPerStrip, but this strip doesn't have an output port."); + } + + if (!Parser_ReadCloseStruct(Parser)) + { + Parser_PushErrorF(Parser, "Struct doesn't close where expected"); + } + } + + return Result; +} + +internal void +AssemblyParser_ReadTag(parser* Parser, v2_strip* StripAt, u32 TagIndex) +{ + if (Parser_ReadOpenStruct(Parser, AssemblyField_Tag)) + { + // TODO(Peter): Need to store the gs_string somewhere we can look it up for display in the interface + // right now they are stored in temp memory and won't persist + gs_string TagName = Parser_ReadStringValue(Parser, AssemblyField_Name); + gs_string TagValue = Parser_ReadStringValue(Parser, AssemblyField_Value); + StripSetTag(StripAt, TagIndex, TagName.ConstString, TagValue.ConstString); + if (!Parser_ReadCloseStruct(Parser)) + { + Parser_PushErrorF(Parser, "Tag struct doesn't close where expected"); + } + } + else + { + Parser_PushErrorF(Parser, "Expected a tag struct, but none was found."); + } +} + + +internal void +AssemblyParser_ReadTagList(parser* Parser, v2_strip* StripAt, assembly* Assembly) +{ + StripAt->TagsCount = Parser_ReadU32Value(Parser, AssemblyField_TagsCount); + // NOTE(pjs): Always add one tag to the input to leave room for the assembly name + StripAt->TagsCount += 1; + StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount); + + StripSetTag(StripAt, 0, ConstString("assembly"), Assembly->Name.ConstString); + + for (u32 Tag = 1; Tag < StripAt->TagsCount; Tag++) + { + AssemblyParser_ReadTag(Parser, StripAt, Tag); + } +} + +internal strip_gen_data AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly); + +internal strip_gen_interpolate_points +AssemblyParser_ReadInterpolatePoints(parser* Parser) +{ + strip_gen_interpolate_points Result = {0}; + if (Parser_ReadOpenStruct(Parser, AssemblyField_InterpolatePoints)) + { + Result.StartPosition = Parser_ReadV3Value(Parser, AssemblyField_Start); + Result.EndPosition = Parser_ReadV3Value(Parser, AssemblyField_End); + Result.LedCount = Parser_ReadU32Value(Parser, AssemblyField_LedCount); + if (!Parser_ReadCloseStruct(Parser)) + { + // TODO(pjs): + } + } + else + { + // TODO(pjs): + } + return Result; +} + +internal strip_gen_sequence +AssemblyParser_ReadSequence(parser* Parser, assembly* Assembly) +{ + strip_gen_sequence Result = {0}; + if (Parser_ReadOpenStruct(Parser, AssemblyField_SegmentSequence)) + { + Result.ElementsCount = Parser_ReadU32Value(Parser, AssemblyField_SegmentSequenceLength); + Result.Elements = PushArray(&Assembly->Arena, strip_gen_data, Result.ElementsCount); + for (u32 i = 0; i < Result.ElementsCount; i++) + { + Result.Elements[i] = AssemblyParser_ReadStripGenData(Parser, Assembly); + } + if (!Parser_ReadCloseStruct(Parser)) + { + // TODO(pjs): + } + } + else + { + // TODO(pjs): + } + return Result; +} + +internal strip_gen_data +AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly) +{ + strip_gen_data Result = {0}; + + if (Parser_ReadOpenStruct(Parser, AssemblyField_Segment)) + { + gs_string PointPlacementType = Parser_ReadStringValue(Parser, AssemblyField_PointPlacementType); + + // TODO(pjs): We want to store enum strings in some unified way + // :EnumStringsGen + if (StringsEqual(PointPlacementType.ConstString, ConstString("InterpolatePoints"))) + { + Result.Method = StripGeneration_InterpolatePoints; + Result.InterpolatePoints = AssemblyParser_ReadInterpolatePoints(Parser); + } + else if (StringsEqual(PointPlacementType.ConstString, + ConstString("SegmentSequence"))) + { + Result.Method = StripGeneration_Sequence; + Result.Sequence = AssemblyParser_ReadSequence(Parser, Assembly); + } + else + { + Parser_PushErrorF(Parser, "Incorrect Point Placement Type found for segment"); + } + + if (!Parser_ReadCloseStruct(Parser)) + { + Parser_PushErrorF(Parser, "Strip Gen Data did not close the struct where expected"); + } + } + + return Result; +} + +internal bool +ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient) +{ + Assembly->LedCountTotal = 0; + + parser Parser = {0}; + Parser.String = FileText; + Parser.Identifiers = &AssemblyFieldIdentifiers[0]; + Parser.IdentifiersCount = AssemblyField_Count; + Parser.At = Parser.String.Str; + Parser.LineStart = Parser.At; + Parser.Arena = &Assembly->Arena; + Parser.Transient = Transient; + + Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName); + Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale); + Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter); + Assembly->StripCount = Parser_ReadU32Value(&Parser, AssemblyField_LedStripCount); + Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount); + + gs_string OutputModeString = Parser_ReadStringValue(&Parser, AssemblyField_OutputMode); + if (StringsEqual(OutputModeString.ConstString, ConstString("UART"))) + { + Assembly->OutputMode = NetworkProtocol_UART; + if (Parser_ReadStringValue(&Parser, AssemblyField_UART_ComPort, &Assembly->UARTComPort, true)) + { + Assembly->NetPortMode = NetworkPortMode_GlobalPort; + } + else + { + Assembly->NetPortMode = NetworkPortMode_PortPerStrip; + } + } + else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN"))) + { + Assembly->OutputMode = NetworkProtocol_SACN; + } + else + { + Parser_PushErrorF(&Parser, "Invalid output mode specified for assembly."); + } + + for (u32 i = 0; i < Assembly->StripCount; i++) + { + v2_strip* StripAt = Assembly->Strips + i; + if (Parser_ReadOpenStruct(&Parser, AssemblyField_LedStrip)) + { + StripAt->SACNAddr = AssemblyParser_ReadSACNAddr(&Parser, *Assembly); + StripAt->UARTAddr = AssemblyParser_ReadUARTAddr(&Parser, *Assembly); + StripAt->GenerationData = AssemblyParser_ReadStripGenData(&Parser, Assembly); + StripAt->LedCount = StripGenData_CountLeds(StripAt->GenerationData); + AssemblyParser_ReadTagList(&Parser, StripAt, Assembly); + + Assembly->LedCountTotal += StripAt->LedCount; + + if (!Parser_ReadCloseStruct(&Parser)) + { + Parser_PushErrorF(&Parser, "Strip struct doesn't close where expected"); + } + } + else + { + Parser_PushErrorF(&Parser, "Expected a strip struct but none was found"); + } + } + + // TODO(pjs): invalidate the file if its incorrect + return true; //Tokenizer.ParsingIsValid; +} + +#define FOLDHAUS_ASSEMBLY_PARSER_CPP +#endif // FOLDHAUS_ASSEMBLY_PARSER_CPP \ No newline at end of file diff --git a/src/app/engine/foldhaus_addressed_data.h b/src/app/engine/foldhaus_addressed_data.h new file mode 100644 index 0000000..47b70d7 --- /dev/null +++ b/src/app/engine/foldhaus_addressed_data.h @@ -0,0 +1,99 @@ +// +// File: foldhaus_addressed_data.h +// Author: Peter Slattery +// Creation Date: 2020-10-01 +// +// addressed_data_buffer is a generic buffer of data that also contains information +// regarding how it should be sent to a sculpture. +// This decouples the encoding step from the sending step. +// +#ifndef FOLDHAUS_ADDRESSED_DATA_H + +enum data_buffer_address_type +{ + AddressType_NetworkIP, + AddressType_ComPort, + AddressType_Invalid, +}; + +struct addressed_data_buffer +{ + union + { + struct + { + u8* Memory; + u32 MemorySize; + }; + gs_data Data; + }; + + data_buffer_address_type AddressType; + + // IP Address + platform_socket_handle SendSocket; + u32 V4SendAddress; + u32 SendPort; + + // COM + gs_const_string ComPort; + + addressed_data_buffer* Next; +}; + +struct addressed_data_buffer_list +{ + gs_memory_arena* Arena; + addressed_data_buffer* Root; + addressed_data_buffer* Head; +}; + +internal void +AddressedDataBufferList_Clear(addressed_data_buffer_list* List) +{ + List->Root = 0; + List->Head = 0; + ClearArena(List->Arena); +} + +internal addressed_data_buffer* +AddressedDataBufferList_PushEmpty(addressed_data_buffer_list* List) +{ + addressed_data_buffer* Result = PushStruct(List->Arena, addressed_data_buffer); + *Result = {0}; + Result->Next = 0; + Result->MemorySize = 0; + Result->Memory = 0; + + SLLPushOrInit(List->Root, List->Head, Result); + + return Result; +} + +internal addressed_data_buffer* +AddressedDataBufferList_Push(addressed_data_buffer_list* List, u32 BufferSize) +{ + addressed_data_buffer* Result = AddressedDataBufferList_PushEmpty(List); + Result->MemorySize = BufferSize; + Result->Memory = PushArray(List->Arena, u8, Result->MemorySize); + return Result; +} + +internal void +AddressedDataBuffer_SetNetworkAddress(addressed_data_buffer* Buffer, platform_socket_handle SendSocket, u32 V4SendAddress, u32 SendPort) +{ + Buffer->AddressType = AddressType_NetworkIP; + Buffer->SendSocket = SendSocket; + Buffer->V4SendAddress = V4SendAddress; + Buffer->SendPort = SendPort; +} + +internal void +AddressedDataBuffer_SetCOMPort(addressed_data_buffer* Buffer, gs_const_string ComPort) +{ + Buffer->AddressType = AddressType_ComPort; + Buffer->ComPort = ComPort; +} + +#define FOLDHAUS_ADDRESSED_DATA_H +#endif // FOLDHAUS_ADDRESSED_DATA_H \ No newline at end of file diff --git a/src/app/foldhaus_network_ordering.h b/src/app/engine/foldhaus_network_ordering.h similarity index 82% rename from src/app/foldhaus_network_ordering.h rename to src/app/engine/foldhaus_network_ordering.h index 65b60c7..05e5afd 100644 --- a/src/app/foldhaus_network_ordering.h +++ b/src/app/engine/foldhaus_network_ordering.h @@ -6,7 +6,7 @@ #ifndef FOLDHAUS_NETWORK_ORDERING_H // Packs a u8 to a known big endian buffer -inline u8* +inline u8* PackB1(u8* ptr, u8 val) { *ptr = val; @@ -14,14 +14,14 @@ PackB1(u8* ptr, u8 val) } //Unpacks a u8 from a known big endian buffer -inline u8 +inline u8 UpackB1(const u8* ptr) { return *ptr; } //Packs a u8 to a known little endian buffer -inline u8* +inline u8* PackL1(u8* ptr, u8 val) { *ptr = val; @@ -29,30 +29,40 @@ PackL1(u8* ptr, u8 val) } //Unpacks a u8 from a known little endian buffer -inline u8 +inline u8 UpackL1(const u8* ptr) { return *ptr; } //Packs a u16 to a known big endian buffer -inline u8* +inline u16 +PackB2(u16 Value) +{ + u16 Result = 0; + u8* Array = (u8*)&Result; + Array[1] = (u8)(Value & 0xFF); + Array[0] = (u8)((Value & 0xFF00) >> 8); + return Result; +} + +inline u8* PackB2(u8* ptr, u16 val) { - ptr[1] = (u8)(val & 0xff); + ptr[1] = (u8)(val & 0xff); ptr[0] = (u8)((val & 0xff00) >> 8); return ptr + sizeof(val); } //Unpacks a u16 from a known big endian buffer -inline u16 +inline u16 UpackB2(const u8* ptr) { return (u16)(ptr[1] | ptr[0] << 8); } //Packs a u16 to a known little endian buffer -inline u8* +inline u8* PackL2(u8* ptr, u16 val) { *((u16*)ptr) = val; @@ -60,14 +70,14 @@ PackL2(u8* ptr, u16 val) } //Unpacks a u16 from a known little endian buffer -inline u16 +inline u16 UpackL2(const u8* ptr) { return *((u16*)ptr); } //Packs a u32 to a known big endian buffer -inline u8* +inline u8* PackB4(u8* ptr, u32 val) { ptr[3] = (u8) (val & 0xff); @@ -78,14 +88,14 @@ PackB4(u8* ptr, u32 val) } //Unpacks a u32 from a known big endian buffer -inline u32 +inline u32 UpackB4(const u8* ptr) { return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24)); } //Packs a u32 to a known little endian buffer -inline u8* +inline u8* PackL4(u8* ptr, u32 val) { *((u32*)ptr) = val; @@ -93,14 +103,14 @@ PackL4(u8* ptr, u32 val) } //Unpacks a u32 from a known little endian buffer -inline u32 +inline u32 UpackL4(const u8* ptr) { return *((u32*)ptr); } //Packs a u64 to a known big endian buffer -inline u8* +inline u8* PackB8(u8* ptr, u64 val) { ptr[7] = (u8) (val & 0xff); @@ -115,17 +125,17 @@ PackB8(u8* ptr, u64 val) } //Unpacks a uint64 from a known big endian buffer -inline u64 +inline u64 UpackB8(const u8* ptr) { return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) | - (((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | - (((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) | + (((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | + (((u64)ptr[2]) << 40) | (((u64)ptr[1]) << 48) | (((u64)ptr[0]) << 56); } //Packs a u64 to a known little endian buffer -inline u8* +inline u8* PackL8(u8* ptr, u64 val) { *((u64*)ptr) = val; @@ -133,7 +143,7 @@ PackL8(u8* ptr, u64 val) } //Unpacks a u64 from a known little endian buffer -inline u64 +inline u64 UpackL8(const u8* ptr) { return *((u64*)ptr); diff --git a/src/app/engine/foldhaus_serializer.h b/src/app/engine/foldhaus_serializer.h new file mode 100644 index 0000000..06f9d71 --- /dev/null +++ b/src/app/engine/foldhaus_serializer.h @@ -0,0 +1,563 @@ +// +// File: foldhaus_serializer.h +// Author: Peter Slattery +// Creation Date: 2020-10-09 +// +#ifndef FOLDHAUS_SERIALIZER_H + +struct serializer +{ + gs_string String; + u32 Indent; + gs_const_string* Identifiers; + u32 IdentifiersCount; +}; + +internal gs_const_string +Serializer_GetIdent(serializer* Serializer, u32 Index) +{ + gs_const_string Result = Serializer->Identifiers[Index]; + return Result; +} + +// Serializing + +internal void +Serializer_WriteIndent(serializer* Serializer) +{ + for (u32 i = 0; i < Serializer->Indent; i++) + { + AppendPrintF(&Serializer->String, " "); + } +} + +internal void +Serializer_WriteF(serializer* Serializer, char* Format, ...) +{ + Serializer_WriteIndent(Serializer); + + va_list Args; + va_start(Args, Format); + PrintFArgsList(&Serializer->String, Format, Args); + va_end(Args); +} + +internal void +Serializer_OpenStruct(serializer* Serializer, gs_const_string StructName) +{ + Serializer_WriteF(Serializer, "%S:{\n", StructName); + Serializer->Indent++; +} + +internal void +Serializer_OpenStruct(serializer* Serializer, u32 StructIdentifier) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, StructIdentifier); + Serializer_WriteF(Serializer, "%S:{\n", Ident); + Serializer->Indent++; +} + +internal void +Serializer_CloseStruct(serializer* Serializer) +{ + Serializer->Indent--; + Serializer_WriteF(Serializer, "};\n"); +} + +internal void +Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, gs_const_string Value) +{ + Serializer_WriteF(Serializer, "%S: %S;\n", Ident, Value); +} + +internal void +Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, gs_const_string Value) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex); + Serializer_WriteValue(Serializer, Ident, Value); +} + +internal void +Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, u32 Value) +{ + Serializer_WriteF(Serializer, "%S: %d;\n", Ident, Value); +} + +internal void +Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, u32 Value) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex); + Serializer_WriteValue(Serializer, Ident, Value); +} + +internal void +Serializer_WriteValue(serializer* Serializer, gs_const_string Ident, r32 Value) +{ + Serializer_WriteF(Serializer, "%S: %f;\n", Ident, Value); +} + +internal void +Serializer_WriteValue(serializer* Serializer, u32 IdentIndex, r32 Value) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex); + Serializer_WriteValue(Serializer, Ident, Value); +} + +internal void +Serializer_WriteStringValue(serializer* Serializer, gs_const_string Ident, gs_const_string Value) +{ + Serializer_WriteF(Serializer, "%S: \"%S\";\n", Ident, Value); +} + +internal void +Serializer_WriteStringValue(serializer* Serializer, u32 IdentIndex, gs_const_string Value) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex); + Serializer_WriteStringValue(Serializer, Ident, Value); +} + +internal void +Serializer_WriteV3Value(serializer* Serializer, gs_const_string Ident, v3 Value) +{ + Serializer_WriteF(Serializer, "%S: (%f, %f, %f);\n", Ident, Value.x, Value.y, Value.z); +} + +internal void +Serializer_WriteV3Value(serializer* Serializer, u32 IdentIndex, v3 Value) +{ + gs_const_string Ident = Serializer_GetIdent(Serializer, IdentIndex); + Serializer_WriteV3Value(Serializer, Ident, Value); +} + +// Parsing + +struct parser_error +{ + gs_string Message; + + gs_string FileName; + u32 LineNumber; + + parser_error* Next; +}; + +struct parser +{ + gs_string FileName; + + gs_string String; + + gs_const_string* Identifiers; + u32 IdentifiersCount; + + u32 Line; + + char* LineStart; + char* At; + + gs_memory_arena* Arena; + gs_memory_arena* Transient; + + parser_error* ErrorsRoot; + parser_error* ErrorsHead; +}; + +internal void +Parser_PushErrorF(parser* Parser, char* Format, ...) +{ + parser_error* Error = PushStruct(Parser->Transient, parser_error); + Error->FileName = Parser->FileName; + Error->LineNumber = Parser->Line; + + Error->Message = PushString(Parser->Transient, 1024); + PrintF(&Error->Message, "File: %S Line: %d - ", Error->FileName, Error->LineNumber); + + va_list Args; + va_start(Args, Format); + PrintFArgsList(&Error->Message, Format, Args); + va_end(Args); + + SLLPushOrInit(Parser->ErrorsRoot, Parser->ErrorsHead, Error); +} + +internal gs_const_string +Parser_GetIdent(parser Parser, u32 Index) +{ + gs_const_string Result = Parser.Identifiers[Index]; + return Result; +} + +internal bool +Parser_AtValidPosition(parser Parser) +{ + u64 Offset = Parser.At - Parser.String.Str; + bool Result = (Offset < Parser.String.Length); + return Result; +} + +internal void +Parser_AdvanceChar(parser* P) +{ + if (IsNewline(P->At[0])) + { + P->Line += 1; + P->LineStart = P->At + 1; + } + P->At++; +} + +internal void +Parser_EatWhitespace(parser* P) +{ + while(Parser_AtValidPosition(*P) && IsNewlineOrWhitespace(P->At[0])) + { + Parser_AdvanceChar(P); + } +} + +internal void +Parser_EatToNewLine(parser* P) +{ + while(Parser_AtValidPosition(*P) && !IsNewline(P->At[0])) + { + Parser_AdvanceChar(P); + } + Parser_EatWhitespace(P); +} + +internal bool +Parser_AdvanceIfTokenEquals(parser* P, gs_const_string Value) +{ + bool Result = true; + + char* PAt = P->At; + char* VAt = Value.Str; + while (*VAt != 0) + { + if (*PAt != *VAt) + { + Result = false; + break; + } + PAt += 1; + VAt += 1; + } + + // TODO(Peter): What if the token is a subset of Value? ie. this would return true for + // T->At = hello_world and Value = hello_ + // But the next token we read would fail + + if (Result) + { + P->At = PAt; + Parser_EatWhitespace(P); + } + return Result; +} + +internal bool +Parser_AdvanceIfLineEnd(parser* P) +{ + bool Result = Parser_AdvanceIfTokenEquals(P, ConstString(";")); + return Result; +} + +internal bool +Parser_ReadString(parser* P, gs_const_string String) +{ + // string; + bool Result = Parser_AdvanceIfTokenEquals(P, String); + Result &= Parser_AdvanceIfLineEnd(P); + return Result; +} + +internal bool +Parser_ReadString(parser* P, u32 IdentIndex) +{ + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + return Parser_ReadString(P, Ident); +} + +internal bool +Parser_ReadStringValue(parser* P, gs_const_string Ident, gs_string* Output, bool ShouldNullTerminate = false) +{ + Assert(Output != 0); + + // ident: "value"; + bool Result = false; + if (Parser_AdvanceIfTokenEquals(P, Ident) && + Parser_AdvanceIfTokenEquals(P, ConstString(":")) && + Parser_AdvanceIfTokenEquals(P, ConstString("\""))) + { + gs_const_string FileString = {0}; + FileString.Str = P->At; + + while (Parser_AtValidPosition(*P) && P->At[0] != '"') + { + Parser_AdvanceChar(P); + } + + FileString.Length = P->At - FileString.Str; + if (Parser_AdvanceIfTokenEquals(P, ConstString("\"")) && + Parser_AdvanceIfLineEnd(P)) + { + u32 StringLength = FileString.Length; + if (ShouldNullTerminate) + { + StringLength += 1; + } + + Result = true; + *Output = PushStringF(P->Arena, StringLength, "%S", FileString); + if (ShouldNullTerminate) + { + NullTerminate(Output); + } + } + else + { + Parser_PushErrorF(P, "String doesn't have a closing quote, or line doesn't end with a semicolon"); + } + } + + return Result; +} + +internal bool +Parser_ReadStringValue(parser* P, u32 IdentIndex, gs_string* Result, bool ShouldNullTerminate = false) +{ + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + return Parser_ReadStringValue(P, Ident, Result, ShouldNullTerminate); +} + +internal gs_string +Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminate = false) +{ + gs_string Result = {0}; + Parser_ReadStringValue(P, Ident, &Result, ShouldNullTerminate); + return Result; +} + +internal gs_string +Parser_ReadStringValue(parser* P, u32 IdentIndex, bool ShouldNullTerminate = false) +{ + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + return Parser_ReadStringValue(P, Ident, ShouldNullTerminate); +} + +internal bool +Parser_ReadOpenStruct(parser* P, gs_const_string Ident) +{ + // ident: { + bool Result = Parser_AdvanceIfTokenEquals(P, Ident); + Result &= Parser_AdvanceIfTokenEquals(P, ConstString(":")); + Result &= Parser_AdvanceIfTokenEquals(P, ConstString("{")); + return Result; +} + +internal bool +Parser_ReadOpenStruct(parser* P, u32 IdentIndex) +{ + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + return Parser_ReadOpenStruct(P, Ident); +} + +internal bool +Parser_ReadCloseStruct(parser* P) +{ + // } + bool Result = Parser_AdvanceIfTokenEquals(P, ConstString("}")); + Result &= Parser_AdvanceIfLineEnd(P); + return Result; +} + +internal bool +Parser_ReadNumberString(parser* P, gs_const_string* Output) +{ + Assert(Output != 0); + + bool Success = false; + + if (IsNumericExtended(P->At[0])) + { + char* NumStart = P->At; + while(Parser_AtValidPosition(*P) && IsNumericExtended(P->At[0])) + { + Parser_AdvanceChar(P); + } + + Output->Str = NumStart; + Output->Length = P->At - NumStart; + Success = true; + } + + return Success; +} + +internal gs_const_string +Parser_ReadNumberString(parser* P) +{ + gs_const_string Result = {0}; + Parser_ReadNumberString(P, &Result); + return Result; +} + +internal bool +Parser_ReadU32Value(parser* P, gs_const_string Ident, u32* Result) +{ + // ident: value; + bool Success = false; + + if (Parser_AdvanceIfTokenEquals(P, Ident) && + Parser_AdvanceIfTokenEquals(P, ConstString(":"))) + { + gs_const_string NumStr = Parser_ReadNumberString(P); + if (Parser_AdvanceIfLineEnd(P)) + { + *Result = (u32)ParseInt(NumStr); + Success = true; + } + else + { + Parser_PushErrorF(P, "U32 Value doesn't end with semicolon"); + } + } + + return Success; +} + +internal u32 +Parser_ReadU32Value(parser* P, gs_const_string Ident) +{ + u32 Result = 0; + Parser_ReadU32Value(P, Ident, &Result); + return Result; +} + +internal u32 +Parser_ReadU32Value(parser* P, u32 IdentIndex) +{ + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + return Parser_ReadU32Value(P, Ident); +} + +internal bool +Parser_ReadR32(parser* P, r32* Result) +{ + bool Success = false; + gs_const_string NumStr = {0}; + if (Parser_ReadNumberString(P, &NumStr)) + { + *Result = (r32)ParseFloat(NumStr); + Success = true; + } + return Success; +} + +internal r32 +Parser_ReadR32(parser* P) +{ + r32 Result = 0; + Parser_ReadR32(P, &Result); + return Result; +} + +internal bool +Parser_ReadR32Value(parser* P, gs_const_string Ident, r32* Result) +{ + // ident: value; + bool Success = false; + if (Parser_AdvanceIfTokenEquals(P, Ident) && + Parser_AdvanceIfTokenEquals(P, ConstString(":"))) + { + r32 Value = Parser_ReadR32(P); + if (Parser_AdvanceIfLineEnd(P)) + { + *Result = Value; + Success = true; + } + else + { + Parser_PushErrorF(P, "R32 Value doesn't end with semicolon"); + } + } + + return Success; +} + +internal r32 +Parser_ReadR32Value(parser* P, gs_const_string Ident) +{ + r32 Result = 0; + Parser_ReadR32Value(P, Ident, &Result); + return Result; +} + +internal r32 +Parser_ReadR32Value(parser* P, u32 IdentIndex) +{ + r32 Result = 0; + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + Parser_ReadR32Value(P, Ident, &Result); + return Result; +} + +internal bool +Parser_ReadV3Value(parser* P, gs_const_string Ident, v3* Result) +{ + Assert(Result != 0); + bool Success = false; + if (Parser_AdvanceIfTokenEquals(P, Ident) && + Parser_AdvanceIfTokenEquals(P, ConstString(":")) && + Parser_AdvanceIfTokenEquals(P, ConstString("("))) + { + r32 X = Parser_ReadR32(P); + if (!Parser_AdvanceIfTokenEquals(P, ConstString(","))) + { + Parser_PushErrorF(P, "V3 Value doesn't have comma separated values"); + } + + r32 Y = Parser_ReadR32(P); + if (!Parser_AdvanceIfTokenEquals(P, ConstString(","))) + { + Parser_PushErrorF(P, "V3 Value doesn't have comma separated values"); + } + + r32 Z = Parser_ReadR32(P); + if (Parser_AdvanceIfTokenEquals(P, ConstString(")")) && + Parser_AdvanceIfLineEnd(P)) + { + Result->x = X; + Result->y = Y; + Result->z = Z; + Success = true; + } + else + { + Parser_PushErrorF(P, "V3 Value doesn't end correctly"); + } + } + + return Success; +} + +internal v3 +Parser_ReadV3Value(parser* P, gs_const_string Ident) +{ + v3 Result = {0}; + Parser_ReadV3Value(P, Ident, &Result); + return Result; +} + +internal v3 +Parser_ReadV3Value(parser* P, u32 IdentIndex) +{ + v3 Result = {0}; + gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); + Parser_ReadV3Value(P, Ident, &Result); + return Result; +} + + +#define FOLDHAUS_SERIALIZER_H +#endif // FOLDHAUS_SERIALIZER_H \ No newline at end of file diff --git a/src/app/sacn/sacn.h b/src/app/engine/sacn/foldhaus_sacn.h similarity index 73% rename from src/app/sacn/sacn.h rename to src/app/engine/sacn/foldhaus_sacn.h index 4c4bc59..6004361 100644 --- a/src/app/sacn/sacn.h +++ b/src/app/engine/sacn/foldhaus_sacn.h @@ -12,7 +12,7 @@ #define IP_ADDRESS_BYTES 16 #define STARTCODE_DMX 0 -/* +/* * a description of the address space being used */ #define PREAMBLE_SIZE_ADDR 0 @@ -52,7 +52,7 @@ /* * data definitions */ -#define ACN_IDENTIFIER "ASC-E1.17\0\0\0" +#define ACN_IDENTIFIER "ASC-E1.17\0\0\0" #define ROOT_VECTOR 4 #define FRAMING_VECTOR 2 #define DMP_VECTOR 2 @@ -159,12 +159,12 @@ VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength) return Cursor; } -internal cid -StringToCID_ (const char* String) +internal cid +gs_stringToCID_ (const char* gs_string) { cid Result = {}; - const char* Src = String; + const char* Src = gs_string; u8* Dest = &Result.Bytes[0]; b32 FirstNibble = true; @@ -193,11 +193,11 @@ StringToCID_ (const char* String) Src++; } - return Result; + return Result; } internal void -InitStreamHeader (u8* Buffer, s32 BufferSize, +InitStreamHeader (u8* Buffer, s32 BufferSize, u16 SlotCount, u8 StartCode, u16 Universe, @@ -208,6 +208,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, cid CID ) { + // TODO(pjs): Replace packing with gs_memory_cursor u8* Cursor = Buffer; @@ -215,13 +216,13 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE); Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE); - GSMemCopy(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE); + CopyMemoryTo(ACN_IDENTIFIER, Cursor, ACN_IDENTIFIER_SIZE); Cursor += ACN_IDENTIFIER_SIZE; // TODO(Peter): If you never use this anywhere else, go back and remove the parameters VHD_PackFlags_(Cursor, false, false, false); - Cursor = VHD_PackLength_(Cursor, - STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount, + Cursor = VHD_PackLength_(Cursor, + STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount, false); // root vector @@ -234,8 +235,8 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, } VHD_PackFlags_(Cursor, false, false, false); - Cursor = VHD_PackLength_(Cursor, - STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount, + Cursor = VHD_PackLength_(Cursor, + STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount, false); // framing vector @@ -243,7 +244,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, // framing source name // :Check - GSMemCopy(SourceName, (char*)Cursor, SOURCE_NAME_SIZE); + CopyMemoryTo(SourceName, (char*)Cursor, SOURCE_NAME_SIZE); Cursor[SOURCE_NAME_SIZE - 1] = '\0'; Cursor += SOURCE_NAME_SIZE; @@ -263,7 +264,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, Cursor = PackB2(Cursor, Universe); VHD_PackFlags_(Cursor, false, false, false); - Cursor = VHD_PackLength_(Cursor, + Cursor = VHD_PackLength_(Cursor, STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount, false); @@ -285,6 +286,7 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, Cursor = PackB1(Cursor, StartCode); Assert(Cursor - Buffer == STREAM_HEADER_SIZE); + } // @@ -292,35 +294,34 @@ InitStreamHeader (u8* Buffer, s32 BufferSize, // internal streaming_acn -InitializeSACN ( context Context) +SACN_Initialize (context Context) { streaming_acn SACN = {}; s32 Multicast_TimeToLive = 20; SACN.SendSocket = Context.PlatformGetSocketHandle(Multicast_TimeToLive); - SACN.CID = StringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}"); + SACN.CID = gs_stringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}"); return SACN; } internal void -SACNCleanup(streaming_acn* SACN, context Context) +SACN_Cleanup(streaming_acn* SACN, context Context) { - Context.PlatformCloseSocket(SACN->SendSocket); } internal void -SACNUpdateSequence (streaming_acn* SACN) +SACN_UpdateSequence (streaming_acn* SACN) { // Never use 0 after the first one - if (++SACN->SequenceIterator == 0) + if (++SACN->SequenceIterator == 0) { ++SACN->SequenceIterator; } } internal void -SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN) +SACN_PrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN) { Assert(SizeReservedForHeader == STREAM_HEADER_SIZE); Assert(Buffer && BufferSize > 0); @@ -331,7 +332,7 @@ SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReser } internal u32 -SACNGetUniverseSendAddress(s32 Universe) +SACN_GetUniverseSendAddress(s32 Universe) { u8 MulticastAddressBuffer[4] = {}; MulticastAddressBuffer[0] = 239; @@ -343,6 +344,52 @@ SACNGetUniverseSendAddress(s32 Universe) return V4Address; } +internal void +SACN_FillBufferWithLeds(u8* BufferStart, u32 BufferSize, v2_strip Strip, led_buffer LedBuffer) +{ + u8* DestChannel = BufferStart; + for (u32 i = 0; i < Strip.LedCount; i++) + { + u32 LedIndex = Strip.LedLUT[i]; + pixel Color = LedBuffer.Colors[LedIndex]; + + DestChannel[0] = Color.R; + DestChannel[1] = Color.G; + DestChannel[2] = Color.B; + DestChannel += 3; + } +} + +internal void +SACN_BuildOutputData(streaming_acn* SACN, addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem) +{ + SACN_UpdateSequence(SACN); + + // TODO(pjs): 512 is a magic number - make it a constant? + s32 BufferHeaderSize = STREAM_HEADER_SIZE; + s32 BufferBodySize = 512; + s32 BufferSize = BufferHeaderSize + BufferBodySize; + + for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) + { + assembly Assembly = Assemblies.Values[AssemblyIdx]; + led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex); + + for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++) + { + v2_strip StripAt = Assembly.Strips[StripIdx]; + + u32 V4SendAddress = SACN_GetUniverseSendAddress(StripAt.SACNAddr.StartUniverse); + u32 SendPort = DEFAULT_STREAMING_ACN_PORT; + + addressed_data_buffer* Data = AddressedDataBufferList_Push(Output, BufferSize); + AddressedDataBuffer_SetNetworkAddress(Data, SACN->SendSocket, V4SendAddress, SendPort); + + SACN_PrepareBufferHeader(StripAt.SACNAddr.StartUniverse, Data->Memory, Data->MemorySize, BufferHeaderSize, *SACN); + SACN_FillBufferWithLeds(Data->Memory + BufferHeaderSize, BufferBodySize, StripAt, *LedBuffer); + } + } +} #define SACN_H #endif // SACN_H \ No newline at end of file diff --git a/src/app/engine/uart/foldhaus_uart.cpp b/src/app/engine/uart/foldhaus_uart.cpp new file mode 100644 index 0000000..d523f6d --- /dev/null +++ b/src/app/engine/uart/foldhaus_uart.cpp @@ -0,0 +1,95 @@ +// +// File: foldhaus_uart.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-10 +// +#ifndef FOLDHAUS_UART_CPP + + +internal void +UART_SetChannelBuffer_Create(gs_memory_cursor* WriteCursor, uart_channel ChannelSettings, v2_strip Strip, led_buffer LedBuffer) +{ + // NOTE(pjs): This is just here because the information is duplicated and I want to be sure + // to catch the error where they are different + Assert(ChannelSettings.PixelsCount == Strip.LedCount); + + uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); + UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); + + uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); + *Channel = ChannelSettings; + + for (u32 i = 0; i < Channel->PixelsCount; i++) + { + u32 LedIndex = Strip.LedLUT[i]; + pixel Color = LedBuffer.Colors[LedIndex]; + + u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); + + // TODO(pjs): Use the Output mask + OutputPixel[0] = Color.R; + OutputPixel[1] = Color.G; + OutputPixel[2] = Color.B; + + if (Channel->ElementsCount == 4) + { + // TODO(pjs): Calculate white from the RGB components? + // Generally we just need a good way to handle the white channel, + // both in the renderer and in output + + //OutputPixel[Channel->WhiteIndex] = Color.W; + } + } + + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); +} + +internal void +UART_DrawAll_Create(gs_memory_cursor* WriteCursor) +{ + uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); + UART_FillHeader(Header, 1, UART_DRAW_ALL); + + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); +} + +internal void +UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assemblies, led_system* LedSystem) +{ + uart_channel ChannelSettings = {0}; + ChannelSettings.ElementsCount = 3; + ChannelSettings.ColorPackingOrder = 36; + + // NOTE(pjs): This is the minimum size of every UART message. SetChannelBuffer messages will + // be bigger than this, but their size is based on the number of pixels in each channel + u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); + + for (u32 AssemblyIdx = 0; AssemblyIdx < Assemblies.Count; AssemblyIdx++) + { + assembly Assembly = Assemblies.Values[AssemblyIdx]; + led_buffer* LedBuffer = LedSystemGetBuffer(LedSystem, Assembly.LedBufferIndex); + + u32 TotalBufferSize = MessageBaseSize * Assembly.StripCount; // SetChannelBuffer messages + TotalBufferSize += MessageBaseSize; // DrawAll message + TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel + + addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); + AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString); + gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data); + + for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++) + { + v2_strip StripAt = Assembly.Strips[StripIdx]; + ChannelSettings.PixelsCount = StripAt.LedCount; + UART_SetChannelBuffer_Create(&WriteCursor, ChannelSettings, StripAt, *LedBuffer); + } + + UART_DrawAll_Create(&WriteCursor); + } +} + + +#define FOLDHAUS_UART_CPP +#endif // FOLDHAUS_UART_CPP \ No newline at end of file diff --git a/src/app/engine/uart/foldhaus_uart.h b/src/app/engine/uart/foldhaus_uart.h new file mode 100644 index 0000000..f866efc --- /dev/null +++ b/src/app/engine/uart/foldhaus_uart.h @@ -0,0 +1,86 @@ +// +// File: foldhaus_uart.h +// Author: Peter Slattery +// Creation Date: 2020-10-01 +// +#ifndef FOLDHAUS_UART_H + +enum uart_record_type +{ + UART_SET_CHANNEL_WS2812 = 1, + UART_DRAW_ALL = 2, +}; + +// NOTE(pjs): these are data packet structures and need to have 1 byte packing +#pragma pack(push, 1) + +struct uart_header +{ + s8 MagicNumber[4]; + u8 Channel; + u8 RecordType; +}; + +struct uart_channel +{ + u8 ElementsCount; + u8 ColorPackingOrder; + u16 PixelsCount; +}; + +struct uart_footer +{ + u32 CRC; +}; + +#pragma pack(pop) + +global u32 UART_CRCTable[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +internal void +UART_FillHeader(uart_header* Header, u8 Channel, u8 RecordType) +{ + Header->MagicNumber[0] = 'U'; + Header->MagicNumber[1] = 'P'; + Header->MagicNumber[2] = 'X'; + Header->MagicNumber[3] = 'L'; + + Header->Channel = Channel; + Header->RecordType = RecordType; +} + +internal u32 +UART_CalculateCRC(u8* BufferStart, u8* BufferEnd) +{ + // Calculate the CRC + u32 CRC = 0xFFFFFFFF; + u32 BytesCount = (u8*)BufferEnd - BufferStart; + for (u32 i = 0; i < BytesCount; i++) + { + u8 At = BufferStart[i]; +#if 0 + // Cameron's Version + CRC = UART_CRCTable[(CRC ^ At) & 0x0F] ^ (CRC >> 4); + CRC = UART_CRCTable[(CRC ^ (At >> 4)) & 0x0F] ^ (CRC >> 4); +#else + // https://github.com/simap/pixelblaze_output_expander/blob/master/firmware/Core/Src/uart.c + u32 TableIndex = (CRC ^ At) & 0xFF; + CRC = (UART_CRCTable[TableIndex] ^ (CRC >> 8)) & 0xFFFFFFFF; +#endif + } + + CRC = CRC ^ 0xFFFFFFFF; + return CRC; +} + +internal void +UART_FillFooter(uart_footer* Footer, u8* BufferStart) +{ + Footer->CRC = UART_CalculateCRC(BufferStart, (u8*)Footer); +} + +#define FOLDHAUS_UART_H +#endif // FOLDHAUS_UART_H \ No newline at end of file diff --git a/src/app/first.cpp b/src/app/first.cpp deleted file mode 100644 index 3501ced..0000000 --- a/src/app/first.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include -#include - -typedef struct AppDel { - Class isa; - id window; -} AppDelegate; - -BOOL AppDel_didFinishLaunching(AppDelegate* self, SEL _command, id Notification) -{ - return YES; -} - -int main(int ArgCount, char** Args) -{ - Class NSApplicationClass = (Class)objc_getClass("NSApplication"); - Class AppDelegateClass = objc_allocateClassPair(NSApplicationClass, "AppDelegate", 0); - - SEL MethodSelector = sel_getUid("applicationDidFinishLaunching:"); - // NOTE(Peter): i = int, @ = object, : = method selector (SEL) - char MethodSignature[] = "i@:@"; - class_addMethod(AppDelegateClass, MethodSelector, (IMP)AppDel_didFinishLaunching, "i@:@"); - objc_registerClassPair(AppDelegateClass); - - return 0; -} \ No newline at end of file diff --git a/src/app/foldhaus_app.cpp b/src/app/foldhaus_app.cpp index 90a737a..af0c7ae 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -8,56 +8,6 @@ #include "foldhaus_platform.h" #include "foldhaus_app.h" -internal v4 -MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, rect WindowBounds) -{ - DEBUG_TRACK_SCOPE(MouseToWorldRay); - r32 X = ((2.0f * MouseX) / gs_Width(WindowBounds)) - 1; - r32 Y = ((2.0f * MouseY) / gs_Height(WindowBounds)) - 1; - - v4 ScreenPos = v4{X, Y, -1, 1}; - - m44 InverseProjection = {}; - Inverse(GetCameraPerspectiveProjectionMatrix(*Camera), &InverseProjection); - - m44 InverseModelView = {}; - Inverse(GetCameraModelViewMatrix(*Camera), &InverseModelView); - InverseModelView = Transpose(InverseModelView); - - v4 ClipSpacePos = InverseProjection * ScreenPos; - v4 WorldPosition = InverseModelView * ClipSpacePos; - return WorldPosition; -} - -struct send_sacn_job_data -{ - - platform_socket_handle SendSocket; - platform_send_to* SendTo; - dmx_buffer_list* DMXBuffers; -}; - -internal void -SACNSendDMXBufferListJob (s32 ThreadID, void* JobData) -{ - DEBUG_TRACK_FUNCTION; - - send_sacn_job_data* Data = (send_sacn_job_data*)JobData; - platform_socket_handle SendSocket = Data->SendSocket; - - dmx_buffer_list* DMXBufferAt = Data->DMXBuffers; - while (DMXBufferAt) - { - dmx_buffer Buffer = DMXBufferAt->Buffer; - - u32 V4SendAddress = SACNGetUniverseSendAddress(Buffer.Universe); - - Data->SendTo(SendSocket, V4SendAddress, DEFAULT_STREAMING_ACN_PORT, (const char*)Buffer.Base, Buffer.TotalSize, 0); - - DMXBufferAt = DMXBufferAt->Next; - } -} - //////////////////////////////////////////////////////////////////////// RELOAD_STATIC_DATA(ReloadStaticData) @@ -70,15 +20,14 @@ RELOAD_STATIC_DATA(ReloadStaticData) INITIALIZE_APPLICATION(InitializeApplication) { app_state* State = (app_state*)Context.MemoryBase; - State->Permanent = {}; - State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; - State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; - State->Transient = {}; - State->Transient.FindAddressRule = FindAddress_InLastBufferOnly; - State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; - State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + *State = {}; - State->GlobalLog = PushStruct(&State->Transient, event_log); + State->Permanent = CreateMemoryArena(Context.ThreadContext.Allocator); + State->Transient = Context.ThreadContext.Transient; + + State->Assemblies = AssemblyArray_Create(8, &State->Permanent); + + State->GlobalLog = PushStruct(State->Transient, event_log); *State->GlobalLog = {0}; s32 CommandQueueSize = 32; @@ -87,13 +36,11 @@ INITIALIZE_APPLICATION(InitializeApplication) CommandQueueSize); State->CommandQueue = InitializeCommandQueue(CommandQueueMemory, CommandQueueSize); - State->ActiveTextEntry.Buffer = MakeString(PushArray(&State->Permanent, char, 256), 0, 256); - // TODO(Peter): put in InitializeInterface? r32 FontSize = 14; { - platform_memory_result FontFile = Context.PlatformReadEntireFile("Anonymous Pro.ttf"); - if (!FontFile.Error) + gs_file FontFile = ReadEntireFile(Context.ThreadContext.FileHandler, ConstString("data/Anonymous Pro.ttf")); + if (FileNoError(FontFile)) { bitmap_font* Font = PushStruct(&State->Permanent, bitmap_font); @@ -102,7 +49,7 @@ INITIALIZE_APPLICATION(InitializeApplication) Font->BitmapBytesPerPixel = 4; 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); + ZeroMemoryBlock(Font->BitmapMemory, Font->BitmapStride * Font->BitmapHeight); platform_font_info FontInfo = Context.PlatformGetFontInfo("Anonymous Pro", FontSize, FontWeight_Normal, false, false, false); Font->PixelHeight = FontInfo.PixelHeight; @@ -136,7 +83,7 @@ INITIALIZE_APPLICATION(InitializeApplication) AddCodepointToFont(Font, Codepoint, 0, 0, CodepointW, CodepointH, CodepointX, CodepointY); } - State->Interface.Font = Font; + State->Interface.Style.Font = Font; Font->BitmapTextureHandle = Context.PlatformGetGPUTextureHandle(Font->BitmapMemory, Font->BitmapWidth, Font->BitmapHeight); @@ -147,37 +94,37 @@ INITIALIZE_APPLICATION(InitializeApplication) } } - State->Interface.FontSize = FontSize; - State->Interface.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; - State->Interface.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; - State->Interface.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; - State->Interface.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; - State->Interface.ButtonColor_Inactive = BlackV4; - State->Interface.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; - State->Interface.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; - State->Interface.TextColor = WhiteV4; - State->Interface.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; - State->Interface.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; - State->Interface.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; - State->Interface.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; - State->Interface.Margin = v2{5, 5}; - State->Interface.RowHeight = State->Interface.Font->PixelHeight + 2 * State->Interface.Margin.y; + State->Interface.Style.FontSize = FontSize; + State->Interface.Style.PanelBGColors[0] = v4{.3f, .3f, .3f, 1}; + State->Interface.Style.PanelBGColors[1] = v4{.4f, .4f, .4f, 1}; + State->Interface.Style.PanelBGColors[2] = v4{.5f, .5f, .5f, 1}; + State->Interface.Style.PanelBGColors[3] = v4{.6f, .6f, .6f, 1}; + State->Interface.Style.ButtonColor_Inactive = BlackV4; + State->Interface.Style.ButtonColor_Active = v4{.1f, .1f, .1f, 1}; + State->Interface.Style.ButtonColor_Selected = v4{.1f, .1f, .3f, 1}; + State->Interface.Style.TextColor = WhiteV4; + State->Interface.Style.ListBGColors[0] = v4{ .16f, .16f, .16f, 1.f }; + State->Interface.Style.ListBGColors[1] = v4{ .18f, .18f, .18f, 1.f }; + State->Interface.Style.ListBGHover = v4{ .22f, .22f, .22f, 1.f }; + State->Interface.Style.ListBGSelected = v4{.44f, .44f, .44f, 1.f }; + State->Interface.Style.Margin = v2{5, 5}; + State->Interface.Style.RowHeight = ui_GetTextLineHeight(State->Interface); - State->Interface_.Style = State->Interface; + State->SACN = SACN_Initialize(Context); - State->SACN = InitializeSACN(Context); - State->NetworkProtocolHeaderSize = STREAM_HEADER_SIZE; + State->Camera.FieldOfView = 45.0f; + State->Camera.AspectRatio = RectAspectRatio(State->WindowBounds); + State->Camera.Near = .1f; + State->Camera.Far = 800.0f; + State->Camera.Position = v3{0, 0, 400}; + State->Camera.LookAt = v3{0, 0, 0 + }; - State->Camera.FieldOfView = DegreesToRadians(45.0f); - State->Camera.AspectRatio = gs_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->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); #if 1 - char Path[] = "blumen_lumen.fold"; - LoadAssembly(State, Context, Path); + gs_const_string SculpturePath = ConstString("data/blumen_lumen_silver_spring.fold"); + LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); #endif State->PixelsToWorldScale = .01f; @@ -186,33 +133,37 @@ INITIALIZE_APPLICATION(InitializeApplication) ReloadStaticData(Context, GlobalDebugServices); - // 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; + State->Modes = OperationModeSystemInit(&State->Permanent, Context.ThreadContext); { // Animation PLAYGROUND State->AnimationSystem = {}; + State->AnimationSystem.Storage = &State->Permanent; + State->AnimationSystem.Animations = AnimationArray_Create(State->AnimationSystem.Storage, 32); + State->AnimationSystem.SecondsPerFrame = 1.f / 24.f; - State->AnimationSystem.PlayableRange.Min = 0; - State->AnimationSystem.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); - State->AnimationSystem.LayersMax = 32; - State->AnimationSystem.Layers = PushArray(&State->Permanent, anim_layer, State->AnimationSystem.LayersMax); - AddLayer(MakeStringLiteral("Base Layer"), &State->AnimationSystem, BlendMode_Overwrite); - AddLayer(MakeStringLiteral("Color Layer"), &State->AnimationSystem, BlendMode_Multiply); - AddLayer(MakeStringLiteral("Sparkles"), &State->AnimationSystem, BlendMode_Add); + + animation Anim = {0}; + Anim.Name = PushStringF(&State->Permanent, 256, "test_anim_one"); + Anim.Layers = AnimLayerArray_Create(State->AnimationSystem.Storage, 8); + Anim.Blocks_ = AnimBlockArray_Create(State->AnimationSystem.Storage, 8); + Anim.PlayableRange.Min = 0; + Anim.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Base Layer"), BlendMode_Overwrite, &State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Color Layer"), BlendMode_Multiply, &State->AnimationSystem); + Animation_AddLayer(&Anim, MakeString("Sparkles"), BlendMode_Add, &State->AnimationSystem); + + Animation_AddBlock(&Anim, 22, 123, 2, 0); + + AnimationArray_Push(&State->AnimationSystem.Animations, Anim); } // End Animation Playground - InitializePanelSystem(&State->PanelSystem); - panel* Panel = TakeNewPanel(&State->PanelSystem); - SetPanelDefinition(Panel, PanelType_SculptureView, State); + InitializePanelSystem(&State->PanelSystem, GlobalPanelDefs, GlobalPanelDefsCount); + PanelSystem_PushPanel(&State->PanelSystem, PanelType_SculptureView, State, Context); } internal void -HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_state Mouse) +HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context) { DEBUG_TRACK_FUNCTION; @@ -226,11 +177,12 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_ } else { - panel_and_bounds PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); + panel_with_layout PanelWithMouseOverIt = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, WindowBounds); if (!PanelWithMouseOverIt.Panel) { return; } State->HotPanel = PanelWithMouseOverIt.Panel; - panel_definition PanelDefinition = GlobalPanelDefs[PanelWithMouseOverIt.Panel->PanelDefinitionIndex]; + s32 PanelTypeIndex = PanelWithMouseOverIt.Panel->TypeIndex; + panel_definition PanelDefinition = GlobalPanelDefs[PanelTypeIndex]; if (!PanelDefinition.InputCommands) { return; } ActiveCommands.Commands = PanelDefinition.InputCommands; @@ -264,60 +216,12 @@ HandleInput (app_state* State, rect WindowBounds, input_queue InputQueue, mouse_ for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) { command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; - Entry->Command.Proc(State, Entry->Event, Mouse); + Entry->Command.Proc(State, Entry->Event, Mouse, Context); } ClearCommandQueue(&State->CommandQueue); } -internal dmx_buffer_list* -CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) -{ - DEBUG_TRACK_FUNCTION; - - dmx_buffer_list* Result = 0; - dmx_buffer_list* Head = 0; - - s32 BufferSize = BufferHeaderSize + 512; - - for (u32 Range = 0; Range < Assembly.LEDUniverseMapCount; Range++) - { - leds_in_universe_range LEDUniverseRange = Assembly.LEDUniverseMap[Range]; - - dmx_buffer_list* NewBuffer = PushStruct(Arena, dmx_buffer_list); - NewBuffer->Buffer.Universe = LEDUniverseRange.Universe; - NewBuffer->Buffer.Base = PushArray(Arena, u8, BufferSize); - NewBuffer->Buffer.TotalSize = BufferSize; - NewBuffer->Buffer.HeaderSize = BufferHeaderSize; - NewBuffer->Next = 0; - - // Append - if (!Result) { - Result = NewBuffer; - Head = Result; - } - Head->Next = NewBuffer; - Head = NewBuffer; - - u8* DestChannel = Head->Buffer.Base + BufferHeaderSize; - for (s32 LEDIdx = LEDUniverseRange.RangeStart; - LEDIdx < LEDUniverseRange.RangeOnePastLast; - LEDIdx++) - { - led LED = Assembly.LEDBuffer.LEDs[LEDIdx]; - pixel Color = Assembly.LEDBuffer.Colors[LED.Index]; - - - DestChannel[0] = Color.R; - DestChannel[1] = Color.G; - DestChannel[2] = Color.B; - DestChannel += 3; - } - } - - return Result; -} - UPDATE_AND_RENDER(UpdateAndRender) { DEBUG_TRACK_FUNCTION; @@ -327,19 +231,26 @@ UPDATE_AND_RENDER(UpdateAndRender) // 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); Context->Mouse.CursorType = CursorType_Arrow; - HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse); + PushRenderClearScreen(RenderBuffer); + State->Camera.AspectRatio = RectAspectRatio(Context->WindowBounds); - if (State->AnimationSystem.TimelineShouldAdvance) { - // TODO(Peter): Revisit this. This implies that the framerate of the animation system - // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure - State->AnimationSystem.CurrentFrame += 1; - // Loop back to the beginning - if (State->AnimationSystem.CurrentFrame > State->AnimationSystem.PlayableRange.Max) - { - State->AnimationSystem.CurrentFrame = 0; + HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); + + { + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + if (State->AnimationSystem.TimelineShouldAdvance) { + // TODO(Peter): Revisit this. This implies that the framerate of the animation system + // is tied to the framerate of the simulation. That seems correct to me, but I'm not sure + State->AnimationSystem.CurrentFrame += 1; + + // Loop back to the beginning + if (State->AnimationSystem.CurrentFrame > ActiveAnim->PlayableRange.Max) + { + State->AnimationSystem.CurrentFrame = 0; + } } } @@ -349,163 +260,102 @@ UPDATE_AND_RENDER(UpdateAndRender) State->AnimationSystem.LastUpdatedFrame = CurrentFrame; r32 FrameTime = CurrentFrame * State->AnimationSystem.SecondsPerFrame; - u32 CurrentBlocksMax = State->AnimationSystem.LayersCount; - b8* CurrentBlocksFilled = PushArray(&State->Transient, b8, CurrentBlocksMax); - GSZeroArray(CurrentBlocksFilled, b8, CurrentBlocksMax); - animation_block* CurrentBlocks = PushArray(&State->Transient, animation_block, CurrentBlocksMax); + animation_frame CurrFrame = AnimationSystem_CalculateAnimationFrame(&State->AnimationSystem, State->Transient); - for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) + led_buffer* LayerLEDBuffers = PushArray(State->Transient, led_buffer, CurrFrame.BlocksCountMax); + for (u32 AssemblyIndex = 0; AssemblyIndex < State->Assemblies.Count; AssemblyIndex++) { - gs_list_entry* BlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); - if (EntryIsFree(BlockEntry)) { continue; } - animation_block Block = BlockEntry->Value; - if (CurrentFrame < Block.Range.Min || CurrentFrame > Block.Range.Max) { continue; } - CurrentBlocksFilled[Block.Layer] = true; - CurrentBlocks[Block.Layer] = Block; - } - - assembly_led_buffer* LayerLEDBuffers = PushArray(&State->Transient, assembly_led_buffer, CurrentBlocksMax); - for (u32 AssemblyIndex = 0; AssemblyIndex < State->ActiveAssemblyIndecies.Used; AssemblyIndex++) - { - gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(AssemblyIndex); - assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); + assembly* Assembly = &State->Assemblies.Values[AssemblyIndex]; + led_buffer* AssemblyLedBuffer = LedSystemGetBuffer(&State->LedSystem, Assembly->LedBufferIndex); - arena_snapshot ResetAssemblyMemorySnapshot = TakeSnapshotOfArena(&State->Transient); - - for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++) + for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) { - if (!CurrentBlocksFilled[Layer]) { continue; } - animation_block Block = CurrentBlocks[Layer]; + if (!CurrFrame.BlocksFilled[Layer]) { continue; } + animation_block Block = CurrFrame.Blocks[Layer]; // Prep Temp Buffer - LayerLEDBuffers[Layer] = Assembly->LEDBuffer; - LayerLEDBuffers[Layer].Colors = PushArray(&State->Transient, pixel, Assembly->LEDBuffer.LEDCount); + LayerLEDBuffers[Layer] = *AssemblyLedBuffer; + LayerLEDBuffers[Layer].Colors = PushArray(State->Transient, pixel, AssemblyLedBuffer->LedCount); u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame; - // TODO(Peter): Temporary - switch(Block.AnimationProcHandle) - { - case 1: - { - TestPatternOne(&LayerLEDBuffers[Layer], SecondsIntoBlock); - }break; - - case 2: - { - TestPatternTwo(&LayerLEDBuffers[Layer], SecondsIntoBlock); - }break; - - case 3: - { - TestPatternThree(&LayerLEDBuffers[Layer], SecondsIntoBlock); - }break; - - // NOTE(Peter): Zero is invalid - InvalidDefaultCase; - } + + // :AnimProcHandle + u32 AnimationProcIndex = Block.AnimationProcHandle - 1; + animation_proc* AnimationProc = GlobalAnimationClips[AnimationProcIndex].Proc; + AnimationProc(&LayerLEDBuffers[Layer], *Assembly, SecondsIntoBlock, State->Transient); } // Consolidate Temp Buffers // We do this in reverse order so that they go from top to bottom - for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++) + animation* ActiveAnim = AnimationSystem_GetActiveAnimation(&State->AnimationSystem); + for (u32 Layer = 0; Layer < CurrFrame.BlocksCountMax; Layer++) { - if (!CurrentBlocksFilled[Layer]) { continue; } + if (!CurrFrame.BlocksFilled[Layer]) { continue; } - switch (State->AnimationSystem.Layers[Layer].BlendMode) + switch (ActiveAnim->Layers.Values[Layer].BlendMode) { case BlendMode_Overwrite: { - for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) { - Assembly->LEDBuffer.Colors[LED] = LayerLEDBuffers[Layer].Colors[LED]; + AssemblyLedBuffer->Colors[LED] = LayerLEDBuffers[Layer].Colors[LED]; } }break; case BlendMode_Add: { - for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) { - u32 R = (u32)Assembly->LEDBuffer.Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R; - u32 G = (u32)Assembly->LEDBuffer.Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G; - u32 B = (u32)Assembly->LEDBuffer.Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B; + u32 R = (u32)AssemblyLedBuffer->Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R; + u32 G = (u32)AssemblyLedBuffer->Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G; + u32 B = (u32)AssemblyLedBuffer->Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B; - Assembly->LEDBuffer.Colors[LED].R = (u8)GSMin(R, (u32)255); - Assembly->LEDBuffer.Colors[LED].G = (u8)GSMin(G, (u32)255); - Assembly->LEDBuffer.Colors[LED].B = (u8)GSMin(B, (u32)255); + AssemblyLedBuffer->Colors[LED].R = (u8)Min(R, (u32)255); + AssemblyLedBuffer->Colors[LED].G = (u8)Min(G, (u32)255); + AssemblyLedBuffer->Colors[LED].B = (u8)Min(B, (u32)255); } }break; case BlendMode_Multiply: { - for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + for (u32 LED = 0; LED < AssemblyLedBuffer->LedCount; LED++) { - r32 DR = (r32)Assembly->LEDBuffer.Colors[LED].R / 255.f; - r32 DG = (r32)Assembly->LEDBuffer.Colors[LED].G / 255.f; - r32 DB = (r32)Assembly->LEDBuffer.Colors[LED].B / 255.f; + r32 DR = (r32)AssemblyLedBuffer->Colors[LED].R / 255.f; + r32 DG = (r32)AssemblyLedBuffer->Colors[LED].G / 255.f; + r32 DB = (r32)AssemblyLedBuffer->Colors[LED].B / 255.f; r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f; r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f; r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f; - Assembly->LEDBuffer.Colors[LED].R = (u8)((DR * SR) * 255.f); - Assembly->LEDBuffer.Colors[LED].G = (u8)((DG * SG) * 255.f); - Assembly->LEDBuffer.Colors[LED].B = (u8)((DB * SB) * 255.f); + AssemblyLedBuffer->Colors[LED].R = (u8)((DR * SR) * 255.f); + AssemblyLedBuffer->Colors[LED].G = (u8)((DG * SG) * 255.f); + AssemblyLedBuffer->Colors[LED].B = (u8)((DB * SB) * 255.f); } }break; } } - - ClearArenaToSnapshot(&State->Transient, ResetAssemblyMemorySnapshot); } } - s32 HeaderSize = State->NetworkProtocolHeaderSize; - dmx_buffer_list* DMXBuffers = 0; - for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { - gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); - assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); - dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(*Assembly, HeaderSize, &State->Transient); - DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers); + // NOTE(pjs): Building data buffers to be sent out to the sculpture + // This array is used on the platform side to actually send the information + assembly_array SACNAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaSACN, State->Transient); + assembly_array UARTAssemblies = AssemblyArray_Filter(State->Assemblies, AssemblyFilter_OutputsViaUART, State->Transient); + SACN_BuildOutputData(&State->SACN, OutputData, SACNAssemblies, &State->LedSystem); + UART_BuildOutputData(OutputData, UARTAssemblies, &State->LedSystem); } - //DEBUG_IF(GlobalDebugServices->Interface.SendSACNData) - { - switch (State->NetworkProtocol) - { - case NetworkProtocol_SACN: - { - SACNUpdateSequence(&State->SACN); - - dmx_buffer_list* CurrentDMXBuffer = DMXBuffers; - while (CurrentDMXBuffer) - { - dmx_buffer Buffer = CurrentDMXBuffer->Buffer; - SACNPrepareBufferHeader(Buffer.Universe, Buffer.Base, Buffer.TotalSize, Buffer.HeaderSize, State->SACN); - CurrentDMXBuffer = CurrentDMXBuffer->Next; - } - - send_sacn_job_data* Job = PushStruct(&State->Transient, send_sacn_job_data); - Job->SendSocket = State->SACN.SendSocket; - Job->SendTo = Context->PlatformSendTo; - Job->DMXBuffers = DMXBuffers; - - Context->GeneralWorkQueue->PushWorkOnQueue(Context->GeneralWorkQueue, SACNSendDMXBufferListJob, Job, "SACN Send Data Job"); - }break; - - InvalidDefaultCase; - } - } - - PushRenderOrthographic(RenderBuffer, 0, 0, gs_Width(State->WindowBounds), gs_Height(State->WindowBounds)); + PushRenderOrthographic(RenderBuffer, State->WindowBounds); PushRenderClearScreen(RenderBuffer); State->WindowBounds = Context->WindowBounds; - State->Interface_.RenderBuffer = RenderBuffer; - State->Interface_.Mouse = Context->Mouse; + State->Interface.RenderBuffer = RenderBuffer; + State->Interface.Mouse = Context->Mouse; - panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, &State->Transient); + panel_layout PanelsToRender = GetPanelLayout(&State->PanelSystem, State->WindowBounds, State->Transient); DrawAllPanels(PanelsToRender, RenderBuffer, &Context->Mouse, State, *Context); for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) @@ -513,30 +363,31 @@ UPDATE_AND_RENDER(UpdateAndRender) operation_mode OperationMode = State->Modes.ActiveModes[m]; if (OperationMode.Render != 0) { - OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse); + OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); } } - Context->GeneralWorkQueue->DoQueueWorkUntilDone(Context->GeneralWorkQueue, 0); + Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); Context->GeneralWorkQueue->ResetWorkQueue(Context->GeneralWorkQueue); // Checking for overflows +#if 0 { DEBUG_TRACK_SCOPE(OverflowChecks); AssertAllocationsNoOverflow(State->Permanent); - for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) + for (u32 i = 0; i < State->Assemblies.Count; i++) { - gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); - assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); + assembly* Assembly = &State->Assemblies.Values[i]; AssertAllocationsNoOverflow(Assembly->Arena); } } +#endif } CLEANUP_APPLICATION(CleanupApplication) { app_state* State = (app_state*)Context.MemoryBase; - SACNCleanup(&State->SACN, Context); + SACN_Cleanup(&State->SACN, Context); } #define FOLDHAUS_APP_CPP diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 47f995f..05bd69f 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -8,128 +8,127 @@ #include "../meta/gs_meta_include.h" #include "../meta/gs_meta_lexer.h" +#include "engine/foldhaus_serializer.h" + #include "../gs_libs/gs_font.h" #include "foldhaus_log.h" #include "interface.h" -#include "foldhaus_network_ordering.h" -#include "dmx/dmx.h" -#include "sacn/sacn.h" +#include "engine/foldhaus_network_ordering.h" -#include "foldhaus_assembly.h" +#include "engine/assembly/foldhaus_assembly.h" +#include "engine/assembly/foldhaus_assembly_parser.cpp" -#include "assembly_parser.h" +#include "engine/sacn/foldhaus_sacn.h" +#include "engine/uart/foldhaus_uart.h" +#include "engine/uart/foldhaus_uart.cpp" -#include "foldhaus_node.h" +typedef struct app_state app_state; -// TODO(Peter): TEMPORARY -//u32 NodeSpecificationsCount = 0; -//node_specification* NodeSpecifications = 0; - - -#include "assembly_parser.cpp" -#include "test_patterns.h" +#include "editor/foldhaus_command_dispatch.h" +#include "editor/foldhaus_operation_mode.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" +#include "editor/foldhaus_panel.h" -typedef struct app_state app_state; - -#include "foldhaus_command_dispatch.h" -#include "foldhaus_operation_mode.h" - -#include "animation/foldhaus_animation.h" - -#include "foldhaus_text_entry.h" - -#include "foldhaus_search_lister.h" - -enum network_protocol -{ - NetworkProtocol_SACN, - NetworkProtocol_ArtNet, - - NetworkProtocol_Count, -}; +#include "engine/animation/foldhaus_animation.h" +#include "engine/animation/foldhaus_animation_serializer.cpp" struct app_state { - rect WindowBounds; + gs_memory_arena Permanent; + gs_memory_arena* Transient; - memory_arena Permanent; - memory_arena Transient; - - s32 NetworkProtocolHeaderSize; + // Engine + // network_protocol NetworkProtocol; - streaming_acn SACN; + led_system LedSystem; + assembly_array Assemblies; + animation_system AnimationSystem; + event_log* GlobalLog; - s32 TotalLEDsCount; - gs_list AssemblyList; - gs_list ActiveAssemblyIndecies; - - camera Camera; - r32 PixelsToWorldScale; + // Interface + // + rect2 WindowBounds; operation_mode_system Modes; input_command_queue CommandQueue; - text_entry ActiveTextEntry; - - ui_interface Interface_; - interface_config Interface; - - animation_system AnimationSystem; - gs_list_handle SelectedAnimationBlockHandle; - u32 SelectedAnimationLayer; + ui_interface Interface; panel_system PanelSystem; panel* HotPanel; - pattern_node_workspace NodeWorkspace; - - event_log* GlobalLog; + camera Camera; // TODO(Peter): move into the sculpture view + r32 PixelsToWorldScale; + handle SelectedAnimationBlockHandle; // TODO(Peter): move into animation panel + u32 SelectedAnimationLayer; // TODO(Peter): move into animation panel }; internal void OpenColorPicker(app_state* State, v4* Address); +#include "engine/assembly/foldhaus_assembly.cpp" + // BEGIN TEMPORARY PATTERNS internal void -TestPatternOne(assembly_led_buffer* Assembly, r32 Time) +TestPatternOne(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) { - for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) + led_strip_list BlumenStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Blumen Lumen"), Transient); + led_strip_list RadiaStrips = AssemblyStripsGetWithTagValue(Assembly, ConstString("assembly"), ConstString("Radialumia"), Transient); + + for (u32 i = 0; i < BlumenStrips.Count; i++) { - led LED = Assembly->LEDs[LEDIdx]; - if (LED.Position.x < 0) + u32 StripIndex = BlumenStrips.StripIndices[i]; + v2_strip StripAt = Assembly.Strips[StripIndex]; + + for (u32 j = 0; j < StripAt.LedCount; j++) { - Assembly->Colors[LED.Index].R = 255; - Assembly->Colors[LED.Index].B = 255; - Assembly->Colors[LED.Index].G = 255; - } - else - { - Assembly->Colors[LED.Index].R = 0; - Assembly->Colors[LED.Index].B = 0; - Assembly->Colors[LED.Index].G = 0; + u32 LedIndex = StripAt.LedLUT[j]; + Leds->Colors[LedIndex] = { 255, 0, 0 }; + } } + + for (u32 i = 0; i < RadiaStrips.Count; i++) + { + u32 StripIndex = RadiaStrips.StripIndices[i]; + v2_strip StripAt = Assembly.Strips[StripIndex]; + + for (u32 j = 0; j < StripAt.LedCount; j++) + { + u32 LedIndex = StripAt.LedLUT[j]; + Leds->Colors[LedIndex] = { 0, 255, 0 }; + } + } +#if 0 + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) + { + v4 LedPosition = Leds->Positions[LedIndex]; + float PercentX = RemapClampedR32(LedPosition.x, -150.0f, 150.0f, 0.0f, 1.0f); + float PercentY = RemapClampedR32(LedPosition.y, -150.0f, 150.0f, 0.0f, 1.0f); + Leds->Colors[LedIndex].R = (u8)(PercentX * 255); + Leds->Colors[LedIndex].G = (u8)(PercentY * 255); + } +#endif + } internal void -TestPatternTwo(assembly_led_buffer* Assembly, r32 Time) +TestPatternTwo(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) { - r32 PeriodicTime = (Time / PI) * 2; + r32 PeriodicTime = (Time / PiR32) * 2; - r32 ZeroOneSin = (GSSin(PeriodicTime) * .5f) + .5f; - r32 ZeroOneCos = (GSCos(PeriodicTime) * .5f) + .5f; + r32 ZeroOneSin = (SinR32(PeriodicTime) * .5f) + .5f; + r32 ZeroOneCos = (CosR32(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 Normal = v4{CosR32(ThetaZ), 0, SinR32(ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 + v4 Right = V4Cross(Normal, v4{0, 1, 0, 0}); v4 FrontCenter = Center + (Normal * 25); v4 BackCenter = Center - (Normal * 25); @@ -137,127 +136,100 @@ TestPatternTwo(assembly_led_buffer* Assembly, r32 Time) r32 OuterRadiusSquared = 1000000; r32 InnerRadiusSquared = 0; - for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { - led LED = Assembly->LEDs[LEDIdx]; - - v4 Position = LED.Position; + v4 Position = Leds->Positions[LedIndex]; v4 ToFront = Position + FrontCenter; v4 ToBack = Position + BackCenter; - r32 ToFrontDotNormal = Dot(ToFront, Normal); - r32 ToBackDotNormal = Dot(ToBack, Normal); + r32 ToFrontDotNormal = V4Dot(ToFront, Normal); + r32 ToBackDotNormal = V4Dot(ToBack, Normal); - ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000); - ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000); + ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000); + ToBackDotNormal = Clamp01(ToBackDotNormal * 1000); - r32 SqDistToCenter = MagSqr(Position); + r32 SqDistToCenter = V4MagSquared(Position); if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) { if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) { - Assembly->Colors[LED.Index] = Color; + Leds->Colors[LedIndex] = Color; } else { - //Assembly->Colors[LED.Index] = {}; + //Leds->Colors[LedIndex] = {}; } } else { - //Assembly->Colors[LED.Index] = {}; + //Leds->Colors[LedIndex] = {}; } } } internal void -TestPatternThree(assembly_led_buffer* Assembly, r32 Time) +TestPatternThree(led_buffer* Leds, assembly Assembly, r32 Time, gs_memory_arena* Transient) { v4 GreenCenter = v4{0, 0, 150, 1}; - r32 GreenRadius = GSAbs(GSSin(Time)) * 200; + r32 GreenRadius = Abs(SinR32(Time)) * 200; v4 TealCenter = v4{0, 0, 150, 1}; - r32 TealRadius = GSAbs(GSSin(Time + 1.5)) * 200; + r32 TealRadius = Abs(SinR32(Time + 1.5)) * 200; r32 FadeDist = 35; - for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) + for (u32 LedIndex = 0; LedIndex < Leds->LedCount; LedIndex++) { - led LED = Assembly->LEDs[LEDIdx]; + v4 LedPosition = Leds->Positions[LedIndex]; u8 Red = 0; u8 Green = 0; u8 Blue = 0; - r32 GreenDist = GSAbs(Mag(LED.Position - GreenCenter) - GreenRadius); - r32 GreenBrightness = GSClamp(0.f, FadeDist - GSAbs(GreenDist), FadeDist); + r32 GreenDist = Abs(V4Mag(LedPosition - GreenCenter) - GreenRadius); + r32 GreenBrightness = Clamp(0.f, FadeDist - Abs(GreenDist), FadeDist); Green = (u8)(GreenBrightness * 255); - r32 TealDist = GSAbs(Mag(LED.Position - TealCenter) - TealRadius); - r32 TealBrightness = GSClamp(0.f, FadeDist - GSAbs(TealDist), FadeDist); + r32 TealDist = Abs(V4Mag(LedPosition - TealCenter) - TealRadius); + r32 TealBrightness = Clamp(0.f, FadeDist - Abs(TealDist), FadeDist); Red = (u8)(TealBrightness * 255); Blue = (u8)(TealBrightness * 255); - Assembly->Colors[LED.Index].R = Red; - Assembly->Colors[LED.Index].B = Green; - Assembly->Colors[LED.Index].G = Green; + Leds->Colors[LedIndex].R = Red; + Leds->Colors[LedIndex].B = Green; + Leds->Colors[LedIndex].G = Green; } } // END TEMPORARY PATTERNS -#include "foldhaus_assembly.cpp" - -#include "foldhaus_text_entry.cpp" -#include "foldhaus_search_lister.cpp" - -#include "foldhaus_default_nodes.h" - -#include "./generated/gs_meta_generated_typeinfo.h" -#include "generated/foldhaus_nodes_generated.h" - - -#include "foldhaus_node.cpp" - FOLDHAUS_INPUT_COMMAND_PROC(EndCurrentOperationMode) { DeactivateCurrentOperationMode(&State->Modes); } -#define PANEL_INIT_PROC(name) void name(panel* Panel, app_state* State) -typedef PANEL_INIT_PROC(panel_init_proc); - -#define PANEL_CLEANUP_PROC(name) void name(panel* Panel, app_state* State) -typedef PANEL_CLEANUP_PROC(panel_cleanup_proc); - -// TODO(Peter): Should be able to take the mouse out of this -#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); - -// NOTE(Peter): This is used by the meta system to generate panel type info -struct panel_definition -{ - char* PanelName; - s32 PanelNameLength; - panel_init_proc* Init; - panel_cleanup_proc* Cleanup; - panel_render_proc* Render; - input_command* InputCommands; - s32 InputCommandsCount; +s32 GlobalAnimationClipsCount = 3; +animation_clip GlobalAnimationClips[] = { + { "Test Pattern One", 16, TestPatternOne }, + { "Test Pattern Two", 16, TestPatternTwo }, + { "Test Pattern Three", 18, TestPatternThree }, }; -#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 "panels/foldhaus_panel_node_graph.h" -#include "panels/foldhaus_panel_file_view.h" +#include "editor/panels/foldhaus_panel_types.h" -#include "generated/foldhaus_panels_generated.h" +#include "editor/panels/foldhaus_panel_file_view.h" +#include "editor/panels/foldhaus_panel_sculpture_view.h" +#include "editor/panels/foldhaus_panel_profiler.h" +#include "editor/panels/foldhaus_panel_dmx_view.h" +#include "editor/panels/foldhaus_panel_animation_timeline.h" +#include "editor/panels/foldhaus_panel_hierarchy.h" -#include "foldhaus_interface.cpp" + +#include "editor/panels/foldhaus_panel_types.cpp" +//#include "generated/foldhaus_panels_generated.h" + +#include "editor/foldhaus_interface.cpp" #include "../meta/gs_meta_include.cpp" diff --git a/src/app/foldhaus_assembly.cpp b/src/app/foldhaus_assembly.cpp deleted file mode 100644 index 0e17226..0000000 --- a/src/app/foldhaus_assembly.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// -// File: foldhaus_assembly.cpp -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_ASSEMBLY_CPP - -internal assembly -ConstructAssemblyFromDefinition (assembly_definition Definition, - string AssemblyName, - v4 RootPosition, - r32 Scale, - memory_arena Arena) -{ - assembly Assembly = {}; - Assembly.Arena = Arena; - - Assembly.Name = MakeString(PushArray(&Assembly.Arena, char, AssemblyName.Length), AssemblyName.Length); - CopyStringTo(AssemblyName, &Assembly.Name); - - // NOTE(Peter): Setting this to zero so we can check at the end of the loop that creates leds - // and make sure we created to correct number. By the time this function returns it should be - // the case that: (Assembly.LEDCount == Definition.TotalLEDCount) - Assembly.LEDBuffer.LEDCount = 0; - Assembly.LEDBuffer.Colors = PushArray(&Assembly.Arena, pixel, Definition.TotalLEDCount); - Assembly.LEDBuffer.LEDs = PushArray(&Assembly.Arena, led, Definition.TotalLEDCount); - Assembly.LEDUniverseMapCount = Definition.LEDStripCount; - Assembly.LEDUniverseMap = PushArray(&Assembly.Arena, leds_in_universe_range, Definition.LEDStripCount); - - // Add LEDs - for (u32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++) - { - led_strip_definition StripDef = Definition.LEDStrips[StripIdx]; - - leds_in_universe_range* LEDUniverseRange = Assembly.LEDUniverseMap + StripIdx; - LEDUniverseRange->Universe = StripDef.StartUniverse; - LEDUniverseRange->RangeStart = Assembly.LEDBuffer.LEDCount; - LEDUniverseRange->RangeOnePastLast = Assembly.LEDBuffer.LEDCount + StripDef.LEDsPerStrip; - - // NOTE(Peter): this should be a switch on the type, but we only have one for - // now. The assert is to remind you to create more cases when necessary - Assert(StripDef.InterpolationType == StripInterpolate_Points); - - v4 WS_StripStart = RootPosition + V4(StripDef.InterpolatePositionStart * Scale, 1); - v4 WS_StripEnd = RootPosition + V4(StripDef.InterpolatePositionEnd * Scale, 1); - s32 LEDsInStripCount = StripDef.LEDsPerStrip; - - Assert(Assembly.LEDBuffer.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount); - - v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)LEDsInStripCount; - for (s32 Step = 0; Step < LEDsInStripCount; Step++) - { - s32 LEDIndex = Assembly.LEDBuffer.LEDCount++; - Assembly.LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step); - Assembly.LEDBuffer.LEDs[LEDIndex].Index = LEDIndex; - } - } - - // NOTE(Peter): Did we create the correct number of LEDs? - Assert(Assembly.LEDBuffer.LEDCount == Definition.TotalLEDCount); - return Assembly; -} - -// NOTE(Peter): These are here so that if we load 2+ sculptures, they don't all -// end up on top of one another. Purely aesthetic. Can remove once we implement -// scene editing tools -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 AssemblyFile = Context.PlatformReadEntireFile(Path); - if (AssemblyFile.Error == PlatformMemory_NoError) - { - assembly_definition AssemblyDefinition = ParseAssemblyFile(AssemblyFile.Base, AssemblyFile.Size, &State->Transient, State->GlobalLog); - - string PathString = MakeStringLiteral(Path); - s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(PathString.Memory, PathString.Length, '\\'); - string FileName = Substring(PathString, IndexOfLastSlash + 1); - - memory_arena AssemblyArena = {}; - AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; - AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; - - v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount]; - r32 Scale = 100; - assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, Offset, Scale, AssemblyArena); - gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly); - - State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle); - State->TotalLEDsCount += NewAssembly.LEDBuffer.LEDCount; - - Context.PlatformFree(AssemblyFile.Base, AssemblyFile.Size); - } - else - { - LogError(State->GlobalLog, "Unable to load assembly file"); - } -} - -internal void -UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context) -{ - assembly* Assembly = State->AssemblyList.GetElementAtIndex(AssemblyIndex); - State->TotalLEDsCount -= Assembly->LEDBuffer.LEDCount; - FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree); - - State->AssemblyList.FreeElementAtIndex(AssemblyIndex); - for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) - { - gs_list_handle Handle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); - if (Handle.Index == AssemblyIndex) - { - State->ActiveAssemblyIndecies.FreeElementAtIndex(i); - break; - } - } -} - - -#define FOLDHAUS_ASSEMBLY_CPP -#endif // FOLDHAUS_ASSEMBLY_CPP \ No newline at end of file diff --git a/src/app/foldhaus_assembly.h b/src/app/foldhaus_assembly.h deleted file mode 100644 index 5852583..0000000 --- a/src/app/foldhaus_assembly.h +++ /dev/null @@ -1,64 +0,0 @@ -// -// File: foldhaus_assembly.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_ASSEMBLY_H - -struct led -{ - s32 Index; - v4 Position; -}; - -union pixel -{ - struct - { - u8 R; - u8 G; - u8 B; - }; - u8 Channels[3]; -}; - -// NOTE(Peter): This structure is so we can keep track of -// what LEDs output to which DMX universe. You don't need -// to use it anywhere else, as all the data for patterns, -// colors, and groups is/will be stored elsewhere. -struct leds_in_universe_range -{ - s32 RangeStart; - s32 RangeOnePastLast; - s32 Universe; -}; - -struct assembly_led_buffer -{ - u32 LEDCount; - pixel* Colors; - led* LEDs; -}; - -struct assembly -{ - memory_arena Arena; - - string Name; - string FilePath; - - assembly_led_buffer LEDBuffer; - -#if 0 - u32 LEDCount; - pixel* Colors; - led* LEDs; -#endif - - u32 LEDUniverseMapCount; - leds_in_universe_range* LEDUniverseMap; -}; - - -#define FOLDHAUS_ASSEMBLY_H -#endif // FOLDHAUS_ASSEMBLY_H \ No newline at end of file diff --git a/src/app/foldhaus_debug.h b/src/app/foldhaus_debug.h index c987469..ca26188 100644 --- a/src/app/foldhaus_debug.h +++ b/src/app/foldhaus_debug.h @@ -3,6 +3,9 @@ // Author: Peter Slattery // Creation Date: 2020-01-01 // +// DESCRIPTION: +// This file contains profiling capabilities for both the engine and app +// #ifndef FOLDHAUS_DEBUG_H #define SCOPE_NAME_LENGTH 256 @@ -30,7 +33,7 @@ struct collated_scope_record struct scope_name { u32 Hash; - string Name; + gs_string Name; char Buffer[SCOPE_NAME_BUFFER_LENGTH]; }; @@ -82,7 +85,7 @@ typedef u8* debug_realloc(u8* Memory, s32 OldSize, s32 NewSize); struct debug_histogram_entry { char ScopeName_[SCOPE_NAME_LENGTH]; - string ScopeName; + gs_string ScopeName; u32 PerFrame_Cycles[HISTOGRAM_DEPTH]; u32 PerFrame_CallCount[HISTOGRAM_DEPTH]; @@ -168,12 +171,12 @@ StartDebugFrame(debug_frame* Frame, debug_services* Services) } internal void -InitDebugServices (debug_services* Services, - s64 PerformanceCountFrequency, - debug_alloc* Alloc, - debug_realloc* Realloc, - debug_timing_proc* GetWallClock, - debug_get_thread_id* GetThreadId, +InitDebugServices (debug_services* Services, + s64 PerformanceCountFrequency, + debug_alloc* Alloc, + debug_realloc* Realloc, + debug_timing_proc* GetWallClock, + debug_get_thread_id* GetThreadId, s32 ThreadCount) { Services->Alloc = Alloc; @@ -233,7 +236,7 @@ GetIndexForNameHash(debug_frame* Frame, u32 NameHash) } // NOTE(Peter): Its not technically wrong to return a -1 here, just means we didn't find it. - // At the time of writing however, this function is only being called in contexts where we + // At the time of writing however, this function is only being called in contexts where we // know there should be an entry in the Name table, so a -1 actually indicates a problem. Assert(Result >= 0); return Result; @@ -359,9 +362,9 @@ BeginTrackingScopeAndGetNameHash (debug_services* Services, char* ScopeName) if (Entry->Hash == 0) // If its new { Entry->Hash = NameHash; - // TODO(Peter): need to initialize all entry name strings to point at the buffer + // TODO(Peter): need to initialize all entry name gs_strings to point at the buffer // This will break eventually. when it does, do this ^^^^ when on startup - CopyCharArrayToString(ScopeName, &Entry->Name); + PrintF(&Entry->Name, "%s", ScopeName); } return NameHash; @@ -402,7 +405,7 @@ internal r32 DEBUGGetSecondsElapsed (s64 Start, s64 End, r32 PerformanceCountFre #define DEBUG_TRACK_FUNCTION scope_tracker ScopeTracker ((char*)__func__, GlobalDebugServices) #define DEBUG_TRACK_SCOPE(name) scope_tracker ScopeTracker_##name (#name, GlobalDebugServices) #else -#define DEBUG_TRACK_FUNCTION +#define DEBUG_TRACK_FUNCTION #define DEBUG_TRACK_SCOPE(name) #endif struct scope_tracker diff --git a/src/app/foldhaus_debug_visuals.h b/src/app/foldhaus_debug_visuals.h deleted file mode 100644 index 3158e78..0000000 --- a/src/app/foldhaus_debug_visuals.h +++ /dev/null @@ -1,126 +0,0 @@ -// -// File: foldhaus_debug_visuals.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_DEBUG_VISUALS_H - -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) -{ - DEBUG_TRACK_SCOPE(DrawDebugInterface); - - v2 TopOfDebugView = v2{StartX, WindowHeight - (NewLineYOffset(*Interface.Font) + 5)}; - v2 TopOfScreenLinePos = TopOfDebugView; - - string DebugString = InitializeEmptyString(PushArray(Transient, char, 256), 256); - - if (GlobalDebugServices->Interface.ShowCameraMouse) - { - PushRenderQuad2D(RenderBuffer, - v2{TopOfDebugView.x, TopOfDebugView.y - 500}, - v2{TopOfDebugView.x + 700, TopOfDebugView.y}, - v4{0, 0, 0, .8f}); - } - - r32 FramesPerSecond = 1.0f / DeltaTime; - - 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.TotalUsed, - State->Modes.Arena.TotalSize, - State->CommandQueue.Used); - DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, WhiteV4); - - v2 ButtonDim = v2{200, (r32)NewLineYOffset(*Interface.Font) + 10}; - TopOfScreenLinePos.y -= ButtonDim.y + 10; - v2 ButtonPos = TopOfScreenLinePos; - button_result CameraBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - MakeStringLiteral("Camera"), Interface, Mouse); - - ButtonPos.x += ButtonDim.x + 10; - button_result ScopeTimeBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - MakeStringLiteral("Scope Time"), Interface, Mouse); - ButtonPos.x += ButtonDim.x + 10; - button_result RenderSculptureBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - MakeStringLiteral("Visualize"), Interface, Mouse); - - ButtonPos.x += ButtonDim.x + 10; - - string SACNButtonString; - if (GlobalDebugServices->Interface.SendSACNData) - { - SACNButtonString = MakeStringLiteral("Turn SACN Off"); - } - else - { - SACNButtonString = MakeStringLiteral("Turn SACN On"); - } - - button_result SendSACNDataBtn = EvaluateButton(RenderBuffer, ButtonPos, ButtonPos + ButtonDim, - SACNButtonString, Interface, Mouse); - - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font) + 10; - - if (CameraBtn.Pressed) - { - GlobalDebugServices->Interface.ShowCameraMouse = !GlobalDebugServices->Interface.ShowCameraMouse; - } - - if (ScopeTimeBtn.Pressed) - { - GlobalDebugServices->Interface.ShowTrackedScopes = !GlobalDebugServices->Interface.ShowTrackedScopes; - } - - if (RenderSculptureBtn.Pressed) - { - GlobalDebugServices->Interface.RenderSculpture = - !GlobalDebugServices->Interface.RenderSculpture; - } - - if (SendSACNDataBtn.Pressed) - { - GlobalDebugServices->Interface.SendSACNData = !GlobalDebugServices->Interface.SendSACNData; - } - - if (GlobalDebugServices->Interface.ShowCameraMouse) - { - PrintF(&DebugString, "Camera x=%.*f y=%.*f z=%.*f LookAt x=%.*f y=%.*f z=%.*f", - 3, Camera.Position.x, - 3, Camera.Position.y, - 3, Camera.Position.z, - 3, Camera.LookAt.x, - 3, Camera.LookAt.y, - 3, Camera.LookAt.z); - DrawString(RenderBuffer, DebugString, Interface.Font, TopOfScreenLinePos, v4{1.0f, 1.0f, 1.0f, 1.0f}); - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - - b32 LeftButtonIsDown = (Mouse.LeftButtonState & KeyState_IsDown) > 0; - b32 LeftButtonWasDown = (Mouse.LeftButtonState & KeyState_WasDown) > 0; - - s32 MousePrecision = 0; - PrintF(&DebugString, "Mouse Pos: (%.*f, %.*f) Down: (%.*f, %.*f) State: %s %s", - MousePrecision, Mouse.Pos.x, - MousePrecision, Mouse.Pos.y, - MousePrecision, Mouse.DownPos.x, - MousePrecision, Mouse.DownPos.y, - (LeftButtonIsDown ? "Is Down" : "Is Not Down"), - (LeftButtonWasDown ? "Was Down" : "Was Not Down")); - 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); - DrawString(RenderBuffer, DebugString, Interface.Font, - TopOfScreenLinePos, WhiteV4); - TopOfScreenLinePos.y -= NewLineYOffset(*Interface.Font); - } -} - - -#define FOLDHAUS_DEBUG_VISUALS_H -#endif // FOLDHAUS_DEBUG_VISUALS_H \ No newline at end of file diff --git a/src/app/foldhaus_log.h b/src/app/foldhaus_log.h index 12ed933..5d1c936 100644 --- a/src/app/foldhaus_log.h +++ b/src/app/foldhaus_log.h @@ -13,7 +13,7 @@ enum log_entry_type struct log_entry { - string Message; + gs_string Message; log_entry_type Type; }; @@ -25,11 +25,11 @@ struct event_log u32 NextEntry; }; -#define LogMessage(_Log, _Message) PushLogEntry(_Log, MakeStringLiteral(_Message), LogEntry_Message) -#define LogError(_Log, _Message) PushLogEntry(_Log, MakeStringLiteral(_Message), LogEntry_Error) +#define LogMessage(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Message) +#define LogError(_Log, _Message) PushLogEntry(_Log, MakeString(_Message), LogEntry_Error) internal void -PushLogEntry(event_log* Log, string Message, log_entry_type Type) +PushLogEntry(event_log* Log, gs_string Message, log_entry_type Type) { u32 NewLogIndex = Log->NextEntry++; if (Log->NextEntry >= LOG_ENTRIES_MAX) @@ -44,5 +44,6 @@ PushLogEntry(event_log* Log, string Message, log_entry_type Type) + #define FOLDHAUS_LOG_H #endif // FOLDHAUS_LOG_H \ No newline at end of file diff --git a/src/app/foldhaus_operation_mode.h b/src/app/foldhaus_operation_mode.h deleted file mode 100644 index 49d71bd..0000000 --- a/src/app/foldhaus_operation_mode.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// File: foldhaus_operation_mode.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_OPERATION_MODE_H - -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); - -struct operation_mode -{ - input_command_registry Commands; - operation_render_proc* Render; - u8* OpStateMemory; -}; - -#define OPERATION_MODES_MAX 32 -struct operation_mode_system -{ - s32 ActiveModesCount; - operation_mode ActiveModes[OPERATION_MODES_MAX]; - arena_snapshot ModeMemorySnapshots[OPERATION_MODES_MAX]; - - // NOTE(Peter): This acts as mode scoped memory. When a mode gets activated, it can allocate - // temporary memory which then gets freed when the mode is deactivated - memory_arena Arena; -}; - -internal operation_mode* -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); - - operation_mode NewMode = {}; - System->ActiveModes[ModeIndex] = NewMode; - - Result = &System->ActiveModes[ModeIndex]; - Result->Render = RenderProc; - return Result; -} - -#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, operation_render_proc* RenderProc) -{ - operation_mode* NewMode = ActivateOperationMode(System, RenderProc); - - InitializeInputCommandRegistry(&NewMode->Commands, CommandsCount, &System->Arena); - for (s32 i = 0; i < CommandsCount; i++) - { - input_command Command = Commands[i]; - RegisterKeyPressCommand(&NewMode->Commands, Command.Key, Command.Flags, Command.Mdfr, Command.Proc); - } - - return NewMode; -} - -internal void -DeactivateCurrentOperationMode (operation_mode_system* System) -{ - Assert(System->ActiveModesCount > 0); - s32 ModeIndex = --System->ActiveModesCount; - ClearArenaToSnapshot(&System->Arena, System->ModeMemorySnapshots[ModeIndex]); -} - -#define CreateOperationState(mode, modeSystem, stateType) \ -(stateType*)CreateOperationState_(mode, modeSystem, sizeof(stateType)) - -#define GetCurrentOperationState(modeSystem, stateType) \ -(stateType*)(modeSystem).ActiveModes[(modeSystem).ActiveModesCount - 1].OpStateMemory; - - -internal u8* -CreateOperationState_ (operation_mode* Mode, operation_mode_system* System, s32 StateSize) -{ - Mode->OpStateMemory = PushSize(&System->Arena, StateSize); - return Mode->OpStateMemory; -} - - -#define FOLDHAUS_OPERATION_MODE_H -#endif // FOLDHAUS_OPERATION_MODE_H \ No newline at end of file diff --git a/src/app/foldhaus_panel.h b/src/app/foldhaus_panel.h deleted file mode 100644 index 27f290a..0000000 --- a/src/app/foldhaus_panel.h +++ /dev/null @@ -1,356 +0,0 @@ -// -// File: foldhaus_panel.h -// Author: Peter Slattery -// Creation Date: 2019-12-26 -// -// Usage: -// Include this file in ONE file in your project. -// Define SetPanelDefinitionExternal -// -#ifndef FOLDHAUS_PANEL_H - -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; - - u8* PanelStateMemory; - u32 PanelStateMemorySize; - - 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; -}; - -///////////////////////////////// -// -// 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); -} - -///////////////////////////////// -// -// 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; -} - - -#define FOLDHAUS_PANEL_H -#endif // FOLDHAUS_PANEL_H \ No newline at end of file diff --git a/src/app/foldhaus_platform.h b/src/app/foldhaus_platform.h index 2ee07cf..96c8685 100644 --- a/src/app/foldhaus_platform.h +++ b/src/app/foldhaus_platform.h @@ -7,25 +7,44 @@ #include -#define GS_LANGUAGE_NO_PROFILER_DEFINES -#include "..\gs_libs\gs_language.h" +#include // TODO Remove -#include "..\gs_libs\gs_radix_sort.h" -#include "..\gs_libs\gs_list.h" -#include "..\gs_libs\gs_bucket.h" +#include "..\gs_libs\gs_types.h" +#include "..\gs_libs\gs_types.cpp" -#define GS_MEMORY_TRACK_ALLOCATIONS -#include "..\gs_libs\gs_memory_arena.h" +struct handle +{ + u32 Generation; + u32 Index; +}; + +inline bool +Handle_IsValid(handle Handle) +{ + bool Result = (Handle.Generation != 0); + return Result; +} #include "..\gs_libs\gs_string.h" #include "foldhaus_debug.h" -global_variable debug_services* GlobalDebugServices; +global debug_services* GlobalDebugServices; -#include "..\gs_libs\gs_vector_matrix.h" +//#include "..\gs_libs\gs_vector_matrix.h" #include "..\gs_libs\gs_input.h" +struct platform_network_address +{ + s32 Family; + u16 Port; + u32 Address; +}; + +typedef s32 platform_socket_handle; +typedef s32 platform_network_address_handle; + #include "foldhaus_renderer.h" +#include "engine/foldhaus_addressed_data.h" typedef struct context context; @@ -34,7 +53,7 @@ typedef struct context context; #define INITIALIZE_APPLICATION(name) void name(context Context) typedef INITIALIZE_APPLICATION(initialize_application); -#define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer) +#define UPDATE_AND_RENDER(name) void name(context* Context, input_queue InputQueue, render_command_buffer* RenderBuffer, addressed_data_buffer_list* OutputData) typedef UPDATE_AND_RENDER(update_and_render); #define RELOAD_STATIC_DATA(name) void name(context Context, debug_services* DebugServices) @@ -63,13 +82,25 @@ enum platform_memory_error PlatformMemory_UnknownError, // You should implement handling this when you see it }; -struct platform_memory_result +struct data { u8* Base; - s32 Size; + u64 Size; +}; + +struct platform_memory_result +{ + data Data; platform_memory_error Error; }; +struct system_path +{ + char* Path; + s32 PathLength; + s32 IndexOfLastSlash; +}; + struct texture_buffer { u8* Memory; @@ -79,68 +110,12 @@ struct texture_buffer s32 BytesPerPixel; }; -struct system_path -{ - char* Path; - s32 PathLength; - s32 IndexOfLastSlash; -}; - -#define PLATFORM_ALLOC(name) u8* name(s32 Size) -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); - -#define PLATFORM_WRITE_ENTIRE_FILE(name) b32 name(char* Path, u8* Contents, s32 Size) -typedef PLATFORM_WRITE_ENTIRE_FILE(platform_write_entire_file); - -#define PLATFORM_GET_FILE_PATH(name) b32 name(char* PathBuffer, s32 BufferLength, const char* FilterStrings) -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; - -#define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive) +#define PLATFORM_GET_SOCKET_HANDLE(name) platform_socket_handle name(s32 Multicast_TimeToLive) typedef PLATFORM_GET_SOCKET_HANDLE(platform_get_socket_handle); -#define PLATFORM_GET_SEND_ADDRESS_HANDLE(name) platform_network_address_handle name(s32 AddressFamily, u16 Port, u32 Address) -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, u32 Address, u32 Port, 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) -typedef PLATFORM_CLOSE_SOCKET(platform_close_socket); - -// File IO - -// TODO(Peter): -struct directory_listing -{ - string Path; - directory_listing* Next; -}; - // Font struct platform_font_info { @@ -175,50 +150,11 @@ typedef DRAW_FONT_CODEPOINT(platform_draw_font_codepoint); #define PLATFORM_THREAD_COUNT 4 -#define THREADED_WORK_PROC(name) void name(s32 ThreadID, void* Data) -typedef THREADED_WORK_PROC(threaded_work_proc); - -typedef struct work_queue work_queue; - -#define PUSH_WORK_ON_QUEUE(name) void name(work_queue* Queue, threaded_work_proc* WorkProc, void* Data, char* JobName) -typedef PUSH_WORK_ON_QUEUE(push_work_on_queue); - -#define DO_QUEUE_WORK_UNTIL_DONE(name) void name(work_queue* Queue, s32 ThreadID) -typedef DO_QUEUE_WORK_UNTIL_DONE(do_queue_work_until_done); - -#define RESET_WORK_QUEUE(name) void name(work_queue* Queue) -typedef RESET_WORK_QUEUE(reset_work_queue); - -struct worker_thread_job -{ - void* Data; - threaded_work_proc* WorkProc; -#ifdef DEBUG - char* JobName; -#endif -}; - -struct work_queue -{ - void* SemaphoreHandle; - - u32 JobsMax; - u32 volatile JobsCount; - u32 volatile NextJobIndex; - u32 volatile JobsCompleted; - worker_thread_job* Jobs; - - // Work Queue - push_work_on_queue* PushWorkOnQueue; - do_queue_work_until_done* DoQueueWorkUntilDone; - reset_work_queue* ResetWorkQueue; -}; - RESET_WORK_QUEUE(ResetWorkQueue) { for (u32 i = 0; i < Queue->JobsMax; i++) { - Queue->Jobs[i].Data = 0; + Queue->Jobs[i].Data = {0}; Queue->Jobs[i].WorkProc = 0; } @@ -238,11 +174,13 @@ GetSecondsElapsed (s64 Start, s64 End, s64 PerformanceCountFrequency) struct context { + gs_thread_context ThreadContext; + u8* MemoryBase; u32 MemorySize; b32 WindowIsVisible; - rect WindowBounds; + rect2 WindowBounds; r32 DeltaTime; mouse_state Mouse; @@ -253,21 +191,13 @@ struct context cleanup_application* CleanupApplication; // Platform Services - work_queue* GeneralWorkQueue; + gs_work_queue* GeneralWorkQueue; - platform_alloc* PlatformAlloc; - platform_free* PlatformFree; - platform_realloc* PlatformRealloc; - platform_read_entire_file* PlatformReadEntireFile; - platform_write_entire_file* PlatformWriteEntireFile; - platform_get_file_path* PlatformGetFilePath; platform_get_gpu_texture_handle* PlatformGetGPUTextureHandle; platform_get_font_info* PlatformGetFontInfo; platform_draw_font_codepoint* PlatformDrawFontCodepoint; + platform_get_socket_handle* PlatformGetSocketHandle; - platform_set_socket_option* PlatformSetSocketOption; - platform_send_to* PlatformSendTo; - platform_close_socket* PlatformCloseSocket; }; diff --git a/src/app/foldhaus_renderer.cpp b/src/app/foldhaus_renderer.cpp index 7988e3e..ece4ee7 100644 --- a/src/app/foldhaus_renderer.cpp +++ b/src/app/foldhaus_renderer.cpp @@ -64,7 +64,7 @@ Render2DQuadBatch (u8* CommandData, s32 QuadCount) v2 P1 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 1)]; v2 P2 = Vertecies[BATCH_2D_VERTEX_INDEX(Quad, Tri, 2)]; v2 UV0 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 0)]; - v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)]; + v2 UV1 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 1)]; v2 UV2 = UVs[BATCH_2D_UV_INDEX(Quad, Tri, 2)]; v4 C0 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 0)]; v4 C1 = Colors[BATCH_2D_COLOR_INDEX(Quad, Tri, 1)]; @@ -107,11 +107,11 @@ RenderCommandBuffer (render_command_buffer CommandBuffer) render_command_set_render_mode* Command = (render_command_set_render_mode*)(CommandHeader + 1); - glViewport(Command->ViewOffsetX, Command->ViewOffsetY, + glViewport(Command->ViewOffsetX, Command->ViewOffsetY, Command->ViewWidth, Command->ViewHeight); - LoadModelView(Command->ModelView.E); - LoadProjection(Command->Projection.E); + LoadModelView(Command->ModelView.Array); + LoadProjection(Command->Projection.Array); if (Command->UseDepthBuffer) { diff --git a/src/app/foldhaus_renderer.h b/src/app/foldhaus_renderer.h index b29130f..e316c71 100644 --- a/src/app/foldhaus_renderer.h +++ b/src/app/foldhaus_renderer.h @@ -19,60 +19,71 @@ struct camera inline m44 GetCameraModelViewMatrix (camera Camera) { - // Forward - v4 CamForward = V4(Normalize(Camera.Position - Camera.LookAt), 0); - // Right - v4 CamRight = Normalize(Cross(v4{0, 1, 0, 0}, CamForward)); - // Up - v4 CamUp = Normalize(Cross(CamForward, CamRight)); - - r32 X = Camera.Position.x; - r32 Y = Camera.Position.y; - r32 Z = Camera.Position.z; - - m44 RotationMatrix = M44( - CamRight.x, CamUp.x, CamForward.x, 0, - CamRight.y, CamUp.y, CamForward.y, 0, - CamRight.z, CamUp.z, CamForward.z, 0, - 0, 0, 0, 1); - - m44 PositionMatrix = M44( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - -X, -Y, -Z, 1 - ); - - m44 ModelViewMatrix = PositionMatrix * RotationMatrix; - + m44 RotationMatrix = M44LookAt(ToV4Point(Camera.Position), ToV4Point(Camera.LookAt)); + m44 PositionMatrix = M44Translation(ToV4Point(-Camera.Position)); + m44 ModelViewMatrix = RotationMatrix * PositionMatrix; return ModelViewMatrix; } inline m44 GetCameraPerspectiveProjectionMatrix(camera Camera) { - r32 Top = Camera.Near * GSTan((Camera.FieldOfView / 2.0f)); - r32 Bottom = -Top; - r32 Right = Top * Camera.AspectRatio; - r32 Left = -Right; + m44 Result = M44ProjectionPerspective(Camera.FieldOfView, Camera.AspectRatio, Camera.Near, Camera.Far); + return Result; +} + +internal m44 +GetCameraMatrix(camera Camera) +{ + m44 ModelView = GetCameraModelViewMatrix(Camera); + m44 Projection = GetCameraPerspectiveProjectionMatrix(Camera); + m44 Result = Projection * ModelView; + return Result; +} + +internal v2 +ProjectWorldPointToScreen(v4 WorldSpacePoint, camera Camera, rect2 WindowBounds) +{ + v2 WindowExtents = v2{Rect2Width(WindowBounds), Rect2Height(WindowBounds)}; + v4 ProjectedPosition = GetCameraMatrix(Camera) * WorldSpacePoint; + ProjectedPosition.xyz /= ProjectedPosition.w; + v2 ScreenPosition = V2MultiplyPairwise(ProjectedPosition.xy, (WindowExtents / 2)) + (WindowExtents / 2); - r32 A = ((Right + Left) / (Right - Left)); - r32 B = ((Top + Bottom) / (Top - Bottom)); - r32 C = -((Camera.Far + Camera.Near) / (Camera.Far - Camera.Near)); - r32 D = -((2 * Camera.Far * Camera.Near) / (Camera.Far - Camera.Near)); + return ScreenPosition; +} + +internal v4_ray +ProjectScreenPointToWorldRay(v2 ScreenPoint, camera Camera, rect2 WindowBounds) +{ + v4_ray Result = {0}; - r32 E = ((2 * Camera.Near) / (Right - Left)); - r32 F = ((2 * Camera.Near) / (Top - Bottom)); + r32 TanFOVOverTwo = TanR32(DegToRadR32(Camera.FieldOfView / 2.0f)); + r32 Aspect = RectAspectRatio(WindowBounds); - m44 PerspectiveProjectionMatrix = - { - E, 0, A, 0, - 0, F, B, 0, - 0, 0, C, D, - 0, 0, -1, 0 - }; + r32 NormalizedX = ScreenPoint.x / Rect2Width(WindowBounds); + r32 NormalizedY = ScreenPoint.y / Rect2Height(WindowBounds); - return PerspectiveProjectionMatrix; + r32 CenteredX = (2.0f * NormalizedX) - 1.0f; + r32 CenteredY = (2.0f * NormalizedY) - 1.0f; + + r32 ScaledX = CenteredX * Aspect; + r32 ScaledY = CenteredY; + + r32 CameraX = ScaledX * TanFOVOverTwo; + r32 CameraY = ScaledY * TanFOVOverTwo; + + r32 Near = Camera.Near; + r32 Far = Camera.Far; + v3 MousePointOnNearPlane = v3{CameraX, CameraY, -1} * Near; + v3 MousePointOnFarPlane = v3{CameraX, CameraY, -1} * Far; + + v4 MouseRayDirection = ToV4Vec(V3Normalize(MousePointOnFarPlane - MousePointOnNearPlane)); + m44 CameraTransform = M44Transpose(M44LookAt(ToV4Point(Camera.Position), ToV4Point(Camera.LookAt))); + + Result.Origin = ToV4Point(Camera.Position); + Result.Direction = CameraTransform * MouseRayDirection; + + return Result; } // Render Commands @@ -195,7 +206,7 @@ struct render_command_set_render_mode typedef u8* renderer_realloc(u8* Base, s32 CurrentSize, s32 NewSize); -#define COMMAND_BUFFER_MIN_GROW_SIZE Megabytes(2) +#define COMMAND_BUFFER_MIN_GROW_SIZE MB(2) struct render_command_buffer { @@ -252,9 +263,9 @@ ResizeBufferIfNecessary(render_command_buffer* Buffer, s32 DataSize) // NewSize = Buffer->CommandMemorySize + (2 * DataSize); s32 SpaceAvailable = Buffer->CommandMemorySize - Buffer->CommandMemoryUsed; s32 SpaceNeeded = DataSize - SpaceAvailable; // This is known to be positive at this point - s32 AdditionSize = GSMax(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE); + s32 AdditionSize = Max(SpaceNeeded, COMMAND_BUFFER_MIN_GROW_SIZE); s32 NewSize = Buffer->CommandMemorySize + AdditionSize; - Buffer->CommandMemory = Buffer->Realloc(Buffer->CommandMemory, + Buffer->CommandMemory = Buffer->Realloc(Buffer->CommandMemory, Buffer->CommandMemorySize, NewSize); Buffer->CommandMemorySize = NewSize; @@ -280,7 +291,7 @@ PushQuad3DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* C internal s32 PushQuad2DBatch (render_command_buffer* Buffer, render_quad_batch_constructor* Constructor, s32 QuadCount, s32 DataSize, u8* MemStart) { - GSZeroMemory(MemStart, DataSize); + ZeroMemoryBlock(MemStart, DataSize); Constructor->Max = QuadCount; Constructor->Count = 0; @@ -297,10 +308,10 @@ internal s32 ThreadSafeIncrementQuadConstructorCount (render_quad_batch_constructor* Constructor) { s32 Result = InterlockedIncrement((long*)&Constructor->Count); - // NOTE(Peter): Have to decrement the value by one. + // NOTE(Peter): Have to decrement the value by one. // Interlocked Increment acts as (++Constructor->Count), not (Constructor->Count++) which // is what we wanted; - // This was causing the first triangle to be garbage data. + // This was causing the first triangle to be garbage data. Result -= 1; return Result; } @@ -311,6 +322,16 @@ struct quad_batch_constructor_reserved_range s32 OnePastLast; }; +internal quad_batch_constructor_reserved_range +ReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded) +{ + quad_batch_constructor_reserved_range Result = {}; + Result.OnePastLast = Constructor->Count + TrisNeeded; + Constructor->Count = Result.OnePastLast; + Result.Start = Result.OnePastLast - TrisNeeded; + return Result; +} + internal quad_batch_constructor_reserved_range ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Constructor, s32 TrisNeeded) { @@ -322,10 +343,12 @@ ThreadSafeReserveRangeInQuadConstructor(render_quad_batch_constructor* Construct inline void SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex, - v4 P0, v4 P1, v4 P2, - v2 UV0, v2 UV1, v2 UV2, + v4 P0, v4 P1, v4 P2, + v2 UV0, v2 UV1, v2 UV2, v4 C0, v4 C1, v4 C2) { + //Assert(P0.w != 0 && P1.w != 0 && P2.w != 0); // Passing vectors, rather than positions. Will draw wrong + // Vertecies Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 0)] = P0; Constructor->Vertecies[BATCH_3D_VERTEX_INDEX(TriIndex, 1)] = P1; @@ -342,13 +365,15 @@ SetTri3DInBatch (render_quad_batch_constructor* Constructor, s32 TriIndex, Constructor->ColorsV[BATCH_3D_COLOR_INDEX(TriIndex, 2)] = C2; } + inline void -PushTri3DOnBatch (render_quad_batch_constructor* Constructor, - v4 P0, v4 P1, v4 P2, - v2 UV0, v2 UV1, v2 UV2, +PushTri3DOnBatch (render_quad_batch_constructor* Constructor, + v4 P0, v4 P1, v4 P2, + v2 UV0, v2 UV1, v2 UV2, v4 C0, v4 C1, v4 C2) { DEBUG_TRACK_FUNCTION; + // TODO(Peter): I think we avoid doing cross thread filling of a batch so do we need this? s32 Tri = ThreadSafeIncrementQuadConstructorCount(Constructor); SetTri3DInBatch(Constructor, Tri, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2); }; @@ -356,18 +381,18 @@ PushTri3DOnBatch (render_quad_batch_constructor* Constructor, internal void PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 P2, v4 P3, v2 UVMin, v2 UVMax, v4 Color) { - Assert(Constructor->Count + 2 < Constructor->Max); + Assert(Constructor->Count + 2 <= Constructor->Max); PushTri3DOnBatch(Constructor, P0, P1, P2, UVMin, v2{UVMax.x, UVMin.y}, UVMax, Color, Color, Color); PushTri3DOnBatch(Constructor, P0, P2, P3, UVMin, UVMax, v2{UVMin.x, UVMax.y}, Color, Color, Color); } internal void -PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, - v4 P0, v4 P1, v4 P2, v4 P3, - v2 UV0, v2 UV1, v2 UV2, v2 UV3, +PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, + v4 P0, v4 P1, v4 P2, v4 P3, + v2 UV0, v2 UV1, v2 UV2, v2 UV3, v4 C0, v4 C1, v4 C2, v4 C3) { - Assert(Constructor->Count < Constructor->Max); + Assert(Constructor->Count <= Constructor->Max); PushTri3DOnBatch(Constructor, P0, P1, P2, UV0, UV1, UV2, C0, C1, C2); PushTri3DOnBatch(Constructor, P0, P2, P3, UV0, UV2, UV3, C0, C2, C3); } @@ -379,8 +404,8 @@ PushQuad3DOnBatch (render_quad_batch_constructor* Constructor, v4 P0, v4 P1, v4 } internal void -PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, - v2 P0, v2 P1, v2 P2, v2 P3, +PushQuad2DOnBatch (render_quad_batch_constructor* Constructor, + v2 P0, v2 P1, v2 P2, v2 P3, v2 UV0, v2 UV1, v2 UV2, v2 UV3, v4 C0, v4 C1, v4 C2, v4 C3) { @@ -466,7 +491,7 @@ internal void PushLine2DOnBatch (render_quad_batch_constructor* Constructor, v2 P0, v2 P1, r32 Thickness, v4 Color) { r32 HalfThickness = Thickness / 2.0f; - v2 Perpendicular = Normalize(PerpendicularCCW(P1 - P0)) * HalfThickness; + v2 Perpendicular = V2Normalize(V2PerpendicularCCW(P1 - P0)) * HalfThickness; PushQuad2DOnBatch(Constructor, P0 - Perpendicular, P1 - Perpendicular, P1 + Perpendicular, P0 + Perpendicular, v2{0, 0}, v2{1, 1}, Color); @@ -495,8 +520,8 @@ PushRenderPerspective (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, { render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode); - Command->ModelView = GetCameraModelViewMatrix(Camera); - Command->Projection = GetCameraPerspectiveProjectionMatrix(Camera); + Command->ModelView = M44Transpose(GetCameraModelViewMatrix(Camera)); + Command->Projection = M44Transpose(GetCameraPerspectiveProjectionMatrix(Camera)); Command->ViewOffsetX = (r32)OffsetX; Command->ViewOffsetY = (r32)OffsetY; @@ -508,25 +533,18 @@ PushRenderPerspective (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, return Command; } +internal void +PushRenderPerspective(render_command_buffer* Buffer, rect2 Viewport, camera Camera) +{ + PushRenderPerspective(Buffer, Viewport.Min.x, Viewport.Min.y, Rect2Width(Viewport), Rect2Height(Viewport), Camera); +} + internal void PushRenderOrthographic (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, s32 ViewWidth, s32 ViewHeight) { render_command_set_render_mode* Command = PushRenderCommand(Buffer, render_command_set_render_mode); - Command->ModelView = m44{ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - }; - - r32 a = 2.0f / ViewWidth; - r32 b = 2.0f / ViewHeight; - Command->Projection = m44{ - a, 0, 0, 0, - 0, b, 0, 0, - 0, 0, 1, 0, - -1, -1, 0, 1 - }; + Command->ModelView = M44Identity(); + Command->Projection = M44ProjectionOrtho((r32)ViewWidth, (r32)ViewHeight, 0, 100, ViewWidth, 0, ViewHeight, 0); Command->ViewOffsetX = (r32)OffsetX; Command->ViewOffsetY = (r32)OffsetY; @@ -536,6 +554,12 @@ PushRenderOrthographic (render_command_buffer* Buffer, s32 OffsetX, s32 OffsetY, Command->UseDepthBuffer = false;; } +internal void +PushRenderOrthographic(render_command_buffer* Buffer, rect2 Viewport) +{ + PushRenderOrthographic(Buffer, Viewport.Min.x, Viewport.Min.y, Rect2Width(Viewport), Rect2Height(Viewport)); +} + internal void PushRenderClearScreen (render_command_buffer* Buffer) { @@ -565,6 +589,13 @@ PushRenderQuad2D (render_command_buffer* Buffer, v2 Min, v2 Max, v4 Color) PushQuad2DOnBatch(&Batch, Min, Max, Color); } +internal void +PushRenderQuad2D(render_command_buffer* Buffer, v2 P0, v2 P1, v2 P2, v2 P3, v4 Color) +{ + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(Buffer, 1); + PushQuad2DOnBatch(&Batch, P0, P1, P2, P3, v2{0,0}, v2{1,1}, Color); +} + internal void PushRenderLine2D (render_command_buffer* Buffer, v2 P0, v2 P1, r32 Thickness, v4 Color) { @@ -610,7 +641,7 @@ PushRenderCameraFacingQuad (render_command_buffer* Buffer, v4 Center, v2 Dimensi } internal render_quad_batch_constructor -PushRenderTexture2DBatch(render_command_buffer* Buffer, s32 QuadCount, +PushRenderTexture2DBatch(render_command_buffer* Buffer, s32 QuadCount, render_texture Texture) { s32 DataSize = BATCH_2D_SIZE(QuadCount); @@ -628,15 +659,15 @@ PushRenderTexture2DBatch(render_command_buffer* Buffer, s32 QuadCount, } internal render_quad_batch_constructor -PushRenderTexture2DBatch (render_command_buffer* Buffer, s32 QuadCount, +PushRenderTexture2DBatch (render_command_buffer* Buffer, s32 QuadCount, u8* TextureMemory, s32 TextureHandle, s32 TextureWidth, s32 TextureHeight, s32 TextureBytesPerPixel, s32 TextureStride) { render_texture Texture = render_texture{ - TextureMemory, - TextureHandle, - TextureWidth, - TextureHeight, + TextureMemory, + TextureHandle, + TextureWidth, + TextureHeight, TextureBytesPerPixel, TextureStride}; return PushRenderTexture2DBatch(Buffer, QuadCount, Texture); diff --git a/src/app/generated/foldhaus_nodes_generated.h b/src/app/generated/foldhaus_nodes_generated.h index bc4eea3..8e9f0f8 100644 --- a/src/app/generated/foldhaus_nodes_generated.h +++ b/src/app/generated/foldhaus_nodes_generated.h @@ -1,14 +1,32 @@ enum node_type { + NodeType_SolidColorProc, + NodeType_RevolvingDiscs, + NodeType_VerticalColorFadeProc, NodeType_Count, }; static node_specification_ NodeSpecifications[] = { +{ NodeType_SolidColorProc, {"SolidColorProc", 14}, gsm_StructType_solid_color_data }, +{ NodeType_RevolvingDiscs, {"RevolvingDiscs", 14}, gsm_StructType_revolving_discs_data }, +{ NodeType_VerticalColorFadeProc, {"VerticalColorFadeProc", 21}, gsm_StructType_vertical_color_fade_data }, }; void CallNodeProc(node_type Type, u8* NodeData) { switch(Type) { + case NodeType_SolidColorProc: + { + SolidColorProc((solid_color_data*)NodeData); + } break; + case NodeType_RevolvingDiscs: + { + RevolvingDiscs((revolving_discs_data*)NodeData); + } break; + case NodeType_VerticalColorFadeProc: + { + VerticalColorFadeProc((vertical_color_fade_data*)NodeData); + } break; } } diff --git a/src/app/generated/foldhaus_panels_generated.h b/src/app/generated/foldhaus_panels_generated.h index 1c7d62c..e69de29 100644 --- a/src/app/generated/foldhaus_panels_generated.h +++ b/src/app/generated/foldhaus_panels_generated.h @@ -1,5 +0,0 @@ -enum panel_type { -}; -global_variable s32 GlobalPanelDefsCount = 0; -global_variable panel_definition GlobalPanelDefs[] = { -}; diff --git a/src/app/generated/gs_meta_generated_typeinfo.h b/src/app/generated/gs_meta_generated_typeinfo.h index bbc61fb..9477f54 100644 --- a/src/app/generated/gs_meta_generated_typeinfo.h +++ b/src/app/generated/gs_meta_generated_typeinfo.h @@ -1,14 +1,110 @@ enum gsm_meta_tag_type { + MetaTag_panel_type_file_view, + MetaTag_panel_type_node_graph, + MetaTag_node_output, + MetaTag_node_struct, + MetaTag_panel_cleanup, + MetaTag_node_input, + MetaTag_panel_init, + MetaTag_panel_type_animation_timeline, + MetaTag_panel_commands, + MetaTag_panel_type_sculpture_view, + MetaTag_node_proc, + MetaTag_panel_type_hierarchy, + MetaTag_panel_type_profiler, + MetaTag_panel_render, + MetaTag_panel_type_dmx_view, }; -gsm_meta_tag MetaTagStrings[] = { +gsm_meta_tag MetaTaggs_strings[] = { + { "panel_type_file_view", 20 }, + { "panel_type_node_graph", 21 }, + { "node_output", 11 }, + { "node_struct", 11 }, + { "panel_cleanup", 13 }, + { "node_input", 10 }, + { "panel_init", 10 }, + { "panel_type_animation_timeline", 29 }, + { "panel_commands", 14 }, + { "panel_type_sculpture_view", 25 }, + { "node_proc", 9 }, + { "panel_type_hierarchy", 20 }, + { "panel_type_profiler", 19 }, + { "panel_render", 12 }, + { "panel_type_dmx_view", 19 }, }; enum gsm_struct_type { + gsm_StructType_r32, + gsm_StructType_solid_color_data, + gsm_StructType_v4, + gsm_StructType_float, + gsm_StructType_color_buffer, + gsm_StructType_pixel, + gsm_StructType_u8, + gsm_StructType_s32, + gsm_StructType_revolving_discs_data, + gsm_StructType_vertical_color_fade_data, gsm_StructType_Count, }; +static gsm_struct_member_type_info StructMembers_v4[] = { + { "x", 1, (u64)&((v4*)0)->x, {}, 0}, + { "y", 1, (u64)&((v4*)0)->y, {}, 0}, + { "z", 1, (u64)&((v4*)0)->z, {}, 0}, + { "w", 1, (u64)&((v4*)0)->w, {}, 0}, + { "r", 1, (u64)&((v4*)0)->r, {}, 0}, + { "g", 1, (u64)&((v4*)0)->g, {}, 0}, + { "b", 1, (u64)&((v4*)0)->b, {}, 0}, + { "a", 1, (u64)&((v4*)0)->a, {}, 0}, + { "xy", 2, (u64)&((v4*)0)->xy, {}, 0}, + { "yz", 2, (u64)&((v4*)0)->yz, {}, 0}, + { "xyz", 3, (u64)&((v4*)0)->xyz, {}, 0}, + { "z", 1, (u64)&((v4*)0)->z, {}, 0}, + { "E", 1, (u64)&((v4*)0)->E, {}, 0}, +}; +static gsm_struct_member_type_info StructMembers_pixel[] = { + { "R", 1, (u64)&((pixel*)0)->R, {}, 0}, + { "G", 1, (u64)&((pixel*)0)->G, {}, 0}, + { "B", 1, (u64)&((pixel*)0)->B, {}, 0}, + { "Channels", 8, (u64)&((pixel*)0)->Channels, {}, 0}, +}; +static gsm_struct_member_type_info StructMembers_color_buffer[] = { + { "LedPositions", 12, (u64)&((color_buffer*)0)->LedPositions, {}, 0}, + { "Colors", 6, (u64)&((color_buffer*)0)->Colors, {}, 0}, + { "LEDCount", 8, (u64)&((color_buffer*)0)->LEDCount, {}, 0}, +}; +static gsm_struct_member_type_info StructMembers_solid_color_data[] = { + { "Color", 5, (u64)&((solid_color_data*)0)->Color, {MetaTag_node_input, }, 1}, + { "Result", 6, (u64)&((solid_color_data*)0)->Result, {MetaTag_node_output, }, 1}, +}; +static gsm_struct_member_type_info StructMembers_revolving_discs_data[] = { + { "Rotation", 8, (u64)&((revolving_discs_data*)0)->Rotation, {MetaTag_node_input, }, 1}, + { "ThetaZ", 6, (u64)&((revolving_discs_data*)0)->ThetaZ, {MetaTag_node_input, }, 1}, + { "ThetaY", 6, (u64)&((revolving_discs_data*)0)->ThetaY, {MetaTag_node_input, }, 1}, + { "DiscWidth", 9, (u64)&((revolving_discs_data*)0)->DiscWidth, {MetaTag_node_input, }, 1}, + { "InnerRadius", 11, (u64)&((revolving_discs_data*)0)->InnerRadius, {MetaTag_node_input, }, 1}, + { "OuterRadius", 11, (u64)&((revolving_discs_data*)0)->OuterRadius, {MetaTag_node_input, }, 1}, + { "Color", 5, (u64)&((revolving_discs_data*)0)->Color, {MetaTag_node_input, }, 1}, + { "Result", 6, (u64)&((revolving_discs_data*)0)->Result, {MetaTag_node_output, }, 1}, +}; +static gsm_struct_member_type_info StructMembers_vertical_color_fade_data[] = { + { "Color", 5, (u64)&((vertical_color_fade_data*)0)->Color, {MetaTag_node_input, }, 1}, + { "Min", 3, (u64)&((vertical_color_fade_data*)0)->Min, {MetaTag_node_input, }, 1}, + { "Max", 3, (u64)&((vertical_color_fade_data*)0)->Max, {MetaTag_node_input, }, 1}, + { "Result", 6, (u64)&((vertical_color_fade_data*)0)->Result, {MetaTag_node_output, }, 1}, +}; static gsm_struct_type_info StructTypes[] = { + { gsm_StructType_r32, "r32", 3, 4, 0, 0, 0, 0 }, + { gsm_StructType_solid_color_data, "solid_color_data", 16, 32, 0, 0, StructMembers_solid_color_data, 2 }, + { gsm_StructType_v4, "v4", 2, 16, 0, 0, StructMembers_v4, 5 }, + { gsm_StructType_float, "float", 5, 4, 0, 0, 0, 0 }, + { gsm_StructType_color_buffer, "color_buffer", 12, 16, 0, 0, StructMembers_color_buffer, 3 }, + { gsm_StructType_pixel, "pixel", 5, 0, 0, 0, StructMembers_pixel, 2 }, + { gsm_StructType_u8, "u8", 2, 0, 0, 0, 0, 0 }, + { gsm_StructType_s32, "s32", 3, 0, 0, 0, 0, 0 }, + { gsm_StructType_revolving_discs_data, "revolving_discs_data", 20, 56, 0, 0, StructMembers_revolving_discs_data, 8 }, + { gsm_StructType_vertical_color_fade_data, "vertical_color_fade_data", 24, 40, 0, 0, StructMembers_vertical_color_fade_data, 4 }, }; -static gsm_u32 StructTypesCount = 0; +static gsm_u32 StructTypesCount = 12; diff --git a/src/app/handmade_math.h b/src/app/handmade_math.h new file mode 100644 index 0000000..049dfdb --- /dev/null +++ b/src/app/handmade_math.h @@ -0,0 +1,3239 @@ +/* + HandmadeMath.h v1.11.0 + + This is a single header file with a bunch of useful functions for game and + graphics math operations. + + ============================================================================= + + You MUST + + #define HANDMADE_MATH_IMPLEMENTATION + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #include "HandmadeMath.h" + + All other files should just #include "HandmadeMath.h" without the #define. + + ============================================================================= + + To disable SSE intrinsics, you MUST + + #define HANDMADE_MATH_NO_SSE + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_NO_SSE + #include "HandmadeMath.h" + + ============================================================================= + + If you would prefer not to use the HMM_ prefix on function names, you can + + #define HMM_PREFIX + + To use a custom prefix instead, you can + + #define HMM_PREFIX(name) YOUR_PREFIX_##name + + ============================================================================= + + To use HandmadeMath without the CRT, you MUST + + #define HMM_SINF MySinF + #define HMM_COSF MyCosF + #define HMM_TANF MyTanF + #define HMM_SQRTF MySqrtF + #define HMM_EXPF MyExpF + #define HMM_LOGF MyLogF + #define HMM_ACOSF MyACosF + #define HMM_ATANF MyATanF + #define HMM_ATAN2F MYATan2F + + Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F, + ExpF, and LogF in EXACTLY one C or C++ file that includes this header, + BEFORE the include, like this: + + #define HMM_SINF MySinF + #define HMM_COSF MyCosF + #define HMM_TANF MyTanF + #define HMM_SQRTF MySqrtF + #define HMM_EXPF MyExpF + #define HMM_LOGF MyLogF + #define HMM_ACOSF MyACosF + #define HMM_ATANF MyATanF + #define HMM_ATAN2F MyATan2F + #define HANDMADE_MATH_IMPLEMENTATION + #include "HandmadeMath.h" + + If you do not define all of these, HandmadeMath.h will use the + versions of these functions that are provided by the CRT. + + ============================================================================= + + LICENSE + + This software is in the public domain. Where that dedication is not + recognized, you are granted a perpetual, irrevocable license to copy, + distribute, and modify this file as you see fit. + + CREDITS + + Written by Zakary Strange (strangezak@gmail.com && @strangezak) + + Functionality: + Matt Mascarenhas (@miblo_) + Aleph + FieryDrake (@fierydrake) + Gingerbill (@TheGingerBill) + Ben Visness (@bvisness) + Trinton Bullard (@Peliex_Dev) + @AntonDan + + Fixes: + Jeroen van Rijn (@J_vanRijn) + Kiljacken (@Kiljacken) + Insofaras (@insofaras) + Daniel Gibson (@DanielGibson) +*/ + +// Dummy macros for when test framework is not present. +#ifndef COVERAGE +#define COVERAGE(a, b) +#endif + +#ifndef ASSERT_COVERED +#define ASSERT_COVERED(a) +#endif + +/* let's figure out if SSE is really available (unless disabled anyway) + (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support) + => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */ +#ifndef HANDMADE_MATH_NO_SSE + +# ifdef _MSC_VER +/* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */ +# if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 ) +# define HANDMADE_MATH__USE_SSE 1 +# endif +# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */ +# ifdef __SSE__ /* they #define __SSE__ if it's supported */ +# define HANDMADE_MATH__USE_SSE 1 +# endif /* __SSE__ */ +# endif /* not _MSC_VER */ + +#endif /* #ifndef HANDMADE_MATH_NO_SSE */ + +#ifdef HANDMADE_MATH__USE_SSE +#include +#endif + +#ifndef HANDMADE_MATH_H +#define HANDMADE_MATH_H + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#if defined(__GNUC__) && (__GNUC__ == 4 && __GNUC_MINOR__ < 8) +#pragma GCC diagnostic ignored "-Wmissing-braces" +#endif +#ifdef __clang__ +#pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" +#endif +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define HMM_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) +#define HMM_DEPRECATED(msg) __declspec(deprecated(msg)) +#else +#define HMM_DEPRECATED(msg) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define HMM_INLINE static inline +#define HMM_EXTERN extern + +#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \ + !defined(HMM_SQRTF) || !defined(HMM_EXPF) || !defined(HMM_LOGF) || \ + !defined(HMM_ACOSF) || !defined(HMM_ATANF)|| !defined(HMM_ATAN2F) +#include +#endif + +#ifndef HMM_SINF +#define HMM_SINF sinf +#endif + +#ifndef HMM_COSF +#define HMM_COSF cosf +#endif + +#ifndef HMM_TANF +#define HMM_TANF tanf +#endif + +#ifndef HMM_SQRTF +#define HMM_SQRTF sqrtf +#endif + +#ifndef HMM_EXPF +#define HMM_EXPF expf +#endif + +#ifndef HMM_LOGF +#define HMM_LOGF logf +#endif + +#ifndef HMM_ACOSF +#define HMM_ACOSF acosf +#endif + +#ifndef HMM_ATANF +#define HMM_ATANF atanf +#endif + +#ifndef HMM_ATAN2F +#define HMM_ATAN2F atan2f +#endif + +#define HMM_PI32 3.14159265359f +#define HMM_PI 3.14159265358979323846 + +#define HMM_MIN(a, b) (a) > (b) ? (b) : (a) +#define HMM_MAX(a, b) (a) < (b) ? (b) : (a) +#define HMM_ABS(a) ((a) > 0 ? (a) : -(a)) +#define HMM_MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)) +#define HMM_SQUARE(x) ((x) * (x)) + +#ifndef HMM_PREFIX +#define HMM_PREFIX(name) HMM_##name +#endif + + typedef union hmm_vec2 + { + struct + { + float X, Y; + }; + + struct + { + float U, V; + }; + + struct + { + float Left, Right; + }; + + struct + { + float Width, Height; + }; + + float Elements[2]; + +#ifdef __cplusplus + inline float &operator[](const int &Index) + { + return Elements[Index]; + } +#endif + } hmm_vec2; + + typedef union hmm_vec3 + { + struct + { + float X, Y, Z; + }; + + struct + { + float U, V, W; + }; + + struct + { + float R, G, B; + }; + + struct + { + hmm_vec2 XY; + float Ignored0_; + }; + + struct + { + float Ignored1_; + hmm_vec2 YZ; + }; + + struct + { + hmm_vec2 UV; + float Ignored2_; + }; + + struct + { + float Ignored3_; + hmm_vec2 VW; + }; + + float Elements[3]; + +#ifdef __cplusplus + inline float &operator[](const int &Index) + { + return Elements[Index]; + } +#endif + } hmm_vec3; + + typedef union hmm_vec4 + { + struct + { + union + { + hmm_vec3 XYZ; + struct + { + float X, Y, Z; + }; + }; + + float W; + }; + struct + { + union + { + hmm_vec3 RGB; + struct + { + float R, G, B; + }; + }; + + float A; + }; + + struct + { + hmm_vec2 XY; + float Ignored0_; + float Ignored1_; + }; + + struct + { + float Ignored2_; + hmm_vec2 YZ; + float Ignored3_; + }; + + struct + { + float Ignored4_; + float Ignored5_; + hmm_vec2 ZW; + }; + + float Elements[4]; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 InternalElementsSSE; +#endif + +#ifdef __cplusplus + inline float &operator[](const int &Index) + { + return Elements[Index]; + } +#endif + } hmm_vec4; + + typedef union hmm_mat4 + { + float Elements[4][4]; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Columns[4]; + + HMM_DEPRECATED("Our matrices are column-major, so this was named incorrectly. Use Columns instead.") + __m128 Rows[4]; +#endif + +#ifdef __cplusplus + inline hmm_vec4 operator[](const int &Index) + { + float* col = Elements[Index]; + + hmm_vec4 result; + result.Elements[0] = col[0]; + result.Elements[1] = col[1]; + result.Elements[2] = col[2]; + result.Elements[3] = col[3]; + + return result; + } +#endif + } hmm_mat4; + + typedef union hmm_quaternion + { + struct + { + union + { + hmm_vec3 XYZ; + struct + { + float X, Y, Z; + }; + }; + + float W; + }; + + float Elements[4]; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 InternalElementsSSE; +#endif + } hmm_quaternion; + + typedef signed int hmm_bool; + + typedef hmm_vec2 hmm_v2; + typedef hmm_vec3 hmm_v3; + typedef hmm_vec4 hmm_v4; + typedef hmm_mat4 hmm_m4; + + + /* + * Floating-point math functions + */ + + COVERAGE(HMM_SinF, 1) + HMM_INLINE float HMM_PREFIX(SinF)(float Radians) + { + ASSERT_COVERED(HMM_SinF); + + float Result = HMM_SINF(Radians); + + return (Result); + } + + COVERAGE(HMM_CosF, 1) + HMM_INLINE float HMM_PREFIX(CosF)(float Radians) + { + ASSERT_COVERED(HMM_CosF); + + float Result = HMM_COSF(Radians); + + return (Result); + } + + COVERAGE(HMM_TanF, 1) + HMM_INLINE float HMM_PREFIX(TanF)(float Radians) + { + ASSERT_COVERED(HMM_TanF); + + float Result = HMM_TANF(Radians); + + return (Result); + } + + COVERAGE(HMM_ACosF, 1) + HMM_INLINE float HMM_PREFIX(ACosF)(float Radians) + { + ASSERT_COVERED(HMM_ACosF); + + float Result = HMM_ACOSF(Radians); + + return (Result); + } + + COVERAGE(HMM_ATanF, 1) + HMM_INLINE float HMM_PREFIX(ATanF)(float Radians) + { + ASSERT_COVERED(HMM_ATanF); + + float Result = HMM_ATANF(Radians); + + return (Result); + } + + COVERAGE(HMM_ATan2F, 1) + HMM_INLINE float HMM_PREFIX(ATan2F)(float Left, float Right) + { + ASSERT_COVERED(HMM_ATan2F); + + float Result = HMM_ATAN2F(Left, Right); + + return (Result); + } + + COVERAGE(HMM_ExpF, 1) + HMM_INLINE float HMM_PREFIX(ExpF)(float Float) + { + ASSERT_COVERED(HMM_ExpF); + + float Result = HMM_EXPF(Float); + + return (Result); + } + + COVERAGE(HMM_LogF, 1) + HMM_INLINE float HMM_PREFIX(LogF)(float Float) + { + ASSERT_COVERED(HMM_LogF); + + float Result = HMM_LOGF(Float); + + return (Result); + } + + COVERAGE(HMM_SquareRootF, 1) + HMM_INLINE float HMM_PREFIX(SquareRootF)(float Float) + { + ASSERT_COVERED(HMM_SquareRootF); + + float Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 In = _mm_set_ss(Float); + __m128 Out = _mm_sqrt_ss(In); + Result = _mm_cvtss_f32(Out); +#else + Result = HMM_SQRTF(Float); +#endif + + return(Result); + } + + COVERAGE(HMM_RSquareRootF, 1) + HMM_INLINE float HMM_PREFIX(RSquareRootF)(float Float) + { + ASSERT_COVERED(HMM_RSquareRootF); + + float Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 In = _mm_set_ss(Float); + __m128 Out = _mm_rsqrt_ss(In); + Result = _mm_cvtss_f32(Out); +#else + Result = 1.0f/HMM_PREFIX(SquareRootF)(Float); +#endif + + return(Result); + } + + HMM_EXTERN float HMM_PREFIX(Power)(float Base, int Exponent); + + COVERAGE(HMM_PowerF, 1) + HMM_INLINE float HMM_PREFIX(PowerF)(float Base, float Exponent) + { + ASSERT_COVERED(HMM_PowerF); + + float Result = HMM_EXPF(Exponent * HMM_LOGF(Base)); + + return (Result); + } + + + /* + * Utility functions + */ + + COVERAGE(HMM_ToRadians, 1) + HMM_INLINE float HMM_PREFIX(ToRadians)(float Degrees) + { + ASSERT_COVERED(HMM_ToRadians); + + float Result = Degrees * (HMM_PI32 / 180.0f); + + return (Result); + } + + COVERAGE(HMM_Lerp, 1) + HMM_INLINE float HMM_PREFIX(Lerp)(float A, float Time, float B) + { + ASSERT_COVERED(HMM_Lerp); + + float Result = (1.0f - Time) * A + Time * B; + + return (Result); + } + + COVERAGE(HMM_Clamp, 1) + HMM_INLINE float HMM_PREFIX(Clamp)(float Min, float Value, float Max) + { + ASSERT_COVERED(HMM_Clamp); + + float Result = Value; + + if(Result < Min) + { + Result = Min; + } + else if(Result > Max) + { + Result = Max; + } + + return (Result); + } + + + /* + * Vector initialization + */ + + COVERAGE(HMM_Vec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(Vec2)(float X, float Y) + { + ASSERT_COVERED(HMM_Vec2); + + hmm_vec2 Result; + + Result.X = X; + Result.Y = Y; + + return (Result); + } + + COVERAGE(HMM_Vec2i, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(Vec2i)(int X, int Y) + { + ASSERT_COVERED(HMM_Vec2i); + + hmm_vec2 Result; + + Result.X = (float)X; + Result.Y = (float)Y; + + return (Result); + } + + COVERAGE(HMM_Vec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(Vec3)(float X, float Y, float Z) + { + ASSERT_COVERED(HMM_Vec3); + + hmm_vec3 Result; + + Result.X = X; + Result.Y = Y; + Result.Z = Z; + + return (Result); + } + + COVERAGE(HMM_Vec3i, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(Vec3i)(int X, int Y, int Z) + { + ASSERT_COVERED(HMM_Vec3i); + + hmm_vec3 Result; + + Result.X = (float)X; + Result.Y = (float)Y; + Result.Z = (float)Z; + + return (Result); + } + + COVERAGE(HMM_Vec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4)(float X, float Y, float Z, float W) + { + ASSERT_COVERED(HMM_Vec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_setr_ps(X, Y, Z, W); +#else + Result.X = X; + Result.Y = Y; + Result.Z = Z; + Result.W = W; +#endif + + return (Result); + } + + COVERAGE(HMM_Vec4i, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4i)(int X, int Y, int Z, int W) + { + ASSERT_COVERED(HMM_Vec4i); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_setr_ps((float)X, (float)Y, (float)Z, (float)W); +#else + Result.X = (float)X; + Result.Y = (float)Y; + Result.Z = (float)Z; + Result.W = (float)W; +#endif + + return (Result); + } + + COVERAGE(HMM_Vec4v, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(Vec4v)(hmm_vec3 Vector, float W) + { + ASSERT_COVERED(HMM_Vec4v); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_setr_ps(Vector.X, Vector.Y, Vector.Z, W); +#else + Result.XYZ = Vector; + Result.W = W; +#endif + + return (Result); + } + + + /* + * Binary vector operations + */ + + COVERAGE(HMM_AddVec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(AddVec2)(hmm_vec2 Left, hmm_vec2 Right) + { + ASSERT_COVERED(HMM_AddVec2); + + hmm_vec2 Result; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + + return (Result); + } + + COVERAGE(HMM_AddVec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(AddVec3)(hmm_vec3 Left, hmm_vec3 Right) + { + ASSERT_COVERED(HMM_AddVec3); + + hmm_vec3 Result; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + + return (Result); + } + + COVERAGE(HMM_AddVec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(AddVec4)(hmm_vec4 Left, hmm_vec4 Right) + { + ASSERT_COVERED(HMM_AddVec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_add_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + Result.W = Left.W + Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_SubtractVec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(SubtractVec2)(hmm_vec2 Left, hmm_vec2 Right) + { + ASSERT_COVERED(HMM_SubtractVec2); + + hmm_vec2 Result; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + + return (Result); + } + + COVERAGE(HMM_SubtractVec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(SubtractVec3)(hmm_vec3 Left, hmm_vec3 Right) + { + ASSERT_COVERED(HMM_SubtractVec3); + + hmm_vec3 Result; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + + return (Result); + } + + COVERAGE(HMM_SubtractVec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(SubtractVec4)(hmm_vec4 Left, hmm_vec4 Right) + { + ASSERT_COVERED(HMM_SubtractVec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_sub_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + Result.W = Left.W - Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_MultiplyVec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2)(hmm_vec2 Left, hmm_vec2 Right) + { + ASSERT_COVERED(HMM_MultiplyVec2); + + hmm_vec2 Result; + + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + + return (Result); + } + + COVERAGE(HMM_MultiplyVec2f, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(MultiplyVec2f)(hmm_vec2 Left, float Right) + { + ASSERT_COVERED(HMM_MultiplyVec2f); + + hmm_vec2 Result; + + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + + return (Result); + } + + COVERAGE(HMM_MultiplyVec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3)(hmm_vec3 Left, hmm_vec3 Right) + { + ASSERT_COVERED(HMM_MultiplyVec3); + + hmm_vec3 Result; + + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + Result.Z = Left.Z * Right.Z; + + return (Result); + } + + COVERAGE(HMM_MultiplyVec3f, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(MultiplyVec3f)(hmm_vec3 Left, float Right) + { + ASSERT_COVERED(HMM_MultiplyVec3f); + + hmm_vec3 Result; + + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + Result.Z = Left.Z * Right; + + return (Result); + } + + COVERAGE(HMM_MultiplyVec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4)(hmm_vec4 Left, hmm_vec4 Right) + { + ASSERT_COVERED(HMM_MultiplyVec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + Result.Z = Left.Z * Right.Z; + Result.W = Left.W * Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_MultiplyVec4f, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(MultiplyVec4f)(hmm_vec4 Left, float Right) + { + ASSERT_COVERED(HMM_MultiplyVec4f); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Scalar = _mm_set1_ps(Right); + Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar); +#else + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + Result.Z = Left.Z * Right; + Result.W = Left.W * Right; +#endif + + return (Result); + } + + COVERAGE(HMM_DivideVec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2)(hmm_vec2 Left, hmm_vec2 Right) + { + ASSERT_COVERED(HMM_DivideVec2); + + hmm_vec2 Result; + + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + + return (Result); + } + + COVERAGE(HMM_DivideVec2f, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(DivideVec2f)(hmm_vec2 Left, float Right) + { + ASSERT_COVERED(HMM_DivideVec2f); + + hmm_vec2 Result; + + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + + return (Result); + } + + COVERAGE(HMM_DivideVec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3)(hmm_vec3 Left, hmm_vec3 Right) + { + ASSERT_COVERED(HMM_DivideVec3); + + hmm_vec3 Result; + + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + Result.Z = Left.Z / Right.Z; + + return (Result); + } + + COVERAGE(HMM_DivideVec3f, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(DivideVec3f)(hmm_vec3 Left, float Right) + { + ASSERT_COVERED(HMM_DivideVec3f); + + hmm_vec3 Result; + + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + Result.Z = Left.Z / Right; + + return (Result); + } + + COVERAGE(HMM_DivideVec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4)(hmm_vec4 Left, hmm_vec4 Right) + { + ASSERT_COVERED(HMM_DivideVec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + Result.Z = Left.Z / Right.Z; + Result.W = Left.W / Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_DivideVec4f, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(DivideVec4f)(hmm_vec4 Left, float Right) + { + ASSERT_COVERED(HMM_DivideVec4f); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Scalar = _mm_set1_ps(Right); + Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar); +#else + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + Result.Z = Left.Z / Right; + Result.W = Left.W / Right; +#endif + + return (Result); + } + + COVERAGE(HMM_EqualsVec2, 1) + HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec2)(hmm_vec2 Left, hmm_vec2 Right) + { + ASSERT_COVERED(HMM_EqualsVec2); + + hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y); + + return (Result); + } + + COVERAGE(HMM_EqualsVec3, 1) + HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec3)(hmm_vec3 Left, hmm_vec3 Right) + { + ASSERT_COVERED(HMM_EqualsVec3); + + hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z); + + return (Result); + } + + COVERAGE(HMM_EqualsVec4, 1) + HMM_INLINE hmm_bool HMM_PREFIX(EqualsVec4)(hmm_vec4 Left, hmm_vec4 Right) + { + ASSERT_COVERED(HMM_EqualsVec4); + + hmm_bool Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W); + + return (Result); + } + + COVERAGE(HMM_DotVec2, 1) + HMM_INLINE float HMM_PREFIX(DotVec2)(hmm_vec2 VecOne, hmm_vec2 VecTwo) + { + ASSERT_COVERED(HMM_DotVec2); + + float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y); + + return (Result); + } + + COVERAGE(HMM_DotVec3, 1) + HMM_INLINE float HMM_PREFIX(DotVec3)(hmm_vec3 VecOne, hmm_vec3 VecTwo) + { + ASSERT_COVERED(HMM_DotVec3); + + float Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z); + + return (Result); + } + + COVERAGE(HMM_DotVec4, 1) + HMM_INLINE float HMM_PREFIX(DotVec4)(hmm_vec4 VecOne, hmm_vec4 VecTwo) + { + ASSERT_COVERED(HMM_DotVec4); + + float Result; + + // NOTE(zak): IN the future if we wanna check what version SSE is support + // we can use _mm_dp_ps (4.3) but for now we will use the old way. + // Or a r = _mm_mul_ps(v1, v2), r = _mm_hadd_ps(r, r), r = _mm_hadd_ps(r, r) for SSE3 +#ifdef HANDMADE_MATH__USE_SSE + __m128 SSEResultOne = _mm_mul_ps(VecOne.InternalElementsSSE, VecTwo.InternalElementsSSE); + __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1)); + SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); + SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); + SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); + _mm_store_ss(&Result, SSEResultOne); +#else + Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W); +#endif + + return (Result); + } + + COVERAGE(HMM_Cross, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(Cross)(hmm_vec3 VecOne, hmm_vec3 VecTwo) + { + ASSERT_COVERED(HMM_Cross); + + hmm_vec3 Result; + + Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y); + Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z); + Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X); + + return (Result); + } + + + /* + * Unary vector operations + */ + + COVERAGE(HMM_LengthSquaredVec2, 1) + HMM_INLINE float HMM_PREFIX(LengthSquaredVec2)(hmm_vec2 A) + { + ASSERT_COVERED(HMM_LengthSquaredVec2); + + float Result = HMM_PREFIX(DotVec2)(A, A); + + return (Result); + } + + COVERAGE(HMM_LengthSquaredVec3, 1) + HMM_INLINE float HMM_PREFIX(LengthSquaredVec3)(hmm_vec3 A) + { + ASSERT_COVERED(HMM_LengthSquaredVec3); + + float Result = HMM_PREFIX(DotVec3)(A, A); + + return (Result); + } + + COVERAGE(HMM_LengthSquaredVec4, 1) + HMM_INLINE float HMM_PREFIX(LengthSquaredVec4)(hmm_vec4 A) + { + ASSERT_COVERED(HMM_LengthSquaredVec4); + + float Result = HMM_PREFIX(DotVec4)(A, A); + + return (Result); + } + + COVERAGE(HMM_LengthVec2, 1) + HMM_INLINE float HMM_PREFIX(LengthVec2)(hmm_vec2 A) + { + ASSERT_COVERED(HMM_LengthVec2); + + float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec2)(A)); + + return (Result); + } + + COVERAGE(HMM_LengthVec3, 1) + HMM_INLINE float HMM_PREFIX(LengthVec3)(hmm_vec3 A) + { + ASSERT_COVERED(HMM_LengthVec3); + + float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec3)(A)); + + return (Result); + } + + COVERAGE(HMM_LengthVec4, 1) + HMM_INLINE float HMM_PREFIX(LengthVec4)(hmm_vec4 A) + { + ASSERT_COVERED(HMM_LengthVec4); + + float Result = HMM_PREFIX(SquareRootF)(HMM_PREFIX(LengthSquaredVec4)(A)); + + return(Result); + } + + COVERAGE(HMM_NormalizeVec2, 2) + HMM_INLINE hmm_vec2 HMM_PREFIX(NormalizeVec2)(hmm_vec2 A) + { + ASSERT_COVERED(HMM_NormalizeVec2); + + hmm_vec2 Result = {0}; + + float VectorLength = HMM_PREFIX(LengthVec2)(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + ASSERT_COVERED(HMM_NormalizeVec2); + + Result.X = A.X * (1.0f / VectorLength); + Result.Y = A.Y * (1.0f / VectorLength); + } + + return (Result); + } + + COVERAGE(HMM_NormalizeVec3, 2) + HMM_INLINE hmm_vec3 HMM_PREFIX(NormalizeVec3)(hmm_vec3 A) + { + ASSERT_COVERED(HMM_NormalizeVec3); + + hmm_vec3 Result = {0}; + + float VectorLength = HMM_PREFIX(LengthVec3)(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + ASSERT_COVERED(HMM_NormalizeVec3); + + Result.X = A.X * (1.0f / VectorLength); + Result.Y = A.Y * (1.0f / VectorLength); + Result.Z = A.Z * (1.0f / VectorLength); + } + + return (Result); + } + + COVERAGE(HMM_NormalizeVec4, 2) + HMM_INLINE hmm_vec4 HMM_PREFIX(NormalizeVec4)(hmm_vec4 A) + { + ASSERT_COVERED(HMM_NormalizeVec4); + + hmm_vec4 Result = {0}; + + float VectorLength = HMM_PREFIX(LengthVec4)(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + ASSERT_COVERED(HMM_NormalizeVec4); + + float Multiplier = 1.0f / VectorLength; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 SSEMultiplier = _mm_set1_ps(Multiplier); + Result.InternalElementsSSE = _mm_mul_ps(A.InternalElementsSSE, SSEMultiplier); +#else + Result.X = A.X * Multiplier; + Result.Y = A.Y * Multiplier; + Result.Z = A.Z * Multiplier; + Result.W = A.W * Multiplier; +#endif + } + + return (Result); + } + + COVERAGE(HMM_FastNormalizeVec2, 1) + HMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalizeVec2)(hmm_vec2 A) + { + ASSERT_COVERED(HMM_FastNormalizeVec2); + + return HMM_PREFIX(MultiplyVec2f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec2)(A, A))); + } + + COVERAGE(HMM_FastNormalizeVec3, 1) + HMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalizeVec3)(hmm_vec3 A) + { + ASSERT_COVERED(HMM_FastNormalizeVec3); + + return HMM_PREFIX(MultiplyVec3f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec3)(A, A))); + } + + COVERAGE(HMM_FastNormalizeVec4, 1) + HMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalizeVec4)(hmm_vec4 A) + { + ASSERT_COVERED(HMM_FastNormalizeVec4); + + return HMM_PREFIX(MultiplyVec4f)(A, HMM_PREFIX(RSquareRootF)(HMM_PREFIX(DotVec4)(A, A))); + } + + + /* + * SSE stuff + */ + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_LinearCombineSSE, 1) + HMM_INLINE __m128 HMM_PREFIX(LinearCombineSSE)(__m128 Left, hmm_mat4 Right) + { + ASSERT_COVERED(HMM_LinearCombineSSE); + + __m128 Result; + Result = _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x00), Right.Columns[0]); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x55), Right.Columns[1])); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xaa), Right.Columns[2])); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xff), Right.Columns[3])); + + return (Result); + } +#endif + + + /* + * Matrix functions + */ + + COVERAGE(HMM_Mat4, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Mat4)(void) + { + ASSERT_COVERED(HMM_Mat4); + + hmm_mat4 Result = {0}; + + return (Result); + } + + COVERAGE(HMM_Mat4d, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Mat4d)(float Diagonal) + { + ASSERT_COVERED(HMM_Mat4d); + + hmm_mat4 Result = HMM_PREFIX(Mat4)(); + + Result.Elements[0][0] = Diagonal; + Result.Elements[1][1] = Diagonal; + Result.Elements[2][2] = Diagonal; + Result.Elements[3][3] = Diagonal; + + return (Result); + } + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_Transpose, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Transpose)(hmm_mat4 Matrix) + { + ASSERT_COVERED(HMM_Transpose); + + hmm_mat4 Result = Matrix; + + _MM_TRANSPOSE4_PS(Result.Columns[0], Result.Columns[1], Result.Columns[2], Result.Columns[3]); + + return (Result); + } +#else + HMM_EXTERN hmm_mat4 HMM_PREFIX(Transpose)(hmm_mat4 Matrix); +#endif + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_AddMat4, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(AddMat4)(hmm_mat4 Left, hmm_mat4 Right) + { + ASSERT_COVERED(HMM_AddMat4); + + hmm_mat4 Result; + + Result.Columns[0] = _mm_add_ps(Left.Columns[0], Right.Columns[0]); + Result.Columns[1] = _mm_add_ps(Left.Columns[1], Right.Columns[1]); + Result.Columns[2] = _mm_add_ps(Left.Columns[2], Right.Columns[2]); + Result.Columns[3] = _mm_add_ps(Left.Columns[3], Right.Columns[3]); + + return (Result); + } +#else + HMM_EXTERN hmm_mat4 HMM_PREFIX(AddMat4)(hmm_mat4 Left, hmm_mat4 Right); +#endif + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_SubtractMat4, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(SubtractMat4)(hmm_mat4 Left, hmm_mat4 Right) + { + ASSERT_COVERED(HMM_SubtractMat4); + + hmm_mat4 Result; + + Result.Columns[0] = _mm_sub_ps(Left.Columns[0], Right.Columns[0]); + Result.Columns[1] = _mm_sub_ps(Left.Columns[1], Right.Columns[1]); + Result.Columns[2] = _mm_sub_ps(Left.Columns[2], Right.Columns[2]); + Result.Columns[3] = _mm_sub_ps(Left.Columns[3], Right.Columns[3]); + + return (Result); + } +#else + HMM_EXTERN hmm_mat4 HMM_PREFIX(SubtractMat4)(hmm_mat4 Left, hmm_mat4 Right); +#endif + + HMM_EXTERN hmm_mat4 HMM_PREFIX(MultiplyMat4)(hmm_mat4 Left, hmm_mat4 Right); + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_MultiplyMat4f, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(MultiplyMat4f)(hmm_mat4 Matrix, float Scalar) + { + ASSERT_COVERED(HMM_MultiplyMat4f); + + hmm_mat4 Result; + + __m128 SSEScalar = _mm_set1_ps(Scalar); + Result.Columns[0] = _mm_mul_ps(Matrix.Columns[0], SSEScalar); + Result.Columns[1] = _mm_mul_ps(Matrix.Columns[1], SSEScalar); + Result.Columns[2] = _mm_mul_ps(Matrix.Columns[2], SSEScalar); + Result.Columns[3] = _mm_mul_ps(Matrix.Columns[3], SSEScalar); + + return (Result); + } +#else + HMM_EXTERN hmm_mat4 HMM_PREFIX(MultiplyMat4f)(hmm_mat4 Matrix, float Scalar); +#endif + + HMM_EXTERN hmm_vec4 HMM_PREFIX(MultiplyMat4ByVec4)(hmm_mat4 Matrix, hmm_vec4 Vector); + +#ifdef HANDMADE_MATH__USE_SSE + COVERAGE(HMM_DivideMat4f, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(DivideMat4f)(hmm_mat4 Matrix, float Scalar) + { + ASSERT_COVERED(HMM_DivideMat4f); + + hmm_mat4 Result; + + __m128 SSEScalar = _mm_set1_ps(Scalar); + Result.Columns[0] = _mm_div_ps(Matrix.Columns[0], SSEScalar); + Result.Columns[1] = _mm_div_ps(Matrix.Columns[1], SSEScalar); + Result.Columns[2] = _mm_div_ps(Matrix.Columns[2], SSEScalar); + Result.Columns[3] = _mm_div_ps(Matrix.Columns[3], SSEScalar); + + return (Result); + } +#else + HMM_EXTERN hmm_mat4 HMM_PREFIX(DivideMat4f)(hmm_mat4 Matrix, float Scalar); +#endif + + + /* + * Common graphics transformations + */ + + COVERAGE(HMM_Orthographic, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Orthographic)(float Left, float Right, float Bottom, float Top, float Near, float Far) + { + ASSERT_COVERED(HMM_Orthographic); + + hmm_mat4 Result = HMM_PREFIX(Mat4)(); + + Result.Elements[0][0] = 2.0f / (Right - Left); + Result.Elements[1][1] = 2.0f / (Top - Bottom); + Result.Elements[2][2] = 2.0f / (Near - Far); + Result.Elements[3][3] = 1.0f; + + Result.Elements[3][0] = (Left + Right) / (Left - Right); + Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); + Result.Elements[3][2] = (Far + Near) / (Near - Far); + + return (Result); + } + + COVERAGE(HMM_Perspective, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Perspective)(float FOV, float AspectRatio, float Near, float Far) + { + ASSERT_COVERED(HMM_Perspective); + + hmm_mat4 Result = HMM_PREFIX(Mat4)(); + + // See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml + + float Cotangent = 1.0f / HMM_PREFIX(TanF)(FOV * (HMM_PI32 / 360.0f)); + + Result.Elements[0][0] = Cotangent / AspectRatio; + Result.Elements[1][1] = Cotangent; + Result.Elements[2][3] = -1.0f; + Result.Elements[2][2] = (Near + Far) / (Near - Far); + Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far); + Result.Elements[3][3] = 0.0f; + + return (Result); + } + + COVERAGE(HMM_Translate, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Translate)(hmm_vec3 Translation) + { + ASSERT_COVERED(HMM_Translate); + + hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f); + + Result.Elements[3][0] = Translation.X; + Result.Elements[3][1] = Translation.Y; + Result.Elements[3][2] = Translation.Z; + + return (Result); + } + + HMM_EXTERN hmm_mat4 HMM_PREFIX(Rotate)(float Angle, hmm_vec3 Axis); + + COVERAGE(HMM_Scale, 1) + HMM_INLINE hmm_mat4 HMM_PREFIX(Scale)(hmm_vec3 Scale) + { + ASSERT_COVERED(HMM_Scale); + + hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f); + + Result.Elements[0][0] = Scale.X; + Result.Elements[1][1] = Scale.Y; + Result.Elements[2][2] = Scale.Z; + + return (Result); + } + + HMM_EXTERN hmm_mat4 HMM_PREFIX(LookAt)(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up); + + + /* + * Quaternion operations + */ + + COVERAGE(HMM_Quaternion, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(Quaternion)(float X, float Y, float Z, float W) + { + ASSERT_COVERED(HMM_Quaternion); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_setr_ps(X, Y, Z, W); +#else + Result.X = X; + Result.Y = Y; + Result.Z = Z; + Result.W = W; +#endif + + return (Result); + } + + COVERAGE(HMM_QuaternionV4, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(QuaternionV4)(hmm_vec4 Vector) + { + ASSERT_COVERED(HMM_QuaternionV4); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = Vector.InternalElementsSSE; +#else + Result.X = Vector.X; + Result.Y = Vector.Y; + Result.Z = Vector.Z; + Result.W = Vector.W; +#endif + + return (Result); + } + + COVERAGE(HMM_AddQuaternion, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(AddQuaternion)(hmm_quaternion Left, hmm_quaternion Right) + { + ASSERT_COVERED(HMM_AddQuaternion); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_add_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + Result.W = Left.W + Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_SubtractQuaternion, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(SubtractQuaternion)(hmm_quaternion Left, hmm_quaternion Right) + { + ASSERT_COVERED(HMM_SubtractQuaternion); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = _mm_sub_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); +#else + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + Result.W = Left.W - Right.W; +#endif + + return (Result); + } + + COVERAGE(HMM_MultiplyQuaternion, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternion)(hmm_quaternion Left, hmm_quaternion Right) + { + ASSERT_COVERED(HMM_MultiplyQuaternion); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(0, 0, 0, 0)), _mm_setr_ps(0.f, -0.f, 0.f, -0.f)); + __m128 SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(0, 1, 2, 3)); + __m128 SSEResultThree = _mm_mul_ps(SSEResultTwo, SSEResultOne); + + SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(1, 1, 1, 1)) , _mm_setr_ps(0.f, 0.f, -0.f, -0.f)); + SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(1, 0, 3, 2)); + SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); + + SSEResultOne = _mm_xor_ps(_mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(2, 2, 2, 2)), _mm_setr_ps(-0.f, 0.f, 0.f, -0.f)); + SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(2, 3, 0, 1)); + SSEResultThree = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); + + SSEResultOne = _mm_shuffle_ps(Left.InternalElementsSSE, Left.InternalElementsSSE, _MM_SHUFFLE(3, 3, 3, 3)); + SSEResultTwo = _mm_shuffle_ps(Right.InternalElementsSSE, Right.InternalElementsSSE, _MM_SHUFFLE(3, 2, 1, 0)); + Result.InternalElementsSSE = _mm_add_ps(SSEResultThree, _mm_mul_ps(SSEResultTwo, SSEResultOne)); +#else + Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X); + Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y); + Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z); + Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W); +#endif + + return (Result); + } + + COVERAGE(HMM_MultiplyQuaternionF, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(MultiplyQuaternionF)(hmm_quaternion Left, float Multiplicative) + { + ASSERT_COVERED(HMM_MultiplyQuaternionF); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Scalar = _mm_set1_ps(Multiplicative); + Result.InternalElementsSSE = _mm_mul_ps(Left.InternalElementsSSE, Scalar); +#else + Result.X = Left.X * Multiplicative; + Result.Y = Left.Y * Multiplicative; + Result.Z = Left.Z * Multiplicative; + Result.W = Left.W * Multiplicative; +#endif + + return (Result); + } + + COVERAGE(HMM_DivideQuaternionF, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(DivideQuaternionF)(hmm_quaternion Left, float Dividend) + { + ASSERT_COVERED(HMM_DivideQuaternionF); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Scalar = _mm_set1_ps(Dividend); + Result.InternalElementsSSE = _mm_div_ps(Left.InternalElementsSSE, Scalar); +#else + Result.X = Left.X / Dividend; + Result.Y = Left.Y / Dividend; + Result.Z = Left.Z / Dividend; + Result.W = Left.W / Dividend; +#endif + + return (Result); + } + + HMM_EXTERN hmm_quaternion HMM_PREFIX(InverseQuaternion)(hmm_quaternion Left); + + COVERAGE(HMM_DotQuaternion, 1) + HMM_INLINE float HMM_PREFIX(DotQuaternion)(hmm_quaternion Left, hmm_quaternion Right) + { + ASSERT_COVERED(HMM_DotQuaternion); + + float Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, Right.InternalElementsSSE); + __m128 SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(2, 3, 0, 1)); + SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); + SSEResultTwo = _mm_shuffle_ps(SSEResultOne, SSEResultOne, _MM_SHUFFLE(0, 1, 2, 3)); + SSEResultOne = _mm_add_ps(SSEResultOne, SSEResultTwo); + _mm_store_ss(&Result, SSEResultOne); +#else + Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W); +#endif + + return (Result); + } + + COVERAGE(HMM_NormalizeQuaternion, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(NormalizeQuaternion)(hmm_quaternion Left) + { + ASSERT_COVERED(HMM_NormalizeQuaternion); + + hmm_quaternion Result; + + float Length = HMM_PREFIX(SquareRootF)(HMM_PREFIX(DotQuaternion)(Left, Left)); + Result = HMM_PREFIX(DivideQuaternionF)(Left, Length); + + return (Result); + } + + COVERAGE(HMM_NLerp, 1) + HMM_INLINE hmm_quaternion HMM_PREFIX(NLerp)(hmm_quaternion Left, float Time, hmm_quaternion Right) + { + ASSERT_COVERED(HMM_NLerp); + + hmm_quaternion Result; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 ScalarLeft = _mm_set1_ps(1.0f - Time); + __m128 ScalarRight = _mm_set1_ps(Time); + __m128 SSEResultOne = _mm_mul_ps(Left.InternalElementsSSE, ScalarLeft); + __m128 SSEResultTwo = _mm_mul_ps(Right.InternalElementsSSE, ScalarRight); + Result.InternalElementsSSE = _mm_add_ps(SSEResultOne, SSEResultTwo); +#else + Result.X = HMM_PREFIX(Lerp)(Left.X, Time, Right.X); + Result.Y = HMM_PREFIX(Lerp)(Left.Y, Time, Right.Y); + Result.Z = HMM_PREFIX(Lerp)(Left.Z, Time, Right.Z); + Result.W = HMM_PREFIX(Lerp)(Left.W, Time, Right.W); +#endif + Result = HMM_PREFIX(NormalizeQuaternion)(Result); + + return (Result); + } + + HMM_EXTERN hmm_quaternion HMM_PREFIX(Slerp)(hmm_quaternion Left, float Time, hmm_quaternion Right); + HMM_EXTERN hmm_mat4 HMM_PREFIX(QuaternionToMat4)(hmm_quaternion Left); + HMM_EXTERN hmm_quaternion HMM_PREFIX(Mat4ToQuaternion)(hmm_mat4 Left); + HMM_EXTERN hmm_quaternion HMM_PREFIX(QuaternionFromAxisAngle)(hmm_vec3 Axis, float AngleOfRotation); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus + +COVERAGE(HMM_LengthVec2CPP, 1) +HMM_INLINE float HMM_PREFIX(Length)(hmm_vec2 A) +{ + ASSERT_COVERED(HMM_LengthVec2CPP); + + float Result = HMM_PREFIX(LengthVec2)(A); + + return (Result); +} + +COVERAGE(HMM_LengthVec3CPP, 1) +HMM_INLINE float HMM_PREFIX(Length)(hmm_vec3 A) +{ + ASSERT_COVERED(HMM_LengthVec3CPP); + + float Result = HMM_PREFIX(LengthVec3)(A); + + return (Result); +} + +COVERAGE(HMM_LengthVec4CPP, 1) +HMM_INLINE float HMM_PREFIX(Length)(hmm_vec4 A) +{ + ASSERT_COVERED(HMM_LengthVec4CPP); + + float Result = HMM_PREFIX(LengthVec4)(A); + + return (Result); +} + +COVERAGE(HMM_LengthSquaredVec2CPP, 1) +HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec2 A) +{ + ASSERT_COVERED(HMM_LengthSquaredVec2CPP); + + float Result = HMM_PREFIX(LengthSquaredVec2)(A); + + return (Result); +} + +COVERAGE(HMM_LengthSquaredVec3CPP, 1) +HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec3 A) +{ + ASSERT_COVERED(HMM_LengthSquaredVec3CPP); + + float Result = HMM_PREFIX(LengthSquaredVec3)(A); + + return (Result); +} + +COVERAGE(HMM_LengthSquaredVec4CPP, 1) +HMM_INLINE float HMM_PREFIX(LengthSquared)(hmm_vec4 A) +{ + ASSERT_COVERED(HMM_LengthSquaredVec4CPP); + + float Result = HMM_PREFIX(LengthSquaredVec4)(A); + + return (Result); +} + +COVERAGE(HMM_NormalizeVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Normalize)(hmm_vec2 A) +{ + ASSERT_COVERED(HMM_NormalizeVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(NormalizeVec2)(A); + + return (Result); +} + +COVERAGE(HMM_NormalizeVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Normalize)(hmm_vec3 A) +{ + ASSERT_COVERED(HMM_NormalizeVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(NormalizeVec3)(A); + + return (Result); +} + +COVERAGE(HMM_NormalizeVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Normalize)(hmm_vec4 A) +{ + ASSERT_COVERED(HMM_NormalizeVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(NormalizeVec4)(A); + + return (Result); +} + +COVERAGE(HMM_FastNormalizeVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(FastNormalize)(hmm_vec2 A) +{ + ASSERT_COVERED(HMM_FastNormalizeVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(FastNormalizeVec2)(A); + + return (Result); +} + +COVERAGE(HMM_FastNormalizeVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(FastNormalize)(hmm_vec3 A) +{ + ASSERT_COVERED(HMM_FastNormalizeVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(FastNormalizeVec3)(A); + + return (Result); +} + +COVERAGE(HMM_FastNormalizeVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(FastNormalize)(hmm_vec4 A) +{ + ASSERT_COVERED(HMM_FastNormalizeVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(FastNormalizeVec4)(A); + + return (Result); +} + +COVERAGE(HMM_NormalizeQuaternionCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Normalize)(hmm_quaternion A) +{ + ASSERT_COVERED(HMM_NormalizeQuaternionCPP); + + hmm_quaternion Result = HMM_PREFIX(NormalizeQuaternion)(A); + + return (Result); +} + +COVERAGE(HMM_DotVec2CPP, 1) +HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec2 VecOne, hmm_vec2 VecTwo) +{ + ASSERT_COVERED(HMM_DotVec2CPP); + + float Result = HMM_PREFIX(DotVec2)(VecOne, VecTwo); + + return (Result); +} + +COVERAGE(HMM_DotVec3CPP, 1) +HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec3 VecOne, hmm_vec3 VecTwo) +{ + ASSERT_COVERED(HMM_DotVec3CPP); + + float Result = HMM_PREFIX(DotVec3)(VecOne, VecTwo); + + return (Result); +} + +COVERAGE(HMM_DotVec4CPP, 1) +HMM_INLINE float HMM_PREFIX(Dot)(hmm_vec4 VecOne, hmm_vec4 VecTwo) +{ + ASSERT_COVERED(HMM_DotVec4CPP); + + float Result = HMM_PREFIX(DotVec4)(VecOne, VecTwo); + + return (Result); +} + +COVERAGE(HMM_DotQuaternionCPP, 1) +HMM_INLINE float HMM_PREFIX(Dot)(hmm_quaternion QuatOne, hmm_quaternion QuatTwo) +{ + ASSERT_COVERED(HMM_DotQuaternionCPP); + + float Result = HMM_PREFIX(DotQuaternion)(QuatOne, QuatTwo); + + return (Result); +} + +COVERAGE(HMM_AddVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Add)(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_AddVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Add)(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_AddVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Add)(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_AddVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddMat4CPP, 1) +HMM_INLINE hmm_mat4 HMM_PREFIX(Add)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_AddMat4CPP); + + hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddQuaternionCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Add)(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_AddQuaternionCPP); + + hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Subtract)(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_SubtractVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Subtract)(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_SubtractVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Subtract)(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_SubtractVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractMat4CPP, 1) +HMM_INLINE hmm_mat4 HMM_PREFIX(Subtract)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_SubtractMat4CPP); + + hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractQuaternionCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Subtract)(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_SubtractQuaternionCPP); + + hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec2fCPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Multiply)(hmm_vec2 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2fCPP); + + hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec3fCPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Multiply)(hmm_vec3 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3fCPP); + + hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec4fCPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_vec4 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4fCPP); + + hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4CPP, 1) +HMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4CPP); + + hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4fCPP, 1) +HMM_INLINE hmm_mat4 HMM_PREFIX(Multiply)(hmm_mat4 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4fCPP); + + hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4ByVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Multiply)(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + ASSERT_COVERED(HMM_MultiplyMat4ByVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector); + + return (Result); +} + +COVERAGE(HMM_MultiplyQuaternionCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionCPP); + + hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyQuaternionFCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Multiply)(hmm_quaternion Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionFCPP); + + hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec2CPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_DivideVec2CPP); + + hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec2fCPP, 1) +HMM_INLINE hmm_vec2 HMM_PREFIX(Divide)(hmm_vec2 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec2fCPP); + + hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec3CPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_DivideVec3CPP); + + hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec3fCPP, 1) +HMM_INLINE hmm_vec3 HMM_PREFIX(Divide)(hmm_vec3 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec3fCPP); + + hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec4CPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_DivideVec4CPP); + + hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec4fCPP, 1) +HMM_INLINE hmm_vec4 HMM_PREFIX(Divide)(hmm_vec4 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec4fCPP); + + hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideMat4fCPP, 1) +HMM_INLINE hmm_mat4 HMM_PREFIX(Divide)(hmm_mat4 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideMat4fCPP); + + hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideQuaternionFCPP, 1) +HMM_INLINE hmm_quaternion HMM_PREFIX(Divide)(hmm_quaternion Left, float Right) +{ + ASSERT_COVERED(HMM_DivideQuaternionFCPP); + + hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_EqualsVec2CPP, 1) +HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_EqualsVec2CPP); + + hmm_bool Result = HMM_PREFIX(EqualsVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_EqualsVec3CPP, 1) +HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_EqualsVec3CPP); + + hmm_bool Result = HMM_PREFIX(EqualsVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_EqualsVec4CPP, 1) +HMM_INLINE hmm_bool HMM_PREFIX(Equals)(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_EqualsVec4CPP); + + hmm_bool Result = HMM_PREFIX(EqualsVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec2Op, 1) +HMM_INLINE hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_AddVec2Op); + + hmm_vec2 Result = HMM_PREFIX(AddVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec3Op, 1) +HMM_INLINE hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_AddVec3Op); + + hmm_vec3 Result = HMM_PREFIX(AddVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec4Op, 1) +HMM_INLINE hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_AddVec4Op); + + hmm_vec4 Result = HMM_PREFIX(AddVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddMat4Op, 1) +HMM_INLINE hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_AddMat4Op); + + hmm_mat4 Result = HMM_PREFIX(AddMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddQuaternionOp, 1) +HMM_INLINE hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_AddQuaternionOp); + + hmm_quaternion Result = HMM_PREFIX(AddQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec2Op, 1) +HMM_INLINE hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_SubtractVec2Op); + + hmm_vec2 Result = HMM_PREFIX(SubtractVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec3Op, 1) +HMM_INLINE hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_SubtractVec3Op); + + hmm_vec3 Result = HMM_PREFIX(SubtractVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractVec4Op, 1) +HMM_INLINE hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_SubtractVec4Op); + + hmm_vec4 Result = HMM_PREFIX(SubtractVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractMat4Op, 1) +HMM_INLINE hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_SubtractMat4Op); + + hmm_mat4 Result = HMM_PREFIX(SubtractMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_SubtractQuaternionOp, 1) +HMM_INLINE hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_SubtractQuaternionOp); + + hmm_quaternion Result = HMM_PREFIX(SubtractQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec2Op, 1) +HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2Op); + + hmm_vec2 Result = HMM_PREFIX(MultiplyVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec3Op, 1) +HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3Op); + + hmm_vec3 Result = HMM_PREFIX(MultiplyVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec4Op, 1) +HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4Op); + + hmm_vec4 Result = HMM_PREFIX(MultiplyVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4Op, 1) +HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4Op); + + hmm_mat4 Result = HMM_PREFIX(MultiplyMat4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyQuaternionOp, 1) +HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionOp); + + hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternion)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec2fOp, 1) +HMM_INLINE hmm_vec2 operator*(hmm_vec2 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2fOp); + + hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec3fOp, 1) +HMM_INLINE hmm_vec3 operator*(hmm_vec3 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3fOp); + + hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec4fOp, 1) +HMM_INLINE hmm_vec4 operator*(hmm_vec4 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4fOp); + + hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4fOp, 1) +HMM_INLINE hmm_mat4 operator*(hmm_mat4 Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4fOp); + + hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyQuaternionFOp, 1) +HMM_INLINE hmm_quaternion operator*(hmm_quaternion Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionFOp); + + hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec2fOpLeft, 1) +HMM_INLINE hmm_vec2 operator*(float Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2fOpLeft); + + hmm_vec2 Result = HMM_PREFIX(MultiplyVec2f)(Right, Left); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec3fOpLeft, 1) +HMM_INLINE hmm_vec3 operator*(float Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3fOpLeft); + + hmm_vec3 Result = HMM_PREFIX(MultiplyVec3f)(Right, Left); + + return (Result); +} + +COVERAGE(HMM_MultiplyVec4fOpLeft, 1) +HMM_INLINE hmm_vec4 operator*(float Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4fOpLeft); + + hmm_vec4 Result = HMM_PREFIX(MultiplyVec4f)(Right, Left); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4fOpLeft, 1) +HMM_INLINE hmm_mat4 operator*(float Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4fOpLeft); + + hmm_mat4 Result = HMM_PREFIX(MultiplyMat4f)(Right, Left); + + return (Result); +} + +COVERAGE(HMM_MultiplyQuaternionFOpLeft, 1) +HMM_INLINE hmm_quaternion operator*(float Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionFOpLeft); + + hmm_quaternion Result = HMM_PREFIX(MultiplyQuaternionF)(Right, Left); + + return (Result); +} + +COVERAGE(HMM_MultiplyMat4ByVec4Op, 1) +HMM_INLINE hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + ASSERT_COVERED(HMM_MultiplyMat4ByVec4Op); + + hmm_vec4 Result = HMM_PREFIX(MultiplyMat4ByVec4)(Matrix, Vector); + + return (Result); +} + +COVERAGE(HMM_DivideVec2Op, 1) +HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_DivideVec2Op); + + hmm_vec2 Result = HMM_PREFIX(DivideVec2)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec3Op, 1) +HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_DivideVec3Op); + + hmm_vec3 Result = HMM_PREFIX(DivideVec3)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec4Op, 1) +HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_DivideVec4Op); + + hmm_vec4 Result = HMM_PREFIX(DivideVec4)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec2fOp, 1) +HMM_INLINE hmm_vec2 operator/(hmm_vec2 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec2fOp); + + hmm_vec2 Result = HMM_PREFIX(DivideVec2f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec3fOp, 1) +HMM_INLINE hmm_vec3 operator/(hmm_vec3 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec3fOp); + + hmm_vec3 Result = HMM_PREFIX(DivideVec3f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideVec4fOp, 1) +HMM_INLINE hmm_vec4 operator/(hmm_vec4 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec4fOp); + + hmm_vec4 Result = HMM_PREFIX(DivideVec4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideMat4fOp, 1) +HMM_INLINE hmm_mat4 operator/(hmm_mat4 Left, float Right) +{ + ASSERT_COVERED(HMM_DivideMat4fOp); + + hmm_mat4 Result = HMM_PREFIX(DivideMat4f)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_DivideQuaternionFOp, 1) +HMM_INLINE hmm_quaternion operator/(hmm_quaternion Left, float Right) +{ + ASSERT_COVERED(HMM_DivideQuaternionFOp); + + hmm_quaternion Result = HMM_PREFIX(DivideQuaternionF)(Left, Right); + + return (Result); +} + +COVERAGE(HMM_AddVec2Assign, 1) +HMM_INLINE hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_AddVec2Assign); + + return (Left = Left + Right); +} + +COVERAGE(HMM_AddVec3Assign, 1) +HMM_INLINE hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_AddVec3Assign); + + return (Left = Left + Right); +} + +COVERAGE(HMM_AddVec4Assign, 1) +HMM_INLINE hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_AddVec4Assign); + + return (Left = Left + Right); +} + +COVERAGE(HMM_AddMat4Assign, 1) +HMM_INLINE hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_AddMat4Assign); + + return (Left = Left + Right); +} + +COVERAGE(HMM_AddQuaternionAssign, 1) +HMM_INLINE hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_AddQuaternionAssign); + + return (Left = Left + Right); +} + +COVERAGE(HMM_SubtractVec2Assign, 1) +HMM_INLINE hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_SubtractVec2Assign); + + return (Left = Left - Right); +} + +COVERAGE(HMM_SubtractVec3Assign, 1) +HMM_INLINE hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_SubtractVec3Assign); + + return (Left = Left - Right); +} + +COVERAGE(HMM_SubtractVec4Assign, 1) +HMM_INLINE hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_SubtractVec4Assign); + + return (Left = Left - Right); +} + +COVERAGE(HMM_SubtractMat4Assign, 1) +HMM_INLINE hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_SubtractMat4Assign); + + return (Left = Left - Right); +} + +COVERAGE(HMM_SubtractQuaternionAssign, 1) +HMM_INLINE hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_SubtractQuaternionAssign); + + return (Left = Left - Right); +} + +COVERAGE(HMM_MultiplyVec2Assign, 1) +HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2Assign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyVec3Assign, 1) +HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3Assign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyVec4Assign, 1) +HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4Assign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyVec2fAssign, 1) +HMM_INLINE hmm_vec2 &operator*=(hmm_vec2 &Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec2fAssign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyVec3fAssign, 1) +HMM_INLINE hmm_vec3 &operator*=(hmm_vec3 &Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec3fAssign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyVec4fAssign, 1) +HMM_INLINE hmm_vec4 &operator*=(hmm_vec4 &Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyVec4fAssign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyMat4fAssign, 1) +HMM_INLINE hmm_mat4 &operator*=(hmm_mat4 &Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4fAssign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_MultiplyQuaternionFAssign, 1) +HMM_INLINE hmm_quaternion &operator*=(hmm_quaternion &Left, float Right) +{ + ASSERT_COVERED(HMM_MultiplyQuaternionFAssign); + + return (Left = Left * Right); +} + +COVERAGE(HMM_DivideVec2Assign, 1) +HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_DivideVec2Assign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideVec3Assign, 1) +HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_DivideVec3Assign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideVec4Assign, 1) +HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_DivideVec4Assign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideVec2fAssign, 1) +HMM_INLINE hmm_vec2 &operator/=(hmm_vec2 &Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec2fAssign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideVec3fAssign, 1) +HMM_INLINE hmm_vec3 &operator/=(hmm_vec3 &Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec3fAssign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideVec4fAssign, 1) +HMM_INLINE hmm_vec4 &operator/=(hmm_vec4 &Left, float Right) +{ + ASSERT_COVERED(HMM_DivideVec4fAssign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideMat4fAssign, 1) +HMM_INLINE hmm_mat4 &operator/=(hmm_mat4 &Left, float Right) +{ + ASSERT_COVERED(HMM_DivideMat4fAssign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_DivideQuaternionFAssign, 1) +HMM_INLINE hmm_quaternion &operator/=(hmm_quaternion &Left, float Right) +{ + ASSERT_COVERED(HMM_DivideQuaternionFAssign); + + return (Left = Left / Right); +} + +COVERAGE(HMM_EqualsVec2Op, 1) +HMM_INLINE hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_EqualsVec2Op); + + return HMM_PREFIX(EqualsVec2)(Left, Right); +} + +COVERAGE(HMM_EqualsVec3Op, 1) +HMM_INLINE hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_EqualsVec3Op); + + return HMM_PREFIX(EqualsVec3)(Left, Right); +} + +COVERAGE(HMM_EqualsVec4Op, 1) +HMM_INLINE hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_EqualsVec4Op); + + return HMM_PREFIX(EqualsVec4)(Left, Right); +} + +COVERAGE(HMM_EqualsVec2OpNot, 1) +HMM_INLINE hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right) +{ + ASSERT_COVERED(HMM_EqualsVec2OpNot); + + return !HMM_PREFIX(EqualsVec2)(Left, Right); +} + +COVERAGE(HMM_EqualsVec3OpNot, 1) +HMM_INLINE hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right) +{ + ASSERT_COVERED(HMM_EqualsVec3OpNot); + + return !HMM_PREFIX(EqualsVec3)(Left, Right); +} + +COVERAGE(HMM_EqualsVec4OpNot, 1) +HMM_INLINE hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right) +{ + ASSERT_COVERED(HMM_EqualsVec4OpNot); + + return !HMM_PREFIX(EqualsVec4)(Left, Right); +} + +#endif /* __cplusplus */ + +#if defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#endif /* HANDMADE_MATH_H */ + +#ifdef HANDMADE_MATH_IMPLEMENTATION + +COVERAGE(HMM_Power, 2) +float HMM_PREFIX(Power)(float Base, int Exponent) +{ + ASSERT_COVERED(HMM_Power); + + float Result = 1.0f; + float Mul = Exponent < 0 ? 1.f / Base : Base; + int X = Exponent < 0 ? -Exponent : Exponent; + while (X) + { + if (X & 1) + { + ASSERT_COVERED(HMM_Power); + + Result *= Mul; + } + + Mul *= Mul; + X >>= 1; + } + + return (Result); +} + +#ifndef HANDMADE_MATH__USE_SSE +COVERAGE(HMM_Transpose, 1) +hmm_mat4 HMM_PREFIX(Transpose)(hmm_mat4 Matrix) +{ + ASSERT_COVERED(HMM_Transpose); + + hmm_mat4 Result; + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows]; + } + } + + return (Result); +} +#endif + +#ifndef HANDMADE_MATH__USE_SSE +COVERAGE(HMM_AddMat4, 1) +hmm_mat4 HMM_PREFIX(AddMat4)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_AddMat4); + + hmm_mat4 Result; + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows]; + } + } + + return (Result); +} +#endif + +#ifndef HANDMADE_MATH__USE_SSE +COVERAGE(HMM_SubtractMat4, 1) +hmm_mat4 HMM_PREFIX(SubtractMat4)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_SubtractMat4); + + hmm_mat4 Result; + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows]; + } + } + + return (Result); +} +#endif + +COVERAGE(HMM_MultiplyMat4, 1) +hmm_mat4 HMM_PREFIX(MultiplyMat4)(hmm_mat4 Left, hmm_mat4 Right) +{ + ASSERT_COVERED(HMM_MultiplyMat4); + + hmm_mat4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.Columns[0] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[0], Left); + Result.Columns[1] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[1], Left); + Result.Columns[2] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[2], Left); + Result.Columns[3] = HMM_PREFIX(LinearCombineSSE)(Right.Columns[3], Left); +#else + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + float Sum = 0; + int CurrentMatrice; + for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice) + { + Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice]; + } + + Result.Elements[Columns][Rows] = Sum; + } + } +#endif + + return (Result); +} + +#ifndef HANDMADE_MATH__USE_SSE +COVERAGE(HMM_MultiplyMat4f, 1) +hmm_mat4 HMM_PREFIX(MultiplyMat4f)(hmm_mat4 Matrix, float Scalar) +{ + ASSERT_COVERED(HMM_MultiplyMat4f); + + hmm_mat4 Result; + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar; + } + } + + return (Result); +} +#endif + +COVERAGE(HMM_MultiplyMat4ByVec4, 1) +hmm_vec4 HMM_PREFIX(MultiplyMat4ByVec4)(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + ASSERT_COVERED(HMM_MultiplyMat4ByVec4); + + hmm_vec4 Result; + +#ifdef HANDMADE_MATH__USE_SSE + Result.InternalElementsSSE = HMM_PREFIX(LinearCombineSSE)(Vector.InternalElementsSSE, Matrix); +#else + int Columns, Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + float Sum = 0; + for(Columns = 0; Columns < 4; ++Columns) + { + Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns]; + } + + Result.Elements[Rows] = Sum; + } +#endif + + return (Result); +} + +#ifndef HANDMADE_MATH__USE_SSE +COVERAGE(HMM_DivideMat4f, 1); +hmm_mat4 HMM_PREFIX(DivideMat4f)(hmm_mat4 Matrix, float Scalar) +{ + ASSERT_COVERED(HMM_DivideMat4f); + + hmm_mat4 Result; + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar; + } + } + + return (Result); +} +#endif + +COVERAGE(HMM_Rotate, 1) +hmm_mat4 HMM_PREFIX(Rotate)(float Angle, hmm_vec3 Axis) +{ + ASSERT_COVERED(HMM_Rotate); + + hmm_mat4 Result = HMM_PREFIX(Mat4d)(1.0f); + + Axis = HMM_PREFIX(NormalizeVec3)(Axis); + + float SinTheta = HMM_PREFIX(SinF)(HMM_PREFIX(ToRadians)(Angle)); + float CosTheta = HMM_PREFIX(CosF)(HMM_PREFIX(ToRadians)(Angle)); + float CosValue = 1.0f - CosTheta; + + Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta; + Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta); + Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta); + + Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta); + Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta; + Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta); + + Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta); + Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta); + Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta; + + return (Result); +} + +COVERAGE(HMM_LookAt, 1) +hmm_mat4 HMM_PREFIX(LookAt)(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up) +{ + ASSERT_COVERED(HMM_LookAt); + + hmm_mat4 Result; + + hmm_vec3 F = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(SubtractVec3)(Center, Eye)); + hmm_vec3 S = HMM_PREFIX(NormalizeVec3)(HMM_PREFIX(Cross)(F, Up)); + hmm_vec3 U = HMM_PREFIX(Cross)(S, F); + + Result.Elements[0][0] = S.X; + Result.Elements[0][1] = U.X; + Result.Elements[0][2] = -F.X; + Result.Elements[0][3] = 0.0f; + + Result.Elements[1][0] = S.Y; + Result.Elements[1][1] = U.Y; + Result.Elements[1][2] = -F.Y; + Result.Elements[1][3] = 0.0f; + + Result.Elements[2][0] = S.Z; + Result.Elements[2][1] = U.Z; + Result.Elements[2][2] = -F.Z; + Result.Elements[2][3] = 0.0f; + + Result.Elements[3][0] = -HMM_PREFIX(DotVec3)(S, Eye); + Result.Elements[3][1] = -HMM_PREFIX(DotVec3)(U, Eye); + Result.Elements[3][2] = HMM_PREFIX(DotVec3)(F, Eye); + Result.Elements[3][3] = 1.0f; + + return (Result); +} + +COVERAGE(HMM_InverseQuaternion, 1) +hmm_quaternion HMM_PREFIX(InverseQuaternion)(hmm_quaternion Left) +{ + ASSERT_COVERED(HMM_InverseQuaternion); + + hmm_quaternion Conjugate; + hmm_quaternion Result; + float Norm = 0; + float NormSquared = 0; + + Conjugate.X = -Left.X; + Conjugate.Y = -Left.Y; + Conjugate.Z = -Left.Z; + Conjugate.W = Left.W; + + Norm = HMM_PREFIX(SquareRootF)(HMM_PREFIX(DotQuaternion)(Left, Left)); + NormSquared = Norm * Norm; + + Result = HMM_PREFIX(DivideQuaternionF)(Conjugate, NormSquared); + + return (Result); +} + +COVERAGE(HMM_Slerp, 1) +hmm_quaternion HMM_PREFIX(Slerp)(hmm_quaternion Left, float Time, hmm_quaternion Right) +{ + ASSERT_COVERED(HMM_Slerp); + + hmm_quaternion Result; + hmm_quaternion QuaternionLeft; + hmm_quaternion QuaternionRight; + + float Cos_Theta = HMM_PREFIX(DotQuaternion)(Left, Right); + float Angle = HMM_PREFIX(ACosF)(Cos_Theta); + + float S1 = HMM_PREFIX(SinF)((1.0f - Time) * Angle); + float S2 = HMM_PREFIX(SinF)(Time * Angle); + float Is = 1.0f / HMM_PREFIX(SinF)(Angle); + + QuaternionLeft = HMM_PREFIX(MultiplyQuaternionF)(Left, S1); + QuaternionRight = HMM_PREFIX(MultiplyQuaternionF)(Right, S2); + + Result = HMM_PREFIX(AddQuaternion)(QuaternionLeft, QuaternionRight); + Result = HMM_PREFIX(MultiplyQuaternionF)(Result, Is); + + return (Result); +} + +COVERAGE(HMM_QuaternionToMat4, 1) +hmm_mat4 HMM_PREFIX(QuaternionToMat4)(hmm_quaternion Left) +{ + ASSERT_COVERED(HMM_QuaternionToMat4); + + hmm_mat4 Result; + + hmm_quaternion NormalizedQuaternion = HMM_PREFIX(NormalizeQuaternion)(Left); + + float XX, YY, ZZ, + XY, XZ, YZ, + WX, WY, WZ; + + XX = NormalizedQuaternion.X * NormalizedQuaternion.X; + YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y; + ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z; + XY = NormalizedQuaternion.X * NormalizedQuaternion.Y; + XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z; + YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z; + WX = NormalizedQuaternion.W * NormalizedQuaternion.X; + WY = NormalizedQuaternion.W * NormalizedQuaternion.Y; + WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z; + + Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ); + Result.Elements[0][1] = 2.0f * (XY + WZ); + Result.Elements[0][2] = 2.0f * (XZ - WY); + Result.Elements[0][3] = 0.0f; + + Result.Elements[1][0] = 2.0f * (XY - WZ); + Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ); + Result.Elements[1][2] = 2.0f * (YZ + WX); + Result.Elements[1][3] = 0.0f; + + Result.Elements[2][0] = 2.0f * (XZ + WY); + Result.Elements[2][1] = 2.0f * (YZ - WX); + Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY); + Result.Elements[2][3] = 0.0f; + + Result.Elements[3][0] = 0.0f; + Result.Elements[3][1] = 0.0f; + Result.Elements[3][2] = 0.0f; + Result.Elements[3][3] = 1.0f; + + return (Result); +} + +// This method taken from Mike Day at Insomniac Games. +// https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf +// +// Note that as mentioned at the top of the paper, the paper assumes the matrix +// would be *post*-multiplied to a vector to rotate it, meaning the matrix is +// the transpose of what we're dealing with. But, because our matrices are +// stored in column-major order, the indices *appear* to match the paper. +// +// For example, m12 in the paper is row 1, column 2. We need to transpose it to +// row 2, column 1. But, because the column comes first when referencing +// elements, it looks like M.Elements[1][2]. +// +// Don't be confused! Or if you must be confused, at least trust this +// comment. :) +COVERAGE(HMM_Mat4ToQuaternion, 4) +hmm_quaternion HMM_PREFIX(Mat4ToQuaternion)(hmm_mat4 M) +{ + float T; + hmm_quaternion Q; + + if (M.Elements[2][2] < 0.0f) { + if (M.Elements[0][0] > M.Elements[1][1]) { + ASSERT_COVERED(HMM_Mat4ToQuaternion); + + T = 1 + M.Elements[0][0] - M.Elements[1][1] - M.Elements[2][2]; + Q = HMM_PREFIX(Quaternion)( + T, + M.Elements[0][1] + M.Elements[1][0], + M.Elements[2][0] + M.Elements[0][2], + M.Elements[1][2] - M.Elements[2][1] + ); + } else { + ASSERT_COVERED(HMM_Mat4ToQuaternion); + + T = 1 - M.Elements[0][0] + M.Elements[1][1] - M.Elements[2][2]; + Q = HMM_PREFIX(Quaternion)( + M.Elements[0][1] + M.Elements[1][0], + T, + M.Elements[1][2] + M.Elements[2][1], + M.Elements[2][0] - M.Elements[0][2] + ); + } + } else { + if (M.Elements[0][0] < -M.Elements[1][1]) { + ASSERT_COVERED(HMM_Mat4ToQuaternion); + + T = 1 - M.Elements[0][0] - M.Elements[1][1] + M.Elements[2][2]; + Q = HMM_PREFIX(Quaternion)( + M.Elements[2][0] + M.Elements[0][2], + M.Elements[1][2] + M.Elements[2][1], + T, + M.Elements[0][1] - M.Elements[1][0] + ); + } else { + ASSERT_COVERED(HMM_Mat4ToQuaternion); + + T = 1 + M.Elements[0][0] + M.Elements[1][1] + M.Elements[2][2]; + Q = HMM_PREFIX(Quaternion)( + M.Elements[1][2] - M.Elements[2][1], + M.Elements[2][0] - M.Elements[0][2], + M.Elements[0][1] - M.Elements[1][0], + T + ); + } + } + + Q = HMM_PREFIX(MultiplyQuaternionF)(Q, 0.5f / HMM_PREFIX(SquareRootF)(T)); + + return Q; +} + +COVERAGE(HMM_QuaternionFromAxisAngle, 1) +hmm_quaternion HMM_PREFIX(QuaternionFromAxisAngle)(hmm_vec3 Axis, float AngleOfRotation) +{ + ASSERT_COVERED(HMM_QuaternionFromAxisAngle); + + hmm_quaternion Result; + + hmm_vec3 AxisNormalized = HMM_PREFIX(NormalizeVec3)(Axis); + float SineOfRotation = HMM_PREFIX(SinF)(AngleOfRotation / 2.0f); + + Result.XYZ = HMM_PREFIX(MultiplyVec3f)(AxisNormalized, SineOfRotation); + Result.W = HMM_PREFIX(CosF)(AngleOfRotation / 2.0f); + + return (Result); +} + +#endif /* HANDMADE_MATH_IMPLEMENTATION */ \ No newline at end of file diff --git a/src/app/interface.h b/src/app/interface.h index 653138f..d382f4c 100644 --- a/src/app/interface.h +++ b/src/app/interface.h @@ -5,7 +5,7 @@ // #ifndef INTERFACE_H -enum string_alignment +enum gs_string_alignment { Align_Left, Align_Center, @@ -60,10 +60,10 @@ DrawCharacterRightAligned (render_quad_batch_constructor* BatchConstructor, char } internal v2 -DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; - char* C = String; + char* C = gs_string; for (s32 i = 0; i < Length; i++) { v2 PositionAfterCharacter = DrawCharacterLeftAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); @@ -74,10 +74,10 @@ DrawStringLeftAligned (render_quad_batch_constructor* BatchConstructor, s32 Leng } internal v2 -DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* String, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) +DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Length, char* gs_string, v2 InitialRegisterPosition, bitmap_font* Font, v4 Color) { v2 RegisterPosition = InitialRegisterPosition; - char* C = String + Length - 1; + char* C = gs_string + Length - 1; for (s32 i = Length - 1; i >= 0; i--) { v2 PositionAfterCharacter = DrawCharacterRightAligned(BatchConstructor, *C, *Font, RegisterPosition, Color); @@ -88,7 +88,7 @@ DrawStringRightAligned (render_quad_batch_constructor* BatchConstructor, s32 Len } internal v2 -DrawString (render_command_buffer* RenderBuffer, string String, bitmap_font* Font, v2 Position, v4 Color, string_alignment Alignment = Align_Left) +DrawString(render_command_buffer* RenderBuffer, gs_string String, bitmap_font* Font, v2 Position, v4 Color, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; v2 LowerRight = Position; @@ -129,7 +129,7 @@ DrawCursor (render_quad_batch_constructor* BatchConstructor, v2 Position, v4 Col } internal v2 -DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, string_alignment Alignment = Align_Left) +Drawgs_stringWithCursor (render_command_buffer* RenderBuffer, gs_string String, s32 CursorPosition, bitmap_font* Font, v2 Position, v4 Color, v4 CursorColor, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; v2 LowerRight = Position; @@ -153,21 +153,21 @@ DrawStringWithCursor (render_command_buffer* RenderBuffer, string String, s32 Cu { RegisterPosition = DrawStringLeftAligned(&BatchConstructor, String.Length - CursorPosition, - String.Memory + CursorPosition, + String.Str + CursorPosition, RegisterPosition, Font, Color); } } else if (Alignment == Align_Right) { RegisterPosition = DrawStringRightAligned(&BatchConstructor, - CursorPosition, String.Memory, + CursorPosition, String.Str, RegisterPosition, Font, Color); DrawCursor(&CursorBatch, RegisterPosition, GreenV4, *Font); if (String.Length - CursorPosition > 0) { RegisterPosition = DrawStringRightAligned(&BatchConstructor, String.Length - CursorPosition, - String.Memory + CursorPosition, + String.Str + CursorPosition, RegisterPosition, Font, Color); } } @@ -201,7 +201,7 @@ struct interface_config struct ui_layout { - rect Bounds; + rect2 Bounds; v2 Margin; r32 RowHeight; r32 RowYAt; @@ -220,7 +220,7 @@ struct ui_interface }; static ui_layout -ui_CreateLayout(ui_interface Interface, rect Bounds) +ui_CreateLayout(ui_interface Interface, rect2 Bounds) { ui_layout Result = {0}; Result.Bounds = Bounds; @@ -263,7 +263,7 @@ ui_EndRow(ui_layout* Layout) } static b32 -ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds) +ui_TryReserveElementBounds(ui_layout* Layout, rect2* Bounds) { b32 Result = true; if (!Layout->DrawHorizontal) @@ -289,7 +289,7 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds) } else { - r32 ElementWidth = gs_Width(Layout->Bounds) / Layout->ColumnsMax; + r32 ElementWidth = Rect2Width(Layout->Bounds) / Layout->ColumnsMax; Bounds->Min = { Layout->Bounds.Min.x + (ElementWidth * Layout->ColumnsCount) + Layout->Margin.x, Layout->RowYAt @@ -309,18 +309,18 @@ ui_TryReserveElementBounds(ui_layout* Layout, rect* Bounds) return Result; } -static rect -ui_ReserveTextLineBounds(ui_interface Interface, string Text, ui_layout* Layout) +static rect2 +ui_ReserveTextLineBounds(ui_interface Interface, gs_string Text, ui_layout* Layout) { - rect Bounds = {0}; + rect2 Bounds = {0}; return Bounds; } -static rect +static rect2 ui_ReserveElementBounds(ui_layout* Layout) { - rect Bounds = {0}; + rect2 Bounds = {0}; if (!ui_TryReserveElementBounds(Layout, &Bounds)) { InvalidCodePath; @@ -328,10 +328,10 @@ ui_ReserveElementBounds(ui_layout* Layout) return Bounds; } -static rect +static rect2 ui_LayoutRemaining(ui_layout Layout) { - rect Result = Layout.Bounds; + rect2 Result = Layout.Bounds; Result.Max.y = Layout.RowYAt; if (Layout.DrawHorizontal) { @@ -339,24 +339,32 @@ ui_LayoutRemaining(ui_layout Layout) } return Result; } + // // Drawing Functions // -static void -ui_FillRect(ui_interface* Interface, rect Bounds, v4 Color) +static r32 +ui_GetTextLineHeight(ui_interface Interface) { - PushRenderQuad2D(Interface->RenderBuffer, gs_RectExpand(Bounds), Color); + r32 Result = Interface.Style.Font->PixelHeight + (2 * Interface.Style.Margin.y); + return Result; } static void -ui_OutlineRect(ui_interface* Interface, rect Bounds, r32 Thickness, v4 Color) +ui_FillRect(ui_interface* Interface, rect2 Bounds, v4 Color) +{ + PushRenderQuad2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Color); +} + +static void +ui_OutlineRect(ui_interface* Interface, rect2 Bounds, r32 Thickness, v4 Color) { PushRenderBoundingBox2D(Interface->RenderBuffer, Bounds.Min, Bounds.Max, Thickness, Color); } internal void -ui_DrawString(ui_interface* Interface, string String, rect Bounds, v4 Color, string_alignment Alignment = Align_Left) +ui_DrawString(ui_interface* Interface, gs_string String, rect2 Bounds, v4 Color, gs_string_alignment Alignment = Align_Left) { DEBUG_TRACK_FUNCTION; render_quad_batch_constructor BatchConstructor = PushRenderTexture2DBatch(Interface->RenderBuffer, @@ -384,9 +392,9 @@ ui_DrawString(ui_interface* Interface, string String, rect Bounds, v4 Color, str } static void -ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, string String, v4 Color, string_alignment Alignment = Align_Left) +ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, gs_string String, v4 Color, gs_string_alignment Alignment = Align_Left) { - rect Bounds = {0}; + rect2 Bounds = {0}; if (!ui_TryReserveElementBounds(Layout, &Bounds)) { // TODO(NAME): Not invalid, just haven't implemented yet. @@ -397,18 +405,18 @@ ui_LayoutDrawString(ui_interface* Interface, ui_layout* Layout, string String, v } static void -ui_TextBox(ui_interface* Interface, rect Bounds, string Text, v4 BGColor, v4 TextColor) +ui_TextBox(ui_interface* Interface, rect2 Bounds, gs_string Text, v4 BGColor, v4 TextColor) { ui_FillRect(Interface, Bounds, BGColor); ui_DrawString(Interface, Text, Bounds, TextColor); } static b32 -ui_Button(ui_interface* Interface, string Text, rect Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) +ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds, v4 InactiveColor, v4 HoverColor, v4 ClickedColor) { b32 Pressed = false; v4 ButtonBG = InactiveColor; - if (gs_PointIsInRect(Interface->Mouse.Pos, Bounds)) + if (PointIsInRect(Bounds, Interface->Mouse.Pos)) { ButtonBG = HoverColor; if (MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState)) @@ -422,7 +430,7 @@ ui_Button(ui_interface* Interface, string Text, rect Bounds, v4 InactiveColor, v } static b32 -ui_Button(ui_interface* Interface, string Text, rect Bounds) +ui_Button(ui_interface* Interface, gs_string Text, rect2 Bounds) { v4 BGColor = Interface->Style.ButtonColor_Inactive; v4 HoverColor = Interface->Style.ButtonColor_Active; @@ -430,25 +438,12 @@ ui_Button(ui_interface* Interface, string Text, rect Bounds) return ui_Button(Interface, Text, Bounds, BGColor, HoverColor, SelectedColor); } -static b32 -ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, string Text, v4 BGColor, v4 HoverColor, v4 SelectColor) +struct list_item_colors { - rect ButtonBounds = {0}; - if (!ui_TryReserveElementBounds(Layout, &ButtonBounds)) - { - ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout); - } - return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor); -} - -static b32 -ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, string Text) -{ - v4 BGColor = Interface->Style.ButtonColor_Inactive; - v4 HoverColor = Interface->Style.ButtonColor_Active; - v4 SelectedColor = Interface->Style.ButtonColor_Selected; - return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor); -} + v4 Hover; + v4 Selected; + v4 BGColor; +}; inline v4 ui_GetListItemBGColor(interface_config Style, u32 ElementIndex) @@ -457,10 +452,54 @@ ui_GetListItemBGColor(interface_config Style, u32 ElementIndex) return Result; } -static b32 -ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, string Text, u32 Index) +static list_item_colors +ui_GetListItemColors(ui_interface* Interface, u32 ListItemIndex) { - rect Bounds = {0}; + list_item_colors Result = {}; + Result.Hover = Interface->Style.ListBGHover; + Result.Selected = Interface->Style.ListBGSelected; + Result.BGColor = ui_GetListItemBGColor(Interface->Style, ListItemIndex); + return Result; +} + +static b32 +ui_ListButton(ui_interface* Interface, gs_string Text, rect2 Bounds, u32 ListItemIndex) +{ + list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); + return ui_Button(Interface, Text, Bounds, Colors.Hover, Colors.Selected, Colors.BGColor); +} + +static b32 +ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, v4 BGColor, v4 HoverColor, v4 SelectColor) +{ + rect2 ButtonBounds = {0}; + if (!ui_TryReserveElementBounds(Layout, &ButtonBounds)) + { + ButtonBounds = ui_ReserveTextLineBounds(*Interface, Text, Layout); + } + return ui_Button(Interface, Text, ButtonBounds, BGColor, HoverColor, SelectColor); +} + +static b32 +ui_LayoutButton(ui_interface* Interface, ui_layout* Layout, gs_string Text) +{ + v4 BGColor = Interface->Style.ButtonColor_Inactive; + v4 HoverColor = Interface->Style.ButtonColor_Active; + v4 SelectedColor = Interface->Style.ButtonColor_Selected; + return ui_LayoutButton(Interface, Layout, Text, BGColor, HoverColor, SelectedColor); +} + +static b32 +ui_LayoutListButton(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 ListItemIndex) +{ + list_item_colors Colors = ui_GetListItemColors(Interface, ListItemIndex); + return ui_LayoutButton(Interface, Layout, Text, Colors.Hover, Colors.Selected, Colors.BGColor); +} + +static b32 +ui_LayoutListEntry(ui_interface* Interface, ui_layout* Layout, gs_string Text, u32 Index) +{ + rect2 Bounds = {0}; if (!ui_TryReserveElementBounds(Layout, &Bounds)) { // TODO(Peter): this isn't really invalid, but I don't have a concrete use case @@ -488,7 +527,7 @@ enum selection_state struct interface_list { - rect ListBounds; + rect2 ListBounds; v2 ListElementDimensions; v2 ElementLabelIndent; @@ -501,10 +540,10 @@ struct interface_list s32 ListElementsCount; }; -internal rect +internal rect2 DrawListElementBackground(interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer) { - rect LineBounds = {}; + rect2 LineBounds = {}; LineBounds.Min = v2{ List->ListBounds.Min.x, List->ListBounds.Max.y - (List->ListElementDimensions.y * (List->ListElementsCount + 1)) @@ -512,7 +551,7 @@ DrawListElementBackground(interface_list* List, mouse_state Mouse, render_comman LineBounds.Max = LineBounds.Min + List->ListElementDimensions; v4 Color = List->LineBGColors[List->ListElementsCount % List->LineBGColorsCount]; - if (PointIsInRange(Mouse.Pos, LineBounds.Min, LineBounds.Max)) + if (PointIsInRect(LineBounds, Mouse.Pos)) { Color = List->LineBGHoverColor; } @@ -521,10 +560,10 @@ DrawListElementBackground(interface_list* List, mouse_state Mouse, render_comman return LineBounds; } -internal rect -DrawListElement(string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) +internal rect2 +DrawListElement(gs_string Label, interface_list* List, mouse_state Mouse, render_command_buffer* RenderBuffer, interface_config Interface) { - rect Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); + rect2 Bounds = DrawListElementBackground(List, Mouse, RenderBuffer); v2 LabelPosition = Bounds.Min + List->ElementLabelIndent; DrawString(RenderBuffer, Label, Interface.Font, LabelPosition, List->TextColor); @@ -539,27 +578,34 @@ EvaluateColorChannelSlider (render_command_buffer* RenderBuffer, v4 ChannelMask, { r32 Result = Current; + // TODO(Peter): Can this come from outside the function? Would rather pass rect around than min/max + rect2 Rect = rect2{ Min, Max }; + render_quad_batch_constructor Batch = PushRenderQuad2DBatch(RenderBuffer, 2); v4 LeftColor = ChannelMask * 0; LeftColor.a = 1.f; v4 RightColor = ChannelMask; PushQuad2DOnBatch(&Batch, - Min, v2{Max.x, Min.y}, Max, v2{Min.x, Max.y}, + RectBottomLeft(Rect), RectBottomRight(Rect), + RectTopRight(Rect), RectTopLeft(Rect), v2{0, 0}, v2{1, 0}, v2{1, 1}, v2{0, 1}, LeftColor, RightColor, RightColor, LeftColor); if (MouseButtonTransitionedDown(Mouse.LeftButtonState)) { - if (PointIsInRange(Mouse.DownPos, Min, Max)) + if (PointIsInRect(Rect, Mouse.DownPos)) { Result = ((r32)Mouse.Pos.x - Min.x) / (Max.x - Min.x); - Result = GSClamp01(Result); + Result = Clamp01(Result); } } r32 DragBarWidth = 8; - v2 DragBarMin = v2{GSLerp(Min.x, Max.x, Result) - (DragBarWidth / 2), Min.y - 2}; + v2 DragBarMin = v2{ + LerpR32(Result, Min.x, Max.x) - (DragBarWidth / 2), + Min.y - 2 + }; v2 DragBarMax = DragBarMin + v2{DragBarWidth, (Max.y - Min.y) + 4}; PushQuad2DOnBatch(&Batch, DragBarMin, DragBarMax, v4{.3f, .3f, .3f, 1.f}); @@ -573,16 +619,18 @@ EvaluateColorPicker (render_command_buffer* RenderBuffer, v4* Value, v2 PanelMin b32 ShouldClose = false; v2 PanelMax = v2{400, 500}; - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRange(Mouse.Pos, PanelMin, PanelMax)) + // TODO(Peter): Can this get passed from outside? rather pass rect2 than min/max pairs + rect2 PanelRect = rect2{PanelMin, PanelMax}; + if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && !PointIsInRect(PanelRect, Mouse.Pos)) { ShouldClose = true; } else { - PushRenderQuad2D(RenderBuffer, PanelMin, PanelMax, v4{.5f, .5f, .5f, 1.f}); + PushRenderQuad2D(RenderBuffer, PanelRect.Min, PanelRect.Max, v4{.5f, .5f, .5f, 1.f}); - v2 TitleMin = v2{PanelMin.x + 5, PanelMax.y - (Config.Font->PixelHeight + 5)}; - DrawString(RenderBuffer, MakeStringLiteral("Color Picker"), Config.Font, + v2 TitleMin = v2{PanelRect.Min.x + 5, PanelRect.Max.y - (Config.Font->PixelHeight + 5)}; + DrawString(RenderBuffer, MakeString("Color Picker"), Config.Font, TitleMin, WhiteV4); v2 SliderDim = v2{(PanelMax.x - PanelMin.x) - 20, 32}; @@ -611,13 +659,13 @@ struct search_lister_result b32 ShouldRemainOpen; }; -typedef string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, string SearchString, s32 Offset); +typedef gs_string search_lister_get_list_item_at_offset(u8* ListMemory, s32 ListLength, gs_string Searchgs_string, s32 Offset); internal search_lister_result -EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string Title, - string* ItemList, s32* ListLUT, s32 ListLength, +EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, gs_string Title, + gs_string* ItemList, s32* ListLUT, s32 ListLength, s32 HotItem, - string* SearchString, s32 SearchStringCursorPosition) + gs_string* Searchgs_string, s32 Searchgs_stringCursorPosition) { search_lister_result Result = {}; Result.ShouldRemainOpen = true; @@ -627,24 +675,24 @@ EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string InvalidCodePath; #if 0 // Title Bar - rect TitleBarBounds = rect{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; + rect2 TitleBarBounds = rect2{v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}}; ui_FillRect(Interface, TitleBarBounds, v4{.3f, .3f, .3f, 1.f}); - ui_DrawString(Interface, Title, TitleBarBounds, Interface->Style.TextColor); + ui_Drawgs_string(Interface, Title, TitleBarBounds, Interface->Style.TextColor); - MakeStringBuffer(DebugString, 256); - PrintF(&DebugString, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); - rect DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); - ui_DrawString(Interface, DebugString, DebugBounds, Interface->Style.TextColor); + MakeStringBuffer(Debuggs_string, 256); + PrintF(&Debuggs_string, "Hot Item: %d | Filtered Items: %d", HotItem, ListLength); + rect2 DebugBounds = MakeRectMinWidth(v2{ TopLeft.x + 256, TopLeft.y - 25}, v2{256, Interface->Style.LineHeight}); + ui_Drawgs_string(Interface, Debuggs_string, DebugBounds, Interface->Style.TextColor); // Search Bar PushRenderQuad2D(RenderBuffer, v2{TopLeft.x, TopLeft.y - 30}, v2{TopLeft.x + 300, TopLeft.y}, v4{.3f, .3f, .3f, 1.f}); - DrawStringWithCursor(RenderBuffer, *SearchString, SearchStringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4); + Drawgs_stringWithCursor(RenderBuffer, *Searchgs_string, Searchgs_stringCursorPosition, Font, v2{TopLeft.x, TopLeft.y - 25}, WhiteV4, GreenV4); TopLeft.y -= 30; for (s32 i = 0; i < ListLength; i++) { s32 FilteredIndex = ListLUT[i]; - string ListItemString = ItemList[FilteredIndex]; + gs_string ListItemgs_string = ItemList[FilteredIndex]; v2 Min = v2{TopLeft.x, TopLeft.y - 30}; v2 Max = Min + Dimension - v2{0, Config.Margin.y}; @@ -655,7 +703,7 @@ EvaluateSearchLister (ui_interface* Interface, v2 TopLeft, v2 Dimension, string ButtonColor = Config.ButtonColor_Active; } - if (ui_Button(Interface, ListItemString, rect{Min, Max})) + if (ui_Button(Interface, ListItemgs_string, rect2{Min, Max})) { Result.SelectedItem = i; } diff --git a/src/app/panels/foldhaus_panel_animation_timeline.h b/src/app/panels/foldhaus_panel_animation_timeline.h deleted file mode 100644 index 36b23fc..0000000 --- a/src/app/panels/foldhaus_panel_animation_timeline.h +++ /dev/null @@ -1,616 +0,0 @@ -// -// File: foldhaus_panel_animation_timeline.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_PANEL_ANIMATION_TIMELINE_H - -// Colors -global_variable v4 TimeSliderColor = v4{.36f, .52f, .78f, 1.f}; - -// -struct animation_timeline_state -{ - frame_range VisibleRange; -}; - -inline u32 -GetFrameFromPointInAnimationPanel(v2 Point, rect PanelBounds, frame_range VisibleRange) -{ - r32 HorizontalPercentOfBounds = (Point.x - PanelBounds.Min.x) / (PanelBounds.Max.x - PanelBounds.Min.x); - u32 VisibleFramesCount = GetFrameCount(VisibleRange); - u32 TimeAtPoint = (u32)(HorizontalPercentOfBounds * VisibleFramesCount) + VisibleRange.Min; - return TimeAtPoint; -} - -inline s32 -GetXPositionFromFrameInAnimationPanel (u32 Frame, rect PanelBounds, frame_range VisibleRange) -{ - r32 PercentOfTimeline = (r32)(Frame - VisibleRange.Min) / (r32)GetFrameCount(VisibleRange); - s32 XPositionAtFrame = (PercentOfTimeline * gs_Width(PanelBounds)) + PanelBounds.Min.x; - return XPositionAtFrame; -} - -internal gs_list_handle -AddAnimationBlockAtCurrentTime (u32 AnimationProcHandle, u32 Layer, animation_system* System) -{ - u32 NewBlockStart = System->CurrentFrame; - u32 NewBlockEnd = NewBlockStart + SecondsToFrames(3, *System); - gs_list_handle Result = AddAnimationBlock(NewBlockStart, NewBlockEnd, AnimationProcHandle, Layer, System); - return Result; -} - -internal void -SelectAnimationBlock(gs_list_handle BlockHandle, app_state* State) -{ - State->SelectedAnimationBlockHandle = BlockHandle; -} - -internal void -DeselectCurrentAnimationBlock(app_state* State) -{ - State->SelectedAnimationBlockHandle = {}; -} - -FOLDHAUS_INPUT_COMMAND_PROC(DeleteAnimationBlockCommand) -{ - if(ListHandleIsValid(State->SelectedAnimationBlockHandle)) - { - RemoveAnimationBlock(State->SelectedAnimationBlockHandle, &State->AnimationSystem); - State->SelectedAnimationBlockHandle = {0}; - } -} - -// -// 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; - frame_range Range = { OpState->StartFrame, OpState->EndFrame }; - u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, Range); - State->AnimationSystem.CurrentFrame = FrameAtMouseX; -} - -FOLDHAUS_INPUT_COMMAND_PROC(EndDragTimeMarker) -{ - DeactivateCurrentOperationMode(&State->Modes); -} - -input_command DragTimeMarkerCommands [] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndDragTimeMarker }, -}; - -internal void -StartDragTimeMarker(rect TimelineBounds, frame_range VisibleFrames, 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 = VisibleFrames.Min; - OpState->EndFrame = VisibleFrames.Max; - OpState->TimelineBounds = TimelineBounds; -} - -// -------------------- - -// -// Drag Animation Clip -// - -#define CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE 10 - -OPERATION_STATE_DEF(drag_animation_clip_state) -{ - rect TimelineBounds; - frame_range VisibleRange; - frame_range ClipRange; -}; - -internal u32 -AttemptToSnapPosition(u32 SnappingFrame, u32 SnapToFrame) -{ - u32 Result = SnappingFrame; - s32 SnapDistance = 5; - if (GSAbs((s32)SnappingFrame - (s32)SnapToFrame) <= SnapDistance) - { - Result = SnapToFrame; - } - return Result; -} - -OPERATION_RENDER_PROC(UpdateDragAnimationClip) -{ - drag_animation_clip_state* OpState = (drag_animation_clip_state*)Operation.OpStateMemory; - - r32 ClipInitialStartFrameXPercent = FrameToPercentRange(OpState->ClipRange.Min, OpState->VisibleRange); - u32 ClipInitialStartFrameXPosition = GSLerp(OpState->TimelineBounds.Min.x, - OpState->TimelineBounds.Max.x, - ClipInitialStartFrameXPercent); - r32 ClipInitialEndFrameXPercent = FrameToPercentRange(OpState->ClipRange.Max, OpState->VisibleRange); - u32 ClipInitialEndFrameXPosition = GSLerp(OpState->TimelineBounds.Min.x, - OpState->TimelineBounds.Max.x, - ClipInitialEndFrameXPercent); - - u32 FrameAtMouseDownX = GetFrameFromPointInAnimationPanel(Mouse.DownPos, OpState->TimelineBounds, OpState->VisibleRange); - - u32 FrameAtMouseX = GetFrameFromPointInAnimationPanel(Mouse.Pos, OpState->TimelineBounds, OpState->VisibleRange); - s32 FrameOffset = (s32)FrameAtMouseX - (s32)FrameAtMouseDownX; - - animation_block* AnimationBlock = State->AnimationSystem.Blocks.GetElementWithHandle(State->SelectedAnimationBlockHandle); - if (!AnimationBlock) - { - EndCurrentOperationMode(State, {}, Mouse); - return; - } - - if (GSAbs(Mouse.DownPos.x - ClipInitialStartFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) - { - s32 NewStartFrame = OpState->ClipRange.Min + FrameOffset; - if (FrameOffset < 0) - { - for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) - { - gs_list_entry* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); - if (EntryIsFree(OtherBlockEntry)) { continue; } - animation_block OtherBlock = OtherBlockEntry->Value; - NewStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max); - } - } - else - { - if (NewStartFrame >= AnimationBlock->Range.Max) - { - NewStartFrame = AnimationBlock->Range.Max - 1; - } - } - AnimationBlock->Range.Min = NewStartFrame; - } - else if (GSAbs(Mouse.DownPos.x - ClipInitialEndFrameXPosition) < CLICK_ANIMATION_BLOCK_EDGE_MAX_SCREEN_DISTANCE) - { - r32 NewEndFrame = OpState->ClipRange.Max + FrameOffset; - if (FrameOffset > 0) - { - for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) - { - gs_list_entry* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); - if (EntryIsFree(OtherBlockEntry)) { continue; } - animation_block OtherBlock = OtherBlockEntry->Value; - NewEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min); - } - } - else - { - if(NewEndFrame <= AnimationBlock->Range.Min) - { - NewEndFrame = AnimationBlock->Range.Min + 1; - } - } - AnimationBlock->Range.Max = NewEndFrame; - } - else - { - u32 NewStartFrame = OpState->ClipRange.Min + FrameOffset; - u32 NewEndFrame = OpState->ClipRange.Max + FrameOffset; - for (u32 i = 0; i < State->AnimationSystem.Blocks.Used; i++) - { - gs_list_entry* OtherBlockEntry = State->AnimationSystem.Blocks.GetEntryAtIndex(i); - if (EntryIsFree(OtherBlockEntry)) { continue; } - animation_block OtherBlock = OtherBlockEntry->Value; - - u32 SnapFramesAmount = 0; - if (FrameOffset > 0) - { - u32 FinalEndFrame = AttemptToSnapPosition(NewEndFrame, OtherBlock.Range.Min); - SnapFramesAmount = FinalEndFrame - NewEndFrame; - } - else if (FrameOffset < 0) - { - u32 FinalStartFrame = AttemptToSnapPosition(NewStartFrame, OtherBlock.Range.Max); - SnapFramesAmount = FinalStartFrame - NewStartFrame; - } - NewEndFrame += SnapFramesAmount; - NewStartFrame += SnapFramesAmount; - } - AnimationBlock->Range.Min = NewStartFrame; - AnimationBlock->Range.Max = NewEndFrame; - } - - s32 PlayableStartFrame = State->AnimationSystem.PlayableRange.Min; - s32 PlayableEndFrame = State->AnimationSystem.PlayableRange.Max; - AnimationBlock->Range.Min = (u32)GSClamp(PlayableStartFrame, (s32)AnimationBlock->Range.Min, PlayableEndFrame); - AnimationBlock->Range.Max = (u32)GSClamp(PlayableStartFrame, (s32)AnimationBlock->Range.Max, PlayableEndFrame); -} - -input_command DragAnimationClipCommands [] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Ended, EndCurrentOperationMode }, -}; - -internal void -SelectAndBeginDragAnimationBlock(gs_list_handle BlockHandle, frame_range VisibleRange, 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->VisibleRange = VisibleRange; - - animation_block* SelectedBlock = State->AnimationSystem.Blocks.GetElementWithHandle(BlockHandle); - OpState->ClipRange = SelectedBlock->Range; -} -// ------------------- - -FOLDHAUS_INPUT_COMMAND_PROC(AddAnimationBlockCommand) -{ - panel_and_bounds ActivePanel = GetPanelContainingPoint(Mouse.Pos, &State->PanelSystem, State->WindowBounds); - frame_range Range = State->AnimationSystem.PlayableRange; - u32 MouseDownFrame = GetFrameFromPointInAnimationPanel(Mouse.Pos, ActivePanel.Bounds, Range); - gs_list_handle NewBlockHandle = AddAnimationBlock(MouseDownFrame, MouseDownFrame + SecondsToFrames(3, State->AnimationSystem), 4, State->SelectedAnimationLayer, &State->AnimationSystem); - SelectAnimationBlock(NewBlockHandle, State); -} - -input_command AnimationTimeline_Commands[] = { - { KeyCode_X, KeyCode_Invalid, Command_Began, DeleteAnimationBlockCommand }, - { KeyCode_A, KeyCode_Invalid, Command_Began, AddAnimationBlockCommand }, -}; -s32 AnimationTimeline_CommandsCount = 2; - -GSMetaTag(panel_init); -GSMetaTag(panel_type_animation_timeline); -internal void -AnimationTimeline_Init(panel* Panel, app_state* State) -{ - // TODO: :FreePanelMemory - animation_timeline_state* TimelineState = PushStruct(&State->Permanent, animation_timeline_state); - TimelineState->VisibleRange = State->AnimationSystem.PlayableRange; - Panel->PanelStateMemory = (u8*)TimelineState; -} - -GSMetaTag(panel_cleanup); -GSMetaTag(panel_type_animation_timeline); -internal void -AnimationTimeline_Cleanup(panel* Panel, app_state* State) -{ - -} - -internal void -DrawFrameBar (animation_system* AnimationSystem, render_command_buffer* RenderBuffer, frame_range VisibleFrames, rect BarBounds, mouse_state Mouse, app_state* State) -{ - MakeStringBuffer(TempString, 256); - - s32 VisibleFrameCount = VisibleFrames.Max - VisibleFrames.Min; - - r32 BarHeight = gs_Height(BarBounds); - r32 BarWidth = gs_Width(BarBounds); - - PushRenderQuad2D(RenderBuffer, gs_RectExpand(BarBounds), v4{.16f, .16f, .16f, 1.f}); - - // Mouse clicked inside frame nubmer bar -> change current frame on timeline - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && - PointIsInRange(Mouse.DownPos, gs_RectExpand(BarBounds))) - { - StartDragTimeMarker(BarBounds, VisibleFrames, State); - } - - // Frame Ticks - u32 TickCount = 10; - for (u32 Tick = 0; Tick < TickCount; Tick++) - { - r32 Percent = (r32)Tick / (r32)TickCount; - u32 Frame = PercentToFrameInRange(Percent, VisibleFrames); - PrintF(&TempString, "%d", Frame); - r32 FramePercent = FrameToPercentRange(Frame, VisibleFrames); - r32 FrameX = GSLerp(BarBounds.Min.x, BarBounds.Max.x, FramePercent); - v2 FrameTextPos = v2{FrameX, BarBounds.Min.y + 2}; - DrawString(RenderBuffer, TempString, State->Interface.Font, FrameTextPos, WhiteV4); - } - - // Time Slider - if (FrameIsInRange(AnimationSystem->CurrentFrame, VisibleFrames)) - { - r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, VisibleFrames); - r32 SliderX = GSLerp(BarBounds.Min.x, BarBounds.Max.x, FrameAtPercentVisibleRange); - - u32 FrameNumberCharCount = GetU32NumberOfCharactersNeeded(AnimationSystem->CurrentFrame); - // space for each character + a margin on either side - r32 SliderWidth = (8 * FrameNumberCharCount) + 8; - r32 SliderHalfWidth = SliderWidth / 2.f; - v2 HeadMin = v2{SliderX - SliderHalfWidth, BarBounds.Min.y}; - v2 HeadMax = v2{SliderX + SliderHalfWidth, BarBounds.Max.y}; - PushRenderQuad2D(RenderBuffer, HeadMin, HeadMax, TimeSliderColor); - - PrintF(&TempString, "%d", AnimationSystem->CurrentFrame); - DrawString(RenderBuffer, TempString, State->Interface.Font, HeadMin + v2{6, 4}, WhiteV4); - } -} - -internal frame_range -DrawTimelineRangeBar (animation_system* AnimationSystem, animation_timeline_state* TimelineState, render_command_buffer* RenderBuffer, rect BarBounds, mouse_state Mouse) -{ - frame_range Result = {0}; - - r32 BarHeight = gs_Height(BarBounds); - r32 BarWidth = gs_Width(BarBounds); - PushRenderQuad2D(RenderBuffer, gs_RectExpand(BarBounds), v4{.16f, .16f, .16f, 1.f}); - - r32 PlayableFrames = (r32)GetFrameCount(AnimationSystem->PlayableRange); - v2 SliderBarDim = v2{25, BarHeight}; - - // Convert Frames To Pixels - r32 VisibleMinPercentPlayable = FrameToPercentRange(TimelineState->VisibleRange.Min, AnimationSystem->PlayableRange); - r32 VisibleMaxPercentPlayable = FrameToPercentRange(TimelineState->VisibleRange.Max, AnimationSystem->PlayableRange); - v2 RangeMinSliderMin = v2{BarBounds.Min.x + (VisibleMinPercentPlayable * gs_Width(BarBounds)), BarBounds.Min.y}; - v2 RangeMaxSliderMin = v2{BarBounds.Min.x + (VisibleMaxPercentPlayable * gs_Width(BarBounds)) - 25, BarBounds.Min.y}; - - if (MouseButtonHeldDown(Mouse.LeftButtonState) || - MouseButtonTransitionedUp(Mouse.LeftButtonState)) - { - v2 MouseDragOffset = Mouse.Pos - Mouse.DownPos; - if (PointIsInRange(Mouse.DownPos, RangeMinSliderMin, RangeMinSliderMin + SliderBarDim)) - { - r32 NewSliderX = RangeMinSliderMin.x + MouseDragOffset.x; - RangeMinSliderMin.x = GSClamp(BarBounds.Min.x, NewSliderX, RangeMaxSliderMin.x - SliderBarDim.x); - } - if (PointIsInRange(Mouse.DownPos, RangeMaxSliderMin, RangeMaxSliderMin + SliderBarDim)) - { - r32 NewSliderX = RangeMaxSliderMin.x + MouseDragOffset.x; - RangeMaxSliderMin.x = GSClamp(RangeMinSliderMin.x + SliderBarDim.x, NewSliderX, BarBounds.Max.x - SliderBarDim.x); - } - } - - v2 RangeMinSliderMax = v2{RangeMinSliderMin.x + 25, BarBounds.Max.y}; - v2 RangeMaxSliderMax = v2{RangeMaxSliderMin.x + 25, BarBounds.Max.y}; - PushRenderQuad2D(RenderBuffer, RangeMinSliderMin, RangeMinSliderMax, v4{.8f, .8f, .8f, 1.f}); - PushRenderQuad2D(RenderBuffer, RangeMaxSliderMin, RangeMaxSliderMax, v4{.8f, .8f, .8f, 1.f}); - - // Convert Pixels Back To Frames and store - VisibleMinPercentPlayable = (RangeMinSliderMin.x - BarBounds.Min.x) / BarWidth; - VisibleMaxPercentPlayable = (RangeMaxSliderMax.x - BarBounds.Min.x) / BarWidth; - u32 VisibleFrameCount = GetFrameCount(AnimationSystem->PlayableRange); - Result.Min = VisibleMinPercentPlayable * VisibleFrameCount; - Result.Max = VisibleMaxPercentPlayable * VisibleFrameCount; - - if (MouseButtonTransitionedUp(Mouse.LeftButtonState)) - { - TimelineState->VisibleRange = Result; - } - - return Result; -} - -#define LAYER_HEIGHT 52 - -internal void -DrawLayerMenu(animation_system* AnimationSystem, rect PanelDim, render_command_buffer* RenderBuffer, app_state* State, mouse_state Mouse) -{ - v2 LayerDim = { gs_Width(PanelDim), LAYER_HEIGHT }; - v2 LayerListMin = PanelDim.Min + v2{0, 24}; - for (u32 LayerIndex = 0; LayerIndex < AnimationSystem->LayersCount; LayerIndex++) - { - anim_layer* Layer = AnimationSystem->Layers + LayerIndex; - rect LayerBounds = {0}; - LayerBounds.Min = { LayerListMin.x, LayerListMin.y + (LayerDim.y * LayerIndex) }; - LayerBounds.Max = LayerBounds.Min + LayerDim; - - if (MouseButtonTransitionedDown(Mouse.LeftButtonState) && - gs_PointIsInRect(Mouse.Pos, LayerBounds)) - { - State->SelectedAnimationLayer = LayerIndex; - } - - v2 LayerTextPos = { LayerBounds.Min.x + 6, LayerBounds.Max.y - 16}; - if (State->SelectedAnimationLayer == LayerIndex) - { - PushRenderBoundingBox2D(RenderBuffer, gs_RectExpand(LayerBounds), 1, WhiteV4); - } - DrawString(RenderBuffer, Layer->Name, State->Interface.Font, LayerTextPos, WhiteV4); - } -} - -internal rect -DrawAnimationBlock (animation_block AnimationBlock, v4 BlockColor, frame_range VisibleFrames, rect TimelineBounds, render_command_buffer* RenderBuffer) -{ - rect BlockBounds = {}; - - r32 TimelineWidth = gs_Width(TimelineBounds); - - u32 ClampedBlockStartFrame = ClampFrameToRange(AnimationBlock.Range.Min, VisibleFrames); - r32 StartFramePercent = FrameToPercentRange(ClampedBlockStartFrame, VisibleFrames); - r32 StartPosition = TimelineWidth * StartFramePercent; - - u32 ClampedBlockEndFrame = ClampFrameToRange(AnimationBlock.Range.Max, VisibleFrames); - r32 EndFramePercent = FrameToPercentRange(ClampedBlockEndFrame, VisibleFrames); - r32 EndPosition = TimelineWidth * EndFramePercent; - - r32 LayerYOffset = LAYER_HEIGHT * AnimationBlock.Layer; - BlockBounds.Min = TimelineBounds.Min + v2{StartPosition, LayerYOffset}; - BlockBounds.Max = TimelineBounds.Min + v2{EndPosition, LayerYOffset + LAYER_HEIGHT}; - - PushRenderQuad2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, BlockColor); - PushRenderBoundingBox2D(RenderBuffer, BlockBounds.Min, BlockBounds.Max, 1, WhiteV4); - - return BlockBounds; -} - -internal gs_list_handle -DrawAnimationTimeline (animation_system* AnimationSystem, animation_timeline_state* TimelineState, rect PanelBounds, gs_list_handle SelectedBlockHandle, ui_interface* Interface, app_state* State) -{ - string TempString = MakeString(PushArray(&State->Transient, char, 256), 256); - gs_list_handle Result = SelectedBlockHandle; - - rect LayerMenuBounds, TimelineBounds; - gs_VSplitRectAtDistanceFromLeft(PanelBounds, 256, &LayerMenuBounds, &TimelineBounds); - - // In Top To Bottom Order - rect TimelineFrameBarBounds, TimelineBlockDisplayBounds, TimelineRangeBarBounds; - gs_HSplitRectAtDistanceFromTop(TimelineBounds, 32, &TimelineFrameBarBounds, &TimelineBounds); - gs_HSplitRectAtDistanceFromBottom(TimelineBounds, 24, &TimelineBlockDisplayBounds, &TimelineRangeBarBounds); - - // TODO(Peter): Clean Up - DrawLayerMenu(AnimationSystem, LayerMenuBounds, Interface->RenderBuffer, State, Interface->Mouse); - - frame_range AdjustedViewRange = {0}; - // TODO(Peter): Clean Up - AdjustedViewRange = DrawTimelineRangeBar(AnimationSystem, TimelineState, Interface->RenderBuffer, TimelineRangeBarBounds, Interface->Mouse); - s32 VisibleFrameCount = AdjustedViewRange.Max - AdjustedViewRange.Min; - - // TODO(Peter): Clean Up - DrawFrameBar(AnimationSystem, Interface->RenderBuffer, AdjustedViewRange, TimelineFrameBarBounds, Interface->Mouse, State); - - ui_FillRect(Interface, TimelineBlockDisplayBounds, v4{.25f, .25f, .25f, 1.0f}); - - // Animation Blocks - b32 MouseDownAndNotHandled = MouseButtonTransitionedDown(Interface->Mouse.LeftButtonState); - gs_list_handle DragBlockHandle = {0}; - for (u32 i = 0; i < AnimationSystem->Blocks.Used; i++) - { - gs_list_entry* AnimationBlockEntry = AnimationSystem->Blocks.GetEntryAtIndex(i); - if (EntryIsFree(AnimationBlockEntry)) { continue; } - - gs_list_handle CurrentBlockHandle = AnimationBlockEntry->Handle; - animation_block AnimationBlockAt = AnimationBlockEntry->Value; - - // If either end is in the range, we should draw it - b32 RangeIsVisible = (FrameIsInRange(AnimationBlockAt.Range.Min, AdjustedViewRange) || - FrameIsInRange(AnimationBlockAt.Range.Max, AdjustedViewRange)); - // If neither end is in the range, but the ends surround the visible range, - // we should still draw it. - RangeIsVisible |= (AnimationBlockAt.Range.Min <= AdjustedViewRange.Min && - AnimationBlockAt.Range.Max>= AdjustedViewRange.Max); - if (RangeIsVisible) - { - v4 BlockColor = BlackV4; - if (GSListHandlesAreEqual(SelectedBlockHandle, CurrentBlockHandle)) - { - BlockColor = PinkV4; - } - // TODO(Peter): Clean Up - rect BlockBounds = DrawAnimationBlock(AnimationBlockAt, BlockColor, AdjustedViewRange, TimelineBounds, Interface->RenderBuffer); - if (gs_PointIsInRect(Interface->Mouse.Pos, BlockBounds)) - { - DragBlockHandle = CurrentBlockHandle; - } - } - } - - if (MouseDownAndNotHandled && ListHandleIsValid(DragBlockHandle)) - { - MouseDownAndNotHandled = false; - // TODO(Peter): Why are we passing state around? - SelectAndBeginDragAnimationBlock(DragBlockHandle, AdjustedViewRange, TimelineBounds, State); - } - - // Time Slider - if (FrameIsInRange(AnimationSystem->CurrentFrame, AdjustedViewRange)) - { - r32 FrameAtPercentVisibleRange = FrameToPercentRange(AnimationSystem->CurrentFrame, AdjustedViewRange); - r32 SliderX = GSLerp(TimelineBounds.Min.x, TimelineBounds.Max.x, FrameAtPercentVisibleRange); - rect SliderBounds = { - v2{ SliderX, TimelineBounds.Min.y }, - v2{ SliderX + 1, TimelineBounds.Max.y } - }; - ui_FillRect(Interface, SliderBounds, TimeSliderColor); - } - - ui_OutlineRect(Interface, TimelineRangeBarBounds, 1.f, RedV4); - ui_OutlineRect(Interface, TimelineFrameBarBounds, 1.f, RedV4); - ui_OutlineRect(Interface, TimelineBlockDisplayBounds, 1.f, RedV4); - - if (MouseDownAndNotHandled && gs_PointIsInRect(Interface->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, ui_interface* Interface, u32 SelectedAnimationLayer, animation_system* AnimationSystem) -{ - ui_layout Layout = ui_CreateLayout(*Interface, PanelBounds); - for (s32 i = 0; i < GlobalAnimationClipsCount; i++) - { - animation_clip Clip = GlobalAnimationClips[i]; - string ClipName = MakeString(Clip.Name, Clip.NameLength); - if (ui_LayoutListEntry(Interface, &Layout, ClipName, i)) - { - AddAnimationBlockAtCurrentTime(i + 1, SelectedAnimationLayer, AnimationSystem); - } - } - // TODO(Peter): Fill up the rest of the area with empty list entries -} - -GSMetaTag(panel_render); -GSMetaTag(panel_type_animation_timeline); -internal void -AnimationTimeline_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) -{ - animation_timeline_state* TimelineState = (animation_timeline_state*)Panel.PanelStateMemory; - gs_list_handle SelectedBlockHandle = State->SelectedAnimationBlockHandle; - - ui_interface* Interface = &State->Interface_; - animation_system* AnimationSystem = &State->AnimationSystem; - - rect TitleBarBounds, PanelContentsBounds; - gs_HSplitRectAtDistanceFromTop(PanelBounds, Interface->Style.RowHeight, &TitleBarBounds, &PanelContentsBounds); - rect AnimationListBounds, TimelineBounds; - gs_VSplitRectAtDistanceFromLeft(PanelContentsBounds, 300, &AnimationListBounds, &TimelineBounds); - - ui_FillRect(Interface, TitleBarBounds, Interface->Style.PanelBGColors[0]); - ui_layout TitleBarLayout = ui_CreateLayout(*Interface, TitleBarBounds); - ui_StartRow(&TitleBarLayout, 3); - { - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Pause"))) - { - State->AnimationSystem.TimelineShouldAdvance = true; - } - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Play"))) - { - State->AnimationSystem.TimelineShouldAdvance = false; - } - if (ui_LayoutButton(Interface, &TitleBarLayout, MakeStringLiteral("Stop"))) - { - State->AnimationSystem.TimelineShouldAdvance = false; - State->AnimationSystem.CurrentFrame = 0; - } - } - ui_EndRow(&TitleBarLayout); - - if (gs_Height(TimelineBounds) > 0) - { - SelectedBlockHandle = DrawAnimationTimeline(AnimationSystem, TimelineState, TimelineBounds, SelectedBlockHandle, Interface, State); - DrawAnimationClipsList(AnimationListBounds, Interface, State->SelectedAnimationLayer, &State->AnimationSystem); - } -} - -#define FOLDHAUS_PANEL_ANIMATION_TIMELINE_H -#endif // FOLDHAUS_PANEL_ANIMATION_TIMELINE_H \ No newline at end of file diff --git a/src/app/panels/foldhaus_panel_file_view.h b/src/app/panels/foldhaus_panel_file_view.h deleted file mode 100644 index 658435b..0000000 --- a/src/app/panels/foldhaus_panel_file_view.h +++ /dev/null @@ -1,56 +0,0 @@ -// -// File: foldhaus_panel_file_view.h -// Author: Peter Slattery -// Creation Date: 2020-03-08 -// -#ifndef FOLDHAUS_PANEL_FILE_VIEW_H - -struct file_view_state -{ - string WorkingDirectory; -}; - -input_command* FileView_Commands = 0; -s32 FileView_CommandsCount = 0; - -GSMetaTag(panel_init); -GSMetaTag(panel_type_file_view); -internal void -FileView_Init(panel* Panel, app_state* State) -{ - // TODO: :FreePanelMemory - file_view_state* FileViewState = PushStruct(&State->Permanent, file_view_state); - FileViewState->WorkingDirectory = MakeString(PushArray(&State->Permanent, char, 256), 256); - PrintF(&FileViewState->WorkingDirectory, "C:\\"); - Panel->PanelStateMemory = (u8*)FileViewState; -} - -GSMetaTag(panel_cleanup); -GSMetaTag(panel_type_file_view); -internal void -FileView_Cleanup(panel* Panel, app_state* State) -{ - -} - -GSMetaTag(panel_render); -GSMetaTag(panel_type_file_view); -internal void -FileView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) -{ - rect HeaderBounds = {0}; - HeaderBounds.Min = {PanelBounds.Min.x, PanelBounds.Max.y - 32}; - HeaderBounds.Max = PanelBounds.Max; - - rect ListBounds = {0}; - ListBounds.Min = PanelBounds.Min; - ListBounds.Max = gs_BottomRight(HeaderBounds); - - PushRenderQuad2D(RenderBuffer, gs_RectExpand(HeaderBounds), PinkV4); - PushRenderQuad2D(RenderBuffer, gs_RectExpand(ListBounds), RedV4); -} - - - -#define FOLDHAUS_PANEL_FILE_VIEW_H -#endif // FOLDHAUS_PANEL_FILE_VIEW_H \ No newline at end of file diff --git a/src/app/panels/foldhaus_panel_hierarchy.h b/src/app/panels/foldhaus_panel_hierarchy.h deleted file mode 100644 index 6f1ff6f..0000000 --- a/src/app/panels/foldhaus_panel_hierarchy.h +++ /dev/null @@ -1,87 +0,0 @@ -// -// File: foldhaus_panel_hierarchy.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_PANEL_HIERARCHY_H - -input_command HierarchyView_Commands[] = {{}}; -s32 HierarchyView_CommandsCount = 0; - -GSMetaTag(panel_init); -GSMetaTag(panel_type_hierarchy); -internal void -HierarchyView_Init(panel* Panel, app_state* State) -{ - -} - -GSMetaTag(panel_cleanup); -GSMetaTag(panel_type_hierarchy); -internal void -HierarchyView_Cleanup(panel* Panel, app_state* State) -{ - -} - -GSMetaTag(panel_render); -GSMetaTag(panel_type_hierarchy); -internal void -HierarchyView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) -{ - ui_layout Layout = ui_CreateLayout(State->Interface_, PanelBounds); - v4 ListItemHover = State->Interface_.Style.ListBGHover; - v4 ListItemSelected = State->Interface_.Style.ListBGSelected; - - string TempString = MakeString(PushArray(&State->Transient, char, 256), 0, 256); - - u32 LineCount = (u32)(gs_Height(PanelBounds) / Layout.RowHeight) + 1; - u32 LinesDrawn = 0; - u32 AssembliesToDraw = GSMin(LineCount, State->ActiveAssemblyIndecies.Used); - for (; LinesDrawn < AssembliesToDraw; LinesDrawn++) - { - rect Bounds = ui_ReserveElementBounds(&Layout); - v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn); - ui_FillRect(&State->Interface_, Bounds, ListItemBGColor); - gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(LinesDrawn); - assembly Assembly = *State->AssemblyList.GetElementWithHandle(AssemblyHandle); - PrintF(&TempString, "%S", Assembly.Name); - - ui_layout ItemLayout = ui_CreateLayout(State->Interface_, Bounds); - ui_StartRow(&ItemLayout, 2); - { - ui_LayoutDrawString(&State->Interface_, &ItemLayout, TempString, State->Interface_.Style.TextColor); - if (ui_LayoutButton(&State->Interface_, &ItemLayout, MakeStringLiteral("X"), ListItemBGColor, ListItemHover, ListItemSelected)) - { - UnloadAssembly(AssemblyHandle.Index, State, Context); - } - } - ui_EndRow(&ItemLayout); - } - - if (LinesDrawn < LineCount) - { - v4 ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn++); - PrintF(&TempString, "+ Add Assembly"); - if (ui_LayoutButton(&State->Interface_, &Layout, TempString, ListItemBGColor, ListItemHover, ListItemSelected)) - { - char FilePath[256]; - b32 Success = Context.PlatformGetFilePath(FilePath, 256, "Foldhaus Files\0*.fold\0\0"); - if (Success) - { - LoadAssembly(State, Context, FilePath); - } - } - - for (; LinesDrawn < LineCount; LinesDrawn++) - { - rect Bounds = ui_ReserveElementBounds(&Layout); - ListItemBGColor = ui_GetListItemBGColor(State->Interface_.Style, LinesDrawn); - ui_FillRect(&State->Interface_, Bounds, ListItemBGColor); - } - } -} - - -#define FOLDHAUS_PANEL_HIERARCHY_H -#endif // FOLDHAUS_PANEL_HIERARCHY_H diff --git a/src/app/panels/foldhaus_panel_sculpture_view.h b/src/app/panels/foldhaus_panel_sculpture_view.h deleted file mode 100644 index 880b2f8..0000000 --- a/src/app/panels/foldhaus_panel_sculpture_view.h +++ /dev/null @@ -1,184 +0,0 @@ -// -// File: foldhaus_panel_sculpture_view.h -// Author: Peter Slattery -// Creation Date: 2020-01-01 -// -#ifndef FOLDHAUS_PANEL_SCULPTURE_VIEW_H - -// 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); -} - -// ---------------- - -GSMetaTag(panel_commands); -GSMetaTag(panel_type_sculpture_view); -global_variable input_command SculptureView_Commands[] = { - { KeyCode_MouseLeftButton, KeyCode_Invalid, Command_Began, Begin3DViewMouseRotate }, -}; -global_variable s32 SculptureView_CommandsCount = 1; - -GSMetaTag(panel_init); -GSMetaTag(panel_type_sculpture_view); -internal void -SculptureView_Init(panel* Panel, app_state* State) -{ - -} - -GSMetaTag(panel_cleanup); -GSMetaTag(panel_type_sculpture_view); -internal void -SculptureView_Cleanup(panel* Panel, app_state* State) -{ - -} - - -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++; - } -} - -GSMetaTag(panel_render); -GSMetaTag(panel_type_sculpture_view); -internal void -SculptureView_Render(panel Panel, rect PanelBounds, render_command_buffer* RenderBuffer, app_state* State, context Context, mouse_state Mouse) -{ - 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; - - u32 MaxLEDsPerJob = 2048; - render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount); - - for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) - { - gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); - assembly Assembly = *State->AssemblyList.GetElementWithHandle(AssemblyHandle); - u32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDBuffer.LEDCount, MaxLEDsPerJob); - - for (u32 Job = 0; Job < JobsNeeded; Job++) - { - draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data); - JobData->LEDs = Assembly.LEDBuffer.LEDs; - JobData->Colors = Assembly.LEDBuffer.Colors; - JobData->StartIndex = Job * MaxLEDsPerJob; - JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDBuffer.LEDCount); - JobData->Batch = &RenderLEDsBatch; - JobData->FaceCameraMatrix; - JobData->ModelViewMatrix = ModelViewMatrix; - JobData->LEDHalfWidth = LEDHalfWidth; - - Context.GeneralWorkQueue->PushWorkOnQueue(Context.GeneralWorkQueue, DrawLEDsInBufferRangeJob, JobData, "Sculpture Draw LEDS"); - } - } - Context.GeneralWorkQueue->DoQueueWorkUntilDone(Context.GeneralWorkQueue, 0); -} - -#define FOLDHAUS_PANEL_SCULPTURE_VIEW_H -#endif // FOLDHAUS_PANEL_SCULPTURE_VIEW_H \ No newline at end of file diff --git a/src/app/gs_osx.mm b/src/app/platform_osx/gs_osx.mm similarity index 100% rename from src/app/gs_osx.mm rename to src/app/platform_osx/gs_osx.mm diff --git a/src/app/gs_osx_fileio.mm b/src/app/platform_osx/gs_osx_fileio.mm similarity index 100% rename from src/app/gs_osx_fileio.mm rename to src/app/platform_osx/gs_osx_fileio.mm diff --git a/src/app/gs_osx_lib.mm b/src/app/platform_osx/gs_osx_lib.mm similarity index 100% rename from src/app/gs_osx_lib.mm rename to src/app/platform_osx/gs_osx_lib.mm diff --git a/src/app/gs_osx_memory.mm b/src/app/platform_osx/gs_osx_memory.mm similarity index 100% rename from src/app/gs_osx_memory.mm rename to src/app/platform_osx/gs_osx_memory.mm diff --git a/src/app/gs_osx_opengl.mm b/src/app/platform_osx/gs_osx_opengl.mm similarity index 100% rename from src/app/gs_osx_opengl.mm rename to src/app/platform_osx/gs_osx_opengl.mm diff --git a/src/app/gs_osx_time.mm b/src/app/platform_osx/gs_osx_time.mm similarity index 100% rename from src/app/gs_osx_time.mm rename to src/app/platform_osx/gs_osx_time.mm diff --git a/src/app/gs_osx_window.mm b/src/app/platform_osx/gs_osx_window.mm similarity index 96% rename from src/app/gs_osx_window.mm rename to src/app/platform_osx/gs_osx_window.mm index 3b0d29c..eefafd3 100644 --- a/src/app/gs_osx_window.mm +++ b/src/app/platform_osx/gs_osx_window.mm @@ -67,7 +67,7 @@ gsosx_CreateWindow(NSApplication* App, int Width, int Height, id Title) [App setMainMenu: MenuBar]; NSMenu* AppMenu = [NSMenu alloc]; - id QuitTitle = [@"Quit " stringByAppendingString: Title]; + id QuitTitle = [@"Quit " gs_stringByAppendinggs_string: Title]; id QuitMenuItem = [[NSMenuItem alloc] initWithTitle: QuitTitle action: @selector(terminate:) keyEquivalent: @"q"]; [AppMenu addItem: QuitMenuItem]; [AppMenuItem setSubmenu: AppMenu]; diff --git a/src/app/win32_foldhaus.cpp b/src/app/platform_win32/win32_foldhaus.cpp similarity index 68% rename from src/app/win32_foldhaus.cpp rename to src/app/platform_win32/win32_foldhaus.cpp index cf2f5c1..653dbe6 100644 --- a/src/app/win32_foldhaus.cpp +++ b/src/app/platform_win32/win32_foldhaus.cpp @@ -11,19 +11,23 @@ #include #include -#include "../meta/gs_meta_include.h" -#include "foldhaus_platform.h" +#include "../../meta/gs_meta_include.h" +#include "../foldhaus_platform.h" -#include "../gs_libs/gs_win32.cpp" +#include "../../gs_libs/gs_win32.cpp" +#include "win32_foldhaus_utils.h" #include "win32_foldhaus_memory.h" #include "win32_foldhaus_fileio.h" #include "win32_foldhaus_dll.h" #include "win32_foldhaus_timing.h" +#include "win32_foldhaus_work_queue.h" +#include "win32_foldhaus_serial.h" +#include "win32_foldhaus_socket.h" -#include "foldhaus_renderer.cpp" +#include "../foldhaus_renderer.cpp" -global_variable b32 Running = false; -global_variable b32 WindowIsActive = false; +global b32 Running = false; +global b32 WindowIsActive = false; char DLLName[] = "foldhaus.dll"; char WorkingDLLName[] = "foldhaus_temp.dll"; @@ -31,224 +35,12 @@ char DLLLockFileName[] = "lock.tmp"; window MainWindow; -struct worker_thread_entry -{ - b32 IsValid; - u32 Index; -}; - -struct worker_thread_info -{ - s32 ID; - HANDLE Handle; - work_queue* Queue; -}; - -PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue) -{ -#ifdef DEBUG - // NOTE(Peter): Just prints out the names of all the pending jobs if we end up - // overflowing the buffer - if (Queue->JobsCount >= Queue->JobsMax) - { - string DebugString = MakeString((char*)malloc(256), 256); - for (u32 i = 0; i < Queue->JobsCount; i++) - { - PrintF(&DebugString, "%d %s\n", i, Queue->Jobs[i].JobName); - NullTerminate(&DebugString); - OutputDebugStringA(DebugString.Memory); - } - } -#endif - Assert(Queue->JobsCount < Queue->JobsMax); - - worker_thread_job* Job = Queue->Jobs + Queue->JobsCount; - Job->WorkProc = WorkProc; - Job->Data = Data; -#ifdef DEBUG - Job->JobName = JobName; -#endif - - // Complete Past Writes before Future Writes - _WriteBarrier(); - _mm_sfence(); - - ++Queue->JobsCount; - ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0); -} - -internal worker_thread_entry -CompleteAndTakeNextJob(work_queue* Queue, worker_thread_entry Completed) -{ - if (Completed.IsValid) - { - InterlockedIncrement((LONG volatile*)&Queue->JobsCompleted); - } - - worker_thread_entry Result = {}; - Result.IsValid = false; - - u32 OriginalNextJobIndex = Queue->NextJobIndex; - while (OriginalNextJobIndex < Queue->JobsCount) - { - u32 Index = InterlockedCompareExchange((LONG volatile*)&Queue->NextJobIndex, - OriginalNextJobIndex + 1, - OriginalNextJobIndex); - if (Index == OriginalNextJobIndex) - { - Result.Index = Index; - Result.IsValid = true; - break; - } - OriginalNextJobIndex = Queue->NextJobIndex; - } - - return Result; -} - -DO_QUEUE_WORK_UNTIL_DONE(Win32DoQueueWorkUntilDone) -{ - worker_thread_entry Entry = {}; - Entry.IsValid = false; - while (Queue->JobsCompleted < Queue->JobsCount) - { - Entry = CompleteAndTakeNextJob(Queue, Entry); - if (Entry.IsValid) - { - Queue->Jobs[Entry.Index].WorkProc(ThreadID, Queue->Jobs[Entry.Index].Data); - } - } -} - -DWORD WINAPI -WorkerThreadProc (LPVOID InputThreadInfo) -{ - worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo; - - worker_thread_entry Entry = {}; - Entry.IsValid = false; - while (true) - { - Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry); - if (Entry.IsValid) - { - ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ID, - ThreadInfo->Queue->Jobs[Entry.Index].Data); - } - else - { - WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0); - } - } - - return 0; -} - PLATFORM_GET_GPU_TEXTURE_HANDLE(Win32GetGPUTextureHandle) { s32 Handle = SubmitTexture(Memory, Width, Height); return Handle; } -struct win32_socket -{ - SOCKET Socket; -}; - -#define SOCKET_DICTIONARY_GROW_SIZE 32 -s32 Win32SocketHandleMax; -s32 Win32SocketHandleCount; -win32_socket* SocketValues; - -PLATFORM_SET_SOCKET_OPTION(Win32SetSocketOption) -{ - s32 SocketIndex = (s32)SocketHandle; - Assert(SocketIndex < Win32SocketHandleCount); - int Error = setsockopt(SocketValues[SocketIndex].Socket, Level, Option, OptionValue, OptionLength); - if (Error == SOCKET_ERROR) - { - Error = WSAGetLastError(); - // TODO(Peter): :ErrorLogging - } - - return Error; -} - -PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) -{ - // NOTE(Peter): These used to be passed in as paramters, but we only use this function - // with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values - // so I was having to include windows.h in the platform agnostic code to accomodate that - // function signature. - s32 AddressFamily = AF_INET; - s32 Type = SOCK_DGRAM; - s32 Protocol = 0; - - if (Win32SocketHandleCount >= Win32SocketHandleMax) - { - s32 NewDictionaryMax = Win32SocketHandleMax + SOCKET_DICTIONARY_GROW_SIZE; - s32 NewDictionaryDataSize = NewDictionaryMax * sizeof(win32_socket); - u8* DictionaryMemory = Win32Alloc(NewDictionaryDataSize); - Assert(DictionaryMemory); - - win32_socket* NewValues = (win32_socket*)(DictionaryMemory); - if (SocketValues) - { - GSMemCopy(SocketValues, NewValues, sizeof(win32_socket) * NewDictionaryMax); - Win32Free((u8*)SocketValues, sizeof(win32_socket) * Win32SocketHandleCount); - } - SocketValues = NewValues; - - Win32SocketHandleMax = NewDictionaryMax; - } - - Assert(Win32SocketHandleCount < Win32SocketHandleMax); - s32 NewSocketIndex = Win32SocketHandleCount++; - - SocketValues[NewSocketIndex].Socket = socket(AddressFamily, Type, Protocol); - - int Error = Win32SetSocketOption(NewSocketIndex, IPPROTO_IP, IP_MULTICAST_TTL, - (const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive)); - - return (platform_socket_handle)NewSocketIndex; -} - -PLATFORM_SEND_TO(Win32SendTo) -{ - s32 SocketIndex = (s32)SocketHandle; - Assert(SocketIndex < Win32SocketHandleCount); - - sockaddr_in SockAddress = {}; - SockAddress.sin_family = AF_INET; - SockAddress.sin_port = HostToNetU16(Port); - SockAddress.sin_addr.s_addr = HostToNetU32(Address); - - s32 LengthSent = sendto(SocketValues[SocketIndex].Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in)); - - if (LengthSent == SOCKET_ERROR) - { - s32 Error = WSAGetLastError(); - if (Error == 10051) - { - } - else - { - // TODO(Peter): :ErrorLogging - InvalidCodePath; - } - } - - return LengthSent; -} - -PLATFORM_CLOSE_SOCKET(Win32CloseSocket) -{ - s32 SocketIndex = (s32)SocketHandle; - Assert(SocketIndex < Win32SocketHandleCount); - - closesocket(SocketValues[SocketIndex].Socket); -} - HDC FontDrawingDC; HBITMAP FontBitmap; HFONT CurrentFont; @@ -265,7 +57,7 @@ GET_FONT_INFO(Win32GetFontInfo) CurrentFont = CreateFont(PixelHeight, 0, 0, 0, FontWeight, - Italic, + Italic, Underline, Strikeout, ANSI_CHARSET, @@ -311,7 +103,7 @@ DRAW_FONT_CODEPOINT(Win32DrawFontCodepoint) COLORREF PixelColor; for (u32 Y = 0; Y < *OutHeight; Y++) { - // NOTE(Peter): XOffset * 4 b/c its 4 bytes per pixel. + // NOTE(Peter): XOffset * 4 b/c its 4 bytes per pixel. u8* Channel = (u8*)Row + (XOffset * 4); for (u32 X = 0; X < *OutWidth; X++) { @@ -392,7 +184,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true, + AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true, ShiftDown, AltDown, CtrlDown, false); Mouse->LeftButtonState = KeyState_IsDown & ~KeyState_WasDown; @@ -414,7 +206,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, false, true, + AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, false, true, ShiftDown, AltDown, CtrlDown, false); Mouse->MiddleButtonState = KeyState_IsDown & ~KeyState_WasDown; @@ -428,7 +220,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, false, true, + AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, false, true, ShiftDown, AltDown, CtrlDown, false); Mouse->RightButtonState = KeyState_IsDown & ~KeyState_WasDown; Mouse->DownPos = Mouse->Pos; @@ -443,7 +235,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false, + AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, true, false, ShiftDown, AltDown, CtrlDown, false); Mouse->LeftButtonState = ~KeyState_IsDown & KeyState_WasDown; @@ -457,7 +249,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, true, false, + AddInputEventEntry(InputQueue, KeyCode_MouseMiddleButton, true, false, ShiftDown, AltDown, CtrlDown, false); Mouse->MiddleButtonState = ~KeyState_IsDown & KeyState_WasDown; @@ -471,7 +263,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 AltDown = GetKeyState(VK_MENU) & 0x8000; b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; - AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, true, false, + AddInputEventEntry(InputQueue, KeyCode_MouseRightButton, true, false, ShiftDown, AltDown, CtrlDown, false); Mouse->RightButtonState = ~KeyState_IsDown & KeyState_WasDown; @@ -496,7 +288,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse b32 CtrlDown = GetKeyState(VK_CONTROL) & 0x8000; // New Input Queue - AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown, + AddInputEventEntry(InputQueue, Key, KeyWasDown, KeyIsDown, ShiftDown, AltDown, CtrlDown, false); }break; @@ -512,7 +304,7 @@ internal void DebugPrint (char* Format, ...) { char Buffer[256]; - string StringBuffer = MakeString(Buffer, 256); + gs_string StringBuffer = MakeString(Buffer, 256); va_list Args; va_start(Args, Format); PrintF(&StringBuffer, Format, Args); @@ -521,7 +313,7 @@ DebugPrint (char* Format, ...) } internal void -SetApplicationLinks (context* Context, win32_dll_refresh DLL, work_queue* WorkQueue) +SetApplicationLinks (context* Context, win32_dll_refresh DLL, gs_work_queue* WorkQueue) { if (DLL.IsValid) { @@ -539,30 +331,25 @@ SetApplicationLinks (context* Context, win32_dll_refresh DLL, work_queue* WorkQu } } +// TODO(Peter): :Redundant remove internal u8* DEBUGAlloc(s32 ElementSize, s32 ElementCount) { - return Win32Alloc(ElementSize * ElementCount); + return (u8*)Win32Alloc(ElementSize * ElementCount, 0); } +// TODO(Peter): :Redundant remove internal u8* Win32Realloc(u8* Buf, s32 OldSize, s32 NewSize) { - u8* NewMemory = Win32Alloc(NewSize); - GSMemCopy(Buf, NewMemory, OldSize); + u8* NewMemory = (u8*)Win32Alloc(NewSize, 0); + CopyMemoryTo(Buf, NewMemory, OldSize); return NewMemory; } -internal s32 -Win32GetThreadId() -{ - s32 Result = GetCurrentThreadId(); - return Result; -} - // NOTE(Peter): Only meant to take one of the values specified below: -// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, -// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, +// IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP, IDC_IBEAM, +// IDC_ICON, IDC_NO, IDC_SIZE, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, // IDC_SIZEWE, IDC_UPARROW, IDC_WAIT internal HCURSOR Win32LoadSystemCursor(char* CursorIdentifier) @@ -577,6 +364,65 @@ Win32LoadSystemCursor(char* CursorIdentifier) return Result; } +internal void +Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_list OutputData) +{ + DEBUG_TRACK_FUNCTION; + + u32 BuffersSent = 0; + + for (addressed_data_buffer* BufferAt = OutputData.Root; + BufferAt != 0; + BufferAt = BufferAt->Next) + { + switch(BufferAt->AddressType) + { + case AddressType_NetworkIP: + { + Win32Socket_SendTo(BufferAt->SendSocket, + BufferAt->V4SendAddress, + BufferAt->SendPort, + (const char*)BufferAt->Memory, + BufferAt->MemorySize, + 0); + }break; + + case AddressType_ComPort: + { + if (BufferAt->ComPort.Length > 0) + { + HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1); + if (SerialPort != INVALID_HANDLE_VALUE) + { + if (Win32SerialPort_Write(SerialPort, BufferAt->Data)) + { + BuffersSent += 1; + } + } + } + else + { + OutputDebugStringA("Skipping data buffer because its COM Port isn't set"); + } + }break; + + InvalidDefaultCase; + } + } + + gs_string OutputStr = AllocatorAllocString(Context.Allocator, 256); + PrintF(&OutputStr, "Buffers Sent: %d\n", BuffersSent); + NullTerminate(&OutputStr); + OutputDebugStringA(OutputStr.Str); +} + +internal void +Win32_SendAddressedDataBuffers_Job(gs_thread_context Context, gs_data Arg) +{ + addressed_data_buffer_list* OutputData = (addressed_data_buffer_list*)Arg.Memory; + Win32_SendAddressedDataBuffers(Context, *OutputData); +} + int WINAPI WinMain ( HINSTANCE HInstance, @@ -585,6 +431,36 @@ WinMain ( INT NCmdShow ) { + gs_thread_context ThreadContext = Win32CreateThreadContext(); + +#if 0 + u32 LedCount = 48; + u32 MessageBaseSize = sizeof(uart_header) + sizeof(uart_channel) + sizeof(uart_footer); + MessageBaseSize += sizeof(u8) * 3 * LedCount; + gs_data MessageBuffer = PushSizeToData(ThreadContext.Transient); + + gs_memory_cursor WriteCursor = CreateMemoryCursor(MessageBuffer); + + uart_header* Header = PushStructOnCursor(WriteCursor, uart_header); + UART_FillHeader(Header, Strip.UARTAddr.Channel, UART_SET_CHANNEL_WS2812); + uart_channel* Channel = PushStructOnCursor(WriteCursor, uart_channel); + *Channel = ChannelSettings; + + for (u32 i = 0; i < LedCount; i++) + { + u8* OutputPixel = PushArrayOnCursor(WriteCursor, u8, 3); + OutputPixel[Channel->RedIndex] = (u8)(i); + OutputPixel[Channel->GreenIndex] = 0; + OutputPixel[Channel->BlueIndex] = 0; + } + + uart_footer* Footer = PushStructOnCursor(WriteCursor, uart_footer); + UART_FillFooter(Footer, (u8*)Header); + +#endif + + + MainWindow = Win32CreateWindow (HInstance, "Foldhaus", 1440, 768, HandleWindowEvents); Win32UpdateWindowDimension(&MainWindow); @@ -594,25 +470,36 @@ WinMain ( OpenGLWindowInfo.DepthBits = 0; CreateOpenGLWindowContext(OpenGLWindowInfo, &MainWindow); + s32 InitialMemorySize = MB(64); + u8* InitialMemory = (u8*)Win32Alloc(InitialMemorySize, 0); + context Context = {}; + Context.ThreadContext = ThreadContext; + Context.MemorySize = InitialMemorySize; + Context.MemoryBase = InitialMemory; + Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; + Context.Mouse = {0}; + + gs_memory_arena PlatformPermanent = CreateMemoryArena(Context.ThreadContext.Allocator); + s64 PerformanceCountFrequency = GetPerformanceFrequency(); s64 LastFrameEnd = GetWallClock(); r32 TargetSecondsPerFrame = 1 / 60.0f; r32 LastFrameSecondsElapsed = 0.0f; - GlobalDebugServices = (debug_services*)malloc(sizeof(debug_services)); + GlobalDebugServices = PushStruct(&PlatformPermanent, debug_services); s32 DebugThreadCount = PLATFORM_THREAD_COUNT + 1; - InitDebugServices(GlobalDebugServices, - PerformanceCountFrequency, - DEBUGAlloc, - Win32Realloc, - GetWallClock, - Win32GetThreadId, + InitDebugServices(GlobalDebugServices, + PerformanceCountFrequency, + DEBUGAlloc, + Win32Realloc, + GetWallClock, + Win32GetThreadId, DebugThreadCount); input_queue InputQueue; { s32 InputQueueMemorySize = sizeof(input_entry) * 32; - u8* InputQueueMemory = Win32Alloc(InputQueueMemorySize); + u8* InputQueueMemory = (u8*)Win32Alloc(InputQueueMemorySize, 0); InputQueue = InitializeInputQueue(InputQueueMemory, InputQueueMemorySize); } @@ -622,36 +509,27 @@ WinMain ( worker_thread_info* WorkerThreads = 0; if (PLATFORM_THREAD_COUNT > 0) { - WorkerThreads = (worker_thread_info*)malloc(sizeof(worker_thread_info) * PLATFORM_THREAD_COUNT); + WorkerThreads = PushArray(&PlatformPermanent, worker_thread_info, PLATFORM_THREAD_COUNT); } - work_queue WorkQueue = {}; - WorkQueue.SemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS); + HANDLE WorkQueueSemaphoreHandle = CreateSemaphoreEx(0, 0, PLATFORM_THREAD_COUNT, 0, 0, SEMAPHORE_ALL_ACCESS); + + gs_work_queue WorkQueue = {}; + WorkQueue.SemaphoreHandle = &WorkQueueSemaphoreHandle; WorkQueue.JobsMax = 512; - WorkQueue.Jobs = (worker_thread_job*)Win32Alloc(sizeof(worker_thread_job) * WorkQueue.JobsMax); + WorkQueue.Jobs = PushArray(&PlatformPermanent, gs_threaded_job, WorkQueue.JobsMax); WorkQueue.NextJobIndex = 0; WorkQueue.PushWorkOnQueue = Win32PushWorkOnQueue; - WorkQueue.DoQueueWorkUntilDone = Win32DoQueueWorkUntilDone; + WorkQueue.CompleteQueueWork = Win32DoQueueWorkUntilDone; WorkQueue.ResetWorkQueue = ResetWorkQueue; - OutputDebugStringA("Hellooooo\n"); - for (s32 i = 0; i < PLATFORM_THREAD_COUNT; i++) { // ID = 0 is reserved for this thread - WorkerThreads[i].ID = i + 1; WorkerThreads[i].Queue = &WorkQueue; WorkerThreads[i].Handle = CreateThread(0, 0, &WorkerThreadProc, (void*)&WorkerThreads[i], 0, 0); } - s32 InitialMemorySize = Megabytes(64); - u8* InitialMemory = Win32Alloc(InitialMemorySize); - context Context = {}; - Context.MemorySize = InitialMemorySize; - Context.MemoryBase = InitialMemory; - Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; - Context.Mouse = {0}; - // Cursors HCURSOR CursorArrow = Win32LoadSystemCursor(IDC_ARROW); HCURSOR CursorPointer = Win32LoadSystemCursor(IDC_HAND); @@ -663,17 +541,8 @@ WinMain ( // 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.PlatformSetSocketOption = Win32SetSocketOption; - Context.PlatformSendTo = Win32SendTo; - Context.PlatformCloseSocket = Win32CloseSocket; Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; @@ -691,20 +560,27 @@ WinMain ( WSADATA WSAData; WSAStartup(MAKEWORD(2, 2), &WSAData); + Win32Sockets = Win32SocketArray_Create(16, &PlatformPermanent); - s32 RenderMemorySize = Megabytes(12); - u8* RenderMemory = Win32Alloc(RenderMemorySize); + Win32SerialArray_Create(ThreadContext); + + s32 RenderMemorySize = MB(12); + u8* RenderMemory = PushSize(&PlatformPermanent, RenderMemorySize); render_command_buffer RenderBuffer = AllocateRenderCommandBuffer(RenderMemory, RenderMemorySize, Win32Realloc); + addressed_data_buffer_list OutputData = {}; + OutputData.Arena = AllocatorAllocStruct(Context.ThreadContext.Allocator, gs_memory_arena); + *OutputData.Arena = CreateMemoryArena(Context.ThreadContext.Allocator); + Context.InitializeApplication(Context); Running = true; Context.WindowIsVisible = true; while (Running) { - if (GlobalDebugServices->RecordFrames) - { - EndDebugFrame(GlobalDebugServices); + if (GlobalDebugServices->RecordFrames) + { + EndDebugFrame(GlobalDebugServices); } DEBUG_TRACK_SCOPE(MainLoop); @@ -715,6 +591,8 @@ WinMain ( Context.ReloadStaticData(Context, GlobalDebugServices); } + AddressedDataBufferList_Clear(&OutputData); + { // Mouse Position POINT MousePos; GetCursorPos (&MousePos); @@ -733,16 +611,24 @@ WinMain ( HandleWindowMessage(Message, &MainWindow, &InputQueue, &Context.Mouse); } - Context.WindowBounds = rect{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; + Context.WindowBounds = rect2{v2{0, 0}, v2{(r32)MainWindow.Width, (r32)MainWindow.Height}}; RenderBuffer.ViewWidth = MainWindow.Width; RenderBuffer.ViewHeight = MainWindow.Height; Context.DeltaTime = LastFrameSecondsElapsed; - Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer); + Context.UpdateAndRender(&Context, InputQueue, &RenderBuffer, &OutputData); RenderCommandBuffer(RenderBuffer); ClearRenderBuffer(&RenderBuffer); + if (true) + { + gs_data ProcArg = {}; + ProcArg.Memory = (u8*)&OutputData; + ProcArg.Size = sizeof(OutputData); + Win32PushWorkOnQueue(&WorkQueue, Win32_SendAddressedDataBuffers_Job, ProcArg, ConstString("Send UART Data")); + } + Context.Mouse.LeftButtonState = GetMouseButtonStateAdvanced(Context.Mouse.LeftButtonState); Context.Mouse.MiddleButtonState = GetMouseButtonStateAdvanced(Context.Mouse.MiddleButtonState); Context.Mouse.RightButtonState = GetMouseButtonStateAdvanced(Context.Mouse.RightButtonState); @@ -784,6 +670,8 @@ WinMain ( SwapBuffers(DeviceContext); ReleaseDC(MainWindow.Handle, DeviceContext); + //Win32DoQueueWorkUntilDone(&WorkQueue, Context.ThreadContext); + s64 FinishedWorkTime = GetWallClock(); r32 SecondsElapsed = GetSecondsElapsed(LastFrameEnd, FinishedWorkTime, PerformanceCountFrequency); @@ -801,6 +689,11 @@ WinMain ( Context.CleanupApplication(Context); + for (s32 SocketIdx = 0; SocketIdx < Win32Sockets.Count; SocketIdx++) + { + Win32Socket_Close(Win32Sockets.Values + SocketIdx); + } + s32 CleanupResult = 0; do { CleanupResult = WSACleanup(); diff --git a/src/app/win32_foldhaus_dll.h b/src/app/platform_win32/win32_foldhaus_dll.h similarity index 84% rename from src/app/win32_foldhaus_dll.h rename to src/app/platform_win32/win32_foldhaus_dll.h index 01b6bea..26071e6 100644 --- a/src/app/win32_foldhaus_dll.h +++ b/src/app/platform_win32/win32_foldhaus_dll.h @@ -22,15 +22,15 @@ struct win32_dll_refresh }; internal int -Win32DLLStringLength(char* String) +Win32DLLgs_stringLength(char* gs_string) { - char* At = String; + char* At = gs_string; while (*At) { At++; }; - return At - String; + return At - gs_string; } internal int -Win32DLLConcatStrings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest) +Win32DLLConcatgs_strings(int ALength, char* A, int BLength, char* B, int DestLength, char* Dest) { char* Dst = Dest; char* AAt = A; @@ -112,14 +112,14 @@ InitializeDLLHotReloading(char* SourceDLLName, ExePath.Path = (char*)VirtualAlloc(NULL, ExePath.PathLength, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); GetApplicationPath(&ExePath); - Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, - Win32DLLStringLength(SourceDLLName), SourceDLLName, + Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, + Win32DLLgs_stringLength(SourceDLLName), SourceDLLName, MAX_PATH, Result.SourceDLLPath); - Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, - Win32DLLStringLength(WorkingDLLFileName), WorkingDLLFileName, + Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, + Win32DLLgs_stringLength(WorkingDLLFileName), WorkingDLLFileName, MAX_PATH, Result.WorkingDLLPath); - Win32DLLConcatStrings(ExePath.IndexOfLastSlash, ExePath.Path, - Win32DLLStringLength(LockFileName), LockFileName, + Win32DLLConcatgs_strings(ExePath.IndexOfLastSlash, ExePath.Path, + Win32DLLgs_stringLength(LockFileName), LockFileName, MAX_PATH, Result.LockFilePath); Win32Free((u8*)ExePath.Path, ExePath.PathLength); diff --git a/src/app/platform_win32/win32_foldhaus_fileio.h b/src/app/platform_win32/win32_foldhaus_fileio.h new file mode 100644 index 0000000..2c4059c --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_fileio.h @@ -0,0 +1,254 @@ +// +// File: win32_foldhaus_fileio.h +// Author: Peter Slattery +// Creation Date: 2020-02-04 +// +// +// NOTE: Relies on having imported foldhaus_platform.h prior to this file +// +#ifndef WIN32_FOLDHAUS_FILEIO_H + +internal u64 +Win32HighLowToU64(u32 LowPart, u32 HighPart) +{ + ULARGE_INTEGER Time = {}; + Time.LowPart = LowPart; + Time.HighPart = HighPart; + u64 Result = Time.QuadPart; + return Result; +} + +internal u64 +Win32FileTimeToU64(FILETIME FileTime) +{ + u64 Result = Win32HighLowToU64(FileTime.dwLowDateTime, FileTime.dwHighDateTime); + return Result; +} + +GET_FILE_INFO(Win32GetFileInfo) +{ + Assert(IsNullTerminated(Path)); + gs_file_info Result = {}; + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + Result.Path = Path; + Result.FileSize = (u64)GetFileSize(FileHandle, NULL) + 1; + FILETIME CreationTime, LastWriteTime; + if (GetFileTime(FileHandle, &CreationTime, (LPFILETIME)0, &LastWriteTime)) + { + Result.CreationTime = Win32FileTimeToU64(CreationTime); + Result.LastWriteTime = Win32FileTimeToU64(LastWriteTime); + } + else + { + PrintLastError(); + } + CloseHandle(FileHandle); + } + return Result; +} + +READ_ENTIRE_FILE(Win32ReadEntireFile) +{ + Assert(DataIsNonEmpty(Memory)); + Assert(IsNullTerminated(Path)); + + gs_file Result = {0}; + u32 Error = 0; + Result.FileInfo.Path = Path; + + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesRead = 0; + if (ReadFile(FileHandle, (LPVOID)Memory.Memory, Memory.Size - 1, (LPDWORD)(&BytesRead), NULL)) + { + Memory.Memory[Memory.Size - 1] = 0; + Result.Data = Memory; + + gs_string AbsolutePath = PushString(FileHandler.Transient, 512); + AbsolutePath.Length = GetFullPathNameA(Path.Str, AbsolutePath.Size, AbsolutePath.Str, NULL); + if (AbsolutePath.Length == 0) + { + Error = GetLastError(); + InvalidCodePath; + } + Result.FileInfo.AbsolutePath = AbsolutePath.ConstString; + } + else + { + // NOTE(Peter): If we get to this error case, it means that the file exists, + // and was successfully opened, but we can't read from it. I'm choosing to + // treat this as a legitimate error at this point. + gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to read file: %S", Path); + if (MessageBox(NULL, Message.Str, "Error", MB_OK) == IDOK) + { + PostQuitMessage(-1); + } + } + CloseHandle(FileHandle); + } + else + { + + } + + return Result; +} + +WRITE_ENTIRE_FILE(Win32WriteEntireFile) +{ + Assert(DataIsNonEmpty(Data)); + Assert(IsNullTerminated(Path)); + + bool Success = false; + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesWritten = 0; + if (WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL)) + { + Success = (BytesWritten == Data.Size); + } + else + { + gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to write to file: %S", Path); + MessageBox(NULL, Message.Str, "Error", MB_OK); + } + CloseHandle(FileHandle); + } + else + { + + } + + return Success; +} + +internal FILETIME +GetFileLastWriteTime(char* Path) +{ + FILETIME Result = {}; + + WIN32_FIND_DATA FindData = {}; + HANDLE FileHandle = FindFirstFileA(Path, &FindData); + + if (FileHandle != INVALID_HANDLE_VALUE) + { + Result = FindData.ftLastWriteTime; + FindClose(FileHandle); + } + else + { + // TODO(Peter): :ErrorLogging + } + + return Result; +} + +struct temp_file_list_entry +{ + gs_file_info Info; + temp_file_list_entry* Next; +}; + +struct temp_file_list +{ + temp_file_list_entry* First; + temp_file_list_entry* Last; +}; + +internal void +Win32SetFileInfoFromFindFileData(gs_file_info* Info, WIN32_FIND_DATA FindFileData, gs_const_string SearchPath, gs_memory_arena* Storage) +{ + u32 FileNameLength = CharArrayLength(FindFileData.cFileName); + + // NOTE(Peter): String Storage + // Storing the string in the final storage means we don't have to copy the string later, and all + // strings will be continguous in memory at the calling site, though they will be before the array + gs_string FileName = PushString(Storage, SearchPath.Length + FileNameLength + 1); + PrintF(&FileName, "%S%.*s", SearchPath, FileName.Size, FindFileData.cFileName); + NullTerminate(&FileName); + + Info->FileSize = Win32HighLowToU64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh); + Info->CreationTime = Win32FileTimeToU64(FindFileData.ftCreationTime); + Info->LastWriteTime = Win32FileTimeToU64(FindFileData.ftLastWriteTime); + Info->Path = FileName.ConstString; + Info->IsDirectory = HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY); +} + +internal u32 +Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list* TempList, gs_const_string Path, gs_memory_arena* Storage, b32 Flags) +{ + u32 FilesCount = 0; + + u32 IndexOfLastSlash = FindLastFromSet(Path, "\\/"); + gs_const_string SearchPath = Substring(Path, 0, IndexOfLastSlash + 1); + + WIN32_FIND_DATA FindFileData; + HANDLE SearchHandle = FindFirstFile(Path.Str, &FindFileData); + if (SearchHandle != INVALID_HANDLE_VALUE) + { + do + { + b32 AddFile = true; + + if (HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + if (HasFlag(Flags, EnumerateDirectory_Recurse)) + { + gs_const_string SubDirName = ConstString(FindFileData.cFileName); + if (!StringsEqual(SubDirName, ConstString(".")) && + !StringsEqual(SubDirName, ConstString(".."))) + { + gs_string SubDirectoryPath = PushString(FileHandler.Transient, SearchPath.Length + SubDirName.Length + 3); + PrintF(&SubDirectoryPath, "%S%S/*\0", SearchPath, SubDirName); + FilesCount += Win32EnumerateDirectoryIntoTempList(FileHandler, TempList, SubDirectoryPath.ConstString, Storage, Flags); + } + } + + AddFile = HasFlag(Flags, EnumerateDirectory_IncludeDirectories); + } + + if (AddFile) + { + temp_file_list_entry* File = PushStruct(FileHandler.Transient, temp_file_list_entry); + *File = {0}; + Win32SetFileInfoFromFindFileData(&File->Info, FindFileData, SearchPath, Storage); + SLLPushOrInit(TempList->First, TempList->Last, File); + FilesCount += 1; + } + }while(FindNextFile(SearchHandle, &FindFileData)); + } + else + { + PrintLastError(); + } + + return FilesCount; +} + +ENUMERATE_DIRECTORY(Win32EnumerateDirectory) +{ + Assert(IsNullTerminated(Path)); + gs_file_info_array Result = {}; + + temp_file_list TempList = {}; + Result.MaxCount = Win32EnumerateDirectoryIntoTempList(FileHandler, &TempList, Path, Storage, Flags); + + Result.Values = PushArray(Storage, gs_file_info, Result.MaxCount); + for (temp_file_list_entry* FileAt = TempList.First; + FileAt != 0; + FileAt = FileAt->Next) + { + // NOTE(Peter): We don't copy the file name here because its already in Storage. + // See String Storage note above ^^ + Result.Values[Result.Count++] = FileAt->Info; + } + + return Result; +} + +#define WIN32_FOLDHAUS_FILEIO_H +#endif // WIN32_FOLDHAUS_FILEIO_H \ No newline at end of file diff --git a/src/app/win32_foldhaus_memory.h b/src/app/platform_win32/win32_foldhaus_memory.h similarity index 50% rename from src/app/win32_foldhaus_memory.h rename to src/app/platform_win32/win32_foldhaus_memory.h index e786c44..100dd1a 100644 --- a/src/app/win32_foldhaus_memory.h +++ b/src/app/platform_win32/win32_foldhaus_memory.h @@ -8,36 +8,28 @@ // #ifndef WIN32_FOLDHAUS_MEMORY_H -PLATFORM_ALLOC(Win32Alloc) +ALLOCATOR_ALLOC(Win32Alloc) { - u8* Result = (u8*)VirtualAlloc(NULL, Size, - MEM_COMMIT | MEM_RESERVE, + u8* Result = (u8*)VirtualAlloc(NULL, Size, + MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (ResultSize != 0) + { + *ResultSize = Size; + } return Result; } -PLATFORM_FREE(Win32Free) +ALLOCATOR_FREE(Win32Free) { - b32 Result = VirtualFree(Base, 0, MEM_RELEASE); + b32 Result = VirtualFree(Ptr, 0, MEM_RELEASE); if (!Result) { - s32 Error = WSAGetLastError(); + s32 Error = GetLastError(); // TODO(Peter): I'm waiting to see an error actually occur here // to know what it could possibly be. InvalidCodePath; } - return Result; -} - -PLATFORM_REALLOC(Win32Realloc) -{ - u8* NewMemory = Win32Alloc(NewSize); - if (Base) - { - GSMemCopy(Base, NewMemory, OldSize); - Win32Free(Base, OldSize); - } - return NewMemory; } #define WIN32_FOLDHAUS_MEMORY_H diff --git a/src/app/platform_win32/win32_foldhaus_serial.h b/src/app/platform_win32/win32_foldhaus_serial.h new file mode 100644 index 0000000..0368547 --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_serial.h @@ -0,0 +1,243 @@ +// +// File: win32_serial.h +// Author: Peter Slattery +// Creation Date: 2020-10-01 +// +#ifndef WIN32_SERIAL_H + +global u32 Win32SerialHandlesCountMax; +global u32 Win32SerialHandlesCount; +global HANDLE* Win32SerialHandles; +global gs_string* Win32SerialPortNames; + +DCB +Win32SerialPort_GetState(HANDLE ComPortHandle) +{ + DEBUG_TRACK_FUNCTION; + DCB ControlSettings = {0}; + ZeroStruct(&ControlSettings); + ControlSettings.DCBlength = sizeof(ControlSettings); + + bool Success = GetCommState(ComPortHandle, &ControlSettings); + Assert(Success); + + return ControlSettings; +} + +void +Win32SerialPort_SetState(HANDLE ComPortHandle, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits) +{ + DEBUG_TRACK_FUNCTION; + DCB ControlSettings = Win32SerialPort_GetState(ComPortHandle); + + // TODO(pjs): Validate BaudRate - There's only certain rates that are valid right? + ControlSettings.BaudRate = BaudRate; + + if (Parity == NOPARITY) + { + ControlSettings.Parity = Parity; + ControlSettings.fParity = 0; + } + if (Parity == EVENPARITY || Parity == ODDPARITY) + { + ControlSettings.Parity = Parity; + ControlSettings.fParity = 1; + } + + ControlSettings.StopBits = StopBits; + ControlSettings.ByteSize = ByteSize; + + ControlSettings.fBinary = true; + + ControlSettings.fOutxCtsFlow = false; + ControlSettings.fOutxDsrFlow = false; + ControlSettings.fDtrControl = DTR_CONTROL_DISABLE; + ControlSettings.fDsrSensitivity = 0; + ControlSettings.fRtsControl = RTS_CONTROL_DISABLE; + ControlSettings.fOutX = false; + ControlSettings.fInX = false; + + ControlSettings.fErrorChar = 0; + ControlSettings.fNull = false; + ControlSettings.fAbortOnError = false; + ControlSettings.wReserved = false; + ControlSettings.XonLim = 2; + ControlSettings.XoffLim = 4; + ControlSettings.XonChar = 0x13; + ControlSettings.XoffChar = 0x19; + ControlSettings.EvtChar = 0; + + bool Success = SetCommState(ComPortHandle, &ControlSettings); +} + +HANDLE +Win32SerialPort_Open(char* PortName) +{ + DEBUG_TRACK_FUNCTION; + HANDLE ComPortHandle = CreateFile(PortName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, // Default Security Attr + OPEN_EXISTING, + 0, // Not overlapped I/O + NULL); + + if (ComPortHandle != INVALID_HANDLE_VALUE) + { + COMMTIMEOUTS Timeouts = { 0 }; + Timeouts.ReadIntervalTimeout = 0; // in milliseconds + Timeouts.ReadTotalTimeoutConstant = 0; // in milliseconds + Timeouts.ReadTotalTimeoutMultiplier = 0; // in milliseconds + Timeouts.WriteTotalTimeoutConstant = 0; // in milliseconds + Timeouts.WriteTotalTimeoutMultiplier = 0; // in milliseconds + + if (SetCommTimeouts(ComPortHandle, &Timeouts)) + { + + } + else + { + s32 Error = GetLastError(); + // TODO(pjs): Error logging + } + } + else + { + // Error + s32 Error = GetLastError(); + // TODO(pjs): Error logging + } + + return ComPortHandle; +} + +void +Win32SerialPort_Close(HANDLE PortHandle) +{ + CloseHandle(PortHandle); +} + +bool +Win32SerialPort_Write(HANDLE PortHandle, gs_data Buffer) +{ + DEBUG_TRACK_FUNCTION; + Assert(PortHandle != INVALID_HANDLE_VALUE); + bool Success = false; + + DWORD BytesWritten = 0; + if (WriteFile(PortHandle, Buffer.Memory, Buffer.Size, &BytesWritten, NULL)) + { + Success = (BytesWritten == Buffer.Size); + if (!Success) + { + OutputDebugString("Error: Entire buffer not written.\n"); + } + } + else + { + OutputDebugStringA("Error: Unable to write to port\n"); + s32 Error = GetLastError(); + //InvalidCodePath; + } + + return Success; +} + +bool +Win32SerialPort_SetRead(HANDLE PortHandle) +{ + bool Status = SetCommMask(PortHandle, EV_RXCHAR); + return Status; +} + +u32 +Win32SerialPort_ReadMessageWhenReady(HANDLE PortHandle, gs_data Data) +{ + u32 ReadSize = 0; + + DWORD EventMask = 0; + bool Status = WaitCommEvent(PortHandle, &EventMask, NULL); + if (Status) + { + DWORD NoBytesRead = 0; + do + { + u8 Byte = 0; + Status = ReadFile(PortHandle, &Byte, sizeof(char), &NoBytesRead, NULL); + Data.Memory[ReadSize] = Byte; + ReadSize++; + } + while (NoBytesRead > 0 && ReadSize < Data.Size); + } + //Read data and store in a buffer + + return ReadSize; +} + +///////////////////////// +// Win32SerialArray + +void +Win32SerialArray_Create(gs_thread_context Context) +{ + DEBUG_TRACK_FUNCTION; + + Win32SerialHandlesCountMax = 32; + Win32SerialHandlesCount = 0; + Win32SerialHandles = AllocatorAllocArray(Context.Allocator, HANDLE, Win32SerialHandlesCountMax); + Win32SerialPortNames = AllocatorAllocArray(Context.Allocator, gs_string, Win32SerialHandlesCountMax); + for (u32 i = 0; i < Win32SerialHandlesCountMax; i++) + { + Win32SerialPortNames[i] = AllocatorAllocString(Context.Allocator, 256); + } +} + +void +Win32SerialArray_Push(HANDLE SerialHandle, gs_const_string PortName) +{ + DEBUG_TRACK_FUNCTION; + + Assert(Win32SerialHandlesCount < Win32SerialHandlesCountMax); + u32 Index = Win32SerialHandlesCount++; + Win32SerialHandles[Index] = SerialHandle; + PrintF(&Win32SerialPortNames[Index], "%S", PortName); +} + +HANDLE +Win32SerialArray_Get(gs_const_string PortName) +{ + DEBUG_TRACK_FUNCTION; + + HANDLE PortHandle = INVALID_HANDLE_VALUE; + for (u32 i = 0; i < Win32SerialHandlesCount; i++) + { + if (StringsEqual(Win32SerialPortNames[i].ConstString, PortName)) + { + PortHandle = Win32SerialHandles[i]; + break; + } + } + return PortHandle; +} + +HANDLE +Win32SerialArray_GetOrOpen(gs_const_string PortName, u32 BaudRate, u8 ByteSize, u8 Parity, u8 StopBits) +{ + DEBUG_TRACK_FUNCTION; + + HANDLE PortHandle = Win32SerialArray_Get(PortName); + if (PortHandle == INVALID_HANDLE_VALUE) + { + Assert(IsNullTerminated(PortName)); + PortHandle = Win32SerialPort_Open(PortName.Str); + if (PortHandle != INVALID_HANDLE_VALUE) + { + Win32SerialPort_SetState(PortHandle, BaudRate, ByteSize, Parity, StopBits); + Win32SerialArray_Push(PortHandle, PortName); + } + } + return PortHandle; +} + +#define WIN32_SERIAL_H +#endif // WIN32_SERIAL_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_socket.h b/src/app/platform_win32/win32_foldhaus_socket.h new file mode 100644 index 0000000..18df318 --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_socket.h @@ -0,0 +1,140 @@ +// +// File: win32_foldhaus_socket.h +// Author: Peter Slattery +// Creation Date: 2020-10-03 +// +#ifndef WIN32_FOLDHAUS_SOCKET_H + +struct win32_socket +{ + SOCKET Socket; +}; + +struct win32_socket_array +{ + win32_socket* Values; + s32 CountMax; + s32 Count; +}; + +////////////////////// +// +// Win32 Socket Array + +internal win32_socket_array +Win32SocketArray_Create(u32 CountMax, gs_memory_arena* Storage) +{ + win32_socket_array Result = {}; + Result.CountMax = CountMax; + Result.Values = PushArray(Storage, win32_socket, CountMax); + return Result; +} + +internal s32 +Win32SocketArray_Take(win32_socket_array* Array) +{ + Assert(Array->Count < Array->CountMax); + s32 Result = Array->Count++; + win32_socket* Socket = Array->Values + Result; + *Socket = {0}; + return Result; +} + +internal win32_socket* +Win32SocketArray_Get(win32_socket_array Array, s32 Index) +{ + Assert(Index < Array.Count); + win32_socket* Result = Array.Values + Index; + return Result; +} + +////////////////////// +// +// Win32 Socket System + +global win32_socket_array Win32Sockets; + +internal s32 +Win32Socket_SetOption(win32_socket* Socket, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) +{ + int Error = setsockopt(Socket->Socket, Level, Option, OptionValue, OptionLength); + if (Error == SOCKET_ERROR) + { + Error = WSAGetLastError(); + // TODO(Peter): :ErrorLogging + } + + return Error; +} + +internal s32 +Win32Socket_SetOption(platform_socket_handle SocketHandle, s32 Level, s32 Option, const char* OptionValue, s32 OptionLength) +{ + win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle); + return Win32Socket_SetOption(Socket, Level, Option, OptionValue, OptionLength); +} + +PLATFORM_GET_SOCKET_HANDLE(Win32GetSocketHandle) +{ + // NOTE(Peter): These used to be passed in as paramters, but we only use this function + // with AF_INET, SOCK_DGRAM, and Protocol = 0. These are also platform specific values + // so I was having to include windows.h in the platform agnostic code to accomodate that + // function signature. + s32 AddressFamily = AF_INET; + s32 Type = SOCK_DGRAM; + s32 Protocol = 0; + + s32 Result = Win32SocketArray_Take(&Win32Sockets); + win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, Result); + Socket->Socket = socket(AddressFamily, Type, Protocol); + if (Socket->Socket != INVALID_SOCKET) + { + int Error = Win32Socket_SetOption(Socket, IPPROTO_IP, IP_MULTICAST_TTL, + (const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive)); + } + else + { + s32 Error = WSAGetLastError(); + InvalidCodePath; + } + + return (platform_socket_handle)Result; +} + +internal s32 +Win32Socket_SendTo(platform_socket_handle SocketHandle, u32 Address, u32 Port, const char* Buffer, s32 BufferLength, s32 Flags) +{ + win32_socket* Socket = Win32SocketArray_Get(Win32Sockets, (s32)SocketHandle); + + sockaddr_in SockAddress = {}; + SockAddress.sin_family = AF_INET; + SockAddress.sin_port = HostToNetU16(Port); + SockAddress.sin_addr.s_addr = HostToNetU32(Address); + + s32 LengthSent = sendto(Socket->Socket, Buffer, BufferLength, Flags, (sockaddr*)&SockAddress, sizeof(sockaddr_in)); + + if (LengthSent == SOCKET_ERROR) + { + s32 Error = WSAGetLastError(); + if (Error == 10051) + { + } + else + { + // TODO(Peter): :ErrorLogging + InvalidCodePath; + } + } + + return LengthSent; +} + +internal void +Win32Socket_Close(win32_socket* Socket) +{ + closesocket(Socket->Socket); + Socket->Socket = INVALID_SOCKET; +} + +#define WIN32_FOLDHAUS_SOCKET_H +#endif // WIN32_FOLDHAUS_SOCKET_H \ No newline at end of file diff --git a/src/app/win32_foldhaus_timing.h b/src/app/platform_win32/win32_foldhaus_timing.h similarity index 100% rename from src/app/win32_foldhaus_timing.h rename to src/app/platform_win32/win32_foldhaus_timing.h diff --git a/src/app/platform_win32/win32_foldhaus_utils.h b/src/app/platform_win32/win32_foldhaus_utils.h new file mode 100644 index 0000000..5392c9f --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_utils.h @@ -0,0 +1,75 @@ +// +// File: win32_foldhaus_utils.h +// Author: Peter Slattery +// Creation Date: 2020-10-01 +// +#ifndef WIN32_FOLDHAUS_UTILS_H + +internal gs_string +Win32DumpErrorAndPrepareMessageBoxString(gs_memory_arena* Arena, char* Format, ...) +{ + s32 Error = GetLastError(); + gs_string ErrorDump = PushString(Arena, 4096); + PrintF(&ErrorDump, + R"FOO(Win32 Error: %s\n +Error Code: %d\n + )FOO", + __FUNCTION__, + Error); + + va_list Args; + va_start(Args, Format); + PrintFArgsList(&ErrorDump, Format, Args); + va_end(Args); + + gs_data ErrorDumpData = StringToData(ErrorDump); + + HANDLE FileHandle = CreateFileA("./crashdump.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesWritten = 0; + if (WriteFile(FileHandle, ErrorDumpData.Memory, ErrorDumpData.Size, &BytesWritten, NULL)) + { + + } + CloseHandle(FileHandle); + } + + AppendPrintF(&ErrorDump, "Program will attempt to continue. See crashdump.txt for info"); + NullTerminate(&ErrorDump); + + return ErrorDump; +} + +DEBUG_PRINT(Win32DebugPrint) +{ + Assert(IsNullTerminated(Message)); + OutputDebugStringA(Message.Str); +} + +#define PrintLastError() PrintLastError_(__FILE__, __LINE__) +internal void +PrintLastError_(char* File, u32 Line) +{ + char DebugStringData[256]; + gs_string DebugString = MakeString(DebugStringData, 0, 256); + u32 Error = GetLastError(); + PrintF(&DebugString, "%s Line %d: Win32 Error %d\n\0", File, Line, Error); + OutputDebugStringA(DebugString.Str); +} + + +internal HINSTANCE +GetHInstance() +{ + HINSTANCE Result = GetModuleHandle(NULL); + if (Result == NULL) + { + PrintLastError(); + } + return Result; +} + + +#define WIN32_FOLDHAUS_UTILS_H +#endif // WIN32_FOLDHAUS_UTILS_H \ No newline at end of file diff --git a/src/app/platform_win32/win32_foldhaus_work_queue.h b/src/app/platform_win32/win32_foldhaus_work_queue.h new file mode 100644 index 0000000..2db58f3 --- /dev/null +++ b/src/app/platform_win32/win32_foldhaus_work_queue.h @@ -0,0 +1,155 @@ +// +// File: win32_foldhaus_work_queue.h +// Author: Peter Slattery +// Creation Date: 2020-10-01 +// +#ifndef WIN32_FOLDHAUS_WORK_QUEUE_H + +struct worker_thread_entry +{ + b32 IsValid; + u32 Index; +}; + +struct worker_thread_info +{ + gs_thread_context ThreadContext; + HANDLE Handle; + gs_work_queue* Queue; +}; + +internal s32 +Win32GetThreadId() +{ + s32 Result = GetCurrentThreadId(); + return Result; +} + +internal gs_thread_context +Win32CreateThreadContext(gs_memory_arena* Transient = 0) +{ + gs_thread_context Result = {0}; + Result.ThreadInfo.ThreadID = Win32GetThreadId(); + Result.Allocator = CreateAllocator(Win32Alloc, Win32Free); + if (Transient != 0) + { + Result.Transient = Transient; + } + else + { + Result.Transient = (gs_memory_arena*)AllocatorAlloc(Result.Allocator, sizeof(gs_memory_arena)).Memory; + *Result.Transient = CreateMemoryArena(Result.Allocator); + } + Result.FileHandler = CreateFileHandler(Win32GetFileInfo, + Win32ReadEntireFile, + Win32WriteEntireFile, + Win32EnumerateDirectory, + Result.Transient); + + return Result; +} + +PUSH_WORK_ON_QUEUE(Win32PushWorkOnQueue) +{ +#ifdef DEBUG + // NOTE(Peter): Just prints out the names of all the pending jobs if we end up + // overflowing the buffer + if (Queue->JobsCount >= Queue->JobsMax) + { + gs_string DebugString = MakeString((char*)malloc(256), 256); + for (u32 i = 0; i < Queue->JobsCount; i++) + { + PrintF(&DebugString, "%d %s\n", i, Queue->Jobs[i].JobName); + NullTerminate(&DebugString); + OutputDebugStringA(DebugString.Str); + } + } +#endif + Assert(Queue->JobsCount < Queue->JobsMax); + + gs_threaded_job* Job = Queue->Jobs + Queue->JobsCount; + Job->WorkProc = WorkProc; + Job->Data = Data; +#ifdef DEBUG + Job->JobName = JobName; +#endif + + // Complete Past Writes before Future Writes + _WriteBarrier(); + _mm_sfence(); + + ++Queue->JobsCount; + ReleaseSemaphore(Queue->SemaphoreHandle, 1, 0); +} + +internal worker_thread_entry +CompleteAndTakeNextJob(gs_work_queue* Queue, worker_thread_entry Completed, gs_thread_context Context) +{ + if (Completed.IsValid) + { + InterlockedIncrement((LONG volatile*)&Queue->JobsCompleted); + } + + worker_thread_entry Result = {}; + Result.IsValid = false; + + u32 OriginalNextJobIndex = Queue->NextJobIndex; + while (OriginalNextJobIndex < Queue->JobsCount) + { + u32 Index = InterlockedCompareExchange((LONG volatile*)&Queue->NextJobIndex, + OriginalNextJobIndex + 1, + OriginalNextJobIndex); + if (Index == OriginalNextJobIndex) + { + Result.Index = Index; + Result.IsValid = true; + break; + } + OriginalNextJobIndex = Queue->NextJobIndex; + } + + return Result; +} + +COMPLETE_QUEUE_WORK(Win32DoQueueWorkUntilDone) +{ + worker_thread_entry Entry = {}; + Entry.IsValid = false; + while (Queue->JobsCompleted < Queue->JobsCount) + { + Entry = CompleteAndTakeNextJob(Queue, Entry, Context); + if (Entry.IsValid) + { + Queue->Jobs[Entry.Index].WorkProc(Context, Queue->Jobs[Entry.Index].Data); + } + } +} + +DWORD WINAPI +WorkerThreadProc (LPVOID InputThreadInfo) +{ + worker_thread_info* ThreadInfo = (worker_thread_info*)InputThreadInfo; + ThreadInfo->ThreadContext = Win32CreateThreadContext(); + + worker_thread_entry Entry = {}; + Entry.IsValid = false; + while (true) + { + ClearArena(ThreadInfo->ThreadContext.Transient); + Entry = CompleteAndTakeNextJob(ThreadInfo->Queue, Entry, ThreadInfo->ThreadContext); + if (Entry.IsValid) + { + ThreadInfo->Queue->Jobs[Entry.Index].WorkProc(ThreadInfo->ThreadContext, + ThreadInfo->Queue->Jobs[Entry.Index].Data); + } + else + { + WaitForSingleObjectEx(ThreadInfo->Queue->SemaphoreHandle, INFINITE, 0); + } + } + + return 0; +} + +#define WIN32_FOLDHAUS_WORK_QUEUE_H +#endif // WIN32_FOLDHAUS_WORK_QUEUE_H \ No newline at end of file diff --git a/src/app/test_patterns.h b/src/app/test_patterns.h index 4215ae0..6d4d0c6 100644 --- a/src/app/test_patterns.h +++ b/src/app/test_patterns.h @@ -8,49 +8,47 @@ GSMetaTag(node_struct); struct solid_color_data { - GSMetaTag(node_input); + GSMetaTag(node_input); v4 Color; GSMetaTag(node_output); color_buffer Result; }; -GSMetaTag(node_proc); // :TagParamsForNodeParamStructs +GSMetaTag(node_proc); // :TagParamsForNodeParamStructs void SolidColorProc(solid_color_data* Data) { - u8 R = (u8)GSClamp(0.f, (Data->Color.r * 255), 255.f); - u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f); - u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f); + u8 R = (u8)Clamp(0.f, (Data->Color.r * 255), 255.f); + u8 G = (u8)Clamp(0.f, (Data->Color.g * 255), 255.f); + u8 B = (u8)Clamp(0.f, (Data->Color.b * 255), 255.f); - led* LED = Data->Result.LEDs; - for (s32 l = 0; l < Data->Result.LEDCount; l++) + for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++) { - Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); + Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount); - Data->Result.Colors[LED->Index].R = R; - Data->Result.Colors[LED->Index].G = G; - Data->Result.Colors[LED->Index].B = B; - LED++; + Data->Result.Colors[LedIndex].R = R; + Data->Result.Colors[LedIndex].G = G; + Data->Result.Colors[LedIndex].B = B; } } GSMetaTag(node_struct); struct vertical_color_fade_data { - GSMetaTag(node_input); + GSMetaTag(node_input); v4 Color; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 Min; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 Max; GSMetaTag(node_output); color_buffer Result; }; -GSMetaTag(node_proc); // :TagParamsForNodeParamStructs +GSMetaTag(node_proc); // :TagParamsForNodeParamStructs void VerticalColorFadeProc(vertical_color_fade_data* Data) { r32 R = (Data->Color.r * 255); @@ -59,18 +57,18 @@ void VerticalColorFadeProc(vertical_color_fade_data* Data) r32 Range = Data->Max - Data->Min; - led* LED = Data->Result.LEDs; - for (s32 l = 0; l < Data->Result.LEDCount; l++) + + for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++) { - Assert(LED->Index >= 0 && LED->Index < Data->Result.LEDCount); + Assert(LedIndex >= 0 && LedIndex < Data->Result.LEDCount); + v4 LedPosition = Data->Result.LedPositions[LedIndex]; - r32 Amount = (LED->Position.y - Data->Min) / Range; - Amount = GSClamp01(1.0f - Amount); + r32 Amount = (LedPosition.y - Data->Min) / Range; + Amount = Clamp01(1.0f - Amount); - Data->Result.Colors[LED->Index].R = (u8)(R * Amount); - Data->Result.Colors[LED->Index].G = (u8)(G * Amount); - Data->Result.Colors[LED->Index].B = (u8)(B * Amount); - LED++; + Data->Result.Colors[LedIndex].R = (u8)(R * Amount); + Data->Result.Colors[LedIndex].G = (u8)(G * Amount); + Data->Result.Colors[LedIndex].B = (u8)(B * Amount); } } @@ -78,45 +76,45 @@ void VerticalColorFadeProc(vertical_color_fade_data* Data) GSMetaTag(node_struct); struct revolving_discs_data { - GSMetaTag(node_input); + GSMetaTag(node_input); r32 Rotation; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 ThetaZ; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 ThetaY; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 DiscWidth; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 InnerRadius; - GSMetaTag(node_input); + GSMetaTag(node_input); r32 OuterRadius; - GSMetaTag(node_input); + GSMetaTag(node_input); v4 Color; GSMetaTag(node_output); color_buffer Result; }; -GSMetaTag(node_proc); // :TagParamsForNodeParamStructs +GSMetaTag(node_proc); // :TagParamsForNodeParamStructs void RevolvingDiscs(revolving_discs_data* Data) { DEBUG_TRACK_FUNCTION; pixel Color = { - (u8)(GSClamp01(Data->Color.r) * 255), - (u8)(GSClamp01(Data->Color.g) * 255), - (u8)(GSClamp01(Data->Color.b) * 255), + (u8)(Clamp01(Data->Color.r) * 255), + (u8)(Clamp01(Data->Color.g) * 255), + (u8)(Clamp01(Data->Color.b) * 255), }; v4 Center = v4{0, 0, 0, 1}; - v4 Normal = v4{GSCos(Data->ThetaZ), 0, GSSin(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 - v4 Right = Cross(Normal, v4{0, 1, 0, 0}); + v4 Normal = v4{CosR32(Data->ThetaZ), 0, SinR32(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1 + v4 Right = V4Cross(Normal, v4{0, 1, 0, 0}); v4 FrontCenter = Center + (Normal * Data->DiscWidth); v4 BackCenter = Center - (Normal * Data->DiscWidth); @@ -124,29 +122,27 @@ void RevolvingDiscs(revolving_discs_data* Data) r32 OuterRadiusSquared = Data->OuterRadius * Data->OuterRadius; r32 InnerRadiusSquared = Data->InnerRadius * Data->InnerRadius; - led* LED = Data->Result.LEDs; - for (s32 l = 0; l < Data->Result.LEDCount; l++) + for (s32 LedIndex = 0; LedIndex < Data->Result.LEDCount; LedIndex++) { - v4 Position = LED->Position; + v4 Position = Data->Result.LedPositions[LedIndex]; v4 ToFront = Position + FrontCenter; v4 ToBack = Position + BackCenter; - r32 ToFrontDotNormal = Dot(ToFront, Normal); - r32 ToBackDotNormal = Dot(ToBack, Normal); + r32 ToFrontDotNormal = V4Dot(ToFront, Normal); + r32 ToBackDotNormal = V4Dot(ToBack, Normal); - ToFrontDotNormal = GSClamp01(ToFrontDotNormal * 1000); - ToBackDotNormal = GSClamp01(ToBackDotNormal * 1000); + ToFrontDotNormal = Clamp01(ToFrontDotNormal * 1000); + ToBackDotNormal = Clamp01(ToBackDotNormal * 1000); - r32 SqDistToCenter = MagSqr(Position); + r32 SqDistToCenter = V4MagSquared(Position); if (SqDistToCenter < OuterRadiusSquared && SqDistToCenter > InnerRadiusSquared) { if (XOR(ToFrontDotNormal > 0, ToBackDotNormal > 0)) { - Data->Result.Colors[LED->Index] = Color; + Data->Result.Colors[LedIndex] = Color; } } - LED++; } } diff --git a/src/app/win32_foldhaus_fileio.h b/src/app/win32_foldhaus_fileio.h deleted file mode 100644 index 7104c5e..0000000 --- a/src/app/win32_foldhaus_fileio.h +++ /dev/null @@ -1,146 +0,0 @@ -// -// File: win32_foldhaus_fileio.h -// Author: Peter Slattery -// Creation Date: 2020-02-04 -// -// -// NOTE: Relies on having imported foldhaus_platform.h prior to this file -// -#ifndef WIN32_FOLDHAUS_FILEIO_H - -PLATFORM_READ_ENTIRE_FILE(Win32ReadEntireFile) -{ - platform_memory_result Result = {}; - Result.Error = PlatformMemory_NoError; - - HANDLE FileHandle = CreateFileA (Path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - - if (FileHandle != INVALID_HANDLE_VALUE) - { - DWORD FileSize = GetFileSize(FileHandle, NULL); - Result.Base = (u8*)VirtualAlloc(NULL, FileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); - if (Result.Base) - { - Result.Size = FileSize; - - s32 BytesRead = 0; - if (ReadFile(FileHandle, (LPVOID)Result.Base, FileSize, (LPDWORD)(&BytesRead), NULL)) - { - - } - else - { - u32 Error = GetLastError(); - // TODO(Peter): :ErrorLogging - Result.Size = 0; - Result.Error = PlatformMemory_UnknownError; - } - } - CloseHandle(FileHandle); - } - else - { - Result.Error = PlatformMemory_FileNotFound; - // TODO(Peter): :ErrorLogging - } - - return Result; -} - -PLATFORM_WRITE_ENTIRE_FILE(Win32WriteEntireFile) -{ - b32 Result = false; - HANDLE FileHandle = CreateFileA ( - Path, - GENERIC_WRITE, - 0, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (FileHandle != INVALID_HANDLE_VALUE) - { - DWORD BytesWritten = 0; - - b32 WriteSuccess = WriteFile(FileHandle, - Contents, Size, - &BytesWritten, - NULL); - - if (WriteSuccess && BytesWritten == (u32)Size) - { - CloseHandle(FileHandle); - Result = true; - } - else - { - Result = false; - } - } - else - { - Result = false; - } - - return Result; -} - -internal FILETIME -GetFileLastWriteTime(char* Path) -{ - FILETIME Result = {}; - - WIN32_FIND_DATA FindData = {}; - HANDLE FileHandle = FindFirstFileA(Path, &FindData); - - if (FileHandle != INVALID_HANDLE_VALUE) - { - Result = FindData.ftLastWriteTime; - FindClose(FileHandle); - } - else - { - // TODO(Peter): :ErrorLogging - } - - return Result; -} - -PLATFORM_GET_FILE_PATH(Win32SystemDialogueOpenFile) -{ - b32 Result = false; - - PathBuffer[0] = 0; - - OPENFILENAMEA OpenFileName = {}; - OpenFileName.lStructSize = sizeof(OpenFileName); - OpenFileName.hwndOwner = NULL; - OpenFileName.lpstrFilter = FilterStrings; - OpenFileName.lpstrCustomFilter = NULL; // NOTE(Peter): for preserving last filter string chosen - OpenFileName.nMaxCustFilter = 0; // NOTE(Peter): ignored since we left CustomFilter null - OpenFileName.nFilterIndex = 1; - OpenFileName.lpstrFile = PathBuffer; - OpenFileName.nMaxFile = BufferLength; - OpenFileName.lpstrFileTitle = NULL; - OpenFileName.nMaxFileTitle = 0; // NOTE(Peter): Ignored since fileTitle is null - OpenFileName.lpstrInitialDir = NULL; - OpenFileName.lpstrTitle = NULL; - OpenFileName.Flags = OFN_ENABLESIZING | OFN_FILEMUSTEXIST; - OpenFileName.lpstrDefExt = NULL; - - Result = GetOpenFileNameA (&OpenFileName); - - return Result; -} - -internal directory_listing -EnumerateDirectory(char* Path, memory_arena* Storage) -{ - directory_listing Result = {}; - // TODO(Peter): - return Result; -} - -#define WIN32_FOLDHAUS_FILEIO_H -#endif // WIN32_FOLDHAUS_FILEIO_H \ No newline at end of file diff --git a/src/gs_libs/gs_font.h b/src/gs_libs/gs_font.h index 7570039..c901bf7 100644 --- a/src/gs_libs/gs_font.h +++ b/src/gs_libs/gs_font.h @@ -82,7 +82,7 @@ GetNextCodepointOffset (bitmap_font* Font, u32* X, u32* Y) } internal void -AddCodepointToFont (bitmap_font* Font, char Codepoint, +AddCodepointToFont (bitmap_font* Font, char Codepoint, s32 XOffset, s32 YOffset, s32 Width, s32 Height, s32 BitmapX, s32 BitmapY) { @@ -100,7 +100,7 @@ AddCodepointToFont (bitmap_font* Font, char Codepoint, Value->BitmapX = BitmapX; Value->BitmapY = BitmapY; Value->UVMin = v2{(r32)BitmapX / (r32)Font->BitmapWidth, (r32)BitmapY / (r32)Font->BitmapHeight}; - Value->UVMax = + Value->UVMax = Value->UVMin + v2{(r32)Width / (r32)Font->BitmapWidth, (r32)Height / (r32)Font->BitmapHeight}; } diff --git a/src/gs_libs/gs_language.h b/src/gs_libs/gs_language.h index dc86a4f..b95b246 100644 --- a/src/gs_libs/gs_language.h +++ b/src/gs_libs/gs_language.h @@ -1,5 +1,6 @@ #ifndef GS_LANGUAGE_H +#if 0 #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) #include @@ -42,6 +43,8 @@ typedef long long int s64; typedef float r32; typedef double r64; +#endif + #ifndef _STDINT #define INT8_MIN (-128) @@ -124,7 +127,7 @@ Test(b32 Result, char* Description, s32* Count) #define DEBUG_TRACK_SCOPE(a) #endif // DEBUG_TRACK_SCOPE #ifndef DEBUG_TRACK_FUNCTION -// #define DEBUG_TRACK_FUNCTION +#define DEBUG_TRACK_FUNCTION #endif // DEBUG_TRACK_FUNCTION #endif // GS_LANGUAGE_NO_PROFILER_DEFINES diff --git a/src/gs_libs/gs_memory_arena.h b/src/gs_libs/gs_memory_arena.h index 350268c..4fbeb3b 100644 --- a/src/gs_libs/gs_memory_arena.h +++ b/src/gs_libs/gs_memory_arena.h @@ -167,21 +167,6 @@ if((expression)) { \ #define GSMem_Assert(expression) #endif -struct data -{ - u8* Memory; - u64 Size; -}; - -typedef data allocator_alloc(u64 Size); -typedef void allocator_free(u8* Base, u64 Size); - -struct base_allocator -{ - allocator_alloc* Alloc; - allocator_free* Free; -}; - enum gs_memory_expansion_rule { MemoryExpansion_Allowed, // Zero is initialization lets the memory grow on its own @@ -207,9 +192,21 @@ enum gs_memory_find_address_rule FindAddress_Count, }; -typedef void* gs_memory_alloc(gs_mem_u32 Size); -typedef void* gs_memory_realloc(void* Address, gs_mem_u32 OldSize, gs_mem_u32 NewSize); -typedef void gs_memory_free(void* Address, gs_mem_u32 Size); +#define PLATFORM_ALLOC(name) u8* name(s32 Size) +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); + +struct platform_memory_handler +{ + platform_alloc* Alloc; + platform_free* Free; + platform_realloc* Realloc; +}; #ifndef GS_MEMORY_BUFFER_SIZE #define GS_MEMORY_BUFFER_SIZE 1024 @@ -244,8 +241,6 @@ struct memory_buffer struct memory_arena { - base_allocator Allocator; - memory_buffer* Buffers; gs_mem_u32 BuffersCount; @@ -254,8 +249,8 @@ struct memory_arena gs_memory_find_address_rule FindAddressRule; gs_memory_expansion_rule ExpansionRule; - gs_memory_alloc* Alloc; - gs_memory_realloc* Realloc; + + platform_memory_handler PlatformMemory; #ifdef GS_MEMORY_TRACK_ALLOCATIONS tracked_allocation_buffer** AllocationBuffers; @@ -283,59 +278,64 @@ struct arena_snapshot #endif }; -#define AllocatorAllocArray(alloc,type,count) (type*)(AllocatorAlloc((alloc), sizeof(type) * (count)).Memory) -#define AllocatorAllocStruct(alloc,type) (type*)(AllocatorAlloc((alloc), sizeof(type)).Memory) -static data -AllocatorAlloc(base_allocator Allocator, gs_mem_u64 Size) -{ - return Allocator.Alloc(Size); -} - +#define PlatformFreeArray(platform, base, type, count) PlatformFree((platform), (gs_mem_u8*)(base), sizeof(type) * (count)) +#define ArenaFree(arena, base, size) PlatformFree((arena).PlatformMemory, (gs_mem_u8*)(base), (gs_mem_u32)(size)) static void -AllocatorFree(base_allocator Allocator, gs_mem_u8* Base, gs_mem_u64 Size) +PlatformFree(platform_memory_handler Platform, gs_mem_u8* Base, gs_mem_u32 Size) { - Allocator.Free(Base, Size); + Assert(Platform.Free != 0); + Platform.Free(Base, Size); } -static memory_arena -CreateMemoryArena(base_allocator Allocator) +#define PlatformAllocArray(platform, type, size) (type*)PlatformAlloc((platform), sizeof(type) * (size)) +#define ArenaAlloc(arena, size) PlatformAlloc((arena).PlatformMemory, (gs_mem_u32)(size)) +#define ArenaAllocStruct(arena, type) (type*)PlatformAlloc((arena).PlatformMemory, sizeof(type)) +#define ArenaAllocArray(arena, type, size) (type*)PlatformAlloc((arena).PlatformMemory, sizeof(type) * (size)) +static gs_mem_u8* +PlatformAlloc(platform_memory_handler Platform, gs_mem_u32 Size) { - memory_arena Result = {0}; - Result.Allocator = Allocator; - Result.ExpansionRule = MemoryExpansion_Allowed; - Result.FindAddressRule = FindAddress_InLastBufferOnly; + Assert(Platform.Alloc != 0); + gs_mem_u8* Result = Platform.Alloc(Size); + return Result; +} + +#define ArenaRealloc(arena, base, oldSize, newSize) PlatformRealloc((arena).PlatformMemory, (gs_mem_u8*)(base), (gs_mem_u32)(oldSize), (gs_mem_u32)(newSize)) +#define ArenaReallocArray(arena, base, type, oldCount, newCount) (type*)PlatformRealloc((arena).PlatformMemory, (gs_mem_u8*)(base), sizeof(type) * oldCount, sizeof(type) * newCount) +static gs_mem_u8* +PlatformRealloc(platform_memory_handler Platform, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize) +{ + gs_mem_u8* Result = 0; + if (Platform.Realloc != 0) + { + Result = Platform.Realloc(Head, OldSize, NewSize); + } + else if (Platform.Alloc != 0 && Platform.Free != 0) + { + Result = PlatformAlloc(Platform, NewSize); + if (Head != 0 && OldSize != 0) + { + CopyMemoryTo(Head, Result, OldSize); + PlatformFree(Platform, Head, OldSize); + } + } + else + { + InvalidCodePath; + } return Result; } static void -FreeMemoryArena(memory_arena* Arena, gs_memory_free* Free = 0) +FreeMemoryArena(memory_arena* Arena) { - if (Free) + for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++) { - for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++) - { - memory_buffer* Buffer = Arena->Buffers + i; - Free(Buffer->Buffer, Buffer->Size); - } - Free(Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount); - } - else - { -#ifdef GS_MEMORY_NO_STD_LIBS - GSMem_Assert(0); -#else - for (gs_mem_u32 i = 0; i < Arena->BuffersCount; i++) - { - memory_buffer* Buffer = Arena->Buffers + i; - free(Buffer->Buffer); - } - free(Arena->Buffers); -#endif + memory_buffer* Buffer = Arena->Buffers + i; + PlatformFree(Arena->PlatformMemory, Buffer->Buffer, Buffer->Size); } + PlatformFree(Arena->PlatformMemory, (u8*)Arena->Buffers, sizeof(memory_buffer) * Arena->BuffersCount); } -#define IsPowerOfTwo(v) ((v != 0) && ((v & (v - 1)) == 0)) - inline gs_mem_u32 GetAlignmentOffset (gs_mem_u64 Address, gs_mem_u32 Alignment, gs_mem_u32 AlignmentMask) { @@ -385,51 +385,17 @@ FindAlignedAddressInBufferWithRoom(memory_arena* Arena, gs_mem_u32 Size, gs_mem_ return Result; } -static gs_mem_u8* -ArenaAlloc(memory_arena* Arena, gs_mem_u32 Size) -{ - gs_mem_u8* Result = 0; - data Data = AllocatorAlloc(Arena->Allocator, Size); - Result = Data.Memory; - return Result; -} - -static gs_mem_u8* -ArenaRealloc(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 OldSize, gs_mem_u32 NewSize) -{ - gs_mem_u8* Result = 0; - - GSMem_Assert(Arena->Allocator.Alloc); - GSMem_Assert(Arena->Allocator.Free); - - data Data = AllocatorAlloc(Arena->Allocator, NewSize); - for (gs_mem_u64 i = 0; i < (gs_mem_u64)OldSize; i++) - { - Data.Memory[i] = Head[i]; - } - - if (Head != 0) - { - AllocatorFree(Arena->Allocator, Head, OldSize); - } - - Result = Data.Memory; - return Result; -} - static memory_buffer* GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded) { GSMem_Assert(Arena->ExpansionRule != MemoryExpansion_Disallowed); - if (Arena->ExpansionRule == MemoryExpansion_OnlyIfFunctionsProvided) - { - GSMem_Assert((Arena->Allocator.Alloc != 0) && (Arena->Allocator.Free != 0)); - } gs_mem_u32 NewBuffersCount = (Arena->BuffersCount + 1); +#if 0 gs_mem_u32 OldBuffersSize = sizeof(memory_buffer) * Arena->BuffersCount; gs_mem_u32 NewBuffersSize = sizeof(memory_buffer) * NewBuffersCount; - Arena->Buffers = (memory_buffer*)ArenaRealloc(Arena, (gs_mem_u8*)Arena->Buffers, OldBuffersSize, NewBuffersSize); +#endif + Arena->Buffers = ArenaReallocArray(*Arena, Arena->Buffers, memory_buffer, Arena->BuffersCount, NewBuffersCount); Arena->BuffersCount = NewBuffersCount; memory_buffer* NewBuffer = Arena->Buffers + (Arena->BuffersCount - 1); @@ -439,7 +405,7 @@ GrowArena(memory_arena* Arena, gs_mem_u32 SizeNeeded) NewBuffer->Size = SizeNeeded; } - NewBuffer->Buffer = ArenaAlloc(Arena, sizeof(gs_mem_u8) * NewBuffer->Size); + NewBuffer->Buffer = ArenaAllocArray(*Arena, gs_mem_u8, NewBuffer->Size); NewBuffer->Used = 0; Arena->TotalSize += NewBuffer->Size; @@ -460,14 +426,20 @@ TrackAllocation(memory_arena* Arena, gs_mem_u8* Head, gs_mem_u32 Size, char* Fil if (Arena->AllocationsUsed >= AllocationsMax) { gs_mem_u32 NewAllocationBuffersCount = Arena->AllocationBuffersCount + 1; - Arena->AllocationBuffers = (tracked_allocation_buffer**)ArenaRealloc(Arena, - (gs_mem_u8*)Arena->AllocationBuffers, - Arena->AllocationBuffersCount * sizeof(void*), - NewAllocationBuffersCount * sizeof(void*)); +#if 0 + gs_mem_u32 OldSize = Arena->AllocationBuffersCount * sizeof(void*); + gs_mem_u32 NewSize = NewAllocationBuffersCount * sizeof(void*); + Arena->AllocationBuffers = (tracked_allocation_buffer**)PlatformRealloc(Arena->PlatformMemory, + (gs_mem_u8*)Arena->AllocationBuffers, + OldSize, NewSize); +#else + Arena->AllocationBuffers = ArenaReallocArray(*Arena, Arena->AllocationBuffers, tracked_allocation_buffer*, Arena->AllocationBuffersCount, NewAllocationBuffersCount); +#endif + Arena->AllocationBuffersCount = NewAllocationBuffersCount; gs_mem_u32 NewBufferIndex = Arena->AllocationBuffersCount - 1; - Arena->AllocationBuffers[NewBufferIndex] = (tracked_allocation_buffer*)ArenaAlloc(Arena, sizeof(tracked_allocation_buffer)); + Arena->AllocationBuffers[NewBufferIndex] = ArenaAllocStruct(*Arena, tracked_allocation_buffer); } gs_mem_u32 AllocationIndex = Arena->AllocationsUsed++; diff --git a/src/gs_libs/gs_radix_sort.h b/src/gs_libs/gs_radix_sort.h index ba9fc22..8e62a27 100644 --- a/src/gs_libs/gs_radix_sort.h +++ b/src/gs_libs/gs_radix_sort.h @@ -10,31 +10,31 @@ TODO #if !defined(GSRad_Assert) #define GSRad_Assert(expression) \ if(!(expression)) { \ - *((int *)0) = 5; \ +*((int *)0) = 5; \ } #endif // !defined(GSRad_Assert) #endif // DEBUG -typedef unsigned long long int gs_rad_u64; +typedef unsigned int gs_rad_u32; typedef unsigned int gs_rad_b32; struct gs_radix_entry { - gs_rad_u64 Radix; - gs_rad_u64 ID; + gs_rad_u32 Radix; + gs_rad_u32 ID; }; static void -RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u64 Start, gs_rad_u64 End, gs_rad_u64 Iteration) +RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u32 Start, gs_rad_u32 End, gs_rad_u32 Iteration) { - gs_rad_u64 Shift = Iteration; - gs_rad_u64 ZerosBoundary = Start; - gs_rad_u64 OnesBoundary = End - 1; + gs_rad_u32 Shift = Iteration; + gs_rad_u32 ZerosBoundary = Start; + gs_rad_u32 OnesBoundary = End - 1; - for (gs_rad_u64 d = Start; d < End; d++) + for (gs_rad_u32 d = Start; d < End; d++) { gs_radix_entry Entry = Data[ZerosBoundary]; - gs_rad_u64 Place = (Entry.Radix >> Shift) & 0x1; + gs_rad_u32 Place = (Entry.Radix >> Shift) & 0x1; if (Place) { gs_radix_entry Evicted = Data[OnesBoundary]; @@ -56,10 +56,10 @@ RadixSortInPlace_ (gs_radix_entry* Data, gs_rad_u64 Start, gs_rad_u64 End, gs_ra } static void -RadixSortInPlace (gs_radix_entry* Data, gs_rad_u64 Count) +RadixSortInPlace (gs_radix_entry* Data, gs_rad_u32 Count) { - gs_rad_u64 Highest = 0; - for (gs_rad_u64 i = 0; i < Count; i++) + gs_rad_u32 Highest = 0; + for (gs_rad_u32 i = 0; i < Count; i++) { if (Data[i].Radix > Highest) { @@ -67,7 +67,7 @@ RadixSortInPlace (gs_radix_entry* Data, gs_rad_u64 Count) } } - gs_rad_u64 Iterations = 0; + gs_rad_u32 Iterations = 0; while (Highest > 1) { ++Iterations; diff --git a/src/gs_libs/gs_string.h b/src/gs_libs/gs_string.h index 8f371fa..6b4efca 100644 --- a/src/gs_libs/gs_string.h +++ b/src/gs_libs/gs_string.h @@ -6,17 +6,6 @@ #ifndef GS_STRING_H #include -//////////////////////////////////////////////////////////////// -// String -//////////////////////////////////////////////////////////////// - -struct string -{ - char* Memory; - s32 Length; - s32 Max; -}; - //////////////////////////////////////////////////////////////// // String Tokenizing //////////////////////////////////////////////////////////////// @@ -114,79 +103,14 @@ struct token { token_type Type; u32 LineNumber; - u64 TextHash; - string Text; + gs_string Text; token* Next; // TODO(Peter): Get rid of this }; -//////////////////////////////////////////////////////////////// -// 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 IsNewlineOrWhitespace (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 void EatChar(tokenizer* T); static b32 AtValidPosition(tokenizer Tokenizer); @@ -208,299 +132,6 @@ static s32 EatPastCharacter(tokenizer* T, char Char); static char* EatNumber(char* C); static s32 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, s32 CharArrayLength); -static bool StringEqualsCharArray (string String, char* CharArray); -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 s32 SearchForCharInSet(string String, char* Set); -static s32 ReverseSearchForCharInSet(string String, char* Set); -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); - -static u32 HashString(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 (s32 Length, char* String); -static parse_result ParseSignedInt (s32 Length, char* String); -static parse_result ParseFloat (s32 Length, char* String); - -// PrintF - -#define StringExpand(str) (str).Length, (str).Memory -static void PrintFArgList(char* Dest, s32 DestMax, char* Format, va_list Args); -static void PrintF(string* String, char* Format, ...); - -// Printing Helper Functions -static u32 GetU32NumberOfCharactersNeeded(u32 Value, u32 Base = 10); -static u32 GetS32NumberOfCharactersNeeded(u32 Value, s32 Base = 10); - -//////////////////////////////////////////////////////////////// -// 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) -{ - DEBUG_TRACK_FUNCTION; - String->Memory = Data; - String->Max = DataSize; - String->Length = 0; -} - -static void -InitializeString(string* String, char* Data, s32 Used, s32 Max) -{ - DEBUG_TRACK_FUNCTION; - String->Memory = Data; - String->Max = Max; - String->Length = Used; -} - -static string -InitializeEmptyString (char* Data, s32 DataSize) -{ - DEBUG_TRACK_FUNCTION; - string Result = {}; - Result.Memory = Data; - Result.Max = DataSize; - Result.Length = 0; - return Result; -} - -static string -InitializeString (char* Data, s32 Used, s32 Max) -{ - DEBUG_TRACK_FUNCTION; - string Result = {}; - Result.Memory = Data; - Result.Max = Max; - Result.Length = Used; - return Result; -} - -static void -ClearString (string* String) -{ - DEBUG_TRACK_FUNCTION; - 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'); } -static bool IsNewlineOrWhitespace (char C) { return (IsWhitespace(C) || IsNewline(C)); } -static bool IsAlpha (char C) -{ - DEBUG_TRACK_FUNCTION; - // TODO(Peter): support UTF8 chars - return ((C >= 'A') && (C <= 'Z')) || ((C >= 'a') && (C <= 'z')) || (C == '_'); -} -static bool IsUpper (char C) -{ - DEBUG_TRACK_FUNCTION; - return ((C >= 'A') && (C <= 'Z')); -} -static bool IsLower (char C) -{ - DEBUG_TRACK_FUNCTION; - return ((C >= 'a') && (C <= 'z')); -} -static bool IsNumeric (char C) -{ - DEBUG_TRACK_FUNCTION; - return (C >= '0') && (C <= '9'); -} -static bool IsNumericExtended (char C) -{ - DEBUG_TRACK_FUNCTION; - return (IsNumeric(C) || (C == 'x') || (C == 'f') || (C == '.')); -} -static bool IsAlphaNumeric (char C) -{ - DEBUG_TRACK_FUNCTION; - return IsAlpha(C) || IsNumeric(C); -} -static bool IsOperator (char C) -{ - DEBUG_TRACK_FUNCTION; - return ((C == '+') || - (C == '-') || - (C == '*') || - (C == '/') || - (C == '=') || - (C == '%') || - (C == '<') || - (C == '>')); -} -static char ToUpper (char A) -{ - DEBUG_TRACK_FUNCTION; - char Result = A; - if (IsLower(A)) - { - Result += 'A' - 'a'; - } - return Result; -} -static char ToLower (char A) -{ - DEBUG_TRACK_FUNCTION; - char Result = A; - if (IsUpper(A)) - { - Result -= 'A' - 'a'; - } - return Result; -} -static bool CharsEqualCaseInsensitive (char A, char B) -{ - DEBUG_TRACK_FUNCTION; - b32 Result = (ToLower(A) == ToLower(B)); - return Result; -} - //////////////////////////////////////////////////////////////// // Tokenizing //////////////////////////////////////////////////////////////// @@ -508,7 +139,6 @@ static bool CharsEqualCaseInsensitive (char A, char B) static void EatChar (tokenizer* T) { - DEBUG_TRACK_FUNCTION; if (AtValidPosition(*T)) { if (IsNewline(*T->At)) @@ -527,7 +157,6 @@ EatChar (tokenizer* T) static b32 AtValidPosition (tokenizer Tokenizer) { - DEBUG_TRACK_FUNCTION; b32 Result = (Tokenizer.At - Tokenizer.Memory) <= Tokenizer.MemoryLength; return Result; } @@ -535,7 +164,6 @@ AtValidPosition (tokenizer Tokenizer) static b32 AtValidToken(tokenizer Tokenizer) { - DEBUG_TRACK_FUNCTION; b32 Result = *Tokenizer.At && Tokenizer.At < (Tokenizer.Memory + Tokenizer.MemoryLength); return Result; } @@ -543,7 +171,6 @@ AtValidToken(tokenizer Tokenizer) static char* EatToNewLine(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && !IsNewline(*Result)) { @@ -555,7 +182,6 @@ EatToNewLine(char* C) static s32 EatToNewLine(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && !IsNewline(*T->At)) { @@ -567,7 +193,6 @@ EatToNewLine(tokenizer* T) static char* EatPastNewLine(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = EatToNewLine(C); while(*Result && IsNewline(*Result)) { @@ -579,7 +204,6 @@ EatPastNewLine(char* C) static s32 EatPastNewLine(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; EatToNewLine(T); @@ -594,7 +218,6 @@ EatPastNewLine(tokenizer* T) static char* EatWhitespace(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && IsNewlineOrWhitespace(*Result)) { Result++; } return Result; @@ -603,7 +226,6 @@ EatWhitespace(char* C) static s32 EatWhitespace(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && IsNewlineOrWhitespace(*T->At)) { EatChar(T); } return T->At - TStart; @@ -612,7 +234,6 @@ EatWhitespace(tokenizer* T) static char* EatToNonWhitespaceOrNewline(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && IsWhitespace(*Result)) { Result++; } return Result; @@ -621,7 +242,6 @@ EatToNonWhitespaceOrNewline(char* C) static s32 EatToNonWhitespaceOrNewline(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && IsWhitespace(*T->At)) { EatChar(T); } return T->At - TStart; @@ -630,7 +250,6 @@ EatToNonWhitespaceOrNewline(tokenizer* T) static char* EatToWhitespace(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && !IsWhitespace(*Result)) { Result++; } return Result; @@ -639,7 +258,6 @@ EatToWhitespace(char* C) static s32 EatToWhitespace(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && !IsWhitespace(*T->At)) { EatChar(T); } return T->At - TStart; @@ -648,7 +266,6 @@ EatToWhitespace(tokenizer* T) static char* EatToCharacter(char* C, char Char) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && *Result != Char) { Result++; } return Result; @@ -657,7 +274,6 @@ EatToCharacter(char* C, char Char) static s32 EatToCharacter(tokenizer* T, char Char) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && *T->At != Char) { EatChar(T); } return T->At - TStart; @@ -666,7 +282,6 @@ EatToCharacter(tokenizer* T, char Char) static char* EatPastCharacter(char* C, char Char) { - DEBUG_TRACK_FUNCTION; char* Result = EatToCharacter(C, Char); if (*Result && *Result == Char) { Result++; } return Result; @@ -675,7 +290,6 @@ EatPastCharacter(char* C, char Char) static s32 EatPastCharacter(tokenizer* T, char Char) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; EatToCharacter(T, Char); if (AtValidPosition(*T) && *T->At == Char) { EatChar(T); } @@ -685,7 +299,6 @@ EatPastCharacter(tokenizer* T, char Char) static char* EatNumber(char* C) { - DEBUG_TRACK_FUNCTION; char* Result = C; while (*Result && IsNumericExtended(*Result)) { Result++; } return Result; @@ -694,1852 +307,12 @@ EatNumber(char* C) static s32 EatNumber(tokenizer* T) { - DEBUG_TRACK_FUNCTION; char* TStart = T->At; while (AtValidPosition(*T) && IsNumericExtended(*T->At)) { EatChar(T); } return T->At - TStart; } -//////////////////////////////////////////////////////////////// -// Basic Char Operations -//////////////////////////////////////////////////////////////// - -static u32 CharToUInt (char C) -{ - DEBUG_TRACK_FUNCTION; - u32 Result = (C - '0'); - return Result; -} - -static s32 -CharArrayLength (char* Array) -{ - DEBUG_TRACK_FUNCTION; - char* C = Array; - s32 Result = 0; - while (*C) - { - *C++; - Result++; - } - return Result; -} - -static s32 -NullTerminatedCharArrayLength (char* CharArray) -{ - DEBUG_TRACK_FUNCTION; - char* Iter = CharArray; - while (*Iter) - { - *Iter++; - } - return (Iter - CharArray); -} - -static bool -CharArraysEqual (char* A, s32 ALength, char* B, s32 BLength) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - s32 StringLength = NullTerminatedCharArrayLength(Array); - return FastReverseIndexOfChar(Array, StringLength, OffsetFromEnd, Find); -} - -static b32 -CharArrayContains(char* Array, char* CheckFor) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - string Result = {}; - Result.Memory = Array; - Result.Length = Length; - Result.Max = Max; - return Result; -} - -static string -MakeString (char* Array, s32 Length) -{ - DEBUG_TRACK_FUNCTION; - string Result = {}; - Result.Memory = Array; - Result.Length = Length; - Result.Max = Length; - return Result; -} - -static string -MakeString (char* Array) -{ - DEBUG_TRACK_FUNCTION; - s32 Length = CharArrayLength (Array); - return MakeString(Array, Length); -} - -static string -MakeStringLiteral (char* String) -{ - DEBUG_TRACK_FUNCTION; - string Result = {}; - Result.Memory = String; - Result.Max = CharArrayLength(String); - Result.Length = Result.Max; - return Result; -} - -static bool -StringEqualsCharArray (string String, char* CharArray, s32 CharArrayLength) -{ - DEBUG_TRACK_FUNCTION; - 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 bool -StringEqualsCharArray (string String, char* CharArray) -{ - DEBUG_TRACK_FUNCTION; - s32 CLength = CharArrayLength(CharArray); - return StringEqualsCharArray(String, CharArray, CLength); -} - -static s32 -FindFirstChar (string String, char C) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - Assert(Dest->Length + 1 <= Dest->Max); - - char* Dst = Dest->Memory + Dest->Length; - *Dst = C; - Dest->Length++; -} - -static void -ConcatCharArrayToString (char* Source, string* Dest) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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 s32 -SearchForCharInSet(string String, char* Set) -{ - DEBUG_TRACK_FUNCTION; - s32 Index = -1; - - char* At = String.Memory; - for (s32 i = 0; i < String.Length; i++) - { - char* Needle = Set; - while (*Needle) - { - if (*At == *Needle) - { - Index = String.Length - i; - break; - } - - Needle++; - } - - if (Index >= 0) - { - break; - } - - At++; - } - - return Index; -} - -static s32 -ReverseSearchForCharInSet(string String, char* Set) -{ - DEBUG_TRACK_FUNCTION; - s32 Index = -1; - - for (s32 i = String.Length - 1; i >= 0; i--) - { - char* Needle = Set; - while (*Needle) - { - if (String.Memory[i] == *Needle) - { - Index = i; - break; - } - - Needle++; - } - - if (Index >= 0) - { - break; - } - } - - return Index; -} - -static string -Substring (string String, s32 Start, s32 End) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - return StringContainsCharArray(SearchIn, SearchFor.Memory, SearchFor.Length); -} - -static b32 -StringContainsCharArrayCaseInsensitive(string SearchIn, char* SearchFor, s32 SearchForLength) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - return StringContainsCharArrayCaseInsensitive(SearchIn, SearchFor.Memory, SearchFor.Length); -} - -static void -NullTerminate (string* String) -{ - DEBUG_TRACK_FUNCTION; - Assert(String->Length + 1 <= String->Max); - *(String->Memory + String->Length) = 0; - String->Length++; -} - -// http://www.cse.yorku.ca/~oz/hash.html -// djb2 hash -static u32 -HashString(string String) -{ - DEBUG_TRACK_FUNCTION; - u32 Hash = 5381; - for (s32 i = 0; i < String.Length; i++) - { - Hash = ((Hash << 5) + Hash) + (u32)String.Memory[i]; /* hash * 33 + c */ - } - return Hash; -} - -static void -InsertStringAt (string* Dest, string Source, s32 At) -{ - DEBUG_TRACK_FUNCTION; - 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 -//////////////////////////////////////////////////////////////// - -// NOTE(Peter): parameters are all in order Length, String because -// that matches the order of C's printf %.*s format specifier. This -// is convenient because you can use StringExpand to parse a string -// struct -// :StringExpandNote -static parse_result -ParseUnsignedInt (s32 Length, char* String) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - char* Start = String; - char* End = EatNumber(String + 1); - return ParseUnsignedInt(End - Start, String); -} - -// :StringExpandNote -static parse_result -ParseSignedInt (s32 Length, char* String) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - char* Start = String; - char* End = EatNumber(String + 1); - return ParseSignedInt(End - Start, String); -} - -// :StringExpandNote -static parse_result -ParseFloat (s32 Length, char* String) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - char* Start = String; - char* End = EatNumber(String + 1); - return ParseFloat(End - Start, String); -} - -static s32 -UIntToString (u32 Int, char* String, s32 MaxLength, b32 FormatFlags = 0, s32 MinimumLength = 0) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - char* DestAt = Dest; - - char* FormatAt = Format; - while (*FormatAt) - { - if (FormatAt[0] != '%') - { - *DestAt++ = *FormatAt++; - } - else if (FormatAt[0] == '%' && FormatAt[1] == '%') // Print the % symbol - { - *DestAt++ = '%'; - FormatAt += 2; - } - 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] == 'S') - { - string InsertString = va_arg(Args, string); - - for (s32 c = 0; c < InsertString.Length; c++) - { - OutChar(&TempDest, InsertString.Memory[c]); - } - } - 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; -} - -static void -PrintF (string* String, char* Format, ...) -{ - DEBUG_TRACK_FUNCTION; - va_list Args; - va_start(Args, Format); - String->Length = 0; - String->Length += PrintFArgsList(String->Memory + String->Length, String->Max - String->Length, Format, Args); - va_end(Args); -} - -static void -AppendPrintF (string* String, char* Format, ...) -{ - DEBUG_TRACK_FUNCTION; - va_list Args; - va_start(Args, Format); - String->Length += PrintFArgsList(String->Memory + String->Length, String->Max - String->Length, Format, Args); - va_end(Args); -} - -// Printing Helper Functions -static u32 -GetU32NumberOfCharactersNeeded(u32 Value, u32 Base) -{ - DEBUG_TRACK_FUNCTION; - u32 Result = 0; - u32 ValueLeft = Value; - // NOTE(Peter): This is in a do while loop because even if the number is 0, - // it'll still take one character to display that. - do - { - Result += 1; - ValueLeft /= Base; - }while (ValueLeft > 0); - return Result; -} - -static u32 -GetS32NumberOfCharactersNeeded(s32 Value, s32 Base) -{ - DEBUG_TRACK_FUNCTION; - u32 Result = 0; - s32 ValueLeft = Value; - if (Value < 0) - { - Result += 1; - ValueLeft = Value * -1; - } - // NOTE(Peter): This is in a do while loop because even if the number is 0, - // it'll still take one character to display that. - do - { - Result += 1; - ValueLeft /= Base; - }while (ValueLeft > 0); - return Result; -} - -//////////////////////////////////////////////////////////////// -// String Memory Function Definitions -//////////////////////////////////////////////////////////////// - -static s32 -CalculateSlotCountFromSize (s32 RequestedSize, s32 SlotSize) -{ - DEBUG_TRACK_FUNCTION; - s32 SlotCount = RequestedSize / SlotSize; - if (SlotCount * SlotSize < RequestedSize) - { - SlotCount += 1; - } - return SlotCount; -} - -static bool -SlotsAreContiguous (slot_header* First, slot_header* Second) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - string Result = {0}; - AllocStringFromStringArena(&Result, Size, Storage); - return Result; -} - -static void -FreeToStringArena (string* String, slot_arena* Storage) -{ - DEBUG_TRACK_FUNCTION; - 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) -{ - DEBUG_TRACK_FUNCTION; - string NewString = AllocStringFromStringArena(NewSize, Storage); - CopyStringTo(*String, &NewString); - FreeToStringArena(String, Storage); - *String = NewString; -} - -#if defined(DEBUG) - -void DEBUGPrintChars (string* String, s32 Count) -{ - DEBUG_TRACK_FUNCTION; - 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 +#endif // GS_STRING_H + + diff --git a/src/gs_libs/gs_string_builder.h b/src/gs_libs/gs_string_builder.h index e6e5df0..1102e97 100644 --- a/src/gs_libs/gs_string_builder.h +++ b/src/gs_libs/gs_string_builder.h @@ -37,7 +37,7 @@ GrowStringBuilder(string_builder* StringBuilder) { StringBuilder->Buffers = NewBuffer; StringBuilder->Head = NewBuffer; - } + } else { StringBuilder->Head->Next = NewBuffer; @@ -60,7 +60,7 @@ Write(string Text, string_builder* StringBuilder) // Copy what there is room for s32 SpaceAvailable = StringBuilder->Head->String.Max - StringBuilder->Head->String.Length; - ConcatString(TextLeft, GSMin(SpaceAvailable, TextLeft.Length), &StringBuilder->Head->String); + ConcatString(TextLeft, Min(SpaceAvailable, TextLeft.Length), &StringBuilder->Head->String); TextLeft.Memory += SpaceAvailable; TextLeft.Length -= SpaceAvailable; @@ -93,7 +93,7 @@ WriteStringBuilderToFile(string_builder StringBuilder, FILE* WriteFile) while (BufferAt) { string String = BufferAt->String; - fwrite(String.Memory, 1, String.Length, WriteFile); + fwrite(String.Str, 1, String.Length, WriteFile); BufferAt = BufferAt->Next; } } diff --git a/src/gs_libs/gs_types.cpp b/src/gs_libs/gs_types.cpp new file mode 100644 index 0000000..12bd157 --- /dev/null +++ b/src/gs_libs/gs_types.cpp @@ -0,0 +1,3403 @@ +// +// File: gs_types.cpp +// Author: Peter Slattery +// Creation Date: 2020-04-18 +// +#ifndef GS_TYPES_CPP + +#define StructToData(ptr, type) StructToData_((u8*)(ptr), sizeof(type)) +internal gs_data +StructToData_(u8* Memory, u64 Size) +{ + gs_data Result = {0}; + Result.Memory = Memory; + Result.Size = Size; + return Result; +} + +internal u32 +U32DivideRoundUp (u32 A, u32 B) +{ + r32 Result = (r32)A / (r32)B; + Result += .99999f; + return (u32)Result; +} + +inline bool XOR(bool A, bool B) { return (A == !B); } +inline bool XOR(b8 A, b8 B) { return (A == !B); } +inline bool XOR(b32 A, b32 B) { return (A == !B); } +inline bool XOR(b64 A, b64 B) { return (A == !B); } + +internal u32 +RoundUpToMultiple(u32 Value, u32 MultipleOf) +{ + u32 Result = Value; + if (MultipleOf != 0) + { + u32 Remainder = Value % MultipleOf; + Result = Value + (MultipleOf - Remainder); + } + return Result; +} +internal u32 +RoundUpToPow2U32(u32 Value) +{ + u32 Result = Value - 1; + Result |= Result >> 1; + Result |= Result >> 2; + Result |= Result >> 4; + Result |= Result >> 8; + Result |= Result >> 16; + Result++; + return Result; +} +internal u32 +RoundUpToPow2U64(u64 Value) +{ + u64 Result = Value - 1; + Result |= Result >> 1; + Result |= Result >> 2; + Result |= Result >> 4; + Result |= Result >> 8; + Result |= Result >> 16; + Result |= Result >> 32; + Result++; + return Result; +} +internal u64 +RoundUpTo64(u64 Value, u64 Alignment) +{ + Value += Alignment - 1; + Value -= Value % Alignment; + return Value; +} + +internal u8 +PowU8(u8 X, u32 Power) +{ + u8 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal u16 +PowU16(u16 X, u32 Power) +{ + u16 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal u32 +PowU32(u32 X, u32 Power) +{ + u32 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal u64 +PowU64(u64 X, u32 Power) +{ + u64 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal s8 +PowS8(s8 X, u32 Power) +{ + s8 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal s16 +PowS16(s16 X, u32 Power) +{ + s16 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal s32 +PowS32(s32 X, u32 Power) +{ + s32 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal s64 +PowS64(s64 X, u32 Power) +{ + s64 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal r32 +PowR32(r32 X, u32 Power) +{ + r32 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} +internal r64 +PowR64(r64 X, u32 Power) +{ + r64 Result = X; + for (u32 i = 1; i < Power; i++) { Result *= X; } + return Result; +} + +internal u8 +LerpU8(r32 T, u8 A, u8 B) +{ + return (u8)((A * (1.0f - T)) + (B * T)); +} +internal u16 +LerpU16(r32 T, u16 A, u16 B) +{ + return (u16)((A * (1.0f - T)) + (B * T)); +} +internal u32 +LerpU32(r32 T, u32 A, u32 B) +{ + return (u32)((A * (1.0f - T)) + (B * T)); +} +internal u64 +LerpU64(r32 T, u64 A, u64 B) +{ + return (u64)((A * (1.0f - T)) + (B * T)); +} +internal s8 +LerpS8(r32 T, s8 A, s8 B) +{ + return (s8)((A * (1.0f - T)) + (B * T)); +} +internal s16 +LerpS16(r32 T, s16 A, s16 B) +{ + return (s16)((A * (1.0f - T)) + (B * T)); +} +internal s32 +LerpS32(r32 T, s32 A, s32 B) +{ + return (s32)((A * (1.0f - T)) + (B * T)); +} +internal s64 +LerpS64(r32 T, s64 A, s64 B) +{ + return (s64)((A * (1.0f - T)) + (B * T)); +} +internal r32 +LerpR32(r32 T, r32 A, r32 B) +{ + return (r32)((A * (1.0f - T)) + (B * T)); +} +internal r64 +LerpR64(r32 T, r64 A, r64 B) +{ + return (r64)((A * (1.0f - T)) + (B * T)); +} + +internal u8 +UnlerpU8(u8 Value, u8 Min, u8 Max) +{ + return (u8)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal u16 +UnlerpU16(u16 Value, u16 Min, u16 Max) +{ + return (u16)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal u32 +UnlerpU32(u32 Value, u32 Min, u32 Max) +{ + return (u32)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal u64 +UnlerpU64(u64 Value, u64 Min, u64 Max) +{ + return (u64)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal s8 +UnlerpS8(s8 Value, s8 Min, s8 Max) +{ + return (s8)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal s16 +UnlerpS16(s16 Value, s16 Min, s16 Max) +{ + return (s16)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal s32 +UnlerpS32(s32 Value, s32 Min, s32 Max) +{ + return (s32)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal s64 +UnlerpS64(s64 Value, s64 Min, s64 Max) +{ + return (s64)((r64)(Value - Min) / (r64)(Max - Min)); +} +internal r32 +UnlerpR32(r32 Value, r32 Min, r32 Max) +{ + return (Value - Min) / (Max - Min); +} +internal r64 +UnlerpR64(r64 Value, r64 Min, r64 Max) +{ + return (Value - Min) / (Max - Min); +} + + +internal u8 +RemapU8(u8 Value, u8 OldMin, u8 OldMax, u8 NewMin, u8 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + u8 Result = (u8)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal u16 +RemapU16(u16 Value, u16 OldMin, u16 OldMax, u16 NewMin, u16 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + u16 Result = (u16)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal u32 +RemapU32(u32 Value, u32 OldMin, u32 OldMax, u32 NewMin, u32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + u32 Result = (u32)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal u64 +RemapU64(u64 Value, u64 OldMin, u64 OldMax, u64 NewMin, u64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + u64 Result = (u64)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal s8 +RemapS8(s8 Value, s8 OldMin, s8 OldMax, s8 NewMin, s8 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + s8 Result = (s8)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal s16 +RemapS16(s16 Value, s16 OldMin, s16 OldMax, s16 NewMin, s16 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + s16 Result = (s16)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal s32 +RemapS32(s32 Value, s32 OldMin, s32 OldMax, s32 NewMin, s32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + s32 Result = (s32)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal s64 +RemapS64(s64 Value, s64 OldMin, s64 OldMax, s64 NewMin, s64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + s64 Result = (s64)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal r32 +RemapR32(r32 Value, r32 OldMin, r32 OldMax, r32 NewMin, r32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r32 Result = (r32)((A * (NewMax - NewMin)) + NewMin); + return Result; +} +internal r64 +RemapR64(r64 Value, r64 OldMin, r64 OldMax, r64 NewMin, r64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 Result = (r64)((A * (NewMax - NewMin)) + NewMin); + return Result; +} + +internal u8 +RemapClampedU8(u8 Value, u8 OldMin, u8 OldMax, u8 NewMin, u8 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + u8 Result = (u8)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal u16 +RemapClampedU16(u16 Value, u16 OldMin, u16 OldMax, u16 NewMin, u16 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + u16 Result = (u16)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal u32 +RemapClampedU32(u32 Value, u32 OldMin, u32 OldMax, u32 NewMin, u32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + u32 Result = (u32)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal u64 +RemapClampedU64(u64 Value, u64 OldMin, u64 OldMax, u64 NewMin, u64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + u64 Result = (u64)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal s8 +RemapClampedS8(s8 Value, s8 OldMin, s8 OldMax, s8 NewMin, s8 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + s8 Result = (s8)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal s16 +RemapClampedS16(s16 Value, s16 OldMin, s16 OldMax, s16 NewMin, s16 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + s16 Result = (s16)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal s32 +RemapClampedS32(s32 Value, s32 OldMin, s32 OldMax, s32 NewMin, s32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + s32 Result = (s32)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal s64 +RemapClampedS64(s64 Value, s64 OldMin, s64 OldMax, s64 NewMin, s64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + s64 Result = (s64)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal r32 +RemapClampedR32(r32 Value, r32 OldMin, r32 OldMax, r32 NewMin, r32 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + r32 Result = (r32)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} +internal r64 +RemapClampedR64(r64 Value, r64 OldMin, r64 OldMax, r64 NewMin, r64 NewMax) +{ + r64 A = (r64)(Value - OldMin) / (r64)(OldMax - OldMin); + r64 AClamped = Clamp01(A); + r64 UnclampedResult = ((AClamped * (NewMax - NewMin)) + NewMin); + r64 Result = (r64)Clamp(NewMin, UnclampedResult, NewMax); + return Result; +} + +internal r32 +FloorR32(r32 V) +{ + return (r32)((s64)V); +} +internal r64 +FloorR64(r64 V) +{ + return (r64)((s64)V); +} + +internal r32 +FractR32(r32 V) +{ + return V - FloorR32(V); +} +internal r64 +FractR64(r64 V) +{ + return V - FloorR64(V); +} + +internal r32 +SqrtR32(r32 V) +{ + return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set_ss(V))); +} +internal u32 +SqrtU32(u32 V) +{ + return sqrt(V); +} + +internal r32 +SinR32(r32 Rad) +{ + return sinf(Rad); +} +internal r64 +SinR64(r64 Rad) +{ + return sin(Rad); +} + +internal r32 +CosR32(r32 Rad) +{ + return cosf(Rad); +} +internal r64 +CosR64(r64 Rad) +{ + return cos(Rad); +} + +internal r32 +TanR32(r32 Rad) +{ + return tanf(Rad); +} +internal r64 +TanR64(r64 Rad) +{ + return tan(Rad); +} + +internal r32 +ASinR32(r32 Rad) +{ + return asinf(Rad); +} +internal r64 +ASinR64(r64 Rad) +{ + return asin(Rad); +} + +internal r32 +ACosR32(r32 Rad) +{ + return acosf(Rad); +} +internal r64 +ACosR64(r64 Rad) +{ + return acos(Rad); +} + +internal r32 +ATanR32(r32 Rad) +{ + return atanf(Rad); +} +internal r64 +ATanR64(r64 Rad) +{ + return atan(Rad); +} + +/////////////////////////// +// +// Vector + +internal v2 +V2MultiplyPairwise(v2 A, v2 B) +{ + v2 Result = v2{ + A.x * B.x, + A.y * B.y, + }; + return Result; +} + +internal v3 +V3MultiplyPairwise(v3 A, v3 B) +{ + v3 Result = v3{ + A.x * B.x, + A.y * B.y, + A.z * B.z, + }; + return Result; +} + +internal v4 +V4MultiplyPairwise(v4 A, v4 B) +{ + v4 Result = v4{ + A.x * B.x, + A.y * B.y, + A.z * B.z, + A.w * B.w, + }; + return Result; +} + + +v2 operator- (v2 A) { return { -A.x, -A.y }; } +v3 operator- (v3 A) { return { -A.x, -A.y, -A.z }; } +v4 operator- (v4 A) { return { -A.x, -A.y, -A.z, -A.w }; } + +v2 operator+ (v2 A, v2 B) { return { A.x + B.x, A.y + B.y }; } +v3 operator+ (v3 A, v3 B) { return { A.x + B.x, A.y + B.y, A.z + B.z }; } +v4 operator+ (v4 A, v4 B) { return { A.x + B.x, A.y + B.y, A.z + B.z, A.w + B.w }; } + +v2 operator- (v2 A, v2 B) { return { A.x - B.x, A.y - B.y }; } +v3 operator- (v3 A, v3 B) { return { A.x - B.x, A.y - B.y, A.z - B.z }; } +v4 operator- (v4 A, v4 B) { return { A.x - B.x, A.y - B.y, A.z - B.z, A.w - B.w }; } + +void operator+= (v2& A, v2 B) { A.x += B.x; A.y += B.y; } +void operator+= (v3& A, v3 B) { A.x += B.x; A.y += B.y; A.z += B.z; } +void operator+= (v4& A, v4 B) { A.x += B.x; A.y += B.y; A.z += B.z; A.w += B.w; } + +void operator-= (v2& A, v2 B) { A.x -= B.x; A.y -= B.y; } +void operator-= (v3& A, v3 B) { A.x -= B.x; A.y -= B.y; A.z -= B.z; } +void operator-= (v4& A, v4 B) { A.x -= B.x; A.y -= B.y; A.z -= B.z; A.w -= B.w; } + +v2 operator* (v2 A, r32 B) { return { A.x * B, A.y * B }; } +v3 operator* (v3 A, r32 B) { return { A.x * B, A.y * B, A.z * B }; } +v4 operator* (v4 A, r32 B) { return { A.x * B, A.y * B, A.z * B, A.w * B }; } + +v2 operator/ (v2 A, r32 B) { return { A.x / B, A.y / B }; } +v3 operator/ (v3 A, r32 B) { return { A.x / B, A.y / B, A.z / B }; } +v4 operator/ (v4 A, r32 B) { return { A.x / B, A.y / B, A.z / B, A.w / B }; } + +void operator*= (v2& A, r32 B) { A.x *= B; A.y *= B; } +void operator*= (v3& A, r32 B) { A.x *= B; A.y *= B; A.z *= B; } +void operator*= (v4& A, r32 B) { A.x *= B; A.y *= B; A.z *= B; A.w *= B; } + +void operator/= (v2& A, r32 B) { A.x /= B; A.y /= B; } +void operator/= (v3& A, r32 B) { A.x /= B; A.y /= B; A.z /= B; } +void operator/= (v4& A, r32 B) { A.x /= B; A.y /= B; A.z /= B; A.w /= B; } + +bool operator == (v2 A, v2 B) { return ((A.x == B.x) && (A.y == B.y)); } +bool operator == (v3 A, v3 B) { return ((A.x == B.x) && (A.y == B.y) && (A.z == B.z)); } +bool operator == (v4 A, v4 B) { return ((A.x == B.x) && (A.y == B.y) && (A.z == B.z) && (A.w == B.w)); } + +bool operator != (v2 A, v2 B) { return !((A.x == B.x) && (A.y == B.y)); } +bool operator != (v3 A, v3 B) { return !((A.x == B.x) && (A.y == B.y) && (A.z == B.z)); } +bool operator != (v4 A, v4 B) { return !((A.x == B.x) && (A.y == B.y) && (A.z == B.z) && (A.w == B.w)); } + +internal v3 ToV3(v2 V, r32 Z = 0) { return v3{V.x, V.y, Z}; } +internal v4 V2ToV4(v2 V, r32 Z = 0, r32 W = 0) { return v4{V.x, V.y, Z, W}; } +internal v4 ToV4_(v3 V, r32 W) +{ + return v4{V.x, V.y, V.z, W}; +} +#define ToV4Point(v) ToV4_((v), 1.0f) // all points have a w value of 1 +#define ToV4Vec(v) ToV4_((v), 0.0f) // all vectors have a w value of 0 ie. they cannot be translated + +internal r32 V2MagSquared(v2 V) { return ((V.x * V.x) + (V.y * V.y)); } +internal r32 V3MagSquared(v3 V) { return ((V.x * V.x) + (V.y * V.y) + (V.z * V.z)); } +internal r32 V4MagSquared(v4 V) { return ((V.x * V.x) + (V.y * V.y) + (V.z * V.z) + (V.w * V.w)); } + +internal r32 V2Mag(v2 V) { return SqrtR32((V.x * V.x) + (V.y * V.y)); } +internal r32 V3Mag(v3 V) { return SqrtR32((V.x * V.x) + (V.y * V.y) + (V.z * V.z)); } +internal r32 V4Mag(v4 V) { return SqrtR32((V.x * V.x) + (V.y * V.y) + (V.z * V.z) + (V.w * V.w)); } + +internal r32 V2DistanceSquared(v2 A, v2 B) { return V2MagSquared(A - B); } +internal r32 V3DistanceSquared(v3 A, v3 B) { return V3MagSquared(A - B); } +internal r32 V4DistanceSquared(v4 A, v4 B) { return V4MagSquared(A - B); } + +internal r32 V2Distance(v2 A, v2 B) { return V2Mag(A - B); } +internal r32 V3Distance(v3 A, v3 B) { return V3Mag(A - B); } +internal r32 V4Distance(v4 A, v4 B) { return V4Mag(A - B); } + +internal v2 +V2Normalize(v2 A) +{ + r32 Magnitude = V2Mag(A); + return A / Magnitude; +} +internal v3 +V3Normalize(v3 A) +{ + r32 Magnitude = V3Mag(A); + return A / Magnitude; +} +internal v4 +V4Normalize(v4 A) +{ + r32 Magnitude = V4Mag(A); + return A / Magnitude; +} + +internal r32 V2Dot(v2 A, v2 B) { return ((A.x * B.x) + (A.y * B.y)); } +internal r32 V3Dot(v3 A, v3 B) { return ((A.x * B.x) + (A.y * B.y) + (A.z * B.z)); } +internal r32 V4Dot(v4 A, v4 B) { return ((A.x * B.x) + (A.y * B.y) + (A.z * B.z) + (A.w * B.w)); } + +internal v2 V2PerpendicularCW(v2 A) { return v2{A.y, -A.x}; } +internal v2 V2PerpendicularCCW(v2 A) { return v2{A.y, A.x}; } + +internal r32 +V2Cross(v2 A, v2 B) +{ + return ((A.x * B.y) - (A.y * B.x)); +} + +internal v3 +V3Cross(v3 A, v3 B) +{ + v3 Result = { + (A.y * B.z) - (A.z * B.y), + (A.z * B.x) - (A.x * B.z), + (A.x * B.y) - (A.y * B.x) + }; + return Result; +} + +internal v4 +V4Cross(v4 A, v4 B) +{ + v4 Result = { + (A.y * B.z) - (A.z * B.y), + (A.z * B.x) - (A.x * B.z), + (A.x * B.y) - (A.y * B.x), + 0 + }; + return Result; +} + +internal v2 +V2Lerp(v2 A, v2 B, r32 T) +{ + v2 Result = v2{ + LerpR32(A.x, B.x, T), + LerpR32(A.y, B.y, T), + }; + return Result; +} + +internal v3 +V3Lerp(v3 A, v3 B, r32 T) +{ + v3 Result = v3{ + LerpR32(A.x, B.x, T), + LerpR32(A.y, B.y, T), + LerpR32(A.z, B.z, T), + }; + return Result; +} + +internal v4 +V4Lerp(v4 A, v4 B, r32 T) +{ + v4 Result = v4{ + LerpR32(A.x, B.x, T), + LerpR32(A.y, B.y, T), + LerpR32(A.z, B.z, T), + LerpR32(A.w, B.w, T), + }; + return Result; +} + +internal v2 +V2Remap(v2 P, v2 OldMin, v2 OldMax, v2 NewMin, v2 NewMax) +{ + v2 Result = {0}; + Result.x = RemapR32(P.x, OldMin.x, OldMax.x, NewMin.x, NewMax.x); + Result.y = RemapR32(P.y, OldMin.y, OldMax.y, NewMin.y, NewMax.y); + return Result; +} + +internal v3 +V3Remap(v3 P, v3 OldMin, v3 OldMax, v3 NewMin, v3 NewMax) +{ + v3 Result = {0}; + Result.x = RemapR32(P.x, OldMin.x, OldMax.x, NewMin.x, NewMax.x); + Result.y = RemapR32(P.y, OldMin.y, OldMax.y, NewMin.y, NewMax.y); + Result.z = RemapR32(P.z, OldMin.z, OldMax.z, NewMin.z, NewMax.z); + return Result; +} + +internal v4 +V4Remap(v4 P, v4 OldMin, v4 OldMax, v4 NewMin, v4 NewMax) +{ + v4 Result = {0}; + Result.x = RemapR32(P.x, OldMin.x, OldMax.x, NewMin.x, NewMax.x); + Result.y = RemapR32(P.y, OldMin.y, OldMax.y, NewMin.y, NewMax.y); + Result.z = RemapR32(P.z, OldMin.z, OldMax.z, NewMin.z, NewMax.z); + Result.w = RemapR32(P.w, OldMin.w, OldMax.w, NewMin.w, NewMax.w); + return Result; +} + +internal v4 +V4RemapAsV3(v4 P, v4 OldMin, v4 OldMax, v4 NewMin, v4 NewMax) +{ + v4 Result = {0}; + Result.xyz = V3Remap(P.xyz, OldMin.xyz, OldMax.xyz, NewMin.xyz, NewMax.xyz); + Result.w = P.w; + return Result; +} + +/////////////////////////// +// +// Ranges + +internal rect2 MakeRect2MinDim(v2 Min, v2 Dim) +{ + rect2 Result = {0}; + Result.Min = Min; + Result.Max = Min + Dim; + return Result; +} + +internal rect2 MakeRect2CenterDim(v2 Center, v2 Dim) +{ + v2 HalfDim = Dim / 2; + rect2 Result = {0}; + Result.Min = Center - HalfDim; + Result.Max = Center + HalfDim; + return Result; +} + +internal b32 ValueInRangeR32(r32 Min, r32 Max, r32 V) +{ + return ((V >= Min) && (V <= Max)); +} + +internal b32 ValueInRange1(range1 Range, r32 V) +{ + return ValueInRangeR32(Range.Min, Range.Max, V); +} +internal b32 ValueInRange2(range2 Range, v2 V) +{ + return (ValueInRangeR32(Range.Min.x, Range.Max.x, V.x) && + ValueInRangeR32(Range.Min.y, Range.Max.y, V.y)); +} +internal b32 ValueInRange3(range3 Range, v3 V) +{ + return (ValueInRangeR32(Range.Min.x, Range.Max.x, V.x) && + ValueInRangeR32(Range.Min.y, Range.Max.y, V.y) && + ValueInRangeR32(Range.Min.z, Range.Max.z, V.z)); +} +internal b32 ValueInRange4(range4 Range, v4 V) +{ + return (ValueInRangeR32(Range.Min.x, Range.Max.x, V.x) && + ValueInRangeR32(Range.Min.y, Range.Max.y, V.y) && + ValueInRangeR32(Range.Min.z, Range.Max.z, V.z) && + ValueInRangeR32(Range.Min.w, Range.Max.w, V.w)); +} + +#define PointIsInRect(range, point) ValueInRange2((range), (point)) + +internal r32 Range1SizeX(range1 Range) { return Range.Max - Range.Min; } +internal r32 Range2SizeX(range2 Range) { return Range.Max.x - Range.Min.x; } +internal r32 Range3SizeX(range3 Range) { return Range.Max.x - Range.Min.x; } +internal r32 Range4SizeX(range4 Range) { return Range.Max.x - Range.Min.x; } + +#define Rect2Width(r) Range2SizeX((r)) + +internal r32 Range2SizeY(range2 Range) { return Range.Max.y - Range.Min.y; } +internal r32 Range3SizeY(range3 Range) { return Range.Max.y - Range.Min.y; } +internal r32 Range4SizeY(range4 Range) { return Range.Max.y - Range.Min.y; } + +#define Rect2Height(r) Range2SizeY((r)) + +internal r32 Range3SizeZ(range3 Range) { return Range.Max.z - Range.Min.z; } +internal r32 Range4SizeZ(range4 Range) { return Range.Max.z - Range.Min.z; } + +internal r32 Range4SizeW(range4 Range) { return Range.Max.w - Range.Min.w; } + +internal r32 Range1Center(range1 Range) { return (Range.Max + Range.Min) / 2.0f; } +internal v2 Range2Center(range2 Range) { return (Range.Max + Range.Min) / 2.0f; } +internal v3 Range3Center(range3 Range) { return (Range.Max + Range.Min) / 2.0f; } +internal v4 Range4Center(range4 Range) { return (Range.Max + Range.Min) / 2.0f; } + +#define Rect2Center(r) Range2Center((r)) + +internal range1 Range1Offset(range1 Range, r32 Delta) { return range1{ Range.Min + Delta, Range.Max + Delta }; } +internal range2 Range2Offset(range2 Range, v2 Delta) { return range2{ Range.Min + Delta, Range.Max + Delta }; } +internal range3 Range3Offset(range3 Range, v3 Delta) { return range3{ Range.Min + Delta, Range.Max + Delta }; } +internal range4 Range4Offset(range4 Range, v4 Delta) { return range4{ Range.Min + Delta, Range.Max + Delta }; } + +#define Rect2Translate(r, d) Range2Offset((r), (d)) +#define Rect2TranslateX(r, dx) Range2Offset((r), v2{(dx), 0}) +#define Rect2TranslateY(r, dy) Range2Offset((r), v2{0, (dy)}) + +internal v2 RectTopLeft(rect2 Rect) +{ + return v2{ Rect.Min.x, Rect.Max.y }; +} +internal v2 RectTopRight(rect2 Rect) +{ + return Rect.Max; +} +internal v2 RectBottomLeft(rect2 Rect) +{ + return Rect.Min; +} +internal v2 RectBottomRight(rect2 Rect) +{ + return v2{ Rect.Max.x, Rect.Min.y }; +} + +internal r32 AspectRatio(r32 Width, r32 Height) { return Width / Height; } +internal r32 RectAspectRatio(rect2 Rect) { return Range2SizeX(Rect) / Range2SizeY(Rect); } + +internal void +RectHSplit(rect2 Rect, r32 YValue, rect2* Top, rect2* Bottom) +{ + r32 ClampedYValue = Clamp(Rect.Min.y, YValue, Rect.Max.y); + Top->Max = Rect.Max; + Top->Min = { Rect.Min.x, ClampedYValue }; + Bottom->Max = { Rect.Max.x, ClampedYValue }; + Bottom->Min = Rect.Min; +} +internal void +RectVSplit(rect2 Rect, r32 XValue, rect2* Left, rect2* Right) +{ + r32 ClampedXValue = Clamp(Rect.Min.x, XValue, Rect.Max.x); + Left->Max = { ClampedXValue, Rect.Max.y}; + Left->Min = Rect.Min; + Right->Max = Rect.Max; + Right->Min = { ClampedXValue, Rect.Min.y }; +} + +internal void +RectHSplitAtDistanceFromTop(rect2 Rect, r32 YDist, rect2* Top, rect2* Bottom) +{ + RectHSplit(Rect, Rect.Max.y - YDist, Top, Bottom); +} +internal void +RectHSplitAtDistanceFromBottom(rect2 Rect, r32 YDist, rect2* Top, rect2* Bottom) +{ + RectHSplit(Rect, Rect.Min.y + YDist, Top, Bottom); +} +internal void +RectVSplitAtDistanceFromRight(rect2 Rect, r32 XDist, rect2* Left, rect2* Right) +{ + RectVSplit(Rect, Rect.Max.x - XDist, Left, Right); +} +internal void +RectVSplitAtDistanceFromLeft(rect2 Rect, r32 XDist, rect2* Left, rect2* Right) +{ + RectVSplit(Rect, Rect.Min.x + XDist, Left, Right); +} +internal void +RectHSplitAtPercent(rect2 Rect, r32 YPercent, rect2* Top, rect2* Bottom) +{ + RectHSplit(Rect, LerpR32(YPercent, Rect.Min.y, Rect.Max.y), Top, Bottom); +} +internal void +RectVSplitAtPercent(rect2 Rect, r32 XPercent, rect2* Left, rect2* Right) +{ + RectVSplit(Rect, LerpR32(XPercent, Rect.Min.x, Rect.Max.x), Left, Right); +} + +internal rect2 +RectInset(rect2 Outer, v2 Amount) +{ + rect2 Result = { Outer.Min + Amount, Outer.Max - Amount }; + return Result; +} +internal rect2 +RectInset(rect2 Outer, r32 UniformAmount) +{ + return RectInset(Outer, v2{UniformAmount, UniformAmount}); +} + + +internal range1 +Range1Union(range1 A, range1 B) +{ + range1 Result = {}; + Result.Min = Max(A.Min, B.Min); + Result.Max = Min(A.Max, B.Max); + return Result; +} +#define Rect2Union(a,b) Range2Union((a), (b)) +internal range2 +Range2Union(range2 A, range2 B) +{ + range2 Result = {}; + Result.Min.x = Max(A.Min.x, B.Min.x); + Result.Min.y = Max(A.Min.y, B.Min.y); + Result.Max.x = Min(A.Max.x, B.Max.x); + Result.Max.y = Min(A.Max.y, B.Max.y); + return Result; +} +internal range3 +Range3Union(range3 A, range3 B) +{ + range3 Result = {}; + Result.Min.x = Max(A.Min.x, B.Min.x); + Result.Min.y = Max(A.Min.y, B.Min.y); + Result.Min.z = Max(A.Min.z, B.Min.z); + Result.Max.x = Min(A.Max.x, B.Max.x); + Result.Max.y = Min(A.Max.y, B.Max.y); + Result.Max.z = Min(A.Max.z, B.Max.z); + return Result; +} + +internal v2 +Rect2GetRectLocalPoint(rect2 Rect, v2 Point) +{ + v2 Result = Point - Rect.Min; + return Result; +} + +/////////////////////////// +// +// Ray + +internal v4 +RayGetPointAlong(v4 RayOrigin, v4 RayDirection, r32 T) +{ + v4 Result = RayOrigin + (RayDirection * T); + return Result; +} + +internal r32 +RayPlaneIntersectionDistance(v4 RayOrigin, v4 RayDirection, v4 PlanePoint, v4 PlaneNormal) +{ + r32 T = 0.0f; + float Denominator = V4Dot(PlaneNormal, RayDirection); + if (Abs(Denominator) > 0.00001f) + { + T = V4Dot(PlanePoint - RayDirection, PlaneNormal) / Denominator; + } + return T; +} + +internal v4 +GetRayPlaneIntersectionPoint(v4 RayOrigin, v4 RayDirection, v4 PlanePoint, v4 PlaneNormal) +{ + v4 Result = {0}; + r32 T = RayPlaneIntersectionDistance(RayOrigin, RayDirection, PlanePoint, PlaneNormal); + if (T >= 0) + { + Result = RayGetPointAlong(RayOrigin, RayDirection, T); + } + return Result; +} +internal v4 +GetRayPlaneIntersectionPoint(v4_ray Ray, v4 PlanePoint, v4 PlaneNormal) +{ + return GetRayPlaneIntersectionPoint(Ray.Origin, Ray.Direction, PlanePoint, PlaneNormal); +} + +internal bool +RayIntersectsPlane(v4 RayOrigin, v4 RayDirection, v4 PlanePoint, v4 PlaneNormal, v4* OutPoint) +{ + bool Result = false; + r32 T = RayPlaneIntersectionDistance(RayOrigin, RayDirection, PlanePoint, PlaneNormal); + if (T >= 0) + { + Result = true; + *OutPoint = RayGetPointAlong(RayOrigin, RayDirection, T); + } + return Result; +} +internal bool +RayIntersectsPlane(v4_ray Ray, v4 PlanePoint, v4 PlaneNormal, v4* OutPoint) +{ + return RayIntersectsPlane(Ray.Origin, Ray.Direction, PlanePoint, PlaneNormal, OutPoint); +} + +/////////////////////////// +// +// Matrices + +internal m44 +M44Identity() +{ + m44 M = {0}; + M.AXx = 1.0f; + M.AYy = 1.0f; + M.AZz = 1.0f; + M.Tw = 1.0f; + return M; +} + +internal m44 +M44Transpose(m44 M) +{ + m44 Result = {0}; + for (u32 Y = 0; Y < 4; Y++) + { + for (u32 X = 0; X < 4; X++) + { + Result.Array[(X * 4) + Y] = M.Array[(Y * 4) + X]; + } + } + return Result; +} + +// Matrix * Matrix + +m44 operator* (m44 L, m44 R) +{ + m44 M = {0}; + + // ci ic ci ic ci ic i ic + M.AXx = (L.AXx * R.AXx) + (L.AYx * R.AXy) + (L.AZx * R.AXz) + (L.Tx * R.AXw); + M.AXy = (L.AXy * R.AXx) + (L.AYy * R.AXy) + (L.AZy * R.AXz) + (L.Ty * R.AXw); + M.AXz = (L.AXz * R.AXx) + (L.AYz * R.AXy) + (L.AZz * R.AXz) + (L.Tz * R.AXw); + M.AXw = (L.AXw * R.AXx) + (L.AYw * R.AXy) + (L.AZw * R.AXz) + (L.Tw * R.AXw); + + M.AYx = (L.AXx * R.AYx) + (L.AYx * R.AYy) + (L.AZx * R.AYz) + (L.Tx * R.AYw); + M.AYy = (L.AXy * R.AYx) + (L.AYy * R.AYy) + (L.AZy * R.AYz) + (L.Ty * R.AYw); + M.AYz = (L.AXz * R.AYx) + (L.AYz * R.AYy) + (L.AZz * R.AYz) + (L.Tz * R.AYw); + M.AYz = (L.AXw * R.AYx) + (L.AYw * R.AYy) + (L.AZw * R.AYz) + (L.Tw * R.AYw); + + M.AZx = (L.AXx * R.AZx) + (L.AYx * R.AZy) + (L.AZx * R.AZz) + (L.Tx * R.AZw); + M.AZy = (L.AXy * R.AZx) + (L.AYy * R.AZy) + (L.AZy * R.AZz) + (L.Ty * R.AZw); + M.AZz = (L.AXz * R.AZx) + (L.AYz * R.AZy) + (L.AZz * R.AZz) + (L.Tz * R.AZw); + M.AZw = (L.AXw * R.AZx) + (L.AYw * R.AZy) + (L.AZw * R.AZz) + (L.Tw * R.AZw); + + M.Tx = (L.AXx * R.Tx) + (L.AYx * R.Ty) + (L.AZx * R.Tz) + (L.Tx * R.Tw); + M.Ty = (L.AXy * R.Tx) + (L.AYy * R.Ty) + (L.AZy * R.Tz) + (L.Ty * R.Tw); + M.Tz = (L.AXz * R.Tx) + (L.AYz * R.Ty) + (L.AZz * R.Tz) + (L.Tz * R.Tw); + M.Tw = (L.AXw * R.Tx) + (L.AYw * R.Ty) + (L.AZw * R.Tz) + (L.Tw * R.Tw); + + return M; +} + +// Matrix * Vector + +v4 operator* (m44 M, v4 V) +{ + v4 Result = {0}; + Result.x = (V.x * M.AXx) + (V.y * M.AYx) + (V.z * M.AZx) + (V.w * M.Tx); + Result.y = (V.x * M.AXy) + (V.y * M.AYy) + (V.z * M.AZy) + (V.w * M.Ty); + Result.z = (V.x * M.AXz) + (V.y * M.AYz) + (V.z * M.AZz) + (V.w * M.Tz); + Result.w = (V.x * M.AXw) + (V.y * M.AYw) + (V.z * M.AZw) + (V.w * M.Tw); + return Result; +} + +internal m44 +M44Translation(v4 Offset) +{ + m44 Result = M44Identity(); + Result.Tx = Offset.x; + Result.Ty = Offset.y; + Result.Tz = Offset.z; + return Result; +} + +internal m44 +M44RotationX(r32 Radians) +{ + r32 CosRad = CosR32(Radians); + r32 SinRad = SinR32(Radians); + m44 Result = M44Identity(); + Result.AYy = CosRad; + Result.AZy = SinRad; + Result.AYz = -SinRad; + Result.AZz = CosRad; + return Result; +} + +internal m44 +M44RotationY(r32 Radians) +{ + r32 CosRad = CosR32(Radians); + r32 SinRad = SinR32(Radians); + m44 Result = M44Identity(); + Result.AXx = CosRad; + Result.AZx = SinRad; + Result.AXz = -SinRad; + Result.AZz = CosRad; + return Result; +} + +internal m44 +M44RotationZ(r32 Radians) +{ + r32 CosRad = CosR32(Radians); + r32 SinRad = SinR32(Radians); + m44 Result = M44Identity(); + Result.AXx = CosRad; + Result.AYx = -SinRad; + Result.AXy = SinRad; + Result.AYy = CosRad; + return Result; +} + +internal m44 +M44Rotation(v3 Radians) +{ + r32 CosX = CosR32(Radians.x); + r32 SinX = SinR32(Radians.x); + r32 CosY = CosR32(Radians.y); + r32 SinY = SinR32(Radians.y); + r32 CosZ = CosR32(Radians.z); + r32 SinZ = SinR32(Radians.z); + + m44 Result = {0}; + Result.AXx = CosY * CosZ; + Result.AXy = -(SinX * SinY * CosZ) + (CosX * SinZ); + Result.AXz = -(CosX * SinY * CosZ) - (SinX * SinZ); + Result.AXw = 0; + + Result.AYx = -(SinZ * CosY); + Result.AYy = (SinX * SinY * SinZ) + (CosX * CosZ); + Result.AYz = (CosX * SinY * SinZ) - (SinX * CosZ); + Result.AYw = 0; + + Result.AZx = SinY; + Result.AZy = SinX * CosY; + Result.AZz = CosX * CosY; + Result.AZw = 0; + + Result.Tx = 0; + Result.Ty = 0; + Result.Tz = 0; + Result.Tw = 1; + + return Result; +} + +internal m44 +M44Scale(v3 Scale) +{ + m44 Result = M44Identity(); + Result.AXx = Scale.x; + Result.AYy = Scale.y; + Result.AZz = Scale.z; + return Result; +} + +internal m44 +M44ScaleUniform(r32 Scale) +{ + m44 Result = M44Identity(); + Result.AXx = Scale; + Result.AYy = Scale; + Result.AZz = Scale; + return Result; +} + +internal m44 +M44CoordinateFrame(v4 Forward, v4 Right, v4 Up) +{ + m44 Result = {0}; + Result.AXx = Right.x; + Result.AYx = Right.y; + Result.AZx = Right.z; + Result.Tx = Right.w; + + Result.AXy = Up.x; + Result.AYy = Up.y; + Result.AZy = Up.z; + Result.Ty = Up.w; + + Result.AXz = Forward.x; + Result.AYz = Forward.y; + Result.AZz = Forward.z; + Result.Tz = Forward.w; + + Result.Tw = 1.0f; + return Result; +} + +internal m44 +M44ModelMatrix(v4 Forward, v4 Right, v4 Up, v4 Position) +{ + m44 RotationMatrix = M44CoordinateFrame(Forward, Right, Up); + m44 PositionMatrix = M44Translation(-Position); + m44 ModelViewMatrix = PositionMatrix * RotationMatrix; + return ModelViewMatrix; +} + +internal m44 +M44ProjectionOrtho(r32 Width, r32 Height, r32 Near, r32 Far, r32 Right, r32 Left, r32 Top, r32 Bottom) +{ + m44 Result = {0}; + Result.AXx = 2.0f / Width; + Result.AYy = 2.0f / Height; + Result.AZz = 2.0f / (Near - Far); + Result.AXw = -(Right + Left) / (Right - Left); + Result.AYw = -(Top + Bottom) / (Top - Bottom); + Result.AZw = -(Far + Near) / (Far - Near); + Result.Tw = 1; + return Result; +} + +internal m44 +M44ProjectionOrtho(r32 Aspect, r32 Scale, r32 Near, r32 Far) +{ + m44 Result = {0}; + r32 Width = Scale * Aspect; + r32 Height = Scale; + r32 Right = Width / 2.0f; + r32 Left = -Right; + r32 Top = Height / 2.0f; + r32 Bottom = -Top; + Result = M44ProjectionOrtho(Width, Height, Near, Far, Right, Left, Top, Bottom); + return Result; +} + +internal m44 +M44ProjectionInterfaceOrtho(r32 Width, r32 Height, r32 Near, r32 Far) +{ + m44 Result = {0}; + r32 Aspect = Width / Height; + r32 Right = Width; + r32 Left = 0; + r32 Top = Height; + r32 Bottom = 0; + Result = M44ProjectionOrtho(Width, Height, Near, Far, Right, Left, Top, Bottom); + return Result; +} + +internal m44 +M44ProjectionPerspective(r32 FieldOfViewDegrees, r32 AspectRatio, r32 Near, r32 Far) +{ + m44 Result = M44Identity(); + + // The perspective divide step involves dividing x and y by -z + // Making Tz = -1 will make Tw of the result = -z + Result.Tw = 0; + Result.AZw = -1; + + // Remap z' from the range [near clip : far clip] to [0 : 1] + r32 ViewRange = Far - Near; + Result.AZz = -((Far + Near) / ViewRange); + Result.Tz = -(2 * Near * Far) / ViewRange; + + // Adjust for field of view - adjust the x' and y coordinates based + // on how + r32 FovBasedScale = TanR32(DegToRadR32(FieldOfViewDegrees / 2)); + r32 Top = Near * FovBasedScale; + r32 Bottom = -Top; + r32 Right = Top * AspectRatio; + r32 Left = -Right; + Result.AXx = (2 * Near) / (Right - Left); + Result.AZx = (Right + Left) / (Right - Left); + Result.AYy = (2 * Near) / (Top - Bottom); + Result.AZy = (Top + Bottom) / (Top - Bottom); + + return Result; +} + +internal m44 +M44LookAt(v4 Position, v4 Target) +{ + // NOTE(Peter): the camera usually points along the -z axis, hence + // Forward = a ray that points from the target back towards your position + v4 Forward = V4Normalize(Position - Target); + v4 Right = V4Normalize(V4Cross(v4{0, 1, 0, 0}, Forward)); + v4 Up = V4Normalize(V4Cross(Forward, Right)); + m44 Result = M44CoordinateFrame(Forward, Right, Up); + return Result; +} + +/////////////////////////// +// +// Strings + +internal gs_const_string ConstString(char* Data, u64 Length) { return gs_const_string{Data, Length}; } +internal gs_const_string ConstString(char* Data) { return gs_const_string{Data, CStringLength(Data)}; } +internal gs_string MakeString(char* Data, u64 Length, u64 Size) +{ + Assert(Length <= Size); + gs_string Result = {0}; + Result.Str = Data; + Result.Length = Length; + Result.Size = Size; + return Result; +} +internal gs_string MakeString(char* Data, u64 Length) +{ + return MakeString(Data, Length, Length); +} +internal gs_string MakeString(char* Data) +{ + u64 StringLength = CStringLength(Data); + return MakeString(Data, StringLength, StringLength); +} +internal gs_string MakeString(gs_const_string ConstString) +{ + return MakeString(ConstString.Str, ConstString.Length); +} + +internal gs_data StringToData(gs_const_string String) +{ + gs_data Result = gs_data{0}; + Result.Memory = (u8*)String.Str; + Result.Size = String.Length * sizeof(char); + return Result; +} +internal gs_data StringToData(gs_string String) +{ + return StringToData(String.ConstString); +} + +internal bool IsSlash(char C) { return ((C == '/') || (C == '\\')); } +internal bool IsUpper(char C) { return(('A' <= C) && (C <= 'Z')); } +internal bool IsLower(char C) { return(('a' <= C) && (C <= 'z')); } +internal bool IsWhitespace(char C) { return (C == ' ' || C == '\n' || C == '\r' || C == '\t' || C == '\f' || C == '\v'); } +internal bool IsNewline(char C) { return (C == '\n') || (C == '\r'); } +internal bool IsNewlineOrWhitespace (char C) { return IsNewline(C) || IsWhitespace(C); } +internal bool IsBase8(char C) { return (C >= '0' && C <= '7'); } +internal bool IsBase10(char C) { return (C >= '0' && C <= '9'); } +internal bool IsBase16(char C) { return (C >= '0' && C <= '9') || (C >= 'A' && C <= 'F'); } +internal bool IsNumericDecimal(char C) { return IsBase10(C) || (C == '.'); } +internal bool IsNumericExtended(char C) { return IsNumericDecimal(C) || (C == 'x') || (C == 'f') || (C == '-'); } +internal bool IsAlpha(char C) { return( (('a' <= C) && (C <= 'z')) || (('A' <= C) && (C <= 'Z')) || C == '_'); } +internal bool IsAlphaNumeric(char C) { return((('a' <= C) && (C <= 'z')) || (('A' <= C) && (C <= 'Z')) || (('0' <= C) && (C <= '9')) || C == '_'); } +internal bool IsOperator(char C) { + return ((C == '+') || (C == '-') || (C == '*') || (C == '/') || + (C == '=') || (C == '%') || (C == '<') || (C == '>')); +} + +internal char +ToUpper(char C) +{ + if ((C >= 'a') && (C <= 'z')) + { + C -= 'a' - 'A'; + } + return C; +} +internal char +ToLower(char C) +{ + if ((C >= 'A') && (C <= 'Z')) + { + C += 'a' - 'A'; + } + return C; +} +internal bool CharsEqualCaseInsensitive(char A, char B) { return ToLower(A) == ToLower(B); } + +internal u64 +CharArrayLength (char* CS) +{ + char* At = CS; + while (*At) { At++; } + return (u64)(At - CS); +} + +internal bool +IsNullTerminated(gs_const_string String) +{ + return (String.Str[String.Length] == 0); +} +internal bool +IsNullTerminated(gs_string String) +{ + return IsNullTerminated(String.ConstString); +} + +internal char +GetChar(gs_const_string String, u64 I) +{ + char Result = 0; + if (I < String.Length) + { + Result = String.Str[I]; + } + return Result; +} +internal char +GetChar(gs_string String, u64 I) +{ + char Result = 0; + if (I < String.Length) + { + Result = String.Str[I]; + } + return Result; +} + +internal gs_const_string +GetStringPrefix(gs_const_string String, u64 Size) +{ + gs_const_string Result = String; + Result.Length = Min(Size, String.Length); + return Result; +} +internal gs_const_string +GetStringPostfix(gs_const_string String, u64 Size) +{ + gs_const_string Result = String; + u64 PostfixSize = Min(Size, String.Length); + Result.Str += (Result.Length - PostfixSize); + Result.Length = PostfixSize; + return Result; +} +internal gs_const_string +GetStringAfter(gs_const_string String, u64 Cut) +{ + gs_const_string Result = String; + u64 CutSize = Min(Cut, String.Length); + Result.Str += CutSize; + Result.Length -= CutSize; + return Result; +} +internal gs_string +GetStringAfter(gs_string String, u64 Cut) +{ + gs_string Result = {0}; + Result.ConstString = GetStringAfter(String.ConstString, Cut); + Result.Size = String.Size - Cut; + return Result; +} +internal gs_const_string +GetStringBefore(gs_const_string String, u64 Cut) +{ + gs_const_string Result = String; + Result.Length = Min(Cut, String.Length); + return Result; +} +internal gs_const_string +Substring(gs_const_string String, u64 First, u64 Last) +{ + gs_const_string Result = {0}; + Result.Str = String.Str + Min(First, String.Length); + Result.Length = Min(Last - First, String.Length); + return Result; +} +internal u64 +FindFirst(gs_const_string String, u64 StartIndex, char C) +{ + u64 Result = StartIndex; + for(; Result < String.Length && C != String.Str[Result]; Result++); + return Result; +} +internal u64 +FindFirst(gs_const_string String, char C) +{ + return FindFirst(String, 0, C); +} + +internal u64 +FindLast(gs_const_string String, u64 StartIndex, char C) +{ + s64 Result = StartIndex; + for(; Result >= 0 && C != String.Str[Result]; Result--); + return (u64)Result; +} + +internal u64 +FindLast(gs_const_string String, char C) +{ + return FindLast(String, String.Length - 1, C); +} + +internal u64 +FindFirstFromSet(gs_const_string String, char* SetArray) +{ + gs_const_string Set = ConstString(SetArray); + u64 Result = String.Length - 1; + for(u64 At = 0; At < String.Length; At++) + { + char CharAt = String.Str[At]; + for (u64 SetAt = 0; SetAt < Set.Length; SetAt++) + { + if (CharAt == Set.Str[SetAt]) + { + Result = At; + // NOTE(Peter): The alternative to this goto is a break in the inner loop + // followed by an if check in the outer loop, that must be evaluated + // every character you check. This is more efficient + goto find_last_from_set_complete; + } + } + } + find_last_from_set_complete: + return Result; +} + +internal u64 +FindLastFromSet(gs_const_string String, char* SetArray) +{ + gs_const_string Set = ConstString(SetArray); + u64 Result = String.Length - 1; + for(s64 At = Result; At >= 0; At--) + { + char CharAt = String.Str[At]; + for (u64 SetAt = 0; SetAt < Set.Length; SetAt++) + { + if (CharAt == Set.Str[SetAt]) + { + Result = (u64)At; + // NOTE(Peter): The alternative to this goto is a break in the inner loop + // followed by an if check in the outer loop, that must be evaluated + // every character you check. This is more efficient + goto find_first_from_set_complete; + } + } + } + find_first_from_set_complete: + return Result; +} + +internal bool +StringsEqualUpToLength(gs_const_string A, gs_const_string B, u64 Length) +{ + bool Result = false; + if (A.Length >= Length && B.Length >= Length) + { + Result = true; + Length = Min(Length, A.Length); + for (u64 i = 0; i < Length; i++) + { + if (A.Str[i] != B.Str[i]) + { + Result = false; + break; + } + } + } + return Result; +} +internal bool +StringsEqual(gs_const_string A, gs_const_string B) +{ + bool Result = false; + if (A.Length == B.Length) + { + Result = StringsEqualUpToLength(A, B, A.Length); + } + return Result; +} +internal bool +StringEqualsCharArray(gs_const_string A, char* B, u64 Length) +{ + gs_const_string BStr = ConstString(B, Length); + return StringsEqual(A, BStr); +} +internal bool +StringsEqualUpToLength(gs_string A, gs_string B, u64 Length) +{ + return StringsEqualUpToLength(A.ConstString, B.ConstString, Length); +} +internal bool +StringsEqual(gs_string A, gs_string B) +{ + return StringsEqual(A.ConstString, B.ConstString); +} +internal bool +StringEqualsCharArray(gs_string A, char* B, u64 Length) +{ + gs_string BStr = MakeString(B, Length); + return StringsEqual(A, BStr); +} + +internal u64 +StringSizeLeft(gs_string String) +{ + u64 Result = String.Size - String.Length; + return Result; +} + +internal void +ReverseStringInPlace(gs_string* String) +{ + char* Start = String->Str; + char* End = String->Str + String->Length; + while (Start < End) + { + End--; + char Temp = End[0]; + End[0] = Start[0]; + Start[0] = Temp; + Start++; + } +} + +internal gs_const_string +GetCharSetForBase(u64 Base) +{ + gs_const_string Result = {0}; + switch(Base) + { + case 8: { Result = Base8Chars; }break; + case 10: { Result = Base10Chars; }break; + case 16: { Result = Base16Chars; }break; + InvalidDefaultCase; + } + return Result; +} +internal u64 +CharToUInt(char C, gs_const_string CharSet) +{ + return (u64)FindFirst(CharSet, C); +} +internal u64 +CharToUInt(char C) +{ + return (u64)CharToUInt(C, Base10Chars); +} +internal u64 +CharToUInt(char C, u64 Base) +{ + return CharToUInt(C, GetCharSetForBase(Base)); +} + +internal u64 +ParseUInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0) +{ + u64 Result = 0; + gs_const_string CharSet = GetCharSetForBase(Base); + u64 i = 0; + for (; i < String.Length; i++) + { + u64 CharIndex = FindFirst(CharSet, String.Str[i]); + if (CharIndex < CharSet.Length) + { + Result = CharToUInt(String.Str[i], CharSet) + (Result * Base); + } + else + { + break; + } + } + if (ParsedLength != 0) + { + *ParsedLength = i; + } + return Result; +} +internal u64 +ParseUInt(u64 Length, char* String, u64 Base = 10, u64* ParsedLength = 0) +{ + return ParseUInt(ConstString(String, Length), Base, ParsedLength); +} +internal u64 +ParseUInt(char* String, u64 Base = 10, u64* ParsedLength = 0) +{ + return ParseUInt(LitString(String), Base, ParsedLength); +} + +internal s64 +ParseInt(gs_const_string String, u64 Base = 10, u64* ParsedLength = 0) +{ + s64 Result = 0; + u64 TempParsedLength = 0; + if (String.Str[0] == '-') + { + Result = -1 * (s64)ParseUInt(GetStringAfter(String, 1), Base, &TempParsedLength); + TempParsedLength += 1; + } + else + { + Result = (s64)ParseUInt(String, Base, &TempParsedLength); + } + if (ParsedLength != 0) + { + *ParsedLength = TempParsedLength; + } + return Result; +} +internal s64 +ParseInt(char* String, u64 Base = 10, u64* ParsedLength = 0) +{ + return ParseInt(LitString(String), Base, ParsedLength); +} + +internal r64 +ParseFloat(gs_const_string String, u64* ParsedLength = 0) +{ + + u64 DecimalIndex = FindFirst(String, '.'); + u64 TempParsedLength = 0; + u64 PlacesAfterPoint = 0; + + gs_const_string IntegerString = GetStringBefore(String, DecimalIndex); + gs_const_string DecimalString = GetStringAfter(String, DecimalIndex + 1); + + r32 Polarity = 1; + if (IntegerString.Str[0] == '-') + { + IntegerString = GetStringAfter(IntegerString, 1); + Polarity = -1; + } + r64 Result = (r64)ParseInt(IntegerString, 10, &TempParsedLength); + + if (TempParsedLength == IntegerString.Length) + { + r64 AfterPoint = (r64)ParseUInt(DecimalString, 10, &PlacesAfterPoint); + r64 Decimal = (AfterPoint / PowR64(10, PlacesAfterPoint)); + Result = Result + Decimal; + Result *= Polarity; + } + + if (ParsedLength != 0) + { + *ParsedLength = TempParsedLength + PlacesAfterPoint; + if (DecimalIndex < String.Length) { *ParsedLength += 1; } + } + return Result; +} +internal r64 +ParseFloat(char* String, u64* ParsedLength = 0) +{ + return ParseFloat(LitString(String), ParsedLength); +} + +internal u64 +AppendString(gs_string* Base, gs_const_string Appendix) +{ + u64 StartIndex = Base->Length; + u64 LengthAvailable = Base->Size - Base->Length; + u64 Written = 0; + for (; Written < Min(LengthAvailable, Appendix.Length); Written++) + { + Base->Str[StartIndex + Written] = Appendix.Str[Written]; + } + Base->Length += Written; + Assert(Base->Length <= Base->Size); + return Written; +} +internal u64 +AppendString(gs_string* Base, gs_string Appendix) +{ + return AppendString(Base, Appendix.ConstString); +} +internal void +NullTerminate(gs_string* String) +{ + if (String->Length < String->Size) + { + String->Str[String->Length] = 0; + } + else + { + String->Str[String->Length - 1] = 0; + } +} + +internal void +OutChar(gs_string* String, char C) +{ + if (String->Length < String->Size) + { + String->Str[String->Length++] = C; + } +} + +internal void +U64ToASCII(gs_string* String, u64 Value, u64 Base, gs_const_string Digits) +{ + u64 ValueRemaining = Value; + u64 At = 0; + do { + u64 Index = ValueRemaining % Base; + char Digit = Digits.Str[Index]; + OutChar(String, Digit); + ValueRemaining /= Base; + }while(ValueRemaining); + char* End = String->Str + String->Length; + ReverseStringInPlace(String); +} + +internal void +U64ToASCII(gs_string* String, u64 Value, u64 Base) +{ + U64ToASCII(String, Value, Base, GetCharSetForBase(Base)); +} + +internal void +R64ToASCII(gs_string* String, r64 Value, u64 Precision) +{ + if (Value < 0) + { + OutChar(String, '-'); + Value = Abs(Value); + } + u64 IntegerPart = (u64)Value; + // NOTE(Peter): If we don't use the inner string, when U64ToASCII reverses the characters + // it'll put the negative sign at the end. + gs_string IntegerString = GetStringAfter(*String, String->Length); + U64ToASCII(&IntegerString, IntegerPart, 10); + String->Length += IntegerString.Length; + Value -= IntegerPart; + if (Value > 0) + { + OutChar(String, '.'); + for (u64 i = 0; i < Precision; i++) + { + Value *= 10.0f; + u64 DecimalPlace = (u64)Value; + Value -= DecimalPlace; + OutChar(String, Base10Chars.Str[DecimalPlace]); + } + } +} + +internal s64 +ReadVarArgsSignedInteger (s32 Width, va_list* Args) +{ + s64 Result = 0; + switch (Width) + { + // NOTE(Peter): For Width lower than 4 bytes, the C++ spec specifies + // that it will get promoted to an int anyways + case 1: { Result = (s64)va_arg(*Args, s32); } break; + case 2: { Result = (s64)va_arg(*Args, s32); } 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) + { + // NOTE(Peter): For Width lower than 4 bytes, the C++ spec specifies + // that it will get promoted to an int anyways + case 1: { Result = (u64)va_arg(*Args, u32); } break; + case 2: { Result = (u64)va_arg(*Args, u32); } 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 (gs_string* String, char* Format, va_list Args) +{ + char* FormatAt = Format; + while (*FormatAt) + { + if (FormatAt[0] != '%') + { + if (FormatAt[0] == '\\') + { + OutChar(String, *FormatAt++); + } + else + { + OutChar(String, *FormatAt++); + } + } + else if (FormatAt[0] == '%' && FormatAt[1] == '%') // Print the % symbol + { + OutChar(String, '%'); + FormatAt += 2; + } + 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 (IsBase10(FormatAt[0])) + { + WidthSpecified = true; + u64 Parsed = 0; + AssertMessage("ParseInt assumes whole string is an integer"); + Width = (s32)ParseInt(FormatAt, 10, &Parsed); + FormatAt += Parsed; + } + 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 (IsBase10(FormatAt[0])) + { + + PrecisionSpecified = true; + u64 Parsed = 0; + AssertMessage("ParseInt assumes whole string is an integer"); + Precision = (s32)ParseInt(FormatAt, 10, &Parsed); + FormatAt += Parsed; + } + 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 Specifiers + gs_string StringRemaining = GetStringAfter(*String, String->Length); + Assert(StringRemaining.Length == 0); + if (FormatAt[0] == 'd' || FormatAt[0] == 'i') + { + s64 SignedInt = ReadVarArgsSignedInteger(Length, &Args); + if (SignedInt < 0) + { + OutChar(&StringRemaining, '-'); + SignedInt *= -1; + } + U64ToASCII(&StringRemaining, (u64)SignedInt, 10, Base10Chars); + } + else if (FormatAt[0] == 'u') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 10, Base10Chars); + } + else if (FormatAt[0] == 'o') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 8, Base8Chars); + } + else if (FormatAt[0] == 'x' || FormatAt[0] == 'X') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 16, Base16Chars); + } + else if (FormatAt[0] == 'f' || FormatAt[0] == 'F') + { + r64 Float = ReadVarArgsFloat(Length, &Args); + s32 AfterPoint = 6; + if (PrecisionSpecified) + { + AfterPoint = Precision; + } + R64ToASCII(&StringRemaining, Float, AfterPoint); + } + else if (FormatAt[0] == 'c') + { + char InsertChar = va_arg(Args, s32); + OutChar(&StringRemaining, InsertChar); + } + else if (FormatAt[0] == 's') + { + char* InsertString = va_arg(Args, char*); + + s32 InsertStringLength = CStringLength(InsertString); + if (PrecisionSpecified) + { + InsertStringLength = Min(InsertStringLength, Precision); + } + InsertStringLength = Min(StringSizeLeft(StringRemaining), InsertStringLength); + + for (s32 c = 0; c < InsertStringLength; c++) + { + OutChar(&StringRemaining, InsertString[c]); + } + } + else if (FormatAt[0] == 'S') + { + gs_const_string InsertString = va_arg(Args, gs_const_string); + + for (s32 c = 0; c < InsertString.Length; c++) + { + OutChar(&StringRemaining, InsertString.Str[c]); + } + } + else if (FormatAt[0] == 'p') + { + // TODO(Peter): Pointer Address + } + else + { + // NOTE(Peter): Non-specifier character found + InvalidCodePath; + } + + String->Length += StringRemaining.Length; + FormatAt++; + } + } + + return String->Length; +} + +internal void +PrintF (gs_string* String, char* Format, ...) +{ + va_list Args; + va_start(Args, Format); + String->Length = 0; + PrintFArgsList(String, Format, Args); + va_end(Args); +} +internal void +PrintF (gs_string* String, const char* Format, ...) +{ + // NOTE(Peter): This variant is here for clang/gcc - C++ spec doesn't allow + // implicit conversion from a const char* (a static c string) to char*, so this + // version of the function just provides the conversion so the compiler will be quiet + // without removing the other implementation, which is more useful + va_list Args; + va_start(Args, Format); + String->Length = 0; + PrintFArgsList(String, (char*)Format, Args); + va_end(Args); +} + +internal void +AppendPrintF (gs_string* String, char* Format, ...) +{ + va_list Args; + va_start(Args, Format); + PrintFArgsList(String, Format, Args); + va_end(Args); +} +internal void +AppendPrintF (gs_string* String, const char* Format, ...) +{ + // NOTE(Peter): This variant is here for clang/gcc - C++ spec doesn't allow + // implicit conversion from a const char* (a static c string) to char*, so this + // version of the function just provides the conversion so the compiler will be quiet + // without removing the other implementation, which is more useful + va_list Args; + va_start(Args, Format); + PrintFArgsList(String, (char*)Format, Args); + va_end(Args); +} + +/////////////////////////// +// +// Memory + +internal gs_data +CreateData(u8* Memory, u64 Size) +{ + gs_data Result = {Memory, Size}; + return Result; +} +internal bool +DataIsNonEmpty(gs_data Data) +{ + return ((Data.Size > 0) && (Data.Memory != 0)); +} + +internal void* AllocatorAlloc_NoOp(u64 Size, u64* SizeResult) { + *SizeResult = 0; + return 0; +} +internal void AllocatorFree_NoOp(void* Base, u64 Size) { return; } + +internal gs_allocator +CreateAllocator_(allocator_allocate* Alloc, allocator_free* Free) +{ + if (Alloc == 0) + { + Alloc = AllocatorAlloc_NoOp; + } + if (Free == 0) + { + Free = AllocatorFree_NoOp; + } + gs_allocator Result = {0}; + Result.Alloc = Alloc; + Result.Free = Free; + return Result; +} +#define CreateAllocator(a, f) CreateAllocator_((allocator_allocate*)(a), (allocator_free*)(f)) + +internal gs_data +AllocatorAlloc_(gs_allocator Allocator, u64 Size, char* Location) +{ + // TODO(Peter): Memory Profiling with Location + u64 SizeResult = 0; + void* Memory = Allocator.Alloc(Size, &SizeResult); + return CreateData((u8*)Memory, SizeResult); +} +internal void +AllocatorFree_(gs_allocator Allocator, void* Base, u64 Size, char* Location) +{ + // TODO(Peter): Memory Profiling with Location + if (Base != 0 && Size != 0) + { + Allocator.Free(Base, Size); + } +} + +#define AllocatorAlloc(alloc,size) AllocatorAlloc_((alloc), (size), FileNameAndLineNumberString) +#define AllocatorAllocStruct(alloc, type) (type*)(AllocatorAlloc((alloc), sizeof(type)).Memory) +#define AllocatorAllocArray(alloc, type, count) (type*)(AllocatorAlloc((alloc), sizeof(type) * (count)).Memory) +#define AllocatorAllocString(alloc, size) gs_string{ AllocatorAllocArray((alloc), char, (size)), 0, (size) } +#define AllocatorFree(alloc,base,size) AllocatorFree_((alloc), (base), (size), FileNameAndLineNumberString) +#define AllocatorFreeArray(alloc,base,type,count) AllocatorFree_((alloc), (base), sizeof(type) * count, FileNameAndLineNumberString) +internal gs_memory_cursor +CreateMemoryCursor(u8* Base, u64 Size) +{ + gs_memory_cursor Result = {0}; + Result.Data.Memory = Base; + Result.Data.Size = Size; + return Result; +}; +internal gs_memory_cursor +CreateMemoryCursor(gs_data Data) +{ + return CreateMemoryCursor(Data.Memory, Data.Size); +} +internal gs_memory_cursor +CreateMemoryCursor(gs_allocator Allocator, u64 Size) +{ + gs_data Data = AllocatorAlloc(Allocator, Size); + return CreateMemoryCursor(Data); +} +internal bool +CursorHasRoom(gs_memory_cursor Cursor, u64 Size) +{ + bool Result = ((Cursor.Position + Size) <= Cursor.Data.Size); + return Result; +} +internal gs_data +PushSizeOnCursor_(gs_memory_cursor* Cursor, u64 Size, char* Location) +{ + gs_data Result = {0}; + if (CursorHasRoom(*Cursor, Size)) + { + Result.Memory = Cursor->Data.Memory + Cursor->Position; + Result.Size = Size; + Cursor->Position += Size; + } + return Result; +} + +#define PushSizeOnCursor(cursor,size) PushSizeOnCursor_((cursor), (size), FileNameAndLineNumberString) +#define PushStructOnCursor(cursor,type) (type*)PushSizeOnCursor_((cursor), sizeof(type), FileNameAndLineNumberString).Memory +#define PushArrayOnCursor(cursor,type,count) (type*)PushSizeOnCursor_((cursor), sizeof(type) * (count), FileNameAndLineNumberString).Memory + +#define MemoryCursor_WriteValue(cursor, type, value) *PushStructOnCursor(cursor, type) = value +#define MemoryCursor_WriteBuffer(cursor, buf, len) CopyMemoryTo((u8*)(buf), PushArrayOnCursor((cursor), u8, (len)), (len)) + +internal void +PopSizeOnCursor(gs_memory_cursor* Cursor, u64 Size) +{ + if (Cursor->Position > Size) + { + Cursor->Position -= Size; + } + else + { + Cursor->Position = 0; + } +} +internal gs_data +AlignCursor(gs_memory_cursor* Cursor, u64 Alignment) +{ + u64 Position = RoundUpTo64(Cursor->Position, Alignment); + Position = Min(Position, Cursor->Data.Size); + u64 NewSize = Position - Cursor->Position; + return PushSizeOnCursor(Cursor, NewSize); +} +internal void +ClearCursor(gs_memory_cursor* Cursor) +{ + Cursor->Position = 0; +} + +internal void +FreeCursorListEntry(gs_allocator Allocator, gs_memory_cursor_list* CursorEntry) +{ + AllocatorFree(Allocator, CursorEntry, CursorEntry->Cursor.Data.Size + sizeof(gs_memory_cursor)); +} + +internal gs_memory_arena +CreateMemoryArena_(arena_type ArenaType, gs_allocator Allocator, u64 ChunkSize, u64 Alignment, gs_memory_arena* ParentArena) +{ + // we only want a parent arena if the type is Arena_SubArena + Assert(((ArenaType == Arena_BaseArena) && (ParentArena == 0)) || + ((ArenaType == Arena_SubArena) && (ParentArena != 0))); + + gs_memory_arena Arena = {}; + Arena.Type = ArenaType; + Arena.Allocator = Allocator; + Arena.Parent = ParentArena; + Arena.MemoryChunkSize = ChunkSize; + Arena.MemoryAlignment = Alignment; + return Arena; +} + +internal gs_memory_arena +CreateMemoryArena(gs_allocator Allocator, u64 ChunkSize = KB(32), u64 Alignment = Bytes(8)) +{ + return CreateMemoryArena_(Arena_BaseArena, Allocator, ChunkSize, Alignment, 0); +} +internal gs_memory_arena +CreateMemorySubArena(gs_memory_arena* Parent, u64 ChunkSize = KB(32), u64 Alignment = Bytes(8)) +{ + return CreateMemoryArena_(Arena_SubArena, Parent->Allocator, ChunkSize, Alignment, Parent); +} + +internal gs_data PushSize_(gs_memory_arena* Arena, u64 Size, char* Location); + +internal void +FreeCursorList(gs_memory_cursor_list* List, gs_allocator Allocator) +{ + gs_memory_cursor_list* CursorAt = List; + while (CursorAt != 0) + { + gs_memory_cursor_list* Prev = CursorAt->Prev; + FreeCursorListEntry(Allocator, CursorAt); + CursorAt = Prev; + } +} + +internal gs_memory_cursor_list* +MemoryArenaNewCursor(gs_memory_arena* Arena, u64 MinSize, char* Location) +{ + // Allocate enough spcae for the minimum size needed + sizeo for the cursor list + u64 AllocSize = Max(MinSize, Arena->MemoryChunkSize) + sizeof(gs_memory_cursor_list); + + gs_data Data = {0}; + switch (Arena->Type) + { + case Arena_SubArena: + { + Data = PushSize_(Arena->Parent, AllocSize, Location); + }break; + + case Arena_BaseArena: + { + Data = AllocatorAlloc_(Arena->Allocator, AllocSize, Location); + }break; + + InvalidDefaultCase; + } + + // Fit the memory cursor into the region allocated + Assert(MinSize + sizeof(gs_memory_cursor_list) <= Data.Size); + gs_memory_cursor_list* Result = (gs_memory_cursor_list*)Data.Memory; + u8* CursorMemoryStart = (u8*)(Result + 1); + u64 CursorMemorySize = Data.Size - sizeof(gs_memory_cursor_list); + Result->Cursor = CreateMemoryCursor(CursorMemoryStart, CursorMemorySize); + + Result->Prev = Arena->CursorList; + Result->Next = 0; + if (Arena->CursorList != 0) + { + Arena->CursorList->Next = Result; + } + Arena->CursorList = Result; + return Result; +} + +internal gs_data +PushSize_(gs_memory_arena* Arena, u64 Size, char* Location) +{ + gs_data Result = {0}; + if (Size > 0) + { + gs_memory_cursor_list* CursorEntry = Arena->CursorList; + if (CursorEntry == 0) + { + CursorEntry = MemoryArenaNewCursor(Arena, Size, Location); + } + if (!CursorHasRoom(CursorEntry->Cursor, Size)) + { + while ((CursorEntry != 0) && !CursorHasRoom(CursorEntry->Cursor, Size)) + { + CursorEntry = CursorEntry->Next; + } + if (CursorEntry == 0) + { + CursorEntry = MemoryArenaNewCursor(Arena, Size, Location); + } + } + Assert(CursorEntry != 0); + Result = PushSizeOnCursor_(&CursorEntry->Cursor, Size, Location); + Assert(Result.Memory != 0); + + gs_data Alignment = AlignCursor(&CursorEntry->Cursor, Arena->MemoryAlignment); + Result.Size += Alignment.Size; + } + + // TODO(Peter): @Cleanup @Efficiency + // There is a case I want to handle at some point: + // You have a Cursor that is empty, but the size you want to allocate is bigger + // than the cursor. So you create a new cursor, of the exact size you need, + // immediately fill it up, and push it onto the head of the cursor list. Now, + // the list looks like this: + // [root] [cursor] ... [empty cursor] [full cursor] [new, empty cursor] + // and you'll never use the memory in 'empty cursor' + // What I'd like to do is, when you fill up a cursor, it gets pushed back until + // the next cursor is more full + // NOTE: Thought on this tho - you don't want this behavior in a scratch arena + // where usage across frames could change drastically. This matters way more in + // a permanent storage (i think) + return Result; +} + +internal void +PopSize(gs_memory_arena* Arena, u64 Size) +{ + gs_allocator Allocator = Arena->Allocator; + gs_memory_cursor_list* CursorEntry = Arena->CursorList; + for (gs_memory_cursor_list* Prev = 0; + CursorEntry != 0 && Size != 0; + CursorEntry = Prev) + { + Prev = CursorEntry->Prev; + if (Size >= CursorEntry->Cursor.Position) + { + Size -= CursorEntry->Cursor.Position; + FreeCursorListEntry(Allocator, CursorEntry); + } + else + { + PopSizeOnCursor(&CursorEntry->Cursor, Size); + break; + } + } + Arena->CursorList = CursorEntry; +} +internal void +FreeMemoryArena(gs_memory_arena* Arena) +{ + gs_allocator Allocator = Arena->Allocator; + gs_memory_cursor_list* CursorEntry = Arena->CursorList; + for (gs_memory_cursor_list* Prev = 0; + CursorEntry != 0; + CursorEntry = Prev) + { + Prev = CursorEntry->Prev; + if (CursorEntry != 0) + { + FreeCursorListEntry(Allocator, CursorEntry); + } + } +} + +#define PushSizeToData(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString) +#define PushSize(arena, size) PushSize_((arena), (size), FileNameAndLineNumberString).Memory +#define PushStruct(arena, type) (type*)(PushSize_((arena), sizeof(type), FileNameAndLineNumberString).Memory) +#define PushArray(arena, type, count) (type*)(PushSize_((arena), sizeof(type) * (count), FileNameAndLineNumberString).Memory) +#define PushString(arena, length) MakeString(PushArray((arena), char, (length)), 0, (length)); + +internal gs_string +PushStringF(gs_memory_arena* Arena, u32 MaxLength, char* Format, ...) +{ + gs_string Result = PushString(Arena, MaxLength); + + va_list Args; + va_start(Args, Format); + PrintFArgsList(&Result, Format, Args); + va_end(Args); + + return Result; +} + +internal void +ClearArena(gs_memory_arena* Arena) +{ + gs_memory_cursor_list* First = 0; + for (gs_memory_cursor_list* CursorEntry = Arena->CursorList; + CursorEntry != 0; + CursorEntry = CursorEntry->Prev) + { + First = CursorEntry; + CursorEntry->Cursor.Position = 0; + } + Arena->CursorList = First; +} + +internal void +FreeArena(gs_memory_arena* Arena) +{ + FreeCursorList(Arena->CursorList, Arena->Allocator); +} + +/////////////////////////// +// +// Debug Print + +inline void +DebugPrint(debug_output Output, gs_const_string Message) +{ + Output.Print(Output, Message); +} + +inline void +DebugPrint(debug_output Output, char* Message) +{ + gs_const_string String = ConstString(Message); + Output.Print(Output, String); +} + +internal void +DebugPrintF(debug_output Output, char* Format, ...) +{ + gs_string Message = PushString(Output.Storage, 1024); + va_list Args; + va_start(Args, Format); + PrintFArgsList(&Message, Format, Args); + NullTerminate(&Message); + Output.Print(Output, Message.ConstString); +} + +/////////////////////////// +// +// Dynamic Array + +internal gs_dynarray +CreateDynarrayWithStorage(gs_memory_arena Storage, u32 ElementSize, u32 ElementsPerBuffer) +{ + gs_dynarray Result = {}; + Result.Arena = Storage; + Result.ElementSize = ElementSize; + Result.ElementsPerBuffer = ElementsPerBuffer; + Result.ElementCount = 0; + return Result; +} + +internal gs_dynarray +CreateDynarray_(gs_allocator Allocator, u32 ElementSize, u32 ElementsPerBuffer) +{ + gs_memory_arena Storage = CreateMemoryArena(Allocator, ElementSize * ElementsPerBuffer); + return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer); +}; + +internal gs_dynarray +CreateDynarray_(gs_memory_arena* Arena, u32 ElementSize, u32 ElementsPerBuffer) +{ + gs_memory_arena Storage = CreateMemorySubArena(Arena, ElementSize * ElementsPerBuffer); + return CreateDynarrayWithStorage(Storage, ElementSize, ElementsPerBuffer); +}; + +internal u64 +CalculateBufferSize(gs_dynarray Array) +{ + u64 Result = Array.ElementsPerBuffer * Array.ElementSize; + return Result; +} + +internal void +GrowDynarray(gs_dynarray* Array) +{ + gs_dynarray_buffer* OldBufferList = Array->Buffers; + u64 NewBuffersCount = Array->BuffersCount + 1; + gs_dynarray_buffer* NewBufferList = AllocatorAllocArray(Array->Arena.Allocator, gs_dynarray_buffer, NewBuffersCount); + if (OldBufferList) + { + CopyArray(OldBufferList, NewBufferList, gs_dynarray_buffer, Array->BuffersCount); + AllocatorFree(Array->Arena.Allocator, OldBufferList, sizeof(gs_dynarray_buffer) * Array->BuffersCount); + } + u64 BufferSize = CalculateBufferSize(*Array); + NewBufferList[Array->BuffersCount].Memory = PushSize(&Array->Arena, BufferSize); + Array->Buffers = NewBufferList; + Array->BuffersCount = NewBuffersCount; +} +internal u64 +DynarraySize(gs_dynarray Array) +{ + u64 Result = Array.BuffersCount * Array.ElementsPerBuffer; + return Result; +} +internal gs_dynarray_handle +IndexToHandle(gs_dynarray* Array, u64 Index) +{ + gs_dynarray_handle Result = {0}; + Result.BufferIndex = Index / Array->ElementsPerBuffer; + Result.IndexInBuffer = Index % Array->ElementsPerBuffer; + return Result; +} +internal u64 +HandleToIndex(gs_dynarray Array, gs_dynarray_handle Handle) +{ + u64 Result = Handle.IndexInBuffer + (Handle.BufferIndex * Array.ElementsPerBuffer); + return Result; +} +internal gs_dynarray_handle +TakeFreeElement(gs_dynarray* Array) +{ + gs_dynarray_handle Result = {0}; + if (Array->ElementCount >= DynarraySize(*Array)) + { + GrowDynarray(Array); + } + Assert(Array->ElementCount < DynarraySize(*Array)); + u64 ElementIndex = Array->ElementCount++; + Result = IndexToHandle(Array, ElementIndex); + return Result; +} +internal bool +HandleIsValid(gs_dynarray Array, gs_dynarray_handle Handle) +{ + bool Result = Handle.IndexInBuffer < Array.ElementsPerBuffer; + Result &= Handle.BufferIndex < Array.BuffersCount; + return Result; +} +internal bool +IndexIsValid(gs_dynarray Array, u64 Index) +{ + bool Result = Index < DynarraySize(Array); + return Result; +} +internal gs_data +GetElementInList_(gs_dynarray* Array, gs_dynarray_handle Handle, u64 SizeRequested) +{ + Assert(SizeRequested == Array->ElementSize); + Assert(HandleIsValid(*Array, Handle)); + gs_dynarray_buffer Buffer = Array->Buffers[Handle.BufferIndex]; + + gs_data Result = {0}; + Result.Memory = Buffer.Memory + (Handle.IndexInBuffer * Array->ElementSize); + Result.Size = SizeRequested; + + return Result; +} +internal gs_data +GetElementInList_(gs_dynarray* Array, u64 Index, u64 SizeRequested) +{ + gs_dynarray_handle Handle = IndexToHandle(Array, Index); + return GetElementInList_(Array, Handle, SizeRequested); +} +internal void +FreeDynarray(gs_dynarray* Array) +{ + gs_allocator Allocator = Array->Arena.Allocator; + u64 BufferSize = CalculateBufferSize(*Array); + for (u64 i = 0; i < Array->BuffersCount; i++) + { + AllocatorFree(Allocator, Array->Buffers[i].Memory, BufferSize); + } + AllocatorFree(Allocator, Array->Buffers, sizeof(gs_dynarray_buffer) * Array->BuffersCount); +} + +#define HandlesAreEqual(ha, hb) ((ha.IndexInBuffer == hb.IndexInBuffer) && (ha.BufferIndex == hb.BufferIndex)) + +#define CreateDynarray(allocator,type,elePerBuf) CreateDynarray_((allocator), sizeof(type), (elePerBuf)) +#define GetElement_(array,type,size,indexOrHandle) (type*)GetElementInList_(array, indexOrHandle, size).Memory +#define GetElement(array,type,indexOrHandle) GetElement_(array, type, sizeof(type), indexOrHandle) + +/////////////////////////// +// +// String Builder + +internal void +GrowStringBuilder_(gs_string_builder* StringBuilder) +{ + gs_string_builder_buffer* NewBuffer = PushStruct(StringBuilder->Arena, gs_string_builder_buffer); + NewBuffer->String = PushString(StringBuilder->Arena, StringBuilder->BufferSize); + SLLPushOrInit(StringBuilder->Root, StringBuilder->Head, NewBuffer); +} + +internal void +OutChar(gs_string_builder* Builder, char C) +{ + if (Builder->Head == 0 || Builder->Head->String.Length >= Builder->Head->String.Size) + { + GrowStringBuilder_(Builder); + } + OutChar(&Builder->Head->String, C); +} + +#if 0 +// TODO: If you need a string builder come back here, otherwise this can stay 0'd out +// was getting in the way +internal void +StringBuilderWriteFArgsList(gs_string_builder* Builder, char* Format, va_list Args) +{ + char* FormatAt = Format; + while (*FormatAt) + { + if (FormatAt[0] != '%') + { + if (FormatAt[0] == '\\') + { + FormatAt++; + Assert(IsBase8(FormatAt[0]) || // Octal Escape Sequences - \0 is in this set + FormatAt[0] == '\'' || + FormatAt[0] == '\"' || + FormatAt[0] == '\?' || + FormatAt[0] == '\\' || + FormatAt[0] == 'a' || // Audible Bell + FormatAt[0] == 'b' || // Backspace + FormatAt[0] == 'f' || // Form Feed - New Page + FormatAt[0] == 'n' || // Line Feed - New Line + FormatAt[0] == 'r' || // Carriage Return + FormatAt[0] == 't' || // Tab + FormatAt[0] == 'v'); // Vertical Tab + + // Not Handled (see cpp spec) \nnn \xnn \unnnn \Unnnnnnnn + Assert(FormatAt[0] != 'x' || FormatAt[0] != 'u' || FormatAt[0] != 'U'); + + if (IsBase8(FormatAt[0])) + { + // TODO(Peter): this should keep going until it finds a non-octal character code + // but the only one we really need is \0 atm so I'm just handling that one + Assert(FormatAt[0] == '0'); + OutChar(Builder, (char)0); + FormatAt++; + } + else + { + OutChar(Builder, *FormatAt++); + } + } + else + { + OutChar(Builder, *FormatAt++); + } + } + else if (FormatAt[0] == '%' && FormatAt[1] == '%') // Print the % symbol + { + OutChar(Builder, '%'); + FormatAt += 2; + } + 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 (IsBase10(FormatAt[0])) + { + WidthSpecified = true; + u64 Parsed = 0; + AssertMessage("ParseInt assumes whole string is an integer"); + Width = (s32)ParseInt(FormatAt, 10, &Parsed); + FormatAt += Parsed; + } + 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 (IsBase10(FormatAt[0])) + { + + PrecisionSpecified = true; + u64 Parsed = 0; + AssertMessage("ParseInt assumes whole string is an integer"); + Precision = (s32)ParseInt(FormatAt, 10, &Parsed); + FormatAt += Parsed; + } + 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 Specifiers + gs_string StringRemaining = GetStringAfter(*String, String->Length); + Assert(StringRemaining.Length == 0); + if (FormatAt[0] == 'd' || FormatAt[0] == 'i') + { + s64 SignedInt = ReadVarArgsSignedInteger(Length, &Args); + if (SignedInt < 0) + { + OutChar(&StringRemaining, '-'); + SignedInt *= -1; + } + U64ToASCII(&StringRemaining, (u64)SignedInt, 10, Base10Chars); + } + else if (FormatAt[0] == 'u') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 10, Base10Chars); + } + else if (FormatAt[0] == 'o') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 8, Base8Chars); + } + else if (FormatAt[0] == 'x' || FormatAt[0] == 'X') + { + u32 UnsignedInt = ReadVarArgsUnsignedInteger(Length, &Args); + U64ToASCII(&StringRemaining, UnsignedInt, 16, Base16Chars); + } + else if (FormatAt[0] == 'f' || FormatAt[0] == 'F') + { + r64 Float = ReadVarArgsFloat(Length, &Args); + s32 AfterPoint = 6; + if (PrecisionSpecified) + { + AfterPoint = Precision; + } + R64ToASCII(&StringRemaining, Float, AfterPoint); + } + else if (FormatAt[0] == 'c') + { + char InsertChar = va_arg(Args, s32); + OutChar(&StringRemaining, InsertChar); + } + else if (FormatAt[0] == 's') + { + char* InsertString = va_arg(Args, char*); + + s32 InsertStringLength = CStringLength(InsertString); + if (PrecisionSpecified) + { + InsertStringLength = Min(InsertStringLength, Precision); + } + InsertStringLength = Min(StringSizeLeft(StringRemaining), InsertStringLength); + + for (s32 c = 0; c < InsertStringLength; c++) + { + OutChar(&StringRemaining, InsertString[c]); + } + } + else if (FormatAt[0] == 'S') + { + gs_const_string InsertString = va_arg(Args, gs_const_string); + + for (s32 c = 0; c < InsertString.Length; c++) + { + OutChar(&StringRemaining, InsertString.Str[c]); + } + } + else if (FormatAt[0] == 'p') + { + // TODO(Peter): Pointer Address + } + else + { + // NOTE(Peter): Non-specifier character found + InvalidCodePath; + } + + String->Length += StringRemaining.Length; + FormatAt++; + } + } + + return String->Length; +} + +internal void +StringBuilderWriteF(gs_string_builder* Builder, char* Format, ...) +{ + va_list Args; + va_start(Args, Format); + StringBuilderWriteFArgsList(Builder, Format, Args); + va_end(Args); +} + +#endif // String builder + +/////////////////////////// +// +// File Handler + +internal u64 +FileHandlerGetFileInfo_NoOp(gs_file_handler FileHandler, gs_const_string Path) +{ + return 0; +} + +internal gs_file +FileHandlerReadFile_NoOp(gs_const_string Path) +{ + return gs_file{0}; +} + +internal bool +FileHandlerWriteFile_NoOp(gs_const_string Path, gs_data Data) +{ + return false; +} + +internal gs_const_string_array +FileHandlerEnumerateDirectory_NoOp(gs_const_string Path, bool Recursive, bool IncludeDirs) +{ + return gs_const_string_array{0}; +} + +internal gs_file_handler +CreateFileHandler(file_handler_get_file_info* GetFileInfo, + file_handler_read_entire_file* ReadEntireFile, + file_handler_write_entire_file* WriteEntireFile, + file_handler_enumerate_directory* EnumerateDirectory, + gs_memory_arena* Transient) +{ + if (GetFileInfo == 0) + { + GetFileInfo = (file_handler_get_file_info*)FileHandlerGetFileInfo_NoOp; + } + if (ReadEntireFile == 0) + { + ReadEntireFile = (file_handler_read_entire_file*)FileHandlerReadFile_NoOp; + } + if (WriteEntireFile == 0) + { + WriteEntireFile = (file_handler_write_entire_file*)FileHandlerWriteFile_NoOp; + } + if (EnumerateDirectory == 0) + { + EnumerateDirectory = (file_handler_enumerate_directory*)FileHandlerEnumerateDirectory_NoOp; + } + gs_file_handler Result = {0}; + Result.GetFileInfo = GetFileInfo; + Result.ReadEntireFile = ReadEntireFile; + Result.WriteEntireFile = WriteEntireFile; + Result.EnumerateDirectory = EnumerateDirectory; + Result.Transient = Transient; + + return Result; +} + +internal gs_const_string +GetNullTerminatedPath(gs_file_handler FileHandler, gs_const_string Path) +{ + gs_const_string Result = {}; + if (!IsNullTerminated(Path)) + { + gs_string NullTermPath = PushString(FileHandler.Transient, Path.Length + 1); + PrintF(&NullTermPath, "%S", Path); + NullTerminate(&NullTermPath); + Result = NullTermPath.ConstString; + } + else + { + Result = Path; + } + return Result; +} + +internal gs_file_info +GetFileInfo(gs_file_handler FileHandler, gs_const_string Path) +{ + Assert(FileHandler.GetFileInfo != 0); + + Path = GetNullTerminatedPath(FileHandler, Path); + gs_file_info Result = FileHandler.GetFileInfo(FileHandler, Path); + return Result; +} + +internal gs_file +ReadEntireFile(gs_file_handler FileHandler, gs_const_string Path, gs_data Memory) +{ + Assert(FileHandler.ReadEntireFile != 0); + + Path = GetNullTerminatedPath(FileHandler, Path); + gs_file Result = FileHandler.ReadEntireFile(FileHandler, Path, Memory); + return Result; +} + +internal gs_file +ReadEntireFile(gs_file_handler FileHandler, gs_const_string Path) +{ + Assert(FileHandler.GetFileInfo != 0); + Assert(FileHandler.ReadEntireFile != 0); + + Path = GetNullTerminatedPath(FileHandler, Path); + gs_file Result = {0}; + gs_file_info FileInfo = FileHandler.GetFileInfo(FileHandler, Path); + if (FileInfo.FileSize > 0) + { + gs_data FileMemory = PushSizeToData(FileHandler.Transient, FileInfo.FileSize); + Result = ReadEntireFile(FileHandler, Path, FileMemory); + } + return Result; +} + +internal bool +WriteEntireFile(gs_file_handler FileHandler, gs_const_string Path, gs_data Memory) +{ + Assert(FileHandler.WriteEntireFile != 0); + + Path = GetNullTerminatedPath(FileHandler, Path); + return FileHandler.WriteEntireFile(FileHandler, Path, Memory); +} + +internal gs_file_info_array +EnumerateDirectory(gs_file_handler FileHandler, gs_memory_arena* Storage, gs_const_string Path, u32 Flags) +{ + Assert(FileHandler.EnumerateDirectory != 0); + + Path = GetNullTerminatedPath(FileHandler, Path); + return FileHandler.EnumerateDirectory(FileHandler, Storage, Path, Flags); +} + +internal bool +FileNoError(gs_file File) +{ + bool Result = (File.Size > 0); + return Result; +} + +////////////////////////// +// +// Timing + +internal s64 +TimeHandlerGetWallClock(gs_time_handler TimeHandler) +{ + s64 Result = TimeHandler.GetWallClock(); + return Result; +} + +internal s64 +TimeHandlerGetSecondsElapsed(gs_time_handler TimeHandler, s64 StartCycles, s64 EndCycles) +{ + s64 Result = TimeHandler.GetSecondsElapsed(StartCycles, EndCycles); + return Result; +} + +/////////////////////////// +// +// Hashes + +internal u32 +HashDJB2ToU32(char* String) +{ + u32 Hash = 5381; + char* C = String; + while(*C) + { + Hash = ((Hash << 5) + Hash) + *C++; + } + return Hash; +} +internal u32 +HashDJB2ToU32(u32 Length, char* String) +{ + u32 Hash = 5381; + for (u32 i = 0; i < Length; i++) + { + Hash = ((Hash << 5) + Hash) + String[i]; + } + return Hash; +} + +internal u64 +HashDJB2ToU64(char* String) +{ + u64 Hash = 5381; + char* C = String; + while(*C) + { + Hash = ((Hash << 5) + Hash) + *C++; + } + return Hash; +} +internal u64 +HashDJB2ToU64(u32 Length, char* String) +{ + u64 Hash = 5381; + for (u32 i = 0; i < Length; i++) + { + Hash = ((Hash << 5) + Hash) + String[i]; + } + return Hash; +} + +/////////////////////////// +// +// Random Series + +internal gs_random_series +InitRandomSeries(u32 Seed) +{ + gs_random_series Result = {0}; + Result.Value = Seed; + return Result; +} + +internal u32 +NextRandom(gs_random_series* Series) +{ + u32 Result = Series->Value; + Result ^= Result << 13; + Result ^= Result >> 17; + Result ^= Result << 5; + Series->Value = Result; + return Result; +} + +internal r32 +NextRandomUnilateral(gs_random_series* Series) +{ + r32 Result = (r32)NextRandom(Series) / (r32)UINT32_MAX; + return Result; +} + +internal r32 +NextRandomBilateral(gs_random_series* Series) +{ + r32 Result = (r32)NextRandom(Series); + Result = Result / (r32)0xFFFFFFFF; + Result = (Result * 2.0f) - 1.0f; + return Result; +} + + +/////////////////////////// +// +// Sort + + +static void +RadixSortInPlace_ (gs_radix_list* List, u32 Start, u32 End, u32 Iteration) +{ + u32 Shift = Iteration; + u32 ZerosBoundary = Start; + u32 OnesBoundary = End - 1; + + for (u32 d = Start; d < End; d++) + { + u64 CurrentIndex = ZerosBoundary; + u64 Radix = List->Radixes.Values[CurrentIndex]; + u64 Place = (Radix >> Shift) & 0x1; + if (Place) + { + u64 EvictedIndex = OnesBoundary; + u64 EvictedRadix = List->Radixes.Values[EvictedIndex]; + u64 EvictedID = List->IDs.Values[EvictedIndex]; + + List->Radixes.Values[EvictedIndex] = Radix; + List->IDs.Values[EvictedIndex] = List->IDs.Values[CurrentIndex]; + + List->Radixes.Values[CurrentIndex] = EvictedRadix; + List->IDs.Values[CurrentIndex] = EvictedID; + + OnesBoundary -= 1; + } + else + { + ZerosBoundary += 1; + } + } + + if (Iteration > 0) + { + RadixSortInPlace_(List, Start, ZerosBoundary, Iteration - 1); + RadixSortInPlace_(List, ZerosBoundary, End, Iteration - 1); + } +} + +static void +RadixSortInPlace (gs_radix_list* List) +{ + u32 Highest = 0; + for (u32 i = 0; i < List->Radixes.Count; i++) + { + if (List->Radixes.Values[i] > Highest) + { + Highest = List->Radixes.Values[i]; + } + } + + u32 Iterations = 0; + while (Highest > 1) + { + ++Iterations; + Highest = Highest >> 1; + } + + RadixSortInPlace_(List, 0, List->Radixes.Count, Iterations); +} + + +/////////////////////////// +// +// Input + +inline bool +KeyIsMouseButton(gs_key Key) +{ + bool Result = (Key >= gs_Key_MouseLeftButton); + Result = Result && Key <= gs_Key_MouseRightButton; + return Result; +} +inline u32 +GetMouseButtonIndex(gs_key Button) +{ + Assert(KeyIsMouseButton(Button)); + u32 Result = Button - gs_Key_MouseLeftButton; + return Result; +} +inline bool +MouseButtonTransitionedDown(gs_mouse_state Mouse, u32 Index) +{ + bool IsDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_IsDownBit)) != 0; + bool WasDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_WasDownBit)) != 0; + return IsDown && !WasDown; +} +inline bool +MouseButtonTransitionedDown(gs_mouse_state Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + return MouseButtonTransitionedDown(Mouse, Index); +} +inline bool +MouseButtonIsDown(gs_mouse_state Mouse, u32 Index) +{ + bool IsDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_IsDownBit)) != 0; + return IsDown; +} +inline bool +MouseButtonIsDown(gs_mouse_state Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + return MouseButtonIsDown(Mouse, Index); +} +inline bool +MouseButtonTransitionedUp(gs_mouse_state Mouse, u32 Index) +{ + bool IsDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_IsDownBit)) != 0; + bool WasDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_WasDownBit)) != 0; + return !IsDown && WasDown; +} +inline bool +MouseButtonTransitionedUp(gs_mouse_state Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + return MouseButtonTransitionedUp(Mouse, Index); +} +inline bool +MouseButtonIsUp(gs_mouse_state Mouse, u32 Index) +{ + bool IsDown = (Mouse.ButtonStates[Index] & (1 << MouseButton_IsDownBit)) != 0; + return !IsDown; +} +inline bool +MouseButtonIsUp(gs_mouse_state Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + return MouseButtonIsUp(Mouse, Index); +} +internal void +SetMouseButtonTransitionedDown(gs_mouse_state* Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + + Mouse->ButtonStates[Index] = 0; + Mouse->ButtonStates[Index] |= MouseButton_IsDown << MouseButton_IsDownBit; + Mouse->ButtonStates[Index] |= MouseButton_WasNotDown << MouseButton_WasDownBit; +} +internal void +SetMouseButtonTransitionedUp(gs_mouse_state* Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + + Mouse->ButtonStates[Index] = 0; + Mouse->ButtonStates[Index] |= MouseButton_IsNotDown << MouseButton_IsDownBit; + Mouse->ButtonStates[Index] |= MouseButton_WasDown << MouseButton_WasDownBit; +} +internal void +AdvanceMouseButtonState(gs_mouse_state* Mouse, gs_key Button) +{ + u32 Index = GetMouseButtonIndex(Button); + + if (MouseButtonIsDown(*Mouse, Index)) + { + Mouse->ButtonStates[Index] |= MouseButton_WasDown << MouseButton_WasDownBit; + } + else + { + Mouse->ButtonStates[Index] &= MouseButton_WasNotDown << MouseButton_WasDownBit; + } +} +internal void +AdvanceMouseButtonsState(gs_mouse_state* Mouse) +{ + AdvanceMouseButtonState(Mouse, gs_Key_MouseLeftButton); + AdvanceMouseButtonState(Mouse, gs_Key_MouseMiddleButton); + AdvanceMouseButtonState(Mouse, gs_Key_MouseRightButton); +} + +/////////////////////////// +// +// Network + + +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_TYPES_CPP +#endif // GS_TYPES_CPP \ No newline at end of file diff --git a/src/gs_libs/gs_types.h b/src/gs_libs/gs_types.h new file mode 100644 index 0000000..e36f2ed --- /dev/null +++ b/src/gs_libs/gs_types.h @@ -0,0 +1,1054 @@ +// +// File: gs_types.h +// Author: Peter Slattery +// Creation Date: 2020-04-18 +// +#ifndef GS_TYPES_H + +#if defined(__clang__) +# pragma GCC diagnostic ignored "-Wunused-value" +# pragma GCC diagnostic ignored "-Wvarargs" +# pragma GCC diagnostic ignored "-Wwritable-strings" +#endif + +#if defined(_MSC_VER) +# include +#endif + +// Someday, we home to remove these includes +#include +#if !defined(GUESS_INTS) +# include +#endif // !defined(GUESS_INTS) + +#include + +#define Glue_(a,b) a##b +#define Glue(a,b) Glue_(a,b) + +#define Stringify_(a) #a +#define Stringify(a) Stringify_(a) + +#define internal static +#define local_persist static +#define global static +#define local_const static const +#define global_const static const +#define external extern "C" + +#if defined(GUESS_INTS) +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +#else +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +#endif + +typedef s8 b8; +typedef s32 b32; +typedef s64 b64; + +typedef float r32; +typedef double r64; + +enum gs_basic_type +{ + gs_BasicType_char, + gs_BasicType_b8, + gs_BasicType_b32, + gs_BasicType_b64, + gs_BasicType_u8, + gs_BasicType_u16, + gs_BasicType_u32, + gs_BasicType_u64, + gs_BasicType_s8, + gs_BasicType_s16, + gs_BasicType_s32, + gs_BasicType_s64, + gs_BasicType_r32, + gs_BasicType_r64, + + gs_BasicType_Count, +}; + +global_const u64 gs_BasicTypeSizes[] = +{ + sizeof(char), + sizeof(b8), + sizeof(b32), + sizeof(b64), + sizeof(u8), + sizeof(u16), + sizeof(u32), + sizeof(u64), + sizeof(s8), + sizeof(s16), + sizeof(s32), + sizeof(s64), + sizeof(r32), + sizeof(r64), +}; + +internal u64 +BasicTypeSize(gs_basic_type Type) +{ + return gs_BasicTypeSizes[(u32)Type]; +} + +global_const u8 MaxU8 = 0xFF; +global_const u16 MaxU16 = 0xFFFF; +global_const u32 MaxU32 = 0xFFFFFFFF; +global_const u64 MaxU64 = 0xFFFFFFFFFFFFFFFF; + +global_const s8 MaxS8 = 127; +global_const s16 MaxS16 = 32767; +global_const s32 MaxS32 = 2147483647; +global_const s64 MaxS64 = 9223372036854775807; + +global_const s8 MinS8 = -127 - 1; +global_const s16 MinS16 = -32767 - 1; +global_const s32 MinS32 = -2147483647 - 1; +global_const s64 MinS64 = -9223372036854775807 - 1; + +global_const r32 MaxR32 = 3.402823466e+38f; +global_const r32 MinR32 = -MaxR32; +global_const r32 SmallestPositiveR32 = 1.1754943508e-38f; +global_const r32 EpsilonR32 = 5.96046448e-8f; + +global_const r32 PiR32 = 3.14159265359f; +global_const r32 HalfPiR32 = 1.5707963267f; +global_const r32 TauR32 = 6.28318530717f; + +global_const r64 MaxR64 = 1.79769313486231e+308; +global_const r64 MinR64 = -MaxR64; +global_const r64 SmallestPositiveR64 = 4.94065645841247e-324; +global_const r64 EpsilonR64 = 1.11022302462515650e-16; + +// TODO: va_start and va_arg replacements + +internal r32 +DegToRadR32(r32 Degrees) +{ + return (Degrees * (PiR32 / 180.0f)); +} + +internal r32 +RadToDegR32(r32 Radians) +{ + return (Radians * (180.0f / PiR32)); +} + +struct s8_array +{ + s8* Values; + u32 Count; + u32 CountMax; +}; + +struct s16_array +{ + s16* Values; + u32 Count; + u32 CountMax; +}; + +struct s32_array +{ + s32* Values; + u32 Count; + u32 CountMax; +}; + +struct s64_array +{ + s64* Values; + u32 Count; + u32 CountMax; +}; + +struct u8_array +{ + u8* Values; + u32 Count; + u32 CountMax; +}; + +struct u16_array +{ + u16* Values; + u32 Count; + u32 CountMax; +}; + +struct u32_array +{ + u32* Values; + u32 Count; + u32 CountMax; +}; + +struct u64_array +{ + u64* Values; + u32 Count; + u32 CountMax; +}; + + +#define PointerDifference(a,b) ((u8*)(a) - (u8*)(b)) +#define PointerToInt(a) PointerDifference(a, 0) +#define Member(type,member) (((type*)0)->member) +#define MemberOffset(type,member) PointerToInt(&Member(type,member)) + +// NOTE(Peter): Makes sure that s doesn't expand in some way that invalidates +// a nested if statement. +#define Statement(s) do{ s }while(0) + +// +// Asserts +// +// AssertAlways and AssertMessageAlways should be used sparingly, because they'll +// still assert in the final build +#define AssertBreak(m) (*((volatile s32*)0) = 0xFFFF) +#define AssertAlways(c) Statement( if (!(c)) { AssertBreak(c); } ) +#define AssertMessageAlways(m) AssertBreak(m) + +#if !SHIP_MODE +# define Assert(c) AssertAlways(c) +# define AssertMessage(m) AssertBreak(m) +# define InvalidDefaultCase default: { AssertBreak("invalid default case"); } break; +# define StaticAssert(c) \ +enum { \ +Glue(gs_AssertFail_, __LINE__) = 1 / (int)(!!(c)), \ +} +#else +# define Assert(c) +# define AssertMessage(m) +# define InvalidDefaultCase default: {} break; +# define StaticAssert(c) +#endif + +#define AssertImplies(a,b) Statement(if(a) { Assert(b); }) +#define InvalidCodePath AssertMessage("invalid code path") +#define NotImplemented AssertMessage("not implemented") +#define DontCompile ImAfraidICantDoThat + +#define LineNumberString Stringify(__LINE__) +#define FileNameAndLineNumberString_ __FILE__ ":" LineNumberString ":" +#define FileNameAndLineNumberString (char*)FileNameAndLineNumberString_ + +// + +#define Bytes(x) (x) +#define KB(x) ((x) << 10) +#define MB(x) ((x) << 20) +#define GB(x) ((x) << 30) +#define TB(x) (((u64)x) << 40) + +#define HasFlag(data, flag) (((data) & (flag)) != 0) +#define HasFlagOnly(data, flag) (((data) & (flag)) == (data)) +#define AddFlag(data, flag) ((data) |= (flag)) +#define RemoveFlag(data, flag) ((data) &= (~(flag))) + +#define Max(a,b) (((a) > (b)) ? (a) : (b)) +#define Min(a,b) (((a) > (b)) ? (b) : (a)) +#define Clamp_(a,x,b) ((x < a) ? a : ((x > b) ? b : x)) +#define Clamp(a,x,b) Clamp_((a), (x), (b)) +#define Clamp01(x) Clamp_(0.0f, (x), 1.0f) +#define Abs(x) (((x) < 0) ? ((x) * -1) : x) +#define Sign(x) ((x) < 0) ? -1 : 1; +#define IsPowerOfTwo(x) (((x) & ((x) - 1)) == 0) +#define IsOdd(x) (((x) & 1) != 0) + +internal void +ZeroMemory_(u8* Memory, u64 Size) +{ + for (u64 i = 0; i < Size; i++) + { + Memory[i] = 0; + } +} + +internal void +CopyMemory_(u8* From, u8* To, u64 Size) +{ + for (u64 i = 0; i < Size; i++) + { + To[i] = From[i]; + } +} + +#define StaticArrayLength(arr) sizeof(arr) / sizeof((arr)[0]) +#define ZeroMemoryBlock(mem,size) ZeroMemory_((u8*)(mem), (size)) +#define ZeroStruct(str) ZeroMemory_((u8*)(str), sizeof(*str)) +#define ZeroArray(arr, type, count) ZeroMemory_((u8*)(arr), sizeof(type) * (count)) + +#define CopyArray(from, to, type, count) CopyMemory_((u8*)(from), (u8*)(to), sizeof(type) * (count)) +#define CopyMemoryTo(from, to, size) CopyMemory_((u8*)(from), (u8*)(to), (size)) +// Singly Linked List Utilities + +#define SLLPush_(list_tail,new_ele) list_tail->Next = new_ele, list_tail = new_ele +#define SLLPush(list_tail,new_ele) (SLLPush_((list_tail), (new_ele))) + +#define SLLPop_(list_tail) list_tail=list_tail=list_tail->next +#define SLLPop(list_tail) (SLLPop_((list_tail))) + +#define SLLNext(ele_at) ele_at = ele_at->Next; +#define SLLPrev(ele_at) ele_at = ele_at->Prev; + +#define SLLInit(head,tail,first_ele) head=first_ele, tail=first_ele; + +#define SLLPushOrInit(first,last,new_ele) \ +if (last) { SLLPush(last, new_ele); } \ +else { SLLInit(first,last,new_ele); } + +// Vectors + +union v2 +{ + struct + { + r32 x; + r32 y; + }; + r32 E[2]; +}; + +union v3 +{ + struct + { + r32 x; + r32 y; + r32 z; + }; + struct + { + r32 r; + r32 g; + r32 b; + }; + struct + { + v2 xy; + r32 _z0; + }; + struct + { + r32 _x0; + v2 yz; + }; + r32 E[3]; +}; + +union v4 +{ + struct + { + r32 x; + r32 y; + r32 z; + r32 w; + }; + struct + { + r32 r; + r32 g; + r32 b; + r32 a; + }; + struct + { + v2 xy; + v2 zw; + }; + struct + { + r32 _x0; + v2 yz; + r32 _w0; + }; + struct + { + v3 xyz; + r32 _w1; + }; + r32 E[4]; +}; + +struct v4_ray +{ + v4 Origin; + v4 Direction; +}; + +#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} + +#define V2Expand(v) v.x, v.y +#define V3Expand(v) v.x, v.y, v.z +#define V4Expand(v) v.x, v.y, v.z, v.w + +struct v2_array +{ + v2* Vectors; + u32 Count; + u32 CountMax; +}; + +struct v3_array +{ + v3* Vectors; + u32 Count; + u32 CountMax; +}; + +struct v4_array +{ + v4* Vectors; + u32 Count; + u32 CountMax; +}; + +struct range1 +{ + r32 Min; + r32 Max; +}; + +struct range2 +{ + v2 Min; + v2 Max; +}; +typedef range2 rect2; + +struct range3 +{ + v3 Min; + v3 Max; +}; + +struct range4 +{ + v4 Min; + v4 Max; +}; + +struct range1_array +{ + range1* Ranges; + u32 Count; + u32 CountMax; +}; + +struct range2_array +{ + range2* Ranges; + u32 Count; + u32 CountMax; +}; + +struct range3_array +{ + range3* Ranges; + u32 Count; + u32 CountMax; +}; + +struct range4_array +{ + range4* Ranges; + u32 Count; + u32 CountMax; +}; + +#define Range1Expand(r) (r).Min, (r).Max +#define Range2Expand(r) (r).Min, (r).Max +#define Rect2Expand(r) (r).Min (r).Max +#define Range3Expand(r) (r).Min, (r).Max +#define Range4Expand(r) (r).Min, (r).Max + +// Matrices +// NOTE(Peter): All matrices are stored in row major order + +union m33 +{ + float Array[9]; + struct + { + r32 AXx; r32 AYx; r32 AZx; + r32 AXy; r32 AYy; r32 AZy; + r32 AXz; r32 AYz; r32 AZz; + }; +}; + +union m44 +{ + float Array[16]; + struct + { + r32 AXx; r32 AYx; r32 AZx; r32 Tx; + r32 AXy; r32 AYy; r32 AZy; r32 Ty; + r32 AXz; r32 AYz; r32 AZz; r32 Tz; + r32 AXw; r32 AYw; r32 AZw; r32 Tw; + }; +}; + +struct m33_array +{ + m33* Matrices; + u32 Count; + u32 CountMax; +}; + +struct m44_array +{ + m44* Matrices; + u32 Count; + u32 CountMax; +}; + +////////////////////////// +// +// Strings + +struct gs_const_string +{ + union + { + char* Str; + u8* Data;; + }; + u64 Length; +}; + +struct gs_string +{ + union + { + gs_const_string ConstString; + struct + { + char* Str; + u64 Length; + }; + }; + u64 Size; +}; + +struct gs_const_string_array +{ + gs_const_string* Strings; + u64 Count; + u64 Used; +}; + +struct gs_string_array +{ + gs_string* Strings; + u64 Count; + u64 CountMax; +}; + +internal u64 +CStringLength(char* Str) +{ + char* At = Str; + while (*At) { At++; } + return PointerDifference(At, Str); +} + +#define StringExpand(str) (int)(str).Length, (str).Str +#define LitString(cstr) gs_const_string{(char*)(cstr), CStringLength((char*)cstr) } + +// The index of the character in these arrays corresponds to its value as a number in +// the relevant base, so you can do FindFirst on them with a char to get the int value +// ie. 3 is at index 3 in Base10Chars. +// ie. C is at index 12 in Base16Chars. +global_const gs_const_string Base8Chars = LitString("01234567"); +global_const gs_const_string Base10Chars = LitString("0123456789"); +global_const gs_const_string Base16Chars = LitString("0123456789ABCDEF"); + +////////////////////////// +// +// Thread Context + +typedef struct gs_thread_context gs_thread_context; + +////////////////////////// +// +// Memory + +struct gs_data +{ + u8* Memory; + u64 Size; +}; + +struct gs_data_array +{ + gs_data* Data; + u64 Count; + u64 CountMax; +}; + +enum gs_access_flag +{ + gs_AccessFlag_Read = 1 << 0, + gs_AccessFlag_Write = 1 << 1, + gs_AccessFlag_Exec = 1 << 2, +}; + +typedef s32 gs_scan_direction; +enum +{ + gs_Scan_Backward = -1, + gs_Scan_Forward = 1, +}; + +#define ALLOCATOR_ALLOC(name) void* name(u64 Size, u64* ResultSize) +typedef ALLOCATOR_ALLOC(allocator_allocate); + +#define ALLOCATOR_FREE(name) void name(void* Ptr, u64 Size) +typedef ALLOCATOR_FREE(allocator_free); + +struct gs_allocator +{ + allocator_allocate* Alloc; + allocator_free* Free; +}; + +struct gs_memory_cursor +{ + gs_data Data; + u64 Position; +}; + +struct gs_memory_cursor_list +{ + gs_memory_cursor Cursor; + gs_memory_cursor_list* Next; + gs_memory_cursor_list* Prev; +}; + +enum arena_type +{ + Arena_BaseArena, + Arena_SubArena, +}; + +struct gs_memory_arena +{ + arena_type Type; + gs_allocator Allocator; + gs_memory_arena* Parent; + + gs_memory_cursor_list* CursorList; + u64 MemoryChunkSize; + u64 MemoryAlignment; +}; + +struct gs_memory_arena_array +{ + gs_memory_arena* Arenas; + u32 Count; + u32 Size; +}; + +/////////////////////////////// +// +// String Builder +// + +struct gs_string_builder_buffer +{ + gs_string String; + gs_string_builder_buffer* Next; +}; + +struct gs_string_builder +{ + gs_memory_arena* Arena; + u32 BufferSize; + gs_string_builder_buffer* Root; + gs_string_builder_buffer* Head; +}; + +/////////////////////////////// +// +// Debug Output +// + +typedef struct debug_output debug_output; + +#define DEBUG_PRINT(name) void name(debug_output Output, gs_const_string Message) +typedef DEBUG_PRINT(debug_print); + +struct debug_output +{ + gs_memory_arena* Storage; + debug_print* Print; +}; + +/////////////////////////////// +// +// Dynamic Array +// +// I like having constant lookup times, along with growable arrays. :) +// NOTE(Peter): If you're using this, you probably want to write a Get +// procedure to auto cast the result to the type you want. I'm even providing a +// debug check for you to make sure that you're requesting a size that matches +// the ElementSize for extra safety. + +struct gs_dynarray_buffer +{ + u8* Memory; +}; + +struct gs_dynarray +{ + gs_memory_arena Arena; + + gs_dynarray_buffer* Buffers; + u64 BuffersCount; + u64 ElementCount; + + u64 ElementSize; + u64 ElementsPerBuffer; +}; + +struct gs_dynarray_handle +{ + u64 BufferIndex; + u64 IndexInBuffer; +}; + +#define INVALID_DYNARRAY_HANDLE gs_dynarray_handle{0, 0} + +struct gs_dynarray_handle_list +{ + gs_dynarray_handle* Handles; + u32 Count; + u32 Size; +}; + +/////////////////////////////// +// +// File IO + +// TODO(Peter): Error Handling Thought +// The gs_file_handler, gs_allocator, etc should contain pointers to a central error buffer +// where errors can be logged + +enum enumerate_directory_flag +{ + EnumerateDirectory_Recurse = 1 << 0, + EnumerateDirectory_IncludeDirectories = 1 << 1, +}; + +struct gs_file_info +{ + gs_const_string Path; + gs_const_string AbsolutePath; + u64 FileSize; + u64 CreationTime; + u64 LastWriteTime; + b32 IsDirectory; +}; + +struct gs_file_info_array +{ + gs_file_info* Values; + u32 Count; + u32 MaxCount; +}; + +struct gs_file +{ + union + { + gs_data Data; + struct + { + u8* Memory; + u64 Size; + }; + }; + gs_file_info FileInfo; +}; + +typedef struct gs_file_handler gs_file_handler; + +#define GET_FILE_INFO(name) gs_file_info name(gs_file_handler FileHandler, gs_const_string Path) +typedef GET_FILE_INFO(file_handler_get_file_info); + +#define READ_ENTIRE_FILE(name) gs_file name(gs_file_handler FileHandler, gs_const_string Path, gs_data Memory) +typedef READ_ENTIRE_FILE(file_handler_read_entire_file); + +#define WRITE_ENTIRE_FILE(name) bool name(gs_file_handler FileHandler, gs_const_string Path, gs_data Data) +typedef WRITE_ENTIRE_FILE(file_handler_write_entire_file); + +#define ENUMERATE_DIRECTORY(name) gs_file_info_array name(gs_file_handler FileHandler, gs_memory_arena* Storage, gs_const_string Path, u32 Flags) +typedef ENUMERATE_DIRECTORY(file_handler_enumerate_directory); + +struct gs_file_handler +{ + file_handler_get_file_info* GetFileInfo; + file_handler_read_entire_file* ReadEntireFile; + file_handler_write_entire_file* WriteEntireFile; + file_handler_enumerate_directory* EnumerateDirectory; + gs_memory_arena* Transient; +}; + + +////////////////////////// +// +// Timing + +#define GET_WALL_CLOCK(name) s64 name() +typedef GET_WALL_CLOCK(get_wall_clock); + +#define GET_SECONDS_ELAPSED(name) r64 name(u64 StartCycles, u64 EndCycles) +typedef GET_SECONDS_ELAPSED(get_seconds_elapsed); + +struct gs_time_handler +{ + get_wall_clock* GetWallClock; + get_seconds_elapsed* GetSecondsElapsed; +}; + +/////////////////////////////// +// +// Random + +struct gs_random_series +{ + u32 Value; +}; + +/////////////////////////////// +// +// Sort + +struct gs_radix_list +{ + u64_array Radixes; + u64_array IDs; +}; + + +/////////////////////////////// +// +// Mouse/Keyboard Input + +enum gs_event_type +{ + gs_EventType_Unknown, + + // Reached end of event stream + gs_EventType_NoMoreEvents, + // There was an event but it requires no action from the using program + gs_EventType_NoEvent, + + gs_EventType_KeyPressed, + gs_EventType_KeyReleased, + + gs_EventType_MouseMoved, + gs_EventType_MouseWheel, + + gs_EventType_Count, +}; + +enum gs_key +{ + gs_Key_Invalid, + + gs_Key_Esc, + + gs_Key_Space, + gs_Key_Tab, + gs_Key_CapsLock, + gs_Key_Shift, gs_Key_LeftShift, gs_Key_RightShift, + gs_Key_Control, gs_Key_LeftCtrl, gs_Key_RightCtrl, + gs_Key_Fn, + gs_Key_Alt, + gs_Key_PageUp, gs_Key_PageDown, + gs_Key_End, gs_Key_Home, gs_Key_Select, + gs_Key_Backspace, gs_Key_Delete, + gs_Key_Enter, + + // Function Keys + gs_Key_F0, gs_Key_F1, gs_Key_F2, gs_Key_F3, gs_Key_F4, gs_Key_F5, gs_Key_F6, gs_Key_F7, + gs_Key_F8, gs_Key_F9, gs_Key_F10, gs_Key_F11, gs_Key_F12, + + // Letters + gs_Key_a, gs_Key_b, gs_Key_c, gs_Key_d, gs_Key_e, gs_Key_f, gs_Key_g, gs_Key_h, + gs_Key_i, gs_Key_j, gs_Key_k, gs_Key_l, gs_Key_m, gs_Key_n, gs_Key_o, gs_Key_p, + gs_Key_q, gs_Key_r, gs_Key_s, gs_Key_t, gs_Key_u, gs_Key_v, gs_Key_w, gs_Key_x, + gs_Key_y, gs_Key_z, + + gs_Key_A, gs_Key_B, gs_Key_C, gs_Key_D, gs_Key_E, gs_Key_F, gs_Key_G, gs_Key_H, + gs_Key_I, gs_Key_J, gs_Key_K, gs_Key_L, gs_Key_M, gs_Key_N, gs_Key_O, gs_Key_P, + gs_Key_Q, gs_Key_R, gs_Key_S, gs_Key_T, gs_Key_U, gs_Key_V, gs_Key_W, gs_Key_X, + gs_Key_Y, gs_Key_Z, + + // Numbers + gs_Key_0, gs_Key_1, gs_Key_2, gs_Key_3, gs_Key_4, gs_Key_5, gs_Key_6, gs_Key_7, + gs_Key_8, gs_Key_9, + + gs_Key_Num0, gs_Key_Num1, gs_Key_Num2, gs_Key_Num3, gs_Key_Num4, gs_Key_Num5, + gs_Key_Num6, gs_Key_Num7, gs_Key_Num8, gs_Key_Num9, + + // Symbols + gs_Key_Bang, gs_Key_At, gs_Key_Pound, gs_Key_Dollar, gs_Key_Percent, gs_Key_Carrot, + gs_Key_Ampersand, gs_Key_Star, gs_Key_LeftParen, gs_Key_RightParen, gs_Key_Minus, gs_Key_Plus, + gs_Key_Equals, gs_Key_Underscore, gs_Key_OpenSquareBracket, gs_Key_CloseSquareBracket, gs_Key_OpenCurlyBracket, + gs_Key_CloseCurlyBracket, gs_Key_Colon, gs_Key_SemiColon, gs_Key_SingleQuote, gs_Key_DoubleQuote, + gs_Key_ForwardSlash, gs_Key_Backslash, gs_Key_Pipe, gs_Key_Comma, gs_Key_Period, + gs_Key_QuestionMark, gs_Key_LessThan, gs_Key_GreaterThan, gs_Key_Tilde, gs_Key_BackQuote, + + // Arrows + gs_Key_UpArrow, + gs_Key_DownArrow, + gs_Key_LeftArrow, + gs_Key_RightArrow, + + // Mouse + // NOTE(Peter): Including this here so we can utilize the same KeyDown, KeyUp etc. functions + gs_Key_MouseLeftButton, + gs_Key_MouseMiddleButton, + gs_Key_MouseRightButton, + gs_Key_MouseX1Button, + gs_Key_MouseX2Button, + + gs_Key_Count, +}; + +enum gs_modifier_key_flags +{ + gs_ModifierKeyFlag_Shift = 1 << 0, + gs_ModifierKeyFlag_Ctrl = 1 << 1, + gs_ModifierKeyFlag_Alt = 1 << 2, +}; + +struct gs_input_event +{ + gs_event_type Type; + gs_key Key; + v2 Position; + r32 Amount; + b32 Modifiers; +}; + +struct gs_input_event_buffer +{ + gs_input_event* Values; + u32 Count; + u32 MaxCount; +}; + +struct gs_mouse_state +{ + v2 Position; + b32 ButtonStates[3]; + v2 DownPosition; +}; + +#define MouseButton_IsDownBit 0 +#define MouseButton_WasDownBit 1 +#define MouseButton_IsDown 1 +#define MouseButton_IsNotDown 0 +#define MouseButton_WasDown 1 +#define MouseButton_WasNotDown 0 + +////////////////////////// +// +// Thread Context + +struct gs_thread_info +{ + u32 ThreadID; +}; + +struct gs_thread_context +{ + gs_thread_info ThreadInfo; + + // TODO(Peter): Pull these handlers out into just a gs_context struct so + // they can be shared across threads. + // specifically the allocator + gs_allocator Allocator; + gs_file_handler FileHandler; + debug_output DebugOutput; + gs_time_handler TimeHandler; + + gs_memory_arena* Transient; +}; + +// Threads & Work Queue + +typedef struct gs_work_queue gs_work_queue; + +struct gs_worker_thread +{ + gs_thread_context Context; + gs_work_queue* Queue; + b32 ShouldExit; +}; + +#define THREAD_PROC(name) void name(gs_thread_context Context, gs_data Data) +typedef THREAD_PROC(thread_proc); + +struct gs_threaded_job +{ + thread_proc* WorkProc; + gs_data Data; + gs_const_string JobName; +}; + +#define PUSH_WORK_ON_QUEUE(name) void name(gs_work_queue* Queue, thread_proc* WorkProc, gs_data Data, gs_const_string JobName) +typedef PUSH_WORK_ON_QUEUE(push_work_on_queue); + +#define COMPLETE_QUEUE_WORK(name) void name(gs_work_queue* Queue, gs_thread_context Context) +typedef COMPLETE_QUEUE_WORK(complete_queue_work); + +#define RESET_WORK_QUEUE(name) void name(gs_work_queue* Queue) +typedef RESET_WORK_QUEUE(reset_work_queue); + +struct gs_work_queue +{ + void* SemaphoreHandle; + + u32 JobsMax; + u32 volatile JobsCount; + u32 volatile NextJobIndex; + u32 volatile JobsCompleted; + gs_threaded_job* Jobs; + + // Work Queue + push_work_on_queue* PushWorkOnQueue; + complete_queue_work* CompleteQueueWork; + reset_work_queue* ResetWorkQueue; +}; + +#define GS_TYPES_H +#endif // GS_TYPES_H \ No newline at end of file diff --git a/src/gs_libs/gs_vector_matrix.h b/src/gs_libs/gs_vector_matrix.h index 3d1cfbd..c089100 100644 --- a/src/gs_libs/gs_vector_matrix.h +++ b/src/gs_libs/gs_vector_matrix.h @@ -75,6 +75,18 @@ union v4 float a; }; + struct + { + v2 xy; + v2 yz; + }; + + struct + { + v3 xyz; + float z; + }; + float E[4]; }; @@ -93,25 +105,12 @@ union v4 union m33 { - struct - { - float a; float b; float c; - float d; float e; float f; - float g; float h; float i; - }; - float E[9]; + float E[3][3]; }; union m44 { - struct - { - float a; float b; float c; float d; - float e; float f; float g; float h; - float i; float j; float k; float l; - float m; float n; float o; float p; - }; - float E[16]; + float E[4][4]; }; ////////////////////////////////////// @@ -636,10 +635,10 @@ PointIsInRange (v2 _P, v2 _Min, v2 _Max) 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); + s32 MinX = Min(_Min.x, _Max.x); + s32 MinY = Min(_Min.y, _Max.y); + s32 MaxX = Max(_Min.x, _Max.x); + s32 MaxY = Max(_Min.y, _Max.y); return (_P.x >= MinX && _P.x <= MaxX && _P.y >= MinY && _P.y <= MaxY); @@ -1271,11 +1270,10 @@ GetLookAtMatrix (v4 Position, v4 Target) 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, + Right.x, Right.y, Right.z, 0, + Up.x, Up.y, Up.z, 0, + Forward.x, Forward.y, Forward.z, 0, 0, 0, 0, 1); - return RotationMatrix; } @@ -1427,11 +1425,11 @@ void TestVectorMatrixMultiplication () // 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"); + TestClean((Lerp(0.f, 1.f, .5f) == .5f), "Vector Lerp"); + TestClean((Min(-.25f, 5.f) == -.25f), "Vector Min"); + TestClean((Max(-.25f, 5.f) == 5.f), "Vector Max"); + TestClean((Clamp(-2.f, -3.f, 5.f) == -2.f), "Vector Clamp, Lower Than Range"); + TestClean((Clamp(-2.f, 6.f, 5.f) == 5.f), "Vector Clamp, Higher Than Range"); ////////////////////////////// // Vector Functions diff --git a/src/gs_libs/gs_win32.cpp b/src/gs_libs/gs_win32.cpp index e2df025..b96ae2e 100644 --- a/src/gs_libs/gs_win32.cpp +++ b/src/gs_libs/gs_win32.cpp @@ -27,7 +27,7 @@ struct window char* ClassName; s32 Width; s32 Height; - WNDPROC WindowEventHandler; + WNDPROC WindowEventHandler; WNDCLASS Class; HWND Handle; @@ -45,7 +45,7 @@ struct handle_window_msg_result #endif }; -global_variable win32_state GlobalWin32State; +global win32_state GlobalWin32State; // Utility internal s32 Win32StringLength(char* String); @@ -66,15 +66,14 @@ internal void Win32DisplayBufferInWindow(win32_offscreen_buffer* Buffer // Memory -internal PLATFORM_ALLOC(Win32Alloc); -internal PLATFORM_FREE(Win32Free); -internal PLATFORM_REALLOC(Win32Realloc); +internal ALLOCATOR_ALLOC(Win32Alloc); +internal ALLOCATOR_FREE(Win32Free); /// // Utils /// -internal s32 +internal s32 Win32StringLength(char* String) { char* At = String; @@ -82,7 +81,7 @@ Win32StringLength(char* String) return At - String; } -internal s32 +internal s32 Win32ConcatStrings(s32 ALength, char* A, s32 BLength, char* B, s32 DestLength, char* Dest) { char* Dst = Dest; @@ -110,7 +109,7 @@ Win32ConcatStrings(s32 ALength, char* A, s32 BLength, char* B, s32 DestLength, c /// internal window -Win32CreateWindow (HINSTANCE HInstance, char* WindowName, s32 Width, s32 Height, +Win32CreateWindow (HINSTANCE HInstance, char* WindowName, s32 Width, s32 Height, WNDPROC WindowEventHandler) { window Result = {}; @@ -131,14 +130,14 @@ Win32CreateWindow (HINSTANCE HInstance, char* WindowName, s32 Width, s32 Height, Result.Handle = CreateWindowEx( 0, Result.Class.lpszClassName, - WindowName, + WindowName, WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, 0, - 0, + 0, HInstance, 0); Result.DeviceContext = GetDC(Result.Handle); @@ -276,9 +275,9 @@ Win32HandleWindowsEvents ( ) { handle_window_event_result EventResult = HandleWindowEventUnlessWouldUseDefault( - WindowHandle, - Msg, - wParam, + WindowHandle, + Msg, + wParam, lParam); if (!EventResult.Handled) @@ -298,92 +297,92 @@ Win32GetKeyCode (int Win32VirtualKey, bool NumpadValid, bool TranslateToChar) if (!TranslateToChar) { - if (Win32VirtualKey == VK_SPACE) { Result = KeyCode_Space; } + if (Win32VirtualKey == VK_SPACE) { Result = KeyCode_Space; } } if (Win32VirtualKey == VK_CAPITAL) { Result = KeyCode_CapsLock; } else if (Win32VirtualKey == VK_TAB) { Result = KeyCode_Tab; } - else if (Win32VirtualKey == VK_LSHIFT) { Result = KeyCode_LeftShift; } + else if (Win32VirtualKey == VK_LSHIFT) { Result = KeyCode_LeftShift; } else if (Win32VirtualKey == VK_RSHIFT) { Result = KeyCode_RightShift; } - else if (Win32VirtualKey == VK_LCONTROL) { Result = KeyCode_LeftCtrl; } + else if (Win32VirtualKey == VK_LCONTROL) { Result = KeyCode_LeftCtrl; } else if (Win32VirtualKey == VK_RCONTROL) { Result = KeyCode_RightCtrl; } // TODO(Peter): support the function key? - //else if (Win32VirtualKey == VK_) { Result = KeyCode_Fn; } + //else if (Win32VirtualKey == VK_) { Result = KeyCode_Fn; } - else if (Win32VirtualKey == VK_MENU) { Result = KeyCode_Alt; } - else if (Win32VirtualKey == VK_PRIOR) { Result = KeyCode_PageUp; } + else if (Win32VirtualKey == VK_MENU) { Result = KeyCode_Alt; } + else if (Win32VirtualKey == VK_PRIOR) { Result = KeyCode_PageUp; } else if (Win32VirtualKey == VK_NEXT) { Result = KeyCode_PageDown; } - else if (Win32VirtualKey == VK_BACK) { Result = KeyCode_Backspace; } + else if (Win32VirtualKey == VK_BACK) { Result = KeyCode_Backspace; } else if (Win32VirtualKey == VK_DELETE) { Result = KeyCode_Delete; } else if (Win32VirtualKey == VK_RETURN) { Result = KeyCode_Enter; } - else if (Win32VirtualKey == VK_F1) { Result = KeyCode_F1; } - else if (Win32VirtualKey == VK_F2) { Result = KeyCode_F2; } - else if (Win32VirtualKey == VK_F3) { Result = KeyCode_F3; } - else if (Win32VirtualKey == VK_F4) { Result = KeyCode_F4; } - else if (Win32VirtualKey == VK_F5) { Result = KeyCode_F5; } - else if (Win32VirtualKey == VK_F6) { Result = KeyCode_F6; } + else if (Win32VirtualKey == VK_F1) { Result = KeyCode_F1; } + else if (Win32VirtualKey == VK_F2) { Result = KeyCode_F2; } + else if (Win32VirtualKey == VK_F3) { Result = KeyCode_F3; } + else if (Win32VirtualKey == VK_F4) { Result = KeyCode_F4; } + else if (Win32VirtualKey == VK_F5) { Result = KeyCode_F5; } + else if (Win32VirtualKey == VK_F6) { Result = KeyCode_F6; } else if (Win32VirtualKey == VK_F7) { Result = KeyCode_F7; } - else if (Win32VirtualKey == VK_F8) { Result = KeyCode_F8; } - else if (Win32VirtualKey == VK_F9) { Result = KeyCode_F9; } - else if (Win32VirtualKey == VK_F10) { Result = KeyCode_F10; } - else if (Win32VirtualKey == VK_F11) { Result = KeyCode_F11; } - else if (Win32VirtualKey == VK_F12) { Result = KeyCode_F12; } + else if (Win32VirtualKey == VK_F8) { Result = KeyCode_F8; } + else if (Win32VirtualKey == VK_F9) { Result = KeyCode_F9; } + else if (Win32VirtualKey == VK_F10) { Result = KeyCode_F10; } + else if (Win32VirtualKey == VK_F11) { Result = KeyCode_F11; } + else if (Win32VirtualKey == VK_F12) { Result = KeyCode_F12; } if (!TranslateToChar) { - if (Win32VirtualKey == 0x30) { Result = KeyCode_0; } - else if (Win32VirtualKey == 0x31) { Result = KeyCode_1; } - else if (Win32VirtualKey == 0x32) { Result = KeyCode_2; } - else if (Win32VirtualKey == 0x33) { Result = KeyCode_3; } - else if (Win32VirtualKey == 0x34) { Result = KeyCode_4; } - else if (Win32VirtualKey == 0x35) { Result = KeyCode_5; } - else if (Win32VirtualKey == 0x36) { Result = KeyCode_6; } + if (Win32VirtualKey == 0x30) { Result = KeyCode_0; } + else if (Win32VirtualKey == 0x31) { Result = KeyCode_1; } + else if (Win32VirtualKey == 0x32) { Result = KeyCode_2; } + else if (Win32VirtualKey == 0x33) { Result = KeyCode_3; } + else if (Win32VirtualKey == 0x34) { Result = KeyCode_4; } + else if (Win32VirtualKey == 0x35) { Result = KeyCode_5; } + else if (Win32VirtualKey == 0x36) { Result = KeyCode_6; } else if (Win32VirtualKey == 0x37) { Result = KeyCode_7; } - else if (Win32VirtualKey == 0x38) { Result = KeyCode_8; } + else if (Win32VirtualKey == 0x38) { Result = KeyCode_8; } else if (Win32VirtualKey == 0x39) { Result = KeyCode_9; } - else if (Win32VirtualKey == 0x41) { Result = KeyCode_A; } - else if (Win32VirtualKey == 0x42) { Result = KeyCode_B; } - else if (Win32VirtualKey == 0x43) { Result = KeyCode_C; } - else if (Win32VirtualKey == 0x44) { Result = KeyCode_D; } - else if (Win32VirtualKey == 0x45) { Result = KeyCode_E; } - else if (Win32VirtualKey == 0x46) { Result = KeyCode_F; } - else if (Win32VirtualKey == 0x47) { Result = KeyCode_G; } + else if (Win32VirtualKey == 0x41) { Result = KeyCode_A; } + else if (Win32VirtualKey == 0x42) { Result = KeyCode_B; } + else if (Win32VirtualKey == 0x43) { Result = KeyCode_C; } + else if (Win32VirtualKey == 0x44) { Result = KeyCode_D; } + else if (Win32VirtualKey == 0x45) { Result = KeyCode_E; } + else if (Win32VirtualKey == 0x46) { Result = KeyCode_F; } + else if (Win32VirtualKey == 0x47) { Result = KeyCode_G; } else if (Win32VirtualKey == 0x48) { Result = KeyCode_H; } - else if (Win32VirtualKey == 0x49) { Result = KeyCode_I; } - else if (Win32VirtualKey == 0x4A) { Result = KeyCode_J; } - else if (Win32VirtualKey == 0x4B) { Result = KeyCode_K; } - else if (Win32VirtualKey == 0x4C) { Result = KeyCode_L; } - else if (Win32VirtualKey == 0x4D) { Result = KeyCode_M; } - else if (Win32VirtualKey == 0x4E) { Result = KeyCode_N; } - else if (Win32VirtualKey == 0x4F) { Result = KeyCode_O; } - else if (Win32VirtualKey == 0x50) { Result = KeyCode_P; } - else if (Win32VirtualKey == 0x51) { Result = KeyCode_Q; } - else if (Win32VirtualKey == 0x52) { Result = KeyCode_R; } - else if (Win32VirtualKey == 0x53) { Result = KeyCode_S; } - else if (Win32VirtualKey == 0x54) { Result = KeyCode_T; } - else if (Win32VirtualKey == 0x55) { Result = KeyCode_U; } - else if (Win32VirtualKey == 0x56) { Result = KeyCode_V; } - else if (Win32VirtualKey == 0x57) { Result = KeyCode_W; } - else if (Win32VirtualKey == 0x58) { Result = KeyCode_X; } - else if (Win32VirtualKey == 0x59) { Result = KeyCode_Y; } + else if (Win32VirtualKey == 0x49) { Result = KeyCode_I; } + else if (Win32VirtualKey == 0x4A) { Result = KeyCode_J; } + else if (Win32VirtualKey == 0x4B) { Result = KeyCode_K; } + else if (Win32VirtualKey == 0x4C) { Result = KeyCode_L; } + else if (Win32VirtualKey == 0x4D) { Result = KeyCode_M; } + else if (Win32VirtualKey == 0x4E) { Result = KeyCode_N; } + else if (Win32VirtualKey == 0x4F) { Result = KeyCode_O; } + else if (Win32VirtualKey == 0x50) { Result = KeyCode_P; } + else if (Win32VirtualKey == 0x51) { Result = KeyCode_Q; } + else if (Win32VirtualKey == 0x52) { Result = KeyCode_R; } + else if (Win32VirtualKey == 0x53) { Result = KeyCode_S; } + else if (Win32VirtualKey == 0x54) { Result = KeyCode_T; } + else if (Win32VirtualKey == 0x55) { Result = KeyCode_U; } + else if (Win32VirtualKey == 0x56) { Result = KeyCode_V; } + else if (Win32VirtualKey == 0x57) { Result = KeyCode_W; } + else if (Win32VirtualKey == 0x58) { Result = KeyCode_X; } + else if (Win32VirtualKey == 0x59) { Result = KeyCode_Y; } else if (Win32VirtualKey == 0x5A) { Result = KeyCode_Z; } } if (NumpadValid) { - if (Win32VirtualKey == VK_NUMPAD0) { Result = KeyCode_Num0; } - else if (Win32VirtualKey == VK_NUMPAD1) { Result = KeyCode_Num1; } - else if (Win32VirtualKey == VK_NUMPAD2) { Result = KeyCode_Num2; } - else if (Win32VirtualKey == VK_NUMPAD3) { Result = KeyCode_Num3; } - else if (Win32VirtualKey == VK_NUMPAD4) { Result = KeyCode_Num4; } - else if (Win32VirtualKey == VK_NUMPAD5) { Result = KeyCode_Num5; } - else if (Win32VirtualKey == VK_NUMPAD6) { Result = KeyCode_Num6; } - else if (Win32VirtualKey == VK_NUMPAD7) { Result = KeyCode_Num7; } - else if (Win32VirtualKey == VK_NUMPAD8) { Result = KeyCode_Num8; } + if (Win32VirtualKey == VK_NUMPAD0) { Result = KeyCode_Num0; } + else if (Win32VirtualKey == VK_NUMPAD1) { Result = KeyCode_Num1; } + else if (Win32VirtualKey == VK_NUMPAD2) { Result = KeyCode_Num2; } + else if (Win32VirtualKey == VK_NUMPAD3) { Result = KeyCode_Num3; } + else if (Win32VirtualKey == VK_NUMPAD4) { Result = KeyCode_Num4; } + else if (Win32VirtualKey == VK_NUMPAD5) { Result = KeyCode_Num5; } + else if (Win32VirtualKey == VK_NUMPAD6) { Result = KeyCode_Num6; } + else if (Win32VirtualKey == VK_NUMPAD7) { Result = KeyCode_Num7; } + else if (Win32VirtualKey == VK_NUMPAD8) { Result = KeyCode_Num8; } else if (Win32VirtualKey == VK_NUMPAD9) { Result = KeyCode_Num9; } } @@ -501,14 +500,14 @@ HandleWindowsMessage ( // NOTE(Peter): Always setting this to true becuase windows is stupid and doesn't // pass the press/release bit through correctly. So now the KEYDOWN/KEYUP Messages above // only translate the message to a WM_CHAR message if its a key down. Since we clear all - // keystates to false at the beginning of an input frame, this will make transitions + // keystates to false at the beginning of an input frame, this will make transitions // get registered correctly. Input.New->KeyStates[KeyIndex] = true; Result.NeedsUpdate = true; } else { - printf("Translated Char Not Recognized: %c\n", TranslatedChar); + printf("Translated Char Not Recognized: %c\n", TranslatedChar); } */ }break; @@ -570,14 +569,14 @@ Win32DisplayBufferInWindow(win32_offscreen_buffer* Win32Buffer, window Window) } ///////////////////////////////////////// -// +// // Open GL // ///////////////////////////////////////// -internal void -OpenGLRenderTriBuffer (u8* Vertecies, s32 VertexElements, +internal void +OpenGLRenderTriBuffer (u8* Vertecies, s32 VertexElements, u8* UVs, s32 UVElements, u8* Colors, s32 ColorsElements, s32 TriCount) @@ -599,7 +598,7 @@ OpenGLRenderTriBuffer (u8* Vertecies, s32 VertexElements, } internal void -OpenGLDraw3DTri (v4 P0, v4 P1, v4 P2, +OpenGLDraw3DTri (v4 P0, v4 P1, v4 P2, v2 UV0, v2 UV1, v2 UV2, v4 C0, v4 C1, v4 C2) { @@ -621,7 +620,7 @@ OpenGLDraw3DTri (v4 P0, v4 P1, v4 P2, } internal void -OpenGLDraw2DTri (v2 P0, v2 P1, v2 P2, +OpenGLDraw2DTri (v2 P0, v2 P1, v2 P2, v2 UV0, v2 UV1, v2 UV2, v4 C0, v4 C1, v4 C2) { @@ -668,14 +667,14 @@ SubmitTexture (u8* Memory, s32 Width, s32 Height) { s32 TextureHandle = NextTextureHandle++; glBindTexture(GL_TEXTURE_2D, TextureHandle); - glTexImage2D(GL_TEXTURE_2D, + glTexImage2D(GL_TEXTURE_2D, 0, // mip map level - GL_RGBA8, - Width, - Height, + GL_RGBA8, + Width, + Height, 0, // border - GL_RGBA, - GL_UNSIGNED_BYTE, + GL_RGBA, + GL_UNSIGNED_BYTE, Memory); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); diff --git a/src/meta/foldhaus_meta.cpp b/src/meta/foldhaus_meta.cpp index 90e9544..f298f2d 100644 --- a/src/meta/foldhaus_meta.cpp +++ b/src/meta/foldhaus_meta.cpp @@ -218,14 +218,14 @@ GeneratePanelMetaInfo(gs_meta_preprocessor Meta, string_builder* PanelEnumGen, s } WriteF(PanelEnumGen, "enum panel_type {\n"); - WriteF(PanelCodeGen, "global_variable s32 GlobalPanelDefsCount = %d;\n", Panels.Used); - WriteF(PanelCodeGen, "global_variable panel_definition GlobalPanelDefs[] = {\n"); + WriteF(PanelCodeGen, "global s32 GlobalPanelDefsCount = %d;\n", Panels.Used); + WriteF(PanelCodeGen, "global panel_definition GlobalPanelDefs[] = {\n"); for (u32 i = 0; i < Panels.Used; i++) { panel_elements* Panel = Panels.GetElementAtIndex(i); string PanelIdentifier = {0}; PanelIdentifier.Max = Panel->PanelIdentifier.Length; - PanelIdentifier.Memory = PushArray(&Meta.Permanent, char, PanelIdentifier.Max); + PanelIdentifier.Memory = (char*)malloc(sizeof(char) * PanelIdentifier.Max); CopyStringTo(Substring(Panel->PanelIdentifier, 11), &PanelIdentifier); MakeReadableIdentifier(&PanelIdentifier); @@ -259,11 +259,11 @@ GeneratePanelMetaInfo(gs_meta_preprocessor Meta, string_builder* PanelEnumGen, s } internal string -AllocAndConcatStrings(base_allocator Allocator, string First, string Second) +AllocAndConcatStrings(string First, string Second) { string Result = {0}; Result.Max = First.Length + Second.Length + 1; - Result.Memory = AllocatorAllocArray(Allocator, char, Result.Max); + Result.Memory = (char*)malloc(sizeof(char) * Result.Max); ConcatString(First, &Result); ConcatString(Second, &Result); NullTerminate(&Result); @@ -271,26 +271,6 @@ AllocAndConcatStrings(base_allocator Allocator, string First, string Second) return Result; } -u64 TotalAllocatedSpace = 0; - -internal data -PlatformAlloc(u64 Size) -{ - data Result = {0}; - Result.Memory = (u8*)malloc(Size); - Result.Size = Size; - - TotalAllocatedSpace += Size; - - return Result; -} - -internal void -PlatformFree(u8* Base, u64 Size) -{ - free((void*)Base); -} - int main(int ArgCount, char* Args[]) { if (ArgCount <= 1) @@ -299,30 +279,22 @@ int main(int ArgCount, char* Args[]) return 0; } - base_allocator Allocator = {0}; - Allocator.Alloc = (allocator_alloc*)PlatformAlloc; - Allocator.Free = (allocator_free*)PlatformFree; - - GlobalDebugServices.Arena = CreateMemoryArena(Allocator); - GlobalDebugServices.Transient = CreateMemoryArena(Allocator); - GlobalDebugServices.ShouldProfile = true; - string RootFile = MakeString(Args[1]); s32 IndexOfLastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); string WorkingDirectory = Substring(RootFile, 0, IndexOfLastSlash + 1); string GeneratedDirectoryName = MakeStringLiteral("generated\\"); - string GeneratedFilesDirectory = AllocAndConcatStrings(Allocator, WorkingDirectory, GeneratedDirectoryName); + string GeneratedFilesDirectory = AllocAndConcatStrings(WorkingDirectory, GeneratedDirectoryName); printf("Putting Generated Files In %s\n", GeneratedFilesDirectory.Memory); - gs_meta_preprocessor Meta = PreprocessProgram(Allocator, Args[1]); + gs_meta_preprocessor Meta = PreprocessProgram(Args[1]); - typeinfo_generator TypeGenerator = InitTypeInfoGenerator(&Meta.TypeTable); + typeinfo_generator TypeGenerator = InitTypeInfoGenerator(Meta.TypeTable); GenerateMetaTagList(Meta.TypeTable, &TypeGenerator); GenerateFilteredTypeInfo(MakeStringLiteral("node_struct"), Meta.TypeTable, &TypeGenerator); GenerateFilteredTypeInfo(MakeStringLiteral("gen_type_info"), Meta.TypeTable, &TypeGenerator); FinishGeneratingTypes(&TypeGenerator); - gsm_code_generator NodeTypeGen = BeginEnumGeneration(&Meta.TypeTable.Arena, "node_type", "NodeType", false, true); + gsm_code_generator NodeTypeGen = BeginEnumGeneration("node_type", "NodeType", false, true); string_builder NodeSpecificationGen = {0}; string_builder CallNodeProcGen = {0}; GenerateNodeMetaInfo(&NodeTypeGen, &NodeSpecificationGen, &CallNodeProcGen, Meta); @@ -331,7 +303,7 @@ int main(int ArgCount, char* Args[]) string_builder PanelCodeGen = {0}; GeneratePanelMetaInfo(Meta, &PanelEnumGen, &PanelCodeGen); - string TypeInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("gs_meta_generated_typeinfo.h")); + string TypeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("gs_meta_generated_typeinfo.h")); FILE* TypeInfoH = fopen(TypeInfoHFilePath.Memory, "w"); if (TypeInfoH) { @@ -347,7 +319,7 @@ int main(int ArgCount, char* Args[]) printf("Error: Unable to open file at %.*s\n", StringExpand(TypeInfoHFilePath)); } - string NodeInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("foldhaus_nodes_generated.h")); + string NodeInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_nodes_generated.h")); FILE* NodeInfoH = fopen(NodeInfoHFilePath.Memory, "w"); if (NodeInfoH) { @@ -361,7 +333,7 @@ int main(int ArgCount, char* Args[]) printf("Error: Unable to open file at %.*s\n", StringExpand(NodeInfoHFilePath)); } - string PanelInfoHFilePath = AllocAndConcatStrings(Allocator, GeneratedFilesDirectory, MakeStringLiteral("foldhaus_panels_generated.h")); + string PanelInfoHFilePath = AllocAndConcatStrings(GeneratedFilesDirectory, MakeStringLiteral("foldhaus_panels_generated.h")); FILE* PanelInfoH = fopen(PanelInfoHFilePath.Memory, "w"); if (PanelInfoH) { @@ -376,10 +348,6 @@ int main(int ArgCount, char* Args[]) FinishMetaprogram(&Meta); - r64 AllocatedMegabytes = (r64)TotalAllocatedSpace / (1024 * 1024); - printf("Total Allocated Space: %lld bytes, or %f MB\n", TotalAllocatedSpace, AllocatedMegabytes); - - //__debugbreak(); return 0; } diff --git a/src/meta/gs_meta.cpp b/src/meta/gs_meta.cpp index eb241c2..36c406a 100644 --- a/src/meta/gs_meta.cpp +++ b/src/meta/gs_meta.cpp @@ -9,8 +9,8 @@ // GSMetaTag() to give commands to the meta layer // // Tag Values -// -// breakpoint +// +// breakpoint // will cause the meta layer to break in the debugger when it reaches // that point in processing the file // TODO: specify which stage you want it to break at @@ -21,40 +21,40 @@ #include #include "..\gs_libs\gs_language.h" -#include "..\gs_libs\gs_radix_sort.h" #include "..\gs_libs\gs_bucket.h" #include "..\gs_libs\gs_memory_arena.h" -#include "..\gs_libs\gs_profiler.h" #include "..\gs_libs\gs_string.h" -global_variable u64 TokenHash_GSMetaTag = HashDJB2ToU64("GSMetaTag"); -global_variable u64 TokenHash_OpenParen = HashDJB2ToU64("("); -global_variable u64 TokenHash_CloseParen = HashDJB2ToU64(")"); -global_variable u64 TokenHash_Semicolon = HashDJB2ToU64(";"); -global_variable u64 TokenHash_Unsigned = HashDJB2ToU64("unsigned"); -global_variable u64 TokenHash_Signed = HashDJB2ToU64("signed"); -global_variable u64 TokenHash_Short = HashDJB2ToU64("short"); -global_variable u64 TokenHash_Int = HashDJB2ToU64("int"); -global_variable u64 TokenHash_Long = HashDJB2ToU64("long"); -global_variable u64 TokenHash_Char = HashDJB2ToU64("char"); -global_variable u64 TokenHash_WCharT = HashDJB2ToU64("wchar_t"); -global_variable u64 TokenHash_Bool = HashDJB2ToU64("bool"); -global_variable u64 TokenHash_Float = HashDJB2ToU64("float"); -global_variable u64 TokenHash_Double = HashDJB2ToU64("double"); -global_variable u64 TokenHash_Star = HashDJB2ToU64("*"); -global_variable u64 TokenHash_Volatile = HashDJB2ToU64("volatile"); -global_variable u64 TokenHash_Const = HashDJB2ToU64("const"); -global_variable u64 TokenHash_OpenSquareBracket = HashDJB2ToU64("["); -global_variable u64 TokenHash_CloseSquareBracket = HashDJB2ToU64("]"); -global_variable u64 TokenHash_Comma = HashDJB2ToU64(","); -global_variable u64 TokenHash_Struct = HashDJB2ToU64("struct"); -global_variable u64 TokenHash_Union = HashDJB2ToU64("union"); -global_variable u64 TokenHash_OpenCurlyBracket = HashDJB2ToU64("{"); -global_variable u64 TokenHash_CloseCurlyBracket = HashDJB2ToU64("}"); -global_variable u64 TokenHash_Typedef = HashDJB2ToU64("typedef"); -global_variable u64 TokenHash_Enum = HashDJB2ToU64("enum"); -global_variable u64 TokenHash_Equals = HashDJB2ToU64("="); +#include "gs_meta_lexer.h" +#include "gs_meta_error.h" + +#include "gs_meta_type_table.h" + +struct source_code_file +{ + string Path; + s32 FileSize; + string Contents; + + s32 FirstTokenIndex; + s32 LastTokenIndex; +}; + +struct token_iter +{ + gs_bucket* Tokens; + token* TokenAt; + s32 TokenAtIndex; + s32 FirstToken; + s32 LastToken; + +#define TOKEN_ITER_SNAPSHOTS_MAX 64 + u32 SnapshotsUsed; + u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX]; + + errors* Errors; +}; struct gsm_profiler_scope { @@ -81,10 +81,31 @@ struct gsm_profiler gs_bucket Categories; }; +struct gs_meta_preprocessor +{ + errors Errors; + + gs_bucket SourceFiles; + gs_bucket Tokens; + + gs_bucket TagList; + + type_table TypeTable; + + // Performance + s64 PreprocessorStartTime; + s64 TokenizeTime; + s64 PreprocTime; + s64 FixupTime; + s64 PreprocessorEndTime; + + gsm_profiler Profiler; +}; + // ------------------------ // Timing / Performance // ------------------------ -#if 0 + internal s64 GetWallClock () { @@ -98,7 +119,7 @@ GetWallClock () } return (s64)Time.QuadPart; } -#endif + internal s64 GetPerformanceFrequency () { @@ -253,63 +274,6 @@ PrintAllCategories(gsm_profiler* Profiler) } } -#include "gs_meta_lexer.h" -#include "gs_meta_error.h" - -#include "gs_meta_type_table.h" - -struct token_array -{ - token* List; - u32 Count; -}; - -struct source_code_file -{ - string Path; - s32 FileSize; - string Contents; - - token_array Tokens; -}; - -struct token_iter -{ - token_array Tokens; - token* TokenAt; - u32 TokenAtIndex; - -#define TOKEN_ITER_SNAPSHOTS_MAX 64 - u32 SnapshotsUsed; - u32 Snapshots[TOKEN_ITER_SNAPSHOTS_MAX]; - - errors* Errors; -}; - -struct gs_meta_preprocessor -{ - memory_arena Permanent; - memory_arena Transient; - - errors Errors; - - gs_bucket SourceFiles; - //gs_bucket Tokens; - - gs_bucket TagList; - - type_table TypeTable; - - // Performance - s64 PreprocessorStartTime; - s64 TokenizeTime; - s64 PreprocTime; - s64 FixupTime; - s64 PreprocessorEndTime; - - gsm_profiler Profiler; -}; - // ------------------------ // Token Iterator // ------------------------ @@ -317,10 +281,10 @@ struct gs_meta_preprocessor internal token* NextToken (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; - if (Iter->TokenAtIndex < Iter->Tokens.Count) + if (Iter->TokenAtIndex < Iter->LastToken) { - Iter->TokenAt = Iter->Tokens.List + Iter->TokenAtIndex++; + Iter->TokenAtIndex++; + Iter->TokenAt = Iter->Tokens->GetElementAtIndex(Iter->TokenAtIndex); } return Iter->TokenAt; @@ -329,7 +293,6 @@ NextToken (token_iter* Iter) internal b32 TokenAtEquals(token_iter* Iter, char* String) { - DEBUG_TRACK_FUNCTION; b32 Result = false; if (StringEqualsCharArray(Iter->TokenAt->Text, String)) { @@ -339,23 +302,9 @@ TokenAtEquals(token_iter* Iter, char* String) return Result; } -internal b32 -TokenAtHashEquals(token_iter* Iter, u64 Hash) -{ - DEBUG_TRACK_FUNCTION; - b32 Result = false; - if (Hash == Iter->TokenAt->TextHash) - { - Result = true; - NextToken(Iter); - } - return Result; -} - internal b32 TokenAtEquals(token_iter* Iter, token_type Type) { - DEBUG_TRACK_FUNCTION; b32 Result = false; if (Iter->TokenAt->Type == Type) { @@ -368,7 +317,6 @@ TokenAtEquals(token_iter* Iter, token_type Type) internal b32 TokenAtEquals(token_iter* Iter, token_type Type, token* Token) { - DEBUG_TRACK_FUNCTION; b32 Result = false; if (Iter->TokenAt->Type == Type) { @@ -382,14 +330,12 @@ TokenAtEquals(token_iter* Iter, token_type Type, token* Token) internal void PushSnapshot (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; Iter->Snapshots[Iter->SnapshotsUsed++] = Iter->TokenAtIndex; } internal void PopSnapshot (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; if (Iter->SnapshotsUsed > 0) { Iter->SnapshotsUsed -= 1; @@ -399,17 +345,15 @@ PopSnapshot (token_iter* Iter) internal void ApplySnapshot (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; u32 SnapshotIndex = Iter->SnapshotsUsed; u32 SnapshotPoint = Iter->Snapshots[SnapshotIndex]; Iter->TokenAtIndex = SnapshotPoint; - Iter->TokenAt = Iter->Tokens.List + Iter->TokenAtIndex; + Iter->TokenAt = Iter->Tokens->GetElementAtIndex(SnapshotPoint); } internal void ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter) { - DEBUG_TRACK_FUNCTION; PopSnapshot(Iter); if (!ParseSuccess) { @@ -421,7 +365,6 @@ ApplySnapshotIfNotParsedAndPop(b32 ParseSuccess, token_iter* Iter) internal s32 GetFileSize (char* FileName) { - DEBUG_TRACK_FUNCTION; s32 Result = 0; FILE* ReadFile = fopen(FileName, "r"); @@ -443,9 +386,8 @@ GetFileSize (char* FileName) // ------------------------- internal s32 -ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, errors* Errors) +ReadEntireFileAndNullTerminate (source_code_file* File, errors* Errors) { - DEBUG_TRACK_FUNCTION; s32 LengthRead = 0; FILE* ReadFile = fopen(File->Path.Memory, "r"); @@ -457,7 +399,7 @@ ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, e Assert(File->Contents.Memory == 0); File->Contents.Max = (s32)FileSize + 1; - File->Contents.Memory = (char*)PushSize(Storage, File->Contents.Max); + File->Contents.Memory = (char*)malloc(File->Contents.Max); size_t ReadSize = fread(File->Contents.Memory, 1, FileSize, ReadFile); File->Contents.Memory[FileSize] = 0; @@ -473,7 +415,6 @@ ReadEntireFileAndNullTerminate (memory_arena* Storage, source_code_file* File, e internal b32 FileAlreadyInSource(string Path, gs_bucket SourceFiles) { - DEBUG_TRACK_FUNCTION; b32 Result = false; for (u32 i = 0; i < SourceFiles.Used; i++) @@ -490,18 +431,19 @@ FileAlreadyInSource(string Path, gs_bucket SourceFiles) } internal void -AddFileToSource(memory_arena* Storage, string RelativePath, source_code_file CurrentFile, gs_bucket* SourceFiles, errors* Errors) +AddFileToSource(string RelativePath, source_code_file CurrentFile, gs_bucket* SourceFiles, errors* Errors) { - DEBUG_TRACK_FUNCTION; source_code_file File = {0}; + File.FirstTokenIndex = -1; + File.LastTokenIndex = -1; + u32 PathLength = RelativePath.Length + 1; - char* PathData = PushArray(Storage, char, PathLength); - File.Path = MakeString(PathData, 0, PathLength); + File.Path = MakeString((char*)malloc(sizeof(char) * PathLength), 0, PathLength); CopyStringTo(RelativePath, &File.Path); NullTerminate(&File.Path); - File.FileSize = ReadEntireFileAndNullTerminate(Storage, &File, Errors); + File.FileSize = ReadEntireFileAndNullTerminate(&File, Errors); if (File.FileSize > 0) { @@ -518,21 +460,8 @@ AddFileToSource(memory_arena* Storage, string RelativePath, source_code_file Cur } internal void -TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File) +TokenizeFile (source_code_file* File, gs_bucket* Tokens) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* Scope = BeginScope(&Meta->Profiler, MakeStringLiteral("tokenize"), File->Path); - - struct token_list - { - token Token; - token_list* Next; - }; - - u32 TokensCount = 0; - token_list* TokensHead = 0; - token_list* TokensTail = 0; - tokenizer Tokenizer = {}; Tokenizer.At = File->Contents.Memory; Tokenizer.Memory = File->Contents.Memory; @@ -541,35 +470,15 @@ TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File) token* LastToken = 0; while(AtValidPosition(Tokenizer)) { - token_list* NewToken = PushStruct(&Meta->Transient, token_list); - NewToken->Token = GetNextToken(&Tokenizer); - NewToken->Next = 0; - - TokensCount++; - if (TokensHead != 0) + token NewToken = GetNextToken(&Tokenizer); + u32 TokenIndex = Tokens->PushElementOnBucket(NewToken); + if (File->FirstTokenIndex < 0) { - TokensTail->Next = NewToken; - TokensTail = NewToken; - } - else - { - TokensHead = NewToken; - TokensTail = NewToken; + File->FirstTokenIndex = (s32)TokenIndex; } } - File->Tokens = {0}; - File->Tokens.Count = TokensCount; - File->Tokens.List = PushArray(&Meta->Permanent, token, File->Tokens.Count); - - token_list* At = TokensHead; - for (u32 i = 0; i < TokensCount; i++) - { - Assert(At != 0); - File->Tokens.List[i] = At->Token; - At = At->Next; - } - EndScope(Scope); + File->LastTokenIndex = Tokens->Used - 1; } // ------------------------ @@ -579,21 +488,20 @@ TokenizeFile (gs_meta_preprocessor* Meta, source_code_file* File) internal b32 ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseMetaTag")); b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_GSMetaTag) && - TokenAtHashEquals(Iter, TokenHash_OpenParen)) + if (TokenAtEquals(Iter, "GSMetaTag") && + TokenAtEquals(Iter, "(")) { token MetaIdentifier = {0}; if (TokenAtEquals(Iter, Token_Identifier, &MetaIdentifier)) { - if (TokenAtHashEquals(Iter, TokenHash_OpenParen) && - TokenAtHashEquals(Iter, TokenHash_Semicolon)) + if (TokenAtEquals(Iter, ")") && + TokenAtEquals(Iter, ";")) { Result = true; type_table_handle MetaTagHandle = GetMetaTagHandle(MetaIdentifier.Text, Meta->TypeTable); @@ -609,7 +517,7 @@ ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta) if (StringsEqual(MetaIdentifier.Text, MakeStringLiteral("breakpoint"))) { - // NOTE(Peter): This is not a temporary breakpoint. It is + // NOTE(Peter): This is not a temporary breakpoint. It is // used to be able to break the meta program at specific points // throughout execution __debugbreak(); @@ -626,15 +534,14 @@ ParseMetaTag(token_iter* Iter, gs_meta_preprocessor* Meta) internal b32 ParseSignedness (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; - // NOTE(Peter): This doesn't really do much at the moment, but + // NOTE(Peter): This doesn't really do much at the moment, but // I want all signedness parsing to happen in one place in case // we ever need to do anything with it. b32 Result = false; - if (TokenAtHashEquals(Iter, TokenHash_Unsigned) || - TokenAtHashEquals(Iter, TokenHash_Signed)) + if (TokenAtEquals(Iter, "unsigned") || + TokenAtEquals(Iter, "signed")) { Result = true; } @@ -645,23 +552,22 @@ ParseSignedness (token_iter* Iter) internal b32 ShortInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); ParseSignedness(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Short)) + if (TokenAtEquals(Iter, "short")) { Result = true; - if (TokenAtHashEquals(Iter, TokenHash_Int)) + if (TokenAtEquals(Iter, "int")) { Result = true; } } ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { + if (Result) + { *TypeHandleOut = GetTypeHandle(MakeStringLiteral("short int"), TypeTable); } return Result; @@ -670,19 +576,18 @@ ShortInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab internal b32 Int (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); ParseSignedness(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Int)) + if (TokenAtEquals(Iter, "int")) { Result = true; } ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { + if (Result) + { *TypeHandleOut = GetTypeHandle(MakeStringLiteral("int"), TypeTable); } return Result; @@ -691,23 +596,22 @@ Int (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) internal b32 LongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); ParseSignedness(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Long)) + if (TokenAtEquals(Iter, "long")) { Result = true; - if (TokenAtHashEquals(Iter, TokenHash_Int)) + if (TokenAtEquals(Iter, "int")) { Result = true; } } ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { + if (Result) + { *TypeHandleOut = GetTypeHandle(MakeStringLiteral("long int"), TypeTable); } return Result; @@ -716,17 +620,16 @@ LongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTabl internal b32 LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); ParseSignedness(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Long)) + if (TokenAtEquals(Iter, "long")) { - if (TokenAtHashEquals(Iter, TokenHash_Long)) + if (TokenAtEquals(Iter, "long")) { Result = true; - if (TokenAtHashEquals(Iter, TokenHash_Int)) + if (TokenAtEquals(Iter, "int")) { Result = true; } @@ -734,8 +637,8 @@ LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table Type } ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (Result) - { + if (Result) + { *TypeHandleOut = GetTypeHandle(MakeStringLiteral("long long int"), TypeTable); } return Result; @@ -744,17 +647,16 @@ LongLongInt (token_iter* Iter, type_table_handle* TypeHandleOut, type_table Type internal b32 ParseChar(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); ParseSignedness(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Char)) + if (TokenAtEquals(Iter, "char")) { Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("char"), TypeTable); } - else if (TokenAtHashEquals(Iter, TokenHash_WCharT)) + else if (TokenAtEquals(Iter, "wchar_t")) { Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("wchar_t"), TypeTable); @@ -767,11 +669,10 @@ ParseChar(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab internal b32 ParseBool(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Bool)) + if (TokenAtEquals(Iter, "bool")) { Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("bool"), TypeTable); @@ -784,11 +685,10 @@ ParseBool(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTab internal b32 ParseFloat(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Float)) + if (TokenAtEquals(Iter, "float")) { Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("float"), TypeTable); @@ -801,11 +701,10 @@ ParseFloat(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTa internal b32 ParseDouble(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Double)) + if (TokenAtEquals(Iter, "double")) { Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("double"), TypeTable); @@ -821,8 +720,7 @@ ParseDouble(token_iter* Iter, type_table_handle* TypeHandleOut, type_table TypeT internal b32 ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeHandleOut) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseType")); b32 Result = false; @@ -839,16 +737,16 @@ ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeH ParseDouble(Iter, TypeHandleOut, Meta->TypeTable)) { Result = true; - } + } else if (StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("void"))) { NextToken(Iter); Result = true; *TypeHandleOut = GetTypeHandle(MakeStringLiteral("void"), Meta->TypeTable); } - else + else { - gsm_profiler_scope* ProfileInnerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfileInnerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseTypeInner")); @@ -862,9 +760,9 @@ ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeH { Result = true; // NOTE(Peter): In this case, we believe we are at a type identifier, - // however, it hasn't been declared yet. This is due to the fact that we + // however, it hasn't been declared yet. This is due to the fact that we // tokenize files, then parse them, then import the files they include, and - // then begin tokenizing, parsing, etc for those files. + // then begin tokenizing, parsing, etc for those files. // In the case that we get an as-of-yet undeclared type, we leave it // up to the calling site to determine what to do with that information // :UndeclaredType @@ -882,9 +780,8 @@ ParseType(token_iter* Iter, gs_meta_preprocessor* Meta, type_table_handle* TypeH internal b32 ParsePointer (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; b32 Result = false; - if (TokenAtHashEquals(Iter, TokenHash_Star)) + if (TokenAtEquals(Iter, "*")) { Result = true; } @@ -894,12 +791,11 @@ ParsePointer (token_iter* Iter) internal b32 ParseConstVolatile (token_iter* Iter) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Volatile) || - TokenAtHashEquals(Iter, TokenHash_Const)) + if (TokenAtEquals(Iter, "volatile") || + TokenAtEquals(Iter, "const")) { Result = true; } @@ -911,8 +807,7 @@ ParseConstVolatile (token_iter* Iter) internal b32 ParseVariableDecl(token_iter* Iter, gs_bucket* VariableList, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseVariableDecl")); b32 Result = false; @@ -947,14 +842,14 @@ ParseVariableDecl(token_iter* Iter, gs_bucket* VariableList, gs_m if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) { // Array Notationg ie r32 x[2]; - // NOTE(Peter): True initially because if there is no array notation, we + // NOTE(Peter): True initially because if there is no array notation, we // are still ok to proceed b32 ArrayParseSuccess = true; u32 ArrayCount = 0; - if (TokenAtHashEquals(Iter, TokenHash_OpenSquareBracket)) + if (TokenAtEquals(Iter, "[")) { // NOTE(Peter): Once we get to this point, we have to complete the entire - // array notation before we have successfully parsed, hence setting + // array notation before we have successfully parsed, hence setting // ArrayParseSucces to false here. ArrayParseSuccess = false; token NumberToken = {}; @@ -972,7 +867,7 @@ ParseVariableDecl(token_iter* Iter, gs_bucket* VariableList, gs_m } } - if (TokenAtHashEquals(Iter, TokenHash_CloseSquareBracket)) + if (TokenAtEquals(Iter, "]")) { ArrayParseSuccess = true; } @@ -1010,7 +905,7 @@ ParseVariableDecl(token_iter* Iter, gs_bucket* VariableList, gs_m PushSnapshot(Iter); if (TokenAtEquals(Iter, Token_Identifier) && - (TokenAtHashEquals(Iter, TokenHash_Comma) || TokenAtHashEquals(Iter, TokenHash_Semicolon))) + (TokenAtEquals(Iter, ",") || TokenAtEquals(Iter, ";"))) { // We are in a declaration list (case 1) ApplySnapshotIfNotParsedAndPop(false, Iter); @@ -1039,14 +934,13 @@ ParseVariableDecl(token_iter* Iter, gs_bucket* VariableList, gs_m internal b32 StructOrUnion(token_iter* Iter, type_definition_type* Type) { - DEBUG_TRACK_FUNCTION; b32 Result = false; - if (TokenAtHashEquals(Iter, TokenHash_Struct)) + if (TokenAtEquals(Iter, "struct")) { Result = true; *Type = TypeDef_Struct; } - else if (TokenAtHashEquals(Iter, TokenHash_Union)) + else if (TokenAtEquals(Iter, "union")) { Result = true; *Type = TypeDef_Union; @@ -1060,8 +954,7 @@ StructOrUnion(token_iter* Iter, type_definition_type* Type) internal b32 ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_preprocessor* Meta, type_definition* ContainingStruct = 0) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseStruct")); b32 Result = false; @@ -1076,7 +969,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) {} // TODO(Peter): Handle name coming after the struct - if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket)) + if (TokenAtEquals(Iter, "{")) { type_definition StructDecl = {}; if (IdentifierToken.Text.Length > 0) @@ -1095,7 +988,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr string AnonStructIdentifier = {}; AnonStructIdentifier.Max = 256; - AnonStructIdentifier.Memory = PushArray(&Meta->Permanent, char, AnonStructIdentifier.Max); + AnonStructIdentifier.Memory = (char*)malloc(sizeof(char) * AnonStructIdentifier.Max); PrintF(&AnonStructIdentifier, "%S_%d", ContainingStruct->Identifier, ContainingStruct->Struct.MemberDecls.Used); @@ -1106,7 +999,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr StructDecl.Type = DeclType; CopyMetaTagsAndClear(&Meta->TagList, &StructDecl.MetaTags); - while (!TokenAtHashEquals(Iter, TokenHash_CloseCurlyBracket)) + while (!TokenAtEquals(Iter, "}")) { type_table_handle MemberStructTypeHandle = InvalidTypeTableHandle; variable_decl MemberDecl = {}; @@ -1116,7 +1009,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr } else if (ParseVariableDecl(Iter, &StructDecl.Struct.MemberDecls, Meta)) { - if (!TokenAtHashEquals(Iter, TokenHash_Semicolon)) + if (!TokenAtEquals(Iter, ";")) { PushFError(Iter->Errors, "No semicolon after struct member variable declaration. %S", StructDecl.Identifier); } @@ -1124,11 +1017,11 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr else if (ParseStruct(Iter, &MemberStructTypeHandle, Meta, &StructDecl)) { // NOTE(Peter): Pretty sure, since we just parsed the struct, that - // MemberStructTypeIndex should never be Invalid (unknown type). + // MemberStructTypeIndex should never be Invalid (unknown type). // Putting this Assert here for now, but remove if there's a valid // reason that you might not be able to find a struct just parsed at // this point. - Assert(TypeHandleIsValid(MemberStructTypeHandle)); + Assert(TypeHandleIsValid(MemberStructTypeHandle)); MemberDecl.TypeHandle = MemberStructTypeHandle; StructDecl.Struct.MemberDecls.PushElementOnBucket(MemberDecl); @@ -1143,7 +1036,7 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr } } - if (TokenAtHashEquals(Iter, TokenHash_Semicolon)) + if (TokenAtEquals(Iter, ";")) { Result = true; *StructTypeHandleOut = PushTypeDefOnTypeTable(StructDecl, &Meta->TypeTable); @@ -1160,11 +1053,10 @@ ParseStruct(token_iter* Iter, type_table_handle* StructTypeHandleOut, gs_meta_pr internal b32 ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_OpenParen)) + if (TokenAtEquals(Iter, "(")) { Result = true; @@ -1183,7 +1075,7 @@ ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, } } - if (TokenAtHashEquals(Iter, TokenHash_CloseParen)) + if (TokenAtEquals(Iter, ")")) { Result = true; } @@ -1196,17 +1088,16 @@ ParseFunctionParameterList (token_iter* Iter, type_definition* FunctionPtrDecl, internal b32 ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; b32 Result = false; PushSnapshot(Iter); type_table_handle ReturnTypeHandle = InvalidTypeTableHandle; if (ParseType(Iter, Meta, &ReturnTypeHandle)) { - if (!TypeHandleIsValid(ReturnTypeHandle)) - { + if (!TypeHandleIsValid(ReturnTypeHandle)) + { ReturnTypeHandle = PushUndeclaredType(Iter->TokenAt->Text, &Meta->TypeTable); - NextToken(Iter); + NextToken(Iter); } b32 IsPointer = ParsePointer(Iter); @@ -1224,7 +1115,7 @@ ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preproces if (ParseFunctionParameterList(Iter, &FunctionPtr, Meta)) { - if (TokenAtHashEquals(Iter, TokenHash_Semicolon)) + if (TokenAtEquals(Iter, ";")) { Result = true; PushTypeDefOnTypeTable(FunctionPtr, &Meta->TypeTable); @@ -1234,18 +1125,17 @@ ParseFunctionDeclaration (token_iter* Iter, token* Identifier, gs_meta_preproces } ApplySnapshotIfNotParsedAndPop(Result, Iter); - if (!Result) - { + if (!Result) + { *Identifier = {0}; } return Result; } -internal b32 +internal b32 ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseTypedef")); b32 Result = false; @@ -1255,7 +1145,7 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) { token TypeToken = {0}; type_table_handle TypeHandle = InvalidTypeTableHandle; - if (TokenAtHashEquals(Iter, TokenHash_Struct) && + if (TokenAtEquals(Iter, "struct") && ParseStruct(Iter, &TypeHandle, Meta)) { Result = true; @@ -1280,7 +1170,7 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) NewType.Size = BasisType->Size; CopyMetaTagsAndClear(&Meta->TagList, &NewType.MetaTags); NewType.Type = BasisType->Type; - if (NewType.Type == TypeDef_Struct || + if (NewType.Type == TypeDef_Struct || NewType.Type == TypeDef_Union) { NewType.Struct = BasisType->Struct; @@ -1299,7 +1189,7 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) { string* Error = TakeError(Iter->Errors); PrintF(Error, "unhandled typedef "); - while (!TokenAtHashEquals(Iter, TokenHash_Semicolon)) + while (!TokenAtEquals(Iter, ";")) { PrintF(Error, "%S ", Iter->TokenAt->Text); NextToken(Iter); @@ -1317,14 +1207,13 @@ ParseTypedef(token_iter* Iter, gs_meta_preprocessor* Meta) internal b32 ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; - gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, MakeStringLiteral("parse"), MakeStringLiteral("ParseEnum")); b32 Result = false; PushSnapshot(Iter); - if (TokenAtHashEquals(Iter, TokenHash_Enum)) + if (TokenAtEquals(Iter, "enum")) { token IdentifierToken = {}; if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken)) @@ -1335,7 +1224,7 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) CopyMetaTagsAndClear(&Meta->TagList, &EnumDecl.MetaTags); EnumDecl.Type = TypeDef_Enum; - if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket)) + if (TokenAtEquals(Iter, "{")) { u32 EnumAcc = 0; @@ -1344,11 +1233,11 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) token EnumIdentifierToken = {}; if (TokenAtEquals(Iter, Token_Identifier, &EnumIdentifierToken)) { - if (TokenAtHashEquals(Iter, TokenHash_Equals)) + if (TokenAtEquals(Iter, "=")) { // TODO(Peter): TempValue is just here until we handle all - // const expr that could define an enum value. Its there so - // that if the first token of an expression is a number, + // const expr that could define an enum value. Its there so + // that if the first token of an expression is a number, // we can avoid using anything from the expression. u32 TempValue = EnumAcc; token NumberToken = {}; @@ -1372,7 +1261,7 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) } s32 EnumValue = EnumAcc++; - if (TokenAtHashEquals(Iter, TokenHash_Comma) || + if (TokenAtEquals(Iter, ",") || StringsEqual(Iter->TokenAt->Text, MakeStringLiteral("}"))) { EnumDecl.Enum.Identifiers.PushElementOnBucket(EnumIdentifierToken.Text); @@ -1386,8 +1275,8 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) } } - if (TokenAtHashEquals(Iter, TokenHash_OpenCurlyBracket) && - TokenAtHashEquals(Iter, TokenHash_Semicolon)) + if (TokenAtEquals(Iter, "}") && + TokenAtEquals(Iter, ";")) { PushTypeDefOnTypeTable(EnumDecl, &Meta->TypeTable); Result = true; @@ -1404,8 +1293,9 @@ ParseEnum (token_iter* Iter, gs_meta_preprocessor* Meta) internal b32 ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta) { - DEBUG_TRACK_FUNCTION; - + gsm_profiler_scope* ProfilerScope = BeginScope(&Meta->Profiler, + MakeStringLiteral("parse"), + MakeStringLiteral("ParseFunction")); b32 Result = false; PushSnapshot(Iter); @@ -1414,8 +1304,11 @@ ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta) { token IdentifierToken = {}; if (TokenAtEquals(Iter, Token_Identifier, &IdentifierToken) && - TokenAtHashEquals(Iter, TokenHash_OpenParen)) + TokenAtEquals(Iter, "(")) { + gsm_profiler_scope* ProfilerInnerScope = BeginScope(&Meta->Profiler, + MakeStringLiteral("parse"), + MakeStringLiteral("ParseFunctionInner")); type_definition FunctionDecl = {}; FunctionDecl.Identifier = IdentifierToken.Text; FunctionDecl.Function.ReturnTypeHandle = ReturnTypeHandle; @@ -1430,29 +1323,29 @@ ParseFunction (token_iter* Iter, gs_meta_preprocessor* Meta) } - if(!TokenAtHashEquals(Iter, TokenHash_Comma)) + if(!TokenAtEquals(Iter, ",")) { break; } } - if (TokenAtHashEquals(Iter, TokenHash_OpenParen)) + if (TokenAtEquals(Iter, ")")) { Result = true; PushTypeDefOnTypeTable(FunctionDecl, &Meta->TypeTable); } + EndScope(ProfilerInnerScope); } } ApplySnapshotIfNotParsedAndPop(Result, Iter); + EndScope(ProfilerScope); return Result; } internal void PrintIndent (u32 Indent) { - DEBUG_TRACK_FUNCTION; - for (u32 i = 0; i < Indent; i++) { printf(" "); @@ -1464,8 +1357,6 @@ internal void PrintStructDecl (type_definition* StructDecl, type_table TypeTable internal void PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0) { - DEBUG_TRACK_FUNCTION; - type_definition* MemberTypeDef = GetTypeDefinition(Member.TypeHandle, TypeTable); if ((MemberTypeDef->Type == TypeDef_Struct || MemberTypeDef->Type == TypeDef_Union) && MemberTypeDef->Identifier.Length == 0) @@ -1498,8 +1389,6 @@ PrintVariableDecl (variable_decl Member, type_table TypeTable, u32 Indent = 0) internal void PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = 0) { - DEBUG_TRACK_FUNCTION; - Assert(StructDecl->Type == TypeDef_Struct || StructDecl->Type == TypeDef_Union); @@ -1533,8 +1422,6 @@ PrintStructDecl (type_definition* StructDecl, type_table TypeTable, u32 Indent = internal void PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; - type_definition* ReturnType = GetTypeDefinition(FnPtrDecl->FunctionPtr.ReturnTypeHandle, TypeTable); printf("%.*s ", StringExpand(ReturnType->Identifier)); @@ -1555,16 +1442,9 @@ PrintFunctionPtrDecl (type_definition* FnPtrDecl, type_table TypeTable) } internal gs_meta_preprocessor -PreprocessProgram (base_allocator Allocator, char* SourceFile) +PreprocessProgram (char* SourceFile) { - DEBUG_TRACK_FUNCTION; - gs_meta_preprocessor Meta = {}; - Meta.Permanent = CreateMemoryArena(Allocator); - Meta.Transient = CreateMemoryArena(Allocator); - - Meta.Errors.Arena = CreateMemoryArena(Allocator); - Meta.TypeTable.Arena = CreateMemoryArena(Allocator); gsm_profiler_scope* TotalScope = BeginScope(&Meta.Profiler, "total", "total"); @@ -1572,10 +1452,10 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile) PopulateTableWithDefaultCPPTypes(&Meta.TypeTable); - string CurrentWorkingDirectory = MakeString(PushArray(&Meta.Permanent, char, 1024), 0, 1024); + string CurrentWorkingDirectory = MakeString((char*)malloc(1024), 0, 1024); string RootFile = MakeString(SourceFile); - AddFileToSource(&Meta.Permanent, RootFile, {}, &Meta.SourceFiles, &Meta.Errors); + AddFileToSource(RootFile, {}, &Meta.SourceFiles, &Meta.Errors); s32 LastSlash = ReverseSearchForCharInSet(RootFile, "\\/"); if (LastSlash <= 0) @@ -1591,22 +1471,28 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile) { source_code_file* File = Meta.SourceFiles.GetElementAtIndex(SourceFileIdx); - gsm_profiler_scope* FileScope = BeginScope(&Meta.Profiler, + gsm_profiler_scope* FileScope = BeginScope(&Meta.Profiler, MakeStringLiteral("file"), File->Path); - TokenizeFile(&Meta, File); + gsm_profiler_scope* TokenizeScope = BeginScope(&Meta.Profiler, + MakeStringLiteral("tokenize"), + File->Path); + TokenizeFile(File, &Meta.Tokens); + EndScope(TokenizeScope); - gsm_profiler_scope* PreprocScope = BeginScope(&Meta.Profiler, + gsm_profiler_scope* PreprocScope = BeginScope(&Meta.Profiler, MakeStringLiteral("preproc"), File->Path); token_iter Iter = {}; - Iter.Tokens = File->Tokens; - Iter.TokenAtIndex = 0; - Iter.TokenAt = File->Tokens.List + Iter.TokenAtIndex; + Iter.Tokens = &Meta.Tokens; + Iter.FirstToken = File->FirstTokenIndex; + Iter.LastToken = File->LastTokenIndex; + Iter.TokenAtIndex = Iter.FirstToken; + Iter.TokenAt = Meta.Tokens.GetElementAtIndex(Iter.TokenAtIndex); Iter.Errors = &Meta.Errors; - while (Iter.TokenAtIndex < Iter.Tokens.Count) + while (Iter.TokenAtIndex < Iter.LastToken) { b32 ParseSuccess = false; @@ -1618,19 +1504,19 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile) // NOTE(Peter): For now we aren't going in and preprocessing the header files // we include from the system // Token_Operator is used to check if the include is of the form '#include ' - // and skip it. + // and skip it. // TODO(Peter): This is only a rough approximation of ignoring system headers // TODO(Peter): We should actually see what parsing system headers would entail if (IncludeFile->Type != Token_Operator) { string TempFilePath = IncludeFile->Text; - gsm_profiler_scope* IncludeScope = BeginScope(&Meta.Profiler, + gsm_profiler_scope* IncludeScope = BeginScope(&Meta.Profiler, MakeStringLiteral("include"), TempFilePath); // NOTE(Peter): if the path is NOT absolute ie "C:\etc - if (!(IsAlpha(TempFilePath.Memory[0]) && - TempFilePath.Memory[1] == ':' && + if (!(IsAlpha(TempFilePath.Memory[0]) && + TempFilePath.Memory[1] == ':' && TempFilePath.Memory[2] == '\\')) { TempFilePath = CurrentWorkingDirectory; @@ -1641,7 +1527,7 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile) ParseSuccess = true; if (!FileAlreadyInSource(TempFilePath, Meta.SourceFiles)) { - AddFileToSource(&Meta.Permanent, TempFilePath, *File, &Meta.SourceFiles, &Meta.Errors); + AddFileToSource(TempFilePath, *File, &Meta.SourceFiles, &Meta.Errors); } EndScope(IncludeScope); } @@ -1714,8 +1600,6 @@ PreprocessProgram (base_allocator Allocator, char* SourceFile) internal void FinishMetaprogram(gs_meta_preprocessor* Meta) { - CollateFrame(&GlobalDebugServices); - FinishProfiler(&Meta->Profiler); PrintAllErrors(Meta->Errors); diff --git a/src/meta/gs_meta_code_generator.h b/src/meta/gs_meta_code_generator.h index 0986e7f..ba431ad 100644 --- a/src/meta/gs_meta_code_generator.h +++ b/src/meta/gs_meta_code_generator.h @@ -37,12 +37,12 @@ struct gsm_code_generator // --------------- internal gsm_code_generator -BeginEnumGeneration(memory_arena* Storage, string EnumIdentifier, string ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) +BeginEnumGeneration(string EnumIdentifier, string ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) { gsm_code_generator Gen = {}; // TODO(Peter): TEMP!! - Gen.Builder = PushStruct(Storage, string_builder); + Gen.Builder = (string_builder*)malloc(sizeof(string_builder)); *Gen.Builder = {}; Gen.Type = gsm_CodeGen_Enum; @@ -60,9 +60,9 @@ BeginEnumGeneration(memory_arena* Storage, string EnumIdentifier, string ValuePr } internal gsm_code_generator -BeginEnumGeneration(memory_arena* Storage, char* EnumIdentifier, char* ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) +BeginEnumGeneration(char* EnumIdentifier, char* ValuePrefix, b32 StartsWithInvalid, b32 EndsWithCount) { - return BeginEnumGeneration(Storage, MakeStringLiteral(EnumIdentifier), + return BeginEnumGeneration(MakeStringLiteral(EnumIdentifier), MakeStringLiteral(ValuePrefix), StartsWithInvalid, EndsWithCount); diff --git a/src/meta/gs_meta_error.h b/src/meta/gs_meta_error.h index 057f6ab..f4f1c68 100644 --- a/src/meta/gs_meta_error.h +++ b/src/meta/gs_meta_error.h @@ -9,28 +9,46 @@ struct error_buffer #define ERROR_BUFFER_SIZE 256 struct errors { - memory_arena Arena; error_buffer* Buffers; u32 BuffersCount; u32 Used; }; +#define ErrorReallocArray(base, type, oldcount, newcount) (type*)ErrorRealloc_((u8*)(base), (u64)(sizeof(type) * oldcount), (u64)(sizeof(type) * newcount)) +internal u8* +ErrorRealloc_(u8* Base, u64 OldSize, u64 NewSize) +{ + Assert(NewSize > 0); + u8* Result = (u8*)malloc(NewSize); + if (Base != 0 && OldSize > 0) + { + GSMemCopy(Base, Result, OldSize); + free(Base); + } + return Result; +} + internal void PushFError (errors* Errors, char* Format, ...) { if (Errors->Used >= (Errors->BuffersCount * ERROR_BUFFER_SIZE)) { +#if 0 Errors->BuffersCount += 1; Errors->Buffers = (error_buffer*)realloc(Errors->Buffers, sizeof(error_buffer*) * Errors->BuffersCount); +#else + Errors->Buffers = ErrorReallocArray(Errors->Buffers, error_buffer, Errors->BuffersCount, Errors->BuffersCount + 1); + Errors->BuffersCount += 1; +#endif error_buffer* NewBuffer = Errors->Buffers + (Errors->BuffersCount - 1); - NewBuffer->Backbuffer = PushArray(&Errors->Arena, char, ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE); - NewBuffer->Contents = PushArray(&Errors->Arena, string, ERROR_BUFFER_SIZE); + NewBuffer->Backbuffer = (char*)malloc(sizeof(char) * ERROR_MAX_LENGTH * ERROR_BUFFER_SIZE); + NewBuffer->Contents = (string*)malloc(sizeof(string) * ERROR_BUFFER_SIZE); for (u32 i = 0; i < ERROR_BUFFER_SIZE; i++) { - NewBuffer->Contents[i].Memory = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH); - NewBuffer->Contents[i].Max = ERROR_MAX_LENGTH; + NewBuffer->Contents[i].Str = NewBuffer->Backbuffer + (i * ERROR_MAX_LENGTH); + NewBuffer->Contents[i].Size = ERROR_MAX_LENGTH; NewBuffer->Contents[i].Length = 0; } } diff --git a/src/meta/gs_meta_lexer.h b/src/meta/gs_meta_lexer.h index a9f9993..60e6647 100644 --- a/src/meta/gs_meta_lexer.h +++ b/src/meta/gs_meta_lexer.h @@ -1,7 +1,7 @@ struct token_selection_spec { b32 MatchText; - string Text; + gs_string Text; }; internal s32 @@ -160,69 +160,69 @@ GetNextToken (tokenizer* Tokenizer) { Result.Type = Token_PoundDefine; EatPreprocessor(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "undef")) { Result.Type = Token_PoundUndef; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "include")) { Result.Type = Token_PoundInclude; - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "ifdef")) { Result.Type = Token_PoundIfDef; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "ifndef")) { Result.Type = Token_PoundIfNDef; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "if")) { Result.Type = Token_PoundIf; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "elif")) { Result.Type = Token_PoundElif; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "else")) { Result.Type = Token_PoundElse; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "endif")) { Result.Type = Token_PoundEndif; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "error")) { Result.Type = Token_PoundError; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } else if (TokenAtEquals(Tokenizer, "pragma")) { Result.Type = Token_PoundPragma; EatToNewLine(Tokenizer); - Result.Text.Length = Tokenizer->At - Result.Text.Memory; + Result.Text.Length = Tokenizer->At - Result.Text.Str; } } - else if (IsNumeric(C)) + else if (IsNumericExtended(C)) { Result.Type = Token_Number; @@ -233,7 +233,7 @@ GetNextToken (tokenizer* Tokenizer) else if (C == '\'') { Result.Type = Token_Char; - Result.Text.Memory = Tokenizer->At; + Result.Text.Str = Tokenizer->At; if (Tokenizer->At[0] && Tokenizer->At[0] == '\\') { ++Tokenizer->At; @@ -245,7 +245,7 @@ GetNextToken (tokenizer* Tokenizer) { Result.Type = Token_String; // replace the length added by the quote - Result.Text.Memory = Tokenizer->At; + Result.Text.Str = Tokenizer->At; Result.Text.Length = EatString(Tokenizer); } // NOTE(Peter): This is after comment parsing so that the division operator @@ -257,6 +257,5 @@ GetNextToken (tokenizer* Tokenizer) Result.Text.Length += EatIdentifier(Tokenizer); } - Result.TextHash = HashDJB2ToU64(Result.Text.Memory); return Result; } \ No newline at end of file diff --git a/src/meta/gs_meta_type_table.h b/src/meta/gs_meta_type_table.h index 7e0bac0..d0d32d9 100644 --- a/src/meta/gs_meta_type_table.h +++ b/src/meta/gs_meta_type_table.h @@ -44,7 +44,6 @@ struct type_table_handle // #define TypeHandleIsValid(handle) (!((handle).BucketIndex == 0) && ((handle).IndexInBucket == 0)) inline b32 TypeHandleIsValid(type_table_handle A) { - DEBUG_TRACK_FUNCTION; b32 FirstBucket = (A.BucketIndex == 0); b32 FirstIndex = (A.IndexInBucket == 0); b32 Both = FirstBucket && FirstIndex; @@ -142,8 +141,6 @@ struct meta_tag_hash_bucket struct type_table { - memory_arena Arena; - type_table_hash_bucket* Types; u32 TypeBucketsCount; @@ -154,7 +151,6 @@ struct type_table internal b32 HandlesAreEqual(type_table_handle A, type_table_handle B) { - DEBUG_TRACK_FUNCTION; b32 Result = ((A.BucketIndex == B.BucketIndex) && (A.IndexInBucket == B.IndexInBucket)); return Result; } @@ -162,7 +158,6 @@ HandlesAreEqual(type_table_handle A, type_table_handle B) internal u32 HashIdentifier(string Identifier) { - DEBUG_TRACK_FUNCTION; u32 IdentHash = HashString(Identifier); if (IdentHash == 0) { @@ -177,7 +172,6 @@ HashIdentifier(string Identifier) internal type_table_handle GetTypeHandle (string Identifier, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_table_handle Result = InvalidTypeTableHandle; u32 IdentHash = HashIdentifier(Identifier); @@ -200,7 +194,6 @@ GetTypeHandle (string Identifier, type_table TypeTable) internal type_table_handle GetMetaTagHandle(string Identifier, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_table_handle Result = InvalidTypeTableHandle; u32 IdentHash = HashIdentifier(Identifier); @@ -223,7 +216,6 @@ GetMetaTagHandle(string Identifier, type_table TypeTable) internal type_table_handle GetMetaTagHandleWithIdentifier(string Identifier, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_table_handle Result = InvalidTypeTableHandle; u32 IdentHash = HashIdentifier(Identifier); @@ -245,7 +237,6 @@ GetMetaTagHandleWithIdentifier(string Identifier, type_table TypeTable) internal b32 HasTag(string Needle, gs_bucket Tags, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; b32 Result = false; type_table_handle NeedleTagHandle = GetMetaTagHandleWithIdentifier(Needle, TypeTable); @@ -268,7 +259,6 @@ HasTag(string Needle, gs_bucket Tags, type_table TypeTable) internal void CopyMetaTagsAndClear(gs_bucket* Source, gs_bucket* Dest) { - DEBUG_TRACK_FUNCTION; for (u32 i = 0; i < Source->Used; i++) { type_table_handle* TagToken = Source->GetElementAtIndex(i); @@ -280,7 +270,6 @@ CopyMetaTagsAndClear(gs_bucket* Source, gs_bucketTypes = (type_table_hash_bucket*)realloc(TypeTable->Types, NewTypesSize); type_table_hash_bucket* NewBucket = TypeTable->Types + NewTypeBucketIndex; - NewBucket->Keys = PushArray(&TypeTable->Arena, u32, TYPE_TABLE_BUCKET_MAX); - NewBucket->Values = PushArray(&TypeTable->Arena, type_definition, TYPE_TABLE_BUCKET_MAX); + NewBucket->Keys = (u32*)malloc(sizeof(u32) * TYPE_TABLE_BUCKET_MAX); + NewBucket->Values = (type_definition*)malloc(sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Values, sizeof(type_definition) * TYPE_TABLE_BUCKET_MAX); @@ -321,7 +310,6 @@ FindSlotForTypeIdentifier(u32 IdentHash, type_table* TypeTable) internal type_table_handle FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; type_table_handle Result = InvalidTypeTableHandle; u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX; @@ -343,8 +331,8 @@ FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable) TypeTable->MetaTags = (meta_tag_hash_bucket*)realloc(TypeTable->MetaTags, NewMetaBucketListSize); meta_tag_hash_bucket* NewBucket = TypeTable->MetaTags + NewMetaBucketIndex; - NewBucket->Keys = PushArray(&TypeTable->Arena, u32, TYPE_TABLE_BUCKET_MAX); - NewBucket->Values = PushArray(&TypeTable->Arena, meta_tag, TYPE_TABLE_BUCKET_MAX); + NewBucket->Keys = (u32*)malloc(sizeof(u32) * TYPE_TABLE_BUCKET_MAX); + NewBucket->Values = (meta_tag*)malloc(sizeof(meta_tag) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Keys, sizeof(u32) * TYPE_TABLE_BUCKET_MAX); GSZeroMemory((u8*)NewBucket->Values, sizeof(meta_tag) * TYPE_TABLE_BUCKET_MAX); @@ -358,7 +346,6 @@ FindSlotForMetaTag(u32 IdentHash, type_table* TypeTable) internal type_table_handle PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; u32 IdentHash = HashIdentifier(TypeDef.Identifier); type_table_handle Result = FindSlotForTypeIdentifier(IdentHash, TypeTable); @@ -378,7 +365,6 @@ PushTypeOnHashTable(type_definition TypeDef, type_table* TypeTable) internal type_table_handle PushUndeclaredType (string Identifier, type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; type_definition UndeclaredTypeDef = {}; UndeclaredTypeDef.Identifier = Identifier; UndeclaredTypeDef.Type = TypeDef_Unknown; @@ -389,7 +375,6 @@ PushUndeclaredType (string Identifier, type_table* TypeTable) internal type_table_handle PushMetaTagOnTable(meta_tag Tag, type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; u32 TagIdentifierHash = HashIdentifier(Tag.Identifier); type_table_handle Result = FindSlotForMetaTag(TagIdentifierHash, TypeTable); @@ -409,7 +394,6 @@ PushMetaTagOnTable(meta_tag Tag, type_table* TypeTable) internal type_definition* GetTypeDefinition(type_table_handle Handle, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; Assert(TypeHandleIsValid(Handle)); type_definition* Result = 0; if (TypeTable.Types[Handle.BucketIndex].Keys != 0) @@ -423,7 +407,6 @@ GetTypeDefinition(type_table_handle Handle, type_table TypeTable) internal type_definition* GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_definition* Result = 0; if (TypeTable.Types[Handle.BucketIndex].Keys != 0) { @@ -435,7 +418,6 @@ GetTypeDefinitionUnsafe(type_table_handle Handle, type_table TypeTable) internal meta_tag* GetMetaTag(type_table_handle Handle, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; meta_tag* Result = 0; if (TypeTable.MetaTags[Handle.BucketIndex].Keys != 0) { @@ -447,7 +429,6 @@ GetMetaTag(type_table_handle Handle, type_table TypeTable) internal type_definition* GetTypeDefinition(string Identifier, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_definition* Result = 0; u32 IdentHash = HashIdentifier(Identifier); u32 Index = IdentHash % TYPE_TABLE_BUCKET_MAX; @@ -466,7 +447,6 @@ GetTypeDefinition(string Identifier, type_table TypeTable) internal type_table_handle PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; // NOTE(Peter): We don't accept type definitions with empty identifiers. // If a struct or union is anonymous, it should be assigned a name of the form // parent_struct_name_# where # is the member index @@ -496,7 +476,6 @@ PushTypeDefOnTypeTable(type_definition TypeDef, type_table* TypeTable) internal s32 GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; s32 Result = -1; type_definition* TypeDef = GetTypeDefinition(TypeHandle, TypeTable); if (TypeDef) @@ -509,7 +488,6 @@ GetSizeOfType (type_table_handle TypeHandle, type_table TypeTable) internal s32 GetSizeOfType (string Identifier, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; s32 Result = -1; type_definition* TypeDef = GetTypeDefinition(Identifier, TypeTable); if (TypeDef) @@ -522,7 +500,6 @@ GetSizeOfType (string Identifier, type_table TypeTable) internal b32 VariableDeclsEqual (variable_decl A, variable_decl B) { - DEBUG_TRACK_FUNCTION; b32 Result = false; if (TypeHandlesEqual(A.TypeHandle, B.TypeHandle) && A.ArrayCount == B.ArrayCount && @@ -536,7 +513,6 @@ VariableDeclsEqual (variable_decl A, variable_decl B) internal b32 StructOrUnionsEqual (type_definition A, type_definition B) { - DEBUG_TRACK_FUNCTION; // NOTE(Peter): Fairly certain the only places this is used are when we // already know the identifiers match Assert(StringsEqual(A.Identifier, B.Identifier)); @@ -565,7 +541,6 @@ StructOrUnionsEqual (type_definition A, type_definition B) internal type_table_handle FindHandleOfMatchingType (type_definition Match, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; type_table_handle Result = InvalidTypeTableHandle; type_table_handle Handle = GetTypeHandle(Match.Identifier, TypeTable); if (TypeHandleIsValid(Handle)) @@ -581,7 +556,6 @@ internal void FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable internal void FixupMemberType (variable_decl* Member, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; if (!TypeHandleIsValid(Member->TypeHandle)) { Member->TypeHandle = GetTypeHandle(Member->Identifier, TypeTable); @@ -592,7 +566,6 @@ FixupMemberType (variable_decl* Member, type_table TypeTable) internal s32 CalculateStructMemberSize (variable_decl Member, type_definition MemberType) { - DEBUG_TRACK_FUNCTION; Assert(TypeHandleIsValid(Member.TypeHandle)); // NOTE(Peter): At one point we were Asserting on struct sizes of zero, but // that's actually incorrect. It is valid to have an empty struct. @@ -614,7 +587,6 @@ CalculateStructMemberSize (variable_decl Member, type_definition MemberType) internal void FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_table TypeTable, errors* Errors) { - DEBUG_TRACK_FUNCTION; // NOTE(Peter): There are a lot of cases where struct members which are pointers // to other structs cause interesting behavior here. // For example: @@ -669,7 +641,6 @@ FixupStructMember (variable_decl* Member, type_definition* MemberTypeDef, type_t internal void FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors) { - DEBUG_TRACK_FUNCTION; type_definition* Struct = GetTypeDefinition(TypeHandle, TypeTable); Assert(Struct->Type == TypeDef_Struct); @@ -715,7 +686,6 @@ FixUpStructSize (type_table_handle TypeHandle, type_table TypeTable, errors* Err internal void FixUpUnionSize (type_table_handle TypeHandle, type_table TypeTable, errors* Errors) { - DEBUG_TRACK_FUNCTION; type_definition* Union = GetTypeDefinition(TypeHandle, TypeTable); Assert(Union->Type == TypeDef_Union); @@ -773,7 +743,6 @@ type_definition CPPBasicTypes[] = { internal void PopulateTableWithDefaultCPPTypes(type_table* TypeTable) { - DEBUG_TRACK_FUNCTION; for (u32 i = 0; i < GSArrayLength(CPPBasicTypes); i++) { PushTypeDefOnTypeTable(CPPBasicTypes[i], TypeTable); @@ -783,7 +752,6 @@ PopulateTableWithDefaultCPPTypes(type_table* TypeTable) internal void PrintTypeDefinition(type_definition TypeDef, type_table TypeTable) { - DEBUG_TRACK_FUNCTION; printf("Type: %.*s\n", StringExpand(TypeDef.Identifier)); printf(" Size: %d\n", TypeDef.Size); @@ -849,7 +817,6 @@ PrintTypeDefinition(type_definition TypeDef, type_table TypeTable) internal void PrintTypeTable(type_table TypeTable) { - DEBUG_TRACK_FUNCTION; for (u32 b = 0; b < TypeTable.TypeBucketsCount; b++) { type_table_hash_bucket Bucket = TypeTable.Types[b]; @@ -866,7 +833,6 @@ PrintTypeTable(type_table TypeTable) internal void DEBUGPrintTypeTableMembership(type_table TypeTable) { - DEBUG_TRACK_FUNCTION; printf("\n--- Type Table Membership --\n"); u32 SlotsAvailable = 0; u32 SlotsFilled = 0; diff --git a/src/meta/gs_meta_typeinfo_generator.h b/src/meta/gs_meta_typeinfo_generator.h index 35008e7..c26cf4a 100644 --- a/src/meta/gs_meta_typeinfo_generator.h +++ b/src/meta/gs_meta_typeinfo_generator.h @@ -3,9 +3,9 @@ // Author: Peter Slattery // Creation Date: 2020-01-19 // -// Usage +// Usage // TODO -// +// // #ifndef GS_META_TYPEINFO_GENERATOR_H @@ -31,15 +31,15 @@ struct typeinfo_generator #define TypeHandleToIndex(handle) ((handle.BucketIndex * TYPE_TABLE_BUCKET_MAX) + handle.IndexInBucket) internal typeinfo_generator -InitTypeInfoGenerator(type_table* TypeTable) +InitTypeInfoGenerator(type_table TypeTable) { typeinfo_generator Result = {}; - Result.TypesMax = TypeTable->TypeBucketsCount * TYPE_TABLE_BUCKET_MAX; - Result.TypesGeneratedMask = PushArray(&TypeTable->Arena, b8, Result.TypesMax); + Result.TypesMax = TypeTable.TypeBucketsCount * TYPE_TABLE_BUCKET_MAX; + Result.TypesGeneratedMask = (b8*)malloc(sizeof(b8) * Result.TypesMax); GSZeroMemory((u8*)Result.TypesGeneratedMask, Result.TypesMax); - Result.TypeList = BeginEnumGeneration(&TypeTable->Arena, "gsm_struct_type", "gsm_StructType", false, true); + Result.TypeList = BeginEnumGeneration("gsm_struct_type", "gsm_StructType", false, true); WriteF(&Result.TypeDefinitions, "static gsm_struct_type_info StructTypes[] = {\n"); return Result; @@ -73,7 +73,7 @@ internal void GenerateStructMemberInfo (variable_decl* Member, string StructIdentifier, type_table TypeTable, typeinfo_generator* Gen) { WriteF(&Gen->StructMembers, "{ \"%S\", %d, ", Member->Identifier, Member->Identifier.Length); - WriteF(&Gen->StructMembers, "(u64)&((%S*)0)->%S, ", StructIdentifier, Member->Identifier); + WriteF(&Gen->StructMembers, "(u64)&((%S*)0)->%S, ", StructIdentifier, Member->Identifier); GenerateMetaTagInfo(Member->MetaTags, TypeTable, &Gen->StructMembers); WriteF(&Gen->StructMembers, "},\n"); } @@ -81,7 +81,7 @@ GenerateStructMemberInfo (variable_decl* Member, string StructIdentifier, type_t internal void GenerateTypeInfo (type_definition* Type, type_table_handle TypeHandle, type_table TypeTable, typeinfo_generator* Generator) { - // TODO(Peter): + // TODO(Peter): // 1. allocate the full range of the types hash table // 2. use bucketindex * bucket_max + indexinbucket to get the consecutive index Generator->TypesGeneratedMask[TypeHandleToIndex(TypeHandle)] = true; @@ -114,7 +114,7 @@ GenerateTypeInfo (type_definition* Type, type_table_handle TypeHandle, type_tabl } } - if (Type->Type == TypeDef_Struct || + if (Type->Type == TypeDef_Struct || Type->Type == TypeDef_Union) { for (u32 m = 0; m < Type->Struct.MemberDecls.Used; m++) @@ -124,10 +124,10 @@ GenerateTypeInfo (type_definition* Type, type_table_handle TypeHandle, type_tabl if ((MemberType->Type == TypeDef_Struct || MemberType->Type == TypeDef_Union) && - MemberType->Struct.IsAnonymous) - { + MemberType->Struct.IsAnonymous) + { continue; // Don't gen info for anonymous struct and union members - } + } if (Generator->TypesGeneratedMask[TypeHandleToIndex(Member->TypeHandle)]) { continue; } diff --git a/src/serial_monitor/first.cpp b/src/serial_monitor/first.cpp new file mode 100644 index 0000000..1f0c6d6 --- /dev/null +++ b/src/serial_monitor/first.cpp @@ -0,0 +1,221 @@ +// +// File: first.cpp +// Author: Peter Slattery +// Creation Date: 2020-10-10 +// +#ifndef FIRST_CPP + + +#include "../gs_libs/gs_types.h" +#include "../gs_libs/gs_types.cpp" + +#define DEBUG_TRACK_FUNCTION + +#include +#include + +//#include "../app/foldhaus_platform.h" +//#include "../gs_libs/gs_win32.cpp" +#include "../app/platform_win32/win32_foldhaus_utils.h" +#include "../app/platform_win32/win32_foldhaus_memory.h" +#include "../app/platform_win32/win32_foldhaus_fileio.h" +#include "../app/platform_win32/win32_foldhaus_serial.h" +#include "../app/platform_win32/win32_foldhaus_work_queue.h" + +#include "../app/engine/uart/foldhaus_uart.h" + +u8* +FindNextHeader(gs_data Data, u8* StartAt) +{ + u8* At = StartAt; + while (!(At[0] == 'U' && + At[1] == 'P' && + At[2] == 'X' && + At[3] == 'L') && + (u32)(At - Data.Memory) < Data.Size) + { + At++; + } + return At; +} + +void +CreateMessage(gs_data* Data, u8 Count) +{ + gs_memory_cursor WriteCursor = CreateMemoryCursor(*Data); + + u32 Channels[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 16, 17, 18, 19, 20, 21, 22, 23, + //40, 41, 42, 43, 44, 45, 46, 47, + }; + + u8* FirstHeaderAddr = 0; + + for (u32 j = 0; j < sizeof(Channels) / sizeof(u32); j++) + { + u32 ChannelIndex = Channels[j]; + uart_header* Header = PushStructOnCursor(&WriteCursor, uart_header); + UART_FillHeader(Header, ChannelIndex, UART_SET_CHANNEL_WS2812); + + if (FirstHeaderAddr == 0) + { + FirstHeaderAddr = (u8*)Header; + } + + uart_channel* Channel = PushStructOnCursor(&WriteCursor, uart_channel); + Channel->ElementsCount = 3; + Channel->ColorPackingOrder = 36; // 10010000 + Channel->PixelsCount = 300; + + for (u32 i = 0; i < Channel->PixelsCount; i++) + { + u8* Pixel = PushArrayOnCursor(&WriteCursor, u8, 3); + Pixel[0] = Count; + Pixel[1] = 0; + Pixel[2] = 255 - Count; + } + + uart_footer* Footer = PushStructOnCursor(&WriteCursor, uart_footer); + Footer->CRC = UART_CalculateCRC((u8*)Header, (u8*)(Footer)); + } + + uart_header* DrawAllHeader = PushStructOnCursor(&WriteCursor, uart_header); + UART_FillHeader(DrawAllHeader, 255, UART_DRAW_ALL); + uart_footer* DrawAllFooter = + PushStructOnCursor(&WriteCursor, uart_footer); + DrawAllFooter->CRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter)); + + Data->Size = ((u8*)DrawAllFooter - (u8*)FirstHeaderAddr) + sizeof(uart_footer); +} + +int main(int ArgCount, char** Args) +{ + gs_thread_context Ctx = Win32CreateThreadContext(); + + HANDLE SerialHandle = Win32SerialPort_Open("\\\\.\\COM9"); + Win32SerialPort_SetState(SerialHandle, 2000000, 8, 0, 1); + + gs_const_string OutFileName = ConstString("./serial_dump.data"); + + + if (false) + { + Win32SerialPort_SetRead(SerialHandle); + + gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); + + Win32SerialPort_SetRead(SerialHandle); + u32 ReadSize = Win32SerialPort_ReadMessageWhenReady(SerialHandle, Data); + + u8* SetChannelHeaderAddr = 0; + uart_header* SetChannelHeader = 0; + uart_header* DrawAllHeader = 0; + u8* ScanAt = Data.Memory; + do + { + ScanAt = FindNextHeader(Data, ScanAt); + uart_header* Header = (uart_header*)ScanAt; + + if (Header->RecordType == UART_SET_CHANNEL_WS2812) + { + printf("Set Channel:\n"); + printf(" Channel: %d\n", Header->Channel); + printf(" Pixels: %d\n", ((uart_channel*)(Header + 1))->PixelsCount); + if (!SetChannelHeader) + { + SetChannelHeaderAddr = (u8*)Header; + SetChannelHeader = Header; + } + } + + if (Header->RecordType == UART_DRAW_ALL) + { + printf("Draw All:\n"); + printf(" Channel: %d\n", Header->Channel); + if (!DrawAllHeader) + { + DrawAllHeader= Header; + } + } + + ScanAt += sizeof(uart_header); + }while(((u32)(ScanAt - Data.Memory + sizeof(uart_header)) < Data.Size)); + + uart_channel* Channel = (uart_channel*)(SetChannelHeader + 1); + + u8* DataStart = (u8*)(Channel + 1); + + uart_footer* Footer = (uart_footer*)(DataStart + (Channel->ElementsCount * Channel->PixelsCount)); + + u32 TestCRC = UART_CalculateCRC((u8*)SetChannelHeader, (u8*)(Footer)); + + uart_footer* DrawAllFooter = (uart_footer*)(DrawAllHeader + 1); + u32 DrawwAllCRC = UART_CalculateCRC((u8*)DrawAllHeader, (u8*)(DrawAllFooter)); + + HANDLE FileHandle = CreateFileA(OutFileName.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesWritten = 0; + if (!WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL)) + { + InvalidCodePath; + } + } + CloseHandle(FileHandle); + Win32SerialPort_Close(SerialHandle); + + } + else if (true) + { + gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); + + u8 Count = 0; + while(true) + { + CreateMessage(&Data, ++Count); + Win32SerialPort_Write(SerialHandle, Data); + Sleep(100); + } + } + else if (false) + { + gs_data Data = PushSizeToData(Ctx.Transient, KB(32)); + gs_file File = Win32ReadEntireFile(Ctx.FileHandler, OutFileName, Data); + + gs_data Messages = {0}; + u8* ScanAt = Data.Memory; + ScanAt = FindNextHeader(Data, ScanAt); + uart_header* FirstHeader = (uart_header*)ScanAt; + ScanAt += sizeof(uart_header); + + uart_header* LastHeader = 0; + do + { + ScanAt = FindNextHeader(Data, ScanAt); + uart_header* Header = (uart_header*)ScanAt; + if (Header->RecordType == UART_DRAW_ALL) + { + LastHeader = Header; + } + ScanAt += sizeof(uart_header); + }while((u32)(ScanAt - Data.Memory) < Data.Size); + + u8* OnePastLastByte = ((u8*)(LastHeader + 1)) + sizeof(uart_footer); + + Messages.Memory = (u8*)FirstHeader; + Messages.Size = OnePastLastByte - Messages.Memory; + + while (true) + { + Win32SerialPort_Write(SerialHandle, Messages); + Sleep(100); + } + } + + return 0; +} + + +#define FIRST_CPP +#endif // FIRST_CPP \ No newline at end of file diff --git a/src/todo.txt b/src/todo.txt index 3339013..6c1bc22 100644 --- a/src/todo.txt +++ b/src/todo.txt @@ -1,45 +1,5 @@ TODO FOLDHAUS -STREAM #0: Metaprogramming -- Metaprogramming - - fix memory layout (remeber to profile before and after) - - use a base_allocator struct to track allocations to begin with - - introduce memory_arenas - - get rid of gs_bucket and gs_list or whatever, just use custom bucket lists - -Profile 0: -Total Allocated Space: 1186150 bytes, or 1.131201 MB -Total Time: 0.062665 seconds - -Profile 1: -Total Allocated Space: 1217890 bytes, or 1.161470 MB -Total Time: 0.061852 seconds - -Profile 2: - - - -Profile 3: -Converted many of the TokenAtEquals to TokenAtHashEquals -Total Allocated Space: 912143773 bytes, or 869.888089 MB -Total Time: 4.915469 - - - - - - - - - - convert gs_memory_arena to using 64 bit integers - - investigate centralizing type table type creation in a similar place, rather than scattered all over -- Make everything truly platform agnostic - - Application DLL - - math.h: present for trig functions (though this is part of the c-std lib, so it should be everywhere) - - windows.h: only thing left is InterlockedIncrement and InterlockedAdd - - Meta Layer - - ??? - STREAM #1: 3D Overhaul - Rendering (Working on this elsewhere) - OpenGL 3 @@ -54,22 +14,15 @@ STREAM #1: 3D Overhaul - leds always face camera - Sculptures - - store scale in the assembly definition file - cache led vertex buffers - custom sculpture update functions (for motion) - - placing sculptures - editing sculpture files (change universe output) - - led groups & subgroups - defined in file - motion - Sculpture View - mouse spatial interaction - handles, and hover for info - debug capabilities (toggle strip/led/universe colors) -STREAM #2: Memory -- Buckets & Lists - - On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place - - Internal Log File NOTE: This should not be a part of the debug system - Save output log to a file continuously @@ -77,11 +30,11 @@ STREAM #2: Memory - Create a bar that displays the most recent error message - :ErrorLogging -STREAM #3: Nodes - Animation System - blending between animation - layers - layer masks by sculpture + - layer masks by tag / value - interface for animation system - add/remove layers - select blend modes @@ -90,23 +43,11 @@ STREAM #3: Nodes - clips can have parameters that drive them? - clips cannot overlap eachother on the same layer -- Node System - - automatic node layout - - blending node layouts - - workspace -> animation block - - generating node workspace as code - - compiling node workspace - - hotload compiled pattern sets - - Serialization - saving scenes - - saving node graphs - - saving animation timelines - saving projects STRAM #4: Completeness -- Win32 Platform Layer - - Enumerate Directory Contents (you started this in win32_foldhaus_fileio.h) - Platform Layer - Mac Platform Layer @@ -137,27 +78,6 @@ Assembly -> SACN interface BUGS - Typing a period into a float value doesn't register. Problem here is that we arent' translating key presses into characters at the win32 layer. Need to do that. -Switch To Nodes -- BUG: Connect a solid color node to output then try and pick a color. I think temporary node buffers are -- overwriting other data when they get evaluated. Bigger solution is to create a system of working -- led buffers that get assigned to nodes as needed. -- gonna need to remove output node from the node lister -- delete nodes -- - Simplify node storage -- - investigate if node connections can be operated on separately from the node headers -- - UpdatedThisFrame can probably go into each connection -- - Allow insertion/deletion within connection table -- - Allow inerstion/deletion within header table -- - maintain free list of connections and headers -- separate node functionality from drawing the nodes -- - pull node position, size, etc out into a parallel data structure. after split names: node_header, interface_node -- - create separate files: foldhaus_node_engine, foldhaus_node_gui -- - store interface_nodes in binary tree -- - allow panning and zooming around the node canvas -- - Investigate why we're giving nodes bounds :NodesDontNeedToKnowTheirBounds -- selector node (has a list of connections that it can switch between) -- evaluation step (one node at a time) - Hardening - 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 @@ -190,3 +110,13 @@ Name - Splash screen (like blender) (thisll be fun) - - Image importer (stb image? or find a png > bmp converter for the image you have) - - Display on startup + +STREAM #0: Metaprogramming +- Metaprogramming + - fix memory layout (remeber to profile before and after) +- Make everything truly platform agnostic + - Application DLL + - math.h: present for trig functions (though this is part of the c-std lib, so it should be everywhere) + - windows.h: only thing left is InterlockedIncrement and InterlockedAdd + - Meta Layer + - ??? diff --git a/src/todo_done.txt b/src/todo_done.txt index b957c7c..6aae2d4 100644 --- a/src/todo_done.txt +++ b/src/todo_done.txt @@ -1,3 +1,8 @@ +x saving animation timelines +x Buckets & Lists + x On second thought, I just really don't like these. Lets get rid of them, and put custom structures in place + + BUGS x if there is nothing in the filtered list when searching for a node, hitting enter still selects one x Search lister - returning from a filtered list that has zero elements to one that has a few, hotItem = -1 @@ -27,11 +32,11 @@ x Add Text Alignment to DrawString x Move nodes over to referencing eachother based on a UID system /Debug -x Make debug scope tracking thread safe - was throwing an error in stringsequal but that stopped. +x Make debug scope tracking thread safe - was throwing an error in stringsequal but that stopped. x Keep an eye out. x Sort Scope Tracking x got the profiler view rudimentarily working -x reimplement the scope list view. +x reimplement the scope list view. x start tracking debug interface state somehow and it would be good to separate that out from global debug state Switch To Nodes