Lumenarium/src/app/patterns/blumen_patterns.h

869 lines
27 KiB
C

//
// File: blumen_patterns.h
// Author: Peter Slattery
// Creation Date: 2021-01-15
//
#ifndef BLUMEN_PATTERNS_H
#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)
{
blumen_lumen_state* BLState = (blumen_lumen_state*)UserData;
Time = Time * BLState->PatternSpeed;
v3 SphereCenter = Assembly.Center - v3{0, -150, 0};
r32 SphereRadius = Time;
r32 SphereBrightness = 1;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Sphere = SDF_SphereNormalized(P, SphereCenter, SphereRadius);
Sphere = Clamp01(-Sphere);
Leds->Colors[LedIndex] = V4ToRGBPixel(WhiteV4 * Sphere);
}
}
internal void
Pattern_HueShift(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 Height = SinR32(Time) * 25;
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
#if 0
phrase_hue Hue = BLState->AssemblyColors[Assembly.AssemblyIndex % 3];
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
v4 HSV = {};
if (CycleProgress < .25f)
{
r32 P = CycleProgress * 4;
HSV = V4Lerp(C0,
}
else if (CycleProgress >= .25f && CycleProgress < .5f)
{
}
else if (CycleProgress >= .5f && CycleProgress < .75f)
{
}
else if (CycleProgress >= .75f)
{
}
#endif
v4 HSV = { CycleProgress * 360, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Dist = Pos.y - Height;
//v4 HSV = { (ModR32(Dist, 25) / 25) * 360, 1, 1, 1 };
//v4 RGB = HSVToRGB(HSV);
u8 R = (u8)(RGB.x * 255);
u8 G = (u8)(RGB.y * 255);
u8 B = (u8)(RGB.z * 255);
Leds->Colors[LedIndex].R = R;
Leds->Colors[LedIndex].G = G;
Leds->Colors[LedIndex].B = B;
}
}
internal void
Pattern_Rainbow(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 HueBase = ModR32(Time * 50, 360);
r32 CycleLength = 5.0f;
r32 CycleProgress = FractR32(Time / CycleLength);
r32 CycleBlend = (SinR32(Time) * .5f) + .5f;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v4 Pos = Leds->Positions[LedIndex];
r32 Hue = HueBase + Pos.y + Pos.x;
v4 HSV = { Hue, 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal void
Pattern_RadialRainbow(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;
v2 RefVector = V2Normalize(v2{ SinR32(Time), CosR32(Time) });
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v2 Vector = v2{
Leds->Positions[LedIndex].x,
Leds->Positions[LedIndex].z
};
Vector = V2Normalize(Vector);
r32 Angle = V2Dot(RefVector, Vector);
v4 HSV = { (Angle * 30) + (Time * 10), 1, 1, 1 };
v4 RGB = HSVToRGB(HSV);
Leds->Colors[LedIndex] = V4ToRGBPixel(RGB);
}
}
internal void
Pattern_BasicFlowers(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 = BLState->AssemblyColors[Assembly.AssemblyIndex % 3];
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
r32 CycleT = ModR32(Time, 10) * 20;
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
v4 P = Leds->Positions[LedIndex];
r32 T = ModR32(P.y + CycleT, 200) / 200.f;
T = Clamp01(T);
v4 Color = {};
if (T < 0.5f)
{
Color = V4Lerp(T * 2, C0, C1);
}
else
{
Color = V4Lerp((T - 0.5f) * 2, C1, C2);
}
Leds->Colors[LedIndex] = V4ToRGBPixel(Color);
}
}
}
internal void
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)
{
r32 Top = 120 + (SinR32(Time) * 10);
r32 Mid = 70 + (CosR32(Time * 2.13) * 20);
r32 Bot = 0;
r32 TopD = Top - Mid;
r32 BotD = Mid - Bot;
r32 MidD = Min(TopD, BotD);
//r32 MaxFadeDistance = 10;
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 PercentTop = Clamp01(1.0f - ((Top - P.y) / TopD));
r32 PercentMid = Clamp01(1.0f - Abs(P.y - Mid) / MidD);
r32 N = Noise3D((P / 17) + v3{Time, -Time, 0});
N = Clamp01(N) * 2;
N = Smoothstep(N);
N *= N;
N = Smoothstep(N);
N *= 1.0f - PowR32(1.0f - PercentMid, 4);
PercentMid = Clamp01(PercentMid + N);
r32 PercentBot = Clamp01(1.0f - ((P.y - Bot) / BotD));
v4 TopC = (C0 * PercentTop);
v4 MidC = (C1 * PercentMid);
v4 BotC = (C2 * PercentBot);
v4 C = {};
if (PercentTop > PercentMid && PercentTop > PercentBot)
{
C = C0;
}
else if (PercentMid > PercentBot)
{
C = C1;
}
else
{
C = C2;
}
r32 ScaleFactor = PercentTop + PercentMid + PercentBot;
C = (TopC + MidC + BotC) / ScaleFactor;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
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;
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);
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];
r32 LedRange = 300.0f;
r32 ScaleFactor = 1.0f / LedRange;
v3 Pp = P.xyz + v3{150, 100, 0};
r32 NoiseA = Noise3D((Pp / BaseGA) + v3{0, 0, Time});
NoiseA = PowR32(NoiseA, 3);
NoiseA = Smoothstep(NoiseA);
r32 NoiseB = Noise3D((Pp / BaseGB) + v3{Time * 0.5f, 0, 0});
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(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)
{
r32 MinBandThickness = 5;
r32 MaxBandThickness = 10;
r32 MaxTransitionPeriod = 120.0f;
r32 BandTransitionPeriod = NextRandomUnilateral(Random) * MaxTransitionPeriod;
r32 BandTransitionBias = (1 - Clamp(0, (Time / (MaxTransitionPeriod / 2)), 0.7f)); // approaches 0.5 over time
BandTransitionPeriod *= BandTransitionBias;
r32 BandPercent = ModR32(Time, BandTransitionPeriod) / BandTransitionPeriod;
BandPercent = Smoothstep(BandPercent);
r32 BandY = -150 + (BandPercent * 290);
r32 ThickRand = NextRandomUnilateral(Random);
// 1 - 4((ThickRand - .5)^2) - distribution curve
ThickRand = 1.0f - ((4 * PowR32(ThickRand, 2)) - (4 * ThickRand) + 1);
r32 BandThickness = MinBandThickness + (ThickRand * (MaxBandThickness - MinBandThickness));
// BandBrightness = 1 - ((2x - 1) ^ 8) where x is BandPercent
r32 BandBrightness = 1.0f - PowR32((2 * BandPercent) - 1, 8);
BandBrightness *= RemapR32(NextRandomUnilateral(Random), 0, 1, .25f, 1);
r32 Result = 1 - Clamp01(Abs(P.y - BandY) / BandThickness);
Result *= BandBrightness;
return Result;
}
internal void
Pattern_Leafy(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;
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++)
{
v4 P = Leds->Positions[LedIndex];
v4 C = {};
r32 B = 0;
// NOTE(PS): initializing the Random seed inside the Led Loop
// so that the bands are consistently calculated for each led
// ie. each time you calculate a band, the random numbers requested
// will always be the same
gs_random_series Random = InitRandomSeries(24601);
u32 BandCount = 25;
for (u32 Band = 0; Band < BandCount; Band++)
{
B += Leafy_BandSDF(P.xyz, &Random, Time);
}
B = Clamp01(B);
C = WhiteV4 * B;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_LeafyPatchy(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;
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++)
{
v4 P = Leds->Positions[LedIndex];
v3 Pp = P.xyz + v3{150, 100, 0};
r32 NoiseA = Fbm3D((Pp / 18), Time * 0.25f);
NoiseA = Smoothstep(NoiseA);
r32 NoiseB = Noise3D((Pp / 35) + v3{0, 0, Time * 0.5f});
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB);
r32 NoiseC = Noise3D((Pp / 25) + v3{0, 0, Time * 4});
r32 CPresence = SinR32((P.y / 50) - Time) + (0.8f * SinR32((P.y / 25) - (Time * 5.0f)));
CPresence = RemapR32(CPresence, -1.8, 1.8, 0, 1);
CPresence = PowR32(CPresence, 4);
NoiseC *= CPresence;
v4 C = (C0 * NoiseA * 0.5f) + (C1 * NoiseB) + (C2 * NoiseC);
C *= 1.0f / (NoiseA + NoiseB + NoiseC);
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal void
Pattern_WavyPatchy(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;
}
internal void
Pattern_VerticalLines(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;
gs_random_series Random = InitRandomSeries(24601);
r32 LightSpeedMin = 1;
r32 LightSpeedMax = 5;
s32 LightTailLength = 10;
for (u32 StripIndex = 0; StripIndex < Assembly.StripCount; StripIndex++)
{
v2_strip Strip = Assembly.Strips[StripIndex];
r32 LightStartHeight = NextRandomUnilateral(&Random);
r32 LightSpeed = LerpR32(NextRandomUnilateral(&Random),
LightSpeedMin,
LightSpeedMax);
r32 LightCurrentHeight = LightStartHeight + (LightSpeed * Time * 0.1f);
s32 StartIndex = (s32)(LightCurrentHeight * (r32)Strip.LedCount) % Strip.LedCount;
for (s32 i = 0; i < LightTailLength; i++)
{
s32 StripLedIndex = StartIndex + i;
if (StripLedIndex >= (s32)Strip.LedCount) continue;
u32 LedIndex = Strip.LedLUT[StripLedIndex];
r32 PctTail = ((r32)i / (r32)LightTailLength);
v4 C = WhiteV4 * PctTail;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
}
internal void
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)
{
DEBUG_TRACK_FUNCTION;
gs_random_series Random = InitRandomSeries((u32)(24601 * (Assembly.Center.x + 1.032f)));
#define SphereCount 32
v3 SphereCenter[SphereCount];
r32 G = RemapR32(Granularity, 1, 5, .75f, 2);
r32 MaxHeightOffset = 250;
r32 MaxSpeed = 10;
r32 SphereRotationRadius = 3.0f;
r32 SphereRadius = 2.0f / G;
for (u32 i = 0; i < SphereCount; i++)
{
r32 SphereSeedA = NextRandomUnilateral(&Random);
SphereSeedA = PowR32(SphereSeedA, 2);
r32 SphereSeedB = NextRandomBilateral(&Random);
r32 SphereSpeed = NextRandomUnilateral(&Random) * MaxSpeed;
r32 SphereTime = Time + SphereSpeed;
r32 HeightOffset = 150 - (SphereSeedA * MaxHeightOffset);
r32 RotationOffset = SphereTime + SphereSeedB * TauR32;
r32 SphereRotationDir = NextRandomBilateral(&Random) < 0 ? -1 : 1;
v3 SpherePosOffset = v3{
SinR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2),
HeightOffset,
CosR32(RotationOffset * SphereRotationDir) * (SphereRotationRadius * 2)
};
SphereCenter[i] = Assembly.Center + SpherePosOffset;
}
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 Dist = 10000000;
for (u32 i = 0; i < SphereCount; i++)
{
r32 SphereSDF = Abs(SDF_Sphere(P, SphereCenter[i], SphereRadius));
SphereSDF = SphereSDF / SphereRadius;
Dist = Min(Dist, SphereSDF);
}
v4 C = BGColor;
if (Dist <= 1)
{
r32 Brightness = Clamp01(SphereRadius - Dist);
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)
{
pixel White = V4ToRGBPixel(WhiteV4);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
Leds->Colors[LedIndex] = White;
}
}
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;
r32 Top = 141;
r32 BulbRange = 50;
pixel White = V4ToRGBPixel(WhiteV4);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
v3 P = Leds->Positions[LedIndex].xyz;
r32 BulbSDF = 1 - Clamp01(((Top - P.y) - BulbRange) / BulbRange);
r32 N = Noise3D((P / 17) + v3{Time, -Time, 0});
N = Clamp01(N) * 2;
N = Smoothstep(N);
N *= N;
N = Smoothstep(N);
N *= 1.0f - PowR32(1.0f - BulbSDF, 4);
BulbSDF += N;
BulbSDF = Clamp01(BulbSDF);
v4 C = WhiteV4 * BulbSDF;
Leds->Colors[LedIndex] = V4ToRGBPixel(C);
}
}
internal v4
GenPatchyColor(v3 P, r32 Time, v4 C0, v4 C1, v4 C2)
{
r32 LedRange = 300.0f;
r32 ScaleFactor = 1.0f / LedRange;
v3 Pp = P + v3{150, 100, 0};
r32 ScaleA = 1;
r32 NoiseA = Noise3D(((Pp / 38) + v3{0, 0, Time}) * ScaleA);
NoiseA = PowR32(NoiseA, 3);
NoiseA = Smoothstep(NoiseA);
r32 ScaleBP = 2;
r32 ScaleB = 15;
r32 NoiseBP = Noise3D(((Pp / 13) + v3{ 0, Time * -0.33f, 0}) * ScaleBP);
NoiseBP = PowR32(NoiseBP, 3);
r32 NoiseB = Noise3D(((Pp / 75) + v3{Time * 0.5f, 0, 0}) * ScaleB);
NoiseB = PowR32(NoiseB, 3);
NoiseB = Smoothstep(NoiseB) * NoiseBP;
r32 ScaleC = 1.5;
r32 NoiseCP = Noise3D(((Pp / 132) + v3{Time * -0.33f, 0, 0}) * 0.5f);
r32 NoiseC = Noise3D(((Pp / 164) + v3{Time * 0.25f, 0, 0}) * ScaleC);
NoiseC = PowR32(NoiseC, 3);
NoiseC = Smoothstep(NoiseC) * NoiseCP;
v4 C = (C0 * NoiseA) + (C1 * NoiseB) + (C2 * NoiseC);
C /= (NoiseA + NoiseB + NoiseC);
return C;
}
internal r32
GenVerticalStrips(v3 P, r32 Time)
{
v2 Right = v2{1, 0};
v2 Pa = V2Normalize(v2{P.x, P.z});
r32 Angle = .5f + (.5f * V2Dot(Pa, Right));
r32 HOffset = 70.0f;
r32 O = 50.0f;
r32 C = 10.0f;
r32 X = Angle;
r32 Y = P.y;
r32 I = FloorR32(Y / C) * C;
I += (X * HOffset) + (Time * 25);
r32 V = FractR32(I / O);
V = 2.0f * (0.5f - Abs(V - 0.5f));
Assert(V >= 0 && V <= 1);
return V;
}
internal v4
GenVerticalLeaves(v3 P, r32 Time, v4 C0, v4 C1, v4 C2)
{
r32 A = GenVerticalStrips(P, Time * .25f);
r32 B = GenVerticalStrips(P * .3f, Time);
r32 C = GenVerticalStrips(P * .25f, Time * 2);
v4 R = (C0 * A) + (C1 * B) + (C2 * C);
R /= A + B + C;
return R;
}
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)
{
DEBUG_TRACK_FUNCTION;
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
GenDotBands(v3 P, r32 Time)
{
r32 RowHeight = 25;
r32 DotRadius = 20;
r32 Y = P.y + 150;
s32 Row = (s32)FloorR32(Y / RowHeight);
r32 RowH = Abs(FractR32(Y / RowHeight));
r32 DotDistY = Max(0, .5f - RowH) * 2;
r32 Angle = (V2Dot(V2Normalize(v2{P.x, P.z}), v2{1,0}) * .5f) + .5f;
r32 DotDistX = Abs(ModR32(Angle, .2f));
r32 DotDist = SqrtR32(PowR32(DotDistX, 2) + PowR32(RowH, 2));
r32 B = (DotRadius - DotDist) / DotRadius;
B = Clamp01(DotDist);
return DotDistY;
}
internal void
Pattern_VoicePattern(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.Pattern)
{
case HuePattern_Wavy:
{
Pattern_WavyOptions(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C0);
}break;
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;
case AddIn_Waves:
{
AddIn_WavesPattern(Leds, Range, Assembly, Time, Transient, UserData, Hue.Granularity, C0, C1, C2);
}break;
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);
led_strip_list Stem = BLState->StemStrips[Assembly.AssemblyIndex];
for (u32 s = 0; s < Stem.Count; s++)
{
u32 StripIndex = Stem.StripIndices[s];
v2_strip Strip = Assembly.Strips[StripIndex];
for (u32 i = 0; i < Strip.LedCount; i++)
{
u32 LedIndex = Strip.LedLUT[i];
Leds->Colors[LedIndex] = WhiteMask;
}
}
}
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;
phrase_hue Hue = BlumenLumen_GetCurrentHue(BLState, Assembly);
v4 C0 = RGBFromPhraseHue(Hue.Hue0);
v4 C1 = RGBFromPhraseHue(Hue.Hue1);
v4 C2 = RGBFromPhraseHue(Hue.Hue2);
pixel HueOut = V4ToRGBPixel(C0);
for (u32 LedIndex = Range.First; LedIndex < Range.OnePastLast; LedIndex++)
{
Leds->Colors[LedIndex] = HueOut;
}
}
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;
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;
}
}
}
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;
// 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