Decoupled assembly from sacn.
This commit is contained in:
parent
726785eec4
commit
70c9c74796
|
@ -0,0 +1 @@
|
|||
/* For future artnet implementation */
|
|
@ -102,33 +102,30 @@ ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer)
|
|||
|
||||
}
|
||||
|
||||
internal void
|
||||
ParseLEDStrip (assembly_definition* Assembly, tokenizer* Tokenizer)
|
||||
internal led_strip_definition
|
||||
ParseLEDStrip (tokenizer* Tokenizer)
|
||||
{
|
||||
led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount;
|
||||
Assert(Assembly->LEDStripCount < Assembly->LEDStripSize);
|
||||
|
||||
Assembly->LEDStripCount++;
|
||||
led_strip_definition Result = {};
|
||||
|
||||
// Control Box Index
|
||||
while (*Tokenizer->At && !IsNumericExtended(*Tokenizer->At)) { Tokenizer->At++; }
|
||||
assembly_token BoxIDToken = ParseToken(Tokenizer);
|
||||
Assert(BoxIDToken.Type == AssemblyToken_Number);
|
||||
LEDStripDef->ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue;
|
||||
Result.ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue;
|
||||
|
||||
// Start Universe
|
||||
EatPastCharacter(Tokenizer, ',');
|
||||
EatWhitespace(Tokenizer);
|
||||
assembly_token StartUniverseToken = ParseToken(Tokenizer);
|
||||
Assert(BoxIDToken.Type == AssemblyToken_Number);
|
||||
LEDStripDef->StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue;
|
||||
Result.StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue;
|
||||
|
||||
// Start Channel
|
||||
EatPastCharacter(Tokenizer, ',');
|
||||
EatWhitespace(Tokenizer);
|
||||
assembly_token StartChannelToken = ParseToken(Tokenizer);
|
||||
Assert(BoxIDToken.Type == AssemblyToken_Number);
|
||||
LEDStripDef->StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue;
|
||||
Result.StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue;
|
||||
|
||||
// Strip Type
|
||||
// TODO(Peter): This is unused for now, and would be a branch point for parsing
|
||||
|
@ -137,32 +134,34 @@ ParseLEDStrip (assembly_definition* Assembly, tokenizer* Tokenizer)
|
|||
EatWhitespace(Tokenizer);
|
||||
if (CharArraysEqualUpToLength(Tokenizer->At, INTERPOLATE_POINTS_IDENTIFIER, CharArrayLength(INTERPOLATE_POINTS_IDENTIFIER)))
|
||||
{
|
||||
LEDStripDef->InterpolationType = StripInterpolate_Points;
|
||||
Result.InterpolationType = StripInterpolate_Points;
|
||||
|
||||
// Start Position
|
||||
EatPastCharacter(Tokenizer, ',');
|
||||
EatWhitespace(Tokenizer);
|
||||
assembly_token StartPositionToken = ParseToken(Tokenizer);
|
||||
Assert(StartPositionToken.Type == AssemblyToken_Vector);
|
||||
LEDStripDef->InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token);
|
||||
Result.InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token);
|
||||
|
||||
// End Position
|
||||
EatPastCharacter(Tokenizer, ',');
|
||||
EatWhitespace(Tokenizer);
|
||||
assembly_token EndPositionToken = ParseToken(Tokenizer);
|
||||
Assert(EndPositionToken.Type == AssemblyToken_Vector);
|
||||
LEDStripDef->InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token);
|
||||
Result.InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token);
|
||||
|
||||
// LEDs Per Strip
|
||||
EatPastCharacter(Tokenizer, ',');
|
||||
EatWhitespace(Tokenizer);
|
||||
assembly_token LEDsPerStripToken = ParseToken(Tokenizer);
|
||||
Assert(BoxIDToken.Type == AssemblyToken_Number);
|
||||
LEDStripDef->LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue;
|
||||
Result.LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue;
|
||||
}
|
||||
|
||||
EatPastCharacter(Tokenizer, '}');
|
||||
EatWhitespace(Tokenizer);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -181,7 +180,13 @@ ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer)
|
|||
{
|
||||
case AssemblyToken_LEDStrip:
|
||||
{
|
||||
ParseLEDStrip(Assembly, Tokenizer);
|
||||
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?
|
||||
|
|
|
@ -56,5 +56,6 @@ struct assembly_definition
|
|||
{
|
||||
s32 LEDStripSize;
|
||||
s32 LEDStripCount;
|
||||
s32 TotalLEDCount;
|
||||
led_strip_definition* LEDStrips;
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
struct dmx_buffer
|
||||
{
|
||||
s32 Universe;
|
||||
u8* Base;
|
||||
s32 TotalSize;
|
||||
s32 HeaderSize;
|
||||
};
|
||||
|
||||
struct dmx_buffer_list
|
||||
{
|
||||
dmx_buffer Buffer;
|
||||
dmx_buffer_list* Next;
|
||||
};
|
||||
|
||||
internal dmx_buffer_list*
|
||||
DMXBufferListGetTail (dmx_buffer_list* List)
|
||||
{
|
||||
dmx_buffer_list* Result = 0;
|
||||
if (List->Next == 0)
|
||||
{
|
||||
Result = List;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = DMXBufferListGetTail(List->Next);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal dmx_buffer_list*
|
||||
DMXBufferListAppend (dmx_buffer_list* AppendTo, dmx_buffer_list* Append)
|
||||
{
|
||||
dmx_buffer_list* Result = 0;
|
||||
|
||||
if (AppendTo)
|
||||
{
|
||||
dmx_buffer_list* Tail = DMXBufferListGetTail(AppendTo);
|
||||
Tail->Next = Append;
|
||||
Result = AppendTo;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Append;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
|
@ -22,186 +22,10 @@ MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 Win
|
|||
return WorldPosition;
|
||||
}
|
||||
|
||||
internal void
|
||||
PushLEDBufferOnList (led_buffer* List, led_buffer* Entry)
|
||||
{
|
||||
if (List->Next)
|
||||
{
|
||||
PushLEDBufferOnList(List->Next, Entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
List->Next = Entry;
|
||||
}
|
||||
}
|
||||
|
||||
internal led_buffer*
|
||||
RemoveLEDBufferFromList (led_buffer* List, led_buffer* Entry)
|
||||
{
|
||||
led_buffer* ListHead = 0;
|
||||
if (List != Entry && List->Next)
|
||||
{
|
||||
ListHead = RemoveLEDBufferFromList(List->Next, Entry);
|
||||
}
|
||||
else if (List == Entry)
|
||||
{
|
||||
ListHead = Entry->Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE(Peter): Trying to remove an entry from a list that doesn't contain it
|
||||
InvalidCodePath;
|
||||
}
|
||||
return ListHead;
|
||||
}
|
||||
|
||||
internal void
|
||||
ConstructAssemblyFromDefinition (assembly_definition Definition,
|
||||
string AssemblyName,
|
||||
v3 RootPosition,
|
||||
r32 Scale,
|
||||
context Context,
|
||||
app_state* State)
|
||||
{
|
||||
Assert(State->AssembliesUsed < ASSEMBLY_LIST_LENGTH);
|
||||
|
||||
assembly* Assembly = State->AssemblyList + State->AssembliesUsed++;
|
||||
|
||||
// 1. Find # of LEDs, # of Universes
|
||||
s32 UniversesUsedByLEDs[2048]; // TODO(Peter): find the max universe number and size these accordingly
|
||||
s32 ChannelsInUniverse[2048];
|
||||
GSZeroMemory(UniversesUsedByLEDs, sizeof(s32) * 2048);
|
||||
GSZeroMemory(ChannelsInUniverse, sizeof(s32) * 2048);
|
||||
s32 UniverseCount = 0;
|
||||
s32 LEDCount = 0;
|
||||
|
||||
for (s32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++)
|
||||
{
|
||||
led_strip_definition StripDef = Definition.LEDStrips[StripIdx];
|
||||
|
||||
s32 ChannelsPerStrip = StripDef.LEDsPerStrip * 3;
|
||||
s32 UniversesPerStrip = IntegerDivideRoundUp(ChannelsPerStrip, 512);
|
||||
s32 ChannelsAllocated = 0;
|
||||
for (s32 UniverseIdx = 0; UniverseIdx < UniversesPerStrip; UniverseIdx++)
|
||||
{
|
||||
s32 UniverseID = StripDef.StartUniverse + UniverseIdx;
|
||||
s32 UniverseIndex = -1;
|
||||
|
||||
for (s32 RegisteredUniverse = 0; RegisteredUniverse < UniverseCount; RegisteredUniverse++)
|
||||
{
|
||||
if (UniversesUsedByLEDs[RegisteredUniverse] == UniverseID)
|
||||
{
|
||||
UniverseIndex = RegisteredUniverse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (UniverseIndex < 0)
|
||||
{
|
||||
UniverseIndex = UniverseCount++;
|
||||
}
|
||||
|
||||
s32 ChannelsRequested = GSMin(STREAM_BODY_SIZE, ChannelsPerStrip - ChannelsAllocated);
|
||||
ChannelsAllocated += ChannelsRequested;
|
||||
ChannelsInUniverse[UniverseIndex] += ChannelsRequested;
|
||||
Assert(ChannelsInUniverse[UniverseIndex] <= 512);
|
||||
|
||||
UniversesUsedByLEDs[UniverseIndex++] = UniverseID;
|
||||
}
|
||||
|
||||
LEDCount += StripDef.LEDsPerStrip;
|
||||
}
|
||||
|
||||
sacn_add_universes_result AddedUniverses = SACNAddUniverses(UniversesUsedByLEDs, UniverseCount, &State->SACN, Context);
|
||||
|
||||
Assembly->MemorySize = CalculateMemorySizeForAssembly(LEDCount, AssemblyName.Length);
|
||||
memory_arena TemporaryAssemblyArena = AllocateNonGrowableArenaWithSpace(Context.PlatformAlloc, Assembly->MemorySize);
|
||||
Assembly->MemoryBase = TemporaryAssemblyArena.CurrentRegion->Base;
|
||||
|
||||
Assembly->Universes = AddedUniverses.NewUniverseBuffer;
|
||||
Assembly->SendBuffer = AddedUniverses.NewSendBuffer;
|
||||
|
||||
Assembly->Name = MakeString(PushArray(&TemporaryAssemblyArena, char, AssemblyName.Length), AssemblyName.Length);
|
||||
CopyStringTo(AssemblyName, &Assembly->Name);
|
||||
|
||||
led_buffer* LEDBuffer = PushStruct(&TemporaryAssemblyArena, led_buffer);
|
||||
LEDBuffer->Next = 0;
|
||||
LEDBuffer->Count = 0;
|
||||
LEDBuffer->Max = LEDCount;
|
||||
LEDBuffer->LEDs = PushArray(&TemporaryAssemblyArena, led, LEDCount);
|
||||
LEDBuffer->Colors = PushArray(&TemporaryAssemblyArena, sacn_pixel, LEDCount);
|
||||
|
||||
Assembly->LEDBuffer = LEDBuffer;
|
||||
|
||||
if (State->LEDBufferList)
|
||||
{
|
||||
PushLEDBufferOnList(State->LEDBufferList, LEDBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
State->LEDBufferList = LEDBuffer;
|
||||
}
|
||||
State->TotalLEDsCount += LEDCount;
|
||||
|
||||
// Add LEDs
|
||||
for (s32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++)
|
||||
{
|
||||
led_strip_definition StripDef = Definition.LEDStrips[StripIdx];
|
||||
|
||||
v3 WS_StripStart = {};
|
||||
v3 WS_StripEnd = {};
|
||||
s32 LEDsInStripCount = 0;
|
||||
|
||||
switch(StripDef.InterpolationType)
|
||||
{
|
||||
case StripInterpolate_Points:
|
||||
{
|
||||
WS_StripStart= StripDef.InterpolatePositionStart * Scale;
|
||||
WS_StripEnd= StripDef.InterpolatePositionEnd * Scale;
|
||||
LEDsInStripCount = StripDef.LEDsPerStrip;
|
||||
|
||||
}break;
|
||||
|
||||
default:
|
||||
{
|
||||
InvalidCodePath;
|
||||
}break;
|
||||
}
|
||||
|
||||
sacn_universe* CurrentUniverse = SACNGetUniverse(StripDef.StartUniverse, &State->SACN);
|
||||
s32 ChannelsUsed = 0;
|
||||
CurrentUniverse->BeginPixelCopyFromOffset = LEDBuffer->Count * sizeof(sacn_pixel);
|
||||
|
||||
r32 Percent = 0;
|
||||
r32 PercentStep = 1 / (r32)LEDsInStripCount;
|
||||
for (s32 Step = 0; Step < LEDsInStripCount; Step++)
|
||||
{
|
||||
v4 LEDPosition = V4(Lerp(WS_StripStart, WS_StripEnd, Percent), 1);
|
||||
s32 LEDIndex = LEDBuffer->Count++;
|
||||
Assert(LEDIndex < LEDCount);
|
||||
|
||||
led* LED = LEDBuffer->LEDs + LEDIndex;
|
||||
sacn_pixel* LEDColor = LEDBuffer->Colors + LEDIndex;
|
||||
|
||||
LED->Position = LEDPosition;
|
||||
LED->Index = LEDIndex;
|
||||
|
||||
Percent += PercentStep;
|
||||
|
||||
ChannelsUsed += 3;
|
||||
if (ChannelsUsed > STREAM_BODY_SIZE)
|
||||
{
|
||||
ChannelsUsed -= STREAM_BODY_SIZE;
|
||||
CurrentUniverse = SACNGetUniverse(CurrentUniverse->Universe + 1, &State->SACN);
|
||||
CurrentUniverse->BeginPixelCopyFromOffset = (LEDBuffer->Count + sizeof(sacn_pixel)) - ChannelsUsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct draw_leds_job_data
|
||||
{
|
||||
led* LEDs;
|
||||
sacn_pixel* Colors;
|
||||
pixel* Colors;
|
||||
s32 StartIndex;
|
||||
s32 OnePastLastIndex;
|
||||
|
||||
|
@ -241,8 +65,8 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
|
|||
LEDIdx < LEDCount;
|
||||
LEDIdx++)
|
||||
{
|
||||
sacn_pixel SACNColor = Data->Colors[LED->Index];
|
||||
v4 Color = v4{SACNColor.R / 255.f, SACNColor.G / 255.f, SACNColor.B / 255.f, 1.0f};
|
||||
pixel PixelColor = Data->Colors[LED->Index];
|
||||
v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
|
||||
|
||||
v4 V4Position = LED->Position;
|
||||
V4Position.w = 0;
|
||||
|
@ -262,25 +86,37 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
|
|||
|
||||
struct send_sacn_job_data
|
||||
{
|
||||
streaming_acn SACN;
|
||||
sacn_universe_buffer UniverseList;
|
||||
s32 StartUniverse;
|
||||
s32 OnePastLastUniverse;
|
||||
platform_send_to* PlatformSendTo;
|
||||
|
||||
platform_socket_handle SendSocket;
|
||||
platform_get_send_address* GetSendAddress;
|
||||
platform_send_to* SendTo;
|
||||
dmx_buffer_list* DMXBuffers;
|
||||
};
|
||||
|
||||
internal void
|
||||
SendSACNBufferData (s32 ThreadID, void* JobData)
|
||||
SACNSendDMXBufferListJob (s32 ThreadID, void* JobData)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
send_sacn_job_data* Data = (send_sacn_job_data*)JobData;
|
||||
platform_get_send_address* GetSendAddress = Data->GetSendAddress;
|
||||
platform_socket_handle SendSocket = Data->SendSocket;
|
||||
platform_send_to* SendTo = Data->SendTo;
|
||||
|
||||
sacn_universe* SendUniverse = Data->UniverseList.Universes + Data->StartUniverse;
|
||||
for (s32 UniverseIdx = Data->StartUniverse; UniverseIdx < Data->OnePastLastUniverse; UniverseIdx++)
|
||||
dmx_buffer_list* DMXBufferAt = Data->DMXBuffers;
|
||||
while (DMXBufferAt)
|
||||
{
|
||||
SACNSendDataToUniverse(&Data->SACN, SendUniverse, Data->PlatformSendTo);
|
||||
SendUniverse++;
|
||||
dmx_buffer Buffer = DMXBufferAt->Buffer;
|
||||
|
||||
u_long V4SendAddress = SACNGetUniverseSendAddress(Buffer.Universe);
|
||||
platform_network_address_handle SendAddress = GetSendAddress(
|
||||
AF_INET,
|
||||
HostToNetU16(DEFAULT_STREAMING_ACN_PORT),
|
||||
HostToNetU32(V4SendAddress));
|
||||
|
||||
SendTo(SendSocket, SendAddress, (const char*)Buffer.Base, Buffer.TotalSize, 0);
|
||||
|
||||
DMXBufferAt = DMXBufferAt->Next;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +148,14 @@ LoadAssembly (app_state* State, context Context, char* Path)
|
|||
string FileName = Substring(PathString, IndexOfLastSlash + 1);
|
||||
|
||||
r32 Scale = 100;
|
||||
ConstructAssemblyFromDefinition(AssemblyDefinition, FileName, v3{0, 0, 0}, Scale, Context, State);
|
||||
Assert(State->AssembliesCount < ASSEMBLY_LIST_LENGTH);
|
||||
assembly NewAssembly = ConstructAssemblyFromDefinition(AssemblyDefinition,
|
||||
FileName,
|
||||
v3{0, 0, 0},
|
||||
Scale,
|
||||
Context);
|
||||
State->AssemblyList[State->AssembliesCount++] = NewAssembly;
|
||||
State->TotalLEDsCount += NewAssembly.LEDCount;
|
||||
|
||||
ClearArenaToSnapshot(State->Transient, TempMemorySnapshot);
|
||||
}
|
||||
|
@ -321,21 +164,19 @@ internal void
|
|||
UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context)
|
||||
{
|
||||
assembly Assembly = State->AssemblyList[AssemblyIndex];
|
||||
SACNRemoveUniverseAndSendBuffer(&State->SACN, Assembly.Universes, Assembly.SendBuffer);
|
||||
|
||||
State->LEDBufferList = RemoveLEDBufferFromList(State->LEDBufferList, Assembly.LEDBuffer);
|
||||
|
||||
/*
|
||||
s32 LEDsInAssembly = Assembly.LEDBuffer->Count;
|
||||
s32 MemoryRequiredForAssembly = CalculateMemorySizeForAssembly(LEDsInAssembly, Assembly.Name.Length);
|
||||
Context.PlatformFree((u8*)Assembly.LEDBuffer, MemoryRequiredForAssembly);
|
||||
|
||||
State->TotalLEDsCount -= LEDsInAssembly;
|
||||
*/
|
||||
|
||||
if (AssemblyIndex != (State->AssembliesUsed - 1))
|
||||
if (AssemblyIndex != (State->AssembliesCount - 1))
|
||||
{
|
||||
State->AssemblyList[AssemblyIndex] = State->AssemblyList[State->AssembliesUsed - 1];
|
||||
State->AssemblyList[AssemblyIndex] = State->AssemblyList[State->AssembliesCount - 1];
|
||||
}
|
||||
State->AssembliesUsed -= 1;
|
||||
State->AssembliesCount -= 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -445,7 +286,8 @@ INITIALIZE_APPLICATION(InitializeApplication)
|
|||
State->Interface.TextColor = WhiteV4;
|
||||
State->Interface.Margin = v2{5, 5};
|
||||
|
||||
State->SACN = InitializeSACN(Context.PlatformAlloc, Context);
|
||||
State->SACN = InitializeSACN(Context);
|
||||
State->NetworkProtocolHeaderSize = STREAM_HEADER_SIZE;
|
||||
|
||||
State->Camera.FieldOfView = DegreesToRadians(45.0f);
|
||||
State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight;
|
||||
|
@ -526,6 +368,50 @@ HandleInput (app_state* State, input_queue InputQueue, mouse_state Mouse)
|
|||
ClearCommandQueue(&State->CommandQueue);
|
||||
}
|
||||
|
||||
internal dmx_buffer_list*
|
||||
CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena)
|
||||
{
|
||||
dmx_buffer_list* Result = 0;
|
||||
dmx_buffer_list* Head = 0;
|
||||
|
||||
s32 BufferSize = BufferHeaderSize + 512;
|
||||
|
||||
s32 Universe = 1;
|
||||
s32 ChannelsUsed = 0;
|
||||
for (s32 l = 0; l < Assembly.LEDCount; l++)
|
||||
{
|
||||
if(ChannelsUsed == 0)
|
||||
{
|
||||
dmx_buffer_list* NewBuffer = PushStruct(Arena, dmx_buffer_list);
|
||||
NewBuffer->Buffer.Universe = Universe;
|
||||
NewBuffer->Buffer.Base = PushArray(Arena, u8, BufferSize);
|
||||
NewBuffer->Buffer.TotalSize = BufferSize;
|
||||
NewBuffer->Buffer.HeaderSize = BufferHeaderSize;
|
||||
|
||||
// Append
|
||||
if (!Result) {
|
||||
Result = NewBuffer;
|
||||
Head = Result;
|
||||
}
|
||||
Head->Next = NewBuffer;
|
||||
Head = NewBuffer;
|
||||
}
|
||||
|
||||
led LED = Assembly.LEDs[l];
|
||||
pixel Color = Assembly.Colors[LED.Index];
|
||||
*((pixel*)(Head->Buffer.Base + ChannelsUsed)) = Color;
|
||||
ChannelsUsed += 3;
|
||||
|
||||
if (ChannelsUsed + 3 >= 512)
|
||||
{
|
||||
Universe++;
|
||||
ChannelsUsed= 0;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
UPDATE_AND_RENDER(UpdateAndRender)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
@ -539,71 +425,57 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
|
||||
HandleInput(State, InputQueue, Mouse);
|
||||
|
||||
if (State->LEDBufferList)
|
||||
for (s32 AssemblyIndex = 0; AssemblyIndex < State->AssembliesCount; AssemblyIndex++)
|
||||
{
|
||||
assembly Assembly = State->AssemblyList[AssemblyIndex];
|
||||
UpdateOutputNodeCalculations(State->OutputNode, State->NodeList,
|
||||
State->Permanent, State->Transient,
|
||||
State->LEDBufferList->LEDs,
|
||||
State->LEDBufferList->Colors,
|
||||
State->LEDBufferList->Count,
|
||||
Assembly.LEDs,
|
||||
Assembly.Colors,
|
||||
Assembly.LEDCount,
|
||||
Context.DeltaTime);
|
||||
ResetNodesUpdateState(State->NodeList);
|
||||
}
|
||||
ClearTransientNodeColorBuffers(State->NodeList);
|
||||
|
||||
{
|
||||
// NOTE(Peter): We know that these two lists should be maintained together. Each element in the list is one sculpture's worth of
|
||||
// information, and should always be evaluated in pairs.
|
||||
sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer;
|
||||
led_buffer* LEDBuffer = State->LEDBufferList;
|
||||
while (UniverseList && LEDBuffer)
|
||||
{
|
||||
for (s32 U = 0; U < UniverseList->Used; U++)
|
||||
{
|
||||
sacn_universe* UniverseOne = UniverseList->Universes + U;
|
||||
Assert(UniverseOne->BeginPixelCopyFromOffset >= 0);
|
||||
|
||||
u8* LEDColorBuffer = (u8*)LEDBuffer->Colors + UniverseOne->BeginPixelCopyFromOffset;
|
||||
u8* SACNSendBuffer = UniverseOne->StartPositionInSendBuffer + STREAM_HEADER_SIZE;
|
||||
|
||||
GSMemCopy(LEDColorBuffer, SACNSendBuffer, STREAM_BODY_SIZE);
|
||||
}
|
||||
UniverseList = UniverseList->Next;
|
||||
LEDBuffer = LEDBuffer->Next;
|
||||
}
|
||||
Assert(!LEDBuffer && !UniverseList);
|
||||
}
|
||||
|
||||
DEBUG_IF(GlobalDebugServices->Interface.SendSACNData)
|
||||
{
|
||||
if (++State->SACN.SequenceIterator == 0) // Never use 0 after the first one
|
||||
s32 HeaderSize = State->NetworkProtocolHeaderSize;
|
||||
dmx_buffer_list* DMXBuffers = 0;
|
||||
for (s32 i = 0; i < State->AssembliesCount; i++)
|
||||
{
|
||||
++State->SACN.SequenceIterator;
|
||||
assembly Assembly = State->AssemblyList[i];
|
||||
dmx_buffer_list* NewDMXBuffers = CreateDMXBuffers(Assembly, HeaderSize, State->Transient);
|
||||
DMXBuffers = DMXBufferListAppend(DMXBuffers, NewDMXBuffers);
|
||||
}
|
||||
|
||||
|
||||
sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer;
|
||||
while (UniverseList)
|
||||
switch (State->NetworkProtocol)
|
||||
{
|
||||
s32 JobCount = 2;
|
||||
s32 UniversesPerJob = UniverseList->Used / JobCount;
|
||||
send_sacn_job_data* SACNData = PushArray(State->Transient, send_sacn_job_data, JobCount);
|
||||
for (s32 i = 0; i < JobCount; i++)
|
||||
case NetworkProtocol_SACN:
|
||||
{
|
||||
SACNData[i].SACN = State->SACN;
|
||||
SACNData[i].UniverseList = *UniverseList;
|
||||
SACNData[i].StartUniverse = i * UniversesPerJob;
|
||||
SACNData[i].OnePastLastUniverse = (i * UniversesPerJob) + UniversesPerJob;
|
||||
if (SACNData[i].OnePastLastUniverse > UniverseList->Used)
|
||||
SACNUpdateSequence(&State->SACN);
|
||||
|
||||
dmx_buffer_list* CurrentDMXBuffer = DMXBuffers;
|
||||
while (CurrentDMXBuffer)
|
||||
{
|
||||
SACNData[i].OnePastLastUniverse = UniverseList->Used;
|
||||
dmx_buffer Buffer = CurrentDMXBuffer->Buffer;
|
||||
SACNPrepareBufferHeader(Buffer.Universe, Buffer.Base, Buffer.TotalSize, Buffer.HeaderSize, State->SACN);
|
||||
CurrentDMXBuffer = CurrentDMXBuffer->Next;
|
||||
}
|
||||
|
||||
send_sacn_job_data* Job = PushStruct(State->Transient, send_sacn_job_data);
|
||||
Job->SendSocket = State->SACN.SendSocket;
|
||||
Job->GetSendAddress = Context.PlatformGetSendAddress;
|
||||
Job->SendTo = Context.PlatformSendTo;
|
||||
Job->DMXBuffers = DMXBuffers;
|
||||
|
||||
Context.GeneralWorkQueue->PushWorkOnQueue(
|
||||
Context.GeneralWorkQueue,
|
||||
SendSACNBufferData,
|
||||
SACNData + i);
|
||||
}
|
||||
UniverseList = UniverseList->Next;
|
||||
SACNSendDMXBufferListJob,
|
||||
Job);
|
||||
}break;
|
||||
|
||||
InvalidDefaultCase;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -637,16 +509,18 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
|
||||
render_quad_batch_constructor BatchConstructor = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount);
|
||||
|
||||
led_buffer* LEDBuffer = State->LEDBufferList;
|
||||
s32 CurrentAssemblyIndex = 0;
|
||||
s32 LEDBufferLEDsAssignedToJobs = 0;
|
||||
|
||||
for (s32 Job = 0; Job < JobsNeeded; Job++)
|
||||
{
|
||||
assembly CurrentAssembly = State->AssemblyList[CurrentAssemblyIndex];
|
||||
|
||||
draw_leds_job_data* JobData = JobDataBank + JobDataBankUsed++;
|
||||
JobData->LEDs = LEDBuffer->LEDs;
|
||||
JobData->Colors = LEDBuffer->Colors;
|
||||
JobData->LEDs = CurrentAssembly.LEDs;
|
||||
JobData->Colors = CurrentAssembly.Colors;
|
||||
JobData->StartIndex = LEDBufferLEDsAssignedToJobs;
|
||||
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LEDBufferSize, LEDBuffer->Count);
|
||||
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LEDBufferSize, CurrentAssembly.LEDCount);
|
||||
|
||||
LEDBufferLEDsAssignedToJobs += JobData->OnePastLastIndex - JobData->StartIndex;
|
||||
|
||||
|
@ -662,11 +536,18 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
DrawLEDsInBufferRangeJob,
|
||||
JobData);
|
||||
|
||||
Assert(LEDBufferLEDsAssignedToJobs <= LEDBuffer->Count); // We should never go OVER the number of leds in the buffer
|
||||
if (LEDBufferLEDsAssignedToJobs == LEDBuffer->Count)
|
||||
// NOTE: We should never go OVER the number of leds in the buffer
|
||||
Assert(LEDBufferLEDsAssignedToJobs <= CurrentAssembly.LEDCount);
|
||||
if (LEDBufferLEDsAssignedToJobs == CurrentAssembly.LEDCount)
|
||||
{
|
||||
LEDBuffer = LEDBuffer->Next;
|
||||
LEDBufferLEDsAssignedToJobs = 0;
|
||||
if (CurrentAssemblyIndex >= State->AssembliesCount)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentAssemblyIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -700,7 +581,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
|
|||
State->Interface, Mouse);
|
||||
|
||||
string InterfaceString = MakeString(PushArray(State->Transient, char, 256), 256);
|
||||
for (int i = 0; i < State->AssembliesUsed; i++)
|
||||
for (int i = 0; i < State->AssembliesCount; i++)
|
||||
{
|
||||
PrintF(&InterfaceString, "Unload %.*s", State->AssemblyList[i].Name.Length, State->AssemblyList[i].Name.Memory);
|
||||
|
||||
|
|
|
@ -4,44 +4,15 @@
|
|||
#include "interface.h"
|
||||
|
||||
#include "foldhaus_network_ordering.h"
|
||||
#include "foldhaus_sacn.h"
|
||||
#include "dmx/dmx.h"
|
||||
#include "sacn/sacn.h"
|
||||
|
||||
struct led
|
||||
{
|
||||
s32 Index;
|
||||
v4 Position;
|
||||
};
|
||||
|
||||
struct led_buffer
|
||||
{
|
||||
sacn_pixel* Colors;
|
||||
led* LEDs;
|
||||
s32 Count;
|
||||
s32 Max;
|
||||
|
||||
led_buffer* Next;
|
||||
};
|
||||
|
||||
#define CalculateMemorySizeForAssembly(leds, name_length) ((sizeof(led) + sizeof(sacn_pixel)) * (leds)) + sizeof(led_buffer) + name_length;
|
||||
struct assembly
|
||||
{
|
||||
s32 MemorySize;
|
||||
u8* MemoryBase;
|
||||
|
||||
string Name;
|
||||
string FilePath;
|
||||
led_buffer* LEDBuffer;
|
||||
|
||||
// Memory managed by the SACN system
|
||||
sacn_universe_buffer* Universes;
|
||||
sacn_send_buffer* SendBuffer;
|
||||
};
|
||||
#include "foldhaus_assembly.h"
|
||||
|
||||
#include "assembly_parser.h"
|
||||
#include "foldhaus_node.h"
|
||||
#include "assembly_parser.cpp"
|
||||
#include "test_patterns.h"
|
||||
#include "kraftwerks_patterns.h"
|
||||
#include "foldhaus_interface.h"
|
||||
|
||||
typedef struct app_state app_state;
|
||||
|
@ -56,15 +27,33 @@ typedef struct app_state app_state;
|
|||
#include "generated/foldhaus_nodes_generated.cpp"
|
||||
#include "foldhaus_search_lister.h"
|
||||
|
||||
enum network_protocol
|
||||
{
|
||||
NetworkProtocol_SACN,
|
||||
NetworkProtocol_ArtNet,
|
||||
|
||||
NetworkProtocol_Count,
|
||||
};
|
||||
|
||||
struct app_state
|
||||
{
|
||||
memory_arena* Permanent;
|
||||
memory_arena* Transient;
|
||||
memory_arena SACNMemory;
|
||||
|
||||
s32 NetworkProtocolHeaderSize;
|
||||
network_protocol NetworkProtocol;
|
||||
|
||||
streaming_acn SACN;
|
||||
|
||||
s32 TotalLEDsCount;
|
||||
led_buffer* LEDBufferList;
|
||||
|
||||
// TODO(Peter): Make this dynamic. We want them contiguous in memory since we'll be accessing them
|
||||
// mostly by looping through them. On the other hand, I don't expect there to ever be more than 100
|
||||
// of them at once.
|
||||
#define ASSEMBLY_LIST_LENGTH 32
|
||||
assembly AssemblyList[ASSEMBLY_LIST_LENGTH];
|
||||
s32 AssembliesCount;
|
||||
|
||||
camera Camera;
|
||||
r32 PixelsToWorldScale;
|
||||
|
@ -74,13 +63,6 @@ struct app_state
|
|||
input_command_queue CommandQueue;
|
||||
text_entry ActiveTextEntry;
|
||||
|
||||
// TODO(Peter): Make this dynamic. We want them contiguous in memory since we'll be accessing them
|
||||
// mostly by looping through them. On the other hand, I don't expect there to ever be more than 100
|
||||
// of them at once.
|
||||
#define ASSEMBLY_LIST_LENGTH 32
|
||||
assembly AssemblyList[ASSEMBLY_LIST_LENGTH];
|
||||
s32 AssembliesUsed;
|
||||
|
||||
node_list* NodeList;
|
||||
node_header* OutputNode;
|
||||
|
||||
|
@ -91,9 +73,10 @@ struct app_state
|
|||
|
||||
internal void OpenColorPicker(app_state* State, v4* Address);
|
||||
|
||||
#include "foldhaus_assembly.cpp"
|
||||
#include "foldhaus_node.cpp"
|
||||
#include "foldhaus_debug_visuals.h"
|
||||
#include "foldhaus_sacn_view.cpp"
|
||||
//#include "foldhaus_sacn_view.cpp"
|
||||
#include "foldhaus_text_entry.cpp"
|
||||
#include "foldhaus_search_lister.cpp"
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
internal assembly
|
||||
ConstructAssemblyFromDefinition (assembly_definition Definition,
|
||||
string AssemblyName,
|
||||
v3 RootPosition,
|
||||
r32 Scale,
|
||||
context Context)
|
||||
{
|
||||
assembly Assembly = {};
|
||||
|
||||
s32 MemorySize = AssemblySize(Definition.TotalLEDCount, AssemblyName.Length);
|
||||
Assembly.Memory = AllocateNonGrowableArenaWithSpace(Context.PlatformAlloc, MemorySize);
|
||||
|
||||
Assembly.Name = MakeString(PushArray(&Assembly.Memory, char, AssemblyName.Length),
|
||||
AssemblyName.Length);
|
||||
CopyStringTo(AssemblyName, &Assembly.Name);
|
||||
|
||||
// NOTE(Peter): Setting this to zero so we can check at the end of the loop that creates leds
|
||||
// and make sure we created to correct number. By the time this function returns it should be
|
||||
// the case that: (Assembly.LEDCount == Definition.TotalLEDCount)
|
||||
Assembly.LEDCount = 0;
|
||||
Assembly.Colors = PushArray(&Assembly.Memory, pixel, Definition.TotalLEDCount);
|
||||
Assembly.LEDs = PushArray(&Assembly.Memory, led, Definition.TotalLEDCount);
|
||||
|
||||
// Add LEDs
|
||||
for (s32 StripIdx = 0; StripIdx < Definition.LEDStripCount; StripIdx++)
|
||||
{
|
||||
led_strip_definition StripDef = Definition.LEDStrips[StripIdx];
|
||||
|
||||
// NOTE(Peter): this should be a switch on the type, but we only have one for
|
||||
// now. The assert is to remind you to create more cases when necessary
|
||||
Assert(StripDef.InterpolationType == StripInterpolate_Points);
|
||||
|
||||
v4 WS_StripStart = V4(StripDef.InterpolatePositionStart * Scale, 1);
|
||||
v4 WS_StripEnd = V4(StripDef.InterpolatePositionEnd * Scale, 1);
|
||||
s32 LEDsInStripCount = StripDef.LEDsPerStrip;
|
||||
|
||||
Assert(Assembly.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount);
|
||||
|
||||
v4 SingleStep = (WS_StripEnd - WS_StripStart) / (r32)LEDsInStripCount;
|
||||
for (s32 Step = 0; Step < LEDsInStripCount; Step++)
|
||||
{
|
||||
s32 LEDIndex = Assembly.LEDCount++;
|
||||
Assembly.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step);
|
||||
Assembly.LEDs[LEDIndex].Index = LEDIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(Peter): Did we create the correct number of LEDs?
|
||||
Assert(Assembly.LEDCount == Definition.TotalLEDCount);
|
||||
return Assembly;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
struct led
|
||||
{
|
||||
s32 Index;
|
||||
v4 Position;
|
||||
};
|
||||
|
||||
union pixel
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8 R;
|
||||
u8 G;
|
||||
u8 B;
|
||||
};
|
||||
u8 Channels[3];
|
||||
};
|
||||
|
||||
#define AssemblySize(leds, name_length) ((sizeof(led) + sizeof(pixel)) * (leds)) + name_length;
|
||||
struct assembly
|
||||
{
|
||||
memory_arena Memory;
|
||||
s32 MemorySize;
|
||||
u8* MemoryBase;
|
||||
|
||||
string Name;
|
||||
string FilePath;
|
||||
|
||||
s32 LEDCount;
|
||||
pixel* Colors;
|
||||
led* LEDs;
|
||||
};
|
|
@ -13,6 +13,9 @@ struct universe_view_operation_state
|
|||
|
||||
OPERATION_RENDER_PROC(RenderUniverseView)
|
||||
{
|
||||
InvalidCodePath;
|
||||
|
||||
#if 0
|
||||
DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay);
|
||||
|
||||
universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory;
|
||||
|
@ -49,9 +52,8 @@ OPERATION_RENDER_PROC(RenderUniverseView)
|
|||
UniverseIdx++)
|
||||
{
|
||||
sacn_universe* Universe = UniverseList->Universes + UniverseIdx;
|
||||
DrawSACNUniversePixels(RenderBuffer, Universe, UniverseDisplayTopLeft, UniverseDisplayDimension);
|
||||
|
||||
DrawSACNUniversePixels(RenderBuffer, Universe,
|
||||
UniverseDisplayTopLeft, UniverseDisplayDimension);
|
||||
|
||||
if (OpState->Zoom > .5f)
|
||||
{
|
||||
|
@ -72,9 +74,11 @@ OPERATION_RENDER_PROC(RenderUniverseView)
|
|||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
UniverseList = UniverseList->Next;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO(Peter): Something isn't working with my laptop trackpad's zoom
|
||||
|
|
|
@ -31,26 +31,6 @@ GSMemCopy (u8* Source, u8* Destination, s32 Count)
|
|||
|
||||
#endif // GS_LANGUAGE_H
|
||||
|
||||
#ifndef GS_PLATFORM_H
|
||||
|
||||
#define PLATFORM_MEMORY_NO_ERROR 0
|
||||
#define PLATFORM_MEMORY_ERROR 1
|
||||
struct platform_memory_result
|
||||
{
|
||||
s32 Size;
|
||||
u8* Base;
|
||||
s32 Error;
|
||||
};
|
||||
|
||||
#define PLATFORM_ALLOC(name) platform_memory_result name(s32 Size)
|
||||
typedef PLATFORM_ALLOC(platform_alloc);
|
||||
|
||||
// Returns 1 if successful, 0 otherwise
|
||||
#define PLATFORM_FREE(name) b32 name(u8* Memory, s32 Size)
|
||||
typedef PLATFORM_FREE(platform_free);
|
||||
|
||||
#endif // GS_PLATFORM_H
|
||||
|
||||
#if !defined Assert && defined DEBUG
|
||||
#define Assert(expression) if(!(expression)){ *((int *)0) = 5; }
|
||||
#define InvalidCodePath Assert(0)
|
||||
|
|
|
@ -1,31 +1,36 @@
|
|||
//Packs a u8 to a known big endian buffer
|
||||
inline u8* PackB1(u8* ptr, u8 val)
|
||||
// Packs a u8 to a known big endian buffer
|
||||
inline u8*
|
||||
PackB1(u8* ptr, u8 val)
|
||||
{
|
||||
*ptr = val;
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
||||
//Unpacks a u8 from a known big endian buffer
|
||||
inline u8 UpackB1(const u8* ptr)
|
||||
inline u8
|
||||
UpackB1(const u8* ptr)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
//Packs a u8 to a known little endian buffer
|
||||
inline u8* PackL1(u8* ptr, u8 val)
|
||||
inline u8*
|
||||
PackL1(u8* ptr, u8 val)
|
||||
{
|
||||
*ptr = val;
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
||||
//Unpacks a u8 from a known little endian buffer
|
||||
inline u8 UpackL1(const u8* ptr)
|
||||
inline u8
|
||||
UpackL1(const u8* ptr)
|
||||
{
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
//Packs a u16 to a known big endian buffer
|
||||
inline u8* PackB2(u8* ptr, u16 val)
|
||||
inline u8*
|
||||
PackB2(u8* ptr, u16 val)
|
||||
{
|
||||
ptr[1] = (u8)(val & 0xff);
|
||||
ptr[0] = (u8)((val & 0xff00) >> 8);
|
||||
|
@ -33,26 +38,30 @@ inline u8* PackB2(u8* ptr, u16 val)
|
|||
}
|
||||
|
||||
//Unpacks a u16 from a known big endian buffer
|
||||
inline u16 UpackB2(const u8* ptr)
|
||||
inline u16
|
||||
UpackB2(const u8* ptr)
|
||||
{
|
||||
return (u16)(ptr[1] | ptr[0] << 8);
|
||||
}
|
||||
|
||||
//Packs a u16 to a known little endian buffer
|
||||
inline u8* PackL2(u8* ptr, u16 val)
|
||||
inline u8*
|
||||
PackL2(u8* ptr, u16 val)
|
||||
{
|
||||
*((u16*)ptr) = val;
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
||||
//Unpacks a u16 from a known little endian buffer
|
||||
inline u16 UpackL2(const u8* ptr)
|
||||
inline u16
|
||||
UpackL2(const u8* ptr)
|
||||
{
|
||||
return *((u16*)ptr);
|
||||
}
|
||||
|
||||
//Packs a u32 to a known big endian buffer
|
||||
inline u8* PackB4(u8* ptr, u32 val)
|
||||
inline u8*
|
||||
PackB4(u8* ptr, u32 val)
|
||||
{
|
||||
ptr[3] = (u8) (val & 0xff);
|
||||
ptr[2] = (u8)((val & 0xff00) >> 8);
|
||||
|
@ -62,26 +71,30 @@ inline u8* PackB4(u8* ptr, u32 val)
|
|||
}
|
||||
|
||||
//Unpacks a u32 from a known big endian buffer
|
||||
inline u32 UpackB4(const u8* ptr)
|
||||
inline u32
|
||||
UpackB4(const u8* ptr)
|
||||
{
|
||||
return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24));
|
||||
}
|
||||
|
||||
//Packs a u32 to a known little endian buffer
|
||||
inline u8* PackL4(u8* ptr, u32 val)
|
||||
inline u8*
|
||||
PackL4(u8* ptr, u32 val)
|
||||
{
|
||||
*((u32*)ptr) = val;
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
||||
//Unpacks a u32 from a known little endian buffer
|
||||
inline u32 UpackL4(const u8* ptr)
|
||||
inline u32
|
||||
UpackL4(const u8* ptr)
|
||||
{
|
||||
return *((u32*)ptr);
|
||||
}
|
||||
|
||||
//Packs a u64 to a known big endian buffer
|
||||
inline u8* PackB8(u8* ptr, u64 val)
|
||||
inline u8*
|
||||
PackB8(u8* ptr, u64 val)
|
||||
{
|
||||
ptr[7] = (u8) (val & 0xff);
|
||||
ptr[6] = (u8)((val & 0xff00) >> 8);
|
||||
|
@ -95,7 +108,8 @@ inline u8* PackB8(u8* ptr, u64 val)
|
|||
}
|
||||
|
||||
//Unpacks a uint64 from a known big endian buffer
|
||||
inline u64 UpackB8(const u8* ptr)
|
||||
inline u64
|
||||
UpackB8(const u8* ptr)
|
||||
{
|
||||
return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) |
|
||||
(((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) |
|
||||
|
@ -104,14 +118,16 @@ inline u64 UpackB8(const u8* ptr)
|
|||
}
|
||||
|
||||
//Packs a u64 to a known little endian buffer
|
||||
inline u8* PackL8(u8* ptr, u64 val)
|
||||
inline u8*
|
||||
PackL8(u8* ptr, u64 val)
|
||||
{
|
||||
*((u64*)ptr) = val;
|
||||
return ptr + sizeof(val);
|
||||
}
|
||||
|
||||
//Unpacks a u64 from a known little endian buffer
|
||||
inline u64 UpackL8(const u8* ptr)
|
||||
inline u64
|
||||
UpackL8(const u8* ptr)
|
||||
{
|
||||
return *((u64*)ptr);
|
||||
}
|
||||
|
|
|
@ -821,12 +821,12 @@ UpdateDraggingNodeValue (v2 MousePos, v2 LastFrameMousePos, node_interaction Int
|
|||
|
||||
internal void UpdateNodeCalculation (node_header* Node, node_list* NodeList,
|
||||
memory_arena* Permanent, memory_arena* Transient,
|
||||
led* LEDs, sacn_pixel* ColorsInit, s32 LEDCount, r32 DeltaTime);
|
||||
led* LEDs, pixel* ColorsInit, s32 LEDCount, r32 DeltaTime);
|
||||
|
||||
internal void
|
||||
UpdateNodesConnectedUpstream (node_header* Node, node_list* NodeList,
|
||||
memory_arena* Permanent, memory_arena* Transient,
|
||||
led* LEDs, sacn_pixel* ColorsInit, s32 LEDCount, r32 DeltaTime)
|
||||
led* LEDs, pixel* ColorsInit, s32 LEDCount, r32 DeltaTime)
|
||||
{
|
||||
for (s32 ConnectionIdx = 0; ConnectionIdx < Node->ConnectionsCount; ConnectionIdx++)
|
||||
{
|
||||
|
@ -877,7 +877,7 @@ UpdateNodesConnectedUpstream (node_header* Node, node_list* NodeList,
|
|||
internal void
|
||||
UpdateNodeCalculation (node_header* Node, node_list* NodeList,
|
||||
memory_arena* Permanent, memory_arena* Transient,
|
||||
led* LEDs, sacn_pixel* ColorsInit, s32 LEDCount, r32 DeltaTime)
|
||||
led* LEDs, pixel* ColorsInit, s32 LEDCount, r32 DeltaTime)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
Assert(Node->PersistentData != 0);
|
||||
|
@ -894,7 +894,7 @@ UpdateNodeCalculation (node_header* Node, node_list* NodeList,
|
|||
// eachother to update.
|
||||
Node->UpdatedThisFrame = true;
|
||||
|
||||
sacn_pixel* Colors = ColorsInit;
|
||||
pixel* Colors = ColorsInit;
|
||||
|
||||
UpdateNodesConnectedUpstream(Node, NodeList, Permanent, Transient, LEDs, Colors, LEDCount, DeltaTime);
|
||||
|
||||
|
@ -910,8 +910,8 @@ UpdateNodeCalculation (node_header* Node, node_list* NodeList,
|
|||
node_led_color_connection* ColorConnection = Connection.LEDsValuePtr;
|
||||
if (!ColorConnection->Colors)
|
||||
{
|
||||
sacn_pixel* ColorsCopy = PushArray(Transient, sacn_pixel, LEDCount);
|
||||
GSMemSet((u8*)ColorsCopy, 0, sizeof(sacn_pixel) * LEDCount);
|
||||
pixel* ColorsCopy = PushArray(Transient, pixel, LEDCount);
|
||||
GSMemSet((u8*)ColorsCopy, 0, sizeof(pixel) * LEDCount);
|
||||
|
||||
ColorConnection->Colors = ColorsCopy;
|
||||
ColorConnection->LEDs = LEDs;
|
||||
|
@ -932,7 +932,7 @@ UpdateNodeCalculation (node_header* Node, node_list* NodeList,
|
|||
internal void
|
||||
UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
|
||||
memory_arena* Permanent, memory_arena* Transient,
|
||||
led* LEDs, sacn_pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
led* LEDs, pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
{
|
||||
Assert(OutputNode->Type == NodeType_OutputNode);
|
||||
|
||||
|
@ -941,8 +941,8 @@ UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
|
|||
node_connection ColorsConnection = OutputNode->Connections[0];
|
||||
if (ColorsConnection.LEDsValuePtr->Colors)
|
||||
{
|
||||
sacn_pixel* DestPixel = Colors;
|
||||
sacn_pixel* SourcePixel = ColorsConnection.LEDsValuePtr->Colors;
|
||||
pixel* DestPixel = Colors;
|
||||
pixel* SourcePixel = ColorsConnection.LEDsValuePtr->Colors;
|
||||
for (s32 i = 0; i < LEDCount; i++)
|
||||
{
|
||||
*DestPixel++ = *SourcePixel++;
|
||||
|
@ -953,7 +953,7 @@ UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
|
|||
#if 0
|
||||
// Trying to put updating nodes in terms of connections, rather than nodes.
|
||||
internal void
|
||||
UpdateAllNodesFloodFill (node_list* NodeList, memory_arena* Permanent, memory_arena* Transient, led* LEDs, sacn_pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
UpdateAllNodesFloodFill (node_list* NodeList, memory_arena* Permanent, memory_arena* Transient, led* LEDs, pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
{
|
||||
s32 NodesUpdated = 0;
|
||||
|
||||
|
@ -998,7 +998,7 @@ UpdateAllNodesFloodFill (node_list* NodeList, memory_arena* Permanent, memory_ar
|
|||
#endif
|
||||
|
||||
internal void
|
||||
UpdateAllNodeCalculations (node_list* NodeList, memory_arena* Permanent, memory_arena* Transient, led* LEDs, sacn_pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
UpdateAllNodeCalculations (node_list* NodeList, memory_arena* Permanent, memory_arena* Transient, led* LEDs, pixel* Colors, s32 LEDCount, r32 DeltaTime)
|
||||
{
|
||||
node_list_iterator NodeIter = GetNodeListIterator(*NodeList);
|
||||
while (NodeIteratorIsValid(NodeIter))
|
||||
|
|
|
@ -7,12 +7,12 @@ typedef enum node_type node_type;
|
|||
|
||||
#define NODE_COLOR_BUFFER \
|
||||
led* LEDs; \
|
||||
sacn_pixel* Colors; \
|
||||
pixel* Colors; \
|
||||
s32 LEDCount;
|
||||
|
||||
#define NAMED_NODE_COLOR_BUFFER(name) \
|
||||
led* name##LEDs; \
|
||||
sacn_pixel* name##Colors; \
|
||||
pixel* name##Colors; \
|
||||
s32 name##LEDCount;
|
||||
|
||||
#define NODE_COLOR_BUFFER_INOUT NODE_COLOR_BUFFER
|
||||
|
|
|
@ -1,612 +0,0 @@
|
|||
#define NETWORKINTID_INVALID -1
|
||||
|
||||
#define DEFAULT_STREAMING_ACN_PORT 5568
|
||||
|
||||
#define IP_ADDRESS_BYTES 16
|
||||
#define STARTCODE_DMX 0
|
||||
|
||||
/*
|
||||
* a description of the address space being used
|
||||
*/
|
||||
#define PREAMBLE_SIZE_ADDR 0
|
||||
#define POSTAMBLE_SIZE_ADDR 2
|
||||
#define ACN_IDENTIFIER_ADDR 4
|
||||
#define ROOT_FLAGS_AND_LENGTH_ADDR 16
|
||||
#define ROOT_VECTOR_ADDR 18
|
||||
#define CID_ADDR 22
|
||||
#define FRAMING_FLAGS_AND_LENGTH_ADDR 38
|
||||
#define FRAMING_VECTOR_ADDR 40
|
||||
#define SOURCE_NAME_ADDR 44
|
||||
#define PRIORITY_ADDR 108
|
||||
#define RESERVED_ADDR 109
|
||||
#define SEQ_NUM_ADDR 111
|
||||
#define OPTIONS_ADDR 112
|
||||
#define UNIVERSE_ADDR 113
|
||||
#define DMP_FLAGS_AND_LENGTH_ADDR 115
|
||||
#define DMP_VECTOR_ADDR 117
|
||||
#define DMP_ADDRESS_AND_DATA_ADDR 118
|
||||
#define FIRST_PROPERTY_ADDRESS_ADDR 119
|
||||
#define ADDRESS_INC_ADDR 121
|
||||
#define PROP_COUNT_ADDR 123
|
||||
#define START_CODE_ADDR 125
|
||||
#define PROP_VALUES_ADDR (START_CODE_ADDR + 1)
|
||||
|
||||
/*
|
||||
* common sizes
|
||||
*/
|
||||
#define STREAM_HEADER_SIZE 126
|
||||
#define STREAM_BODY_SIZE 512
|
||||
|
||||
#define SOURCE_NAME_SIZE 64
|
||||
#define RLP_PREAMBLE_SIZE 16
|
||||
#define RLP_POSTAMBLE_SIZE 0
|
||||
#define ACN_IDENTIFIER_SIZE 12
|
||||
|
||||
/*
|
||||
* data definitions
|
||||
*/
|
||||
#define ACN_IDENTIFIER "ASC-E1.17\0\0\0"
|
||||
#define ROOT_VECTOR 4
|
||||
#define FRAMING_VECTOR 2
|
||||
#define DMP_VECTOR 2
|
||||
#define ADDRESS_AND_DATA_FORMAT 0xa1
|
||||
#define ADDRESS_INC 1
|
||||
#define DMP_FIRST_PROPERTY_ADDRESS_FORCE 0
|
||||
#define RESERVED_VALUE 0
|
||||
|
||||
//for support of the early draft
|
||||
#define DRAFT_STREAM_HEADER_SIZE 90
|
||||
#define DRAFT_SOURCE_NAME_SIZE 32
|
||||
|
||||
//for support of the early draft
|
||||
#define DRAFT_ROOT_VECTOR 3
|
||||
|
||||
const u32 VHD_MAXFLAGBYTES = 7; //The maximum amount of bytes used to pack the flags, len, and vector
|
||||
const u32 VHD_MAXLEN = 0x0fffff; //The maximum packet length is 20 bytes long
|
||||
const u32 VHD_MAXMINLENGTH = 4095; //The highest length that will fit in the "smallest" length pack
|
||||
|
||||
//Defines for the VHD flags
|
||||
const u8 VHD_L_FLAG = 0x80;
|
||||
const u8 VHD_V_FLAG = 0x40;
|
||||
const u8 VHD_H_FLAG = 0x20;
|
||||
const u8 VHD_D_FLAG = 0x10;
|
||||
|
||||
#define CID_Bytes 16
|
||||
struct cid
|
||||
{
|
||||
u8 Bytes[CID_Bytes];
|
||||
};
|
||||
|
||||
struct sacn_universe
|
||||
{
|
||||
s16 Universe;
|
||||
|
||||
u8* StartPositionInSendBuffer;
|
||||
s32 SizeInSendBuffer;
|
||||
s32 OffsetInSendBuffer;
|
||||
|
||||
s32 BeginPixelCopyFromOffset;
|
||||
|
||||
platform_network_address_handle SendAddress;
|
||||
};
|
||||
|
||||
struct sacn_pixel
|
||||
{
|
||||
u8 R;
|
||||
u8 G;
|
||||
u8 B;
|
||||
};
|
||||
|
||||
struct sacn_send_buffer
|
||||
{
|
||||
u8* Memory;
|
||||
s32 Size;
|
||||
sacn_send_buffer* Next;
|
||||
};
|
||||
|
||||
struct sacn_universe_buffer
|
||||
{
|
||||
sacn_universe* Universes;
|
||||
s32 Used;
|
||||
s32 Max;
|
||||
sacn_universe_buffer* Next;
|
||||
};
|
||||
|
||||
struct streaming_acn
|
||||
{
|
||||
memory_arena Memory;
|
||||
|
||||
// These get created and freed together
|
||||
sacn_universe_buffer* UniverseBuffer;
|
||||
sacn_send_buffer* SendBuffer;
|
||||
|
||||
platform_socket_handle SendSocket;
|
||||
cid CID;
|
||||
|
||||
s32 SequenceIterator;
|
||||
};
|
||||
|
||||
|
||||
// SACN Data Header Functions
|
||||
internal void InitStreamHeader (u8* Buffer, s32 BufferSize, u16 SlotCount, u8 StartCode, u16 Universe, u8 Priority, u16 Reserved, u8 Options, const char* SourceName, cid CID);
|
||||
internal void SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft);
|
||||
internal void VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData);
|
||||
internal u8* VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength);
|
||||
internal cid StringToCID_ (const char* String);
|
||||
|
||||
#define CalculateSendBufferSize(UniverseCount) ((UniverseCount * (STREAM_HEADER_SIZE + STREAM_BODY_SIZE)) + sizeof(sacn_send_buffer))
|
||||
#define CalculateUniverseBufferSize(UniverseCount) ((UniverseCount * sizeof(sacn_universe)) + sizeof(sacn_universe_buffer))
|
||||
|
||||
// Utility
|
||||
|
||||
internal sacn_pixel
|
||||
PackFloatsToSACNPixel (r32 R, r32 G, r32 B)
|
||||
{
|
||||
sacn_pixel Result = {};
|
||||
Result.R = (u8)(GSClamp01(R) * 255);
|
||||
Result.G = (u8)(GSClamp01(G) * 255);
|
||||
Result.B = (u8)(GSClamp01(B) * 255);
|
||||
return Result;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
internal sacn_universe*
|
||||
SACNGetUniverse (s32 UniverseNumber, streaming_acn* SACN)
|
||||
{
|
||||
sacn_universe* Result = 0;
|
||||
|
||||
sacn_universe_buffer* Header = SACN->UniverseBuffer;
|
||||
while (Header)
|
||||
{
|
||||
sacn_universe* Cursor = Header->Universes;
|
||||
for (s32 i = 0; i < Header->Used; i++)
|
||||
{
|
||||
if (Cursor->Universe == UniverseNumber)
|
||||
{
|
||||
Result = Cursor;
|
||||
break;
|
||||
}
|
||||
Cursor++;
|
||||
}
|
||||
Header = Header->Next;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNPushSendBufferOnList (sacn_send_buffer* ListHead, sacn_send_buffer* NewBuffer)
|
||||
{
|
||||
if (ListHead->Next)
|
||||
{
|
||||
SACNPushSendBufferOnList(ListHead->Next, NewBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ListHead->Next = NewBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
internal sacn_send_buffer*
|
||||
SACNRemoveSendBufferFromList (sacn_send_buffer* List, sacn_send_buffer* Entry)
|
||||
{
|
||||
sacn_send_buffer* ListHead = 0;
|
||||
if (List != Entry && List->Next)
|
||||
{
|
||||
ListHead = SACNRemoveSendBufferFromList(List->Next, Entry);
|
||||
}
|
||||
else if (List == Entry)
|
||||
{
|
||||
ListHead = Entry->Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE(Peter): Trying to remove an entry from a list that doesn't contain it
|
||||
InvalidCodePath;
|
||||
}
|
||||
return ListHead;
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNPushUniverseBufferOnList (sacn_universe_buffer* ListHead, sacn_universe_buffer* NewBuffer)
|
||||
{
|
||||
if (ListHead->Next)
|
||||
{
|
||||
SACNPushUniverseBufferOnList(ListHead->Next, NewBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ListHead->Next = NewBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
internal sacn_universe_buffer*
|
||||
SACNRemoveUniverseBufferFromList (sacn_universe_buffer* List, sacn_universe_buffer* Entry)
|
||||
{
|
||||
sacn_universe_buffer* ListHead = 0;
|
||||
if (List != Entry && List->Next)
|
||||
{
|
||||
ListHead = SACNRemoveUniverseBufferFromList(List->Next, Entry);
|
||||
}
|
||||
else if (List == Entry)
|
||||
{
|
||||
ListHead = Entry->Next;
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE(Peter): Trying to remove an entry from a list that doesn't contain it
|
||||
InvalidCodePath;
|
||||
}
|
||||
return ListHead;
|
||||
}
|
||||
|
||||
struct sacn_add_universes_result
|
||||
{
|
||||
sacn_send_buffer* NewSendBuffer;
|
||||
sacn_universe_buffer* NewUniverseBuffer;
|
||||
};
|
||||
|
||||
internal sacn_add_universes_result
|
||||
SACNAddUniverses(s32* Universes, s32 UniversesLength, streaming_acn* SACN, context Context)
|
||||
{
|
||||
sacn_add_universes_result Result = {};
|
||||
|
||||
// Determine which universes are already registered and not to be readded.
|
||||
// NOTE(Peter): This might create funky behaviour if two sculptures start sending data to the same universe
|
||||
// but I'm not sure its incorrect behavior. I think, eventually, we will want to spit out a report from
|
||||
// this function that says what universes were duplicated. We might want to display this information to the user
|
||||
// in a way that they don't have to exit out of every single time they load the software. Not sure
|
||||
s32 UniversesToAdd = 0;
|
||||
for (s32 i = 0; i < UniversesLength; i++)
|
||||
{
|
||||
sacn_universe* UniverseExists = SACNGetUniverse(Universes[i], SACN);
|
||||
if (UniverseExists)
|
||||
{
|
||||
Universes[i] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
UniversesToAdd++;
|
||||
}
|
||||
}
|
||||
|
||||
// Reallocate and Copy over the send buffer
|
||||
|
||||
s32 SendBufferSize = CalculateSendBufferSize(UniversesToAdd);
|
||||
u8* SendBufferMemory = PushArray(&SACN->Memory, u8, SendBufferSize);
|
||||
sacn_send_buffer* SendBufferHeader = (sacn_send_buffer*)SendBufferMemory;
|
||||
SendBufferHeader->Memory = (u8*)(SendBufferHeader + 1);
|
||||
SendBufferHeader->Size = SendBufferSize - sizeof(sacn_send_buffer);
|
||||
SendBufferHeader->Next = 0;
|
||||
if (SACN->SendBuffer)
|
||||
{
|
||||
SACNPushSendBufferOnList(SACN->SendBuffer, SendBufferHeader);
|
||||
}
|
||||
else
|
||||
{
|
||||
SACN->SendBuffer = SendBufferHeader;
|
||||
}
|
||||
|
||||
s32 UniverseBufferSize = CalculateUniverseBufferSize(UniversesToAdd);
|
||||
u8* UniverseBufferMemory = PushArray(&SACN->Memory, u8, UniverseBufferSize);
|
||||
sacn_universe_buffer* UniverseBufferHeader = (sacn_universe_buffer*)UniverseBufferMemory;
|
||||
UniverseBufferHeader->Universes = (sacn_universe*)(UniverseBufferHeader + 1);
|
||||
UniverseBufferHeader->Used = 0;
|
||||
UniverseBufferHeader->Max = UniversesToAdd;
|
||||
if (SACN->UniverseBuffer)
|
||||
{
|
||||
SACNPushUniverseBufferOnList(SACN->UniverseBuffer, UniverseBufferHeader);
|
||||
}
|
||||
else
|
||||
{
|
||||
SACN->UniverseBuffer = UniverseBufferHeader;
|
||||
}
|
||||
|
||||
// Add each of the valid universes
|
||||
for (s32 j = 0; j < UniversesLength; j++)
|
||||
{
|
||||
if (Universes[j] >= 0)
|
||||
{
|
||||
Assert(UniverseBufferHeader->Used < UniverseBufferHeader->Max);
|
||||
s32 Index = UniverseBufferHeader->Used++;
|
||||
s32 UniverseID = Universes[j];
|
||||
|
||||
UniverseBufferHeader->Universes[Index].Universe = UniverseID;
|
||||
UniverseBufferHeader->Universes[Index].SizeInSendBuffer = STREAM_HEADER_SIZE + STREAM_BODY_SIZE;
|
||||
UniverseBufferHeader->Universes[Index].BeginPixelCopyFromOffset = -1;
|
||||
|
||||
// Configure how the universe looks into the pixel color buffer
|
||||
s32 SendBufferOffset = (Index * (STREAM_HEADER_SIZE + STREAM_BODY_SIZE));
|
||||
u8* SendBufferStartPosition = SendBufferHeader->Memory + SendBufferOffset;
|
||||
UniverseBufferHeader->Universes[Index].OffsetInSendBuffer = SendBufferOffset;
|
||||
UniverseBufferHeader->Universes[Index].StartPositionInSendBuffer = SendBufferStartPosition;
|
||||
|
||||
// Set up the Send Address
|
||||
u8 MulticastAddressBuffer[IP_ADDRESS_BYTES];
|
||||
GSMemSet(MulticastAddressBuffer, 0, IP_ADDRESS_BYTES);
|
||||
MulticastAddressBuffer[12] = 239;
|
||||
MulticastAddressBuffer[13] = 255;
|
||||
PackB2(MulticastAddressBuffer + 14, UniverseID);
|
||||
u_long V4Address = (u_long)UpackB4(MulticastAddressBuffer + IP_ADDRESS_BYTES - sizeof(u32));
|
||||
|
||||
GSMemSet(&UniverseBufferHeader->Universes[Index].SendAddress, 0, sizeof(sockaddr_in));
|
||||
UniverseBufferHeader->Universes[Index].SendAddress = Context.PlatformGetSendAddress(
|
||||
AF_INET,
|
||||
HostToNetU16(DEFAULT_STREAMING_ACN_PORT),
|
||||
HostToNetU32(V4Address));
|
||||
|
||||
s32 SlotCount = 512;
|
||||
InitStreamHeader(UniverseBufferHeader->Universes[Index].StartPositionInSendBuffer,
|
||||
UniverseBufferHeader->Universes[Index].SizeInSendBuffer,
|
||||
SlotCount,
|
||||
STARTCODE_DMX,
|
||||
UniverseID,
|
||||
0,
|
||||
0, // Reserved
|
||||
0, // Options
|
||||
"Source 1",
|
||||
SACN->CID
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Result.NewUniverseBuffer = UniverseBufferHeader;
|
||||
Result.NewSendBuffer= SendBufferHeader;
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNRemoveUniverseAndSendBuffer(streaming_acn* SACN, sacn_universe_buffer* Universes, sacn_send_buffer* SendBuffer)
|
||||
{
|
||||
SACN->UniverseBuffer = SACNRemoveUniverseBufferFromList(SACN->UniverseBuffer, Universes);
|
||||
SACN->SendBuffer = SACNRemoveSendBufferFromList(SACN->SendBuffer, SendBuffer);
|
||||
}
|
||||
|
||||
internal streaming_acn
|
||||
InitializeSACN (platform_alloc* PlatformAlloc, context Context)
|
||||
{
|
||||
streaming_acn SACN = {};
|
||||
|
||||
InitMemoryArena(&SACN.Memory, 0, 0, PlatformAlloc);
|
||||
|
||||
SACN.SendSocket = Context.PlatformGetSocketHandle(AF_INET, SOCK_DGRAM, 0);
|
||||
int Multicast_TimeToLive = 20;
|
||||
int Error = Context.PlatformSetSocketOption(SACN.SendSocket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
|
||||
SACN.CID = StringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
|
||||
|
||||
SACN.UniverseBuffer = 0;
|
||||
SACN.SendBuffer = 0;
|
||||
|
||||
return SACN;
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNSendDataToUniverse (streaming_acn* SACN, sacn_universe* Universe, platform_send_to* PlatformSendTo)
|
||||
{
|
||||
//DEBUG_TRACK_FUNCTION;
|
||||
|
||||
u8* StartPositionInSendBuffer = (u8*)Universe->StartPositionInSendBuffer;
|
||||
SetStreamHeaderSequence_(StartPositionInSendBuffer, SACN->SequenceIterator, false);
|
||||
|
||||
PlatformSendTo(SACN->SendSocket, Universe->SendAddress, (const char*)StartPositionInSendBuffer, Universe->SizeInSendBuffer, 0);
|
||||
#if 0 // Old Network Code
|
||||
// TODO(Peter): HUGE NOTE!!!!!!!!
|
||||
// This needs to be put on a separate thread. The sendto call is really slowing us down.
|
||||
s32 LengthSent = sendto(SACN->SendSocket, (const char*)StartPositionInSendBuffer, Universe->SizeInSendBuffer,
|
||||
0, (sockaddr*)(&Universe->SendAddress), sizeof(sockaddr_in));
|
||||
|
||||
if (LengthSent == SOCKET_ERROR)
|
||||
{
|
||||
s32 LastSocketError = WSAGetLastError();
|
||||
InvalidCodePath;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNCleanup(streaming_acn* SACN, context Context)
|
||||
{
|
||||
Context.PlatformCloseSocket(SACN->SendSocket);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// SACN Data Header Functions
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
internal void
|
||||
InitStreamHeader (u8* Buffer, s32 BufferSize,
|
||||
u16 SlotCount,
|
||||
u8 StartCode,
|
||||
u16 Universe,
|
||||
u8 Priority,
|
||||
u16 Reserved,
|
||||
u8 Options,
|
||||
const char* SourceName,
|
||||
cid CID
|
||||
)
|
||||
{
|
||||
|
||||
u8* Cursor = Buffer;
|
||||
|
||||
// Preamble Size
|
||||
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
|
||||
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
|
||||
|
||||
memcpy(Cursor, ACN_IDENTIFIER, ACN_IDENTIFIER_SIZE);
|
||||
Cursor += ACN_IDENTIFIER_SIZE;
|
||||
|
||||
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount,
|
||||
false);
|
||||
|
||||
// root vector
|
||||
Cursor = PackB4(Cursor, ROOT_VECTOR);
|
||||
|
||||
// CID Pack
|
||||
for (s32 i = 0; i < CID_Bytes; i++)
|
||||
{
|
||||
*Cursor++ = CID.Bytes[i];
|
||||
}
|
||||
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount,
|
||||
false);
|
||||
|
||||
// framing vector
|
||||
Cursor = PackB4(Cursor, FRAMING_VECTOR);
|
||||
|
||||
// framing source name
|
||||
strncpy((char*)Cursor, SourceName, SOURCE_NAME_SIZE);
|
||||
Cursor[SOURCE_NAME_SIZE - 1] = '\0';
|
||||
Cursor += SOURCE_NAME_SIZE;
|
||||
|
||||
// priority
|
||||
Cursor = PackB1(Cursor, Priority);
|
||||
|
||||
// reserved
|
||||
Cursor = PackB2(Cursor, Reserved);
|
||||
|
||||
// Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data
|
||||
Cursor = PackB1(Cursor, 0);
|
||||
|
||||
// Options
|
||||
Cursor = PackB1(Cursor, Options);
|
||||
|
||||
// Universe
|
||||
Cursor = PackB2(Cursor, Universe);
|
||||
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount,
|
||||
false);
|
||||
|
||||
// DMP Vector
|
||||
Cursor = PackB1(Cursor, DMP_VECTOR);
|
||||
|
||||
// DMP Address and data type
|
||||
Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT);
|
||||
|
||||
// DMP first property address
|
||||
Cursor = PackB2(Cursor, 0);
|
||||
|
||||
// DMP Address Increment
|
||||
Cursor = PackB2(Cursor, ADDRESS_INC);
|
||||
|
||||
// Property Value Count -- Includes one byte for start code
|
||||
Cursor = PackB2(Cursor, SlotCount + 1);
|
||||
|
||||
Cursor = PackB1(Cursor, StartCode);
|
||||
|
||||
s32 DiffSize = Cursor - Buffer;
|
||||
if (Cursor - Buffer != STREAM_HEADER_SIZE)
|
||||
{
|
||||
InvalidCodePath;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
PackB1(Buffer + SEQ_NUM_ADDR, Sequence);
|
||||
}
|
||||
|
||||
internal void
|
||||
VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData)
|
||||
{
|
||||
u8* Cursor = Buffer;
|
||||
u8 NewByte = UpackB1(Cursor) & 0x8f;
|
||||
|
||||
if (!InheritVec) { NewByte |= VHD_V_FLAG; }
|
||||
if (!InheritHead) { NewByte |= VHD_H_FLAG; }
|
||||
if (!InheritData) { NewByte |= VHD_D_FLAG; }
|
||||
|
||||
PackB1(Cursor, NewByte);
|
||||
}
|
||||
|
||||
internal u8*
|
||||
VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
|
||||
{
|
||||
u8* Cursor = Buffer;
|
||||
u32 AdjustedLength = Length;
|
||||
if (IncludeLength)
|
||||
{
|
||||
if (Length + 1 > VHD_MAXMINLENGTH)
|
||||
{
|
||||
AdjustedLength += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustedLength += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Mask out the length bits to keep flags intact
|
||||
u8 NewByte = UpackB1(Cursor) & 0x70;
|
||||
if (AdjustedLength > VHD_MAXMINLENGTH)
|
||||
{
|
||||
NewByte |= VHD_L_FLAG;
|
||||
}
|
||||
|
||||
u8 PackBuffer[4];
|
||||
PackB4(PackBuffer, AdjustedLength);
|
||||
if (AdjustedLength <= VHD_MAXMINLENGTH)
|
||||
{
|
||||
NewByte |= (PackBuffer[2] & 0x0f);
|
||||
Cursor = PackB1(Cursor, NewByte);
|
||||
Cursor = PackB1(Cursor, PackBuffer[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewByte |= (PackBuffer[1] & 0x0f);
|
||||
Cursor = PackB1(Cursor, PackBuffer[2]);
|
||||
Cursor = PackB1(Cursor, PackBuffer[3]);
|
||||
}
|
||||
|
||||
return Cursor;
|
||||
}
|
||||
|
||||
internal cid
|
||||
StringToCID_ (const char* String)
|
||||
{
|
||||
cid Result = {};
|
||||
|
||||
const char* Src = String;
|
||||
u8* Dest = &Result.Bytes[0];
|
||||
b32 FirstNibble = true;
|
||||
|
||||
while(*Src && (Dest - &Result.Bytes[0] < CID_Bytes))
|
||||
{
|
||||
u8 Offset = 0;
|
||||
if ((*Src >= 0x30) && (*Src <= 0x39)){ Offset = 0x30; }
|
||||
else if ((*Src >= 0x41) && (*Src <= 0x46)) { Offset = 0x37; }
|
||||
else if ((*Src >= 0x61) && (*Src <= 0x66)) { Offset = 0x66; }
|
||||
|
||||
if (Offset != 0)
|
||||
{
|
||||
if (FirstNibble)
|
||||
{
|
||||
*Dest = (u8)(*Src - Offset);
|
||||
*Dest <<= 4;
|
||||
FirstNibble = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*Dest |= (*Src - Offset);
|
||||
Dest++;
|
||||
FirstNibble = true;
|
||||
}
|
||||
}
|
||||
Src++;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
|
@ -7,7 +7,6 @@ NodeType_AddNodeProc,
|
|||
NodeType_SinWave,
|
||||
NodeType_MultiplyPatterns,
|
||||
NodeType_OutputNode,
|
||||
NodeType_SwdColorProc,
|
||||
NodeType_SolidColorProc,
|
||||
NodeType_VerticalColorFadeProc,
|
||||
NodeType_RevolvingDiscs,
|
||||
|
@ -56,12 +55,6 @@ node_struct_member MemberList_output_node_data[] = {
|
|||
{ MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((output_node_data*)0)->ResultLEDs, IsInputMember },
|
||||
};
|
||||
|
||||
node_struct_member MemberList_swd_color_data[] = {
|
||||
{ MemberType_v4, "Color", (u64)&((swd_color_data*)0)->Color, IsInputMember },
|
||||
{ MemberType_v4, "ColorB", (u64)&((swd_color_data*)0)->ColorB, IsInputMember },
|
||||
{ MemberType_NODE_COLOR_BUFFER, "LEDs", (u64)&((swd_color_data*)0)->LEDs, IsInputMember | IsOutputMember},
|
||||
};
|
||||
|
||||
node_struct_member MemberList_solid_color_data[] = {
|
||||
{ MemberType_v4, "Color", (u64)&((solid_color_data*)0)->Color, IsInputMember },
|
||||
{ MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((solid_color_data*)0)->ResultLEDs, IsOutputMember},
|
||||
|
@ -93,12 +86,11 @@ node_specification NodeSpecifications[] = {
|
|||
{ NodeType_SinWave, "SinWave", 7, MemberList_sin_wave_data, 20, 4, false},
|
||||
{ NodeType_MultiplyPatterns, "MultiplyPatterns", 16, MemberList_multiply_patterns_data, 60, 3, false},
|
||||
{ NodeType_OutputNode, "OutputNode", 10, MemberList_output_node_data, 20, 1, false},
|
||||
{ NodeType_SwdColorProc, "SwdColorProc", 12, MemberList_swd_color_data, 52, 3, false},
|
||||
{ NodeType_SolidColorProc, "SolidColorProc", 14, MemberList_solid_color_data, 36, 2, false},
|
||||
{ NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 44, 4, false},
|
||||
{ NodeType_RevolvingDiscs, "RevolvingDiscs", 14, MemberList_revolving_discs_data, 60, 8, false},
|
||||
};
|
||||
s32 NodeSpecificationsCount = 11;
|
||||
s32 NodeSpecificationsCount = 10;
|
||||
|
||||
internal void CallNodeProc(node_header* Node, u8* Data, led* LEDs, s32 LEDsCount, r32 DeltaTime)
|
||||
{
|
||||
|
@ -112,7 +104,6 @@ case NodeType_AddNodeProc: { AddNodeProc((add_data*)Data, DeltaTime); } break;
|
|||
case NodeType_SinWave: { SinWave((sin_wave_data*)Data, DeltaTime); } break;
|
||||
case NodeType_MultiplyPatterns: { MultiplyPatterns((multiply_patterns_data*)Data, DeltaTime); } break;
|
||||
case NodeType_OutputNode: { OutputNode((output_node_data*)Data, DeltaTime); } break;
|
||||
case NodeType_SwdColorProc: { SwdColorProc((swd_color_data*)Data, DeltaTime); } break;
|
||||
case NodeType_SolidColorProc: { SolidColorProc((solid_color_data*)Data, DeltaTime); } break;
|
||||
case NodeType_VerticalColorFadeProc: { VerticalColorFadeProc((vertical_color_fade_data*)Data, DeltaTime); } break;
|
||||
case NodeType_RevolvingDiscs: { RevolvingDiscs((revolving_discs_data*)Data, DeltaTime); } break;
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
// This file left empty for SwD Kraftwerks
|
||||
|
||||
|
||||
NODE_STRUCT(swd_color_data)
|
||||
{
|
||||
NODE_IN(v4, Color);
|
||||
NODE_IN(v4, ColorB);
|
||||
NODE_COLOR_BUFFER_INOUT;
|
||||
};
|
||||
|
||||
NODE_PROC(SwdColorProc, swd_color_data)
|
||||
{
|
||||
u8 R = (u8)GSClamp(0.f, (Data->Color.r * 255), 255.f);
|
||||
u8 G = (u8)GSClamp(0.f, (Data->Color.g * 255), 255.f);
|
||||
u8 B = (u8)GSClamp(0.f, (Data->Color.b * 255), 255.f);
|
||||
|
||||
led* LED = Data->LEDs;
|
||||
for (s32 l = 0; l < Data->LEDCount; l++)
|
||||
{
|
||||
Assert(LED->Index >= 0 && LED->Index < Data->LEDCount);
|
||||
|
||||
Data->Colors[LED->Index].R = R;
|
||||
Data->Colors[LED->Index].G = R;
|
||||
Data->Colors[LED->Index].B = R;
|
||||
LED++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
#define NETWORKINTID_INVALID -1
|
||||
|
||||
#define DEFAULT_STREAMING_ACN_PORT 5568
|
||||
|
||||
#define IP_ADDRESS_BYTES 16
|
||||
#define STARTCODE_DMX 0
|
||||
|
||||
/*
|
||||
* a description of the address space being used
|
||||
*/
|
||||
#define PREAMBLE_SIZE_ADDR 0
|
||||
#define POSTAMBLE_SIZE_ADDR 2
|
||||
#define ACN_IDENTIFIER_ADDR 4
|
||||
#define ROOT_FLAGS_AND_LENGTH_ADDR 16
|
||||
#define ROOT_VECTOR_ADDR 18
|
||||
#define CID_ADDR 22
|
||||
#define FRAMING_FLAGS_AND_LENGTH_ADDR 38
|
||||
#define FRAMING_VECTOR_ADDR 40
|
||||
#define SOURCE_NAME_ADDR 44
|
||||
#define PRIORITY_ADDR 108
|
||||
#define RESERVED_ADDR 109
|
||||
#define SEQ_NUM_ADDR 111
|
||||
#define OPTIONS_ADDR 112
|
||||
#define UNIVERSE_ADDR 113
|
||||
#define DMP_FLAGS_AND_LENGTH_ADDR 115
|
||||
#define DMP_VECTOR_ADDR 117
|
||||
#define DMP_ADDRESS_AND_DATA_ADDR 118
|
||||
#define FIRST_PROPERTY_ADDRESS_ADDR 119
|
||||
#define ADDRESS_INC_ADDR 121
|
||||
#define PROP_COUNT_ADDR 123
|
||||
#define START_CODE_ADDR 125
|
||||
#define PROP_VALUES_ADDR (START_CODE_ADDR + 1)
|
||||
|
||||
/*
|
||||
* common sizes
|
||||
*/
|
||||
#define STREAM_HEADER_SIZE 126
|
||||
#define STREAM_BODY_SIZE 512
|
||||
|
||||
#define SOURCE_NAME_SIZE 64
|
||||
#define RLP_PREAMBLE_SIZE 16
|
||||
#define RLP_POSTAMBLE_SIZE 0
|
||||
#define ACN_IDENTIFIER_SIZE 12
|
||||
|
||||
/*
|
||||
* data definitions
|
||||
*/
|
||||
#define ACN_IDENTIFIER "ASC-E1.17\0\0\0"
|
||||
#define ROOT_VECTOR 4
|
||||
#define FRAMING_VECTOR 2
|
||||
#define DMP_VECTOR 2
|
||||
#define ADDRESS_AND_DATA_FORMAT 0xa1
|
||||
#define ADDRESS_INC 1
|
||||
#define DMP_FIRST_PROPERTY_ADDRESS_FORCE 0
|
||||
#define RESERVED_VALUE 0
|
||||
|
||||
//for support of the early draft
|
||||
#define DRAFT_STREAM_HEADER_SIZE 90
|
||||
#define DRAFT_SOURCE_NAME_SIZE 32
|
||||
|
||||
//for support of the early draft
|
||||
#define DRAFT_ROOT_VECTOR 3
|
||||
|
||||
const u32 VHD_MAXFLAGBYTES = 7; //The maximum amount of bytes used to pack the flags, len, and vector
|
||||
const u32 VHD_MAXLEN = 0x0fffff; //The maximum packet length is 20 bytes long
|
||||
const u32 VHD_MAXMINLENGTH = 4095; //The highest length that will fit in the "smallest" length pack
|
||||
|
||||
//Defines for the VHD flags
|
||||
const u8 VHD_L_FLAG = 0x80;
|
||||
const u8 VHD_V_FLAG = 0x40;
|
||||
const u8 VHD_H_FLAG = 0x20;
|
||||
const u8 VHD_D_FLAG = 0x10;
|
||||
|
||||
#define CID_Bytes 16
|
||||
struct cid
|
||||
{
|
||||
u8 Bytes[CID_Bytes];
|
||||
};
|
||||
|
||||
struct streaming_acn
|
||||
{
|
||||
platform_socket_handle SendSocket;
|
||||
cid CID;
|
||||
s32 SequenceIterator;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//
|
||||
// SACN Data Header Functions
|
||||
//
|
||||
///////////////////////////////////////////////
|
||||
|
||||
internal void
|
||||
SetStreamHeaderSequence_ (u8* Buffer, u8 Sequence, b32 Draft)
|
||||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
PackB1(Buffer + SEQ_NUM_ADDR, Sequence);
|
||||
}
|
||||
|
||||
internal void
|
||||
VHD_PackFlags_(u8* Buffer, b32 InheritVec, b32 InheritHead, b32 InheritData)
|
||||
{
|
||||
u8* Cursor = Buffer;
|
||||
u8 NewByte = UpackB1(Cursor) & 0x8f;
|
||||
|
||||
if (!InheritVec) { NewByte |= VHD_V_FLAG; }
|
||||
if (!InheritHead) { NewByte |= VHD_H_FLAG; }
|
||||
if (!InheritData) { NewByte |= VHD_D_FLAG; }
|
||||
|
||||
PackB1(Cursor, NewByte);
|
||||
}
|
||||
|
||||
internal u8*
|
||||
VHD_PackLength_(u8* Buffer, u32 Length, b32 IncludeLength)
|
||||
{
|
||||
u8* Cursor = Buffer;
|
||||
u32 AdjustedLength = Length;
|
||||
if (IncludeLength)
|
||||
{
|
||||
if (Length + 1 > VHD_MAXMINLENGTH)
|
||||
{
|
||||
AdjustedLength += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
AdjustedLength += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Mask out the length bits to keep flags intact
|
||||
u8 NewByte = UpackB1(Cursor) & 0x70;
|
||||
if (AdjustedLength > VHD_MAXMINLENGTH)
|
||||
{
|
||||
NewByte |= VHD_L_FLAG;
|
||||
}
|
||||
|
||||
u8 PackBuffer[4];
|
||||
PackB4(PackBuffer, AdjustedLength);
|
||||
if (AdjustedLength <= VHD_MAXMINLENGTH)
|
||||
{
|
||||
NewByte |= (PackBuffer[2] & 0x0f);
|
||||
Cursor = PackB1(Cursor, NewByte);
|
||||
Cursor = PackB1(Cursor, PackBuffer[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
NewByte |= (PackBuffer[1] & 0x0f);
|
||||
Cursor = PackB1(Cursor, PackBuffer[2]);
|
||||
Cursor = PackB1(Cursor, PackBuffer[3]);
|
||||
}
|
||||
|
||||
return Cursor;
|
||||
}
|
||||
|
||||
internal cid
|
||||
StringToCID_ (const char* String)
|
||||
{
|
||||
cid Result = {};
|
||||
|
||||
const char* Src = String;
|
||||
u8* Dest = &Result.Bytes[0];
|
||||
b32 FirstNibble = true;
|
||||
|
||||
while(*Src && (Dest - &Result.Bytes[0] < CID_Bytes))
|
||||
{
|
||||
u8 Offset = 0;
|
||||
if ((*Src >= 0x30) && (*Src <= 0x39)){ Offset = 0x30; }
|
||||
else if ((*Src >= 0x41) && (*Src <= 0x46)) { Offset = 0x37; }
|
||||
else if ((*Src >= 0x61) && (*Src <= 0x66)) { Offset = 0x66; }
|
||||
|
||||
if (Offset != 0)
|
||||
{
|
||||
if (FirstNibble)
|
||||
{
|
||||
*Dest = (u8)(*Src - Offset);
|
||||
*Dest <<= 4;
|
||||
FirstNibble = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*Dest |= (*Src - Offset);
|
||||
Dest++;
|
||||
FirstNibble = true;
|
||||
}
|
||||
}
|
||||
Src++;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal void
|
||||
InitStreamHeader (u8* Buffer, s32 BufferSize,
|
||||
u16 SlotCount,
|
||||
u8 StartCode,
|
||||
u16 Universe,
|
||||
u8 Priority,
|
||||
u16 Reserved,
|
||||
u8 Options,
|
||||
const char* SourceName,
|
||||
cid CID
|
||||
)
|
||||
{
|
||||
|
||||
u8* Cursor = Buffer;
|
||||
|
||||
// Preamble Size
|
||||
Cursor = PackB2(Cursor, RLP_PREAMBLE_SIZE);
|
||||
Cursor = PackB2(Cursor, RLP_POSTAMBLE_SIZE);
|
||||
|
||||
memcpy(Cursor, ACN_IDENTIFIER, ACN_IDENTIFIER_SIZE);
|
||||
Cursor += ACN_IDENTIFIER_SIZE;
|
||||
|
||||
// TODO(Peter): If you never use this anywhere else, go back and remove the parameters
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - RLP_PREAMBLE_SIZE + SlotCount,
|
||||
false);
|
||||
|
||||
// root vector
|
||||
Cursor = PackB4(Cursor, ROOT_VECTOR);
|
||||
|
||||
// CID Pack
|
||||
for (s32 i = 0; i < CID_Bytes; i++)
|
||||
{
|
||||
*Cursor++ = CID.Bytes[i];
|
||||
}
|
||||
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - FRAMING_FLAGS_AND_LENGTH_ADDR + SlotCount,
|
||||
false);
|
||||
|
||||
// framing vector
|
||||
Cursor = PackB4(Cursor, FRAMING_VECTOR);
|
||||
|
||||
// framing source name
|
||||
strncpy((char*)Cursor, SourceName, SOURCE_NAME_SIZE);
|
||||
Cursor[SOURCE_NAME_SIZE - 1] = '\0';
|
||||
Cursor += SOURCE_NAME_SIZE;
|
||||
|
||||
// priority
|
||||
Cursor = PackB1(Cursor, Priority);
|
||||
|
||||
// reserved
|
||||
Cursor = PackB2(Cursor, Reserved);
|
||||
|
||||
// Sequence # is always set to 0/NONE at the beginning, but it is incremented when sending data
|
||||
Cursor = PackB1(Cursor, 0);
|
||||
|
||||
// Options
|
||||
Cursor = PackB1(Cursor, Options);
|
||||
|
||||
// Universe
|
||||
Cursor = PackB2(Cursor, Universe);
|
||||
|
||||
VHD_PackFlags_(Cursor, false, false, false);
|
||||
Cursor = VHD_PackLength_(Cursor,
|
||||
STREAM_HEADER_SIZE - DMP_FLAGS_AND_LENGTH_ADDR + SlotCount,
|
||||
false);
|
||||
|
||||
// DMP Vector
|
||||
Cursor = PackB1(Cursor, DMP_VECTOR);
|
||||
|
||||
// DMP Address and data type
|
||||
Cursor = PackB1(Cursor, ADDRESS_AND_DATA_FORMAT);
|
||||
|
||||
// DMP first property address
|
||||
Cursor = PackB2(Cursor, 0);
|
||||
|
||||
// DMP Address Increment
|
||||
Cursor = PackB2(Cursor, ADDRESS_INC);
|
||||
|
||||
// Property Value Count -- Includes one byte for start code
|
||||
Cursor = PackB2(Cursor, SlotCount + 1);
|
||||
|
||||
Cursor = PackB1(Cursor, StartCode);
|
||||
|
||||
Assert(Cursor - Buffer == STREAM_HEADER_SIZE);
|
||||
}
|
||||
|
||||
//
|
||||
// New SACN
|
||||
//
|
||||
|
||||
internal streaming_acn
|
||||
InitializeSACN ( context Context)
|
||||
{
|
||||
streaming_acn SACN = {};
|
||||
|
||||
SACN.SendSocket = Context.PlatformGetSocketHandle(AF_INET, SOCK_DGRAM, 0);
|
||||
int Multicast_TimeToLive = 20;
|
||||
int Error = Context.PlatformSetSocketOption(SACN.SendSocket, IPPROTO_IP, IP_MULTICAST_TTL,
|
||||
(const char*)(&Multicast_TimeToLive), sizeof(Multicast_TimeToLive));
|
||||
SACN.CID = StringToCID_ ("{67F9D986-544E-4abb-8986-D5F79382586C}");
|
||||
|
||||
return SACN;
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNCleanup(streaming_acn* SACN, context Context)
|
||||
{
|
||||
Context.PlatformCloseSocket(SACN->SendSocket);
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNUpdateSequence (streaming_acn* SACN)
|
||||
{
|
||||
// Never use 0 after the first one
|
||||
if (++SACN->SequenceIterator == 0)
|
||||
{
|
||||
++SACN->SequenceIterator;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
SACNPrepareBufferHeader (s32 Universe, u8* Buffer, s32 BufferSize, s32 SizeReservedForHeader, streaming_acn SACN)
|
||||
{
|
||||
Assert(SizeReservedForHeader == STREAM_HEADER_SIZE);
|
||||
Assert(Buffer && BufferSize > 0);
|
||||
|
||||
s32 Priority = 0;
|
||||
InitStreamHeader(Buffer, BufferSize, STREAM_BODY_SIZE, STARTCODE_DMX, Universe, Priority, 0, 0, "Lumenarium", SACN.CID);
|
||||
SetStreamHeaderSequence_(Buffer, SACN.SequenceIterator, false);
|
||||
}
|
||||
|
||||
internal u_long
|
||||
SACNGetUniverseSendAddress(s32 Universe)
|
||||
{
|
||||
u8 MulticastAddressBuffer[4] = {};
|
||||
MulticastAddressBuffer[0] = 239;
|
||||
MulticastAddressBuffer[1] = 255;
|
||||
MulticastAddressBuffer[2] = (u8)(Universe & 0xff00); // high bit
|
||||
MulticastAddressBuffer[3] = (u8)((Universe & 0x00ff) >> 8); // low bit
|
||||
|
||||
u_long V4Address = (u_long)UpackB4(MulticastAddressBuffer);
|
||||
return V4Address;
|
||||
}
|
|
@ -71,7 +71,11 @@ NODE_PROC(RevolvingDiscs, revolving_discs_data)
|
|||
{
|
||||
DEBUG_TRACK_FUNCTION;
|
||||
|
||||
sacn_pixel Color = PackFloatsToSACNPixel(Data->Color.r, Data->Color.g, Data->Color.b);
|
||||
pixel Color = {
|
||||
(u8)(GSClamp01(Data->Color.r) * 255),
|
||||
(u8)(GSClamp01(Data->Color.g) * 255),
|
||||
(u8)(GSClamp01(Data->Color.b) * 255),
|
||||
};
|
||||
|
||||
v4 Center = v4{0, 0, 0, 1};
|
||||
v4 Normal = v4{GSCos(Data->ThetaZ), 0, GSSin(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
#include <windows.h>
|
||||
#include "gs_platform.h"
|
||||
#include "gs_win32.h"
|
||||
|
||||
int main (int ArgCount, char** Args)
|
||||
{
|
||||
window MainWindow = PlatformCreateWindow("Test Window", 1024, 768);
|
||||
|
||||
win32_opengl_window_info OpenGLInfo = {};
|
||||
OpenGLInfo.ColorBits = 32;
|
||||
OpenGLInfo.AlphaBits = 8;
|
||||
Win32CreateOpenGLContext(OpenGLInfo, MainWindow);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -608,6 +608,7 @@ INT NCmdShow
|
|||
Context.PlatformGetSocketHandle = Win32GetSocketHandle;
|
||||
Context.PlatformGetSendAddress = Win32GetSendAddress;
|
||||
Context.PlatformSetSocketOption = Win32SetSocketOption;
|
||||
Context.PlatformSendTo = Win32SendTo;
|
||||
Context.PlatformCloseSocket = Win32CloseSocket;
|
||||
Context.PlatformGetFontInfo = Win32GetFontInfo;
|
||||
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;
|
||||
|
|
7
todo.txt
7
todo.txt
|
@ -1,7 +1,12 @@
|
|||
TODO FOLDHAUS
|
||||
|
||||
YOU WERE IN THE MIDDLE OF
|
||||
Simplifying memory layout of sacn
|
||||
|
||||
|
||||
Assembly -> SACN interface
|
||||
- you need to rebuild the map from leds -> universes
|
||||
- - thinking about storing a sparse array of { led_start_index, led_count, led_universe, led_channel }
|
||||
- that we can iterate over to populate dmx buffers
|
||||
|
||||
BUGS
|
||||
- Typing a period into a float value doesn't register. Problem here is that we arent' translating key presses into characters at the win32 layer. Need to do that.
|
||||
|
|
Loading…
Reference in New Issue