Add UI Tint/Saturation settings

Does the color tinting in the vertex shader.
This commit is contained in:
Henrik Rydgård 2022-02-11 15:12:52 +01:00
parent e88ddbb42a
commit ce2995f952
16 changed files with 190 additions and 77 deletions

View File

@ -73,7 +73,7 @@ struct UniformDesc {
int16_t vertexReg; // For D3D
int16_t fragmentReg; // For D3D
UniformType type;
int16_t offset;
int16_t offset; // in bytes
// TODO: Support array elements etc.
};

View File

@ -226,6 +226,7 @@ static const std::vector<ShaderSource> vsCol = {
"varying vec4 oColor0;\n"
"uniform mat4 WorldViewProj;\n"
"uniform vec2 TintSaturation;\n"
"void main() {\n"
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
" oColor0 = Color0;\n"
@ -235,6 +236,7 @@ static const std::vector<ShaderSource> vsCol = {
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj : register(c0);\n"
"float2 TintSaturation : register(c4);\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
@ -247,6 +249,7 @@ static const std::vector<ShaderSource> vsCol = {
"struct VS_OUTPUT { float4 Color0 : COLOR0; float4 Position : SV_Position; };\n"
"cbuffer ConstantBuffer : register(b0) {\n"
" matrix WorldViewProj;\n"
" float2 TintSaturation;\n"
"};\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
@ -256,20 +259,22 @@ static const std::vector<ShaderSource> vsCol = {
"}\n"
},
{ ShaderLanguage::GLSL_VULKAN,
"#version 450\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n"
"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
" mat4 WorldViewProj;\n"
"} myBufferVals;\n"
"layout (location = 0) in vec4 pos;\n"
"layout (location = 1) in vec4 inColor;\n"
"layout (location = 0) out vec4 outColor;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"void main() {\n"
" outColor = inColor;\n"
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
"}\n"
R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (std140, set = 0, binding = 0) uniform bufferVals {
mat4 WorldViewProj;
vec2 TintSaturation;
} myBufferVals;
layout (location = 0) in vec4 pos;
layout (location = 1) in vec4 inColor;
layout (location = 0) out vec4 outColor;
out gl_PerVertex { vec4 gl_Position; };
void main() {
outColor = inColor;
gl_Position = myBufferVals.WorldViewProj * pos;
}
)"
}
};
@ -279,71 +284,145 @@ const UniformBufferDesc vsColBufDesc { sizeof(VsColUB), {
static const std::vector<ShaderSource> vsTexCol = {
{ GLSL_1xx,
"#if __VERSION__ >= 130\n"
"#define attribute in\n"
"#define varying out\n"
"#endif\n"
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"attribute vec2 TexCoord0;\n"
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
" oColor0 = Color0;\n"
" oTexCoord0 = TexCoord0;\n"
"}\n"
R"(
#if __VERSION__ >= 130
#define attribute in
#define varying out
#endif
attribute vec3 Position;
attribute vec4 Color0;
attribute vec2 TexCoord0;
varying vec4 oColor0;
varying vec2 oTexCoord0;
uniform mat4 WorldViewProj;
uniform vec2 TintSaturation;
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
void main() {
gl_Position = WorldViewProj * vec4(Position, 1.0);
vec3 hsv = rgb2hsv(Color0.xyz);
hsv.x += TintSaturation.x;
hsv.y *= TintSaturation.y;
oColor0 = vec4(hsv2rgb(hsv), Color0.w);
oTexCoord0 = TexCoord0;
})",
},
{ ShaderLanguage::HLSL_D3D9,
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj : register(c0);\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
" output.Texcoord0 = input.Texcoord0;\n"
" output.Color0 = input.Color0;\n"
" return output;\n"
"}\n"
R"(
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
float4x4 WorldViewProj : register(c0);
float2 TintSaturation : register(c4);
float3 rgb2hsv(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
float3 hsv2rgb(float3 c) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
VS_OUTPUT main(VS_INPUT input) {
VS_OUTPUT output;
float3 hsv = rgb2hsv(input.Color0.xyz);
hsv.x += TintSaturation.x;
hsv.y *= TintSaturation.y;
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
output.Position = mul(float4(input.Position, 1.0), WorldViewProj);
output.Texcoord0 = input.Texcoord0;
return output;
}
)"
},
{ ShaderLanguage::HLSL_D3D11,
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Color0 : COLOR0; float2 Texcoord0 : TEXCOORD0; float4 Position : SV_Position; };\n"
"cbuffer ConstantBuffer : register(b0) {\n"
" matrix WorldViewProj;\n"
"};\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(WorldViewProj, float4(input.Position, 1.0));\n"
" output.Texcoord0 = input.Texcoord0;\n"
" output.Color0 = input.Color0;\n"
" return output;\n"
"}\n"
R"(
struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };
struct VS_OUTPUT { float4 Color0 : COLOR0; float2 Texcoord0 : TEXCOORD0; float4 Position : SV_Position; };
cbuffer ConstantBuffer : register(b0) {
matrix WorldViewProj;
float2 TintSaturation;
};
float3 rgb2hsv(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
float3 hsv2rgb(float3 c) {
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, saturate(p - K.xxx), c.y);
}
VS_OUTPUT main(VS_INPUT input) {
VS_OUTPUT output;
float3 hsv = rgb2hsv(input.Color0.xyz);
hsv.x += TintSaturation.x;
hsv.y *= TintSaturation.y;
output.Color0 = float4(hsv2rgb(hsv), input.Color0.w);
output.Position = mul(WorldViewProj, float4(input.Position, 1.0));
output.Texcoord0 = input.Texcoord0;
return output;
}
)"
},
{ ShaderLanguage::GLSL_VULKAN,
"#version 450\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"#extension GL_ARB_shading_language_420pack : enable\n"
"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
" mat4 WorldViewProj;\n"
"} myBufferVals;\n"
"layout (location = 0) in vec4 pos;\n"
"layout (location = 1) in vec4 inColor;\n"
"layout (location = 2) in vec2 inTexCoord;\n"
"layout (location = 0) out vec4 outColor;\n"
"layout (location = 1) out vec2 outTexCoord;\n"
"out gl_PerVertex { vec4 gl_Position; };\n"
"void main() {\n"
" outColor = inColor;\n"
" outTexCoord = inTexCoord;\n"
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
"}\n"
}
};
R"(#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (std140, set = 0, binding = 0) uniform bufferVals {
mat4 WorldViewProj;
vec2 TintSaturation;
} myBufferVals;
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
layout (location = 0) in vec4 pos;
layout (location = 1) in vec4 inColor;
layout (location = 2) in vec2 inTexCoord;
layout (location = 0) out vec4 outColor;
layout (location = 1) out vec2 outTexCoord;
out gl_PerVertex { vec4 gl_Position; };
void main() {
vec3 hsv = rgb2hsv(inColor.xyz);
hsv.x += myBufferVals.TintSaturation.x;
hsv.y *= myBufferVals.TintSaturation.y;
outColor = vec4(hsv2rgb(hsv), inColor.w);
outTexCoord = inTexCoord;
gl_Position = myBufferVals.WorldViewProj * pos;
}
)"
} };
const UniformBufferDesc vsTexColBufDesc{ sizeof(VsTexColUB),{
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 }
{ "WorldViewProj", 0, -1, UniformType::MATRIX4X4, 0 },
{ "TintSaturation", 4, -1, UniformType::FLOAT2, 64 },
} };
ShaderModule *CreateShader(DrawContext *draw, ShaderStage stage, const std::vector<ShaderSource> &sources) {

View File

@ -715,6 +715,9 @@ extern const UniformBufferDesc UBPresetDesc;
struct VsTexColUB {
float WorldViewProj[16];
float tint;
float saturation;
float pad[2];
};
extern const UniformBufferDesc vsTexColBufDesc;
struct VsColUB {

View File

@ -87,6 +87,8 @@ void DrawBuffer::Flush(bool set_blend_state) {
VsTexColUB ub{};
memcpy(ub.WorldViewProj, drawMatrix_.getReadPtr(), sizeof(Lin::Matrix4x4));
ub.tint = tint_;
ub.saturation = saturation_;
draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub));
if (vbuf_) {
draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_, Draw::UPDATE_DISCARD);

View File

@ -180,6 +180,11 @@ public:
curZ_ = curZ;
}
void SetTintSaturation(float tint, float saturation) {
tint_ = tint;
saturation_ = saturation;
}
private:
struct Vertex {
float x, y, z;
@ -206,5 +211,7 @@ private:
float fontscalex = 1.0f;
float fontscaley = 1.0f;
float tint_ = 0.0f;
float saturation_ = 1.0f;
float curZ_ = 0.0f;
};

View File

@ -2,6 +2,7 @@
#include <algorithm>
#include "Core/Config.h"
#include "Common/System/Display.h"
#include "Common/System/System.h"
#include "Common/UI/UI.h"
@ -56,6 +57,8 @@ void UIContext::BeginFrame() {
}
uidrawbufferTop_->SetCurZ(0.0f);
uidrawbuffer_->SetCurZ(0.0f);
uidrawbuffer_->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation);
uidrawbufferTop_->SetTintSaturation(g_Config.fUITint, g_Config.fUISaturation);
ActivateTopScissor();
}

View File

@ -528,7 +528,7 @@ std::string PopupSliderChoice::ValueText() const {
EventReturn PopupSliderChoiceFloat::HandleClick(EventParams &e) {
restoreFocus_ = HasFocus();
SliderFloatPopupScreen *popupScreen = new SliderFloatPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_);
SliderFloatPopupScreen *popupScreen = new SliderFloatPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_, liveUpdate_);
popupScreen->OnChange.Handle(this, &PopupSliderChoiceFloat::HandleChange);
if (e.v)
popupScreen->SetPopupOrigin(e.v);
@ -707,6 +707,9 @@ EventReturn SliderFloatPopupScreen::OnSliderChange(EventParams &params) {
sprintf(temp, "%0.3f", sliderValue_);
edit_->SetText(temp);
changing_ = false;
if (liveUpdate_) {
*value_ = sliderValue_;
}
return EVENT_DONE;
}
@ -736,6 +739,8 @@ void SliderFloatPopupScreen::OnCompleted(DialogResult result) {
e.a = (int)*value_;
e.f = *value_;
OnChange.Trigger(e);
} else {
*value_ = originalValue_;
}
}

View File

@ -206,8 +206,8 @@ private:
class SliderFloatPopupScreen : public PopupScreen {
public:
SliderFloatPopupScreen(float *value, float minValue, float maxValue, const std::string &title, float step = 1.0f, const std::string &units = "")
: PopupScreen(title, "OK", "Cancel"), units_(units), value_(value), minValue_(minValue), maxValue_(maxValue), step_(step), changing_(false) {}
SliderFloatPopupScreen(float *value, float minValue, float maxValue, const std::string &title, float step = 1.0f, const std::string &units = "", bool liveUpdate = false)
: PopupScreen(title, "OK", "Cancel"), units_(units), value_(value), originalValue_(*value), minValue_(minValue), maxValue_(maxValue), step_(step), changing_(false), liveUpdate_(liveUpdate) {}
void CreatePopupContents(UI::ViewGroup *parent) override;
Event OnChange;
@ -222,11 +222,13 @@ private:
UI::TextEdit *edit_;
std::string units_;
float sliderValue_;
float originalValue_;
float *value_;
float minValue_;
float maxValue_;
float step_;
bool changing_;
bool liveUpdate_;
};
class TextEditPopupScreen : public PopupScreen {
@ -388,7 +390,9 @@ public:
void SetZeroLabel(const std::string &str) {
zeroLabel_ = str;
}
void SetLiveUpdate(bool update) {
liveUpdate_ = update;
}
Event OnChange;
protected:
@ -406,6 +410,7 @@ private:
std::string units_;
ScreenManager *screenManager_;
bool restoreFocus_;
bool liveUpdate_ = false;
};
class PopupTextInputChoice: public AbstractChoiceWithValueDisplay {

View File

@ -579,6 +579,8 @@ static ConfigSetting generalSettings[] = {
ConfigSetting("InternalScreenRotation", &g_Config.iInternalScreenRotation, ROTATION_LOCKED_HORIZONTAL),
ConfigSetting("BackgroundAnimation", &g_Config.iBackgroundAnimation, 1, true, false),
ConfigSetting("UITint", &g_Config.fUITint, 0.0, true, false),
ConfigSetting("UISaturation", &g_Config.fUISaturation, 1.0, true, false),
#if defined(USING_WIN_UI)
ConfigSetting("TopMost", &g_Config.bTopMost, false),

View File

@ -186,6 +186,9 @@ public:
int iWindowWidth; // Windows and other windowed environments
int iWindowHeight;
float fUITint;
float fUISaturation;
bool bVertexCache;
bool bTextureBackoffCache;
bool bTextureSecondaryCache;

View File

@ -892,6 +892,9 @@ void GameSettingsScreen::CreateViews() {
return UI::EVENT_CONTINUE;
});
systemSettings->Add(new PopupSliderChoiceFloat(&g_Config.fUITint, 0.0, 1.0, n->T("Color Tint"), 0.01f, screenManager()))->SetLiveUpdate(true);
systemSettings->Add(new PopupSliderChoiceFloat(&g_Config.fUISaturation, 0.0, 1.0, n->T("Color Saturation"), 0.01f, screenManager()))->SetLiveUpdate(true);
static const char *backgroundAnimations[] = { "No animation", "Floating symbols", "Recent games", "Waves", "Moving background" };
systemSettings->Add(new PopupMultiChoice(&g_Config.iBackgroundAnimation, sy->T("UI background animation"), backgroundAnimations, 0, ARRAY_SIZE(backgroundAnimations), sy->GetName(), screenManager()));

View File

@ -332,8 +332,9 @@ void DrawBackground(UIContext &dc, float alpha, float x, float y, float z) {
dc.Flush();
dc.RebindTexture();
} else {
// I_BG original color: 0xFF754D24
ImageID img = ImageID("I_BG");
ui_draw2d.DrawImageStretch(img, dc.GetBounds(), bgColor);
ui_draw2d.DrawImageStretch(img, dc.GetBounds(), bgColor & 0xFF754D24);
}
#if PPSSPP_PLATFORM(IOS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB