Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ec584f35d | ||
|
|
1c2e633bb6 | ||
|
|
1e2aad05b5 | ||
|
|
8359ad9a98 | ||
|
|
92f575adfd | ||
|
|
916ead982e |
17
CHANGELOG.md
Normal file
17
CHANGELOG.md
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
## 1.2
|
||||
|
||||
* Added support for GLFW 3.1, see issue #13
|
||||
* Added configurable solid background color, see #16
|
||||
* Fixed issue with excessive file reads from `~/.Xauthority` see #15
|
||||
|
||||
## 1.1
|
||||
|
||||
* Added `circle` module
|
||||
* Added anti-aliasing to the `radial` module, written into the shader itself
|
||||
* Default configuration values should create more appealing visualizers now
|
||||
* Massive performance improvements, see issue #10
|
||||
|
||||
## 1.0
|
||||
|
||||
* All versions of GLava with `1.0` version numbers are older development releases.
|
||||
18
README.md
18
README.md
@@ -1,7 +1,7 @@
|
||||
## GLava
|
||||
<img align="left" width="200" height="200" src="https://thumbs.gfycat.com/DefiantInformalIndianspinyloach-size_restricted.gif" />
|
||||
|
||||
GLava is an OpenGL audio spectrum visualizer. Its primary use case is for desktop widgets or backgrounds. Displayed to the left is the `radial` shader module running in GLava.
|
||||
GLava is an OpenGL audio spectrum visualizer. Its primary use case is for desktop windows or backgrounds. Displayed to the left is the `radial` shader module, and [here is a demonstration video](https://streamable.com/dgpj8). Development is active, and reporting issues is encouranged.
|
||||
|
||||
**Compiling** (Or use the [`glava-git` AUR package](https://aur.archlinux.org/packages/glava-git/))**:**
|
||||
|
||||
@@ -19,7 +19,7 @@ You can pass `BUILD=debug` to the makefile for debug builds of both glad and gla
|
||||
|
||||
- X11
|
||||
- PulseAudio
|
||||
- GLFW 3.2+
|
||||
- GLFW 3.1+
|
||||
- Linux or BSD
|
||||
|
||||
**Additional compile time requirements:**
|
||||
@@ -47,14 +47,15 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
|
||||
| WM | ! | Details
|
||||
| :---: | --- | --- |
|
||||
| GNOME (on X11) |  | No notable issues
|
||||
| Openbox (LXDE or standalone) |  | Untested, but should work without issues
|
||||
| Openbox (LXDE or standalone) |  | [Some tweaks may be required](https://www.reddit.com/r/unixporn/comments/7vcgi4/oc_after_receiving_positive_feedback_here_i/dtrkvja/)
|
||||
| Xfwm (XFCE) |  | Untested, but should work without issues
|
||||
| Fluxbox |  | Untested, but should work without issues
|
||||
| iceWM |  | No notable issues
|
||||
| kwin (KDE) |  | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
|
||||
| AwesomeWM |  | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout
|
||||
| Budgie Desktop |  | `"xroot"` transparency breaks with Budgie's wallpaper window
|
||||
| kwin (KDE) |  | [Issues with workspaces and stacking](https://github.com/wacossusca34/glava/issues/4), needs further testing
|
||||
| i3 (and i3-gaps) |  | [i3 does not respect the `"desktop"` window type](https://github.com/wacossusca34/glava/issues/6)
|
||||
| EXWM |  | EXWM does not have a desktop, and forces window decorations
|
||||
| AwesomeWM |  | Requires the WM to be restarted (`Super + Ctl + R`) in order for new desktop windows to behave correctly, can still be focused, may require other changes to config depending on layout
|
||||
| Unity |  | Needs testing
|
||||
| Enlightenment |  | Needs testing
|
||||
| Bspwm |  | Needs testing
|
||||
@@ -62,13 +63,6 @@ GLava aims to be compatible with _most_ EWMH compliant window managers. Below is
|
||||
| xmonad |  | Needs testing
|
||||
| Any non EWMH-compliant WM |  | Window types and hints will not work if the window manager does not support the EWMH standards.
|
||||
|
||||
|
||||
### [Demo](https://streamable.com/dgpj8)
|
||||
|
||||
Above is the `graph` module, below is the `bars` module, `circle` to the left, and `radial` is to the right:
|
||||
|
||||
<img src="https://thumbs.gfycat.com/LittleUniformGermanpinscher-size_restricted.gif">
|
||||
|
||||
## 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:
|
||||
|
||||
2
glava.c
2
glava.c
@@ -18,7 +18,7 @@
|
||||
#include "render.h"
|
||||
#include "xwin.h"
|
||||
|
||||
#define GLAVA_VERSION "1.1"
|
||||
#define GLAVA_VERSION "1.2"
|
||||
#ifdef GLAD_DEBUG
|
||||
#define GLAVA_RELEASE_TYPE_PREFIX "debug, "
|
||||
#else
|
||||
|
||||
100
render.c
100
render.c
@@ -97,9 +97,14 @@ struct gl_data {
|
||||
int rate; /* framerate */
|
||||
double tcounter;
|
||||
int fcounter, ucounter, kcounter;
|
||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop, smooth_pass;
|
||||
bool print_fps, avg_window, interpolate, force_geometry, copy_desktop,
|
||||
smooth_pass, use_alpha;
|
||||
void** t_data;
|
||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio, smooth_factor, fft_scale, fft_cutoff;
|
||||
float gravity_step, target_spu, fr, ur, smooth_distance, smooth_ratio,
|
||||
smooth_factor, fft_scale, fft_cutoff;
|
||||
struct {
|
||||
float r, g, b, a;
|
||||
} clear_color;
|
||||
float* interpolate_buf[6];
|
||||
int geometry[4];
|
||||
};
|
||||
@@ -147,7 +152,7 @@ static GLuint shaderload(const char* rpath,
|
||||
"#define UNIFORM_LIMIT %d\n"
|
||||
"#define PRE_SMOOTHED_AUDIO %d\n"
|
||||
"#define SMOOTH_FACTOR %.6f\n"
|
||||
"#define XROOT %d\n";
|
||||
"#define USE_ALPHA %d\n";
|
||||
|
||||
struct glsl_ext ext = {
|
||||
.source = raw ? NULL : map,
|
||||
@@ -166,7 +171,7 @@ static GLuint shaderload(const char* rpath,
|
||||
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->copy_desktop ? 1 : 0);
|
||||
gl->use_alpha ? 1 : 0);
|
||||
if (written < 0) {
|
||||
fprintf(stderr, "snprintf() encoding error while prepending header to shader '%s'\n", path);
|
||||
return 0;
|
||||
@@ -699,10 +704,12 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
.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 }
|
||||
.geometry = { 0, 0, 500, 400 },
|
||||
.clear_color = { 0.0F, 0.0F, 0.0F, 0.0F }
|
||||
};
|
||||
|
||||
#ifdef GLAD_DEBUG
|
||||
@@ -742,10 +749,14 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
|
||||
bool native_opacity = !strcmp("native", (char*) args[0]);
|
||||
|
||||
gl->use_alpha = true;
|
||||
|
||||
#ifdef GLFW_TRANSPARENT_FRAMEBUFFER
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, native_opacity ? GLFW_TRUE : GLFW_FALSE);
|
||||
gl->use_alpha = false;
|
||||
#elif GLFW_TRANSPARENT
|
||||
glfwWindowHint(GLFW_TRANSPARENT, native_opacity ? GLFW_TRUE : GLFW_FALSE);
|
||||
gl->use_alpha = false;
|
||||
#else
|
||||
if (native_opacity)
|
||||
printf("WARNING: the linked version of GLFW3 does not have transparency support"
|
||||
@@ -763,6 +774,63 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
.name = "setbg", .fmt = "s",
|
||||
.handler = RHANDLER(name, args, {
|
||||
float* results[] = {
|
||||
&gl->clear_color.r,
|
||||
&gl->clear_color.g,
|
||||
&gl->clear_color.b,
|
||||
&gl->clear_color.a
|
||||
};
|
||||
const size_t elem_sz = 2;
|
||||
char* str = (char*) args[0];
|
||||
size_t t, len = strlen(str), i = 0, s = 0;
|
||||
uint8_t elem_bytes[elem_sz];
|
||||
/* Ignore '0x' prefix, if present */
|
||||
if (len >= 2 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
|
||||
len -= 2;
|
||||
str += 2;
|
||||
}
|
||||
for (t = 0; t < len && t < 8; ++t) {
|
||||
char c = str[t];
|
||||
uint8_t b;
|
||||
/* obtain value from character */
|
||||
switch (c) {
|
||||
case 'a' ... 'f': b = (c - 'a') + 10; break;
|
||||
case 'A' ... 'F': b = (c - 'A') + 10; break;
|
||||
case '0' ... '9': b = c - '0'; break;
|
||||
default:
|
||||
fprintf(stderr, "Invalid value for `setbg` request: '%s'\n", (char*) args[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
elem_bytes[s] = b;
|
||||
if (s >= elem_sz - 1) { /* advance to next element */
|
||||
uint32_t e = 0; /* component storage */
|
||||
/* mask storage with input data */
|
||||
for (size_t v = 0; v < elem_sz; ++v) {
|
||||
e |= (uint32_t) elem_bytes[v] << (((elem_sz - 1) - v) * 4);
|
||||
}
|
||||
/* convert to [0, 1] as floating point value */
|
||||
*results[i] = (float) e / (float) ((1 << (elem_sz * 4)) - 1);
|
||||
printf("[DEBUG] component %d value: %d (float: %f)\n", i, e, *results[i]);
|
||||
s = 0;
|
||||
++i;
|
||||
} else { /* advance character */
|
||||
++s;
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
{
|
||||
.name = "setbgf", .fmt = "ffff",
|
||||
.handler = RHANDLER(name, args, {
|
||||
gl->clear_color.r = *(float*) args[0];
|
||||
gl->clear_color.g = *(float*) args[1];
|
||||
gl->clear_color.b = *(float*) args[2];
|
||||
gl->clear_color.a = *(float*) args[3];
|
||||
})
|
||||
},
|
||||
{
|
||||
.name = "mod", .fmt = "s",
|
||||
.handler = RHANDLER(name, args, {
|
||||
@@ -1002,8 +1070,6 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
size_t m_len = strlen(module);
|
||||
size_t bsz = d_len + m_len + 2;
|
||||
@@ -1156,6 +1222,8 @@ struct renderer* rd_new(const char** paths, const char* entry, const char* force
|
||||
|
||||
glfwShowWindow(gl->w);
|
||||
|
||||
glClearColor(gl->clear_color.r, gl->clear_color.g, gl->clear_color.b, gl->clear_color.a);
|
||||
|
||||
if (xwintype) {
|
||||
xwin_settype(r, xwintype);
|
||||
free(xwintype);
|
||||
@@ -1281,15 +1349,15 @@ void rd_update(struct renderer* r, float* lb, float* rb, size_t bsz, bool modifi
|
||||
static bool setup = false;
|
||||
/* Shader to flip texture and override alpha channel */
|
||||
static const char* frag_shader =
|
||||
"uniform sampler2D tex;" "\n"
|
||||
"uniform ivec2 screen;" "\n"
|
||||
"out vec4 fragment;" "\n"
|
||||
"in vec4 gl_FragCoord;" "\n"
|
||||
"void main() {" "\n"
|
||||
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
|
||||
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
|
||||
" fragment.a = 1.0F;" "\n"
|
||||
"}" "\n";
|
||||
"uniform sampler2D tex;" "\n"
|
||||
"uniform ivec2 screen;" "\n"
|
||||
"out vec4 fragment;" "\n"
|
||||
"in vec4 gl_FragCoord;" "\n"
|
||||
"void main() {" "\n"
|
||||
" fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, " "\n"
|
||||
" (screen.y - gl_FragCoord.y) / screen.y));" "\n"
|
||||
" fragment.a = 1.0F;" "\n"
|
||||
"}" "\n";
|
||||
if (!setup) {
|
||||
bg_prog = shaderlink(shaderload(NULL, GL_VERTEX_SHADER, VERTEX_SHADER_SRC,
|
||||
NULL, NULL, 330, true, gl),
|
||||
|
||||
@@ -11,6 +11,7 @@ out vec4 fragment; /* output */
|
||||
void main() {
|
||||
fragment = texelFetch(tex, ivec2(gl_FragCoord.x, gl_FragCoord.y), 0);
|
||||
#if C_SMOOTH > 0
|
||||
#if USE_ALPHA
|
||||
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),
|
||||
@@ -27,4 +28,5 @@ void main() {
|
||||
fragment = avg;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ out vec4 fragment;
|
||||
|
||||
void main() {
|
||||
|
||||
#if XROOT > 0
|
||||
#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 = 0;
|
||||
#else
|
||||
@@ -47,7 +47,7 @@ void main() {
|
||||
float d = sqrt((dx * dx) + (dy * dy)); /* distance */
|
||||
if (d > C_RADIUS - (float(C_LINE) / 2.0F) && d < C_RADIUS + (float(C_LINE) / 2.0F)) {
|
||||
fragment = OUTLINE;
|
||||
#if XROOT > 0
|
||||
#if USE_ALPHA > 0
|
||||
fragment.a *= ((float(C_LINE) / 2.0F) - abs(d - C_RADIUS)) * C_ALIAS_FACTOR;
|
||||
#else
|
||||
return; /* return immediately if there is no alpha blending available */
|
||||
@@ -73,7 +73,7 @@ void main() {
|
||||
v *= AMPLIFY; /* amplify */
|
||||
#undef smooth_f
|
||||
/* offset to fragment distance from inner circle */
|
||||
#if XROOT > 0
|
||||
#if USE_ALPHA > 0
|
||||
#define ALIAS_FACTOR (((BAR_WIDTH / 2) - abs(ym)) * BAR_ALIAS_FACTOR)
|
||||
d -= C_RADIUS; /* start bar overlapping the inner circle for blending */
|
||||
#else
|
||||
@@ -90,7 +90,7 @@ void main() {
|
||||
#else
|
||||
r = COLOR;
|
||||
#endif
|
||||
#if XROOT > 0
|
||||
#if USE_ALPHA > 0
|
||||
r.a *= ALIAS_FACTOR;
|
||||
#endif
|
||||
APPLY_FRAG(fragment, r);
|
||||
@@ -98,7 +98,7 @@ void main() {
|
||||
}
|
||||
#if BAR_OUTLINE_WIDTH > 0
|
||||
if (d <= v) {
|
||||
#if XROOT > 0
|
||||
#if USE_ALPHA > 0
|
||||
vec4 r = BAR_OUTLINE;
|
||||
r.a *= ALIAS_FACTOR;
|
||||
APPLY_FRAG(fragment, r);
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
/* GLFW window geometry (x, y, width, height) */
|
||||
#request setgeometry 0 0 400 600
|
||||
|
||||
/* Window background color (RGB format).
|
||||
Only works with `setopacity "none"` */
|
||||
#request setbg 3C3C3C
|
||||
|
||||
/* (X11 only) EWMH Window type. Possible values are:
|
||||
|
||||
"desktop", "dock", "toolbar", "menu",
|
||||
|
||||
22
xwin.c
22
xwin.c
@@ -16,6 +16,11 @@
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
/* Hack to make GLFW 3.1 headers work with GLava. We don't use the context APIs from GLFW, but
|
||||
the old headers require one of them to be selected for exposure in glfw3native.h. */
|
||||
#if (GLFW_VERSION_MAJOR == 3 && GLFW_VERSION_MINOR <= 1)
|
||||
#define GLFW_EXPOSE_NATIVE_GLX
|
||||
#endif
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <GLFW/glfw3native.h>
|
||||
@@ -24,8 +29,12 @@
|
||||
#include "xwin.h"
|
||||
|
||||
bool xwin_should_render(void) {
|
||||
bool ret = true;
|
||||
Display* d = XOpenDisplay(0);
|
||||
bool ret = true, should_close = false;
|
||||
Display* d = glfwGetX11Display();
|
||||
if (!d) {
|
||||
d = XOpenDisplay(0);
|
||||
should_close = true;
|
||||
}
|
||||
|
||||
Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true);
|
||||
Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true);
|
||||
@@ -58,7 +67,8 @@ bool xwin_should_render(void) {
|
||||
}
|
||||
}
|
||||
close:
|
||||
XCloseDisplay(d);
|
||||
if (should_close)
|
||||
XCloseDisplay(d);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -66,7 +76,7 @@ bool xwin_should_render(void) {
|
||||
-> "desktop", "dock", "toolbar", "menu", "utility", "splash", "dialog", "normal" */
|
||||
static void xwin_changeatom(struct renderer* rd, const char* type, const char* atom, const char* fmt, int mode) {
|
||||
Window w = glfwGetX11Window((GLFWwindow*) rd_get_impl_window(rd));
|
||||
Display* d = XOpenDisplay(0);
|
||||
Display* d = glfwGetX11Display();
|
||||
Atom wtype = XInternAtom(d, atom, false);
|
||||
size_t len = strlen(type), t;
|
||||
char formatted[len + 1];
|
||||
@@ -81,7 +91,6 @@ static void xwin_changeatom(struct renderer* rd, const char* type, const char* a
|
||||
snprintf(buf, sizeof(buf), fmt, formatted);
|
||||
Atom desk = XInternAtom(d, buf, false);
|
||||
XChangeProperty(d, w, wtype, XA_ATOM, 32, mode, (unsigned char*) &desk, 1);
|
||||
XCloseDisplay(d);
|
||||
}
|
||||
|
||||
void xwin_settype(struct renderer* rd, const char* type) {
|
||||
@@ -127,7 +136,7 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
|
||||
glfwGetFramebufferSize(gwin, &w, &h);
|
||||
glfwGetWindowPos(gwin, &x, &y);
|
||||
XColor c;
|
||||
Display* d = XOpenDisplay(0);
|
||||
Display* d = glfwGetX11Display();
|
||||
Pixmap p = get_pixmap(d, RootWindow(d, DefaultScreen(d)));
|
||||
|
||||
/* Obtain section of root pixmap using XShm */
|
||||
@@ -228,7 +237,6 @@ unsigned int xwin_copyglbg(struct renderer* rd, unsigned int tex) {
|
||||
shmctl(shminfo.shmid, IPC_RMID, NULL);
|
||||
|
||||
XDestroyImage(image);
|
||||
XCloseDisplay(d);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user