initial commit
This commit is contained in:
38
Makefile
Normal file
38
Makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
src = $(wildcard *.c)
|
||||
obj = $(src:.c=.o)
|
||||
|
||||
LDFLAGS = -lpulse -lpulse-simple -pthread -lOpenGL -lglfw -ldl -lm -lX11
|
||||
|
||||
PYTHON = python
|
||||
|
||||
GLAD_INSTALL_DIR = glad
|
||||
GLAD_SRCFILE = ./glad/src/glad.c
|
||||
GLAD_ARGS_RELEASE = --generator=c --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic
|
||||
GLAD_ARGS_DEBUG = --generator=c-debug --extensions=GL_EXT_framebuffer_multisample,GL_EXT_texture_filter_anisotropic
|
||||
CFLAGS_COMMON = -I glad/include
|
||||
|
||||
CFLAGS_USE = $(CFLAGS_COMMON) $(CFLAGS)
|
||||
|
||||
all: glad glava
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS_USE) -o $@ -c $<
|
||||
|
||||
glava: $(obj)
|
||||
$(CC) -o $@ $^ glad.o $(LDFLAGS)
|
||||
|
||||
.PHONY: glad
|
||||
glad:
|
||||
cd $(GLAD_INSTALL_DIR) && $(PYTHON) -m glad $(GLAD_ARGS_RELEASE) --out-path=.
|
||||
$(CC) $(CFLAGS_USE) -o glad.o $(GLAD_SRCFILE) -c
|
||||
|
||||
.PHONY: glad-debug
|
||||
glad-debug:
|
||||
cd $(GLAD_INSTALL_DIR) && $(PYTHON) -m glad $(GLAD_ARGS_DEBUG) --out-path=.
|
||||
$(CC) $(CFLAGS_USE) -o glad.o $(GLAD_SRCFILE) -c
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f $(obj) glava glad.o
|
||||
|
||||
CFLAGS = -ggdb
|
||||
85
fifo.c
Normal file
85
fifo.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "fifo.h"
|
||||
|
||||
//input: FIFO
|
||||
void* input_fifo(void* data)
|
||||
{
|
||||
struct audio_data *audio = (struct audio_data *)data;
|
||||
int fd;
|
||||
int n = 0;
|
||||
signed char buf[1024];
|
||||
int tempr, templ, lo;
|
||||
int q, i;
|
||||
int t = 0;
|
||||
int size = 1024;
|
||||
int bytes = 0;
|
||||
int flags;
|
||||
struct timespec req = { .tv_sec = 0, .tv_nsec = 10000000 };
|
||||
|
||||
fd = open(audio->source, O_RDONLY);
|
||||
flags = fcntl(fd, F_GETFL, 0);
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
while (1) {
|
||||
|
||||
bytes = read(fd, buf, sizeof(buf));
|
||||
|
||||
if (bytes == -1) { //if no bytes read sleep 10ms and zero shared buffer
|
||||
nanosleep (&req, NULL);
|
||||
t++;
|
||||
if (t > 10) {
|
||||
for (i = 0; i < 2048; i++)audio->audio_out_l[i] = 0;
|
||||
for (i = 0; i < 2048; i++)audio->audio_out_r[i] = 0;
|
||||
t = 0;
|
||||
}
|
||||
} else { //if bytes read go ahead
|
||||
t = 0;
|
||||
for (q = 0; q < (size / 4); q++) {
|
||||
|
||||
tempr = ( buf[ 4 * q + 3] << 2);
|
||||
|
||||
lo = ( buf[4 * q + 2] >> 6);
|
||||
if (lo < 0)lo = abs(lo) + 1;
|
||||
if (tempr >= 0)tempr = tempr + lo;
|
||||
else tempr = tempr - lo;
|
||||
|
||||
templ = ( buf[ 4 * q + 1] << 2);
|
||||
|
||||
lo = ( buf[ 4 * q] >> 6);
|
||||
if (lo < 0)lo = abs(lo) + 1;
|
||||
if (templ >= 0)templ = templ + lo;
|
||||
else templ = templ - lo;
|
||||
|
||||
if (audio->channels == 1) audio->audio_out_l[n] = (tempr +
|
||||
templ) /
|
||||
2;
|
||||
|
||||
|
||||
//stereo storing channels in buffer
|
||||
if (audio->channels == 2) {
|
||||
audio->audio_out_l[n] = templ;
|
||||
audio->audio_out_r[n] = tempr;
|
||||
}
|
||||
|
||||
n++;
|
||||
if (n == 2048 - 1)n = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (audio->terminate == 1) {
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
17
fifo.h
Normal file
17
fifo.h
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct audio_data {
|
||||
volatile float* audio_out_r;
|
||||
volatile float* audio_out_l;
|
||||
bool modified;
|
||||
size_t audio_buf_sz, sample_sz;
|
||||
int format;
|
||||
unsigned int rate;
|
||||
char *source; // pulse source
|
||||
int channels;
|
||||
int terminate; // shared variable used to terminate audio thread
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
void* input_fifo(void* data);
|
||||
83
glava.c
Normal file
83
glava.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "fifo.h"
|
||||
#include "pulse_input.h"
|
||||
#include "render.h"
|
||||
#include "xwincheck.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char* audio_source = argc >= 2 ? argv[1] : NULL; //TODO: change
|
||||
|
||||
renderer* r = rd_new(0, 0, 400, 500, "shaders");
|
||||
|
||||
float b0[r->bufsize_request], b1[r->bufsize_request];
|
||||
size_t t;
|
||||
for (t = 0; t < r->bufsize_request; ++t) {
|
||||
b0[t] = 0.0F;
|
||||
b1[t] = 0.0F;
|
||||
}
|
||||
|
||||
struct audio_data audio = {
|
||||
.source = ({
|
||||
char* src = NULL;
|
||||
if (audio_source && strcmp(audio_source, "auto") != 0) {
|
||||
src = malloc(1 + strlen(audio_source));
|
||||
strcpy(src, audio_source);
|
||||
}
|
||||
src;
|
||||
}),
|
||||
.rate = (unsigned int) r->rate_request,
|
||||
.format = -1,
|
||||
.terminate = 0,
|
||||
.channels = 2,
|
||||
.audio_out_r = b0,
|
||||
.audio_out_l = b1,
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
||||
.audio_buf_sz = r->bufsize_request,
|
||||
.sample_sz = r->samplesize_request,
|
||||
.modified = false
|
||||
};
|
||||
if (!audio.source) {
|
||||
get_pulse_default_sink(&audio);
|
||||
printf("Using default PulseAudio sink: %s\n", audio.source);
|
||||
}
|
||||
|
||||
pthread_t thread;
|
||||
int thread_id = pthread_create(&thread, NULL, input_pulse, (void*) &audio);
|
||||
|
||||
float lb[r->bufsize_request], rb[r->bufsize_request];
|
||||
while (r->alive) {
|
||||
|
||||
bool modified; /* if the audio buffer has been updated by the streaming thread */
|
||||
|
||||
/* lock the audio mutex and read our data */
|
||||
pthread_mutex_lock(&audio.mutex);
|
||||
modified = audio.modified;
|
||||
if (modified) {
|
||||
/* create our own copies of the audio buffers, so the streaming thread can continue to append to it */
|
||||
memcpy(lb, (void*) audio.audio_out_l, r->bufsize_request * sizeof(float));
|
||||
memcpy(rb, (void*) audio.audio_out_r, r->bufsize_request * sizeof(float));
|
||||
audio.modified = false; /* set this flag to false until the next time we read */
|
||||
}
|
||||
pthread_mutex_unlock(&audio.mutex);
|
||||
|
||||
/* Only render if needed (ie. stop rendering when fullscreen windows are focused) */
|
||||
if (xwin_should_render()) {
|
||||
rd_update(r, lb, rb, r->bufsize_request, modified);
|
||||
} else {
|
||||
/* Sleep for 50ms and then attempt to render again */
|
||||
struct timespec tv = {
|
||||
.tv_sec = 0, .tv_nsec = 50 * 1000000
|
||||
};
|
||||
nanosleep(&tv, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
rd_destroy(r);
|
||||
}
|
||||
371
glsl_ext.c
Normal file
371
glsl_ext.c
Normal file
@@ -0,0 +1,371 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "glsl_ext.h"
|
||||
|
||||
struct sbuf {
|
||||
char* buf;
|
||||
size_t at; /* index of final null character */
|
||||
size_t bsize; /* actual buffer size */
|
||||
};
|
||||
|
||||
#define append(sbuf, str) n_append(sbuf, strlen(str), str)
|
||||
|
||||
static inline void expand_for(struct sbuf* sbuf, size_t len) {
|
||||
bool resize = false;
|
||||
while (len + 1 > sbuf->bsize - sbuf->at) {
|
||||
sbuf->bsize *= 2;
|
||||
resize = true;
|
||||
}
|
||||
if (resize)
|
||||
sbuf->buf = realloc(sbuf->buf, sbuf->bsize);
|
||||
}
|
||||
|
||||
/* append 'n' bytes from 'str' to the resizable buffer */
|
||||
static void n_append(struct sbuf* sbuf, size_t len, const char* str) {
|
||||
expand_for(sbuf, len);
|
||||
memcpy(sbuf->buf + sbuf->at, str, len);
|
||||
sbuf->at += len;
|
||||
sbuf->buf[sbuf->at] = '\0';
|
||||
}
|
||||
|
||||
#define s_append(sbuf, fmt, ...) se_append(sbuf, 64, fmt, __VA_ARGS__)
|
||||
|
||||
/* append the formatted string to the resizable buffer, where elen is extra space for formatted chars */
|
||||
static void se_append(struct sbuf* sbuf, size_t elen, const char* fmt, ...) {
|
||||
size_t space = strlen(fmt) + elen;
|
||||
expand_for(sbuf, space);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int written;
|
||||
if ((written = vsnprintf(sbuf->buf + sbuf->at, space, fmt, args)) < 0)
|
||||
abort();
|
||||
sbuf->at += space;
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define parse_error(line, f, fmt, ...) \
|
||||
fprintf(stderr, "[%s:%d] " fmt "\n", f, (int) line, __VA_ARGS__); \
|
||||
abort()
|
||||
|
||||
#define parse_error_s(line, f, s) \
|
||||
fprintf(stderr, "[%s:%d] " s "\n", f, (int) line); \
|
||||
abort()
|
||||
|
||||
struct schar {
|
||||
char* buf;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
/* handle raw arguments for #include and #request directives */
|
||||
/* NOTE: munmap needs to be called on the result */
|
||||
static struct schar directive(struct glsl_ext* ext, char** args,
|
||||
size_t args_sz, bool include,
|
||||
size_t line, const char* f) {
|
||||
if (include) {
|
||||
if (args_sz == 0) {
|
||||
parse_error_s(line, f, "No arguments provided to #include directive!");
|
||||
}
|
||||
char* target = args[0];
|
||||
|
||||
char path[strlen(ext->cd) + strlen(target) + 2];
|
||||
snprintf(path, sizeof(path) / sizeof(char), "%s/%s", ext->cd, target);
|
||||
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
parse_error(line, f, "failed to load GLSL shader source specified by #include directive '%s': %s\n",
|
||||
path, strerror(errno));
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
fstat(fd, &st);
|
||||
|
||||
char* map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (!map) {
|
||||
parse_error(line, f, "failed to map GLSL shader source specified by #include directive '%s': %s\n",
|
||||
path, strerror(errno));
|
||||
}
|
||||
|
||||
struct glsl_ext next = {
|
||||
.source = map,
|
||||
.source_len = st.st_size,
|
||||
.cd = ext->cd,
|
||||
.handlers = ext->handlers
|
||||
};
|
||||
|
||||
/* recursively process */
|
||||
ext_process(&next, target);
|
||||
|
||||
struct schar ret = {
|
||||
.buf = next.processed,
|
||||
.sz = next.p_len
|
||||
};
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
|
||||
if (args_sz > 0) {
|
||||
char* request = args[0];
|
||||
|
||||
struct request_handler* handler;
|
||||
bool found = false;
|
||||
size_t t, i;
|
||||
for (t = 0; (handler = &ext->handlers[t])->name != NULL; ++t) {
|
||||
if(!strcmp(handler->name, request)) {
|
||||
found = true;
|
||||
void** processed_args = malloc(strlen(handler->fmt) * sizeof(void*));
|
||||
|
||||
char c;
|
||||
size_t i;
|
||||
for (i = 0; (c = handler->fmt[i]) != '\0'; ++i) {
|
||||
if (args_sz <= 1 + i) {
|
||||
parse_error(line, f,
|
||||
"failed to execute request '%s': expected format '%s'\n",
|
||||
request, handler->fmt);
|
||||
}
|
||||
char* raw = args[1 + i];
|
||||
switch (c) {
|
||||
case 'i':
|
||||
{
|
||||
int v = (int) strtol(raw, NULL, 0);
|
||||
processed_args[i] = malloc(sizeof(int));
|
||||
*(int*) processed_args[i] = v;
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
{
|
||||
float f = strtof(raw, NULL);
|
||||
processed_args[i] = malloc(sizeof(float));
|
||||
*(float*) processed_args[i] = f;
|
||||
break;
|
||||
}
|
||||
case 's': { *(char**) &processed_args[i] = raw; break; }
|
||||
case 'b':
|
||||
{
|
||||
bool v;
|
||||
if (!strcmp(raw, "true")) {
|
||||
v = true;
|
||||
} else if (!strcmp(raw, "false")) {
|
||||
v = false;
|
||||
} else if (strlen(raw) == 1) {
|
||||
switch (raw[0]) {
|
||||
case 't': { v = true; break; }
|
||||
case 'f': { v = false; break; }
|
||||
case '1': { v = true; break; }
|
||||
case '0': { v = false; break; }
|
||||
default:
|
||||
parse_error_s(line, f, "tried to parse invalid raw string into a boolean");
|
||||
}
|
||||
} else {
|
||||
parse_error_s(line, f, "tried to parse invalid raw string into a boolean");
|
||||
}
|
||||
processed_args[i] = malloc(sizeof(bool));
|
||||
*(bool*) processed_args[i] = v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler->handler(request, processed_args);
|
||||
|
||||
for (i = 0; (c = handler->fmt[i]) != '\0'; ++i)
|
||||
if (c != 's')
|
||||
free(processed_args[i]);
|
||||
free(processed_args);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
parse_error(line, f, "unknown request type '%s'", request);
|
||||
}
|
||||
}
|
||||
|
||||
struct schar ret = {
|
||||
.buf = NULL,
|
||||
.sz = 0
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* state machine parser */
|
||||
void ext_process(struct glsl_ext* ext, const char* f) {
|
||||
|
||||
#define LINE_START 0
|
||||
#define IGNORING 1
|
||||
#define MACRO 2
|
||||
#define REQUEST 3
|
||||
#define INCLUDE 4
|
||||
|
||||
struct sbuf sbuf = {
|
||||
.buf = malloc(256),
|
||||
.at = 0,
|
||||
.bsize = 256
|
||||
};
|
||||
|
||||
size_t source_len = ext->source_len;
|
||||
size_t t;
|
||||
char at;
|
||||
int state = LINE_START;
|
||||
size_t macro_start_idx, arg_start_idx;
|
||||
size_t line = 1;
|
||||
bool quoted = false, arg_start;
|
||||
char** args = NULL;
|
||||
size_t args_sz = 0;
|
||||
|
||||
for (t = 0; t <= source_len; ++t) {
|
||||
at = source_len == t ? '\0' : ext->source[t];
|
||||
if (at == '\n')
|
||||
++line;
|
||||
switch (state) {
|
||||
case LINE_START: /* processing start of line */
|
||||
{
|
||||
switch (at) {
|
||||
case '#': {
|
||||
macro_start_idx = t;
|
||||
state = MACRO;
|
||||
continue; }
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
goto copy;
|
||||
default: {
|
||||
state = IGNORING;
|
||||
goto copy; }
|
||||
}
|
||||
}
|
||||
case IGNORING: /* copying GLSL source or unrelated preprocessor syntax */
|
||||
if (at == '\n') {
|
||||
state = LINE_START;
|
||||
}
|
||||
goto copy;
|
||||
case MACRO: /* processing start of macro */
|
||||
{
|
||||
switch (at) {
|
||||
case '\n':
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\0':
|
||||
{
|
||||
/* end parsing directive */
|
||||
if (!strncmp("#request", &ext->source[macro_start_idx], t - macro_start_idx)
|
||||
|| !strncmp("#REQUEST", &ext->source[macro_start_idx], t - macro_start_idx)) {
|
||||
state = REQUEST;
|
||||
goto prepare_arg_parse;
|
||||
} else if (!strncmp("#include", &ext->source[macro_start_idx], t - macro_start_idx)
|
||||
|| !strncmp("#INCLUDE", &ext->source[macro_start_idx], t - macro_start_idx)) {
|
||||
state = INCLUDE;
|
||||
goto prepare_arg_parse;
|
||||
} else {
|
||||
n_append(&sbuf, t - macro_start_idx, &ext->source[macro_start_idx]);
|
||||
state = IGNORING;
|
||||
goto copy;
|
||||
}
|
||||
prepare_arg_parse:
|
||||
{
|
||||
arg_start_idx = t + 1;
|
||||
arg_start = true;
|
||||
args = malloc(sizeof(char*));
|
||||
args_sz = 0;
|
||||
*args = NULL;
|
||||
}
|
||||
}
|
||||
case 'a' ... 'z':
|
||||
case 'A' ... 'Z':
|
||||
continue;
|
||||
default:
|
||||
/* invalid char, malformed! */
|
||||
parse_error(line, f, "Unexpected character '%c' while parsing GLSL directive", at);
|
||||
}
|
||||
}
|
||||
/* scope-violating macro to copy the result of the currently parsed argument */
|
||||
#define copy_arg(end) \
|
||||
do { if (end - arg_start_idx > 0) { \
|
||||
++args_sz; \
|
||||
args = realloc(args, sizeof(char*) * args_sz); \
|
||||
args[args_sz - 1] = malloc((end - arg_start_idx) + 1); \
|
||||
memcpy(args[args_sz - 1], &ext->source[arg_start_idx], end - arg_start_idx); \
|
||||
args[args_sz - 1][end - arg_start_idx] = '\0'; \
|
||||
} } while (0)
|
||||
case REQUEST:
|
||||
case INCLUDE:
|
||||
{
|
||||
switch (at) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\n':
|
||||
case '\0':
|
||||
if (!quoted) {
|
||||
/* end arg */
|
||||
copy_arg(t);
|
||||
arg_start = true;
|
||||
arg_start_idx = t + 1;
|
||||
} else arg_start = false;
|
||||
|
||||
if (at == '\n') {
|
||||
/* end directive */
|
||||
size_t a;
|
||||
printf("[DEBUG] handling request/include for %d args\n", args_sz);
|
||||
for (a = 0; a < args_sz; ++a) {
|
||||
printf("[DEBUG] [%d]: \"%s\"\n", a, args[a]);
|
||||
}
|
||||
struct schar r = directive(ext, args, args_sz, state == INCLUDE, line, f);
|
||||
for (a = 0; a < args_sz; ++a) {
|
||||
printf("[DEBUG POST] [%d]: \"%s\"\n", a, args[a]);
|
||||
}
|
||||
for (a = 0; a < args_sz; ++a) {
|
||||
free(args[a]);
|
||||
}
|
||||
args_sz = 0;
|
||||
/* if something was returned (ie. included file), paste the results */
|
||||
if (r.buf) {
|
||||
n_append(&sbuf, r.sz, r.buf);
|
||||
append(&sbuf, "\n");
|
||||
}
|
||||
munmap(r.buf, r.sz);
|
||||
state = LINE_START;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (quoted) {
|
||||
/* end arg */
|
||||
copy_arg(t);
|
||||
quoted = false;
|
||||
arg_start = true;
|
||||
arg_start_idx = t + 1;
|
||||
} else if (arg_start) {
|
||||
++arg_start_idx;
|
||||
quoted = true;
|
||||
} else arg_start = false;
|
||||
break;
|
||||
default:
|
||||
arg_start = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
copy:
|
||||
if (at != '\0')
|
||||
n_append(&sbuf, 1, &at);
|
||||
}
|
||||
ext->processed = sbuf.buf;
|
||||
ext->p_len = sbuf.at;
|
||||
|
||||
if (args)
|
||||
free(args);
|
||||
}
|
||||
void ext_free(struct glsl_ext* ext) {
|
||||
free(ext->processed);
|
||||
}
|
||||
36
glsl_ext.h
Normal file
36
glsl_ext.h
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
#define RHANDLER(name, args, ...) \
|
||||
({ void _handler(const char* name, void** args) __VA_ARGS__ _handler; })
|
||||
|
||||
struct request_handler {
|
||||
const char* name;
|
||||
/*
|
||||
handler format:
|
||||
'i' - signed integer (void* -> int*)
|
||||
'f' - float (void* -> float*)
|
||||
's' - string (void* -> const char*)
|
||||
'b' - bool (void* -> bool*)
|
||||
|
||||
example:
|
||||
|
||||
.fmt = "sii" // takes a string, and then two integers
|
||||
.fmt = "ffb" // takes two floats, then a boolean
|
||||
*/
|
||||
const char* fmt;
|
||||
void (*handler)(const char* name, void** args);
|
||||
};
|
||||
|
||||
struct glsl_ext {
|
||||
char* processed; /* OUT: null terminated processed source */
|
||||
size_t p_len; /* OUT: length of processed buffer, excluding null char */
|
||||
const char* source; /* IN: raw data passed via ext_process */
|
||||
size_t source_len; /* IN: raw source len */
|
||||
const char* cd; /* IN: current directory */
|
||||
|
||||
/* IN: NULL (where the last element's 'name' member is NULL) terminated
|
||||
array of request handlers */
|
||||
struct request_handler* handlers;
|
||||
};
|
||||
|
||||
void ext_process(struct glsl_ext* ext, const char* f);
|
||||
void ext_free (struct glsl_ext* ext);
|
||||
205
pulse_input.c
Normal file
205
pulse_input.c
Normal file
@@ -0,0 +1,205 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
#include "fifo.h"
|
||||
|
||||
static pa_mainloop *m_pulseaudio_mainloop;
|
||||
|
||||
static void cb(__attribute__((unused)) pa_context *pulseaudio_context,
|
||||
const pa_server_info *i,
|
||||
void *userdata) {
|
||||
|
||||
//getting default sink name
|
||||
struct audio_data *audio = (struct audio_data *)userdata;
|
||||
audio->source = malloc(sizeof(char) * 1024);
|
||||
|
||||
strcpy(audio->source,i->default_sink_name);
|
||||
|
||||
//appending .monitor suffix
|
||||
audio->source = strcat(audio->source, ".monitor");
|
||||
|
||||
//quiting mainloop
|
||||
pa_context_disconnect(pulseaudio_context);
|
||||
pa_context_unref(pulseaudio_context);
|
||||
pa_mainloop_quit(m_pulseaudio_mainloop, 0);
|
||||
pa_mainloop_free(m_pulseaudio_mainloop);
|
||||
}
|
||||
|
||||
|
||||
static void pulseaudio_context_state_callback(pa_context *pulseaudio_context,
|
||||
void *userdata) {
|
||||
|
||||
//make sure loop is ready
|
||||
switch (pa_context_get_state(pulseaudio_context))
|
||||
{
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
//printf("UNCONNECTED\n");
|
||||
break;
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
//printf("CONNECTING\n");
|
||||
break;
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
//printf("AUTHORIZING\n");
|
||||
break;
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
//printf("SETTING_NAME\n");
|
||||
break;
|
||||
case PA_CONTEXT_READY://extract default sink name
|
||||
//printf("READY\n");
|
||||
pa_operation_unref(pa_context_get_server_info(
|
||||
pulseaudio_context, cb, userdata));
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
printf("failed to connect to pulseaudio server\n");
|
||||
exit(EXIT_FAILURE);
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
//printf("PulseAudio context terminated!\n");
|
||||
pa_mainloop_quit(m_pulseaudio_mainloop, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void get_pulse_default_sink(struct audio_data* audio) {
|
||||
|
||||
pa_mainloop_api *mainloop_api;
|
||||
pa_context *pulseaudio_context;
|
||||
int ret;
|
||||
|
||||
// Create a mainloop API and connection to the default server
|
||||
m_pulseaudio_mainloop = pa_mainloop_new();
|
||||
|
||||
mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop);
|
||||
pulseaudio_context = pa_context_new(mainloop_api, "cava device list");
|
||||
|
||||
|
||||
// This function connects to the pulse server
|
||||
pa_context_connect(pulseaudio_context, NULL, PA_CONTEXT_NOFLAGS,
|
||||
NULL);
|
||||
|
||||
|
||||
// printf("connecting to server\n");
|
||||
|
||||
//This function defines a callback so the server will tell us its state.
|
||||
pa_context_set_state_callback(pulseaudio_context,
|
||||
pulseaudio_context_state_callback,
|
||||
(void*)audio);
|
||||
|
||||
|
||||
|
||||
// starting a mainloop to get default sink
|
||||
|
||||
// starting with one non blokng iteration in case pulseaudio is not able to run
|
||||
if (!(ret = pa_mainloop_iterate(m_pulseaudio_mainloop, 0, &ret))){
|
||||
printf("Could not open pulseaudio mainloop to "
|
||||
"find default device name: %d\n"
|
||||
"check if pulseaudio is running\n",
|
||||
ret);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pa_mainloop_run(m_pulseaudio_mainloop, &ret);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Sample format for native 'float' type */
|
||||
#ifndef __STDC_IEC_559__
|
||||
#error "IEC 60559 standard unsupported on target system"
|
||||
#endif
|
||||
|
||||
#ifdef __ORDER_LITTLE_ENDIAN__
|
||||
#define FSAMPLE_FORMAT PA_SAMPLE_FLOAT32LE
|
||||
#elif __ORDER_BIG_ENDIAN__
|
||||
#define FSAMPLE_FORMAT PA_SAMPLE_FLOAT32BE
|
||||
#else
|
||||
#error "Unsupported float format (requires 32 bit IEEE (little or big endian) floating point support)"
|
||||
#endif
|
||||
|
||||
void* input_pulse(void* data) {
|
||||
struct audio_data *audio = (struct audio_data *)data;
|
||||
int i, n;
|
||||
size_t ssz = audio->sample_sz;
|
||||
float buf[ssz / 2];
|
||||
|
||||
/* The sample type to use */
|
||||
const pa_sample_spec ss = {
|
||||
.format = FSAMPLE_FORMAT,
|
||||
.rate = audio->rate,
|
||||
.channels = 2
|
||||
};
|
||||
const pa_buffer_attr pb = {
|
||||
.maxlength = ssz * 2,
|
||||
.fragsize = ssz
|
||||
};
|
||||
|
||||
pa_simple *s = NULL;
|
||||
int error;
|
||||
|
||||
if (!(s = pa_simple_new(NULL, "glava", PA_STREAM_RECORD,
|
||||
audio->source, "audio for glava",
|
||||
&ss, NULL, &pb, &error))) {
|
||||
fprintf(stderr, __FILE__ ": Could not open pulseaudio source: %s, %s. "
|
||||
"To find a list of your pulseaudio sources run 'pacmd list-sources'\n",
|
||||
audio->source, pa_strerror(error));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
float* bl = (float*) audio->audio_out_l;
|
||||
float* br = (float*) audio->audio_out_r;
|
||||
size_t fsz = audio->audio_buf_sz;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Record some data ... */
|
||||
if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
|
||||
fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&audio->mutex);
|
||||
|
||||
/* progressing the audio buffer, making space for new write */
|
||||
|
||||
memmove(bl, &bl[ssz / 4], (fsz - (ssz / 4)) * sizeof(float));
|
||||
memmove(br, &br[ssz / 4], (fsz - (ssz / 4)) * sizeof(float));
|
||||
|
||||
// sorting out channelss
|
||||
|
||||
for (n = 0, i = 0; i < ssz / 2; i += 2) {
|
||||
|
||||
// size_t idx = (i / 2) + (at * (BUFSIZE / 2));
|
||||
|
||||
int idx = (fsz - (ssz / 4)) + n;
|
||||
|
||||
if (audio->channels == 1) bl[idx] = (buf[i] + buf[i + 1]) / 2;
|
||||
|
||||
// stereo storing channels in buffer
|
||||
if (audio->channels == 2) {
|
||||
bl[idx] = buf[i];
|
||||
br[idx] = buf[i + 1];
|
||||
}
|
||||
++n;
|
||||
}
|
||||
audio->modified = true;
|
||||
|
||||
pthread_mutex_unlock(&audio->mutex);
|
||||
|
||||
if (audio->terminate == 1) {
|
||||
pa_simple_free(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
3
pulse_input.h
Normal file
3
pulse_input.h
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
void get_pulse_default_sink(struct audio_data* audio);
|
||||
void* input_pulse(void* data);
|
||||
12
render.h
Normal file
12
render.h
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
struct gl_data;
|
||||
|
||||
typedef struct renderer {
|
||||
bool alive;
|
||||
size_t bufsize_request, rate_request, samplesize_request;
|
||||
struct gl_data* gl;
|
||||
} renderer;
|
||||
|
||||
struct renderer* rd_new(int x, int y, int w, int h, const char* shader_path);
|
||||
void rd_update(struct renderer*, float* lb, float* rb, size_t bsz, bool modified);
|
||||
void rd_destroy(struct renderer*);
|
||||
82
shaders/graph/1.frag
Normal file
82
shaders/graph/1.frag
Normal file
@@ -0,0 +1,82 @@
|
||||
|
||||
layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
|
||||
#request uniform "screen" screen
|
||||
uniform ivec2 screen; /* screen dimensions */
|
||||
|
||||
#request uniform "audio_sz" audio_sz
|
||||
uniform int audio_sz;
|
||||
|
||||
#request setavgframes 4
|
||||
#request setavgwindow true
|
||||
// #request interpolate true
|
||||
|
||||
#request uniform "audio_l" audio_l
|
||||
#request transform audio_l "window"
|
||||
#request transform audio_l "fft"
|
||||
#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 "avg"
|
||||
uniform sampler1D audio_r;
|
||||
|
||||
out vec4 fragment;
|
||||
|
||||
#include "settings.glsl"
|
||||
|
||||
#define CUT 0.5
|
||||
#define SAMPLE_RANGE 0.2
|
||||
#define SAMPLE_AMT 22
|
||||
|
||||
#define WSCALE 11
|
||||
#define VSCALE 6000
|
||||
|
||||
#define DIRECTION 1
|
||||
|
||||
#define RCOL_OFF (gl_FragCoord.x / 3000)
|
||||
#define LCOL_OFF ((screen.x - gl_FragCoord.x) / 3000)
|
||||
#define COLOR vec4(vec3(0.3 + RCOL_OFF, 0.3, 0.3 + LCOL_OFF) + (gl_FragCoord.y / 170), 1)
|
||||
|
||||
#if DIRECTION < 0
|
||||
#define LEFT_IDX (gl_FragCoord.x)
|
||||
#define RIGHT_IDX (-gl_FragCoord.x + screen.x)
|
||||
#else
|
||||
#define LEFT_IDX (half_w - gl_FragCoord.x)
|
||||
#define RIGHT_IDX (gl_FragCoord.x - half_w)
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
float half_w = (screen.x / 2);
|
||||
if (gl_FragCoord.x < half_w) {
|
||||
float s = 0, r;
|
||||
int t;
|
||||
for (t = -SAMPLE_AMT; t <= SAMPLE_AMT; ++t) {
|
||||
s += (texture(audio_l, log((LEFT_IDX + (t * SAMPLE_RANGE)) / (half_w)) / WSCALE).r);
|
||||
}
|
||||
s /= float(SAMPLE_AMT * 2) + 1;
|
||||
s *= VSCALE;
|
||||
|
||||
if (gl_FragCoord.y + 1.5 <= s) {
|
||||
fragment = COLOR;
|
||||
} else {
|
||||
fragment = vec4(0, 0, 0, 0);
|
||||
}
|
||||
} else {
|
||||
float s = 0, r;
|
||||
int t;
|
||||
for (t = -SAMPLE_AMT; t <= SAMPLE_AMT; ++t) {
|
||||
s += (texture(audio_r, log((RIGHT_IDX + (t * SAMPLE_RANGE)) / (half_w)) / WSCALE).r);
|
||||
}
|
||||
s /= float(SAMPLE_AMT * 2) + 1;
|
||||
s *= VSCALE;
|
||||
|
||||
if (gl_FragCoord.y + 1.5 <= s) {
|
||||
fragment = COLOR;
|
||||
} else {
|
||||
fragment = vec4(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
shaders/graph/2.frag
Normal file
28
shaders/graph/2.frag
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
|
||||
#request uniform "prev" tex
|
||||
uniform sampler2D tex; /* screen texture */
|
||||
#request uniform "screen" screen
|
||||
uniform ivec2 screen; /* screen dimensions */
|
||||
|
||||
out vec4 fragment; /* output */
|
||||
|
||||
void main() {
|
||||
fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, gl_FragCoord.y / screen.y));
|
||||
|
||||
float a0 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
float a1 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a2 = texture(tex, vec2((gl_FragCoord.x + 0) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a3 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
|
||||
float a4 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
float a5 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a6 = texture(tex, vec2((gl_FragCoord.x - 0) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a7 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
|
||||
float avg = (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) / 8.0;
|
||||
if (gl_FragCoord.y > 1) {
|
||||
fragment *= avg;
|
||||
}
|
||||
}
|
||||
28
shaders/graph/3.frag.old
Normal file
28
shaders/graph/3.frag.old
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
|
||||
#request uniform "screen" screen
|
||||
#request uniform "prev" tex
|
||||
|
||||
uniform sampler2D tex; /* screen texture */
|
||||
uniform ivec2 screen; /* screen dimensions */
|
||||
|
||||
out vec4 fragment; /* output */
|
||||
|
||||
void main() {
|
||||
fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, gl_FragCoord.y / screen.y));
|
||||
|
||||
float a0 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
float a1 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a2 = texture(tex, vec2((gl_FragCoord.x + 0) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a3 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
|
||||
float a4 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
float a5 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a6 = texture(tex, vec2((gl_FragCoord.x - 0) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a7 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
|
||||
float avg = (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) / 8.0;
|
||||
|
||||
if (gl_FragCoord.y > 1) fragment *= avg;
|
||||
}
|
||||
4
shaders/graph/settings.glsl
Normal file
4
shaders/graph/settings.glsl
Normal file
@@ -0,0 +1,4 @@
|
||||
#define MIN_THICKNESS 1
|
||||
#define MAX_THICKNESS 12
|
||||
#define BASE_COLOR vec4(0.7, 0.2, 0.45, 1)
|
||||
#define AMPLIFY 500
|
||||
74
shaders/rc.glsl
Normal file
74
shaders/rc.glsl
Normal file
@@ -0,0 +1,74 @@
|
||||
|
||||
/* The module to use. A module is a set of shaders used to produce
|
||||
the visualizer. The structure for a module is the following:
|
||||
|
||||
module_name [directory]
|
||||
1.frag [file: fragment shader],
|
||||
2.frag [file: fragment shader],
|
||||
...
|
||||
|
||||
Shaders are loaded in numerical order, starting at '1.frag',
|
||||
continuing indefinitely. The results of each shader (except
|
||||
for the final pass) is given to the next shader in the list
|
||||
as a 2D sampler.
|
||||
|
||||
See documentation for more details. */
|
||||
#request mod graph
|
||||
|
||||
/* GLFW window hints */
|
||||
#request setfloating true
|
||||
#request setdecorated true
|
||||
#request setfocused true
|
||||
#request setmaximized false
|
||||
|
||||
/* GLFW window title */
|
||||
#request settitle "GLava"
|
||||
|
||||
/* GLFW buffer swap interval (vsync), set to '0' to prevent
|
||||
waiting for refresh, '1' (or more) to wait for the specified
|
||||
amount of frames. */
|
||||
#request setswap 1
|
||||
|
||||
/* Frame limiter, set to the frames per second (FPS) desired or
|
||||
simple set to zero (or lower) to disable the frame limiter. */
|
||||
#request setframerate 0
|
||||
|
||||
/* Enable/disable printing framerate every second */
|
||||
#request setprintframes true
|
||||
|
||||
/* Audio buffer size to be used for processing and shaders.
|
||||
Increasing this value can have the effect of adding 'gravity'
|
||||
to FFT output, as the audio signal will remain in the buffer
|
||||
longer.
|
||||
|
||||
This value has a _massive_ effect on FFT performance and
|
||||
quality for some modules. */
|
||||
#request setbufsize 4096
|
||||
|
||||
/* Scale down the audio buffer before any operations are
|
||||
performed on the data. Higher values are faster.
|
||||
|
||||
This value can affect the output of various transformations,
|
||||
since it applies (crude) averaging to the data when shrinking
|
||||
the buffer. It is reccommended to use `setsamplerate` and
|
||||
`setsamplesize` to improve performance or accuracy instead. */
|
||||
#request setbufscale 1
|
||||
|
||||
/* PulseAudio sample rate. Lower values can add 'gravity' to
|
||||
FFT output, but can also reduce accuracy (especially for
|
||||
higher frequencies). Most hardware samples at 44100Hz.
|
||||
|
||||
Lower sample rates also can make output more choppy, when
|
||||
not using smoothing algorithms. */
|
||||
#request setsamplerate 22000
|
||||
|
||||
/* PulseAudio sample buffer size. Lower values result in more
|
||||
frequent audio updates (also depends on sampling rate), but
|
||||
will also require all transformations to be applied much
|
||||
more frequently (slower) */
|
||||
#request setsamplesize 1024
|
||||
|
||||
/* OpenGL context and GLSL shader versions, do not change unless
|
||||
you _absolutely_ know what you are doing. */
|
||||
#request setversion 3 3
|
||||
#request setshaderversion 330
|
||||
24
shaders/wave/1.frag
Normal file
24
shaders/wave/1.frag
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
|
||||
#request uniform "screen" screen
|
||||
uniform ivec2 screen; /* screen dimensions */
|
||||
|
||||
#request uniform "audio_l" audio_l
|
||||
#request transform audio_l "window"
|
||||
#request transform audio_l "wrange"
|
||||
uniform sampler1D audio_l;
|
||||
|
||||
out vec4 fragment;
|
||||
|
||||
#include "settings.glsl"
|
||||
|
||||
void main() {
|
||||
float os = ((texture(audio_l, gl_FragCoord.x / screen.x).r - 0.5) * AMPLIFY) + 0.5f;
|
||||
float s = (os + (screen.y * 0.5f) - 0.5f); /* center to screen coords */
|
||||
if (abs(s - gl_FragCoord.y) < clamp(abs(s - (screen.y * 0.5)) * 6, MIN_THICKNESS, MAX_THICKNESS)) {
|
||||
fragment = BASE_COLOR + (abs((screen.y * 0.5f) - s) * 0.02);
|
||||
} else {
|
||||
fragment = vec4(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
26
shaders/wave/2.frag
Normal file
26
shaders/wave/2.frag
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
layout(pixel_center_integer) in vec4 gl_FragCoord;
|
||||
|
||||
#request uniform "prev" tex
|
||||
uniform sampler2D tex; /* screen texture */
|
||||
#request uniform "screen" screen
|
||||
uniform ivec2 screen; /* screen dimensions */
|
||||
|
||||
out vec4 fragment; /* output */
|
||||
|
||||
void main() {
|
||||
fragment = texture(tex, vec2(gl_FragCoord.x / screen.x, gl_FragCoord.y / screen.y));
|
||||
|
||||
float a0 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
float a1 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a2 = texture(tex, vec2((gl_FragCoord.x + 0) / screen.x, (gl_FragCoord.y + 1) / screen.y)).a;
|
||||
float a3 = texture(tex, vec2((gl_FragCoord.x + 1) / screen.x, (gl_FragCoord.y + 0) / screen.y)).a;
|
||||
|
||||
float a4 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
float a5 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a6 = texture(tex, vec2((gl_FragCoord.x - 0) / screen.x, (gl_FragCoord.y - 1) / screen.y)).a;
|
||||
float a7 = texture(tex, vec2((gl_FragCoord.x - 1) / screen.x, (gl_FragCoord.y - 0) / screen.y)).a;
|
||||
|
||||
float avg = (a0 + a1 + a2 + a3 + a4 + a5 + a6 + a7) / 8.0;
|
||||
fragment *= avg;
|
||||
}
|
||||
4
shaders/wave/settings.glsl
Normal file
4
shaders/wave/settings.glsl
Normal file
@@ -0,0 +1,4 @@
|
||||
#define MIN_THICKNESS 1
|
||||
#define MAX_THICKNESS 10
|
||||
#define BASE_COLOR vec4(0.7, 0.2, 0.45, 1)
|
||||
#define AMPLIFY 500
|
||||
49
xwincheck.c
Normal file
49
xwincheck.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "xwincheck.h"
|
||||
|
||||
bool xwin_should_render(void) {
|
||||
bool ret = true;
|
||||
Display* d = XOpenDisplay(0);
|
||||
|
||||
Atom prop = XInternAtom(d, "_NET_ACTIVE_WINDOW", true);
|
||||
Atom fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", true);
|
||||
|
||||
Atom actual_type;
|
||||
int actual_format, t;
|
||||
unsigned long nitems, bytes_after;
|
||||
unsigned char* data;
|
||||
|
||||
int handler(Display* d, XErrorEvent* e) {}
|
||||
|
||||
XSetErrorHandler(handler); /* dummy error handler */
|
||||
|
||||
if (Success != XGetWindowProperty(d, RootWindow(d, 0), prop, 0, 1, false, AnyPropertyType,
|
||||
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
|
||||
goto close; /* if an error occurs here, the WM probably isn't EWMH compliant */
|
||||
}
|
||||
|
||||
Window active = ((Window*) data)[0];
|
||||
|
||||
prop = XInternAtom(d, "_NET_WM_STATE", true);
|
||||
|
||||
if (Success != XGetWindowProperty(d, active, prop, 0, LONG_MAX, false, AnyPropertyType,
|
||||
&actual_type, &actual_format, &nitems, &bytes_after, &data)) {
|
||||
goto close; /* some WMs are a little slow on creating _NET_WM_STATE, so errors may occur here */
|
||||
}
|
||||
for (t = 0; t < nitems; ++t) {
|
||||
if (fullscreen == ((Atom*) data)[t]) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
close:
|
||||
XCloseDisplay(d);
|
||||
return ret;
|
||||
}
|
||||
2
xwincheck.h
Normal file
2
xwincheck.h
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
bool xwin_should_render(void);
|
||||
Reference in New Issue
Block a user