comparison src/paranormal/xform.c @ 149:fd9c0a5871ac trunk

[svn] - new and IMPROVED paranormal visualization studio
author nenolod
date Mon, 30 Oct 2006 23:02:33 -0800
parents
children adf9f4b26039
comparison
equal deleted inserted replaced
148:9d9fc9e1de48 149:fd9c0a5871ac
1 /* FIXME: allow for only using an xform on part of the img? */
2 /* FIXME: perhaps combine these into a single vector field
3 so that only 1 apply_xform needs to be done for as many
4 of these as someone wants to use */
5
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
9
10 #include <math.h>
11
12 #include <glib.h>
13
14 #include "paranormal.h"
15 #include "actuators.h"
16 #include "pn_utils.h"
17
18 struct xform_vector
19 {
20 guint offset; /* the offset of the top left pixel */
21 guint16 w; /* 4:4:4:4 NE, NW, SE, SW pixel weights
22 The total should be 16 */
23
24 /* if offset < 0 then w is the color index to
25 which the pixel will be set */
26 };
27
28 static void
29 xfvec (float x, float y, struct xform_vector *v)
30 {
31 float xd, yd;
32 int weight[4];
33
34 if (x >= pn_image_data->width-1 || y >= pn_image_data->height-1
35 || x < 0 || y < 0)
36 {
37 v->offset = -1;
38 v->w = 0;
39 return;
40 }
41
42 v->offset = PN_IMG_INDEX (floor(x), floor(y));
43
44 xd = x - floor (x);
45 yd = y - floor (y);
46
47 weight[3] = xd * yd * 16;
48 weight[2] = (1-xd) * yd * 16;
49 weight[1] = xd * (1-yd) * 16;
50 weight[0] = 16 - weight[3] - weight[2] - weight[1]; /* just in case */
51
52 v->w = (weight[0]<<12) | (weight[1]<<8) | (weight[2]<<4) | weight[3];
53 }
54
55 static void
56 apply_xform (struct xform_vector *vfield)
57 {
58 int i;
59 struct xform_vector *v;
60 register guchar *srcptr;
61 register guchar *destptr;
62 register int color;
63
64 for (i=0, v=vfield, destptr=pn_image_data->surface[1];
65 i<pn_image_data->width*pn_image_data->height;
66 i++, v++, destptr++)
67 {
68 /* off the screen */
69 if (v->offset < 0)
70 {
71 *destptr = (guchar)v->w;
72 continue;
73 }
74
75 srcptr = pn_image_data->surface[0] + v->offset;
76
77 /* exactly on the pixel */
78 if (v->w == 0)
79 *destptr = *srcptr;
80
81 /* gotta blend the points */
82 else
83 {
84 color = *srcptr * (v->w>>12);
85 color += *++srcptr * ((v->w>>8) & 0x0f);
86 color += *(srcptr+=pn_image_data->width) * (v->w & 0x0f);
87 color += *(--srcptr) * ((v->w>>4) & 0x0f);
88 color >>= 4;
89 *destptr = (guchar)color;
90 }
91 }
92 }
93
94 /* **************** xform_spin **************** */
95 /* FIXME: Describe these better, how they are backwards */
96 /* FIXME: better name? */
97 struct pn_actuator_option_desc xform_spin_opts[] =
98 {
99 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: -8.0 } },
100 { "r_add", "The number of pixels by which the r coordinate will be "
101 "increased (before scaling)", OPT_TYPE_FLOAT, { fval: 0.0 } },
102 { "r_scale", "The amount by which the r coordinate of each pixel will "
103 "be scaled", OPT_TYPE_FLOAT, { fval: 1.0 } },
104 { 0 }
105 };
106
107 struct xform_spin_data
108 {
109 int width, height;
110 struct xform_vector *vfield;
111 };
112
113 static void
114 xform_spin_init (gpointer *data)
115 {
116 *data = g_new0 (struct xform_spin_data, 1);
117 }
118
119 static void
120 xform_spin_cleanup (gpointer data)
121 {
122 struct xform_spin_data *d = (struct xform_spin_data *) data;
123
124
125 if (d)
126 {
127 if (d->vfield)
128 g_free (d->vfield);
129 g_free (d);
130 }
131 }
132
133 static void
134 xform_spin_exec (const struct pn_actuator_option *opts,
135 gpointer data)
136 {
137 struct xform_spin_data *d = (struct xform_spin_data*)data;
138 float i, j;
139
140 if (d->width != pn_image_data->width
141 || d->height != pn_image_data->height)
142 {
143 d->width = pn_image_data->width;
144 d->height = pn_image_data->height;
145
146 if (d->vfield)
147 g_free (d->vfield);
148
149 d->vfield = g_malloc (sizeof(struct xform_vector)
150 * d->width * d->height);
151
152 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
153 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
154 {
155 float r, t = 0;
156 float x, y;
157
158 r = sqrt (i*i + j*j);
159 if (r)
160 t = asin (j/r);
161 if (i < 0)
162 t = M_PI - t;
163
164 t += opts[0].val.fval * M_PI/180.0;
165 r += opts[1].val.fval;
166 r *= opts[2].val.fval;
167
168 x = (r * cos (t)) + (pn_image_data->width>>1);
169 y = (pn_image_data->height>>1) - (r * sin (t));
170
171 xfvec (x, y, &d->vfield
172 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
173 ((pn_image_data->height>>1)-(int)rint(j)))]);
174 }
175 }
176
177 apply_xform (d->vfield);
178 pn_swap_surfaces ();
179 }
180
181 struct pn_actuator_desc builtin_xform_spin =
182 {
183 "xform_spin", "Rotates and radially scales the image",
184 0, xform_spin_opts,
185 xform_spin_init, xform_spin_cleanup, xform_spin_exec
186 };
187
188 /* **************** xform_ripple **************** */
189 struct pn_actuator_option_desc xform_ripple_opts[] =
190 {
191 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } },
192 { "ripples", "The number of ripples that fit on the screen "
193 "(horizontally)", OPT_TYPE_FLOAT, { fval: 8 } },
194 { "base_speed", "The minimum number of pixels to move each pixel",
195 OPT_TYPE_FLOAT, { fval: 1 } },
196 { "mod_speed", "The maximum number of pixels by which base_speed"
197 " will be modified", OPT_TYPE_FLOAT, { fval: 1 } },
198 { 0 }
199 };
200
201 struct xform_ripple_data
202 {
203 int width, height;
204 struct xform_vector *vfield;
205 };
206
207 static void
208 xform_ripple_init (gpointer *data)
209 {
210 *data = g_new0 (struct xform_ripple_data, 1);
211 }
212
213 static void
214 xform_ripple_cleanup (gpointer data)
215 {
216 struct xform_ripple_data *d = (struct xform_ripple_data*) data;
217
218 if (d)
219 {
220 if (d->vfield)
221 g_free (d->vfield);
222 g_free (d);
223 }
224 }
225
226 static void
227 xform_ripple_exec (const struct pn_actuator_option *opts,
228 gpointer data)
229 {
230 struct xform_ripple_data *d = (struct xform_ripple_data*)data;
231 float i, j;
232
233 if (d->width != pn_image_data->width
234 || d->height != pn_image_data->height)
235 {
236 d->width = pn_image_data->width;
237 d->height = pn_image_data->height;
238
239 if (d->vfield)
240 g_free (d->vfield);
241
242 d->vfield = g_malloc (sizeof(struct xform_vector)
243 * d->width * d->height);
244
245 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
246 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
247 {
248 float r, t = 0;
249 float x, y;
250
251 r = sqrt (i*i + j*j);
252 if (r)
253 t = asin (j/r);
254 if (i < 0)
255 t = M_PI - t;
256
257 t += opts[0].val.fval * M_PI/180.0;
258
259 if (r > 4)//(pn_image_data->width/(2*opts[1].val.fval)))
260 r -= opts[2].val.fval + (opts[3].val.fval/2) *
261 (1 + sin ((r/(pn_image_data->width/(2*opts[1].val.fval)))*M_PI));
262 /* else if (r > 4) */
263 /* r *= r/(pn_image_data->width/opts[1].val.fval); */
264 else /* don't let it explode */
265 r = 1000000;
266
267
268 x = (r * cos (t)) + (pn_image_data->width>>1);
269 y = (pn_image_data->height>>1) - (r * sin (t));
270
271 xfvec (x, y, &d->vfield
272 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
273 ((pn_image_data->height>>1)-(int)rint(j)))]);
274 }
275 }
276
277 apply_xform (d->vfield);
278 pn_swap_surfaces ();
279 }
280
281 struct pn_actuator_desc builtin_xform_ripple =
282 {
283 "xform_ripple", "Creates an ripple effect",
284 0, xform_ripple_opts,
285 xform_ripple_init, xform_ripple_cleanup, xform_ripple_exec
286 };
287
288 /* **************** xform_bump_spin **************** */
289 struct pn_actuator_option_desc xform_bump_spin_opts[] =
290 {
291 { "angle", "The angle of rotation", OPT_TYPE_FLOAT, { fval: 0 } },
292 { "bumps", "The number of bumps that on the image",
293 OPT_TYPE_FLOAT, { fval: 8 } },
294 { "base_scale", "The base radial scale",
295 OPT_TYPE_FLOAT, { fval: 0.95 } },
296 { "mod_scale", "The maximum amount that should be "
297 "added to the base_scale to create the 'bump' effect",
298 OPT_TYPE_FLOAT, { fval: .1 } },
299 { 0 }
300 };
301
302 struct xform_bump_spin_data
303 {
304 int width, height;
305 struct xform_vector *vfield;
306 };
307
308 static void
309 xform_bump_spin_init (gpointer *data)
310 {
311 *data = g_new0 (struct xform_bump_spin_data, 1);
312 }
313
314 static void
315 xform_bump_spin_cleanup (gpointer data)
316 {
317 struct xform_bump_spin_data *d = (struct xform_bump_spin_data*) data;
318
319 if (d)
320 {
321 if (d->vfield)
322 g_free (d->vfield);
323 g_free (d);
324 }
325 }
326
327 static void
328 xform_bump_spin_exec (const struct pn_actuator_option *opts,
329 gpointer data)
330 {
331 struct xform_bump_spin_data *d = (struct xform_bump_spin_data*)data;
332 float i, j;
333
334 if (d->width != pn_image_data->width
335 || d->height != pn_image_data->height)
336 {
337 d->width = pn_image_data->width;
338 d->height = pn_image_data->height;
339
340 if (d->vfield)
341 g_free (d->vfield);
342
343 d->vfield = g_malloc (sizeof(struct xform_vector)
344 * d->width * d->height);
345
346 for (j=-(pn_image_data->height>>1)+1; j<=pn_image_data->height>>1; j++)
347 for (i=-(pn_image_data->width>>1); i<pn_image_data->width>>1; i++)
348 {
349 float r, t = 0;
350 float x, y;
351
352 r = sqrt (i*i + j*j);
353 if (r)
354 t = asin (j/r);
355 if (i < 0)
356 t = M_PI - t;
357
358 t += opts[0].val.fval * M_PI/180.0;
359
360 r *= opts[2].val.fval + opts[3].val.fval
361 * (1 + sin (t*opts[1].val.fval));
362
363 x = (r * cos (t)) + (pn_image_data->width>>1);
364 y = (pn_image_data->height>>1) - (r * sin (t));
365
366 xfvec (x, y, &d->vfield
367 [PN_IMG_INDEX ((pn_image_data->width>>1)+(int)rint(i),
368 ((pn_image_data->height>>1)-(int)rint(j)))]);
369 }
370 }
371
372 apply_xform (d->vfield);
373 pn_swap_surfaces ();
374 }
375
376 struct pn_actuator_desc builtin_xform_bump_spin =
377 {
378 "xform_bump_spin", "Rotate the image at a varying speed to create "
379 "the illusion of bumps",
380 0, xform_bump_spin_opts,
381 xform_bump_spin_init, xform_bump_spin_cleanup, xform_bump_spin_exec
382 };
383