MythTV master
ifs.cpp
Go to the documentation of this file.
1/* -*- Mode: C; tab-width: 4 -*- */
2/* ifs --- modified iterated functions system */
3
4//#if !defined( lint ) && !defined( SABER )
5//static const char sccsid[] = "@(#)ifs.c 5.00 2002/04/11 baffe";
6//#endif
7
8/*-
9 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
10 *
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation.
16 *
17 * This file is provided AS IS with no warranties of any kind. The author
18 * shall have no liability with respect to the infringement of copyrights,
19 * trade secrets or any patents by this file or any part thereof. In no
20 * event will the author be liable for any lost revenue or profits or
21 * other special, indirect and consequential damages.
22 *
23 * If this mode is weird and you have an old MetroX server, it is buggy.
24 * There is a free SuSE-enhanced MetroX X server that is fine.
25 *
26 * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
27 *
28 * Revision History:
29 * 11-Apr-2002: Make ifs.c system-indendant. (ifs.h added)
30 * 01-Nov-2000: Allocation checks
31 * 10-May-1997: jwz@jwz.org: turned into a standalone program.
32 * Made it render into an offscreen bitmap and then copy
33 * that onto the screen, to reduce flicker.
34 */
35
36//#ifdef STANDALONE
37
38#include <array>
39#include <cmath>
40#include <cstdio>
41#include <cstdlib>
42
43#include "ifs.h"
44#include "goom_core.h"
45#include "goom_tools.h"
46
48
49/*****************************************************/
50
51using DBL = double;
52using F_PT = float;
53
54/*****************************************************/
55
56static constexpr uint8_t FIX { 12 };
57static constexpr uint16_t UNIT { 1<<FIX };
58static constexpr size_t MAX_SIMI { 6 };
59
60static constexpr int8_t MAX_DEPTH_2 { 10 };
61static constexpr int8_t MAX_DEPTH_3 { 6 };
62static constexpr int8_t MAX_DEPTH_4 { 4 };
63static constexpr int8_t MAX_DEPTH_5 { 2 };
64
65static inline F_PT DBL_To_F_PT(DBL x)
66{ return static_cast<F_PT>( static_cast<DBL>(UNIT) * x ); };
67
68using SIMI = struct Similitude_Struct;
69using FRACTAL = struct Fractal_Struct;
70
72{
73
79};
80
81using SimiData = std::array<SIMI,5 * MAX_SIMI>;
82
84{
85
86 size_t m_nbSimi { 0 };
88 int m_depth { 0 };
89 int m_col { 0 };
90 int m_count { 0 };
91 int m_speed { 6 };
92 int m_width { 0 };
93 int m_height { 0 };
94 int m_lx { 0 };
95 int m_ly { 0 };
96 DBL m_rMean { 0.0 };
97 DBL m_drMean { 0.0 };
98 DBL m_dr2Mean { 0.0 };
99 int m_curPt { 0 };
100 int m_maxPt { 0 };
101
102 std::vector<IFSPoint> m_buffer1;
103 std::vector<IFSPoint> m_buffer2;
104// Pixmap dbuf;
105// GC dbuf_gc;
106};
107
108static FRACTAL *Root = nullptr;
110
111/* Used by the Trace recursive method */
113static int Cur_Pt;
114
115/*****************************************************/
116static constexpr double MAXRAND { 2147483648.0 }; /* unsigned 1<<31 as a * * * * float */
117
118static DBL
120{
121 DBL y = static_cast<double>(MythRandom(0, (1U << 31) - 1)) / MAXRAND;
122 y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
123 if (rand_bool())
124 return (c + y);
125 return (c - y);
126}
127
128static DBL
130{
131 DBL y = static_cast<double>(MythRandom(0, (1U << 31) - 1)) / MAXRAND;
132 y = A * (1.0 - exp (-y * y * S)) / (1.0 - exp (-S));
133 return (c + y);
134}
135
136static void
137Random_Simis (FRACTAL * F, SimiData &simi_set, int offset, int count)
138{
139 SIMI * Cur = &simi_set[offset];
140 while (count--) {
141 Cur->m_dCx = Gauss_Rand (0.0, .8, 4.0);
142 Cur->m_dCy = Gauss_Rand (0.0, .8, 4.0);
143 Cur->m_dR = Gauss_Rand (F->m_rMean, F->m_drMean, 3.0);
144 Cur->m_dR2 = Half_Gauss_Rand (0.0, F->m_dr2Mean, 2.0);
145 Cur->m_dA = Gauss_Rand (0.0, 360.0, 4.0) * (M_PI / 180.0);
146 Cur->m_dA2 = Gauss_Rand (0.0, 360.0, 4.0) * (M_PI / 180.0);
147 Cur++;
148 }
149}
150
151static void
153{
154 Fractal->m_buffer1.clear();
155 Fractal->m_buffer2.clear();
156}
157
158
159/***************************************************************/
160
161void
162init_ifs (int width, int height)
163{
164// printf ("initing ifs\n");
165
166 if (Root == nullptr) {
167 Root = new FRACTAL;
168 }
169 FRACTAL *Fractal = Root;
170
171// fprintf (stderr,"--ifs freeing ex-buffers\n");
172 free_ifs_buffers (Fractal);
173// fprintf (stderr,"--ifs ok\n");
174
175 int i = MythRandomInt(2, 5); /* Number of centers */
176 switch (i) {
177 case 3:
178 Fractal->m_depth = MAX_DEPTH_3;
179 Fractal->m_rMean = .6;
180 Fractal->m_drMean = .4;
181 Fractal->m_dr2Mean = .3;
182 break;
183
184 case 4:
185 Fractal->m_depth = MAX_DEPTH_4;
186 Fractal->m_rMean = .5;
187 Fractal->m_drMean = .4;
188 Fractal->m_dr2Mean = .3;
189 break;
190
191 case 5:
192 Fractal->m_depth = MAX_DEPTH_5;
193 Fractal->m_rMean = .5;
194 Fractal->m_drMean = .4;
195 Fractal->m_dr2Mean = .3;
196 break;
197
198 default:
199 case 2:
200 Fractal->m_depth = MAX_DEPTH_2;
201 Fractal->m_rMean = .7;
202 Fractal->m_drMean = .3;
203 Fractal->m_dr2Mean = .4;
204 break;
205 }
206// fprintf( stderr, "N=%d\n", i );
207 Fractal->m_nbSimi = i;
208 Fractal->m_maxPt = Fractal->m_nbSimi - 1;
209 for (i = 0; i <= Fractal->m_depth + 2; ++i)
210 Fractal->m_maxPt *= Fractal->m_nbSimi;
211
212 Fractal->m_buffer1.resize(Fractal->m_maxPt);
213 Fractal->m_buffer2.resize(Fractal->m_maxPt);
214
215// printf ("--ifs setting params\n");
216 Fractal->m_speed = 6;
217 Fractal->m_width = width; /* modif by JeKo */
218 Fractal->m_height = height; /* modif by JeKo */
219 Fractal->m_curPt = 0;
220 Fractal->m_count = 0;
221 Fractal->m_lx = (Fractal->m_width - 1) / 2;
222 Fractal->m_ly = (Fractal->m_height - 1) / 2;
223 Fractal->m_col = MythRandomInt(0, (width * height) - 1); /* modif by JeKo */
224
225 Random_Simis (Fractal, Fractal->m_components, 0, 5 * MAX_SIMI);
226
227 /*
228 * #ifndef NO_DBUF
229 * if (Fractal->dbuf != None)
230 * XFreePixmap(display, Fractal->dbuf);
231 * Fractal->dbuf = XCreatePixmap(display, window,
232 * Fractal->m_width, Fractal->m_height, 1);
233 * * Allocation checked *
234 * if (Fractal->dbuf != None) {
235 * XGCValues gcv;
236 *
237 * gcv.foreground = 0;
238 * gcv.background = 0;
239 * gcv.graphics_exposures = False;
240 * gcv.function = GXcopy;
241 *
242 * if (Fractal->dbuf_gc != None)
243 * XFreeGC(display, Fractal->dbuf_gc);
244 * if ((Fractal->dbuf_gc = XCreateGC(display, Fractal->dbuf,
245 * GCForeground | GCBackground | GCGraphicsExposures | GCFunction,
246 * &gcv)) == None) {
247 * XFreePixmap(display, Fractal->dbuf);
248 * Fractal->dbuf = None;
249 * } else {
250 * XFillRectangle(display, Fractal->dbuf,
251 * Fractal->dbuf_gc, 0, 0, Fractal->m_width, Fractal->m_height);
252 * XSetBackground(display, gc, MI_BLACK_PIXEL(mi));
253 * XSetFunction(display, gc, GXcopy);
254 * }
255 * }
256 * #endif
257 */
258 // MI_CLEARWINDOW(mi);
259
260 /* don't want any exposure events from XCopyPlane */
261 // XSetGraphicsExposures(display, gc, False);
262
263}
264
265
266/***************************************************************/
267
268/* Should be taken care of already... but just in case */
269#if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
270#undef inline
271#define inline /* */
272#endif
273static inline void
274Transform (SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
275{
276 xo = xo - Simi->m_fCx;
277 xo = (xo * Simi->m_fR) / UNIT;
278 yo = yo - Simi->m_fCy;
279 yo = (yo * Simi->m_fR) / UNIT;
280
281 F_PT xx = xo - Simi->m_fCx;
282 xx = (xx * Simi->m_fR2) / UNIT;
283 F_PT yy = -yo - Simi->m_fCy;
284 yy = (yy * Simi->m_fR2) / UNIT;
285
286 *x =
287 ((xo * Simi->m_fCt - yo * Simi->m_fSt + xx * Simi->m_fCt2 - yy * Simi->m_fSt2) / UNIT ) + Simi->m_fCx;
288 *y =
289 ((xo * Simi->m_fSt + yo * Simi->m_fCt + xx * Simi->m_fSt2 + yy * Simi->m_fCt2) / UNIT ) + Simi->m_fCy;
290}
291
292/***************************************************************/
293
294static void
295Trace (FRACTAL * F, F_PT xo, F_PT yo)
296{
297 F_PT x = NAN;
298 F_PT y = NAN;
299
300 SIMI *Cur = (Cur_F->m_components).data();
301 for (int i = Cur_F->m_nbSimi; i != 0; --i, Cur++) {
302 Transform (Cur, xo, yo, &x, &y);
303
304 Buf->x = F->m_lx + ((x * F->m_lx) / (UNIT*2) );
305 Buf->y = F->m_ly - ((y * F->m_ly) / (UNIT*2) );
306 Buf++;
307
308 Cur_Pt++;
309
310 if (F->m_depth && (((x - xo) / 16) != 0.0F) && (((y - yo) / 16) != 0.0F)) {
311 F->m_depth--;
312 Trace (F, x, y);
313 F->m_depth++;
314 }
315 }
316}
317
318static void
319Draw_Fractal ( void /* ModeInfo * mi */ )
320{
321 FRACTAL *F = Root;
322 int i = 0;
323 SIMI *Cur = nullptr;
324 SIMI *Simi = nullptr;
325
326 for (Cur = (F->m_components).data(), i = F->m_nbSimi; i; --i, Cur++) {
327 Cur->m_fCx = DBL_To_F_PT (Cur->m_dCx);
328 Cur->m_fCy = DBL_To_F_PT (Cur->m_dCy);
329
330 Cur->m_fCt = DBL_To_F_PT (cos (Cur->m_dA));
331 Cur->m_fSt = DBL_To_F_PT (sin (Cur->m_dA));
332 Cur->m_fCt2 = DBL_To_F_PT (cos (Cur->m_dA2));
333 Cur->m_fSt2 = DBL_To_F_PT (sin (Cur->m_dA2));
334
335 Cur->m_fR = DBL_To_F_PT (Cur->m_dR);
336 Cur->m_fR2 = DBL_To_F_PT (Cur->m_dR2);
337 }
338
339
340 Cur_Pt = 0;
341 Cur_F = F;
342 Buf = F->m_buffer2.data();
343 for (Cur = (F->m_components).data(), i = F->m_nbSimi; i; --i, Cur++) {
344 F_PT xo = Cur->m_fCx;
345 F_PT yo = Cur->m_fCy;
346 int j = 0;
347 for (Simi = (F->m_components).data(), j = F->m_nbSimi; j; --j, Simi++) {
348 F_PT x = NAN;
349 F_PT y = NAN;
350 if (Simi == Cur)
351 continue;
352 Transform (Simi, xo, yo, &x, &y);
353 Trace (F, x, y);
354 }
355 }
356
357 /* Erase previous */
358
359/* if (F->m_curPt) {
360 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
361 if (F->dbuf != None) {
362 XSetForeground(display, F->dbuf_gc, 0);
363*/
364 /* XDrawPoints(display, F->dbuf, F->dbuf_gc, F->m_buffer1, F->m_curPt, * * * *
365 * CoordModeOrigin); */
366/* XFillRectangle(display, F->dbuf, F->dbuf_gc, 0, 0,
367 F->m_width, F->m_height);
368 } else
369 XDrawPoints(display, window, gc, F->m_buffer1, F->m_curPt, CoordModeOrigin);
370 }
371 if (MI_NPIXELS(mi) < 2)
372 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
373 else
374 XSetForeground(display, gc, MI_PIXEL(mi, F->Col % MI_NPIXELS(mi)));
375 if (Cur_Pt) {
376 if (F->dbuf != None) {
377 XSetForeground(display, F->dbuf_gc, 1);
378 XDrawPoints(display, F->dbuf, F->dbuf_gc, F->m_buffer2, Cur_Pt,
379 CoordModeOrigin);
380 } else
381 XDrawPoints(display, window, gc, F->m_buffer2, Cur_Pt, CoordModeOrigin);
382 }
383 if (F->dbuf != None)
384 XCopyPlane(display, F->dbuf, window, gc, 0, 0, F->m_width, F->m_height, 0, 0, 1);
385*/
386
387 F->m_curPt = Cur_Pt;
388 F->m_buffer1.swap(F->m_buffer2);
389}
390
391
392IFSPoint *
393draw_ifs ( /* ModeInfo * mi */ int *nbPoints)
394{
395 if (Root == nullptr)
396 return nullptr;
397 FRACTAL *F = Root; // [/*MI_SCREEN(mi)*/0];
398 if (F->m_buffer1.empty())
399 return nullptr;
400
401 DBL u = (DBL) (F->m_count) * (DBL) (F->m_speed) / 1000.0;
402 DBL uu = u * u;
403 DBL v = 1.0 - u;
404 DBL vv = v * v;
405 DBL u0 = vv * v;
406 DBL u1 = 3.0 * vv * u;
407 DBL u2 = 3.0 * v * uu;
408 DBL u3 = u * uu;
409
410 SIMI *S = (F->m_components).data();
411 SIMI *S1 = &F->m_components[1 * F->m_nbSimi];
412 SIMI *S2 = &F->m_components[2 * F->m_nbSimi];
413 SIMI *S3 = &F->m_components[3 * F->m_nbSimi];
414 SIMI *S4 = &F->m_components[4 * F->m_nbSimi];
415
416 for (int i = F->m_nbSimi; i; --i, S++, S1++, S2++, S3++, S4++) {
417 S->m_dCx = (u0 * S1->m_dCx) + (u1 * S2->m_dCx) + (u2 * S3->m_dCx) + (u3 * S4->m_dCx);
418 S->m_dCy = (u0 * S1->m_dCy) + (u1 * S2->m_dCy) + (u2 * S3->m_dCy) + (u3 * S4->m_dCy);
419 S->m_dR = (u0 * S1->m_dR) + (u1 * S2->m_dR) + (u2 * S3->m_dR) + (u3 * S4->m_dR);
420 S->m_dR2 = (u0 * S1->m_dR2) + (u1 * S2->m_dR2) + (u2 * S3->m_dR2) + (u3 * S4->m_dR2);
421 S->m_dA = (u0 * S1->m_dA) + (u1 * S2->m_dA) + (u2 * S3->m_dA) + (u3 * S4->m_dA);
422 S->m_dA2 = (u0 * S1->m_dA2) + (u1 * S2->m_dA2) + (u2 * S3->m_dA2) + (u3 * S4->m_dA2);
423 }
424
425 // MI_IS_DRAWN(mi) = True;
426
427 Draw_Fractal ( /* mi */ );
428
429 if (F->m_count >= 1000 / F->m_speed) {
430 S = (F->m_components).data();
431 S1 = &F->m_components[1 * F->m_nbSimi];
432 S2 = &F->m_components[2 * F->m_nbSimi];
433 S3 = &F->m_components[3 * F->m_nbSimi];
434 S4 = &F->m_components[4 * F->m_nbSimi];
435
436 for (int i = F->m_nbSimi; i; --i, S++, S1++, S2++, S3++, S4++) {
437 S2->m_dCx = (2.0 * S4->m_dCx) - S3->m_dCx;
438 S2->m_dCy = (2.0 * S4->m_dCy) - S3->m_dCy;
439 S2->m_dR = (2.0 * S4->m_dR) - S3->m_dR;
440 S2->m_dR2 = (2.0 * S4->m_dR2) - S3->m_dR2;
441 S2->m_dA = (2.0 * S4->m_dA) - S3->m_dA;
442 S2->m_dA2 = (2.0 * S4->m_dA2) - S3->m_dA2;
443
444 *S1 = *S4;
445 }
446 Random_Simis (F, F->m_components, 3 * F->m_nbSimi, F->m_nbSimi);
447
448 Random_Simis (F, F->m_components, 4 * F->m_nbSimi, F->m_nbSimi);
449
450 F->m_count = 0;
451 }
452 else
453 {
454 F->m_count++;
455 }
456
457 F->m_col++;
458
459 /* #1 code added by JeKo */
460 (*nbPoints) = Cur_Pt;
461 return F->m_buffer2.data();
462 /* #1 end */
463}
464
465
466/***************************************************************/
467
468void
470{
471 delete Root;
472 Root = nullptr;
473}
static constexpr double M_PI
Definition: goom_tools.h:9
float F_PT
Definition: ifs.cpp:52
static void Draw_Fractal(void)
Definition: ifs.cpp:319
std::array< SIMI, 5 *MAX_SIMI > SimiData
Definition: ifs.cpp:81
void init_ifs(int width, int height)
Definition: ifs.cpp:162
Fractal_Struct FRACTAL
Definition: ifs.cpp:69
static constexpr uint16_t UNIT
Definition: ifs.cpp:57
static int Cur_Pt
Definition: ifs.cpp:113
static constexpr uint8_t FIX
Definition: ifs.cpp:56
void release_ifs()
Definition: ifs.cpp:469
static constexpr int8_t MAX_DEPTH_4
Definition: ifs.cpp:62
static constexpr int8_t MAX_DEPTH_2
Definition: ifs.cpp:60
static constexpr double MAXRAND
Definition: ifs.cpp:116
double DBL
Definition: ifs.cpp:51
static constexpr int8_t MAX_DEPTH_3
Definition: ifs.cpp:61
static DBL Half_Gauss_Rand(DBL c, DBL A, DBL S)
Definition: ifs.cpp:129
IFSPoint * Buf
Definition: ifs.cpp:112
static F_PT DBL_To_F_PT(DBL x)
Definition: ifs.cpp:65
static DBL Gauss_Rand(DBL c, DBL A, DBL S)
Definition: ifs.cpp:119
static constexpr int8_t MAX_DEPTH_5
Definition: ifs.cpp:63
static void Transform(SIMI *Simi, F_PT xo, F_PT yo, F_PT *x, F_PT *y)
Definition: ifs.cpp:274
static void free_ifs_buffers(FRACTAL *Fractal)
Definition: ifs.cpp:152
static void Random_Simis(FRACTAL *F, SimiData &simi_set, int offset, int count)
Definition: ifs.cpp:137
static FRACTAL * Root
Definition: ifs.cpp:108
static FRACTAL * Cur_F
Definition: ifs.cpp:109
IFSPoint * draw_ifs(int *nbPoints)
Definition: ifs.cpp:393
static void Trace(FRACTAL *F, F_PT xo, F_PT yo)
Definition: ifs.cpp:295
static constexpr size_t MAX_SIMI
Definition: ifs.cpp:58
unsigned short uint16_t
Definition: iso6937tables.h:3
Convenience inline random number generator functions.
int MythRandomInt(int min, int max)
generate a uniformly distributed random signed int in the closed interval [min, max].
Definition: mythrandom.h:58
uint32_t MythRandom()
generate 32 random bits
Definition: mythrandom.h:20
bool rand_bool(uint32_t chance=2)
return a random bool with P(true) = 1/chance
Definition: mythrandom.h:86
int m_depth
Definition: ifs.cpp:88
int m_maxPt
Definition: ifs.cpp:100
int m_speed
Definition: ifs.cpp:91
DBL m_rMean
Definition: ifs.cpp:96
std::vector< IFSPoint > m_buffer2
Definition: ifs.cpp:103
std::vector< IFSPoint > m_buffer1
Definition: ifs.cpp:102
size_t m_nbSimi
Definition: ifs.cpp:86
int m_col
Definition: ifs.cpp:89
int m_curPt
Definition: ifs.cpp:99
int m_width
Definition: ifs.cpp:92
int m_height
Definition: ifs.cpp:93
DBL m_dr2Mean
Definition: ifs.cpp:98
SimiData m_components
Definition: ifs.cpp:87
int m_lx
Definition: ifs.cpp:94
DBL m_drMean
Definition: ifs.cpp:97
int m_count
Definition: ifs.cpp:90
int m_ly
Definition: ifs.cpp:95
Definition: ifs.h:11
int32_t x
Definition: ifs.h:12
int32_t y
Definition: ifs.h:12