summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2021-09-26 18:09:14 -0700
committerVito Caputo <vcaputo@pengaru.com>2021-09-26 18:13:28 -0700
commit1b26c9e5b8fcda39ecffbe56e3dd8d90c9b6fe4a (patch)
treeec343bb97325ac6ebb5f574e8408bf951acdd8a5
parentaac6a90282480d6dfed7876586b582094371b934 (diff)
pig: implement rudimentary GNU Rocket integrationHEADmaster
This creates GNU Rocket tracks for all active float uniforms in the loaded shaders. Simply start a GNU Rocket editor listening on the standard port @ localhost, and the tracks should appear. The automatic setting of these uniforms becomes overriden by the track values, which can be annoying.
-rw-r--r--Makefile.am2
-rw-r--r--README18
-rw-r--r--configure.ac3
-rw-r--r--librocket/Makefile.am2
-rw-r--r--src/Makefile.am4
-rw-r--r--src/pig.c132
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
diff --git a/README b/README
index b8d21aa..777a25c 100644
--- a/README
+++ b/README
@@ -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
diff --git a/src/pig.c b/src/pig.c
index 6161b8d..ece968c 100644
--- a/src/pig.c
+++ b/src/pig.c
@@ -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;
}
© 2021 All Rights Reserved