Marko Pintera 10 лет назад
Родитель
Сommit
f4e58bdc79

+ 17 - 0
BansheeCore/Include/BsPixelData.h

@@ -316,6 +316,13 @@ namespace BansheeEngine
 		 */
 		 */
 		void setColors(const Vector<Color>& colors);
 		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:
 	private:
 		/**
 		/**
 		 * @brief	Set the rowPitch and slicePitch so that the buffer is laid out consecutive
 		 * @brief	Set the rowPitch and slicePitch so that the buffer is laid out consecutive
@@ -327,6 +334,16 @@ namespace BansheeEngine
 			mSlicePitch = getWidth()*getHeight();
 			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.
 		 * @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;
 		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 depth = mExtents.getDepth();
 		UINT32 height = mExtents.getHeight();
 		UINT32 height = mExtents.getHeight();
 		UINT32 width = mExtents.getWidth();
 		UINT32 width = mExtents.getWidth();
 
 
 		UINT32 totalNumElements = width * height * depth;
 		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;
 			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()
 	UINT32 PixelData::getInternalBufferSize()
 	{
 	{
 		return getSize();
 		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>
   <ItemGroup>
   <ItemGroup>
     <Compile Include="BrowseDialog.cs" />
     <Compile Include="BrowseDialog.cs" />
+    <Compile Include="ColorPicker.cs" />
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgCustomInspector.cs" />
     <Compile Include="DbgEditorWindow.cs" />
     <Compile Include="DbgEditorWindow.cs" />
     <Compile Include="DbgGizmo.cs" />
     <Compile Include="DbgGizmo.cs" />

+ 102 - 0
MBansheeEngine/Color.cs

@@ -118,6 +118,108 @@ namespace BansheeEngine
             return !(lhs == rhs);
             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()
         public override int GetHashCode()
         {
         {
             return r.GetHashCode() ^ g.GetHashCode() << 2 ^ b.GetHashCode() >> 2 ^ a.GetHashCode() >> 1;
             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
         // 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();
             GUIArea newArea = new GUIArea();
             Internal_CreateInstance(newArea, parent, x, y, width, height, depth);
             Internal_CreateInstance(newArea, parent, x, y, width, height, depth);
@@ -38,7 +38,7 @@ namespace BansheeEngine
             return newArea;
             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);
             Internal_SetArea(mCachedPtr, x, y, width, height, depth);
         }
         }
@@ -63,10 +63,10 @@ namespace BansheeEngine
         }
         }
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [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)]
         [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)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Destroy(IntPtr nativeInstance);
         private static extern void Internal_Destroy(IntPtr nativeInstance);

+ 1 - 1
MBansheeEngine/GUI/GUIPanel.cs

@@ -29,7 +29,7 @@ namespace BansheeEngine
             _mainLayout = mainArea.layout;
             _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);
             GUIArea area = GUIArea.Create(this, x, y, width, height, depth);
             area.SetParent(this);
             area.SetParent(this);

+ 2 - 2
MBansheeEngine/GUI/GUISlider.cs

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

+ 3 - 3
MBansheeEngine/PixelData.cs

@@ -126,17 +126,17 @@ namespace BansheeEngine
         private PixelData()
         private PixelData()
         { }
         { }
 
 
-        public PixelData(PixelVolume volume, PixelFormat format)
+        public PixelData(PixelVolume volume, PixelFormat format = PixelFormat.R8G8B8A8)
         {
         {
             Internal_CreateInstance(this, volume, format);
             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);
             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);
             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()
         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)
             int numSamples = 1, bool hasMipmaps = false, bool gammaCorrection = false)
         {
         {
             Internal_CreateInstance(this, format, width, height, usage, numSamples, hasMipmaps, gammaCorrection);
             Internal_CreateInstance(this, format, width, height, usage, numSamples, hasMipmaps, gammaCorrection);
@@ -25,6 +25,11 @@ namespace BansheeEngine
             Internal_SetPixels(mCachedPtr, data, mipLevel);
             Internal_SetPixels(mCachedPtr, data, mipLevel);
         }
         }
 
 
+        public void SetPixels(Color[] data, int mipLevel = 0)
+        {
+            Internal_SetPixelsArray(mCachedPtr, data, mipLevel);
+        }
+
         public AsyncOp GetGPUPixels(int mipLevel = 0)
         public AsyncOp GetGPUPixels(int mipLevel = 0)
         {
         {
             return Internal_GetGPUPixels(mCachedPtr, mipLevel);
             return Internal_GetGPUPixels(mCachedPtr, mipLevel);
@@ -42,5 +47,8 @@ namespace BansheeEngine
 
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetPixels(IntPtr thisPtr, PixelData data, int mipLevel);
         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_getPixels(ScriptTexture2D* thisPtr, UINT32 mipLevel);
 		static MonoObject* internal_getGPUPixels(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_setPixels(ScriptTexture2D* thisPtr, MonoObject* data, UINT32 mipLevel);
+		static void internal_setPixelsArray(ScriptTexture2D* thisPtr, MonoArray* colors, UINT32 mipLevel);
 
 
 		ScriptTexture2D(MonoObject* instance, const HTexture& texture);
 		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_GetPixels", &ScriptTexture2D::internal_getPixels);
 		metaData.scriptClass->addInternalCall("Internal_GetGPUPixels", &ScriptTexture2D::internal_getGPUPixels);
 		metaData.scriptClass->addInternalCall("Internal_GetGPUPixels", &ScriptTexture2D::internal_getGPUPixels);
 		metaData.scriptClass->addInternalCall("Internal_SetPixels", &ScriptTexture2D::internal_setPixels);
 		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,
 	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()
 	void ScriptTexture2D::_onManagedInstanceDeleted()
 	{
 	{
 		mManagedInstance = nullptr;
 		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. 
 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.
 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.
 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.
  - These methods are called often and cause allocations whenever they are.