Mercurial > audlegacy-plugins
changeset 408:290588854a9d trunk
[svn] - rovascope -- a variant of the paranormal visualization engine that is
uses random data instead of presets.
line wrap: on
line diff
--- a/ChangeLog Fri Jan 05 19:31:47 2007 -0800 +++ b/ChangeLog Sat Jan 06 01:57:34 2007 -0800 @@ -1,3 +1,11 @@ +2007-01-06 03:31:47 +0000 William Pitcock <nenolod@nenolod.net> + revision [892] + - update to Objective-Make II + + trunk/mk/objective.mk | 41 +++++++++++++++++++++++++++++++++-------- + 1 file changed, 33 insertions(+), 8 deletions(-) + + 2007-01-05 12:54:33 +0000 Giacomo Lozito <james@develia.org> revision [890] - removed gdk_threads_enter/leave from song_change.c, it's not needed here and brings troubles too
--- a/configure.ac Fri Jan 05 19:31:47 2007 -0800 +++ b/configure.ac Sat Jan 06 01:57:34 2007 -0800 @@ -966,7 +966,7 @@ ]) if test "$have_paranormal" = "yes"; then - VISUALIZATION_PLUGINS="$VISUALIZATION_PLUGINS paranormal" + VISUALIZATION_PLUGINS="$VISUALIZATION_PLUGINS paranormal rovascope" fi if test "$have_xspf" = "yes"; then
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/Makefile Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,32 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +OBJECTIVE_LIBS = librovascope$(SHARED_SUFFIX) + +SUBDIRS = libcalc + +LIBDIR = $(plugindir)/$(VISUALIZATION_PLUGIN_DIR) + +LIBADD = $(GTK_LIBS) $(XML_LIBS) $(SDL_LIBS) libcalc/libcalc.a + +SOURCES = \ + actuators.c \ + actuatorbin.c \ + beatdetect.c \ + builtins.c \ + cmaps.c \ + containers.c \ + drawing.c \ + freq.c \ + general.c \ + misc.c \ + paranormal.c \ + plugin.c \ + wave.c \ + xform.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(ARCH_DEFINES) $(XML_CPPFLAGS) $(SDL_CFLAGS) -I../../intl -I../.. + +include ../../mk/objective.mk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/TODO Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,13 @@ +More immediate points: + +- blend surface + +- container_stepped + executes <step> amount of instructions.. step increases or decreases + on beat + +- container_repeat + executes the child instructions <step> amount of times.. step + increases or decreases on beat + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/actuators.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,179 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glib.h> + +#include "actuators.h" +//#include "containers.h" + +/* FIXME: container options override containees - fix this? */ +/* FIXME: add actuator groups (by a group name string) */ + +/* FIXME: add support for copying containers' children (optionally) */ +struct pn_actuator * +copy_actuator (const struct pn_actuator *a) +{ + struct pn_actuator *actuator; + int i; + + actuator = g_new (struct pn_actuator, 1); + + actuator->desc = a->desc; + + /* Make an options table */ + if (actuator->desc->option_descs) + { + /* count the options */ + for (i=0; actuator->desc->option_descs[i].name; i++); + + actuator->options = g_new (struct pn_actuator_option, i); + for (i=0; actuator->desc->option_descs[i].name; i++) + { + actuator->options[i].desc = &actuator->desc->option_descs[i]; + + /* copy the default options */ + switch (actuator->desc->option_descs[i].type) + { + case OPT_TYPE_INT: + case OPT_TYPE_COLOR_INDEX: + case OPT_TYPE_FLOAT: + case OPT_TYPE_COLOR: + case OPT_TYPE_BOOLEAN: + memcpy (&actuator->options[i].val, + &a->options[i].val, + sizeof (union actuator_option_val)); + break; + case OPT_TYPE_STRING: + actuator->options[i].val.sval = g_strdup(a->options[i].val.sval); + break; + default: + break; + } + } + + /* the NULL option */ + actuator->options[i].desc = NULL; + } + else + actuator->options = NULL; + + if (actuator->desc->init) + actuator->desc->init (&actuator->data); + + return actuator; +} + +struct pn_actuator_desc * +get_actuator_desc (const char *name) +{ + int i; + + for (i=0; builtin_table[i]; i++) + if (! g_strcasecmp (name, builtin_table[i]->name) || ! g_strcasecmp(name, builtin_table[i]->dispname)) + break; + + /* actuator not found */ + if (! builtin_table[i]) + return NULL; + + return builtin_table[i]; +} + +struct pn_actuator * +create_actuator (const char *name) +{ + int i; + struct pn_actuator_desc *desc; + struct pn_actuator *actuator; + + /* find the actuatoreration */ + desc = get_actuator_desc (name); + + if (! desc) + return NULL; + + actuator = g_new (struct pn_actuator, 1); + actuator->desc = desc; + + /* Make an options table */ + if (actuator->desc->option_descs) + { + /* count the options */ + for (i=0; actuator->desc->option_descs[i].name != NULL; i++); + + actuator->options = g_new0 (struct pn_actuator_option, i + 1); + for (i=0; actuator->desc->option_descs[i].name != NULL; i++) + { + actuator->options[i].desc = &actuator->desc->option_descs[i]; + + /* copy the default options */ + switch (actuator->desc->option_descs[i].type) + { + case OPT_TYPE_INT: + case OPT_TYPE_COLOR_INDEX: + case OPT_TYPE_FLOAT: + case OPT_TYPE_COLOR: + case OPT_TYPE_BOOLEAN: + memcpy (&actuator->options[i].val, + &actuator->desc->option_descs[i].default_val, + sizeof (union actuator_option_val)); + break; + case OPT_TYPE_STRING: + /* NOTE: It's not realloc'ed so don't free it */ + actuator->options[i].val.sval = + actuator->desc->option_descs[i].default_val.sval; + break; + } + } + + /* the NULL option */ + actuator->options[i].desc = NULL; + } + else + actuator->options = NULL; + + if (actuator->desc->init) + actuator->desc->init (&actuator->data); + + return actuator; +} + +void +destroy_actuator (struct pn_actuator *actuator) +{ + int i; + + if (actuator->desc->cleanup) + actuator->desc->cleanup (actuator->data); + + /* find any option val's that need to be freed */ + if (actuator->options) + for (i=0; actuator->options[i].desc; i++) + switch (actuator->options[i].desc->type) + { + case OPT_TYPE_INT: + case OPT_TYPE_FLOAT: + case OPT_TYPE_COLOR: + case OPT_TYPE_COLOR_INDEX: + case OPT_TYPE_BOOLEAN: + break; + case OPT_TYPE_STRING: + if (actuator->options[i].val.sval + != actuator->options[i].desc->default_val.sval) + g_free ((char *)actuator->options[i].val.sval); + } + + g_free (actuator->options); + g_free (actuator); +} + +void +exec_actuator (struct pn_actuator *actuator) +{ + g_assert (actuator); + g_assert (actuator->desc); + g_assert (actuator->desc->exec); + actuator->desc->exec (actuator->options, actuator->data); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/actuators.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,99 @@ +/* FIXME: rename actuators to pn_actuators */ +/* FIXME: add a color type to the OPT_TYPE's */ + +#ifndef _ACTUATORS_H +#define _ACTUATORS_H + +#include <glib.h> +#include <SDL.h> + +/* Helper macros for actuator functions */ +#define PN_ACTUATOR_INIT_FUNC(f) ((void (*) (gpointer *data))f) +#define PN_ACTUATOR_CLEANUP_FUNC(f) ((void (*) (gpointer data))f) +#define PN_ACTUATOR_EXEC_FUNC(f) \ +((void (*) (const struct pn_actuator_option *opts, gpointer data))f) + +struct pn_color +{ + guchar r, g, b; + guchar spluzz; /* gotta look like an SDL_Color */ +}; + + +union actuator_option_val +{ + int ival; + float fval; + const char *sval; + struct pn_color cval; + gboolean bval; +}; + +/* A actuator's option description */ +struct pn_actuator_option_desc +{ + const char *name; + const char *doc; /* option documentation */ + enum + { + OPT_TYPE_INT = 0, + OPT_TYPE_FLOAT = 1, + OPT_TYPE_STRING = 2, + OPT_TYPE_COLOR = 3, + OPT_TYPE_COLOR_INDEX = 4, /* uses ival */ + OPT_TYPE_BOOLEAN = 5 + } type; + union actuator_option_val default_val; +}; + +/* The actual option instance */ +struct pn_actuator_option +{ + const struct pn_actuator_option_desc *desc; + union actuator_option_val val; +}; + +/* An operation's description */ +struct pn_actuator_desc +{ + const char *name; /* e.g. "container_simple" */ + const char *dispname; /* e.g. "Simple Container" */ + const char *doc; /* documentation txt */ + const enum + { + ACTUATOR_FLAG_CONTAINER = 1<<0 + } flags; + + /* A null terminating (ie a actuator_option_desc == {0,...,0}) + array - OPTIONAL (optional fields can be NULL) */ + const struct pn_actuator_option_desc *option_descs; + + /* Init function - data points to the actuator.data - OPTIONAL */ + void (*init) (gpointer *data); + + /* Cleanup actuatortion - OPTIONAL */ + void (*cleanup) (gpointer data); + + /* Execute actuatortion - REQUIRED (duh!) */ + void (*exec) (const struct pn_actuator_option *opts, gpointer data); +}; + +/* An actual operation instance */ +struct pn_actuator +{ + const struct pn_actuator_desc *desc; + struct pn_actuator_option *options; + gpointer data; +}; + +/* The array containing all operations (see builtins.c) */ +extern struct pn_actuator_desc *builtin_table[]; + +/* functions for actuators */ +struct pn_actuator_desc *get_actuator_desc (const char *name); +struct pn_actuator *copy_actuator (const struct pn_actuator *a); +struct pn_actuator *create_actuator (const char *name); +void destroy_actuator (struct pn_actuator *actuator); +void exec_actuator (struct pn_actuator *actuator); + +#endif /* _ACTUATORS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/beatdetect.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,30 @@ +#include "paranormal.h" + +/* + * This algorithm is by Janusz Gregorcyzk, the implementation is + * mine, however. + * + * -- nenolod + */ +int +pn_is_new_beat(void) +{ + gint i; + gint total = 0; + gboolean ret = FALSE; + static gint previous; + + for (i = 1; i < 512; i++) + { + total += abs (pn_sound_data->pcm_data[0][i] - + pn_sound_data->pcm_data[0][i - 1]); + } + + total /= 512; + + ret = (total > (2 * previous)); + + previous = total; + + return ret; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/builtins.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,102 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "actuators.h" + +#define DECLARE_ACTUATOR(a) extern struct pn_actuator_desc builtin_##a; + +/* **************** containers **************** */ + +DECLARE_ACTUATOR (container_simple); +DECLARE_ACTUATOR (container_once); +DECLARE_ACTUATOR (container_cycle); +DECLARE_ACTUATOR (container_onbeat); + +/* **************** cmaps **************** */ + +DECLARE_ACTUATOR (cmap_bwgradient); +DECLARE_ACTUATOR (cmap_gradient); +DECLARE_ACTUATOR (cmap_dynamic); + +/* **************** freq **************** */ +DECLARE_ACTUATOR (freq_dots); +DECLARE_ACTUATOR (freq_drops); + +/* **************** general **************** */ +DECLARE_ACTUATOR (general_fade); +DECLARE_ACTUATOR (general_blur); +DECLARE_ACTUATOR (general_mosaic); +DECLARE_ACTUATOR (general_clear); +DECLARE_ACTUATOR (general_noop); +DECLARE_ACTUATOR (general_invert); +DECLARE_ACTUATOR (general_replace); +DECLARE_ACTUATOR (general_swap); +DECLARE_ACTUATOR (general_copy); +DECLARE_ACTUATOR (general_flip); + +/* **************** misc **************** */ +DECLARE_ACTUATOR (misc_floater); + +/* **************** wave **************** */ +DECLARE_ACTUATOR (wave_horizontal); +DECLARE_ACTUATOR (wave_vertical); +DECLARE_ACTUATOR (wave_normalize); +DECLARE_ACTUATOR (wave_smooth); +DECLARE_ACTUATOR (wave_radial); +DECLARE_ACTUATOR (wave_scope); + +/* **************** xform **************** */ +DECLARE_ACTUATOR (xform_spin); +DECLARE_ACTUATOR (xform_ripple); +DECLARE_ACTUATOR (xform_bump_spin); +DECLARE_ACTUATOR (xform_halfrender); +DECLARE_ACTUATOR (xform_movement); +DECLARE_ACTUATOR (xform_dynmovement); + +/* **************** builtin_table **************** */ +struct pn_actuator_desc *builtin_table[] = +{ + /* **************** containers **************** */ + &builtin_container_simple, + &builtin_container_once, + &builtin_container_cycle, + &builtin_container_onbeat, + + /* **************** cmaps **************** */ + &builtin_cmap_bwgradient, + &builtin_cmap_gradient, + &builtin_cmap_dynamic, + /* **************** freq **************** */ + &builtin_freq_dots, + &builtin_freq_drops, + /* **************** general **************** */ + &builtin_general_fade, + &builtin_general_blur, + &builtin_general_mosaic, + &builtin_general_clear, + &builtin_general_noop, + &builtin_general_invert, + &builtin_general_replace, + &builtin_general_swap, + &builtin_general_copy, + &builtin_general_flip, + /* **************** misc **************** */ + &builtin_misc_floater, + /* **************** wave **************** */ + &builtin_wave_horizontal, + &builtin_wave_vertical, + &builtin_wave_normalize, + &builtin_wave_smooth, + &builtin_wave_radial, + &builtin_wave_scope, + /* **************** xform **************** */ + &builtin_xform_spin, + &builtin_xform_ripple, + &builtin_xform_bump_spin, + &builtin_xform_halfrender, + &builtin_xform_movement, + &builtin_xform_dynmovement, + /* **************** the end! **************** */ + NULL +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/cmaps.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,185 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glib.h> + +#include "paranormal.h" +#include "actuators.h" + +#include "libcalc/calc.h" + +#define STD_CMAP_OPTS { "low_index", "The lowest index of the \ +color map that should be altered", OPT_TYPE_COLOR_INDEX, { ival: 0 } },\ +{ "high_index", "The highest index of the color map that should be \ +altered", OPT_TYPE_COLOR_INDEX, { ival: 255 } } + +static struct pn_color black = {0, 0, 0}; +static struct pn_color white = {255, 255, 255}; + +/* **************** cmap generation funcs **************** */ +static void +cmap_gen_gradient (int step, const struct pn_color *a, + const struct pn_color *b, + struct pn_color *c) +{ + c->r = a->r + step * ((((float)b->r) - ((float)a->r)) / 256.0); + c->g = a->g + step * ((((float)b->g) - ((float)a->g)) / 256.0); + c->b = a->b + step * ((((float)b->b) - ((float)a->b)) / 256.0); +} + +/* **************** cmap_gradient **************** */ +static struct pn_actuator_option_desc cmap_gradient_opts[] = +{ + STD_CMAP_OPTS, + { "lcolor", "The low color used in the gradient generation", + OPT_TYPE_COLOR, { cval: {0, 0, 0} } }, + { "hcolor", "The high color used in the gradient generation", + OPT_TYPE_COLOR, { cval: {0, 0, 0} } }, + { NULL } +}; + +static void +cmap_gradient_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i; + + for (i=opts[0].val.ival; i<=opts[1].val.ival; i++) + cmap_gen_gradient (((i-opts[0].val.ival)<<8)/(opts[1].val.ival + - opts[0].val.ival), + &opts[2].val.cval, &opts[3].val.cval, + &pn_image_data->cmap[i]); +} + +struct pn_actuator_desc builtin_cmap_gradient = +{ + "cmap_gradient", + "Normal colourmap", + "Sets the colormap to a gradient going from <lcolor> to " + "<hcolor>", + 0, cmap_gradient_opts, + NULL, NULL, cmap_gradient_exec +}; + +/* **************** cmap_bwgradient **************** */ +static struct pn_actuator_option_desc cmap_bwgradient_opts[] = +{ + STD_CMAP_OPTS, + { "color", "The intermediate color to use in the gradient", + OPT_TYPE_COLOR, { cval: {191, 191, 191} } }, + { NULL } +}; + +static void +cmap_bwgradient_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i; + + for (i=opts[0].val.ival; i<128 && i<=opts[1].val.ival; i++) + cmap_gen_gradient (i<<1, &black, &opts[2].val.cval, + &pn_image_data->cmap[i]); + + for (i=128; i<256 && i<=opts[1].val.ival; i++) + cmap_gen_gradient ((i-128)<<1, &opts[2].val.cval, &white, + &pn_image_data->cmap[i]); +} + +struct pn_actuator_desc builtin_cmap_bwgradient = +{ + "cmap_bwgradient", + "Value-based colourmap", + "Sets the colormap to a gradient going from black to " + "white, via an intermediate color", + 0, cmap_bwgradient_opts, + NULL, NULL, cmap_bwgradient_exec +}; + +/* **************** cmap_dynamic **************** */ +static struct pn_actuator_option_desc cmap_dynamic_opts[] = +{ + STD_CMAP_OPTS, + { "script", "The script to run on each step.", + OPT_TYPE_STRING, { sval: "red = red + 0.01; blue = blue + 0.01; green = green + 0.01;" } }, + { NULL } +}; + +typedef struct { + expression_t *expr; + symbol_dict_t *dict; +} PnDynamicColourmapData; + +static void +cmap_dynamic_init(gpointer *data) +{ + *data = g_new0(PnDynamicColourmapData, 1); +} + +static void +cmap_dynamic_cleanup(gpointer data) +{ + PnDynamicColourmapData *d = (PnDynamicColourmapData *) data; + + if (d->expr) + expr_free(d->expr); + if (d->dict) + dict_free(d->dict); + + g_free(d); +} + +static void +cmap_dynamic_exec(const struct pn_actuator_option *opts, + gpointer data) +{ + PnDynamicColourmapData *d = (PnDynamicColourmapData *) data; + gint i, j; + gdouble *rf, *bf, *gf, *inf; + gint rn, bn, gn; + + if (!d->dict && !d->expr) + { + d->dict = dict_new(); + if (!d->dict) + return; + + d->expr = expr_compile_string(opts[2].val.sval, d->dict); + if (!d->expr) + { + dict_free(d->dict); + d->dict = NULL; + return; + } + } + + rf = dict_variable(d->dict, "red"); + gf = dict_variable(d->dict, "green"); + bf = dict_variable(d->dict, "blue"); + inf = dict_variable(d->dict, "index"); + + for (i = opts[0].val.ival; i < 255 && i <= opts[1].val.ival; i++) + { + *inf = ((gdouble)i / 255.0); + + expr_execute(d->expr, d->dict); + + /* Convert rf/bf/gf to realworld values. */ + rn = (gdouble)(*rf * 255); + gn = (gdouble)(*gf * 255); + bn = (gdouble)(*bf * 255); + + pn_image_data->cmap[i].r = rn; + pn_image_data->cmap[i].g = gn; + pn_image_data->cmap[i].b = bn; + } +} + +struct pn_actuator_desc builtin_cmap_dynamic = +{ + "cmap_dynamic", + "Dynamic Colourmap", + "Scriptable colourmap modifier.", + 0, cmap_dynamic_opts, + cmap_dynamic_init, cmap_dynamic_cleanup, cmap_dynamic_exec +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/containers.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,250 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> + +#include <glib.h> + +#include "actuators.h" +#include "paranormal.h" + +/* **************** all containers **************** */ + +/* Add a actuator to a container (end of list) */ +void +container_add_actuator (struct pn_actuator *container, struct pn_actuator *a) +{ + g_assert (container->desc->flags & ACTUATOR_FLAG_CONTAINER); + g_assert (a); + + *((GSList **)container->data) = + g_slist_append (*(GSList **)container->data, a); +} + +void +container_remove_actuator (struct pn_actuator *container, struct pn_actuator *a) +{ + g_assert (container->desc->flags & ACTUATOR_FLAG_CONTAINER); + g_assert (a); + + *((GSList **)container->data) = + g_slist_remove (*(GSList **)container->data, a); +} + +/* clear the containee list */ +void +container_unlink_actuators (struct pn_actuator *container) +{ + g_assert (container->desc->flags & ACTUATOR_FLAG_CONTAINER); + + g_slist_free (*(GSList **)container->data); + *(GSList **)container->data = NULL; +} + +/* this does NOT free data */ +static void +container_cleanup (GSList** data) +{ + GSList *child; + + for (child = *data; child; child = child->next) + destroy_actuator ((struct pn_actuator *) child->data); + + g_slist_free (*data); +} + +/* **************** container_simple **************** */ +static void +container_simple_init (GSList ***data) +{ + *data = g_new0 (GSList *, 1); +} + +static void +container_simple_cleanup (GSList **data) +{ + container_cleanup (data); + g_free (data); +} + +static void +container_simple_exec (const struct pn_actuator_option *opts, + GSList **data) +{ + GSList *child; + + for (child = *data; child; child = child->next) + exec_actuator ((struct pn_actuator *) child->data); +} + +struct pn_actuator_desc builtin_container_simple = +{ + "container_simple", + "Simple Container", + "A simple (unconditional) container\n\n" + "This is usually used as the root actuator of a list", + ACTUATOR_FLAG_CONTAINER, NULL, + PN_ACTUATOR_INIT_FUNC (container_simple_init), + PN_ACTUATOR_CLEANUP_FUNC (container_simple_cleanup), + PN_ACTUATOR_EXEC_FUNC (container_simple_exec) +}; + +/* **************** container_once **************** */ +struct container_once_data +{ + GSList *children; /* This MUST be first! */ + + gboolean done; +}; + +static void +container_once_init (struct container_once_data **data) +{ + *data = g_new0 (struct container_once_data, 1); +} + +static void +container_once_cleanup (GSList **data) +{ + container_cleanup (data); + g_free (data); +} + +static void +container_once_exec (const struct pn_actuator_option *opts, + struct container_once_data *data) +{ + if (! data->done) + { + GSList *child; + + for (child = data->children; child; child = child->next) + exec_actuator ((struct pn_actuator *) child->data); + + data->done = TRUE; + } +} + +struct pn_actuator_desc builtin_container_once = +{ + "container_once", + "Initialization Container", + "A container whose contents get executed exactly once.\n\n" + "This is often used to set initial graphics states such as the\n" + "pixel depth, or to display some text (such as credits)", + ACTUATOR_FLAG_CONTAINER, NULL, + PN_ACTUATOR_INIT_FUNC (container_once_init), + PN_ACTUATOR_CLEANUP_FUNC (container_once_cleanup), + PN_ACTUATOR_EXEC_FUNC (container_once_exec) +}; + +/* **************** container_cycle ***************** */ +static struct pn_actuator_option_desc container_cycle_opts[] = +{ + { "change_interval", "The number of seconds between changing the " + "child to be executed", OPT_TYPE_INT, { ival: 20 } }, + { "beat", "Whether or not the change should only occur on a beat", + OPT_TYPE_BOOLEAN, { bval: TRUE } }, + { NULL } +}; + +struct container_cycle_data +{ + GSList *children; + GSList *current; + int last_change; +}; + +static void +container_cycle_init (gpointer *data) +{ + *data = g_new0 (struct container_cycle_data, 1); +} + +static void +container_cycle_cleanup (gpointer data) +{ + container_cleanup (data); + g_free (data); +} + +static void +container_cycle_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + struct container_cycle_data *cdata = (struct container_cycle_data*)data; + int now; + + /* + * Change branch if all of the requirements are met for the branch to change. + */ + if ((opts[1].val.bval == TRUE && pn_new_beat != FALSE) || opts[1].val.bval == FALSE) + { + now = SDL_GetTicks(); + + if (now - cdata->last_change + > opts[0].val.ival * 1000) + { + cdata->last_change = now; + + /* FIXME: add randomization support */ + if (cdata->current) + cdata->current = cdata->current->next; + } + } + + if (! cdata->current) + cdata->current = cdata->children; + + if (cdata->current) + exec_actuator ((struct pn_actuator*)cdata->current->data); +} + +struct pn_actuator_desc builtin_container_cycle = +{ + "container_cycle", + "Branched-execution Container", + "A container that alternates which of its children is executed; it " + "can either change on an interval, or only on a beat.", + ACTUATOR_FLAG_CONTAINER, container_cycle_opts, + container_cycle_init, container_cycle_cleanup, container_cycle_exec +}; + +/* **************** container_onbeat **************** */ +static void +container_onbeat_init (GSList ***data) +{ + *data = g_new0 (GSList *, 1); +} + +static void +container_onbeat_cleanup (GSList **data) +{ + container_cleanup (data); + g_free (data); +} + +static void +container_onbeat_exec (const struct pn_actuator_option *opts, + GSList **data) +{ + GSList *child; + + if (pn_new_beat == TRUE) + { + for (child = *data; child; child = child->next) + exec_actuator ((struct pn_actuator *) child->data); + } +} + +struct pn_actuator_desc builtin_container_onbeat = +{ + "container_onbeat", + "OnBeat Container", + "A simple container which only triggers on a beat.", + ACTUATOR_FLAG_CONTAINER, NULL, + PN_ACTUATOR_INIT_FUNC (container_onbeat_init), + PN_ACTUATOR_CLEANUP_FUNC (container_onbeat_cleanup), + PN_ACTUATOR_EXEC_FUNC (container_onbeat_exec) +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/containers.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,8 @@ +#ifndef _CONTAINERS_H +#define _CONTAINERS_H + +void container_add_actuator (struct pn_actuator *container, struct pn_actuator *a); +void container_remove_actuator (struct pn_actuator *container, struct pn_actuator *a); +void container_unlink_actuators (struct pn_actuator *container); + +#endif /* _CONTAINERS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/drawing.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,45 @@ +#include <math.h> + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +extern SDL_Surface *screen; + +void +pn_draw_dot (guint x, guint y, guchar value) +{ + if (x > pn_image_data->width || x < 0 || y > pn_image_data->height || y < 0) + return; + + pn_image_data->surface[0][PN_IMG_INDEX(x, y)] = value; +} + +void +pn_draw_line (guint _x0, guint _y0, guint _x1, guint _y1, guchar value) +{ + gint x0 = _x0; + gint y0 = _y0; + gint x1 = _x1; + gint y1 = _y1; + + gint dx = x1 - x0; + gint dy = y1 - y0; + + pn_draw_dot(x0, y0, value); + + if (dx != 0) + { + gfloat m = (gfloat) dy / (gfloat) dx; + gfloat b = y0 - m * x0; + + dx = (x1 > x0) ? 1 : - 1; + while (x0 != x1) + { + x0 += dx; + y0 = m * x0 + b; + + pn_draw_dot(x0, y0, value); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/drawing.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,9 @@ +#include <glib.h> + +#ifndef PN_DRAWING_H +#define PN_DRAWING_H + +void pn_draw_dot (guint x, guint y, guchar value); +void pn_draw_line (guint _x0, guint _y0, guint _x1, guint _y1, guchar value); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/freq.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,64 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> + +#include <glib.h> + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +/* **************** freq_dots **************** */ +/* FIXME: take this piece of crap out */ +static void +freq_dots_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i, basex; + + basex = (pn_image_data->width>>1)-128; + for (i=basex < 0 ? -basex : 0 ; i < 256; i++) + { + pn_image_data->surface[0][PN_IMG_INDEX (basex+i, (pn_image_data->height>>1) + - CAP (pn_sound_data->freq_data[0][i], 120))] + = 0xff; + pn_image_data->surface[0][PN_IMG_INDEX (basex+256-i, (pn_image_data->height>>1) + + CAP (pn_sound_data->freq_data[1][i], 120))] + = 0xff; + } +} + +struct pn_actuator_desc builtin_freq_dots = +{ + "freq_dots", + "Frequency Scope", + "Draws dots varying vertically with the freqency data.", + 0, NULL, + NULL, NULL, freq_dots_exec +}; + +/* **************** freq_drops **************** */ +static void +freq_drops_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i,j; + + for (i=0; i<256; i++) + for (j=0; j<pn_sound_data->freq_data[0][i]>>3; i++) + pn_image_data->surface[0][PN_IMG_INDEX (rand() % pn_image_data->width, + rand() % pn_image_data->height)] + = 0xff; +} + +struct pn_actuator_desc builtin_freq_drops = +{ + "freq_drops", + "Random Dots", + "Draws dots at random on the image (louder music = more dots)", + 0, NULL, + NULL, NULL, freq_drops_exec +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/general.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,311 @@ +/* FIXME: what to name this file? */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +/* **************** general_fade **************** */ +static struct pn_actuator_option_desc general_fade_opts[] = +{ + { "amount", "The amount by which the color index of each " + "pixel should be decreased by each frame (MAX 255)", + OPT_TYPE_INT, { ival: 3 } }, + { NULL } +}; + +static void +general_fade_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int amt = opts[0].val.ival > 255 || opts[0].val.ival < 0 ? 3 : opts[0].val.ival; + int i, j; + + for (j=0; j<pn_image_data->height; j++) + for (i=0; i<pn_image_data->width; i++) + pn_image_data->surface[0][PN_IMG_INDEX (i, j)] = + CAPLO (pn_image_data->surface[0][PN_IMG_INDEX (i, j)] + - amt, 0); +} + +struct pn_actuator_desc builtin_general_fade = +{ + "general_fade", "Fade-out", "Decreases the color index of each pixel", + 0, general_fade_opts, + NULL, NULL, general_fade_exec +}; + +/* **************** general_blur **************** */ +/* FIXME: add a variable radius */ +/* FIXME: SPEEEED */ +static void +general_blur_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i,j; + register guchar *srcptr = pn_image_data->surface[0]; + register guchar *destptr = pn_image_data->surface[1]; + register int sum; + + for (j=0; j<pn_image_data->height; j++) + for (i=0; i<pn_image_data->width; i++) + { + sum = *(srcptr)<<2; + + /* top */ + if (j > 0) + { + sum += *(srcptr-pn_image_data->width)<<1; + if (i > 0) + sum += *(srcptr-pn_image_data->width-1); + if (i < pn_image_data->width-1) + sum += *(srcptr-pn_image_data->width+1); + } + /* bottom */ + if (j < pn_image_data->height-1) + { + sum += *(srcptr+pn_image_data->width)<<1; + if (i > 0) + sum += *(srcptr+pn_image_data->width-1); + if (i < pn_image_data->width-1) + sum += *(srcptr+pn_image_data->width+1); + } + /* left */ + if (i > 0) + sum += *(srcptr-1)<<1; + /* right */ + if (i < pn_image_data->width-1) + sum += *(srcptr+1)<<1; + + *destptr++ = (guchar)(sum >> 4); + srcptr++; + } + + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_general_blur = +{ + "general_blur", "Blur", "A simple 1 pixel radius blur", + 0, NULL, + NULL, NULL, general_blur_exec +}; + +/* **************** general_mosaic **************** */ +/* FIXME: add a variable radius */ +/* FIXME: SPEEEED */ +static struct pn_actuator_option_desc general_mosaic_opts[] = +{ + { "radius", "The pixel radius that should be used for the effect.", + OPT_TYPE_INT, { ival: 6 } }, + { NULL } +}; + +static void +general_mosaic_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i,j; + register guchar *srcptr = pn_image_data->surface[0]; + register guchar *destptr = pn_image_data->surface[1]; + register int sum; + int radius = opts[0].val.ival > 255 || opts[0].val.ival < 0 ? 6 : opts[0].val.ival; + + for (j=0; j<pn_image_data->height; j += radius) + for (i=0; i<pn_image_data->width; i += radius) + { + int ii = 0, jj = 0; + guchar bval = 0; + + /* find the brightest colour */ + for (jj = 0; jj < radius && (j + jj < pn_image_data->height); jj++) + for (ii = 0; ii < radius && (i + ii < pn_image_data->width); ii++) + { + guchar val = srcptr[PN_IMG_INDEX(i + ii, j + jj)]; + + if (val > bval) + bval = val; + } + + for (jj = 0; jj < radius && (j + jj < pn_image_data->height); jj++) + for (ii = 0; ii < radius && (i + ii < pn_image_data->width); ii++) + { + destptr[PN_IMG_INDEX(i + ii, j + jj)] = bval; + } + } + + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_general_mosaic = +{ + "general_mosaic", "Mosaic", "A simple mosaic effect.", + 0, general_mosaic_opts, + NULL, NULL, general_mosaic_exec +}; + +/* **************** general_clear **************** */ +static void +general_clear_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + memset(pn_image_data->surface[0], '\0', + (pn_image_data->height * pn_image_data->width)); +} + +struct pn_actuator_desc builtin_general_clear = +{ + "general_clear", "Clear Surface", "Clears the surface.", + 0, NULL, + NULL, NULL, general_clear_exec +}; + +/* **************** general_noop **************** */ +static void +general_noop_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + return; +} + +struct pn_actuator_desc builtin_general_noop = +{ + "general_noop", "Do Nothing", "Does absolutely nothing.", + 0, NULL, + NULL, NULL, general_noop_exec +}; + +/* **************** general_invert **************** */ +static void +general_invert_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i, j; + + for (j=0; j < pn_image_data->height; j++) + for (i=0; i < pn_image_data->width; i++) + pn_image_data->surface[0][PN_IMG_INDEX (i, j)] = + 255 - pn_image_data->surface[0][PN_IMG_INDEX (i, j)]; +} + +struct pn_actuator_desc builtin_general_invert = +{ + "general_invert", "Value Invert", "Performs a value invert.", + 0, NULL, + NULL, NULL, general_invert_exec +}; + +/* **************** general_replace **************** */ +static struct pn_actuator_option_desc general_replace_opts[] = +{ + { "start", "The beginning colour value that should be replaced by the value of out.", + OPT_TYPE_INT, { ival: 250 } }, + { "end", "The ending colour value that should be replaced by the value of out.", + OPT_TYPE_INT, { ival: 255 } }, + { "out", "The colour value that in is replaced with.", + OPT_TYPE_INT, { ival: 0 } }, + { NULL } +}; + +static void +general_replace_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + register int i, j; + register guchar val; + guchar begin = opts[0].val.ival > 255 || opts[0].val.ival < 0 ? 250 : opts[0].val.ival; + guchar end = opts[1].val.ival > 255 || opts[1].val.ival < 0 ? 255 : opts[1].val.ival; + guchar out = opts[2].val.ival > 255 || opts[2].val.ival < 0 ? 0 : opts[2].val.ival; + + for (j=0; j < pn_image_data->height; j++) + for (i=0; i < pn_image_data->width; i++) + { + val = pn_image_data->surface[0][PN_IMG_INDEX (i, j)]; + if (val >= begin && val <= end) + pn_image_data->surface[0][PN_IMG_INDEX (i, j)] = out; + } +} + +struct pn_actuator_desc builtin_general_replace = +{ + "general_replace", "Value Replace", "Performs a value replace on a range of values.", + 0, general_replace_opts, + NULL, NULL, general_replace_exec +}; + +/* **************** general_swap **************** */ +static void +general_swap_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_general_swap = +{ + "general_swap", "Swap Surface", "Swaps the surface.", + 0, NULL, + NULL, NULL, general_swap_exec +}; + +/* **************** general_copy **************** */ +static void +general_copy_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + memcpy(pn_image_data->surface[1], pn_image_data->surface[0], + (pn_image_data->width * pn_image_data->height)); +} + +struct pn_actuator_desc builtin_general_copy = +{ + "general_copy", "Copy Surface", "Copies the surface to the other surface.", + 0, NULL, + NULL, NULL, general_copy_exec +}; + +/* **************** general_flip **************** */ +static struct pn_actuator_option_desc general_flip_opts[] = +{ + { "direction", "Negative is horizontal, positive is vertical.", + OPT_TYPE_INT, { ival: -1 } }, + { NULL } +}; + +static void +general_flip_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + gint x, y; + + if (opts[0].val.ival < 0) + { + for (y = 0; y < pn_image_data->height; y++) + for (x = 0; x < pn_image_data->width; x++) + { + pn_image_data->surface[1][PN_IMG_INDEX(pn_image_data->width - x, y)] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + } + } + else + { + for (y = 0; y < pn_image_data->height; y++) + for (x = 0; x < pn_image_data->width; x++) + { + pn_image_data->surface[1][PN_IMG_INDEX(x, pn_image_data->height - y)] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + } + } + + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_general_flip = +{ + "general_flip", "Flip Surface", "Flips the surface.", + 0, general_flip_opts, + NULL, NULL, general_flip_exec +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/Makefile Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,19 @@ +include ../../../mk/rules.mk +include ../../../mk/init.mk + +OBJECTIVE_LIBS_NOINST = libcalc.a + +LIBDIR = $(plugindir)/$(VISUALIZATION_PLUGIN_DIR) + +LIBADD = $(GTK_LIBS) $(XML_LIBS) $(SDL_LIBS) + +SOURCES = dict.c execute.c function.c parser.c storage.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) $(ARCH_DEFINES) $(XML_CPPFLAGS) $(SDL_CFLAGS) -I../../intl -I../.. + +include ../../../mk/objective.mk + +libcalc.a: $(OBJECTS) + $(AR) cq $@ $(OBJECTS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/calc.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,30 @@ +/* calc.h -- an all-in-one include file for libcalc + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_CALC_H +#define Included_CALC_H + +#include "dict.h" +#include "execute.h" +#include "parser.h" +#include "storage.h" + +#endif /* Included_CALC_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/dict.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,99 @@ +/* dict.c -- symbol dictionary structures + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define V_SPACE_INIT 8 +#define V_SPACE_INCR 8 + +#include <glib.h> +#include <string.h> + +#include "dict.h" + +static void more_variables (symbol_dict_t *dict) { + var_t *new_var; + + dict->v_space += V_SPACE_INCR; + + new_var = (var_t *)g_malloc (dict->v_space * sizeof(var_t)); + + memcpy (new_var, dict->variables, dict->v_count * sizeof(var_t)); + g_free (dict->variables); + + dict->variables = new_var; +} + +symbol_dict_t *dict_new (void) { + symbol_dict_t *dict; + + dict = (symbol_dict_t *) g_malloc (sizeof(symbol_dict_t)); + + /* Allocate space for variables. */ + dict->v_count = 0; + dict->v_space = V_SPACE_INIT; + dict->variables = (var_t *)g_malloc (dict->v_space * sizeof(var_t)); + + return dict; +} + +void dict_free (symbol_dict_t *dict) { + int i; + + if (!dict) + return; + + /* Free memory used by variables. */ + for (i = 0; i < dict->v_count; i++) + g_free (dict->variables[i].name); + g_free (dict->variables); + + g_free (dict); +} + +static int dict_define_variable (symbol_dict_t *dict, const char *name) { + var_t *var; + + if (dict->v_count >= dict->v_space) + more_variables (dict); + + var = &dict->variables[dict->v_count]; + + var->value = 0.0; + var->name = g_strdup (name); + + return dict->v_count++; +} + +int dict_lookup (symbol_dict_t *dict, const char *name) { + int i; + + for (i = 0; i < dict->v_count; i++) { + if (strcmp (dict->variables[i].name, name) == 0) + return i; + } + + /* Not defined -- define a new variable. */ + return dict_define_variable (dict, name); +} + +double *dict_variable (symbol_dict_t *dict, const char *var_name) { + int id = dict_lookup (dict, var_name); + return &dict->variables[id].value; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/dict.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,46 @@ +/* dict.h -- symbol dictionary structures + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_DICT_H +#define Included_DICT_H + +/* A variable. */ +typedef struct { + char *name; + double value; +} var_t; + +/* A symbol dictionary. */ +typedef struct { + /* Variables. */ + var_t *variables; + int v_count; + int v_space; +} symbol_dict_t; + +/* Prototypes. */ +symbol_dict_t *dict_new (void); +void dict_free (symbol_dict_t *dict); + +int dict_lookup (symbol_dict_t *calc, const char *name); +double* dict_variable (symbol_dict_t *calc, const char *var_name); + +#endif /* Included_DICT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/execute.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,121 @@ +/* execute.c -- execute precompiled expression expr + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib.h> +#include <math.h> + +#include "execute.h" +#include "function.h" + +/* Execution stack. */ + +gboolean check_stack (ex_stack *stack, int depth) { + if (stack->sp < depth) { + g_warning ("Stack error"); + return FALSE; + } + + return TRUE; +} + +void push (ex_stack *stack, double value) { + g_assert (stack); + + if (stack->sp < STACK_DEPTH) { + stack->value[stack->sp++] = value; + } else { + g_warning ("Stack overflow"); + } +} + +double pop (ex_stack *stack) { + g_assert (stack); + + if (stack->sp > 0) { + return stack->value[--stack->sp]; + } else { + g_warning ("Stack error (stack empty)"); + return 0.0; + } +} + +/* */ + +void expr_execute (expression_t *expr, symbol_dict_t *dict) { + char op, *str = expr->data->str; + ex_stack stack = { 0, { 0.0 }}; + + while ((op = *str++)) { + switch (op) { + case 'l': /* Load a variable. */ + push (&stack, dict->variables[load_int (str)].value); + str += sizeof (int); + break; + + case 's': /* Store to a variable. */ + dict->variables[load_int (str)].value = pop (&stack); + str += sizeof (int); + break; + + case 'f': /* Call a function. */ + function_call (load_int (str), &stack); + str += sizeof (int); + break; + + case 'c': /* Load a constant. */ + push (&stack, load_double (str)); + str += sizeof (double); + break; + + case 'n': /* Do a negation. */ + push (&stack, -pop (&stack)); + break; + + case '+': /* Do an addition. */ + push (&stack, pop (&stack) + pop (&stack)); + break; + case '-': /* Do a subtraction. */ + push (&stack, pop (&stack) - pop (&stack)); + break; + case '*': /* Do a multiplication. */ + push (&stack, pop (&stack) * pop (&stack)); + break; + case '/': /* Do a division. */ + if (check_stack (&stack, 2)) { + double y = stack.value[stack.sp - 2] / stack.value[stack.sp - 1]; + stack.sp -= 2; + push (&stack, y); + } + break; + case '^': /* Do an exponentiation. */ + if (check_stack (&stack, 2)) { + double y = pow (stack.value[stack.sp - 2], stack.value[stack.sp - 1]); + stack.sp -= 2; + push (&stack, y); + } + break; + + default: + g_warning ("Invalid opcode: %c", op); + return; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/execute.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,46 @@ +/* execute.h -- execute precompiled expression code + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_EXECUTE_H +#define Included_EXECUTE_H + +#include <glib.h> + +#include "dict.h" +#include "storage.h" + +/* Execution stack. */ + +typedef struct { +#define STACK_DEPTH 64 + int sp; /* stack pointer */ + double value[STACK_DEPTH]; +} ex_stack; + +/* Prototypes. */ + +gboolean check_stack (ex_stack *stack, int depth); +void push (ex_stack *stack, double value); +double pop (ex_stack *stack); + +void expr_execute (expression_t *expr, symbol_dict_t *dict); + +#endif /* Included_EXECUTE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/function.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,106 @@ +/* function.c -- + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib.h> +#include <math.h> +#include <string.h> + +#include "function.h" + +/* Function pointer type. */ +typedef struct { + char *name; + double (*funcptr)(ex_stack *stack); +} func_t; + +/* */ + +static double f_log (ex_stack *stack) { + return log (pop (stack)); +} + +static double f_sin (ex_stack *stack) { + return sin (pop (stack)); +} + +static double f_cos (ex_stack *stack) { + return cos (pop (stack)); +} + +static double f_tan (ex_stack *stack) { + return tan (pop (stack)); +} + +static double f_asin (ex_stack *stack) { + return asin (pop (stack)); +} + +static double f_acos (ex_stack *stack) { + return acos (pop (stack)); +} + +static double f_atan (ex_stack *stack) { + return atan (pop (stack)); +} + +static double f_if (ex_stack *stack) { + double a = pop (stack); + double b = pop (stack); + return (pop (stack) != 0.0) ? a : b; +} + +static double f_div (ex_stack *stack) { + int y = (int)pop (stack); + int x = (int)pop (stack); + return (y == 0) ? 0 : (x / y); +} + +/* */ + +static const func_t init[] = { + { "sin", f_sin }, + { "cos", f_cos }, + { "tan", f_tan }, + { "asin", f_asin }, + { "acos", f_acos }, + { "atan", f_atan }, + { "log", f_log }, + { "if", f_if }, + { "div", f_div } +}; + +int function_lookup (const char *name) { + int i; + + for (i = 0; i < sizeof (init) / sizeof (init[0]); i++) + if (strcmp (init[i].name, name) == 0) + return i; + + g_warning ("Unknown function: %s\n", name); + return -1; +} + +void function_call (int func_id, ex_stack *stack) { + g_assert (func_id >= 0); + g_assert (func_id < sizeof (init) / sizeof (init[0])); + + push (stack, (*init[func_id].funcptr)(stack)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/function.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,32 @@ +/* function.h -- + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_FUNCTION +#define Included_FUNCTION + +#include "execute.h" + +/* Prototypes. */ + +int function_lookup (const char *name); +void function_call (int func_id, ex_stack *stack); + +#endif /* Included_FUNCTION */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/parser.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,1521 @@ +/* A Bison parser, made by GNU Bison 1.875d. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + + 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; either version 2, or (at your option) + any later version. + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + NAME = 258, + NUMBER = 259, + NEG = 260 + }; +#endif +#define NAME 258 +#define NUMBER 259 +#define NEG 260 + + + + +/* Copy the first part of user declarations. */ +#line 26 "parser.y" + +#include <ctype.h> +#include <glib.h> +#include <locale.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include "dict.h" +#include "execute.h" +#include "function.h" +#include "parser.h" +#include "storage.h" + +#define YYPARSE_PARAM yyparam +#define YYLEX_PARAM yyparam + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str); + +#define GENERATE(str) if (!expr_add_compile (((parser_control *)yyparam)->expr, \ + ((parser_control *)yyparam)->dict, str)) \ + YYABORT; + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 54 "parser.y" +typedef union YYSTYPE { +char *s_value; +char c_value; +double d_value; +int i_value; +} YYSTYPE; +/* Line 191 of yacc.c. */ +#line 118 "parser.c" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 130 "parser.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +# ifndef YYFREE +# define YYFREE free +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# endif + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# endif +# else +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (defined (YYSTYPE_IS_TRIVIAL) && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short int yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short int) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined (__GNUC__) && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short int yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 65 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 18 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 5 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 22 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 37 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 260 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 14, 15, 8, 7, 13, 6, 2, 9, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, + 17, 5, 16, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 11, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 10 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 4, 7, 8, 10, 13, 16, 18, + 22, 24, 26, 30, 35, 39, 43, 47, 51, 55, + 59, 62, 66 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 19, 0, -1, -1, 19, 20, -1, -1, 22, -1, + 20, 12, -1, 1, 12, -1, 22, -1, 21, 13, + 22, -1, 4, -1, 3, -1, 3, 5, 22, -1, + 3, 14, 21, 15, -1, 22, 16, 22, -1, 22, + 17, 22, -1, 22, 7, 22, -1, 22, 6, 22, + -1, 22, 8, 22, -1, 22, 9, 22, -1, 6, + 22, -1, 22, 11, 22, -1, 14, 22, 15, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned char yyrline[] = +{ + 0, 76, 76, 77, 81, 82, 84, 85, 90, 93, + 98, 104, 110, 116, 123, 125, 128, 130, 132, 134, + 136, 138, 140 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "NAME", "NUMBER", "'='", "'-'", "'+'", + "'*'", "'/'", "NEG", "'^'", "';'", "','", "'('", "')'", "'>'", "'<'", + "$accept", "input", "expression_list", "argument_list", "expression", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short int yytoknum[] = +{ + 0, 256, 257, 258, 259, 61, 45, 43, 42, 47, + 260, 94, 59, 44, 40, 41, 62, 60 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 18, 19, 19, 20, 20, 20, 20, 21, 21, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 0, 2, 0, 1, 2, 2, 1, 3, + 1, 1, 3, 4, 3, 3, 3, 3, 3, 3, + 2, 3, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 2, 0, 1, 0, 11, 10, 0, 0, 3, 5, + 7, 0, 0, 20, 0, 6, 0, 0, 0, 0, + 0, 0, 0, 12, 0, 8, 22, 17, 16, 18, + 19, 21, 14, 15, 0, 13, 9 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 1, 8, 24, 9 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -10 +static const yysigned_char yypact[] = +{ + -10, 17, -10, -8, 22, -10, 47, 47, -3, 38, + -10, 47, 47, -9, 26, -10, 47, 47, 47, 47, + 47, 47, 47, 38, 9, 38, -10, 48, 48, -9, + -9, -9, 38, 38, 47, -10, 38 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -10, -10, -10, -10, -6 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -5 +static const yysigned_char yytable[] = +{ + 13, 14, 20, 0, 10, 23, 25, 21, 22, 15, + 27, 28, 29, 30, 31, 32, 33, 2, 3, 0, + 4, 5, 34, 6, 35, 0, 0, 11, 36, -4, + 0, 7, 16, 17, 18, 19, 12, 20, 0, 0, + 0, 26, 21, 22, 16, 17, 18, 19, 0, 20, + 4, 5, 0, 6, 21, 22, 18, 19, 0, 20, + 0, 7, 0, 0, 21, 22 +}; + +static const yysigned_char yycheck[] = +{ + 6, 7, 11, -1, 12, 11, 12, 16, 17, 12, + 16, 17, 18, 19, 20, 21, 22, 0, 1, -1, + 3, 4, 13, 6, 15, -1, -1, 5, 34, 12, + -1, 14, 6, 7, 8, 9, 14, 11, -1, -1, + -1, 15, 16, 17, 6, 7, 8, 9, -1, 11, + 3, 4, -1, 6, 16, 17, 8, 9, -1, 11, + -1, 14, -1, -1, 16, 17 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 19, 0, 1, 3, 4, 6, 14, 20, 22, + 12, 5, 14, 22, 22, 12, 6, 7, 8, 9, + 11, 16, 17, 22, 21, 22, 15, 22, 22, 22, + 22, 22, 22, 22, 13, 15, 22 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + ((Current).first_line = (Rhs)[1].first_line, \ + (Current).first_column = (Rhs)[1].first_column, \ + (Current).last_line = (Rhs)[N].last_line, \ + (Current).last_column = (Rhs)[N].last_column) +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short int *bottom, short int *top) +#else +static void +yy_stack_print (bottom, top) + short int *bottom; + short int *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if defined (YYMAXDEPTH) && YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + /* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short int yyssa[YYINITDEPTH]; + short int *yyss = yyssa; + register short int *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short int *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short int *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 5: +#line 83 "parser.y" + { ;} + break; + + case 7: +#line 86 "parser.y" + { yyerrok; ;} + break; + + case 8: +#line 91 "parser.y" + { + ;} + break; + + case 9: +#line 94 "parser.y" + { + ;} + break; + + case 10: +#line 99 "parser.y" + { + char *buf = g_strdup_printf ("c%f:", yyvsp[0].d_value); + GENERATE (buf); + g_free (buf); + ;} + break; + + case 11: +#line 105 "parser.y" + { + char *buf = g_strdup_printf ("l%s:", yyvsp[0].s_value); + GENERATE (buf); + g_free (buf); + ;} + break; + + case 12: +#line 111 "parser.y" + { + char *buf = g_strdup_printf ("s%s:", yyvsp[-2].s_value); + GENERATE (buf); + g_free (buf); + ;} + break; + + case 13: +#line 117 "parser.y" + { + char *buf = g_strdup_printf ("f%s:", yyvsp[-3].s_value); + GENERATE (buf); + g_free (buf); + ;} + break; + + case 14: +#line 124 "parser.y" + { GENERATE (">"); ;} + break; + + case 15: +#line 126 "parser.y" + { GENERATE ("<"); ;} + break; + + case 16: +#line 129 "parser.y" + { GENERATE ("+"); ;} + break; + + case 17: +#line 131 "parser.y" + { GENERATE ("-"); ;} + break; + + case 18: +#line 133 "parser.y" + { GENERATE ("*"); ;} + break; + + case 19: +#line 135 "parser.y" + { GENERATE ("/"); ;} + break; + + case 20: +#line 137 "parser.y" + { GENERATE ("n"); ;} + break; + + case 21: +#line 139 "parser.y" + { GENERATE ("^"); ;} + break; + + case 22: +#line 141 "parser.y" + { ;} + break; + + + } + +/* Line 1010 of yacc.c. */ +#line 1140 "parser.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + const char* yyprefix; + char *yymsg; + int yyx; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 0; + + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yysize += yystrlen (yyprefix) + yystrlen (yytname [yyx]); + yycount += 1; + if (yycount == 5) + { + yysize = 0; + break; + } + } + yysize += (sizeof ("syntax error, unexpected ") + + yystrlen (yytname[yytype])); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yyprefix = ", expecting "; + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + yyp = yystpcpy (yyp, yyprefix); + yyp = yystpcpy (yyp, yytname[yyx]); + yyprefix = " or "; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* If at end of input, pop the error token, + then the rest of the stack, then return failure. */ + if (yychar == YYEOF) + for (;;) + { + YYPOPSTACK; + if (yyssp == yyss) + YYABORT; + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + } + } + else + { + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + +#ifdef __GNUC__ + /* Pacify GCC when the user code never invokes YYERROR and the label + yyerrorlab therefore never appears in user code. */ + if (0) + goto yyerrorlab; +#endif + + yyvsp -= yylen; + yyssp -= yylen; + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + YYPOPSTACK; + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 144 "parser.y" + +/* End of grammar */ + +/* Called by yyparse on error. */ +int yyerror (char *s) { + /* Ignore errors, just print a warning. */ + g_warning ("%s\n", s); + return 0; +} + +int yylex (YYSTYPE *yylval, void *yyparam) { + int c; + parser_control *pc = (parser_control *) yyparam; + + /* Ignore whitespace, get first nonwhite character. */ + while ((c = vfs_getc (pc->input)) == ' ' || c == '\t' || c == '\n'); + + /* End of input ? */ + if (c == EOF) + return 0; + + /* Char starts a number => parse the number. */ + if (isdigit (c)) { + vfs_fseek (pc->input, -1, SEEK_CUR); /* Put the char back. */ + { + char *old_locale, *saved_locale; + + old_locale = setlocale (LC_ALL, NULL); + saved_locale = g_strdup (old_locale); + setlocale (LC_ALL, "C"); + sscanf (((VFSBuffer *)(pc->input->handle))->iter, "%lf", &yylval->d_value); + + while (isdigit(c) || c == '.') + { + c = vfs_getc(pc->input); + } + + vfs_fseek(pc->input, -1, SEEK_CUR); + + setlocale (LC_ALL, saved_locale); + g_free (saved_locale); + } + return NUMBER; + } + + /* Char starts an identifier => read the name. */ + if (isalpha (c)) { + GString *sym_name; + + sym_name = g_string_new (NULL); + + do { + sym_name = g_string_append_c (sym_name, c); + + /* Get another character. */ + c = vfs_getc (pc->input); + } while (c != EOF && isalnum (c)); + + vfs_fseek (pc->input, -1, SEEK_CUR); + + yylval->s_value = sym_name->str; + + g_string_free (sym_name, FALSE); + + return NAME; + } + + /* Any other character is a token by itself. */ + return c; +} + +static int load_name (char *str, char **name) { + int count = 0; + GString *new = g_string_new (NULL); + + while (*str != 0 && *str != ':') { + g_string_append_c (new, *str++); + count++; + } + + *name = new->str; + g_string_free (new, FALSE); + + return count; +} + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str) { + char op; + double dval; + int i; + char *name; + + while ((op = *str++)) { + switch (op) { + case 'c': /* A constant. */ + store_byte (expr, 'c'); + sscanf (str, "%lf%n", &dval, &i); + str += i; + store_double (expr, dval); + str++; /* Skip ';' */ + break; + + case 'f': /* A function call. */ + store_byte (expr, 'f'); + str += load_name (str, &name); + i = function_lookup (name); + if (i < 0) return FALSE; /* Fail on error. */ + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + case 'l': /* Load a variable. */ + case 's': /* Store a variable. */ + store_byte (expr, op); + str += load_name (str, &name); + i = dict_lookup (dict, name); + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + default: /* Copy verbatim. */ + store_byte (expr, op); + break; + } + } + + return TRUE; +} + +expression_t *expr_compile_string (const char* str, symbol_dict_t *dict) +{ + parser_control pc; + VFSFile *stream; + + g_return_val_if_fail(str != NULL && dict != NULL, NULL); + + stream = vfs_buffer_new_from_string ( (char *) str ); + + pc.input = stream; + pc.expr = expr_new (); + pc.dict = dict; + + if (yyparse (&pc) != 0) { + /* Check for error. */ + expr_free (pc.expr); + pc.expr = NULL; + } + + vfs_fclose (stream); + + return pc.expr; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/parser.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,42 @@ +/* parser.h -- header file for libexp + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_PARSER_H +#define Included_PARSER_H + +#include <glib.h> +#include <stdio.h> +#include <audacious/vfs.h> +#include <audacious/vfs_buffer.h> + +#include "execute.h" + +/* Structure passed do yyparse. */ +typedef struct { + VFSFile *input; + expression_t *expr; + symbol_dict_t *dict; +} parser_control; + +/* Prototypes. */ +expression_t *expr_compile_string (const char *str, symbol_dict_t *dict); + +#endif /* Included_PARSER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/parser.y Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,298 @@ +/* parser.y -- Bison parser for libexp + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* suppress conflict warnings */ +%expect 37 + +/* C declarations. */ +%{ +#include <ctype.h> +#include <glib.h> +#include <locale.h> +#include <math.h> +#include <stdio.h> +#include <string.h> + +#include "dict.h" +#include "execute.h" +#include "function.h" +#include "parser.h" +#include "storage.h" + +#define YYPARSE_PARAM yyparam +#define YYLEX_PARAM yyparam + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str); + +#define GENERATE(str) if (!expr_add_compile (((parser_control *)yyparam)->expr, \ + ((parser_control *)yyparam)->dict, str)) \ + YYABORT; +%} + +%pure_parser + +/* Data types. */ +%union { +char *s_value; +char c_value; +double d_value; +int i_value; +} + +/* Terminal symbols. */ +%token <s_value> NAME +%token <d_value> NUMBER + +/* Precedence rules. */ +%right '=' +%left '-' '+' +%left '*' '/' +%left NEG +%right '^' + +/* Grammar follows */ +%% + +/* Input consits of a (possibly empty) list of expressions. */ +input: /* empty */ + | input expression_list +; + +/* expression_list is a ';' separated list of expressions. */ +expression_list: /* empty */ + | expression + { } + | expression_list ';' + | error ';' + { yyerrok; } + +/* argument list is a comma separated list od expressions */ +argument_list: + expression + { + } + | argument_list ',' expression + { + } + +/* expression is a C-like expression. */ +expression: NUMBER + { + char *buf = g_strdup_printf ("c%f:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME + { + char *buf = g_strdup_printf ("l%s:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME '=' expression + { + char *buf = g_strdup_printf ("s%s:", $1); + GENERATE (buf); + g_free (buf); + } + | NAME '(' argument_list ')' + { + char *buf = g_strdup_printf ("f%s:", $1); + GENERATE (buf); + g_free (buf); + } + + | expression '>' expression + { GENERATE (">"); } + | expression '<' expression + { GENERATE ("<"); } + + | expression '+' expression + { GENERATE ("+"); } + | expression '-' expression + { GENERATE ("-"); } + | expression '*' expression + { GENERATE ("*"); } + | expression '/' expression + { GENERATE ("/"); } + | '-' expression %prec NEG + { GENERATE ("n"); } + | expression '^' expression + { GENERATE ("^"); } + | '(' expression ')' + { } +; + +%% +/* End of grammar */ + +/* Called by yyparse on error. */ +int yyerror (char *s) { + /* Ignore errors, just print a warning. */ + g_warning ("%s\n", s); + return 0; +} + +int yylex (YYSTYPE *yylval, void *yyparam) { + int c; + parser_control *pc = (parser_control *) yyparam; + + /* Ignore whitespace, get first nonwhite character. */ + while ((c = vfs_getc (pc->input)) == ' ' || c == '\t' || c == '\n'); + + /* End of input ? */ + if (c == EOF) + return 0; + + /* Char starts a number => parse the number. */ + if (isdigit (c)) { + vfs_fseek (pc->input, -1, SEEK_CUR); /* Put the char back. */ + { + char *old_locale, *saved_locale; + + old_locale = setlocale (LC_ALL, NULL); + saved_locale = g_strdup (old_locale); + setlocale (LC_ALL, "C"); + sscanf (((VFSBuffer *)(pc->input->handle))->iter, "%lf", &yylval->d_value); + + while (isdigit(c) || c == '.') + { + c = vfs_getc(pc->input); + } + + vfs_fseek(pc->input, -1, SEEK_CUR); + + setlocale (LC_ALL, saved_locale); + g_free (saved_locale); + } + return NUMBER; + } + + /* Char starts an identifier => read the name. */ + if (isalpha (c)) { + GString *sym_name; + + sym_name = g_string_new (NULL); + + do { + sym_name = g_string_append_c (sym_name, c); + + /* Get another character. */ + c = vfs_getc (pc->input); + } while (c != EOF && isalnum (c)); + + vfs_fseek (pc->input, -1, SEEK_CUR); + + yylval->s_value = sym_name->str; + + g_string_free (sym_name, FALSE); + + return NAME; + } + + /* Any other character is a token by itself. */ + return c; +} + +static int load_name (char *str, char **name) { + int count = 0; + GString *new = g_string_new (NULL); + + while (*str != 0 && *str != ':') { + g_string_append_c (new, *str++); + count++; + } + + *name = new->str; + g_string_free (new, FALSE); + + return count; +} + +static gboolean expr_add_compile (expression_t *expr, symbol_dict_t *dict, + char *str) { + char op; + double dval; + int i; + char *name; + + while ((op = *str++)) { + switch (op) { + case 'c': /* A constant. */ + store_byte (expr, 'c'); + sscanf (str, "%lf%n", &dval, &i); + str += i; + store_double (expr, dval); + str++; /* Skip ';' */ + break; + + case 'f': /* A function call. */ + store_byte (expr, 'f'); + str += load_name (str, &name); + i = function_lookup (name); + if (i < 0) return FALSE; /* Fail on error. */ + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + case 'l': /* Load a variable. */ + case 's': /* Store a variable. */ + store_byte (expr, op); + str += load_name (str, &name); + i = dict_lookup (dict, name); + store_int (expr, i); + g_free (name); + str++; /* Skip ';' */ + break; + + default: /* Copy verbatim. */ + store_byte (expr, op); + break; + } + } + + return TRUE; +} + +expression_t *expr_compile_string (const char* str, symbol_dict_t *dict) +{ + parser_control pc; + VFSFile *stream; + + g_return_val_if_fail(str != NULL && dict != NULL, NULL); + + stream = vfs_buffer_new_from_string ( (char *) str ); + + pc.input = stream; + pc.expr = expr_new (); + pc.dict = dict; + + if (yyparse (&pc) != 0) { + /* Check for error. */ + expr_free (pc.expr); + pc.expr = NULL; + } + + vfs_fclose (stream); + + return pc.expr; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/storage.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,79 @@ +/* storage.c -- + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <glib.h> +#include <stddef.h> + +#include "storage.h" + +/* Code block. */ + +expression_t *expr_new (void) { + expression_t *new_expr; + + new_expr = (expression_t *)g_malloc (sizeof(expression_t)); + new_expr->data = g_string_new (NULL); + return new_expr; +} + +void expr_free (expression_t *expr) { + if (!expr) + return; + + g_string_free (expr->data, TRUE); + g_free (expr); +} + +static void load_data (char *str, void *dest, size_t size) { + char *ch = (char *)dest; + while (size--) + *ch++ = *str++; +} + +int load_int (char *str) { + int val; + load_data (str, &val, sizeof(val)); + return val; +} + +double load_double (char *str) { + double val; + load_data (str, &val, sizeof(val)); + return val; +} + +static void store_data (expression_t *expr, void *src, size_t size) { + char *ch = (char *)src; + while (size--) + store_byte (expr, *ch++); +} + +void store_byte (expression_t *expr, char byte) { + g_string_append_c (expr->data, byte); +} + +void store_int (expression_t *expr, int val) { + store_data (expr, &val, sizeof(val)); +} + +void store_double (expression_t *expr, double val) { + store_data (expr, &val, sizeof(val)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/libcalc/storage.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,42 @@ +/* storage.h -- + * + * Copyright (C) 2001 Janusz Gregorczyk <jgregor@kki.net.pl> + * + * This file is part of xvs. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef Included_STORAGE_H +#define Included_STORAGE_H + +#include <glib.h> + +typedef struct { + GString *data; +} expression_t; + +/* Expr block. */ +expression_t *expr_new (void); +void expr_free (expression_t *expr); + +int load_int (char *str); +double load_double (char *str); + +void store_byte (expression_t *expr, char byte); +void store_int (expression_t *expr, int val); +void store_double (expression_t *expr, double val); + +#endif /* Included_STORAGE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/misc.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,128 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> + +#include <glib.h> + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +/* ******************** misc_floater ******************** */ +static struct pn_actuator_option_desc misc_floater_opts[] = +{ + { "value", "The colour value for the floater.", + OPT_TYPE_INT, { ival: 255 } }, + { NULL } +}; + +typedef enum +{ + float_up = 0x1, + float_down = 0x2, + float_left = 0x4, + float_right = 0x8, +} FloaterDirection; + +struct floater_state_data +{ + FloaterDirection dir; + gint x; + gint y; +}; + +static void +misc_floater_init(gpointer *data) +{ + struct floater_state_data *opaque_data = g_new0(struct floater_state_data, 1); + *data = opaque_data; + opaque_data->x = rand() % pn_image_data->width; + opaque_data->y = rand() % pn_image_data->height; + opaque_data->dir = (FloaterDirection) rand() % 15; /* sum of all dir values */ +} + +static void +misc_floater_cleanup(gpointer data) +{ + g_free(data); +} + +/* + * This implementation isn't very great. + * Anyone want to improve it? :( + */ +static void +misc_floater_exec(const struct pn_actuator_option *opts, gpointer data) +{ + struct floater_state_data *opaque_data = (struct floater_state_data *) data; + guchar value = (opts[0].val.ival < 0 || opts[0].val.ival > 255) ? 255 : opts[0].val.ival; + + /* determine the root coordinate first */ + if (opaque_data->dir & float_up) + opaque_data->y -= 1; + if (opaque_data->dir & float_down) + opaque_data->y += 1; + + if (opaque_data->dir & float_left) + opaque_data->x -= 1; + if (opaque_data->dir & float_right) + opaque_data->x += 1; + + /* make sure we're within surface boundaries. segfaults suck, afterall. */ + if (opaque_data->x + 1 <= pn_image_data->width && + opaque_data->x - 1 >= 0 && + opaque_data->y + 1 <= pn_image_data->height && + opaque_data->y - 1 >= 0) + { + /* draw it. i could use a loop here, but i don't see much reason in it, + * so i don't think i will at this time. -nenolod + */ + pn_image_data->surface[0][PN_IMG_INDEX(opaque_data->x, opaque_data->y)] = value; + pn_image_data->surface[0][PN_IMG_INDEX(opaque_data->x + 1, opaque_data->y)] = value; + pn_image_data->surface[0][PN_IMG_INDEX(opaque_data->x - 1, opaque_data->y)] = value; + pn_image_data->surface[0][PN_IMG_INDEX(opaque_data->x, opaque_data->y + 1)] = value; + pn_image_data->surface[0][PN_IMG_INDEX(opaque_data->x, opaque_data->y - 1)] = value; + } + + /* check if we need to change direction yet, and if so, do so. */ + if (pn_new_beat == TRUE) + opaque_data->dir = (FloaterDirection) rand() % 15; /* sum of all dir values */ + + /* now adjust the direction so we stay in boundary */ + if (opaque_data->x - 1 <= 0 && opaque_data->dir & float_left) + { + opaque_data->dir &= ~float_left; + opaque_data->dir |= float_right; + } + + if (opaque_data->x + 1 >= pn_image_data->width && opaque_data->dir & float_right) + { + opaque_data->dir &= ~float_right; + opaque_data->dir |= float_left; + } + + if (opaque_data->y - 1 <= 0 && opaque_data->dir & float_up) + { + opaque_data->dir &= ~float_up; + opaque_data->dir |= float_down; + } + + if (opaque_data->y + 1 >= pn_image_data->height && opaque_data->dir & float_down) + { + opaque_data->dir &= ~float_down; + opaque_data->dir |= float_up; + } +} + +struct pn_actuator_desc builtin_misc_floater = +{ + "misc_floater", + "Floating Particle", + "A floating particle.", + 0, misc_floater_opts, + misc_floater_init, misc_floater_cleanup, misc_floater_exec +}; +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/paranormal.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,234 @@ +/* FIXME: add fullscreen / screenshots */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <math.h> + +#include <SDL.h> + +#include <gtk/gtk.h> +#include <gdk/gdk.h> +#include <gdk/gdkx.h> + +#include "paranormal.h" +#include "actuators.h" + +/* SDL stuffs */ +SDL_Surface *screen; + +/* Globals */ +struct pn_rc *pn_rc; +struct pn_image_data *pn_image_data; +struct pn_sound_data *pn_sound_data; + +/* Trig Pre-Computes */ +float sin_val[360]; +float cos_val[360]; + +gboolean pn_new_beat; + +extern SDL_mutex *config_mutex; + +/* **************** drawing doodads **************** */ + +static void +blit_to_screen (void) +{ + int j; + + SDL_LockSurface (screen); + + /* FIXME: add scaling support */ + + SDL_SetPalette (screen, SDL_LOGPAL|SDL_PHYSPAL, + (SDL_Color*)pn_image_data->cmap, 0, 256); + SDL_SetAlpha (screen, 0, 255); + + for (j=0; j<pn_image_data->height; j++) + memcpy (screen->pixels + j*screen->pitch, + pn_image_data->surface[0] + j*pn_image_data->width, + pn_image_data->width); + + + SDL_UnlockSurface (screen); + + SDL_UpdateRect (screen, 0, 0, 0, 0); +} + +static void +resize_video (guint w, guint h) +{ + pn_image_data->width = w; + pn_image_data->height = h; + + if (pn_image_data->surface[0]) + g_free (pn_image_data->surface[0]); + if (pn_image_data->surface[1]) + g_free (pn_image_data->surface[1]); + + pn_image_data->surface[0] = g_malloc0 (w * h); + pn_image_data->surface[1] = g_malloc0 (w * h); + + screen = SDL_SetVideoMode (w, h, 8, SDL_HWSURFACE | + SDL_HWPALETTE | SDL_RESIZABLE); + if (! screen) + pn_fatal_error ("Unable to create a new SDL window: %s", + SDL_GetError ()); +} + +static void +take_screenshot (void) +{ + char fname[32]; + struct stat buf; + int i=0; + + do + sprintf (fname, "pn_%05d.bmp", ++i); + while (stat (fname, &buf) == 0); + + SDL_SaveBMP (screen, fname); +} + +/* FIXME: This should resize the video to a user-set + fullscreen res */ +static void +toggle_fullscreen (void) +{ + SDL_WM_ToggleFullScreen (screen); + if (SDL_ShowCursor (SDL_QUERY) == SDL_ENABLE) + SDL_ShowCursor (SDL_DISABLE); + else + SDL_ShowCursor (SDL_ENABLE); +} + +/* **************** basic renderer management **************** */ +void +pn_init (void) +{ + int i; +#ifdef FULLSCREEN_HACK + char SDL_windowhack[32]; + GdkScreen *screen; +#endif + + pn_sound_data = g_new0 (struct pn_sound_data, 1); + pn_image_data = g_new0 (struct pn_image_data, 1); + +#ifdef FULLSCREEN_HACK + screen = gdk_screen_get_default(); + sprintf(SDL_windowhack,"SDL_WINDOWID=%d", + GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(screen))); + putenv(SDL_windowhack); +#endif + + if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) < 0) + pn_fatal_error ("Unable to initialize SDL: %s", SDL_GetError ()); + +#ifndef FULLSCREEN_HACK + resize_video (640, 360); +#else + resize_video (1280, 1024); +#endif + + SDL_WM_SetCaption ("Rovascope " VERSION, PACKAGE); + + for(i=0; i<360; i++) + { + sin_val[i] = sin(i*(M_PI/180.0)); + cos_val[i] = cos(i*(M_PI/180.0)); + } +} + +void +pn_cleanup (void) +{ + SDL_FreeSurface (screen); + SDL_Quit (); + + + if (pn_image_data) + { + if (pn_image_data->surface[0]) + g_free (pn_image_data->surface[0]); + if (pn_image_data->surface[1]) + g_free (pn_image_data->surface[1]); + g_free (pn_image_data); + } + if (pn_sound_data) + g_free (pn_sound_data); +} + +/* Renders one frame and handles the SDL window */ +void +pn_render (void) +{ + SDL_Event event; + + /* Handle window events */ + while (SDL_PollEvent (&event)) + { + switch (event.type) + { + case SDL_QUIT: + pn_quit (); + g_assert_not_reached (); + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: + pn_quit (); + g_assert_not_reached (); + case SDLK_RETURN: + if (event.key.keysym.mod & (KMOD_ALT | KMOD_META)) + toggle_fullscreen (); + break; + case SDLK_BACKQUOTE: + take_screenshot (); + break; + default: + break; + } + break; + case SDL_VIDEORESIZE: + resize_video (event.resize.w, event.resize.h); + break; + } + } + + pn_new_beat = pn_is_new_beat(); + + if (pn_rc->actuator) + { + exec_actuator (pn_rc->actuator); + blit_to_screen (); + } + + if (pn_new_beat && (rand() % 4 == 0)) + { + struct pn_actuator *a; + GSList *list = *(GSList **)pn_rc->actuator->data; + + container_remove_actuator (pn_rc->actuator, list->data); + + SDL_mutexP(config_mutex); + a = rovascope_get_random_actuator(); + container_add_actuator (pn_rc->actuator, a); + SDL_mutexV(config_mutex); + } +} + +/* this MUST be called if a builtin's output is to surface[1] + (by the builtin, after it is done) */ +void +pn_swap_surfaces (void) +{ + guchar *tmp = pn_image_data->surface[0]; + pn_image_data->surface[0] = pn_image_data->surface[1]; + pn_image_data->surface[1] = tmp; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/paranormal.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,64 @@ +#ifndef _PARANORMAL_H +#define _PARANORMAL_H + +#include <glib.h> + +#include "actuators.h" + +struct pn_sound_data +{ + gint16 pcm_data[2][512]; + gint16 freq_data[2][256]; +}; + +struct pn_image_data +{ + int width, height; + struct pn_color cmap[256]; + guchar *surface[2]; +}; + +/* The executable (ie xmms.c or standalone.c) + is responsible for allocating this and filling + it with default/saved values */ +struct pn_rc +{ + struct pn_actuator *actuator; +}; + +/* core funcs */ +void pn_init (void); +void pn_cleanup (void); +void pn_render (void); +void pn_swap_surfaces (void); + +/* Implemented elsewhere (ie xmms.c or standalone.c) */ +void pn_set_rc (); +void pn_fatal_error (const char *fmt, ...); +void pn_error (const char *fmt, ...); +void pn_quit (void); + +/* Implimented in cfg.c */ +void pn_configure (void); + +/* globals used for rendering */ +extern struct pn_rc *pn_rc; +extern struct pn_sound_data *pn_sound_data; +extern struct pn_image_data *pn_image_data; + +extern gboolean pn_new_beat; + +/* global trig pre-computes */ +extern float sin_val[360]; +extern float cos_val[360]; + +/* beat detection */ +int pn_is_new_beat(void); + +struct pn_actuator *rovascope_get_random_colourmap(void); +struct pn_actuator *rovascope_get_random_general(void); +struct pn_actuator *rovascope_get_random_normal_scope(void); + +struct pn_actuator *rovascope_get_random_actuator(void); + +#endif /* _PARANORMAL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/plugin.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,468 @@ +/* FIXME: issues with not uniniting variables between + enables? I wasn't too careful about that, but it + seems to work fine. If there are problems perhaps + look for a bug there? +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <memory.h> +#include <math.h> +#include <setjmp.h> +#include <unistd.h> + +#include <glib.h> +#include <glib/gi18n.h> + +#include <gtk/gtk.h> +#include <audacious/plugin.h> +#include <SDL/SDL.h> +#include <SDL/SDL_thread.h> + +#include "paranormal.h" +#include "actuators.h" +#include "containers.h" + +/* Error reporting dlg */ +static GtkWidget *err_dialog; + +/* Draw thread stuff */ +/* FIXME: Do I need mutex for pn_done? */ +static SDL_Thread *draw_thread = NULL; +static SDL_mutex *sound_data_mutex; +SDL_mutex *config_mutex; + +static gboolean pn_done = FALSE; +jmp_buf quit_jmp; +gboolean timeout_set = FALSE; +guint quit_timeout; + +/* Sound stuffs */ +static gboolean new_pcm_data = FALSE; +static gboolean new_freq_data = FALSE; +static gint16 tmp_pcm_data[2][512]; +static gint16 tmp_freq_data[2][256]; + +/* XMMS interface */ +static void pn_xmms_init (void); +static void pn_xmms_cleanup (void); +static void pn_xmms_about (void); +static void pn_xmms_configure (void); +static void pn_xmms_render_pcm (gint16 data[2][512]); +static void pn_xmms_render_freq (gint16 data[2][256]); + +static VisPlugin pn_vp = +{ + NULL, + NULL, + 0, + "Rovascope " VERSION, + 2, + 2, + pn_xmms_init, + pn_xmms_cleanup, + pn_xmms_about, + pn_xmms_configure, + NULL, /* disable_plugin */ + NULL, /* pn_xmms_playback_start */ + NULL, /* pn_xmms_playback_stop */ + pn_xmms_render_pcm, + pn_xmms_render_freq +}; + +VisPlugin * +get_vplugin_info (void) +{ + return &pn_vp; +} + +static void +load_pn_rc (void) +{ + struct pn_actuator *a, *b; + + if (! pn_rc) + pn_rc = g_new0 (struct pn_rc, 1); + + /* load a default preset */ + pn_rc->actuator = create_actuator ("container_simple"); + if (! pn_rc->actuator) goto ugh; + a = create_actuator ("container_once"); + if (! a) goto ugh; + + b = rovascope_get_random_colourmap (); + + container_add_actuator (a, b); + container_add_actuator (pn_rc->actuator, a); + + a = rovascope_get_random_normal_scope (); + if (! a) goto ugh; + container_add_actuator (pn_rc->actuator, a); + + a = create_actuator ("xform_movement"); + if (! a) goto ugh; + a->options[0].val.sval = g_strdup("d = cos(d)^2;"); + container_add_actuator (pn_rc->actuator, a); + + a = rovascope_get_random_general(); + if (! a) goto ugh; + container_add_actuator (pn_rc->actuator, a); + + a = rovascope_get_random_general(); + if (! a) goto ugh; + container_add_actuator (pn_rc->actuator, a); + + return; + + ugh: + if (pn_rc->actuator) + destroy_actuator (pn_rc->actuator); + pn_error ("Error loading default preset"); +} + +static int +draw_thread_fn (gpointer data) +{ + gfloat fps = 0.0; + guint last_time = 0, last_second = 0; + guint this_time; + pn_init (); + + /* Used when pn_quit is called from this thread */ + if (setjmp (quit_jmp) != 0) + pn_done = TRUE; + + while (! pn_done) + { + SDL_mutexP (sound_data_mutex); + if (new_freq_data) + { + memcpy (pn_sound_data->freq_data, tmp_freq_data, + sizeof (gint16) * 2 * 256); + new_freq_data = FALSE; + } + if (new_pcm_data) + { + memcpy (pn_sound_data->pcm_data, tmp_pcm_data, + sizeof (gint16) * 2 * 512); + new_freq_data = FALSE; + } + SDL_mutexV (sound_data_mutex); + SDL_mutexP (config_mutex); + pn_render (); + SDL_mutexV (config_mutex); + + /* Compute the FPS */ + this_time = SDL_GetTicks (); + + fps = fps * .95 + (1000. / (gfloat) (this_time - last_time)) * .05; + if (this_time > 2000 + last_second) + { + last_second = this_time; + g_print ("FPS: %f\n", fps); + } + last_time = this_time; + +#ifdef _POSIX_PRIORITY_SCHEDULING + sched_yield(); +#endif + } + + /* Just in case a pn_quit () was called in the loop */ +/* SDL_mutexV (sound_data_mutex); */ + + pn_cleanup (); + + return 0; +} + +/* Is there a better way to do this? this = messy + It appears that calling disable_plugin () in some + thread other than the one that called pn_xmms_init () + causes a seg fault :( */ +static int +quit_timeout_fn (gpointer data) +{ + if (pn_done) + { + pn_vp.disable_plugin (&pn_vp); + return FALSE; + } + + return TRUE; +} + +static void +pn_xmms_init (void) +{ + /* If it isn't already loaded, load the run control */ + if (! pn_rc) + load_pn_rc (); + + sound_data_mutex = SDL_CreateMutex (); + config_mutex = SDL_CreateMutex (); + if (! sound_data_mutex) + pn_fatal_error ("Unable to create a new mutex: %s", + SDL_GetError ()); + + pn_done = FALSE; + draw_thread = SDL_CreateThread (draw_thread_fn, NULL); + if (! draw_thread) + pn_fatal_error ("Unable to create a new thread: %s", + SDL_GetError ()); + + /* Add a gtk timeout to test for quits */ + quit_timeout = gtk_timeout_add (1000, quit_timeout_fn, NULL); + timeout_set = TRUE; +} + +static void +pn_xmms_cleanup (void) +{ + if (timeout_set) + { + gtk_timeout_remove (quit_timeout); + timeout_set = FALSE; + } + + if (draw_thread) + { + pn_done = TRUE; + SDL_WaitThread (draw_thread, NULL); + draw_thread = NULL; + } + + if (sound_data_mutex) + { + SDL_DestroyMutex (sound_data_mutex); + sound_data_mutex = NULL; + } + + if (config_mutex) + { + SDL_DestroyMutex (config_mutex); + config_mutex = NULL; + } +} + +static void +about_close_clicked(GtkWidget *w, GtkWidget **window) +{ + gtk_widget_destroy(*window); + *window=NULL; +} + +static void +about_closed(GtkWidget *w, GdkEvent *e, GtkWidget **window) +{ + about_close_clicked(w,window); +} + +static void +pn_xmms_about (void) +{ + xmms_show_message("About Rovascope", + +"Rovascope " VERSION "\n\n\ +Copyright (C) 2007, William Pitcock <nenolod -at- dereferenced.org>\n\ +\ +Derived from:\ +Paranormal Visualization Studio\n\ +\n\ +Copyright (C) 2006, William Pitcock <nenolod -at- nenolod.net>\n\ +Portions Copyright (C) 2001, Jamie Gennis <jgennis -at- mindspring.com>\n\ +\n\ +This program is free software; you can redistribute it and/or modify\n\ +it under the terms of the GNU General Public License as published by\n\ +the Free Software Foundation; either version 2 of the License, or\n\ +(at your option) any later version.\n\ +\n\ +This program is distributed in the hope that it will be useful,\n\ +but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ +GNU General Public License for more details.\n\ +\n\ +You should have received a copy of the GNU General Public License\n\ +along with this program; if not, write to the Free Software\n\ +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\n\ +USA", _("Ok"), FALSE, NULL, NULL); +} + +static void +pn_xmms_configure (void) +{ + +} + +static void +pn_xmms_render_pcm (gint16 data[2][512]) +{ + SDL_mutexP (sound_data_mutex); + memcpy (tmp_pcm_data, data, sizeof (gint16) * 2 * 512); + new_pcm_data = TRUE; + SDL_mutexV (sound_data_mutex); +} + +static void +pn_xmms_render_freq (gint16 data[2][256]) +{ + SDL_mutexP (sound_data_mutex); + memcpy (tmp_freq_data, data, sizeof (gint16) * 2 * 256); + new_freq_data = TRUE; + SDL_mutexV (sound_data_mutex); +} + +/* **************** paranormal.h stuff **************** */ + +void +pn_set_rc (struct pn_rc *new_rc) +{ + if (config_mutex) + SDL_mutexP (config_mutex); + + if (! pn_rc) + load_pn_rc (); + + if (pn_rc->actuator) + destroy_actuator (pn_rc->actuator); + pn_rc->actuator = new_rc->actuator; + + if (config_mutex) + SDL_mutexV (config_mutex); +} + +void +pn_fatal_error (const char *fmt, ...) +{ + char *errstr; + va_list ap; + GtkWidget *dialog; + GtkWidget *close, *label; + + /* Don't wanna try to lock GDK if we already have it */ + if (draw_thread && SDL_ThreadID () == SDL_GetThreadID (draw_thread)) + GDK_THREADS_ENTER (); + + /* now report the error... */ + va_start (ap, fmt); + errstr = g_strdup_vprintf (fmt, ap); + va_end (ap); + + dialog=gtk_dialog_new(); + gtk_window_set_title(GTK_WINDOW(dialog), "Error - Paranormal Visualization Studio - " VERSION); + gtk_container_border_width (GTK_CONTAINER (dialog), 8); + + label=gtk_label_new(errstr); + fprintf (stderr, "%s\n", errstr); + g_free (errstr); + + close = gtk_button_new_with_label ("Close"); + gtk_signal_connect_object (GTK_OBJECT (close), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (dialog)); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label, FALSE, + FALSE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area), close, + FALSE, FALSE, 0); + gtk_widget_show (label); + gtk_widget_show (close); + + gtk_widget_show (dialog); + gtk_widget_grab_focus (dialog); + + if (draw_thread && SDL_ThreadID () == SDL_GetThreadID (draw_thread)) + GDK_THREADS_LEAVE (); + + pn_quit (); +} + + +void +pn_error (const char *fmt, ...) +{ + char *errstr; + va_list ap; + static GtkWidget *text; + static GtkTextBuffer *textbuf; + + /* now report the error... */ + va_start (ap, fmt); + errstr = g_strdup_vprintf (fmt, ap); + va_end (ap); + fprintf (stderr, "Rovascope-CRITICAL **: %s\n", errstr); + + /* This is the easiest way of making sure we don't + get stuck trying to lock a mutex that this thread + already owns since this fn can be called from either + thread */ + if (draw_thread && SDL_ThreadID () == SDL_GetThreadID (draw_thread)) + GDK_THREADS_ENTER (); + + if (! err_dialog) + { + GtkWidget *close; + + err_dialog=gtk_dialog_new(); + gtk_window_set_title (GTK_WINDOW (err_dialog), "Error - Paranormal Visualization Studio - " VERSION); + gtk_window_set_policy (GTK_WINDOW (err_dialog), FALSE, FALSE, FALSE); + gtk_widget_set_usize (err_dialog, 400, 200); + gtk_container_border_width (GTK_CONTAINER (err_dialog), 8); + + textbuf = gtk_text_buffer_new(NULL); + text = gtk_text_view_new_with_buffer (textbuf); + + close = gtk_button_new_with_label ("Close"); + gtk_signal_connect_object (GTK_OBJECT (close), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_hide), + GTK_OBJECT (err_dialog)); + gtk_signal_connect_object (GTK_OBJECT (err_dialog), "delete-event", + GTK_SIGNAL_FUNC (gtk_widget_hide), + GTK_OBJECT (err_dialog)); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (err_dialog)->vbox), text, FALSE, + FALSE, 0); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (err_dialog)->action_area), close, + FALSE, FALSE, 0); + gtk_widget_show (text); + gtk_widget_show (close); + } + + gtk_text_buffer_set_text(GTK_TEXT_BUFFER(textbuf), errstr, -1); + g_free (errstr); + + gtk_widget_show (err_dialog); + gtk_widget_grab_focus (err_dialog); + + if (draw_thread && SDL_ThreadID () == SDL_GetThreadID (draw_thread)) + GDK_THREADS_LEAVE (); +} + + +/* This is confusing... + Don't call this from anywhere but the draw thread or + the initialization xmms thread (ie NOT the xmms sound + data functions) */ +void +pn_quit (void) +{ + if (draw_thread && SDL_ThreadID () == SDL_GetThreadID (draw_thread)) + { + /* We're in the draw thread so be careful */ + longjmp (quit_jmp, 1); + } + else + { + /* We're not in the draw thread, so don't sweat it... + addendum: looks like we have to bend over backwards (forwards?) + for xmms here too */ + pn_vp.disable_plugin (&pn_vp); + while (1) + gtk_main_iteration (); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/pn_utils.h Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,15 @@ +#ifndef _PN_UTILS_H +#define _PN_UTILS_H + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#define CAP(i,c) (i > c ? c : i < -(c) ? -(c) : i) +#define CAPHILO(i,h,l) (i > h ? h : i < l ? l : i) +#define CAPHI(i,h) (i > h ? h : i) +#define CAPLO(i,l) (i < l ? l : i) + +#define PN_IMG_INDEX(x,y) ((x) + (pn_image_data->width * (y))) + +#endif /* _PN_UTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/wave.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,528 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <math.h> + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +#include "drawing.h" + +#include "libcalc/calc.h" + +/* **************** wave_horizontal **************** */ +struct pn_actuator_option_desc wave_horizontal_opts[] = +{ + {"channels", "Which sound channels to use: negative = channel 1, \npositive = channel 2, " + "zero = both (two wave-forms.)", OPT_TYPE_INT, {ival: -1} }, + {"value", "The colour value to use.", OPT_TYPE_INT, {ival: 255} }, + {"lines", "Use lines instead of dots.", OPT_TYPE_BOOLEAN, {bval: TRUE} }, + { NULL } +}; + +static void +wave_horizontal_exec_dots (const struct pn_actuator_option *opts, + gpointer data) +{ + int i; + int channel = ( opts[0].val.ival < 0 ) ? 0 : 1; + guchar value = (opts[1].val.ival < 0 || opts[1].val.ival > 255) ? 255 : opts[1].val.ival; + + for (i=0; i<pn_image_data->width; i++) { + + /*single channel, centered horz.*/ + if ( opts[0].val.ival ) { + pn_image_data->surface[0][PN_IMG_INDEX (i, (pn_image_data->height>>1) + - CAP (pn_sound_data->pcm_data[channel] + [i*512/pn_image_data->width]>>8, + (pn_image_data->height>>1)-1))] + = value; + } + + /*both channels, at 1/4 and 3/4 of the screen*/ + else { + pn_image_data->surface[0][PN_IMG_INDEX( i, (pn_image_data->height>>2) - + CAP( (pn_sound_data->pcm_data[0] + [i*512/pn_image_data->width]>>9), + (pn_image_data->height>>2)-1))] + = value; + + pn_image_data->surface[0][PN_IMG_INDEX( i, 3*(pn_image_data->height>>2) - + CAP( (pn_sound_data->pcm_data[1] + [i*512/pn_image_data->width]>>9), + (pn_image_data->height>>2)-1))] + = value; + } + } +} + +void +wave_horizontal_exec_lines (const struct pn_actuator_option *opts, + gpointer data) +{ + int channel = ( opts[0].val.ival < 0 ) ? 0 : 1; + guchar value = (opts[1].val.ival < 0 || opts[1].val.ival > 255) ? 255 : opts[1].val.ival; + int *x_pos, *y_pos; /* dynamic tables which store the positions for the line */ + int *x2_pos, *y2_pos; /* dynamic tables which store the positions for the line */ + int i; + float step; + + x_pos = g_new0(int, 257); + y_pos = g_new0(int, 257); + x2_pos = g_new0(int, 257); + y2_pos = g_new0(int, 257); + + step = pn_image_data->width / 256.; + + /* calculate the line. */ + for (i = 0; i < 256; i++) + { + if (opts[0].val.ival != 0) + { + x_pos[i] = i * step; + y_pos[i] = (pn_image_data->height>>1) - + CAP (pn_sound_data->pcm_data[channel][i * 2]>>8, + (pn_image_data->height>>1)-1); + } + else + { + x_pos[i] = i * step; + y_pos[i] = (pn_image_data->height>>2) - + CAP (pn_sound_data->pcm_data[0][i * 2]>>9, + (pn_image_data->height>>2)-1); + + x2_pos[i] = i * step; + y2_pos[i] = 3*(pn_image_data->height>>2) - + CAP (pn_sound_data->pcm_data[1][i * 2]>>9, + (pn_image_data->height>>2)-1); + + } + } + + /* draw the line. */ + for (i = 1; i < 256; i++) + { + pn_draw_line(x_pos[i - 1], y_pos[i - 1], x_pos[i], y_pos[i], value); + + if ( opts[0].val.ival == 0 ) + pn_draw_line(x2_pos[i - 1], y2_pos[i - 1], x2_pos[i], y2_pos[i], value); + } + + g_free(x_pos); + g_free(y_pos); + g_free(x2_pos); + g_free(y2_pos); +} + +static void +wave_horizontal_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + if (opts[2].val.bval == TRUE) + wave_horizontal_exec_lines(opts, data); + else + wave_horizontal_exec_dots(opts, data); +} + +struct pn_actuator_desc builtin_wave_horizontal = +{ + "wave_horizontal", "Horizontal Waveform", + "Draws one or two waveforms horizontally across " + "the drawing surface", + 0, wave_horizontal_opts, + NULL, NULL, wave_horizontal_exec +}; + +/* **************** wave_vertical **************** */ +struct pn_actuator_option_desc wave_vertical_opts[] = +{ + {"channels", "Which sound channels to use: negative = channel 1, \npositive = channel 2, " + "zero = both (two wave-forms.)", OPT_TYPE_INT, {ival: -1} }, + {"value", "The colour value to use.", OPT_TYPE_INT, {ival: 255} }, + {"lines", "Use lines instead of dots.", OPT_TYPE_BOOLEAN, {bval: TRUE} }, + { NULL } +}; + +static void +wave_vertical_exec_dots (const struct pn_actuator_option *opts, + gpointer data) +{ + int i; + int channel = ( opts[0].val.ival < 0 ) ? 0 : 1; + guchar value = (opts[1].val.ival < 0 || opts[1].val.ival > 255) ? 255 : opts[1].val.ival; + + for (i=0; i<pn_image_data->height; i++) { + if ( opts[0].val.ival ) { + pn_image_data->surface[0][PN_IMG_INDEX ((pn_image_data->width>>1) + - CAP (pn_sound_data->pcm_data[channel] + [i*512/pn_image_data->height]>>8, + (pn_image_data->width>>1)-1), i)] + = value; + } + else { + pn_image_data->surface[0][PN_IMG_INDEX ((pn_image_data->width>>2) + - CAP (pn_sound_data->pcm_data[0] + [i*512/pn_image_data->height]>>9, + (pn_image_data->width>>2)-1), i)] + = value; + pn_image_data->surface[0][PN_IMG_INDEX ((3*pn_image_data->width>>2) + -CAP (pn_sound_data->pcm_data[1] + [i*512/pn_image_data->height]>>9, + (pn_image_data->width>>2)-1), i)] + + = value; + } + } +} + +static void +wave_vertical_exec_lines (const struct pn_actuator_option *opts, + gpointer data) +{ + int channel = ( opts[0].val.ival < 0 ) ? 0 : 1; + guchar value = (opts[1].val.ival < 0 || opts[1].val.ival > 255) ? 255 : opts[1].val.ival; + int *x_pos, *y_pos; /* dynamic tables which store the positions for the line */ + int *x2_pos, *y2_pos; /* dynamic tables which store the positions for the line */ + int i; + float step; + + x_pos = g_new0(int, 129); + y_pos = g_new0(int, 129); + x2_pos = g_new0(int, 129); + y2_pos = g_new0(int, 129); + + step = pn_image_data->height / 128.; + + /* calculate the line. */ + for (i = 0; i < 128; i++) + { + if (opts[0].val.ival != 0) + { + x_pos[i] = (pn_image_data->width>>1) - + CAP (pn_sound_data->pcm_data[channel] + [i*4]>>8, + (pn_image_data->width>>1)-1); + y_pos[i] = i * step; + } + else + { + x_pos[i] = (pn_image_data->width>>2) + - CAP (pn_sound_data->pcm_data[0] + [i*4]>>9, + (pn_image_data->width>>2)-1); + y_pos[i] = i * step; + + x2_pos[i] = 3*(pn_image_data->width>>2) + - CAP (pn_sound_data->pcm_data[1] + [i*4]>>9, + (pn_image_data->width>>2)-1); + y2_pos[i] = i * step; + } + } + + /* draw the line. */ + for (i = 1; i < 128; i++) + { + pn_draw_line(x_pos[i - 1], y_pos[i - 1], x_pos[i], y_pos[i], value); + + if ( opts[0].val.ival == 0 ) + pn_draw_line(x2_pos[i - 1], y2_pos[i - 1], x2_pos[i], y2_pos[i], value); + } + + g_free(x_pos); + g_free(y_pos); + g_free(x2_pos); + g_free(y2_pos); +} + +static void +wave_vertical_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + if (opts[2].val.bval == TRUE) + wave_vertical_exec_lines(opts, data); + else + wave_vertical_exec_dots(opts, data); +} + +struct pn_actuator_desc builtin_wave_vertical = +{ + "wave_vertical", "Vertical Waveform", + "Draws one or two waveforms vertically across " + "the drawing surface", + 0, wave_vertical_opts, + NULL, NULL, wave_vertical_exec +}; + +/* FIXME: allow for only 1 channel for wave_normalize & wave_smooth */ +/* **************** wave_normalize **************** */ +static struct pn_actuator_option_desc wave_normalize_opts[] = +{ + { "height", "If positive, the height, in pixels, to which the waveform will be " + "normalized; if negative, hfrac is used", OPT_TYPE_INT, { ival: -1 } }, + { "hfrac", "If positive, the fraction of the horizontal image size to which the " + "waveform will be normalized; if negative, vfrac is used", + OPT_TYPE_FLOAT, { fval: -1 } }, + { "vfrac", "If positive, the fraction of the vertical image size to which the " + "waveform will be normalized", + OPT_TYPE_FLOAT, { fval: .125 } }, + { "channels", "Which sound channel(s) to normalize: negative = channel 1,\n" + "\tpositive = channel 2, 0 = both channels.", + OPT_TYPE_INT, { ival: 0 } }, + { NULL } +}; + +static void +wave_normalize_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i, j, max=0; + float denom; + + for (j=0; j<2; j++) + { + if ( !(opts[3].val.ival) || (opts[3].val.ival < 0 && j == 0) || + (opts[3].val.ival > 0 && j == 1) ) { + + for (i=0; i<512; i++) + if (abs(pn_sound_data->pcm_data[j][i]) > max) + max = abs(pn_sound_data->pcm_data[j][i]); + + if (opts[0].val.ival > 0) + denom = max/(opts[0].val.ival<<8); + else if (opts[1].val.fval > 0) + denom = max/(opts[1].val.fval * (pn_image_data->width<<8)); + else + denom = max/(opts[2].val.fval * (pn_image_data->height<<8)); + + if (denom > 0) + for (i=0; i<512; i++) + pn_sound_data->pcm_data[j][i] + /= denom; + } + } +} + +struct pn_actuator_desc builtin_wave_normalize = +{ + "wave_normalize", "Normalize Waveform Data", + "Normalizes the waveform data used by the wave_* actuators", + 0, wave_normalize_opts, + NULL, NULL, wave_normalize_exec +}; + +/* **************** wave_smooth **************** */ +struct pn_actuator_option_desc wave_smooth_opts[] = +{ + { "channels", "Which sound channel(s) to smooth: negative = channel 1, \n" + "\tpositive = channel 2, 0 = both channels.", + OPT_TYPE_INT, { ival: 0 } }, + {0} +}; + +static void +wave_smooth_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i, j, k; + gint16 tmp[512]; + + for (j=0; j<2; j++) + { + if ( !(opts[0].val.ival) || (opts[0].val.ival < 0 && j == 0) || + (opts[0].val.ival > 0 && j == 1) ) { + + for (i=4; i<508; i++) + { + k = (pn_sound_data->pcm_data[j][i]<<3) + + (pn_sound_data->pcm_data[j][i+1]<<2) + + (pn_sound_data->pcm_data[j][i-1]<<2) + + (pn_sound_data->pcm_data[j][i+2]<<2) + + (pn_sound_data->pcm_data[j][i-2]<<2) + + (pn_sound_data->pcm_data[j][i+3]<<1) + + (pn_sound_data->pcm_data[j][i-3]<<1) + + (pn_sound_data->pcm_data[j][i+4]<<1) + + (pn_sound_data->pcm_data[j][i-4]<<1); + tmp[i] = k >> 5; + } + memcpy (pn_sound_data->pcm_data[j]+4, tmp, sizeof (gint16) * 504); + } + } +} + +struct pn_actuator_desc builtin_wave_smooth = +{ + "wave_smooth", "Smooth Waveform Data", + "Smooth out the waveform data used by the wave_* actuators", + 0, wave_smooth_opts, + NULL, NULL, wave_smooth_exec +}; + +/* **************** wave_radial **************** */ +static struct pn_actuator_option_desc wave_radial_opts[] = +{ + { "base_radius", " ", + OPT_TYPE_FLOAT, { fval: 0 } }, + {"value", "The colour value to use.", OPT_TYPE_INT, {ival: 255} }, +/* {"lines", "Use lines instead of dots.", OPT_TYPE_BOOLEAN, {bval: TRUE} }, */ + { NULL } +}; + +static void +wave_radial_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + int i, x, y; + guchar value = (opts[1].val.ival < 0 || opts[1].val.ival > 255) ? 255 : opts[1].val.ival; + + for(i=0; i<360; i++) + { + x = (pn_image_data->width>>1) + + (opts[0].val.fval + (pn_sound_data->pcm_data[0][(int)(i*(512.0/360.0))]>>8)) + * cos_val[i]; + y = (pn_image_data->height>>1) + + (opts[0].val.fval + (pn_sound_data->pcm_data[0][(int)(i*(512.0/360.0))]>>8)) + * sin_val[i]; + + pn_image_data->surface[0][PN_IMG_INDEX (CAPHILO(x,pn_image_data->width,0), + CAPHILO(y,pn_image_data->height,0))] + = value; + } +}; + +struct pn_actuator_desc builtin_wave_radial = +{ + "wave_radial", "Radial Waveform", + "Draws a single waveform varying" + " radially from the center of the image", + 0, wave_radial_opts, + NULL, NULL, wave_radial_exec +}; + +/* **************** wave_scope **************** */ + +static struct pn_actuator_option_desc wave_scope_opts[] = +{ + {"init_script", "Initialization script.", OPT_TYPE_STRING, {sval: "n = 800; t = -0.05;"} }, + {"frame_script", "Script to run at the beginning of each frame.", OPT_TYPE_STRING, {sval: "t = t + 0.05;"} }, + {"sample_script", "Script to run for each sample.", OPT_TYPE_STRING, {sval: "d = index + value; r = t + index * 3.141952924 * 4; x = cos(r) * d; y = sin(r) * d;"} }, + {"lines", "Use lines instead of dots.", OPT_TYPE_BOOLEAN, {bval: TRUE} }, + { NULL } +}; + +struct pn_scope_data +{ + expression_t *expr_on_init, *expr_on_frame, *expr_on_sample; + symbol_dict_t *dict; + gboolean reset; +}; + +static void +wave_scope_init(gpointer *data) +{ + *data = g_new0(struct pn_scope_data, 1); + + /* the expressions will need to be compiled, so prepare for that */ + ((struct pn_scope_data *)*data)->reset = TRUE; +} + +static void +wave_scope_cleanup(gpointer op_data) +{ + struct pn_scope_data *data = (struct pn_scope_data *) op_data; + + g_return_if_fail(data != NULL); + + if (data->expr_on_init) + expr_free(data->expr_on_init); + + if (data->expr_on_frame) + expr_free(data->expr_on_frame); + + if (data->expr_on_sample) + expr_free(data->expr_on_sample); + + if (data->dict) + dict_free(data->dict); + + if (data) + g_free(data); +} + +static void +wave_scope_exec(const struct pn_actuator_option *opts, + gpointer op_data) +{ + struct pn_scope_data *data = (struct pn_scope_data *) op_data; + gint i; + gdouble *xf, *yf, *index, *value, *points; + + if (data->reset) + { + if (data->dict) + dict_free(data->dict); + + data->dict = dict_new(); + + if (opts[0].val.sval != NULL) + data->expr_on_init = expr_compile_string(opts[0].val.sval, data->dict); + + if (opts[1].val.sval != NULL) + data->expr_on_frame = expr_compile_string(opts[1].val.sval, + data->dict); + + if (opts[2].val.sval != NULL) + data->expr_on_sample = expr_compile_string(opts[2].val.sval, + data->dict); + + if (data->expr_on_init != NULL) + expr_execute(data->expr_on_init, data->dict); + + data->reset = FALSE; + } + + xf = dict_variable(data->dict, "x"); + yf = dict_variable(data->dict, "y"); + index = dict_variable(data->dict, "index"); + value = dict_variable(data->dict, "value"); + points = dict_variable(data->dict, "points"); + + if (data->expr_on_frame != NULL) + expr_execute(data->expr_on_frame, data->dict); + + if (*points > 513 || *points == 0) + *points = 513; + + if (data->expr_on_sample != NULL) + { + for (i = 0; i < *points; i++) + { + gint x, y; + static gint oldx, oldy; + + *value = 1.0 * pn_sound_data->pcm_data[0][i & 511] / 32768.0; + *index = i / (*points - 1); + + expr_execute(data->expr_on_sample, data->dict); + + x = (gint)(((*xf + 1.0) * (pn_image_data->width - 1) / 2) + 0.5); + y = (gint)(((*yf + 1.0) * (pn_image_data->height - 1) / 2) + 0.5); + + if (i != 0) + pn_draw_line(oldx, oldy, x, y, 255); + + oldx = x; + oldy = y; + } + } +} + +struct pn_actuator_desc builtin_wave_scope = +{ + "wave_scope", "Scope", + "A programmable scope.", + 0, wave_scope_opts, + wave_scope_init, wave_scope_cleanup, wave_scope_exec +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rovascope/xform.c Sat Jan 06 01:57:34 2007 -0800 @@ -0,0 +1,764 @@ +/* FIXME: allow for only using an xform on part of the img? */ +/* FIXME: perhaps combine these into a single vector field + so that only 1 apply_xform needs to be done for as many + of these as someone wants to use */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <math.h> + +#include <glib.h> + +#include "paranormal.h" +#include "actuators.h" +#include "pn_utils.h" + +#include "libcalc/calc.h" + +struct xform_vector +{ + gint32 offset; /* the offset of the top left pixel */ + guint16 w; /* 4:4:4:4 NE, NW, SE, SW pixel weights + The total should be 16 */ + + /* if offset < 0 then w is the color index to + which the pixel will be set */ +}; + +static void +xfvec (float x, float y, struct xform_vector *v) +{ + float xd, yd; + int weight[4]; + + if (x >= pn_image_data->width-1 || y >= pn_image_data->height-1 + || x < 0 || y < 0) + { + v->offset = -1; + v->w = 0; + return; + } + + v->offset = PN_IMG_INDEX (floor(x), floor(y)); + + xd = x - floor (x); + yd = y - floor (y); + + weight[3] = xd * yd * 16; + weight[2] = (1-xd) * yd * 16; + weight[1] = xd * (1-yd) * 16; + weight[0] = 16 - weight[3] - weight[2] - weight[1]; /* just in case */ + + v->w = (weight[0]<<12) | (weight[1]<<8) | (weight[2]<<4) | weight[3]; +} + +static void +apply_xform (struct xform_vector *vfield) +{ + int i; + struct xform_vector *v; + register guchar *srcptr; + register guchar *destptr; + register int color; + + if (vfield == NULL) + return; + + for (i=0, v=vfield, destptr=pn_image_data->surface[1]; + i<pn_image_data->width*pn_image_data->height; + i++, v++, destptr++) + { + /* off the screen */ + if (v->offset < 0) + { + *destptr = (guchar)v->w; + continue; + } + + srcptr = pn_image_data->surface[0] + v->offset; + + /* exactly on the pixel */ + if (v->w == 0) + *destptr = *srcptr; + + /* gotta blend the points */ + else + { + color = *srcptr * (v->w>>12); + color += *++srcptr * ((v->w>>8) & 0x0f); + color += *(srcptr+=pn_image_data->width) * (v->w & 0x0f); + color += *(--srcptr) * ((v->w>>4) & 0x0f); + color >>= 4; + *destptr = (guchar)color; + } + } +} + +/* **************** xform_spin **************** */ +/* FIXME: Describe these better, how they are backwards */ +/* FIXME: better name? */ +struct pn_actuator_option_desc xform_spin_opts[] = +{ + { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: -8.0 } }, + { "r_add", "The number of pixels by which the r coordinate will be " + "increased (before scaling)", OPT_TYPE_FLOAT, { fval: 0.0 } }, + { "r_scale", "The amount by which the r coordinate of each pixel will " + "be scaled", OPT_TYPE_FLOAT, { fval: 1.0 } }, + { NULL } +}; + +struct xform_spin_data +{ + int width, height; + struct xform_vector *vfield; +}; + +static void +xform_spin_init (gpointer *data) +{ + *data = g_new0 (struct xform_spin_data, 1); +} + +static void +xform_spin_cleanup (gpointer data) +{ + struct xform_spin_data *d = (struct xform_spin_data *) data; + + + if (d) + { + if (d->vfield) + g_free (d->vfield); + g_free (d); + } +} + +static void +xform_spin_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + struct xform_spin_data *d = (struct xform_spin_data*)data; + float i, j; + + if (d->width != pn_image_data->width + || d->height != pn_image_data->height) + { + d->width = pn_image_data->width; + d->height = pn_image_data->height; + + if (d->vfield) + g_free (d->vfield); + + d->vfield = g_malloc0 (sizeof(struct xform_vector) + * d->width * d->height); + + for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++) + for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++) + { + float r, t = 0; + float x, y; + + r = sqrt (i*i + j*j); + if (r) + t = asin (j/r); + if (i < 0) + t = M_PI - t; + + t += opts[0].val.fval * M_PI/180.0; + r += opts[1].val.fval; + r *= opts[2].val.fval; + + x = (r * cos (t)) + (pn_image_data->width>>1); + y = (pn_image_data->height>>1) - (r * sin (t)); + + xfvec (x, y, &d->vfield + [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i), + ((pn_image_data->height>>1)-(int)rint(j)))]); + } + } + + apply_xform (d->vfield); + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_spin = +{ + "xform_spin", "Spin Transform", + "Rotates and radially scales the image", + 0, xform_spin_opts, + xform_spin_init, xform_spin_cleanup, xform_spin_exec +}; + +/* **************** xform_ripple **************** */ +struct pn_actuator_option_desc xform_ripple_opts[] = +{ + { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } }, + { "ripples", "The number of ripples that fit on the screen " + "(horizontally)", OPT_TYPE_FLOAT, { fval: 8 } }, + { "base_speed", "The minimum number of pixels to move each pixel", + OPT_TYPE_FLOAT, { fval: 1 } }, + { "mod_speed", "The maximum number of pixels by which base_speed" + " will be modified", OPT_TYPE_FLOAT, { fval: 1 } }, + { NULL } +}; + +struct xform_ripple_data +{ + int width, height; + struct xform_vector *vfield; +}; + +static void +xform_ripple_init (gpointer *data) +{ + *data = g_new0 (struct xform_ripple_data, 1); +} + +static void +xform_ripple_cleanup (gpointer data) +{ + struct xform_ripple_data *d = (struct xform_ripple_data*) data; + + if (d) + { + if (d->vfield) + g_free (d->vfield); + g_free (d); + } +} + +static void +xform_ripple_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + struct xform_ripple_data *d = (struct xform_ripple_data*)data; + float i, j; + + if (d->width != pn_image_data->width + || d->height != pn_image_data->height) + { + d->width = pn_image_data->width; + d->height = pn_image_data->height; + + if (d->vfield) + g_free (d->vfield); + + d->vfield = g_malloc (sizeof(struct xform_vector) + * d->width * d->height); + + for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++) + for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++) + { + float r, t = 0; + float x, y; + + r = sqrt (i*i + j*j); + if (r) + t = asin (j/r); + if (i < 0) + t = M_PI - t; + + t += opts[0].val.fval * M_PI/180.0; + + if (r > 4)//(pn_image_data->width/(2*opts[1].val.fval))) + r -= opts[2].val.fval + (opts[3].val.fval/2) * + (1 + sin ((r/(pn_image_data->width/(2*opts[1].val.fval)))*M_PI)); +/* else if (r > 4) */ +/* r *= r/(pn_image_data->width/opts[1].val.fval); */ + else /* don't let it explode */ + r = 1000000; + + + x = (r * cos (t)) + (pn_image_data->width>>1); + y = (pn_image_data->height>>1) - (r * sin (t)); + + xfvec (x, y, &d->vfield + [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i), + ((pn_image_data->height>>1)-(int)rint(j)))]); + } + } + + apply_xform (d->vfield); + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_ripple = +{ + "xform_ripple", "Ripple Transform", "Creates an ripple effect", + 0, xform_ripple_opts, + xform_ripple_init, xform_ripple_cleanup, xform_ripple_exec +}; + +/* **************** xform_bump_spin **************** */ +struct pn_actuator_option_desc xform_bump_spin_opts[] = +{ + { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } }, + { "bumps", "The number of bumps that on the image", + OPT_TYPE_FLOAT, { fval: 8 } }, + { "base_scale", "The base radial scale", + OPT_TYPE_FLOAT, { fval: 0.95 } }, + { "mod_scale", "The maximum amount that should be " + "added to the base_scale to create the 'bump' effect", + OPT_TYPE_FLOAT, { fval: .1 } }, + { NULL } +}; + +struct xform_bump_spin_data +{ + int width, height; + struct xform_vector *vfield; +}; + +static void +xform_bump_spin_init (gpointer *data) +{ + *data = g_new0 (struct xform_bump_spin_data, 1); +} + +static void +xform_bump_spin_cleanup (gpointer data) +{ + struct xform_bump_spin_data *d = (struct xform_bump_spin_data*) data; + + if (d) + { + if (d->vfield) + g_free (d->vfield); + g_free (d); + } +} + +static void +xform_bump_spin_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + struct xform_bump_spin_data *d = (struct xform_bump_spin_data*)data; + float i, j; + + if (d->width != pn_image_data->width + || d->height != pn_image_data->height) + { + d->width = pn_image_data->width; + d->height = pn_image_data->height; + + if (d->vfield) + g_free (d->vfield); + + d->vfield = g_malloc (sizeof(struct xform_vector) + * d->width * d->height); + + for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++) + for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++) + { + float r, t = 0; + float x, y; + + r = sqrt (i*i + j*j); + if (r) + t = asin (j/r); + if (i < 0) + t = M_PI - t; + + t += opts[0].val.fval * M_PI/180.0; + + r *= opts[2].val.fval + opts[3].val.fval + * (1 + sin (t*opts[1].val.fval)); + + x = (r * cos (t)) + (pn_image_data->width>>1); + y = (pn_image_data->height>>1) - (r * sin (t)); + + xfvec (x, y, &d->vfield + [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i), + ((pn_image_data->height>>1)-(int)rint(j)))]); + } + } + + apply_xform (d->vfield); + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_bump_spin = +{ + "xform_bump_spin", "Bump Transform", + "Rotate the image at a varying speed to create " + "the illusion of bumps", + 0, xform_bump_spin_opts, + xform_bump_spin_init, xform_bump_spin_cleanup, xform_bump_spin_exec +}; + +/* **************** xform_halfrender **************** */ +struct pn_actuator_option_desc xform_halfrender_opts[] = +{ + { "direction", "Negative is horizontal, positive is vertical.", + OPT_TYPE_INT, { ival: 1 } }, + { "render_twice", "Render the second image.", + OPT_TYPE_BOOLEAN, { bval: TRUE } }, + { NULL } +}; + +static void +xform_halfrender_exec (const struct pn_actuator_option *opts, + gpointer data) +{ + gint x, y; + + if (opts[0].val.ival < 0) + { + for (y = 0; y < pn_image_data->height; y += 2) + { + for (x = 0; x < pn_image_data->width; x++) + { + pn_image_data->surface[1][PN_IMG_INDEX(x, y / 2)] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + if (opts[1].val.bval) + { + pn_image_data->surface[1][PN_IMG_INDEX(x, (y / 2) + (pn_image_data->height / 2))] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + } + } + } + } + else + { + for (y = 0; y < pn_image_data->height; y++) + { + for (x = 0; x < pn_image_data->width; x += 2) + { + pn_image_data->surface[1][PN_IMG_INDEX(x / 2, y)] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + if (opts[1].val.bval) + { + pn_image_data->surface[1][PN_IMG_INDEX((x / 2) + (pn_image_data->width / 2), y)] = + pn_image_data->surface[0][PN_IMG_INDEX(x, y)]; + } + } + } + } + + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_halfrender = +{ + "xform_halfrender", "Halfrender Transform", + "Divides the surface in half and renders it twice.", + 0, xform_halfrender_opts, + NULL, NULL, xform_halfrender_exec +}; + +/* **************** xform_movement **************** */ +struct pn_actuator_option_desc xform_movement_opts[] = +{ + { "formula", "The formula to evaluate.", + OPT_TYPE_STRING, { sval: "r = r * cos(r); d = sin(d);" } }, + { "polar", "Whether the coordinates are polar or not.", + OPT_TYPE_BOOLEAN, { bval: TRUE } }, + { NULL } +}; + +typedef struct { + int width, height; /* Previous width and height. */ + struct xform_vector *vfield; +} PnMovementData; + +static void +xform_movement_init (gpointer *data) +{ + *data = g_new0(PnMovementData, 1); +} + +static void +xform_movement_cleanup (gpointer data) +{ + PnMovementData *d = (PnMovementData *) data; + + if (d) + { + if (d->vfield) + g_free (d->vfield); + g_free (d); + } +} + +inline void +xform_trans_polar (struct xform_vector *vfield, gint x, gint y, + expression_t *expr, symbol_dict_t *dict) +{ + gdouble *rf, *df; + gdouble xf, yf; + gint xn, yn; + + rf = dict_variable(dict, "r"); + df = dict_variable(dict, "d"); + + /* Points (xf, yf) must be in a (-1..1) square. */ + xf = 2.0 * x / (pn_image_data->width - 1) - 1.0; + yf = 2.0 * y / (pn_image_data->height - 1) - 1.0; + + /* Now, convert to polar coordinates r and d. */ + *rf = hypot(xf, yf); + *df = atan2(yf, xf); + + /* Run the script. */ + expr_execute(expr, dict); + + /* Back to (-1..1) square. */ + xf = (*rf) * cos ((*df)); + yf = (*rf) * sin ((*df)); + + /* Convert back to physical coordinates. */ + xn = (int)(((xf + 1.0) * (pn_image_data->width - 1) / 2) + 0.5); + yn = (int)(((yf + 1.0) * (pn_image_data->height - 1) / 2) + 0.5); + + if (xn < 0 || xn >= pn_image_data->width || yn < 0 || yn >= pn_image_data->height) + { + xn = x; yn = y; + } + + xfvec (xn, yn, &vfield[PN_IMG_INDEX (x, y)]); +} + +inline void +xform_trans_literal (struct xform_vector *vfield, gint x, gint y, + expression_t *expr, symbol_dict_t *dict) +{ + gdouble rf, df; + gdouble *xf, *yf; + gint xn, yn; + + xf = dict_variable(dict, "x"); + yf = dict_variable(dict, "y"); + + /* Points (xf, yf) must be in a (-1..1) square. */ + *xf = 2.0 * x / (pn_image_data->width - 1) - 1.0; + *yf = 2.0 * y / (pn_image_data->height - 1) - 1.0; + + /* Run the script. */ + expr_execute(expr, dict); + + /* Convert back to physical coordinates. */ + xn = (int)(((*xf + 1.0) * (pn_image_data->width - 1) / 2) + 0.5); + yn = (int)(((*yf + 1.0) * (pn_image_data->height - 1) / 2) + 0.5); + + if (xn < 0 || xn >= pn_image_data->width || yn < 0 || yn >= pn_image_data->height) + { + xn = x; yn = y; + } + + xfvec (xn, yn, &vfield[PN_IMG_INDEX (x, y)]); +} + +static void +xform_movement_exec (const struct pn_actuator_option *opts, + gpointer odata) +{ + PnMovementData *d = (PnMovementData *) odata; + void (*transform_func)(struct xform_vector *, gint, gint, expression_t *, symbol_dict_t *) = + opts[1].val.bval == TRUE ? xform_trans_polar : xform_trans_literal; + + if (d->width != pn_image_data->width + || d->height != pn_image_data->height) + { + gint i, j; + gdouble *rf, *df; + gdouble xf, yf; + gint xn, yn; + expression_t *expr; + symbol_dict_t *dict; + + d->width = pn_image_data->width; + d->height = pn_image_data->height; + + if (d->vfield) + { + g_free (d->vfield); + d->vfield = NULL; + } + + if (opts[0].val.sval == NULL) + return; + + dict = dict_new(); + expr = expr_compile_string(opts[0].val.sval, dict); + if (!expr) + { + dict_free(dict); + return; + } + + rf = dict_variable(dict, "r"); + df = dict_variable(dict, "d"); + + d->vfield = g_malloc (sizeof(struct xform_vector) + * d->width * d->height); + + for (j = 0; j < pn_image_data->height; j++) + for (i = 0; i < pn_image_data->width; i++) + { + transform_func(d->vfield, i, j, expr, dict); + } + } + + apply_xform (d->vfield); + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_movement = +{ + "xform_movement", "Movement Transform", + "A customizable blitter.", + 0, xform_movement_opts, + xform_movement_init, xform_movement_cleanup, xform_movement_exec +}; + +/* **************** xform_dynmovement **************** */ +/* FIXME: really slow */ +struct pn_actuator_option_desc xform_dynmovement_opts[] = +{ + { "init_script", "The formula to evaluate on init.", + OPT_TYPE_STRING, { sval: "" } }, + { "beat_script", "The formula to evaluate on each beat.", + OPT_TYPE_STRING, { sval: "" } }, + { "frame_script", "The formula to evaluate on each frame.", + OPT_TYPE_STRING, { sval: "" } }, + { "point_script", "The formula to evaluate.", + OPT_TYPE_STRING, { sval: "d = 0.15;" } }, + { "polar", "Whether or not the coordinates to use are polar.", + OPT_TYPE_BOOLEAN, { bval: TRUE } }, + { NULL } +}; + +typedef struct { + int width, height; /* Previous width and height. */ + expression_t *expr_init; + expression_t *expr_frame; + expression_t *expr_beat; + expression_t *expr_point; + symbol_dict_t *dict; + struct xform_vector *vfield; +} PnDynMovementData; + +static void +xform_dynmovement_init (gpointer *data) +{ + *data = g_new0(PnDynMovementData, 1); +} + +static void +xform_dynmovement_cleanup (gpointer data) +{ + PnDynMovementData *d = (PnDynMovementData *) data; + + if (d) + { + if (d->expr_init) + expr_free (d->expr_init); + if (d->expr_beat) + expr_free (d->expr_beat); + if (d->expr_frame) + expr_free (d->expr_frame); + if (d->expr_point) + expr_free (d->expr_point); + if (d->dict) + dict_free (d->dict); + if (d->vfield) + g_free (d->vfield); + g_free (d); + } +} + +static void +xform_dynmovement_exec (const struct pn_actuator_option *opts, + gpointer odata) +{ + PnDynMovementData *d = (PnDynMovementData *) odata; + gint i, j; + gdouble *rf, *df; + gdouble xf, yf; + gint xn, yn; + void (*transform_func)(struct xform_vector *, gint, gint, expression_t *, symbol_dict_t *) = + opts[4].val.bval == TRUE ? xform_trans_polar : xform_trans_literal; + gboolean make_table = FALSE; + + if (d->width != pn_image_data->width + || d->height != pn_image_data->height) + { + d->width = pn_image_data->width; + d->height = pn_image_data->height; + + if (d->vfield) + { + g_free (d->vfield); + d->vfield = NULL; + } + + if (opts[3].val.sval == NULL) + return; + + if (!d->dict) + d->dict = dict_new(); + else + { + dict_free(d->dict); + d->dict = dict_new(); + } + + if (d->expr_init) + { + expr_free(d->expr_init); + d->expr_init = NULL; + } + + /* initialize */ + d->expr_init = expr_compile_string(opts[0].val.sval, d->dict); + + if (d->expr_init != NULL) + { + expr_execute(d->expr_init, d->dict); + } + + d->expr_beat = expr_compile_string(opts[1].val.sval, d->dict); + d->expr_frame = expr_compile_string(opts[2].val.sval, d->dict); + d->expr_point = expr_compile_string(opts[3].val.sval, d->dict); + + d->vfield = g_malloc (sizeof(struct xform_vector) + * d->width * d->height); + + make_table = TRUE; + } + + rf = dict_variable(d->dict, "r"); + df = dict_variable(d->dict, "d"); + + if (*opts[2].val.sval != '\0' || pn_new_beat) + make_table = TRUE; + + /* run the on-frame script. */ + if (make_table == TRUE) + { + if (d->expr_beat != NULL) + expr_execute(d->expr_beat, d->dict); + + if (d->expr_frame != NULL) + expr_execute(d->expr_frame, d->dict); + + for (j = 0; j < pn_image_data->height; j++) + for (i = 0; i < pn_image_data->width; i++) + { + transform_func(d->vfield, i, j, d->expr_point, d->dict); + } + } + + apply_xform (d->vfield); + pn_swap_surfaces (); +} + +struct pn_actuator_desc builtin_xform_dynmovement = +{ + "xform_dynmovement", "Dynamic Movement Transform", + "A customizable blitter.", + 0, xform_dynmovement_opts, + xform_dynmovement_init, xform_dynmovement_cleanup, xform_dynmovement_exec +};