xref: /haiku/src/add-ons/screen_savers/ifs/IFS.cpp (revision e443b44ab8fe2bcd95af5b63257efa4f7ded80a0)
1bc679b60SStephan Aßmus /*
2bc679b60SStephan Aßmus  * Copyright 2006, Haiku.
3bc679b60SStephan Aßmus  * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
4bc679b60SStephan Aßmus  *
5bc679b60SStephan Aßmus  * Distributed under the terms of the MIT License.
6bc679b60SStephan Aßmus  *
7bc679b60SStephan Aßmus  * Authors:
8bc679b60SStephan Aßmus  *		Massimino Pascal <Pascal.Massimon@ens.fr>
9bc679b60SStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
10bc679b60SStephan Aßmus  */
11bc679b60SStephan Aßmus 
12bc679b60SStephan Aßmus /*! When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
13bc679b60SStephan Aßmus  */
14bc679b60SStephan Aßmus 
15bc679b60SStephan Aßmus #include "IFS.h"
16bc679b60SStephan Aßmus 
17bc679b60SStephan Aßmus #include <new>
18bc679b60SStephan Aßmus #include <malloc.h>
19bc679b60SStephan Aßmus #include <stdio.h>
20bc679b60SStephan Aßmus #include <string.h>
21bc679b60SStephan Aßmus 
22bc679b60SStephan Aßmus #include <Bitmap.h>
23bc679b60SStephan Aßmus #include <OS.h>
24bc679b60SStephan Aßmus #include <Screen.h>
25bc679b60SStephan Aßmus #include <View.h>
26bc679b60SStephan Aßmus 
27bc679b60SStephan Aßmus #include <unistd.h>  // for getpid()
28bc679b60SStephan Aßmus #include <sys/time.h> // for gettimeofday()
29bc679b60SStephan Aßmus 
30bc679b60SStephan Aßmus using std::nothrow;
31bc679b60SStephan Aßmus 
32bc679b60SStephan Aßmus #define HALF 0
33bc679b60SStephan Aßmus 
34bc679b60SStephan Aßmus // The following 'random' numbers are taken from CRC, 18th Edition, page 622.
35bc679b60SStephan Aßmus // Each array element was taken from the corresponding line in the table,
36bc679b60SStephan Aßmus // except that a[0] was from line 100. 8s and 9s in the table were simply
37bc679b60SStephan Aßmus // skipped. The high order digit was taken mod 4.
38bc679b60SStephan Aßmus 
39bc679b60SStephan Aßmus #define VectorSize 55
40bc679b60SStephan Aßmus static unsigned int a[VectorSize] = {
41bc679b60SStephan Aßmus  035340171546, 010401501101, 022364657325, 024130436022, 002167303062, //  5
42bc679b60SStephan Aßmus  037570375137, 037210607110, 016272055420, 023011770546, 017143426366, // 10
43bc679b60SStephan Aßmus  014753657433, 021657231332, 023553406142, 004236526362, 010365611275, // 14
44bc679b60SStephan Aßmus  007117336710, 011051276551, 002362132524, 001011540233, 012162531646, // 20
45bc679b60SStephan Aßmus  007056762337, 006631245521, 014164542224, 032633236305, 023342700176, // 25
46bc679b60SStephan Aßmus  002433062234, 015257225043, 026762051606, 000742573230, 005366042132, // 30
47bc679b60SStephan Aßmus  012126416411, 000520471171, 000725646277, 020116577576, 025765742604, // 35
48bc679b60SStephan Aßmus  007633473735, 015674255275, 017555634041, 006503154145, 021576344247, // 40
49bc679b60SStephan Aßmus  014577627653, 002707523333, 034146376720, 030060227734, 013765414060, // 45
50bc679b60SStephan Aßmus  036072251540, 007255221037, 024364674123, 006200353166, 010126373326, // 50
51bc679b60SStephan Aßmus  015664104320, 016401041535, 016215305520, 033115351014, 017411670323  // 55
52bc679b60SStephan Aßmus };
53bc679b60SStephan Aßmus 
54bc679b60SStephan Aßmus static int i1, i2;
55bc679b60SStephan Aßmus 
56bc679b60SStephan Aßmus // ya_random
57bc679b60SStephan Aßmus unsigned int
58bc679b60SStephan Aßmus ya_random (void)
59bc679b60SStephan Aßmus {
60bc679b60SStephan Aßmus   register int ret = a[i1] + a[i2];
61bc679b60SStephan Aßmus   a[i1] = ret;
62bc679b60SStephan Aßmus   if (++i1 >= VectorSize) i1 = 0;
63bc679b60SStephan Aßmus   if (++i2 >= VectorSize) i2 = 0;
64bc679b60SStephan Aßmus   return ret;
65bc679b60SStephan Aßmus }
66bc679b60SStephan Aßmus 
67bc679b60SStephan Aßmus // ya_rand_init
68bc679b60SStephan Aßmus void
69bc679b60SStephan Aßmus ya_rand_init(unsigned int seed)
70bc679b60SStephan Aßmus {
71bc679b60SStephan Aßmus   int i;
72bc679b60SStephan Aßmus   if (seed == 0)
73bc679b60SStephan Aßmus     {
74bc679b60SStephan Aßmus       struct timeval tp;
75bc679b60SStephan Aßmus       struct timezone tzp;
76bc679b60SStephan Aßmus       gettimeofday(&tp, &tzp);
77bc679b60SStephan Aßmus       /* ignore overflow */
78bc679b60SStephan Aßmus       seed = (999*tp.tv_sec) + (1001*tp.tv_usec) + (1003 * getpid());
79bc679b60SStephan Aßmus     }
80bc679b60SStephan Aßmus 
81bc679b60SStephan Aßmus   a[0] += seed;
82bc679b60SStephan Aßmus   for (i = 1; i < VectorSize; i++)
83bc679b60SStephan Aßmus     {
84bc679b60SStephan Aßmus       seed = a[i-1]*1001 + seed*999;
85bc679b60SStephan Aßmus       a[i] += seed;
86bc679b60SStephan Aßmus     }
87bc679b60SStephan Aßmus 
88bc679b60SStephan Aßmus   i1 = a[0] % VectorSize;
89bc679b60SStephan Aßmus   i2 = (i1 + 024) % VectorSize;
90bc679b60SStephan Aßmus }
91bc679b60SStephan Aßmus 
92bc679b60SStephan Aßmus #define random()   ya_random()
93bc679b60SStephan Aßmus #define RAND_MAX   0xFFFFFFFF
94bc679b60SStephan Aßmus 
95bc679b60SStephan Aßmus #define FLOAT_TO_INT(x)  (int32)( (float)(UNIT)*(x) )
96bc679b60SStephan Aßmus 
97bc679b60SStephan Aßmus #define LRAND()			((long) (random() & 0x7fffffff))
98bc679b60SStephan Aßmus #define NRAND(n)		((int) (LRAND() % (n)))
99bc679b60SStephan Aßmus #define MAXRAND			(2147483648.0) // unsigned 1<<31 as a float
100bc679b60SStephan Aßmus #define SRAND(n)		// already seeded by screenhack.c TODO: ?!? is it?
101bc679b60SStephan Aßmus 
102bc679b60SStephan Aßmus 
103bc679b60SStephan Aßmus // gauss_rand
104bc679b60SStephan Aßmus static float
105bc679b60SStephan Aßmus gauss_rand(float c, float A, float S)
106bc679b60SStephan Aßmus {
107bc679b60SStephan Aßmus 	float         y;
108bc679b60SStephan Aßmus 
109bc679b60SStephan Aßmus 	y = (float) LRAND() / MAXRAND;
110bc679b60SStephan Aßmus 	y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
111bc679b60SStephan Aßmus 	if (NRAND(2))
112bc679b60SStephan Aßmus 		return (c + y);
113bc679b60SStephan Aßmus 	return (c - y);
114bc679b60SStephan Aßmus }
115bc679b60SStephan Aßmus 
116bc679b60SStephan Aßmus // half_gauss_rand
117bc679b60SStephan Aßmus static float
118bc679b60SStephan Aßmus half_gauss_rand(float c, float A, float S)
119bc679b60SStephan Aßmus {
120bc679b60SStephan Aßmus 	float         y;
121bc679b60SStephan Aßmus 
122bc679b60SStephan Aßmus 	y = (float) LRAND() / MAXRAND;
123bc679b60SStephan Aßmus 	y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
124bc679b60SStephan Aßmus 	return (c + y);
125bc679b60SStephan Aßmus }
126bc679b60SStephan Aßmus 
127bc679b60SStephan Aßmus // transform
128bc679b60SStephan Aßmus inline void
129bc679b60SStephan Aßmus transform(SIMI* Simi, int32 xo, int32 yo, int32* x, int32* y)
130bc679b60SStephan Aßmus {
131bc679b60SStephan Aßmus 	int32        xx, yy;
132bc679b60SStephan Aßmus 
133bc679b60SStephan Aßmus 	xo = xo - Simi->Cx;
134bc679b60SStephan Aßmus 	xo = (xo * Simi->R) / UNIT;
135bc679b60SStephan Aßmus 	yo = yo - Simi->Cy;
136bc679b60SStephan Aßmus 	yo = (yo * Simi->R) / UNIT;
137bc679b60SStephan Aßmus 
138bc679b60SStephan Aßmus 	xx = xo - Simi->Cx;
139bc679b60SStephan Aßmus 	xx = (xx * Simi->R2) / UNIT;
140bc679b60SStephan Aßmus 	yy = -yo - Simi->Cy;
141bc679b60SStephan Aßmus 	yy = (yy * Simi->R2) / UNIT;
142bc679b60SStephan Aßmus 
143bc679b60SStephan Aßmus 	*x = ((xo * Simi->Ct - yo * Simi->St + xx * Simi->Ct2 - yy * Simi->St2) / UNIT) + Simi->Cx;
144bc679b60SStephan Aßmus 	*y = ((xo * Simi->St + yo * Simi->Ct + xx * Simi->St2 + yy * Simi->Ct2) / UNIT) + Simi->Cy;
145bc679b60SStephan Aßmus }
146bc679b60SStephan Aßmus 
147bc679b60SStephan Aßmus 
148bc679b60SStephan Aßmus // constructor
149bc679b60SStephan Aßmus IFS::IFS(BRect bounds)
1507bcfb215SJohn Scipione 	:
1517bcfb215SJohn Scipione 	fRoot(NULL),
1527bcfb215SJohn Scipione 	fCurrentFractal(NULL),
1537bcfb215SJohn Scipione 	fPointBuffer(NULL),
1547bcfb215SJohn Scipione 	fCurrentPoint(0),
155bc679b60SStephan Aßmus 	fAdditive(false),
156bc679b60SStephan Aßmus 	fCurrentMarkValue(1)
157bc679b60SStephan Aßmus {
158*e443b44aSStephan Aßmus 	if (!bounds.IsValid())
159*e443b44aSStephan Aßmus 		return;
160*e443b44aSStephan Aßmus 
161bc679b60SStephan Aßmus 	ya_rand_init(system_time());
162bc679b60SStephan Aßmus 
163bc679b60SStephan Aßmus 	int         i;
164bc679b60SStephan Aßmus 	FRACTAL    *Fractal;
165bc679b60SStephan Aßmus 
166bc679b60SStephan Aßmus 	if (fRoot == NULL) {
167bc679b60SStephan Aßmus 		fRoot = (FRACTAL*) calloc(1, sizeof (FRACTAL));
168bc679b60SStephan Aßmus 		if (fRoot == NULL)
169bc679b60SStephan Aßmus 			return;
170bc679b60SStephan Aßmus 	}
171bc679b60SStephan Aßmus 	Fractal = fRoot;
172bc679b60SStephan Aßmus 
173bc679b60SStephan Aßmus 	_FreeBuffers(Fractal);
174bc679b60SStephan Aßmus 	i = (NRAND(4)) + 2;	// Number of centers
175bc679b60SStephan Aßmus 	switch (i) {
176bc679b60SStephan Aßmus 		case 3:
177bc679b60SStephan Aßmus 			Fractal->Depth = fAdditive ? MAX_DEPTH_3 + 1 : MAX_DEPTH_3;
178bc679b60SStephan Aßmus 			Fractal->r_mean = .6;
179bc679b60SStephan Aßmus 			Fractal->dr_mean = .4;
180bc679b60SStephan Aßmus 			Fractal->dr2_mean = .3;
181bc679b60SStephan Aßmus 			break;
182bc679b60SStephan Aßmus 
183bc679b60SStephan Aßmus 		case 4:
184bc679b60SStephan Aßmus 			Fractal->Depth = MAX_DEPTH_4;
185bc679b60SStephan Aßmus 			Fractal->r_mean = .5;
186bc679b60SStephan Aßmus 			Fractal->dr_mean = .4;
187bc679b60SStephan Aßmus 			Fractal->dr2_mean = .3;
188bc679b60SStephan Aßmus 			break;
189bc679b60SStephan Aßmus 
190bc679b60SStephan Aßmus 		case 5:
191bc679b60SStephan Aßmus 			Fractal->Depth = MAX_DEPTH_5;
192bc679b60SStephan Aßmus 			Fractal->r_mean = .5;
193bc679b60SStephan Aßmus 			Fractal->dr_mean = .4;
194bc679b60SStephan Aßmus 			Fractal->dr2_mean = .3;
195bc679b60SStephan Aßmus 			break;
196bc679b60SStephan Aßmus 
197bc679b60SStephan Aßmus 		case 2:
19852a95e6fSJohn Scipione 		default:
199bc679b60SStephan Aßmus 			Fractal->Depth = fAdditive ? MAX_DEPTH_2 + 1 : MAX_DEPTH_2;
200bc679b60SStephan Aßmus 			Fractal->r_mean = .7;
201bc679b60SStephan Aßmus 			Fractal->dr_mean = .3;
202bc679b60SStephan Aßmus 			Fractal->dr2_mean = .4;
203bc679b60SStephan Aßmus 			break;
204bc679b60SStephan Aßmus 	}
205bc679b60SStephan Aßmus 	// fprintf( stderr, "N=%d\n", i );
206bc679b60SStephan Aßmus 	Fractal->Nb_Simi = i;
207bc679b60SStephan Aßmus 	Fractal->Max_Pt = Fractal->Nb_Simi - 1;
208bc679b60SStephan Aßmus 	for (i = 0; i <= Fractal->Depth + 2; ++i)
209bc679b60SStephan Aßmus 		Fractal->Max_Pt *= Fractal->Nb_Simi;
210bc679b60SStephan Aßmus 
211bc679b60SStephan Aßmus 	if ((Fractal->buffer1 = (Point *) calloc(Fractal->Max_Pt,
212bc679b60SStephan Aßmus 			sizeof (Point))) == NULL) {
213bc679b60SStephan Aßmus 		_FreeIFS(Fractal);
214bc679b60SStephan Aßmus 		return;
215bc679b60SStephan Aßmus 	}
216bc679b60SStephan Aßmus 	if ((Fractal->buffer2 = (Point *) calloc(Fractal->Max_Pt,
217bc679b60SStephan Aßmus 			sizeof (Point))) == NULL) {
218bc679b60SStephan Aßmus 		_FreeIFS(Fractal);
219bc679b60SStephan Aßmus 		return;
220bc679b60SStephan Aßmus 	}
221bc679b60SStephan Aßmus 	Fractal->Speed = 6;
222bc679b60SStephan Aßmus #if HALF
223bc679b60SStephan Aßmus 	Fractal->Width = bounds.IntegerWidth() / 2 + 1;
224bc679b60SStephan Aßmus 	Fractal->Height = bounds.IntegerHeight() / 2 + 1;
225bc679b60SStephan Aßmus #else
226bc679b60SStephan Aßmus 	Fractal->Width = bounds.IntegerWidth() + 1;
227bc679b60SStephan Aßmus 	Fractal->Height = bounds.IntegerHeight() + 1;
228bc679b60SStephan Aßmus #endif
229bc679b60SStephan Aßmus 	Fractal->Cur_Pt = 0;
230bc679b60SStephan Aßmus 	Fractal->Count = 0;
231bc679b60SStephan Aßmus 	Fractal->Lx = (Fractal->Width - 1) / 2;
232bc679b60SStephan Aßmus 	Fractal->Ly = (Fractal->Height - 1) / 2;
233bc679b60SStephan Aßmus 	Fractal->Col = NRAND(Fractal->Width * Fractal->Height - 1) + 1;
234bc679b60SStephan Aßmus 
235bc679b60SStephan Aßmus 	_RandomSimis(Fractal, Fractal->Components, 5 * MAX_SIMI);
236bc679b60SStephan Aßmus 
237bc679b60SStephan Aßmus 	delete Fractal->bitmap;
238bc679b60SStephan Aßmus 	Fractal->bitmap = new (nothrow) BBitmap(BRect(0.0, 0.0,
239bc679b60SStephan Aßmus 											Fractal->Width - 1,
240bc679b60SStephan Aßmus 											Fractal->Height - 1),
241bc679b60SStephan Aßmus 											0,
242bc679b60SStephan Aßmus 											B_RGB32);
243bc679b60SStephan Aßmus 	delete Fractal->markBitmap;
244bc679b60SStephan Aßmus 	Fractal->markBitmap = new (nothrow) BBitmap(BRect(0.0, 0.0,
245bc679b60SStephan Aßmus 												Fractal->Width - 1,
246bc679b60SStephan Aßmus 												Fractal->Height - 1),
247bc679b60SStephan Aßmus 												0,
248bc679b60SStephan Aßmus 												B_GRAY8);
249bc679b60SStephan Aßmus 	// Allocation checked
250bc679b60SStephan Aßmus 	if (Fractal->bitmap != NULL && Fractal->bitmap->IsValid()) {
251bc679b60SStephan Aßmus 		memset(Fractal->bitmap->Bits(), 0, Fractal->bitmap->BitsLength());
252bc679b60SStephan Aßmus 	} else {
253bc679b60SStephan Aßmus 		delete Fractal->bitmap;
254bc679b60SStephan Aßmus 		Fractal->bitmap = NULL;
255bc679b60SStephan Aßmus 	}
256bc679b60SStephan Aßmus 	if (Fractal->markBitmap != NULL && Fractal->markBitmap->IsValid()) {
257bc679b60SStephan Aßmus 		memset(Fractal->markBitmap->Bits(), 0, Fractal->markBitmap->BitsLength());
258bc679b60SStephan Aßmus 	} else {
259bc679b60SStephan Aßmus 		delete Fractal->markBitmap;
260bc679b60SStephan Aßmus 		Fractal->markBitmap = NULL;
261bc679b60SStephan Aßmus 	}
262bc679b60SStephan Aßmus }
263bc679b60SStephan Aßmus 
264bc679b60SStephan Aßmus // destructor
265bc679b60SStephan Aßmus IFS::~IFS()
266bc679b60SStephan Aßmus {
267bc679b60SStephan Aßmus 	if (fRoot != NULL) {
268bc679b60SStephan Aßmus 		_FreeIFS(fRoot);
269bc679b60SStephan Aßmus 		free((void*) fRoot);
270bc679b60SStephan Aßmus 	}
271bc679b60SStephan Aßmus }
272bc679b60SStephan Aßmus 
273bc679b60SStephan Aßmus // Draw
274bc679b60SStephan Aßmus void
275bc679b60SStephan Aßmus IFS::Draw(BView* view, const buffer_info* info, int32 frames)
276bc679b60SStephan Aßmus {
277bc679b60SStephan Aßmus //bigtime_t now = system_time();
278bc679b60SStephan Aßmus 	int         i;
279bc679b60SStephan Aßmus 	float         u, uu, v, vv, u0, u1, u2, u3;
280bc679b60SStephan Aßmus 	SIMI       *S, *S1, *S2, *S3, *S4;
281bc679b60SStephan Aßmus 	FRACTAL    *F;
282bc679b60SStephan Aßmus 
283bc679b60SStephan Aßmus 	if (fRoot == NULL)
284bc679b60SStephan Aßmus 		return;
285bc679b60SStephan Aßmus 	F = fRoot;
286bc679b60SStephan Aßmus 	if (F->buffer1 == NULL)
287bc679b60SStephan Aßmus 		return;
288bc679b60SStephan Aßmus 
289bc679b60SStephan Aßmus //if (frames > 1)
290bc679b60SStephan Aßmus //	printf("skipping %ld frames\n", frames);
291bc679b60SStephan Aßmus 
292bc679b60SStephan Aßmus 	// do this as many times as necessary to calculate the missing frames
293bc679b60SStephan Aßmus 	// so the animation doesn't jerk when we miss a few frames
294bc679b60SStephan Aßmus 	for (int32 frame = 0; frame < frames; frame++) {
295bc679b60SStephan Aßmus 
296bc679b60SStephan Aßmus 		u = (float) (F->Count) * (float) (F->Speed) / 1000.0;
297bc679b60SStephan Aßmus 		uu = u * u;
298bc679b60SStephan Aßmus 		v = 1.0 - u;
299bc679b60SStephan Aßmus 		vv = v * v;
300bc679b60SStephan Aßmus 		u0 = vv * v;
301bc679b60SStephan Aßmus 		u1 = 3.0 * vv * u;
302bc679b60SStephan Aßmus 		u2 = 3.0 * v * uu;
303bc679b60SStephan Aßmus 		u3 = u * uu;
304bc679b60SStephan Aßmus 
305bc679b60SStephan Aßmus 		S = F->Components;
306bc679b60SStephan Aßmus 		S1 = S + F->Nb_Simi;
307bc679b60SStephan Aßmus 		S2 = S1 + F->Nb_Simi;
308bc679b60SStephan Aßmus 		S3 = S2 + F->Nb_Simi;
309bc679b60SStephan Aßmus 		S4 = S3 + F->Nb_Simi;
310bc679b60SStephan Aßmus 
311bc679b60SStephan Aßmus 		for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
312bc679b60SStephan Aßmus 			S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x;
313bc679b60SStephan Aßmus 			S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y;
314bc679b60SStephan Aßmus 			S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r;
315bc679b60SStephan Aßmus 			S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2;
316bc679b60SStephan Aßmus 			S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A;
317bc679b60SStephan Aßmus 			S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2;
318bc679b60SStephan Aßmus 		}
319bc679b60SStephan Aßmus 
320bc679b60SStephan Aßmus //bigtime_t beforeDraw = system_time();
321bc679b60SStephan Aßmus 		if (frame == frames - 1)
322bc679b60SStephan Aßmus 			_DrawFractal(view, info);
323bc679b60SStephan Aßmus 
324bc679b60SStephan Aßmus //bigtime_t draw = system_time() - beforeDraw;
325bc679b60SStephan Aßmus 
326bc679b60SStephan Aßmus 		if (F->Count >= 1000 / F->Speed) {
327bc679b60SStephan Aßmus 			S = F->Components;
328bc679b60SStephan Aßmus 			S1 = S + F->Nb_Simi;
329bc679b60SStephan Aßmus 			S2 = S1 + F->Nb_Simi;
330bc679b60SStephan Aßmus 			S3 = S2 + F->Nb_Simi;
331bc679b60SStephan Aßmus 			S4 = S3 + F->Nb_Simi;
332bc679b60SStephan Aßmus 
333bc679b60SStephan Aßmus 			for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
334bc679b60SStephan Aßmus 				S2->c_x = 2.0 * S4->c_x - S3->c_x;
335bc679b60SStephan Aßmus 				S2->c_y = 2.0 * S4->c_y - S3->c_y;
336bc679b60SStephan Aßmus 				S2->r = 2.0 * S4->r - S3->r;
337bc679b60SStephan Aßmus 				S2->r2 = 2.0 * S4->r2 - S3->r2;
338bc679b60SStephan Aßmus 				S2->A = 2.0 * S4->A - S3->A;
339bc679b60SStephan Aßmus 				S2->A2 = 2.0 * S4->A2 - S3->A2;
340bc679b60SStephan Aßmus 
341bc679b60SStephan Aßmus 				*S1 = *S4;
342bc679b60SStephan Aßmus 			}
343bc679b60SStephan Aßmus 			_RandomSimis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
344bc679b60SStephan Aßmus 
345bc679b60SStephan Aßmus 			_RandomSimis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
346bc679b60SStephan Aßmus 
347bc679b60SStephan Aßmus 			F->Count = 0;
348bc679b60SStephan Aßmus 		} else
349bc679b60SStephan Aßmus 			F->Count++;
350bc679b60SStephan Aßmus //		F->Col++;
351bc679b60SStephan Aßmus //bigtime_t finish = (system_time() - now) - draw;
352bc679b60SStephan Aßmus //if (info)
353bc679b60SStephan Aßmus //printf("draw: %lld\nnon-draw: %lld\n\n", draw, finish);
354bc679b60SStephan Aßmus 	}
355bc679b60SStephan Aßmus 
356bc679b60SStephan Aßmus }
357bc679b60SStephan Aßmus 
358bc679b60SStephan Aßmus // SetAdditive
359bc679b60SStephan Aßmus void
360bc679b60SStephan Aßmus IFS::SetAdditive(bool additive)
361bc679b60SStephan Aßmus {
362bc679b60SStephan Aßmus 	fAdditive = additive;
363bc679b60SStephan Aßmus }
364bc679b60SStephan Aßmus 
365bc679b60SStephan Aßmus // SetSpeed
366bc679b60SStephan Aßmus void
367bc679b60SStephan Aßmus IFS::SetSpeed(int32 speed)
368bc679b60SStephan Aßmus {
369bc679b60SStephan Aßmus 	if (fRoot && speed > 0 && speed <= 12)
370bc679b60SStephan Aßmus 		fRoot->Speed = speed;
371bc679b60SStephan Aßmus }
372bc679b60SStephan Aßmus 
373bc679b60SStephan Aßmus // Draw
374bc679b60SStephan Aßmus void
375bc679b60SStephan Aßmus IFS::_DrawFractal(BView* view, const buffer_info* info)
376bc679b60SStephan Aßmus {
377bc679b60SStephan Aßmus 	FRACTAL* F = fRoot;
378bc679b60SStephan Aßmus 	int i, j;
379bc679b60SStephan Aßmus 	int32 x, y, xo, yo;
380bc679b60SStephan Aßmus 	SIMI* Cur, *Simi;
381bc679b60SStephan Aßmus 
382bc679b60SStephan Aßmus 	for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
383bc679b60SStephan Aßmus 		Cur->Cx = FLOAT_TO_INT(Cur->c_x);
384bc679b60SStephan Aßmus 		Cur->Cy = FLOAT_TO_INT(Cur->c_y);
385bc679b60SStephan Aßmus 
386bc679b60SStephan Aßmus 		Cur->Ct = FLOAT_TO_INT(cos(Cur->A));
387bc679b60SStephan Aßmus 		Cur->St = FLOAT_TO_INT(sin(Cur->A));
388bc679b60SStephan Aßmus 		Cur->Ct2 = FLOAT_TO_INT(cos(Cur->A2));
389bc679b60SStephan Aßmus 		Cur->St2 = FLOAT_TO_INT(sin(Cur->A2));
390bc679b60SStephan Aßmus 
391bc679b60SStephan Aßmus 		Cur->R = FLOAT_TO_INT(Cur->r);
392bc679b60SStephan Aßmus 		Cur->R2 = FLOAT_TO_INT(Cur->r2);
393bc679b60SStephan Aßmus 	}
394bc679b60SStephan Aßmus 
395bc679b60SStephan Aßmus 
396bc679b60SStephan Aßmus 	fCurrentPoint = 0;
397bc679b60SStephan Aßmus 	fCurrentFractal = F;
398bc679b60SStephan Aßmus 	fPointBuffer = F->buffer2;
399bc679b60SStephan Aßmus 	for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
400bc679b60SStephan Aßmus 		xo = Cur->Cx;
401bc679b60SStephan Aßmus 		yo = Cur->Cy;
402bc679b60SStephan Aßmus 		for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
403bc679b60SStephan Aßmus 			if (Simi == Cur)
404bc679b60SStephan Aßmus 				continue;
405bc679b60SStephan Aßmus 			transform(Simi, xo, yo, &x, &y);
406bc679b60SStephan Aßmus 			_Trace(F, x, y);
407bc679b60SStephan Aßmus 		}
408bc679b60SStephan Aßmus 	}
409bc679b60SStephan Aßmus 
410bc679b60SStephan Aßmus 	if (F->bitmap != NULL && F->markBitmap != NULL) {
411bc679b60SStephan Aßmus 		uint8* bits = (uint8*)F->bitmap->Bits();
412bc679b60SStephan Aßmus 		uint32 bpr = F->bitmap->BytesPerRow();
413bc679b60SStephan Aßmus 		uint8* markBits = (uint8*)F->markBitmap->Bits();
414bc679b60SStephan Aßmus 		uint32 markBPR = F->markBitmap->BytesPerRow();
415bc679b60SStephan Aßmus 		int32 minX = F->Width;
416bc679b60SStephan Aßmus 		int32 minY = F->Height;
417bc679b60SStephan Aßmus 		int32 maxX = 0;
418bc679b60SStephan Aßmus 		int32 maxY = 0;
419bc679b60SStephan Aßmus 		// Erase previous dots from bitmap,
420bc679b60SStephan Aßmus 		// but only if we're not in BDirectWindow mode,
421bc679b60SStephan Aßmus 		// since the dots will have been erased already
422bc679b60SStephan Aßmus 		if (!info) {
423bc679b60SStephan Aßmus 			if (F->Cur_Pt) {
424bc679b60SStephan Aßmus 				for (int32 i = 0; i <  F->Cur_Pt; i++) {
425bc679b60SStephan Aßmus 					Point p = F->buffer1[i];
426bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
427bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
428bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
429bc679b60SStephan Aßmus 						*(uint32*)&bits[offset] = 0;
430bc679b60SStephan Aßmus 						if (minX > p.x)
431bc679b60SStephan Aßmus 							minX = p.x;
432bc679b60SStephan Aßmus 						if (minY > p.y)
433bc679b60SStephan Aßmus 							minY = p.y;
434bc679b60SStephan Aßmus 						if (maxX < p.x)
435bc679b60SStephan Aßmus 							maxX = p.x;
436bc679b60SStephan Aßmus 						if (maxY < p.y)
437bc679b60SStephan Aßmus 							maxY = p.y;
438bc679b60SStephan Aßmus 					}
439bc679b60SStephan Aßmus 				}
440bc679b60SStephan Aßmus 			}
441bc679b60SStephan Aßmus 		}
442bc679b60SStephan Aßmus 		// draw the new dots into the bitmap
443bc679b60SStephan Aßmus 		if (fCurrentPoint) {
444bc679b60SStephan Aßmus 			if (info) {
445bc679b60SStephan Aßmus 				for (int32 i = 0; i <  fCurrentPoint; i++) {
446bc679b60SStephan Aßmus 					Point p = F->buffer2[i];
447bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
448bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
449bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
450bc679b60SStephan Aßmus 						if (fAdditive) {
451bc679b60SStephan Aßmus 							if (bits[offset + 0] < 255) {
452bc679b60SStephan Aßmus 								bits[offset + 0] += 51;
453bc679b60SStephan Aßmus 								bits[offset + 1] += 51;
454bc679b60SStephan Aßmus 								bits[offset + 2] += 51;
455bc679b60SStephan Aßmus 							}
456bc679b60SStephan Aßmus 						} else {
457bc679b60SStephan Aßmus 							*(uint32*)&bits[offset] = 0xffffffff;
458bc679b60SStephan Aßmus 						}
459bc679b60SStephan Aßmus 					}
460bc679b60SStephan Aßmus 				}
461bc679b60SStephan Aßmus 			} else {
462bc679b60SStephan Aßmus 				// in this version, remember the bounds rectangle
463bc679b60SStephan Aßmus 				for (int32 i = 0; i <  fCurrentPoint; i++) {
464bc679b60SStephan Aßmus 					Point p = F->buffer2[i];
465bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
466bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
467bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
468bc679b60SStephan Aßmus 						if (fAdditive) {
469bc679b60SStephan Aßmus 							if (bits[offset + 0] < 255) {
470bc679b60SStephan Aßmus 								bits[offset + 0] += 15;
471bc679b60SStephan Aßmus 								bits[offset + 1] += 15;
472bc679b60SStephan Aßmus 								bits[offset + 2] += 15;
473bc679b60SStephan Aßmus 							}
474bc679b60SStephan Aßmus 						} else {
475bc679b60SStephan Aßmus 							*(uint32*)&bits[offset] = 0xffffffff;
476bc679b60SStephan Aßmus 						}
477bc679b60SStephan Aßmus 						if (minX > p.x)
478bc679b60SStephan Aßmus 							minX = p.x;
479bc679b60SStephan Aßmus 						if (minY > p.y)
480bc679b60SStephan Aßmus 							minY = p.y;
481bc679b60SStephan Aßmus 						if (maxX < p.x)
482bc679b60SStephan Aßmus 							maxX = p.x;
483bc679b60SStephan Aßmus 						if (maxY < p.y)
484bc679b60SStephan Aßmus 							maxY = p.y;
485bc679b60SStephan Aßmus 					}
486bc679b60SStephan Aßmus 				}
487bc679b60SStephan Aßmus 			}
488bc679b60SStephan Aßmus 		}
489bc679b60SStephan Aßmus 		if (info && info->bits) {
490bc679b60SStephan Aßmus 
491bc679b60SStephan Aßmus 			uint8* screenBits = (uint8*)info->bits;
492bc679b60SStephan Aßmus 			uint32 screenBPR = info->bytesPerRow;
493bc679b60SStephan Aßmus 			int32 left = info->bounds.left;
494bc679b60SStephan Aßmus 			int32 top = info->bounds.top;
495bc679b60SStephan Aßmus 			int32 bpp = info->bits_per_pixel;
496bc679b60SStephan Aßmus 			screenBits += left * bpp + top * bpr;
497bc679b60SStephan Aßmus 
498bc679b60SStephan Aßmus 			int32 screenWidth = info->bounds.right - left;
499bc679b60SStephan Aßmus 			int32 screenHeight = info->bounds.bottom - top;
500bc679b60SStephan Aßmus 
501bc679b60SStephan Aßmus //printf("using BDirectWindow (%p  %dx%d)\n", this, F->Width, F->Height);
502bc679b60SStephan Aßmus 			// redraw the previous points on screen
503bc679b60SStephan Aßmus 			// with the contents of the current bitmap
504bc679b60SStephan Aßmus 			//
505bc679b60SStephan Aßmus 			// draw the new points, erasing the bitmap as we go
506bc679b60SStephan Aßmus 			int32 maxPoints = max_c(F->Cur_Pt, fCurrentPoint);
507bc679b60SStephan Aßmus 			if (maxPoints > 0) {
508bc679b60SStephan Aßmus 
509bc679b60SStephan Aßmus //				BScreen screen(B_MAIN_SCREEN_ID);
510bc679b60SStephan Aßmus //				screen.WaitForRetrace();
511bc679b60SStephan Aßmus 
512bc679b60SStephan Aßmus 				for (int32 i = 0; i < maxPoints; i++) {
513bc679b60SStephan Aßmus 					// copy previous points (black)
514bc679b60SStephan Aßmus 					if (i < F->Cur_Pt) {
515bc679b60SStephan Aßmus 						Point p = F->buffer1[i];
516bc679b60SStephan Aßmus 						if (p.x >= 0 && p.x < F->Width && p.x < screenWidth
517bc679b60SStephan Aßmus 							&& p.y >= 0 && p.y < F->Height && p.y < screenHeight) {
518bc679b60SStephan Aßmus 							int32 markOffset = markBPR * p.y + p.x;
519bc679b60SStephan Aßmus 							if (markBits[markOffset] != fCurrentMarkValue) {
520bc679b60SStephan Aßmus 								int32 offset = bpr * p.y + p.x * 4;
521bc679b60SStephan Aßmus 								// copy the pixel to the screen
522bc679b60SStephan Aßmus 								uint32* src = (uint32*)&bits[offset];
523bc679b60SStephan Aßmus 								if (bpp == 32) {
524bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 4;
525bc679b60SStephan Aßmus 									*(uint32*)&screenBits[screenOffset] = *src;
526bc679b60SStephan Aßmus 								} else if (bpp == 16) {
527bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 2;
528bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
529bc679b60SStephan Aßmus 										(uint16)(((bits[offset + 2] & 0xf8) << 8) |
530bc679b60SStephan Aßmus 												 ((bits[offset + 1] & 0xfc) << 3) |
531bc679b60SStephan Aßmus 										  		  (bits[offset] >> 3));
532bc679b60SStephan Aßmus 								} else if (bpp == 15) {
533bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 2;
534bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
535bc679b60SStephan Aßmus 										(uint16)(((bits[offset + 2] & 0xf8) << 7) |
536bc679b60SStephan Aßmus 												 ((bits[offset + 1] & 0xf8) << 2) |
537bc679b60SStephan Aßmus 										  		  (bits[offset] >> 3));
538bc679b60SStephan Aßmus 								} else if (bpp == 8) {
539bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x;
540bc679b60SStephan Aßmus 									screenBits[screenOffset] = bits[offset];
541bc679b60SStephan Aßmus 								}
542bc679b60SStephan Aßmus 								*src = 0;
543bc679b60SStephan Aßmus 								markBits[markOffset] = fCurrentMarkValue;
544bc679b60SStephan Aßmus 							} // else it means the pixel has been copied already
545bc679b60SStephan Aßmus 						}
546bc679b60SStephan Aßmus 					}
547bc679b60SStephan Aßmus 					// copy current points (white) and erase them from the bitmap
548bc679b60SStephan Aßmus 					if (i < fCurrentPoint) {
549bc679b60SStephan Aßmus 						Point p = F->buffer2[i];
550bc679b60SStephan Aßmus 						if (p.x >= 0 && p.x < F->Width && p.x < screenWidth
551bc679b60SStephan Aßmus 							&& p.y >= 0 && p.y < F->Height && p.y < screenHeight) {
552bc679b60SStephan Aßmus 							int32 markOffset = markBPR * p.y + p.x;
553bc679b60SStephan Aßmus 							int32 offset = bpr * p.y + p.x * 4;
554bc679b60SStephan Aßmus 							// copy the pixel to the screen
555bc679b60SStephan Aßmus 							uint32* src = (uint32*)&bits[offset];
556bc679b60SStephan Aßmus 							if (markBits[markOffset] != fCurrentMarkValue) {
557bc679b60SStephan Aßmus 								if (bpp == 32) {
558bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 4;
559bc679b60SStephan Aßmus 									*(uint32*)&screenBits[screenOffset] = *src;
560bc679b60SStephan Aßmus 								} else if (bpp == 16) {
561bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 2;
562bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
563bc679b60SStephan Aßmus 										(uint16)(((bits[offset + 2] & 0xf8) << 8) |
564bc679b60SStephan Aßmus 												 ((bits[offset + 1] & 0xfc) << 3) |
565bc679b60SStephan Aßmus 										  		  (bits[offset] >> 3));
566bc679b60SStephan Aßmus 								} else if (bpp == 15) {
567bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x * 2;
568bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
569bc679b60SStephan Aßmus 										(uint16)(((bits[offset + 2] & 0xf8) << 7) |
570bc679b60SStephan Aßmus 												 ((bits[offset + 1] & 0xf8) << 2) |
571bc679b60SStephan Aßmus 										  		  (bits[offset] >> 3));
572bc679b60SStephan Aßmus 								} else if (bpp == 1) {
573bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x;
574bc679b60SStephan Aßmus 									screenBits[screenOffset] = bits[offset];
575bc679b60SStephan Aßmus 								}
576bc679b60SStephan Aßmus 								markBits[markOffset] = fCurrentMarkValue;
577bc679b60SStephan Aßmus 							} // else it means the pixel has been copied already
578bc679b60SStephan Aßmus 							*src = 0;
579bc679b60SStephan Aßmus 						}
580bc679b60SStephan Aßmus 					}
581bc679b60SStephan Aßmus 				}
582bc679b60SStephan Aßmus 			}
583bc679b60SStephan Aßmus 		} else {
584bc679b60SStephan Aßmus //printf("using BView (%p  %dx%d)\n", this, F->Width, F->Height);
585bc679b60SStephan Aßmus 			// if not in BDirectWindow mode, draw the bitmap
586bc679b60SStephan Aßmus 			BRect b(minX, minY, maxX, maxY);
587bc679b60SStephan Aßmus 			view->DrawBitmapAsync(F->bitmap, b, b);
588bc679b60SStephan Aßmus 		}
589bc679b60SStephan Aßmus 	}
590bc679b60SStephan Aßmus 
591bc679b60SStephan Aßmus 	// flip buffers
592bc679b60SStephan Aßmus 	F->Cur_Pt = fCurrentPoint;
593bc679b60SStephan Aßmus 	fPointBuffer = F->buffer1;
594bc679b60SStephan Aßmus 	F->buffer1 = F->buffer2;
595bc679b60SStephan Aßmus 	F->buffer2 = fPointBuffer;
596bc679b60SStephan Aßmus 	if (fCurrentMarkValue == 255)
597bc679b60SStephan Aßmus 		fCurrentMarkValue = 0;
598bc679b60SStephan Aßmus 	else
599bc679b60SStephan Aßmus 		fCurrentMarkValue++;
600bc679b60SStephan Aßmus }
601bc679b60SStephan Aßmus 
602bc679b60SStephan Aßmus // _Trace
603bc679b60SStephan Aßmus void
604bc679b60SStephan Aßmus IFS::_Trace(FRACTAL* F, int32 xo, int32 yo)
605bc679b60SStephan Aßmus {
606bc679b60SStephan Aßmus 	int32 x, y, i;
607bc679b60SStephan Aßmus 	SIMI* Cur;
608bc679b60SStephan Aßmus 
609bc679b60SStephan Aßmus 	Cur = fCurrentFractal->Components;
610bc679b60SStephan Aßmus 	for (i = fCurrentFractal->Nb_Simi; i; --i, Cur++) {
611bc679b60SStephan Aßmus 		transform(Cur, xo, yo, &x, &y);
612bc679b60SStephan Aßmus 		// fPointBuffer->x = F->Lx + (x * F->Lx / (UNIT * 2));
613bc679b60SStephan Aßmus 		// fPointBuffer->y = F->Ly - (y * F->Ly / (UNIT * 2));
614bc679b60SStephan Aßmus 		fPointBuffer->x = (UNIT * 2 + x) * F->Lx / (UNIT * 2);
615bc679b60SStephan Aßmus 		fPointBuffer->y = (UNIT * 2 - y) * F->Ly / (UNIT * 2);
616bc679b60SStephan Aßmus 		fPointBuffer++;
617bc679b60SStephan Aßmus 		fCurrentPoint++;
618bc679b60SStephan Aßmus 
619bc679b60SStephan Aßmus 		if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
620bc679b60SStephan Aßmus 			F->Depth--;
621bc679b60SStephan Aßmus 			_Trace(F, x, y);
622bc679b60SStephan Aßmus 			F->Depth++;
623bc679b60SStephan Aßmus 		}
624bc679b60SStephan Aßmus 	}
625bc679b60SStephan Aßmus }
626bc679b60SStephan Aßmus 
627bc679b60SStephan Aßmus // _RandomSimis
628bc679b60SStephan Aßmus void
629bc679b60SStephan Aßmus IFS::_RandomSimis(FRACTAL* f, SIMI* cur, int i) const
630bc679b60SStephan Aßmus {
631bc679b60SStephan Aßmus 	while (i--) {
632bc679b60SStephan Aßmus 		cur->c_x = gauss_rand(0.0, .8, 4.0);
633bc679b60SStephan Aßmus 		cur->c_y = gauss_rand(0.0, .8, 4.0);
634bc679b60SStephan Aßmus 		cur->r = gauss_rand(f->r_mean, f->dr_mean, 3.0);
635bc679b60SStephan Aßmus 		cur->r2 = half_gauss_rand(0.0,f->dr2_mean, 2.0);
636bc679b60SStephan Aßmus 		cur->A = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
637bc679b60SStephan Aßmus 		cur->A2 = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
638bc679b60SStephan Aßmus 		cur++;
639bc679b60SStephan Aßmus 	}
640bc679b60SStephan Aßmus }
641bc679b60SStephan Aßmus 
642bc679b60SStephan Aßmus // _FreeBuffers
643bc679b60SStephan Aßmus void
644bc679b60SStephan Aßmus IFS::_FreeBuffers(FRACTAL *f)
645bc679b60SStephan Aßmus {
646bc679b60SStephan Aßmus 	if (f->buffer1) {
647bc679b60SStephan Aßmus 		free((void*) f->buffer1);
648bc679b60SStephan Aßmus 		f->buffer1 = (Point*)NULL;
649bc679b60SStephan Aßmus 	}
650bc679b60SStephan Aßmus 	if (f->buffer2) {
651bc679b60SStephan Aßmus 		free((void*) f->buffer2);
652bc679b60SStephan Aßmus 		f->buffer2 = (Point*)NULL;
653bc679b60SStephan Aßmus 	}
654bc679b60SStephan Aßmus }
655bc679b60SStephan Aßmus 
656bc679b60SStephan Aßmus // _FreeIFS
657bc679b60SStephan Aßmus void
658bc679b60SStephan Aßmus IFS::_FreeIFS(FRACTAL* f)
659bc679b60SStephan Aßmus {
660bc679b60SStephan Aßmus 	_FreeBuffers(f);
661bc679b60SStephan Aßmus 	delete f->bitmap;
662bc679b60SStephan Aßmus 	f->bitmap = NULL;
663bc679b60SStephan Aßmus 	delete f->markBitmap;
664bc679b60SStephan Aßmus 	f->markBitmap = NULL;
665bc679b60SStephan Aßmus }
666bc679b60SStephan Aßmus 
667bc679b60SStephan Aßmus 
668bc679b60SStephan Aßmus 
669