-
-
Notifications
You must be signed in to change notification settings - Fork 59
Home
GLava installs with two configuration folders that it can use, the install path (usually /etc/xdg
), and the user configuration path (usually ~/.config/glava
). By default, the user configuration folder is empty (or does not exist), and can be created properly by running glava --copy-config
. This will create the following structure in your user config directory:
Name | Type | Source or target path | Description |
---|---|---|---|
rc.glsl |
copied file | /etc/xdg/rc.glsl |
Global user config |
smooth_parameters.glsl |
copied file | /etc/xdg/smooth_parameters.glsl |
Smoothing options |
[module].glsl |
copied file | /etc/xdg/glava/module.glsl |
Module-specific options |
[module] |
symlink | /etc/xdg/glava/module |
Module source files |
Module sources are intentionally symlinked to prevent duplicating larger source files and reflect future changes to GLava's modules. This means you do not need to copy over new configuration files when you update GLava.
The provided modules for GLava are as follows:
Name | Description |
---|---|
bars |
cava style vertical bar visualizer |
radial |
Similar to bars , except bars are drawn around a circle |
graph |
Draw a vertical, solid graph of the fft output data |
wave |
Draw the raw audio wave received from PulseAudio |
circle |
Draw a circle-style visualizer, where the radius is the visualizer amplitude |
Documentation for global settings and modules can be found in the extensive comments in rc.glsl
, smooth_parameters.glsl
, and other *.glsl
config files that belong to their respective modules. If the file does not reside within a subdirectory, then it is considered to be for user configuration.
The configuration format may be confusing at first. This is because the format is in GLSL, the same language that is used to write the shaders that belong to GLava's modules. User parameters are usually set with #request
directives (requesting some action from GLava's C code), or with #define
(parameters for GLSL shaders). Nearly every behaviour in GLava is configurable via these directives with the following format:
#request [Name of request] [Request parameters]...
#define [Name of macro variable] [Macro contents]
Note that the contents of a variable created with #define
copies all text after the variable name, including spaces, into value. Some module configurations use simple GLSL code within #define
macros to create interesting effects (ie. color gradients).
Colors are represented in floating point value, meaning all four components (RGBA) are between 0.0
and 1.0
in a vec4
type. However, GLava allows more traditional color constants using #RRGGBBAA
which is predominantly used throughout the module configs.
Because we are working in GLSL, we have access to some handy functions for producing various effects with our colors. For example a gradient can be defined with:
#define COLOR mix(#3366b2, #a0a0b2, clamp(d / 80, 0, 1))
Where d
is a module-defined variable that corresponds to baseline fragment distance, mix
simply interpolates between the two input colors and clamp(..., 0, 1)
limits our inputs between 0 and 1. This is very similar to how bars.glsl
defines its default gradient.
Other functions of interest are dot
, cross
, ceil
, floor
, distance
, and trigonometric functions (ie. asin
, cosh
, or tan
).
Most modules omit transparency bits on constant hexadecimal colors, meaning they default to FF
or 1.0
(fully opaque). In most cases you can simply tack on transparency bits to the end of these definitions and compute on these values in the same way since the underlying type is equivalent.
GLava offers the ability to stream simple types to it at runtime via the --pipe
feature:
--pipe[=BIND[:TYPE]] binds a value to be read from stdin. The input my be read using
`@name` or `@name:default` syntax within shader sources.
A stream of inputs (each overriding the previous) must be
assigned with the `name = value` syntax and separated by
newline ('\n') characters.
BIND
can be any valid name, and TYPE
must be a valid GLSL type. This type defaults to vec4
, which is sufficient for most purposes as this is the underlying type used to represent colors.
Bindings can be used for most #define
variables in a fairly flexible manner (eg. in bars.glsl
):
#define COLOR @fg:#3C3CA8
This would expand to a generated uniform if --pipe=fg
were passed, otherwise it would evaluate to #3C3CA8
. This syntax normally only reads a single symbol after the colon (:
), but you can pass more complex expressions by using brackets: @name:(...)
. You can also nest binding syntax:
#define BACKGROUND @bg:(@fg:#3C3CA8 * 0.4)
Data is easily provided while running:
# writing to stdin
$ glava --pipe=fg
fg = #FF0000
# piping to stdin
$ echo "fg = #FF0000" | glava --pipe=fg
For a more advanced example, here's how to stream unique colors from the currently playing song in MPD:
$ while true; do echo fg = \#`mpc | head -n 1 | md5sum | cut -c 1-6`; sleep 0.35; done | glava --pipe=fg
GLava is a simple C program that sets up the nessecary OpenGL and Xlib code for sets of 2D fragment shaders (executed per pixel) to be ran. It adds special #request
directives that GLava itself processes in order for the shader source code request data to be sent to shader uniforms, and to perform some processing on said uniforms before it is sent to the GPU. All of the actual rendering is done in fragment shaders (which are compiled at runtime), thus giving you a lot of freedom on how you would like to display visualizer data.
The general process for making your own module is:
-
Create a folder in either your
~/.config/glava
directory for the module, or the shader install path (usually `/etc/xdg/glava) and symlink to the installed module in your local config. -
Create a
1.frag
file inside the folder. This is the first fragment shader executed for the module, and is the final (output) shader if you do not add any additional shaders. If you choose to add more shaders, the output of1.frag
can be requested from2.frag
with#request uniform "prev" <name>
, where<name>
is the name of thesampler2D
uniform you want to bind it to. -
Optionally create a configuration file for your module (in the root install/config directory), to allow users to set various parameters for your shader. Include it via:
/* If installing the module in /etx/xdg/glava, include the system configuration first: */ #include "@mymoduleconfig.glsl" /* Then include the user config, overriding any system values. */ #include ":mymoduleconfig.glsl"
The
:
specifies the root config load path, and the@
always refers to the installation directory.
To obtain nicely processed audio visualizer data in a sampler1D
, use the following code:
/* We need the texture size for smoothing */
#request uniform "audio_sz" audio_sz
uniform int audio_sz;
#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;
#include ":util/smooth.glsl"
And then obtain your smoothed data using the smooth_audio
function with one of the audio textures like so:
float result = smooth_audio(audio_l, audio_sz, index, 0.025);
Where index
is a value between 0.0F
(inclusive) and 1.0F
(exclusive). The final parameter can be increased or decreased for more or less smoothing. smooth_audio
is a simple kernel smoother that uses parameters from :smooth_parameters.glsl
.
The output of a shader pass is always stored in fragment
, and the entry point is always main
:
out vec4 fragment;
void main() {
fragment = #ff0000;
}