---
 src/Makefile            |    6 +-
 src/compiler/compiler.c |  793 +++++++++++++++++++++++++++++++++++++++++++++++
 src/compiler/compiler.h |  238 ++++++++++++++
 src/gui/guirender.c     |    2 +-
 src/gui/guirender.h     |    2 +-
 src/gui/patcheditor.c   |    2 +-
 src/gui/performance.c   |    2 +-
 src/renderer/compiler.c |  793 -----------------------------------------------
 src/renderer/compiler.h |  238 --------------
 src/renderer/eval.c     |    2 +-
 src/renderer/renderer.c |    2 +-
 src/renderer/renderer.h |    2 +-
 12 files changed, 1041 insertions(+), 1041 deletions(-)
 create mode 100644 src/compiler/compiler.c
 create mode 100644 src/compiler/compiler.h
 delete mode 100644 src/renderer/compiler.c
 delete mode 100644 src/renderer/compiler.h

diff --git a/src/Makefile b/src/Makefile
index c34a254..d96d028 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -53,10 +53,10 @@ ifeq ($(WITH_PDF),1)
 endif
 OBJS += $(addprefix translations/,french.o german.o)
 OBJS += $(addprefix renderer/,framedescriptor.o analyzer.o sampler.o \
-       compiler.o eval.o line.o wave.o font.o osd.o raster.o renderer.o \
+       eval.o line.o wave.o font.o osd.o raster.o renderer.o \
        videoinreconf.o)
-OBJS += $(addprefix compiler/,fpvm.o parser_helper.o scanner.o parser.o \
-       unique.o)
+OBJS += $(addprefix compiler/,compiler.o fpvm.o parser_helper.o scanner.o \
+       parser.o unique.o)
 
 POBJS=$(addprefix $(OBJDIR)/,$(OBJS))
 
diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c
new file mode 100644
index 0000000..d745d63
--- /dev/null
+++ b/src/compiler/compiler.c
@@ -0,0 +1,793 @@
+/*
+ * Flickernoise
+ * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include <fpvm/fpvm.h>
+#include <fpvm/schedulers.h>
+#include <fpvm/pfpu.h>
+
+#include "../pixbuf/pixbuf.h"
+#include "compiler.h"
+
+struct compiler_sc {
+       struct patch *p;
+
+       const char *basedir;
+       report_message rmc;
+       int linenr;
+
+       struct fpvm_fragment pfv_fragment;
+       struct fpvm_fragment pvv_fragment;
+};
+
+static void comp_report(struct compiler_sc *sc, const char *format, ...)
+{
+       va_list args;
+       int len;
+       char outbuf[512];
+
+       va_start(args, format);
+       len = vsnprintf(outbuf, sizeof(outbuf), format, args);
+       va_end(args);
+       sc->rmc(outbuf);
+}
+
+/****************************************************************/
+/* PER-FRAME VARIABLES                                          */
+/****************************************************************/
+
+static const char pfv_names[COMP_PFV_COUNT][FPVM_MAXSYMLEN] = {
+       "sx",
+       "sy",
+       "cx",
+       "cy",
+       "rot",
+       "dx",
+       "dy",
+       "zoom",
+       "decay",
+       "wave_mode",
+       "wave_scale",
+       "wave_additive",
+       "wave_usedots",
+       "wave_brighten",
+       "wave_thick",
+       "wave_x",
+       "wave_y",
+       "wave_r",
+       "wave_g",
+       "wave_b",
+       "wave_a",
+
+       "ob_size",
+       "ob_r",
+       "ob_g",
+       "ob_b",
+       "ob_a",
+       "ib_size",
+       "ib_r",
+       "ib_g",
+       "ib_b",
+       "ib_a",
+
+       "nMotionVectorsX",
+       "nMotionVectorsY",
+       "mv_dx",
+       "mv_dy",
+       "mv_l",
+       "mv_r",
+       "mv_g",
+       "mv_b",
+       "mv_a",
+
+       "bTexWrap",
+
+       "time",
+       "bass",
+       "mid",
+       "treb",
+       "bass_att",
+       "mid_att",
+       "treb_att",
+
+       "warp",
+       "fWarpAnimSpeed",
+       "fWarpScale",
+
+       "q1",
+       "q2",
+       "q3",
+       "q4",
+       "q5",
+       "q6",
+       "q7",
+       "q8",
+
+       "fVideoEchoAlpha",
+       "fVideoEchoZoom",
+       "nVideoEchoOrientation",
+
+       "dmx1",
+       "dmx2",
+       "dmx3",
+       "dmx4",
+       "dmx5",
+       "dmx6",
+       "dmx7",
+       "dmx8",
+
+       "idmx1",
+       "idmx2",
+       "idmx3",
+       "idmx4",
+       "idmx5",
+       "idmx6",
+       "idmx7",
+       "idmx8",
+
+       "osc1",
+       "osc2",
+       "osc3",
+       "osc4",
+       
+       "midi1",
+       "midi2",
+       "midi3",
+       "midi4",
+       "midi5",
+       "midi6",
+       "midi7",
+       "midi8",
+
+       "video_a",
+       
+       "image1_a",
+       "image1_x",
+       "image1_y",
+       "image1_zoom",
+       "image2_a",
+       "image2_x",
+       "image2_y",
+       "image2_zoom"
+};
+
+static int pfv_from_name(const char *name)
+{
+       int i;
+       
+       for(i=0;i<COMP_PFV_COUNT;i++) {
+               if(strcmp(pfv_names[i], name) == 0)
+                       return i;
+       }
+
+       if(strcmp(name, "fDecay") == 0) return pfv_decay;
+       if(strcmp(name, "nWaveMode") == 0) return pfv_wave_mode;
+       if(strcmp(name, "fWaveScale") == 0) return pfv_wave_scale;
+       if(strcmp(name, "bAdditiveWaves") == 0) return pfv_wave_additive;
+       if(strcmp(name, "bWaveDots") == 0) return pfv_wave_usedots;
+       if(strcmp(name, "bMaximizeWaveColor") == 0) return pfv_wave_brighten;
+       if(strcmp(name, "bWaveThick") == 0) return pfv_wave_thick;
+       if(strcmp(name, "fWaveAlpha") == 0) return pfv_wave_a;
+       return -1;
+}
+
+static void pfv_update_patch_requires(struct compiler_sc *sc, int pfv)
+{
+       if(pfv >= pfv_dmx1 && pfv <= pfv_idmx8)         sc->p->require |= 
REQUIRE_DMX;
+       if(pfv >= pfv_osc1 && pfv <= pfv_osc4)          sc->p->require |= 
REQUIRE_OSC;
+       if(pfv >= pfv_midi1 && pfv <= pfv_midi8)        sc->p->require |= 
REQUIRE_MIDI;
+       if(pfv == pfv_video_a)                          sc->p->require |= 
REQUIRE_VIDEO;
+}
+
+static void load_defaults(struct compiler_sc *sc)
+{
+       int i;
+
+       for(i=0;i<COMP_PFV_COUNT;i++)
+               sc->p->pfv_initial[i] = 0.0;
+       sc->p->pfv_initial[pfv_sx] = 1.0;
+       sc->p->pfv_initial[pfv_sy] = 1.0;
+       sc->p->pfv_initial[pfv_cx] = 0.5;
+       sc->p->pfv_initial[pfv_cy] = 0.5;
+       sc->p->pfv_initial[pfv_zoom] = 1.0;
+       sc->p->pfv_initial[pfv_decay] = 1.0;
+       sc->p->pfv_initial[pfv_wave_mode] = 1.0;
+       sc->p->pfv_initial[pfv_wave_scale] = 1.0;
+       sc->p->pfv_initial[pfv_wave_r] = 1.0;
+       sc->p->pfv_initial[pfv_wave_g] = 1.0;
+       sc->p->pfv_initial[pfv_wave_b] = 1.0;
+       sc->p->pfv_initial[pfv_wave_a] = 1.0;
+       sc->p->pfv_initial[pfv_wave_x] = 0.5;
+       sc->p->pfv_initial[pfv_wave_y] = 0.5;
+
+       sc->p->pfv_initial[pfv_mv_x] = 16.0;
+       sc->p->pfv_initial[pfv_mv_y] = 12.0;
+       sc->p->pfv_initial[pfv_mv_dx] = 0.02;
+       sc->p->pfv_initial[pfv_mv_dy] = 0.02;
+       sc->p->pfv_initial[pfv_mv_l] = 1.0;
+
+       sc->p->pfv_initial[pfv_warp_scale] = 1.0;
+       
+       sc->p->pfv_initial[pfv_video_echo_zoom] = 1.0;
+       
+       sc->p->pfv_initial[pfv_image1_x] = 0.5;
+       sc->p->pfv_initial[pfv_image1_y] = 0.5;
+       sc->p->pfv_initial[pfv_image1_zoom] = 1.0;
+       sc->p->pfv_initial[pfv_image2_x] = 0.5;
+       sc->p->pfv_initial[pfv_image2_y] = 0.5;
+       sc->p->pfv_initial[pfv_image2_zoom] = 1.0;
+}
+
+static void set_initial(struct compiler_sc *sc, int pfv, float x)
+{
+       sc->p->pfv_initial[pfv] = x;
+}
+
+static void initial_to_pfv(struct compiler_sc *sc, int pfv)
+{
+       int r;
+
+       r = sc->p->pfv_allocation[pfv];
+       if(r < 0) return;
+       sc->p->perframe_regs[r] = sc->p->pfv_initial[pfv];
+}
+
+static void all_initials_to_pfv(struct compiler_sc *sc)
+{
+       int i;
+       for(i=0;i<COMP_PFV_COUNT;i++)
+               initial_to_pfv(sc, i);
+}
+
+static void pfv_bind_callback(void *_sc, const char *sym, int reg)
+{
+       struct compiler_sc *sc = _sc;
+       int pfv;
+       
+       pfv = pfv_from_name(sym);
+       if(pfv >= 0) {
+               pfv_update_patch_requires(sc, pfv);
+               sc->p->pfv_allocation[pfv] = reg;
+       }
+}
+
+static bool init_pfv(struct compiler_sc *sc)
+{
+       int i;
+
+       fpvm_init(&sc->pfv_fragment, 0);
+       fpvm_set_bind_mode(&sc->pfv_fragment, FPVM_BIND_ALL);
+       for(i=0;i<COMP_PFV_COUNT;i++)
+               sc->p->pfv_allocation[i] = -1;
+       fpvm_set_bind_callback(&sc->pfv_fragment, pfv_bind_callback, sc);
+       return true;
+}
+
+static bool finalize_pfv(struct compiler_sc *sc)
+{
+       /* assign dummy values for output */
+       if(!fpvm_assign(&sc->pfv_fragment, "_Xo", "_Xi")) goto fail_fpvm;
+       if(!fpvm_assign(&sc->pfv_fragment, "_Yo", "_Yi")) goto fail_fpvm;
+       if(!fpvm_finalize(&sc->pfv_fragment)) goto fail_fpvm;
+       #ifdef COMP_DEBUG
+       printf("per-frame FPVM fragment:\n");
+       fpvm_dump(&sc->pfv_fragment);
+       #endif
+
+       return true;
+fail_fpvm:
+       comp_report(sc, "failed to finalize per-frame variables: %s", 
fpvm_get_last_error(&sc->pfv_fragment));
+       return false;
+}
+
+static bool schedule_pfv(struct compiler_sc *sc)
+{
+       sc->p->perframe_prog_length = fpvm_default_schedule(&sc->pfv_fragment,
+               (unsigned int *)sc->p->perframe_prog, (unsigned int 
*)sc->p->perframe_regs);
+       if(sc->p->perframe_prog_length < 0) {
+               comp_report(sc, "per-frame VLIW scheduling failed");
+               return false;
+       }
+       all_initials_to_pfv(sc);
+       #ifdef COMP_DEBUG
+       printf("per-frame PFPU fragment:\n");
+       pfpu_dump(sc->p->perframe_prog, sc->p->perframe_prog_length);
+       #endif
+
+       return true;
+}
+
+static bool add_per_frame(struct compiler_sc *sc, char *dest, char *val)
+{
+       if(!fpvm_assign(&sc->pfv_fragment, dest, val)) {
+               comp_report(sc, "failed to add per-frame equation l. %d: %s", 
sc->linenr, fpvm_get_last_error(&sc->pfv_fragment));
+               return false;
+       }
+       return true;
+}
+
+/****************************************************************/
+/* PER-VERTEX VARIABLES                                         */
+/****************************************************************/
+
+static const char pvv_names[COMP_PVV_COUNT][FPVM_MAXSYMLEN] = {
+       /* System */
+       "_texsize",
+       "_hmeshsize",
+       "_vmeshsize",
+
+       /* MilkDrop */
+       "sx",
+       "sy",
+       "cx",
+       "cy",
+       "rot",
+       "dx",
+       "dy",
+       "zoom",
+
+       "time",
+       "bass",
+       "mid",
+       "treb",
+       "bass_att",
+       "mid_att",
+       "treb_att",
+
+       "warp",
+       "fWarpAnimSpeed",
+       "fWarpScale",
+
+       "q1",
+       "q2",
+       "q3",
+       "q4",
+       "q5",
+       "q6",
+       "q7",
+       "q8",
+
+       "idmx1",
+       "idmx2",
+       "idmx3",
+       "idmx4",
+       "idmx5",
+       "idmx6",
+       "idmx7",
+       "idmx8",
+       
+       "osc1",
+       "osc2",
+       "osc3",
+       "osc4",
+       
+       "midi1",
+       "midi2",
+       "midi3",
+       "midi4",
+       "midi5",
+       "midi6",
+       "midi7",
+       "midi8",
+};
+
+static int pvv_from_name(const char *name)
+{
+       int i;
+       
+       for(i=0;i<COMP_PVV_COUNT;i++) {
+               if(strcmp(pvv_names[i], name) == 0)
+                       return i;
+       }
+       return -1;
+}
+
+static void pvv_update_patch_requires(struct compiler_sc *sc, int pvv)
+{
+       if(pvv >= pvv_idmx1 && pvv <= pvv_idmx8)        sc->p->require |= 
REQUIRE_DMX;
+       if(pvv >= pvv_osc1 && pvv <= pvv_osc4)          sc->p->require |= 
REQUIRE_OSC;
+       if(pvv >= pvv_midi1 && pvv <= pvv_midi8)        sc->p->require |= 
REQUIRE_MIDI;
+}
+
+static void pvv_bind_callback(void *_sc, const char *sym, int reg)
+{
+       struct compiler_sc *sc = _sc;
+       int pvv;
+       
+       pvv = pvv_from_name(sym);
+       if(pvv >= 0) {
+               pvv_update_patch_requires(sc, pvv);
+               sc->p->pvv_allocation[pvv] = reg;
+       }
+}
+
+static bool init_pvv(struct compiler_sc *sc)
+{
+       int i;
+
+       fpvm_init(&sc->pvv_fragment, 1);
+       for(i=0;i<COMP_PVV_COUNT;i++)
+               sc->p->pvv_allocation[i] = -1;
+       fpvm_set_bind_callback(&sc->pvv_fragment, pvv_bind_callback, sc);
+       
+       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_SOURCE);
+       #define A(dest, val) if(!fpvm_assign(&sc->pvv_fragment, dest, val)) 
goto fail_assign
+       A("x", "i2f(_Xi)*_hmeshsize");
+       A("y", "i2f(_Yi)*_vmeshsize");
+       A("rad", "sqrt(sqr(x-0.5)+sqr(y-0.5))");
+       /* TODO: generate ang */
+       #undef A
+       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_ALL);
+       
+       return true;
+
+fail_assign:
+       comp_report(sc, "failed to add equation to per-vertex header: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
+       return false;
+}
+
+static int finalize_pvv(struct compiler_sc *sc)
+{
+       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_SOURCE);
+       
+       #define A(dest, val) if(!fpvm_assign(&sc->pvv_fragment, dest, val)) 
goto fail_assign
+
+       /* Zoom */
+       A("_invzoom", "1/zoom");
+       A("_xz", "_invzoom*(x-0.5)+0.5");
+       A("_yz", "_invzoom*(y-0.5)+0.5");
+
+       /* Scale */
+       A("_xs", "(_xz-cx)/sx+cx");
+       A("_ys", "(_yz-cy)/sy+cy");
+
+       /* Warp */
+       A("_warptime", "time*fWarpAnimSpeed");
+       A("_invwarpscale", "1/fWarpScale");
+       A("_f0", "11.68 + 4.0*cos(_warptime*1.413 + 10)");
+       A("_f1", "8.77 + 3.0*cos(_warptime*1.113 + 7)");
+       A("_f2", "10.54 + 3.0*cos(_warptime*1.233 + 3)");
+       A("_f3", "11.49 + 4.0*cos(_warptime*0.933 + 5)");
+       A("_ox2", "2*x-1");
+       A("_oy2", "2*y-1");
+       A("_xw", "_xs+warp*0.0035*("
+               "sin(_warptime*0.333+_invwarpscale*(_ox2*_f0-_oy2*_f3))"
+               "+cos(_warptime*0.753-_invwarpscale*(_ox2*_f1-_oy2*_f2)))");
+       A("_yw", "_ys+warp*0.0035*("
+               "cos(_warptime*0.375-_invwarpscale*(_ox2*_f2+_oy2*_f1))"
+               "+sin(_warptime*0.825+_invwarpscale*(_ox2*_f0+_oy2*_f3)))");
+
+       /* Rotate */
+       A("_cosr", "cos(rot)");
+       A("_sinr", "sin(0-rot)");
+       A("_u", "_xw-cx");
+       A("_v", "_yw-cy");
+       A("_xr", "_u*_cosr-_v*_sinr+cx");
+       A("_yr", "_u*_sinr+_v*_cosr+cy");
+
+       /* Translate */
+       A("_xd", "_xr-dx");
+       A("_yd", "_yr-dy");
+
+       /* Convert to framebuffer coordinates */
+       A("_Xo", "f2i(_xd*_texsize)");
+       A("_Yo", "f2i(_yd*_texsize)");
+
+       #undef A
+
+       if(!fpvm_finalize(&sc->pvv_fragment)) goto fail_finalize;
+       #ifdef COMP_DEBUG
+       printf("per-vertex FPVM fragment:\n");
+       fpvm_dump(&sc->pvv_fragment);
+       #endif
+
+       return true;
+fail_assign:
+       comp_report(sc, "failed to add equation to per-vertex footer: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
+       return false;
+fail_finalize:
+       comp_report(sc, "failed to finalize per-vertex variables: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
+       return false;
+}
+
+static bool schedule_pvv(struct compiler_sc *sc)
+{
+       sc->p->pervertex_prog_length = fpvm_default_schedule(&sc->pvv_fragment,
+               (unsigned int *)sc->p->pervertex_prog, (unsigned int 
*)sc->p->pervertex_regs);
+       if(sc->p->pervertex_prog_length < 0) {
+               comp_report(sc, "per-vertex VLIW scheduling failed");
+               return false;
+       }
+       #ifdef COMP_DEBUG
+       printf("per-vertex PFPU fragment:\n");
+       pfpu_dump(sc->p->pervertex_prog, sc->p->pervertex_prog_length);
+       #endif
+
+       return true;
+}
+
+static bool add_per_vertex(struct compiler_sc *sc, char *dest, char *val)
+{
+       if(!fpvm_assign(&sc->pvv_fragment, dest, val)) {
+               comp_report(sc, "failed to add per-vertex equation l. %d: 
%s\n", sc->linenr, fpvm_get_last_error(&sc->pvv_fragment));
+               return false;
+       }
+       return true;
+}
+
+/****************************************************************/
+/* PARSING                                                      */
+/****************************************************************/
+
+static bool process_equation(struct compiler_sc *sc, char *equation, bool 
per_vertex)
+{
+       char *c, *c2;
+
+       c = strchr(equation, '=');
+       if(!c) {
+               comp_report(sc, "error l.%d: malformed equation (%s)", 
sc->linenr, equation);
+               return false;
+       }
+       *c = 0;
+
+       if(*equation == 0) {
+               comp_report(sc, "error l.%d: missing lvalue", sc->linenr);
+               return false;
+       }
+       c2 = c - 1;
+       while((c2 > equation) && (*c2 == ' ')) *c2-- = 0;
+
+       c++;
+       while(*c == ' ') c++;
+
+       if(*equation == 0) {
+               comp_report(sc, "error l.%d: missing lvalue", sc->linenr);
+               return false;
+       }
+       if(*c == 0) {
+               comp_report(sc, "error l.%d: missing rvalue", sc->linenr);
+               return false;
+       }
+
+       if(per_vertex)
+               return add_per_vertex(sc, equation, c);
+       else
+               return add_per_frame(sc, equation, c);
+}
+
+static bool process_equations(struct compiler_sc *sc, char *equations, bool 
per_vertex)
+{
+       char *c;
+
+       while(*equations) {
+               c = strchr(equations, ';');
+               if(!c)
+                       return process_equation(sc, equations, per_vertex);
+               *c = 0;
+               if(!process_equation(sc, equations, per_vertex)) return false;
+               equations = c + 1;
+       }
+       return true;
+}
+
+static bool process_top_assign(struct compiler_sc *sc, char *left, char *right)
+{
+       int pfv;
+
+       while(*right == ' ') right++;
+       if(*right == 0) return true;
+       
+       if(strncmp(left, "imagefile", 9) == 0) {
+               int image_n;
+               char *totalname;
+               
+               image_n = atoi(left+9);
+               if((image_n < 1) || (image_n > IMAGE_COUNT)) {
+                       comp_report(sc, "warning l.%d: ignoring image with out 
of bounds number %d", sc->linenr, image_n);
+                       return true;
+               }
+               image_n--;
+               if(right[0] == '/')
+                       totalname = strdup(right);
+               else {
+                       totalname = malloc(strlen(sc->basedir) + strlen(right) 
+ 0);
+                       if(totalname == NULL) return true;
+                       strcpy(totalname, sc->basedir);
+                       strcat(totalname, right);
+               }
+               pixbuf_dec_ref(sc->p->images[image_n]);
+               sc->p->images[image_n] = pixbuf_get(totalname);
+               free(totalname);
+               return true;
+       }
+
+       pfv = pfv_from_name(left);
+       if(pfv >= 0) {
+               /* patch initial condition or global parameter */
+               pfv_update_patch_requires(sc, pfv);
+               set_initial(sc, pfv, atof(right));
+               return true;
+       }
+
+       if(strncmp(left, "per_frame", 9) == 0)
+               /* per-frame equation */
+               return process_equations(sc, right, false);
+
+       if((strncmp(left, "per_vertex", 10) == 0) || (strncmp(left, 
"per_pixel", 9) == 0))
+               /* per-vertex equation */
+               return process_equations(sc, right, true);
+
+       comp_report(sc, "warning l.%d: ignoring unknown parameter %s", 
sc->linenr, left);
+
+       return true;
+}
+
+static bool process_line(struct compiler_sc *sc, char *line)
+{
+       char *c;
+
+       while(*line == ' ') line++;
+       if(*line == 0) return true;
+       if(*line == '[') return true;
+
+       c = strstr(line, "//");
+       if(c) *c = 0;
+
+       c = line + strlen(line) - 1;
+       while((c >= line) && (*c == ' ')) *c-- = 0;
+       if(*line == 0) return true;
+
+       c = strchr(line, '=');
+       if(!c) {
+               comp_report(sc, "error l.%d: '=' expected", sc->linenr);
+               return false;
+       }
+       *c = 0;
+       return process_top_assign(sc, line, c+1);
+}
+
+static bool parse_patch(struct compiler_sc *sc, char *patch_code)
+{
+       char *eol;
+
+       while(*patch_code) {
+               sc->linenr++;
+               eol = strchr(patch_code, '\n');
+               if(!eol) {
+                       if(!process_line(sc, patch_code))
+                               return false;
+                       else
+                               return true;
+               }
+               *eol = 0;
+               if(*patch_code == 0) {
+                       patch_code = eol + 1;
+                       continue;
+               }
+               if(*(eol - 1) == '\r') *(eol - 1) = 0;
+               if(!process_line(sc, patch_code))
+                       return false;
+               patch_code = eol + 1;
+       }
+
+       return true;
+}
+
+struct patch *patch_compile(const char *basedir, const char *patch_code, 
report_message rmc)
+{
+       struct compiler_sc *sc;
+       struct patch *p;
+       char *patch_code_copy;
+       int i;
+
+       sc = malloc(sizeof(struct compiler_sc));
+       if(sc == NULL) {
+               rmc("Failed to allocate memory for compiler internal data");
+               return NULL;
+       }
+       p = sc->p = malloc(sizeof(struct patch));
+       if(sc->p == NULL) {
+               rmc("Failed to allocate memory for patch");
+               free(sc);
+               return NULL;
+       }
+       for(i=0;i<IMAGE_COUNT;i++)
+               sc->p->images[i] = NULL;
+       sc->p->require = 0;
+       sc->p->original = NULL;
+       sc->p->next = NULL;
+
+       sc->basedir = basedir;
+       sc->rmc = rmc;
+       sc->linenr = 0;
+
+       load_defaults(sc);
+       if(!init_pfv(sc)) goto fail;
+       if(!init_pvv(sc)) goto fail;
+
+       patch_code_copy = strdup(patch_code);
+       if(patch_code_copy == NULL) {
+               rmc("Failed to allocate memory for patch code");
+               goto fail;
+       }
+       if(!parse_patch(sc, patch_code_copy)) {
+               free(patch_code_copy);
+               goto fail;
+       }
+       free(patch_code_copy);
+
+       if(!finalize_pfv(sc)) goto fail;
+       if(!schedule_pfv(sc)) goto fail;
+       if(!finalize_pvv(sc)) goto fail;
+       if(!schedule_pvv(sc)) goto fail;
+
+       free(sc);
+       return p;
+fail:
+       free(sc->p);
+       free(sc);
+       return NULL;
+}
+
+struct patch *patch_compile_filename(const char *filename, const char 
*patch_code, report_message rmc)
+{
+       char *basedir;
+       char *c;
+       struct patch *p;
+       
+       basedir = strdup(filename);
+       if(basedir == NULL) return NULL;
+       c = strrchr(basedir, '/');
+       if(c != NULL) {
+               c++;
+               *c = 0;
+               p = patch_compile(basedir, patch_code, rmc);
+       } else
+               p = patch_compile("/", patch_code, rmc);
+       free(basedir);
+       return p;
+}
+
+struct patch *patch_copy(struct patch *p)
+{
+       struct patch *new_patch;
+       int i;
+       
+       new_patch = malloc(sizeof(struct patch));
+       assert(new_patch != NULL);
+       memcpy(new_patch, p, sizeof(struct patch));
+       new_patch->original = p;
+       new_patch->next = NULL;
+       for(i=0;i<IMAGE_COUNT;i++)
+               pixbuf_inc_ref(new_patch->images[i]);
+       return new_patch;
+}
+
+void patch_free(struct patch *p)
+{
+       int i;
+       
+       for(i=0;i<IMAGE_COUNT;i++)
+               pixbuf_dec_ref(p->images[i]);
+       free(p);
+}
diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h
new file mode 100644
index 0000000..46e62a1
--- /dev/null
+++ b/src/compiler/compiler.h
@@ -0,0 +1,238 @@
+/*
+ * Flickernoise
+ * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __COMPILER_H
+#define __COMPILER_H
+
+#include <rtems.h>
+#include <bsp/milkymist_pfpu.h>
+
+#include "../renderer/framedescriptor.h"
+#include "../pixbuf/pixbuf.h"
+
+enum {
+       pfv_sx = 0,
+       pfv_sy,
+       pfv_cx,
+       pfv_cy,
+       pfv_rot,
+       pfv_dx,
+       pfv_dy,
+       pfv_zoom,
+       pfv_decay,
+       pfv_wave_mode,
+       pfv_wave_scale,
+       pfv_wave_additive,
+       pfv_wave_usedots,
+       pfv_wave_brighten,
+       pfv_wave_thick,
+       pfv_wave_x,
+       pfv_wave_y,
+       pfv_wave_r,
+       pfv_wave_g,
+       pfv_wave_b,
+       pfv_wave_a,
+
+       pfv_ob_size,
+       pfv_ob_r,
+       pfv_ob_g,
+       pfv_ob_b,
+       pfv_ob_a,
+       pfv_ib_size,
+       pfv_ib_r,
+       pfv_ib_g,
+       pfv_ib_b,
+       pfv_ib_a,
+
+       pfv_mv_x,
+       pfv_mv_y,
+       pfv_mv_dx,
+       pfv_mv_dy,
+       pfv_mv_l,
+       pfv_mv_r,
+       pfv_mv_g,
+       pfv_mv_b,
+       pfv_mv_a,
+
+       pfv_tex_wrap,
+
+       pfv_time,
+       pfv_bass,
+       pfv_mid,
+       pfv_treb,
+       pfv_bass_att,
+       pfv_mid_att,
+       pfv_treb_att,
+
+       pfv_warp,
+       pfv_warp_anim_speed,
+       pfv_warp_scale,
+
+       pfv_q1,
+       pfv_q2,
+       pfv_q3,
+       pfv_q4,
+       pfv_q5,
+       pfv_q6,
+       pfv_q7,
+       pfv_q8,
+
+       pfv_video_echo_alpha,
+       pfv_video_echo_zoom,
+       pfv_video_echo_orientation,
+
+       pfv_dmx1,
+       pfv_dmx2,
+       pfv_dmx3,
+       pfv_dmx4,
+       pfv_dmx5,
+       pfv_dmx6,
+       pfv_dmx7,
+       pfv_dmx8,
+
+       pfv_idmx1,
+       pfv_idmx2,
+       pfv_idmx3,
+       pfv_idmx4,
+       pfv_idmx5,
+       pfv_idmx6,
+       pfv_idmx7,
+       pfv_idmx8,
+
+       pfv_osc1,
+       pfv_osc2,
+       pfv_osc3,
+       pfv_osc4,
+       
+       pfv_midi1,
+       pfv_midi2,
+       pfv_midi3,
+       pfv_midi4,
+       pfv_midi5,
+       pfv_midi6,
+       pfv_midi7,
+       pfv_midi8,
+
+       pfv_video_a,
+       
+       pfv_image1_a,
+       pfv_image1_x,
+       pfv_image1_y,
+       pfv_image1_zoom,
+       pfv_image2_a,
+       pfv_image2_x,
+       pfv_image2_y,
+       pfv_image2_zoom,
+
+       COMP_PFV_COUNT /* must be last */
+};
+
+enum {
+       /* System */
+       pvv_texsize,
+       pvv_hmeshsize,
+       pvv_vmeshsize,
+
+       /* MilkDrop */
+       pvv_sx,
+       pvv_sy,
+       pvv_cx,
+       pvv_cy,
+       pvv_rot,
+       pvv_dx,
+       pvv_dy,
+       pvv_zoom,
+
+       pvv_time,
+       pvv_bass,
+       pvv_mid,
+       pvv_treb,
+       pvv_bass_att,
+       pvv_mid_att,
+       pvv_treb_att,
+
+       pvv_warp,
+       pvv_warp_anim_speed,
+       pvv_warp_scale,
+
+       pvv_q1,
+       pvv_q2,
+       pvv_q3,
+       pvv_q4,
+       pvv_q5,
+       pvv_q6,
+       pvv_q7,
+       pvv_q8,
+
+       pvv_idmx1,
+       pvv_idmx2,
+       pvv_idmx3,
+       pvv_idmx4,
+       pvv_idmx5,
+       pvv_idmx6,
+       pvv_idmx7,
+       pvv_idmx8,
+
+       pvv_osc1,
+       pvv_osc2,
+       pvv_osc3,
+       pvv_osc4,
+       
+       pvv_midi1,
+       pvv_midi2,
+       pvv_midi3,
+       pvv_midi4,
+       pvv_midi5,
+       pvv_midi6,
+       pvv_midi7,
+       pvv_midi8,
+
+       COMP_PVV_COUNT /* must be last */
+};
+
+#define REQUIRE_DMX    (1 << 0)
+#define REQUIRE_OSC    (1 << 1)
+#define REQUIRE_MIDI   (1 << 2)
+#define REQUIRE_VIDEO  (1 << 3)
+
+struct patch {
+       /* per-frame */
+       struct pixbuf *images[IMAGE_COUNT];             /* < images used in 
this patch */
+       float pfv_initial[COMP_PFV_COUNT];              /* < patch initial 
conditions */
+       int pfv_allocation[COMP_PFV_COUNT];             /* < where per-frame 
variables are mapped in PFPU regf, -1 if unmapped */
+       int perframe_prog_length;                       /* < how many 
instructions in perframe_prog */
+       unsigned int perframe_prog[PFPU_PROGSIZE];      /* < PFPU per-frame 
microcode */
+       float perframe_regs[PFPU_REG_COUNT];            /* < PFPU initial 
per-frame regf */
+       /* per-vertex */
+       int pvv_allocation[COMP_PVV_COUNT];             /* < where per-vertex 
variables are mapped in PFPU regf, -1 if unmapped */
+       int pervertex_prog_length;                      /* < how many 
instructions in pervertex_prog */
+       unsigned int pervertex_prog[PFPU_PROGSIZE];     /* < PFPU per-vertex 
microcode */
+       float pervertex_regs[PFPU_REG_COUNT];           /* < PFPU initial 
per-vertex regf */
+       /* meta */
+       unsigned int require;                           /* < bitmask: dmx, osc, 
midi, video */
+       void *original;                                 /* < original patch 
(with initial register values) */
+       struct patch *next;                             /* < used when chaining 
patches in mashups */
+};
+
+typedef void (*report_message)(const char *);
+
+struct patch *patch_compile(const char *basedir, const char *patch_code, 
report_message rmc);
+struct patch *patch_compile_filename(const char *filename, const char 
*patch_code, report_message rmc);
+struct patch *patch_copy(struct patch *p);
+void patch_free(struct patch *p);
+
+#endif /* __COMPILER_H */
diff --git a/src/gui/guirender.c b/src/gui/guirender.c
index 0f1d63a..e91982a 100644
--- a/src/gui/guirender.c
+++ b/src/gui/guirender.c
@@ -25,7 +25,7 @@
 #include <mtkeycodes.h>
 #include <bsp/milkymist_video.h>
 
-#include "../renderer/compiler.h"
+#include "../compiler/compiler.h"
 #include "../renderer/renderer.h"
 #include "resmgr.h"
 #include "../fb.h"
diff --git a/src/gui/guirender.h b/src/gui/guirender.h
index f6f4b1f..13f5483 100644
--- a/src/gui/guirender.h
+++ b/src/gui/guirender.h
@@ -18,7 +18,7 @@
 #ifndef __GUIRENDER_H
 #define __GUIRENDER_H
 
-#include "../renderer/compiler.h"
+#include "../compiler/compiler.h"
 
 typedef void (*guirender_stop_callback)();
 
diff --git a/src/gui/patcheditor.c b/src/gui/patcheditor.c
index 049486f..7f232cc 100644
--- a/src/gui/patcheditor.c
+++ b/src/gui/patcheditor.c
@@ -27,7 +27,7 @@
 #include "filedialog.h"
 #include "patcheditor.h"
 #include "../renderer/framedescriptor.h"
-#include "../renderer/compiler.h"
+#include "../compiler/compiler.h"
 #include "../input.h"
 #include "guirender.h"
 
diff --git a/src/gui/performance.c b/src/gui/performance.c
index 8813d3a..da751d0 100644
--- a/src/gui/performance.c
+++ b/src/gui/performance.c
@@ -33,7 +33,7 @@
 #include "../fb.h"
 #include "messagebox.h"
 #include "../config.h"
-#include "../renderer/compiler.h"
+#include "../compiler/compiler.h"
 #include "../renderer/renderer.h"
 #include "guirender.h"
 #include "performance.h"
diff --git a/src/renderer/compiler.c b/src/renderer/compiler.c
deleted file mode 100644
index d745d63..0000000
--- a/src/renderer/compiler.c
+++ /dev/null
@@ -1,793 +0,0 @@
-/*
- * Flickernoise
- * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <fpvm/fpvm.h>
-#include <fpvm/schedulers.h>
-#include <fpvm/pfpu.h>
-
-#include "../pixbuf/pixbuf.h"
-#include "compiler.h"
-
-struct compiler_sc {
-       struct patch *p;
-
-       const char *basedir;
-       report_message rmc;
-       int linenr;
-
-       struct fpvm_fragment pfv_fragment;
-       struct fpvm_fragment pvv_fragment;
-};
-
-static void comp_report(struct compiler_sc *sc, const char *format, ...)
-{
-       va_list args;
-       int len;
-       char outbuf[512];
-
-       va_start(args, format);
-       len = vsnprintf(outbuf, sizeof(outbuf), format, args);
-       va_end(args);
-       sc->rmc(outbuf);
-}
-
-/****************************************************************/
-/* PER-FRAME VARIABLES                                          */
-/****************************************************************/
-
-static const char pfv_names[COMP_PFV_COUNT][FPVM_MAXSYMLEN] = {
-       "sx",
-       "sy",
-       "cx",
-       "cy",
-       "rot",
-       "dx",
-       "dy",
-       "zoom",
-       "decay",
-       "wave_mode",
-       "wave_scale",
-       "wave_additive",
-       "wave_usedots",
-       "wave_brighten",
-       "wave_thick",
-       "wave_x",
-       "wave_y",
-       "wave_r",
-       "wave_g",
-       "wave_b",
-       "wave_a",
-
-       "ob_size",
-       "ob_r",
-       "ob_g",
-       "ob_b",
-       "ob_a",
-       "ib_size",
-       "ib_r",
-       "ib_g",
-       "ib_b",
-       "ib_a",
-
-       "nMotionVectorsX",
-       "nMotionVectorsY",
-       "mv_dx",
-       "mv_dy",
-       "mv_l",
-       "mv_r",
-       "mv_g",
-       "mv_b",
-       "mv_a",
-
-       "bTexWrap",
-
-       "time",
-       "bass",
-       "mid",
-       "treb",
-       "bass_att",
-       "mid_att",
-       "treb_att",
-
-       "warp",
-       "fWarpAnimSpeed",
-       "fWarpScale",
-
-       "q1",
-       "q2",
-       "q3",
-       "q4",
-       "q5",
-       "q6",
-       "q7",
-       "q8",
-
-       "fVideoEchoAlpha",
-       "fVideoEchoZoom",
-       "nVideoEchoOrientation",
-
-       "dmx1",
-       "dmx2",
-       "dmx3",
-       "dmx4",
-       "dmx5",
-       "dmx6",
-       "dmx7",
-       "dmx8",
-
-       "idmx1",
-       "idmx2",
-       "idmx3",
-       "idmx4",
-       "idmx5",
-       "idmx6",
-       "idmx7",
-       "idmx8",
-
-       "osc1",
-       "osc2",
-       "osc3",
-       "osc4",
-       
-       "midi1",
-       "midi2",
-       "midi3",
-       "midi4",
-       "midi5",
-       "midi6",
-       "midi7",
-       "midi8",
-
-       "video_a",
-       
-       "image1_a",
-       "image1_x",
-       "image1_y",
-       "image1_zoom",
-       "image2_a",
-       "image2_x",
-       "image2_y",
-       "image2_zoom"
-};
-
-static int pfv_from_name(const char *name)
-{
-       int i;
-       
-       for(i=0;i<COMP_PFV_COUNT;i++) {
-               if(strcmp(pfv_names[i], name) == 0)
-                       return i;
-       }
-
-       if(strcmp(name, "fDecay") == 0) return pfv_decay;
-       if(strcmp(name, "nWaveMode") == 0) return pfv_wave_mode;
-       if(strcmp(name, "fWaveScale") == 0) return pfv_wave_scale;
-       if(strcmp(name, "bAdditiveWaves") == 0) return pfv_wave_additive;
-       if(strcmp(name, "bWaveDots") == 0) return pfv_wave_usedots;
-       if(strcmp(name, "bMaximizeWaveColor") == 0) return pfv_wave_brighten;
-       if(strcmp(name, "bWaveThick") == 0) return pfv_wave_thick;
-       if(strcmp(name, "fWaveAlpha") == 0) return pfv_wave_a;
-       return -1;
-}
-
-static void pfv_update_patch_requires(struct compiler_sc *sc, int pfv)
-{
-       if(pfv >= pfv_dmx1 && pfv <= pfv_idmx8)         sc->p->require |= 
REQUIRE_DMX;
-       if(pfv >= pfv_osc1 && pfv <= pfv_osc4)          sc->p->require |= 
REQUIRE_OSC;
-       if(pfv >= pfv_midi1 && pfv <= pfv_midi8)        sc->p->require |= 
REQUIRE_MIDI;
-       if(pfv == pfv_video_a)                          sc->p->require |= 
REQUIRE_VIDEO;
-}
-
-static void load_defaults(struct compiler_sc *sc)
-{
-       int i;
-
-       for(i=0;i<COMP_PFV_COUNT;i++)
-               sc->p->pfv_initial[i] = 0.0;
-       sc->p->pfv_initial[pfv_sx] = 1.0;
-       sc->p->pfv_initial[pfv_sy] = 1.0;
-       sc->p->pfv_initial[pfv_cx] = 0.5;
-       sc->p->pfv_initial[pfv_cy] = 0.5;
-       sc->p->pfv_initial[pfv_zoom] = 1.0;
-       sc->p->pfv_initial[pfv_decay] = 1.0;
-       sc->p->pfv_initial[pfv_wave_mode] = 1.0;
-       sc->p->pfv_initial[pfv_wave_scale] = 1.0;
-       sc->p->pfv_initial[pfv_wave_r] = 1.0;
-       sc->p->pfv_initial[pfv_wave_g] = 1.0;
-       sc->p->pfv_initial[pfv_wave_b] = 1.0;
-       sc->p->pfv_initial[pfv_wave_a] = 1.0;
-       sc->p->pfv_initial[pfv_wave_x] = 0.5;
-       sc->p->pfv_initial[pfv_wave_y] = 0.5;
-
-       sc->p->pfv_initial[pfv_mv_x] = 16.0;
-       sc->p->pfv_initial[pfv_mv_y] = 12.0;
-       sc->p->pfv_initial[pfv_mv_dx] = 0.02;
-       sc->p->pfv_initial[pfv_mv_dy] = 0.02;
-       sc->p->pfv_initial[pfv_mv_l] = 1.0;
-
-       sc->p->pfv_initial[pfv_warp_scale] = 1.0;
-       
-       sc->p->pfv_initial[pfv_video_echo_zoom] = 1.0;
-       
-       sc->p->pfv_initial[pfv_image1_x] = 0.5;
-       sc->p->pfv_initial[pfv_image1_y] = 0.5;
-       sc->p->pfv_initial[pfv_image1_zoom] = 1.0;
-       sc->p->pfv_initial[pfv_image2_x] = 0.5;
-       sc->p->pfv_initial[pfv_image2_y] = 0.5;
-       sc->p->pfv_initial[pfv_image2_zoom] = 1.0;
-}
-
-static void set_initial(struct compiler_sc *sc, int pfv, float x)
-{
-       sc->p->pfv_initial[pfv] = x;
-}
-
-static void initial_to_pfv(struct compiler_sc *sc, int pfv)
-{
-       int r;
-
-       r = sc->p->pfv_allocation[pfv];
-       if(r < 0) return;
-       sc->p->perframe_regs[r] = sc->p->pfv_initial[pfv];
-}
-
-static void all_initials_to_pfv(struct compiler_sc *sc)
-{
-       int i;
-       for(i=0;i<COMP_PFV_COUNT;i++)
-               initial_to_pfv(sc, i);
-}
-
-static void pfv_bind_callback(void *_sc, const char *sym, int reg)
-{
-       struct compiler_sc *sc = _sc;
-       int pfv;
-       
-       pfv = pfv_from_name(sym);
-       if(pfv >= 0) {
-               pfv_update_patch_requires(sc, pfv);
-               sc->p->pfv_allocation[pfv] = reg;
-       }
-}
-
-static bool init_pfv(struct compiler_sc *sc)
-{
-       int i;
-
-       fpvm_init(&sc->pfv_fragment, 0);
-       fpvm_set_bind_mode(&sc->pfv_fragment, FPVM_BIND_ALL);
-       for(i=0;i<COMP_PFV_COUNT;i++)
-               sc->p->pfv_allocation[i] = -1;
-       fpvm_set_bind_callback(&sc->pfv_fragment, pfv_bind_callback, sc);
-       return true;
-}
-
-static bool finalize_pfv(struct compiler_sc *sc)
-{
-       /* assign dummy values for output */
-       if(!fpvm_assign(&sc->pfv_fragment, "_Xo", "_Xi")) goto fail_fpvm;
-       if(!fpvm_assign(&sc->pfv_fragment, "_Yo", "_Yi")) goto fail_fpvm;
-       if(!fpvm_finalize(&sc->pfv_fragment)) goto fail_fpvm;
-       #ifdef COMP_DEBUG
-       printf("per-frame FPVM fragment:\n");
-       fpvm_dump(&sc->pfv_fragment);
-       #endif
-
-       return true;
-fail_fpvm:
-       comp_report(sc, "failed to finalize per-frame variables: %s", 
fpvm_get_last_error(&sc->pfv_fragment));
-       return false;
-}
-
-static bool schedule_pfv(struct compiler_sc *sc)
-{
-       sc->p->perframe_prog_length = fpvm_default_schedule(&sc->pfv_fragment,
-               (unsigned int *)sc->p->perframe_prog, (unsigned int 
*)sc->p->perframe_regs);
-       if(sc->p->perframe_prog_length < 0) {
-               comp_report(sc, "per-frame VLIW scheduling failed");
-               return false;
-       }
-       all_initials_to_pfv(sc);
-       #ifdef COMP_DEBUG
-       printf("per-frame PFPU fragment:\n");
-       pfpu_dump(sc->p->perframe_prog, sc->p->perframe_prog_length);
-       #endif
-
-       return true;
-}
-
-static bool add_per_frame(struct compiler_sc *sc, char *dest, char *val)
-{
-       if(!fpvm_assign(&sc->pfv_fragment, dest, val)) {
-               comp_report(sc, "failed to add per-frame equation l. %d: %s", 
sc->linenr, fpvm_get_last_error(&sc->pfv_fragment));
-               return false;
-       }
-       return true;
-}
-
-/****************************************************************/
-/* PER-VERTEX VARIABLES                                         */
-/****************************************************************/
-
-static const char pvv_names[COMP_PVV_COUNT][FPVM_MAXSYMLEN] = {
-       /* System */
-       "_texsize",
-       "_hmeshsize",
-       "_vmeshsize",
-
-       /* MilkDrop */
-       "sx",
-       "sy",
-       "cx",
-       "cy",
-       "rot",
-       "dx",
-       "dy",
-       "zoom",
-
-       "time",
-       "bass",
-       "mid",
-       "treb",
-       "bass_att",
-       "mid_att",
-       "treb_att",
-
-       "warp",
-       "fWarpAnimSpeed",
-       "fWarpScale",
-
-       "q1",
-       "q2",
-       "q3",
-       "q4",
-       "q5",
-       "q6",
-       "q7",
-       "q8",
-
-       "idmx1",
-       "idmx2",
-       "idmx3",
-       "idmx4",
-       "idmx5",
-       "idmx6",
-       "idmx7",
-       "idmx8",
-       
-       "osc1",
-       "osc2",
-       "osc3",
-       "osc4",
-       
-       "midi1",
-       "midi2",
-       "midi3",
-       "midi4",
-       "midi5",
-       "midi6",
-       "midi7",
-       "midi8",
-};
-
-static int pvv_from_name(const char *name)
-{
-       int i;
-       
-       for(i=0;i<COMP_PVV_COUNT;i++) {
-               if(strcmp(pvv_names[i], name) == 0)
-                       return i;
-       }
-       return -1;
-}
-
-static void pvv_update_patch_requires(struct compiler_sc *sc, int pvv)
-{
-       if(pvv >= pvv_idmx1 && pvv <= pvv_idmx8)        sc->p->require |= 
REQUIRE_DMX;
-       if(pvv >= pvv_osc1 && pvv <= pvv_osc4)          sc->p->require |= 
REQUIRE_OSC;
-       if(pvv >= pvv_midi1 && pvv <= pvv_midi8)        sc->p->require |= 
REQUIRE_MIDI;
-}
-
-static void pvv_bind_callback(void *_sc, const char *sym, int reg)
-{
-       struct compiler_sc *sc = _sc;
-       int pvv;
-       
-       pvv = pvv_from_name(sym);
-       if(pvv >= 0) {
-               pvv_update_patch_requires(sc, pvv);
-               sc->p->pvv_allocation[pvv] = reg;
-       }
-}
-
-static bool init_pvv(struct compiler_sc *sc)
-{
-       int i;
-
-       fpvm_init(&sc->pvv_fragment, 1);
-       for(i=0;i<COMP_PVV_COUNT;i++)
-               sc->p->pvv_allocation[i] = -1;
-       fpvm_set_bind_callback(&sc->pvv_fragment, pvv_bind_callback, sc);
-       
-       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_SOURCE);
-       #define A(dest, val) if(!fpvm_assign(&sc->pvv_fragment, dest, val)) 
goto fail_assign
-       A("x", "i2f(_Xi)*_hmeshsize");
-       A("y", "i2f(_Yi)*_vmeshsize");
-       A("rad", "sqrt(sqr(x-0.5)+sqr(y-0.5))");
-       /* TODO: generate ang */
-       #undef A
-       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_ALL);
-       
-       return true;
-
-fail_assign:
-       comp_report(sc, "failed to add equation to per-vertex header: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
-       return false;
-}
-
-static int finalize_pvv(struct compiler_sc *sc)
-{
-       fpvm_set_bind_mode(&sc->pvv_fragment, FPVM_BIND_SOURCE);
-       
-       #define A(dest, val) if(!fpvm_assign(&sc->pvv_fragment, dest, val)) 
goto fail_assign
-
-       /* Zoom */
-       A("_invzoom", "1/zoom");
-       A("_xz", "_invzoom*(x-0.5)+0.5");
-       A("_yz", "_invzoom*(y-0.5)+0.5");
-
-       /* Scale */
-       A("_xs", "(_xz-cx)/sx+cx");
-       A("_ys", "(_yz-cy)/sy+cy");
-
-       /* Warp */
-       A("_warptime", "time*fWarpAnimSpeed");
-       A("_invwarpscale", "1/fWarpScale");
-       A("_f0", "11.68 + 4.0*cos(_warptime*1.413 + 10)");
-       A("_f1", "8.77 + 3.0*cos(_warptime*1.113 + 7)");
-       A("_f2", "10.54 + 3.0*cos(_warptime*1.233 + 3)");
-       A("_f3", "11.49 + 4.0*cos(_warptime*0.933 + 5)");
-       A("_ox2", "2*x-1");
-       A("_oy2", "2*y-1");
-       A("_xw", "_xs+warp*0.0035*("
-               "sin(_warptime*0.333+_invwarpscale*(_ox2*_f0-_oy2*_f3))"
-               "+cos(_warptime*0.753-_invwarpscale*(_ox2*_f1-_oy2*_f2)))");
-       A("_yw", "_ys+warp*0.0035*("
-               "cos(_warptime*0.375-_invwarpscale*(_ox2*_f2+_oy2*_f1))"
-               "+sin(_warptime*0.825+_invwarpscale*(_ox2*_f0+_oy2*_f3)))");
-
-       /* Rotate */
-       A("_cosr", "cos(rot)");
-       A("_sinr", "sin(0-rot)");
-       A("_u", "_xw-cx");
-       A("_v", "_yw-cy");
-       A("_xr", "_u*_cosr-_v*_sinr+cx");
-       A("_yr", "_u*_sinr+_v*_cosr+cy");
-
-       /* Translate */
-       A("_xd", "_xr-dx");
-       A("_yd", "_yr-dy");
-
-       /* Convert to framebuffer coordinates */
-       A("_Xo", "f2i(_xd*_texsize)");
-       A("_Yo", "f2i(_yd*_texsize)");
-
-       #undef A
-
-       if(!fpvm_finalize(&sc->pvv_fragment)) goto fail_finalize;
-       #ifdef COMP_DEBUG
-       printf("per-vertex FPVM fragment:\n");
-       fpvm_dump(&sc->pvv_fragment);
-       #endif
-
-       return true;
-fail_assign:
-       comp_report(sc, "failed to add equation to per-vertex footer: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
-       return false;
-fail_finalize:
-       comp_report(sc, "failed to finalize per-vertex variables: %s", 
fpvm_get_last_error(&sc->pvv_fragment));
-       return false;
-}
-
-static bool schedule_pvv(struct compiler_sc *sc)
-{
-       sc->p->pervertex_prog_length = fpvm_default_schedule(&sc->pvv_fragment,
-               (unsigned int *)sc->p->pervertex_prog, (unsigned int 
*)sc->p->pervertex_regs);
-       if(sc->p->pervertex_prog_length < 0) {
-               comp_report(sc, "per-vertex VLIW scheduling failed");
-               return false;
-       }
-       #ifdef COMP_DEBUG
-       printf("per-vertex PFPU fragment:\n");
-       pfpu_dump(sc->p->pervertex_prog, sc->p->pervertex_prog_length);
-       #endif
-
-       return true;
-}
-
-static bool add_per_vertex(struct compiler_sc *sc, char *dest, char *val)
-{
-       if(!fpvm_assign(&sc->pvv_fragment, dest, val)) {
-               comp_report(sc, "failed to add per-vertex equation l. %d: 
%s\n", sc->linenr, fpvm_get_last_error(&sc->pvv_fragment));
-               return false;
-       }
-       return true;
-}
-
-/****************************************************************/
-/* PARSING                                                      */
-/****************************************************************/
-
-static bool process_equation(struct compiler_sc *sc, char *equation, bool 
per_vertex)
-{
-       char *c, *c2;
-
-       c = strchr(equation, '=');
-       if(!c) {
-               comp_report(sc, "error l.%d: malformed equation (%s)", 
sc->linenr, equation);
-               return false;
-       }
-       *c = 0;
-
-       if(*equation == 0) {
-               comp_report(sc, "error l.%d: missing lvalue", sc->linenr);
-               return false;
-       }
-       c2 = c - 1;
-       while((c2 > equation) && (*c2 == ' ')) *c2-- = 0;
-
-       c++;
-       while(*c == ' ') c++;
-
-       if(*equation == 0) {
-               comp_report(sc, "error l.%d: missing lvalue", sc->linenr);
-               return false;
-       }
-       if(*c == 0) {
-               comp_report(sc, "error l.%d: missing rvalue", sc->linenr);
-               return false;
-       }
-
-       if(per_vertex)
-               return add_per_vertex(sc, equation, c);
-       else
-               return add_per_frame(sc, equation, c);
-}
-
-static bool process_equations(struct compiler_sc *sc, char *equations, bool 
per_vertex)
-{
-       char *c;
-
-       while(*equations) {
-               c = strchr(equations, ';');
-               if(!c)
-                       return process_equation(sc, equations, per_vertex);
-               *c = 0;
-               if(!process_equation(sc, equations, per_vertex)) return false;
-               equations = c + 1;
-       }
-       return true;
-}
-
-static bool process_top_assign(struct compiler_sc *sc, char *left, char *right)
-{
-       int pfv;
-
-       while(*right == ' ') right++;
-       if(*right == 0) return true;
-       
-       if(strncmp(left, "imagefile", 9) == 0) {
-               int image_n;
-               char *totalname;
-               
-               image_n = atoi(left+9);
-               if((image_n < 1) || (image_n > IMAGE_COUNT)) {
-                       comp_report(sc, "warning l.%d: ignoring image with out 
of bounds number %d", sc->linenr, image_n);
-                       return true;
-               }
-               image_n--;
-               if(right[0] == '/')
-                       totalname = strdup(right);
-               else {
-                       totalname = malloc(strlen(sc->basedir) + strlen(right) 
+ 0);
-                       if(totalname == NULL) return true;
-                       strcpy(totalname, sc->basedir);
-                       strcat(totalname, right);
-               }
-               pixbuf_dec_ref(sc->p->images[image_n]);
-               sc->p->images[image_n] = pixbuf_get(totalname);
-               free(totalname);
-               return true;
-       }
-
-       pfv = pfv_from_name(left);
-       if(pfv >= 0) {
-               /* patch initial condition or global parameter */
-               pfv_update_patch_requires(sc, pfv);
-               set_initial(sc, pfv, atof(right));
-               return true;
-       }
-
-       if(strncmp(left, "per_frame", 9) == 0)
-               /* per-frame equation */
-               return process_equations(sc, right, false);
-
-       if((strncmp(left, "per_vertex", 10) == 0) || (strncmp(left, 
"per_pixel", 9) == 0))
-               /* per-vertex equation */
-               return process_equations(sc, right, true);
-
-       comp_report(sc, "warning l.%d: ignoring unknown parameter %s", 
sc->linenr, left);
-
-       return true;
-}
-
-static bool process_line(struct compiler_sc *sc, char *line)
-{
-       char *c;
-
-       while(*line == ' ') line++;
-       if(*line == 0) return true;
-       if(*line == '[') return true;
-
-       c = strstr(line, "//");
-       if(c) *c = 0;
-
-       c = line + strlen(line) - 1;
-       while((c >= line) && (*c == ' ')) *c-- = 0;
-       if(*line == 0) return true;
-
-       c = strchr(line, '=');
-       if(!c) {
-               comp_report(sc, "error l.%d: '=' expected", sc->linenr);
-               return false;
-       }
-       *c = 0;
-       return process_top_assign(sc, line, c+1);
-}
-
-static bool parse_patch(struct compiler_sc *sc, char *patch_code)
-{
-       char *eol;
-
-       while(*patch_code) {
-               sc->linenr++;
-               eol = strchr(patch_code, '\n');
-               if(!eol) {
-                       if(!process_line(sc, patch_code))
-                               return false;
-                       else
-                               return true;
-               }
-               *eol = 0;
-               if(*patch_code == 0) {
-                       patch_code = eol + 1;
-                       continue;
-               }
-               if(*(eol - 1) == '\r') *(eol - 1) = 0;
-               if(!process_line(sc, patch_code))
-                       return false;
-               patch_code = eol + 1;
-       }
-
-       return true;
-}
-
-struct patch *patch_compile(const char *basedir, const char *patch_code, 
report_message rmc)
-{
-       struct compiler_sc *sc;
-       struct patch *p;
-       char *patch_code_copy;
-       int i;
-
-       sc = malloc(sizeof(struct compiler_sc));
-       if(sc == NULL) {
-               rmc("Failed to allocate memory for compiler internal data");
-               return NULL;
-       }
-       p = sc->p = malloc(sizeof(struct patch));
-       if(sc->p == NULL) {
-               rmc("Failed to allocate memory for patch");
-               free(sc);
-               return NULL;
-       }
-       for(i=0;i<IMAGE_COUNT;i++)
-               sc->p->images[i] = NULL;
-       sc->p->require = 0;
-       sc->p->original = NULL;
-       sc->p->next = NULL;
-
-       sc->basedir = basedir;
-       sc->rmc = rmc;
-       sc->linenr = 0;
-
-       load_defaults(sc);
-       if(!init_pfv(sc)) goto fail;
-       if(!init_pvv(sc)) goto fail;
-
-       patch_code_copy = strdup(patch_code);
-       if(patch_code_copy == NULL) {
-               rmc("Failed to allocate memory for patch code");
-               goto fail;
-       }
-       if(!parse_patch(sc, patch_code_copy)) {
-               free(patch_code_copy);
-               goto fail;
-       }
-       free(patch_code_copy);
-
-       if(!finalize_pfv(sc)) goto fail;
-       if(!schedule_pfv(sc)) goto fail;
-       if(!finalize_pvv(sc)) goto fail;
-       if(!schedule_pvv(sc)) goto fail;
-
-       free(sc);
-       return p;
-fail:
-       free(sc->p);
-       free(sc);
-       return NULL;
-}
-
-struct patch *patch_compile_filename(const char *filename, const char 
*patch_code, report_message rmc)
-{
-       char *basedir;
-       char *c;
-       struct patch *p;
-       
-       basedir = strdup(filename);
-       if(basedir == NULL) return NULL;
-       c = strrchr(basedir, '/');
-       if(c != NULL) {
-               c++;
-               *c = 0;
-               p = patch_compile(basedir, patch_code, rmc);
-       } else
-               p = patch_compile("/", patch_code, rmc);
-       free(basedir);
-       return p;
-}
-
-struct patch *patch_copy(struct patch *p)
-{
-       struct patch *new_patch;
-       int i;
-       
-       new_patch = malloc(sizeof(struct patch));
-       assert(new_patch != NULL);
-       memcpy(new_patch, p, sizeof(struct patch));
-       new_patch->original = p;
-       new_patch->next = NULL;
-       for(i=0;i<IMAGE_COUNT;i++)
-               pixbuf_inc_ref(new_patch->images[i]);
-       return new_patch;
-}
-
-void patch_free(struct patch *p)
-{
-       int i;
-       
-       for(i=0;i<IMAGE_COUNT;i++)
-               pixbuf_dec_ref(p->images[i]);
-       free(p);
-}
diff --git a/src/renderer/compiler.h b/src/renderer/compiler.h
deleted file mode 100644
index 2f1169f..0000000
--- a/src/renderer/compiler.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Flickernoise
- * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __COMPILER_H
-#define __COMPILER_H
-
-#include <rtems.h>
-#include <bsp/milkymist_pfpu.h>
-
-#include "framedescriptor.h"
-#include "../pixbuf/pixbuf.h"
-
-enum {
-       pfv_sx = 0,
-       pfv_sy,
-       pfv_cx,
-       pfv_cy,
-       pfv_rot,
-       pfv_dx,
-       pfv_dy,
-       pfv_zoom,
-       pfv_decay,
-       pfv_wave_mode,
-       pfv_wave_scale,
-       pfv_wave_additive,
-       pfv_wave_usedots,
-       pfv_wave_brighten,
-       pfv_wave_thick,
-       pfv_wave_x,
-       pfv_wave_y,
-       pfv_wave_r,
-       pfv_wave_g,
-       pfv_wave_b,
-       pfv_wave_a,
-
-       pfv_ob_size,
-       pfv_ob_r,
-       pfv_ob_g,
-       pfv_ob_b,
-       pfv_ob_a,
-       pfv_ib_size,
-       pfv_ib_r,
-       pfv_ib_g,
-       pfv_ib_b,
-       pfv_ib_a,
-
-       pfv_mv_x,
-       pfv_mv_y,
-       pfv_mv_dx,
-       pfv_mv_dy,
-       pfv_mv_l,
-       pfv_mv_r,
-       pfv_mv_g,
-       pfv_mv_b,
-       pfv_mv_a,
-
-       pfv_tex_wrap,
-
-       pfv_time,
-       pfv_bass,
-       pfv_mid,
-       pfv_treb,
-       pfv_bass_att,
-       pfv_mid_att,
-       pfv_treb_att,
-
-       pfv_warp,
-       pfv_warp_anim_speed,
-       pfv_warp_scale,
-
-       pfv_q1,
-       pfv_q2,
-       pfv_q3,
-       pfv_q4,
-       pfv_q5,
-       pfv_q6,
-       pfv_q7,
-       pfv_q8,
-
-       pfv_video_echo_alpha,
-       pfv_video_echo_zoom,
-       pfv_video_echo_orientation,
-
-       pfv_dmx1,
-       pfv_dmx2,
-       pfv_dmx3,
-       pfv_dmx4,
-       pfv_dmx5,
-       pfv_dmx6,
-       pfv_dmx7,
-       pfv_dmx8,
-
-       pfv_idmx1,
-       pfv_idmx2,
-       pfv_idmx3,
-       pfv_idmx4,
-       pfv_idmx5,
-       pfv_idmx6,
-       pfv_idmx7,
-       pfv_idmx8,
-
-       pfv_osc1,
-       pfv_osc2,
-       pfv_osc3,
-       pfv_osc4,
-       
-       pfv_midi1,
-       pfv_midi2,
-       pfv_midi3,
-       pfv_midi4,
-       pfv_midi5,
-       pfv_midi6,
-       pfv_midi7,
-       pfv_midi8,
-
-       pfv_video_a,
-       
-       pfv_image1_a,
-       pfv_image1_x,
-       pfv_image1_y,
-       pfv_image1_zoom,
-       pfv_image2_a,
-       pfv_image2_x,
-       pfv_image2_y,
-       pfv_image2_zoom,
-
-       COMP_PFV_COUNT /* must be last */
-};
-
-enum {
-       /* System */
-       pvv_texsize,
-       pvv_hmeshsize,
-       pvv_vmeshsize,
-
-       /* MilkDrop */
-       pvv_sx,
-       pvv_sy,
-       pvv_cx,
-       pvv_cy,
-       pvv_rot,
-       pvv_dx,
-       pvv_dy,
-       pvv_zoom,
-
-       pvv_time,
-       pvv_bass,
-       pvv_mid,
-       pvv_treb,
-       pvv_bass_att,
-       pvv_mid_att,
-       pvv_treb_att,
-
-       pvv_warp,
-       pvv_warp_anim_speed,
-       pvv_warp_scale,
-
-       pvv_q1,
-       pvv_q2,
-       pvv_q3,
-       pvv_q4,
-       pvv_q5,
-       pvv_q6,
-       pvv_q7,
-       pvv_q8,
-
-       pvv_idmx1,
-       pvv_idmx2,
-       pvv_idmx3,
-       pvv_idmx4,
-       pvv_idmx5,
-       pvv_idmx6,
-       pvv_idmx7,
-       pvv_idmx8,
-
-       pvv_osc1,
-       pvv_osc2,
-       pvv_osc3,
-       pvv_osc4,
-       
-       pvv_midi1,
-       pvv_midi2,
-       pvv_midi3,
-       pvv_midi4,
-       pvv_midi5,
-       pvv_midi6,
-       pvv_midi7,
-       pvv_midi8,
-
-       COMP_PVV_COUNT /* must be last */
-};
-
-#define REQUIRE_DMX    (1 << 0)
-#define REQUIRE_OSC    (1 << 1)
-#define REQUIRE_MIDI   (1 << 2)
-#define REQUIRE_VIDEO  (1 << 3)
-
-struct patch {
-       /* per-frame */
-       struct pixbuf *images[IMAGE_COUNT];             /* < images used in 
this patch */
-       float pfv_initial[COMP_PFV_COUNT];              /* < patch initial 
conditions */
-       int pfv_allocation[COMP_PFV_COUNT];             /* < where per-frame 
variables are mapped in PFPU regf, -1 if unmapped */
-       int perframe_prog_length;                       /* < how many 
instructions in perframe_prog */
-       unsigned int perframe_prog[PFPU_PROGSIZE];      /* < PFPU per-frame 
microcode */
-       float perframe_regs[PFPU_REG_COUNT];            /* < PFPU initial 
per-frame regf */
-       /* per-vertex */
-       int pvv_allocation[COMP_PVV_COUNT];             /* < where per-vertex 
variables are mapped in PFPU regf, -1 if unmapped */
-       int pervertex_prog_length;                      /* < how many 
instructions in pervertex_prog */
-       unsigned int pervertex_prog[PFPU_PROGSIZE];     /* < PFPU per-vertex 
microcode */
-       float pervertex_regs[PFPU_REG_COUNT];           /* < PFPU initial 
per-vertex regf */
-       /* meta */
-       unsigned int require;                           /* < bitmask: dmx, osc, 
midi, video */
-       void *original;                                 /* < original patch 
(with initial register values) */
-       struct patch *next;                             /* < used when chaining 
patches in mashups */
-};
-
-typedef void (*report_message)(const char *);
-
-struct patch *patch_compile(const char *basedir, const char *patch_code, 
report_message rmc);
-struct patch *patch_compile_filename(const char *filename, const char 
*patch_code, report_message rmc);
-struct patch *patch_copy(struct patch *p);
-void patch_free(struct patch *p);
-
-#endif /* __COMPILER_H */
diff --git a/src/renderer/eval.c b/src/renderer/eval.c
index 380a7ea..e41c641 100644
--- a/src/renderer/eval.c
+++ b/src/renderer/eval.c
@@ -28,7 +28,7 @@
 #include <bsp/milkymist_tmu.h>
 
 #include "../pixbuf/pixbuf.h"
-#include "compiler.h"
+#include "../compiler/compiler.h"
 #include "framedescriptor.h"
 #include "renderer.h"
 
diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c
index b8388ba..5bad9a4 100644
--- a/src/renderer/renderer.c
+++ b/src/renderer/renderer.c
@@ -21,7 +21,7 @@
 #include <stdlib.h>
 
 #include "sampler.h"
-#include "compiler.h"
+#include "../compiler/compiler.h"
 #include "eval.h"
 #include "raster.h"
 #include "osd.h"
diff --git a/src/renderer/renderer.h b/src/renderer/renderer.h
index 41ac5df..fc50f32 100644
--- a/src/renderer/renderer.h
+++ b/src/renderer/renderer.h
@@ -18,7 +18,7 @@
 #ifndef __RENDERER_H
 #define __RENDERER_H
 
-#include "compiler.h"
+#include "../compiler/compiler.h"
 
 extern int renderer_texsize;
 extern int renderer_hmeshlast;
-- 
1.7.1

_______________________________________________
http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org
IRC: #milkymist@Freenode

Reply via email to