Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 99 additions & 1 deletion src/effects/color.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,109 @@ uniform float red;
uniform float green;
uniform float blue;
uniform float blend;
uniform int mode;

const int NORMAL = 0;
const int MULTIPLY = 1;
const int SCREEN = 2;
const int OVERLAY = 3;
const int DARKEN = 4;
const int LIGHTEN = 5;
const int PLUS_DARKER = 6;
const int PLUS_LIGHTER = 7;
const int COLOR_DODGE = 8;
const int COLOR_BURN = 9;
const int HARD_LIGHT = 10;
const int SOFT_LIGHT = 11;
const int DIFFERENCE = 12;
const int EXCLUSION = 13;
const int HUE = 14;
const int SATURATION = 15;
const int COLOR = 16;
const int LUMINOSITY = 17;

vec3 rgb_to_hsl(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 hsl_to_rgb(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);
}

float soft_light_channel(float base, float _blend) {
if (_blend < 0.5) {
return base - (1.0 - 2.0 * _blend) * base * (1.0 - base);
} else {
float d = (base < 0.25)
? ((16.0 * base - 12.0) * base + 4.0) * base
: sqrt(base);
return base + (2.0 * _blend - 1.0) * (d - base);
}
}

vec3 get_blend(vec3 base, vec3 _blend) {
if (mode == MULTIPLY) return base * _blend;
if (mode == SCREEN) return 1 - (1 - base) * (1 - _blend);
if (mode == OVERLAY) {
vec3 result;
result.r = base.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
result.g = base.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
result.b = base.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
return result;
}
if (mode == DARKEN) return min(base, _blend);
if (mode == LIGHTEN) return max(base, _blend);
if (mode == PLUS_DARKER) return base + _blend - 1;
if (mode == PLUS_LIGHTER) return base + _blend;
if (mode == COLOR_DODGE) return base / (1 - _blend);
if (mode == COLOR_BURN) return 1 - (1 - base) / _blend;
if (mode == HARD_LIGHT) {
vec3 result;
result.r = _blend.r < 0.5 ? (2.0 * base.r * _blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - _blend.r));
result.g = _blend.g < 0.5 ? (2.0 * base.g * _blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - _blend.g));
result.b = _blend.b < 0.5 ? (2.0 * base.b * _blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - _blend.b));
return result;
}
if (mode == SOFT_LIGHT) {
return vec3(soft_light_channel(base.r, _blend.r), soft_light_channel(base.g, _blend.g), soft_light_channel(base.b, _blend.b));
}
if (mode == DIFFERENCE) return abs(base - _blend);
if (mode == EXCLUSION) return 0.5 - 2 * (base - 0.5) * (_blend - 0.5);
if (mode == HUE) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(blend_hsl.x, base_hsl.y, base_hsl.z));
}
if (mode == SATURATION) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(base_hsl.x, blend_hsl.y, base_hsl.z));
}
if (mode == COLOR) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(blend_hsl.x, blend_hsl.y, base_hsl.z));
}
if (mode == LUMINOSITY) {
vec3 base_hsl = rgb_to_hsl(base);
vec3 blend_hsl = rgb_to_hsl(_blend);
return hsl_to_rgb(vec3(base_hsl.x, base_hsl.y, blend_hsl.z));
}
return _blend; // For NORMAL
}

void main() {
vec4 c = texture2D(tex, cogl_tex_coord_in[0].st);
vec3 pix_color = c.xyz;
vec3 color = vec3(red, green, blue);
vec3 color = get_blend(pix_color, vec3(red, green, blue));

cogl_color_out = vec4(mix(pix_color, color, blend), 1.);
}
32 changes: 30 additions & 2 deletions src/effects/color.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import GObject from 'gi://GObject';

import * as utils from '../conveniences/utils.js';

const Shell = await utils.import_in_shell_only('gi://Shell');
const Clutter = await utils.import_in_shell_only('gi://Clutter');

const SHADER_FILENAME = 'color.glsl';
const DEFAULT_PARAMS = {
color: [0.0, 0.0, 0.0, 0.0]
color: [0.0, 0.0, 0.0, 0.0],
blend_mode: 0
};


Expand Down Expand Up @@ -47,7 +49,18 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
0.0, 1.0,
0.0,
),
'blend_mode': GObject.ParamSpec.int(
`blend_mode`,
`Blend mode`,
`Blend mode`,
GObject.ParamFlags.READWRITE,
0, 17,
0,
)
}
// Normal (0), Multiply (1), Screen (2), Overlay (3), Darken (4), Lighten (5), Plus darker (6), Plus lighter (7), Color dodge (8),
// Color burn (9), Hard light (10), Soft light (11), Difference (12), Exclusion (13), Hue (14), Saturation (15), Color (16),
// Luminosity (17)
}, class ColorEffect extends Clutter.ShaderEffect {
constructor(params) {
// initialize without color as a parameter
Expand All @@ -58,14 +71,16 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
this._green = null;
this._blue = null;
this._blend = null;
this._blend_mode = null;

// set shader source
this._source = utils.get_shader_source(Shell, SHADER_FILENAME, import.meta.url);
if (this._source)
this.set_shader_source(this._source);

// set shader color
// set params; utils.setup_params doesn't work here with color
this.color = 'color' in params ? color : this.constructor.default_params.color;
this.blend_mode = 'blend_mode' in params ? params.blend_mode : this.constructor.default_params.blend_mode;
}

static get default_params() {
Expand Down Expand Up @@ -121,6 +136,18 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
}
}

get blend_mode() {
return this._blend_mode;
}

set blend_mode(value) {
if (this._blend_mode !== value) {
this._blend_mode = value;

this.set_uniform_value('mode', this._blend_mode);
}
}

set color(rgba) {
let [r, g, b, a] = rgba;
this.red = r;
Expand All @@ -136,5 +163,6 @@ export const ColorEffect = utils.IS_IN_PREFERENCES ?
/// False set function, only cares about the color. Too hard to change.
set(params) {
this.color = params.color;
this.blend_mode = params.blend_mode;
}
});
25 changes: 25 additions & 0 deletions src/effects/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,31 @@ export function get_supported_effects(_ = () => "") {
name: _("Color"),
description: _("The color to blend in. The blending amount is controled by the opacity of the color."),
type: "rgba"
},
blend_mode: {
name: _("Blend mode"),
description: _("How the color is blended in."),
type: "dropdown",
options: [
_("Normal"),
_("Multiply"),
_("Screen"),
_("Overlay"),
_("Darken"),
_("Lighten"),
_("Plus darker"),
_("Plus lighter"),
_("Color dodge"),
_("Color burn"),
_("Hard light"),
_("Soft light"),
_("Difference"),
_("Exclusion"),
_("Hue"),
_("Saturation"),
_("Color"),
_("Luminosity")
]
}
}
},
Expand Down