Lots of pattern work, plus color fading

This commit is contained in:
PS 2021-04-09 00:42:04 -10:00
parent 7ff47ad445
commit 7a103dae42
9 changed files with 528 additions and 205 deletions

View File

@ -35,7 +35,7 @@ blocks:{
max: 2000; max: 2000;
}; };
layer_index: 1; layer_index: 1;
animation_name: "Pattern_VerticalLines"; animation_name: "Pattern_Leafy";
}; };
block:{ block:{
frame_range:{ frame_range:{

View File

@ -1,16 +1,20 @@
lumenarium_animation_file; lumenarium_animation_file;
animation_name: "voice_anim"; animation_name: "voice_anim";
layers_count: 1; layers_count: 2;
blocks_count: 1; blocks_count: 2;
playable_range:{ playable_range:{
min: 0; min: 0;
max: 3600; max: 3600;
}; };
layers:{ layers:{
layer:{ layer:{
name: "[New Layer]"; name: "Base";
blend: "Add"; blend: "Add";
}; };
layer:{
name: "Add In";
blend: "Overwrite";
};
}; };
blocks:{ blocks:{
block:{ block:{
@ -19,6 +23,14 @@ blocks:{
max: 3599; max: 3599;
}; };
layer_index: 0; 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";
}; };
}; };

View File

@ -8,7 +8,14 @@
internal pixel internal pixel
LedBlend_Overwrite(pixel PixelA, pixel PixelB, u8* UserData) 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 internal pixel

View File

@ -171,17 +171,8 @@ Pattern_BasicFlowers(led_buffer* Leds, led_buffer_range Range, assembly Assembly
} }
internal void 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 Top = 120 + (SinR32(Time) * 10);
r32 Mid = 70 + (CosR32(Time * 2.13) * 20); r32 Mid = 70 + (CosR32(Time * 2.13) * 20);
r32 Bot = 0; r32 Bot = 0;
@ -233,7 +224,7 @@ Pattern_Wavy(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Ti
} }
internal void 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; DEBUG_TRACK_FUNCTION;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData; 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 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2); 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++) for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{ {
v4 P = Leds->Positions[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; r32 ScaleFactor = 1.0f / LedRange;
v3 Pp = P.xyz + v3{150, 100, 0}; 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 = PowR32(NoiseA, 3);
NoiseA = Smoothstep(NoiseA); 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 = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB); NoiseB = Smoothstep(NoiseB);
v4 CB = C1 * NoiseB;
v4 C = (C0 * NoiseA) + (C1 * NoiseB); #if 1
C /= (NoiseA + NoiseB); 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); 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 internal r32
Leafy_BandSDF(v3 P, gs_random_series* Random, r32 Time) 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 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; DEBUG_TRACK_FUNCTION;
Time = Time * BLState->PatternSpeed;
gs_random_series Random = InitRandomSeries(24601); gs_random_series Random = InitRandomSeries((u32)(24601 * (Assembly.Center.x + 1.032f)));
#define SphereCount 32 #define SphereCount 32
v3 SphereCenter[SphereCount]; v3 SphereCenter[SphereCount];
r32 MaxHeightOffset = 150; r32 G = RemapR32(Granularity, 1, 5, .75f, 2);
r32 MaxHeightOffset = 250;
r32 MaxSpeed = 10; r32 MaxSpeed = 10;
r32 SphereRadius = 2.0f; r32 SphereRotationRadius = 3.0f;
r32 SphereRadius = 2.0f / G;
for (u32 i = 0; i < SphereCount; i++) for (u32 i = 0; i < SphereCount; i++)
{ {
r32 SphereSeedA = NextRandomBilateral(&Random); r32 SphereSeedA = NextRandomUnilateral(&Random);
SphereSeedA = PowR32(SphereSeedA, 2);
r32 SphereSeedB = NextRandomBilateral(&Random); r32 SphereSeedB = NextRandomBilateral(&Random);
r32 SphereSpeed = NextRandomUnilateral(&Random) * MaxSpeed; r32 SphereSpeed = NextRandomUnilateral(&Random) * MaxSpeed;
r32 SphereTime = Time + SphereSpeed; r32 SphereTime = Time + SphereSpeed;
r32 HeightOffset = SphereTime + (SphereSeedA * MaxHeightOffset); r32 HeightOffset = 150 - (SphereSeedA * MaxHeightOffset);
r32 RotationOffset = SphereTime + SphereSeedB * TauR32; r32 RotationOffset = SphereTime + SphereSeedB * TauR32;
r32 SphereRotationDir = NextRandomBilateral(&Random) < 0 ? -1 : 1; r32 SphereRotationDir = NextRandomBilateral(&Random) < 0 ? -1 : 1;
v3 SpherePosOffset = v3{ v3 SpherePosOffset = v3{
SinR32(RotationOffset * SphereRotationDir) * (SphereRadius * 2), SinR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2),
HeightOffset, HeightOffset,
CosR32(RotationOffset * SphereRotationDir) * (SphereRadius * 2) CosR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2)
}; };
SphereCenter[i] = Assembly.Center + SpherePosOffset; 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); Dist = Min(Dist, SphereSDF);
} }
v4 C = BlackV4; v4 C = BGColor;
if (Dist <= 1) if (Dist <= 1)
{ {
r32 Brightness = Clamp01(SphereRadius - Dist); r32 Brightness = Clamp01(SphereRadius - Dist);
C = WhiteV4 * Brightness; C = V4Lerp(Brightness, BGColor, FGColor);
} }
Leds->Colors[LedIndex] = V4ToRGBPixel(C); 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 internal void
Pattern_AllOnMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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 internal void
Pattern_BulbMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed; Time = Time * BLState->PatternSpeed;
@ -571,26 +607,47 @@ GenVerticalLeaves(v3 P, r32 Time, v4 C0, v4 C1, v4 C2)
return R; return R;
} }
internal r32 internal void
GenLiquidBands(v3 P, r32 Offset, r32 Time) 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; DEBUG_TRACK_FUNCTION;
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); 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; r32 S = Fbm3D(P0 * .005f, Time) * 250;
S += ModR32((Time * 100) - (150 * i), 400); S += ModR32((Time * 100) - (150 * i), 400);
r32 Y = (P.y - Offset);
r32 V = (Width - Abs(Y - S)) / Width; r32 V = (Width - Abs(Y - S)) / Width;
V = Clamp01(V); V = Clamp01(V);
VAcc += V; Bands += V;
} }
return VAcc; C = V4Lerp(Bands, C * .5f, C2P);
Leds->Colors[LedIndex] = pixel{(u8)C.r, (u8)C.g, (u8)C.b};
}
} }
internal r32 internal r32
@ -618,33 +675,69 @@ GenDotBands(v3 P, r32 Time)
internal void internal void
Pattern_VoicePattern(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; DEBUG_TRACK_FUNCTION;
Time = Time * BLState->PatternSpeed;
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly); phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0); v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1); v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2); 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 = {}; default:
C += GenPatchyColor(P, Time, C0, C2, {}); {
//C = GenVerticalLeaves((P - Assembly.Center) + v3{0, 150, 0}, Time, C0, C1, C2); Pattern_PatchyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2);
//r32 Bands = GenLiquidBands(P, -250, Time); }break;
//C = V4Lerp(Bands, C * .5f, C1); }
//C = WhiteV4 * GenDotBands(P - Assembly.Center, Time);
Leds->Colors[LedIndex] = V4ToRGBPixel(C); }
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;
case AddIn_Waves:
{
AddIn_WavesPattern(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2);
}break;
case AddIn_None:
default:
{
}break;
} }
} }
internal void internal void
Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
pixel WhiteMask = V4ToRGBPixel(WhiteV4); pixel WhiteMask = V4ToRGBPixel(WhiteV4);
@ -665,6 +758,8 @@ Pattern_StemSolid(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r
internal void internal void
Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed; Time = Time * BLState->PatternSpeed;
@ -683,6 +778,8 @@ Pattern_PrimaryHue(led_buffer* Leds, led_buffer_range Range, assembly Assembly,
internal void internal void
Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed; Time = Time * BLState->PatternSpeed;
@ -718,6 +815,8 @@ Pattern_GrowFadeMask(led_buffer* Leds, led_buffer_range Range, assembly Assembly
internal void internal void
Pattern_RainbowLoadingBar(led_buffer* Leds, led_buffer_range Range, assembly Assembly, r32 Time, gs_memory_arena* Transient, u8* UserData) 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; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed; Time = Time * BLState->PatternSpeed;

View File

@ -214,6 +214,7 @@ BlumenLumen_LoadPatterns(app_state* State)
Patterns_PushPattern(Patterns, Pattern_AllOnMask, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_AllOnMask, PATTERN_MULTITHREADED);
Patterns_PushPattern(Patterns, Pattern_BulbMask, PATTERN_MULTITHREADED); Patterns_PushPattern(Patterns, Pattern_BulbMask, PATTERN_MULTITHREADED);
Patterns_PushPattern(Patterns, Pattern_VoicePattern, 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_StemSolid, PATTERN_MULTITHREADED);
Patterns_PushPattern(Patterns, Pattern_PrimaryHue, 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.Hue0.Flags = Hue_Value;
BLState->StandardPatternHues.Hue1.Flags = Hue_Value; BLState->StandardPatternHues.Hue1.Flags = Hue_Value;
BLState->StandardPatternHues.Hue2.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); BlumenLumen_AppendBootupLog(State, BLState, Context);
return Result; return Result;
@ -423,6 +428,38 @@ BlumenLumen_UpdateMotorState(blumen_lumen_state* BLState, motor_status_packet Mo
BLState->ShouldUpdateLog = true; 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 internal void
BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context) 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); u64 NameHash = HashDJB2ToU32(Mic.AnimationFileName);
u32 NameLen = CStringLength(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) if (NewHue.Phrase.Length > 0)
{ {
bool IsLonger = (BLState->NextHotHue.Phrase.Length < NewHue.Phrase.Length); 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); r32 SecondsSincePhraseBegan = SecondsElapsed(BLState->TimePhraseReceptionBegan, Context->SystemTime_Current);
if (SecondsSincePhraseBegan > PhrasePriorityMessageGroupingTime) if (SecondsSincePhraseBegan > PhrasePriorityMessageGroupingTime)
{ {
// if we are in standard color mode, shift all flowers to the new color BlumenLumen_ApplyNextHotHue(BLState, *Context, &DebugStr, State);
// 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_AdvanceHueFade(BLState, *Context);
// Update next frames Hues // Update next frames Hues
r32 AnimTime = AnimationSystem_GetCurrentTime(State->AnimationSystem); r32 AnimTime = AnimationSystem_GetCurrentTime(State->AnimationSystem);
AnimTime = (r32)Context->TotalTime; AnimTime = (r32)Context->TotalTime;
@ -737,8 +750,6 @@ US_CUSTOM_DEBUG_UI(BlumenLumen_DebugUI)
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory; blumen_lumen_state* BLState = (blumen_lumen_state*)UserData.Memory;
ui_interface* I = &State->Interface; ui_interface* I = &State->Interface;
// NOTE(PS): Motors
{
motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket; motor_packet PendingPacket = BLState->DEBUG_PendingMotorPacket;
for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++) for (u32 MotorIndex = 0; MotorIndex < BL_FLOWER_COUNT; MotorIndex++)
@ -840,8 +851,31 @@ US_CUSTOM_DEBUG_UI(BlumenLumen_DebugUI)
BlumenLumen_UpdateMotorState(BLState, Motor, Context); 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++)
{
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);
}
US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup) US_CUSTOM_CLEANUP(BlumenLumen_CustomCleanup)
{ {

View File

@ -157,6 +157,8 @@ struct blumen_lumen_state
system_time LastSendTime; system_time LastSendTime;
phrase_hue StandardPatternHues; phrase_hue StandardPatternHues;
r32 AssemblyColorsTransitionTimeLeft[BL_FLOWER_COUNT];
phrase_hue NextAssemblyColors[BL_FLOWER_COUNT];
phrase_hue AssemblyColors[BL_FLOWER_COUNT]; phrase_hue AssemblyColors[BL_FLOWER_COUNT];
u32 LastAssemblyColorSet; u32 LastAssemblyColorSet;
@ -188,10 +190,41 @@ struct blumen_lumen_state
bool DEBUG_IgnoreWeatherDimmingLeds; bool DEBUG_IgnoreWeatherDimmingLeds;
bool ShouldUpdateLog; bool ShouldUpdateLog;
phrase_hue PendingPhrase;
}; };
#include "message_queue.cpp" #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 internal phrase_hue
BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly) BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly)
{ {
@ -206,7 +239,15 @@ BlumenLumen_GetCurrentHue(blumen_lumen_state* BLState, assembly Assembly)
case BlumenPattern_VoiceCommand: 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; }break;
} }

View File

@ -105,6 +105,9 @@ r32 GlobalAnimSpeed = 1.0f;
// activated mode // activated mode
r32 GlobalAnimTransitionSpeed = 5.0f; 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; r64 PhrasePriorityMessageGroupingTime = 1.0f;
// How often should Lumenarium send its status to the python server? // How often should Lumenarium send its status to the python server?

View File

@ -281,13 +281,14 @@ Fbm3D(v3 P, r32 T)
r32 F = 0.0; r32 F = 0.0;
F += 0.500000f * Noise3D(Pp + Tt); Pp = Pp * 2.02; F += 0.500000f * Noise3D(Pp + Tt); Pp = Pp * 2.02;
F += 0.031250f * Noise3D(Pp); Pp = Pp * 2.01; //F += 0.031250f * Noise3D(Pp); Pp = Pp * 2.01;
F += 0.250000f * Noise3D(Pp - Tt); Pp = Pp * 2.03; F += 0.300000f * Noise3D(Pp - Tt); Pp = Pp * 2.03;
F += 0.125000f * Noise3D(Pp); Pp = Pp * 2.01; F += 0.125000f * Noise3D(Pp); Pp = Pp * 2.01;
F += 0.062500f * Noise3D(Pp + Tt); Pp = Pp * 2.04; 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; return F;
} }

View File

@ -10,6 +10,19 @@ enum p_hue_flag
Hue_Black = 2, 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 typedef struct p_hue
{ {
r64 Hue; r64 Hue;
@ -25,6 +38,10 @@ typedef struct phrase_hue_map
p_hue* Hue0; p_hue* Hue0;
p_hue* Hue1; p_hue* Hue1;
p_hue* Hue2; p_hue* Hue2;
u32* Gran; // granularity
r32* Speed;
u8* Pattern;
u8* AddIn;
} phrase_hue_map; } phrase_hue_map;
typedef struct phrase_hue typedef struct phrase_hue
@ -34,8 +51,62 @@ typedef struct phrase_hue
p_hue Hue0; p_hue Hue0;
p_hue Hue1; p_hue Hue1;
p_hue Hue2; p_hue Hue2;
u32 Granularity;
r32 Speed;
u8 Pattern;
u8 AddIn;
} phrase_hue; } 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 internal p_hue
CreateHueFromString(gs_const_string Str) CreateHueFromString(gs_const_string Str)
{ {
@ -46,7 +117,13 @@ CreateHueFromString(gs_const_string Str)
Result.Flags = Hue_White; Result.Flags = Hue_White;
} else { } else {
Result.Flags = Hue_Value; 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; return Result;
} }
@ -76,6 +153,10 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
Result.Hue0 = PushArray(Arena, p_hue, Result.CountMax); Result.Hue0 = PushArray(Arena, p_hue, Result.CountMax);
Result.Hue1 = PushArray(Arena, p_hue, Result.CountMax); Result.Hue1 = PushArray(Arena, p_hue, Result.CountMax);
Result.Hue2 = 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; s32 DestOffset = 0;
for (u32 Row = 1; Row < Sheet.RowCount; Row++) for (u32 Row = 1; Row < Sheet.RowCount; Row++)
@ -90,6 +171,11 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
gs_const_string Hue1Str = CSVSheet_GetCell(Sheet, 2, Row); gs_const_string Hue1Str = CSVSheet_GetCell(Sheet, 2, Row);
gs_const_string Hue2Str = CSVSheet_GetCell(Sheet, 3, Row); gs_const_string Hue2Str = CSVSheet_GetCell(Sheet, 3, Row);
gs_const_string Homonyms = CSVSheet_GetCell(Sheet, 4, 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 || if (Phrase.Length == 0 ||
Hue0Str.Length == 0 || Hue0Str.Length == 0 ||
Hue1Str.Length == 0 || Hue1Str.Length == 0 ||
@ -115,6 +201,36 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
Result.Hue0[Index] = CreateHueFromString(Hue0Str); Result.Hue0[Index] = CreateHueFromString(Hue0Str);
Result.Hue1[Index] = CreateHueFromString(Hue1Str); Result.Hue1[Index] = CreateHueFromString(Hue1Str);
Result.Hue2[Index] = CreateHueFromString(Hue2Str); 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; Result.Count = Result.CountMax + DestOffset;
@ -123,24 +239,34 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
} }
internal phrase_hue 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 = {}; phrase_hue Result = {};
for (u32 i = 0; i < Map.Count; i++) for (u32 i = 0; i < Map.Count; i++)
{ {
if (Map.PhraseHashes[i] == PhraseHash) if (Map.PhraseHashes[i] == PhraseHash)
{ {
Result.Phrase = Map.Phrases[i]; Result = PhraseHueMap_Get(Map, i);
Result.PhraseHash = Map.PhraseHashes[i];
Result.Hue0 = Map.Hue0[i];
Result.Hue1 = Map.Hue1[i];
Result.Hue2 = Map.Hue2[i];
break; break;
} }
} }
return Result; return Result;
} }