//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// using System; using bs; namespace bs.Editor { /** @addtogroup Windows * @{ */ /// /// A color picker window that allows the user to select from a gamut of colors. /// [DefaultSize(270, 400)] public class ColorPicker : ModalWindow { private const int SliderIndividualWidth = 150; private const int SliderIndividualHeight = 15; private const int ColorBoxWidth = 200; private const int ColorBoxHeight = 200; private const int SliderSideWidth = 40; private const int SliderSideHeight = 200; // Value used by Photoshop private const float MaxOverexposedValue = 191 / 255.0f; private const float MaxExposureRange = 10.0f; private float colRed, colGreen, colBlue; private float colRedHDR, colGreenHDR, colBlueHDR; private float colHue, colSaturation, colValue; private float colAlpha = 1.0f; private float exposure = 0.0f; private bool hdr = false; private ColorSlider1DHorz sliderR, sliderG, sliderB, sliderA; private ColorSlider2D colorBox; private ColorSlider1DVert sideSlider; private ColorBoxMode colorBoxMode = ColorBoxMode.BG_R; private SliderMode sliderMode = SliderMode.HSV; private GUIColorField guiColor; private GUITexture guiSlider2DTex; private GUITexture guiSliderVertTex; private GUITexture guiSliderRHorzTex; private GUITexture guiSliderGHorzTex; private GUITexture guiSliderBHorzTex; private GUITexture guiSliderAHorzTex; private GUIButton guiColorBoxBtn; private GUIButton guiColorModeBtn; private GUISliderV guiSliderVert; private GUISliderH guiSliderRHorz; private GUISliderH guiSliderGHorz; private GUISliderH guiSliderBHorz; private GUISliderH guiSliderAHorz; private GUITexture guiSlider2DHandle; private GUILabel guiLabelR; private GUILabel guiLabelG; private GUILabel guiLabelB; private GUILabel guiLabelA; private GUIIntField guiInputR; private GUIIntField guiInputG; private GUIIntField guiInputB; private GUIIntField guiInputA; private GUILabel guiLabelExposure; private GUISliderH guiSliderExposure; private GUIFloatField guiInputExposure; private GUIButton guiOK; private GUIButton guiCancel; private Action closedCallback; /// /// Determines color gamut shown in the color box. /// public enum ColorBoxMode { BG_R, BR_G, RG_B, SV_H, HV_S, HS_V } /// /// Determines color gamut shown in the horizontal sliders. /// public enum SliderMode { RGB, HSV } /// /// Returns currently selected color as RGBA values. /// public Color SelectedColor { get { if(hdr) return new Color(colRedHDR, colGreenHDR, colBlueHDR, colAlpha); return new Color(colRed, colGreen, colBlue, colAlpha); } } /// /// Currently selected color, suitable for GUI display; /// private Color GUIColor { get { Color color = new Color(colRed, colGreen, colBlue, colAlpha); if (hdr) return color.Gamma; return color; } } /// /// Shows the color picker window. /// /// Optional callback to trigger when the user selects a color or cancels out /// of the dialog. /// If true, the color intensity can be selected along with the color itself. /// A. instance of the color picker window. public static ColorPicker Show(bool hdr = false, Action closedCallback = null) { ColorPicker picker = new ColorPicker(Color.Black, hdr, closedCallback); return picker; } /// /// Shows the color picker window and sets the initial color to show. /// /// Initial color to display. /// If true, the color intensity can be selected along with the color itself. /// Optional callback to trigger when the user selects a color or cancels out /// of the dialog. /// A. instance of the color picker window. public static ColorPicker Show(Color color, bool hdr = false, Action closedCallback = null) { ColorPicker picker = new ColorPicker(color, hdr, closedCallback); return picker; } /// /// Constructs a new color picker window. /// /// Initial color to display. /// If true, the color intensity can be selected along with the color itself. /// Optional callback to trigger when the user selects a color or cancels out /// of the dialog. protected ColorPicker(Color color, bool hdr, Action closedCallback = null) : base(false) { Title = new LocEdString("Color Picker"); colRedHDR = color.r; colGreenHDR = color.g; colBlueHDR = color.b; colAlpha = color.a; this.hdr = hdr; HDRToLDR(); RGBToHSV(); this.closedCallback = closedCallback; } private void OnInitialize() { guiColor = new GUIColorField(); guiColor.SetWidth(100); guiSlider2DTex = new GUITexture(null, GUIOption.FixedHeight(ColorBoxHeight), GUIOption.FixedWidth(ColorBoxWidth)); guiSliderVertTex = new GUITexture(null, GUIOption.FixedHeight(SliderSideHeight), GUIOption.FixedWidth(SliderSideWidth)); guiSliderRHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight)); guiSliderGHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight)); guiSliderBHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight)); guiSliderAHorzTex = new GUITexture(null, GUIOption.FixedHeight(SliderIndividualHeight)); guiColorBoxBtn = new GUIButton(colorBoxMode.ToString()); guiColorModeBtn = new GUIButton(sliderMode.ToString()); guiSliderVert = new GUISliderV(EditorStylesInternal.ColorSliderVert); guiSliderRHorz = new GUISliderH(EditorStylesInternal.ColorSliderHorz); guiSliderGHorz = new GUISliderH(EditorStylesInternal.ColorSliderHorz); guiSliderBHorz = new GUISliderH(EditorStylesInternal.ColorSliderHorz); guiSliderAHorz = new GUISliderH(EditorStylesInternal.ColorSliderHorz); guiSlider2DHandle = new GUITexture(null, EditorStylesInternal.ColorSlider2DHandle); guiLabelR = new GUILabel(new LocEdString("R")); guiLabelG = new GUILabel(new LocEdString("G")); guiLabelB = new GUILabel(new LocEdString("B")); guiLabelA = new GUILabel(new LocEdString("A")); guiInputR = new GUIIntField(); guiInputG = new GUIIntField(); guiInputB = new GUIIntField(); guiInputA = new GUIIntField(); guiOK = new GUIButton(new LocEdString("OK")); guiCancel = new GUIButton(new LocEdString("Cancel")); guiColorBoxBtn.OnClick += OnColorBoxModeChanged; guiColorModeBtn.OnClick += OnSliderModeChanged; guiSliderVert.OnChanged += OnSliderVertChanged; guiSliderRHorz.OnChanged += OnSliderRHorzChanged; guiSliderGHorz.OnChanged += OnSliderGHorzChanged; guiSliderBHorz.OnChanged += OnSliderBHorzChanged; guiSliderAHorz.OnChanged += OnSliderAHorzChanged; guiInputR.OnChanged += OnInputRChanged; guiInputG.OnChanged += OnInputGChanged; guiInputB.OnChanged += OnInputBChanged; guiInputA.OnChanged += OnInputAChanged; guiOK.OnClick += OnOK; guiCancel.OnClick += OnCancel; if (hdr) { guiSliderExposure = new GUISliderH(); guiSliderExposure.SetRange(-MaxExposureRange, MaxExposureRange); guiSliderExposure.OnChanged += OnSliderExposureChanged; guiLabelExposure = new GUILabel(new LocEdString("Exposure")); guiInputExposure = new GUIFloatField(); guiInputExposure.SetRange(-MaxExposureRange, MaxExposureRange); guiInputExposure.OnChanged += OnInputExposureChanged; } GUIPanel mainPanel = GUI.AddPanel(0); mainPanel.SetWidth(ContentWidth); mainPanel.SetHeight(ContentHeight); GUILayout v0 = mainPanel.AddLayoutY(); v0.AddSpace(5); GUILayout h0 = v0.AddLayoutX(); h0.AddSpace(10); h0.AddElement(guiColor); h0.AddFlexibleSpace(); h0.AddElement(guiColorBoxBtn); h0.AddElement(guiColorModeBtn); h0.AddSpace(10); v0.AddSpace(10); GUILayout h1 = v0.AddLayoutX(); h1.AddSpace(10); h1.AddElement(guiSlider2DTex); h1.AddFlexibleSpace(); h1.AddElement(guiSliderVertTex); h1.AddSpace(10); v0.AddSpace(10); GUILayout h2 = v0.AddLayoutX(); h2.AddSpace(10); h2.AddElement(guiLabelR); h2.AddFlexibleSpace(); h2.AddElement(guiSliderRHorzTex); h2.AddFlexibleSpace(); h2.AddElement(guiInputR); h2.AddSpace(10); v0.AddSpace(5); GUILayout h3 = v0.AddLayoutX(); h3.AddSpace(10); h3.AddElement(guiLabelG); h3.AddFlexibleSpace(); h3.AddElement(guiSliderGHorzTex); h3.AddFlexibleSpace(); h3.AddElement(guiInputG); h3.AddSpace(10); v0.AddSpace(5); GUILayout h4 = v0.AddLayoutX(); h4.AddSpace(10); h4.AddElement(guiLabelB); h4.AddFlexibleSpace(); h4.AddElement(guiSliderBHorzTex); h4.AddFlexibleSpace(); h4.AddElement(guiInputB); h4.AddSpace(10); v0.AddSpace(5); GUILayout h5 = v0.AddLayoutX(); h5.AddSpace(10); h5.AddElement(guiLabelA); h5.AddFlexibleSpace(); h5.AddElement(guiSliderAHorzTex); h5.AddFlexibleSpace(); h5.AddElement(guiInputA); h5.AddSpace(10); if (hdr) { v0.AddSpace(5); GUILayout hExposure = v0.AddLayoutX(); hExposure.AddSpace(10); hExposure.AddElement(guiLabelExposure); hExposure.AddFlexibleSpace(); hExposure.AddElement(guiSliderExposure); hExposure.AddFlexibleSpace(); hExposure.AddElement(guiInputExposure); hExposure.AddSpace(10); } v0.AddSpace(10); GUILayout h6 = v0.AddLayoutX(); h6.AddFlexibleSpace(); h6.AddElement(guiOK); h6.AddSpace(10); h6.AddElement(guiCancel); h6.AddFlexibleSpace(); v0.AddSpace(5); GUIPanel overlay = GUI.AddPanel(-1); overlay.SetWidth(ContentWidth); overlay.SetHeight(ContentHeight); overlay.AddElement(guiSliderVert); overlay.AddElement(guiSliderRHorz); overlay.AddElement(guiSliderGHorz); overlay.AddElement(guiSliderBHorz); overlay.AddElement(guiSliderAHorz); overlay.AddElement(guiSlider2DHandle); colorBox = new ColorSlider2D(guiSlider2DTex, guiSlider2DHandle, ColorBoxWidth, ColorBoxHeight); sideSlider = new ColorSlider1DVert(guiSliderVertTex, guiSliderVert, SliderSideWidth, SliderSideHeight); sliderR = new ColorSlider1DHorz(guiSliderRHorzTex, guiSliderRHorz, SliderIndividualWidth, SliderIndividualHeight); sliderG = new ColorSlider1DHorz(guiSliderGHorzTex, guiSliderGHorz, SliderIndividualWidth, SliderIndividualHeight); sliderB = new ColorSlider1DHorz(guiSliderBHorzTex, guiSliderBHorz, SliderIndividualWidth, SliderIndividualHeight); sliderA = new ColorSlider1DHorz(guiSliderAHorzTex, guiSliderAHorz, SliderIndividualWidth, SliderIndividualHeight); colorBox.OnValueChanged += OnColorBoxValueChanged; Color startA = new Color(0, 0, 0, 1); Color stepA = new Color(1, 1, 1, 0); sliderA.UpdateTexture(startA, stepA, false, false); guiInputA.SetRange(0, 255); guiInputA.Value = 255; guiSliderAHorz.Percent = 1.0f; guiColor.Value = GUIColor; UpdateInputBoxValues(); Update2DSliderValues(); Update1DSliderValues(); UpdateSliderMode(); Update2DSliderTextures(); Update1DSliderTextures(); } private void OnEditorUpdate() { Vector2I windowPos = ScreenToWindowPos(Input.PointerPosition); colorBox.UpdateInput(windowPos); } /// /// Fills a 2D area with colors using the provided starting point and gradients. /// /// Width of the area to fill. /// Height of the area to fill. /// Array to contain the output. Must be of /// * size. /// Initial color in the top-left corner of the area. /// Gradient towards which the colors increase to the right of the area. /// Gradient towards which the colors increase to the bottom of the area. private static void FillArea(int width, int height, Color[] colors, Color start, Color rightGradient, Color downGradient) { Color rightDelta = new Color(0, 0, 0, 0); if (width > 1) rightDelta = rightGradient / (width - 1); Color downDelta = new Color(0, 0, 0, 0); if (height > 1) downDelta = downGradient / (height - 1); Color verticalColor = start; for (int y = 0; y < height; y++) { int rowIdx = (height - y - 1) * width; Color currentColor = verticalColor; for (int x = 0; x < width; x++) { colors[rowIdx + x] = currentColor; currentColor += rightDelta; } verticalColor += downDelta; } } /// /// Decomposes a HDR RGB color into a normalized RGB color and an exposure value. /// /// Input HDR color to decompose. /// Output exposure value of the color. /// Output normalized RGB color. private static Color DecomposeHDR(Color hdrColor, out float exposure) { // Note: Replicating Photoshop's behaviour float maxColorComponent = MathEx.Max(hdrColor.r, hdrColor.g, hdrColor.b); if (maxColorComponent == 0.0f || (maxColorComponent >= 1.0f / 255.0f && maxColorComponent < 1.0f)) { exposure = 0.0f; return hdrColor; } else { float scaleFactor = MaxOverexposedValue / maxColorComponent; exposure = MathEx.Log(1.0f / scaleFactor) / MathEx.Log(2); Color output = new Color(); output.r = MathEx.Min(MaxOverexposedValue, scaleFactor * hdrColor.r); output.g = MathEx.Min(MaxOverexposedValue, scaleFactor * hdrColor.g); output.b = MathEx.Min(MaxOverexposedValue, scaleFactor * hdrColor.b); output.a = hdrColor.a; return output; } } /// /// Converts the currently selected HDR RGB color into normalized [0-1] range. This is a no-op if HDR is not /// enabled on the slider. /// void HDRToLDR() { if (hdr) { Color ldrColor = DecomposeHDR( new Color(colRedHDR, colGreenHDR, colBlueHDR, colAlpha), out exposure); colRed = ldrColor.r; colGreen = ldrColor.g; colBlue = ldrColor.b; } else { colRed = colRedHDR; colGreen = colGreenHDR; colBlue = colBlueHDR; } } /// /// Converts the currently selected RGB color to an HDR color using the current exposure value. /// void LDRToHDR() { if (hdr) { colRedHDR = colRed * MathEx.Pow(2.0f, exposure); colGreenHDR = colGreen * MathEx.Pow(2.0f, exposure); colBlueHDR = colBlue * MathEx.Pow(2.0f, exposure); } else { colRedHDR = colRed; colGreenHDR = colGreen; colBlueHDR = colBlue; } } /// /// Converts the currently selected color from HSV to RGB color space. /// void HSVToRGB() { Color hsv = new Color(colHue, colSaturation, colValue); Color rgb = Color.HSV2RGB(hsv); colRed = rgb.r; colGreen = rgb.g; colBlue = rgb.b; } /// /// Converts the currently selected color from RGB to HSV color space. /// void RGBToHSV() { Color rgb = new Color(colRed, colGreen, colBlue); Color hsv = Color.RGB2HSV(rgb); colHue = hsv.r; colSaturation = hsv.g; colValue = hsv.b; } /// /// Triggered when the user selects a new mode for the color box, changing the gamut of colors displayed in the box. /// void OnColorBoxModeChanged() { int maxModes = Enum.GetNames(colorBoxMode.GetType()).Length; colorBoxMode = (ColorBoxMode)(((int)colorBoxMode + 1) % maxModes); guiColorBoxBtn.SetContent(colorBoxMode.ToString()); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user selects a new mode for the side slider, changing the gamut of colors displayed in the /// slider. /// void OnSliderModeChanged() { int maxModes = Enum.GetNames(sliderMode.GetType()).Length; sliderMode = (SliderMode)(((int)sliderMode + 1) % maxModes); UpdateSliderMode(); guiColorModeBtn.SetContent(sliderMode.ToString()); UpdateInputBoxValues(); Update1DSliderTextures(); Update1DSliderValues(); } /// /// Triggered when the user selects a color in the color box. /// /// Location on the color box that was selected. void OnColorBoxValueChanged(Vector2 value) { switch (colorBoxMode) { case ColorBoxMode.BG_R: colBlue = value.x; colGreen = value.y; RGBToHSV(); break; case ColorBoxMode.BR_G: colBlue = value.x; colRed = value.y; RGBToHSV(); break; case ColorBoxMode.RG_B: colRed = value.x; colGreen = value.y; RGBToHSV(); break; case ColorBoxMode.SV_H: colSaturation = value.x; colValue = value.y; HSVToRGB(); break; case ColorBoxMode.HV_S: colHue = value.x; colValue = value.y; HSVToRGB(); break; case ColorBoxMode.HS_V: colHue = value.x; colSaturation = value.y; HSVToRGB(); break; } LDRToHDR(); guiColor.Value = GUIColor; UpdateInputBoxValues(); Update1DSliderTextures(); Update1DSliderValues(); UpdateSideSliderTexture(); Vector2 xy; float z; GetColorBoxValues(out xy, out z); guiSliderVert.Percent = 1.0f - z; } /// /// Triggered when the user moves the side slider. /// /// New value of the slider. void OnSliderVertChanged(float percent) { percent = 1.0f - percent; switch (colorBoxMode) { case ColorBoxMode.BG_R: colRed = percent; RGBToHSV(); break; case ColorBoxMode.BR_G: colGreen = percent; RGBToHSV(); break; case ColorBoxMode.RG_B: colBlue = percent; RGBToHSV(); break; case ColorBoxMode.SV_H: colHue = percent; HSVToRGB(); break; case ColorBoxMode.HV_S: colSaturation = percent; HSVToRGB(); break; case ColorBoxMode.HS_V: colValue = percent; HSVToRGB(); break; } LDRToHDR(); guiColor.Value = GUIColor; UpdateInputBoxValues(); Update1DSliderTextures(); Update1DSliderValues(); } /// /// Triggered when the user moves the horizontal Red/Hue slider. /// /// New value of the slider. void OnSliderRHorzChanged(float percent) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colHue = percent; HSVToRGB(); } else { colRed = percent; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; UpdateInputBoxValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user moves the horizontal Green/Saturation slider. /// /// New value of the slider. void OnSliderGHorzChanged(float percent) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colSaturation = percent; HSVToRGB(); } else { colGreen = percent; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; UpdateInputBoxValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user moves the horizontal Blue/Value slider. /// /// New value of the slider. void OnSliderBHorzChanged(float percent) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colValue = percent; HSVToRGB(); } else { colBlue = percent; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; UpdateInputBoxValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user moves the horizontal alpha slider. /// /// New value of the slider. void OnSliderAHorzChanged(float percent) { colAlpha = percent; guiColor.Value = GUIColor; guiInputA.Value = MathEx.RoundToInt(colAlpha * 255.0f); } /// /// Triggered when the user inputs new value in the Red/Hue input box. /// /// New value in the input box. void OnInputRChanged(int value) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colHue = value/359.0f; HSVToRGB(); } else { colRed = value/255.0f; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; Update1DSliderValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user inputs new value in the Green/Saturation input box. /// /// New value in the input box. void OnInputGChanged(int value) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colSaturation = value / 255.0f; HSVToRGB(); } else { colGreen = value / 255.0f; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; Update1DSliderValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user inputs new value in the Blue/Value input box. /// /// New value in the input box. void OnInputBChanged(int value) { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { colValue = value / 255.0f; HSVToRGB(); } else { colBlue = value / 255.0f; RGBToHSV(); } LDRToHDR(); guiColor.Value = GUIColor; Update1DSliderValues(); Update2DSliderTextures(); Update2DSliderValues(); } /// /// Triggered when the user inputs new value in the alpha input box. /// /// New value in the input box. void OnInputAChanged(int value) { colAlpha = value/255.0f; guiColor.Value = GUIColor; guiSliderAHorz.Percent = colAlpha; } /// /// Triggered when the exposure slider changes. /// /// New exposure value. void OnSliderExposureChanged(float value) { exposure = value; LDRToHDR(); guiSliderExposure.Value = value; } /// /// Triggered when user inputs new value in the exposure input box. /// /// New exposure value. void OnInputExposureChanged(float value) { exposure = value; LDRToHDR(); guiInputExposure.Value = value; } /// /// Triggered when the user selects a color and closes the dialog. /// void OnOK() { if (closedCallback != null) closedCallback(true, SelectedColor); Close(); } /// /// Triggered when the user cancels color selection and closes the dialog. /// void OnCancel() { if (closedCallback != null) closedCallback(false, SelectedColor); Close(); } /// /// Updates Red/Green/Blue or Hue/Saturation/Value labels and input box ranges depending on currently active mode. /// void UpdateSliderMode() { if (sliderMode == SliderMode.RGB) { guiLabelR.SetContent(new LocEdString("R")); guiLabelG.SetContent(new LocEdString("G")); guiLabelB.SetContent(new LocEdString("B")); guiInputR.SetRange(0, 255); guiInputG.SetRange(0, 255); guiInputB.SetRange(0, 255); } else { guiLabelR.SetContent(new LocEdString("H")); guiLabelG.SetContent(new LocEdString("S")); guiLabelB.SetContent(new LocEdString("V")); guiInputR.SetRange(0, 359); guiInputG.SetRange(0, 255); guiInputB.SetRange(0, 255); } } /// /// Updates Red/Green/Blue or Hue/Saturation/Value input boxes with currently selected color. /// void UpdateInputBoxValues() { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { guiInputR.Value = MathEx.RoundToInt(colHue * 359.0f); guiInputG.Value = MathEx.RoundToInt(colSaturation * 255.0f); guiInputB.Value = MathEx.RoundToInt(colValue * 255.0f); } else { guiInputR.Value = MathEx.RoundToInt(colRed * 255.0f); guiInputG.Value = MathEx.RoundToInt(colGreen * 255.0f); guiInputB.Value = MathEx.RoundToInt(colBlue * 255.0f); } if (hdr) guiInputExposure.Value = exposure; } /// /// Updates Red/Green/Blue or Hue/Saturation/Value sliders with currently selected color. /// void Update1DSliderValues() { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { guiSliderRHorz.Percent = colHue; guiSliderGHorz.Percent = colSaturation; guiSliderBHorz.Percent = colValue; } else { guiSliderRHorz.Percent = colRed; guiSliderGHorz.Percent = colGreen; guiSliderBHorz.Percent = colBlue; } if (hdr) guiSliderExposure.Value = exposure; } /// /// Returns the current color in the form of color box and side slider coordinates. /// /// Coordinates on the color box the current color is located on. /// Coordinates on the side slider the current color is located on. void GetColorBoxValues(out Vector2 xy, out float z) { xy = Vector2.Zero; z = 0.0f; switch (colorBoxMode) { case ColorBoxMode.BG_R: xy.x = colBlue; xy.y = colGreen; z = colRed; break; case ColorBoxMode.BR_G: xy.x = colBlue; xy.y = colRed; z = colGreen; break; case ColorBoxMode.RG_B: xy.x = colRed; xy.y = colGreen; z = colBlue; break; case ColorBoxMode.SV_H: xy.x = colSaturation; xy.y = colValue; z = colHue; break; case ColorBoxMode.HV_S: xy.x = colHue; xy.y = colValue; z = colSaturation; break; case ColorBoxMode.HS_V: xy.x = colHue; xy.y = colSaturation; z = colValue; break; } } /// /// Updates values of the color box and side slider according to the current color. /// void Update2DSliderValues() { Vector2 xy = Vector2.Zero; float z = 0.0f; GetColorBoxValues(out xy, out z); colorBox.SetValue(xy); guiSliderVert.Percent = z; } /// /// Generates textures to display for all horizontal (RGB/HSV) sliders depending on active slider mode. /// void Update1DSliderTextures() { bool isHSV = sliderMode == SliderMode.HSV; if (isHSV) { Color startH = new Color(0, 1, 1); Color stepH = new Color(1, 0, 0, 0); sliderR.UpdateTexture(startH, stepH, true, false); Color startS = new Color(colHue, 0, MathEx.Max(colValue, 0.2f)); Color stepS = new Color(0, 1, 0, 0); sliderG.UpdateTexture(startS, stepS, true, false); Color startV = new Color(colHue, colSaturation, 0); Color stepV = new Color(0, 0, 1, 0); sliderB.UpdateTexture(startV, stepV, true, false); } else { Color startR = new Color(0, colGreen, colBlue); Color stepR = new Color(1, 0, 0, 0); sliderR.UpdateTexture(startR, stepR, false, hdr); Color startG = new Color(colRed, 0, colBlue); Color stepG = new Color(0, 1, 0, 0); sliderG.UpdateTexture(startG, stepG, false, hdr); Color startB = new Color(colRed, colGreen, 0); Color stepB = new Color(0, 0, 1, 0); sliderB.UpdateTexture(startB, stepB, false, hdr); } } /// /// Generates a texture for the side slider depending on active color box mode. /// void UpdateSideSliderTexture() { switch (colorBoxMode) { case ColorBoxMode.BG_R: sideSlider.UpdateTexture(new Color(0, colGreen, colBlue, 1), new Color(1, 0, 0, 0), false, hdr); break; case ColorBoxMode.BR_G: sideSlider.UpdateTexture(new Color(colRed, 0, colBlue, 1), new Color(0, 1, 0, 0), false, hdr); break; case ColorBoxMode.RG_B: sideSlider.UpdateTexture(new Color(colRed, colGreen, 0, 1), new Color(0, 0, 1, 0), false, hdr); break; case ColorBoxMode.SV_H: sideSlider.UpdateTexture(new Color(0, 1, 1, 1), new Color(1, 0, 0, 0), true, false); break; case ColorBoxMode.HV_S: sideSlider.UpdateTexture(new Color(colHue, 0, MathEx.Max(colValue, 0.2f), 1), new Color(0, 1, 0, 0), true, false); break; case ColorBoxMode.HS_V: sideSlider.UpdateTexture(new Color(colHue, colSaturation, 0, 1), new Color(0, 0, 1, 0), true, false); break; } } /// /// Generates textures for the color box and the side slider depending on active color box mode. /// void Update2DSliderTextures() { UpdateSideSliderTexture(); float[] valueLookup = new float[] { colRed, colGreen, colBlue, colHue, colSaturation, colValue }; colorBox.UpdateTexture(colorBoxMode, valueLookup[(int)colorBoxMode]); } /// /// Manages GUI for a 1D horizontal slider (used RGB/HSV display). /// public class ColorSlider1DHorz { private const int SLIDER_X_OFFSET = 3; private const int SLIDER_Y_OFFSET = 5; private int width, height; private Texture texture; private SpriteTexture spriteTexture; private GUITexture guiTexture; private GUISliderH guiSlider; /// /// Creates a new horizontal slider. /// /// GUI element to display the slider color range on. /// Slider rendered on top of the texture that may be moved by the user to select a /// color. /// Width of the slider in pixels. /// Height of the slider in pixels. public ColorSlider1DHorz(GUITexture guiTexture, GUISliderH guiSlider, int width, int height) { this.width = width; this.height = height; this.guiTexture = guiTexture; this.guiSlider = guiSlider; texture = Texture.Create2D(width, height); spriteTexture = new SpriteTexture(texture); } /// /// Updates the displayed texture with specified color information. /// /// Initial color on the left of the slider. /// Final color to the right of the slider. /// Determines are the provided colors in RGB or HSV space. /// True if the provided colors are in linear color space. public void UpdateTexture(Color start, Color step, bool isHSV, bool isLinear) { Color[] colors = new Color[width * height]; FillArea(width, height, colors, start, step, new Color(0, 0, 0, 0)); if (isHSV) { for (int i = 0; i < colors.Length; i++) colors[i] = Color.HSV2RGB(colors[i]); } else { // If RGB, convert to gamma space if needed if (isLinear) { for (int i = 0; i < colors.Length; i++) colors[i] = colors[i].Gamma; } } texture.SetPixels(colors); guiTexture.SetTexture(spriteTexture); Rect2I sliderBounds = guiTexture.Bounds; sliderBounds.x -= SLIDER_X_OFFSET; sliderBounds.width += SLIDER_X_OFFSET * 2; sliderBounds.y -= SLIDER_Y_OFFSET; sliderBounds.height += SLIDER_Y_OFFSET; guiSlider.Bounds = sliderBounds; } } /// /// Manages GUI for a 1D vertical slider (side slider along with the color box). /// public class ColorSlider1DVert { private const int SLIDER_X_OFFSET = 5; private const int SLIDER_Y_OFFSET = 3; private int width, height; private Texture texture; private SpriteTexture spriteTexture; private GUITexture guiTexture; private GUISliderV guiSlider; /// /// Creates a new vertical slider. /// /// GUI element to display the slider color range on. /// Slider rendered on top of the texture that may be moved by the user to select a /// color. /// Width of the slider in pixels. /// Height of the slider in pixels. public ColorSlider1DVert(GUITexture guiTexture, GUISliderV guiSlider, int width, int height) { this.width = width; this.height = height; this.guiTexture = guiTexture; this.guiSlider = guiSlider; texture = Texture.Create2D(width, height); spriteTexture = new SpriteTexture(texture); } /// /// Updates the displayed texture with specified color information. /// /// Initial color on the top of the slider. /// Final color to the bottom of the slider. /// Determines are the provided colors in RGB or HSV space. /// True if the provided colors are in linear color space. public void UpdateTexture(Color start, Color step, bool isHSV, bool isLinear) { Color[] colors = new Color[width * height]; FillArea(width, height, colors, start, new Color(0, 0, 0, 0), step); if (isHSV) { for (int i = 0; i < colors.Length; i++) colors[i] = Color.HSV2RGB(colors[i]); } else { // If RGB, convert to gamma space if needed if (isLinear) { for (int i = 0; i < colors.Length; i++) colors[i] = colors[i].Gamma; } } texture.SetPixels(colors); guiTexture.SetTexture(spriteTexture); Rect2I sliderBounds = guiTexture.Bounds; sliderBounds.x -= SLIDER_X_OFFSET; sliderBounds.width += SLIDER_X_OFFSET; sliderBounds.y -= SLIDER_Y_OFFSET; sliderBounds.height += SLIDER_Y_OFFSET * 2; guiSlider.Bounds = sliderBounds; } } /// /// Manages GUI for a 2D color box, as well as manually handling color box input. Color box serves as a 2D sliders /// as you can portion of it to select a color. /// public class ColorSlider2D { private int width, height; private Texture texture; private SpriteTexture spriteTexture; private GUITexture guiTexture; private GUITexture guiSliderHandle; private Vector2 oldValue = new Vector2(-1, -1); public delegate void OnValueChangedDelegate(Vector2 value); public event OnValueChangedDelegate OnValueChanged; /// /// Creates a new color box. /// /// GUI element to display the 2D color range on. /// Texture to be used for displaying the position of the currently selected /// color. /// Width of the slider in pixels. /// Height of the slider in pixels. public ColorSlider2D(GUITexture guiTexture, GUITexture guiSliderHandle, int width, int height) { this.width = width; this.height = height; this.guiTexture = guiTexture; this.guiSliderHandle = guiSliderHandle; texture = Texture.Create2D(width, height); spriteTexture = new SpriteTexture(texture); } /// /// Updates the texture displayed on the color box. /// /// Mode determining the color gamut shown in the color box. /// Value of the third component (normally retrieved from the separate side slider). public void UpdateTexture(ColorBoxMode mode, float value) { Color[] colors = new Color[width * height]; switch (mode) { case ColorBoxMode.BG_R: FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 0, 1, 0), new Color(0, 1, 0, 0)); break; case ColorBoxMode.BR_G: FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(0, 0, 1, 0), new Color(1, 0, 0, 0)); break; case ColorBoxMode.RG_B: FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0)); break; case ColorBoxMode.SV_H: FillArea(width, height, colors, new Color(value, 0, 0, 1), new Color(0, 1, 0, 0), new Color(0, 0, 1, 0)); for (int i = 0; i < colors.Length; i++) colors[i] = Color.HSV2RGB(colors[i]); break; case ColorBoxMode.HV_S: FillArea(width, height, colors, new Color(0, value, 0, 1), new Color(1, 0, 0, 0), new Color(0, 0, 1, 0)); for (int i = 0; i < colors.Length; i++) colors[i] = Color.HSV2RGB(colors[i]); break; case ColorBoxMode.HS_V: FillArea(width, height, colors, new Color(0, 0, value, 1), new Color(1, 0, 0, 0), new Color(0, 1, 0, 0)); for (int i = 0; i < colors.Length; i++) colors[i] = Color.HSV2RGB(colors[i]); break; } texture.SetPixels(colors); guiTexture.SetTexture(spriteTexture); } /// /// Handles input over the color box, moving the handle as needed. /// /// Position of the pointer relative to the color picker window. public void UpdateInput(Vector2I windowPos) { if (Input.IsPointerButtonHeld(PointerButton.Left)) { Rect2I bounds = guiTexture.Bounds; if (bounds.Contains(windowPos)) { Vector2 newValue = Vector2.Zero; newValue.x = (windowPos.x - bounds.x) / (float)bounds.width; newValue.y = 1.0f - (windowPos.y - bounds.y) / (float)bounds.height; SetValue(newValue); } } } /// /// Moves the handle to a specific location on the color box and selects that color. /// /// Coordinates relative to the color box. public void SetValue(Vector2 value) { Vector2 pos = value; pos.y = 1.0f - pos.y; if (oldValue == value) return; Rect2I handleBounds = guiSliderHandle.Bounds; Rect2I boxBounds = guiTexture.Bounds; handleBounds.x = boxBounds.x + MathEx.RoundToInt(pos.x * boxBounds.width) - handleBounds.width / 2; handleBounds.y = boxBounds.y + MathEx.RoundToInt(pos.y * boxBounds.height) - handleBounds.height / 2; guiSliderHandle.Bounds = handleBounds; oldValue = value; if (OnValueChanged != null) OnValueChanged(value); } } } /** @} */ }