2
0
Marko Pintera 11 жил өмнө
parent
commit
f4e58bdc79

+ 17 - 0
BansheeCore/Include/BsPixelData.h

@@ -316,6 +316,13 @@ namespace BansheeEngine
 		 */
 		void setColors(const Vector<Color>& colors);
 
+		/**
+		 * @brief	Initializes the internal buffer with the provided set of colors.
+		 *			The array should be of width * height * depth size and mapped
+		 *			as such: arrayIdx = x + y * width + z * width * height.
+		 */
+		void setColors(Color* colors, UINT32 numElements);
+
 	private:
 		/**
 		 * @brief	Set the rowPitch and slicePitch so that the buffer is laid out consecutive
@@ -327,6 +334,16 @@ namespace BansheeEngine
 			mSlicePitch = getWidth()*getHeight();
 		}
 
+		/**
+		 * @brief	Initializes the internal buffer with the provided set of colors.
+		 *			The array should be of width * height * depth size and mapped
+		 *			as such: arrayIdx = x + y * width + z * width * height.
+		 *
+		 * @note	A generic method that is reused in other more specific "setColors" calls.
+		 */
+		template<class T>
+		void setColorsInternal(const T& colors, UINT32 numElements);
+
 		/**
 		 * @brief	Returns the needed size of the internal buffer, in bytes.
 		 */

+ 17 - 3
BansheeCore/Source/BsPixelData.cpp

@@ -122,16 +122,17 @@ namespace BansheeEngine
 		return colors;
 	}
 
-	void PixelData::setColors(const Vector<Color>& colors)
+	template<class T>
+	void PixelData::setColorsInternal(const T& colors, UINT32 numElements)
 	{
 		UINT32 depth = mExtents.getDepth();
 		UINT32 height = mExtents.getHeight();
 		UINT32 width = mExtents.getWidth();
 
 		UINT32 totalNumElements = width * height * depth;
-		if (colors.size() != totalNumElements)
+		if (numElements != totalNumElements)
 		{
-			LOGERR("Unable to set colors, invalid array size.")
+			LOGERR("Unable to set colors, invalid array size.");
 			return;
 		}
 
@@ -160,6 +161,19 @@ namespace BansheeEngine
 		}
 	}
 
+	template BS_CORE_EXPORT void PixelData::setColorsInternal(Color* const &, UINT32);
+	template BS_CORE_EXPORT void PixelData::setColorsInternal(const Vector<Color>&, UINT32);
+
+	void PixelData::setColors(const Vector<Color>& colors)
+	{
+		setColorsInternal(colors, (UINT32)colors.size());
+	}
+
+	void PixelData::setColors(Color* colors, UINT32 numElements)
+	{
+		setColorsInternal(colors, numElements);
+	}
+
 	UINT32 PixelData::getInternalBufferSize()
 	{
 		return getSize();

+ 761 - 0
MBansheeEditor/ColorPicker.cs

@@ -0,0 +1,761 @@
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    public class ColorPicker : ModalWindow
+    {
+        private const int SliderIndividualWidth = 150;
+        private const int SliderIndividualHeight = 20;
+
+        private const int ColorBoxWidth = 150;
+        private const int ColorBoxHeight = 150;
+
+        private const int SliderSideWidth = 40;
+        private const int SliderSideHeight = 150;
+
+        private float colRed, colGreen, colBlue;
+        private float colHue, colSaturation, colValue;
+        private float colAlpha = 1.0f;
+
+        private ColorSlider1DHorz sliderR, sliderG, sliderB;
+        private ColorSlider2D colorBox;
+        private ColorSlider1DVert sideSlider;
+
+        private ColorBoxMode colorBoxMode;
+        private SliderMode sliderMode;
+
+        private GUIColorField guiColor;
+        private GUITexture guiSlider2DTex;
+        private GUITexture guiSliderVertTex;
+        private GUITexture guiSliderRHorzTex;
+        private GUITexture guiSliderGHorzTex;
+        private GUITexture guiSliderBHorzTex;
+
+        private GUIButton guiColorBoxBtn;
+        private GUIButton guiColorModeBtn;
+
+        private GUISliderV guiSliderVert;
+        private GUISliderH guiSliderRHorz;
+        private GUISliderH guiSliderGHorz;
+        private GUISliderH guiSliderBHorz;
+        private GUITexture guiSlider2DHandle;
+
+        private GUILabel guiLabelR;
+        private GUILabel guiLabelG;
+        private GUILabel guiLabelB;
+
+        private GUIIntField guiInputR;
+        private GUIIntField guiInputG;
+        private GUIIntField guiInputB;
+
+        public enum ColorBoxMode
+        {
+            BG_R,
+            BR_G,
+            RG_B,
+            SV_H,
+            HV_S,
+            HS_V
+        }
+
+        public enum SliderMode
+        {
+            RGB,
+            HSV
+        }
+
+        public Color SelectedColor
+        {
+            get
+            {
+                return new Color(colRed, colGreen, colBlue, colAlpha);
+            }
+        }
+
+        public static ColorPicker Show()
+        {
+            return new ColorPicker();
+        }
+
+        protected ColorPicker()
+            : base(false)
+        {
+            Title = "Color Picker";
+            Width = 250;
+            Height = 75;
+        }
+
+        private void OnInitialize()
+        {
+            guiColor = new GUIColorField();
+            guiSlider2DTex = new GUITexture(null);
+            guiSliderVertTex = new GUITexture(null);
+            guiSliderRHorzTex = new GUITexture(null);
+            guiSliderGHorzTex = new GUITexture(null);
+            guiSliderBHorzTex = new GUITexture(null);
+
+            guiColorBoxBtn = new GUIButton(colorBoxMode.ToString());
+            guiColorModeBtn = new GUIButton(sliderMode.ToString());
+
+            guiSliderVert = new GUISliderV();
+            guiSliderRHorz = new GUISliderH();
+            guiSliderGHorz = new GUISliderH();
+            guiSliderBHorz = new GUISliderH();
+            guiSlider2DHandle = new GUITexture(null);
+
+            guiLabelR = new GUILabel("R");
+            guiLabelG = new GUILabel("G");
+            guiLabelB = new GUILabel("B");
+
+            guiInputR = new GUIIntField();
+            guiInputG = new GUIIntField();
+            guiInputB = new GUIIntField();
+
+            guiColorBoxBtn.OnClick += OnColorBoxModeChanged;
+            guiColorModeBtn.OnClick += OnSliderModeChanged;
+
+            guiSliderVert.OnChanged += OnSliderVertChanged;
+            guiSliderRHorz.OnChanged += OnSliderRHorzChanged;
+            guiSliderGHorz.OnChanged += OnSliderGHorzChanged;
+            guiSliderBHorz.OnChanged += OnSliderBHorzChanged;
+
+            guiInputR.OnChanged += OnInputRChanged;
+            guiInputG.OnChanged += OnInputGChanged;
+            guiInputB.OnChanged += OnInputBChanged;
+
+            GUILayout v0 = GUI.layout.AddLayoutY();
+
+            GUILayout h0 = v0.AddLayoutX();
+            h0.AddElement(guiColor);
+            h0.AddFlexibleSpace();
+            h0.AddElement(guiColorBoxBtn);
+            h0.AddElement(guiColorModeBtn);
+
+            v0.AddSpace(20);
+
+            GUILayout h1 = v0.AddLayoutX();
+            h1.AddElement(guiSlider2DTex);
+            h1.AddFlexibleSpace();
+            h1.AddElement(guiSliderVertTex);
+            h1.AddSpace(10);
+
+            v0.AddSpace(30);
+
+            GUILayout h2 = v0.AddLayoutX();
+            h2.AddElement(guiLabelR);
+            h2.AddFlexibleSpace();
+            h2.AddElement(guiSliderRHorzTex);
+            h2.AddFlexibleSpace();
+            h2.AddElement(guiInputR);
+
+            GUILayout h3 = v0.AddLayoutX();
+            h3.AddElement(guiLabelG);
+            h3.AddFlexibleSpace();
+            h3.AddElement(guiSliderGHorzTex);
+            h3.AddFlexibleSpace();
+            h3.AddElement(guiInputG);
+
+            GUILayout h4 = v0.AddLayoutX();
+            h4.AddElement(guiLabelB);
+            h4.AddFlexibleSpace();
+            h4.AddElement(guiSliderBHorzTex);
+            h4.AddFlexibleSpace();
+            h4.AddElement(guiInputB);
+
+            GUIArea overlay = GUI.AddArea(0, 0, Width, Height, -1); // TODO - Create an area with explicit layout here
+            overlay.layout.AddElement(guiSliderVert);
+            overlay.layout.AddElement(guiSliderRHorz);
+            overlay.layout.AddElement(guiSliderGHorz);
+            overlay.layout.AddElement(guiSliderBHorz);
+            overlay.layout.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);
+
+            colorBox.OnValueChanged += OnColorBoxValueChanged;
+
+            // TODO
+            //WHen slider value changes convert RGB->HSV and vice versa as needed
+            //Actually position overlay elements
+            //Add alpha slider
+        }
+
+        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;
+            int idx = 0;
+            for (int y = 0; y < height; y++)
+            {
+                Color currentColor = verticalColor;
+                for (int x = 0; x < width; x++)
+                {
+                    colors[idx++] = currentColor;
+                    currentColor += rightDelta;
+                }
+                verticalColor += downDelta;
+            }
+        }
+
+        void HSVToRGB()
+        {
+            Color hsv = new Color(colHue, colSaturation, colValue);
+            Color rgb = Color.HSV2RGB(hsv);
+
+            colRed = rgb.r;
+            colGreen = rgb.g;
+            colBlue = rgb.b;
+        }
+
+        void RGBToHSV()
+        {
+            Color rgb = new Color(colRed, colGreen, colBlue);
+            Color hsv = Color.RGB2HSV(rgb);
+
+            colHue = hsv.r;
+            colSaturation = hsv.g;
+            colValue = hsv.b;
+        }
+
+        void OnColorBoxModeChanged()
+        {
+            int maxModes = Enum.GetNames(colorBoxMode.GetType()).Length;
+            colorBoxMode = (ColorBoxMode)(((int)colorBoxMode + 1) % maxModes);
+
+            guiColorBoxBtn.SetContent(colorBoxMode.ToString());
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnSliderModeChanged()
+        {
+            int maxModes = Enum.GetNames(sliderMode.GetType()).Length;
+            sliderMode = (SliderMode)(((int)sliderMode + 1) % maxModes);
+
+            if (sliderMode == SliderMode.RGB)
+            {
+                guiLabelR.SetContent("R");
+                guiLabelG.SetContent("G");
+                guiLabelB.SetContent("B");
+
+                guiInputR.SetRange(0, 255);
+                guiInputG.SetRange(0, 255);
+                guiInputB.SetRange(0, 255);
+            }
+            else
+            {
+                guiLabelR.SetContent("H");
+                guiLabelG.SetContent("S");
+                guiLabelB.SetContent("V");
+
+                guiInputR.SetRange(0, 359);
+                guiInputG.SetRange(0, 255);
+                guiInputB.SetRange(0, 255);
+            }
+
+            guiColorModeBtn.SetContent(sliderMode.ToString());
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+        }
+
+        void OnColorBoxValueChanged(Vector2 value)
+        {
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    colGreen = value.x;
+                    colBlue = value.y;
+                    RGBToHSV();
+                    break;
+                case ColorBoxMode.BR_G:
+                    colRed = value.x;
+                    colBlue = 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;
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+        }
+
+        void OnSliderVertChanged(float 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;
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update1DSliderTextures();
+            Update1DSliderValues();
+        }
+
+        void OnSliderRHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colHue = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colRed = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnSliderGHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colSaturation = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colGreen = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnSliderBHorzChanged(float percent)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colValue = percent;
+                HSVToRGB();
+            }
+            else
+            {
+                colBlue = percent;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            UpdateInputBoxValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnInputRChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colHue = value/359.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colRed = value/255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnInputGChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colSaturation = value / 255.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colGreen = value / 255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        void OnInputBChanged(int value)
+        {
+            bool isHSV = sliderMode == SliderMode.HSV;
+            if (isHSV)
+            {
+                colValue = value / 255.0f;
+                HSVToRGB();
+            }
+            else
+            {
+                colBlue = value / 255.0f;
+                RGBToHSV();
+            }
+
+            guiColor.Value = SelectedColor;
+            Update1DSliderValues();
+            Update2DSliderTextures();
+            Update2DSliderValues();
+        }
+
+        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);
+            }
+        }
+
+        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;
+            }
+        }
+
+        void Update2DSliderValues()
+        {
+            Vector2 xy = Vector2.zero;
+            float z = 0.0f;
+
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    xy.x = colBlue;
+                    xy.y = colGreen;
+                    z = colRed;
+                    break;
+                case ColorBoxMode.BR_G:
+                    xy.x = colRed;
+                    xy.y = colBlue;
+                    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;
+            }
+
+            colorBox.SetValue(xy);
+            guiSliderVert.Percent = z;
+        }
+
+        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, false);
+
+                Color startS = new Color(colHue, 0, MathEx.Max(colValue, 0.2f));
+                Color stepS = new Color(0, 1, 0, 0);
+
+                sliderG.UpdateTexture(startS, stepS, false);
+
+                Color startV = new Color(colHue, colSaturation, 0);
+                Color stepV = new Color(0, 0, 1, 0);
+
+                sliderB.UpdateTexture(startV, stepV, false);
+            }
+            else
+            {
+                Color startR = new Color(0, colGreen, colBlue);
+                Color stepR = new Color(1, 0, 0, 0);
+
+                sliderR.UpdateTexture(startR, stepR, false);
+
+                Color startG = new Color(colRed, 0, colBlue);
+                Color stepG = new Color(0, 1, 0, 0);
+
+                sliderG.UpdateTexture(startG, stepG, false);
+
+                Color startB = new Color(colRed, colGreen, 0);
+                Color stepB = new Color(0, 0, 1, 0);
+
+                sliderB.UpdateTexture(startB, stepB, false);
+            }
+        }
+
+        void Update2DSliderTextures()
+        {
+            switch (colorBoxMode)
+            {
+                case ColorBoxMode.BG_R:
+                    sideSlider.UpdateTexture(new Color(0, colGreen, colBlue, 1), new Color(1, 0, 0, 0), false);
+                    break;
+                case ColorBoxMode.BR_G:
+                    sideSlider.UpdateTexture(new Color(colRed, 0, colBlue, 1), new Color(0, 1, 0, 0), false);
+                    break;
+                case ColorBoxMode.RG_B:
+                    sideSlider.UpdateTexture(new Color(colRed, colGreen, 0, 1), new Color(0, 0, 1, 0), false);
+                    break;
+                case ColorBoxMode.SV_H:
+                    sideSlider.UpdateTexture(new Color(0, 1, 1, 1), new Color(1, 0, 0, 0), true);
+                    break;
+                case ColorBoxMode.HV_S:
+                    sideSlider.UpdateTexture(new Color(colHue, 0, MathEx.Max(colValue, 0.2f), 1), new Color(0, 1, 0, 0), true);
+                    break;
+                case ColorBoxMode.HS_V:
+                    sideSlider.UpdateTexture(new Color(colHue, colSaturation, 0, 1), new Color(0, 0, 1, 0), true);
+                    break;
+            }
+
+            float[] valueLookup = new float[] { colRed, colGreen, colBlue, colHue, colSaturation, colValue };
+            colorBox.UpdateTexture(colorBoxMode, valueLookup[(int)colorBoxMode]);
+        }
+
+        public class ColorSlider1DHorz
+        {
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUISliderH guiSlider;
+
+            public ColorSlider1DHorz(GUITexture guiTexture, GUISliderH guiSlider, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+                this.guiTexture = guiTexture;
+                this.guiSlider = guiSlider;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            public void UpdateTexture(Color start, Color step, bool isHSV)
+            {
+                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]);
+                }
+
+                texture.SetPixels(colors);
+                guiTexture.SetTexture(spriteTexture);
+            }
+        }
+
+        public class ColorSlider1DVert
+        {
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUISliderV guiSlider;
+
+            public ColorSlider1DVert(GUITexture guiTexture, GUISliderV guiSlider, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+                this.guiTexture = guiTexture;
+                this.guiSlider = guiSlider;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            public void UpdateTexture(Color start, Color step, bool isHSV)
+            {
+                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]);
+                }
+
+                texture.SetPixels(colors);
+                guiTexture.SetTexture(spriteTexture);
+            }
+        }
+
+        public class ColorSlider2D
+        {
+            private int width, height;
+            private Texture2D texture;
+            private SpriteTexture spriteTexture;
+
+            private GUITexture guiTexture;
+            private GUITexture guiSliderHandle;
+
+            public delegate void OnValueChangedDelegate(Vector2 value);
+            public event OnValueChangedDelegate OnValueChanged;
+
+            public ColorSlider2D(GUITexture guiTexture, GUITexture guiSliderHandle, int width, int height)
+            {
+                this.width = width;
+                this.height = height;
+
+                this.guiTexture = guiTexture;
+                this.guiSliderHandle = guiSliderHandle;
+
+                texture = new Texture2D(width, height);
+                spriteTexture = new SpriteTexture(texture);
+            }
+
+            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);
+            }
+
+            public void UpdateInput()
+            {
+                // TODO - Detect mouse input over GUITexture, detect coordinates and update gui slider handle position
+                // TODO - Trigger OnValueChanged as needed
+            }
+
+            public void SetValue(Vector2 value)
+            {
+                // TODO - Move the handle to this position
+            }
+        }
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -40,6 +40,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="BrowseDialog.cs" />
+    <Compile Include="ColorPicker.cs" />
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgEditorWindow.cs" />
     <Compile Include="DbgGizmo.cs" />

+ 102 - 0
MBansheeEngine/Color.cs

@@ -118,6 +118,108 @@ namespace BansheeEngine
             return !(lhs == rhs);
         }
 
+        public static Color RGB2HSV(Color input)
+        {
+            Color output = input;
+
+            float min = input.r < input.g ? input.r : input.g;
+            min = min < input.b ? min : input.b;
+
+            float max = input.r > input.g ? input.r : input.g;
+            max = max > input.b ? max : input.b;
+
+            output.b = max;
+
+            float delta = max - min;
+            if (max > 0.0f)
+                output.g = (delta / max);
+            else
+            {
+                output.g = 0.0f;
+                output.r = float.NaN;
+                return output;
+            }
+
+            if (input.r >= max)
+                output.r = (input.g - input.b) / delta;
+            else
+            {
+                if (input.g >= max)
+                    output.r = 2.0f + (input.b - input.r) / delta;
+                else
+                    output.r = 4.0f + (input.r - input.g) / delta;
+            }
+
+            output.r /= 6.0f;
+
+            if (output.r < 0.0f)
+                output.r += 1.0f;
+
+            return output;
+        }
+
+        public static Color HSV2RGB(Color input)
+        {
+            Color output = input;
+
+            if (input.g <= 0.0)
+            {
+                output.r = input.b;
+                output.g = input.b;
+                output.b = input.b;
+
+                return output;
+            }
+
+            float hh = input.r;
+            if (hh >= 1.0f)
+                hh = 0.0f;
+
+            hh *= 6.0f;
+
+            int i = (int)hh;
+            float ff = hh - i;
+            float p = input.b * (1.0f - input.g);
+            float q = input.b * (1.0f - (input.g * ff));
+            float t = input.b * (1.0f - (input.g * (1.0f - ff)));
+
+            switch (i)
+            {
+                case 0:
+                    output.r = input.b;
+                    output.g = t;
+                    output.b = p;
+                    break;
+                case 1:
+                    output.r = q;
+                    output.g = input.b;
+                    output.b = p;
+                    break;
+                case 2:
+                    output.r = p;
+                    output.g = input.b;
+                    output.b = t;
+                    break;
+                case 3:
+                    output.r = p;
+                    output.g = q;
+                    output.b = input.b;
+                    break;
+                case 4:
+                    output.r = t;
+                    output.g = p;
+                    output.b = input.b;
+                    break;
+                default:
+                    output.r = input.b;
+                    output.g = p;
+                    output.b = q;
+                    break;
+            }
+
+            return output;
+        }
+
         public override int GetHashCode()
         {
             return r.GetHashCode() ^ g.GetHashCode() << 2 ^ b.GetHashCode() >> 2 ^ a.GetHashCode() >> 1;

+ 4 - 4
MBansheeEngine/GUI/GUIArea.cs

@@ -29,7 +29,7 @@ namespace BansheeEngine
         }
 
         // Note: Should only ever be called by its parent GUIPanel
-        internal static GUIArea Create(GUIPanel parent, int x, int y, int width, int height, UInt16 depth)
+        internal static GUIArea Create(GUIPanel parent, int x, int y, int width, int height, Int16 depth)
         {
             GUIArea newArea = new GUIArea();
             Internal_CreateInstance(newArea, parent, x, y, width, height, depth);
@@ -38,7 +38,7 @@ namespace BansheeEngine
             return newArea;
         }
 
-        public void SetArea(int x, int y, int width, int height, UInt16 depth = 0)
+        public void SetArea(int x, int y, int width, int height, Int16 depth = 0)
         {
             Internal_SetArea(mCachedPtr, x, y, width, height, depth);
         }
@@ -63,10 +63,10 @@ namespace BansheeEngine
         }
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(GUIArea instance, GUIPanel parent, int x, int y, int width, int height, UInt16 depth);
+        private static extern void Internal_CreateInstance(GUIArea instance, GUIPanel parent, int x, int y, int width, int height, Int16 depth);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetArea(IntPtr nativeInstance, int x, int y, int width, int height, UInt16 depth);
+        private static extern void Internal_SetArea(IntPtr nativeInstance, int x, int y, int width, int height, Int16 depth);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Destroy(IntPtr nativeInstance);

+ 1 - 1
MBansheeEngine/GUI/GUIPanel.cs

@@ -29,7 +29,7 @@ namespace BansheeEngine
             _mainLayout = mainArea.layout;
         }
 
-        public GUIArea AddArea(int x, int y, int width, int height, UInt16 depth = 0)
+        public GUIArea AddArea(int x, int y, int width, int height, Int16 depth = 0)
         {
             GUIArea area = GUIArea.Create(this, x, y, width, height, depth);
             area.SetParent(this);

+ 2 - 2
MBansheeEngine/GUI/GUISlider.cs

@@ -20,7 +20,7 @@ namespace BansheeEngine
             Internal_CreateInstance(this, style, options);
         }
 
-        public GUISliderH(string style)
+        public GUISliderH(string style = "")
         {
             Internal_CreateInstance(this, style, new GUIOption[0]);
         }
@@ -66,7 +66,7 @@ namespace BansheeEngine
             Internal_CreateInstance(this, style, options);
         }
 
-        public GUISliderV(string style)
+        public GUISliderV(string style = "")
         {
             Internal_CreateInstance(this, style, new GUIOption[0]);
         }

+ 3 - 3
MBansheeEngine/PixelData.cs

@@ -126,17 +126,17 @@ namespace BansheeEngine
         private PixelData()
         { }
 
-        public PixelData(PixelVolume volume, PixelFormat format)
+        public PixelData(PixelVolume volume, PixelFormat format = PixelFormat.R8G8B8A8)
         {
             Internal_CreateInstance(this, volume, format);
         }
 
-        public PixelData(int width, int height, PixelFormat format)
+        public PixelData(int width, int height, PixelFormat format = PixelFormat.R8G8B8A8)
         {
             Internal_CreateInstance(this, new PixelVolume(0, 0, width, height), format);
         }
 
-        public PixelData(int width, int height, int depth, PixelFormat format)
+        public PixelData(int width, int height, int depth, PixelFormat format = PixelFormat.R8G8B8A8)
         {
             Internal_CreateInstance(this, new PixelVolume(0, 0, 0, width, height, depth), format);
         }

+ 9 - 1
MBansheeEngine/Texture2D.cs

@@ -9,7 +9,7 @@ namespace BansheeEngine
         private Texture2D()
         { }
 
-        public Texture2D(PixelFormat format, int width, int height, TextureUsage usage = TextureUsage.Default, 
+        public Texture2D(int width, int height, PixelFormat format = PixelFormat.R8G8B8A8, TextureUsage usage = TextureUsage.Default, 
             int numSamples = 1, bool hasMipmaps = false, bool gammaCorrection = false)
         {
             Internal_CreateInstance(this, format, width, height, usage, numSamples, hasMipmaps, gammaCorrection);
@@ -25,6 +25,11 @@ namespace BansheeEngine
             Internal_SetPixels(mCachedPtr, data, mipLevel);
         }
 
+        public void SetPixels(Color[] data, int mipLevel = 0)
+        {
+            Internal_SetPixelsArray(mCachedPtr, data, mipLevel);
+        }
+
         public AsyncOp GetGPUPixels(int mipLevel = 0)
         {
             return Internal_GetGPUPixels(mCachedPtr, mipLevel);
@@ -42,5 +47,8 @@ namespace BansheeEngine
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetPixels(IntPtr thisPtr, PixelData data, int mipLevel);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPixelsArray(IntPtr thisPtr, Color[] data, int mipLevel);
     }
 }

+ 1 - 0
SBansheeEngine/Include/BsScriptTexture2D.h

@@ -26,6 +26,7 @@ namespace BansheeEngine
 		static MonoObject* internal_getPixels(ScriptTexture2D* thisPtr, UINT32 mipLevel);
 		static MonoObject* internal_getGPUPixels(ScriptTexture2D* thisPtr, UINT32 mipLevel);
 		static void internal_setPixels(ScriptTexture2D* thisPtr, MonoObject* data, UINT32 mipLevel);
+		static void internal_setPixelsArray(ScriptTexture2D* thisPtr, MonoArray* colors, UINT32 mipLevel);
 
 		ScriptTexture2D(MonoObject* instance, const HTexture& texture);
 

+ 16 - 0
SBansheeEngine/Source/BsScriptTexture2D.cpp

@@ -27,6 +27,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetPixels", &ScriptTexture2D::internal_getPixels);
 		metaData.scriptClass->addInternalCall("Internal_GetGPUPixels", &ScriptTexture2D::internal_getGPUPixels);
 		metaData.scriptClass->addInternalCall("Internal_SetPixels", &ScriptTexture2D::internal_setPixels);
+		metaData.scriptClass->addInternalCall("Internal_SetPixelsArray", &ScriptTexture2D::internal_setPixelsArray);
 	}
 
 	void ScriptTexture2D::internal_createInstance(MonoObject* instance, PixelFormat format, UINT32 width,
@@ -84,6 +85,21 @@ namespace BansheeEngine
 		}
 	}
 
+	void ScriptTexture2D::internal_setPixelsArray(ScriptTexture2D* thisPtr, MonoArray* colors, UINT32 mipLevel)
+	{
+		Color* colorsRaw = (Color*)mono_array_addr_with_size(colors, sizeof(Color), 0);
+		UINT32 numElements = (UINT32)mono_array_length(colors);
+
+		HTexture texture = thisPtr->mTexture;
+		const TextureProperties& props = texture->getProperties();
+
+		PixelDataPtr pixelData = bs_shared_ptr<PixelData>(props.getWidth(), props.getHeight(), props.getDepth(), props.getFormat());
+		pixelData->setColors(colorsRaw, numElements);
+
+		UINT32 subresourceIdx = texture->getProperties().mapToSubresourceIdx(0, mipLevel);
+		texture->writeSubresource(gCoreAccessor(), subresourceIdx, pixelData, false);
+	}
+
 	void ScriptTexture2D::_onManagedInstanceDeleted()
 	{
 		mManagedInstance = nullptr;

+ 4 - 0
TODO.txt

@@ -44,6 +44,10 @@ There seems to be a bug in Mono when passing complex structs from C# to C++. e.g
 will corrupt the parameter after it, even if layout and size is exact as the C++ version. 
 Rect3 has child structs (Vector3) which could be the reason. Be aware of other similar problems.
 
+Mono cannot marshal structures? Taken from their documentation:
+ Internal calls do not provide support for marshalling structures. This means that any API calls that take a structure 
+ (excluding the system types like int32, int64, etc) must be passed as a pointer, in C# this means passing the value as a "ref" or "out" parameter.
+
 Create a stack allocatable custom vector implementation and make getResourceDependencies and getCoreDependencies use it.
  - These methods are called often and cause allocations whenever they are.