diff --git a/metadata/pixdecor.xml b/metadata/pixdecor.xml
index f0fcc26..5f02b54 100644
--- a/metadata/pixdecor.xml
+++ b/metadata/pixdecor.xml
@@ -92,70 +92,104 @@
+ <_short>Effect Type
+ <_long>Sets the effect type.
+ none
+
+ none
+ <_name>None
+
+
+ smoke
+ <_name>Smoke
+
+
+ ink
+ <_name>Ink
+
+
+ fumes
+ <_name>Fumes
+
+
+ fast_smoke
+ <_name>Fast Smoke
+
+
+
+ clouds
+ <_name>Clouds
+
+
+ halftone
+ <_name>Halftone
+
+
+ pattern
+ <_name>Pattern
+
+
+ lava
+ <_name>Lava
+
+
+ hex
+ <_name>Hex
+
+
+ zebra
+ <_name>Zebra
+
+
+ neural_network
+ <_name>Neural network
+
+
+ hexagon_maze
+ <_name>Hexagon maze
+
+
+ raymarched_truchet
+ <_name>Raymarched truchet
+
+
+ neon_pattern
+ <_name>Neon pattern
+
+
+ neon_rings
+ <_name>Neon rings
+
+
+ deco
+ <_name>Deco
+
+
+ ice
+ <_name>Ice
+
+
+ fire
+ <_name>Fire
+
+
+ flame
+ <_name>Flame
+
+
+
+
<_short>Shade
diff --git a/src/deco-effects.cpp b/src/deco-effects.cpp
index 2d5ff45..24c25a8 100644
--- a/src/deco-effects.cpp
+++ b/src/deco-effects.cpp
@@ -6,7 +6,7 @@
* Copyright (c) 2024 Ilia Bozhinov
* - Awesome optimizations
* Copyright (c) 2024 Andrew Pliatsikas
- * - Ported effect shaders to compute
+ * - Fast smoke, fumes, flame and beveled glass
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,7 +31,9 @@
#include
#include "deco-effects.hpp"
+#include "effect-shaders.hpp"
#include "smoke-shaders.hpp"
+#include "overlay-shaders.hpp"
namespace wf
@@ -43,6 +45,16 @@ 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"(
@@ -183,13 +195,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 =
@@ -1660,6 +1667,151 @@ void main() {
}
)";
+// ported from https://www.shadertoy.com/view/3djfzy
+static const char *render_source_ice =
+ R"(#version 320 es
+precision highp float;
+
+layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+layout(binding = 0, rgba32f) writeonly uniform highp image2D outputImage;
+
+layout(location = 5) uniform int width;
+layout(location = 6) uniform int height;
+layout(location = 9) uniform float current_time;
+
+float rand(in vec2 _st) {
+ return fract(sin(dot(_st.xy, vec2(-0.820, -0.840))) * 4757.153);
+}
+
+float noise(in vec2 _st) {
+ const vec2 d = vec2(0.0, 1.0);
+ vec2 b = floor(_st), f = smoothstep(vec2(0.0), vec2(0.1, 0.3), fract(_st));
+ return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
+}
+
+float fbm(in vec2 _st) {
+ float v = sin(current_time * 0.005) * 0.2;
+ float a = 0.3;
+ vec2 shift = vec2(100.0);
+ // Rotate to reduce axial bias
+ mat2 rot = mat2(cos(0.5), sin(1.0), -sin(0.5), acos(0.5));
+ for (int i = 0; i < 3; ++i) {
+ v += a * noise(_st);
+ _st = rot * _st * 2.0 + shift;
+ a *= 1.5;
+ }
+ return v;
+}
+
+void main() {
+ ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
+ if (gid.x >= width || gid.y >= height) return;
+
+ vec2 st = (vec2(gid) * 2.0 - vec2(width, height)) / min(float(width), float(height)) * 0.5;
+
+ vec2 coord = st * 0.2;
+ float len;
+ for (int i = 0; i < 3; i++) {
+ len = length(coord);
+ coord.x += sin(coord.y + current_time * 0.001) * 2.1;
+ coord.y += cos(coord.x + current_time * 0.001 + cos(len * 1.0)) * 1.0;
+ }
+ len -= 3.0;
+
+ vec3 color = vec3(0.0);
+
+ vec2 q = vec2(0.0);
+ q.x = fbm(st);
+ q.y = fbm(st + vec2(-0.450, 0.650));
+
+ vec2 r = vec2(0.0);
+ r.x = fbm(st + 1.0 * q + vec2(0.570, 0.520) + 0.1 * current_time*0.01);
+ r.y = fbm(st + 1.0 * q + vec2(0.340, -0.570) + 0.05 * current_time*0.01);
+ float f = fbm(st + r);
+
+ color = mix(color, cos(len + vec3(0.5, 0.0, -0.1)), 1.0);
+ color = mix(vec3(0.478, 0.738, 0.760), vec3(0.563, 0.580, 0.667), color);
+
+ vec4 fragColor = vec4((f * f * f + .6 * f * f + .5 * f) * color, 1.0);
+
+ imageStore(outputImage, gid, fragColor);
+}
+
+)";
+
+
+// ported from https://www.shadertoy.com/view/XsXXRN
+static const char *render_source_fire =
+ R"(
+
+ #version 320 es
+precision highp float;
+
+layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+layout(binding = 0, rgba32f) writeonly uniform highp image2D outputImage;
+
+layout(location = 5) uniform int width;
+layout(location = 6) uniform int height;
+layout(location = 9) uniform float current_time;
+
+float rand(vec2 n) {
+ return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
+}
+
+float noise(vec2 n) {
+ const vec2 d = vec2(0.0, 1.0);
+ vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
+ return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
+}
+
+float fbm(vec2 n) {
+ float total = 0.0, amplitude = 1.0;
+ for (int i = 0; i < 4; i++) {
+ total += noise(n) * amplitude;
+ n += n;
+ amplitude *= 0.5;
+ }
+ return total;
+}
+
+void main() {
+ ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
+ if (gid.x >= width || gid.y >= height) return;
+
+ // Only flip the y-coordinate when storing the result
+ ivec2 storePos = ivec2(gid.x, height - 1 - gid.y);
+
+ const vec3 c1 = vec3(0.5, 0.0, 0.1);
+ const vec3 c2 = vec3(0.9, 0.0, 0.0);
+ const vec3 c3 = vec3(0.2, 0.0, 0.0);
+ const vec3 c4 = vec3(1.0, 0.9, 0.0);
+ const vec3 c5 = vec3(0.1);
+ const vec3 c6 = vec3(0.9);
+
+ vec2 speed = vec2(0.7, 0.4);
+ float shift = 1.0;
+ float alpha = 1.0;
+
+ // Reduce the effect of current_time by making the change more subtle
+ float timeEffect = current_time * 0.05; // Slowing down the animation by reducing the current_time factor
+
+ vec2 p = vec2(gid) * 8.0 / float(width);
+ float q = fbm(p - timeEffect * 0.1);
+ vec2 r = vec2(fbm(p + q + timeEffect * speed.x - p.x - p.y), fbm(p + q - timeEffect * speed.y));
+ vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y);
+ vec4 fragColor = vec4(c * cos(shift * float(gid.y) / float(height)), alpha);
+
+ // Store the color flipped vertically
+ imageStore(outputImage, storePos, fragColor);
+}
+
+)";
+
+
+
+
+
+
static const char *rounded_corner_overlay =
R"(
#version 320 es
@@ -1769,7 +1921,7 @@ layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout(location = 5) uniform int width;
layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
+layout(location = 10) uniform int beveled_radius;
layout(location = 1) uniform int title_height;
layout(location = 2) uniform int border_size;
@@ -1811,7 +1963,7 @@ float sin01(float x) {
vec4 drawCurveBenzier(vec2 p1, vec2 p2, int setCount) {
vec4 col = vec4(0.0);
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
- float curveRadius = float(radius);
+ float curveRadius = float(beveled_radius/2);
// Draw the lines connecting the points
vec2 fragCoord = vec2(storePos);
@@ -1833,7 +1985,7 @@ vec4 drawCurveBenzier(vec2 p1, vec2 p2, int setCount) {
vec4 drawCurve(vec2 p1, vec2 p2, int setCount) {
vec4 col = vec4(0.0);
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
- float curveRadius = float(radius + 1);
+ float curveRadius = float(beveled_radius + 1);
vec2 fragCoord = vec2(storePos);
float t = clamp(dot(fragCoord - p1, p2 - p1) / dot(p2 - p1, p2 - p1), 0.0, 1.0);
@@ -1885,7 +2037,7 @@ void main() {
vec2 z1 = vec2(0.0 + THICCNESS + space, 0.0 + THICCNESS);
vec2 z2 = vec2(float(width) - THICCNESS - space, 0.0 + THICCNESS);
- float curveRadius = float(radius);
+ float curveRadius = float(beveled_radius);
// Draw the lines connecting the points
int setwidth = int(width);
@@ -1903,7 +2055,7 @@ else {
col += drawCurve(x1, x2, setheight);
col += drawCurve(y1, y2, setwidth);
col += drawCurve(z1, z2, setwidth);
- }
+ }
float INNERspace = 0.0;
@@ -2148,8 +2300,52 @@ void smoke_t::destroy_programs()
void smoke_t::create_programs()
{
destroy_programs();
- OpenGL::render_begin();
- if ((std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink"))
+
+
+
+ static std::map fragment_effect_sources = {
+ {"clouds", effect_clouds_fragment},
+ {"halftone", effect_halftone_fragment},
+ {"pattern", effect_pattern_fragment},
+ {"lava", effect_lava_fragment},
+ {"hex", effect_hex_fragment},
+ {"zebra", effect_zebra_fragment},
+ {"neural_network", effect_neural_network_fragment},
+ {"hexagon_maze", effect_hexagon_maze_fragment},
+ {"raymarched_truchet", effect_raymarched_truchet_fragment},
+ {"neon_pattern", effect_neon_pattern_fragment},
+ {"neon_rings", effect_neon_rings_fragment},
+ {"deco", effect_deco_fragment},
+ {"ice", effect_ice_fragment},
+ {"fire", effect_fire_fragment},
+ // {"smoke", effect_render_fragment},
+
+ };
+
+ static std::map overlay_effect_sources = {
+ {"none", overlay_no_overlay},
+ {"rounded_corners", overlay_rounded_corners},
+ {"beveled_glass", overlay_beveled_glass},
+ };
+
+
+ if (std::string(compute_fragment_shader) == "fragment_shader"){
+
+ 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;
+ }
+}
+
+ OpenGL::render_begin();
+ if ((std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink") )
{
setup_shader(&motion_program, motion_source);
setup_shader(&diffuse1_program, stitch_smoke_shader(diffuse1_source));
@@ -2163,7 +2359,58 @@ void smoke_t::create_programs()
setup_shader(&advect1_program, stitch_smoke_shader(advect1_source));
setup_shader(&advect2_program, stitch_smoke_shader(advect2_source));
setup_shader(&render_program, std::string(render_source) + effect_run_for_region_main);
- } else if (std::string(effect_type) == "clouds")
+ }
+ else if ((std::string(effect_type) == "fumes"))
+ {
+ setup_shader(&motion_program, fumes_motion_source);
+ setup_shader(&diffuse1_program, stitch_smoke_shader(fumes_diffuse1_source));
+/**/ setup_shader(&diffuse2_program, stitch_smoke_shader(fumes_diffuse2_source));
+ setup_shader(&project1_program, stitch_smoke_shader(fumes_project1_source));
+ setup_shader(&project2_program, stitch_smoke_shader(fumes_project2_source));
+ setup_shader(&project3_program, stitch_smoke_shader(fumes_project3_source));
+/**/ setup_shader(&project4_program, stitch_smoke_shader(fumes_project4_source));
+/**/ setup_shader(&project5_program, stitch_smoke_shader(fumes_project5_source));
+/**/ setup_shader(&project6_program, stitch_smoke_shader(fumes_project6_source));
+ setup_shader(&advect1_program, stitch_smoke_shader(fumes_advect1_source));
+/**/ setup_shader(&advect2_program, stitch_smoke_shader(fumes_advect2_source));
+ setup_shader(&render_program, std::string(fumes_render_source) + effect_run_for_region_main);
+ }
+ else if ((std::string(effect_type) == "fast_smoke"))
+ {
+ setup_shader(&motion_program, fast_smoke_motion_source);
+ setup_shader(&diffuse1_program, stitch_smoke_shader(fast_smoke_diffuse1_source));
+/**/ setup_shader(&diffuse2_program, stitch_smoke_shader(fast_smoke_diffuse2_source));
+ setup_shader(&project1_program, stitch_smoke_shader(fast_smoke_project1_source));
+ setup_shader(&project2_program, stitch_smoke_shader(fast_smoke_project2_source));
+ setup_shader(&project3_program, stitch_smoke_shader(fast_smoke_project3_source));
+/**/ setup_shader(&project4_program, stitch_smoke_shader(fast_smoke_project4_source));
+/**/ setup_shader(&project5_program, stitch_smoke_shader(fast_smoke_project5_source));
+/**/ setup_shader(&project6_program, stitch_smoke_shader(fast_smoke_project6_source));
+ setup_shader(&advect1_program, stitch_smoke_shader(fast_smoke_advect1_source));
+/**/ setup_shader(&advect2_program, stitch_smoke_shader(fast_smoke_advect2_source));
+ setup_shader(&render_program, std::string(fast_smoke_render_source) + effect_run_for_region_main);
+ }
+
+
+
+ else if ((std::string(effect_type) == "flame"))
+ {
+ setup_shader(&motion_program, flame_motion_source);
+ setup_shader(&diffuse1_program, stitch_smoke_shader(flame_diffuse1_source));
+/**/ setup_shader(&diffuse2_program, stitch_smoke_shader(flame_diffuse2_source));
+ setup_shader(&project1_program, stitch_smoke_shader(flame_project1_source));
+ setup_shader(&project2_program, stitch_smoke_shader(flame_project2_source));
+ setup_shader(&project3_program, stitch_smoke_shader(flame_project3_source));
+/**/ setup_shader(&project4_program, stitch_smoke_shader(flame_project4_source));
+/**/ setup_shader(&project5_program, stitch_smoke_shader(flame_project5_source));
+/**/ setup_shader(&project6_program, stitch_smoke_shader(flame_project6_source));
+ setup_shader(&advect1_program, stitch_smoke_shader(flame_advect1_source));
+/**/ setup_shader(&advect2_program, stitch_smoke_shader(flame_advect2_source));
+ setup_shader(&render_program, std::string(flame_render_source) + effect_run_for_region_main);
+ }
+
+
+ else if (std::string(effect_type) == "clouds")
{
setup_shader(&render_program, render_source_clouds);
} else if (std::string(effect_type) == "halftone")
@@ -2200,7 +2447,14 @@ void smoke_t::create_programs()
{
setup_shader(&render_program, render_source_deco);
}
-
+ else if (std::string(effect_type) == "ice")
+ {
+ setup_shader(&render_program, render_source_ice);
+ }
+ else if (std::string(effect_type) == "fire")
+ {
+ setup_shader(&render_program, render_source_fire);
+ }
if (std::string(overlay_engine) == "rounded_corners")
{
setup_shader(&render_overlay_program, rounded_corner_overlay);
@@ -2339,20 +2593,20 @@ void smoke_t::recreate_textures(wf::geometry_t rectangle)
destroy_textures();
create_textures();
+ GLuint fb;
+ GL_CALL(glGenFramebuffers(1, &fb));
+ GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
+
GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, rectangle.width, rectangle.height));
- if ((std::string(effect_type) != "smoke") && (std::string(effect_type) != "ink"))
+ if ((std::string(effect_type) != "smoke") && (std::string(effect_type) != "ink")&& (std::string(effect_type) != "fumes") && (std::string(effect_type) != "fast_smoke") && (std::string(effect_type) != "flame"))
{
return;
}
- GLuint fb;
- GL_CALL(glGenFramebuffers(1, &fb));
- GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
-
wf::color_t clear_color{0, 0, 0, 0};
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture, 0));
@@ -2414,7 +2668,14 @@ 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)
{
- bool smoke = (std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink");
+ 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"|| (std::string(effect_type) == "fumes") || (std::string(effect_type) == "fast_smoke") || (std::string(effect_type) == "flame"));
if ((rectangle.width <= 0) || (rectangle.height <= 0))
{
return;
@@ -2423,6 +2684,14 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
int radius = shadow_radius;
int diffuse_iterations = 2;
+
+ if (std::string(effect_type) == "fumes")
+ {
+
+ diffuse_iterations = 10;
+ }
+
+
OpenGL::render_begin(fb);
if ((rectangle.width != saved_width) || (rectangle.height != saved_height))
{
@@ -2482,6 +2751,7 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
GL_CALL(glBindTexture(GL_TEXTURE_2D, b1d));
GL_CALL(glBindImageTexture(6, b1d, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
+
if ((point.x >= radius) && (point.y >= radius))
{
GL_CALL(glUseProgram(motion_program));
@@ -2499,6 +2769,16 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
}
+
+
+
+
+
+
+
+
+
+
for (int k = 0; k < diffuse_iterations; k++)
{
run_shader_region(diffuse1_program, border_region, wf::dimensions(rectangle));
@@ -2549,7 +2829,7 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
GL_CALL(glUniform1i(5, rectangle.width));
GL_CALL(glUniform1i(6, rectangle.height));
GL_CALL(glUniform1i(7, radius * 2));
- GL_CALL(glUniform1f(9, effect_animate ? ((wf::get_current_time() / 30) & 0xFF) : 0.0));
+ GL_CALL(glUniform1f(9, effect_animate ? (wf::get_current_time() / 30.0) : 0.0));
GL_CALL(glDispatchCompute(rectangle.width / 15, rectangle.height / 15, 1));
GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
}
@@ -2575,8 +2855,16 @@ void smoke_t::step_effect(const wf::render_target_t& fb, wf::geometry_t rectangl
GL_CALL(glUniform1i(5, rectangle.width));
GL_CALL(glUniform1i(6, rectangle.height));
GL_CALL(glUniform1i(7, rounded_corner_radius));
+
+
+ if (std::string(overlay_engine) == "beveled_glass")
+ {
+ GL_CALL(glUniform1i(10, beveled_radius));
+ }
+
if (std::string(overlay_engine) == "rounded_corners")
{
+
GLfloat shadow_color_f[4] =
{GLfloat(wf::color_t(shadow_color).r), GLfloat(wf::color_t(shadow_color).g),
GLfloat(wf::color_t(shadow_color).b), GLfloat(wf::color_t(shadow_color).a)};
@@ -2592,9 +2880,79 @@ 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,int border_size, int title_height)
+{
+ glm::vec4 color;
+
+ 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.uniform1i("border_size", border_size);
+ fragment_effect_only_program.uniform1i("title_height", title_height);
+ fragment_effect_only_program.uniform1f("width", rectangle.width);
+ fragment_effect_only_program.uniform1f("height", rectangle.height);
+
+ 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);
+ fragment_effect_only_program.uniform2f("topLeftCorner", rectangle.x, rectangle.y);
+ color = glm::vec4(shadow_color.value().r,shadow_color.value().g,shadow_color.value().b,shadow_color.value().a);
+ fragment_effect_only_program.uniform4f("shadow_color", color);
+//testing purposes
+ // Assuming color is of type glm::vec4
+glm::vec4 black(0.5f, 0.5f, 0.5f, 1.0f); // RGB values for black, A set to 1 for full opacity
+glm::vec4 white(1.0f, 1.0f, 1.0f, .8f); // RGB values for white, A set to 1 for full opacity
+
+// Assuming 'fragment_effect_only_program' is your shader program object
+fragment_effect_only_program.uniform4f("decor_color", black); // Set decor_color to black
+fragment_effect_only_program.uniform4f("smoke_color", white); // Set smoke_color to white
+
+ }
+
+ else if (std::string(overlay_engine) == "beveled_glass")
+ {
+ fragment_effect_only_program.uniform2f("topLeftCorner", rectangle.x, rectangle.y);
+ fragment_effect_only_program.uniform1i("border_size", border_size);
+ fragment_effect_only_program.uniform1i("title_height", title_height+border_size);
+ fragment_effect_only_program.uniform1i("beveled_radius", beveled_radius);
+
+
+ }
+
+
+ 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)
+ const wf::region_t& scissor, int border_size, int title_height)
{
+
+ if (fragment_effect_only_program.get_program_id(wf::TEXTURE_TYPE_RGBA) != 0)
+ {
+ run_fragment_shader(fb, rectangle, scissor, border_size, title_height);
+
+ 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);
diff --git a/src/deco-effects.hpp b/src/deco-effects.hpp
index c92c88c..c8cb601 100644
--- a/src/deco-effects.hpp
+++ b/src/deco-effects.hpp
@@ -19,26 +19,36 @@ class smoke_t
advect1_program, advect2_program, render_program, render_overlay_program,
texture, b0u, b0v, b0d, b1u, b1v, b1d, neural_network_tex;
+ int last_shadow_radius = 0;
+
+ OpenGL::program_t fragment_effect_only_program{};
+
int saved_width = -1, saved_height = -1;
+ wf::option_wrapper_t compute_fragment_shader{"pixdecor/compute_fragment_shader"};
wf::option_wrapper_t effect_type{"pixdecor/effect_type"};
wf::option_wrapper_t overlay_engine{"pixdecor/overlay_engine"};
wf::option_wrapper_t effect_animate{"pixdecor/animate"};
wf::option_wrapper_t rounded_corner_radius{"pixdecor/rounded_corner_radius"};
wf::option_wrapper_t shadow_color{"pixdecor/shadow_color"};
+ wf::option_wrapper_t beveled_radius{"pixdecor/beveled_radius"};
+
public:
smoke_t();
~smoke_t();
void run_shader(GLuint program, int width, int height, int title_height, int border_size, int radius);
+ void run_fragment_shader(const wf::render_target_t& fb,
+ wf::geometry_t rectangle, const wf::region_t& scissor,int border_size, int title_height);
+
void run_shader_region(GLuint program, const wf::region_t & region, const wf::dimensions_t & size);
void dispatch_region(const wf::region_t& region);
void step_effect(const wf::render_target_t& fb, wf::geometry_t rectangle,
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);
- void render_effect(const wf::render_target_t& fb, wf::geometry_t rectangle, const wf::region_t& scissor);
+ void render_effect(const wf::render_target_t& fb, wf::geometry_t rectangle, const wf::region_t& scissor,int border_size,int title_height );
void recreate_textures(wf::geometry_t rectangle);
void create_programs();
void destroy_programs();
diff --git a/src/deco-subsurface.cpp b/src/deco-subsurface.cpp
index 16b112e..7df554c 100644
--- a/src/deco-subsurface.cpp
+++ b/src/deco-subsurface.cpp
@@ -148,6 +148,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in
void render_region(const wf::render_target_t& fb, wf::point_t origin, const wf::region_t& region)
{
int border = theme.get_border_size();
+ int title = theme.get_title_height();
wlr_box geometry{origin.x, origin.y, size.width, size.height};
bool activated = false;
@@ -163,7 +164,7 @@ class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_in
OpenGL::render_begin(fb);
- theme.render_background(fb, geometry, region, activated, current_cursor_position);
+ theme.render_background(fb, geometry, region, activated, current_cursor_position,border, title);
if (!titlebar_opt)
{
diff --git a/src/deco-theme.cpp b/src/deco-theme.cpp
index d2e1b06..fb89a17 100644
--- a/src/deco-theme.cpp
+++ b/src/deco-theme.cpp
@@ -112,7 +112,7 @@ void decoration_theme_t::set_maximize(bool state)
* @param active Whether to use active or inactive colors
*/
void decoration_theme_t::render_background(const wf::render_target_t& fb,
- wf::geometry_t rectangle, const wf::region_t& scissor, bool active, wf::pointf_t p)
+ wf::geometry_t rectangle, const wf::region_t& scissor, bool active, wf::pointf_t p,int border_size, int title_height)
{
if ((std::string(effect_type) == "none") && (std::string(overlay_engine) == "none"))
{
@@ -123,7 +123,7 @@ void decoration_theme_t::render_background(const wf::render_target_t& fb,
}
} else
{
- smoke.render_effect(fb, rectangle, scissor);
+ smoke.render_effect(fb, rectangle, scissor,border_size, title_height);
}
}
diff --git a/src/deco-theme.hpp b/src/deco-theme.hpp
index 3334d48..9cfad81 100644
--- a/src/deco-theme.hpp
+++ b/src/deco-theme.hpp
@@ -45,8 +45,8 @@ class decoration_theme_t
* @param scissor The GL scissor rectangle to use.
* @param active Whether to use active or inactive colors
*/
- void render_background(const wf::render_target_t& fb,
- wf::geometry_t rectangle, const wf::region_t& scissor, bool active, wf::pointf_t p);
+ void render_background(const wf::render_target_t& fb,
+ wf::geometry_t rectangle, const wf::region_t& scissor, bool active, wf::pointf_t p,int border_size, int title_height);
/**
* Render the given text on a cairo_surface_t with the given size.
diff --git a/src/effect-shaders.hpp b/src/effect-shaders.hpp
new file mode 100644
index 0000000..1b72c96
--- /dev/null
+++ b/src/effect-shaders.hpp
@@ -0,0 +1,1487 @@
+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(1080, 1920);
+
+ 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(1920, 1080);
+ 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(1920, 1080);
+ 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(1920, 1080);
+ 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);
+})";
+
+static const char *effect_halftone_fragment = R"(
+
+
+
+ const vec2 resolution = vec2(1280.0, 720.0);
+ const float timeFactor = 0.025;
+
+ float rand(vec2 uv) {
+ return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
+ }
+
+ vec2 rotate(vec2 p, float theta) {
+ vec2 sncs = vec2(sin(theta), cos(theta));
+ return vec2(p.x * sncs.y - p.y * sncs.x, p.x * sncs.x + p.y * sncs.y);
+ }
+
+ float swirl(vec2 coord, float t) {
+ float l = length(coord) / resolution.x;
+ float phi = atan(coord.y, coord.x + 1e-6);
+ return sin(l * 10.0 + phi - t * 4.0) * 0.5 + 0.5;
+ }
+
+ float halftone(vec2 coord, float angle, float t, float amp) {
+ coord -= resolution * 0.5;
+ float size = resolution.x / (60.0 + sin(current_time * timeFactor * 0.5) * 50.0);
+ vec2 uv = rotate(coord / size, angle / 180.0 * 3.14159);
+ vec2 ip = floor(uv); // column, row
+ vec2 odd = vec2(0.5 * mod(ip.y, 2.0), 0.0); // odd line offset
+ vec2 cp = floor(uv - odd) + odd; // dot center
+ float d = length(uv - cp - 0.5) * size; // distance
+ float r = swirl(cp * size, t) * size * 0.5 * amp; // dot radius
+ return 1.0 - clamp(d - r, 0.0, 1.0);
+ }
+
+
+vec4 effect_color(vec2 pos) {
+
+
+
+ vec3 c1 = 1.0 - vec3(1.0, 0.0, 0.0) * halftone(relativePosition, 0.0, current_time * timeFactor * 1.00, 0.7);
+ vec3 c2 = 1.0 - vec3(0.0, 1.0, 0.0) * halftone(relativePosition, 30.0, current_time * timeFactor * 1.33, 0.7);
+ vec3 c3 = 1.0 - vec3(0.0, 0.0, 1.0) * halftone(relativePosition, -30.0, current_time * timeFactor * 1.66, 0.7);
+ vec3 c4 = 1.0 - vec3(1.0, 1.0, 1.0) * halftone(relativePosition, 60.0, current_time * timeFactor * 2.13, 0.4);
+ fragColor = vec4(c1 * c2 * c3 * c4, 1.0);
+
+
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+
+static const char *effect_zebra_fragment = R"(
+
+const float resolutionY = 720.0;
+
+
+vec4 effect_color(vec2 pos) {
+
+ const float pi = 3.14159265359;
+ float size = resolutionY / 10.; // cell size in pixel
+
+ vec2 p1 = gl_FragCoord.xy / size; // normalized pos
+ vec2 p2 = fract(p1) - 0.5; // relative pos from cell center
+
+
+
+// random number
+ float rnd = dot(floor(p1), vec2(12.9898, 78.233));
+ rnd = fract(sin(rnd) * 43758.5453);
+
+ // rotation matrix
+ float phi = rnd * pi * 2. + current_time/30.0 * 0.4;
+ mat2 rot = mat2(cos(phi), -sin(phi), sin(phi), cos(phi));
+
+ vec2 p3 = rot * p2; // apply rotation
+ p3.y += sin(p3.x * 5. + current_time/30.0 * 2.) * 0.12; // wave
+
+ float rep = fract(rnd * 13.285) * 8. + 2.; // line repetition
+ float gr = fract(p3.y * rep + current_time/30.0 * 0.8); // repeating gradient
+
+ // make antialiased line by saturating the gradient
+ float c = clamp((0.25 - abs(0.5 - gr)) * size * 0.75 / rep, 0., 1.);
+ c *= max(0., 1. - length(p2) * 0.6); // darken corners
+
+ vec2 bd = (0.5 - abs(p2)) * size - 2.; // border lines
+ c *= clamp(min(bd.x, bd.y), 0., 1.);
+
+ fragColor = vec4(vec3(c), 1.0);
+
+
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+static const char *effect_lava_fragment = R"(
+
+
+
+
+
+
+vec3 effect(float speed, vec2 uv, float time, float scale) {
+ float t = mod(time * 0.005, 6.0);
+ float rt = 0.00000000000001 * sin(t * 0.45);
+
+ mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
+ vec2 uva = uv * m1 * scale;
+ float irt = 0.005 * cos(t * 0.05);
+ mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
+
+ for (int i = 1; i < 40; i += 1) {
+ float it = float(i);
+ uva *= m2;
+ uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
+ uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));
+ }
+
+ float n = 0.5;
+ float r = n + n * sin(4.0 * uva.x + t);
+ float gb = n + n * sin(3.0 * uva.y);
+ return vec3(r, gb * 0.8 * r, gb * r);
+}
+
+vec4 effect_color(vec2 pos) {
+
+ vec2 uv = (gl_FragCoord.xy - 0.5 * vec2(width, height)) / vec2(width, height);
+ uv *= (10.3 + 0.1 * sin(current_time * 0.01));
+
+
+
+ vec3 col = effect(0.001, uv, current_time, 0.5);
+
+ // Set the fragment color
+ fragColor = vec4(col, 1.0);
+
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+
+static const char *effect_pattern_fragment = R"(
+
+
+float rand(vec2 uv) {
+ return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+vec3 hue2rgb(float h) {
+ h = fract(h) * 6.0 - 2.0;
+ return clamp(vec3(abs(h - 1.0) - 1.0, 2.0 - abs(h), 2.0 - abs(h - 2.0)), 0.0, 1.0);
+}
+
+vec3 eyes(vec2 coord, vec2 resolution) {
+ const float pi = 3.141592;
+ float t = 0.4 * current_time * 0.05;
+ float aspectRatio = resolution.x / resolution.y;
+ float div = 20.0;
+ float sc = 30.0;
+
+ vec2 p = (coord - resolution / 2.0) / sc - 0.5;
+
+ float dir = floor(rand(floor(p) + floor(t) * 0.11) * 4.0) * pi / 2.0;
+ vec2 offs = vec2(sin(dir), cos(dir)) * 0.6;
+ offs *= smoothstep(0.0, 0.1, fract(t));
+ offs *= smoothstep(0.4, 0.5, 1.0 - fract(t));
+
+ float l = length(fract(p) + offs - 0.5);
+ float rep = sin((rand(floor(p)) * 2.0 + 2.0) * t) * 4.0 + 5.0;
+ float c = (abs(0.5 - fract(l * rep + 0.5)) - 0.25) * sc / rep;
+
+ vec2 gr = (abs(0.5 - fract(p + 0.5)) - 0.05) * sc;
+ c = clamp(min(min(c, gr.x), gr.y), 0.0, 1.0);
+
+ return hue2rgb(rand(floor(p) * 0.3231)) * c;
+}
+
+
+
+vec4 effect_color(vec2 pos) {
+
+
+ vec2 resolution = vec2(float(width), float(height));
+ pos = gl_FragCoord.xy;
+ vec3 color = eyes(pos, resolution);
+ fragColor = vec4(color, 1.0);
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+
+
+
+static const char *effect_hex_fragment = R"(
+
+
+
+vec2 iResolution;
+
+float rand(vec2 co) {
+ return fract(sin(dot(co.xy, vec2(12.9898, 4.1414))) * 43758.5453);
+}
+
+vec4 hexagon(vec2 p)
+{
+ vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503);
+
+ vec2 pi = floor(q);
+ vec2 pf = fract(q);
+
+ float v = mod(pi.x * 9.0, 0.0);
+
+ float ca = step(1.0, v);
+ float cb = step(2.0, v);
+ vec2 ma = step(pf.xy, pf.yx);
+
+ float e = 0.0;
+ float f = length((fract(p) - 10.5) * vec2(1.0, 0.85));
+
+ return vec4(pi + ca - cb * ma, e, f);
+}
+
+
+vec4 effect_color(vec2 pos) {
+
+
+ vec2 resolution = vec2(float(width), float(height));
+ pos = (gl_FragCoord.xy - 0.5) / resolution;
+ pos.y *= resolution.y / resolution.x;
+
+
+ vec2 uv = (gl_FragCoord.xy - 0.5) / resolution;
+ uv = 2.0 * uv - 1.0;
+ uv *= (10.3 + 0.1 * sin(current_time * 0.01));
+
+ float randVal = rand(uv);
+
+ vec2 p = (-float(width) + 2.0 * gl_FragCoord.xy) / float(height);
+ vec4 h = hexagon(40.0 * p + vec2(0.5 * current_time * 0.125));
+
+ float col = 0.01 + 0.15 * rand(vec2(h.xy)) * 1.0;
+ col *= 4.3 + 0.15 * sin(10.0 * h.z);
+
+ vec3 shadeColor1 = vec3(0.1, 0.1, 0.1) + 1.1 * col * h.z;
+ vec3 shadeColor2 = vec3(0.4, 0.4, 0.4) + 1.1 * col;
+ vec3 shadeColor3 = vec3(0.9, 0.9, 0.9) + 0.1 * col;
+
+ vec3 finalColor = mix(shadeColor1, mix(shadeColor2, shadeColor3, randVal), col);
+
+ fragColor = vec4(finalColor, 1.0);
+
+ return vec4(fragColor);
+}
+)";
+
+
+
+
+
+
+static const char *effect_neural_network_fragment = R"(
+
+const vec2 iResolution = vec2(1920.0, 1080.0);
+
+mat2 rotate2D(float r) {
+ float c = cos(r);
+ float s = sin(r);
+ return mat2(c, -s, s, c);
+}
+
+
+
+vec4 effect_color(vec2 pos) {
+
+ pos = gl_FragCoord.xy;
+
+
+ // Normalized pixel coordinates (from 0 to 1)
+ vec2 uv = (pos - 0.5 * iResolution) / iResolution.x;
+
+ // Scale the uv coordinates
+ uv *= 10.00;
+
+ vec3 col = vec3(0);
+ float t = 0.05 * current_time;
+
+ vec2 n = vec2(0), q;
+ vec2 N = vec2(0);
+ vec2 p = uv + sin(t * 0.1) / 10.0;
+ float S = 10.0;
+ mat2 m = rotate2D(1.0);
+
+ for (float j = 0.0; j < 30.0; j++) {
+ p *= m;
+ n *= m;
+ q = p * S + j + n + t;
+ n += sin(q);
+ N += cos(q) / S;
+ S *= 1.2;
+ }
+
+ col = vec3(1, 2, 4) * pow((N.x + N.y + 0.2) + 0.005 / length(N), 2.1);
+
+ fragColor = vec4(col, 1.0);
+
+ return vec4(fragColor);
+}
+)";
+
+
+
+
+
+
+
+static const char *effect_hexagon_maze_fragment = R"(
+
+
+
+//vec2 iResolution;
+
+
+const vec2 iResolution = vec2(1920.0, 1080.0);
+
+// Interlaced variation - Interesting, but patched together in a hurry.
+//#define INTERLACING
+
+// A quick hack to get rid of the winding overlay - in order to show the maze only.
+//#define MAZE_ONLY
+
+
+
+// Helper vector. If you're doing anything that involves regular triangles or hexagons, the
+// 30-60-90 triangle will be involved in some way, which has sides of 1, sqrt(3) and 2.
+const vec2 s = vec2(1, 1.7320508);
+
+// Standard vec2 to float hash - Based on IQ's original.
+float hash21(vec2 p){ return fract(sin(dot(p, vec2(141.173, 289.927)))*43758.5453); }
+
+
+// Standard 2D rotation formula.
+mat2 r2(in float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }
+
+// The 2D hexagonal isosuface function: If you were to render a horizontal line and one that
+// slopes at 60 degrees, mirror, then combine them, you'd arrive at the following.
+float hex(in vec2 p){
+
+ p = abs(p);
+
+ // Below is equivalent to:
+ //return max(p.x*.5 + p.y*.866025, p.x);
+
+ return max(dot(p, s*.5), p.x); // Hexagon.
+
+}
+
+// This function returns the hexagonal grid coordinate for the grid cell, and the corresponding
+// hexagon cell ID - in the form of the central hexagonal point. That's basically all you need to
+// produce a hexagonal grid.
+//
+// When working with 2D, I guess it's not that important to streamline this particular function.
+// However, if you need to raymarch a hexagonal grid, the number of operations tend to matter.
+// This one has minimal setup, one "floor" call, a couple of "dot" calls, a ternary operator, etc.
+// To use it to raymarch, you'd have to double up on everything - in order to deal with
+// overlapping fields from neighboring cells, so the fewer operations the better.
+vec4 getHex(vec2 p){
+
+ // The hexagon centers: Two sets of repeat hexagons are required to fill in the space, and
+ // the two sets are stored in a "vec4" in order to group some calculations together. The hexagon
+ // center we'll eventually use will depend upon which is closest to the current point. Since
+ // the central hexagon point is unique, it doubles as the unique hexagon ID.
+ vec4 hC = floor(vec4(p, p - vec2(.5, 1))/s.xyxy) + .5;
+
+ // Centering the coordinates with the hexagon centers above.
+ vec4 h = vec4(p - hC.xy*s, p - (hC.zw + .5)*s);
+
+ // Nearest hexagon center (with respect to p) to the current point. In other words, when
+ // "h.xy" is zero, we're at the center. We're also returning the corresponding hexagon ID -
+ // in the form of the hexagonal central point. Note that a random constant has been added to
+ // "hC.zw" to further distinguish it from "hC.xy."
+ //
+ // On a side note, I sometimes compare hex distances, but I noticed that Iomateron compared
+ // the Euclidian version, which seems neater, so I've adopted that.
+ return dot(h.xy, h.xy).5) p.y = -p.y;
+
+
+
+ // Determining the closest of the three arcs to the current point, the keeping a copy
+ // of the vector used to produce it. That way, you'll know just to render that particular
+ // decorated arc, lines, etc - instead of all three.
+ const float r = 1.;
+ const float th = .2; // Arc thickness.
+
+ // Arc one.
+ q = p - vec2(0, r)/s;
+ vec3 da = vec3(q, dfPol(q));
+
+ // Arc two. "r2" could be hardcoded, but this is a relatively cheap 2D example.
+ q = r2(3.14159*2./3.)*p - vec2(0, r)/s;
+ vec3 db = vec3(q, dfPol(q));
+
+ // Arc three.
+ q = r2(3.14159*4./3.)*p - vec2(0, r)/s;
+ vec3 dc = vec3(q, dfPol(q));
+
+ // Compare distance fields, and return the vector used to produce the closest one.
+ vec3 q3 = da.z.5 && lRnd.x<.5) hLines2 *= smoothstep(0., .02, ln);
+ if(lRnd.x>.5) hLines2 *= dMask;
+ #else
+ if(rnd>.5) hLines2 *= smoothstep(0., .02, ln);
+ hLines2 *= dMask;
+ #endif
+ bg = mix(bg, vec3(0), hLines2*tr);
+
+ float eDist3 = hex(h3.xy);
+ float hLines3 = smoothstep(0., .02, eDist3 - .5 + .02);
+ #ifdef INTERLACING
+ if(rnd<=.5 && lRnd.x>.5) hLines3 *= smoothstep(0., .02, ln);
+ if(lRnd.x>.5) hLines3 *= dMask;
+ #else
+ if(rnd<=.5) hLines3 *= smoothstep(0., .02, ln);
+ hLines3 *= dMask;
+ #endif
+ bg = mix(bg, vec3(0), hLines3*tr);
+
+
+ // Using the two off-centered hex coordinates to give the background a bit of highlighting.
+ float shade = max(1.25 - dot(h2.xy, h2.xy)*2., 0.);
+ shade = min(shade, max(dot(h3.xy, h3.xy)*3. + .25, 0.));
+ bg = mix(bg, vec3(0), (1.-shade)*.5);
+
+ // I wanted to change the colors of everything at the last minute. It's pretty hacky, so
+ // when I'm feeling less lazy, I'll tidy it up. :)
+ vec3 dotCol = bg.zyx*vec3(1.5, .4, .4);
+ vec3 bCol = mix(bg.zyx, bg.yyy, .25);
+ bg = mix(bg.yyy, bg.zyx, .25);
+
+
+ // Under the random threshold, and we draw the lines under the Truchet pattern.
+ #ifdef INTERLACING
+ if(lRnd.x>.5){
+ bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));
+ bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln)));
+ // Center lines.
+ bg = mix(bg, vec3(0), smoothstep(0., .02, eDist3 - .5 + .02)*tr);
+ }
+ #else
+ bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));
+ bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln)));
+ #endif
+
+
+
+ // Apply the Truchet shadow to the background.
+ bg = mix(bg, vec3(0), (1. - smoothstep(0., .07, d))*.5);
+
+
+ // Place the Truchet field to the background, with some additional shading to give it a
+ // slightly rounded, raised feel.
+ //vec3 col = mix(bg, vec3(1)*max(-d*3. + .7, 0.), (1. - dMask)*.65);
+ // Huttarl suggest slightly more shading on the snake-like pattern edges, so I added just a touch.
+ vec3 col = mix(bg, vec3(1)*max(-d*9. + .4, 0.), (1. - dMask)*.65);
+
+
+
+ // Apply the moving dot pattern to the Truchet.
+ //dotCol = mix(dotCol, dotCol.xzy, dot(sin(u*3.14159*2. - cos(u.yx*3.14159*2.)*3.14159), vec2(.25)) + .5);
+ col = mix(col, vec3(0), (1. - dMask)*(1. - smoothstep(0., .02, d2)));
+ col = mix(col, dotCol, (1. - dMask)*(1. - smoothstep(0., .02, d2 + .125)));
+
+ // Truchet border.
+ col = mix(col, vec3(0), 1. - smoothstep(0., .015, dBord));
+
+ #ifdef INTERLACING
+ // Over the random threshold, and we draw the lines over the Truchet.
+ if(lRnd.x<=.5){
+ col = mix(col, vec3(0), (1. - smoothstep(0., .015, lnBord)));
+ col = mix(col, bCol, (1. - smoothstep(0., .015, ln)));
+ // Center lines.
+ col = mix(col, vec3(0), smoothstep(0., .02, eDist2 - .5 + .02)*tr);
+ }
+ #endif
+
+
+
+
+ // Using the offset hex values for a bit of fake 3D highlighting.
+ //if(rnd>.5) h3.y = -h3.y; // All raised edges. Spoils the mild 3D illusion.
+ #ifdef INTERLACING
+ float trSn = max(dMask, 1. - smoothstep(0., .015, lnBord))*.75 + .25;
+ #else
+ float trSn = dMask*.75 + .25;
+ #endif
+ col = mix(col, vec3(0), trSn*(1. - hex(s/2.+h2.xy)));
+ col = mix(col, vec3(0), trSn*(1. - hex(s/2.-h3.xy)));
+
+
+ // Using the edge distance to produce some repeat contour lines. Standard stuff.
+ //if (rnd>.5) h.xy = -h.yx;
+ //float cont = clamp(cos(hex(h.xy)*6.283*12.)*1.5 + 1.25, 0., 1.);
+ //col = mix(col, vec3(0), (1. - smoothstep(0., .015, ln))*(smoothstep(0., .015, d))*(1.-cont)*.5);
+
+
+ // Very basic hatch line effect.
+ float gr = dot(col, vec3(.299, .587, .114));
+ float hatch = (gr<.45)? clamp(sin((sc.x - sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;
+ float hatch2 = (gr<.25)? clamp(sin((sc.x + sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;
+
+ col *= min(hatch, hatch2)*.5 + .5;
+ col *= clamp(sin((sc.x - sc.y)*3.14159*80.)*1.5 + .75, 0., 1.)*.25 + 1.;
+
+
+ // Subtle vignette.
+ u = fragCoord/iResolution.xy;
+ col *= pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .125) + .25;
+ // Colored variation.
+ //col = mix(pow(min(vec3(1.5, 1, 1)*col, 1.), vec3(1, 3, 16)), col,
+ //pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .25)*.75 + .25);
+
+
+
+ // Rough gamma correction.
+ fragColor = vec4(sqrt(max(col, 0.)), 1);
+ return vec4(fragColor);
+}
+)";
+
+
+
+
+
+
+
+
+
+
+static const char *effect_raymarched_truchet_fragment = R"(
+
+float heightMap(in vec2 p) {
+ p *= 3.0;
+ vec2 h = vec2(p.x + p.y * 0.57735, p.y * 1.1547);
+ vec2 f = fract(h);
+ h -= f;
+ float c = fract((h.x + h.y) / 3.0);
+ h = c < 0.666 ? (c < 0.333 ? h : h + 1.0) : h + step(f.yx, f);
+ p -= vec2(h.x - h.y * 0.5, h.y * 0.8660254);
+ c = fract(cos(dot(h, vec2(41, 289))) * 43758.5453);
+ p -= p * step(c, 0.5) * 2.0;
+ p -= vec2(-1, 0);
+ c = dot(p, p);
+ p -= vec2(1.5, 0.8660254);
+ c = min(c, dot(p, p));
+ p -= vec2(0, -1.73205);
+ c = min(c, dot(p, p));
+ return sqrt(c);
+}
+
+float map(vec3 p) {
+ float c = heightMap(p.xy);
+ c = cos(c * 6.283 * 1.0) + cos(c * 6.283 * 2.0);
+ c = clamp(c * 0.6 + 0.5, 0.0, 1.0);
+ return 1.0 - p.z - c * 0.025;
+}
+
+vec3 getNormal(vec3 p, inout float edge, inout float crv) {
+ vec2 e = vec2(0.01, 0);
+ float d1 = map(p + e.xyy), d2 = map(p - e.xyy);
+ float d3 = map(p + e.yxy), d4 = map(p - e.yxy);
+ float d5 = map(p + e.yyx), d6 = map(p - e.yyx);
+ float d = map(p) * 2.0;
+ edge = abs(d1 + d2 - d) + abs(d3 + d4 - d) + abs(d5 + d6 - d);
+ edge = smoothstep(0.0, 1.0, sqrt(edge / e.x * 2.0));
+ crv = clamp((d1 + d2 + d3 + d4 + d5 + d6 - d * 3.0) * 32.0 + 0.6, 0.0, 1.0);
+ e = vec2(0.0025, 0);
+ d1 = map(p + e.xyy); d2 = map(p - e.xyy);
+ d3 = map(p + e.yxy); d4 = map(p - e.yxy);
+ d5 = map(p + e.yyx); d6 = map(p - e.yyx);
+ return normalize(vec3(d1 - d2, d3 - d4, d5 - d6));
+}
+
+float calculateAO(in vec3 p, in vec3 n) {
+ float sca = 2.0, occ = 0.0;
+ for (float i = 0.0; i < 5.0; i++) {
+ float hr = 0.01 + i * 0.5 / 4.0;
+ float dd = map(n * hr + p);
+ occ += (hr - dd) * sca;
+ sca *= 0.7;
+ }
+ return clamp(1.0 - occ, 0.0, 1.0);
+}
+
+float n3D(vec3 p) {
+ const vec3 s = vec3(7, 157, 113);
+ vec3 ip = floor(p); p -= ip;
+ vec4 h = vec4(0.0, s.yz, s.y + s.z) + dot(ip, s);
+ p = p * p * (3.0 - 2.0 * p);
+ h = mix(fract(sin(h) * 43758.5453), fract(sin(h + s.x) * 43758.5453), p.x);
+ h.xy = mix(h.xz, h.yw, p.y);
+ return mix(h.x, h.y, p.z);
+}
+
+vec3 envMap(vec3 rd, vec3 sn) {
+ vec3 sRd = rd;
+ rd.xy -= current_time/100.0 * 0.25;
+ rd *= 3.0;
+ float c = n3D(rd) * 0.57 + n3D(rd * 2.0) * 0.28 + n3D(rd * 4.0) * 0.15;
+ c = smoothstep(0.4, 1.0, c);
+ vec3 col = vec3(c, c * c, c * c * c * c);
+ return mix(col, col.yzx, sRd * 0.25 + 0.25);
+}
+
+
+
+vec2 hash22(vec2 p) {
+ float n = sin(dot(p, vec2(41.0, 289.0))); // Use floating point literals for constants
+ return fract(vec2(262144.0, 32768.0) * n) * 0.75 + 0.25; // Make sure all numbers are floats
+}
+
+float Voronoi(in vec2 p) {
+ vec2 g = floor(p), o; p -= g;
+ vec3 d = vec3(1);
+ for (int y = -1; y <= 1; y++) {
+ for (int x = -1; x <= 1; x++) {
+ o = vec2(x, y);
+ o += hash22(g + o) - p;
+ d.z = dot(o, o);
+ d.y = max(d.x, min(d.y, d.z));
+ d.x = min(d.x, d.z);
+ }
+ }
+ return max(d.y / 1.2 - d.x * 1.0, 0.0) / 1.2;
+}
+
+const vec2 iResolution = vec2(1920.0, 1080.0);
+
+
+vec4 effect_color(vec2 pos) {
+
+
+
+ vec2 fragCoord = gl_FragCoord.xy;
+ vec3 rd = normalize(vec3(2.0 * fragCoord - iResolution, iResolution.y));
+ float tm = current_time / 100.0;
+ vec2 a = sin(vec2(1.570796, 0.0) + sin(tm / 4.0) * 0.3);
+ rd.xy = mat2(a, -a.y, a.x) * rd.xy;
+ vec3 ro = vec3(tm, cos(tm / 4.0), 0.0);
+ vec3 lp = ro + vec3(cos(tm / 2.0) * 0.5, sin(tm / 2.0) * 0.5, -0.5);
+
+ float d = 0.0;
+ float t = 0.0;
+
+
+ for (int j = 0; j < 32; j++) {
+ d = map(ro + rd * t);
+ t += d * 0.7;
+ if (d < 0.001) break;
+ }
+ float edge, crv;
+ vec3 sp = ro + rd * t;
+ vec3 sn = getNormal(sp, edge, crv);
+ vec3 ld = lp - sp;
+ float c = heightMap(sp.xy);
+ vec3 fold = cos(vec3(1, 2, 4) * c * 6.283);
+ float c2 = heightMap((sp.xy + sp.z * 0.025) * 6.);
+ c2 = cos(c2 * 6.283 * 3.);
+ c2 = (clamp(c2 + 0.5, 0.0, 1.0));
+ vec3 oC = vec3(1);
+ if (fold.x > 0.) oC = vec3(1, 0.05, 0.1) * c2;
+ if (fold.x < 0.05 && fold.y < 0.) oC = vec3(1, 0.7, 0.45) * (c2 * 0.25 + 0.75);
+ else if (fold.x < 0.) oC = vec3(1, 0.8, 0.4) * c2;
+ float lDist = max(length(ld), 0.001);
+ float atten = 1.0 / (1.0 + lDist * 0.125);
+ ld /= lDist;
+ float diff = max(dot(ld, sn), 0.0);
+ float spec = pow(max(dot(reflect(-ld, sn), -rd), 0.0), 16.0);
+ float fre = pow(clamp(dot(sn, rd) + 1.0, 0.0, 1.0), 3.0);
+ crv = crv * 0.9 + 0.1;
+ float ao = calculateAO(sp, sn);
+ vec3 col = oC * (diff + 0.5) + vec3(1.0, 0.7, 0.4) * spec * 2.0 + vec3(0.4, 0.7, 1.0) * fre;
+ col += (oC * 0.5 + 0.5) * envMap(reflect(rd, sn), sn) * 6.0;
+ col *= 1.0 - edge * 0.85;
+ col *= atten * crv * ao;
+ fragColor = vec4(sqrt(clamp(col, 0.0, 1.0)), 1.0);
+
+
+ return vec4(fragColor);
+}
+
+
+)";
+
+
+
+
+
+
+
+
+static const char *effect_neon_rings_fragment = R"(
+
+#define PI 3.14159265358979323846
+#define TWO_PI 6.28318530717958647692
+
+const vec2 iResolution = vec2(1920.0, 1080.0);
+
+mat2 rotate2D(float r) {
+ float c = cos(r);
+ float s = sin(r);
+ return mat2(c, -s, s, c);
+}
+
+vec4 effect_color(vec2 pos) {
+
+
+ // Use gl_FragCoord as the pixel position
+// pos = ivec2(gl_FragCoord.xy);
+
+ // pos = ivec2(gl_FragCoord.xy);
+ // int x = pos.x;
+ // int y = pos.y;
+
+ // Number of circles
+ int numCircles = 5;
+
+ // Initialize final color
+ vec3 finalColor = vec3(0.0);
+
+ for (int i = 0; i < numCircles; ++i) {
+ // Calculate UV coordinates for each circle
+// vec2 uv = vec2(pos) / vec2(width / 3, height / 3);
+ vec2 uv = vec2(pos) / vec2(width*0.3333333333333, height*0.3333333333333);
+
+ // Calculate polar coordinates
+ float a = atan(uv.y, uv.x);
+ float r = length(uv) * (0.2 + 0.1 * float(i));
+
+ // Map polar coordinates to UV
+ uv = vec2(a / TWO_PI, r);
+
+ // Apply horizontal movement based on time for each circle
+ float xOffset = sin(current_time * 0.02 + float(i)) * 0.2;
+ uv.x += xOffset;
+
+ // Time-dependent color
+ float xCol = (uv.x - (current_time / 300000.0)) * 3.0;
+ xCol = mod(xCol, 3.0);
+ vec3 horColour = vec3(0.25, 0.25, 0.25);
+
+ if (xCol < 1.0) {
+ horColour.r += 1.0 - xCol;
+ horColour.g += xCol;
+ } else if (xCol < 2.0) {
+ xCol -= 1.0;
+ horColour.g += 1.0 - xCol;
+ horColour.b += xCol;
+ } else {
+ xCol -= 2.0;
+ horColour.b += 1.0 - xCol;
+ horColour.r += xCol;
+ }
+
+ // Draw color beam
+ uv = (2.0 * uv) - 1.0;
+ float beamWidth = (0.7 + 0.5 * cos(uv.x * 1.0 * TWO_PI * 0.15 * clamp(floor(5.0 + 1.0 * cos(current_time)), 0.0, 1.0))) * abs(1.0 / (30.0 * uv.y));
+ vec3 horBeam = vec3(beamWidth);
+
+ // Add the color for the current circle to the final color
+ finalColor += ((horBeam) * horColour);
+ }
+
+ // Output the final color
+ fragColor = vec4(finalColor, 1.0);
+
+
+ return vec4(fragColor);
+}
+)";
+
+
+
+
+static const char *effect_deco_fragment = R"(
+
+vec3 effect(float speed, vec2 uv, float time, float scale) {
+ float t = mod(time * 0.005, 6.0);
+ float rt = 0.00000000000001 * sin(t * 0.45);
+
+ mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
+ vec2 uva = uv * m1 * scale;
+ float irt = 0.005 * cos(t * 0.05);
+ mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
+
+ for (int i = 1; i < 400; i += 1) {
+ float it = float(i);
+ uva *= m2;
+ uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
+ uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));
+ }
+
+ float n = 0.5;
+ float r = n + n * sin(4.0 * uva.x + t);
+ float gb = n + n * sin(3.0 * uva.y);
+ return vec3(r, gb * 0.8 * r, gb * r);
+}
+
+vec4 effect_color(vec2 pos) {
+
+ vec2 uv = (gl_FragCoord.xy - 0.5 * vec2(width, height)) / vec2(width, height);
+ uv *= (10.3 + 0.1 * sin(current_time * 0.01));
+
+
+
+ vec3 col = effect(0.001, uv, current_time, 0.5);
+
+ // Set the fragment color
+ fragColor = vec4(col, 1.0);
+
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+
+
+
+
+
+
+// ported from https://www.shadertoy.com/view/3djfzy
+static const char *effect_ice_fragment =
+ R"(
+
+vec3 effect(float speed, vec2 uv, float time, float scale) {
+ float t = mod(time * 0.005, 6.0);
+ float rt = 0.00000000000001 * sin(t * 0.45);
+
+ mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
+ vec2 uva = uv * m1 * scale;
+ float irt = 0.005 * cos(t * 0.05);
+ mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
+
+ for (int i = 1; i < 400; i += 1) {
+ float it = float(i);
+ uva *= m2;
+ uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
+ uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));
+ }
+
+ float n = 0.5;
+ float r = n + n * sin(4.0 * uva.x + t);
+ float gb = n + n * sin(3.0 * uva.y);
+ return vec3(r, gb * 0.8 * r, gb * r);
+}
+
+
+
+
+
+
+
+
+float rand(in vec2 _st) {
+ return fract(sin(dot(_st.xy, vec2(-0.820, -0.840))) * 4757.153);
+}
+
+float noise(in vec2 _st) {
+ const vec2 d = vec2(0.0, 1.0);
+ vec2 b = floor(_st), f = smoothstep(vec2(0.0), vec2(0.1, 0.3), fract(_st));
+ return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
+}
+
+float fbm(in vec2 _st) {
+ float v = sin(current_time * 0.005) * 0.2;
+ float a = 0.3;
+ vec2 shift = vec2(100.0);
+ mat2 rot = mat2(cos(0.5), sin(1.0), -sin(0.5), acos(0.5));
+ for (int i = 0; i < 3; ++i) {
+ v += a * noise(_st);
+ _st = rot * _st * 2.0 + shift;
+ a *= 1.5;
+ }
+ return v;
+}
+
+vec4 effect_color(vec2 pos) {
+
+
+
+
+
+ vec2 st = (gl_FragCoord.xy * 2.0 - vec2(width, height)) / min(float(width), float(height)) * 0.5;
+
+ vec2 coord = st * 0.2;
+ float len;
+ for (int i = 0; i < 3; i++) {
+ len = length(coord);
+ coord.x += sin(coord.y + current_time * 0.001) * 2.1;
+ coord.y += cos(coord.x + current_time * 0.001 + cos(len * 1.0)) * 1.0;
+ }
+ len -= 3.0;
+
+ vec3 color = vec3(0.0);
+
+ vec2 q = vec2(0.0);
+ q.x = fbm(st);
+ q.y = fbm(st + vec2(-0.450, 0.650));
+
+ vec2 r = vec2(0.0);
+ r.x = fbm(st + 1.0 * q + vec2(0.570, 0.520) + 0.1 * current_time * 0.01);
+ r.y = fbm(st + 1.0 * q + vec2(0.340, -0.570) + 0.05 * current_time * 0.01);
+ float f = fbm(st + r);
+
+ color = mix(color, cos(len + vec3(0.5, 0.0, -0.1)), 1.0);
+ color = mix(vec3(0.478, 0.738, 0.760), vec3(0.563, 0.580, 0.667), color);
+
+ fragColor = vec4((f * f * f + .6 * f * f + .5 * f) * color, 1.0);
+
+
+ return vec4(fragColor);
+}
+)";
+
+
+
+
+
+static const char *effect_fire_fragment = R"(
+
+vec3 effect(float speed, vec2 uv, float time, float scale) {
+
+
+
+
+ float t = mod(time * 0.005, 6.0);
+ float rt = 0.00000000000001 * sin(t * 0.45);
+
+ mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
+ vec2 uva = uv * m1 * scale;
+ float irt = 0.005 * cos(t * 0.05);
+ mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
+
+ for (int i = 1; i < 400; i += 1) {
+ float it = float(i);
+ uva *= m2;
+ uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
+ uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));
+ }
+
+ float n = 0.5;
+ float r = n + n * sin(4.0 * uva.x + t);
+ float gb = n + n * sin(3.0 * uva.y);
+ return vec3(r, gb * 0.8 * r, gb * r);
+}
+
+
+float rand(vec2 n) {
+ return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
+}
+
+float noise(vec2 n) {
+ const vec2 d = vec2(0.0, 1.0);
+ vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
+ return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
+}
+
+float fbm(vec2 n) {
+ float total = 0.0, amplitude = 1.0;
+ for (int i = 0; i < 4; i++) {
+ total += noise(n) * amplitude;
+ n += n;
+ amplitude *= 0.5;
+ }
+ return total;
+}
+vec4 effect_color(vec2 pos) {
+
+ vec2 gid = gl_FragCoord.xy;
+ vec2 normalizedCoords = gid / vec2(width, height); // Normalize the coordinates
+
+ const vec3 c1 = vec3(0.5, 0.0, 0.1);
+ const vec3 c2 = vec3(0.9, 0.0, 0.0);
+ const vec3 c3 = vec3(0.2, 0.0, 0.0);
+ const vec3 c4 = vec3(1.0, 0.9, 0.0);
+ const vec3 c5 = vec3(0.1);
+ const vec3 c6 = vec3(0.9);
+
+ vec2 speed = vec2(0.7, 0.4);
+ float shift = 1.0;
+ float alpha = 1.0;
+
+ float timeEffect = current_time * 0.05; // Slowing down the animation by reducing the current_time factor
+
+ vec2 p = normalizedCoords * 8.0;
+ float q = fbm(p - timeEffect * 0.1);
+ vec2 r = vec2(fbm(p + q + timeEffect * speed.x - p.x - p.y), fbm(p + q - timeEffect * speed.y));
+ vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y);
+ fragColor = vec4(c * cos(shift * normalizedCoords.y), alpha);
+
+
+ return vec4(fragColor);
+}
+
+)";
+
+
+
+
+static const char *effect_render_fragment = R"(
+
+precision lowp float;
+precision lowp sampler2D;
+
+uniform sampler2D in_b0d;
+uniform bool ink;
+uniform vec4 smoke_color;
+uniform vec4 decor_color;
+//uniform int regionInfo[20]; // This will likely go unused in this shader.
+
+//out vec4 fragColor;
+
+vec4 effect_color(vec2 pos) {
+
+ vec2 texCoord = gl_FragCoord.xy;
+ float c, a;
+ vec3 color;
+
+ vec4 s = texture(in_b0d, texCoord);
+ c = s.x * 800.0;
+ if (c > 255.0)
+ c = 255.0;
+ a = c / 255.0; // Normalize alpha to the range 0.0 to 1.0
+ if (ink)
+ {
+ if (c > 2.0)
+ color = mix(decor_color.rgb, smoke_color.rgb, clamp(a, 0.0, 1.0));
+ else
+ color = mix(decor_color.rgb, vec3(0.0, 0.0, 0.0), clamp(a, 0.0, 1.0));
+
+ if (c > 1.5)
+ fragColor = vec4(color, 1.0);
+ else
+ fragColor = decor_color;
+ return vec4(fragColor);
+ }
+
+ else
+ {
+ color = mix(decor_color.rgb, smoke_color.rgb, clamp(a, 0.0, 1.0));
+
+
+ fragColor = vec4(color, decor_color.a);
+return vec4(fragColor);
+
+
+
+ }
+
+ fragColor = vec4(color, decor_color.a);
+return vec4(fragColor);
+
+}
+
+
+
+)";
+
+
+
+
+
+
diff --git a/src/overlay-shaders.hpp b/src/overlay-shaders.hpp
new file mode 100644
index 0000000..1fc936a
--- /dev/null
+++ b/src/overlay-shaders.hpp
@@ -0,0 +1,412 @@
+static const char *overlay_no_overlay = R"(
+vec4 overlay_function(vec2 position)
+{
+ return effect_color(position);
+})";
+
+static const char *overlay_rounded_corners = R"(
+uniform int corner_radius;
+uniform int shadow_radius;
+uniform vec4 shadow_color;
+
+vec4 overlay_function(vec2 pos)
+{
+ vec4 c = shadow_color;
+ vec4 m = vec4(0.0);
+ float diffuse = 1.0 / max(float(shadow_radius / 2), 1.0);
+
+ float distanceToEdgeX = ceil(min(pos.x, width - pos.x));
+ float distanceToEdgeY = ceil(min(pos.y, height - pos.y));
+
+ float radii_sum = float(shadow_radius) + float(corner_radius);
+
+ // We have a corner
+ if ((distanceToEdgeX <= radii_sum) && (distanceToEdgeY <= radii_sum))
+ {
+ float d = distance(vec2(distanceToEdgeX, distanceToEdgeY), vec2(radii_sum)) - float(corner_radius);
+ vec4 s = mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
+
+ vec4 eff_color = effect_color(pos);
+ return mix(eff_color, s, clamp(d, 0.0, 1.0));
+ }
+
+ bool closeToX = ceil(distanceToEdgeX) < float(shadow_radius);
+ bool closeToY = ceil(distanceToEdgeY) < float(shadow_radius);
+
+ if (!closeToX && !closeToY)
+ {
+ return effect_color(pos);
+ }
+
+ // Edges
+ float d = float(shadow_radius) - (closeToX ? distanceToEdgeX : distanceToEdgeY);
+ return mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
+})";
+
+
+
+
+static const char *overlay_beveled_glass = R"(
+
+
+#define MARKER_RADIUS 12.5
+#define THICCNESS 2.0
+
+uniform int beveled_radius;
+uniform int title_height;
+uniform int border_size;
+
+
+
+bool isInsideTriangle(vec2 p, vec2 a, vec2 b, vec2 c) {
+ vec2 v0 = b - a;
+ vec2 v1 = c - a;
+ vec2 v2 = p - a;
+
+ float dot00 = dot(v0, v0);
+ float dot01 = dot(v0, v1);
+ float dot02 = dot(v0, v2);
+ float dot11 = dot(v1, v1);
+ float dot12 = dot(v1, v2);
+
+ float invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
+ float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+ float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+
+ return (u >= 0.0) && (v >= 0.0) && (u + v <= 1.0);
+}
+
+
+vec4 toBezier(float delta, int i, vec4 P0, vec4 P1, vec4 P2, vec4 P3)
+{
+ float t = delta * float(i);
+ float t2 = t * t;
+ float one_minus_t = 1.0 - t;
+ float one_minus_t2 = one_minus_t * one_minus_t;
+ return (P0 * one_minus_t2 * one_minus_t + P1 * 3.0 * t * one_minus_t2 + P2 * 3.0 * t2 * one_minus_t + P3 * t2 * t);
+}
+
+float sin01(float x) {
+ return (sin(x) + 1.0) / 2.0;
+}
+
+
+
+
+
+vec4 drawCurveBenzier(vec2 p1, vec2 p2, int setCount) {
+ vec4 col = vec4(0.0);
+ vec2 fragCoord = gl_FragCoord.xy;
+ float curveRadius = float(beveled_radius/2);
+
+ for (int i = 0; i <= setCount; ++i) {
+ vec4 bezierPoint = toBezier(1.0 / float(setCount), i, vec4(p1, 0.0, 1.0), vec4(p1 + (p2 - p1) * 0.5, 0.0, 1.0), vec4(p1 + (p2 - p1) * 0.5, 0.0, 1.0), vec4(p2, 0.0, 1.0));
+ vec2 curvePoint = bezierPoint.xy / bezierPoint.w;
+ float distance = length(fragCoord - curvePoint);
+ float curveIntensity = smoothstep(0.0, THICCNESS, curveRadius - distance);
+ col.rgb += vec3(0.1, 0.1, 0.1) * curveIntensity;
+ col.a = max(col.a, curveIntensity);
+ }
+
+ return col;
+}
+
+
+
+vec4 drawCurve(vec2 p1, vec2 p2, int setCount) {
+ vec4 col = vec4(0.0);
+ ivec2 storePos = ivec2(gl_FragCoord.xy);
+
+ float curveRadius = float(beveled_radius + 1);
+ vec2 fragCoord = vec2(storePos);
+
+ float t = clamp(dot(fragCoord - p1, p2 - p1) / dot(p2 - p1, p2 - p1), 0.0, 1.0);
+ vec2 curvePoint = mix(p1, p2, t);
+
+ float distance = length(fragCoord - curvePoint);
+ float curveIntensity = smoothstep(0.0, curveRadius, curveRadius - distance);
+
+ // Calculate gradient along the line with grey to white to grey
+ vec3 gradientColor;
+
+ if (t < 0.5) {
+ gradientColor = mix(vec3(0.7), vec3(1.0), t * 2.0);
+ } else {
+ gradientColor = mix(vec3(1.0), vec3(0.7), (t - 0.5) * 2.0);
+ }
+
+ // Use the curveIntensity to interpolate between gradient colors
+ col.rgb = gradientColor * curveIntensity;
+ col.a = max(col.a, curveIntensity);
+
+ return col;
+}
+
+
+
+
+vec4 overlay_function(vec2 pos)
+{
+
+
+
+vec2 fragCoord = gl_FragCoord.xy;
+
+
+
+
+
+ vec4 col = vec4(0.0);
+ float space = 15.0;
+
+ vec2 p1 = vec2(0.0 + THICCNESS, float(height) - THICCNESS - space);
+ vec2 p2 = vec2(0.0 + THICCNESS, 0.0 + THICCNESS + space);
+
+ vec2 x1 = vec2(float(width) - THICCNESS, float(height) - THICCNESS - space);
+ vec2 x2 = vec2(float(width) - THICCNESS, 0.0 + THICCNESS + space);
+
+ vec2 y1 = vec2(0.0 + THICCNESS + space, float(height) - THICCNESS);
+ vec2 y2 = vec2(float(width) - THICCNESS - space, float(height) - THICCNESS);
+
+ vec2 z1 = vec2(0.0 + THICCNESS + space, 0.0 + THICCNESS);
+ vec2 z2 = vec2(float(width) - THICCNESS - space, 0.0 + THICCNESS);
+
+
+ float curveRadius = float(beveled_radius);
+// Draw the lines connecting the points
+
+int setwidth = int(width);
+int setheight = int(height);
+
+
+if (setwidth<=400 && setheight<=300 ){
+ col += drawCurveBenzier(p1, p2, setheight);
+ col += drawCurveBenzier(x1, x2, setheight);
+ col += drawCurveBenzier(y1, y2, setwidth);
+ col += drawCurveBenzier(z1, z2, setwidth);
+}
+else {
+ col += drawCurve(p1, p2, setheight);
+ col += drawCurve(x1, x2, setheight);
+ col += drawCurve(y1, y2, setwidth);
+ col += drawCurve(z1, z2, setwidth);
+ }
+
+
+float INNERspace = 0.0;
+
+
+
+
+//left
+ vec2 INNERp1 = vec2(0.0 - THICCNESS+ float(border_size), float(height) + THICCNESS -float(title_height) );
+ vec2 INNERp2 = vec2(0.0 - THICCNESS+ float(border_size),0.0 - THICCNESS + INNERspace+float(border_size));
+//right
+ vec2 INNERx1 = vec2(float(width) + THICCNESS-float(border_size), float(height) + THICCNESS -float(title_height));
+ vec2 INNERx2 = vec2(float(width) + THICCNESS-float(border_size),0.0 - THICCNESS + INNERspace+float(border_size));
+
+
+//top
+ vec2 INNERy1 = vec2(0.0 + THICCNESS + INNERspace+float(border_size), float(height) + THICCNESS -float(title_height));
+ vec2 INNERy2 = vec2(float(width) - THICCNESS - INNERspace-float(border_size), float(height) + THICCNESS-float(title_height));
+
+//bottom
+ vec2 INNERz1 = vec2(0.0 +INNERspace+float(border_size), 0.0 - THICCNESS + INNERspace+float(border_size));
+ vec2 INNERz2 = vec2(float(width) - THICCNESS - INNERspace-float(border_size) ,0.0 - THICCNESS + INNERspace+float(border_size) );
+
+
+
+
+
+if (setwidth<=400 && setheight<=300 ){
+ col += drawCurveBenzier(INNERp1, INNERp2, setheight);
+ col += drawCurveBenzier(INNERx1, INNERx2, setheight);
+ col += drawCurveBenzier(INNERy1, INNERy2, setwidth);
+ col += drawCurveBenzier(INNERz1, INNERz2, setwidth);
+}
+else{
+ col += drawCurve(INNERp1, INNERp2, setheight);
+ col += drawCurve(INNERx1, INNERx2, setheight);
+ col += drawCurve(INNERy1, INNERy2, setwidth);
+ col += drawCurve(INNERz1, INNERz2, setwidth);
+ }
+
+
+ vec2 p3 = fragCoord;
+ vec2 p12 = p2 - p1;
+ vec2 p13 = p3 - p1;
+
+ vec2 x3 = fragCoord;
+ vec2 x12 = x2 - x1;
+ vec2 x13 = x3 - x1;
+
+ vec2 y3 = fragCoord;
+ vec2 y12 = y2 - y1;
+ vec2 y13 = y3 - y1;
+
+ vec2 z3 = fragCoord;
+ vec2 z12 = z2 - z1;
+ vec2 z13 = z3 - z1;
+
+ float d = dot(p12, p13) / length(p12); // = length(p13) * cos(angle)
+ float dx = dot(x12, x13) / length(x12);
+ float dy = dot(y12, y13) / length(y12);
+ float dz = dot(z12, z13) / length(z12);
+
+ vec2 p4 = p1 + normalize(p12) * d;
+ vec2 x4 = x1 + normalize(x12) * dx;
+ vec2 y4 = y1 + normalize(y12) * dy;
+ vec2 z4 = z1 + normalize(z12) * dz;
+
+
+ if (((length(p4 - p3) < THICCNESS && length(p4 - p1) <= length(p12) && length(p4 - p2) <= length(p12)) ||
+ (length(x4 - x3) < THICCNESS && length(x4 - x1) <= length(x12) && length(x4 - x2) <= length(x12))) ||
+ (length(y4 - y3) < THICCNESS && length(y4 - y1) <= length(y12) && length(y4 - y2) <= length(y12)) ||
+ (length(z4 - z3) < THICCNESS && length(z4 - z1) <= length(z12) && length(z4 - z2) <= length(z12))) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+
+
+
+ vec2 INNERp3 = fragCoord;
+ vec2 INNERp12 = INNERp2 - INNERp1;
+ vec2 INNERp13 = INNERp3 - INNERp1;
+
+ vec2 INNERx3 = fragCoord;
+ vec2 INNERx12 = INNERx2 - INNERx1;
+ vec2 INNERx13 = INNERx3 - INNERx1;
+
+ vec2 INNERy3 = fragCoord;
+ vec2 INNERy12 = INNERy2 - INNERy1;
+ vec2 INNERy13 = INNERy3 - INNERy1;
+
+ vec2 INNERz3 = fragCoord;
+ vec2 INNERz12 = INNERz2 - INNERz1;
+ vec2 INNERz13 = INNERz3 - INNERz1;
+
+ float INNERd = dot(INNERp12, INNERp13) / length(INNERp12); // = length(p13) * cos(angle)
+ float INNERdx = dot(INNERx12, INNERx13) / length(INNERx12);
+ float INNERdy = dot(INNERy12, INNERy13) / length(INNERy12);
+ float INNERdz = dot(INNERz12, INNERz13) / length(INNERz12);
+
+ vec2 INNERp4 = INNERp1 + normalize(INNERp12) * INNERd;
+ vec2 INNERx4 = INNERx1 + normalize(INNERx12) * INNERdx;
+ vec2 INNERy4 = INNERy1 + normalize(INNERy12) * INNERdy;
+ vec2 INNERz4 = INNERz1 + normalize(INNERz12) * INNERdz;
+
+ if (((length(INNERp4 - INNERp3) < THICCNESS && length(INNERp4 - INNERp1) <= length(INNERp12) && length(INNERp4 - INNERp2) <= length(INNERp12)) ||
+ (length(INNERx4 - INNERx3) < THICCNESS && length(INNERx4 - INNERx1) <= length(INNERx12) && length(INNERx4 - INNERx2) <= length(INNERx12))) ||
+ (length(INNERy4 - INNERy3) < THICCNESS && length(INNERy4 - INNERy1) <= length(INNERy12) && length(INNERy4 - INNERy2) <= length(INNERy12)) ||
+ (length(INNERz4 - INNERz3) < THICCNESS && length(INNERz4 - INNERz1) <= length(INNERz12) && length(INNERz4 - INNERz2) <= length(INNERz12))) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+
+
+ // Draw the lines connecting the points
+ // Calculate the line segment connecting p1 and y1
+ vec2 dir = normalize(y1 - p1);
+ vec2 relPoint = fragCoord - p1;
+ float alongLine = dot(relPoint, dir);
+ float distance = length(relPoint - alongLine * dir);
+
+ // Draw the line connecting p1 and y1
+ if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(y1 - p1)) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+
+
+
+ dir = normalize(y2 - x1);
+ relPoint = fragCoord - x1;
+ alongLine = dot(relPoint, dir);
+ distance = length(relPoint - alongLine * dir);
+
+ if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(x1 - y2)) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+
+
+ dir = normalize(p2 - z1);
+ relPoint = fragCoord - z1;
+ alongLine = dot(relPoint, dir);
+ distance = length(relPoint - alongLine * dir);
+
+ if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(z1 - p2)) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+
+
+
+ dir = normalize(x2 - z2);
+ relPoint = fragCoord - z2;
+ alongLine = dot(relPoint, dir);
+ distance = length(relPoint - alongLine * dir);
+
+ if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(x2 - z2)) {
+ col = vec4(0.1, 0.1, 0.1, 1.0);
+ }
+ // Draw other lines...
+
+ vec2 t1 = vec2(0.0, float(height));
+ vec2 t2 = vec2(float(width), float(height));
+ vec2 t3 = vec2(-0.5, -0.5);
+ vec2 t4 = vec2(float(width), -0.5);
+
+
+
+vec4 combine_col= col+effect_color(pos);
+
+
+
+
+
+int shadow_radius=-0;
+int corner_radius=15;
+
+
+vec4 c = vec4(1.0);
+vec4 m = vec4(0.0, 0.0, 0.0, 0.0); // Transparent for the cut corners
+float diffuse = 1.0 / max(float(shadow_radius / 2), 1.0);
+
+float distanceToEdgeX = ceil(min(pos.x, width - pos.x));
+float distanceToEdgeY = ceil(min(pos.y, height - pos.y));
+
+float radii_sum = float(shadow_radius) + float(corner_radius);
+
+// Check for 45-degree cut corners
+if ((distanceToEdgeX <= radii_sum) && (distanceToEdgeY <= radii_sum))
+{
+ // Calculate if within the 45-degree triangle area
+ float diagonalDistance = distanceToEdgeX + distanceToEdgeY;
+ if (diagonalDistance <= radii_sum) {
+ // Inside the cut corner area, make it fully transparent
+ return m; // Return transparent color
+ }
+}
+
+/*
+bool closeToX = distanceToEdgeX < float(shadow_radius);
+bool closeToY = distanceToEdgeY < float(shadow_radius);
+
+if (!closeToX && !closeToY)
+{
+ // return effect_color(pos);
+}
+
+// Handle shadow along edges
+float shadow_d = float(shadow_radius) - (closeToX ? distanceToEdgeX : distanceToEdgeY);
+vec4 edgeShadow = mix(c, m, 1.0 - exp(-pow(shadow_d * diffuse, 2.0)));
+vec4 shadow = vec4(edgeShadow.rgb, edgeShadow.a * clamp(1.0 - shadow_d / float(shadow_radius), 0.0, 1.0)); // Adjust alpha to fade shadow
+*/
+
+ return combine_col;
+
+})";
+
+
+
+
+
+
+
+
diff --git a/src/smoke-shaders.hpp b/src/smoke-shaders.hpp
index 5956ca1..f94ff80 100644
--- a/src/smoke-shaders.hpp
+++ b/src/smoke-shaders.hpp
@@ -443,3 +443,1199 @@ void run_pixel(int x, int y)
}
imageStore(out_tex, ivec2(x, y), vec4(color, decor_color.a));
})";
+
+/*///////////////////////////////////////////////
+ ______ _ _ __ __ ______ _____
+ | ____|| | | || \/ || ____| / ____|
+ | |__ | | | || \ / || |__ | (___
+ | __| | | | || |\/| || __| \___ \
+ | | | |__| || | | || |____ ____) |
+ |_| \____/ |_| |_||______| |_____/
+
+*////////////////////////////////////////////////
+
+static const char *fumes_motion_source =
+ R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 1, r32f) uniform writeonly image2D out_b0u;
+layout (binding = 2, r32f) uniform readonly image2D in_b0v;
+layout (binding = 2, r32f) uniform writeonly image2D out_b0v;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (binding = 3, r32f) uniform writeonly image2D out_b0d;
+layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+layout(location = 1) uniform int title_height;
+layout(location = 2) uniform int border_size;
+layout(location = 3) uniform int px;
+layout(location = 4) uniform int py;
+layout(location = 5) uniform int width;
+layout(location = 6) uniform int height;
+layout(location = 7) uniform int rand1;
+layout(location = 8) uniform int rand2;
+layout(location = 9) uniform int radius;
+
+void motion(int x, int y)
+{
+ int i, i0, i1, j, j0, j1, d = 2;
+
+ if (x - d < 1)
+ i0 = 1;
+ else
+ i0 = x - d;
+ if (i0 + 2 * d > width - 1)
+ i1 = width - 1;
+ else
+ i1 = i0 + 2 * d;
+
+ if (y - d < 1)
+ j0 = 1;
+ else
+ j0 = y - d;
+ if (j0 + 2 * d > height - 1)
+ j1 = height - 1;
+ else
+ j1 = j0 + 2 * d;
+
+ for (i = i0; i < i1; i++)
+ {
+ for (j = j0; j < j1; j++) {
+ if (i < radius || j < radius || i > (width - 1) - radius || j > (height - 1) - radius || (i > border_size && i < (width - 1) - border_size && j > (title_height - 1) && j < (height - 1) - border_size))
+ {
+ continue;
+ }
+ vec4 b0u = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0v = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0d = imageLoad(in_b0u, ivec2(i, j));
+ float u = b0u.x;
+ float v = b0v.x;
+ float d = b0d.x;
+ imageStore(out_b0u, ivec2(i, j), vec4(u + float(256*15 - (rand1 & 512*15)), 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(i, j), vec4(v + float(256*15 - (rand2 & 512*15)), 0.0, 0.0, 0.0));
+ // imageStore(out_b0d, ivec2(i, j), vec4(0.0, 0.0, 0.0, 0.0));
+ }
+ }
+ }
+
+void main()
+{
+ motion(px, py);
+}
+)";
+
+static const char *fumes_diffuse1_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k;
+ float t = 0.0002;
+ float a = 0.002;
+ vec4 s = imageLoad(in_b0u, ivec2(x, y));
+ vec4 d1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 d2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 d3 = imageLoad(in_b1u, ivec2(x, y - 1));
+ vec4 d4 = imageLoad(in_b1u, ivec2(x, y + 1));
+ float sx = s.x;
+ float du1 = d1.x;
+ float du2 = d2.x;
+ float du3 = d3.x;
+ float du4 = d4.x;
+ float t1 = du1 + du2 + du3 + du4;
+ s = imageLoad(in_b0v, ivec2(x, y));
+ d1 = imageLoad(in_b1v, ivec2(x - 1, y));
+ d2 = imageLoad(in_b1v, ivec2(x + 1, y));
+ d3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ d4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float sy = s.x;
+ du1 = d1.x;
+ du2 = d2.x;
+ du3 = d3.x;
+ du4 = d4.x;
+ float t2 = du1 + du2 + du3 + du4;
+ imageStore(out_b1u, ivec2(x, y), vec4((sx + a * t1) / (1.0 + 4.0 * a) * 0.9999999999999999999999995, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4((sy + a * t2) / (1.0 + 4.0 * a) * 0.9999999999999999999999995, 0.0, 0.0, 0.0));
+
+
+}
+)";
+
+static const char *fumes_project1_source =
+ R"(
+void run_pixel(int x, int y) {
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+// s = width;
+
+ vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float v1 = s3.x;
+ float v2 = s4.x;
+ imageStore(out_b0u, ivec2(x, y), vec4(0.0, 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(x, y), vec4(-0.5 * h * (u2 - u1 + v2 - v1), 0.0, 0.0, 0.0));
+}
+)";
+
+static const char *fumes_project2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0 = imageLoad(in_b0v, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+
+ imageStore(out_b0u, ivec2(x, y), vec4((s0.x + u1 + u2 + u3 + u4) / 4.0, 0.0, 0.0, 0.0));
+})";
+
+static const char *fumes_project3_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0x = imageLoad(in_b1u, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s0y = imageLoad(in_b1v, ivec2(x, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float su = s0x.x;
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float sv = s0y.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+ imageStore(out_b1u, ivec2(x, y), vec4(su - 0.5 * (u2 - u1) / h, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4(sv - 0.5 * (u4 - u3) / h, 0.0, 0.0, 0.0));
+})";
+
+static const char *fumes_advect1_source =
+ R"(
+
+void run_pixel(int x, int y) /* b1.u, b1.v, b1.u, b0.u */
+{
+ int stride;
+ int i, j;
+ float fx, fy;
+ stride = width;
+
+ vec4 sx = imageLoad(in_b1u, ivec2(x, y));
+ vec4 sy = imageLoad(in_b1v, ivec2(x, y));
+ float ix = float(x) - sx.x;
+ float iy = float(y) - sy.x;
+
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process u component
+ vec4 s0x = imageLoad(in_b1u, ivec2(i, j));
+ vec4 s1x = imageLoad(in_b1u, ivec2(i + 1, j));
+ vec4 s2x = imageLoad(in_b1u, ivec2(i, j + 1));
+ vec4 s3x = imageLoad(in_b1u, ivec2(i + 1, j + 1));
+ float p1 = (s0x.x * (1.0 - fx) + s1x.x * fx) * (1.0 - fy) + (s2x.x * (1.0 - fx) + s3x.x * fx) * fy;
+ imageStore(out_b0u, ivec2(x, y), vec4(p1, 0.0, 0.0, 0.0));
+
+ ix = float(x) - sx.x;
+ iy = float(y) - sy.x;
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process v component
+ vec4 s0y = imageLoad(in_b1v, ivec2(i, j));
+ vec4 s1y = imageLoad(in_b1v, ivec2(i + 1, j));
+ vec4 s2y = imageLoad(in_b1v, ivec2(i, j + 1));
+ vec4 s3y = imageLoad(in_b1v, ivec2(i + 1, j + 1));
+ float p2 = (s0y.x * (1.0 - fx) + s1y.x * fx) * (1.0 - fy) + (s2y.x * (1.0 - fx) + s3y.x * fx) * fy;
+ imageStore(out_b0v, ivec2(x, y), vec4(p2, 0.0, 0.0, 0.0));
+})";
+
+static const char *fumes_project4_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fumes_project5_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fumes_project6_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fumes_diffuse2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fumes_advect2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+
+})";
+
+//math from https://inria.hal.science/inria-00596050/document
+static const char *fumes_render_source =
+ R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 0, rgba32f) uniform writeonly image2D out_tex;
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+
+layout(location = 4) uniform bool ink;
+layout(location = 8) uniform vec4 smoke_color;
+layout(location = 9) uniform vec4 decor_color;
+layout(location = 10) uniform int regionInfo[20];
+
+
+const float K = 1000.0;
+const float v = 0.0000000000005; // Viscosity
+const vec2 Step = vec2(0.005, 0.005); // Texture step for resolution
+const vec4 ExternalForces = vec4(-0.0, 0.0, 10.0, 0.0);
+const float dt = -0.2; // Constant small time step
+
+bool IsBoundary(vec2 UV) {
+ // Implement your boundary condition check here
+ return false;
+}
+
+float rand(vec2 uv) {
+ return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+
+void run_pixel(int x, int y)
+{
+
+
+ ivec2 coords = ivec2(x, y);
+ vec2 UV = (vec2(coords) + 0.5) / vec2(imageSize(in_b0d));
+
+
+
+ float CScale = 1.0 / 2.0;
+ float S = K / dt;
+
+ vec4 FC = imageLoad(in_b0d, ivec2(x, y));
+ vec4 FR = imageLoad(in_b0d, ivec2(x + 1, y));
+ vec4 FL = imageLoad(in_b0d, ivec2(x - 1, y));
+ vec4 FT = imageLoad(in_b0d, ivec2(x, y + 1));
+ vec4 FD = imageLoad(in_b0d, ivec2(x, y - 1));
+
+
+ mat4 FieldMat = mat4(FR, FL, FT, FD);
+ // du/dx, du/dy
+ vec3 UdX = (FieldMat[0].xyz - FieldMat[1].xyz) * CScale;
+ vec3 UdY = (FieldMat[2].xyz - FieldMat[3].xyz) * CScale;
+ float Udiv = UdX.x + UdY.y;
+ vec2 DdX = vec2(UdX.z, UdY.z);
+ // Solve for density.
+ FC.z -= dt * dot(vec3(DdX, Udiv), FC.xyz);
+ // Related to stability.
+ FC.z = clamp(FC.z, 0.5, 3.0);
+ // Solve for Velocity.
+ vec2 PdX = S * DdX;
+ vec2 Laplacian = vec2(1.0) * dot(vec4(1.0), vec4(FieldMat)) - 4.0 * FC.xy;
+ vec2 ViscosityForce = v * Laplacian;
+ // Semi-lagrangian advection.
+ // Assuming you want to change the direction along the x-axis:
+// Adjust the texture coordinates accordingly to change the direction of advection
+
+// Update the texture coordinates for advection
+vec2 Was = UV - dt * FC.xy * Step;
+
+// Modify the texture coordinates based on the desired direction
+// For example, to change the direction along the y-axis:
+ Was.y = UV.y - dt * FC.y * Step.y;
+Was.x = UV.x + dt * FC.x * Step.x;
+// Convert Was to texture coordinates
+Was = Was * vec2(imageSize(in_b0u));
+
+// Sample the velocity texture using the updated coordinates
+vec2 newVelocity = imageLoad(in_b0u, ivec2(Was)).xy;
+
+// Update FC.xy with the new velocity
+FC.xy = newVelocity;
+
+
+ FC.xy = imageLoad(in_b0u, ivec2(Was)).xy;
+ FC.xy += dt * (ViscosityForce - PdX + ExternalForces.xy);
+
+ // Output
+ // imageStore(out_tex, coords, FC* 1.0);
+
+// Calculate the density value
+float density = FC.x;
+
+// Define a threshold to determine the blend factor
+float threshold = 0.02;
+
+
+//vec4 blendedColor = mix(vec4(1.0,0.0,0.0,FC*-10.0), vec4(0.0,0.0,0.0,FC*1.0), smoothstep(0.0, 1.0, density / threshold));
+
+// Blend between the two colors based on the density value
+//vec4 blendedColor = mix(vec4(1.0,0.0,0.0,FC*-10.0), vec4(1.0,1.0,1.0,FC*1.0), smoothstep(0.0, 1.0, density / threshold));
+//vec4 blendedColor = mix(vec4(1.0,1.0,1.0,FC*-10.0), vec4(0.0,0.0,0.0,FC*1.0), smoothstep(0.0, 1.0, density / threshold));
+
+
+ // Inside the pixel processing loop
+ vec2 seed = vec2(34.0, 78.0); // Initial seed values
+
+ // Inside the pixel processing loop
+ vec2 seed2 = vec2(14.0, 98.0); // Initial seed values
+ // Inside the pixel processing loop
+ vec2 seed3 = vec2(49.0, 178.0); // Initial seed values
+
+
+// Generate pseudo-random numbers based on the pixel coordinates (x, y)
+float randomValueR = rand(UV + seed);
+float randomValueG = rand(UV + 2.0 * seed2); // Use a different seed for green to ensure variety
+float randomValueB = rand(UV + 3.0 * seed3); // Use another different seed for blue
+
+// Create a random color using the random values for each component
+vec4 randomColor = vec4(randomValueR, randomValueG, randomValueB, smoothstep(0.0, 1.0, density / threshold));
+
+ // Add the random color to the smoke color
+ vec4 smokeWithRandomColor = smoke_color;
+
+
+
+
+vec4 blendedColor = mix(vec4(vec4(smokeWithRandomColor.r*.5,smokeWithRandomColor.g*.5,smokeWithRandomColor.b*-0.5,FC*-10.0)), vec4(smokeWithRandomColor.r,smokeWithRandomColor.g,smokeWithRandomColor.b,FC*1.0), smoothstep(0.0, 1.0, density / threshold));
+
+// Output the blended color
+//imageStore(out_tex, coords, blendedColor);
+
+// Blend the decor color with the blended smoke color
+vec4 finalColor = mix(decor_color, blendedColor, blendedColor.a);
+
+// Output the final color
+imageStore(out_tex, coords, finalColor);
+})";
+
+
+
+
+/*///////////////////////////////////////////////
+ _____
+ / ____|
+ | (___
+ fast \ ___ \ moke
+ ____) |
+ |_____/
+
+*////////////////////////////////////////////////
+
+static const char *fast_smoke_motion_source =
+ R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 1, r32f) uniform writeonly image2D out_b0u;
+layout (binding = 2, r32f) uniform readonly image2D in_b0v;
+layout (binding = 2, r32f) uniform writeonly image2D out_b0v;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (binding = 3, r32f) uniform writeonly image2D out_b0d;
+layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+layout(location = 1) uniform int title_height;
+layout(location = 2) uniform int border_size;
+layout(location = 3) uniform int px;
+layout(location = 4) uniform int py;
+layout(location = 5) uniform int width;
+layout(location = 6) uniform int height;
+layout(location = 7) uniform int rand1;
+layout(location = 8) uniform int rand2;
+layout(location = 9) uniform int radius;
+
+void motion(int x, int y)
+{
+ int i, i0, i1, j, j0, j1, d = 2;
+
+ if (x - d < 1)
+ i0 = 1;
+ else
+ i0 = x - d;
+ if (i0 + 2 * d > width - 1)
+ i1 = width - 1;
+ else
+ i1 = i0 + 2 * d;
+
+ if (y - d < 1)
+ j0 = 1;
+ else
+ j0 = y - d;
+ if (j0 + 2 * d > height - 1)
+ j1 = height - 1;
+ else
+ j1 = j0 + 2 * d;
+
+ for (i = i0; i < i1; i++)
+ {
+ for (j = j0; j < j1; j++) {
+ if (i < radius || j < radius || i > (width - 1) - radius || j > (height - 1) - radius || (i > border_size && i < (width - 1) - border_size && j > (title_height - 1) && j < (height - 1) - border_size))
+ {
+ continue;
+ }
+ vec4 b0u = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0v = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0d = imageLoad(in_b0u, ivec2(i, j));
+ float u = b0u.x;
+ float v = b0v.x;
+ float d = b0d.x;
+ imageStore(out_b0u, ivec2(i, j), vec4(u + float(256*1 - (rand1 & 512*1)), 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(i, j), vec4(v + float(256*1 - (rand2 & 512*1)), 0.0, 0.0, 0.0));
+ // imageStore(out_b0d, ivec2(i, j), vec4(0.0, 0.0, 0.0, 0.0));
+ }
+ }
+ }
+
+void main()
+{
+ motion(px, py);
+}
+)";
+
+static const char *fast_smoke_diffuse1_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k;
+ float t = 0.0002;
+ float a = 0.002;
+ vec4 s = imageLoad(in_b0u, ivec2(x, y));
+ vec4 d1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 d2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 d3 = imageLoad(in_b1u, ivec2(x, y - 1));
+ vec4 d4 = imageLoad(in_b1u, ivec2(x, y + 1));
+ float sx = s.x;
+ float du1 = d1.x;
+ float du2 = d2.x;
+ float du3 = d3.x;
+ float du4 = d4.x;
+ float t1 = du1 + du2 + du3 + du4;
+ s = imageLoad(in_b0v, ivec2(x, y));
+ d1 = imageLoad(in_b1v, ivec2(x - 1, y));
+ d2 = imageLoad(in_b1v, ivec2(x + 1, y));
+ d3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ d4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float sy = s.x;
+ du1 = d1.x;
+ du2 = d2.x;
+ du3 = d3.x;
+ du4 = d4.x;
+ float t2 = du1 + du2 + du3 + du4;
+ imageStore(out_b1u, ivec2(x, y), vec4((sx + a * t1) / (1.0 + 4.0 * a) * 0.9999999999999999999999999999999999999999995, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4((sy + a * t2) / (1.0 + 4.0 * a) * 0.9999999999999999999999999999999999999999995, 0.0, 0.0, 0.0));
+
+
+}
+)";
+
+static const char *fast_smoke_project1_source =
+ R"(
+void run_pixel(int x, int y) {
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+// s = width;
+
+ vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float v1 = s3.x;
+ float v2 = s4.x;
+ imageStore(out_b0u, ivec2(x, y), vec4(0.0, 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(x, y), vec4(-0.5 * h * (u2 - u1 + v2 - v1), 0.0, 0.0, 0.0));
+}
+)";
+
+static const char *fast_smoke_project2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0 = imageLoad(in_b0v, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+
+ imageStore(out_b0u, ivec2(x, y), vec4((s0.x + u1 + u2 + u3 + u4) / 4.0, 0.0, 0.0, 0.0));
+})";
+
+static const char *fast_smoke_project3_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0x = imageLoad(in_b1u, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s0y = imageLoad(in_b1v, ivec2(x, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float su = s0x.x;
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float sv = s0y.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+ imageStore(out_b1u, ivec2(x, y), vec4(su - 0.5 * (u2 - u1) / h, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4(sv - 0.5 * (u4 - u3) / h, 0.0, 0.0, 0.0));
+})";
+
+static const char *fast_smoke_advect1_source =
+ R"(
+
+void run_pixel(int x, int y) /* b1.u, b1.v, b1.u, b0.u */
+{
+ int stride;
+ int i, j;
+ float fx, fy;
+ stride = width;
+
+ vec4 sx = imageLoad(in_b1u, ivec2(x, y));
+ vec4 sy = imageLoad(in_b1v, ivec2(x, y));
+ float ix = float(x) - sx.x;
+ float iy = float(y) - sy.x;
+
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process u component
+ vec4 s0x = imageLoad(in_b1u, ivec2(i, j));
+ vec4 s1x = imageLoad(in_b1u, ivec2(i + 1, j));
+ vec4 s2x = imageLoad(in_b1u, ivec2(i, j + 1));
+ vec4 s3x = imageLoad(in_b1u, ivec2(i + 1, j + 1));
+ float p1 = (s0x.x * (1.0 - fx) + s1x.x * fx) * (1.0 - fy) + (s2x.x * (1.0 - fx) + s3x.x * fx) * fy;
+ imageStore(out_b0u, ivec2(x, y), vec4(p1, 0.0, 0.0, 0.0));
+
+ ix = float(x) - sx.x;
+ iy = float(y) - sy.x;
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process v component
+ vec4 s0y = imageLoad(in_b1v, ivec2(i, j));
+ vec4 s1y = imageLoad(in_b1v, ivec2(i + 1, j));
+ vec4 s2y = imageLoad(in_b1v, ivec2(i, j + 1));
+ vec4 s3y = imageLoad(in_b1v, ivec2(i + 1, j + 1));
+ float p2 = (s0y.x * (1.0 - fx) + s1y.x * fx) * (1.0 - fy) + (s2y.x * (1.0 - fx) + s3y.x * fx) * fy;
+ imageStore(out_b0v, ivec2(x, y), vec4(p2, 0.0, 0.0, 0.0));
+})";
+
+static const char *fast_smoke_project4_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fast_smoke_project5_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fast_smoke_project6_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fast_smoke_diffuse2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *fast_smoke_advect2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+
+})";
+
+//math from https://inria.hal.science/inria-00596050/document
+static const char *fast_smoke_render_source =
+ R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 0, rgba32f) uniform writeonly image2D out_tex;
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+
+layout(location = 4) uniform bool ink;
+layout(location = 8) uniform vec4 smoke_color;
+layout(location = 9) uniform vec4 decor_color;
+layout(location = 10) uniform int regionInfo[20];
+
+
+const float K = 1.0;
+const float v = 0.0005; // Viscosity
+const vec2 Step = vec2(0.005, 0.005); // Texture step for resolution
+const vec4 ExternalForces = vec4(-0.0, 0.0, 10.0, 0.0);
+const float dt = 0.2; // Constant small time step
+const float k = 0.1; // Or replace with the appropriate diffusion coefficient value
+
+
+bool IsBoundary(vec2 UV) {
+ // Implement your boundary condition check here
+ return false;
+}
+
+
+void run_pixel(int x, int y)
+{
+
+
+ ivec2 coords = ivec2(x, y);
+ vec2 UV = (vec2(coords) + 0.5) / vec2(imageSize(in_b0d));
+
+
+ float CScale = 1.0 / 2.0;
+ float S = K / dt;
+
+ vec4 FC = imageLoad(in_b0d, ivec2(x, y));
+ vec4 FR = imageLoad(in_b0d, ivec2(x + 1, y));
+ vec4 FL = imageLoad(in_b0d, ivec2(x - 1, y));
+ vec4 FT = imageLoad(in_b0d, ivec2(x, y + 1));
+ vec4 FD = imageLoad(in_b0d, ivec2(x, y - 1));
+
+
+ mat4 FieldMat = mat4(FR, FL, FT, FD);
+ // du/dx, du/dy
+ vec3 UdX = (FieldMat[0].xyz - FieldMat[1].xyz) * CScale;
+ vec3 UdY = (FieldMat[2].xyz - FieldMat[3].xyz) * CScale;
+ float Udiv = UdX.x + UdY.y;
+ vec2 DdX = vec2(UdX.z, UdY.z);
+ // Solve for density.
+ FC.z -= dt * dot(vec3(DdX, Udiv), FC.xyz);
+ // Related to stability.
+ FC.z = clamp(FC.z, 0.5, 3.0);
+ // Solve for Velocity.
+ vec2 PdX = S * DdX;
+ vec2 Laplacian = vec2(1.0) * dot(vec4(0.0), vec4(FieldMat)) - 4000000.0 * FC.xy;
+ vec2 ViscosityForce = v * Laplacian;
+ // Semi-lagrangian advection.
+ // Assuming you want to change the direction along the x-axis:
+// Adjust the texture coordinates accordingly to change the direction of advection
+
+// Update the texture coordinates for advection
+vec2 Was = UV - dt * FC.xy * Step;
+
+// Modify the texture coordinates based on the desired direction
+// For example, to change the direction along the y-axis:
+// Was.y = UV.y - dt * FC.y * Step.y;
+//Was.x = UV.x + dt * FC.x * Step.x;
+// Convert Was to texture coordinates
+Was = Was * vec2(imageSize(in_b0u));
+
+// Sample the velocity texture using the updated coordinates
+vec2 newVelocity = imageLoad(in_b0u, ivec2(Was)).xy;
+
+// Update FC.xy with the new velocity
+FC.xy = newVelocity;
+
+
+ FC.xy = imageLoad(in_b0u, ivec2(Was)).xy;
+ FC.xy += dt * (ViscosityForce - PdX + ExternalForces.xy);
+
+ // Output
+ // imageStore(out_tex, coords, FC* 1.0);
+
+// Calculate the density value
+float density = FC.x;
+
+// Define a threshold to determine the blend factor
+float threshold = 0.02;
+
+
+ /// Semi-Lagrangian advection
+vec2 advectionOffset = newVelocity * dt;
+vec2 advectedCoords = UV - advectionOffset;
+advectedCoords = clamp(advectedCoords, vec2(0.0), vec2(1.0));
+
+// Convert the floating-point texture coordinates to integer indices
+ivec2 texCoords = ivec2(clamp(advectedCoords * vec2(imageSize(in_b0u)), vec2(0.0), vec2(imageSize(in_b0u)) - 1.0));
+
+// Sample the velocity texture using the updated integer indices
+ newVelocity = imageLoad(in_b0u, texCoords).xy;
+
+
+
+
+UdX = (FR.xyz - FL.xyz) * (1.0 / 2.0);
+ UdY = (FT.xyz - FD.xyz) * (1.0 / 2.0);
+Udiv = UdX.x - UdX.y + UdY.x - UdY.y; // Divergence of the velocity field
+
+float laplacian = dot(vec4(1.0), vec4(FC.z, FC.z, FC.z, FC.z)) - 4.0 * FC.z;
+FC.z += dt * k * laplacian;
+
+
+ // FC.xy = newVelocity;
+
+
+ // Calculate the final density value
+ density = FC.x;
+
+
+
+
+vec4 blendedColor = mix(vec4(smoke_color.r,smoke_color.g,smoke_color.b,FC*-10.0), vec4(smoke_color.r,smoke_color.g,smoke_color.b,FC*10.0), smoothstep(0.0, 1.0, density*FC.z*10.0 / threshold));
+
+//vec4 blendedColor = mix(vec4(smoke_color.r,smoke_color.g,smoke_color.b,FC*-10.0), vec4(smoke_color.r,smoke_color.g,smoke_color.b,1.0), smoothstep(0.0, 1.0, density*FC.z / threshold));
+
+
+
+
+
+// Output the blended color
+//imageStore(out_tex, coords, blendedColor);
+
+// Blend the decor color with the blended smoke color
+vec4 finalColor = mix(decor_color, blendedColor, blendedColor.a);
+
+
+ // Apply threshold and blend colors
+// blendedColor = mix(vec4(smoke_color.r, smoke_color.g, smoke_color.b, FC.z * -10.0), vec4(smoke_color.r, smoke_color.g, smoke_color.b, FC.z * 1.0), smoothstep(0.0, 1.0, density / threshold));
+
+
+
+// Output the final color
+imageStore(out_tex, coords, finalColor);
+})";
+
+
+
+/*///////////////////////////////////////////////
+ ______ _ ____ ______
+ | ____|| | | __ \ | ____|
+ | |__ | | | |__\ | | |____
+ | __| | | | ___ | | ____|
+ | | | | | | \ \ | |____
+ |_| |_| |_| |_| |______|
+
+*////////////////////////////////////////////////
+
+
+static const char *flame_motion_source =
+ R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 1, r32f) uniform writeonly image2D out_b0u;
+layout (binding = 2, r32f) uniform readonly image2D in_b0v;
+layout (binding = 2, r32f) uniform writeonly image2D out_b0v;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (binding = 3, r32f) uniform writeonly image2D out_b0d;
+layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+layout(location = 1) uniform int title_height;
+layout(location = 2) uniform int border_size;
+layout(location = 3) uniform int px;
+layout(location = 4) uniform int py;
+layout(location = 5) uniform int width;
+layout(location = 6) uniform int height;
+layout(location = 7) uniform int rand1;
+layout(location = 8) uniform int rand2;
+layout(location = 9) uniform int radius;
+
+void motion(int x, int y)
+{
+ int i, i0, i1, j, j0, j1, d = 2;
+
+ if (x - d < 1)
+ i0 = 1;
+ else
+ i0 = x - d;
+ if (i0 + 2 * d > width - 1)
+ i1 = width - 1;
+ else
+ i1 = i0 + 2 * d;
+
+ if (y - d < 1)
+ j0 = 1;
+ else
+ j0 = y - d;
+ if (j0 + 2 * d > height - 1)
+ j1 = height - 1;
+ else
+ j1 = j0 + 2 * d;
+
+ for (i = i0; i < i1; i++)
+ {
+ for (j = j0; j < j1; j++) {
+ if (i < radius || j < radius || i > (width - 1) - radius || j > (height - 1) - radius || (i > border_size && i < (width - 1) - border_size && j > (title_height - 1) && j < (height - 1) - border_size))
+ {
+ continue;
+ }
+ vec4 b0u = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0v = imageLoad(in_b0u, ivec2(i, j));
+ vec4 b0d = imageLoad(in_b0u, ivec2(i, j));
+ float u = b0u.x;
+ float v = b0v.x;
+ float d = b0d.x;
+ imageStore(out_b0u, ivec2(i, j), vec4(u + float(256*4 - (rand1 & 512*4)), 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(i, j), vec4(v + float(256*4 - (rand2 & 512*4)), 0.0, 0.0, 0.0));
+ // imageStore(out_b0d, ivec2(i, j), vec4(0.0, 0.0, 0.0, 0.0));
+ }
+ }
+ }
+
+void main()
+{
+ motion(px, py);
+}
+)";
+
+static const char *flame_diffuse1_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k;
+ float t = 0.0002;
+ float a = 0.002;
+ vec4 s = imageLoad(in_b0u, ivec2(x, y));
+ vec4 d1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 d2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 d3 = imageLoad(in_b1u, ivec2(x, y - 1));
+ vec4 d4 = imageLoad(in_b1u, ivec2(x, y + 1));
+ float sx = s.x;
+ float du1 = d1.x;
+ float du2 = d2.x;
+ float du3 = d3.x;
+ float du4 = d4.x;
+ float t1 = du1 + du2 + du3 + du4;
+ s = imageLoad(in_b0v, ivec2(x, y));
+ d1 = imageLoad(in_b1v, ivec2(x - 1, y));
+ d2 = imageLoad(in_b1v, ivec2(x + 1, y));
+ d3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ d4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float sy = s.x;
+ du1 = d1.x;
+ du2 = d2.x;
+ du3 = d3.x;
+ du4 = d4.x;
+ float t2 = du1 + du2 + du3 + du4;
+ imageStore(out_b1u, ivec2(x, y), vec4((sx + a * t1) / (1.0 + 4.0 * a) * 0.9999999999999999999999999999999999999999995, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4((sy + a * t2) / (1.0 + 4.0 * a) * 0.9999999999999999999999999999999999999999995, 0.0, 0.0, 0.0));
+
+
+}
+)";
+
+static const char *flame_project1_source =
+ R"(
+void run_pixel(int x, int y) {
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+// s = width;
+
+ vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b1v, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b1v, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float v1 = s3.x;
+ float v2 = s4.x;
+ imageStore(out_b0u, ivec2(x, y), vec4(0.0, 0.0, 0.0, 0.0));
+ imageStore(out_b0v, ivec2(x, y), vec4(-0.5 * h * (u2 - u1 + v2 - v1), 0.0, 0.0, 0.0));
+}
+)";
+
+static const char *flame_project2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0 = imageLoad(in_b0v, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+
+ imageStore(out_b0u, ivec2(x, y), vec4((s0.x + u1 + u2 + u3 + u4) / 4.0, 0.0, 0.0, 0.0));
+})";
+
+static const char *flame_project3_source =
+ R"(
+void run_pixel(int x, int y)
+{
+ int k, l, s;
+ float h;
+
+ h = 1.0 / float(width);
+ s = width;
+
+ vec4 s0x = imageLoad(in_b1u, ivec2(x, y));
+ vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
+ vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
+ vec4 s0y = imageLoad(in_b1v, ivec2(x, y));
+ vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
+ vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
+ float su = s0x.x;
+ float u1 = s1.x;
+ float u2 = s2.x;
+ float sv = s0y.x;
+ float u3 = s3.x;
+ float u4 = s4.x;
+ imageStore(out_b1u, ivec2(x, y), vec4(su - 0.5 * (u2 - u1) / h, 0.0, 0.0, 0.0));
+ imageStore(out_b1v, ivec2(x, y), vec4(sv - 0.5 * (u4 - u3) / h, 0.0, 0.0, 0.0));
+})";
+
+static const char *flame_advect1_source =
+ R"(
+
+void run_pixel(int x, int y) /* b1.u, b1.v, b1.u, b0.u */
+{
+ int stride;
+ int i, j;
+ float fx, fy;
+ stride = width;
+
+ vec4 sx = imageLoad(in_b1u, ivec2(x, y));
+ vec4 sy = imageLoad(in_b1v, ivec2(x, y));
+ float ix = float(x) - sx.x;
+ float iy = float(y) - sy.x;
+
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process u component
+ vec4 s0x = imageLoad(in_b1u, ivec2(i, j));
+ vec4 s1x = imageLoad(in_b1u, ivec2(i + 1, j));
+ vec4 s2x = imageLoad(in_b1u, ivec2(i, j + 1));
+ vec4 s3x = imageLoad(in_b1u, ivec2(i + 1, j + 1));
+ float p1 = (s0x.x * (1.0 - fx) + s1x.x * fx) * (1.0 - fy) + (s2x.x * (1.0 - fx) + s3x.x * fx) * fy;
+ imageStore(out_b0u, ivec2(x, y), vec4(p1, 0.0, 0.0, 0.0));
+
+ ix = float(x) - sx.x;
+ iy = float(y) - sy.x;
+
+ ix = clamp(ix, 0.5, float(width) - 1.5);
+ iy = clamp(iy, 0.5, float(height) - 1.5);
+
+ i = int(ix);
+ j = int(iy);
+ fx = ix - float(i);
+ fy = iy - float(j);
+
+ // Process v component
+ vec4 s0y = imageLoad(in_b1v, ivec2(i, j));
+ vec4 s1y = imageLoad(in_b1v, ivec2(i + 1, j));
+ vec4 s2y = imageLoad(in_b1v, ivec2(i, j + 1));
+ vec4 s3y = imageLoad(in_b1v, ivec2(i + 1, j + 1));
+ float p2 = (s0y.x * (1.0 - fx) + s1y.x * fx) * (1.0 - fy) + (s2y.x * (1.0 - fx) + s3y.x * fx) * fy;
+ imageStore(out_b0v, ivec2(x, y), vec4(p2, 0.0, 0.0, 0.0));
+})";
+
+static const char *flame_project4_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *flame_project5_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *flame_project6_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *flame_diffuse2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+})";
+
+static const char *flame_advect2_source =
+ R"(
+void run_pixel(int x, int y)
+{
+
+})";
+
+static const char *flame_render_source =
+R"(
+#version 320 es
+
+precision lowp image2D;
+
+layout (binding = 0, rgba32f) uniform writeonly image2D out_tex;
+layout (binding = 1, r32f) uniform readonly image2D in_b0u;
+layout (binding = 3, r32f) uniform readonly image2D in_b0d;
+layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
+
+layout(location = 4) uniform bool ink;
+layout(location = 8) uniform vec4 smoke_color;
+layout(location = 9) uniform vec4 decor_color;
+layout(location = 10) uniform int regionInfo[20];
+
+const float K = 10000.0;
+const float v = 0.0000000000005; // Viscosity
+const vec2 Step = vec2(0.5, 0.5); // Texture step for resolution
+const vec4 ExternalForces = vec4(-0.0, 0.0, 10.0, 0.0);
+const float dt = -0.2; // Constant small time step
+
+bool IsBoundary(vec2 UV) {
+ // Implement your boundary condition check here
+ return false;
+}
+
+float rand(vec2 uv) {
+ return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
+}
+
+void run_pixel(int x, int y)
+{
+ ivec2 coords = ivec2(x, y);
+
+ // Calculate UV coordinates
+ vec2 UV = (vec2(coords) + 0.5) / vec2(imageSize(in_b0d));
+
+ // Load neighboring pixels
+ vec4 FR = imageLoad(in_b0d, coords + ivec2(1, 0));
+ vec4 FL = imageLoad(in_b0d, coords + ivec2(-1, 0));
+ vec4 FT = imageLoad(in_b0d, coords + ivec2(0, 1));
+ vec4 FD = imageLoad(in_b0d, coords + ivec2(0, -1));
+
+ // Calculate gradients
+ vec3 UdX = (FR.xyz - FL.xyz) * 0.5;
+ vec3 UdY = (FT.xyz - FD.xyz) * 0.5;
+ float Udiv = UdX.x + UdY.y;
+ vec2 DdX = vec2(UdX.z, UdY.z);
+
+ // Update density
+ vec4 FC = imageLoad(in_b0d, coords);
+ FC.z -= dt * dot(vec3(DdX, Udiv), FC.xyz) + K * dot(DdX, DdX) - 5.0; // Updated density equation
+ FC.z = clamp(FC.z, 0.5, 3.0);
+
+ // Update velocity
+ vec2 Was = UV - dt * FC.xy * Step;
+ Was.y = UV.y - dt * FC.y * Step.y;
+ Was.x = UV.x + dt * FC.x * Step.x;
+ Was = Was * vec2(imageSize(in_b0u));
+ vec2 newVelocity = imageLoad(in_b0u, ivec2(Was)).xy;
+ FC.xy = newVelocity;
+ FC.xy += dt * (v * ((FR.x + FL.x + FT.x + FD.x) / 100.0) - DdX );
+
+ // Calculate density value
+ float density = FC.x;
+
+ // Calculate blended color
+ vec4 blendedColor = mix(vec4(0.5 * FC.x, 0.05 * FC.x, -0.05 * FC.x, -10.0 * FC.x), vec4(0.1 * FC.x,0.1 * FC.x,0.5 * FC.x, FC.x), smoothstep(0.0, 1.0, density / 10.02));
+
+ // Blend decor color with smoke color
+// vec4 finalColor = mix(decor_color, blendedColor, blendedColor.a * -FC.z*10.0);
+ vec4 finalColor = mix(vec4(0.0,0.0,0.0,1.0), blendedColor, blendedColor.a * -FC.z*10.0);
+ // Output the final color
+ imageStore(out_tex, coords, finalColor);
+}
+)";