From 29a9bd79176718edc0fe6261b4ecc2c6563d764c Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 22 Jan 2025 17:21:46 +0000 Subject: [PATCH] ground work before gui --- Engine/source/core/color.h | 192 ++-- Engine/source/gfx/gfxDrawUtil.cpp | 43 +- Engine/source/gfx/gfxDrawUtil.h | 14 +- Engine/source/gui/controls/guiColorPicker.cpp | 869 ++++++++++-------- Engine/source/gui/controls/guiColorPicker.h | 142 +-- .../rendering/scripts/gfxData/shaders.tscript | 4 +- .../fixedFunction/gl/roundedRectangleP.glsl | 27 +- .../fixedFunction/roundedRectangleP.hlsl | 34 +- 8 files changed, 724 insertions(+), 601 deletions(-) diff --git a/Engine/source/core/color.h b/Engine/source/core/color.h index d6753406f..dbae2eb8e 100644 --- a/Engine/source/core/color.h +++ b/Engine/source/core/color.h @@ -466,72 +466,48 @@ inline void ColorI::set(const ColorI& in_rCopy, inline void ColorI::set(const Hsb& color) { - U32 r = 0; - U32 g = 0; - U32 b = 0; + // Normalize the input HSB values + F64 H = (F64)color.hue / 360.0; // Hue: [0, 360] -> [0, 1] + F64 S = (F64)color.sat / 100.0; // Saturation: [0, 100] -> [0, 1] + F64 B = (F64)color.brightness / 100.0; // Brightness: [0, 100] -> [0, 1] - F64 L = ((F64)color.brightness) / 100.0; - F64 S = ((F64)color.sat) / 100.0; - F64 H = ((F64)color.hue) / 360.0; + F64 r = 0.0, g = 0.0, b = 0.0; - if (color.sat == 0) - { - r = color.brightness; - g = color.brightness; - b = color.brightness; - } - else - { - F64 temp1 = 0; - if (L < 0.50) - { - temp1 = L*(1 + S); - } - else - { - temp1 = L + S - (L*S); - } + if(S == 0.0) + { + // Achromatic case (grey scale) + r = g = b = B; + } + else + { + // Compute chroma + F64 C = B * S; - F64 temp2 = 2.0*L - temp1; + // Intermediate value for the hue + F64 X = C * (1 - mFabsD(mFmodD(H * 6.0, 2.0) - 1)); - F64 temp3 = 0; - for (S32 i = 0; i < 3; i++) - { - switch (i) - { - case 0: // red - { - temp3 = H + 0.33333; - if (temp3 > 1.0) - temp3 -= 1.0; - HSLtoRGB_Subfunction(r, temp1, temp2, temp3); - break; - } - case 1: // green - { - temp3 = H; - HSLtoRGB_Subfunction(g, temp1, temp2, temp3); - break; - } - case 2: // blue - { - temp3 = H - 0.33333; - if (temp3 < 0) - temp3 += 1; - HSLtoRGB_Subfunction(b, temp1, temp2, temp3); - break; - } - default: - { + // Minimum component + F64 m = B - C; - } - } - } - } - red = (U32)((((F64)r) / 100) * 255); - green = (U32)((((F64)g) / 100) * 255); - blue = (U32)((((F64)b) / 100) * 255); - alpha = 255; + // Assign r, g, b based on the hue sector + if (H >= 0.0 && H < 1.0 / 6.0) { r = C; g = X; b = 0.0; } + else if (H >= 1.0 / 6.0 && H < 2.0 / 6.0) { r = X; g = C; b = 0.0; } + else if (H >= 2.0 / 6.0 && H < 3.0 / 6.0) { r = 0.0; g = C; b = X; } + else if (H >= 3.0 / 6.0 && H < 4.0 / 6.0) { r = 0.0; g = X; b = C; } + else if (H >= 4.0 / 6.0 && H < 5.0 / 6.0) { r = X; g = 0.0; b = C; } + else if (H >= 5.0 / 6.0 && H <= 1.0) { r = C; g = 0.0; b = X; } + + // Add the minimum component to normalize to the brightness + r += m; + g += m; + b += m; + } + + // Convert normalized [0.0, 1.0] RGB values to integer [0, 255] + red = static_cast(r * 255.0); + green = static_cast(g * 255.0); + blue = static_cast(b * 255.0); + alpha = 255; // Set alpha to fully opaque } // This is a subfunction of HSLtoRGB @@ -744,70 +720,50 @@ inline U16 ColorI::get4444() const inline ColorI::Hsb ColorI::getHSB() const { - F64 rPercent = ((F64)red) / 255; - F64 gPercent = ((F64)green) / 255; - F64 bPercent = ((F64)blue) / 255; + // Normalize RGB values to [0, 1] + F64 rPercent = (F64)red / 255.0; + F64 gPercent = (F64)green / 255.0; + F64 bPercent = (F64)blue / 255.0; - F64 maxColor = 0.0; - if ((rPercent >= gPercent) && (rPercent >= bPercent)) - maxColor = rPercent; - if ((gPercent >= rPercent) && (gPercent >= bPercent)) - maxColor = gPercent; - if ((bPercent >= rPercent) && (bPercent >= gPercent)) - maxColor = bPercent; + // Find the min and max values among the normalized RGB values + F64 maxColor = mMax( rPercent, mMax(gPercent, bPercent)); + F64 minColor = mMin( rPercent, mMin(gPercent, bPercent)); - F64 minColor = 0.0; - if ((rPercent <= gPercent) && (rPercent <= bPercent)) - minColor = rPercent; - if ((gPercent <= rPercent) && (gPercent <= bPercent)) - minColor = gPercent; - if ((bPercent <= rPercent) && (bPercent <= gPercent)) - minColor = bPercent; + // Initialize H, S, B + F64 H = 0.0, S = 0.0, B = maxColor; - F64 H = 0.0; - F64 S = 0.0; - F64 B = 0.0; + // Compute saturation + F64 delta = maxColor - minColor; + if (delta > 0.0) + { + S = delta / maxColor; // Saturation - B = (maxColor + minColor) / 2.0; + // Compute hue + if (maxColor == rPercent) + { + H = 60.0 * mFmodD(((gPercent - bPercent) / delta), 6.0); + } + else if (maxColor == gPercent) + { + H = 60.0 * (((bPercent - rPercent) / delta) + 2.0); + } + else if (maxColor == bPercent) + { + H = 60.0 * (((rPercent - gPercent) / delta) + 4.0); + } + } - if (maxColor == minColor) - { - H = 0.0; - S = 0.0; - } - else - { - if (B < 0.50) - { - S = (maxColor - minColor) / (maxColor + minColor); - } - else - { - S = (maxColor - minColor) / (2.0 - maxColor - minColor); - } - if (maxColor == rPercent) - { - H = (gPercent - bPercent) / (maxColor - minColor); - } - if (maxColor == gPercent) - { - H = 2.0 + (bPercent - rPercent) / (maxColor - minColor); - } - if (maxColor == bPercent) - { - H = 4.0 + (rPercent - gPercent) / (maxColor - minColor); - } - } + // Normalize hue to [0, 360) + if (H < 0.0) + H += 360.0; - ColorI::Hsb val; - val.sat = (U32)(S * 100); - val.brightness = (U32)(B * 100); - H = H*60.0; - if (H < 0.0) - H += 360.0; - val.hue = (U32)H; + // Prepare the output HSB struct + ColorI::Hsb val; + val.hue = static_cast(H); + val.sat = static_cast(S * 100.0); // Saturation as percentage + val.brightness = static_cast(B * 100.0); // Brightness as percentage - return val; + return val; } inline String ColorI::getHex() const diff --git a/Engine/source/gfx/gfxDrawUtil.cpp b/Engine/source/gfx/gfxDrawUtil.cpp index 49de99d5e..40e6d15c5 100644 --- a/Engine/source/gfx/gfxDrawUtil.cpp +++ b/Engine/source/gfx/gfxDrawUtil.cpp @@ -540,35 +540,35 @@ void GFXDrawUtil::drawRect( const Point2F &upperLeft, const Point2F &lowerRight, //----------------------------------------------------------------------------- // Draw Rectangle Fill //----------------------------------------------------------------------------- -void GFXDrawUtil::drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +void GFXDrawUtil::drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor, bool gradientFill) { - drawRoundedRect(0.0f, rect.point, Point2F(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); + drawRoundedRect(0.0f, rect.point, Point2F(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor, gradientFill); } -void GFXDrawUtil::drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +void GFXDrawUtil::drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor, bool gradientFill) { - drawRoundedRect(0.0f, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor); + drawRoundedRect(0.0f, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor, gradientFill); } -void GFXDrawUtil::drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +void GFXDrawUtil::drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor, bool gradientFill) { - drawRoundedRect(0.0f, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); + drawRoundedRect(0.0f, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor, gradientFill); } -void GFXDrawUtil::drawRectFill(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize,const ColorI& borderColor) +void GFXDrawUtil::drawRectFill(const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize,const ColorI& borderColor, bool gradientFill) { // draw a rounded rect with 0 radiuse. - drawRoundedRect(0.0f, upperLeft, lowerRight, color, borderSize, borderColor); + drawRoundedRect(0.0f, upperLeft, lowerRight, color, borderSize, borderColor, gradientFill); } -void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize, const ColorI& borderColor, bool gradientFill) { - drawRoundedRect(cornerRadius, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor); + drawRoundedRect(cornerRadius, rect.point, Point2I(rect.extent.x + rect.point.x - 1, rect.extent.y + rect.point.y - 1), color, borderSize, borderColor, gradientFill); } -void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor) +void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize, const ColorI& borderColor, bool gradientFill) { - drawRoundedRect(cornerRadius, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor); + drawRoundedRect(cornerRadius, Point2F((F32)upperLeft.x, (F32)upperLeft.y), Point2F((F32)lowerRight.x, (F32)lowerRight.y), color, borderSize, borderColor, gradientFill); } void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, @@ -576,7 +576,8 @@ void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, const Point2F& lowerRight, const ColorI& color, const F32& borderSize, - const ColorI& borderColor) + const ColorI& borderColor, + bool gradientFill) { // NorthWest and NorthEast facing offset vectors @@ -595,6 +596,14 @@ void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, for (S32 i = 0; i < 4; i++) verts[i].color = color; + if (gradientFill) + { + verts[0].texCoord.set(0.0f, 0.0f); // top left + verts[1].texCoord.set(1.0f, 0.0f); // top right + verts[2].texCoord.set(0.0f, 1.0f); // bottom left + verts[3].texCoord.set(1.0f, 1.0f); // bottom right + } + verts.unlock(); mDevice->setVertexBuffer(verts); @@ -623,6 +632,14 @@ void GFXDrawUtil::drawRoundedRect(const F32& cornerRadius, mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$sizeUni"), size); mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$borderSize"), borderSize); mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$borderCol"), borderColor); + if (gradientFill) + { + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$gradientFill"), 1.0f); + } + else + { + mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$gradientFill"), 0.0f); + } Point2F rectCenter((F32)(topLeftCorner.x + (size.x / 2.0)), (F32)(topLeftCorner.y + (size.y / 2.0))); mRoundRectangleShaderConsts->setSafe(mRoundRectangleShader->getShaderConstHandle("$rectCenter"), rectCenter); diff --git a/Engine/source/gfx/gfxDrawUtil.h b/Engine/source/gfx/gfxDrawUtil.h index 7a641fb64..583feb407 100644 --- a/Engine/source/gfx/gfxDrawUtil.h +++ b/Engine/source/gfx/gfxDrawUtil.h @@ -57,13 +57,13 @@ public: // Draw Rectangles : FILL //----------------------------------------------------------------------------- - void drawRectFill(const Point2F& upperL, const Point2F& lowerR, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); - void drawRoundedRect(const F32& cornerRadius, const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0)); + void drawRectFill(const Point2F& upperL, const Point2F& lowerR, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRectFill(const RectF& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRectFill(const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRectFill(const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRoundedRect(const F32& cornerRadius, const RectI& rect, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRoundedRect(const F32& cornerRadius, const Point2I& upperLeft, const Point2I& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); + void drawRoundedRect(const F32& cornerRadius, const Point2F& upperLeft, const Point2F& lowerRight, const ColorI& color, const F32& borderSize = 0.0f, const ColorI& borderColor = ColorI(0, 0, 0, 0), bool gradientFill = false); void draw2DSquare(const Point2F& screenPoint, F32 width, F32 spinAngle = 0.0f); diff --git a/Engine/source/gui/controls/guiColorPicker.cpp b/Engine/source/gui/controls/guiColorPicker.cpp index 09e47a97e..ced6daba8 100644 --- a/Engine/source/gui/controls/guiColorPicker.cpp +++ b/Engine/source/gui/controls/guiColorPicker.cpp @@ -30,25 +30,6 @@ #include "gfx/primBuilder.h" #include "gfx/gfxDrawUtil.h" -/// @name Common colors we use -/// @{ -LinearColorF colorWhite(1.,1.,1.); -LinearColorF colorWhiteBlend(1.,1.,1.,.75); -LinearColorF colorBlack(.0,.0,.0); -LinearColorF colorAlpha(0.0f, 0.0f, 0.0f, 0.0f); -LinearColorF colorAlphaW(1.0f, 1.0f, 1.0f, 0.0f); - -ColorI GuiColorPickerCtrl::mColorRange[7] = { - ColorI(255,0,0), // Red - ColorI(255,0,255), // Pink - ColorI(0,0,255), // Blue - ColorI(0,255,255), // Light blue - ColorI(0,255,0), // Green - ColorI(255,255,0), // Yellow - ColorI(255,0,0), // Red -}; -/// @} - IMPLEMENT_CONOBJECT(GuiColorPickerCtrl); ConsoleDocClass( GuiColorPickerCtrl, @@ -60,53 +41,49 @@ ConsoleDocClass( GuiColorPickerCtrl, GuiColorPickerCtrl::GuiColorPickerCtrl() { setExtent(140, 30); - mDisplayMode = pPallet; - mBaseColor = LinearColorF(1.,.0,1.); - mPickColor = LinearColorF(.0,.0,.0); - mSelectorPos = Point2I(0,0); + mDisplayMode = pPalette; + mSelectorMode = sHorizontal; mMouseDown = mMouseOver = false; mActive = true; - mPositionChanged = false; mSelectorGap = 1; mActionOnMove = false; mShowReticle = true; - mSelectColor = false; - mSetColor = mSetColor.BLACK; - mBitmap = NULL; + mSelectedHue = 0; + mSelectedAlpha = 255; + mSelectedSaturation = 100; + mSelectedBrightness = 100; } GuiColorPickerCtrl::~GuiColorPickerCtrl() { - if (mBitmap) - { - delete mBitmap; - mBitmap = NULL; - } } ImplementEnumType( GuiColorPickMode, "\n\n" "@ingroup GuiUtil" "@internal" ) - { GuiColorPickerCtrl::pPallet, "Pallete" }, - { GuiColorPickerCtrl::pHorizColorRange, "HorizColor"}, - { GuiColorPickerCtrl::pVertColorRange, "VertColor" }, - { GuiColorPickerCtrl::pHorizColorBrightnessRange, "HorizBrightnessColor" }, - { GuiColorPickerCtrl::pVertColorBrightnessRange, "VertBrightnessColor" }, - { GuiColorPickerCtrl::pBlendColorRange, "BlendColor" }, - { GuiColorPickerCtrl::pHorizAlphaRange, "HorizAlpha" }, - { GuiColorPickerCtrl::pVertAlphaRange, "VertAlpha" }, + { GuiColorPickerCtrl::pPalette, "Pallete" }, + { GuiColorPickerCtrl::pBlendRange, "BlendRange" }, + { GuiColorPickerCtrl::pHueRange, "HueRange"}, + { GuiColorPickerCtrl::pAlphaRange, "AlphaRange" }, { GuiColorPickerCtrl::pDropperBackground, "Dropper" }, EndImplementEnumType; +ImplementEnumType(GuiColorSelectorMode, + "\n\n" + "@ingroup GuiUtil" + "@internal") +{ GuiColorPickerCtrl::sHorizontal, "Horizontal" }, +{ GuiColorPickerCtrl::sVertical, "Vertical" }, +EndImplementEnumType; + void GuiColorPickerCtrl::initPersistFields() { docsURL; addGroup("ColorPicker"); - addField("baseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl)); - addField("pickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl)); addField("selectorGap", TypeS32, Offset(mSelectorGap, GuiColorPickerCtrl)); addField("displayMode", TYPEID< PickMode >(), Offset(mDisplayMode, GuiColorPickerCtrl) ); + addField("selectorMode", TYPEID< SelectorMode >(), Offset(mSelectorMode, GuiColorPickerCtrl) ); addField("actionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl)); addField("showReticle", TypeBool, Offset(mShowReticle, GuiColorPickerCtrl)); endGroup("ColorPicker"); @@ -114,248 +91,227 @@ void GuiColorPickerCtrl::initPersistFields() Parent::initPersistFields(); } -// Function to draw a box which can have 4 different colors in each corner blended together -void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, LinearColorF &c1, LinearColorF &c2, LinearColorF &c3, LinearColorF &c4) +void GuiColorPickerCtrl::renderBlendRange(RectI& bounds) +{ + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, 100, 100)); + GFX->getDrawUtil()->drawRectFill(bounds, currentColor, 0.0f, ColorI(0,0,0,0), true); +} + +void GuiColorPickerCtrl::renderBlendSelector(RectI& bounds) +{ + // Determine the relative saturation position within the gradient + F32 relPosX = F32(mSelectedSaturation) / 100.0f; + // Determine the relative brightness position within the gradient + F32 relPosY = 1.0f - F32(mSelectedBrightness) / 100.0f; + + // Calculate the selector position + Point2I selectorPos; + RectI selectorRect; + + selectorPos.x = bounds.point.x + static_cast(relPosX * bounds.extent.x); + selectorPos.y = bounds.point.y + static_cast(relPosY * bounds.extent.y); + selectorRect.set(Point2I(selectorPos.x - mSelectorGap, selectorPos.y - mSelectorGap), Point2I(mSelectorGap * 2, mSelectorGap * 2)); + + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, mSelectedSaturation, mSelectedBrightness)); + GFX->getDrawUtil()->drawRectFill(selectorRect, currentColor, 2.0f, ColorI::WHITE); +} + +void GuiColorPickerCtrl::renderHueGradient(RectI& bounds, U32 numColours) { GFX->setStateBlock(mStateBlock); + F32 stepSize = F32(bounds.extent.x) / F32(numColours); // For horizontal mode + F32 stepSizeY = F32(bounds.extent.y) / F32(numColours); // For vertical mode S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x; S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y; - LinearColorF col[4]; - col[0] = c1; - col[1] = c2; - col[2] = c3; - col[3] = c4; + // Begin primitive building, 4 vertices per rectangle + PrimBuild::begin(GFXTriangleStrip, numColours * 4); - //A couple of checks to determine if color blend - if (c1 == colorWhite && c3 == colorAlpha && c4 == colorBlack) + for (U32 i = 0; i < numColours; i++) { - //Color - PrimBuild::begin(GFXTriangleStrip, 4); + U32 currentHue = static_cast((F32(i) / F32(numColours)) * 360.0f); + U32 nextHue = static_cast((F32(i + 1) / F32(numColours)) * 360.0f); - PrimBuild::color(col[1]); - PrimBuild::vertex2i(l, t); + ColorI currentColor, nextColor; + currentColor.set(ColorI::Hsb(currentHue, 100, 100)); + nextColor.set(ColorI::Hsb(nextHue, 100, 100)); - PrimBuild::color(col[1]); - PrimBuild::vertex2i(r, t); + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + { + // Draw a rectangle for the current segment + F32 xStart = l + i * stepSize; + F32 xEnd = l + (i + 1) * stepSize; - PrimBuild::color(col[1]); - PrimBuild::vertex2i(l, b); + PrimBuild::color(currentColor); + PrimBuild::vertex2i(xStart, t); // Top-left - PrimBuild::color(col[1]); - PrimBuild::vertex2i(r, b); + PrimBuild::color(nextColor); + PrimBuild::vertex2i(xEnd, t); // Top-right - PrimBuild::end(); + PrimBuild::color(currentColor); + PrimBuild::vertex2i(xStart, b); // Bottom-left - //White - PrimBuild::begin(GFXTriangleStrip, 4); + PrimBuild::color(nextColor); + PrimBuild::vertex2i(xEnd, b); // Bottom-right - PrimBuild::color(col[0]); - PrimBuild::vertex2i(l, t); + break; + } + case GuiColorPickerCtrl::sVertical: + { + // Draw a rectangle for the current segment + F32 yStart = t + i * stepSizeY; + F32 yEnd = t + (i + 1) * stepSizeY; - PrimBuild::color(colorAlphaW); - PrimBuild::vertex2i(r, t); + PrimBuild::color(currentColor); + PrimBuild::vertex2i(l, yStart); // Top-left - PrimBuild::color(col[0]); - PrimBuild::vertex2i(l, b); + PrimBuild::color(currentColor); + PrimBuild::vertex2i(r, yStart); // Top-right - PrimBuild::color(colorAlphaW); - PrimBuild::vertex2i(r, b); + PrimBuild::color(nextColor); + PrimBuild::vertex2i(l, yEnd); // Bottom-left - PrimBuild::end(); + PrimBuild::color(nextColor); + PrimBuild::vertex2i(r, yEnd); // Bottom-right - //Black - PrimBuild::begin(GFXTriangleStrip, 4); - - PrimBuild::color(col[2]); - PrimBuild::vertex2i(l, t); - PrimBuild::color(col[2]); - PrimBuild::vertex2i(r, t); - - PrimBuild::color(col[3]); - PrimBuild::vertex2i(l, b); - - PrimBuild::color(col[3]); - PrimBuild::vertex2i(r, b); - - PrimBuild::end(); + break; + } + default: + break; + } } - else - { - PrimBuild::begin(GFXTriangleStrip, 4); - PrimBuild::color(col[0]); - PrimBuild::vertex2i(l, t); - - PrimBuild::color(col[1]); - PrimBuild::vertex2i(r, t); - - PrimBuild::color(col[3]); - PrimBuild::vertex2i(l, b); - - PrimBuild::color(col[2]); - PrimBuild::vertex2i(r, b); - - PrimBuild::end(); - } + PrimBuild::end(); } -//-------------------------------------------------------------------------- -/// Function to draw a set of boxes blending throughout an array of colors -void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors) +void GuiColorPickerCtrl::renderHueSelector(RectI& bounds) { + // Determine the relative position within the gradient + F32 relPos = F32(mSelectedHue) / 360.0f; + // Calculate the selector position + Point2I selectorPos; + RectI selectorRect; + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + // X is proportional to the hue, Y is centered vertically + selectorPos.x = bounds.point.x + static_cast(relPos * bounds.extent.x); + selectorPos.y = bounds.point.y; + selectorRect.set(Point2I(selectorPos.x - mSelectorGap, selectorPos.y), Point2I(mSelectorGap * 2, bounds.extent.y)); + break; + + case GuiColorPickerCtrl::sVertical: + // Y is proportional to the hue, X is centered horizontally + selectorPos.x = bounds.point.x; + selectorPos.y = bounds.point.y + static_cast(relPos * bounds.extent.y); + selectorRect.set(Point2I(selectorPos.x, selectorPos.y - mSelectorGap), Point2I(bounds.extent.x, mSelectorGap * 2)); + break; + default: + return; // Invalid mode, don't render selector + } + + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, 100, 100)); + GFX->getDrawUtil()->drawRectFill(selectorRect, currentColor, 2.0f, ColorI::WHITE); +} + +void GuiColorPickerCtrl::renderAlphaGradient(RectI& bounds) +{ GFX->setStateBlock(mStateBlock); - S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x + 4; - S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y + 4; + // Define the rectangle bounds + S32 l = bounds.point.x; + S32 r = bounds.point.x + bounds.extent.x; + S32 t = bounds.point.y; + S32 b = bounds.point.y + bounds.extent.y; - // Calculate increment value - S32 x_inc = int(mFloor((r - l) / F32(numColors - 1))); - S32 y_inc = int(mFloor((b - t) / F32(numColors - 1))); + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, 100, 100)); - ColorI *col = new ColorI[numColors]; - dMemcpy(col, colors, numColors * sizeof(ColorI)); - for (U16 i = 0; i < numColors - 1; i++) - col[i] = colors[i]; + ColorI alphaCol = currentColor; + alphaCol.alpha = 0; - for (U16 i = 0; i < numColors - 1; i++) + // Begin primitive building, 4 vertices per rectangle + PrimBuild::begin(GFXTriangleStrip,4); + + switch (mSelectorMode) { - // This is not efficent, but then again it doesn't really need to be. -pw - PrimBuild::begin(GFXTriangleStrip, 4); - - if (!vertical) // Horizontal (+x) - { - // First color - PrimBuild::color(col[i]); - PrimBuild::vertex2i(l, t); - PrimBuild::color(col[i + 1]); - PrimBuild::vertex2i(l + x_inc, t); - - // Second color - PrimBuild::color(col[i]); - PrimBuild::vertex2i(l, b); - PrimBuild::color(col[i + 1]); - PrimBuild::vertex2i(l + x_inc, b); - l += x_inc; - } - else // Vertical (+y) - { - // First color - PrimBuild::color(col[i]); - PrimBuild::vertex2i(l, t); - PrimBuild::color(col[i + 1]); - PrimBuild::vertex2i(l, t + y_inc); - - // Second color - PrimBuild::color(col[i]); - PrimBuild::vertex2i(r, t); - PrimBuild::color(col[i + 1]); - PrimBuild::vertex2i(r, t + y_inc); - t += y_inc; - } - PrimBuild::end(); - } - - SAFE_DELETE_ARRAY(col); -} - -void GuiColorPickerCtrl::drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode) -{ - if( !mShowReticle ) - return; - - U16 sMax = mSelectorGap*2; - const ColorI color = colorWhiteBlend.toColorI(); - switch (mode) + case GuiColorPickerCtrl::sHorizontal: { - case sVertical: - // Now draw the vertical selector Up -> Pos - if (selectorPos.y > bounds.point.y) - GFX->getDrawUtil()->drawLine(selectorPos.x, bounds.point.y, selectorPos.x, selectorPos.y-sMax-1, color); - // Down -> Pos - if (selectorPos.y < bounds.point.y + bounds.extent.y) - GFX->getDrawUtil()->drawLine(selectorPos.x, selectorPos.y + sMax, selectorPos.x, bounds.point.y + bounds.extent.y, color); - break; - case sHorizontal: - // Now draw the horizontal selector Left -> Pos - if (selectorPos.x > bounds.point.x) - GFX->getDrawUtil()->drawLine(bounds.point.x, selectorPos.y-1, selectorPos.x-sMax, selectorPos.y-1, color); - // Right -> Pos - if (selectorPos.x < bounds.point.x + bounds.extent.x) - GFX->getDrawUtil()->drawLine(bounds.point.x+mSelectorPos.x+sMax, selectorPos.y-1, bounds.point.x + bounds.extent.x, selectorPos.y-1, color); + PrimBuild::color(alphaCol); + PrimBuild::vertex2i(l, t); // Top-left + + PrimBuild::color(currentColor); + PrimBuild::vertex2i(r, t); // Top-right + + PrimBuild::color(alphaCol); + PrimBuild::vertex2i(l, b); // Bottom-left + + PrimBuild::color(currentColor); + PrimBuild::vertex2i(r, b); // Bottom-right break; } -} - -//-------------------------------------------------------------------------- -/// Function to invoke calls to draw the picker box and selector -void GuiColorPickerCtrl::renderColorBox(RectI &bounds) -{ - RectI pickerBounds; - pickerBounds.point.x = bounds.point.x+1; - pickerBounds.point.y = bounds.point.y+1; - pickerBounds.extent.x = bounds.extent.x-1; - pickerBounds.extent.y = bounds.extent.y-1; - - if (mProfile->mBorder) - GFX->getDrawUtil()->drawRect(bounds, mProfile->mBorderColor); - - Point2I selectorPos = Point2I(bounds.point.x+mSelectorPos.x+1, bounds.point.y+mSelectorPos.y+1); - - // Draw color box differently depending on mode - RectI blendRect; - switch (mDisplayMode) + case GuiColorPickerCtrl::sVertical: { - case pHorizColorRange: - drawBlendRangeBox( pickerBounds, false, 7, mColorRange); - drawSelector( pickerBounds, selectorPos, sVertical ); - break; - case pVertColorRange: - drawBlendRangeBox( pickerBounds, true, 7, mColorRange); - drawSelector( pickerBounds, selectorPos, sHorizontal ); - break; - case pHorizColorBrightnessRange: - blendRect = pickerBounds; - blendRect.point.y++; - blendRect.extent.y -= 2; - drawBlendRangeBox( pickerBounds, false, 7, mColorRange); - // This is being drawn slightly offset from the larger rect so as to insure 255 and 0 - // can both be selected for every color. - drawBlendBox( blendRect, colorAlpha, colorAlpha, colorBlack, colorBlack ); - blendRect.point.y += blendRect.extent.y - 1; - blendRect.extent.y = 2; - GFX->getDrawUtil()->drawRect( blendRect, colorBlack.toColorI()); - drawSelector( pickerBounds, selectorPos, sHorizontal ); - drawSelector( pickerBounds, selectorPos, sVertical ); - break; - case pVertColorBrightnessRange: - drawBlendRangeBox( pickerBounds, true, 7, mColorRange); - drawBlendBox( pickerBounds, colorAlpha, colorBlack, colorBlack, colorAlpha ); - drawSelector( pickerBounds, selectorPos, sHorizontal ); - drawSelector( pickerBounds, selectorPos, sVertical ); - break; - case pHorizAlphaRange: - drawBlendBox( pickerBounds, colorBlack, colorWhite, colorWhite, colorBlack ); - drawSelector( pickerBounds, selectorPos, sVertical ); - break; - case pVertAlphaRange: - drawBlendBox( pickerBounds, colorBlack, colorBlack, colorWhite, colorWhite ); - drawSelector( pickerBounds, selectorPos, sHorizontal ); - break; - case pBlendColorRange: - drawBlendBox( pickerBounds, colorWhite, mBaseColor, colorAlpha, colorBlack ); - drawSelector( pickerBounds, selectorPos, sHorizontal ); - drawSelector( pickerBounds, selectorPos, sVertical ); - break; - case pDropperBackground: - break; - case pPallet: + PrimBuild::color(currentColor); + PrimBuild::vertex2i(l, t); // Top-left + + PrimBuild::color(currentColor); + PrimBuild::vertex2i(r, t); // Top-right + + PrimBuild::color(alphaCol); + PrimBuild::vertex2i(l, b); // Bottom-left + + PrimBuild::color(alphaCol); + PrimBuild::vertex2i(r, b); // Bottom-right + break; + } default: - GFX->getDrawUtil()->drawRectFill( pickerBounds, mBaseColor.toColorI()); - break; + break; } + + PrimBuild::end(); + +} + +void GuiColorPickerCtrl::renderAlphaSelector(RectI& bounds) +{ + // Determine the relative position within the gradient + F32 relPos = F32(mSelectedAlpha) / 255.0f; + + // Calculate the selector position + Point2I selectorPos; + RectI selectorRect; + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + // X is proportional to the hue, Y is centered vertically + selectorPos.x = bounds.point.x + static_cast(relPos * bounds.extent.x); + selectorPos.y = bounds.point.y; + selectorRect.set(Point2I(selectorPos.x - mSelectorGap, selectorPos.y), Point2I(mSelectorGap * 2, bounds.extent.y)); + break; + + case GuiColorPickerCtrl::sVertical: + // Y is proportional to the hue, X is centered horizontally + selectorPos.x = bounds.point.x; + selectorPos.y = bounds.point.y + static_cast(relPos * bounds.extent.y); + selectorRect.set(Point2I(selectorPos.x, selectorPos.y - mSelectorGap), Point2I(bounds.extent.x, mSelectorGap * 2)); + break; + default: + return; // Invalid mode, don't render selector + } + + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, 100, 100)); + currentColor.alpha = mSelectedAlpha; + + GFX->getDrawUtil()->drawRectFill(selectorRect, currentColor, 2.0f, ColorI::WHITE); } void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect) @@ -371,89 +327,43 @@ void GuiColorPickerCtrl::onRender(Point2I offset, const RectI& updateRect) } RectI boundsRect(offset, getExtent()); - renderColorBox(boundsRect); - if (mPositionChanged || mBitmap == NULL) + switch (mDisplayMode) { - bool nullBitmap = false; - - if (mPositionChanged == false && mBitmap == NULL) - nullBitmap = true; - - mPositionChanged = false; - Point2I extent = getRoot()->getExtent(); - - // If we are anything but a pallete, change the pick color - if (mDisplayMode != pPallet) - { - Point2I resolution = getRoot()->getExtent(); - - U32 buf_x = offset.x + mSelectorPos.x; - U32 buf_y = resolution.y - (extent.y - (offset.y + mSelectorPos.y)); - - GFXTexHandle bb(resolution.x, resolution.y, GFXFormatR8G8B8A8_SRGB, &GFXRenderTargetSRGBProfile, avar("%s() - bb (line %d)", __FUNCTION__, __LINE__)); - - GFXTarget *targ = GFX->getActiveRenderTarget(); - targ->resolveTo(bb); - - if (mBitmap) - { - delete mBitmap; - mBitmap = NULL; - } - - mBitmap = new GBitmap(bb.getWidth(), bb.getHeight(),false,GFXFormatR8G8B8A8); - - bb.copyToBmp(mBitmap); - - if (!nullBitmap) - { - if (mSelectColor) - { - Point2I pos = findColor(mSetColor, offset, resolution, *mBitmap); - mSetColor = mSetColor.BLACK; - mSelectColor = false; - setSelectorPos(pos); - } - else - { - ColorI tmp; - mBitmap->getColor(buf_x, buf_y, tmp); - - mPickColor = (LinearColorF)tmp; - - // Now do onAction() if we are allowed - if (mActionOnMove) - onAction(); - } - } - } + case GuiColorPickerCtrl::pPalette: + { + ColorI currentColor; + currentColor.set(ColorI::Hsb(mSelectedHue, mSelectedSaturation, mSelectedBrightness)); + currentColor.alpha = mSelectedAlpha; + GFX->getDrawUtil()->drawRectFill(boundsRect, currentColor); + break; + } + case GuiColorPickerCtrl::pBlendRange: + { + renderBlendRange(boundsRect); + renderBlendSelector(boundsRect); + break; + } + case GuiColorPickerCtrl::pHueRange: + { + renderHueGradient(boundsRect, 7); + if(mShowReticle) renderHueSelector(boundsRect); + break; + } + case GuiColorPickerCtrl::pAlphaRange: + { + renderAlphaGradient(boundsRect); + if (mShowReticle) renderAlphaSelector(boundsRect); + break; + } + default: + break; } //render the children renderChildControls(offset, updateRect); } -void GuiColorPickerCtrl::setSelectorPos(const LinearColorF & color) -{ - if (mBitmap && !mPositionChanged) - { - Point2I resolution = getRoot() ? getRoot()->getExtent() : Point2I(1024, 768); - RectI rect(getGlobalBounds()); - Point2I pos = findColor(color, rect.point, resolution, *mBitmap); - mSetColor = mSetColor.BLACK; - mSelectColor = false; - - setSelectorPos(pos); - } - else - { - mSetColor = color; - mSelectColor = true; - mPositionChanged = true; - } -} - Point2I GuiColorPickerCtrl::findColor(const LinearColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp) { Point2I ext = getExtent(); @@ -516,57 +426,154 @@ Point2I GuiColorPickerCtrl::findColor(const LinearColorF & color, const Point2I& return closestPos; } -void GuiColorPickerCtrl::setSelectorPos(const Point2I &pos) -{ - Point2I ext = getExtent(); - mSelectorPos.x = mClamp(pos.x, 1, ext.x - 1); - mSelectorPos.y = mClamp(pos.y, 1, ext.y - 1); - mPositionChanged = true; - setUpdate(); -} - void GuiColorPickerCtrl::onMouseDown(const GuiEvent &event) { if (!mActive) return; - if (mDisplayMode == pDropperBackground) - return; - mouseLock(this); if (mProfile->mCanKeyFocus) setFirstResponder(); - if (mActive && (mDisplayMode != pDropperBackground)) - onAction(); - - // Update the picker cross position - if (mDisplayMode != pPallet) - setSelectorPos(globalToLocalCoord(event.mousePoint)); - + Point2I ext = getExtent(); + Point2I mousePoint = globalToLocalCoord(event.mousePoint); mMouseDown = true; + + switch (mDisplayMode) + { + case GuiColorPickerCtrl::pPalette: + return; + case GuiColorPickerCtrl::pBlendRange: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + F32 relY = 1.0f - F32(mousePoint.y) / F32(ext.y); + setSelectedSaturation(static_cast(relX * 100.0f)); + setSelectedBrightness(static_cast(relY * 100.0f)); + break; + } + case GuiColorPickerCtrl::pHueRange: + { + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + setSelectedHue(static_cast(relX * 360.0f)); + break; + } + case GuiColorPickerCtrl::sVertical: + { + F32 relY = F32(mousePoint.y) / F32(ext.y); + setSelectedHue(static_cast(relY * 360.0f)); + break; + } + default: + break; + } + break; + } + case GuiColorPickerCtrl::pAlphaRange: + { + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + setSelectedAlpha(static_cast(relX * 255.0f)); + break; + } + case GuiColorPickerCtrl::sVertical: + { + F32 relY = F32(mousePoint.y) / F32(ext.y); + setSelectedAlpha(static_cast(relY * 255.0f)); + break; + } + default: + break; + } + break; + } + default: + break; + } + + if (mActive) + onAction(); } //-------------------------------------------------------------------------- void GuiColorPickerCtrl::onMouseDragged(const GuiEvent &event) { - if ((mActive && mMouseDown) || (mActive && (mDisplayMode == pDropperBackground))) + if ((mActive && mMouseDown)) { - // Update the picker cross position - if (mDisplayMode != pPallet) - setSelectorPos(globalToLocalCoord(event.mousePoint)); - } + Point2I ext = getExtent(); + Point2I mousePoint = globalToLocalCoord(event.mousePoint); - if( !mActionOnMove ) - execAltConsoleCallback(); + switch (mDisplayMode) + { + case GuiColorPickerCtrl::pPalette: + return; + case GuiColorPickerCtrl::pBlendRange: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + F32 relY = 1.0f - F32(mousePoint.y) / F32(ext.y); + setSelectedSaturation(static_cast(relX * 100.0f)); + setSelectedBrightness(static_cast(relY * 100.0f)); + break; + } + case GuiColorPickerCtrl::pHueRange: + { + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + setSelectedHue(static_cast(relX * 360.0f)); + break; + } + case GuiColorPickerCtrl::sVertical: + { + F32 relY = F32(mousePoint.y) / F32(ext.y); + setSelectedHue(static_cast(relY * 360.0f)); + break; + } + default: + break; + } + break; + } + case GuiColorPickerCtrl::pAlphaRange: + { + switch (mSelectorMode) + { + case GuiColorPickerCtrl::sHorizontal: + { + F32 relX = F32(mousePoint.x) / F32(ext.x); + setSelectedAlpha(static_cast(relX * 255.0f)); + break; + } + case GuiColorPickerCtrl::sVertical: + { + F32 relY = F32(mousePoint.y) / F32(ext.y); + setSelectedAlpha(static_cast(relY * 255.0f)); + break; + } + default: + break; + } + break; + } + default: + break; + } + + onAction(); + } } void GuiColorPickerCtrl::onMouseMove(const GuiEvent &event) { - // Only for dropper mode - if (mActive && (mDisplayMode == pDropperBackground)) - setSelectorPos(globalToLocalCoord(event.mousePoint)); } void GuiColorPickerCtrl::onMouseEnter(const GuiEvent &event) @@ -580,54 +587,164 @@ void GuiColorPickerCtrl::onMouseLeave(const GuiEvent &) mMouseOver = false; } +void GuiColorPickerCtrl::setSelectedHue(const U32& hueValue) +{ + if (hueValue < 0) + { + mSelectedHue = 0; + return; + } + + if (hueValue > 360) + { + mSelectedHue = 360; + return; + } + + mSelectedHue = hueValue; + +} + +void GuiColorPickerCtrl::setSelectedBrightness(const U32& brightValue) +{ + if (brightValue < 0) + { + mSelectedBrightness = 0; + return; + } + + if (brightValue > 100) + { + mSelectedBrightness = 100; + return; + } + + mSelectedBrightness = brightValue; +} + +void GuiColorPickerCtrl::setSelectedSaturation(const U32& satValue) +{ + if (satValue < 0) + { + mSelectedSaturation = 0; + return; + } + + if (satValue > 100) + { + mSelectedSaturation = 100; + return; + } + + mSelectedSaturation = satValue; +} + +void GuiColorPickerCtrl::setSelectedAlpha(const U32& alphaValue) +{ + if (alphaValue < 0) + { + mSelectedAlpha = 0; + return; + } + + if (alphaValue > 255) + { + mSelectedAlpha = 255; + return; + } + + mSelectedAlpha = alphaValue; +} + void GuiColorPickerCtrl::onMouseUp(const GuiEvent &) { //if we released the mouse within this control, perform the action - if (mActive && mMouseDown && (mDisplayMode != pDropperBackground)) + if (mActive && mMouseDown) mMouseDown = false; - if (mActive && (mDisplayMode == pDropperBackground)) - { - // In a dropper, the alt command executes the mouse up action (to signal stopping) - execAltConsoleCallback(); - } - mouseUnlock(); } -const char *GuiColorPickerCtrl::getScriptValue() +/// +/// This command is to be used by Palette only as it updates everything else across the colour picker gui. +/// +DefineEngineMethod(GuiColorPickerCtrl, executeUpdate, void, (), , "Execute the onAction command.") { - static char temp[256]; - LinearColorF color = getValue(); - dSprintf( temp, 256, "%f %f %f %f", color.red, color.green, color.blue, color.alpha ); - return temp; + object->onAction(); } -void GuiColorPickerCtrl::setScriptValue(const char *value) +DefineEngineMethod(GuiColorPickerCtrl, setSelectedHue, void, (U32 hueValue), , "Sets the selected hue value should be 0-360.") { - LinearColorF newValue; - dSscanf(value, "%f %f %f %f", &newValue.red, &newValue.green, &newValue.blue, &newValue.alpha); - setValue(newValue); + object->setSelectedHue(hueValue); } -DefineEngineMethod(GuiColorPickerCtrl, getSelectorPos, Point2I, (), , "Gets the current position of the selector") +DefineEngineMethod(GuiColorPickerCtrl, getSelectedHue, S32, (), , "Gets the current selected hue value.") { - return object->getSelectorPos(); + return object->getSelectedHue(); } -DefineEngineMethod(GuiColorPickerCtrl, setSelectorPos, void, (Point2I newPos), , "Sets the current position of the selector") +DefineEngineMethod(GuiColorPickerCtrl, setSelectedBrightness, void, (U32 brightness), , "Sets the selected brightness value should be 0-100.") { - object->setSelectorPos(newPos); + object->setSelectedBrightness(brightness); } -DefineEngineMethod(GuiColorPickerCtrl, updateColor, void, (), , "Forces update of pick color") +DefineEngineMethod(GuiColorPickerCtrl, getSelectedBrightness, S32, (), , "Gets the current selected brightness.") { - object->updateColor(); + return object->getSelectedBrightness(); } -DefineEngineMethod(GuiColorPickerCtrl, setSelectorColor, void, (LinearColorF color), , - "Sets the current position of the selector based on a color.n" - "@param color Color to look for.n") +DefineEngineMethod(GuiColorPickerCtrl, setSelectedSaturation, void, (U32 saturation), , "Sets the selected saturation value should be 0-100.") { - object->setSelectorPos(color); + object->setSelectedSaturation(saturation); +} + +DefineEngineMethod(GuiColorPickerCtrl, getSelectedSaturation, S32, (), , "Gets the current selected saturation value.") +{ + return object->getSelectedSaturation(); +} + +DefineEngineMethod(GuiColorPickerCtrl, setSelectedAlpha, void, (U32 alpha), , "Sets the selected alpha value should be 0-255.") +{ + object->setSelectedAlpha(alpha); +} + +DefineEngineMethod(GuiColorPickerCtrl, getSelectedAlpha, S32, (), , "Gets the current selected alpha value.") +{ + return object->getSelectedAlpha(); +} + +DefineEngineMethod(GuiColorPickerCtrl, setSelectedColorI, void, (ColorI col), , "Sets the current selected hsb from a colorI value.") +{ + ColorI::Hsb hsb(col.getHSB()); + object->setSelectedHue(hsb.hue); + object->setSelectedSaturation(hsb.sat); + object->setSelectedBrightness(hsb.brightness); + object->setSelectedAlpha(col.alpha); +} + +DefineEngineMethod(GuiColorPickerCtrl, getSelectedColorI, ColorI, (), , "Gets the current selected hsb as a colorI value.") +{ + ColorI col; + col.set(ColorI::Hsb(object->getSelectedHue(), object->getSelectedSaturation(), object->getSelectedBrightness())); + col.alpha = object->getSelectedAlpha(); + return col; +} + +DefineEngineMethod(GuiColorPickerCtrl, setSelectedLinearColor, void, (LinearColorF colF), , "Sets the current selected hsb froma a LinearColorF value.") +{ + ColorI col = colF.toColorI(); + ColorI::Hsb hsb(col.getHSB()); + object->setSelectedHue(hsb.hue); + object->setSelectedSaturation(hsb.sat); + object->setSelectedBrightness(hsb.brightness); + object->setSelectedAlpha(col.alpha); +} + + +DefineEngineMethod(GuiColorPickerCtrl, getSelectedLinearColor, LinearColorF, (), , "Gets the current selected hsb as a LinearColorF value.") +{ + ColorI col; + col.set(ColorI::Hsb(object->getSelectedHue(), object->getSelectedSaturation(), object->getSelectedBrightness())); + col.alpha = object->getSelectedAlpha(); + return LinearColorF(col); } diff --git a/Engine/source/gui/controls/guiColorPicker.h b/Engine/source/gui/controls/guiColorPicker.h index ad6c52d0f..0375c48ff 100644 --- a/Engine/source/gui/controls/guiColorPicker.h +++ b/Engine/source/gui/controls/guiColorPicker.h @@ -32,25 +32,22 @@ /// This control draws a box containing a color specified by mPickColor, /// in a way according to one of the PickMode enum's, stored as mDisplayMode. /// -/// The color the box represents is stored as mBaseColour (for pPallete, pBlendColorRange), +/// The color the box represents is stored as mBaseColour (for pPalette, pBlendColorRange), /// whilst the color chosen by the box is stored as mPickColor. /// /// Whenever the control is clicked, it will do one of many things : /// -/// -# If its in pPallete mode, execute the regular "command" -/// -# If its in pBlendColorRange mode, update the selector position. The position will be re-read upon the next render. In addition, a cross will be drawn where the color has been selected from. As with 1, "command" will be executed. -/// -# If its in pHorizColorRange or pVertColorRange mode, it will function in a similar manner to 2, but the selector will resemble a horizontal or vertical bar. -/// -# If its in pHorizAlphaRange or pVertAlphaRange mode, it will also function the same way as 3 +/// -# If its in pPalette mode, execute the regular "command" +/// -# If its in pBlendRange mode, update the selector position. The position will be re-read upon the next render. In addition, a cross will be drawn where the color has been selected from. As with 1, "command" will be executed. +/// -# If its in pHueRange or pAlphaRange mode, it will function in a similar manner to 2, but the selector will resemble a horizontal or vertical bar. +/// -# If its in pAlphaRange mode, it will also function the same way as 3 /// -# If its in pDropperBackground mode, nothing will happen /// /// Colours are drawn in different ways according to mDisplayMode: /// -/// -# With pPallete, a box with a blank color, mBaseColor is drawn. -/// -# With pHorizColorRange, a horizontal box with colors blending in the range, mColorRange. -/// -# With pVertColorRange, a vertical box with colors blending in the range, mColorRange. -/// -# With pBlendColorRange, a box, the bottom colors being black, but the top left being white, and the top right being mBaseColor. -/// -# With pHorizAlphaRange, a horizontal box with black blending with an alpha from 0 to 255 -/// -# With pVertAlphaRange, a vertical box with black blending with an apha from 0 to 255 +/// -# With pPalette, a box with a blank color, mBaseColor is drawn. +/// -# With pHueRange, a box containing the hue range 0-360. +/// -# With pAlphaRange, a box containing the alpha range 0-255. /// -# With pDropperBackground, nothing is drawn class GuiColorPickerCtrl : public GuiControl { @@ -59,14 +56,10 @@ class GuiColorPickerCtrl : public GuiControl public: enum PickMode { - pPallet = 0, ///< We just have a solid color; We just act like a pallet - pHorizColorRange, ///< We have a range of base colors going horizontally - pVertColorRange, ///< We have a range of base colors going vertically - pHorizColorBrightnessRange, ///< HorizColorRange with brightness - pVertColorBrightnessRange, ///< VertColorRange with brightness - pBlendColorRange, ///< We have a box which shows a range in brightness of the color - pHorizAlphaRange, ///< We have a box which shows a range in alpha going horizontally - pVertAlphaRange, ///< We have a box which shows a range in alpha going vertically + pPalette = 0, ///< We just have a solid color; We just act like a pallet + pBlendRange, ///< The full range of brightness and saturation. + pHueRange, ///< The full hue range 0-360. + pAlphaRange, ///< The full alpha range 0-255. pDropperBackground ///< The control does not draw anything; Only does something when you click, or move the mouse (when active) }; @@ -77,37 +70,63 @@ class GuiColorPickerCtrl : public GuiControl }; protected: - /// @name Core Rendering functions - /// @{ - void renderColorBox(RectI &bounds); ///< Function that draws the actual color box - void drawSelector(RectI &bounds, Point2I &selectorPos, SelectorMode mode); /// < Function that draws the selection indicator - void drawBlendBox(RectI &bounds, LinearColorF &c1, LinearColorF &c2, LinearColorF &c3, LinearColorF &c4); - void drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors); - /// @} + + /// + /// Render the hue gradient for pBlendRange mode. + /// + /// The bounds of the ctrl. + void renderBlendRange(RectI& bounds); + + /// + /// Render the selector for pBlendRange mode. + /// + /// The bounds of the ctrl. + void renderBlendSelector(RectI& bounds); + + /// + /// Render the hue gradient for pHueRange mode. + /// + /// The bounds of the ctrl. + /// The number of splits in the gradient. 7 as default. + void renderHueGradient(RectI& bounds, U32 numColours); + + /// + /// Render the selector for pHueRange mode. + /// + /// The bounds of the ctrl. + void renderHueSelector(RectI& bounds); + + /// + /// Render the alpha gradient for pAlphaRange mode. + /// + /// The bounds of the ctrl. + void renderAlphaGradient(RectI& bounds); + + /// + /// Render the selector for pAlphaRange mode. + /// + /// The bounds of the ctrl. + void renderAlphaSelector(RectI& bounds); /// @name Core Variables /// @{ - LinearColorF mPickColor; ///< Color that has been picked from control - LinearColorF mBaseColor; ///< Colour we display (in case of pallet and blend mode) PickMode mDisplayMode; ///< Current color display mode of the selector - - Point2I mSelectorPos; ///< Current position of the selector - bool mPositionChanged; ///< Current position has changed since last render? + SelectorMode mSelectorMode; ///< Current color display mode of the selector + U32 mSelectedHue; + U32 mSelectedSaturation; + U32 mSelectedBrightness; + U32 mSelectedAlpha; + bool mMouseOver; ///< Mouse is over? bool mMouseDown; ///< Mouse button down? bool mActionOnMove; ///< Perform onAction() when position has changed? - - bool mSelectColor; - LinearColorF mSetColor; - GBitmap* mBitmap; + bool mShowReticle; ///< Show reticle on render Point2I findColor(const LinearColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp); S32 mSelectorGap; ///< The half-way "gap" between the selector pos and where the selector is allowed to draw. GFXStateBlockRef mStateBlock; - - static ColorI mColorRange[7]; ///< Color range for pHorizColorRange and pVertColorRange /// @} public: @@ -120,23 +139,7 @@ class GuiColorPickerCtrl : public GuiControl static void initPersistFields(); void onRender(Point2I offset, const RectI &updateRect) override; - bool mShowReticle; ///< Show reticle on render - /// @name Color Value Functions - /// @{ - /// NOTE: setValue only sets baseColor, since setting pickColor wouldn't be useful - void setValue(LinearColorF &value) {mBaseColor = value;} - /// NOTE: getValue() returns baseColor if pallet (since pallet controls can't "pick" colours themselves) - LinearColorF getValue() { return mDisplayMode == pPallet ? mBaseColor : mPickColor; } - const char *getScriptValue() override; - void setScriptValue(const char *value) override; - void updateColor() {mPositionChanged = true;} - /// @} - - /// @name Selector Functions - /// @{ - void setSelectorPos(const Point2I &pos); ///< Set new pos (in local coords) - void setSelectorPos(const LinearColorF & color); - Point2I getSelectorPos() {return mSelectorPos;} + /// @} /// @name Input Events @@ -149,9 +152,40 @@ class GuiColorPickerCtrl : public GuiControl void onMouseEnter(const GuiEvent &) override; void onMouseLeave(const GuiEvent &) override; /// @} + + // script getters and setters + /// + /// Set the selected hue. + /// + /// Hue value, 0 - 360. + void setSelectedHue(const U32& hueValue); + U32 getSelectedHue() { return mSelectedHue; } + + /// + /// Set the selected brightness. + /// + /// Brightness value, 0 - 100. + void setSelectedBrightness(const U32& brightValue); + U32 getSelectedBrightness() { return mSelectedBrightness; } + + /// + /// Set the selected saturation. + /// + /// Saturation value, 0 - 100. + void setSelectedSaturation(const U32& satValue); + U32 getSelectedSaturation() { return mSelectedSaturation; } + + /// + /// Set the selected alpha. + /// + /// Alpha value, 0 - 255. + void setSelectedAlpha(const U32& alphaValue); + U32 getSelectedAlpha() { return mSelectedAlpha; } }; typedef GuiColorPickerCtrl::PickMode GuiColorPickMode; +typedef GuiColorPickerCtrl::SelectorMode GuiColorSelectorMode; DefineEnumType( GuiColorPickMode ); +DefineEnumType(GuiColorSelectorMode); #endif diff --git a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript index 239c76a80..099b382db 100644 --- a/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript +++ b/Templates/BaseGame/game/core/rendering/scripts/gfxData/shaders.tscript @@ -156,10 +156,10 @@ singleton ShaderData( CubemapSaveShader ) //----------------------------------------------------------------------------- singleton ShaderData( RoundedRectangleGUI ) { - DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/colorV.hlsl"; + DXVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/addColorTextureV.hlsl"; DXPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/roundedRectangleP.hlsl"; - OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/colorV.glsl"; + OGLVertexShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/addColorTextureV.glsl"; OGLPixelShaderFile = $Core::CommonShaderPath @ "/fixedFunction/gl/roundedRectangleP.glsl"; pixVersion = 3.0; diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl index 57599b550..af422ebdf 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/gl/roundedRectangleP.glsl @@ -20,6 +20,7 @@ // IN THE SOFTWARE. //----------------------------------------------------------------------------- in vec4 color; +in vec2 texCoord; out vec4 OUT_col; @@ -29,6 +30,7 @@ uniform vec2 oneOverViewport; uniform float radius; uniform float borderSize; uniform vec4 borderCol; +uniform float gradientFill; float RoundedRectSDF(vec2 p, vec2 size, float radius) { @@ -57,13 +59,16 @@ void main() float cornerRadius = radius; - // if ((p.y < 0.0 && p.x < 0.0) || // top left corner - // (p.y < 0.0 && p.x > 0.0) || // top right corner - // (p.y > 0.0 && p.x > 0.0) || // bottom right corner. - // (p.y > 0.0 && p.x < 0.0)) // bottom left corner - // { - // cornerRadius = radius; - // } + vec4 baseColor = color; + + if(gradientFill > 0.5f) + { + float blendX = (1.0 - texCoord.x); + float blendY = texCoord.y; + + vec4 interpolatedColor = mix(mix(baseColor,vec4(1.0f, 1.0f, 1.0f, 1.0f), blendX),vec4(0.0f, 0.0f, 0.0f, 1.0f), blendY); + baseColor = interpolatedColor; + } if(cornerRadius > 0.0 || halfBorder > 0.0) { @@ -73,14 +78,8 @@ void main() { if(sdf < 0.0) { - // if ((p.y >= -halfSize.y - radius + halfBorder && p.y <= -halfSize.y + radius - halfBorder) || // top border - // (p.y >= halfSize.y - radius + halfBorder && p.y <= halfSize.y + radius - halfBorder) || // bottom border - // (p.x >= -halfSize.x - radius + halfBorder && p.x <= -halfSize.x + radius - halfBorder) || // left border - // (p.x >= halfSize.x - radius + halfBorder && p.x <= halfSize.x + radius - halfBorder) ) { // right border - - // } toColor = color; - sdf = abs(sdf) / borderSize; + sdf = abs(sdf) - borderSize; } } diff --git a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl index 9dbffc4f4..71968bfad 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/fixedFunction/roundedRectangleP.hlsl @@ -26,14 +26,17 @@ struct Conn { float4 HPOS : TORQUE_POSITION; float4 color : COLOR; + float2 texCoord : TEXCOORD0; }; + uniform float2 sizeUni; uniform float2 rectCenter; uniform float2 oneOverViewport; uniform float radius; uniform float borderSize; uniform float4 borderCol; +uniform float gradientFill; float RoundedRectSDF(float2 p, float2 size, float radius) { @@ -62,13 +65,16 @@ float4 main(Conn IN) : TORQUE_TARGET0 float cornerRadius = radius; - // if ((p.y < 0.0 && p.x < 0.0) || // top left corner - // (p.y < 0.0 && p.x > 0.0) || // top right corner - // (p.y > 0.0 && p.x > 0.0) || // bottom right corner. - // (p.y > 0.0 && p.x < 0.0)) // bottom left corner - // { - // cornerRadius = radius; - // } + float4 baseColor = IN.color; + + if(gradientFill > 0.5f) + { + float blendX = (1.0 - IN.texCoord.x); + float blendY = IN.texCoord.y; + + float4 interpolatedColor = lerp(lerp(baseColor,float4(1.0f, 1.0f, 1.0f, 1.0f), blendX),float4(0.0f, 0.0f, 0.0f, 1.0f), blendY); + baseColor = interpolatedColor; + } if(cornerRadius > 0.0 || halfBorder > 0.0) { @@ -78,19 +84,13 @@ float4 main(Conn IN) : TORQUE_TARGET0 { if(sdf < 0.0) { - // if ((p.y >= -halfSize.y - radius + halfBorder && p.y <= -halfSize.y + radius - halfBorder) || // top border - // (p.y >= halfSize.y - radius + halfBorder && p.y <= halfSize.y + radius - halfBorder) || // bottom border - // (p.x >= -halfSize.x - radius + halfBorder && p.x <= -halfSize.x + radius - halfBorder) || // left border - // (p.x >= halfSize.x - radius + halfBorder && p.x <= halfSize.x + radius - halfBorder) ) { // right border - - // } - toColor = IN.color; - sdf = abs(sdf) / borderSize; + toColor = baseColor; + sdf = abs(sdf) - borderSize; } } else{ - fromColor = IN.color; + fromColor = baseColor; } float alpha = smoothstep(-1.0, 1.0, sdf); @@ -98,6 +98,6 @@ float4 main(Conn IN) : TORQUE_TARGET0 } else { - return IN.color; + return baseColor; } } \ No newline at end of file