diff --git a/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuColorPickerPreview.cs b/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuColorPickerPreview.cs new file mode 100644 index 0000000000..fcb4eaf419 --- /dev/null +++ b/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuColorPickerPreview.cs @@ -0,0 +1,59 @@ +using NitroxClient.Unity.Helper; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace NitroxClient.MonoBehaviours.Gui.MainMenu.ServerJoin; + +public class MainMenuColorPickerPreview : MonoBehaviour, IPointerDownHandler, IPointerUpHandler +{ + private Image previewImage; + private CanvasGroup cg; + + public void Init(uGUI_ColorPicker colorPicker) + { + GameObject colorPreview = new("ColorPreview"); + colorPreview.transform.SetParent(colorPicker.pointer.transform); + colorPreview.transform.localPosition = new Vector3(-30, 30, 0); + colorPreview.transform.localRotation = Quaternion.identity; + colorPreview.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f); + previewImage = colorPreview.AddComponent(); + previewImage.sprite = CreateCircleSprite(); + cg = colorPreview.AddComponent(); + cg.alpha = 0; + + colorPicker.onColorChange.AddListener(OnColorPickerDrag); + } + + private static Sprite CreateCircleSprite() + { + const int HALF_SIZE = 50; + const int RADIUS = 42; + Texture2D tex = new(HALF_SIZE * 2, HALF_SIZE * 2); + for (int y = -HALF_SIZE; y <= HALF_SIZE; y++) + { + for (int x = -HALF_SIZE; x <= HALF_SIZE; x++) + { + bool isInsideCircle = x * x + y * y <= RADIUS * RADIUS; + tex.SetPixel(HALF_SIZE + x, HALF_SIZE + y, isInsideCircle ? Color.white : Color.clear); + } + } + + tex.Apply(); + return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f), 200); + } + + private void OnColorPickerDrag(ColorChangeEventData data) => previewImage.color = data.color; + + public void OnPointerDown(PointerEventData _) + { + StopAllCoroutines(); + StartCoroutine(cg.ShiftAlpha(1, 0.25f, 1.5f, true)); + } + + public void OnPointerUp(PointerEventData _) + { + StopAllCoroutines(); + StartCoroutine(cg.ShiftAlpha(0, 0.25f, 1.5f, false)); + } +} diff --git a/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuJoinServerPanel.cs b/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuJoinServerPanel.cs index 01747ef3ec..1d2d5ddb22 100644 --- a/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuJoinServerPanel.cs +++ b/NitroxClient/MonoBehaviours/Gui/MainMenu/ServerJoin/MainMenuJoinServerPanel.cs @@ -22,6 +22,7 @@ public class MainMenuJoinServerPanel : MonoBehaviour, uGUI_INavigableIconGrid, u private GameObject playerSettingsPanel; private TextMeshProUGUI header; private uGUI_ColorPicker colorPicker; + private MainMenuColorPickerPreview colorPickerPreview; private Slider saturationSlider; private uGUI_InputField playerNameInputField; @@ -73,6 +74,8 @@ private IEnumerator AsyncSetup(GameObject savedGamesRef) colorPicker.pointer.localScale = new Vector3(1f, 1.46f, 1); saturationSlider = colorPicker.saturationSlider; saturationSlider.transform.localPosition = new Vector3(197, 0, 0); + colorPickerPreview = colorPicker.gameObject.AddComponent(); + colorPickerPreview.Init(colorPicker); GameObject buttonLeft = Instantiate(newGameButtonRef, parent); buttonLeft.GetComponent().sizeDelta = new Vector2(160, 45); @@ -199,6 +202,10 @@ public void SelectItem(object item) if (selectedItem == selectableItems[1]) { colorPicker.pointer.GetComponent().color = Color.cyan; + if (GameInput.GetPrimaryDevice() == GameInput.Device.Controller) + { + colorPickerPreview.OnPointerDown(null); + } } else if (selectedItem == selectableItems[3] || selectedItem == selectableItems[4]) { @@ -233,7 +240,14 @@ public void DeselectItem() } else if (selectedItem.TryGetComponent(out uGUI_ColorPicker selectedColorPicker)) { - selectedColorPicker.pointer.GetComponent().color = Color.white; + Image colorPickerPointer = selectedColorPicker.pointer.GetComponent(); + + if (colorPickerPointer.color != Color.white && + GameInput.GetPrimaryDevice() == GameInput.Device.Controller) + { + colorPickerPreview.OnPointerUp(null); + } + colorPickerPointer.color = Color.white; } else if (selectedItem.TryGetComponentInChildren(out uGUI_BasicColorSwap colorSwap)) { diff --git a/NitroxClient/Unity/Helper/RendererHelpers.cs b/NitroxClient/Unity/Helper/RendererHelpers.cs index 36c8c553d3..3d5835effb 100644 --- a/NitroxClient/Unity/Helper/RendererHelpers.cs +++ b/NitroxClient/Unity/Helper/RendererHelpers.cs @@ -1,105 +1,134 @@ -using NitroxClient.GameLogic.PlayerLogic.PlayerModel.ColorSwap; +using System.Collections; +using NitroxClient.GameLogic.PlayerLogic.PlayerModel.ColorSwap; using UnityEngine; +using UnityEngine.UI; -namespace NitroxClient.Unity.Helper +namespace NitroxClient.Unity.Helper; + +public static class RendererHelpers { - public static class RendererHelpers + //This entire method is necessary in order to deal with the fact that UWE compiles Subnautica in a mode + //that prevents us from accessing the pixel map of the 2D textures they apply to their materials. + public static Texture2D Clone(this Texture2D sourceTexture) { - //This entire method is necessary in order to deal with the fact that UWE compiles Subnautica in a mode - //that prevents us from accessing the pixel map of the 2D textures they apply to their materials. - public static Texture2D Clone(this Texture2D sourceTexture) - { - // Create a temporary RenderTexture of the same size as the texture - RenderTexture tmp = RenderTexture.GetTemporary( - sourceTexture.width, - sourceTexture.height, - 0, - RenderTextureFormat.Default, - RenderTextureReadWrite.Linear); + // Create a temporary RenderTexture of the same size as the texture + RenderTexture tmp = RenderTexture.GetTemporary( + sourceTexture.width, + sourceTexture.height, + 0, + RenderTextureFormat.Default, + RenderTextureReadWrite.Linear); - // Blit the pixels on texture to the RenderTexture - Graphics.Blit(sourceTexture, tmp); - // Backup the currently set RenderTexture - RenderTexture previous = RenderTexture.active; - // Set the current RenderTexture to the temporary one we created - RenderTexture.active = tmp; - // Create a new readable Texture2D to copy the pixels to it - Texture2D clonedTexture = new Texture2D(sourceTexture.width, sourceTexture.height); - // Copy the pixels from the RenderTexture to the new Texture - clonedTexture.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0); - clonedTexture.Apply(); - // Reset the active RenderTexture - RenderTexture.active = previous; - // Release the temporary RenderTexture - RenderTexture.ReleaseTemporary(tmp); + // Blit the pixels on texture to the RenderTexture + Graphics.Blit(sourceTexture, tmp); + // Backup the currently set RenderTexture + RenderTexture previous = RenderTexture.active; + // Set the current RenderTexture to the temporary one we created + RenderTexture.active = tmp; + // Create a new readable Texture2D to copy the pixels to it + Texture2D clonedTexture = new(sourceTexture.width, sourceTexture.height); + // Copy the pixels from the RenderTexture to the new Texture + clonedTexture.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0); + clonedTexture.Apply(); + // Reset the active RenderTexture + RenderTexture.active = previous; + // Release the temporary RenderTexture + RenderTexture.ReleaseTemporary(tmp); - return clonedTexture; - // "clonedTexture" now has the same pixels from "texture" and it's readable. - } + return clonedTexture; + // "clonedTexture" now has the same pixels from "texture" and it's readable. + } - //This applies a color filter to a specific region of a 2D texture. - public static void SwapTextureColors( - this Texture2D texture, - HsvSwapper filter, - TextureBlock textureBlock) - { - Color[] pixels = texture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); + //This applies a color filter to a specific region of a 2D texture. + public static void SwapTextureColors( + this Texture2D texture, + HsvSwapper filter, + TextureBlock textureBlock) + { + Color[] pixels = texture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); - filter.SwapColors(pixels); + filter.SwapColors(pixels); - texture.SetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight, pixels); - texture.Apply(); - } + texture.SetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight, pixels); + texture.Apply(); + } - public static void UpdateMainTextureColors(this Material material, Color[] pixels) - { - Texture2D mainTexture = (Texture2D)material.mainTexture; - mainTexture.SetPixels(pixels); - mainTexture.Apply(); - } + public static void UpdateMainTextureColors(this Material material, Color[] pixels) + { + Texture2D mainTexture = (Texture2D)material.mainTexture; + mainTexture.SetPixels(pixels); + mainTexture.Apply(); + } - //This applies a color filter to a specific region of a 2D texture. - public static void UpdateMainTextureColors( - this Material material, - Color[] pixels, - //IColorSwapStrategy colorSwapStrategy, - TextureBlock textureBlock) - { - Texture2D mainTexture = (Texture2D)material.mainTexture; - //Color[] pixels = mainTexture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); - //pixelIndexes.ForEach(pixelIndex => pixels[pixelIndex] = colorSwapStrategy.SwapColor(pixels[pixelIndex])); - mainTexture.SetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight, pixels); - mainTexture.Apply(); - } + //This applies a color filter to a specific region of a 2D texture. + public static void UpdateMainTextureColors( + this Material material, + Color[] pixels, + //IColorSwapStrategy colorSwapStrategy, + TextureBlock textureBlock) + { + Texture2D mainTexture = (Texture2D)material.mainTexture; + //Color[] pixels = mainTexture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); + //pixelIndexes.ForEach(pixelIndex => pixels[pixelIndex] = colorSwapStrategy.SwapColor(pixels[pixelIndex])); + mainTexture.SetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight, pixels); + mainTexture.Apply(); + } - public static void ApplyClonedTexture(this Material material) - { - Texture2D mainTexture = (Texture2D)material.mainTexture; - Texture2D clonedTexture = mainTexture.Clone(); - material.mainTexture = clonedTexture; - } + public static void ApplyClonedTexture(this Material material) + { + Texture2D mainTexture = (Texture2D)material.mainTexture; + Texture2D clonedTexture = mainTexture.Clone(); + material.mainTexture = clonedTexture; + } + + public static SkinnedMeshRenderer GetRenderer(this GameObject playerModel, string equipmentGameObjectName) + { + return playerModel + .transform + .Find(equipmentGameObjectName) + .gameObject + .GetComponent(); + } + + public static Color[] GetMainTexturePixels(this Material material) + { + Texture2D mainTexture = (Texture2D)material.mainTexture; + return mainTexture.GetPixels(); + } + + public static Color[] GetMainTexturePixelBlock( + this Material material, + TextureBlock textureBlock) + { + Texture2D mainTexture = (Texture2D)material.mainTexture; + return mainTexture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); + } - public static SkinnedMeshRenderer GetRenderer(this GameObject playerModel, string equipmentGameObjectName) + /// Copied from MainMenuLoadButton.ShiftAlpha() + public static IEnumerator ShiftAlpha( + this CanvasGroup cg, + float targetAlpha, + float animTime, + float power, + bool toActive, + Selectable buttonToSelect = null) + { + float start = Time.time; + while (Time.time - start < animTime) { - return playerModel - .transform - .Find(equipmentGameObjectName) - .gameObject - .GetComponent(); + cg.alpha = Mathf.Lerp(cg.alpha, targetAlpha, Mathf.Pow(Mathf.Clamp01((Time.time - start) / animTime), power)); + yield return null; } - - public static Color[] GetMainTexturePixels(this Material material) + cg.alpha = targetAlpha; + if (toActive) { - Texture2D mainTexture = (Texture2D)material.mainTexture; - return mainTexture.GetPixels(); + cg.interactable = true; + cg.blocksRaycasts = true; } - - public static Color[] GetMainTexturePixelBlock( - this Material material, - TextureBlock textureBlock) + else { - Texture2D mainTexture = (Texture2D)material.mainTexture; - return mainTexture.GetPixels(textureBlock.X, textureBlock.Y, textureBlock.BlockWidth, textureBlock.BlockHeight); + cg.interactable = false; + cg.blocksRaycasts = false; } } }