2 * ifs.c --- modified iterated functions system for goom.
6 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted,
10 * provided that the above copyright notice appear in all copies and that
11 * both that copyright notice and this permission notice appear in
12 * supporting documentation.
14 * This file is provided AS IS with no warranties of any kind. The author
15 * shall have no liability with respect to the infringement of copyrights,
16 * trade secrets or any patents by this file or any part thereof. In no
17 * event will the author be liable for any lost revenue or profits or
18 * other special, indirect and consequential damages.
20 * If this mode is weird and you have an old MetroX server, it is buggy.
21 * There is a free SuSE-enhanced MetroX X server that is fine.
23 * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
26 * 13-Dec-2003: Added some goom specific stuffs (to make ifs a VisualFX).
27 * 11-Apr-2002: jeko@ios-software.com: Make ifs.c system-indendant. (ifs.h added)
28 * 01-Nov-2000: Allocation checks
29 * 10-May-1997: jwz@jwz.org: turned into a standalone program.
30 * Made it render into an offscreen bitmap and then copy
31 * that onto the screen, to reduce flicker.
34 /* #ifdef STANDALONE */
40 #include "goom_config.h"
46 #include "goom_graphic.h"
48 #include "goom_tools.h"
50 typedef struct _ifsPoint
59 #define PROGCLASS "IFS"
61 #define HACK_INIT init_ifs
62 #define HACK_DRAW draw_ifs
64 #define ifs_opts xlockmore_opts
66 #define DEFAULTS "*delay: 20000 \n" \
71 #define LRAND() ((long) (goom_random(goomInfo->gRandom) & 0x7fffffff))
72 #define NRAND(n) ((int) (LRAND() % (n)))
74 #if RAND_MAX < 0x10000
75 #define MAXRAND (((float)(RAND_MAX<16)+((float)RAND_MAX)+1.0f)/127.0f)
77 #define MAXRAND (2147483648.0/127.0) /* unsigned 1<<31 / 127.0 (cf goom_tools) as a float */
80 /*****************************************************/
85 /* typedef float F_PT; */
87 /*****************************************************/
90 #define UNIT ( 1<<FIX )
93 #define MAX_DEPTH_2 10
101 * settings for a PC 120Mhz... *
102 #define MAX_DEPTH_2 10
103 #define MAX_DEPTH_3 6
104 #define MAX_DEPTH_4 4
105 #define MAX_DEPTH_5 3
108 #define DBL_To_F_PT(x) (F_PT)( (DBL)(UNIT)*(x) )
110 typedef struct Similitude_Struct SIMI;
111 typedef struct Fractal_Struct FRACTAL;
113 struct Similitude_Struct
118 F_PT Ct, St, Ct2, St2;
124 struct Fractal_Struct
128 SIMI Components[5 * MAX_SIMI];
131 int Width, Height, Lx, Ly;
132 DBL r_mean, dr_mean, dr2_mean;
135 IFSPoint *Buffer1, *Buffer2;
138 typedef struct _IFS_DATA
143 /* Used by the Trace recursive method */
150 /*****************************************************/
153 Gauss_Rand (PluginInfo * goomInfo, DBL c, DBL A, DBL S)
157 y = (DBL) LRAND () / MAXRAND;
158 y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
165 Half_Gauss_Rand (PluginInfo * goomInfo, DBL c, DBL A, DBL S)
169 y = (DBL) LRAND () / MAXRAND;
170 y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
175 Random_Simis (PluginInfo * goomInfo, FRACTAL * F, SIMI * Cur, int i)
178 Cur->c_x = Gauss_Rand (goomInfo, 0.0, .8, 4.0);
179 Cur->c_y = Gauss_Rand (goomInfo, 0.0, .8, 4.0);
180 Cur->r = Gauss_Rand (goomInfo, F->r_mean, F->dr_mean, 3.0);
181 Cur->r2 = Half_Gauss_Rand (goomInfo, 0.0, F->dr2_mean, 2.0);
182 Cur->A = Gauss_Rand (goomInfo, 0.0, 360.0, 4.0) * (M_PI / 180.0);
183 Cur->A2 = Gauss_Rand (goomInfo, 0.0, 360.0, 4.0) * (M_PI / 180.0);
189 free_ifs_buffers (FRACTAL * Fractal)
191 if (Fractal->Buffer1 != NULL) {
192 (void) free ((void *) Fractal->Buffer1);
193 Fractal->Buffer1 = (IFSPoint *) NULL;
195 if (Fractal->Buffer2 != NULL) {
196 (void) free ((void *) Fractal->Buffer2);
197 Fractal->Buffer2 = (IFSPoint *) NULL;
203 free_ifs (FRACTAL * Fractal)
205 free_ifs_buffers (Fractal);
208 /***************************************************************/
211 init_ifs (PluginInfo * goomInfo, IfsData * data)
215 int width = goomInfo->screen.width;
216 int height = goomInfo->screen.height;
218 if (data->Root == NULL) {
219 data->Root = (FRACTAL *) malloc (sizeof (FRACTAL));
220 if (data->Root == NULL)
222 data->Root->Buffer1 = (IFSPoint *) NULL;
223 data->Root->Buffer2 = (IFSPoint *) NULL;
225 Fractal = data->Root;
227 free_ifs_buffers (Fractal);
229 i = (NRAND (4)) + 2; /* Number of centers */
232 Fractal->Depth = MAX_DEPTH_3;
233 Fractal->r_mean = .6;
234 Fractal->dr_mean = .4;
235 Fractal->dr2_mean = .3;
239 Fractal->Depth = MAX_DEPTH_4;
240 Fractal->r_mean = .5;
241 Fractal->dr_mean = .4;
242 Fractal->dr2_mean = .3;
246 Fractal->Depth = MAX_DEPTH_5;
247 Fractal->r_mean = .5;
248 Fractal->dr_mean = .4;
249 Fractal->dr2_mean = .3;
254 Fractal->Depth = MAX_DEPTH_2;
255 Fractal->r_mean = .7;
256 Fractal->dr_mean = .3;
257 Fractal->dr2_mean = .4;
260 Fractal->Nb_Simi = i;
261 Fractal->Max_Pt = Fractal->Nb_Simi - 1;
262 for (i = 0; i <= Fractal->Depth + 2; ++i)
263 Fractal->Max_Pt *= Fractal->Nb_Simi;
265 if ((Fractal->Buffer1 = (IFSPoint *) calloc (Fractal->Max_Pt,
266 sizeof (IFSPoint))) == NULL) {
270 if ((Fractal->Buffer2 = (IFSPoint *) calloc (Fractal->Max_Pt,
271 sizeof (IFSPoint))) == NULL) {
277 Fractal->Width = width; /* modif by JeKo */
278 Fractal->Height = height; /* modif by JeKo */
281 Fractal->Lx = (Fractal->Width - 1) / 2;
282 Fractal->Ly = (Fractal->Height - 1) / 2;
283 Fractal->Col = rand () % (width * height); /* modif by JeKo */
285 Random_Simis (goomInfo, Fractal, Fractal->Components, 5 * MAX_SIMI);
289 /***************************************************************/
292 Transform (SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
297 xo = (xo * Simi->R) >> FIX; /* / UNIT; */
299 yo = (yo * Simi->R) >> FIX; /* / UNIT; */
302 xx = (xx * Simi->R2) >> FIX; /* / UNIT; */
304 yy = (yy * Simi->R2) >> FIX; /* / UNIT; */
306 *x = ((xo * Simi->Ct - yo * Simi->St + xx * Simi->Ct2 - yy * Simi->St2)
307 >> FIX /* / UNIT */ ) + Simi->Cx;
308 *y = ((xo * Simi->St + yo * Simi->Ct + xx * Simi->St2 + yy * Simi->Ct2)
309 >> FIX /* / UNIT */ ) + Simi->Cy;
312 /***************************************************************/
315 Trace (FRACTAL * F, F_PT xo, F_PT yo, IfsData * data)
320 Cur = data->Cur_F->Components;
321 for (i = data->Cur_F->Nb_Simi; i; --i, Cur++) {
322 Transform (Cur, xo, yo, &x, &y);
324 data->Buf->x = F->Lx + ((x * F->Lx) >> (FIX + 1) /* /(UNIT*2) */ );
325 data->Buf->y = F->Ly - ((y * F->Ly) >> (FIX + 1) /* /(UNIT*2) */ );
330 if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
332 Trace (F, x, y, data);
339 Draw_Fractal (IfsData * data)
341 FRACTAL *F = data->Root;
346 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
347 Cur->Cx = DBL_To_F_PT (Cur->c_x);
348 Cur->Cy = DBL_To_F_PT (Cur->c_y);
350 Cur->Ct = DBL_To_F_PT (cos (Cur->A));
351 Cur->St = DBL_To_F_PT (sin (Cur->A));
352 Cur->Ct2 = DBL_To_F_PT (cos (Cur->A2));
353 Cur->St2 = DBL_To_F_PT (sin (Cur->A2));
355 Cur->R = DBL_To_F_PT (Cur->r);
356 Cur->R2 = DBL_To_F_PT (Cur->r2);
362 data->Buf = F->Buffer2;
363 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
366 for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
369 Transform (Simi, xo, yo, &x, &y);
370 Trace (F, x, y, data);
376 F->Cur_Pt = data->Cur_Pt;
377 data->Buf = F->Buffer1;
378 F->Buffer1 = F->Buffer2;
379 F->Buffer2 = data->Buf;
384 draw_ifs (PluginInfo * goomInfo, int *nbpt, IfsData * data)
387 DBL u, uu, v, vv, u0, u1, u2, u3;
388 SIMI *S, *S1, *S2, *S3, *S4;
391 if (data->Root == NULL)
394 if (F->Buffer1 == NULL)
397 u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0;
408 S2 = S1 + F->Nb_Simi;
409 S3 = S2 + F->Nb_Simi;
410 S4 = S3 + F->Nb_Simi;
412 for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
413 S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x;
414 S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y;
415 S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r;
416 S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2;
417 S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A;
418 S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2;
423 if (F->Count >= 1000 / F->Speed) {
426 S2 = S1 + F->Nb_Simi;
427 S3 = S2 + F->Nb_Simi;
428 S4 = S3 + F->Nb_Simi;
430 for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
431 S2->c_x = 2.0 * S4->c_x - S3->c_x;
432 S2->c_y = 2.0 * S4->c_y - S3->c_y;
433 S2->r = 2.0 * S4->r - S3->r;
434 S2->r2 = 2.0 * S4->r2 - S3->r2;
435 S2->A = 2.0 * S4->A - S3->A;
436 S2->A2 = 2.0 * S4->A2 - S3->A2;
440 Random_Simis (goomInfo, F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
442 Random_Simis (goomInfo, F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
450 (*nbpt) = data->Cur_Pt;
455 /***************************************************************/
458 release_ifs (IfsData * data)
460 if (data->Root != NULL) {
461 free_ifs (data->Root);
462 (void) free ((void *) data->Root);
463 data->Root = (FRACTAL *) NULL;
467 #define RAND() goom_random(goomInfo->gRandom)
470 ifs_update (PluginInfo * goomInfo, Pixel * data, Pixel * back, int increment,
473 static int couleur = 0xc0c0c0c0;
474 static int v[4] = { 2, 4, 3, 2 };
475 static int col[4] = { 2, 4, 3, 2 };
480 static int mode = MOD_MERVER;
481 static int justChanged = 0;
482 static int cycle = 0;
489 int couleursl = couleur;
490 int width = goomInfo->screen.width;
491 int height = goomInfo->screen.height;
498 cycle10 = cycle / 10;
500 cycle10 = 7 - cycle / 10;
503 unsigned char *tmp = (unsigned char *) &couleursl;
505 for (i = 0; i < 4; i++) {
506 *tmp = (*tmp) >> cycle10;
511 points = draw_ifs (goomInfo, &nbpt, fx_data);
515 movd_m2r (couleursl, mm1);
516 punpckldq_r2r (mm1, mm1);
517 for (i = 0; i < nbpt; i += increment) {
521 if ((x < width) && (y < height) && (x > 0) && (y > 0)) {
522 int pos = x + (y * width);
524 movd_m2r (back[pos], mm0);
525 paddusb_r2r (mm1, mm0);
526 movd_r2m (mm0, data[pos]);
529 emms (); /*__asm__ __volatile__ ("emms");*/
531 for (i = 0; i < nbpt; i += increment) {
532 int x = (int) points[i].x & 0x7fffffff;
533 int y = (int) points[i].y & 0x7fffffff;
535 if ((x < width) && (y < height)) {
536 int pos = x + (int) (y * width);
538 unsigned char *bra = (unsigned char *) &back[pos];
539 unsigned char *dra = (unsigned char *) &data[pos];
540 unsigned char *cra = (unsigned char *) &couleursl;
557 col[ALPHA] = couleur >> (ALPHA * 8) & 0xff;
558 col[BLEU] = couleur >> (BLEU * 8) & 0xff;
559 col[VERT] = couleur >> (VERT * 8) & 0xff;
560 col[ROUGE] = couleur >> (ROUGE * 8) & 0xff;
562 if (mode == MOD_MER) {
563 col[BLEU] += v[BLEU];
564 if (col[BLEU] > 255) {
566 v[BLEU] = -(RAND () % 4) - 1;
568 if (col[BLEU] < 32) {
570 v[BLEU] = (RAND () % 4) + 1;
573 col[VERT] += v[VERT];
574 if (col[VERT] > 200) {
576 v[VERT] = -(RAND () % 3) - 2;
578 if (col[VERT] > col[BLEU]) {
579 col[VERT] = col[BLEU];
582 if (col[VERT] < 32) {
584 v[VERT] = (RAND () % 3) + 2;
587 col[ROUGE] += v[ROUGE];
588 if (col[ROUGE] > 64) {
590 v[ROUGE] = -(RAND () % 4) - 1;
592 if (col[ROUGE] < 0) {
594 v[ROUGE] = (RAND () % 4) + 1;
597 col[ALPHA] += v[ALPHA];
598 if (col[ALPHA] > 0) {
600 v[ALPHA] = -(RAND () % 4) - 1;
602 if (col[ALPHA] < 0) {
604 v[ALPHA] = (RAND () % 4) + 1;
607 if (((col[VERT] > 32) && (col[ROUGE] < col[VERT] + 40)
608 && (col[VERT] < col[ROUGE] + 20) && (col[BLEU] < 64)
609 && (RAND () % 20 == 0)) && (justChanged < 0)) {
610 mode = RAND () % 3 ? MOD_FEU : MOD_MERVER;
613 } else if (mode == MOD_MERVER) {
614 col[BLEU] += v[BLEU];
615 if (col[BLEU] > 128) {
617 v[BLEU] = -(RAND () % 4) - 1;
619 if (col[BLEU] < 16) {
621 v[BLEU] = (RAND () % 4) + 1;
624 col[VERT] += v[VERT];
625 if (col[VERT] > 200) {
627 v[VERT] = -(RAND () % 3) - 2;
629 if (col[VERT] > col[ALPHA]) {
630 col[VERT] = col[ALPHA];
633 if (col[VERT] < 32) {
635 v[VERT] = (RAND () % 3) + 2;
638 col[ROUGE] += v[ROUGE];
639 if (col[ROUGE] > 128) {
641 v[ROUGE] = -(RAND () % 4) - 1;
643 if (col[ROUGE] < 0) {
645 v[ROUGE] = (RAND () % 4) + 1;
648 col[ALPHA] += v[ALPHA];
649 if (col[ALPHA] > 255) {
651 v[ALPHA] = -(RAND () % 4) - 1;
653 if (col[ALPHA] < 0) {
655 v[ALPHA] = (RAND () % 4) + 1;
658 if (((col[VERT] > 32) && (col[ROUGE] < col[VERT] + 40)
659 && (col[VERT] < col[ROUGE] + 20) && (col[BLEU] < 64)
660 && (RAND () % 20 == 0)) && (justChanged < 0)) {
661 mode = RAND () % 3 ? MOD_FEU : MOD_MER;
664 } else if (mode == MOD_FEU) {
666 col[BLEU] += v[BLEU];
667 if (col[BLEU] > 64) {
669 v[BLEU] = -(RAND () % 4) - 1;
673 v[BLEU] = (RAND () % 4) + 1;
676 col[VERT] += v[VERT];
677 if (col[VERT] > 200) {
679 v[VERT] = -(RAND () % 3) - 2;
681 if (col[VERT] > col[ROUGE] + 20) {
682 col[VERT] = col[ROUGE] + 20;
683 v[VERT] = -(RAND () % 3) - 2;
684 v[ROUGE] = (RAND () % 4) + 1;
685 v[BLEU] = (RAND () % 4) + 1;
689 v[VERT] = (RAND () % 3) + 2;
692 col[ROUGE] += v[ROUGE];
693 if (col[ROUGE] > 255) {
695 v[ROUGE] = -(RAND () % 4) - 1;
697 if (col[ROUGE] > col[VERT] + 40) {
698 col[ROUGE] = col[VERT] + 40;
699 v[ROUGE] = -(RAND () % 4) - 1;
701 if (col[ROUGE] < 0) {
703 v[ROUGE] = (RAND () % 4) + 1;
706 col[ALPHA] += v[ALPHA];
707 if (col[ALPHA] > 0) {
709 v[ALPHA] = -(RAND () % 4) - 1;
711 if (col[ALPHA] < 0) {
713 v[ALPHA] = (RAND () % 4) + 1;
716 if (((col[ROUGE] < 64) && (col[VERT] > 32) && (col[VERT] < col[BLEU])
718 && (RAND () % 20 == 0)) && (justChanged < 0)) {
719 mode = RAND () % 2 ? MOD_MER : MOD_MERVER;
724 couleur = (col[ALPHA] << (ALPHA * 8))
725 | (col[BLEU] << (BLEU * 8))
726 | (col[VERT] << (VERT * 8))
727 | (col[ROUGE] << (ROUGE * 8));
730 /** VISUAL_FX WRAPPER FOR IFS */
733 ifs_vfx_apply (VisualFX * _this, Pixel * src, Pixel * dest,
734 PluginInfo * goomInfo)
737 IfsData *data = (IfsData *) _this->fx_data;
739 if (!data->initalized) {
740 data->initalized = 1;
741 init_ifs (goomInfo, data);
743 ifs_update (goomInfo, dest, src, goomInfo->update.ifs_incr, data);
744 /*TODO: trouver meilleur soluce pour increment (mettre le code de gestion de l'ifs dans ce fichier: ifs_vfx_apply) */
748 ifs_vfx_init (VisualFX * _this, PluginInfo * info)
751 IfsData *data = (IfsData *) malloc (sizeof (IfsData));
753 data->Root = (FRACTAL *) NULL;
754 data->initalized = 0;
755 _this->fx_data = data;
759 ifs_vfx_free (VisualFX * _this)
761 IfsData *data = (IfsData *) _this->fx_data;
768 ifs_visualfx_create (void)
772 vfx.init = ifs_vfx_init;
773 vfx.free = ifs_vfx_free;
774 vfx.apply = ifs_vfx_apply;