Finished parsing the new assembly file format

This commit is contained in:
Peter Slattery 2020-06-09 20:33:51 -07:00
parent c2f3b9193d
commit bfd9d6671c
8 changed files with 381 additions and 502 deletions

View File

@ -5,440 +5,386 @@
// //
#ifndef ASSEMBLY_PARSER_CPP #ifndef ASSEMBLY_PARSER_CPP
internal assembly_token enum assembly_field
ParseToken (tokenizer* Tokenizer)
{ {
assembly_token Result = {}; AssemblyField_AssemblyName,
Result.Token = Tokenizer->At; AssemblyField_AssemblyScale,
Result.Length = 1; AssemblyField_LedStripCount,
EatChar(Tokenizer);
if (*Result.Token == ':'){ Result.Type = AssemblyToken_Colon; } AssemblyField_LedStrip,
else if (*Result.Token == ';'){ Result.Type = AssemblyToken_SemiColon; } AssemblyField_ControlBoxId,
else if (*Result.Token =='{'){ Result.Type = AssemblyToken_LeftCurlyBrace; } AssemblyField_StartUniverse,
else if (*Result.Token =='}'){ Result.Type = AssemblyToken_RightCurlyBrace; } AssemblyField_StartChannel,
else if (*Result.Token ==','){ Result.Type = AssemblyToken_Comma; } AssemblyField_PointPlacementType,
else if (IsNumericExtended(*Result.Token)) AssemblyField_InterpolatePoints,
{ AssemblyField_Start,
while(*Tokenizer->At && IsNumericExtended(*Tokenizer->At)) { EatChar(Tokenizer); } AssemblyField_End,
Result.Type = AssemblyToken_Number; AssemblyField_LedCount,
Result.Length = Tokenizer->At - Result.Token; AssemblyField_TagsCount,
} AssemblyField_Tag,
else if (*Result.Token =='\"') AssemblyField_Name,
{ AssemblyField_Value,
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; AssemblyField_Count,
} };
internal v3 global_variable char* AssemblyFieldIdentifiers[] = {
ParseAssemblyVector (char* String) "assembly_name", // AssemblyField_AssemblyName
"assembly_scale", // AssemblyField_AssemblyScale
"led_strip_count", // AssemblyField_LedStripCount
"led_strip", // AssemblyField_LedStrip
"control_box_id", // AssemblyField_ControlBoxId
"start_universe", // AssemblyField_StartUniverse
"start_channel", // AssemblyField_StartChannel
"point_placement_type", // AssemblyField_PointPlacementType
"interpolate_points", // AssemblyField_InterpolatePoints
"start", // AssemblyField_Start
"end", // AssemblyField_End
"led_count", // AssemblyField_LedCount
"tags_count", // AssemblyField_TagCount
"tag", // AssemblyField_Tag
"name", // AssemblyField_Name
"value", // AssemblyField_Value
};
struct assembly_tokenizer
{ {
v3 Result = {}; string Text;
char* At;
tokenizer Tokenizer = {}; u32 LineNumber;
Tokenizer.At = String; };
EatWhitespace(&Tokenizer); internal bool
Result.x = ParseFloatUnsafe(Tokenizer.At).FloatValue; AtValidPosition(assembly_tokenizer* T)
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; bool Result = ((T->At - T->Text.Memory) < T->Text.Length);
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; return Result;
} }
internal void internal void
ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer) AdvanceChar(assembly_tokenizer* T)
{ {
EatWhitespace(Tokenizer); if (IsNewline(T->At[0]))
while(*Tokenizer->At)
{ {
EatWhitespace(Tokenizer); T->LineNumber += 1;
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->At++;
// 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 internal void
ParseTokenEquals (tokenizer* T, char* Validate) 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* TAt = T->At;
char* VAt = Validate; char* VAt = Value;
while (((TAt - T->Memory) < T->MemoryLength) && *VAt) while (*VAt != 0)
{ {
if (*VAt != *TAt) if (*TAt != *VAt)
{ {
Result = false; Result = false;
break; break;
} }
TAt++; TAt += 1;
*VAt++; 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) if (Result)
{ {
T->At = TAt; T->At = TAt;
EatWhitespace(T); EatWhitespace(T);
} }
return Result; return Result;
} }
internal b32 internal bool
ParseComma(tokenizer* T) ReadFieldIdentifier(assembly_field Field, assembly_tokenizer* T)
{ {
b32 Result = ParseTokenEquals(T, ","); bool Result = false;
return Result; if (AdvanceIfTokenEquals(T, AssemblyFieldIdentifiers[Field]))
}
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++) if (AdvanceIfTokenEquals(T, ":"))
{ {
b32 ValueSuccess = ParseFloat(T, &(Value->E[i])); Result = true;
if (!ValueSuccess)
{
Result = false;
break;
}
b32 CommaSuccess = ParseComma(T);
if (!CommaSuccess)
{
break;
}
} }
else
if (!ParseCloseParen(T))
{ {
Result = false; // TODO(Peter): Error
} }
} }
else else
{ {
Result = false; // TODO(Peter): Error
} }
return Result; return Result;
} }
// TODO(Peter): :ErrorLogging internal bool
#define ParseLEDStripToken(tokenizer, parse_expr, error_msg) \ ReadFieldEnd(assembly_tokenizer* T)
(parse_expr) && (ParseComma(tokenizer))
internal b32
ParseLEDStripCount (tokenizer* T, u32* Value)
{ {
b32 Result = false; bool Result = AdvanceIfTokenEquals(T, ";");
if (Result)
if (ParseTokenEquals(T, LED_STRIP_COUNT_IDENTIFIER))
{ {
EatWhitespace(T); 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; Result = true;
} }
} }
return Result; return Result;
} }
internal b32 internal bool
ParseLEDStrip (led_strip_definition* Strip, tokenizer* T, memory_arena* Arena) ReadStructClosing(assembly_tokenizer* T)
{ {
b32 Result = false; bool Result = AdvanceIfTokenEquals(T, "};");
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; return Result;
} }
internal assembly_definition internal void
ParseAssemblyFile (u8* FileBase, s32 FileSize, memory_arena* Arena, event_log* EventLog) ParseAssemblyFile(assembly* Assembly, string FileText, memory_arena* Transient)
{ {
assembly_definition Assembly = {}; Assert(Assembly->Arena.Alloc != 0);
Assembly->LedCountTotal = 0;
tokenizer Tokenizer = {}; assembly_tokenizer Tokenizer = {};
Tokenizer.At = (char*)FileBase; Tokenizer.Text = FileText;
Tokenizer.Memory = (char*)FileBase; Tokenizer.At = Tokenizer.Text.Memory;
Tokenizer.MemoryLength = FileSize;
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); v2_strip* StripAt = Assembly->Strips + i;
if (ReadStructOpening(AssemblyField_LedStrip, &Tokenizer))
while (AtValidPosition(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++; StripAt->StartPosition = ReadV3Field(AssemblyField_Start, &Tokenizer);
StripAt->EndPosition = ReadV3Field(AssemblyField_End, &Tokenizer);
if (ParseLEDStrip(LEDStrip, &Tokenizer, Arena)) if (!ReadStructClosing(&Tokenizer))
{ {
Assembly.TotalLEDCount += LEDStrip->LEDsPerStrip; // TODO(Peter): Error
} InvalidCodePath;
else
{
LogError(EventLog, "Unable to parse LED strip in assembly file");
break;
} }
} }
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; // 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
else string TagName = ReadStringField(AssemblyField_Name, &Tokenizer, Transient);
{ string TagValue = ReadStringField(AssemblyField_Value, &Tokenizer, Transient);
LogError(EventLog, "Did not find ent of file identifier in assembly file"); TagAt->NameHash = HashString(TagName);
break; 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 #define ASSEMBLY_PARSER_CPP

View File

@ -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

View File

@ -176,7 +176,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->Camera.LookAt = v3{0, 0, 0}; State->Camera.LookAt = v3{0, 0, 0};
#if 1 #if 1
string SculpturePath = MakeStringLiteral("data/blumen_lumen.fold"); string SculpturePath = MakeStringLiteral("data/blumen_lumen_v2.fold");
LoadAssembly(State, Context, SculpturePath); LoadAssembly(State, Context, SculpturePath);
#endif #endif
@ -208,7 +208,9 @@ INITIALIZE_APPLICATION(InitializeApplication)
InitializePanelSystem(&State->PanelSystem); InitializePanelSystem(&State->PanelSystem);
panel* Panel = TakeNewPanel(&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 internal void
@ -462,6 +464,9 @@ UPDATE_AND_RENDER(UpdateAndRender)
s32 HeaderSize = State->NetworkProtocolHeaderSize; s32 HeaderSize = State->NetworkProtocolHeaderSize;
dmx_buffer_list* DMXBuffers = 0; 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++) for (u32 i = 0; i < State->ActiveAssemblyIndecies.Used; i++)
{ {
gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(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); dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(*Assembly, HeaderSize, &State->Transient);
DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers); DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers);
} }
#endif
//DEBUG_IF(GlobalDebugServices->Interface.SendSACNData) //DEBUG_IF(GlobalDebugServices->Interface.SendSACNData)
{ {

View File

@ -18,17 +18,13 @@
#include "sacn/sacn.h" #include "sacn/sacn.h"
#include "foldhaus_assembly.h" #include "foldhaus_assembly.h"
#include "assembly_parser.cpp"
#include "assembly_parser.h"
#include "foldhaus_node.h" #include "foldhaus_node.h"
// TODO(Peter): TEMPORARY typedef struct app_state app_state;
//u32 NodeSpecificationsCount = 0;
//node_specification* NodeSpecifications = 0;
#include "assembly_parser.cpp"
#include "test_patterns.h" #include "test_patterns.h"
// TODO(Peter): something we can do later is to remove all reliance on app_state and context // 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. // perform operations on, like panel_draw_requests = { bounds, panel* } etc.
#include "foldhaus_panel.h" #include "foldhaus_panel.h"
typedef struct app_state app_state;
#include "foldhaus_command_dispatch.h" #include "foldhaus_command_dispatch.h"
#include "foldhaus_operation_mode.h" #include "foldhaus_operation_mode.h"
@ -55,6 +49,13 @@ enum network_protocol
NetworkProtocol_Count, NetworkProtocol_Count,
}; };
struct led_buffer
{
led* Leds;
pixel* Colors;
led_buffer* Next;
};
struct app_state struct app_state
{ {
rect WindowBounds; rect WindowBounds;

View File

@ -5,60 +5,40 @@
// //
#ifndef FOLDHAUS_ASSEMBLY_CPP #ifndef FOLDHAUS_ASSEMBLY_CPP
internal assembly internal void
ConstructAssemblyFromDefinition (assembly_definition Definition, ConstructAssemblyFromDefinition (assembly* Assembly, string AssemblyName, v4 RootPosition)
string AssemblyName,
v4 RootPosition,
r32 Scale,
memory_arena Arena)
{ {
assembly Assembly = {}; Assembly->LEDBuffer.LEDCount = 0;
Assembly.Arena = Arena; Assembly->LEDBuffer.Colors = PushArray(&Assembly->Arena, pixel, Assembly->LedCountTotal);
Assembly->LEDBuffer.LEDs = PushArray(&Assembly->Arena, led, Assembly->LedCountTotal);
Assembly.Name = MakeString(PushArray(&Assembly.Arena, char, AssemblyName.Length), AssemblyName.Length); Assembly->LEDUniverseMapCount = Assembly->LedCountTotal;
CopyStringTo(AssemblyName, &Assembly.Name); Assembly->LEDUniverseMap = PushArray(&Assembly->Arena, leds_in_universe_range, Assembly->LedCountTotal);
// 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 // 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; 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 LEDUniverseRange->Universe = StripAt->StartUniverse;
// now. The assert is to remind you to create more cases when necessary LEDUniverseRange->RangeStart = Assembly->LEDBuffer.LEDCount;
Assert(StripDef.InterpolationType == StripInterpolate_Points); LEDUniverseRange->RangeOnePastLast = Assembly->LEDBuffer.LEDCount + StripAt->LedCount;
v4 WS_StripStart = RootPosition + V4(StripDef.InterpolatePositionStart * Scale, 1); v4 WS_StripStart = RootPosition + V4(StripAt->StartPosition * Assembly->Scale, 1);
v4 WS_StripEnd = RootPosition + V4(StripDef.InterpolatePositionEnd * Scale, 1); v4 WS_StripEnd = RootPosition + V4(StripAt->EndPosition * Assembly->Scale, 1);
s32 LEDsInStripCount = StripDef.LEDsPerStrip; s32 LEDsInStripCount = StripAt->LedCount;
Assert(Assembly.LEDBuffer.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)LEDsInStripCount; v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)LEDsInStripCount;
for (s32 Step = 0; Step < LEDsInStripCount; Step++) for (s32 Step = 0; Step < LEDsInStripCount; Step++)
{ {
s32 LEDIndex = Assembly.LEDBuffer.LEDCount++; s32 LEDIndex = Assembly->LEDBuffer.LEDCount;
Assembly.LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step); Assembly->LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step);
Assembly.LEDBuffer.LEDs[LEDIndex].Index = LEDIndex; 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 // 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); platform_memory_result AssemblyFile = ReadEntireFile(Context, Path);
if (AssemblyFile.Error == PlatformMemory_NoError) 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, '\\'); s32 IndexOfLastSlash = FastLastIndexOfCharInCharArray(Path.Memory, Path.Length, '\\');
string FileName = Substring(Path, IndexOfLastSlash + 1); string FileName = Substring(Path, IndexOfLastSlash + 1);
memory_arena AssemblyArena = {}; assembly NewAssembly = {};
AssemblyArena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; NewAssembly.Arena.Alloc = (gs_memory_alloc*)Context.PlatformAlloc;
AssemblyArena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; NewAssembly.Arena.Realloc = (gs_memory_realloc*)Context.PlatformRealloc;
ParseAssemblyFile(&NewAssembly, AssemblyFileText, &State->Transient);
v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount]; v4 Offset = TempAssemblyOffsets[State->ActiveAssemblyIndecies.Used % TempAssemblyOffsetsCount];
r32 Scale = 100; ConstructAssemblyFromDefinition(&NewAssembly, FileName, Offset);
assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, Offset, Scale, AssemblyArena);
gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly); gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly);
State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle); State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle);

View File

@ -40,6 +40,30 @@ struct assembly_led_buffer
led* LEDs; 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 struct assembly
{ {
memory_arena Arena; memory_arena Arena;
@ -47,13 +71,13 @@ struct assembly
string Name; string Name;
string FilePath; string FilePath;
assembly_led_buffer LEDBuffer; r32 Scale;
#if 0 u32 StripCount;
u32 LEDCount; v2_strip* Strips;
pixel* Colors;
led* LEDs; s32 LedCountTotal;
#endif assembly_led_buffer LEDBuffer;
u32 LEDUniverseMapCount; u32 LEDUniverseMapCount;
leds_in_universe_range* LEDUniverseMap; leds_in_universe_range* LEDUniverseMap;

View File

@ -242,12 +242,12 @@ FOLDHAUS_INPUT_COMMAND_PROC(EndSplitPanelOperation)
if (XDistance > YDistance) if (XDistance > YDistance)
{ {
r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / gs_Width(PanelBounds); r32 XPercent = (Mouse.Pos.x - PanelBounds.Min.x) / gs_Width(PanelBounds);
SplitPanelVertically(Panel, XPercent, PanelBounds, &State->PanelSystem); SplitPanelVertically(Panel, XPercent, &State->PanelSystem);
} }
else else
{ {
r32 YPercent = (Mouse.Pos.y - PanelBounds.Min.y) / gs_Height(PanelBounds); 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; Panel->Left->Panel.PanelDefinitionIndex = Panel->PanelDefinitionIndex;

View File

@ -154,10 +154,9 @@ FreePanelAtIndex(s32 Index, panel_system* PanelSystem)
} }
internal void 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 (Percent >= 0.0f && Percent <= 1.0f)
if (SplitX > ParentBounds.Min.x && SplitX < ParentBounds.Max.x)
{ {
Parent->SplitDirection = PanelSplit_Vertical; Parent->SplitDirection = PanelSplit_Vertical;
Parent->SplitPercent = Percent; Parent->SplitPercent = Percent;
@ -171,10 +170,9 @@ SplitPanelVertically(panel* Parent, r32 Percent, rect ParentBounds, panel_system
} }
internal void 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 (Percent >= 0.0f && Percent <= 1.0f)
if (SplitY > ParentBounds.Min.y && SplitY < ParentBounds.Max.y)
{ {
Parent->SplitDirection = PanelSplit_Horizontal; Parent->SplitDirection = PanelSplit_Horizontal;
Parent->SplitPercent = Percent; Parent->SplitPercent = Percent;