Mercurial > audlegacy-plugins
diff src/paranormal/xform.c @ 333:afc61c0efc05 trunk
[svn] - add Trans / Movement implementation
author | nenolod |
---|---|
date | Tue, 05 Dec 2006 02:16:09 -0800 |
parents | a1517b09cb3a |
children | a9f1bd76a3e6 |
line wrap: on
line diff
--- a/src/paranormal/xform.c Tue Dec 05 01:07:41 2006 -0800 +++ b/src/paranormal/xform.c Tue Dec 05 02:16:09 2006 -0800 @@ -15,6 +15,8 @@ #include "actuators.h" #include "pn_utils.h" +#include "libcalc/calc.h" + struct xform_vector { gint32 offset; /* the offset of the top left pixel */ @@ -442,3 +444,120 @@ 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: "d = 0.15;" } }, + { 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); + } +} + +static void +xform_movement_exec (const struct pn_actuator_option *opts, + gpointer odata) +{ + PnMovementData *d = (PnMovementData *) odata; + + 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++) + { + /* Points (xf, yf) must be in a (-1..1) square. */ + xf = 2.0 * i / (pn_image_data->width - 1) - 1.0; + yf = 2.0 * j / (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 = i; yn = j; + } + + xfvec (xn, yn, &d->vfield[PN_IMG_INDEX (i, j)]); + } + } + + 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 +};