summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/pig.c132
2 files changed, 134 insertions, 2 deletions
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;
}
© All Rights Reserved