diff --git a/src/artnet/artnet.h b/src/artnet/artnet.h new file mode 100644 index 0000000..f57667b --- /dev/null +++ b/src/artnet/artnet.h @@ -0,0 +1 @@ +/* For future artnet implementation */ \ No newline at end of file diff --git a/src/assembly_parser.cpp b/src/assembly_parser.cpp index 094dcdb..0784b09 100644 --- a/src/assembly_parser.cpp +++ b/src/assembly_parser.cpp @@ -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? diff --git a/src/assembly_parser.h b/src/assembly_parser.h index a465de4..ccc384d 100644 --- a/src/assembly_parser.h +++ b/src/assembly_parser.h @@ -56,5 +56,6 @@ struct assembly_definition { s32 LEDStripSize; s32 LEDStripCount; + s32 TotalLEDCount; led_strip_definition* LEDStrips; }; \ No newline at end of file diff --git a/src/dmx/dmx.h b/src/dmx/dmx.h new file mode 100644 index 0000000..1851529 --- /dev/null +++ b/src/dmx/dmx.h @@ -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; +} \ No newline at end of file diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index df1af3d..d83a233 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -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, + State->Permanent, State->Transient, + 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); diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index 53a3619..b8a723b 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -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" diff --git a/src/foldhaus_assembly.cpp b/src/foldhaus_assembly.cpp new file mode 100644 index 0000000..84ca649 --- /dev/null +++ b/src/foldhaus_assembly.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; +} diff --git a/src/foldhaus_assembly.h b/src/foldhaus_assembly.h new file mode 100644 index 0000000..3a38c83 --- /dev/null +++ b/src/foldhaus_assembly.h @@ -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; +}; diff --git a/src/foldhaus_interface.cpp b/src/foldhaus_interface.cpp index 21e2a86..cc1c53a 100644 --- a/src/foldhaus_interface.cpp +++ b/src/foldhaus_interface.cpp @@ -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 diff --git a/src/foldhaus_memory.h b/src/foldhaus_memory.h index 61464af..16e2378 100644 --- a/src/foldhaus_memory.h +++ b/src/foldhaus_memory.h @@ -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) diff --git a/src/foldhaus_network_ordering.h b/src/foldhaus_network_ordering.h index 22d0aab..36349a5 100644 --- a/src/foldhaus_network_ordering.h +++ b/src/foldhaus_network_ordering.h @@ -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); } diff --git a/src/foldhaus_node.cpp b/src/foldhaus_node.cpp index 3768e2e..f7658d5 100644 --- a/src/foldhaus_node.cpp +++ b/src/foldhaus_node.cpp @@ -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)) diff --git a/src/foldhaus_node.h b/src/foldhaus_node.h index 60b7726..309277d 100644 --- a/src/foldhaus_node.h +++ b/src/foldhaus_node.h @@ -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 diff --git a/src/foldhaus_sacn.h b/src/foldhaus_sacn.h deleted file mode 100644 index 8d90d72..0000000 --- a/src/foldhaus_sacn.h +++ /dev/null @@ -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; -} diff --git a/src/generated/foldhaus_nodes_generated.cpp b/src/generated/foldhaus_nodes_generated.cpp index 5e06e73..25fa0d0 100644 --- a/src/generated/foldhaus_nodes_generated.cpp +++ b/src/generated/foldhaus_nodes_generated.cpp @@ -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; diff --git a/src/kraftwerks_patterns.h b/src/kraftwerks_patterns.h deleted file mode 100644 index 2435d7e..0000000 --- a/src/kraftwerks_patterns.h +++ /dev/null @@ -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++; - } -} diff --git a/src/sacn/sacn.h b/src/sacn/sacn.h new file mode 100644 index 0000000..cb18e0e --- /dev/null +++ b/src/sacn/sacn.h @@ -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; +} \ No newline at end of file diff --git a/src/test_patterns.h b/src/test_patterns.h index cf40866..0b34d54 100644 --- a/src/test_patterns.h +++ b/src/test_patterns.h @@ -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 diff --git a/src/testmain.cpp b/src/testmain.cpp deleted file mode 100644 index 0c9350c..0000000 --- a/src/testmain.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#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; -} \ No newline at end of file diff --git a/src/win32_foldhaus.cpp b/src/win32_foldhaus.cpp index 3877ac5..e3d53d1 100644 --- a/src/win32_foldhaus.cpp +++ b/src/win32_foldhaus.cpp @@ -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; diff --git a/todo.txt b/todo.txt index 61671f2..a057795 100644 --- a/todo.txt +++ b/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.