Mercurial > audlegacy-plugins
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 |