From bfd9d6671cfc9cdbb655ffc7c4fe583e9e075aea Mon Sep 17 00:00:00 2001 From: Peter Slattery Date: Tue, 9 Jun 2020 20:33:51 -0700 Subject: [PATCH] Finished parsing the new assembly file format --- src/app/assembly_parser.cpp | 646 +++++++++++++++------------------ src/app/assembly_parser.h | 76 ---- src/app/foldhaus_app.cpp | 10 +- src/app/foldhaus_app.h | 19 +- src/app/foldhaus_assembly.cpp | 74 ++-- src/app/foldhaus_assembly.h | 38 +- src/app/foldhaus_interface.cpp | 4 +- src/app/foldhaus_panel.h | 16 +- 8 files changed, 381 insertions(+), 502 deletions(-) delete mode 100644 src/app/assembly_parser.h diff --git a/src/app/assembly_parser.cpp b/src/app/assembly_parser.cpp index 459f644..5b6605a 100644 --- a/src/app/assembly_parser.cpp +++ b/src/app/assembly_parser.cpp @@ -5,440 +5,386 @@ // #ifndef ASSEMBLY_PARSER_CPP -internal assembly_token -ParseToken (tokenizer* Tokenizer) +enum assembly_field { - assembly_token Result = {}; - Result.Token = Tokenizer->At; - Result.Length = 1; - EatChar(Tokenizer); + AssemblyField_AssemblyName, + AssemblyField_AssemblyScale, + AssemblyField_LedStripCount, - 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); } - } + AssemblyField_LedStrip, + AssemblyField_ControlBoxId, + AssemblyField_StartUniverse, + AssemblyField_StartChannel, + AssemblyField_PointPlacementType, + AssemblyField_InterpolatePoints, + AssemblyField_Start, + AssemblyField_End, + AssemblyField_LedCount, + AssemblyField_TagsCount, + AssemblyField_Tag, + AssemblyField_Name, + AssemblyField_Value, - return Result; -} + AssemblyField_Count, +}; -internal v3 -ParseAssemblyVector (char* String) -{ - v3 Result = {}; +global_variable char* AssemblyFieldIdentifiers[] = { + "assembly_name", // AssemblyField_AssemblyName + "assembly_scale", // AssemblyField_AssemblyScale + "led_strip_count", // AssemblyField_LedStripCount - tokenizer Tokenizer = {}; - Tokenizer.At = String; + "led_strip", // AssemblyField_LedStrip - EatWhitespace(&Tokenizer); - Result.x = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); + "control_box_id", // AssemblyField_ControlBoxId + "start_universe", // AssemblyField_StartUniverse + "start_channel", // AssemblyField_StartChannel - EatWhitespace(&Tokenizer); - Result.y = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); + "point_placement_type", // AssemblyField_PointPlacementType + "interpolate_points", // AssemblyField_InterpolatePoints + "start", // AssemblyField_Start + "end", // AssemblyField_End - EatWhitespace(&Tokenizer); - Result.z = ParseFloatUnsafe(Tokenizer.At).FloatValue; - EatPastCharacter(&Tokenizer, ','); + "led_count", // AssemblyField_LedCount - return Result; -} + "tags_count", // AssemblyField_TagCount + "tag", // AssemblyField_Tag + "name", // AssemblyField_Name + "value", // AssemblyField_Value +}; -internal b32 -ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer) +struct assembly_tokenizer { - b32 HeaderIsValid = false; + string Text; + char* At; - 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; -} + u32 LineNumber; +}; -internal led_strip_definition -ParseLEDStrip (tokenizer* Tokenizer) +internal bool +AtValidPosition(assembly_tokenizer* T) { - 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); - + bool Result = ((T->At - T->Text.Memory) < T->Text.Length); return Result; } internal void -ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer) +AdvanceChar(assembly_tokenizer* T) { - EatWhitespace(Tokenizer); - - while(*Tokenizer->At) + if (IsNewline(T->At[0])) { - 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; - } + T->LineNumber += 1; } - - // 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); + T->At++; } -inline b32 -ParseTokenEquals (tokenizer* T, char* Validate) +internal void +EatWhitespace(assembly_tokenizer* T) { - b32 Result = true; + while(AtValidPosition(T) && IsNewlineOrWhitespace(T->At[0])) + { + AdvanceChar(T); + } +} + +internal bool +AdvanceIfTokenEquals(assembly_tokenizer* T, char* Value) +{ + bool Result = true; char* TAt = T->At; - char* VAt = Validate; - while (((TAt - T->Memory) < T->MemoryLength) && *VAt) + char* VAt = Value; + while (*VAt != 0) { - if (*VAt != *TAt) + if (*TAt != *VAt) { Result = false; break; } - TAt++; - *VAt++; + TAt += 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) { T->At = TAt; EatWhitespace(T); } - return Result; } -internal b32 -ParseComma(tokenizer* T) +internal bool +ReadFieldIdentifier(assembly_field Field, assembly_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)) + bool Result = false; + if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field])) { - for (u32 i = 0; i < 3; i++) + if (AdvanceIfTokenEquals(T, ":")) { - b32 ValueSuccess = ParseFloat(T, &(Value->E[i])); - if (!ValueSuccess) - { - Result = false; - break; - } - - b32 CommaSuccess = ParseComma(T); - if (!CommaSuccess) - { - break; - } + Result = true; } - - if (!ParseCloseParen(T)) + else { - Result = false; + // TODO(Peter): Error } } else { - Result = false; + // TODO(Peter): Error } - return Result; } -// TODO(Peter): :ErrorLogging -#define ParseLEDStripToken(tokenizer, parse_expr, error_msg) \ -(parse_expr) && (ParseComma(tokenizer)) - -internal b32 -ParseLEDStripCount (tokenizer* T, u32* Value) +internal bool +ReadFieldEnd(assembly_tokenizer* T) { - b32 Result = false; - - if (ParseTokenEquals(T, LED_STRIP_COUNT_IDENTIFIER)) + bool Result = AdvanceIfTokenEquals(T, ";"); + if (Result) { EatWhitespace(T); - if (ParseUnsignedInteger(T, Value)) + } + else + { + // TODO(Peter): Error + } + return Result; +} + +internal string +ReadString(assembly_tokenizer* T) +{ + string Result = {}; + if (AdvanceIfTokenEquals(T, "\"")) + { + char* StringStart = T->At; + while(AtValidPosition(T) && T->At[0] != '\"') + { + T->At++; + } + Result.Memory = StringStart; + Result.Max = T->At - StringStart; + Result.Length = Result.Max; + if (AdvanceIfTokenEquals(T, "\"")) + { + // Success + } + else + { + // TODO(Peter): Error + } + } + return Result; +} + +internal string +GetNumberString(assembly_tokenizer* T) +{ + string Result = {}; + Result.Memory = T->At; + while(AtValidPosition(T) && IsNumericExtended(T->At[0])) + { + AdvanceChar(T); + } + Result.Length = T->At - Result.Memory; + Result.Max = Result.Length; + return Result; +} + +internal r32 +ReadFloat(assembly_tokenizer* T) +{ + r32 Result = 0; + string NumberString = GetNumberString(T); + parse_result ParsedFloat = ParseFloat(StringExpand(NumberString)); + Result = ParsedFloat.FloatValue; + return Result; +} + +internal s32 +ReadInt(assembly_tokenizer* T) +{ + s32 Result = 0; + string NumberString = GetNumberString(T); + parse_result ParsedInt = ParseSignedInt(StringExpand(NumberString)); + Result = ParsedInt.SignedIntValue; + return Result; +} + +internal string +ReadStringField(assembly_field Field, assembly_tokenizer* T, memory_arena* Arena) +{ + string Result = {}; + if (ReadFieldIdentifier(Field, T)) + { + string ExistingString = ReadString(T); + if (ReadFieldEnd(T)) + { + // Success + Result = PushString(Arena, ExistingString.Length); + CopyStringTo(ExistingString, &Result); + } + else + { + // TODO(Peter): Error + } + } + return Result; +} + +internal r32 +ReadFloatField(assembly_field Field, assembly_tokenizer* T) +{ + r32 Result = 0.0f; + if (ReadFieldIdentifier(Field, T)) + { + Result = ReadFloat(T); + if (!ReadFieldEnd(T)) + { + // TODO(Peter): Error + } + } + return Result; +} + +internal s32 +ReadIntField(assembly_field Field, assembly_tokenizer* T) +{ + r32 Result = 0.0f; + if (ReadFieldIdentifier(Field, T)) + { + Result = ReadInt(T); + if (!ReadFieldEnd(T)) + { + // TODO(Peter): Error + } + } + return Result; +} + +internal v3 +ReadV3Field(assembly_field Field, assembly_tokenizer* T) +{ + v3 Result = {}; + if (ReadFieldIdentifier(Field, T)) + { + if (AdvanceIfTokenEquals(T, "(")) + { + Result.x = ReadFloat(T); + if (AdvanceIfTokenEquals(T, ",")) + { + Result.y = ReadFloat(T); + if (AdvanceIfTokenEquals(T, ",")) + { + Result.z = ReadFloat(T); + + if (AdvanceIfTokenEquals(T, ")")) + { + if (!ReadFieldEnd(T)) + { + // TODO(Peter): Error + } + } + } + } + } + } + return Result; +} + +internal bool +ReadStructOpening(assembly_field Field, assembly_tokenizer* T) +{ + bool Result = false; + if (ReadFieldIdentifier(Field, T)) + { + if (AdvanceIfTokenEquals(T, "{")) { Result = true; } } - return Result; } -internal b32 -ParseLEDStrip (led_strip_definition* Strip, tokenizer* T, memory_arena* Arena) +internal bool +ReadStructClosing(assembly_tokenizer* T) { - 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; - } - } - + bool Result = AdvanceIfTokenEquals(T, "};"); return Result; } -internal assembly_definition -ParseAssemblyFile (u8* FileBase, s32 FileSize, memory_arena* Arena, event_log* EventLog) +internal void +ParseAssemblyFile(assembly* Assembly, string FileText, memory_arena* Transient) { - assembly_definition Assembly = {}; + Assert(Assembly->Arena.Alloc != 0); + Assembly->LedCountTotal = 0; - tokenizer Tokenizer = {}; - Tokenizer.At = (char*)FileBase; - Tokenizer.Memory = (char*)FileBase; - Tokenizer.MemoryLength = FileSize; + assembly_tokenizer Tokenizer = {}; + Tokenizer.Text = FileText; + Tokenizer.At = Tokenizer.Text.Memory; - if (ParseLEDStripCount(&Tokenizer, &Assembly.LEDStripSize)) + Assembly->Name = ReadStringField(AssemblyField_AssemblyName, &Tokenizer, &Assembly->Arena); + Assembly->Scale = ReadFloatField(AssemblyField_AssemblyScale, &Tokenizer); + + Assembly->StripCount = ReadIntField(AssemblyField_LedStripCount, &Tokenizer); + Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount); + + for (u32 i = 0; i < Assembly->StripCount; i++) { - Assembly.LEDStrips = PushArray(Arena, led_strip_definition, Assembly.LEDStripSize); - - while (AtValidPosition(Tokenizer)) + v2_strip* StripAt = Assembly->Strips + i; + if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer)) { - EatWhitespace(&Tokenizer); + StripAt->ControlBoxID = ReadIntField(AssemblyField_ControlBoxId, &Tokenizer); + StripAt->StartUniverse = ReadIntField(AssemblyField_StartUniverse, &Tokenizer); + StripAt->StartChannel = ReadIntField(AssemblyField_StartChannel, &Tokenizer); - if (Assembly.LEDStripCount < Assembly.LEDStripSize) + // TODO(Peter): Need to store this + string PointPlacementType = ReadStringField(AssemblyField_PointPlacementType, &Tokenizer, &Assembly->Arena); + // TODO(Peter): Switch on value of PointPlacementType + if (ReadStructOpening(AssemblyField_InterpolatePoints, &Tokenizer)) { - led_strip_definition* LEDStrip = Assembly.LEDStrips + Assembly.LEDStripCount++; - - if (ParseLEDStrip(LEDStrip, &Tokenizer, Arena)) + StripAt->StartPosition = ReadV3Field(AssemblyField_Start, &Tokenizer); + StripAt->EndPosition = ReadV3Field(AssemblyField_End, &Tokenizer); + if (!ReadStructClosing(&Tokenizer)) { - Assembly.TotalLEDCount += LEDStrip->LEDsPerStrip; - } - else - { - LogError(EventLog, "Unable to parse LED strip in assembly file"); - break; + // TODO(Peter): Error + InvalidCodePath; } } - else + + StripAt->LedCount = ReadIntField(AssemblyField_LedCount, &Tokenizer); + Assembly->LedCountTotal += StripAt->LedCount; + + StripAt->TagsCount = ReadIntField(AssemblyField_TagsCount, &Tokenizer); + StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount); + for (u32 Tag = 0; Tag < StripAt->TagsCount; Tag++) { - if (ParseTokenEquals(&Tokenizer, END_ASSEMBLY_FILE_IDENTIFIER)) + v2_tag* TagAt = StripAt->Tags + Tag; + if (ReadStructOpening(AssemblyField_Tag, &Tokenizer)) { - break; - } - else - { - LogError(EventLog, "Did not find ent of file identifier in assembly file"); - break; + // TODO(Peter): Need to store the string somewhere we can look it up for display in the interface + // right now they are stored in temp memory and won't persist + string TagName = ReadStringField(AssemblyField_Name, &Tokenizer, Transient); + string TagValue = ReadStringField(AssemblyField_Value, &Tokenizer, Transient); + TagAt->NameHash = HashString(TagName); + TagAt->ValueHash = HashString(TagValue); + if (!ReadStructClosing(&Tokenizer)) + { + // TODO(Peter): Error + InvalidCodePath; + } } } + + if (!ReadStructClosing(&Tokenizer)) + { + // TODO(Peter): Error + InvalidCodePath; + } } } - else - { - // TODO(Peter): :ErrorLoggong - InvalidCodePath; - } - - return Assembly; } #define ASSEMBLY_PARSER_CPP 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_app.cpp b/src/app/foldhaus_app.cpp index 43b913e..5684f52 100644 --- a/src/app/foldhaus_app.cpp +++ b/src/app/foldhaus_app.cpp @@ -176,7 +176,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Camera.LookAt = v3{0, 0, 0}; #if 1 - string SculpturePath = MakeStringLiteral("data/blumen_lumen.fold"); + string SculpturePath = MakeStringLiteral("data/blumen_lumen_v2.fold"); LoadAssembly(State, Context, SculpturePath); #endif @@ -208,7 +208,9 @@ INITIALIZE_APPLICATION(InitializeApplication) InitializePanelSystem(&State->PanelSystem); panel* Panel = TakeNewPanel(&State->PanelSystem); - SetPanelDefinition(Panel, PanelType_SculptureView, State); + SplitPanelVertically(Panel, .5f, &State->PanelSystem); + SetPanelDefinition(&Panel->Left->Panel, PanelType_ProfilerView, State); + SetPanelDefinition(&Panel->Right->Panel, PanelType_SculptureView, State); } internal void @@ -462,6 +464,9 @@ UPDATE_AND_RENDER(UpdateAndRender) s32 HeaderSize = State->NetworkProtocolHeaderSize; dmx_buffer_list* DMXBuffers = 0; + // TODO(Peter): Come back and re add this in. It was tanking frame rate after + // updates to the assembly file format +#if 0 for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++) { gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); @@ -469,6 +474,7 @@ UPDATE_AND_RENDER(UpdateAndRender) dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(*Assembly, HeaderSize, &State->Transient); DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers); } +#endif //DEBUG_IF(GlobalDebugServices->Interface.SendSACNData) { diff --git a/src/app/foldhaus_app.h b/src/app/foldhaus_app.h index 47f995f..7a29134 100644 --- a/src/app/foldhaus_app.h +++ b/src/app/foldhaus_app.h @@ -18,17 +18,13 @@ #include "sacn/sacn.h" #include "foldhaus_assembly.h" +#include "assembly_parser.cpp" -#include "assembly_parser.h" #include "foldhaus_node.h" -// TODO(Peter): TEMPORARY -//u32 NodeSpecificationsCount = 0; -//node_specification* NodeSpecifications = 0; +typedef struct app_state app_state; - -#include "assembly_parser.cpp" #include "test_patterns.h" // TODO(Peter): something we can do later is to remove all reliance on app_state and context @@ -36,8 +32,6 @@ // perform operations on, like panel_draw_requests = { bounds, panel* } etc. #include "foldhaus_panel.h" -typedef struct app_state app_state; - #include "foldhaus_command_dispatch.h" #include "foldhaus_operation_mode.h" @@ -55,11 +49,18 @@ enum network_protocol NetworkProtocol_Count, }; +struct led_buffer +{ + led* Leds; + pixel* Colors; + led_buffer* Next; +}; + struct app_state { rect WindowBounds; - memory_arena Permanent; + memory_arena Permanent; memory_arena Transient; s32 NetworkProtocolHeaderSize; diff --git a/src/app/foldhaus_assembly.cpp b/src/app/foldhaus_assembly.cpp index 7b870db..dd9223e 100644 --- a/src/app/foldhaus_assembly.cpp +++ b/src/app/foldhaus_assembly.cpp @@ -5,60 +5,40 @@ // #ifndef FOLDHAUS_ASSEMBLY_CPP -internal assembly -ConstructAssemblyFromDefinition (assembly_definition Definition, - string AssemblyName, - v4 RootPosition, - r32 Scale, - memory_arena Arena) +internal void +ConstructAssemblyFromDefinition (assembly* Assembly, string AssemblyName, v4 RootPosition) { - 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); + Assembly->LEDBuffer.LEDCount = 0; + Assembly->LEDBuffer.Colors = PushArray(&Assembly->Arena, pixel, Assembly->LedCountTotal); + Assembly->LEDBuffer.LEDs = PushArray(&Assembly->Arena, led, Assembly->LedCountTotal); + Assembly->LEDUniverseMapCount = Assembly->LedCountTotal; + Assembly->LEDUniverseMap = PushArray(&Assembly->Arena, leds_in_universe_range, Assembly->LedCountTotal); // Add LEDs - for (u32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++) + for (u32 StripIdx = 0; StripIdx < Assembly->StripCount; StripIdx++) { - led_strip_definition StripDef = Definition.LEDStrips[StripIdx]; + //led_strip_definition StripDef = Definition.LEDStrips[StripIdx]; + v2_strip* StripAt = &Assembly->Strips[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; + leds_in_universe_range* LEDUniverseRange = &Assembly->LEDUniverseMap[StripIdx]; - // 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); + LEDUniverseRange->Universe = StripAt->StartUniverse; + LEDUniverseRange->RangeStart = Assembly->LEDBuffer.LEDCount; + LEDUniverseRange->RangeOnePastLast = Assembly->LEDBuffer.LEDCount + StripAt->LedCount; - 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 WS_StripStart = RootPosition + V4(StripAt->StartPosition * Assembly->Scale, 1); + v4 WS_StripEnd = RootPosition + V4(StripAt->EndPosition * Assembly->Scale, 1); + s32 LEDsInStripCount = StripAt->LedCount; 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; + s32 LEDIndex = Assembly->LEDBuffer.LEDCount; + Assembly->LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step); + Assembly->LEDBuffer.LEDs[LEDIndex].Index = LEDIndex; + Assembly->LEDBuffer.LEDCount += 1; } } - - // 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 @@ -73,18 +53,18 @@ LoadAssembly (app_state* State, context Context, string Path) platform_memory_result AssemblyFile = ReadEntireFile(Context, Path); if (AssemblyFile.Error == PlatformMemory_NoError) { - assembly_definition AssemblyDefinition = ParseAssemblyFile(AssemblyFile.Base, AssemblyFile.Size, &State->Transient, State->GlobalLog); + string AssemblyFileText = MakeString((char*)AssemblyFile.Base); s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(Path.Memory, Path.Length, '\\'); string FileName = Substring(Path, IndexOfLastSlash + 1); - memory_arena AssemblyArena = {}; - AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; - AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + assembly NewAssembly = {}; + NewAssembly.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; + NewAssembly.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; + ParseAssemblyFile(&NewAssembly, AssemblyFileText, &State->Transient); v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount]; - r32 Scale = 100; - assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, Offset, Scale, AssemblyArena); + ConstructAssemblyFromDefinition(&NewAssembly, FileName, Offset); gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly); State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle); diff --git a/src/app/foldhaus_assembly.h b/src/app/foldhaus_assembly.h index 5852583..e414e7a 100644 --- a/src/app/foldhaus_assembly.h +++ b/src/app/foldhaus_assembly.h @@ -22,7 +22,7 @@ union pixel u8 Channels[3]; }; -// NOTE(Peter): This structure is so we can keep track of +// 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. @@ -40,6 +40,30 @@ struct assembly_led_buffer led* LEDs; }; +struct v2_tag +{ + u64 NameHash; + u64 ValueHash; +}; + +struct v2_strip +{ + s32 ControlBoxID; // TODO(Peter): I don't think we need this anymore + s32 StartUniverse; + s32 StartChannel; + + // TODO(Peter): When we create more ways to calculate points, this needs to become + // a type enum and a union + v3 StartPosition; + v3 EndPosition; + + u32 LedCount; + u32* LedLUT; + + u32 TagsCount; + v2_tag* Tags; +}; + struct assembly { memory_arena Arena; @@ -47,13 +71,13 @@ struct assembly string Name; string FilePath; - assembly_led_buffer LEDBuffer; + r32 Scale; -#if 0 - u32 LEDCount; - pixel* Colors; - led* LEDs; -#endif + u32 StripCount; + v2_strip* Strips; + + s32 LedCountTotal; + assembly_led_buffer LEDBuffer; u32 LEDUniverseMapCount; leds_in_universe_range* LEDUniverseMap; diff --git a/src/app/foldhaus_interface.cpp b/src/app/foldhaus_interface.cpp index 86684f5..823b652 100644 --- a/src/app/foldhaus_interface.cpp +++ b/src/app/foldhaus_interface.cpp @@ -242,12 +242,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation) if (XDistance > YDistance) { r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / gs_Width(PanelBounds); - SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); + SplitPanelVertically(Panel, XPercent, &State->PanelSystem); } else { r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / gs_Height(PanelBounds); - SplitPanelHorizontally(Panel, YPercent, PanelBounds, &State->PanelSystem); + SplitPanelHorizontally(Panel, YPercent, &State->PanelSystem); } Panel->Left->Panel.PanelDefinitionIndex = Panel->PanelDefinitionIndex; diff --git a/src/app/foldhaus_panel.h b/src/app/foldhaus_panel.h index 27f290a..2929c8b 100644 --- a/src/app/foldhaus_panel.h +++ b/src/app/foldhaus_panel.h @@ -4,7 +4,7 @@ // Creation Date: 2019-12-26 // // Usage: -// Include this file in ONE file in your project. +// Include this file in ONE file in your project. // Define SetPanelDefinitionExternal // #ifndef FOLDHAUS_PANEL_H @@ -67,8 +67,8 @@ struct panel_system }; // 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. +// 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; @@ -154,10 +154,9 @@ FreePanelAtIndex(s32 Index, panel_system* PanelSystem) } internal void -SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) +SplitPanelVertically(panel* Parent, r32 Percent, panel_system* PanelSystem) { - r32 SplitX = GSLerp(ParentBounds.Min.x, ParentBounds.Max.x, Percent); - if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x) + if (Percent >= 0.0f && Percent <= 1.0f) { Parent->SplitDirection = PanelSplit_Vertical; Parent->SplitPercent = Percent; @@ -171,10 +170,9 @@ SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system } internal void -SplitPanelHorizontally(panel* Parent, r32 Percent, rect ParentBounds, panel_system* PanelSystem) +SplitPanelHorizontally(panel* Parent, r32 Percent, panel_system* PanelSystem) { - r32 SplitY = GSLerp(ParentBounds.Min.y, ParentBounds.Max.y, Percent); - if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y) + if (Percent >= 0.0f && Percent <= 1.0f) { Parent->SplitDirection = PanelSplit_Horizontal; Parent->SplitPercent = Percent;