From d42b1a6be8a35c78809ac4252ead4c4d7ee2c942 Mon Sep 17 00:00:00 2001 From: Azaezel Date: Thu, 22 Dec 2016 06:37:34 -0600 Subject: [PATCH] colorPicker/swatch srgb display. dependency from @rextimmy: tolinear and togamma for color+lumnance. --- Engine/source/core/color.h | 50 +++++++++-- .../gui/buttons/guiSwatchButtonCtrl.cpp | 10 ++- .../source/gui/buttons/guiSwatchButtonCtrl.h | 2 +- Engine/source/gui/controls/guiColorPicker.cpp | 90 ++++++++++++------- Engine/source/gui/controls/guiColorPicker.h | 1 + .../Empty/game/tools/gui/colorPicker.ed.gui | 25 ++++++ .../Full/game/tools/gui/colorPicker.ed.gui | 25 ++++++ 7 files changed, 162 insertions(+), 41 deletions(-) diff --git a/Engine/source/core/color.h b/Engine/source/core/color.h index aaf4f16e7..e429ac962 100644 --- a/Engine/source/core/color.h +++ b/Engine/source/core/color.h @@ -34,6 +34,9 @@ #include "console/engineAPI.h" #endif +const F32 gGamma = 2.2f; +const F32 gOneOverGamma = 1.f / 2.2f; + class ColorI; @@ -104,8 +107,10 @@ class ColorF (alpha >= 0.0f && alpha <= 1.0f); } void clamp(); - ColorF toLinear() const; - ColorF toGamma() const; + ColorF toLinear(); + ColorF toGamma(); + //calculate luminance, make sure color is linear first + F32 luminance(); static const ColorF ZERO; static const ColorF ONE; @@ -209,6 +214,9 @@ class ColorI operator const U8*() const { return &red; } + ColorI toLinear(); + ColorI toGamma(); + static const ColorI ZERO; static const ColorI ONE; static const ColorI WHITE; @@ -465,14 +473,32 @@ inline void ColorF::clamp() alpha = 0.0f; } -inline ColorF ColorF::toLinear() const +inline ColorF ColorF::toGamma() { - return ColorF(mPow(red, 2.2f), mPow(green, 2.2f), mPow(blue, 2.2f), alpha); + ColorF color; + color.red = mPow(red,gOneOverGamma); + color.green = mPow(green, gOneOverGamma); + color.blue = mPow(blue, gOneOverGamma); + color.alpha = alpha; + return color; } -inline ColorF ColorF::toGamma() const +inline ColorF ColorF::toLinear() { - return ColorF(mPow(red, 1.0f / 2.2f), mPow(green, 1.0f / 2.2f), mPow(blue, 1.0f / 2.2f), alpha); + ColorF color; + color.red = mPow(red,gGamma); + color.green = mPow(green, gGamma); + color.blue = mPow(blue, gGamma); + color.alpha = alpha; + return color; +} + +inline F32 ColorF::luminance() +{ + // ITU BT.709 + //return red * 0.2126f + green * 0.7152f + blue * 0.0722f; + // ITU BT.601 + return red * 0.3f + green * 0.59f + blue * 0.11f; } //------------------------------------------------------------------------------ @@ -945,6 +971,18 @@ inline String ColorI::getHex() const return result; } +inline ColorI ColorI::toGamma() +{ + ColorF color = (ColorF)*this; + return (ColorI)color.toGamma(); +} + +inline ColorI ColorI::toLinear() +{ + ColorF color = (ColorF)*this; + return (ColorI)color.toLinear(); +} + //-------------------------------------- INLINE CONVERSION OPERATORS inline ColorF::operator ColorI() const { diff --git a/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp b/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp index 6e169a361..fcccca0e4 100644 --- a/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp +++ b/Engine/source/gui/buttons/guiSwatchButtonCtrl.cpp @@ -58,7 +58,7 @@ ConsoleDocClass( GuiSwatchButtonCtrl, //----------------------------------------------------------------------------- GuiSwatchButtonCtrl::GuiSwatchButtonCtrl() - : mSwatchColor( 1, 1, 1, 1 ) + : mSwatchColor(1, 1, 1, 1), mUseSRGB(false) { mButtonText = StringTable->insert( "" ); setExtent(140, 30); @@ -71,7 +71,8 @@ GuiSwatchButtonCtrl::GuiSwatchButtonCtrl() void GuiSwatchButtonCtrl::initPersistFields() { - addField( "color", TypeColorF, Offset( mSwatchColor, GuiSwatchButtonCtrl ), "The foreground color of GuiSwatchButtonCtrl" ); + addField("color", TypeColorF, Offset(mSwatchColor, GuiSwatchButtonCtrl), "The foreground color of GuiSwatchButtonCtrl"); + addField( "useSRGB", TypeBool, Offset( mUseSRGB, GuiSwatchButtonCtrl ), "Render using sRGB scale" ); addField( "gridBitmap", TypeString, Offset( mGridBitmap, GuiSwatchButtonCtrl ), "The bitmap used for the transparent grid" ); @@ -107,7 +108,10 @@ void GuiSwatchButtonCtrl::onRender( Point2I offset, const RectI &updateRect ) drawer->drawBitmapStretch( mGrid, renderRect ); // Draw swatch color as fill... - drawer->drawRectFill( renderRect, mSwatchColor ); + if (!mUseSRGB) + drawer->drawRectFill( renderRect, mSwatchColor.toGamma() ); + else + drawer->drawRectFill(renderRect, mSwatchColor); // Draw any borders... drawer->drawRect( renderRect, borderColor ); diff --git a/Engine/source/gui/buttons/guiSwatchButtonCtrl.h b/Engine/source/gui/buttons/guiSwatchButtonCtrl.h index 56bd1279d..866864685 100644 --- a/Engine/source/gui/buttons/guiSwatchButtonCtrl.h +++ b/Engine/source/gui/buttons/guiSwatchButtonCtrl.h @@ -40,7 +40,7 @@ class GuiSwatchButtonCtrl : public GuiButtonBaseCtrl /// The color to display on the button. ColorF mSwatchColor; - + bool mUseSRGB; ///< use sRGB color scale /// Bitmap used for mGrid String mGridBitmap; diff --git a/Engine/source/gui/controls/guiColorPicker.cpp b/Engine/source/gui/controls/guiColorPicker.cpp index 2fad6aa69..5043c8a46 100644 --- a/Engine/source/gui/controls/guiColorPicker.cpp +++ b/Engine/source/gui/controls/guiColorPicker.cpp @@ -73,6 +73,7 @@ GuiColorPickerCtrl::GuiColorPickerCtrl() mSelectColor = false; mSetColor = mSetColor.BLACK; mBitmap = NULL; + mUseSRGB = false; } GuiColorPickerCtrl::~GuiColorPickerCtrl() @@ -104,6 +105,7 @@ void GuiColorPickerCtrl::initPersistFields() addGroup("ColorPicker"); addField("baseColor", TypeColorF, Offset(mBaseColor, GuiColorPickerCtrl)); addField("pickColor", TypeColorF, Offset(mPickColor, GuiColorPickerCtrl)); + addField("useSRGB", TypeBool, Offset(mUseSRGB, GuiColorPickerCtrl), "Render using sRGB scale"); addField("selectorGap", TypeS32, Offset(mSelectorGap, GuiColorPickerCtrl)); addField("displayMode", TYPEID< PickMode >(), Offset(mDisplayMode, GuiColorPickerCtrl) ); addField("actionOnMove", TypeBool,Offset(mActionOnMove, GuiColorPickerCtrl)); @@ -120,24 +122,35 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x; S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y; - + + ColorF col[4]; + col[0] = c1; + col[1] = c2; + col[2] = c3; + col[3] = c4; + if (!mUseSRGB) + { + for (U32 i = 0; i < 4; i++) + col[i] = col[i].toGamma(); + } + //A couple of checks to determine if color blend //A couple of checks to determine if color blend - if(c1 == colorWhite && c3 == colorAlpha && c4 == colorBlack) + if (c1 == colorWhite && c3 == colorAlpha && c4 == colorBlack) { //Color PrimBuild::begin(GFXTriangleStrip, 4); - PrimBuild::color( c2 ); + PrimBuild::color(col[1]); PrimBuild::vertex2i(l, t); - PrimBuild::color( c2 ); + PrimBuild::color(col[1]); PrimBuild::vertex2i(r, t); - PrimBuild::color( c2 ); - PrimBuild::vertex2i( l, b ); + PrimBuild::color(col[1]); + PrimBuild::vertex2i(l, b); - PrimBuild::color( c2 ); + PrimBuild::color(col[1]); PrimBuild::vertex2i(r, b); PrimBuild::end(); @@ -145,14 +158,14 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col //White PrimBuild::begin(GFXTriangleStrip, 4); - PrimBuild::color(c1); + PrimBuild::color(col[0]); PrimBuild::vertex2i(l, t); - PrimBuild::color( colorAlphaW ); + PrimBuild::color(colorAlphaW); PrimBuild::vertex2i(r, t); - PrimBuild::color( c1 ); - PrimBuild::vertex2i( l, b ); + PrimBuild::color(col[0]); + PrimBuild::vertex2i(l, b); PrimBuild::color(colorAlphaW); PrimBuild::vertex2i(r, b); @@ -162,15 +175,15 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col //Black PrimBuild::begin(GFXTriangleStrip, 4); - PrimBuild::color(c3); + PrimBuild::color(col[2]); PrimBuild::vertex2i(l, t); - PrimBuild::color( c3 ); - PrimBuild::vertex2i( r, t ); + PrimBuild::color(col[2]); + PrimBuild::vertex2i(r, t); - PrimBuild::color( c4 ); + PrimBuild::color(col[3]); PrimBuild::vertex2i(l, b); - PrimBuild::color( c4 ); + PrimBuild::color(col[3]); PrimBuild::vertex2i(r, b); PrimBuild::end(); @@ -179,17 +192,17 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col { PrimBuild::begin(GFXTriangleStrip, 4); - PrimBuild::color( c1 ); - PrimBuild::vertex2i( l, t ); + PrimBuild::color(col[0]); + PrimBuild::vertex2i(l, t); - PrimBuild::color( c2 ); - PrimBuild::vertex2i( r, t ); + PrimBuild::color(col[1]); + PrimBuild::vertex2i(r, t); - PrimBuild::color(c4); + PrimBuild::color(col[3]); PrimBuild::vertex2i(l, b); - PrimBuild::color( c3 ); - PrimBuild::vertex2i( r, b ); + PrimBuild::color(col[2]); + PrimBuild::vertex2i(r, b); PrimBuild::end(); } @@ -199,6 +212,7 @@ void GuiColorPickerCtrl::drawBlendBox(RectI &bounds, ColorF &c1, ColorF &c2, Col /// Function to draw a set of boxes blending throughout an array of colors void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numColors, ColorI *colors) { + GFX->setStateBlock(mStateBlock); S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x + 4; @@ -208,6 +222,20 @@ void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numC S32 x_inc = int(mFloor((r - l) / F32(numColors - 1))); S32 y_inc = int(mFloor((b - t) / F32(numColors - 1))); + ColorI *col = new ColorI[numColors]; + dMemcpy(col, colors, numColors * sizeof(ColorI)); + if (mUseSRGB) + { + for (U16 i = 0; i < numColors - 1; i++) + col[i] = colors[i]; + } + else + { + for (U16 i = 0; i < numColors - 1; i++) + col[i] = colors[i].toGamma(); + } + + for (U16 i = 0; i < numColors - 1; i++) { // This is not efficent, but then again it doesn't really need to be. -pw @@ -216,30 +244,30 @@ void GuiColorPickerCtrl::drawBlendRangeBox(RectI &bounds, bool vertical, U8 numC if (!vertical) // Horizontal (+x) { // First color - PrimBuild::color(colors[i]); + PrimBuild::color(col[i]); PrimBuild::vertex2i(l, t); - PrimBuild::color(colors[i + 1]); + PrimBuild::color(col[i + 1]); PrimBuild::vertex2i(l + x_inc, t); // Second color - PrimBuild::color(colors[i]); + PrimBuild::color(col[i]); PrimBuild::vertex2i(l, b); - PrimBuild::color(colors[i + 1]); + PrimBuild::color(col[i + 1]); PrimBuild::vertex2i(l + x_inc, b); l += x_inc; } else // Vertical (+y) { // First color - PrimBuild::color(colors[i]); + PrimBuild::color(col[i]); PrimBuild::vertex2i(l, t); - PrimBuild::color(colors[i + 1]); + PrimBuild::color(col[i + 1]); PrimBuild::vertex2i(l, t + y_inc); // Second color - PrimBuild::color(colors[i]); + PrimBuild::color(col[i]); PrimBuild::vertex2i(r, t); - PrimBuild::color(colors[i + 1]); + PrimBuild::color(col[i + 1]); PrimBuild::vertex2i(r, t + y_inc); t += y_inc; } diff --git a/Engine/source/gui/controls/guiColorPicker.h b/Engine/source/gui/controls/guiColorPicker.h index 42531c3bb..c742cea79 100644 --- a/Engine/source/gui/controls/guiColorPicker.h +++ b/Engine/source/gui/controls/guiColorPicker.h @@ -90,6 +90,7 @@ class GuiColorPickerCtrl : public GuiControl ColorF mPickColor; ///< Color that has been picked from control ColorF mBaseColor; ///< Colour we display (in case of pallet and blend mode) PickMode mDisplayMode; ///< Current color display mode of the selector + bool mUseSRGB; ///< use sRGB color scale Point2I mSelectorPos; ///< Current position of the selector bool mPositionChanged; ///< Current position has changed since last render? diff --git a/Templates/Empty/game/tools/gui/colorPicker.ed.gui b/Templates/Empty/game/tools/gui/colorPicker.ed.gui index c203ca52e..d8f15e76b 100644 --- a/Templates/Empty/game/tools/gui/colorPicker.ed.gui +++ b/Templates/Empty/game/tools/gui/colorPicker.ed.gui @@ -718,6 +718,22 @@ canSave = "1"; canSaveDynamicFields = "0"; }; + new GuiCheckBoxCtrl() { + text = "use sRGB"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "360 105"; + extent = "66 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + variable = "$displayAsSRGB"; + command = "useSRGBctrl($displayAsSRGB);"; + }; }; }; //--- OBJECT WRITE END --- @@ -727,6 +743,15 @@ $ColorPickerCancelCallback = ""; $ColorPickerUpdateCallback = ""; $ColorCallbackType = 1; // ColorI +function useSRGBctrl(%colorScale) +{ +ColorPickerDlg.useSRGB = %colorScale; +ColorRangeSelect.useSRGB = %colorScale; +ColorBlendSelect.useSRGB = %colorScale; +myColor.useSRGB = %colorScale; +oldColor.useSRGB = %colorScale; +} + // This function pushes the color picker dialog and returns to a callback the selected value function GetColorI( %currentColor, %callback, %root, %updateCallback, %cancelCallback ) { diff --git a/Templates/Full/game/tools/gui/colorPicker.ed.gui b/Templates/Full/game/tools/gui/colorPicker.ed.gui index c203ca52e..d8f15e76b 100644 --- a/Templates/Full/game/tools/gui/colorPicker.ed.gui +++ b/Templates/Full/game/tools/gui/colorPicker.ed.gui @@ -718,6 +718,22 @@ canSave = "1"; canSaveDynamicFields = "0"; }; + new GuiCheckBoxCtrl() { + text = "use sRGB"; + groupNum = "-1"; + buttonType = "ToggleButton"; + useMouseEvents = "0"; + position = "360 105"; + extent = "66 16"; + minExtent = "8 2"; + horizSizing = "right"; + vertSizing = "bottom"; + profile = "GuiCheckBoxProfile"; + visible = "1"; + active = "1"; + variable = "$displayAsSRGB"; + command = "useSRGBctrl($displayAsSRGB);"; + }; }; }; //--- OBJECT WRITE END --- @@ -727,6 +743,15 @@ $ColorPickerCancelCallback = ""; $ColorPickerUpdateCallback = ""; $ColorCallbackType = 1; // ColorI +function useSRGBctrl(%colorScale) +{ +ColorPickerDlg.useSRGB = %colorScale; +ColorRangeSelect.useSRGB = %colorScale; +ColorBlendSelect.useSRGB = %colorScale; +myColor.useSRGB = %colorScale; +oldColor.useSRGB = %colorScale; +} + // This function pushes the color picker dialog and returns to a callback the selected value function GetColorI( %currentColor, %callback, %root, %updateCallback, %cancelCallback ) {