diff --git a/README.md b/README.md index 039fa71..02bd323 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,10 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is | Any non EWMH-compliant WM | ![-](https://placehold.it/15/f03c15/000000?text=+) | Window types and hints will not work if the window manager does not support the EWMH standards. +### [Demo](https://streamable.com/dgpj8) + + + ## Licensing GLava is licensed under the terms of the GPLv3. GLava includes some (heavily modified) source code that originated from [cava](https://github.com/karlstav/cava), which was initially provided under the MIT license. The source files that originated from cava are the following: diff --git a/render.c b/render.c index 71ccb7a..acf3fe8 100644 --- a/render.c +++ b/render.c @@ -727,7 +727,7 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force char* xwintype = NULL, * wintitle = "GLava"; char** xwinstates = malloc(1); size_t xwinstates_sz = 0; - bool loading_module = true; + bool loading_module = true, loading_smooth_pass = false; struct gl_sfbo* current = NULL; size_t t_count = 0; @@ -828,25 +828,35 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force { .name = "setsamplesize", .fmt = "i", .handler = RHANDLER(name, args, { r->samplesize_request = *(int*) args[0]; }) }, { .name = "setavgframes", .fmt = "i", - .handler = RHANDLER(name, args, { gl->avg_frames = *(int*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->avg_frames = *(int*) args[0]; }) }, { .name = "setavgwindow", .fmt = "b", - .handler = RHANDLER(name, args, { gl->avg_window = *(bool*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->avg_window = *(bool*) args[0]; }) }, { .name = "setgravitystep", .fmt = "f", - .handler = RHANDLER(name, args, { gl->gravity_step = *(float*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->gravity_step = *(float*) args[0]; }) }, { .name = "setsmoothpass", .fmt = "b", - .handler = RHANDLER(name, args, { gl->smooth_pass = *(bool*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->smooth_pass = *(bool*) args[0]; }) }, { .name = "setsmoothfactor", .fmt = "f", - .handler = RHANDLER(name, args, { gl->smooth_factor = *(float*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->smooth_factor = *(float*) args[0]; }) }, { .name = "setsmooth", .fmt = "f", - .handler = RHANDLER(name, args, { gl->smooth_distance = *(float*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->smooth_distance = *(float*) args[0]; }) }, { .name = "setsmoothratio", .fmt = "f", - .handler = RHANDLER(name, args, { gl->smooth_ratio = *(float*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->smooth_ratio = *(float*) args[0]; }) }, { .name = "setinterpolate", .fmt = "b", - .handler = RHANDLER(name, args, { gl->interpolate = *(bool*) args[0]; }) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->interpolate = *(bool*) args[0]; }) }, { .name = "setfftscale", .fmt = "f", - .handler = RHANDLER(name, args, { gl->fft_scale = *(float*) args[0];}) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->fft_scale = *(float*) args[0];}) }, { .name = "setfftcutoff", .fmt = "f", - .handler = RHANDLER(name, args, { gl->fft_cutoff = *(float*) args[0];}) }, + .handler = RHANDLER(name, args, { + if (!loading_smooth_pass) gl->fft_cutoff = *(float*) args[0];}) }, { .name = "transform", .fmt = "ss", .handler = RHANDLER(name, args, { @@ -1096,6 +1106,8 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force } while (found); } } + + /* Compile smooth pass shader */ { const char* util_folder = "util"; @@ -1103,10 +1115,11 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force size_t usz = d_len + u_len + 2; char util[usz]; /* module pack path to use */ snprintf(util, usz, "%s/%s", data, util_folder); - + loading_smooth_pass = true; if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag"))) { abort(); } + loading_smooth_pass = false; } gl->stages = stages; diff --git a/shaders/circle.glsl b/shaders/circle.glsl new file mode 100644 index 0000000..ea4ffba --- /dev/null +++ b/shaders/circle.glsl @@ -0,0 +1,24 @@ +/* center radius (pixels) */ +#define C_RADIUS 128 +/* center line thickness (pixels) */ +#define C_LINE 2 +/* outline color */ +#define OUTLINE vec4(0.20, 0.20, 0.20, 1) +/* Amplify magnitude of the results each bar displays */ +#define AMPLIFY 150 +/* Angle (in radians) for how much to rotate the visualizer */ +#define ROTATE (PI / 2) +/* Whether to switch left/right audio buffers */ +#define INVERT 0 +/* Whether to fill in the space between the line and inner circle */ +#define C_FILL 0 +/* Whether to apply a post-processing image smoothing effect + 1 to enable, 0 to disable. Only works with `xroot` transparency, + and improves performance if disabled. */ +#define C_SMOOTH 1 + +/* Gravity step, overrude frin `smooth_parameters.glsl` */ +#request setgravitystep 6.0 + +/* Smoothing factor, override from `smooth_parameters.glsl` */ +#request setsmoothfactor 0.01 diff --git a/shaders/circle/1.frag b/shaders/circle/1.frag new file mode 100644 index 0000000..a83473d --- /dev/null +++ b/shaders/circle/1.frag @@ -0,0 +1,83 @@ +layout(pixel_center_integer) in vec4 gl_FragCoord; + +#request uniform "screen" screen +uniform ivec2 screen; + +#request uniform "audio_sz" audio_sz +uniform int audio_sz; + +#include ":util/smooth.glsl" +#include ":circle.glsl" + +#request uniform "audio_l" audio_l +#request transform audio_l "window" +#request transform audio_l "fft" +#request transform audio_l "gravity" +#request transform audio_l "avg" +uniform sampler1D audio_l; + +#request uniform "audio_r" audio_r +#request transform audio_r "window" +#request transform audio_r "fft" +#request transform audio_r "gravity" +#request transform audio_r "avg" +uniform sampler1D audio_r; + +out vec4 fragment; + +#define TWOPI 6.28318530718 +#define PI 3.14159265359 + +/* This shader is based on radial.glsl, refer to it for more commentary */ + +float apply_smooth(float theta) { + + float idx = theta + ROTATE; + float dir = mod(abs(idx), TWOPI); + if (dir > PI) + idx = -sign(idx) * (TWOPI - dir); + if (INVERT > 0) + idx = -idx; + + float pos = abs(idx) / (PI + 0.001F); + #define smooth_f(tex) smooth_audio(tex, audio_sz, pos) + float v; + if (idx > 0) v = smooth_f(audio_l); + else v = smooth_f(audio_r); + v *= AMPLIFY; + #undef smooth_f + return v; +} + +void main() { + float + dx = gl_FragCoord.x - (screen.x / 2), + dy = gl_FragCoord.y - (screen.y / 2); + float theta = atan(dy, dx); + float d = sqrt((dx * dx) + (dy * dy)); + float adv = (1.0F / d) * (C_LINE * 0.5); + float + adj0 = theta + adv, + adj1 = theta - adv; + d -= C_RADIUS; + if (d >= -(float(C_LINE) / 2.0F)) { + float v = apply_smooth(theta); + + adj0 = apply_smooth(adj0) - v; + adj1 = apply_smooth(adj1) - v; + + float + dmax = max(adj0, adj1), + dmin = min(adj0, adj1); + + d -= v; + #if C_FILL > 0 + #define BOUNDS (d < (float(C_LINE) / 2.0F)) + #else + #define BOUNDS (d > -(float(C_LINE) / 2.0F) && d < (float(C_LINE) / 2.0F)) || (d <= dmax && d >= dmin) + #endif + if (BOUNDS) { + fragment = OUTLINE; + } + } +} diff --git a/shaders/circle/2.frag b/shaders/circle/2.frag new file mode 100644 index 0000000..abd9c6e --- /dev/null +++ b/shaders/circle/2.frag @@ -0,0 +1,30 @@ + +in vec4 gl_FragCoord; + +#request uniform "prev" tex +uniform sampler2D tex; /* screen texture */ + +out vec4 fragment; /* output */ + +#include ":circle.glsl" + +void main() { + fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0); + #if C_SMOOTH > 0 + vec4 + a0 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 0)), 0), + a1 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 1)), 0), + a2 = texelFetch(tex, ivec2((gl_FragCoord.x + 0), (gl_FragCoord.y + 1)), 0), + a3 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 0)), 0), + + a4 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 0)), 0), + a5 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 1)), 0), + a6 = texelFetch(tex, ivec2((gl_FragCoord.x - 0), (gl_FragCoord.y - 1)), 0), + a7 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 0)), 0); + + vec4 avg = (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) / 8.0; + if (fragment.a == 0) { + fragment = avg; + } + #endif +} diff --git a/shaders/graph.glsl b/shaders/graph.glsl index 560bda0..113f48c 100644 --- a/shaders/graph.glsl +++ b/shaders/graph.glsl @@ -1,6 +1,6 @@ /* Vertical scale, larger values will amplify output */ -#define VSCALE 450 +#define VSCALE 300 /* Rendering direction, either -1 (outwards) or 1 (inwards). */ #define DIRECTION 1 @@ -20,3 +20,9 @@ #define OUTLINE vec4(0.15, 0.15, 0.15, 1) /* 1 to invert (vertically), 0 otherwise */ #define INVERT 0 + +/* Gravity step, overrude frin `smooth_parameters.glsl` */ +#request setgravitystep 2.4 + +/* Smoothing factor, override from `smooth_parameters.glsl` */ +#request setsmoothfactor 0.015 diff --git a/shaders/graph/1.frag b/shaders/graph/1.frag index 682a7ae..90cd0ae 100644 --- a/shaders/graph/1.frag +++ b/shaders/graph/1.frag @@ -39,6 +39,7 @@ uniform int audio_sz; with 'setavgwindow'. */ +#include ":util/smooth.glsl" #include ":graph.glsl" #request uniform "audio_l" audio_l @@ -57,8 +58,6 @@ uniform sampler1D audio_r; out vec4 fragment; -#include ":util/smooth.glsl" - /* distance from center */ #define CDIST (abs((screen.x / 2) - gl_FragCoord.x) / screen.x) /* distance from sides (far) */ diff --git a/shaders/radial.glsl b/shaders/radial.glsl index 5cccab7..1f66a7c 100644 --- a/shaders/radial.glsl +++ b/shaders/radial.glsl @@ -27,3 +27,9 @@ the background. */ #define BAR_ALIAS_FACTOR 1.2 #define C_ALIAS_FACTOR 1.8 + +/* Gravity step, overrude frin `smooth_parameters.glsl` */ +#request setgravitystep 5.0 + +/* Smoothing factor, override from `smooth_parameters.glsl` */ +#request setsmoothfactor 0.02 diff --git a/shaders/radial/1.frag b/shaders/radial/1.frag index 68456a4..8054d1d 100644 --- a/shaders/radial/1.frag +++ b/shaders/radial/1.frag @@ -6,6 +6,7 @@ uniform ivec2 screen; #request uniform "audio_sz" audio_sz uniform int audio_sz; +#include ":util/smooth.glsl" #include ":radial.glsl" #request uniform "audio_l" audio_l @@ -23,7 +24,6 @@ uniform sampler1D audio_l; uniform sampler1D audio_r; out vec4 fragment; -#include ":util/smooth.glsl" #define TWOPI 6.28318530718 #define PI 3.14159265359 diff --git a/shaders/smooth_parameters.glsl b/shaders/smooth_parameters.glsl index 1ae7129..f84357c 100644 --- a/shaders/smooth_parameters.glsl +++ b/shaders/smooth_parameters.glsl @@ -1,6 +1,11 @@ /* Settings for smoothing functions and transformations commonly - used to display FFT output */ + used to display FFT output. + + IMPORTANT: THESE VALUES CAN BE OVERRIDDEN IN MODULE CONFIG + FILES, IF CHANGING VALUES HERE DOES NOT WORK, CHECK + TO MAKE SURE THEY ARE NOT BEING SET ELSEWHERE. +*/ /* The type of formula to use for weighting values when smoothing. Possible values: @@ -10,7 +15,7 @@ like a sine wave - linear not rounded at all, just use linear distance */ -#define ROUND_FORMULA circular +#define ROUND_FORMULA sinusoidal /* Factor used to scale frequencies. Lower values allows lower frequencies to occupy more space. */ diff --git a/shaders/wave/2.frag b/shaders/wave/2.frag index 700e264..58cc30e 100644 --- a/shaders/wave/2.frag +++ b/shaders/wave/2.frag @@ -11,18 +11,18 @@ out vec4 fragment; /* output */ #include ":wave.glsl" void main() { - fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, gl_FragCoord.y / screen.y)); + fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0); vec4 - a0 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)), - a1 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 1) / screen.y)), - a2 = texture(tex, vec2((gl_FragCoord.x + 0) / screen.x, (gl_FragCoord.y + 1) / screen.y)), - a3 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)), + a0 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 0)), 0), + a1 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 1)), 0), + a2 = texelFetch(tex, ivec2((gl_FragCoord.x + 0), (gl_FragCoord.y + 1)), 0), + a3 = texelFetch(tex, ivec2((gl_FragCoord.x + 1), (gl_FragCoord.y + 0)), 0), - a4 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)), - a5 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 1) / screen.y)), - a6 = texture(tex, vec2((gl_FragCoord.x - 0) / screen.x, (gl_FragCoord.y - 1) / screen.y)), - a7 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)); + a4 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 0)), 0), + a5 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 1)), 0), + a6 = texelFetch(tex, ivec2((gl_FragCoord.x - 0), (gl_FragCoord.y - 1)), 0), + a7 = texelFetch(tex, ivec2((gl_FragCoord.x - 1), (gl_FragCoord.y - 0)), 0); vec4 avg = (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) / 8.0; if (avg.a > 0){