From 175f58fd077def0127a09081b37581abbd9bb701 Mon Sep 17 00:00:00 2001 From: PS Date: Thu, 8 Apr 2021 18:11:56 -1000 Subject: [PATCH 1/8] Pattern Grow Fade Mask --- src/app/patterns/blumen_patterns.h | 37 +++++++++++++++++++++++- src/app/ss_blumen_lumen/blumen_lumen.cpp | 2 ++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 8684d56..bdfc539 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -662,7 +662,7 @@ Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r v2_strip Strip = Assembly.Strips[StripIndex]; for (u32 i = 0; i < Strip.LedCount; i++) { - v4 P = Leds->Positions[i]; + v4 P = Leds->Positions[Strip.LedLUT[i]]; Leds->Colors[i] = WhiteMask; } } @@ -686,5 +686,40 @@ Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, } } +internal void +Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + Time = Time * BLState->PatternSpeed; + + r32 Period = 10.0f; // seconds + r32 ElapsedPct = FractR32(Time / Period); + + r32 ElapsedPctGrow = PowR32(ElapsedPct * 2, 2); + r32 ElapsedPctFade = Clamp01((ElapsedPct * 2) - 1); + + r32 Radius = 300 * ElapsedPctGrow; + + v3 Origin = Assembly.Center - v3{0, 150, 0}; + + r32 Brightness = Smoothstep(1.0f - ElapsedPctFade); + + pixel COutside = V4ToRGBPixel(BlackV4); + pixel CInside = V4ToRGBPixel(WhiteV4 * Brightness); + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) + { + v3 P = Leds->Positions[LedIndex].xyz; + r32 Dist = V3Mag(P - Origin); + if (Dist < Radius) + { + Leds->Colors[LedIndex] = CInside; + } + else + { + Leds->Colors[LedIndex] = COutside; + } + } +} + #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H \ No newline at end of file diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index b80c80e..cef7f08 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -217,6 +217,8 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_StemSolid, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_PrimaryHue, PATTERN_MULTITHREADED); + + Patterns_PushPattern(Patterns, Pattern_GrowFadeMask, PATTERN_MULTITHREADED); } internal void From 40014ca4714c7a27fde28691a9a774d34f9a048a Mon Sep 17 00:00:00 2001 From: PS Date: Thu, 8 Apr 2021 20:58:44 -1000 Subject: [PATCH 2/8] Rainbow Loading Pattern --- .../audio_responses/voice_command.foldanim | 2 +- src/app/patterns/blumen_patterns.h | 45 +++++++++++++++++++ src/app/ss_blumen_lumen/blumen_lumen.cpp | 1 + 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim b/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim index b5b409a..8303d19 100644 --- a/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim +++ b/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim @@ -19,6 +19,6 @@ blocks:{ max: 3599; }; layer_index: 0; - animation_name: "Pattern_VoicePattern"; + animation_name: "Pattern_RainbowLoadingBar"; }; }; diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index bdfc539..e98594f 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -721,5 +721,50 @@ Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly } } +internal void +Pattern_RainbowLoadingBar(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + Time = Time * BLState->PatternSpeed; + + // constants + r32 Period = 5.0f; // seconds + r32 CSpeed = 16.0f; + r32 HIncrement = CSpeed * Period; + r32 HOffset = CSpeed * Period; + r32 MaxSphereRadius = 300; + + // sphere + r32 ElapsedPct = FractR32(Time / Period); + r32 ElapsedPctGrow = PowR32(ElapsedPct, 2); + r32 Radius = MaxSphereRadius * ElapsedPctGrow; + v3 Origin = Assembly.Center - v3{0, 150, 0}; + + // colors + r32 T = Time * CSpeed; + r32 TimeStep0 = T; + r32 TimeStep1 = T + HOffset; + r32 Hue0 = FloorR32(TimeStep0 / HIncrement) * HIncrement; + r32 Hue1 = FloorR32(TimeStep1 / HIncrement) * HIncrement; + v4 H0 = v4{ModR32(Hue0, 360), 1, 1, 1}; + v4 H1 = v4{ModR32(Hue1, 360), 1, 1, 1}; + pixel C0 = V4ToRGBPixel(HSVToRGB(H0)); + pixel C1 = V4ToRGBPixel(HSVToRGB(H1)); + + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) + { + v3 P = Leds->Positions[LedIndex].xyz; + r32 Dist = V3Mag(P - Origin); + if (Dist < Radius) + { + Leds->Colors[LedIndex] = C1; + } + else + { + Leds->Colors[LedIndex] = C0; + } + } +} + #define BLUMEN_PATTERNS_H #endif // BLUMEN_PATTERNS_H \ No newline at end of file diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index cef7f08..d9ed8bb 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -219,6 +219,7 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_PrimaryHue, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_GrowFadeMask, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_RainbowLoadingBar, PATTERN_MULTITHREADED); } internal void From 7ff47ad4455ee3983dfb1697a7ab916cb7e0618c Mon Sep 17 00:00:00 2001 From: PS Date: Thu, 8 Apr 2021 21:01:11 -1000 Subject: [PATCH 3/8] Fixed Pattern_StemSolid --- src/app/patterns/blumen_patterns.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index e98594f..fac6499 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -646,12 +646,6 @@ internal void Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; - Time = Time * BLState->PatternSpeed; - - phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); - v4 C0 = RGBFromPhraseHue(Hue.Hue0); - v4 C1 = RGBFromPhraseHue(Hue.Hue1); - v4 C2 = RGBFromPhraseHue(Hue.Hue2); pixel WhiteMask = V4ToRGBPixel(WhiteV4); @@ -662,8 +656,8 @@ Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r v2_strip Strip = Assembly.Strips[StripIndex]; for (u32 i = 0; i < Strip.LedCount; i++) { - v4 P = Leds->Positions[Strip.LedLUT[i]]; - Leds->Colors[i] = WhiteMask; + u32 LedIndex = Strip.LedLUT[i]; + Leds->Colors[LedIndex] = WhiteMask; } } } From 7a103dae420b19ea36c36671b458fb405acc810e Mon Sep 17 00:00:00 2001 From: PS Date: Fri, 9 Apr 2021 00:42:04 -1000 Subject: [PATCH 4/8] Lots of pattern work, plus color fading --- .../ambient_patterns/ambient_1.foldanim | 2 +- .../audio_responses/voice_command.foldanim | 20 +- .../animation/foldhaus_animation_renderer.cpp | 9 +- src/app/patterns/blumen_patterns.h | 215 ++++++++++---- src/app/ss_blumen_lumen/blumen_lumen.cpp | 272 ++++++++++-------- src/app/ss_blumen_lumen/blumen_lumen.h | 43 ++- .../ss_blumen_lumen/blumen_lumen_settings.h | 3 + src/app/ss_blumen_lumen/gfx_math.h | 9 +- src/app/ss_blumen_lumen/phrase_hue_map.h | 160 +++++++++-- 9 files changed, 528 insertions(+), 205 deletions(-) diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/ambient_1.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/ambient_1.foldanim index 19d552e..d7a5167 100644 --- a/app_run_tree/data/blumen_animations/ambient_patterns/ambient_1.foldanim +++ b/app_run_tree/data/blumen_animations/ambient_patterns/ambient_1.foldanim @@ -35,7 +35,7 @@ blocks:{ max: 2000; }; layer_index: 1; - animation_name: "Pattern_VerticalLines"; + animation_name: "Pattern_Leafy"; }; block:{ frame_range:{ diff --git a/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim b/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim index 8303d19..c21484c 100644 --- a/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim +++ b/app_run_tree/data/blumen_animations/audio_responses/voice_command.foldanim @@ -1,16 +1,20 @@ lumenarium_animation_file; animation_name: "voice_anim"; -layers_count: 1; -blocks_count: 1; +layers_count: 2; +blocks_count: 2; playable_range:{ min: 0; max: 3600; }; layers:{ layer:{ - name: "[New Layer]"; + name: "Base"; blend: "Add"; }; + layer:{ + name: "Add In"; + blend: "Overwrite"; + }; }; blocks:{ block:{ @@ -19,6 +23,14 @@ blocks:{ max: 3599; }; layer_index: 0; - animation_name: "Pattern_RainbowLoadingBar"; + animation_name: "Pattern_VoicePattern"; + }; + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 1; + animation_name: "Pattern_VoiceAddIns"; }; }; diff --git a/src/app/engine/animation/foldhaus_animation_renderer.cpp b/src/app/engine/animation/foldhaus_animation_renderer.cpp index 208c87a..5bdaec1 100644 --- a/src/app/engine/animation/foldhaus_animation_renderer.cpp +++ b/src/app/engine/animation/foldhaus_animation_renderer.cpp @@ -8,7 +8,14 @@ internal pixel LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData) { - return PixelB; + pixel Result = PixelB; + if (PixelB.R == 0 && + PixelB.G == 0 && + PixelB.G == 0) + { + Result = PixelA; + } + return Result; } internal pixel diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index fac6499..732192c 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -171,17 +171,8 @@ Pattern_BasicFlowers(led_buffer* Leds, led_buffer_range Range, assembly Assembly } internal void -Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_WavyOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2) { - DEBUG_TRACK_FUNCTION; - blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; - Time = Time * BLState->PatternSpeed; - - phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); - v4 C0 = RGBFromPhraseHue(Hue.Hue0); - v4 C1 = RGBFromPhraseHue(Hue.Hue1); - v4 C2 = RGBFromPhraseHue(Hue.Hue2); - r32 Top = 120 + (SinR32(Time) * 10); r32 Mid = 70 + (CosR32(Time * 2.13) * 20); r32 Bot = 0; @@ -233,7 +224,7 @@ Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Ti } internal void -Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { DEBUG_TRACK_FUNCTION; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; @@ -244,6 +235,18 @@ Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 v4 C1 = RGBFromPhraseHue(Hue.Hue1); v4 C2 = RGBFromPhraseHue(Hue.Hue2); + Pattern_WavyOptions(Leds, Range, Assembly, Time, Transient, UserData, 1, C0, C1, C2); +} + +internal void +Pattern_PatchyOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2) +{ + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + + r32 BaseGA = 50.000f * (1 / Granularity); + r32 BaseGB = 135.20f * (1 / Granularity); + r32 BaseGC = 260.74f * (1 / Granularity); + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) { v4 P = Leds->Positions[LedIndex]; @@ -251,22 +254,41 @@ Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 r32 ScaleFactor = 1.0f / LedRange; v3 Pp = P.xyz + v3{150, 100, 0}; - r32 NoiseA = Noise3D((Pp / 38) + v3{0, 0, Time}); + r32 NoiseA = Noise3D((Pp / BaseGA) + v3{0, 0, Time}); NoiseA = PowR32(NoiseA, 3); NoiseA = Smoothstep(NoiseA); - v4 CA = C0 * NoiseA; - r32 NoiseB = Noise3D((Pp / 75) + v3{Time * 0.5f, 0, 0}); + r32 NoiseB = Noise3D((Pp / BaseGB) + v3{Time * 0.5f, 0, 0}); NoiseB = PowR32(NoiseB, 3); NoiseB = Smoothstep(NoiseB); - v4 CB = C1 * NoiseB; - v4 C = (C0 * NoiseA) + (C1 * NoiseB); - C /= (NoiseA + NoiseB); +#if 1 + r32 NoiseC = Noise3D((Pp / BaseGC) + v3{Time * 0.5f, 0, 0}); + NoiseC = PowR32(NoiseC, 3); + NoiseC = Smoothstep(NoiseC); +#else + r32 NoiseC = 0; +#endif + + v4 C = (C0 * NoiseA) + (C1 * NoiseB) + (C2 * NoiseC); + C /= (NoiseA + NoiseB + NoiseC); Leds->Colors[LedIndex] = V4ToRGBPixel(C); } } +internal void +Pattern_Patchy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); + v4 C0 = RGBFromPhraseHue(Hue.Hue0); + v4 C1 = RGBFromPhraseHue(Hue.Hue1); + v4 C2 = RGBFromPhraseHue(Hue.Hue2); + Time = Time * BLState->PatternSpeed; + Pattern_PatchyOptions(Leds, Range, Assembly, Time, Transient, UserData, 5, C0, C1, C2); +} + internal r32 Leafy_BandSDF(v3 P, gs_random_series* Random, r32 Time) { @@ -412,33 +434,35 @@ Pattern_VerticalLines(led_buffer* Leds, led_buffer_range Range, assembly Assembl } internal void -Pattern_Rotary(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +Pattern_RotaryOptions(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 BGColor, v4 FGColor) { - blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; - Time = Time * BLState->PatternSpeed; + DEBUG_TRACK_FUNCTION; - gs_random_series Random = InitRandomSeries(24601); + gs_random_series Random = InitRandomSeries((u32)(24601 * (Assembly.Center.x + 1.032f))); #define SphereCount 32 v3 SphereCenter[SphereCount]; - r32 MaxHeightOffset = 150; + r32 G = RemapR32(Granularity, 1, 5, .75f, 2); + r32 MaxHeightOffset = 250; r32 MaxSpeed = 10; - r32 SphereRadius = 2.0f; + r32 SphereRotationRadius = 3.0f; + r32 SphereRadius = 2.0f / G; for (u32 i = 0; i < SphereCount; i++) { - r32 SphereSeedA = NextRandomBilateral(&Random); + r32 SphereSeedA = NextRandomUnilateral(&Random); + SphereSeedA = PowR32(SphereSeedA, 2); r32 SphereSeedB = NextRandomBilateral(&Random); r32 SphereSpeed = NextRandomUnilateral(&Random) * MaxSpeed; r32 SphereTime = Time + SphereSpeed; - r32 HeightOffset = SphereTime + (SphereSeedA * MaxHeightOffset); + r32 HeightOffset = 150 - (SphereSeedA * MaxHeightOffset); r32 RotationOffset = SphereTime + SphereSeedB * TauR32; r32 SphereRotationDir = NextRandomBilateral(&Random) < 0 ? -1 : 1; v3 SpherePosOffset = v3{ - SinR32(RotationOffset * SphereRotationDir) * (SphereRadius * 2), + SinR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2), HeightOffset, - CosR32(RotationOffset * SphereRotationDir) * (SphereRadius * 2) + CosR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2) }; SphereCenter[i] = Assembly.Center + SpherePosOffset; } @@ -455,17 +479,27 @@ Pattern_Rotary(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Dist = Min(Dist, SphereSDF); } - v4 C = BlackV4; + v4 C = BGColor; if (Dist <= 1) { r32 Brightness = Clamp01(SphereRadius - Dist); - C = WhiteV4 * Brightness; + C = V4Lerp(Brightness, BGColor, FGColor); } Leds->Colors[LedIndex] = V4ToRGBPixel(C); } } +internal void +Pattern_Rotary(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + DEBUG_TRACK_FUNCTION; + + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + Time = Time * BLState->PatternSpeed; + Pattern_RotaryOptions(Leds, Range, Assembly, Time, Transient, UserData, 2, BlackV4, WhiteV4); +} + internal void Pattern_AllOnMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { @@ -480,6 +514,8 @@ Pattern_AllOnMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r internal void Pattern_BulbMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; Time = Time * BLState->PatternSpeed; @@ -571,26 +607,47 @@ GenVerticalLeaves(v3 P, r32 Time, v4 C0, v4 C1, v4 C2) return R; } -internal r32 -GenLiquidBands(v3 P, r32 Offset, r32 Time) +internal void +AddIn_WavesPattern(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData, r32 Granularity, v4 C0, v4 C1, v4 C2) { - r32 Width = 30; - r32 VAcc = 0; - for (u32 i = 1; i < 3; i++) - { - v3 P0 = v3{P.x + (23.124f * i), 0, P.z - (-12.34f * i)}; - - r32 Y = (P.y - Offset); - r32 S = Fbm3D(P0 * .005f, Time) * 250; - S += ModR32((Time * 100) - (150 * i), 400); - - r32 V = (Width - Abs(Y - S)) / Width; - V = Clamp01(V); - - VAcc += V; - } + DEBUG_TRACK_FUNCTION; - return VAcc; + v4 C2P = C2 * 255; + + for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) + { + v3 P = Leds->Positions[LedIndex].xyz; + + v4 C = v4{ + (r32)Leds->Colors[LedIndex].R, + (r32)Leds->Colors[LedIndex].G, + (r32)Leds->Colors[LedIndex].B, + 1 + }; + + r32 Offset = -250; + r32 Width = 30; + r32 Bands = 0; + for (u32 i = 1; i <= 1; i++) + { + P.x = FloorR32(P.x); + P.z = FloorR32(P.z); + + v3 P0 = v3{P.x + (23.124f * i), 0, P.z - (-12.34f * i) + Time}; + r32 S = Fbm3D(P0 * .005f, Time) * 250; + S += ModR32((Time * 100) - (150 * i), 400); + + r32 Y = (P.y - Offset); + r32 V = (Width - Abs(Y - S)) / Width; + V = Clamp01(V); + + Bands += V; + } + + C = V4Lerp(Bands, C * .5f, C2P); + + Leds->Colors[LedIndex] = pixel{(u8)C.r, (u8)C.g, (u8)C.b}; + } } internal r32 @@ -618,33 +675,69 @@ GenDotBands(v3 P, r32 Time) internal void Pattern_VoicePattern(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { - blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; - Time = Time * BLState->PatternSpeed; + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); v4 C0 = RGBFromPhraseHue(Hue.Hue0); v4 C1 = RGBFromPhraseHue(Hue.Hue1); v4 C2 = RGBFromPhraseHue(Hue.Hue2); - for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++) + Time = Time * BLState->PatternSpeed * Hue.Speed;; + + switch (Hue.Pattern) { - v3 P = Leds->Positions[LedIndex].xyz; + case HuePattern_Wavy: + { + Pattern_WavyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C0); + }break; - v4 C = {}; - C += GenPatchyColor(P, Time, C0, C2, {}); - //C = GenVerticalLeaves((P - Assembly.Center) + v3{0, 150, 0}, Time, C0, C1, C2); - //r32 Bands = GenLiquidBands(P, -250, Time); - //C = V4Lerp(Bands, C * .5f, C1); + default: + { + Pattern_PatchyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2); + }break; + } + + +} + +internal void +Pattern_VoiceAddIns(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + DEBUG_TRACK_FUNCTION; + + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; + phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); + v4 C0 = RGBFromPhraseHue(Hue.Hue0); + v4 C1 = RGBFromPhraseHue(Hue.Hue1); + v4 C2 = RGBFromPhraseHue(Hue.Hue2); + + Time = Time * BLState->PatternSpeed * Hue.Speed;; + + switch (Hue.AddIn) + { + case AddIn_Rotary: + { + Pattern_RotaryOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, BlackV4, C2); + }break; - //C = WhiteV4 * GenDotBands(P - Assembly.Center, Time); + case AddIn_Waves: + { + AddIn_WavesPattern(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2); + }break; - Leds->Colors[LedIndex] = V4ToRGBPixel(C); + case AddIn_None: + default: + { + }break; } } internal void Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; pixel WhiteMask = V4ToRGBPixel(WhiteV4); @@ -665,6 +758,8 @@ Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r internal void Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; Time = Time * BLState->PatternSpeed; @@ -683,6 +778,8 @@ Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, internal void Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; Time = Time * BLState->PatternSpeed; @@ -718,6 +815,8 @@ Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly internal void Pattern_RainbowLoadingBar(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { + DEBUG_TRACK_FUNCTION; + blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; Time = Time * BLState->PatternSpeed; diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index d9ed8bb..295a47d 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -214,6 +214,7 @@ BlumenLumen_LoadPatterns(app_state* State) Patterns_PushPattern(Patterns, Pattern_AllOnMask, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_BulbMask, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_VoicePattern, PATTERN_MULTITHREADED); + Patterns_PushPattern(Patterns, Pattern_VoiceAddIns, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_StemSolid, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_PrimaryHue, PATTERN_MULTITHREADED); @@ -399,6 +400,10 @@ BlumenLumen_CustomInit(app_state* State, context Context) BLState->StandardPatternHues.Hue0.Flags = Hue_Value; BLState->StandardPatternHues.Hue1.Flags = Hue_Value; BLState->StandardPatternHues.Hue2.Flags = Hue_Value; + BLState->StandardPatternHues.Granularity = 1; + BLState->StandardPatternHues.Speed = 1; + BLState->StandardPatternHues.AddIn = AddIn_Rotary; + BLState->StandardPatternHues.Pattern = HuePattern_Wavy; BlumenLumen_AppendBootupLog(State, BLState, Context); return Result; @@ -423,6 +428,38 @@ BlumenLumen_UpdateMotorState(blumen_lumen_state* BLState, motor_status_packet Mo BLState->ShouldUpdateLog = true; } +internal void +BlumenLumen_ApplyNextHotHue(blumen_lumen_state* BLState, context Context, gs_string* DebugStr, app_state* State) +{ + // if we are in standard color mode, shift all flowers to the new color + // otherwise, only shift the next flower in the sequence to the new color + phrase_hue NewHue = BLState->NextHotHue; + + PrintF(DebugStr, "Switching To: %S\n", NewHue.Phrase); + NullTerminate(DebugStr); + OutputDebugString(DebugStr->Str); + + + if (BLState->PatternMode == BlumenPattern_Standard) + { + BlumenLumen_SetNextHue(BLState, 0, NewHue); + BlumenLumen_SetNextHue(BLState, 1, NewHue); + BlumenLumen_SetNextHue(BLState, 2, NewHue); + } + else + { + u32 AssemblyIdx = BLState->LastAssemblyColorSet; + BlumenLumen_SetNextHue(BLState, AssemblyIdx, NewHue); + BLState->LastAssemblyColorSet = (BLState->LastAssemblyColorSet + 1) % 3; + } + + BlumenLumen_SetPatternMode(BlumenPattern_VoiceCommand, GlobalAnimTransitionSpeed, &State->AnimationSystem, BLState); + BLState->TimeLastSetToVoiceMode = Context.SystemTime_Current; + BLState->LastHuePhrase = NewHue; + BLState->ShouldUpdateLog = true; + BLState->InPhraseReceptionMode = false; +} + internal void BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) { @@ -447,7 +484,7 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) u64 NameHash = HashDJB2ToU32(Mic.AnimationFileName); u32 NameLen = CStringLength(Mic.AnimationFileName); - phrase_hue NewHue = PhraseHueMap_Get(BLState->PhraseHueMap, NameHash); + phrase_hue NewHue = PhraseHueMap_Find(BLState->PhraseHueMap, NameHash); if (NewHue.Phrase.Length > 0) { bool IsLonger = (BLState->NextHotHue.Phrase.Length < NewHue.Phrase.Length); @@ -510,36 +547,12 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) r32 SecondsSincePhraseBegan = SecondsElapsed(BLState->TimePhraseReceptionBegan, Context->SystemTime_Current); if (SecondsSincePhraseBegan > PhrasePriorityMessageGroupingTime) { - // if we are in standard color mode, shift all flowers to the new color - // otherwise, only shift the next flower in the sequence to the new color - phrase_hue NewHue = BLState->NextHotHue; - - PrintF(&DebugStr, "Switching To: %S\n", NewHue.Phrase); - NullTerminate(&DebugStr); - OutputDebugString(DebugStr.Str); - - - if (BLState->PatternMode == BlumenPattern_Standard) - { - BLState->AssemblyColors[0] = NewHue; - BLState->AssemblyColors[1] = NewHue; - BLState->AssemblyColors[2] = NewHue; - } - else - { - u32 AssemblyIdx = BLState->LastAssemblyColorSet; - BLState->AssemblyColors[AssemblyIdx] = NewHue; - BLState->LastAssemblyColorSet = (BLState->LastAssemblyColorSet + 1) % 3; - } - - BlumenLumen_SetPatternMode(BlumenPattern_VoiceCommand, GlobalAnimTransitionSpeed, &State->AnimationSystem, BLState); - BLState->TimeLastSetToVoiceMode = Context->SystemTime_Current; - BLState->LastHuePhrase = NewHue; - BLState->ShouldUpdateLog = true; - BLState->InPhraseReceptionMode = false; + BlumenLumen_ApplyNextHotHue(BLState, *Context, &DebugStr, State); } } + BlumenLumen_AdvanceHueFade(BLState, *Context); + // Update next frames Hues r32 AnimTime = AnimationSystem_GetCurrentTime(State->AnimationSystem); AnimTime = (r32)Context->TotalTime; @@ -737,110 +750,131 @@ US_CUSTOM_DEBUG_UI(BlumenLumen_DebugUI) blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; ui_interface* I = &State->Interface; - // NOTE(PS): Motors + motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket; + + for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++) { - motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket; - - for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++) + gs_string Label = PushStringF(State->Transient, 32, "Motor %d", MotorIndex); + ui_BeginRow(I, 5); { - gs_string Label = PushStringF(State->Transient, 32, "Motor %d", MotorIndex); - ui_BeginRow(I, 5); + ui_Label(I, Label); + + bool IsClosed = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Closed; + if (ui_ToggleText(I, MakeString("Closed (1)"), IsClosed)) { - ui_Label(I, Label); - - bool IsClosed = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Closed; - if (ui_ToggleText(I, MakeString("Closed (1)"), IsClosed)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_Closed; - } - bool IsHOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_HalfOpen; - if (ui_ToggleText(I, MakeString("Half Open (3)"), IsHOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_HalfOpen; - } - bool IsMOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_MostlyOpen; - if (ui_ToggleText(I, MakeString("Mostly Open (4)"), IsMOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_MostlyOpen; - } - bool IsOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Open; - if (ui_ToggleText(I, MakeString("Open (2)"), IsOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_Open; - } + PendingPacket.FlowerPositions[MotorIndex] = MotorState_Closed; } + bool IsHOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_HalfOpen; + if (ui_ToggleText(I, MakeString("Half Open (3)"), IsHOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_HalfOpen; + } + bool IsMOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_MostlyOpen; + if (ui_ToggleText(I, MakeString("Mostly Open (4)"), IsMOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_MostlyOpen; + } + bool IsOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Open; + if (ui_ToggleText(I, MakeString("Open (2)"), IsOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_Open; + } + } + ui_EndRow(I); + } + BLState->DEBUG_PendingMotorPacket = PendingPacket; + + if (ui_Button(I, MakeString("Send Motor Packet"))) + { + blumen_packet Packet = {}; + Packet.Type = PacketType_MotorState; + Packet.MotorPacket = BLState->DEBUG_PendingMotorPacket; + gs_data Msg = StructToData(&Packet, blumen_packet); + MessageQueue_Write(&BLState->OutgoingMsgQueue, Msg); + + DEBUG_SentMotorCommand(Packet.MotorPacket, Context.ThreadContext); + } + + motor_packet MotorPos = BLState->LastKnownMotorState; + ui_Label(I, MakeString("Current Motor Positions")); + { + for (u32 i = 0; i < BL_FLOWER_COUNT; i++) + { + ui_BeginRow(I, 2); + gs_string MotorStr = PushStringF(State->Transient, 32, + "Motor %d", + i); + ui_Label(I, MotorStr); + + gs_string StateStr = {}; + switch (MotorPos.FlowerPositions[i]) + { + case MotorState_Closed: { + StateStr = MakeString("Closed"); + } break; + case MotorState_HalfOpen: { + StateStr = MakeString("Half Open"); + } break; + case MotorState_MostlyOpen: { + StateStr = MakeString("Mostly Open"); + } break; + case MotorState_Open: { + StateStr = MakeString("Open"); + } break; + } + + ui_Label(I, StateStr); ui_EndRow(I); } - BLState->DEBUG_PendingMotorPacket = PendingPacket; + } + + BLState->DEBUG_IgnoreWeatherDimmingLeds = ui_LabeledToggle(I, MakeString("Ignore Weather Dimming Leds"), BLState->DEBUG_IgnoreWeatherDimmingLeds); + + ui_Label(I, MakeString("Set Internal Motor State:")); + if (ui_Button(I, MakeString("Closed"))) + { + motor_status_packet Motor = {}; + Motor.Pos.FlowerPositions[0] = MotorState_Closed; + Motor.Pos.FlowerPositions[1] = MotorState_Closed; + Motor.Pos.FlowerPositions[2] = MotorState_Closed; + Motor.Temperature = 16; - if (ui_Button(I, MakeString("Send Motor Packet"))) - { - blumen_packet Packet = {}; - Packet.Type = PacketType_MotorState; - Packet.MotorPacket = BLState->DEBUG_PendingMotorPacket; - gs_data Msg = StructToData(&Packet, blumen_packet); - MessageQueue_Write(&BLState->OutgoingMsgQueue, Msg); - - DEBUG_SentMotorCommand(Packet.MotorPacket, Context.ThreadContext); - } + BlumenLumen_UpdateMotorState(BLState, Motor, Context); + } + if (ui_Button(I, MakeString("Open"))) + { + motor_status_packet Motor = {}; + Motor.Pos.FlowerPositions[0] = MotorState_Open; + Motor.Pos.FlowerPositions[1] = MotorState_Open; + Motor.Pos.FlowerPositions[2] = MotorState_Open; + Motor.Temperature = 16; - motor_packet MotorPos = BLState->LastKnownMotorState; - ui_Label(I, MakeString("Current Motor Positions")); + BlumenLumen_UpdateMotorState(BLState, Motor, Context); + } + + if (ui_BeginLabeledDropdown(I, MakeString("Phrase"), MakeString(BLState->PendingPhrase.Phrase))) + { + u32 ListCount = BLState->PhraseHueMap.Count; + ui_BeginList(I, MakeString("Phrase List"), 5, ListCount); + for (u32 i = 0; i < ListCount; i++) { - for (u32 i = 0; i < BL_FLOWER_COUNT; i++) + gs_string Str = MakeString(BLState->PhraseHueMap.Phrases[i]); + if (ui_Button(I, Str)) { - ui_BeginRow(I, 2); - gs_string MotorStr = PushStringF(State->Transient, 32, - "Motor %d", - i); - ui_Label(I, MotorStr); - - gs_string StateStr = {}; - switch (MotorPos.FlowerPositions[i]) - { - case MotorState_Closed: { - StateStr = MakeString("Closed"); - } break; - case MotorState_HalfOpen: { - StateStr = MakeString("Half Open"); - } break; - case MotorState_MostlyOpen: { - StateStr = MakeString("Mostly Open"); - } break; - case MotorState_Open: { - StateStr = MakeString("Open"); - } break; - } - - ui_Label(I, StateStr); - ui_EndRow(I); + BLState->PendingPhrase = PhraseHueMap_Get(BLState->PhraseHueMap, i); } } - - BLState->DEBUG_IgnoreWeatherDimmingLeds = ui_LabeledToggle(I, MakeString("Ignore Weather Dimming Leds"), BLState->DEBUG_IgnoreWeatherDimmingLeds); - - ui_Label(I, MakeString("Set Internal Motor State:")); - if (ui_Button(I, MakeString("Closed"))) - { - motor_status_packet Motor = {}; - Motor.Pos.FlowerPositions[0] = MotorState_Closed; - Motor.Pos.FlowerPositions[1] = MotorState_Closed; - Motor.Pos.FlowerPositions[2] = MotorState_Closed; - Motor.Temperature = 16; - - BlumenLumen_UpdateMotorState(BLState, Motor, Context); - } - if (ui_Button(I, MakeString("Open"))) - { - motor_status_packet Motor = {}; - Motor.Pos.FlowerPositions[0] = MotorState_Open; - Motor.Pos.FlowerPositions[1] = MotorState_Open; - Motor.Pos.FlowerPositions[2] = MotorState_Open; - Motor.Temperature = 16; - - BlumenLumen_UpdateMotorState(BLState, Motor, Context); - } + ui_EndList(I); } + ui_EndLabeledDropdown(I); + if (ui_Button(I, MakeString("Say Phrase"))) + { + gs_string DebugStr = PushString(State->Transient, 256); + BLState->NextHotHue = BLState->PendingPhrase; + BlumenLumen_ApplyNextHotHue(BLState, Context, &DebugStr, State); + } + + InterfaceAssert(I->PerFrameMemory); } US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup) diff --git a/src/app/ss_blumen_lumen/blumen_lumen.h b/src/app/ss_blumen_lumen/blumen_lumen.h index 8b381cf..a22cb40 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.h +++ b/src/app/ss_blumen_lumen/blumen_lumen.h @@ -157,6 +157,8 @@ struct blumen_lumen_state system_time LastSendTime; phrase_hue StandardPatternHues; + r32 AssemblyColorsTransitionTimeLeft[BL_FLOWER_COUNT]; + phrase_hue NextAssemblyColors[BL_FLOWER_COUNT]; phrase_hue AssemblyColors[BL_FLOWER_COUNT]; u32 LastAssemblyColorSet; @@ -188,10 +190,41 @@ struct blumen_lumen_state bool DEBUG_IgnoreWeatherDimmingLeds; bool ShouldUpdateLog; + + phrase_hue PendingPhrase; }; #include "message_queue.cpp" +internal void +BlumenLumen_SetNextHue(blumen_lumen_state* BLState, u32 AssemblyIndex, phrase_hue Hue) +{ +#if 1 + BLState->NextAssemblyColors[AssemblyIndex] = Hue; + BLState->AssemblyColorsTransitionTimeLeft[AssemblyIndex] = PhraseHueFadeInDuration; +#else + BLState->AssemblyColors[AssemblyIndex] = Hue; +#endif +} + +internal void +BlumenLumen_AdvanceHueFade(blumen_lumen_state* BLState, context Context) +{ + for (u32 i = 0; i < BL_FLOWER_COUNT; i++) + { + r32 T = BLState->AssemblyColorsTransitionTimeLeft[i]; + if (T > 0) + { + T -= Context.DeltaTime; + if (T <= 0) + { + BLState->AssemblyColors[i] = BLState->NextAssemblyColors[i]; + } + BLState->AssemblyColorsTransitionTimeLeft[i] = T; + } + } +} + internal phrase_hue BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly) { @@ -206,7 +239,15 @@ BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly) case BlumenPattern_VoiceCommand: { - Result = BLState->AssemblyColors[Assembly.AssemblyIndex % 3]; + u32 i = Assembly.AssemblyIndex % 3; + r32 T = BLState->AssemblyColorsTransitionTimeLeft[i]; + if (T > 0) + { + T = Clamp(T / PhraseHueFadeInDuration, 0, 1); + Result = LerpPhraseHue(T, BLState->NextAssemblyColors[i], BLState->AssemblyColors[i]); + } else { + Result = BLState->AssemblyColors[i]; + } }break; } diff --git a/src/app/ss_blumen_lumen/blumen_lumen_settings.h b/src/app/ss_blumen_lumen/blumen_lumen_settings.h index 46f69b8..b610b2b 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen_settings.h +++ b/src/app/ss_blumen_lumen/blumen_lumen_settings.h @@ -105,6 +105,9 @@ r32 GlobalAnimSpeed = 1.0f; // activated mode r32 GlobalAnimTransitionSpeed = 5.0f; +// how long it takes to fade from the old voice hue to the new one +r32 PhraseHueFadeInDuration = 2.0f; // seconds + r64 PhrasePriorityMessageGroupingTime = 1.0f; // How often should Lumenarium send its status to the python server? diff --git a/src/app/ss_blumen_lumen/gfx_math.h b/src/app/ss_blumen_lumen/gfx_math.h index 8b1acc8..34b667d 100644 --- a/src/app/ss_blumen_lumen/gfx_math.h +++ b/src/app/ss_blumen_lumen/gfx_math.h @@ -281,13 +281,14 @@ Fbm3D(v3 P, r32 T) r32 F = 0.0; F += 0.500000f * Noise3D(Pp + Tt); Pp = Pp * 2.02; - F += 0.031250f * Noise3D(Pp); Pp = Pp * 2.01; - F += 0.250000f * Noise3D(Pp - Tt); Pp = Pp * 2.03; + //F += 0.031250f * Noise3D(Pp); Pp = Pp * 2.01; + F += 0.300000f * Noise3D(Pp - Tt); Pp = Pp * 2.03; F += 0.125000f * Noise3D(Pp); Pp = Pp * 2.01; F += 0.062500f * Noise3D(Pp + Tt); Pp = Pp * 2.04; - F += 0.015625f * Noise3D(Pp + Tv); + //F += 0.015625f * Noise3D(Pp + Tv); + r32 D = 0.9875f; - F = F / 0.984375f; + F = F / D; return F; } diff --git a/src/app/ss_blumen_lumen/phrase_hue_map.h b/src/app/ss_blumen_lumen/phrase_hue_map.h index 34ef475..91256d4 100644 --- a/src/app/ss_blumen_lumen/phrase_hue_map.h +++ b/src/app/ss_blumen_lumen/phrase_hue_map.h @@ -10,6 +10,19 @@ enum p_hue_flag Hue_Black = 2, }; +enum p_hue_pattern +{ + HuePattern_Patchy, + HuePattern_Wavy, +}; + +enum p_hue_add_in +{ + AddIn_None, + AddIn_Waves, + AddIn_Rotary, +}; + typedef struct p_hue { r64 Hue; @@ -25,6 +38,10 @@ typedef struct phrase_hue_map p_hue* Hue0; p_hue* Hue1; p_hue* Hue2; + u32* Gran; // granularity + r32* Speed; + u8* Pattern; + u8* AddIn; } phrase_hue_map; typedef struct phrase_hue @@ -34,8 +51,62 @@ typedef struct phrase_hue p_hue Hue0; p_hue Hue1; p_hue Hue2; + u32 Granularity; + r32 Speed; + u8 Pattern; + u8 AddIn; } phrase_hue; +internal p_hue +LerpPHue(r32 T, p_hue A, p_hue B) +{ + p_hue Result = {}; + + if (Abs(A.Hue - B.Hue) < 180.0f) + { + Result.Hue = LerpR64(T, A.Hue, B.Hue); + } + else + { + Result.Hue = LerpR64(T, A.Hue + 360.0f, B.Hue); + Result.Hue = ModR32(Result.Hue, 360.0f); + } + + if (T < 0.5f) + { + Result.Flags = A.Flags; + } else { + Result.Flags = B.Flags; + } + return Result; +} + +internal phrase_hue +LerpPhraseHue(r32 T, phrase_hue A, phrase_hue B) +{ + phrase_hue Result = {}; + Result.Hue0 = LerpPHue(T, A.Hue0, B.Hue0); + Result.Hue1 = LerpPHue(T, A.Hue1, B.Hue1); + Result.Hue2 = LerpPHue(T, A.Hue2, B.Hue2); + Result.Granularity = (u32)LerpR32(T, (r32)A.Granularity, (r32)B.Granularity); + Result.Speed = LerpR32(T, A.Speed, B.Speed); + + if (T < .5f) { + Result.Phrase = A.Phrase; + Result.PhraseHash = A.PhraseHash; + Result.Pattern = A.Pattern; + Result.AddIn = A.AddIn; + } + else { + Result.Phrase = B.Phrase; + Result.PhraseHash = B.PhraseHash; + Result.Pattern = B.Pattern; + Result.AddIn = B.AddIn; + } + + return Result; +} + internal p_hue CreateHueFromString(gs_const_string Str) { @@ -46,7 +117,13 @@ CreateHueFromString(gs_const_string Str) Result.Flags = Hue_White; } else { Result.Flags = Hue_Value; - Result.Hue = (r64)ParseFloat(Str); + parse_float_result Parsed = ValidateAndParseFloat(Str); + if (!Parsed.Success) + { + OutputDebugString("Failed to Parse CSV Float\n"); + Parsed.Value = 0.0; + } + Result.Hue = Parsed.Value; } return Result; } @@ -73,9 +150,13 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena) Result.CountMax = Sheet.RowCount - 1; // we don't include the header row Result.Phrases = PushArray(Arena, gs_const_string, Result.CountMax); Result.PhraseHashes = PushArray(Arena, u64, Result.CountMax); - Result.Hue0 = PushArray(Arena, p_hue, Result.CountMax); - Result.Hue1 = PushArray(Arena, p_hue, Result.CountMax); - Result.Hue2 = PushArray(Arena, p_hue, Result.CountMax); + Result.Hue0 = PushArray(Arena, p_hue, Result.CountMax); + Result.Hue1 = PushArray(Arena, p_hue, Result.CountMax); + Result.Hue2 = PushArray(Arena, p_hue, Result.CountMax); + Result.Gran = PushArray(Arena, u32, Result.CountMax); + Result.Pattern = PushArray(Arena, u8, Result.CountMax); + Result.Speed = PushArray(Arena, r32, Result.CountMax); + Result.AddIn = PushArray(Arena, u8, Result.CountMax); s32 DestOffset = 0; for (u32 Row = 1; Row < Sheet.RowCount; Row++) @@ -86,10 +167,15 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena) gs_const_string Phrase = CSVSheet_GetCell(Sheet, 0, Row); - gs_const_string Hue0Str = CSVSheet_GetCell(Sheet, 1, Row); - gs_const_string Hue1Str = CSVSheet_GetCell(Sheet, 2, Row); - gs_const_string Hue2Str = CSVSheet_GetCell(Sheet, 3, Row); - gs_const_string Homonyms = CSVSheet_GetCell(Sheet, 4, Row); + gs_const_string Hue0Str = CSVSheet_GetCell(Sheet, 1, Row); + gs_const_string Hue1Str = CSVSheet_GetCell(Sheet, 2, Row); + gs_const_string Hue2Str = CSVSheet_GetCell(Sheet, 3, Row); + gs_const_string Homonyms = CSVSheet_GetCell(Sheet, 4, Row); + gs_const_string Granularity = CSVSheet_GetCell(Sheet, 5, Row); + gs_const_string Speed = CSVSheet_GetCell(Sheet, 6, Row); + gs_const_string Pattern = CSVSheet_GetCell(Sheet, 7, Row); + gs_const_string AddIn = CSVSheet_GetCell(Sheet, 8, Row); + if (Phrase.Length == 0 || Hue0Str.Length == 0 || Hue1Str.Length == 0 || @@ -115,6 +201,36 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena) Result.Hue0[Index] = CreateHueFromString(Hue0Str); Result.Hue1[Index] = CreateHueFromString(Hue1Str); Result.Hue2[Index] = CreateHueFromString(Hue2Str); + + parse_float_result ParsedSpeed = ValidateAndParseFloat(Speed); + if (!ParsedSpeed.Success) + { + ParsedSpeed.Value = 1.0; + } + Result.Speed[Index] = ParsedSpeed.Value; + + if (StringsEqual(Pattern, ConstString("wavy"))) + { + Result.Pattern[Index] = HuePattern_Wavy; + } else { + Result.Pattern[Index] = HuePattern_Patchy; + } + + if (StringsEqual(AddIn, ConstString("waves"))) + { + Result.AddIn[Index] = AddIn_Waves; + } else if (StringsEqual(AddIn, ConstString("rotary"))) { + Result.AddIn[Index] = AddIn_Rotary; + } else { + Result.AddIn[Index] = AddIn_None; + } + + parse_uint_result ParsedGranularity = ValidateAndParseUInt(Granularity); + if (!ParsedGranularity.Success) + { + ParsedGranularity.Value = 1; + } + Result.Gran[Index] = ParsedGranularity.Value; } Result.Count = Result.CountMax + DestOffset; @@ -123,24 +239,34 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena) } internal phrase_hue -PhraseHueMap_Get(phrase_hue_map Map, u64 PhraseHash) +PhraseHueMap_Get(phrase_hue_map Map, u32 Index) +{ + Assert(Index < Map.Count); + phrase_hue Result = {}; + Result.Phrase = Map.Phrases[Index]; + Result.PhraseHash = Map.PhraseHashes[Index]; + Result.Hue0 = Map.Hue0[Index]; + Result.Hue1 = Map.Hue1[Index]; + Result.Hue2 = Map.Hue2[Index]; + Result.Granularity = Map.Gran[Index]; + Result.Speed = Map.Speed[Index]; + Result.AddIn = Map.AddIn[Index]; + Result.Pattern = Map.Pattern[Index]; + return Result; +} + +internal phrase_hue +PhraseHueMap_Find(phrase_hue_map Map, u64 PhraseHash) { phrase_hue Result = {}; - for (u32 i = 0; i < Map.Count; i++) { if (Map.PhraseHashes[i] == PhraseHash) { - Result.Phrase = Map.Phrases[i]; - Result.PhraseHash = Map.PhraseHashes[i]; - Result.Hue0 = Map.Hue0[i]; - Result.Hue1 = Map.Hue1[i]; - Result.Hue2 = Map.Hue2[i]; - + Result = PhraseHueMap_Get(Map, i); break; } } - return Result; } From 0c96f6bd19491725be506fe8b93aea049bfd4b8e Mon Sep 17 00:00:00 2001 From: PS Date: Fri, 9 Apr 2021 00:58:50 -1000 Subject: [PATCH 5/8] Added setting for turning leds off at certain times of day --- .../ambient_patterns/ambient_0.foldanim | 92 ------------------- src/app/ss_blumen_lumen/blumen_lumen.cpp | 19 ++++ .../ss_blumen_lumen/blumen_lumen_settings.h | 14 ++- 3 files changed, 31 insertions(+), 94 deletions(-) delete mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/ambient_0.foldanim diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/ambient_0.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/ambient_0.foldanim deleted file mode 100644 index b965ed5..0000000 --- a/app_run_tree/data/blumen_animations/ambient_patterns/ambient_0.foldanim +++ /dev/null @@ -1,92 +0,0 @@ -lumenarium_animation_file; -animation_name: "ambient_0"; -layers_count: 2; -blocks_count: 9; -playable_range:{ - min: 0; - max: 1000; -}; -layers:{ - layer:{ - name: "Color"; - blend: "Add"; - }; - layer:{ - name: "Mask"; - blend: "Multiply"; - }; -}; -blocks:{ - block:{ - frame_range:{ - min: 88; - max: 315; - }; - layer_index: 0; - animation_name: "Pattern_Rotary"; - }; - block:{ - frame_range:{ - min: 156; - max: 429; - }; - layer_index: 1; - animation_name: "Pattern_LeafyPatchy"; - }; - block:{ - frame_range:{ - min: 403; - max: 675; - }; - layer_index: 1; - animation_name: "Pattern_Patchy"; - }; - block:{ - frame_range:{ - min: 643; - max: 997; - }; - layer_index: 1; - animation_name: "Pattern_LeafyPatchy"; - }; - block:{ - frame_range:{ - min: 253; - max: 571; - }; - layer_index: 0; - animation_name: "Pattern_VerticalLines"; - }; - block:{ - frame_range:{ - min: 522; - max: 772; - }; - layer_index: 0; - animation_name: "Pattern_Rotary"; - }; - block:{ - frame_range:{ - min: 737; - max: 998; - }; - layer_index: 0; - animation_name: "Pattern_VerticalLines"; - }; - block:{ - frame_range:{ - min: 0; - max: 117; - }; - layer_index: 0; - animation_name: "Pattern_VerticalLines"; - }; - block:{ - frame_range:{ - min: 0; - max: 179; - }; - layer_index: 1; - animation_name: "Pattern_StemSolid"; - }; -}; diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index 295a47d..be23b28 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -693,6 +693,25 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } + bool TimelineShouldAdvance = false; + r32 OverrideBrightness = 0.0f; + for (u32 i = 0; i < LedOnTimesCount; i++) + { + time_range Range = LedOnTimes[i]; + bool CurrTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Current, Range); + if (CurrTimeInRange) + { + // If we're in one of the specified time ranges, + // play animations and set brightness + OverrideBrightness = BLState->BrightnessPercent; + TimelineShouldAdvance = State->AnimationSystem.TimelineShouldAdvance; + break; + } + } + State->AnimationSystem.TimelineShouldAdvance = TimelineShouldAdvance; + BLState->BrightnessPercent = OverrideBrightness; + + // Dim the leds based on temp data if (!BLState->DEBUG_IgnoreWeatherDimmingLeds) { diff --git a/src/app/ss_blumen_lumen/blumen_lumen_settings.h b/src/app/ss_blumen_lumen/blumen_lumen_settings.h index b610b2b..129a54f 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen_settings.h +++ b/src/app/ss_blumen_lumen/blumen_lumen_settings.h @@ -27,17 +27,27 @@ gs_const_string AmbientPatternFolder = ConstString("data/blumen_animations/ambie gs_const_string VoicePatternFolder = ConstString("data/blumen_animations/audio_responses/*.foldanim"); // The times of day when the motors should be open. +// +// @TimeFormat: documentation follows // these are in the format { Start_Hour, Start_Minute, End_Hour, End_Minute } // Hours are in the range 0-23 inclusive // Minutes are in the range 0-59 inclusive +// // NOTE: There is no need to modify the MotorOpenTimesCount variable - // it is a compile time constant that gets calculated automatically global time_range MotorOpenTimes[] = { - { 12, 45, 17, 45 }, - { 19, 00, 23, 00 }, + { 12, 45, 17, 45 }, // 12:45pm to 5:45pm + { 19, 00, 23, 00 }, // 7:00pm to 11:00pm }; global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit +// The times of day when the leds should be on +// Search for @TimeFormat to find documentation +global time_range LedOnTimes[] = { + { 00, 00, 23, 59 }, // literally always +}; +global u32 LedOnTimesCount = CArrayLength(LedOnTimes); // do not edit + // How long it takes to fade from the default pattern to the // voice activated pattern r32 VoiceCommandFadeDuration = 1.0f; // in seconds From ee1163be952718eec06166ccf500b2708dcda8fe Mon Sep 17 00:00:00 2001 From: PS Date: Fri, 9 Apr 2021 01:00:00 -1000 Subject: [PATCH 6/8] Ambient Patterns --- .../ambient_patterns/fishy_0.foldanim | 48 +++++++++++++++++++ .../patchy_loading_bar.foldanim | 36 ++++++++++++++ .../ambient_patterns/primary_hue_0.foldanim | 28 +++++++++++ .../ambient_patterns/rainbow_0.foldanim | 28 +++++++++++ .../rainbow_loading_bar.foldanim | 28 +++++++++++ .../ambient_patterns/wavy_0.foldanim | 28 +++++++++++ 6 files changed, 196 insertions(+) create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/fishy_0.foldanim create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/patchy_loading_bar.foldanim create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/primary_hue_0.foldanim create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/rainbow_0.foldanim create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/rainbow_loading_bar.foldanim create mode 100644 app_run_tree/data/blumen_animations/ambient_patterns/wavy_0.foldanim diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/fishy_0.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/fishy_0.foldanim new file mode 100644 index 0000000..7119bbc --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/fishy_0.foldanim @@ -0,0 +1,48 @@ +lumenarium_animation_file; +animation_name: "fishy_0"; +layers_count: 3; +blocks_count: 3; +playable_range:{ + min: 0; + max: 3600; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "Color"; + blend: "Multiply"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 2; + animation_name: "Pattern_HueShift"; + }; + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 1; + animation_name: "Pattern_StemSolid"; + }; + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 0; + animation_name: "Pattern_Rotary"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/patchy_loading_bar.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/patchy_loading_bar.foldanim new file mode 100644 index 0000000..1fe290a --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/patchy_loading_bar.foldanim @@ -0,0 +1,36 @@ +lumenarium_animation_file; +animation_name: "patchy_loading_bar_0"; +layers_count: 2; +blocks_count: 2; +playable_range:{ + min: 0; + max: 3350; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Multiply"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 1; + animation_name: "Pattern_Patchy"; + }; + block:{ + frame_range:{ + min: 0; + max: 3600; + }; + layer_index: 0; + animation_name: "Pattern_GrowFadeMask"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/primary_hue_0.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/primary_hue_0.foldanim new file mode 100644 index 0000000..66670b8 --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/primary_hue_0.foldanim @@ -0,0 +1,28 @@ +lumenarium_animation_file; +animation_name: "primary_hue_0"; +layers_count: 2; +blocks_count: 1; +playable_range:{ + min: 0; + max: 360; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 36000; + }; + layer_index: 1; + animation_name: "Pattern_PrimaryHue"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_0.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_0.foldanim new file mode 100644 index 0000000..ab6f4e3 --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_0.foldanim @@ -0,0 +1,28 @@ +lumenarium_animation_file; +animation_name: "rainbow"; +layers_count: 2; +blocks_count: 1; +playable_range:{ + min: 0; + max: 360; +}; +layers:{ + layer:{ + name: "Mask"; + blend: "Add"; + }; + layer:{ + name: "Color"; + blend: "Add"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 360; + }; + layer_index: 1; + animation_name: "Pattern_Rainbow"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_loading_bar.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_loading_bar.foldanim new file mode 100644 index 0000000..6f6f0c6 --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/rainbow_loading_bar.foldanim @@ -0,0 +1,28 @@ +lumenarium_animation_file; +animation_name: "rainbow_loading_bar_0"; +layers_count: 2; +blocks_count: 1; +playable_range:{ + min: 0; + max: 9000; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 9000; + }; + layer_index: 1; + animation_name: "Pattern_RainbowLoadingBar"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/ambient_patterns/wavy_0.foldanim b/app_run_tree/data/blumen_animations/ambient_patterns/wavy_0.foldanim new file mode 100644 index 0000000..2ed33bc --- /dev/null +++ b/app_run_tree/data/blumen_animations/ambient_patterns/wavy_0.foldanim @@ -0,0 +1,28 @@ +lumenarium_animation_file; +animation_name: "wavy_0"; +layers_count: 2; +blocks_count: 1; +playable_range:{ + min: 0; + max: 7200; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "Color"; + blend: "Add"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 0; + max: 7200; + }; + layer_index: 1; + animation_name: "Pattern_Wavy"; + }; +}; From 7e1e22ed5a402b7cae86206ceadb81d748d23c16 Mon Sep 17 00:00:00 2001 From: PS Date: Fri, 9 Apr 2021 01:48:29 -1000 Subject: [PATCH 7/8] Created a panel for the Awaken sequence --- src/app/patterns/blumen_patterns.h | 6 + src/app/ss_blumen_lumen/blumen_lumen.cpp | 357 ++++++++++++++--------- src/app/ss_blumen_lumen/blumen_lumen.h | 22 ++ 3 files changed, 255 insertions(+), 130 deletions(-) diff --git a/src/app/patterns/blumen_patterns.h b/src/app/patterns/blumen_patterns.h index 732192c..534d78e 100644 --- a/src/app/patterns/blumen_patterns.h +++ b/src/app/patterns/blumen_patterns.h @@ -7,6 +7,12 @@ #define FLOWER_COLORS_COUNT 12 +internal void +Pattern_None(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) +{ + // just here so you can fade in from black +} + internal void Pattern_AltBloomMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) { diff --git a/src/app/ss_blumen_lumen/blumen_lumen.cpp b/src/app/ss_blumen_lumen/blumen_lumen.cpp index be23b28..ab31797 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.cpp +++ b/src/app/ss_blumen_lumen/blumen_lumen.cpp @@ -201,6 +201,7 @@ BlumenLumen_LoadPatterns(app_state* State) } Patterns->Count = 0; + Patterns_PushPattern(Patterns, Pattern_None, PATTERN_SINGLETHREADED); Patterns_PushPattern(Patterns, Pattern_HueShift, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_Rainbow, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_BasicFlowers, PATTERN_MULTITHREADED); @@ -307,6 +308,7 @@ BlumenLumen_UpdateLog(app_state* State, blumen_lumen_state* BLState, context Con { case BlumenPattern_Standard: { PatternMode = "Standard"; } break; case BlumenPattern_VoiceCommand: { PatternMode = "Voice Command"; } break; + case BlumenPattern_NoControl: { PatternMode = "No Control: Someone's doing the Awaken sequence!"; } break; } AppendPrintF(&FileStr, "Pattern Mode: %s\n", PatternMode); @@ -394,6 +396,15 @@ BlumenLumen_CustomInit(app_state* State, context Context) AnimationSystem_LoadAnimationFromFile(&State->AnimationSystem, State->Patterns, Context, ConstString("data/blumen_animations/anim_demo.foldanim")); BlumenLumen_SetPatternMode(BlumenPattern_Standard, GlobalAnimTransitionSpeed, &State->AnimationSystem, BLState); + + BLState->AwakenHandle = AnimationSystem_LoadAnimationFromFile(&State->AnimationSystem, + State->Patterns, + Context, + ConstString("data/blumen_animations/awaken.foldanim")); + BLState->OffAnimHandle = AnimationSystem_LoadAnimationFromFile(&State->AnimationSystem, + State->Patterns, + Context, + ConstString("data/blumen_animations/off_anim.foldanim")); #endif State->AnimationSystem.TimelineShouldAdvance = true; @@ -587,7 +598,8 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } // Open / Close the Motor - if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue)) + if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue) && + !BLState->IgnoreTimeOfDay_MotorState) { for (u32 i = 0; i < MotorOpenTimesCount; i++) { @@ -693,24 +705,26 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) } } - bool TimelineShouldAdvance = false; - r32 OverrideBrightness = 0.0f; - for (u32 i = 0; i < LedOnTimesCount; i++) + if (!BLState->IgnoreTimeOfDay_LedDimming) { - time_range Range = LedOnTimes[i]; - bool CurrTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Current, Range); - if (CurrTimeInRange) + bool TimelineShouldAdvance = false; + r32 OverrideBrightness = 0.0f; + for (u32 i = 0; i < LedOnTimesCount; i++) { - // If we're in one of the specified time ranges, - // play animations and set brightness - OverrideBrightness = BLState->BrightnessPercent; - TimelineShouldAdvance = State->AnimationSystem.TimelineShouldAdvance; - break; + time_range Range = LedOnTimes[i]; + bool CurrTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Current, Range); + if (CurrTimeInRange) + { + // If we're in one of the specified time ranges, + // play animations and set brightness + OverrideBrightness = BLState->BrightnessPercent; + TimelineShouldAdvance = State->AnimationSystem.TimelineShouldAdvance; + break; + } } + State->AnimationSystem.TimelineShouldAdvance = TimelineShouldAdvance; + BLState->BrightnessPercent = OverrideBrightness; } - State->AnimationSystem.TimelineShouldAdvance = TimelineShouldAdvance; - BLState->BrightnessPercent = OverrideBrightness; - // Dim the leds based on temp data if (!BLState->DEBUG_IgnoreWeatherDimmingLeds) @@ -769,131 +783,214 @@ US_CUSTOM_DEBUG_UI(BlumenLumen_DebugUI) blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; ui_interface* I = &State->Interface; - motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket; - - for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++) + ui_BeginRow(I, BlumenDebug_Count); + for (u32 i = 0; i < BlumenDebug_Count; i++) { - gs_string Label = PushStringF(State->Transient, 32, "Motor %d", MotorIndex); - ui_BeginRow(I, 5); + if (ui_Button(I, MakeString(BlDebugUiModeStrings[i]))) { - ui_Label(I, Label); - - bool IsClosed = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Closed; - if (ui_ToggleText(I, MakeString("Closed (1)"), IsClosed)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_Closed; - } - bool IsHOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_HalfOpen; - if (ui_ToggleText(I, MakeString("Half Open (3)"), IsHOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_HalfOpen; - } - bool IsMOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_MostlyOpen; - if (ui_ToggleText(I, MakeString("Mostly Open (4)"), IsMOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_MostlyOpen; - } - bool IsOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Open; - if (ui_ToggleText(I, MakeString("Open (2)"), IsOpen)) - { - PendingPacket.FlowerPositions[MotorIndex] = MotorState_Open; - } - } - ui_EndRow(I); - } - BLState->DEBUG_PendingMotorPacket = PendingPacket; - - if (ui_Button(I, MakeString("Send Motor Packet"))) - { - blumen_packet Packet = {}; - Packet.Type = PacketType_MotorState; - Packet.MotorPacket = BLState->DEBUG_PendingMotorPacket; - gs_data Msg = StructToData(&Packet, blumen_packet); - MessageQueue_Write(&BLState->OutgoingMsgQueue, Msg); - - DEBUG_SentMotorCommand(Packet.MotorPacket, Context.ThreadContext); - } - - motor_packet MotorPos = BLState->LastKnownMotorState; - ui_Label(I, MakeString("Current Motor Positions")); - { - for (u32 i = 0; i < BL_FLOWER_COUNT; i++) - { - ui_BeginRow(I, 2); - gs_string MotorStr = PushStringF(State->Transient, 32, - "Motor %d", - i); - ui_Label(I, MotorStr); - - gs_string StateStr = {}; - switch (MotorPos.FlowerPositions[i]) - { - case MotorState_Closed: { - StateStr = MakeString("Closed"); - } break; - case MotorState_HalfOpen: { - StateStr = MakeString("Half Open"); - } break; - case MotorState_MostlyOpen: { - StateStr = MakeString("Mostly Open"); - } break; - case MotorState_Open: { - StateStr = MakeString("Open"); - } break; - } - - ui_Label(I, StateStr); - ui_EndRow(I); + BLState->DebugMode = (bl_debug_ui_mode)i; } } + ui_EndRow(I); - BLState->DEBUG_IgnoreWeatherDimmingLeds = ui_LabeledToggle(I, MakeString("Ignore Weather Dimming Leds"), BLState->DEBUG_IgnoreWeatherDimmingLeds); - - ui_Label(I, MakeString("Set Internal Motor State:")); - if (ui_Button(I, MakeString("Closed"))) + switch (BLState->DebugMode) { - motor_status_packet Motor = {}; - Motor.Pos.FlowerPositions[0] = MotorState_Closed; - Motor.Pos.FlowerPositions[1] = MotorState_Closed; - Motor.Pos.FlowerPositions[2] = MotorState_Closed; - Motor.Temperature = 16; - - BlumenLumen_UpdateMotorState(BLState, Motor, Context); - } - if (ui_Button(I, MakeString("Open"))) - { - motor_status_packet Motor = {}; - Motor.Pos.FlowerPositions[0] = MotorState_Open; - Motor.Pos.FlowerPositions[1] = MotorState_Open; - Motor.Pos.FlowerPositions[2] = MotorState_Open; - Motor.Temperature = 16; - - BlumenLumen_UpdateMotorState(BLState, Motor, Context); - } - - if (ui_BeginLabeledDropdown(I, MakeString("Phrase"), MakeString(BLState->PendingPhrase.Phrase))) - { - u32 ListCount = BLState->PhraseHueMap.Count; - ui_BeginList(I, MakeString("Phrase List"), 5, ListCount); - for (u32 i = 0; i < ListCount; i++) + case BlumenDebug_Motors: { - gs_string Str = MakeString(BLState->PhraseHueMap.Phrases[i]); - if (ui_Button(I, Str)) + motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket; + + BLState->IgnoreTimeOfDay_MotorState = ui_ToggleText(I, MakeString("Motors Ignore Time Limit"), BLState->IgnoreTimeOfDay_MotorState); + + for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++) { - BLState->PendingPhrase = PhraseHueMap_Get(BLState->PhraseHueMap, i); + gs_string Label = PushStringF(State->Transient, 32, "Motor %d", MotorIndex); + ui_BeginRow(I, 5); + { + ui_Label(I, Label); + + bool IsClosed = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Closed; + if (ui_ToggleText(I, MakeString("Closed (1)"), IsClosed)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_Closed; + } + bool IsHOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_HalfOpen; + if (ui_ToggleText(I, MakeString("Half Open (3)"), IsHOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_HalfOpen; + } + bool IsMOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_MostlyOpen; + if (ui_ToggleText(I, MakeString("Mostly Open (4)"), IsMOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_MostlyOpen; + } + bool IsOpen = PendingPacket.FlowerPositions[MotorIndex] == MotorState_Open; + if (ui_ToggleText(I, MakeString("Open (2)"), IsOpen)) + { + PendingPacket.FlowerPositions[MotorIndex] = MotorState_Open; + } + } + ui_EndRow(I); } - } - ui_EndList(I); + BLState->DEBUG_PendingMotorPacket = PendingPacket; + + if (ui_Button(I, MakeString("Send Motor Packet"))) + { + blumen_packet Packet = {}; + Packet.Type = PacketType_MotorState; + Packet.MotorPacket = BLState->DEBUG_PendingMotorPacket; + gs_data Msg = StructToData(&Packet, blumen_packet); + MessageQueue_Write(&BLState->OutgoingMsgQueue, Msg); + DEBUG_SentMotorCommand(Packet.MotorPacket, Context.ThreadContext); + + } + + motor_packet MotorPos = BLState->LastKnownMotorState; + ui_Label(I, MakeString("Current Motor Positions")); + { + for (u32 i = 0; i < BL_FLOWER_COUNT; i++) + { + ui_BeginRow(I, 2); + gs_string MotorStr = PushStringF(State->Transient, 32, + "Motor %d", + i); + ui_Label(I, MotorStr); + + gs_string StateStr = {}; + switch (MotorPos.FlowerPositions[i]) + { + case MotorState_Closed: { + StateStr = MakeString("Closed"); + } break; + case MotorState_HalfOpen: { + StateStr = MakeString("Half Open"); + } break; + case MotorState_MostlyOpen: { + StateStr = MakeString("Mostly Open"); + } break; + case MotorState_Open: { + StateStr = MakeString("Open"); + } break; + } + + ui_Label(I, StateStr); + ui_EndRow(I); + } + } + + ui_Label(I, MakeString("Set Internal Motor State:")); + if (ui_Button(I, MakeString("Closed"))) + { + motor_status_packet Motor = {}; + Motor.Pos.FlowerPositions[0] = MotorState_Closed; + Motor.Pos.FlowerPositions[1] = MotorState_Closed; + Motor.Pos.FlowerPositions[2] = MotorState_Closed; + Motor.Temperature = 16; + + BlumenLumen_UpdateMotorState(BLState, Motor, Context); + } + if (ui_Button(I, MakeString("Open"))) + { + motor_status_packet Motor = {}; + Motor.Pos.FlowerPositions[0] = MotorState_Open; + Motor.Pos.FlowerPositions[1] = MotorState_Open; + Motor.Pos.FlowerPositions[2] = MotorState_Open; + Motor.Temperature = 16; + + BlumenLumen_UpdateMotorState(BLState, Motor, Context); + } + } break; + + case BlumenDebug_Leds: + { + BLState->DEBUG_IgnoreWeatherDimmingLeds = ui_LabeledToggle(I, MakeString("Ignore Weather Dimming Leds"), BLState->DEBUG_IgnoreWeatherDimmingLeds); + + BLState->IgnoreTimeOfDay_LedDimming = ui_ToggleText(I, MakeString("Leds Ignore Time Limit"), BLState->IgnoreTimeOfDay_LedDimming); + + if (ui_BeginLabeledDropdown(I, MakeString("Phrase"), MakeString(BLState->PendingPhrase.Phrase))) + { + u32 ListCount = BLState->PhraseHueMap.Count; + ui_BeginList(I, MakeString("Phrase List"), 5, ListCount); + for (u32 i = 0; i < ListCount; i++) + { + gs_string Str = MakeString(BLState->PhraseHueMap.Phrases[i]); + if (ui_Button(I, Str)) + { + BLState->PendingPhrase = PhraseHueMap_Get(BLState->PhraseHueMap, i); + } + } + ui_EndList(I); + } + ui_EndLabeledDropdown(I); + if (ui_Button(I, MakeString("Say Phrase"))) + { + gs_string DebugStr = PushString(State->Transient, 256); + BLState->NextHotHue = BLState->PendingPhrase; + BlumenLumen_ApplyNextHotHue(BLState, Context, &DebugStr, State); + } + + InterfaceAssert(I->PerFrameMemory); + }break; + + case BlumenDebug_Awaken: + { + ui_Label(I, MakeString("Step 1:")); + ui_Label(I, MakeString("Leds off, flowers closed")); + if (ui_Button(I, MakeString("Prepare"))) + { + // motors closed + blumen_packet M = {}; + M.Type = PacketType_MotorState; + M.MotorPacket.FlowerPositions[0] = MotorState_Closed; + M.MotorPacket.FlowerPositions[1] = MotorState_Closed; + M.MotorPacket.FlowerPositions[2] = MotorState_Closed; + gs_data D = StructToData(&M, blumen_packet); + MessageQueue_Write(&BLState->OutgoingMsgQueue, D); + + // animation + State->AnimationSystem.RepeatMode = AnimationRepeat_Single; + AnimationFadeGroup_FadeTo(&State->AnimationSystem.ActiveFadeGroup, + BLState->OffAnimHandle, + VoiceCommandFadeDuration); + + BLState->PatternMode = BlumenPattern_NoControl; + BLState->IgnoreTimeOfDay_LedDimming = true; + BLState->IgnoreTimeOfDay_MotorState = true; + } + + ui_Label(I, MakeString("Step 2:")); + if (ui_Button(I, MakeString("Begin Light Show"))) + { + AnimationFadeGroup_FadeTo(&State->AnimationSystem.ActiveFadeGroup, + BLState->AwakenHandle, + VoiceCommandFadeDuration); + } + + ui_Label(I, MakeString("Step 3:")); + if (ui_Button(I, MakeString("Open Flowers"))) + { + // motors closed + blumen_packet M = {}; + M.Type = PacketType_MotorState; + M.MotorPacket.FlowerPositions[0] = MotorState_Open; + M.MotorPacket.FlowerPositions[1] = MotorState_Open; + M.MotorPacket.FlowerPositions[2] = MotorState_Open; + gs_data D = StructToData(&M, blumen_packet); + MessageQueue_Write(&BLState->OutgoingMsgQueue, D); + } + + ui_Label(I, MakeString("Step 4:")); + ui_Label(I, MakeString("Resets Lumenarium")); + if (ui_Button(I, MakeString("Complete"))) + { + BLState->IgnoreTimeOfDay_LedDimming = false; + BLState->IgnoreTimeOfDay_MotorState = false; + BlumenLumen_SetPatternMode(BlumenPattern_Standard, GlobalAnimTransitionSpeed, &State->AnimationSystem, + BLState); + } + }break; + + InvalidDefaultCase; } - ui_EndLabeledDropdown(I); - if (ui_Button(I, MakeString("Say Phrase"))) - { - gs_string DebugStr = PushString(State->Transient, 256); - BLState->NextHotHue = BLState->PendingPhrase; - BlumenLumen_ApplyNextHotHue(BLState, Context, &DebugStr, State); - } - - InterfaceAssert(I->PerFrameMemory); } US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup) diff --git a/src/app/ss_blumen_lumen/blumen_lumen.h b/src/app/ss_blumen_lumen/blumen_lumen.h index a22cb40..eb266eb 100644 --- a/src/app/ss_blumen_lumen/blumen_lumen.h +++ b/src/app/ss_blumen_lumen/blumen_lumen.h @@ -7,10 +7,26 @@ #include "message_queue.h" +enum bl_debug_ui_mode +{ + BlumenDebug_Motors, + BlumenDebug_Leds, + BlumenDebug_Awaken, + + BlumenDebug_Count, +}; + +char* BlDebugUiModeStrings[] = { + "Motors", + "Leds", + "Awaken", +}; + enum bl_pattern_mode { BlumenPattern_Standard, BlumenPattern_VoiceCommand, + BlumenPattern_NoControl, BlumenPattern_Count, }; @@ -172,6 +188,8 @@ struct blumen_lumen_state bl_pattern_mode PatternMode; animation_handle_array ModeAnimations[BlumenPattern_Count]; + animation_handle OffAnimHandle; + animation_handle AwakenHandle; phrase_hue_map PhraseHueMap; @@ -186,10 +204,14 @@ struct blumen_lumen_state r32 PatternSpeed; // Debug + bl_debug_ui_mode DebugMode; + motor_packet DEBUG_PendingMotorPacket; bool DEBUG_IgnoreWeatherDimmingLeds; bool ShouldUpdateLog; + bool IgnoreTimeOfDay_LedDimming; + bool IgnoreTimeOfDay_MotorState; phrase_hue PendingPhrase; }; From 6cb0749f2ca7690907d15e9372e75e5a5a90bbfa Mon Sep 17 00:00:00 2001 From: PS Date: Fri, 9 Apr 2021 01:52:14 -1000 Subject: [PATCH 8/8] awaken and off_anim --- .../data/blumen_animations/awaken.foldanim | 64 +++++++++++++++++++ .../data/blumen_animations/off_anim.foldanim | 12 ++++ 2 files changed, 76 insertions(+) create mode 100644 app_run_tree/data/blumen_animations/awaken.foldanim create mode 100644 app_run_tree/data/blumen_animations/off_anim.foldanim diff --git a/app_run_tree/data/blumen_animations/awaken.foldanim b/app_run_tree/data/blumen_animations/awaken.foldanim new file mode 100644 index 0000000..efd7194 --- /dev/null +++ b/app_run_tree/data/blumen_animations/awaken.foldanim @@ -0,0 +1,64 @@ +lumenarium_animation_file; +animation_name: "awaken"; +layers_count: 3; +blocks_count: 5; +playable_range:{ + min: 0; + max: 7200; +}; +layers:{ + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Add"; + }; + layer:{ + name: "[New Layer]"; + blend: "Multiply"; + }; +}; +blocks:{ + block:{ + frame_range:{ + min: 94; + max: 1363; + }; + layer_index: 0; + animation_name: "Pattern_Leafy"; + }; + block:{ + frame_range:{ + min: 1169; + max: 7200; + }; + layer_index: 0; + animation_name: "Pattern_BulbMask"; + }; + block:{ + frame_range:{ + min: 71; + max: 7200; + }; + layer_index: 2; + animation_name: "Pattern_Wavy"; + }; + block:{ + frame_range:{ + min: 2135; + max: 2555; + }; + layer_index: 1; + animation_name: "Pattern_None"; + }; + block:{ + frame_range:{ + min: 2470; + max: 7200; + }; + layer_index: 1; + animation_name: "Pattern_StemSolid"; + }; +}; diff --git a/app_run_tree/data/blumen_animations/off_anim.foldanim b/app_run_tree/data/blumen_animations/off_anim.foldanim new file mode 100644 index 0000000..d7a3d45 --- /dev/null +++ b/app_run_tree/data/blumen_animations/off_anim.foldanim @@ -0,0 +1,12 @@ +lumenarium_animation_file; +animation_name: "off_anim"; +layers_count: 0; +blocks_count: 0; +playable_range:{ + min: 0; + max: 2; +}; +layers:{ +}; +blocks:{ +};