Skip to content

Commit

Permalink
UI|Shaders|Client: Home background tinting
Browse files Browse the repository at this point in the history
Columns that are not highlighted are desaturated to reduce the number
of colors visible at once (too much noise).

The client's renderer.pack now has a new "include/hsv.glsl" for HSV
color calculations.
  • Loading branch information
skyjake committed Oct 15, 2016
1 parent 0407fad commit 78ff6ed
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 7 deletions.
4 changes: 4 additions & 0 deletions doomsday/apps/client/include/ui/home/columnwidget.h
Expand Up @@ -50,10 +50,14 @@ class ColumnWidget : public de::GuiWidget
// Events.
bool dispatchEvent(de::Event const &event,
bool (de::Widget::*memberFunc)(de::Event const &)) override;
void update() override;

signals:
void mouseActivity(QObject const *columnWidget);

protected:
void updateStyle() override;

private:
DENG2_PRIVATE(d)
};
Expand Down
Expand Up @@ -110,6 +110,8 @@ gamefilter {
#

home {
color background.tint { rgb <0.48, 0.50, 0.49> }

color icon.shadow { rgb $= label.shadow.rgb }
color icon.doom { rgb <1.0, 0.7, 0.2> }
color icon.heretic { rgb <0.4, 0.7, 0.25> }
Expand Down
Expand Up @@ -96,5 +96,34 @@ generic {
gl_FragColor = vColor * texture2D(uTex, vUV);
}"
}

shader hsv.color_ucolor inherits generic.textured.color_ucolor {
vertex = "
uniform highp mat4 uMvpMatrix;
uniform highp vec4 uColor;
attribute highp vec4 aVertex;
attribute highp vec2 aUV;
attribute highp vec4 aColor;
varying highp vec2 vUV;
varying highp vec4 vColor;

void main(void) {
gl_Position = uMvpMatrix * aVertex;
vUV = aUV;
vColor = aColor * uColor;
}"
include.fragment <include/hsv.glsl>
fragment = "
uniform sampler2D uTex;
uniform highp float uSaturation;
varying highp vec2 vUV;
varying highp vec4 vColor;

void main(void) {
highp vec4 hsv = rgbToHsv(texture2D(uTex, vUV));
hsv.y *= uSaturation;
gl_FragColor = vColor * hsvToRgb(hsv);
}"
}
}
}
@@ -0,0 +1,123 @@
/*
* The Doomsday Engine Project
* Common OpenGL Shaders: HSV/RGB Color Conversions
*
* Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* LGPL: http://www.gnu.org/licenses/lgpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy of
* the GNU Lesser General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

/**
* Converts an RGBA value to HSVA. Hue uses degrees as the unit.
*/
highp vec4 rgbToHsv(highp vec4 rgb)
{
highp vec4 hsv;
hsv.a = rgb.a;

highp float rgbMin = min(min(rgb.r, rgb.g), rgb.b);
highp float rgbMax = max(max(rgb.r, rgb.g), rgb.b);
highp float delta = rgbMax - rgbMin;

hsv.z = rgbMax;

if (delta < 0.00001)
{
hsv.xy = vec2(0.0);
return hsv;
}

if (rgbMax > 0.0)
{
hsv.y = delta / rgbMax;
}
else
{
hsv.xy = vec2(0.0);
return hsv;
}

if (rgb.r >= rgbMax)
{
hsv.x = (rgb.g - rgb.b) / delta;
}
else
{
if (rgb.g >= rgbMax)
{
hsv.x = 2.0 + (rgb.b - rgb.r) / delta;
}
else
{
hsv.x = 4.0 + (rgb.r - rgb.g) / delta;
}
}

hsv.x *= 60.0;
if (hsv.x < 0.0)
{
hsv.x += 360.0;
}
return hsv;
}

highp vec4 hsvToRgb(highp vec4 hsv)
{
highp vec4 rgb;
rgb.a = hsv.a;

if (hsv.y <= 0.0)
{
rgb.rgb = vec3(hsv.z);
return rgb;
}

highp float hh = hsv.x;
if (hh >= 360.0) hh = 0.0;
hh /= 60.0;

highp float ff = fract(hh);
highp float p = hsv.z * (1.0 - hsv.y);
highp float q = hsv.z * (1.0 - (hsv.y * ff));
highp float t = hsv.z * (1.0 - (hsv.y * (1.0 - ff)));

int i = int(hh);

if (i == 0)
{
rgb.rgb = vec3(hsv.z, t, p);
}
else if (i == 1)
{
rgb.rgb = vec3(q, hsv.z, p);
}
else if (i == 2)
{
rgb.rgb = vec3(p, hsv.z, t);
}
else if (i == 3)
{
rgb.rgb = vec3(p, q, hsv.z);
}
else if (i == 4)
{
rgb.rgb = vec3(t, p, hsv.z);
}
else
{
rgb.rgb = vec3(hsv.z, p, q);
}

return rgb;
}
39 changes: 32 additions & 7 deletions doomsday/apps/client/src/ui/home/columnwidget.cpp
Expand Up @@ -18,10 +18,11 @@

#include "ui/home/columnwidget.h"

#include <de/App>
#include <de/GLProgram>
#include <de/LabelWidget>
#include <de/StyleProceduralImage>
#include <de/Range>
#include <de/App>
#include <de/StyleProceduralImage>
#include <de/math.h>

#include <QColor>
Expand All @@ -35,7 +36,7 @@ DENG_GUI_PIMPL(ColumnWidget)
*/
struct BackgroundImage : public StyleProceduralImage
{
Animation colorAnim { 0, Animation::Linear };
AnimationVector3 colorAnim { Animation::Linear };
bool needUpdate = false;

BackgroundImage(DotPath const &styleImageId, ColumnWidget &owner)
Expand All @@ -45,7 +46,7 @@ DENG_GUI_PIMPL(ColumnWidget)
void setColor(Color const &color)
{
StyleProceduralImage::setColor(color);
colorAnim.setValue(color.x, 0.5);
colorAnim.setValue(color, 0.5);
}

bool update() override
Expand Down Expand Up @@ -73,7 +74,7 @@ DENG_GUI_PIMPL(ColumnWidget)

Rectanglef const norm = owner().normalizedRect();
verts.makeQuad(rect,
Vector4f(colorAnim, colorAnim, colorAnim, 1.f),
Vector4f(colorAnim.value(), 1.f),
Rectanglef(uv.topLeft + norm.topLeft * uv.size(),
uv.topLeft + norm.bottomRight * uv.size()));

Expand All @@ -94,10 +95,16 @@ DENG_GUI_PIMPL(ColumnWidget)
ScrollAreaWidget *scrollArea;
HeaderWidget *header;
Rule const *maxContentWidth = nullptr;
Vector4f backTintColor;

GLUniform uSaturation { "uSaturation", GLUniform::Float }; // background saturation
Animation backSaturation { 0.f, Animation::Linear };

Impl(Public *i) : Base(i)
{
back = new LabelWidget;
back->setShaderId("generic.textured.hsv.color_ucolor");
back->shaderProgram() << uSaturation;
back->margins().setZero();

scrollArea = new ScrollAreaWidget;
Expand Down Expand Up @@ -136,14 +143,16 @@ ColumnWidget::ColumnWidget(String const &name)
add(d->back);
add(d->scrollArea);

updateStyle();

setBackgroundImage("home.background.column");
setBehavior(ChildVisibilityClipping);
}

void ColumnWidget::setBackgroundImage(DotPath const &imageId)
{
auto *img = new Impl::BackgroundImage(imageId, *this);
img->setColor(Vector4f(.5f, .5f, .5f, 1.f));
img->setColor(d->backTintColor);
d->back->setImage(img);
}

Expand Down Expand Up @@ -181,7 +190,9 @@ void ColumnWidget::setHighlighted(bool highlighted)
d->highlighted = highlighted;

auto &img = d->back->image()->as<Impl::BackgroundImage>();
img.setColor(highlighted? Vector4f(1, 1, 1, 1) : Vector4f(.5f, .5f, .5f, 1.f));
img.setColor(highlighted? Vector4f(1, 1, 1, 1) : d->backTintColor);

d->backSaturation.setValue(highlighted? 1.f : 0.f, 0.5);
}
}

Expand All @@ -190,6 +201,20 @@ bool ColumnWidget::isHighlighted() const
return d->highlighted;
}

void ColumnWidget::update()
{
GuiWidget::update();

d->uSaturation = d->backSaturation;
}

void ColumnWidget::updateStyle()
{
GuiWidget::updateStyle();

d->backTintColor = Vector4f(style().colors().colorf("home.background.tint"), 1.f);
}

bool ColumnWidget::dispatchEvent(Event const &event, bool (Widget::*memberFunc)(Event const &))
{
// Observe mouse clicks occurring in the column.
Expand Down

0 comments on commit 78ff6ed

Please sign in to comment.