diff --git a/src/animation/foldhaus_animation.h b/src/animation/foldhaus_animation.h index b975592..c5b0434 100644 --- a/src/animation/foldhaus_animation.h +++ b/src/animation/foldhaus_animation.h @@ -5,7 +5,7 @@ // #ifndef FOLDHAUS_ANIMATION -#define ANIMATION_PROC(name) void name(assembly* Assembly, r32 Time) +#define ANIMATION_PROC(name) void name(assembly_led_buffer* Assembly, r32 Time) typedef ANIMATION_PROC(animation_proc); struct frame_range @@ -21,9 +21,18 @@ struct animation_block u32 Layer; }; +enum blend_mode +{ + BlendMode_Overwrite, + BlendMode_Add, + BlendMode_Multiply, + BlendMode_Count, +}; + struct anim_layer { string Name; + blend_mode BlendMode; }; #define ANIMATION_SYSTEM_LAYERS_MAX 128 @@ -124,7 +133,7 @@ RemoveAnimationBlock(gs_list_handle AnimationBlockHandle, animation_system* Anim // Layers internal u32 -AddLayer (string Name, animation_system* AnimationSystem) +AddLayer (string Name, animation_system* AnimationSystem, blend_mode BlendMode = BlendMode_Overwrite) { // TODO(Peter): If this assert fires its time to make the layer buffer system // resizable. @@ -136,6 +145,7 @@ AddLayer (string Name, animation_system* AnimationSystem) *NewLayer = {0}; NewLayer->Name = MakeString(PushArray(&AnimationSystem->Storage, char, Name.Length), Name.Length); CopyStringTo(Name, &NewLayer->Name); + NewLayer->BlendMode = BlendMode; return Result; } diff --git a/src/foldhaus_app.cpp b/src/foldhaus_app.cpp index a62d462..3209387 100644 --- a/src/foldhaus_app.cpp +++ b/src/foldhaus_app.cpp @@ -74,6 +74,7 @@ INITIALIZE_APPLICATION(InitializeApplication) State->Permanent.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; State->Permanent.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; State->Transient = {}; + State->Transient.FindAddressRule = FindAddress_InLastBufferOnly; State->Transient.Alloc = (gs_memory_alloc*)Context.PlatformAlloc; State->Transient.Realloc = (gs_memory_realloc*)Context.PlatformRealloc; @@ -192,9 +193,9 @@ INITIALIZE_APPLICATION(InitializeApplication) State->AnimationSystem.PlayableRange.Max = SecondsToFrames(15, State->AnimationSystem); State->AnimationSystem.LayersMax = 32; State->AnimationSystem.Layers = PushArray(&State->Permanent, anim_layer, State->AnimationSystem.LayersMax); - AddLayer(MakeStringLiteral("Base Layer"), &State->AnimationSystem); - AddLayer(MakeStringLiteral("Color Layer"), &State->AnimationSystem); - AddLayer(MakeStringLiteral("Sparkles"), &State->AnimationSystem); + AddLayer(MakeStringLiteral("Base Layer"), &State->AnimationSystem, BlendMode_Overwrite); + AddLayer(MakeStringLiteral("Color Layer"), &State->AnimationSystem, BlendMode_Multiply); + AddLayer(MakeStringLiteral("Sparkles"), &State->AnimationSystem, BlendMode_Add); } // End Animation Playground @@ -296,8 +297,8 @@ CreateDMXBuffers(assembly Assembly, s32 BufferHeaderSize, memory_arena* Arena) LEDIdx < LEDUniverseRange.RangeOnePastLast; LEDIdx++) { - led LED = Assembly.LEDs[LEDIdx]; - pixel Color = Assembly.Colors[LED.Index]; + led LED = Assembly.LEDBuffer.LEDs[LEDIdx]; + pixel Color = Assembly.LEDBuffer.Colors[LED.Index]; DestChannel[0] = Color.R; @@ -356,6 +357,103 @@ UPDATE_AND_RENDER(UpdateAndRender) CurrentBlocks[Block.Layer] = Block; } +#if 1 + assembly_led_buffer* LayerLEDBuffers = PushArray(&State->Transient, assembly_led_buffer, CurrentBlocksMax); + + for (u32 AssemblyIndex = 0; AssemblyIndex < State->ActiveAssemblyIndecies.Used; AssemblyIndex++) + { + gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(AssemblyIndex); + assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); + + arena_snapshot ResetAssemblyMemorySnapshot = TakeSnapshotOfArena(&State->Transient); + + for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++) + { + if (!CurrentBlocksFilled[Layer]) { continue; } + animation_block Block = CurrentBlocks[Layer]; + + // Prep Temp Buffer + LayerLEDBuffers[Layer] = Assembly->LEDBuffer; + LayerLEDBuffers[Layer].Colors = PushArray(&State->Transient, pixel, Assembly->LEDBuffer.LEDCount); + + u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; + r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame; + // TODO(Peter): Temporary + switch(Block.AnimationProcHandle) + { + case 1: + { + TestPatternOne(&LayerLEDBuffers[Layer], SecondsIntoBlock); + }break; + + case 2: + { + TestPatternTwo(&LayerLEDBuffers[Layer], SecondsIntoBlock); + }break; + + case 3: + { + TestPatternThree(&LayerLEDBuffers[Layer], SecondsIntoBlock); + }break; + + // NOTE(Peter): Zero is invalid + InvalidDefaultCase; + } + } + + // Consolidate Temp Buffers + // We do this in reverse order so that they go from top to bottom + for (u32 Layer = 0; Layer < CurrentBlocksMax; Layer++) + { + if (!CurrentBlocksFilled[Layer]) { continue; } + + switch (State->AnimationSystem.Layers[Layer].BlendMode) + { + case BlendMode_Overwrite: + { + for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + { + Assembly->LEDBuffer.Colors[LED] = LayerLEDBuffers[Layer].Colors[LED]; + } + }break; + + case BlendMode_Add: + { + for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + { + u32 R = (u32)Assembly->LEDBuffer.Colors[LED].R + (u32)LayerLEDBuffers[Layer].Colors[LED].R; + u32 G = (u32)Assembly->LEDBuffer.Colors[LED].G + (u32)LayerLEDBuffers[Layer].Colors[LED].G; + u32 B = (u32)Assembly->LEDBuffer.Colors[LED].B + (u32)LayerLEDBuffers[Layer].Colors[LED].B; + + Assembly->LEDBuffer.Colors[LED].R = (u8)GSMin(R, (u32)255); + Assembly->LEDBuffer.Colors[LED].G = (u8)GSMin(G, (u32)255); + Assembly->LEDBuffer.Colors[LED].B = (u8)GSMin(B, (u32)255); + } + }break; + + case BlendMode_Multiply: + { + for (u32 LED = 0; LED < Assembly->LEDBuffer.LEDCount; LED++) + { + r32 DR = (r32)Assembly->LEDBuffer.Colors[LED].R / 255.f; + r32 DG = (r32)Assembly->LEDBuffer.Colors[LED].G / 255.f; + r32 DB = (r32)Assembly->LEDBuffer.Colors[LED].B / 255.f; + + r32 SR = (r32)LayerLEDBuffers[Layer].Colors[LED].R / 255.f; + r32 SG = (r32)LayerLEDBuffers[Layer].Colors[LED].G / 255.f; + r32 SB = (r32)LayerLEDBuffers[Layer].Colors[LED].B / 255.f; + + Assembly->LEDBuffer.Colors[LED].R = (u8)((DR * SR) * 255.f); + Assembly->LEDBuffer.Colors[LED].G = (u8)((DG * SG) * 255.f); + Assembly->LEDBuffer.Colors[LED].B = (u8)((DB * SB) * 255.f); + } + }break; + } + } + + ClearArenaToSnapshot(&State->Transient, ResetAssemblyMemorySnapshot); + } +#else for (s32 Layer = CurrentBlocksMax - 1; Layer >= 0; Layer--) { if (!CurrentBlocksFilled[Layer]) { continue; } @@ -365,6 +463,11 @@ UPDATE_AND_RENDER(UpdateAndRender) gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(j); assembly* Assembly = State->AssemblyList.GetElementWithHandle(AssemblyHandle); + // TEmporary + assembly_led_buffer TempBuffer = Assembly->LEDBuffer; + TempBuffer.Colors = PushArray(&State->Transient, pixel, TempBuffer.LEDCount); + GSZeroArray(TempBuffer.Colors, pixel, TempBuffer.LEDCount); + u32 FramesIntoBlock = CurrentFrame - Block.Range.Min; r32 SecondsIntoBlock = FramesIntoBlock * State->AnimationSystem.SecondsPerFrame; // TODO(Peter): Temporary @@ -372,24 +475,31 @@ UPDATE_AND_RENDER(UpdateAndRender) { case 1: { - TestPatternOne(Assembly, SecondsIntoBlock); + TestPatternOne(&TempBuffer, SecondsIntoBlock); }break; case 2: { - TestPatternTwo(Assembly, SecondsIntoBlock); + TestPatternTwo(&TempBuffer, SecondsIntoBlock); }break; case 3: { - TestPatternThree(Assembly, SecondsIntoBlock); + TestPatternThree(&TempBuffer, SecondsIntoBlock); }break; // NOTE(Peter): Zero is invalid InvalidDefaultCase; } + + // Temporary + for (u32 i = 0; i < TempBuffer.LEDCount; i++) + { + Assembly->LEDBuffer.Colors[i] = TempBuffer.Colors[i]; + } } } +#endif } s32 HeaderSize = State->NetworkProtocolHeaderSize; diff --git a/src/foldhaus_app.h b/src/foldhaus_app.h index 840af74..c64769b 100644 --- a/src/foldhaus_app.h +++ b/src/foldhaus_app.h @@ -96,19 +96,28 @@ internal void OpenColorPicker(app_state* State, v4* Address); // BEGIN TEMPORARY PATTERNS internal void -TestPatternOne(assembly* Assembly, r32 Time) +TestPatternOne(assembly_led_buffer* Assembly, r32 Time) { for (u32 LEDIdx = 0; LEDIdx < Assembly->LEDCount; LEDIdx++) { led LED = Assembly->LEDs[LEDIdx]; - Assembly->Colors[LED.Index].R = 255; - Assembly->Colors[LED.Index].B = 255; - Assembly->Colors[LED.Index].G = 255; + if (LED.Position.x < 0) + { + Assembly->Colors[LED.Index].R = 255; + Assembly->Colors[LED.Index].B = 255; + Assembly->Colors[LED.Index].G = 255; + } + else + { + Assembly->Colors[LED.Index].R = 0; + Assembly->Colors[LED.Index].B = 0; + Assembly->Colors[LED.Index].G = 0; + } } } internal void -TestPatternTwo(assembly* Assembly, r32 Time) +TestPatternTwo(assembly_led_buffer* Assembly, r32 Time) { r32 PeriodicTime = (Time / PI) * 2; @@ -162,7 +171,7 @@ TestPatternTwo(assembly* Assembly, r32 Time) } internal void -TestPatternThree(assembly* Assembly, r32 Time) +TestPatternThree(assembly_led_buffer* Assembly, r32 Time) { v4 GreenCenter = v4{0, 0, 150, 1}; r32 GreenRadius = GSAbs(GSSin(Time)) * 200; diff --git a/src/foldhaus_assembly.cpp b/src/foldhaus_assembly.cpp index 1fb23e3..0e17226 100644 --- a/src/foldhaus_assembly.cpp +++ b/src/foldhaus_assembly.cpp @@ -21,9 +21,9 @@ ConstructAssemblyFromDefinition (assembly_definition Definition, // 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.Arena, pixel, Definition.TotalLEDCount); - Assembly.LEDs = PushArray(&Assembly.Arena, led, Definition.TotalLEDCount); + Assembly.LEDBuffer.LEDCount = 0; + Assembly.LEDBuffer.Colors = PushArray(&Assembly.Arena, pixel, Definition.TotalLEDCount); + Assembly.LEDBuffer.LEDs = PushArray(&Assembly.Arena, led, Definition.TotalLEDCount); Assembly.LEDUniverseMapCount = Definition.LEDStripCount; Assembly.LEDUniverseMap = PushArray(&Assembly.Arena, leds_in_universe_range, Definition.LEDStripCount); @@ -34,8 +34,8 @@ ConstructAssemblyFromDefinition (assembly_definition Definition, leds_in_universe_range* LEDUniverseRange = Assembly.LEDUniverseMap + StripIdx; LEDUniverseRange->Universe = StripDef.StartUniverse; - LEDUniverseRange->RangeStart = Assembly.LEDCount; - LEDUniverseRange->RangeOnePastLast = Assembly.LEDCount + StripDef.LEDsPerStrip; + LEDUniverseRange->RangeStart = Assembly.LEDBuffer.LEDCount; + LEDUniverseRange->RangeOnePastLast = Assembly.LEDBuffer.LEDCount + StripDef.LEDsPerStrip; // NOTE(Peter): this should be a switch on the type, but we only have one for // now. The assert is to remind you to create more cases when necessary @@ -45,19 +45,19 @@ ConstructAssemblyFromDefinition (assembly_definition Definition, v4 WS_StripEnd = RootPosition + V4(StripDef.InterpolatePositionEnd * Scale, 1); s32 LEDsInStripCount = StripDef.LEDsPerStrip; - Assert(Assembly.LEDCount + LEDsInStripCount <= Definition.TotalLEDCount); + Assert(Assembly.LEDBuffer.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; + s32 LEDIndex = Assembly.LEDBuffer.LEDCount++; + Assembly.LEDBuffer.LEDs[LEDIndex].Position = WS_StripStart + (SingleStep * Step); + Assembly.LEDBuffer.LEDs[LEDIndex].Index = LEDIndex; } } // NOTE(Peter): Did we create the correct number of LEDs? - Assert(Assembly.LEDCount == Definition.TotalLEDCount); + Assert(Assembly.LEDBuffer.LEDCount == Definition.TotalLEDCount); return Assembly; } @@ -89,7 +89,7 @@ LoadAssembly (app_state* State, context Context, char* Path) gs_list_handle NewAssemblyHandle = State->AssemblyList.PushElementOnList(NewAssembly); State->ActiveAssemblyIndecies.PushElementOnList(NewAssemblyHandle); - State->TotalLEDsCount += NewAssembly.LEDCount; + State->TotalLEDsCount += NewAssembly.LEDBuffer.LEDCount; Context.PlatformFree(AssemblyFile.Base, AssemblyFile.Size); } @@ -103,7 +103,7 @@ internal void UnloadAssembly (u32 AssemblyIndex, app_state* State, context Context) { assembly* Assembly = State->AssemblyList.GetElementAtIndex(AssemblyIndex); - State->TotalLEDsCount -= Assembly->LEDCount; + State->TotalLEDsCount -= Assembly->LEDBuffer.LEDCount; FreeMemoryArena(&Assembly->Arena, (gs_memory_free*)Context.PlatformFree); State->AssemblyList.FreeElementAtIndex(AssemblyIndex); diff --git a/src/foldhaus_assembly.h b/src/foldhaus_assembly.h index f53084b..5852583 100644 --- a/src/foldhaus_assembly.h +++ b/src/foldhaus_assembly.h @@ -33,6 +33,13 @@ struct leds_in_universe_range s32 Universe; }; +struct assembly_led_buffer +{ + u32 LEDCount; + pixel* Colors; + led* LEDs; +}; + struct assembly { memory_arena Arena; @@ -40,9 +47,13 @@ struct assembly string Name; string FilePath; + assembly_led_buffer LEDBuffer; + +#if 0 u32 LEDCount; pixel* Colors; led* LEDs; +#endif u32 LEDUniverseMapCount; leds_in_universe_range* LEDUniverseMap; diff --git a/src/generated/foldhaus_nodes_generated.h b/src/generated/foldhaus_nodes_generated.h index f72b4bb..8e9f0f8 100644 --- a/src/generated/foldhaus_nodes_generated.h +++ b/src/generated/foldhaus_nodes_generated.h @@ -1,28 +1,28 @@ enum node_type { - NodeType_RevolvingDiscs, NodeType_SolidColorProc, + NodeType_RevolvingDiscs, NodeType_VerticalColorFadeProc, NodeType_Count, }; static node_specification_ NodeSpecifications[] = { -{ NodeType_RevolvingDiscs, {"RevolvingDiscs", 14}, gsm_StructType_revolving_discs_data }, { NodeType_SolidColorProc, {"SolidColorProc", 14}, gsm_StructType_solid_color_data }, +{ NodeType_RevolvingDiscs, {"RevolvingDiscs", 14}, gsm_StructType_revolving_discs_data }, { NodeType_VerticalColorFadeProc, {"VerticalColorFadeProc", 21}, gsm_StructType_vertical_color_fade_data }, }; void CallNodeProc(node_type Type, u8* NodeData) { switch(Type) { - case NodeType_RevolvingDiscs: - { - RevolvingDiscs((revolving_discs_data*)NodeData); - } break; case NodeType_SolidColorProc: { SolidColorProc((solid_color_data*)NodeData); } break; + case NodeType_RevolvingDiscs: + { + RevolvingDiscs((revolving_discs_data*)NodeData); + } break; case NodeType_VerticalColorFadeProc: { VerticalColorFadeProc((vertical_color_fade_data*)NodeData); diff --git a/src/panels/foldhaus_panel_sculpture_view.h b/src/panels/foldhaus_panel_sculpture_view.h index 8b3acb1..880b2f8 100644 --- a/src/panels/foldhaus_panel_sculpture_view.h +++ b/src/panels/foldhaus_panel_sculpture_view.h @@ -160,15 +160,15 @@ SculptureView_Render(panel Panel, rect PanelBounds, render_command_buffer* Rende { gs_list_handle AssemblyHandle = *State->ActiveAssemblyIndecies.GetElementAtIndex(i); assembly Assembly = *State->AssemblyList.GetElementWithHandle(AssemblyHandle); - u32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDCount, MaxLEDsPerJob); + u32 JobsNeeded = IntegerDivideRoundUp(Assembly.LEDBuffer.LEDCount, MaxLEDsPerJob); for (u32 Job = 0; Job < JobsNeeded; Job++) { draw_leds_job_data* JobData = PushStruct(&State->Transient, draw_leds_job_data); - JobData->LEDs = Assembly.LEDs; - JobData->Colors = Assembly.Colors; + JobData->LEDs = Assembly.LEDBuffer.LEDs; + JobData->Colors = Assembly.LEDBuffer.Colors; JobData->StartIndex = Job * MaxLEDsPerJob; - JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDCount); + JobData->OnePastLastIndex = GSMin(JobData->StartIndex + MaxLEDsPerJob, Assembly.LEDBuffer.LEDCount); JobData->Batch = &RenderLEDsBatch; JobData->FaceCameraMatrix; JobData->ModelViewMatrix = ModelViewMatrix; diff --git a/todo.txt b/todo.txt index 06de4c0..9cc8e05 100644 --- a/todo.txt +++ b/todo.txt @@ -86,6 +86,7 @@ Ground Up Reengineering - - setting start and end of timeline (how long is a loop) - clips can have parameters that drive them? + - clips cannot overlap eachother on the same layer - Node System - automatic node layout