Added passes for premultiplied alpha, fixed alpha blending for native transparency
This commit is contained in:
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@ obj = $(src:.c=.o)
|
||||
# Build type parameter
|
||||
|
||||
ifeq ($(BUILD),debug)
|
||||
CFLAGS_BUILD = -O1 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
CFLAGS_BUILD = -O0 -ggdb -Wall -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||
GLAD_GEN = c-debug
|
||||
ASAN = -lasan
|
||||
else
|
||||
|
||||
@@ -86,7 +86,6 @@ static void* create_and_bind(const char* name, const char* class,
|
||||
|
||||
XVisualInfo* vi;
|
||||
XSetWindowAttributes attr;
|
||||
GC gc;
|
||||
GLXFBConfig* fbc;
|
||||
int fb_sz, best = -1, samp = -1;
|
||||
|
||||
@@ -175,8 +174,6 @@ static void* create_and_bind(const char* name, const char* class,
|
||||
|
||||
XFree(vi);
|
||||
|
||||
gc = XCreateGC(display, w->w, 0, 0);
|
||||
|
||||
XStoreName(display, w->w, name);
|
||||
|
||||
Atom dwin = XInternAtom(display, "WM_DELETE_WINDOW", false);
|
||||
|
||||
136
render.c
136
render.c
@@ -85,7 +85,7 @@ struct gl_bind {
|
||||
|
||||
struct gl_sfbo {
|
||||
GLuint fbo, tex, shader;
|
||||
bool valid;
|
||||
bool valid, nativeonly;
|
||||
const char* name;
|
||||
struct gl_bind* binds;
|
||||
size_t binds_sz;
|
||||
@@ -109,7 +109,7 @@ struct gl_data {
|
||||
double tcounter;
|
||||
int fcounter, ucounter, kcounter;
|
||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop,
|
||||
smooth_pass, use_alpha;
|
||||
smooth_pass, premultiply_alpha;
|
||||
void** t_data;
|
||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio,
|
||||
smooth_factor, fft_scale, fft_cutoff;
|
||||
@@ -165,7 +165,8 @@ static GLuint shaderload(const char* rpath,
|
||||
"#define UNIFORM_LIMIT %d\n"
|
||||
"#define PRE_SMOOTHED_AUDIO %d\n"
|
||||
"#define SMOOTH_FACTOR %.6f\n"
|
||||
"#define USE_ALPHA %d\n";
|
||||
"#define USE_ALPHA %d\n"
|
||||
"#define PREMULTIPLY_ALPHA %d\n";
|
||||
|
||||
struct glsl_ext ext = {
|
||||
.source = raw ? NULL : map,
|
||||
@@ -180,11 +181,11 @@ static GLuint shaderload(const char* rpath,
|
||||
/* If this is raw input, skip processing */
|
||||
if (!raw) ext_process(&ext, rpath);
|
||||
|
||||
size_t blen = strlen(header_fmt) + 42;
|
||||
size_t blen = strlen(header_fmt) + 64;
|
||||
GLchar* buf = malloc((blen * sizeof(GLchar*)) + ext.p_len);
|
||||
int written = snprintf(buf, blen, header_fmt, (int) shader_version, (int) max_uniforms,
|
||||
gl->smooth_pass ? 1 : 0, (double) gl->smooth_factor,
|
||||
gl->use_alpha ? 1 : 0);
|
||||
1, gl->premultiply_alpha ? 1 : 0);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
||||
return 0;
|
||||
@@ -696,35 +697,35 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
|
||||
struct gl_data* gl = r->gl;
|
||||
*gl = (struct gl_data) {
|
||||
.w = NULL,
|
||||
.wcb = NULL,
|
||||
.stages = NULL,
|
||||
.rate = 0,
|
||||
.tcounter = 0.0D,
|
||||
.fcounter = 0,
|
||||
.ucounter = 0,
|
||||
.kcounter = 0,
|
||||
.fr = 1.0F,
|
||||
.ur = 1.0F,
|
||||
.print_fps = true,
|
||||
.bufscale = 1,
|
||||
.avg_frames = 6,
|
||||
.avg_window = true,
|
||||
.gravity_step = 4.2,
|
||||
.interpolate = true,
|
||||
.force_geometry = false,
|
||||
.smooth_factor = 0.025,
|
||||
.smooth_distance = 0.01,
|
||||
.smooth_ratio = 4,
|
||||
.bg_tex = 0,
|
||||
.sm_prog = 0,
|
||||
.copy_desktop = true,
|
||||
.use_alpha = true,
|
||||
.smooth_pass = true,
|
||||
.fft_scale = 10.2F,
|
||||
.fft_cutoff = 0.3F,
|
||||
.geometry = { 0, 0, 500, 400 },
|
||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
||||
.w = NULL,
|
||||
.wcb = NULL,
|
||||
.stages = NULL,
|
||||
.rate = 0,
|
||||
.tcounter = 0.0D,
|
||||
.fcounter = 0,
|
||||
.ucounter = 0,
|
||||
.kcounter = 0,
|
||||
.fr = 1.0F,
|
||||
.ur = 1.0F,
|
||||
.print_fps = true,
|
||||
.bufscale = 1,
|
||||
.avg_frames = 6,
|
||||
.avg_window = true,
|
||||
.gravity_step = 4.2,
|
||||
.interpolate = true,
|
||||
.force_geometry = false,
|
||||
.smooth_factor = 0.025,
|
||||
.smooth_distance = 0.01,
|
||||
.smooth_ratio = 4,
|
||||
.bg_tex = 0,
|
||||
.sm_prog = 0,
|
||||
.copy_desktop = true,
|
||||
.premultiply_alpha = true,
|
||||
.smooth_pass = true,
|
||||
.fft_scale = 10.2F,
|
||||
.fft_cutoff = 0.3F,
|
||||
.geometry = { 0, 0, 500, 400 },
|
||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
||||
};
|
||||
|
||||
bool forced = force_backend != NULL;
|
||||
@@ -803,7 +804,7 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
|
||||
bool native_opacity = !strcmp("native", (char*) args[0]);
|
||||
|
||||
gl->use_alpha = true;
|
||||
gl->premultiply_alpha = native_opacity;
|
||||
|
||||
gl->wcb->set_transparent(native_opacity);
|
||||
|
||||
@@ -853,6 +854,17 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
.name = "nativeonly", .fmt = "b",
|
||||
.handler = RHANDLER(name, args, {
|
||||
if (current)
|
||||
current->nativeonly = *(bool*) args[0];
|
||||
else {
|
||||
fprintf(stderr, "`nativeonly` request needs module context\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
})
|
||||
},
|
||||
WINDOW_HINT(floating),
|
||||
WINDOW_HINT(decorated),
|
||||
WINDOW_HINT(focused),
|
||||
@@ -1079,8 +1091,10 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
glDisable(GL_MULTISAMPLE);
|
||||
glDisable(GL_LINE_SMOOTH);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (!gl->premultiply_alpha) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
size_t m_len = strlen(module);
|
||||
size_t bsz = d_len + m_len + 2;
|
||||
@@ -1141,11 +1155,12 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
|
||||
struct gl_sfbo* s = &stages[idx - 1];
|
||||
*s = (struct gl_sfbo) {
|
||||
.name = strdup(d->d_name),
|
||||
.shader = 0,
|
||||
.valid = false,
|
||||
.binds = malloc(1),
|
||||
.binds_sz = 0
|
||||
.name = strdup(d->d_name),
|
||||
.shader = 0,
|
||||
.valid = false,
|
||||
.nativeonly = false,
|
||||
.binds = malloc(1),
|
||||
.binds_sz = 0
|
||||
};
|
||||
|
||||
current = s;
|
||||
@@ -1183,6 +1198,23 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
} while (found);
|
||||
}
|
||||
}
|
||||
|
||||
gl->stages = stages;
|
||||
gl->stages_sz = count;
|
||||
|
||||
{
|
||||
struct gl_sfbo* final = NULL;
|
||||
if (!gl->premultiply_alpha) {
|
||||
for (size_t t = 0; t < gl->stages_sz; ++t) {
|
||||
if (!gl->stages[t].nativeonly) {
|
||||
final = &gl->stages[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Invalidate framebuffer and use direct rendering if it was instantiated
|
||||
due to a following `nativeonly` shader pass. */
|
||||
if (final) final->valid = false;
|
||||
}
|
||||
|
||||
/* Compile smooth pass shader */
|
||||
|
||||
@@ -1193,15 +1225,11 @@ struct renderer* rd_new(const char** paths, const char* entry,
|
||||
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"))) {
|
||||
if (!(gl->sm_prog = shaderbuild(gl, util, data, handlers, shader_version, "smooth_pass.frag")))
|
||||
abort();
|
||||
}
|
||||
loading_smooth_pass = false;
|
||||
}
|
||||
|
||||
gl->stages = stages;
|
||||
gl->stages_sz = count;
|
||||
|
||||
/* target seconds per update */
|
||||
gl->target_spu = (float) (r->samplesize_request / 4) / (float) r->rate_request;
|
||||
|
||||
@@ -1337,6 +1365,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
|
||||
/* Current shader program */
|
||||
struct gl_sfbo* current = &gl->stages[t];
|
||||
|
||||
if (current->nativeonly && !gl->premultiply_alpha)
|
||||
continue;
|
||||
|
||||
/* Bind framebuffer if this is not the final pass */
|
||||
if (current->valid)
|
||||
@@ -1377,9 +1408,9 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
/* We need to disable blending, we might read in bogus alpha values due
|
||||
to how we obtain the background texture (format is four byte `rgb_`,
|
||||
where the last value is skipped) */
|
||||
glDisable(GL_BLEND);
|
||||
if (!gl->premultiply_alpha) glDisable(GL_BLEND);
|
||||
drawoverlay(&gl->overlay);
|
||||
glEnable(GL_BLEND);
|
||||
if (!gl->premultiply_alpha) glEnable(GL_BLEND);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
@@ -1457,7 +1488,8 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
|
||||
/* setup and bind framebuffer to texture */
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sm->fbo);
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_1D, sm->tex, 0);
|
||||
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,\
|
||||
GL_TEXTURE_1D, sm->tex, 0);
|
||||
|
||||
switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
|
||||
case GL_FRAMEBUFFER_COMPLETE: break;
|
||||
@@ -1478,11 +1510,11 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
glUniform1i(sm_uw, sz); /* target texture width */
|
||||
glUniform1i(sm_usz, sz); /* source texture width */
|
||||
glUniform1i(sm_utex, offset);
|
||||
glDisable(GL_BLEND);
|
||||
if (!gl->premultiply_alpha) glDisable(GL_BLEND);
|
||||
glViewport(0, 0, sz, 1);
|
||||
drawoverlay(&gl->overlay);
|
||||
glViewport(0, 0, ww, wh);
|
||||
glEnable(GL_BLEND);
|
||||
if (!gl->premultiply_alpha) glEnable(GL_BLEND);
|
||||
|
||||
/* Return state */
|
||||
glUseProgram(current->shader);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* center radius (pixels) */
|
||||
#define C_RADIUS 128
|
||||
/* center line thickness (pixels) */
|
||||
#define C_LINE 2
|
||||
#define C_LINE 1.5
|
||||
/* outline color */
|
||||
#define OUTLINE #333333
|
||||
/* Amplify magnitude of the results each bar displays */
|
||||
|
||||
1
shaders/circle/3.frag
Normal file
1
shaders/circle/3.frag
Normal file
@@ -0,0 +1 @@
|
||||
#include ":util/premultiply.frag"
|
||||
@@ -29,10 +29,10 @@ out vec4 fragment;
|
||||
#define PI 3.14159265359
|
||||
|
||||
void main() {
|
||||
|
||||
|
||||
#if USE_ALPHA > 0
|
||||
#define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - f.a), max(c.a, f.a))
|
||||
fragment.a;
|
||||
#define APPLY_FRAG(f, c) f = vec4(f.rgb * f.a + c.rgb * (1 - clamp(f.a, 0, 1)), max(c.a, f.a))
|
||||
fragment = #00000000;
|
||||
#else
|
||||
#define APPLY_FRAG(f, c) f = c
|
||||
#endif
|
||||
|
||||
1
shaders/radial/2.frag
Normal file
1
shaders/radial/2.frag
Normal file
@@ -0,0 +1 @@
|
||||
#include ":util/premultiply.frag"
|
||||
@@ -28,10 +28,9 @@
|
||||
|
||||
/* Set window background opacity mode. Possible values are:
|
||||
|
||||
"native" - True transparency provided by the compositor.
|
||||
Requires GLFW 3.3+ and an active compositor. Can
|
||||
reduce performance on some systems, and will not
|
||||
blend with the visualizer's alpha layer.
|
||||
"native" - True transparency provided by the compositor. Can
|
||||
reduce performance on some systems, depending on
|
||||
the compositor used.
|
||||
|
||||
"xroot" - Maintain a copy of the root window's pixmap
|
||||
(usually the desktop background) to provide a
|
||||
@@ -54,8 +53,8 @@
|
||||
#request setgeometry 0 0 800 600
|
||||
|
||||
/* Window background color (RGB format).
|
||||
Only works with `setopacity "none"` */
|
||||
#request setbg 000000
|
||||
Does not work with `setopacity "xroot"` */
|
||||
#request setbg 00000000
|
||||
|
||||
/* (X11 only) EWMH Window type. Possible values are:
|
||||
|
||||
@@ -68,7 +67,7 @@
|
||||
|
||||
https://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#idm140130317606816
|
||||
*/
|
||||
#request setxwintype "desktop"
|
||||
#request setxwintype "normal"
|
||||
|
||||
/* (X11 only) EWMH Window state atoms (multiple can be specified).
|
||||
Possible values are:
|
||||
|
||||
15
shaders/util/premultiply.frag
Normal file
15
shaders/util/premultiply.frag
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
#request nativeonly true
|
||||
|
||||
#request uniform "prev" tex
|
||||
uniform sampler2D tex;
|
||||
|
||||
out vec4 fragment;
|
||||
in vec4 gl_FragCoord;
|
||||
|
||||
void main() {
|
||||
fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
|
||||
#if PREMULTIPLY_ALPHA > 0
|
||||
fragment.rgb *= fragment.a;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user