Decoupled assembly from sacn.

This commit is contained in:
Peter Slattery 2019-11-22 16:07:25 -08:00
parent 726785eec4
commit 70c9c74796
21 changed files with 712 additions and 1028 deletions

1
src/artnet/artnet.h Normal file
View File

@ -0,0 +1 @@
/* For future artnet implementation */

View File

@ -102,33 +102,30 @@ ParseAssemblyFileHeader (assembly_definition* Assembly, tokenizer* Tokenizer)
} }
internal void internal led_strip_definition
ParseLEDStrip (assembly_definition* Assembly, tokenizer* Tokenizer) ParseLEDStrip (tokenizer* Tokenizer)
{ {
led_strip_definition* LEDStripDef = Assembly->LEDStrips + Assembly->LEDStripCount; led_strip_definition Result = {};
Assert(Assembly->LEDStripCount < Assembly->LEDStripSize);
Assembly->LEDStripCount++;
// Control Box Index // Control Box Index
while (*Tokenizer->At && !IsNumericExtended(*Tokenizer->At)) { Tokenizer->At++; } while (*Tokenizer->At && !IsNumericExtended(*Tokenizer->At)) { Tokenizer->At++; }
assembly_token BoxIDToken = ParseToken(Tokenizer); assembly_token BoxIDToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number); Assert(BoxIDToken.Type == AssemblyToken_Number);
LEDStripDef->ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue; Result.ControlBoxID = ParseSignedIntUnsafe(BoxIDToken.Token).SignedIntValue;
// Start Universe // Start Universe
EatPastCharacter(Tokenizer, ','); EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
assembly_token StartUniverseToken = ParseToken(Tokenizer); assembly_token StartUniverseToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number); Assert(BoxIDToken.Type == AssemblyToken_Number);
LEDStripDef->StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue; Result.StartUniverse = ParseSignedIntUnsafe(StartUniverseToken.Token).SignedIntValue;
// Start Channel // Start Channel
EatPastCharacter(Tokenizer, ','); EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
assembly_token StartChannelToken = ParseToken(Tokenizer); assembly_token StartChannelToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number); Assert(BoxIDToken.Type == AssemblyToken_Number);
LEDStripDef->StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue; Result.StartChannel = ParseSignedIntUnsafe(StartChannelToken.Token).SignedIntValue;
// Strip Type // Strip Type
// TODO(Peter): This is unused for now, and would be a branch point for parsing // 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); EatWhitespace(Tokenizer);
if (CharArraysEqualUpToLength(Tokenizer->At, INTERPOLATE_POINTS_IDENTIFIER, CharArrayLength(INTERPOLATE_POINTS_IDENTIFIER))) if (CharArraysEqualUpToLength(Tokenizer->At, INTERPOLATE_POINTS_IDENTIFIER, CharArrayLength(INTERPOLATE_POINTS_IDENTIFIER)))
{ {
LEDStripDef->InterpolationType = StripInterpolate_Points; Result.InterpolationType = StripInterpolate_Points;
// Start Position // Start Position
EatPastCharacter(Tokenizer, ','); EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
assembly_token StartPositionToken = ParseToken(Tokenizer); assembly_token StartPositionToken = ParseToken(Tokenizer);
Assert(StartPositionToken.Type == AssemblyToken_Vector); Assert(StartPositionToken.Type == AssemblyToken_Vector);
LEDStripDef->InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token); Result.InterpolatePositionStart = ParseAssemblyVector(StartPositionToken.Token);
// End Position // End Position
EatPastCharacter(Tokenizer, ','); EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
assembly_token EndPositionToken = ParseToken(Tokenizer); assembly_token EndPositionToken = ParseToken(Tokenizer);
Assert(EndPositionToken.Type == AssemblyToken_Vector); Assert(EndPositionToken.Type == AssemblyToken_Vector);
LEDStripDef->InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token); Result.InterpolatePositionEnd = ParseAssemblyVector(EndPositionToken.Token);
// LEDs Per Strip // LEDs Per Strip
EatPastCharacter(Tokenizer, ','); EatPastCharacter(Tokenizer, ',');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
assembly_token LEDsPerStripToken = ParseToken(Tokenizer); assembly_token LEDsPerStripToken = ParseToken(Tokenizer);
Assert(BoxIDToken.Type == AssemblyToken_Number); Assert(BoxIDToken.Type == AssemblyToken_Number);
LEDStripDef->LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue; Result.LEDsPerStrip = ParseSignedIntUnsafe(LEDsPerStripToken.Token).SignedIntValue;
} }
EatPastCharacter(Tokenizer, '}'); EatPastCharacter(Tokenizer, '}');
EatWhitespace(Tokenizer); EatWhitespace(Tokenizer);
return Result;
} }
internal void internal void
@ -181,7 +180,13 @@ ParseAssemblyFileBody (assembly_definition* Assembly, tokenizer* Tokenizer)
{ {
case AssemblyToken_LEDStrip: 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; } break;
// TODO(Peter): Other cases? What else would need to be in the assembly body? // TODO(Peter): Other cases? What else would need to be in the assembly body?

View File

@ -56,5 +56,6 @@ struct assembly_definition
{ {
s32 LEDStripSize; s32 LEDStripSize;
s32 LEDStripCount; s32 LEDStripCount;
s32 TotalLEDCount;
led_strip_definition* LEDStrips; led_strip_definition* LEDStrips;
}; };

47
src/dmx/dmx.h Normal file
View File

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

View File

@ -22,186 +22,10 @@ MouseToWorldRay(r32 MouseX, r32 MouseY, camera* Camera, r32 WindowWidth, r32 Win
return WorldPosition; 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 struct draw_leds_job_data
{ {
led* LEDs; led* LEDs;
sacn_pixel* Colors; pixel* Colors;
s32 StartIndex; s32 StartIndex;
s32 OnePastLastIndex; s32 OnePastLastIndex;
@ -241,8 +65,8 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
LEDIdx < LEDCount; LEDIdx < LEDCount;
LEDIdx++) LEDIdx++)
{ {
sacn_pixel SACNColor = Data->Colors[LED->Index]; pixel PixelColor = Data->Colors[LED->Index];
v4 Color = v4{SACNColor.R / 255.f, SACNColor.G / 255.f, SACNColor.B / 255.f, 1.0f}; v4 Color = v4{PixelColor.R / 255.f, PixelColor.G / 255.f, PixelColor.B / 255.f, 1.0f};
v4 V4Position = LED->Position; v4 V4Position = LED->Position;
V4Position.w = 0; V4Position.w = 0;
@ -262,25 +86,37 @@ DrawLEDsInBufferRangeJob (s32 ThreadID, void* JobData)
struct send_sacn_job_data struct send_sacn_job_data
{ {
streaming_acn SACN;
sacn_universe_buffer UniverseList; platform_socket_handle SendSocket;
s32 StartUniverse; platform_get_send_address* GetSendAddress;
s32 OnePastLastUniverse; platform_send_to* SendTo;
platform_send_to* PlatformSendTo; dmx_buffer_list* DMXBuffers;
}; };
internal void internal void
SendSACNBufferData (s32 ThreadID, void* JobData) SACNSendDMXBufferListJob (s32 ThreadID, void* JobData)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
send_sacn_job_data* Data = (send_sacn_job_data*)JobData; 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; dmx_buffer_list* DMXBufferAt = Data->DMXBuffers;
for (s32 UniverseIdx = Data->StartUniverse; UniverseIdx < Data->OnePastLastUniverse; UniverseIdx++) while (DMXBufferAt)
{ {
SACNSendDataToUniverse(&Data->SACN, SendUniverse, Data->PlatformSendTo); dmx_buffer Buffer = DMXBufferAt->Buffer;
SendUniverse++;
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); string FileName = Substring(PathString, IndexOfLastSlash + 1);
r32 Scale = 100; 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); ClearArenaToSnapshot(State->Transient, TempMemorySnapshot);
} }
@ -321,21 +164,19 @@ internal void
UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context) UnloadAssembly (s32 AssemblyIndex, app_state* State, context Context)
{ {
assembly Assembly = State->AssemblyList[AssemblyIndex]; 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 LEDsInAssembly = Assembly.LEDBuffer->Count;
s32 MemoryRequiredForAssembly = CalculateMemorySizeForAssembly(LEDsInAssembly, Assembly.Name.Length); s32 MemoryRequiredForAssembly = CalculateMemorySizeForAssembly(LEDsInAssembly, Assembly.Name.Length);
Context.PlatformFree((u8*)Assembly.LEDBuffer, MemoryRequiredForAssembly); Context.PlatformFree((u8*)Assembly.LEDBuffer, MemoryRequiredForAssembly);
State->TotalLEDsCount -= LEDsInAssembly; 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.TextColor = WhiteV4;
State->Interface.Margin = v2{5, 5}; 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.FieldOfView = DegreesToRadians(45.0f);
State->Camera.AspectRatio = (r32)Context.WindowWidth / (r32)Context.WindowHeight; 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); 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) UPDATE_AND_RENDER(UpdateAndRender)
{ {
DEBUG_TRACK_FUNCTION; DEBUG_TRACK_FUNCTION;
@ -539,71 +425,57 @@ UPDATE_AND_RENDER(UpdateAndRender)
HandleInput(State, InputQueue, Mouse); 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, UpdateOutputNodeCalculations(State->OutputNode, State->NodeList,
State->Permanent, State->Transient, State->Permanent, State->Transient,
State->LEDBufferList->LEDs, Assembly.LEDs,
State->LEDBufferList->Colors, Assembly.Colors,
State->LEDBufferList->Count, Assembly.LEDCount,
Context.DeltaTime); Context.DeltaTime);
ResetNodesUpdateState(State->NodeList); ResetNodesUpdateState(State->NodeList);
} }
ClearTransientNodeColorBuffers(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) 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);
} }
switch (State->NetworkProtocol)
{
case NetworkProtocol_SACN:
{
SACNUpdateSequence(&State->SACN);
sacn_universe_buffer* UniverseList = State->SACN.UniverseBuffer; dmx_buffer_list* CurrentDMXBuffer = DMXBuffers;
while (UniverseList) while (CurrentDMXBuffer)
{ {
s32 JobCount = 2; dmx_buffer Buffer = CurrentDMXBuffer->Buffer;
s32 UniversesPerJob = UniverseList->Used / JobCount; SACNPrepareBufferHeader(Buffer.Universe, Buffer.Base, Buffer.TotalSize, Buffer.HeaderSize, State->SACN);
send_sacn_job_data* SACNData = PushArray(State->Transient, send_sacn_job_data, JobCount); CurrentDMXBuffer = CurrentDMXBuffer->Next;
for (s32 i = 0; i < JobCount; i++)
{
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)
{
SACNData[i].OnePastLastUniverse = UniverseList->Used;
} }
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->PushWorkOnQueue(
Context.GeneralWorkQueue, Context.GeneralWorkQueue,
SendSACNBufferData, SACNSendDMXBufferListJob,
SACNData + i); Job);
} }break;
UniverseList = UniverseList->Next;
InvalidDefaultCase;
} }
} }
@ -637,16 +509,18 @@ UPDATE_AND_RENDER(UpdateAndRender)
render_quad_batch_constructor BatchConstructor = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount); render_quad_batch_constructor BatchConstructor = PushRenderQuad3DBatch(RenderBuffer, State->TotalLEDsCount);
led_buffer* LEDBuffer = State->LEDBufferList; s32 CurrentAssemblyIndex = 0;
s32 LEDBufferLEDsAssignedToJobs = 0; s32 LEDBufferLEDsAssignedToJobs = 0;
for (s32 Job = 0; Job < JobsNeeded; Job++) for (s32 Job = 0; Job < JobsNeeded; Job++)
{ {
assembly CurrentAssembly = State->AssemblyList[CurrentAssemblyIndex];
draw_leds_job_data* JobData = JobDataBank + JobDataBankUsed++; draw_leds_job_data* JobData = JobDataBank + JobDataBankUsed++;
JobData->LEDs = LEDBuffer->LEDs; JobData->LEDs = CurrentAssembly.LEDs;
JobData->Colors = LEDBuffer->Colors; JobData->Colors = CurrentAssembly.Colors;
JobData->StartIndex = LEDBufferLEDsAssignedToJobs; JobData->StartIndex = LEDBufferLEDsAssignedToJobs;
JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LEDBufferSize, LEDBuffer->Count); JobData->OnePastLastIndex = GSMin(JobData->StartIndex + LEDBufferSize, CurrentAssembly.LEDCount);
LEDBufferLEDsAssignedToJobs += JobData->OnePastLastIndex - JobData->StartIndex; LEDBufferLEDsAssignedToJobs += JobData->OnePastLastIndex - JobData->StartIndex;
@ -662,11 +536,18 @@ UPDATE_AND_RENDER(UpdateAndRender)
DrawLEDsInBufferRangeJob, DrawLEDsInBufferRangeJob,
JobData); JobData);
Assert(LEDBufferLEDsAssignedToJobs <= LEDBuffer->Count); // We should never go OVER the number of leds in the buffer // NOTE: We should never go OVER the number of leds in the buffer
if (LEDBufferLEDsAssignedToJobs == LEDBuffer->Count) Assert(LEDBufferLEDsAssignedToJobs <= CurrentAssembly.LEDCount);
if (LEDBufferLEDsAssignedToJobs == CurrentAssembly.LEDCount)
{ {
LEDBuffer = LEDBuffer->Next; if (CurrentAssemblyIndex >= State->AssembliesCount)
LEDBufferLEDsAssignedToJobs = 0; {
break;
}
else
{
CurrentAssemblyIndex++;
}
} }
} }
@ -700,7 +581,7 @@ UPDATE_AND_RENDER(UpdateAndRender)
State->Interface, Mouse); State->Interface, Mouse);
string InterfaceString = MakeString(PushArray(State->Transient, char, 256), 256); 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); PrintF(&InterfaceString, "Unload %.*s", State->AssemblyList[i].Name.Length, State->AssemblyList[i].Name.Memory);

View File

@ -4,44 +4,15 @@
#include "interface.h" #include "interface.h"
#include "foldhaus_network_ordering.h" #include "foldhaus_network_ordering.h"
#include "foldhaus_sacn.h" #include "dmx/dmx.h"
#include "sacn/sacn.h"
struct led #include "foldhaus_assembly.h"
{
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 "assembly_parser.h" #include "assembly_parser.h"
#include "foldhaus_node.h" #include "foldhaus_node.h"
#include "assembly_parser.cpp" #include "assembly_parser.cpp"
#include "test_patterns.h" #include "test_patterns.h"
#include "kraftwerks_patterns.h"
#include "foldhaus_interface.h" #include "foldhaus_interface.h"
typedef struct app_state app_state; typedef struct app_state app_state;
@ -56,15 +27,33 @@ typedef struct app_state app_state;
#include "generated/foldhaus_nodes_generated.cpp" #include "generated/foldhaus_nodes_generated.cpp"
#include "foldhaus_search_lister.h" #include "foldhaus_search_lister.h"
enum network_protocol
{
NetworkProtocol_SACN,
NetworkProtocol_ArtNet,
NetworkProtocol_Count,
};
struct app_state struct app_state
{ {
memory_arena* Permanent; memory_arena* Permanent;
memory_arena* Transient; memory_arena* Transient;
memory_arena SACNMemory; memory_arena SACNMemory;
s32 NetworkProtocolHeaderSize;
network_protocol NetworkProtocol;
streaming_acn SACN; streaming_acn SACN;
s32 TotalLEDsCount; 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; camera Camera;
r32 PixelsToWorldScale; r32 PixelsToWorldScale;
@ -74,13 +63,6 @@ struct app_state
input_command_queue CommandQueue; input_command_queue CommandQueue;
text_entry ActiveTextEntry; 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_list* NodeList;
node_header* OutputNode; node_header* OutputNode;
@ -91,9 +73,10 @@ struct app_state
internal void OpenColorPicker(app_state* State, v4* Address); internal void OpenColorPicker(app_state* State, v4* Address);
#include "foldhaus_assembly.cpp"
#include "foldhaus_node.cpp" #include "foldhaus_node.cpp"
#include "foldhaus_debug_visuals.h" #include "foldhaus_debug_visuals.h"
#include "foldhaus_sacn_view.cpp" //#include "foldhaus_sacn_view.cpp"
#include "foldhaus_text_entry.cpp" #include "foldhaus_text_entry.cpp"
#include "foldhaus_search_lister.cpp" #include "foldhaus_search_lister.cpp"

51
src/foldhaus_assembly.cpp Normal file
View File

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

31
src/foldhaus_assembly.h Normal file
View File

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

View File

@ -13,6 +13,9 @@ struct universe_view_operation_state
OPERATION_RENDER_PROC(RenderUniverseView) OPERATION_RENDER_PROC(RenderUniverseView)
{ {
InvalidCodePath;
#if 0
DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay); DEBUG_TRACK_SCOPE(DrawUniverseOutputDisplay);
universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory; universe_view_operation_state* OpState = (universe_view_operation_state*)Operation.OpStateMemory;
@ -49,9 +52,8 @@ OPERATION_RENDER_PROC(RenderUniverseView)
UniverseIdx++) UniverseIdx++)
{ {
sacn_universe* Universe = UniverseList->Universes + UniverseIdx; sacn_universe* Universe = UniverseList->Universes + UniverseIdx;
DrawSACNUniversePixels(RenderBuffer, Universe, UniverseDisplayTopLeft, UniverseDisplayDimension);
DrawSACNUniversePixels(RenderBuffer, Universe,
UniverseDisplayTopLeft, UniverseDisplayDimension);
if (OpState->Zoom > .5f) if (OpState->Zoom > .5f)
{ {
@ -72,9 +74,11 @@ OPERATION_RENDER_PROC(RenderUniverseView)
{ {
break; break;
} }
} }
UniverseList = UniverseList->Next; UniverseList = UniverseList->Next;
} }
#endif
} }
// TODO(Peter): Something isn't working with my laptop trackpad's zoom // TODO(Peter): Something isn't working with my laptop trackpad's zoom

View File

@ -31,26 +31,6 @@ GSMemCopy (u8* Source, u8* Destination, s32 Count)
#endif // GS_LANGUAGE_H #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 #if !defined Assert && defined DEBUG
#define Assert(expression) if(!(expression)){ *((int *)0) = 5; } #define Assert(expression) if(!(expression)){ *((int *)0) = 5; }
#define InvalidCodePath Assert(0) #define InvalidCodePath Assert(0)

View File

@ -1,31 +1,36 @@
//Packs a u8 to a known big endian buffer // Packs a u8 to a known big endian buffer
inline u8* PackB1(u8* ptr, u8 val) inline u8*
PackB1(u8* ptr, u8 val)
{ {
*ptr = val; *ptr = val;
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u8 from a known big endian buffer //Unpacks a u8 from a known big endian buffer
inline u8 UpackB1(const u8* ptr) inline u8
UpackB1(const u8* ptr)
{ {
return *ptr; return *ptr;
} }
//Packs a u8 to a known little endian buffer //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; *ptr = val;
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u8 from a known little endian buffer //Unpacks a u8 from a known little endian buffer
inline u8 UpackL1(const u8* ptr) inline u8
UpackL1(const u8* ptr)
{ {
return *ptr; return *ptr;
} }
//Packs a u16 to a known big endian buffer //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[1] = (u8)(val & 0xff);
ptr[0] = (u8)((val & 0xff00) >> 8); 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 //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); return (u16)(ptr[1] | ptr[0] << 8);
} }
//Packs a u16 to a known little endian buffer //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; *((u16*)ptr) = val;
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u16 from a known little endian buffer //Unpacks a u16 from a known little endian buffer
inline u16 UpackL2(const u8* ptr) inline u16
UpackL2(const u8* ptr)
{ {
return *((u16*)ptr); return *((u16*)ptr);
} }
//Packs a u32 to a known big endian buffer //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[3] = (u8) (val & 0xff);
ptr[2] = (u8)((val & 0xff00) >> 8); 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 //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)); return (u32)(ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24));
} }
//Packs a u32 to a known little endian buffer //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; *((u32*)ptr) = val;
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u32 from a known little endian buffer //Unpacks a u32 from a known little endian buffer
inline u32 UpackL4(const u8* ptr) inline u32
UpackL4(const u8* ptr)
{ {
return *((u32*)ptr); return *((u32*)ptr);
} }
//Packs a u64 to a known big endian buffer //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[7] = (u8) (val & 0xff);
ptr[6] = (u8)((val & 0xff00) >> 8); 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 //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) | return ((u64)ptr[7]) | (((u64)ptr[6]) << 8) | (((u64)ptr[5]) << 16) |
(((u64)ptr[4]) << 24) | (((u64)ptr[3]) << 32) | (((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 //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; *((u64*)ptr) = val;
return ptr + sizeof(val); return ptr + sizeof(val);
} }
//Unpacks a u64 from a known little endian buffer //Unpacks a u64 from a known little endian buffer
inline u64 UpackL8(const u8* ptr) inline u64
UpackL8(const u8* ptr)
{ {
return *((u64*)ptr); return *((u64*)ptr);
} }

View File

@ -821,12 +821,12 @@ UpdateDraggingNodeValue (v2 MousePos, v2 LastFrameMousePos, node_interaction Int
internal void UpdateNodeCalculation (node_header* Node, node_list* NodeList, internal void UpdateNodeCalculation (node_header* Node, node_list* NodeList,
memory_arena* Permanent, memory_arena* Transient, 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 internal void
UpdateNodesConnectedUpstream (node_header* Node, node_list* NodeList, UpdateNodesConnectedUpstream (node_header* Node, node_list* NodeList,
memory_arena* Permanent, memory_arena* Transient, 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++) for (s32 ConnectionIdx = 0; ConnectionIdx < Node->ConnectionsCount; ConnectionIdx++)
{ {
@ -877,7 +877,7 @@ UpdateNodesConnectedUpstream (node_header* Node, node_list* NodeList,
internal void internal void
UpdateNodeCalculation (node_header* Node, node_list* NodeList, UpdateNodeCalculation (node_header* Node, node_list* NodeList,
memory_arena* Permanent, memory_arena* Transient, 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; DEBUG_TRACK_FUNCTION;
Assert(Node->PersistentData != 0); Assert(Node->PersistentData != 0);
@ -894,7 +894,7 @@ UpdateNodeCalculation (node_header* Node, node_list* NodeList,
// eachother to update. // eachother to update.
Node->UpdatedThisFrame = true; Node->UpdatedThisFrame = true;
sacn_pixel* Colors = ColorsInit; pixel* Colors = ColorsInit;
UpdateNodesConnectedUpstream(Node, NodeList, Permanent, Transient, LEDs, Colors, LEDCount, DeltaTime); 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; node_led_color_connection* ColorConnection = Connection.LEDsValuePtr;
if (!ColorConnection->Colors) if (!ColorConnection->Colors)
{ {
sacn_pixel* ColorsCopy = PushArray(Transient, sacn_pixel, LEDCount); pixel* ColorsCopy = PushArray(Transient, pixel, LEDCount);
GSMemSet((u8*)ColorsCopy, 0, sizeof(sacn_pixel) * LEDCount); GSMemSet((u8*)ColorsCopy, 0, sizeof(pixel) * LEDCount);
ColorConnection->Colors = ColorsCopy; ColorConnection->Colors = ColorsCopy;
ColorConnection->LEDs = LEDs; ColorConnection->LEDs = LEDs;
@ -932,7 +932,7 @@ UpdateNodeCalculation (node_header* Node, node_list* NodeList,
internal void internal void
UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList, UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
memory_arena* Permanent, memory_arena* Transient, 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); Assert(OutputNode->Type == NodeType_OutputNode);
@ -941,8 +941,8 @@ UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
node_connection ColorsConnection = OutputNode->Connections[0]; node_connection ColorsConnection = OutputNode->Connections[0];
if (ColorsConnection.LEDsValuePtr->Colors) if (ColorsConnection.LEDsValuePtr->Colors)
{ {
sacn_pixel* DestPixel = Colors; pixel* DestPixel = Colors;
sacn_pixel* SourcePixel = ColorsConnection.LEDsValuePtr->Colors; pixel* SourcePixel = ColorsConnection.LEDsValuePtr->Colors;
for (s32 i = 0; i < LEDCount; i++) for (s32 i = 0; i < LEDCount; i++)
{ {
*DestPixel++ = *SourcePixel++; *DestPixel++ = *SourcePixel++;
@ -953,7 +953,7 @@ UpdateOutputNodeCalculations (node_header* OutputNode, node_list* NodeList,
#if 0 #if 0
// Trying to put updating nodes in terms of connections, rather than nodes. // Trying to put updating nodes in terms of connections, rather than nodes.
internal void 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; s32 NodesUpdated = 0;
@ -998,7 +998,7 @@ UpdateAllNodesFloodFill (node_list* NodeList, memory_arena* Permanent, memory_ar
#endif #endif
internal void 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); node_list_iterator NodeIter = GetNodeListIterator(*NodeList);
while (NodeIteratorIsValid(NodeIter)) while (NodeIteratorIsValid(NodeIter))

View File

@ -7,12 +7,12 @@ typedef enum node_type node_type;
#define NODE_COLOR_BUFFER \ #define NODE_COLOR_BUFFER \
led* LEDs; \ led* LEDs; \
sacn_pixel* Colors; \ pixel* Colors; \
s32 LEDCount; s32 LEDCount;
#define NAMED_NODE_COLOR_BUFFER(name) \ #define NAMED_NODE_COLOR_BUFFER(name) \
led* name##LEDs; \ led* name##LEDs; \
sacn_pixel* name##Colors; \ pixel* name##Colors; \
s32 name##LEDCount; s32 name##LEDCount;
#define NODE_COLOR_BUFFER_INOUT NODE_COLOR_BUFFER #define NODE_COLOR_BUFFER_INOUT NODE_COLOR_BUFFER

View File

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

View File

@ -7,7 +7,6 @@ NodeType_AddNodeProc,
NodeType_SinWave, NodeType_SinWave,
NodeType_MultiplyPatterns, NodeType_MultiplyPatterns,
NodeType_OutputNode, NodeType_OutputNode,
NodeType_SwdColorProc,
NodeType_SolidColorProc, NodeType_SolidColorProc,
NodeType_VerticalColorFadeProc, NodeType_VerticalColorFadeProc,
NodeType_RevolvingDiscs, 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 }, { 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[] = { node_struct_member MemberList_solid_color_data[] = {
{ MemberType_v4, "Color", (u64)&((solid_color_data*)0)->Color, IsInputMember }, { MemberType_v4, "Color", (u64)&((solid_color_data*)0)->Color, IsInputMember },
{ MemberType_NODE_COLOR_BUFFER, "ResultLEDs", (u64)&((solid_color_data*)0)->ResultLEDs, IsOutputMember}, { 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_SinWave, "SinWave", 7, MemberList_sin_wave_data, 20, 4, false},
{ NodeType_MultiplyPatterns, "MultiplyPatterns", 16, MemberList_multiply_patterns_data, 60, 3, false}, { NodeType_MultiplyPatterns, "MultiplyPatterns", 16, MemberList_multiply_patterns_data, 60, 3, false},
{ NodeType_OutputNode, "OutputNode", 10, MemberList_output_node_data, 20, 1, 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_SolidColorProc, "SolidColorProc", 14, MemberList_solid_color_data, 36, 2, false},
{ NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 44, 4, false}, { NodeType_VerticalColorFadeProc, "VerticalColorFadeProc", 21, MemberList_vertical_color_fade_data, 44, 4, false},
{ NodeType_RevolvingDiscs, "RevolvingDiscs", 14, MemberList_revolving_discs_data, 60, 8, 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) 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_SinWave: { SinWave((sin_wave_data*)Data, DeltaTime); } break;
case NodeType_MultiplyPatterns: { MultiplyPatterns((multiply_patterns_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_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_SolidColorProc: { SolidColorProc((solid_color_data*)Data, DeltaTime); } break;
case NodeType_VerticalColorFadeProc: { VerticalColorFadeProc((vertical_color_fade_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; case NodeType_RevolvingDiscs: { RevolvingDiscs((revolving_discs_data*)Data, DeltaTime); } break;

View File

@ -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++;
}
}

338
src/sacn/sacn.h Normal file
View File

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

View File

@ -71,7 +71,11 @@ NODE_PROC(RevolvingDiscs, revolving_discs_data)
{ {
DEBUG_TRACK_FUNCTION; 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 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 v4 Normal = v4{GSCos(Data->ThetaZ), 0, GSSin(Data->ThetaZ), 0}; // NOTE(Peter): dont' need to normalize. Should always be 1

View File

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

View File

@ -608,6 +608,7 @@ INT NCmdShow
Context.PlatformGetSocketHandle = Win32GetSocketHandle; Context.PlatformGetSocketHandle = Win32GetSocketHandle;
Context.PlatformGetSendAddress = Win32GetSendAddress; Context.PlatformGetSendAddress = Win32GetSendAddress;
Context.PlatformSetSocketOption = Win32SetSocketOption; Context.PlatformSetSocketOption = Win32SetSocketOption;
Context.PlatformSendTo = Win32SendTo;
Context.PlatformCloseSocket = Win32CloseSocket; Context.PlatformCloseSocket = Win32CloseSocket;
Context.PlatformGetFontInfo = Win32GetFontInfo; Context.PlatformGetFontInfo = Win32GetFontInfo;
Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint; Context.PlatformDrawFontCodepoint = Win32DrawFontCodepoint;

View File

@ -1,7 +1,12 @@
TODO FOLDHAUS TODO FOLDHAUS
YOU WERE IN THE MIDDLE OF 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 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. - 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.