This commit is contained in:
Peter Slattery 2021-04-09 22:19:36 -04:00
commit 00a4cb5e39
4 changed files with 61 additions and 36 deletions

View File

@ -678,7 +678,7 @@ AnimationSystem_Init(animation_system_desc Desc)
Result.ActiveFadeGroup.FadeElapsed = 0; Result.ActiveFadeGroup.FadeElapsed = 0;
// Settings // Settings
Result.Multithreaded = true; Result.Multithreaded = false;
return Result; return Result;
} }

View File

@ -413,14 +413,15 @@ BlumenLumen_CustomInit(app_state* State, context Context)
#endif #endif
State->AnimationSystem.TimelineShouldAdvance = true; State->AnimationSystem.TimelineShouldAdvance = true;
BLState->StandardPatternHues.Hue0.Flags = Hue_Value;
BLState->StandardPatternHues.Hue1.Flags = Hue_Value;
BLState->StandardPatternHues.Hue2.Flags = Hue_Value;
BLState->StandardPatternHues.Granularity = 1; BLState->StandardPatternHues.Granularity = 1;
BLState->StandardPatternHues.Speed = 1; BLState->StandardPatternHues.Speed = 1;
BLState->StandardPatternHues.AddIn = AddIn_Rotary; BLState->StandardPatternHues.AddIn = AddIn_Rotary;
BLState->StandardPatternHues.Pattern = HuePattern_Wavy; BLState->StandardPatternHues.Pattern = HuePattern_Wavy;
BLState->DebugHue.Hue0.HSV = v4{0, 1, 1, 1};
BLState->DebugHue.Hue1.HSV = v4{0, 1, 1, 1};
BLState->DebugHue.Hue2.HSV = v4{0, 1, 1, 1};
BlumenLumen_AppendBootupLog(State, BLState, Context); BlumenLumen_AppendBootupLog(State, BLState, Context);
return Result; return Result;
} }
@ -456,7 +457,8 @@ BlumenLumen_ApplyNextHotHue(blumen_lumen_state* BLState, context Context, gs_str
OutputDebugString(DebugStr->Str); OutputDebugString(DebugStr->Str);
if (BLState->PatternMode == BlumenPattern_Standard) if (BLState->PatternMode == BlumenPattern_Standard ||
NewHue.OverrideAll)
{ {
BlumenLumen_SetNextHue(BLState, 0, NewHue); BlumenLumen_SetNextHue(BLState, 0, NewHue);
BlumenLumen_SetNextHue(BLState, 1, NewHue); BlumenLumen_SetNextHue(BLState, 1, NewHue);
@ -581,9 +583,15 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
r32 ColorRelOscSpeed = 1 * ColorSpeed;; r32 ColorRelOscSpeed = 1 * ColorSpeed;;
r32 ColorOscillation = (SinR32(BaseTime * ColorOscSpeed) + 1) / 2; r32 ColorOscillation = (SinR32(BaseTime * ColorOscSpeed) + 1) / 2;
r32 ColorRelationship = 30 + (((1 + SinR32(BaseTime * ColorRelOscSpeed)) / 2) * 300); r32 ColorRelationship = 30 + (((1 + SinR32(BaseTime * ColorRelOscSpeed)) / 2) * 300);
BLState->StandardPatternHues.Hue0.Hue = ModR32(ColorOscillation * 360, 360);
BLState->StandardPatternHues.Hue1.Hue = ModR32(BaseTime + ColorRelationship, 360); r32 H0 = ModR32(ColorOscillation * 360, 360);
BLState->StandardPatternHues.Hue2.Hue = LerpR32(.3f, BLState->StandardPatternHues.Hue0.Hue, BLState->StandardPatternHues.Hue1.Hue); r32 H1 = ModR32(BaseTime + ColorRelationship, 360);
// TODO(PS): use our new HSV lerp
r32 H2 = LerpR32(.3f, H0, H1);
BLState->StandardPatternHues.Hue0.HSV = v4{ H0, 1, 1, 1 };
BLState->StandardPatternHues.Hue1.HSV = v4{ H1, 1, 1, 1 };
BLState->StandardPatternHues.Hue2.HSV = v4{ H2, 1, 1, 1 };
// Transition back to standard mode after some time // Transition back to standard mode after some time
if (BLState->PatternMode == BlumenPattern_VoiceCommand) if (BLState->PatternMode == BlumenPattern_VoiceCommand)
@ -616,6 +624,10 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue) && if (MessageQueue_CanWrite(BLState->OutgoingMsgQueue) &&
!BLState->IgnoreTimeOfDay_MotorState) !BLState->IgnoreTimeOfDay_MotorState)
{ {
u64 NanosSinceLastSend = Context->SystemTime_Current.NanosSinceEpoch - BLState->LastSendTime.NanosSinceEpoch;
r32 SecondsSinceLastSend = (r64)NanosSinceLastSend * NanosToSeconds;
bool ShouldSendCurrentState = SecondsSinceLastSend >= MotorResendStatePeriod;
for (u32 i = 0; i < MotorOpenTimesCount; i++) for (u32 i = 0; i < MotorOpenTimesCount; i++)
{ {
time_range Range = MotorOpenTimes[i]; time_range Range = MotorOpenTimes[i];
@ -626,9 +638,13 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
bool LastTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Last, Range); bool LastTimeInRange = SystemTimeIsInTimeRange(Context->SystemTime_Last, Range);
#if 0
bool SendOpen = CurrTimeInRange && !LastSendTimeInRange; bool SendOpen = CurrTimeInRange && !LastSendTimeInRange;
bool SendClose = !CurrTimeInRange && LastSendTimeInRange; bool SendClose = !CurrTimeInRange && LastSendTimeInRange;
#else
bool SendOpen = CurrTimeInRange && ShouldSendCurrentState;
bool SendClose = !CurrTimeInRange && ShouldSendCurrentState;
#endif
//SendOpen = SecondsSinceLastSend > 2; //SendOpen = SecondsSinceLastSend > 2;
if (SendOpen) if (SendOpen)
{ {
@ -643,6 +659,7 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
Packet.MotorPacket.FlowerPositions[1] = 2; Packet.MotorPacket.FlowerPositions[1] = 2;
Packet.MotorPacket.FlowerPositions[2] = 2; Packet.MotorPacket.FlowerPositions[2] = 2;
MotorCommand = Packet; MotorCommand = Packet;
break;
} }
else if (SendClose) else if (SendClose)
{ {
@ -656,6 +673,7 @@ BlumenLumen_CustomUpdate(gs_data UserData, app_state* State, context* Context)
Packet.MotorPacket.FlowerPositions[1] = 1; Packet.MotorPacket.FlowerPositions[1] = 1;
Packet.MotorPacket.FlowerPositions[2] = 1; Packet.MotorPacket.FlowerPositions[2] = 1;
MotorCommand = Packet; MotorCommand = Packet;
break;
} }
} }
@ -953,9 +971,9 @@ US_CUSTOM_DEBUG_UI(BlumenLumen_DebugUI)
if (BLState->DebugOverrideHue) if (BLState->DebugOverrideHue)
{ {
phrase_hue PHue = BLState->DebugHue; phrase_hue PHue = BLState->DebugHue;
PHue.Hue0.Hue = (r64)ui_LabeledRangeSlider(I, MakeString("Hue0"), (r32)PHue.Hue0.Hue, 0, 360); PHue.Hue0.HSV.x = (r64)ui_LabeledRangeSlider(I, MakeString("Hue0"), (r32)PHue.Hue0.HSV.x, 0, 360);
PHue.Hue1.Hue = (r64)ui_LabeledRangeSlider(I, MakeString("Hue1"), (r32)PHue.Hue1.Hue, 0, 360); PHue.Hue1.HSV.x = (r64)ui_LabeledRangeSlider(I, MakeString("Hue1"), (r32)PHue.Hue1.HSV.x, 0, 360);
PHue.Hue2.Hue = (r64)ui_LabeledRangeSlider(I, MakeString("Hue2"), (r32)PHue.Hue2.Hue, 0, 360); PHue.Hue2.HSV.x = (r64)ui_LabeledRangeSlider(I, MakeString("Hue2"), (r32)PHue.Hue2.HSV.x, 0, 360);
PHue.Granularity = (u32)ui_LabeledRangeSlider(I, MakeString("Granularity"), (r32)PHue.Granularity, 0, 5); PHue.Granularity = (u32)ui_LabeledRangeSlider(I, MakeString("Granularity"), (r32)PHue.Granularity, 0, 5);
PHue.Speed = ui_LabeledRangeSlider(I, MakeString("Speed"), PHue.Speed, 0, 4); PHue.Speed = ui_LabeledRangeSlider(I, MakeString("Speed"), PHue.Speed, 0, 4);

View File

@ -42,6 +42,11 @@ global time_range MotorOpenTimes[] = {
}; };
global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit global u32 MotorOpenTimesCount = CArrayLength(MotorOpenTimes); // do not edit
// Lumenarium repeatedly resends the current motor state to the python
// server. This variable determines how much time elapses between each
// message.
global r32 MotorResendStatePeriod = 90.0f; // seconds
// The times of day when the leds should be on // The times of day when the leds should be on
// Search for @TimeFormat to find documentation // Search for @TimeFormat to find documentation
global time_range LedOnTimes[] = { global time_range LedOnTimes[] = {

View File

@ -29,8 +29,7 @@ enum p_hue_add_in
typedef struct p_hue typedef struct p_hue
{ {
r64 Hue; v4 HSV;
p_hue_flag Flags;
} p_hue; } p_hue;
typedef struct phrase_hue_map typedef struct phrase_hue_map
@ -46,6 +45,7 @@ typedef struct phrase_hue_map
r32* Speed; r32* Speed;
u8* Pattern; u8* Pattern;
u8* AddIn; u8* AddIn;
bool* OverrideAll;
} phrase_hue_map; } phrase_hue_map;
typedef struct phrase_hue typedef struct phrase_hue
@ -59,6 +59,7 @@ typedef struct phrase_hue
r32 Speed; r32 Speed;
u8 Pattern; u8 Pattern;
u8 AddIn; u8 AddIn;
bool OverrideAll;
} phrase_hue; } phrase_hue;
internal p_hue internal p_hue
@ -66,22 +67,25 @@ LerpPHue(r32 T, p_hue A, p_hue B)
{ {
p_hue Result = {}; p_hue Result = {};
if (Abs(A.Hue - B.Hue) < 180.0f) if (Abs(A.HSV.x - B.HSV.x) < 180.0f)
{ {
Result.Hue = LerpR64(T, A.Hue, B.Hue); Result.HSV.x = LerpR64(T, A.HSV.x, B.HSV.x);
}
else if (B.HSV.x > A.HSV.x)
{
Result.HSV.x = LerpR64(T, A.HSV.x, B.HSV.x - 360.0f);
} }
else else
{ {
Result.Hue = LerpR64(T, A.Hue + 360.0f, B.Hue); Result.HSV.x = LerpR64(T, A.HSV.x - 360.0f, B.HSV.x);
Result.Hue = ModR32(Result.Hue, 360.0f);
} }
if (Result.HSV.x < 360) Result.HSV.x += 360;
if (Result.HSV.x > 360) Result.HSV.x -= 360;
Result.HSV.x = Clamp(0, Result.HSV.x, 360);
Result.HSV.y = LerpR32(T, A.HSV.y, B.HSV.y);
Result.HSV.z = LerpR32(T, A.HSV.z, B.HSV.z);
Result.HSV.w = LerpR32(T, A.HSV.w, B.HSV.w);
if (T < 0.5f)
{
Result.Flags = A.Flags;
} else {
Result.Flags = B.Flags;
}
return Result; return Result;
} }
@ -116,18 +120,18 @@ CreateHueFromString(gs_const_string Str)
{ {
p_hue Result = {}; p_hue Result = {};
if (Str.Str[0] == 'b') { if (Str.Str[0] == 'b') {
Result.Flags = Hue_Black; Result.HSV = v4{0, 0, 0, 1 };
} else if (Str.Str[0] == 'w') { } else if (Str.Str[0] == 'w') {
Result.Flags = Hue_White; Result.HSV = v4{0, 0, 1, 1 };;
} else { } else {
Result.Flags = Hue_Value;
parse_float_result Parsed = ValidateAndParseFloat(Str); parse_float_result Parsed = ValidateAndParseFloat(Str);
if (!Parsed.Success) if (!Parsed.Success)
{ {
OutputDebugString("Failed to Parse CSV Float\n"); OutputDebugString("Failed to Parse CSV Float\n");
Parsed.Value = 0.0; Parsed.Value = 0.0;
} }
Result.Hue = Parsed.Value; Result.HSV = v4{ (r32)Parsed.Value, 1, 1, 1 };
} }
return Result; return Result;
} }
@ -135,14 +139,7 @@ CreateHueFromString(gs_const_string Str)
internal v4 internal v4
RGBFromPhraseHue (p_hue H) RGBFromPhraseHue (p_hue H)
{ {
v4 Result = {}; v4 Result = H.HSV;
switch (H.Flags)
{
case Hue_Black: { Result = v4{1, 0, 0, 1}; } break;
case Hue_White: { Result = v4{1, 0, 1, 1}; } break;
case Hue_Value: { Result = v4{(r32)H.Hue, 1, 1, 1}; } break;
InvalidDefaultCase;
}
Result = HSVToRGB(Result); Result = HSVToRGB(Result);
return Result; return Result;
} }
@ -163,6 +160,7 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
Result.Pattern = PushArray(Arena, u8, Result.CountMax); Result.Pattern = PushArray(Arena, u8, Result.CountMax);
Result.Speed = PushArray(Arena, r32, Result.CountMax); Result.Speed = PushArray(Arena, r32, Result.CountMax);
Result.AddIn = PushArray(Arena, u8, Result.CountMax); Result.AddIn = PushArray(Arena, u8, Result.CountMax);
Result.OverrideAll = PushArray(Arena, bool, Result.CountMax);
// this lets us tightly pack phrase_hues even if there is a // this lets us tightly pack phrase_hues even if there is a
// row in the csv that is empty or invalid // row in the csv that is empty or invalid
@ -182,6 +180,7 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
gs_const_string Speed = CSVSheet_GetCell(Sheet, 6, Row); gs_const_string Speed = CSVSheet_GetCell(Sheet, 6, Row);
gs_const_string Pattern = CSVSheet_GetCell(Sheet, 7, Row); gs_const_string Pattern = CSVSheet_GetCell(Sheet, 7, Row);
gs_const_string AddIn = CSVSheet_GetCell(Sheet, 8, Row); gs_const_string AddIn = CSVSheet_GetCell(Sheet, 8, Row);
gs_const_string OverrideAll = CSVSheet_GetCell(Sheet, 9, Row);
// essential parameters // essential parameters
if (Phrase.Length == 0 || if (Phrase.Length == 0 ||
@ -239,6 +238,8 @@ PhraseHueMap_GenFromCSV(gscsv_sheet Sheet, gs_memory_arena* Arena)
ParsedGranularity.Value = 1; ParsedGranularity.Value = 1;
} }
Result.Gran[Index] = ParsedGranularity.Value; Result.Gran[Index] = ParsedGranularity.Value;
Result.OverrideAll[Index] = StringsEqualUpToLength(OverrideAll, ConstString("yes"), 3);
} }
Result.Count = Result.CountMax + DestOffset; Result.Count = Result.CountMax + DestOffset;
@ -260,6 +261,7 @@ PhraseHueMap_Get(phrase_hue_map Map, u32 Index)
Result.Speed = Map.Speed[Index]; Result.Speed = Map.Speed[Index];
Result.AddIn = Map.AddIn[Index]; Result.AddIn = Map.AddIn[Index];
Result.Pattern = Map.Pattern[Index]; Result.Pattern = Map.Pattern[Index];
Result.OverrideAll = Map.OverrideAll[Index];
return Result; return Result;
} }