diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | librocket/Makefile.am | 2 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/pig.c | 132 |
6 files changed, 150 insertions, 11 deletions
diff --git a/Makefile.am b/Makefile.am index fa18170..97f4617 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS = libplay libstage src +SUBDIRS = libplay librocket libstage src @@ -25,21 +25,25 @@ The set of uniforms pig wires up to the shaders are currently: uniform float rand; ``` -alpha: is always 1.f currently, this comes in by virtue of libstage integration. - when your shader is used as a shader-node w/libstage for instance, this - value would reflect stage_t.alpha, set via stage_set_alpha() or at stage_t - create time via stage_conf_t.alpha. +alpha: is always 1.f currently, this comes in by virtue of libstage + integration. When your shader is used as a shader-node w/libstage for + instance, this value would reflect stage_t.alpha, set via + stage_set_alpha() or at stage_t create time via stage_conf_t.alpha. time: time since program start in seconds.fraction T: 0.f - 1.f, cycled at 1HZ, intended for driving animation/effects. The time uniform can be considered absolute time, whereas this would be - relative to the shader's start, with a duration assumed of 1 second. - In the future there will probably be flags or something to set the - duration and range. + relative to the shader's start, with a duration assumed of 1 second. In + the future there will probably be flags or something to set the duration + and range. color: 0.f - 1.f, a random color, randomized every cycle of T seed: 0.f - 1.f, a random seed, randomized every cycle of T rand: 0.f - 1.f, a random number, randomized every run of the shader + +For externally controlling uniforms, GNU Rocket support has been integrated as +well. The current implementation exposes any float type uniforms as tracks for +external control. diff --git a/configure.ac b/configure.ac index 04830fc..7ff618a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_INIT([pig], [1.0], [vcaputo@pengaru.com]) -AM_INIT_AUTOMAKE([-Wall -Werror foreign]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) AC_CONFIG_MACRO_DIRS([m4]) AC_PROG_CC AM_PROG_CC_C_O @@ -21,6 +21,7 @@ CFLAGS="$GL_CFLAGS $CFLAGS" AC_CONFIG_FILES([ Makefile + librocket/Makefile src/Makefile ]) diff --git a/librocket/Makefile.am b/librocket/Makefile.am new file mode 100644 index 0000000..1a97dfa --- /dev/null +++ b/librocket/Makefile.am @@ -0,0 +1,2 @@ +noinst_LIBRARIES = librocket.a +librocket_a_SOURCES = rocket/lib/device.c rocket/lib/track.c diff --git a/src/Makefile.am b/src/Makefile.am index b6bf5f0..0f809dc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,5 +23,5 @@ pig_SOURCES = \ v3f.h \ v4f.h -pig_CPPFLAGS = -I@top_srcdir@/libstage/src -I@top_srcdir@/libplay/src -ffast-math -pig_LDADD = @top_builddir@/libstage/src/libstage.a @top_builddir@/libplay/src/libplay.a -lm -ldl +pig_CPPFLAGS = -I@top_srcdir@/libplay/src -I@top_srcdir@/librocket/rocket/lib -I@top_srcdir@/libstage/src -ffast-math +pig_LDADD = @top_builddir@/libplay/src/libplay.a @top_builddir@/librocket/librocket.a @top_builddir@/libstage/src/libstage.a -lm -ldl @@ -20,6 +20,7 @@ #include <play.h> #include <stage.h> +#include <sync.h> #include "checker-node.h" #include "clear-node.h" @@ -33,6 +34,9 @@ #define PIG_DEFAULT_WIDTH 640 #define PIG_DEFAULT_HEIGHT 480 +#define PIG_DEFAULT_BPM "125" +#define PIG_DEFAULT_RPB "8" + //#define PIG_WINDOW_FLAGS (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL) #define PIG_WINDOW_FLAGS (SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI) @@ -50,6 +54,17 @@ typedef struct pig_t { m4f_t transform; float seed; v3f_t color; + + struct { + int active; /* is sync/rocket active? */ + char *host; + struct sync_device *dev; + int beats_per_min; /* BPM (PIG_DEFAULT_BPM, PIG_ROCKET_BPM) */ + int rows_per_beat; /* rows per beat (PIG_DEFAULT_RPB, PIG_ROCKET_RPB) */ + int ms_per_row; /* (1000 * 60) / (beats_per_min * rows_per_beat) */ + int row; /* current row */ + int paused; + } sync; } pig_t; @@ -70,6 +85,85 @@ static void randomize_color(v3f_t *color) } +static void pig_sync_connect(pig_t *pig) +{ + if (sync_tcp_connect(pig->sync.dev, pig->sync.host, SYNC_DEFAULT_PORT)) + warn_if(pig->sync.active, + "unable to connect rocket sync to \"%s\"", pig->sync.host); + else + pig->sync.active = 1; +} + + +static void pig_sync_setup(pig_t *pig) +{ + char *sync_host = "localhost"; + char *dev_name = "pig"; + char *bpm = PIG_DEFAULT_BPM; + char *rpb = PIG_DEFAULT_RPB; + char *env; + + if ((env = getenv("PIG_ROCKET_HOST"))) + sync_host = env; + + if ((env = getenv("PIG_ROCKET_NAME"))) + dev_name = env; + + if ((env = getenv("PIG_ROCKET_BPM"))) + bpm = env; + + if ((env = getenv("PIG_ROCKET_RPB"))) + rpb = env; + + pig->sync.host = sync_host; + pig->sync.beats_per_min = atoi(bpm); + pig->sync.rows_per_beat = atoi(rpb); + pig->sync.ms_per_row = (60 * 1000) / (pig->sync.beats_per_min * pig->sync.rows_per_beat); + + fatal_if(!(pig->sync.dev = sync_create_device(dev_name)), + "unable to create rocket sync device \"%s\"", dev_name); + + pig_sync_connect(pig); +} + + +static void pig_sync_pause(void *ctxt, int flag) +{ + pig_t *pig = ctxt; + + pig->sync.paused = flag; +} + + +static void pig_sync_set_row(void *ctxt, int row) +{ + pig_t *pig = ctxt; + + pig->sync.row = row; +} + + +static int pig_sync_is_playing(void *ctxt) +{ + pig_t *pig = ctxt; + + return !pig->sync.paused; +} + + +static void pig_sync_update(pig_t *pig) +{ + static struct sync_cb pig_sync_cb = { + pig_sync_pause, + pig_sync_set_row, + pig_sync_is_playing, + }; + + if (sync_update(pig->sync.dev, pig->sync.row, &pig_sync_cb, pig)) + pig_sync_connect(pig); +} + + static void pig_uniforms_func(shader_t *shader, void *uniforms_ctxt, void *render_ctxt, unsigned n_uniforms, const int *uniforms, const m4f_t *model_x, float alpha) { play_t *play = render_ctxt; @@ -98,6 +192,20 @@ static void pig_uniforms_func(shader_t *shader, void *uniforms_ctxt, void *rende t1 = play_ticks_reset(play, PLAY_TICKS_TIMER1); } + if (pig->sync.active) { + /* another timer advances the rkt row */ + if (play_ticks_elapsed(play, PLAY_TICKS_TIMER3, pig->sync.ms_per_row)) { + if (!pig->sync.paused) + pig->sync.row++; + } + + pig_sync_update(pig); + } else { + /* periodically check if rkt editor is up */ + if (play_ticks_elapsed(play, PLAY_TICKS_TIMER3, 5000)) + pig_sync_connect(pig); + } + glUniform1f(uniforms[0], alpha); glUniformMatrix4fv(uniforms[1], 1, GL_FALSE, &model_x->m[0][0]); // TODO: make transform manipulatable glUniform3f(uniforms[2], pig->color.x, pig->color.y, pig->color.z); // TODO: make color configurable @@ -105,6 +213,28 @@ static void pig_uniforms_func(shader_t *shader, void *uniforms_ctxt, void *rende glUniform1f(uniforms[4], (float)t1 * .001f); glUniform1f(uniforms[5], pig->seed); glUniform1f(uniforms[6], r); + + if (pig->sync.active) { + /* look for float uniforms and ensure they're setup as sync tracks */ + /* TODO: we should probably handle int uniforms as well, just round what sync_get_val() gives back? */ + /* TODO: currently this is done as an override of the builtins, but it would be nice if sync_get_val() + * had some concept of being enabled; if the track is completely empty, sync_get_val() should give NaN + * or something, then we skip the glUniform1f() altogether, so an empty track could be used to leave + * the builtin value if applicable, while still allowing exposing those builtin uniforms to sequencing + * if desired. + */ + shader_active_uniforms(shader, &n_active_uniforms, &active_uniforms); + for (int i = 0; i < n_active_uniforms; i++) { + if (active_uniforms[i].type == GL_FLOAT) { + const struct sync_track *track = NULL; + + fatal_if(!(track = sync_get_track(pig->sync.dev, active_uniforms[i].name)), + "unable to get track"); + + glUniform1f(active_uniforms[i].location, sync_get_val(track, pig->sync.row)); + } + } + } } static const char *pig_uniforms[] = { @@ -258,6 +388,8 @@ static void * pig_init(play_t *play, int argc, char *argv[], unsigned flags) pig_uniforms ); + pig_sync_setup(pig); + return pig; } |