diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs index 8ed68cd07..93b75d32c 100644 --- a/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs @@ -12,6 +12,11 @@ /// public bool TurnOffLed { get; set; } + /// + /// Ignores the color and uses the rainbow color functionality for the LED. + /// + public bool UseRainbow { get; set; } + /// /// Packed RGB int of the color /// diff --git a/src/Ryujinx.Common/Utilities/Rainbow.cs b/src/Ryujinx.Common/Utilities/Rainbow.cs new file mode 100644 index 000000000..42222f157 --- /dev/null +++ b/src/Ryujinx.Common/Utilities/Rainbow.cs @@ -0,0 +1,76 @@ +using System; +using System.Drawing; + +namespace Ryujinx.Common.Utilities +{ + public class Rainbow + { + public const float Speed = 1; + + public static Color Color { get; private set; } = Color.Blue; + + public static void Tick() + { + Color = HsbToRgb( + (Color.GetHue() + Speed) / 360, + 1, + 1 + ); + + RainbowColorUpdated?.Invoke(Color.ToArgb()); + } + + public static event Action RainbowColorUpdated; + + private static Color HsbToRgb(float hue, float saturation, float brightness) + { + int r = 0, g = 0, b = 0; + if (saturation == 0) + { + r = g = b = (int)(brightness * 255.0f + 0.5f); + } + else + { + float h = (hue - (float)Math.Floor(hue)) * 6.0f; + float f = h - (float)Math.Floor(h); + float p = brightness * (1.0f - saturation); + float q = brightness * (1.0f - saturation * f); + float t = brightness * (1.0f - (saturation * (1.0f - f))); + switch ((int)h) + { + case 0: + r = (int)(brightness * 255.0f + 0.5f); + g = (int)(t * 255.0f + 0.5f); + b = (int)(p * 255.0f + 0.5f); + break; + case 1: + r = (int)(q * 255.0f + 0.5f); + g = (int)(brightness * 255.0f + 0.5f); + b = (int)(p * 255.0f + 0.5f); + break; + case 2: + r = (int)(p * 255.0f + 0.5f); + g = (int)(brightness * 255.0f + 0.5f); + b = (int)(t * 255.0f + 0.5f); + break; + case 3: + r = (int)(p * 255.0f + 0.5f); + g = (int)(q * 255.0f + 0.5f); + b = (int)(brightness * 255.0f + 0.5f); + break; + case 4: + r = (int)(t * 255.0f + 0.5f); + g = (int)(p * 255.0f + 0.5f); + b = (int)(brightness * 255.0f + 0.5f); + break; + case 5: + r = (int)(brightness * 255.0f + 0.5f); + g = (int)(p * 255.0f + 0.5f); + b = (int)(q * 255.0f + 0.5f); + break; + } + } + return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b)); + } + } +} diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs index f64e1c479..00d079a2b 100644 --- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs +++ b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Services.Hid; using SDL2; using System; @@ -235,8 +236,11 @@ namespace Ryujinx.Input.SDL2 { if (_configuration.Led.TurnOffLed) (this as IGamepad).ClearLed(); + else if (_configuration.Led.UseRainbow) + Rainbow.RainbowColorUpdated += clr => SetLed((uint)clr); else SetLed(_configuration.Led.LedColor); + } _buttonsUserMapping.Clear(); diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL2.Common/SDL2Driver.cs index 851c07867..47c5e60c5 100644 --- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs +++ b/src/Ryujinx.SDL2.Common/SDL2Driver.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -167,6 +168,8 @@ namespace Ryujinx.SDL2.Common HandleSDLEvent(ref evnt); } }); + + Rainbow.Tick(); waitHandle.Wait(WaitTimeMs); } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index d4a52c003..4946a24f5 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -7628,7 +7628,7 @@ "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "Custom LED", + "en_US": "LED", "es_ES": "", "fr_FR": "", "he_IL": "", @@ -7672,6 +7672,31 @@ "zh_TW": "" } }, + { + "ID": "ControllerSettingsLedColorRainbow", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Rainbow", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "ControllerSettingsSave", "Translations": { @@ -23023,4 +23048,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index ae3676853..6f0f7f47f 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -388,42 +388,6 @@ namespace Ryujinx.Ava.UI.Models.Input } } - private bool _enableLedChanging; - - public bool EnableLedChanging - { - get => _enableLedChanging; - set - { - _enableLedChanging = value; - OnPropertyChanged(); - } - } - - private bool _turnOffLed; - - public bool TurnOffLed - { - get => _turnOffLed; - set - { - _turnOffLed = value; - OnPropertyChanged(); - } - } - - private Color _ledColor; - - public Color LedColor - { - get => _ledColor; - set - { - _ledColor = value; - OnPropertyChanged(); - } - } - private bool _enableMotion; public bool EnableMotion { @@ -445,6 +409,58 @@ namespace Ryujinx.Ava.UI.Models.Input OnPropertyChanged(); } } + + private bool _enableLedChanging; + + public bool EnableLedChanging + { + get => _enableLedChanging; + set + { + _enableLedChanging = value; + OnPropertyChanged(); + } + } + + public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed; + + private bool _turnOffLed; + + public bool TurnOffLed + { + get => _turnOffLed; + set + { + _turnOffLed = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ShowLedColorPicker)); + } + } + + private bool _useRainbowLed; + + public bool UseRainbowLed + { + get => _useRainbowLed; + set + { + _useRainbowLed = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ShowLedColorPicker)); + } + } + + private Color _ledColor; + + public Color LedColor + { + get => _ledColor; + set + { + _ledColor = value; + OnPropertyChanged(); + } + } public GamepadInputConfig(InputConfig config) { @@ -525,6 +541,7 @@ namespace Ryujinx.Ava.UI.Models.Input { EnableLedChanging = controllerInput.Led.EnableLed; TurnOffLed = controllerInput.Led.TurnOffLed; + UseRainbowLed = controllerInput.Led.UseRainbow; uint rawColor = controllerInput.Led.LedColor; byte alpha = (byte)(rawColor >> 24); byte red = (byte)(rawColor >> 16); @@ -593,6 +610,7 @@ namespace Ryujinx.Ava.UI.Models.Input { EnableLed = EnableLedChanging, TurnOffLed = this.TurnOffLed, + UseRainbow = UseRainbowLed, LedColor = LedColor.ToUInt32() }, Version = InputConfig.CurrentVersion, diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 6b8673a9f..a4218c61e 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -495,19 +495,20 @@ Margin="0,-1,0,0"> + - + + +