implemented segmented led strips

This commit is contained in:
PS 2020-10-11 20:54:38 -07:00
parent 0ba59d3767
commit bfd50c9129
9 changed files with 451 additions and 157 deletions

View File

@ -166,7 +166,7 @@ SculptureView_Render(panel Panel, rect2 PanelBounds, render_command_buffer* Rend
u32 MaxLEDsPerJob = 2048; u32 MaxLEDsPerJob = 2048;
render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal); render_quad_batch_constructor RenderLEDsBatch = PushRenderQuad3DBatch(RenderBuffer, State->LedSystem.LedsCountTotal);
u32 FocusPixel = 256; u32 FocusPixel = 100;
for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++) for (u32 BufferIndex = 0; BufferIndex < State->LedSystem.BuffersCount; BufferIndex++)
{ {

View File

@ -135,6 +135,46 @@ LedBufferSetLed(led_buffer* Buffer, u32 Led, v4 Position)
Buffer->Positions[Led] = Position; Buffer->Positions[Led] = Position;
} }
internal u32
Assembly_ConstructStrip(assembly* Assembly, led_buffer* LedBuffer, v2_strip* StripAt, strip_gen_data GenData, v4 RootPosition, u32 LedStartIndex)
{
u32 LedsAdded = 0;
switch (GenData.Method)
{
case StripGeneration_InterpolatePoints:
{
strip_gen_interpolate_points InterpPoints = GenData.InterpolatePoints;
v4 WS_StripStart = RootPosition + ToV4Point(InterpPoints.StartPosition * Assembly->Scale);
v4 WS_StripEnd = RootPosition + ToV4Point(InterpPoints.EndPosition * Assembly->Scale);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)InterpPoints.LedCount;
for (u32 Step = 0; Step < InterpPoints.LedCount; Step++)
{
s32 LedIndex = LedStartIndex + LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step] = LedIndex;
}
}break;
case StripGeneration_Sequence:
{
strip_gen_sequence Sequence = GenData.Sequence;
for (u32 i = 0; i < Sequence.ElementsCount; i++)
{
__debugbreak();
strip_gen_data SegmentGenData = Sequence.Elements[i];
LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, SegmentGenData, RootPosition, LedStartIndex + LedsAdded);
}
}break;
InvalidDefaultCase;
}
return LedsAdded;
}
internal void internal void
ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem) ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
{ {
@ -150,17 +190,8 @@ ConstructAssemblyFromDefinition (assembly* Assembly, led_system* LedSystem)
v2_strip* StripAt = &Assembly->Strips[StripIdx]; v2_strip* StripAt = &Assembly->Strips[StripIdx];
StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount); StripAt->LedLUT = PushArray(&Assembly->Arena, u32, StripAt->LedCount);
v4 WS_StripStart = RootPosition + ToV4Point(StripAt->StartPosition * Assembly->Scale); strip_gen_data GenData = StripAt->GenerationData;
v4 WS_StripEnd = RootPosition + ToV4Point(StripAt->EndPosition * Assembly->Scale); LedsAdded += Assembly_ConstructStrip(Assembly, LedBuffer, StripAt, GenData, RootPosition, LedsAdded);
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)StripAt->LedCount;
for (u32 Step = 0; Step < StripAt->LedCount; Step++)
{
s32 LedIndex = LedsAdded++;
v4 LedPosition = WS_StripStart + (SingleStep * Step);
LedBufferSetLed(LedBuffer, LedIndex, LedPosition);
StripAt->LedLUT[Step] = LedIndex;
}
} }
} }

View File

@ -58,6 +58,41 @@ struct strip_sacn_addr
struct strip_uart_addr struct strip_uart_addr
{ {
u8 Channel; u8 Channel;
gs_string ComPort;
// This may not be used based on the value of the parent
// assembly's NetworkPortMode field
};
enum strip_gen_method
{
StripGeneration_InterpolatePoints,
StripGeneration_Sequence,
StripGeneration_Count,
};
typedef struct strip_gen_data strip_gen_data;
struct strip_gen_interpolate_points
{
v3 StartPosition;
v3 EndPosition;
u32 LedCount;
};
struct strip_gen_sequence
{
strip_gen_data* Elements;
u32 ElementsCount;
};
struct strip_gen_data
{
strip_gen_method Method;
strip_gen_interpolate_points InterpolatePoints;
strip_gen_sequence Sequence;
}; };
struct v2_strip struct v2_strip
@ -67,10 +102,7 @@ struct v2_strip
strip_sacn_addr SACNAddr; strip_sacn_addr SACNAddr;
strip_uart_addr UARTAddr; strip_uart_addr UARTAddr;
// TODO(Peter): When we create more ways to calculate points, this needs to become strip_gen_data GenerationData;
// a type enum and a union
v3 StartPosition;
v3 EndPosition;
u32 LedCount; u32 LedCount;
u32* LedLUT; u32* LedLUT;
@ -86,6 +118,21 @@ struct led_strip_list
u32* StripIndices; u32* StripIndices;
}; };
enum network_port_mode
{
// This enum defines the scope which contains what network
// port each address should be sent over.
NetworkPortMode_GlobalPort,
// GlobalPort means that the port is defined in the assembly structure
NetworkPortMode_PortPerStrip,
// PortPerStrip means that the address stored in the strip structure
// should be used, and each strip might have a different port
NetworkPortMode_Count,
};
struct assembly struct assembly
{ {
gs_memory_arena Arena; gs_memory_arena Arena;
@ -102,7 +149,8 @@ struct assembly
v2_strip* Strips; v2_strip* Strips;
network_protocol OutputMode; network_protocol OutputMode;
gs_const_string UARTComPort; network_port_mode NetPortMode;
gs_string UARTComPort;
}; };
struct assembly_array struct assembly_array
@ -120,6 +168,31 @@ LedSystemGetBuffer(led_system* System, u32 Index)
return Result; return Result;
} }
internal u32
StripGenData_CountLeds(strip_gen_data Data)
{
u32 Result = 0;
switch (Data.Method)
{
case StripGeneration_InterpolatePoints:
{
Result += Data.InterpolatePoints.LedCount;
}break;
case StripGeneration_Sequence:
{
for (u32 i = 0; i < Data.Sequence.ElementsCount; i++)
{
Result += StripGenData_CountLeds(Data.Sequence.Elements[i]);
}
}break;
InvalidDefaultCase;
}
return Result;
}
#define FOLDHAUS_ASSEMBLY_H #define FOLDHAUS_ASSEMBLY_H
#endif // FOLDHAUS_ASSEMBLY_H #endif // FOLDHAUS_ASSEMBLY_H

View File

@ -33,10 +33,16 @@ enum assembly_field
AssemblyField_UART_ComPort, AssemblyField_UART_ComPort,
AssemblyField_PointPlacementType, AssemblyField_PointPlacementType,
AssemblyField_InterpolatePoints, AssemblyField_InterpolatePoints,
AssemblyField_Start, AssemblyField_Start,
AssemblyField_End, AssemblyField_End,
AssemblyField_LedCount, AssemblyField_LedCount,
AssemblyField_SegmentSequence,
AssemblyField_SegmentSequenceLength,
AssemblyField_Segment,
AssemblyField_TagsCount, AssemblyField_TagsCount,
AssemblyField_Tag, AssemblyField_Tag,
AssemblyField_Name, AssemblyField_Name,
@ -63,12 +69,16 @@ global gs_const_string AssemblyFieldIdentifiers[] = {
ConstString("com_port"), // AssemblyField_UART_ComPort ConstString("com_port"), // AssemblyField_UART_ComPort
ConstString("point_placement_type"), // AssemblyField_PointPlacementType ConstString("point_placement_type"), // AssemblyField_PointPlacementType
ConstString("interpolate_points"), // AssemblyField_InterpolatePoints ConstString("interpolate_points"), // AssemblyField_InterpolatePoints
ConstString("start"), // AssemblyField_Start ConstString("start"), // AssemblyField_Start
ConstString("end"), // AssemblyField_End ConstString("end"), // AssemblyField_End
ConstString("led_count"), // AssemblyField_LedCount ConstString("led_count"), // AssemblyField_LedCount
ConstString("segment_sequence"), // AssemblyField_SegmentSequence
ConstString("segment_count"), // AssemblyField_SegmentSequenceLength
ConstString("segment"), // AssemblyField_Segment
ConstString("tags_count"), // AssemblyField_TagCount ConstString("tags_count"), // AssemblyField_TagCount
ConstString("tag"), // AssemblyField_Tag ConstString("tag"), // AssemblyField_Tag
ConstString("name"), // AssemblyField_Name ConstString("name"), // AssemblyField_Name
@ -84,6 +94,170 @@ StripSetTag(v2_strip* Strip, u32 TagIndex, gs_const_string TagName, gs_const_str
TagAt->ValueHash = HashDJB2ToU32(StringExpand(TagValue)); TagAt->ValueHash = HashDJB2ToU32(StringExpand(TagValue));
} }
internal strip_sacn_addr
AssemblyParser_ReadSACNAddr(parser* Parser, assembly Assembly)
{
strip_sacn_addr Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputSACN))
{
Result.StartUniverse = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartUniverse);
Result.StartChannel = Parser_ReadU32Value(Parser, AssemblyField_SACN_StartChannel);
if (!Parser_ReadCloseStruct(Parser))
{
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
return Result;
}
internal strip_uart_addr
AssemblyParser_ReadUARTAddr(parser* Parser, assembly Assembly)
{
strip_uart_addr Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_OutputUART))
{
Result.Channel = (u8)Parser_ReadU32Value(Parser, AssemblyField_UART_Channel);
bool HasNetPort = Parser_ReadStringValue(Parser, AssemblyField_UART_ComPort, &Result.ComPort, true);
if (Assembly.NetPortMode == NetworkPortMode_PortPerStrip && !HasNetPort)
{
Parser_PushErrorF(Parser, "NetPortMode for assembly is PortPerStrip, but this strip doesn't have an output port.");
}
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Struct doesn't close where expected");
}
}
return Result;
}
internal void
AssemblyParser_ReadTag(parser* Parser, v2_strip* StripAt, u32 TagIndex)
{
if (Parser_ReadOpenStruct(Parser, AssemblyField_Tag))
{
// TODO(Peter): Need to store the gs_string somewhere we can look it up for display in the interface
// right now they are stored in temp memory and won't persist
gs_string TagName = Parser_ReadStringValue(Parser, AssemblyField_Name);
gs_string TagValue = Parser_ReadStringValue(Parser, AssemblyField_Value);
StripSetTag(StripAt, TagIndex, TagName.ConstString, TagValue.ConstString);
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Tag struct doesn't close where expected");
}
}
else
{
Parser_PushErrorF(Parser, "Expected a tag struct, but none was found.");
}
}
internal void
AssemblyParser_ReadTagList(parser* Parser, v2_strip* StripAt, assembly* Assembly)
{
StripAt->TagsCount = Parser_ReadU32Value(Parser, AssemblyField_TagsCount);
// NOTE(pjs): Always add one tag to the input to leave room for the assembly name
StripAt->TagsCount += 1;
StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount);
StripSetTag(StripAt, 0, ConstString("assembly"), Assembly->Name.ConstString);
for (u32 Tag = 1; Tag < StripAt->TagsCount; Tag++)
{
AssemblyParser_ReadTag(Parser, StripAt, Tag);
}
}
internal strip_gen_data AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly);
internal strip_gen_interpolate_points
AssemblyParser_ReadInterpolatePoints(parser* Parser)
{
strip_gen_interpolate_points Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_InterpolatePoints))
{
Result.StartPosition = Parser_ReadV3Value(Parser, AssemblyField_Start);
Result.EndPosition = Parser_ReadV3Value(Parser, AssemblyField_End);
Result.LedCount = Parser_ReadU32Value(Parser, AssemblyField_LedCount);
if (!Parser_ReadCloseStruct(Parser))
{
// TODO(pjs):
}
}
else
{
// TODO(pjs):
}
return Result;
}
internal strip_gen_sequence
AssemblyParser_ReadSequence(parser* Parser, assembly* Assembly)
{
strip_gen_sequence Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_SegmentSequence))
{
Result.ElementsCount = Parser_ReadU32Value(Parser, AssemblyField_SegmentSequenceLength);
Result.Elements = PushArray(&Assembly->Arena, strip_gen_data, Result.ElementsCount);
for (u32 i = 0; i < Result.ElementsCount; i++)
{
Result.Elements[i] = AssemblyParser_ReadStripGenData(Parser, Assembly);
}
if (!Parser_ReadCloseStruct(Parser))
{
// TODO(pjs):
}
}
else
{
// TODO(pjs):
}
return Result;
}
internal strip_gen_data
AssemblyParser_ReadStripGenData(parser* Parser, assembly* Assembly)
{
strip_gen_data Result = {0};
if (Parser_ReadOpenStruct(Parser, AssemblyField_Segment))
{
gs_string PointPlacementType = Parser_ReadStringValue(Parser, AssemblyField_PointPlacementType);
// TODO(pjs): We want to store enum strings in some unified way
// :EnumStringsGen
if (StringsEqual(PointPlacementType.ConstString, ConstString("InterpolatePoints")))
{
Result.Method = StripGeneration_InterpolatePoints;
Result.InterpolatePoints = AssemblyParser_ReadInterpolatePoints(Parser);
}
else if (StringsEqual(PointPlacementType.ConstString,
ConstString("SegmentSequence")))
{
Result.Method = StripGeneration_Sequence;
Result.Sequence = AssemblyParser_ReadSequence(Parser, Assembly);
}
else
{
Parser_PushErrorF(Parser, "Incorrect Point Placement Type found for segment");
}
if (!Parser_ReadCloseStruct(Parser))
{
Parser_PushErrorF(Parser, "Strip Gen Data did not close the struct where expected");
}
}
return Result;
}
internal bool internal bool
ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient) ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileText, gs_memory_arena* Transient)
{ {
@ -96,19 +270,26 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
Parser.At = Parser.String.Str; Parser.At = Parser.String.Str;
Parser.LineStart = Parser.At; Parser.LineStart = Parser.At;
Parser.Arena = &Assembly->Arena; Parser.Arena = &Assembly->Arena;
Parser.Transient = Transient;
Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName); Assembly->Name = Parser_ReadStringValue(&Parser, AssemblyField_AssemblyName);
Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale); Assembly->Scale = Parser_ReadR32Value(&Parser, AssemblyField_AssemblyScale);
Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter); Assembly->Center = Parser_ReadV3Value(&Parser, AssemblyField_AssemblyCenter);
Assembly->StripCount = Parser_ReadU32Value(&Parser, AssemblyField_LedStripCount); Assembly->StripCount = Parser_ReadU32Value(&Parser, AssemblyField_LedStripCount);
Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount); Assembly->Strips = PushArray(&Assembly->Arena, v2_strip, Assembly->StripCount);
gs_string OutputModeString = Parser_ReadStringValue(&Parser, AssemblyField_OutputMode); gs_string OutputModeString = Parser_ReadStringValue(&Parser, AssemblyField_OutputMode);
if (StringsEqual(OutputModeString.ConstString, ConstString("UART"))) if (StringsEqual(OutputModeString.ConstString, ConstString("UART")))
{ {
Assembly->OutputMode = NetworkProtocol_UART; Assembly->OutputMode = NetworkProtocol_UART;
Assembly->UARTComPort = Parser_ReadStringValue(&Parser, AssemblyField_UART_ComPort, true).ConstString; if (Parser_ReadStringValue(&Parser, AssemblyField_UART_ComPort, &Assembly->UARTComPort, true))
{
Assembly->NetPortMode = NetworkPortMode_GlobalPort;
}
else
{
Assembly->NetPortMode = NetworkPortMode_PortPerStrip;
}
} }
else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN"))) else if (StringsEqual(OutputModeString.ConstString, ConstString("SACN")))
{ {
@ -116,7 +297,7 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
} }
else else
{ {
//TokenizerPushError(&Tokenizer, "Invalid output mode specified."); Parser_PushErrorF(&Parser, "Invalid output mode specified for assembly.");
} }
for (u32 i = 0; i < Assembly->StripCount; i++) for (u32 i = 0; i < Assembly->StripCount; i++)
@ -124,83 +305,26 @@ ParseAssemblyFile(assembly* Assembly, gs_const_string FileName, gs_string FileTe
v2_strip* StripAt = Assembly->Strips + i; v2_strip* StripAt = Assembly->Strips + i;
if (Parser_ReadOpenStruct(&Parser, AssemblyField_LedStrip)) if (Parser_ReadOpenStruct(&Parser, AssemblyField_LedStrip))
{ {
if (Parser_ReadOpenStruct(&Parser, AssemblyField_OutputSACN)) StripAt->SACNAddr = AssemblyParser_ReadSACNAddr(&Parser, *Assembly);
{ StripAt->UARTAddr = AssemblyParser_ReadUARTAddr(&Parser, *Assembly);
StripAt->SACNAddr.StartUniverse = Parser_ReadU32Value(&Parser, AssemblyField_SACN_StartUniverse); StripAt->GenerationData = AssemblyParser_ReadStripGenData(&Parser, Assembly);
StripAt->SACNAddr.StartChannel = Parser_ReadU32Value(&Parser, AssemblyField_SACN_StartChannel); StripAt->LedCount = StripGenData_CountLeds(StripAt->GenerationData);
AssemblyParser_ReadTagList(&Parser, StripAt, Assembly);
if (!Parser_ReadCloseStruct(&Parser))
{
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
if (Parser_ReadOpenStruct(&Parser, AssemblyField_OutputUART))
{
StripAt->UARTAddr.Channel = (u8)Parser_ReadU32Value(&Parser, AssemblyField_UART_Channel);
if (!Parser_ReadCloseStruct(&Parser))
{
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
// TODO(Peter): Need to store this
gs_string PointPlacementType = Parser_ReadStringValue(&Parser, AssemblyField_PointPlacementType);
// TODO(Peter): Switch on value of PointPlacementType
if (Parser_ReadOpenStruct(&Parser, AssemblyField_InterpolatePoints))
{
StripAt->StartPosition = Parser_ReadV3Value(&Parser, AssemblyField_Start);
StripAt->EndPosition = Parser_ReadV3Value(&Parser, AssemblyField_End);
if (!Parser_ReadCloseStruct(&Parser))
{
// TODO(Peter): @ErrorHandling
// Have this function prepend the filename and line number.
// Create an error display popup window, or an error log window that takes over a panel automatically
// TokenizerPushError(&Tokenizer, "Unable to read
}
}
StripAt->LedCount = Parser_ReadU32Value(&Parser, AssemblyField_LedCount);
Assembly->LedCountTotal += StripAt->LedCount; Assembly->LedCountTotal += StripAt->LedCount;
StripAt->TagsCount = Parser_ReadU32Value(&Parser, AssemblyField_TagsCount);
// NOTE(pjs): Always add one tag to the input to leave room for the assembly name
StripAt->TagsCount += 1;
StripAt->Tags = PushArray(&Assembly->Arena, v2_tag, StripAt->TagsCount);
StripSetTag(StripAt, 0, ConstString("assembly"), Assembly->Name.ConstString);
for (u32 Tag = 1; Tag < StripAt->TagsCount; Tag++)
{
if (Parser_ReadOpenStruct(&Parser, AssemblyField_Tag))
{
// TODO(Peter): Need to store the gs_string somewhere we can look it up for display in the interface
// right now they are stored in temp memory and won't persist
gs_string TagName = Parser_ReadStringValue(&Parser, AssemblyField_Name);
gs_string TagValue = Parser_ReadStringValue(&Parser, AssemblyField_Value);
StripSetTag(StripAt, Tag, TagName.ConstString, TagValue.ConstString);
if (!Parser_ReadCloseStruct(&Parser)) if (!Parser_ReadCloseStruct(&Parser))
{ {
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected"); Parser_PushErrorF(&Parser, "Strip struct doesn't close where expected");
} }
} }
else else
{ {
//TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found"); Parser_PushErrorF(&Parser, "Expected a strip struct but none was found");
}
}
if (!Parser_ReadCloseStruct(&Parser))
{
//TokenizerPushError(&Tokenizer, "Struct doesn't close where expected");
}
}
else
{
//TokenizerPushError(&Tokenizer, "Expected a struct opening, but none was found");
} }
} }
// TODO(pjs): invalidate the file if its incorrect
return true; //Tokenizer.ParsingIsValid; return true; //Tokenizer.ParsingIsValid;
} }

View File

@ -1,18 +0,0 @@
//
// File: foldhaus_parser.h
// Author: Peter Slattery
// Creation Date: 2020-10-09
//
#ifndef FOLDHAUS_PARSER_H
struct parser
{
gs_string String;
gs_const_string* Identifiers;
u32 IdentifiersCount;
};
#define FOLDHAUS_PARSER_H
#endif // FOLDHAUS_PARSER_H

View File

@ -134,11 +134,17 @@ Serializer_WriteV3Value(serializer* Serializer, u32 IdentIndex, v3 Value)
struct parser_error struct parser_error
{ {
gs_string Message; gs_string Message;
gs_string FileName;
u32 LineNumber;
parser_error* Next; parser_error* Next;
}; };
struct parser struct parser
{ {
gs_string FileName;
gs_string String; gs_string String;
gs_const_string* Identifiers; gs_const_string* Identifiers;
@ -160,7 +166,11 @@ internal void
Parser_PushErrorF(parser* Parser, char* Format, ...) Parser_PushErrorF(parser* Parser, char* Format, ...)
{ {
parser_error* Error = PushStruct(Parser->Transient, parser_error); parser_error* Error = PushStruct(Parser->Transient, parser_error);
Error->FileName = Parser->FileName;
Error->LineNumber = Parser->Line;
Error->Message = PushString(Parser->Transient, 1024); Error->Message = PushString(Parser->Transient, 1024);
PrintF(&Error->Message, "File: %S Line: %d - ", Error->FileName, Error->LineNumber);
va_list Args; va_list Args;
va_start(Args, Format); va_start(Args, Format);
@ -268,11 +278,13 @@ Parser_ReadString(parser* P, u32 IdentIndex)
return Parser_ReadString(P, Ident); return Parser_ReadString(P, Ident);
} }
internal gs_string internal bool
Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminate = false) Parser_ReadStringValue(parser* P, gs_const_string Ident, gs_string* Output, bool ShouldNullTerminate = false)
{ {
Assert(Output != 0);
// ident: "value"; // ident: "value";
gs_string Result = {}; bool Result = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) && if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")) && Parser_AdvanceIfTokenEquals(P, ConstString(":")) &&
Parser_AdvanceIfTokenEquals(P, ConstString("\""))) Parser_AdvanceIfTokenEquals(P, ConstString("\"")))
@ -294,10 +306,12 @@ Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminat
{ {
StringLength += 1; StringLength += 1;
} }
Result = PushStringF(P->Arena, StringLength, "%S", FileString);
Result = true;
*Output = PushStringF(P->Arena, StringLength, "%S", FileString);
if (ShouldNullTerminate) if (ShouldNullTerminate)
{ {
NullTerminate(&Result); NullTerminate(Output);
} }
} }
else else
@ -305,11 +319,22 @@ Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminat
Parser_PushErrorF(P, "String doesn't have a closing quote, or line doesn't end with a semicolon"); Parser_PushErrorF(P, "String doesn't have a closing quote, or line doesn't end with a semicolon");
} }
} }
else
{ return Result;
Parser_PushErrorF(P, "String doesn't begin correctly");
} }
internal bool
Parser_ReadStringValue(parser* P, u32 IdentIndex, gs_string* Result, bool ShouldNullTerminate = false)
{
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadStringValue(P, Ident, Result, ShouldNullTerminate);
}
internal gs_string
Parser_ReadStringValue(parser* P, gs_const_string Ident, bool ShouldNullTerminate = false)
{
gs_string Result = {0};
Parser_ReadStringValue(P, Ident, &Result, ShouldNullTerminate);
return Result; return Result;
} }
@ -346,42 +371,66 @@ Parser_ReadCloseStruct(parser* P)
return Result; return Result;
} }
internal gs_const_string internal bool
Parser_ReadNumberString(parser* P) Parser_ReadNumberString(parser* P, gs_const_string* Output)
{ {
gs_const_string Result = {}; Assert(Output != 0);
Result.Str = P->At;
bool Success = false;
if (IsNumericExtended(P->At[0]))
{
char* NumStart = P->At;
while(Parser_AtValidPosition(*P) && IsNumericExtended(P->At[0])) while(Parser_AtValidPosition(*P) && IsNumericExtended(P->At[0]))
{ {
Parser_AdvanceChar(P); Parser_AdvanceChar(P);
} }
Result.Length = P->At - Result.Str;
Output->Str = NumStart;
Output->Length = P->At - NumStart;
Success = true;
}
return Success;
}
internal gs_const_string
Parser_ReadNumberString(parser* P)
{
gs_const_string Result = {0};
Parser_ReadNumberString(P, &Result);
return Result; return Result;
} }
internal u32 internal bool
Parser_ReadU32Value(parser* P, gs_const_string Ident) Parser_ReadU32Value(parser* P, gs_const_string Ident, u32* Result)
{ {
// ident: value; // ident: value;
u32 Result = 0; bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) && if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":"))) Parser_AdvanceIfTokenEquals(P, ConstString(":")))
{ {
gs_const_string NumStr = Parser_ReadNumberString(P); gs_const_string NumStr = Parser_ReadNumberString(P);
if (Parser_AdvanceIfLineEnd(P)) if (Parser_AdvanceIfLineEnd(P))
{ {
Result = (u32)ParseInt(NumStr); *Result = (u32)ParseInt(NumStr);
Success = true;
} }
else else
{ {
Parser_PushErrorF(P, "U32 Value doesn't end with semicolon"); Parser_PushErrorF(P, "U32 Value doesn't end with semicolon");
} }
} }
else
{ return Success;
Parser_PushErrorF(P, "U32 value doesn't begin properly");
} }
internal u32
Parser_ReadU32Value(parser* P, gs_const_string Ident)
{
u32 Result = 0;
Parser_ReadU32Value(P, Ident, &Result);
return Result; return Result;
} }
@ -392,52 +441,72 @@ Parser_ReadU32Value(parser* P, u32 IdentIndex)
return Parser_ReadU32Value(P, Ident); return Parser_ReadU32Value(P, Ident);
} }
internal bool
Parser_ReadR32(parser* P, r32* Result)
{
bool Success = false;
gs_const_string NumStr = {0};
if (Parser_ReadNumberString(P, &NumStr))
{
*Result = (r32)ParseFloat(NumStr);
Success = true;
}
return Success;
}
internal r32 internal r32
Parser_ReadR32(parser* P) Parser_ReadR32(parser* P)
{ {
r32 Result = 0; r32 Result = 0;
gs_const_string NumStr = Parser_ReadNumberString(P); Parser_ReadR32(P, &Result);
Result = (r32)ParseFloat(NumStr);
return Result; return Result;
} }
internal r32 internal bool
Parser_ReadR32Value(parser* P, gs_const_string Ident) Parser_ReadR32Value(parser* P, gs_const_string Ident, r32* Result)
{ {
// ident: value; // ident: value;
r32 Result = 0; bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) && if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":"))) Parser_AdvanceIfTokenEquals(P, ConstString(":")))
{ {
r32 Value = Parser_ReadR32(P); r32 Value = Parser_ReadR32(P);
if (Parser_AdvanceIfLineEnd(P)) if (Parser_AdvanceIfLineEnd(P))
{ {
Result = Value; *Result = Value;
Success = true;
} }
else else
{ {
Parser_PushErrorF(P, "R32 Value doesn't end with semicolon"); Parser_PushErrorF(P, "R32 Value doesn't end with semicolon");
} }
} }
else
{ return Success;
Parser_PushErrorF(P, "R32 value doesn't begin properly");
} }
internal r32
Parser_ReadR32Value(parser* P, gs_const_string Ident)
{
r32 Result = 0;
Parser_ReadR32Value(P, Ident, &Result);
return Result; return Result;
} }
internal u32 internal r32
Parser_ReadR32Value(parser* P, u32 IdentIndex) Parser_ReadR32Value(parser* P, u32 IdentIndex)
{ {
r32 Result = 0;
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadR32Value(P, Ident); Parser_ReadR32Value(P, Ident, &Result);
return Result;
} }
internal v3 internal bool
Parser_ReadV3Value(parser* P, gs_const_string Ident) Parser_ReadV3Value(parser* P, gs_const_string Ident, v3* Result)
{ {
v3 Result = {0}; Assert(Result != 0);
bool Success = false;
if (Parser_AdvanceIfTokenEquals(P, Ident) && if (Parser_AdvanceIfTokenEquals(P, Ident) &&
Parser_AdvanceIfTokenEquals(P, ConstString(":")) && Parser_AdvanceIfTokenEquals(P, ConstString(":")) &&
Parser_AdvanceIfTokenEquals(P, ConstString("("))) Parser_AdvanceIfTokenEquals(P, ConstString("(")))
@ -458,27 +527,35 @@ Parser_ReadV3Value(parser* P, gs_const_string Ident)
if (Parser_AdvanceIfTokenEquals(P, ConstString(")")) && if (Parser_AdvanceIfTokenEquals(P, ConstString(")")) &&
Parser_AdvanceIfLineEnd(P)) Parser_AdvanceIfLineEnd(P))
{ {
Result.x = X; Result->x = X;
Result.y = Y; Result->y = Y;
Result.z = Z; Result->z = Z;
Success = true;
} }
else else
{ {
Parser_PushErrorF(P, "V3 Value doesn't end correctly"); Parser_PushErrorF(P, "V3 Value doesn't end correctly");
} }
} }
else
{ return Success;
Parser_PushErrorF(P, "V3 Value doesn't begin correctly");
} }
internal v3
Parser_ReadV3Value(parser* P, gs_const_string Ident)
{
v3 Result = {0};
Parser_ReadV3Value(P, Ident, &Result);
return Result; return Result;
} }
internal v3 internal v3
Parser_ReadV3Value(parser* P, u32 IdentIndex) Parser_ReadV3Value(parser* P, u32 IdentIndex)
{ {
v3 Result = {0};
gs_const_string Ident = Parser_GetIdent(*P, IdentIndex); gs_const_string Ident = Parser_GetIdent(*P, IdentIndex);
return Parser_ReadV3Value(P, Ident); Parser_ReadV3Value(P, Ident, &Result);
return Result;
} }

View File

@ -76,7 +76,7 @@ UART_BuildOutputData(addressed_data_buffer_list* Output, assembly_array Assembli
TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel TotalBufferSize += ChannelSettings.ElementsCount * Assembly.LedCountTotal; // pixels * channels per pixel
addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize); addressed_data_buffer* Buffer = AddressedDataBufferList_Push(Output, TotalBufferSize);
AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort); AddressedDataBuffer_SetCOMPort(Buffer, Assembly.UARTComPort.ConstString);
gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data); gs_memory_cursor WriteCursor = CreateMemoryCursor(Buffer->Data);
for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++) for (u32 StripIdx = 0; StripIdx < Assembly.StripCount; StripIdx++)

View File

@ -123,7 +123,7 @@ INITIALIZE_APPLICATION(InitializeApplication)
State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128); State->LedSystem = LedSystemInitialize(Context.ThreadContext.Allocator, 128);
#if 1 #if 1
gs_const_string SculpturePath = ConstString("data/blumen_lumen_v2.fold"); gs_const_string SculpturePath = ConstString("data/blumen_lumen_silver_spring.fold");
LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog); LoadAssembly(&State->Assemblies, &State->LedSystem, State->Transient, Context, SculpturePath, State->GlobalLog);
#endif #endif

View File

@ -388,6 +388,8 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_
}break; }break;
case AddressType_ComPort: case AddressType_ComPort:
{
if (BufferAt->ComPort.Length > 0)
{ {
HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1); HANDLE SerialPort = Win32SerialArray_GetOrOpen(BufferAt->ComPort, 2000000, 8, NOPARITY, 1);
if (SerialPort != INVALID_HANDLE_VALUE) if (SerialPort != INVALID_HANDLE_VALUE)
@ -397,6 +399,11 @@ Win32_SendAddressedDataBuffers(gs_thread_context Context, addressed_data_buffer_
BuffersSent += 1; BuffersSent += 1;
} }
} }
}
else
{
OutputDebugStringA("Skipping data buffer because its COM Port isn't set");
}
}break; }break;
InvalidDefaultCase; InvalidDefaultCase;