comparison src/paranormal-ng/xform.c @ 2078:1fa3c8cd366a

paranormal-ng: a GL visualiser. lots to do, most stuff won't work, but hey, this will do cool stuff too soon
author William Pitcock <nenolod@atheme.org>
date Mon, 15 Oct 2007 06:20:13 -0500
parents
children 9084e2e05f4a
comparison
equal deleted inserted replaced
2077:e5b639ab62b0 2078:1fa3c8cd366a
1 /*
2 * paranormal: iterated pipeline-driven visualization plugin
3 * Copyright (c) 2006, 2007 William Pitcock <nenolod@dereferenced.org>
4 * Portions copyright (c) 2001 Jamie Gennis <jgennis@mindspring.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; under version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* FIXME: allow for only using an xform on part of the img? */
21 /* FIXME: perhaps combine these into a single vector field
22 so that only 1 apply_xform needs to be done for as many
23 of these as someone wants to use */
24
25 #include <config.h>
26
27 #include <math.h>
28
29 #include <glib.h>
30
31 #include "paranormal.h"
32 #include "actuators.h"
33 #include "pn_utils.h"
34
35 #include "libcalc/calc.h"
36
37 struct xform_vector
38 {
39 gint32 offset; /* the offset of the top left pixel */
40 guint16 w; /* 4:4:4:4 NE, NW, SE, SW pixel weights
41 The total should be 16 */
42
43 /* if offset < 0 then w is the color index to
44 which the pixel will be set */
45 };
46
47 static void
48 xfvec (float x, float y, struct xform_vector *v)
49 {
50 float xd, yd;
51 int weight[4];
52
53 if (x >= pn_image_data->width-1 || y >= pn_image_data->height-1
54 || x < 0 || y < 0)
55 {
56 v->offset = -1;
57 v->w = 0;
58 return;
59 }
60
61 v->offset = PN_IMG_INDEX (floor(x), floor(y));
62
63 xd = x - floor (x);
64 yd = y - floor (y);
65
66 weight[3] = xd * yd * 16;
67 weight[2] = (1-xd) * yd * 16;
68 weight[1] = xd * (1-yd) * 16;
69 weight[0] = 16 - weight[3] - weight[2] - weight[1]; /* just in case */
70
71 v->w = (weight[0]<<12) | (weight[1]<<8) | (weight[2]<<4) | weight[3];
72 }
73
74 static void
75 apply_xform (struct xform_vector *vfield)
76 {
77 int i;
78 struct xform_vector *v;
79 register guchar *srcptr;
80 register guchar *destptr;
81 register int color;
82
83 if (vfield == NULL)
84 return;
85
86 for (i=0, v=vfield, destptr=pn_image_data->surface[1];
87 i<pn_image_data->width*pn_image_data->height;
88 i++, v++, destptr++)
89 {
90 /* off the screen */
91 if (v->offset < 0)
92 {
93 *destptr = (guchar)v->w;
94 continue;
95 }
96
97 srcptr = pn_image_data->surface[0] + v->offset;
98
99 /* exactly on the pixel */
100 if (v->w == 0)
101 *destptr = *srcptr;
102
103 /* gotta blend the points */
104 else
105 {
106 color = *srcptr * (v->w>>12);
107 color += *++srcptr * ((v->w>>8) & 0x0f);
108 color += *(srcptr+=pn_image_data->width) * (v->w & 0x0f);
109 color += *(--srcptr) * ((v->w>>4) & 0x0f);
110 color >>= 4;
111 *destptr = (guchar)color;
112 }
113 }
114 }
115
116 /* **************** xform_spin **************** */
117 /* FIXME: Describe these better, how they are backwards */
118 /* FIXME: better name? */
119 struct pn_actuator_option_desc xform_spin_opts[] =
120 {
121 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: -8.0 } },
122 { "r_add", "The number of pixels by which the r coordinate will be "
123 "increased (before scaling)", OPT_TYPE_FLOAT, { fval: 0.0 } },
124 { "r_scale", "The amount by which the r coordinate of each pixel will "
125 "be scaled", OPT_TYPE_FLOAT, { fval: 1.0 } },
126 { NULL }
127 };
128
129 struct xform_spin_data
130 {
131 int width, height;
132 struct xform_vector *vfield;
133 };
134
135 static void
136 xform_spin_init (gpointer *data)
137 {
138 *data = g_new0 (struct xform_spin_data, 1);
139 }
140
141 static void
142 xform_spin_cleanup (gpointer data)
143 {
144 struct xform_spin_data *d = (struct xform_spin_data *) data;
145
146
147 if (d)
148 {
149 if (d->vfield)
150 g_free (d->vfield);
151 g_free (d);
152 }
153 }
154
155 static void
156 xform_spin_exec (const struct pn_actuator_option *opts,
157 gpointer data)
158 {
159 struct xform_spin_data *d = (struct xform_spin_data*)data;
160 float i, j;
161
162 if (d->width != pn_image_data->width
163 || d->height != pn_image_data->height)
164 {
165 d->width = pn_image_data->width;
166 d->height = pn_image_data->height;
167
168 if (d->vfield)
169 g_free (d->vfield);
170
171 d->vfield = g_malloc0 (sizeof(struct xform_vector)
172 * d->width * d->height);
173
174 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
175 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
176 {
177 float r, t = 0;
178 float x, y;
179
180 r = sqrt (i*i + j*j);
181 if (r)
182 t = asin (j/r);
183 if (i < 0)
184 t = M_PI - t;
185
186 t += opts[0].val.fval * M_PI/180.0;
187 r += opts[1].val.fval;
188 r *= opts[2].val.fval;
189
190 x = (r * cos (t)) + (pn_image_data->width>>1);
191 y = (pn_image_data->height>>1) - (r * sin (t));
192
193 xfvec (x, y, &d->vfield
194 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
195 ((pn_image_data->height>>1)-(int)rint(j)))]);
196 }
197 }
198
199 apply_xform (d->vfield);
200 pn_swap_surfaces ();
201 }
202
203 struct pn_actuator_desc builtin_xform_spin =
204 {
205 "xform_spin", "Spin Transform",
206 "Rotates and radially scales the image",
207 0, xform_spin_opts,
208 xform_spin_init, xform_spin_cleanup, xform_spin_exec
209 };
210
211 /* **************** xform_ripple **************** */
212 struct pn_actuator_option_desc xform_ripple_opts[] =
213 {
214 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } },
215 { "ripples", "The number of ripples that fit on the screen "
216 "(horizontally)", OPT_TYPE_FLOAT, { fval: 8 } },
217 { "base_speed", "The minimum number of pixels to move each pixel",
218 OPT_TYPE_FLOAT, { fval: 1 } },
219 { "mod_speed", "The maximum number of pixels by which base_speed"
220 " will be modified", OPT_TYPE_FLOAT, { fval: 1 } },
221 { NULL }
222 };
223
224 struct xform_ripple_data
225 {
226 int width, height;
227 struct xform_vector *vfield;
228 };
229
230 static void
231 xform_ripple_init (gpointer *data)
232 {
233 *data = g_new0 (struct xform_ripple_data, 1);
234 }
235
236 static void
237 xform_ripple_cleanup (gpointer data)
238 {
239 struct xform_ripple_data *d = (struct xform_ripple_data*) data;
240
241 if (d)
242 {
243 if (d->vfield)
244 g_free (d->vfield);
245 g_free (d);
246 }
247 }
248
249 static void
250 xform_ripple_exec (const struct pn_actuator_option *opts,
251 gpointer data)
252 {
253 struct xform_ripple_data *d = (struct xform_ripple_data*)data;
254 float i, j;
255
256 if (d->width != pn_image_data->width
257 || d->height != pn_image_data->height)
258 {
259 d->width = pn_image_data->width;
260 d->height = pn_image_data->height;
261
262 if (d->vfield)
263 g_free (d->vfield);
264
265 d->vfield = g_malloc (sizeof(struct xform_vector)
266 * d->width * d->height);
267
268 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
269 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
270 {
271 float r, t = 0;
272 float x, y;
273
274 r = sqrt (i*i + j*j);
275 if (r)
276 t = asin (j/r);
277 if (i < 0)
278 t = M_PI - t;
279
280 t += opts[0].val.fval * M_PI/180.0;
281
282 if (r > 4)//(pn_image_data->width/(2*opts[1].val.fval)))
283 r -= opts[2].val.fval + (opts[3].val.fval/2) *
284 (1 + sin ((r/(pn_image_data->width/(2*opts[1].val.fval)))*M_PI));
285 /* else if (r > 4) */
286 /* r *= r/(pn_image_data->width/opts[1].val.fval); */
287 else /* don't let it explode */
288 r = 1000000;
289
290
291 x = (r * cos (t)) + (pn_image_data->width>>1);
292 y = (pn_image_data->height>>1) - (r * sin (t));
293
294 xfvec (x, y, &d->vfield
295 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
296 ((pn_image_data->height>>1)-(int)rint(j)))]);
297 }
298 }
299
300 apply_xform (d->vfield);
301 pn_swap_surfaces ();
302 }
303
304 struct pn_actuator_desc builtin_xform_ripple =
305 {
306 "xform_ripple", "Ripple Transform", "Creates an ripple effect",
307 0, xform_ripple_opts,
308 xform_ripple_init, xform_ripple_cleanup, xform_ripple_exec
309 };
310
311 /* **************** xform_bump_spin **************** */
312 struct pn_actuator_option_desc xform_bump_spin_opts[] =
313 {
314 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } },
315 { "bumps", "The number of bumps that on the image",
316 OPT_TYPE_FLOAT, { fval: 8 } },
317 { "base_scale", "The base radial scale",
318 OPT_TYPE_FLOAT, { fval: 0.95 } },
319 { "mod_scale", "The maximum amount that should be "
320 "added to the base_scale to create the 'bump' effect",
321 OPT_TYPE_FLOAT, { fval: .1 } },
322 { NULL }
323 };
324
325 struct xform_bump_spin_data
326 {
327 int width, height;
328 struct xform_vector *vfield;
329 };
330
331 static void
332 xform_bump_spin_init (gpointer *data)
333 {
334 *data = g_new0 (struct xform_bump_spin_data, 1);
335 }
336
337 static void
338 xform_bump_spin_cleanup (gpointer data)
339 {
340 struct xform_bump_spin_data *d = (struct xform_bump_spin_data*) data;
341
342 if (d)
343 {
344 if (d->vfield)
345 g_free (d->vfield);
346 g_free (d);
347 }
348 }
349
350 static void
351 xform_bump_spin_exec (const struct pn_actuator_option *opts,
352 gpointer data)
353 {
354 struct xform_bump_spin_data *d = (struct xform_bump_spin_data*)data;
355 float i, j;
356
357 if (d->width != pn_image_data->width
358 || d->height != pn_image_data->height)
359 {
360 d->width = pn_image_data->width;
361 d->height = pn_image_data->height;
362
363 if (d->vfield)
364 g_free (d->vfield);
365
366 d->vfield = g_malloc (sizeof(struct xform_vector)
367 * d->width * d->height);
368
369 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
370 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
371 {
372 float r, t = 0;
373 float x, y;
374
375 r = sqrt (i*i + j*j);
376 if (r)
377 t = asin (j/r);
378 if (i < 0)
379 t = M_PI - t;
380
381 t += opts[0].val.fval * M_PI/180.0;
382
383 r *= opts[2].val.fval + opts[3].val.fval
384 * (1 + sin (t*opts[1].val.fval));
385
386 x = (r * cos (t)) + (pn_image_data->width>>1);
387 y = (pn_image_data->height>>1) - (r * sin (t));
388
389 xfvec (x, y, &d->vfield
390 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
391 ((pn_image_data->height>>1)-(int)rint(j)))]);
392 }
393 }
394
395 apply_xform (d->vfield);
396 pn_swap_surfaces ();
397 }
398
399 struct pn_actuator_desc builtin_xform_bump_spin =
400 {
401 "xform_bump_spin", "Bump Transform",
402 "Rotate the image at a varying speed to create "
403 "the illusion of bumps",
404 0, xform_bump_spin_opts,
405 xform_bump_spin_init, xform_bump_spin_cleanup, xform_bump_spin_exec
406 };
407
408 /* **************** xform_halfrender **************** */
409 struct pn_actuator_option_desc xform_halfrender_opts[] =
410 {
411 { "direction", "Negative is horizontal, positive is vertical.",
412 OPT_TYPE_INT, { ival: 1 } },
413 { "render_twice", "Render the second image.",
414 OPT_TYPE_BOOLEAN, { bval: TRUE } },
415 { NULL }
416 };
417
418 static void
419 xform_halfrender_exec (const struct pn_actuator_option *opts,
420 gpointer data)
421 {
422 gint x, y;
423
424 if (opts[0].val.ival < 0)
425 {
426 for (y = 0; y < pn_image_data->height; y += 2)
427 {
428 for (x = 0; x < pn_image_data->width; x++)
429 {
430 pn_image_data->surface[1][PN_IMG_INDEX(x, y / 2)] =
431 pn_image_data->surface[0][PN_IMG_INDEX(x, y)];
432 if (opts[1].val.bval)
433 {
434 pn_image_data->surface[1][PN_IMG_INDEX(x, (y / 2) + (pn_image_data->height / 2))] =
435 pn_image_data->surface[0][PN_IMG_INDEX(x, y)];
436 }
437 }
438 }
439 }
440 else
441 {
442 for (y = 0; y < pn_image_data->height; y++)
443 {
444 for (x = 0; x < pn_image_data->width; x += 2)
445 {
446 pn_image_data->surface[1][PN_IMG_INDEX(x / 2, y)] =
447 pn_image_data->surface[0][PN_IMG_INDEX(x, y)];
448 if (opts[1].val.bval)
449 {
450 pn_image_data->surface[1][PN_IMG_INDEX((x / 2) + (pn_image_data->width / 2), y)] =
451 pn_image_data->surface[0][PN_IMG_INDEX(x, y)];
452 }
453 }
454 }
455 }
456
457 pn_swap_surfaces ();
458 }
459
460 struct pn_actuator_desc builtin_xform_halfrender =
461 {
462 "xform_halfrender", "Halfrender Transform",
463 "Divides the surface in half and renders it twice.",
464 0, xform_halfrender_opts,
465 NULL, NULL, xform_halfrender_exec
466 };
467
468 /* **************** xform_movement **************** */
469 struct pn_actuator_option_desc xform_movement_opts[] =
470 {
471 { "formula", "The formula to evaluate.",
472 OPT_TYPE_STRING, { sval: "r = r * cos(r); d = sin(d);" } },
473 { "polar", "Whether the coordinates are polar or not.",
474 OPT_TYPE_BOOLEAN, { bval: TRUE } },
475 { NULL }
476 };
477
478 typedef struct {
479 int width, height; /* Previous width and height. */
480 struct xform_vector *vfield;
481 } PnMovementData;
482
483 static void
484 xform_movement_init (gpointer *data)
485 {
486 *data = g_new0(PnMovementData, 1);
487 }
488
489 static void
490 xform_movement_cleanup (gpointer data)
491 {
492 PnMovementData *d = (PnMovementData *) data;
493
494 if (d)
495 {
496 if (d->vfield)
497 g_free (d->vfield);
498 g_free (d);
499 }
500 }
501
502 inline void
503 xform_trans_polar (struct xform_vector *vfield, gint x, gint y,
504 expression_t *expr, symbol_dict_t *dict)
505 {
506 gdouble *rf, *df;
507 gdouble xf, yf;
508 gint xn, yn;
509
510 rf = dict_variable(dict, "r");
511 df = dict_variable(dict, "d");
512
513 /* Points (xf, yf) must be in a (-1..1) square. */
514 xf = 2.0 * x / (pn_image_data->width - 1) - 1.0;
515 yf = 2.0 * y / (pn_image_data->height - 1) - 1.0;
516
517 /* Now, convert to polar coordinates r and d. */
518 *rf = hypot(xf, yf);
519 *df = atan2(yf, xf);
520
521 /* Run the script. */
522 expr_execute(expr, dict);
523
524 /* Back to (-1..1) square. */
525 xf = (*rf) * cos ((*df));
526 yf = (*rf) * sin ((*df));
527
528 /* Convert back to physical coordinates. */
529 xn = (int)(((xf + 1.0) * (pn_image_data->width - 1) / 2) + 0.5);
530 yn = (int)(((yf + 1.0) * (pn_image_data->height - 1) / 2) + 0.5);
531
532 if (xn < 0 || xn >= pn_image_data->width || yn < 0 || yn >= pn_image_data->height)
533 {
534 xn = x; yn = y;
535 }
536
537 xfvec (xn, yn, &vfield[PN_IMG_INDEX (x, y)]);
538 }
539
540 inline void
541 xform_trans_literal (struct xform_vector *vfield, gint x, gint y,
542 expression_t *expr, symbol_dict_t *dict)
543 {
544 gdouble rf, df;
545 gdouble *xf, *yf;
546 gint xn, yn;
547
548 xf = dict_variable(dict, "x");
549 yf = dict_variable(dict, "y");
550
551 /* Points (xf, yf) must be in a (-1..1) square. */
552 *xf = 2.0 * x / (pn_image_data->width - 1) - 1.0;
553 *yf = 2.0 * y / (pn_image_data->height - 1) - 1.0;
554
555 /* Run the script. */
556 expr_execute(expr, dict);
557
558 /* Convert back to physical coordinates. */
559 xn = (int)(((*xf + 1.0) * (pn_image_data->width - 1) / 2) + 0.5);
560 yn = (int)(((*yf + 1.0) * (pn_image_data->height - 1) / 2) + 0.5);
561
562 if (xn < 0 || xn >= pn_image_data->width || yn < 0 || yn >= pn_image_data->height)
563 {
564 xn = x; yn = y;
565 }
566
567 xfvec (xn, yn, &vfield[PN_IMG_INDEX (x, y)]);
568 }
569
570 static void
571 xform_movement_exec (const struct pn_actuator_option *opts,
572 gpointer odata)
573 {
574 PnMovementData *d = (PnMovementData *) odata;
575 void (*transform_func)(struct xform_vector *, gint, gint, expression_t *, symbol_dict_t *) =
576 opts[1].val.bval == TRUE ? xform_trans_polar : xform_trans_literal;
577
578 if (d->width != pn_image_data->width
579 || d->height != pn_image_data->height)
580 {
581 gint i, j;
582 gdouble *rf, *df;
583 gdouble xf, yf;
584 gint xn, yn;
585 expression_t *expr;
586 symbol_dict_t *dict;
587
588 d->width = pn_image_data->width;
589 d->height = pn_image_data->height;
590
591 if (d->vfield)
592 {
593 g_free (d->vfield);
594 d->vfield = NULL;
595 }
596
597 if (opts[0].val.sval == NULL)
598 return;
599
600 dict = dict_new();
601 expr = expr_compile_string(opts[0].val.sval, dict);
602 if (!expr)
603 {
604 dict_free(dict);
605 return;
606 }
607
608 rf = dict_variable(dict, "r");
609 df = dict_variable(dict, "d");
610
611 d->vfield = g_malloc (sizeof(struct xform_vector)
612 * d->width * d->height);
613
614 for (j = 0; j < pn_image_data->height; j++)
615 for (i = 0; i < pn_image_data->width; i++)
616 {
617 transform_func(d->vfield, i, j, expr, dict);
618 }
619 }
620
621 apply_xform (d->vfield);
622 pn_swap_surfaces ();
623 }
624
625 struct pn_actuator_desc builtin_xform_movement =
626 {
627 "xform_movement", "Movement Transform",
628 "A customizable blitter.",
629 0, xform_movement_opts,
630 xform_movement_init, xform_movement_cleanup, xform_movement_exec
631 };
632
633 /* **************** xform_dynmovement **************** */
634 /* FIXME: really slow */
635 struct pn_actuator_option_desc xform_dynmovement_opts[] =
636 {
637 { "init_script", "The formula to evaluate on init.",
638 OPT_TYPE_STRING, { sval: "" } },
639 { "beat_script", "The formula to evaluate on each beat.",
640 OPT_TYPE_STRING, { sval: "" } },
641 { "frame_script", "The formula to evaluate on each frame.",
642 OPT_TYPE_STRING, { sval: "" } },
643 { "point_script", "The formula to evaluate.",
644 OPT_TYPE_STRING, { sval: "d = 0.15;" } },
645 { "polar", "Whether or not the coordinates to use are polar.",
646 OPT_TYPE_BOOLEAN, { bval: TRUE } },
647 { NULL }
648 };
649
650 typedef struct {
651 int width, height; /* Previous width and height. */
652 expression_t *expr_init;
653 expression_t *expr_frame;
654 expression_t *expr_beat;
655 expression_t *expr_point;
656 symbol_dict_t *dict;
657 struct xform_vector *vfield;
658 } PnDynMovementData;
659
660 static void
661 xform_dynmovement_init (gpointer *data)
662 {
663 *data = g_new0(PnDynMovementData, 1);
664 }
665
666 static void
667 xform_dynmovement_cleanup (gpointer data)
668 {
669 PnDynMovementData *d = (PnDynMovementData *) data;
670
671 if (d)
672 {
673 if (d->expr_init)
674 expr_free (d->expr_init);
675 if (d->expr_beat)
676 expr_free (d->expr_beat);
677 if (d->expr_frame)
678 expr_free (d->expr_frame);
679 if (d->expr_point)
680 expr_free (d->expr_point);
681 if (d->dict)
682 dict_free (d->dict);
683 if (d->vfield)
684 g_free (d->vfield);
685 g_free (d);
686 }
687 }
688
689 static void
690 xform_dynmovement_exec (const struct pn_actuator_option *opts,
691 gpointer odata)
692 {
693 PnDynMovementData *d = (PnDynMovementData *) odata;
694 gint i, j;
695 gdouble *rf, *df;
696 gdouble xf, yf;
697 gint xn, yn;
698 void (*transform_func)(struct xform_vector *, gint, gint, expression_t *, symbol_dict_t *) =
699 opts[4].val.bval == TRUE ? xform_trans_polar : xform_trans_literal;
700 gboolean make_table = FALSE;
701
702 if (d->width != pn_image_data->width
703 || d->height != pn_image_data->height)
704 {
705 d->width = pn_image_data->width;
706 d->height = pn_image_data->height;
707
708 if (d->vfield)
709 {
710 g_free (d->vfield);
711 d->vfield = NULL;
712 }
713
714 if (opts[3].val.sval == NULL)
715 return;
716
717 if (!d->dict)
718 d->dict = dict_new();
719 else
720 {
721 dict_free(d->dict);
722 d->dict = dict_new();
723 }
724
725 if (d->expr_init)
726 {
727 expr_free(d->expr_init);
728 d->expr_init = NULL;
729 }
730
731 /* initialize */
732 d->expr_init = expr_compile_string(opts[0].val.sval, d->dict);
733
734 if (d->expr_init != NULL)
735 {
736 expr_execute(d->expr_init, d->dict);
737 }
738
739 d->expr_beat = expr_compile_string(opts[1].val.sval, d->dict);
740 d->expr_frame = expr_compile_string(opts[2].val.sval, d->dict);
741 d->expr_point = expr_compile_string(opts[3].val.sval, d->dict);
742
743 d->vfield = g_malloc (sizeof(struct xform_vector)
744 * d->width * d->height);
745
746 make_table = TRUE;
747 }
748
749 rf = dict_variable(d->dict, "r");
750 df = dict_variable(d->dict, "d");
751
752 if (*opts[2].val.sval != '\0' || pn_new_beat)
753 make_table = TRUE;
754
755 /* run the on-frame script. */
756 if (make_table == TRUE)
757 {
758 if (d->expr_beat != NULL)
759 expr_execute(d->expr_beat, d->dict);
760
761 if (d->expr_frame != NULL)
762 expr_execute(d->expr_frame, d->dict);
763
764 for (j = 0; j < pn_image_data->height; j++)
765 for (i = 0; i < pn_image_data->width; i++)
766 {
767 transform_func(d->vfield, i, j, d->expr_point, d->dict);
768 }
769 }
770
771 apply_xform (d->vfield);
772 pn_swap_surfaces ();
773 }
774
775 struct pn_actuator_desc builtin_xform_dynmovement =
776 {
777 "xform_dynmovement", "Dynamic Movement Transform",
778 "A customizable blitter.",
779 0, xform_dynmovement_opts,
780 xform_dynmovement_init, xform_dynmovement_cleanup, xform_dynmovement_exec
781 };