Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a single-pass-fragment-shader path #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
96 changes: 90 additions & 6 deletions src/deco-effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#include "deco-effects.hpp"
#include "smoke-shaders.hpp"
#include "effect-shaders.hpp"
#include "overlay-shaders.hpp"


namespace wf
Expand All @@ -43,6 +45,14 @@ static std::string stitch_smoke_shader(const std::string& source)
return smoke_header + source + effect_run_for_region_main;
}

static GLint compile_fragment_effect_program(const std::string& effect_source, const std::string& overlay_source)
{
std::string full_fragment =
generic_effect_fragment_header + effect_source + overlay_source + generic_effect_fragment_main;

return OpenGL::compile_program(generic_effect_vertex_shader, full_fragment);
}

// ported from https://www.shadertoy.com/view/WdXBW4
static const char *render_source_clouds =
R"(
Expand Down Expand Up @@ -183,13 +193,8 @@ void main() {
// Mix the cloud color with the background, considering darkness, cover, and alpha
vec3 finalColor = mix(skycolour, cloudColor * clouddark, cloudPattern + noiseShape + noiseColor) * (1.0 - cloudCover) + cloudColor * cloudCover;
finalColor = mix(skycolour, finalColor, cloudAlpha);

imageStore(out_tex, pos, vec4(finalColor, 1.0));
}



)";
})";

// ported from https://github.com/keijiro/ShaderSketches/blob/master/Fragment/Dots3.glsl
static const char *render_source_halftone =
Expand Down Expand Up @@ -2143,11 +2148,39 @@ void smoke_t::destroy_programs()
project2_program = project3_program = project4_program = project5_program =
project6_program = advect1_program = advect2_program = render_program =
render_overlay_program = GLuint(-1);

fragment_effect_only_program.free_resources();
}

void smoke_t::create_programs()
{
destroy_programs();

static std::map<std::string, std::string> fragment_effect_sources = {
{"clouds", effect_clouds_fragment},
{"neon_pattern", effect_neon_pattern_fragment},
};

static std::map<std::string, std::string> overlay_effect_sources = {
{"none", overlay_no_overlay},
{"rounded_corners", overlay_rounded_corners},
};

if (fragment_effect_sources.count(effect_type) &&
overlay_effect_sources.count(overlay_engine))
{
OpenGL::render_begin();
GLint program = compile_fragment_effect_program(
fragment_effect_sources[effect_type],
overlay_effect_sources[overlay_engine]);
fragment_effect_only_program.set_simple(program);
OpenGL::render_end();
return;
} else
{
fragment_effect_only_program.set_simple(0);
}

OpenGL::render_begin();
if ((std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink"))
{
Expand Down Expand Up @@ -2414,6 +2447,13 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
bool ink, wf::pointf_t p, wf::color_t decor_color, wf::color_t effect_color,
int title_height, int border_size, int shadow_radius)
{
last_shadow_radius = shadow_radius;
if (fragment_effect_only_program.get_program_id(wf::TEXTURE_TYPE_RGBA) > 0)
{
// Fragment-only programs are directly rendered and don't need any preparation.
return;
}

bool smoke = (std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink");
if ((rectangle.width <= 0) || (rectangle.height <= 0))
{
Expand Down Expand Up @@ -2592,9 +2632,53 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
OpenGL::render_end();
}

void smoke_t::run_fragment_shader(const wf::render_target_t& fb,
wf::geometry_t rectangle, const wf::region_t& scissor)
{
fragment_effect_only_program.use(wf::TEXTURE_TYPE_RGBA);

GLfloat vertexData[] = {
1.0f * rectangle.x, 1.0f * rectangle.y + rectangle.height,
1.0f * rectangle.x + rectangle.width, 1.0f * rectangle.y + rectangle.height,
1.0f * rectangle.x + rectangle.width, 1.0f * rectangle.y,
1.0f * rectangle.x, 1.0f * rectangle.y,
};

fragment_effect_only_program.attrib_pointer("position", 2, 0, vertexData);
fragment_effect_only_program.uniformMatrix4f("MVP", fb.get_orthographic_projection());

fragment_effect_only_program.uniform1f("current_time", wf::get_current_time() / 30.0);
fragment_effect_only_program.uniform1f("width", rectangle.width);
fragment_effect_only_program.uniform1f("height", rectangle.height);
fragment_effect_only_program.uniform2f("topLeftCorner", rectangle.x, rectangle.y);

if (std::string(overlay_engine) == "rounded_corners")
{
fragment_effect_only_program.uniform1i("shadow_radius", last_shadow_radius * 2);
fragment_effect_only_program.uniform1i("corner_radius", rounded_corner_radius);
}

glm::vec4 color {
shadow_color.value().r, shadow_color.value().g, shadow_color.value().b, shadow_color.value().a};
fragment_effect_only_program.uniform4f("shadow_color", color);

for (auto& box : scissor)
{
fb.logic_scissor(wlr_box_from_pixman_box(box));
GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
}

}

void smoke_t::render_effect(const wf::render_target_t& fb, wf::geometry_t rectangle,
const wf::region_t& scissor)
{
if (fragment_effect_only_program.get_program_id(wf::TEXTURE_TYPE_RGBA) != 0)
{
run_fragment_shader(fb, rectangle, scissor);
return;
}

OpenGL::render_transformed_texture(wf::texture_t{texture}, rectangle,
fb.get_orthographic_projection(), glm::vec4{1},
OpenGL::TEXTURE_TRANSFORM_INVERT_Y | OpenGL::RENDER_FLAG_CACHED);
Expand Down
6 changes: 5 additions & 1 deletion src/deco-effects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <wayfire/option-wrapper.hpp>
#include <wayfire/core.hpp>
#include <wayfire/opengl.hpp>
#include <map>
#include <GLES3/gl32.h>

namespace wf
Expand All @@ -19,20 +18,25 @@ class smoke_t
advect1_program, advect2_program, render_program, render_overlay_program,
texture, b0u, b0v, b0d, b1u, b1v, b1d, neural_network_tex;

OpenGL::program_t fragment_effect_only_program{};
int saved_width = -1, saved_height = -1;

wf::option_wrapper_t<std::string> effect_type{"pixdecor/effect_type"};
wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
wf::option_wrapper_t<bool> effect_animate{"pixdecor/animate"};
wf::option_wrapper_t<int> rounded_corner_radius{"pixdecor/rounded_corner_radius"};
wf::option_wrapper_t<wf::color_t> shadow_color{"pixdecor/shadow_color"};
int last_shadow_radius = 0;

public:
smoke_t();
~smoke_t();

void run_shader(GLuint program, int width, int height, int title_height, int border_size, int radius);
void run_shader_region(GLuint program, const wf::region_t & region, const wf::dimensions_t & size);
void run_fragment_shader(const wf::render_target_t& fb,
wf::geometry_t rectangle, const wf::region_t& scissor);

void dispatch_region(const wf::region_t& region);

void step_effect(const wf::render_target_t& fb, wf::geometry_t rectangle,
Expand Down
181 changes: 181 additions & 0 deletions src/effect-shaders.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
static const char *generic_effect_vertex_shader = R"(
#version 320 es

in highp vec2 position;
out highp vec2 relativePosition;

uniform mat4 MVP;
uniform vec2 topLeftCorner;

void main() {
relativePosition = position.xy - topLeftCorner;
gl_Position = MVP * vec4(position.xy, 0.0, 1.0);
})";

static const char *generic_effect_fragment_header = R"(
#version 320 es
precision highp float;
precision highp image2D;

in highp vec2 relativePosition;
uniform float current_time;
uniform float width;
uniform float height;

out vec4 fragColor;
)";

static const char *generic_effect_fragment_main = R"(
void main()
{
fragColor = overlay_function(relativePosition);
})";

// ported from https://www.shadertoy.com/view/WdXBW4
static const char *effect_clouds_fragment = R"(
float cloudscale=2.1; // Added cloudscale parameter
const mat2 m = mat2(1.6, 1.2, -1.2, 1.6);

vec2 hash(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}

float noise(vec2 p) {
const float K1 = 0.366025404; // (sqrt(3)-1)/2;
const float K2 = 0.211324865; // (3-sqrt(3))/6;
vec2 i = floor(p + (p.x + p.y) * K1);
vec2 a = p - i + (i.x + i.y) * K2;
vec2 o = (a.x > a.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec2 b = a - o + K2;
vec2 c = a - 1.0 + 2.0 * K2;
vec3 h = max(0.5 - vec3(dot(a, a), dot(b, b), dot(c, c)), 0.0);
vec3 n = h * h * h * h * vec3(dot(a, hash(i + 0.0)), dot(b, hash(i + o)), dot(c, hash(i + 1.0)));
return dot(n, vec3(70.0));
}

float fbm(vec2 n) {
float total = 0.0, amplitude = 0.1;
for (int i = 0; i < 7; i++) {
total += noise(n) * amplitude;
n = m * n;
amplitude *= 0.4;
}
return total;
}

vec4 effect_color(vec2 pos)
{
vec2 uv = pos / vec2(width, height);

float time = 0.003 * current_time; // Time variable for animation

float cloudPattern1 = fbm(uv * 10.0 * cloudscale + time);
float cloudPattern2 = fbm(uv * 5.0 * cloudscale + time);
float cloudPattern3 = fbm(uv * 3.0 * cloudscale + time);

// Combine different cloud patterns with different weights
float cloudPattern = 0.5 * cloudPattern1 + 0.3 * cloudPattern2 + 0.2 * cloudPattern3;

// Ridge noise shape
float ridgeNoiseShape = 0.0;
uv *= cloudscale * 1.1; // Adjust scale
float weight = 0.8;
for (int i = 0; i < 8; i++) {
ridgeNoiseShape += abs(weight * noise(uv));
uv = m * uv + time;
weight *= 0.7;
}

// Noise shape
float noiseShape = 0.0;
uv = vec2(pos) / vec2(width, height);
uv *= cloudscale * 1.1; // Adjust scale
weight = 0.7;
for (int i = 0; i < 8; i++) {
noiseShape += weight * noise(uv);
uv = m * uv + time;
weight *= 0.6;
}

noiseShape *= ridgeNoiseShape + noiseShape;

// Noise color
float noiseColor = 0.0;
uv = vec2(pos) / vec2(width, height);
uv *= 2.0 * cloudscale; // Adjust scale
weight = 0.4;
for (int i = 0; i < 7; i++) {
noiseColor += weight * noise(uv);
uv = m * uv + time;
weight *= 0.6;
}

// Noise ridge color
float noiseRidgeColor = 0.0;
uv = vec2(pos) / vec2(width, height);
uv *= 3.0 * cloudscale; // Adjust scale
weight = 0.4;
for (int i = 0; i < 7; i++) {
noiseRidgeColor += abs(weight * noise(uv));
uv = m * uv + time;
weight *= 0.6;
}

noiseColor += noiseRidgeColor;

// Sky tint
float skytint = 0.5;
vec3 skyColour1 = vec3(0.1, 0.2, 0.3);
vec3 skyColour2 = vec3(0.4, 0.7, 1.0);
vec3 skycolour = mix(skyColour1, skyColour2, smoothstep(0.4, 0.6, uv.y));

// Cloud darkness
float clouddark = 0.5;

// Cloud Cover, Cloud Alpha
float cloudCover = 0.01;
float cloudAlpha = 2.0;

// Movement effect
uv = uv + time;

// Use a bright color for clouds
vec3 cloudColor = vec3(1.0, 1.0, 1.0); ; // Bright white color for clouds

// Mix the cloud color with the background, considering darkness, cover, and alpha
vec3 finalColor = mix(skycolour, cloudColor * clouddark, cloudPattern + noiseShape + noiseColor) * (1.0 - cloudCover) + cloudColor * cloudCover;
finalColor = mix(skycolour, finalColor, cloudAlpha);

return vec4(finalColor, 1.0);
})";

// ported from https://www.shadertoy.com/view/mtyGWy
static const char *effect_neon_pattern_fragment = R"(
vec3 palette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.263, 0.416, 0.557);
return a + b * cos(6.28318 * (c * t + d));
}

vec4 effect_color(vec2 pos) {
vec2 uv = pos / vec2(width, height);
vec2 uv0 = uv;
vec3 finalColor = vec3(0.0);

for (float i = 0.0; i < 4.0; i++) {
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(uv0));

vec3 col = palette(length(uv0) + i * 0.4 + current_time * 0.000001);

d = sin(d * 8.0 + current_time * 0.02) / 8.0;
d = abs(d);
d = pow(0.01 / d, 1.2);
finalColor += col * d;
}

return vec4(finalColor, 1.0);
})";
Loading