Finished parsing the new assembly file format
This commit is contained in:
parent
c2f3b9193d
commit
bfd9d6671c
|
@ -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
|
||||||
v3 Result = {};
|
"led_strip_count", // AssemblyField_LedStripCount
|
||||||
|
|
||||||
tokenizer Tokenizer = {};
|
"led_strip", // AssemblyField_LedStrip
|
||||||
Tokenizer.At = String;
|
|
||||||
|
|
||||||
EatWhitespace(&Tokenizer);
|
"control_box_id", // AssemblyField_ControlBoxId
|
||||||
Result.x = ParseFloatUnsafe(Tokenizer.At).FloatValue;
|
"start_universe", // AssemblyField_StartUniverse
|
||||||
EatPastCharacter(&Tokenizer, ',');
|
"start_channel", // AssemblyField_StartChannel
|
||||||
|
|
||||||
EatWhitespace(&Tokenizer);
|
"point_placement_type", // AssemblyField_PointPlacementType
|
||||||
Result.y = ParseFloatUnsafe(Tokenizer.At).FloatValue;
|
"interpolate_points", // AssemblyField_InterpolatePoints
|
||||||
EatPastCharacter(&Tokenizer, ',');
|
"start", // AssemblyField_Start
|
||||||
|
"end", // AssemblyField_End
|
||||||
|
|
||||||
EatWhitespace(&Tokenizer);
|
"led_count", // AssemblyField_LedCount
|
||||||
Result.z = ParseFloatUnsafe(Tokenizer.At).FloatValue;
|
|
||||||
EatPastCharacter(&Tokenizer, ',');
|
|
||||||
|
|
||||||
return Result;
|
"tags_count", // AssemblyField_TagCount
|
||||||
}
|
"tag", // AssemblyField_Tag
|
||||||
|
"name", // AssemblyField_Name
|
||||||
|
"value", // AssemblyField_Value
|
||||||
|
};
|
||||||
|
|
||||||
internal b32
|
struct assembly_tokenizer
|
||||||
ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer)
|
|
||||||
{
|
{
|
||||||
b32 HeaderIsValid = false;
|
string Text;
|
||||||
|
char* At;
|
||||||
|
|
||||||
if (CharArraysEqualUpToLength(Tokenizer->At, LED_STRIP_COUNT_IDENTIFIER, CharArrayLength(LED_STRIP_COUNT_IDENTIFIER)))
|
u32 LineNumber;
|
||||||
{
|
};
|
||||||
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
|
internal bool
|
||||||
ParseLEDStrip (tokenizer* Tokenizer)
|
AtValidPosition(assembly_tokenizer* T)
|
||||||
{
|
{
|
||||||
led_strip_definition Result = {};
|
bool Result = ((T->At - T->Text.Memory) < T->Text.Length);
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -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
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,11 +49,18 @@ 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;
|
||||||
|
|
||||||
memory_arena Permanent;
|
memory_arena Permanent;
|
||||||
memory_arena Transient;
|
memory_arena Transient;
|
||||||
|
|
||||||
s32 NetworkProtocolHeaderSize;
|
s32 NetworkProtocolHeaderSize;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -22,7 +22,7 @@ union pixel
|
||||||
u8 Channels[3];
|
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
|
// what LEDs output to which DMX universe. You don't need
|
||||||
// to use it anywhere else, as all the data for patterns,
|
// to use it anywhere else, as all the data for patterns,
|
||||||
// colors, and groups is/will be stored elsewhere.
|
// colors, and groups is/will be stored elsewhere.
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// Creation Date: 2019-12-26
|
// Creation Date: 2019-12-26
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
// Include this file in ONE file in your project.
|
// Include this file in ONE file in your project.
|
||||||
// Define SetPanelDefinitionExternal
|
// Define SetPanelDefinitionExternal
|
||||||
//
|
//
|
||||||
#ifndef FOLDHAUS_PANEL_H
|
#ifndef FOLDHAUS_PANEL_H
|
||||||
|
@ -67,8 +67,8 @@ struct panel_system
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(Peter): This representation is used to let external code render and interact
|
// 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
|
// with panels. It shouldn't be stored across frame boundaries as the pointers to
|
||||||
// Panel's are liable to change.
|
// Panel's are liable to change.
|
||||||
struct panel_with_layout
|
struct panel_with_layout
|
||||||
{
|
{
|
||||||
panel* Panel;
|
panel* Panel;
|
||||||
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue