xref: /haiku/src/add-ons/screen_savers/ifs/IFS.cpp (revision da8162be21b36442f34a731873d2358a0d63c25a)
1bc679b60SStephan Aßmus /*
2bc679b60SStephan Aßmus  * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
398b054feSJohn Scipione  * Copyright 2006-2014, Haiku, Inc. All rights reserved.
4bc679b60SStephan Aßmus  *
5bc679b60SStephan Aßmus  * Distributed under the terms of the MIT License.
6bc679b60SStephan Aßmus  *
7bc679b60SStephan Aßmus  * Authors:
898b054feSJohn Scipione  *		Stephan Aßmus, superstippi@gmx.de
998b054feSJohn Scipione  *		Massimino Pascal, Pascal.Massimon@ens.fr
1098b054feSJohn Scipione  *		John Scipione, jscipione@gmail.com
11bc679b60SStephan Aßmus  */
12bc679b60SStephan Aßmus 
13bc679b60SStephan Aßmus /*! When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
14bc679b60SStephan Aßmus  */
15bc679b60SStephan Aßmus 
16bc679b60SStephan Aßmus #include "IFS.h"
17bc679b60SStephan Aßmus 
18bc679b60SStephan Aßmus #include <new>
19bc679b60SStephan Aßmus #include <malloc.h>
20bc679b60SStephan Aßmus #include <stdio.h>
21bc679b60SStephan Aßmus #include <string.h>
22bc679b60SStephan Aßmus 
23bc679b60SStephan Aßmus #include <Bitmap.h>
24bc679b60SStephan Aßmus #include <OS.h>
25bc679b60SStephan Aßmus #include <Screen.h>
26bc679b60SStephan Aßmus #include <View.h>
27bc679b60SStephan Aßmus 
2898b054feSJohn Scipione #include <unistd.h>
2998b054feSJohn Scipione 	// for getpid()
3098b054feSJohn Scipione #include <sys/time.h>
3198b054feSJohn Scipione 	// for gettimeofday()
32bc679b60SStephan Aßmus 
33bc679b60SStephan Aßmus 
34bc679b60SStephan Aßmus #define HALF 0
3598b054feSJohn Scipione #define random() ya_random()
3698b054feSJohn Scipione 
3798b054feSJohn Scipione #define FLOAT_TO_INT(x) (int32)((float)(UNIT)*(x))
3898b054feSJohn Scipione 
3998b054feSJohn Scipione #define LRAND() ((long) (random() & 0x7fffffff))
4098b054feSJohn Scipione #define NRAND(n) ((int) (LRAND() % (n)))
4198b054feSJohn Scipione #define MAXRAND (2147483648.0)
4298b054feSJohn Scipione 	// unsigned 1<<31 as a float
4398b054feSJohn Scipione #define SRAND(n)
4498b054feSJohn Scipione 	// already seeded by screenhack.c TODO: ?!? is it?
45bc679b60SStephan Aßmus 
46bc679b60SStephan Aßmus // The following 'random' numbers are taken from CRC, 18th Edition, page 622.
47bc679b60SStephan Aßmus // Each array element was taken from the corresponding line in the table,
48bc679b60SStephan Aßmus // except that a[0] was from line 100. 8s and 9s in the table were simply
49bc679b60SStephan Aßmus // skipped. The high order digit was taken mod 4.
50bc679b60SStephan Aßmus 
5198b054feSJohn Scipione #define VECTOR_SIZE 55
5298b054feSJohn Scipione 
5398b054feSJohn Scipione static unsigned int a[VECTOR_SIZE] = {
54bc679b60SStephan Aßmus 	035340171546, 010401501101, 022364657325, 024130436022, 002167303062, //  5
55bc679b60SStephan Aßmus 	037570375137, 037210607110, 016272055420, 023011770546, 017143426366, // 10
56bc679b60SStephan Aßmus 	014753657433, 021657231332, 023553406142, 004236526362, 010365611275, // 14
57bc679b60SStephan Aßmus 	007117336710, 011051276551, 002362132524, 001011540233, 012162531646, // 20
58bc679b60SStephan Aßmus 	007056762337, 006631245521, 014164542224, 032633236305, 023342700176, // 25
59bc679b60SStephan Aßmus 	002433062234, 015257225043, 026762051606, 000742573230, 005366042132, // 30
60bc679b60SStephan Aßmus 	012126416411, 000520471171, 000725646277, 020116577576, 025765742604, // 35
61bc679b60SStephan Aßmus 	007633473735, 015674255275, 017555634041, 006503154145, 021576344247, // 40
62bc679b60SStephan Aßmus 	014577627653, 002707523333, 034146376720, 030060227734, 013765414060, // 45
63bc679b60SStephan Aßmus 	036072251540, 007255221037, 024364674123, 006200353166, 010126373326, // 50
64bc679b60SStephan Aßmus 	015664104320, 016401041535, 016215305520, 033115351014, 017411670323  // 55
65bc679b60SStephan Aßmus };
66bc679b60SStephan Aßmus 
67bc679b60SStephan Aßmus 
6898b054feSJohn Scipione static int i1;
6998b054feSJohn Scipione static int i2;
7098b054feSJohn Scipione 
7198b054feSJohn Scipione 
72bc679b60SStephan Aßmus unsigned int
ya_random(void)73bc679b60SStephan Aßmus ya_random(void)
74bc679b60SStephan Aßmus {
75*95080923SMichael Brumbelow 	int ret = a[i1] + a[i2];
76bc679b60SStephan Aßmus 	a[i1] = ret;
7798b054feSJohn Scipione 	if (++i1 >= VECTOR_SIZE)
7898b054feSJohn Scipione 		i1 = 0;
7998b054feSJohn Scipione 
8098b054feSJohn Scipione 	if (++i2 >= VECTOR_SIZE)
8198b054feSJohn Scipione 		i2 = 0;
8298b054feSJohn Scipione 
83bc679b60SStephan Aßmus 	return ret;
84bc679b60SStephan Aßmus }
85bc679b60SStephan Aßmus 
8698b054feSJohn Scipione 
87bc679b60SStephan Aßmus void
ya_rand_init(unsigned int seed)88bc679b60SStephan Aßmus ya_rand_init(unsigned int seed)
89bc679b60SStephan Aßmus {
90bc679b60SStephan Aßmus 	int i;
9198b054feSJohn Scipione 	if (seed == 0) {
92bc679b60SStephan Aßmus 		struct timeval tp;
93bc679b60SStephan Aßmus 		struct timezone tzp;
94bc679b60SStephan Aßmus 		gettimeofday(&tp, &tzp);
9598b054feSJohn Scipione 		// ignore overflow
96bc679b60SStephan Aßmus 		seed = (999*tp.tv_sec) + (1001*tp.tv_usec) + (1003 * getpid());
97bc679b60SStephan Aßmus 	}
98bc679b60SStephan Aßmus 
99bc679b60SStephan Aßmus 	a[0] += seed;
10098b054feSJohn Scipione 	for (i = 1; i < VECTOR_SIZE; i++) {
101bc679b60SStephan Aßmus 		seed = a[i-1]*1001 + seed*999;
102bc679b60SStephan Aßmus 		a[i] += seed;
103bc679b60SStephan Aßmus 	}
104bc679b60SStephan Aßmus 
10598b054feSJohn Scipione 	i1 = a[0] % VECTOR_SIZE;
106e1633b42SAdrien Destugues 	i2 = (i1 + 24) % VECTOR_SIZE;
107bc679b60SStephan Aßmus }
108bc679b60SStephan Aßmus 
109bc679b60SStephan Aßmus 
110bc679b60SStephan Aßmus 
111bc679b60SStephan Aßmus static float
gauss_rand(float c,float A,float S)112bc679b60SStephan Aßmus gauss_rand(float c, float A, float S)
113bc679b60SStephan Aßmus {
11498b054feSJohn Scipione 	float y = (float) LRAND() / MAXRAND;
115bc679b60SStephan Aßmus 	y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
116bc679b60SStephan Aßmus 	if (NRAND(2))
117bc679b60SStephan Aßmus 		return (c + y);
11898b054feSJohn Scipione 
119bc679b60SStephan Aßmus 	return (c - y);
120bc679b60SStephan Aßmus }
121bc679b60SStephan Aßmus 
12298b054feSJohn Scipione 
123bc679b60SStephan Aßmus static float
half_gauss_rand(float c,float A,float S)124bc679b60SStephan Aßmus half_gauss_rand(float c, float A, float S)
125bc679b60SStephan Aßmus {
12698b054feSJohn Scipione 	float y = (float) LRAND() / MAXRAND;
127bc679b60SStephan Aßmus 	y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
12898b054feSJohn Scipione 
129bc679b60SStephan Aßmus 	return (c + y);
130bc679b60SStephan Aßmus }
131bc679b60SStephan Aßmus 
13298b054feSJohn Scipione 
133bc679b60SStephan Aßmus inline void
transform(SIMILITUDE * Similitude,int32 xo,int32 yo,int32 * x,int32 * y)13498b054feSJohn Scipione transform(SIMILITUDE* Similitude, int32 xo, int32 yo, int32* x, int32* y)
135bc679b60SStephan Aßmus {
13698b054feSJohn Scipione 	int32 xx;
13798b054feSJohn Scipione 	int32 yy;
138bc679b60SStephan Aßmus 
13998b054feSJohn Scipione 	xo = xo - Similitude->Cx;
14098b054feSJohn Scipione 	xo = (xo * Similitude->R) / UNIT;
14198b054feSJohn Scipione 	yo = yo - Similitude->Cy;
14298b054feSJohn Scipione 	yo = (yo * Similitude->R) / UNIT;
143bc679b60SStephan Aßmus 
14498b054feSJohn Scipione 	xx = xo - Similitude->Cx;
14598b054feSJohn Scipione 	xx = (xx * Similitude->R2) / UNIT;
14698b054feSJohn Scipione 	yy = -yo - Similitude->Cy;
14798b054feSJohn Scipione 	yy = (yy * Similitude->R2) / UNIT;
148bc679b60SStephan Aßmus 
14998b054feSJohn Scipione 	*x = ((xo * Similitude->Ct - yo * Similitude->St + xx * Similitude->Ct2
15098b054feSJohn Scipione 		- yy * Similitude->St2) / UNIT) + Similitude->Cx;
15198b054feSJohn Scipione 	*y = ((xo * Similitude->St + yo * Similitude->Ct + xx * Similitude->St2
15298b054feSJohn Scipione 		+ yy * Similitude->Ct2) / UNIT) + Similitude->Cy;
153bc679b60SStephan Aßmus }
154bc679b60SStephan Aßmus 
155bc679b60SStephan Aßmus 
15698b054feSJohn Scipione 
IFS(BRect bounds)157bc679b60SStephan Aßmus IFS::IFS(BRect bounds)
1587bcfb215SJohn Scipione 	:
1597bcfb215SJohn Scipione 	fRoot(NULL),
1607bcfb215SJohn Scipione 	fCurrentFractal(NULL),
1617bcfb215SJohn Scipione 	fPointBuffer(NULL),
1627bcfb215SJohn Scipione 	fCurrentPoint(0),
163bc679b60SStephan Aßmus 	fAdditive(false),
164bc679b60SStephan Aßmus 	fCurrentMarkValue(1)
165bc679b60SStephan Aßmus {
166e443b44aSStephan Aßmus 	if (!bounds.IsValid())
167e443b44aSStephan Aßmus 		return;
168e443b44aSStephan Aßmus 
169bc679b60SStephan Aßmus 	ya_rand_init(system_time());
170bc679b60SStephan Aßmus 
171bc679b60SStephan Aßmus 	int i;
172bc679b60SStephan Aßmus 	FRACTAL* Fractal;
173bc679b60SStephan Aßmus 
174bc679b60SStephan Aßmus 	if (fRoot == NULL) {
175bc679b60SStephan Aßmus 		fRoot = (FRACTAL*)calloc(1, sizeof(FRACTAL));
176bc679b60SStephan Aßmus 		if (fRoot == NULL)
177bc679b60SStephan Aßmus 			return;
178bc679b60SStephan Aßmus 	}
179bc679b60SStephan Aßmus 	Fractal = fRoot;
180bc679b60SStephan Aßmus 
181bc679b60SStephan Aßmus 	_FreeBuffers(Fractal);
18298b054feSJohn Scipione 	i = (NRAND(4)) + 2;
18398b054feSJohn Scipione 		// Number of centers
184bc679b60SStephan Aßmus 	switch (i) {
18598b054feSJohn Scipione 		case 2:
18698b054feSJohn Scipione 		default:
18798b054feSJohn Scipione 			Fractal->Depth = fAdditive ? MAX_DEPTH_2 + 1 : MAX_DEPTH_2;
18898b054feSJohn Scipione 			Fractal->r_mean = 0.7;
18998b054feSJohn Scipione 			Fractal->dr_mean = 0.3;
19098b054feSJohn Scipione 			Fractal->dr2_mean = 0.4;
19198b054feSJohn Scipione 			break;
19298b054feSJohn Scipione 
193bc679b60SStephan Aßmus 		case 3:
194bc679b60SStephan Aßmus 			Fractal->Depth = fAdditive ? MAX_DEPTH_3 + 1 : MAX_DEPTH_3;
19598b054feSJohn Scipione 			Fractal->r_mean = 0.6;
19698b054feSJohn Scipione 			Fractal->dr_mean = 0.4;
19798b054feSJohn Scipione 			Fractal->dr2_mean = 0.3;
198bc679b60SStephan Aßmus 			break;
199bc679b60SStephan Aßmus 
200bc679b60SStephan Aßmus 		case 4:
201bc679b60SStephan Aßmus 			Fractal->Depth = MAX_DEPTH_4;
20298b054feSJohn Scipione 			Fractal->r_mean = 0.5;
20398b054feSJohn Scipione 			Fractal->dr_mean = 0.4;
20498b054feSJohn Scipione 			Fractal->dr2_mean = 0.3;
205bc679b60SStephan Aßmus 			break;
206bc679b60SStephan Aßmus 
207bc679b60SStephan Aßmus 		case 5:
208bc679b60SStephan Aßmus 			Fractal->Depth = MAX_DEPTH_5;
20998b054feSJohn Scipione 			Fractal->r_mean = 0.5;
21098b054feSJohn Scipione 			Fractal->dr_mean = 0.4;
21198b054feSJohn Scipione 			Fractal->dr2_mean = 0.3;
212bc679b60SStephan Aßmus 			break;
213bc679b60SStephan Aßmus 	}
214bc679b60SStephan Aßmus 
21598b054feSJohn Scipione 	Fractal->SimilitudeCount = i;
21698b054feSJohn Scipione 	Fractal->MaxPoint = Fractal->SimilitudeCount - 1;
21798b054feSJohn Scipione 	for (i = 0; i <= Fractal->Depth + 2; ++i)
21898b054feSJohn Scipione 		Fractal->MaxPoint *= Fractal->SimilitudeCount;
21998b054feSJohn Scipione 
22098b054feSJohn Scipione 	if ((Fractal->buffer1 = (Point *)calloc(Fractal->MaxPoint,
221bc679b60SStephan Aßmus 			sizeof(Point))) == NULL) {
222bc679b60SStephan Aßmus 		_FreeIFS(Fractal);
223bc679b60SStephan Aßmus 		return;
224bc679b60SStephan Aßmus 	}
22598b054feSJohn Scipione 	if ((Fractal->buffer2 = (Point *)calloc(Fractal->MaxPoint,
226bc679b60SStephan Aßmus 			sizeof(Point))) == NULL) {
227bc679b60SStephan Aßmus 		_FreeIFS(Fractal);
228bc679b60SStephan Aßmus 		return;
229bc679b60SStephan Aßmus 	}
230bc679b60SStephan Aßmus 	Fractal->Speed = 6;
231bc679b60SStephan Aßmus #if HALF
232bc679b60SStephan Aßmus 	Fractal->Width = bounds.IntegerWidth() / 2 + 1;
233bc679b60SStephan Aßmus 	Fractal->Height = bounds.IntegerHeight() / 2 + 1;
234bc679b60SStephan Aßmus #else
235bc679b60SStephan Aßmus 	Fractal->Width = bounds.IntegerWidth() + 1;
236bc679b60SStephan Aßmus 	Fractal->Height = bounds.IntegerHeight() + 1;
237bc679b60SStephan Aßmus #endif
23898b054feSJohn Scipione 	Fractal->CurrentPoint = 0;
239bc679b60SStephan Aßmus 	Fractal->Count = 0;
240bc679b60SStephan Aßmus 	Fractal->Lx = (Fractal->Width - 1) / 2;
241bc679b60SStephan Aßmus 	Fractal->Ly = (Fractal->Height - 1) / 2;
242bc679b60SStephan Aßmus 	Fractal->Col = NRAND(Fractal->Width * Fractal->Height - 1) + 1;
243bc679b60SStephan Aßmus 
24498b054feSJohn Scipione 	_RandomSimilitudes(Fractal, Fractal->Components, 5 * MAX_SIMILITUDE);
245bc679b60SStephan Aßmus 
246bc679b60SStephan Aßmus 	delete Fractal->bitmap;
24798b054feSJohn Scipione 	Fractal->bitmap = new BBitmap(BRect(0.0, 0.0,
24898b054feSJohn Scipione 		Fractal->Width - 1, Fractal->Height - 1), 0, B_RGB32);
249bc679b60SStephan Aßmus 	delete Fractal->markBitmap;
25098b054feSJohn Scipione 	Fractal->markBitmap = new BBitmap(BRect(0.0, 0.0,
25198b054feSJohn Scipione 		Fractal->Width - 1, Fractal->Height - 1), 0, B_GRAY8);
25298b054feSJohn Scipione 
25398b054feSJohn Scipione 	// allocation checked
25498b054feSJohn Scipione 	if (Fractal->bitmap != NULL && Fractal->bitmap->IsValid())
255bc679b60SStephan Aßmus 		memset(Fractal->bitmap->Bits(), 0, Fractal->bitmap->BitsLength());
25698b054feSJohn Scipione 	else {
257bc679b60SStephan Aßmus 		delete Fractal->bitmap;
258bc679b60SStephan Aßmus 		Fractal->bitmap = NULL;
259bc679b60SStephan Aßmus 	}
26098b054feSJohn Scipione 
261bc679b60SStephan Aßmus 	if (Fractal->markBitmap != NULL && Fractal->markBitmap->IsValid()) {
26298b054feSJohn Scipione 		memset(Fractal->markBitmap->Bits(), 0,
26398b054feSJohn Scipione 			Fractal->markBitmap->BitsLength());
264bc679b60SStephan Aßmus 	} else {
265bc679b60SStephan Aßmus 		delete Fractal->markBitmap;
266bc679b60SStephan Aßmus 		Fractal->markBitmap = NULL;
267bc679b60SStephan Aßmus 	}
268bc679b60SStephan Aßmus }
269bc679b60SStephan Aßmus 
27098b054feSJohn Scipione 
~IFS()271bc679b60SStephan Aßmus IFS::~IFS()
272bc679b60SStephan Aßmus {
273bc679b60SStephan Aßmus 	if (fRoot != NULL) {
274bc679b60SStephan Aßmus 		_FreeIFS(fRoot);
275bc679b60SStephan Aßmus 		free((void*)fRoot);
276bc679b60SStephan Aßmus 	}
277bc679b60SStephan Aßmus }
278bc679b60SStephan Aßmus 
27998b054feSJohn Scipione 
280bc679b60SStephan Aßmus void
Draw(BView * view,const buffer_info * info,int32 frames)281bc679b60SStephan Aßmus IFS::Draw(BView* view, const buffer_info* info, int32 frames)
282bc679b60SStephan Aßmus {
283bc679b60SStephan Aßmus 	int i;
28498b054feSJohn Scipione 	float u;
28598b054feSJohn Scipione 	float uu;
28698b054feSJohn Scipione 	float v;
28798b054feSJohn Scipione 	float vv;
28898b054feSJohn Scipione 	float u0;
28998b054feSJohn Scipione 	float u1;
29098b054feSJohn Scipione 	float u2;
29198b054feSJohn Scipione 	float u3;
29298b054feSJohn Scipione 	SIMILITUDE* S;
29398b054feSJohn Scipione 	SIMILITUDE* S1;
29498b054feSJohn Scipione 	SIMILITUDE* S2;
29598b054feSJohn Scipione 	SIMILITUDE* S3;
29698b054feSJohn Scipione 	SIMILITUDE* S4;
297bc679b60SStephan Aßmus 	FRACTAL* F;
298bc679b60SStephan Aßmus 
299bc679b60SStephan Aßmus 	if (fRoot == NULL)
300bc679b60SStephan Aßmus 		return;
30198b054feSJohn Scipione 
302bc679b60SStephan Aßmus 	F = fRoot;
303bc679b60SStephan Aßmus 	if (F->buffer1 == NULL)
304bc679b60SStephan Aßmus 		return;
305bc679b60SStephan Aßmus 
306bc679b60SStephan Aßmus 	// do this as many times as necessary to calculate the missing frames
307bc679b60SStephan Aßmus 	// so the animation doesn't jerk when we miss a few frames
308bc679b60SStephan Aßmus 	for (int32 frame = 0; frame < frames; frame++) {
309bc679b60SStephan Aßmus 		u = (float) (F->Count) * (float) (F->Speed) / 1000.0;
310bc679b60SStephan Aßmus 		uu = u * u;
311bc679b60SStephan Aßmus 		v = 1.0 - u;
312bc679b60SStephan Aßmus 		vv = v * v;
313bc679b60SStephan Aßmus 		u0 = vv * v;
314bc679b60SStephan Aßmus 		u1 = 3.0 * vv * u;
315bc679b60SStephan Aßmus 		u2 = 3.0 * v * uu;
316bc679b60SStephan Aßmus 		u3 = u * uu;
317bc679b60SStephan Aßmus 
318bc679b60SStephan Aßmus 		S = F->Components;
31998b054feSJohn Scipione 		S1 = S + F->SimilitudeCount;
32098b054feSJohn Scipione 		S2 = S1 + F->SimilitudeCount;
32198b054feSJohn Scipione 		S3 = S2 + F->SimilitudeCount;
32298b054feSJohn Scipione 		S4 = S3 + F->SimilitudeCount;
323bc679b60SStephan Aßmus 
32498b054feSJohn Scipione 		for (i = F->SimilitudeCount; i; --i, S++, S1++, S2++, S3++, S4++) {
325bc679b60SStephan Aßmus 			S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x;
326bc679b60SStephan Aßmus 			S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y;
327bc679b60SStephan Aßmus 			S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r;
328bc679b60SStephan Aßmus 			S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2;
329bc679b60SStephan Aßmus 			S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A;
330bc679b60SStephan Aßmus 			S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2;
331bc679b60SStephan Aßmus 		}
332bc679b60SStephan Aßmus 
333bc679b60SStephan Aßmus 		if (frame == frames - 1)
334bc679b60SStephan Aßmus 			_DrawFractal(view, info);
335bc679b60SStephan Aßmus 
336bc679b60SStephan Aßmus 		if (F->Count >= 1000 / F->Speed) {
337bc679b60SStephan Aßmus 			S = F->Components;
33898b054feSJohn Scipione 			S1 = S + F->SimilitudeCount;
33998b054feSJohn Scipione 			S2 = S1 + F->SimilitudeCount;
34098b054feSJohn Scipione 			S3 = S2 + F->SimilitudeCount;
34198b054feSJohn Scipione 			S4 = S3 + F->SimilitudeCount;
342bc679b60SStephan Aßmus 
34398b054feSJohn Scipione 			for (i = F->SimilitudeCount; i; --i, S++, S1++, S2++, S3++, S4++) {
344bc679b60SStephan Aßmus 				S2->c_x = 2.0 * S4->c_x - S3->c_x;
345bc679b60SStephan Aßmus 				S2->c_y = 2.0 * S4->c_y - S3->c_y;
346bc679b60SStephan Aßmus 				S2->r = 2.0 * S4->r - S3->r;
347bc679b60SStephan Aßmus 				S2->r2 = 2.0 * S4->r2 - S3->r2;
348bc679b60SStephan Aßmus 				S2->A = 2.0 * S4->A - S3->A;
349bc679b60SStephan Aßmus 				S2->A2 = 2.0 * S4->A2 - S3->A2;
350bc679b60SStephan Aßmus 
351bc679b60SStephan Aßmus 				*S1 = *S4;
352bc679b60SStephan Aßmus 			}
35398b054feSJohn Scipione 			_RandomSimilitudes(F, F->Components + 3 * F->SimilitudeCount,
35498b054feSJohn Scipione 				F->SimilitudeCount);
35598b054feSJohn Scipione 			_RandomSimilitudes(F, F->Components + 4 * F->SimilitudeCount,
35698b054feSJohn Scipione 				F->SimilitudeCount);
357bc679b60SStephan Aßmus 
358bc679b60SStephan Aßmus 			F->Count = 0;
359bc679b60SStephan Aßmus 		} else
360bc679b60SStephan Aßmus 			F->Count++;
36198b054feSJohn Scipione 	}
362bc679b60SStephan Aßmus }
363bc679b60SStephan Aßmus 
364bc679b60SStephan Aßmus 
365bc679b60SStephan Aßmus void
SetAdditive(bool additive)366bc679b60SStephan Aßmus IFS::SetAdditive(bool additive)
367bc679b60SStephan Aßmus {
368bc679b60SStephan Aßmus 	fAdditive = additive;
369bc679b60SStephan Aßmus }
370bc679b60SStephan Aßmus 
37198b054feSJohn Scipione 
372bc679b60SStephan Aßmus void
SetSpeed(int32 speed)373bc679b60SStephan Aßmus IFS::SetSpeed(int32 speed)
374bc679b60SStephan Aßmus {
375bc679b60SStephan Aßmus 	if (fRoot && speed > 0 && speed <= 12)
376bc679b60SStephan Aßmus 		fRoot->Speed = speed;
377bc679b60SStephan Aßmus }
378bc679b60SStephan Aßmus 
37998b054feSJohn Scipione 
380bc679b60SStephan Aßmus void
_DrawFractal(BView * view,const buffer_info * info)381bc679b60SStephan Aßmus IFS::_DrawFractal(BView* view, const buffer_info* info)
382bc679b60SStephan Aßmus {
383bc679b60SStephan Aßmus 	FRACTAL* F = fRoot;
38498b054feSJohn Scipione 	int i;
38598b054feSJohn Scipione 	int j;
38698b054feSJohn Scipione 	int32 x;
38798b054feSJohn Scipione 	int32 y;
38898b054feSJohn Scipione 	int32 xo;
38998b054feSJohn Scipione 	int32 yo;
39098b054feSJohn Scipione 	SIMILITUDE* Current;
39198b054feSJohn Scipione 	SIMILITUDE* Similitude;
392bc679b60SStephan Aßmus 
39398b054feSJohn Scipione 	for (Current = F->Components, i = F->SimilitudeCount; i; --i, Current++) {
39498b054feSJohn Scipione 		Current->Cx = FLOAT_TO_INT(Current->c_x);
39598b054feSJohn Scipione 		Current->Cy = FLOAT_TO_INT(Current->c_y);
396bc679b60SStephan Aßmus 
39798b054feSJohn Scipione 		Current->Ct = FLOAT_TO_INT(cos(Current->A));
39898b054feSJohn Scipione 		Current->St = FLOAT_TO_INT(sin(Current->A));
39998b054feSJohn Scipione 		Current->Ct2 = FLOAT_TO_INT(cos(Current->A2));
40098b054feSJohn Scipione 		Current->St2 = FLOAT_TO_INT(sin(Current->A2));
401bc679b60SStephan Aßmus 
40298b054feSJohn Scipione 		Current->R = FLOAT_TO_INT(Current->r);
40398b054feSJohn Scipione 		Current->R2 = FLOAT_TO_INT(Current->r2);
404bc679b60SStephan Aßmus 	}
405bc679b60SStephan Aßmus 
406bc679b60SStephan Aßmus 	fCurrentPoint = 0;
407bc679b60SStephan Aßmus 	fCurrentFractal = F;
408bc679b60SStephan Aßmus 	fPointBuffer = F->buffer2;
40998b054feSJohn Scipione 	for (Current = F->Components, i = F->SimilitudeCount; i; --i, Current++) {
41098b054feSJohn Scipione 		xo = Current->Cx;
41198b054feSJohn Scipione 		yo = Current->Cy;
41298b054feSJohn Scipione 		for (Similitude = F->Components, j = F->SimilitudeCount; j;
41398b054feSJohn Scipione 				--j, Similitude++) {
41498b054feSJohn Scipione 			if (Similitude == Current)
415bc679b60SStephan Aßmus 				continue;
41698b054feSJohn Scipione 
41798b054feSJohn Scipione 			transform(Similitude, xo, yo, &x, &y);
418bc679b60SStephan Aßmus 			_Trace(F, x, y);
419bc679b60SStephan Aßmus 		}
420bc679b60SStephan Aßmus 	}
421bc679b60SStephan Aßmus 
422bc679b60SStephan Aßmus 	if (F->bitmap != NULL && F->markBitmap != NULL) {
423bc679b60SStephan Aßmus 		uint8* bits = (uint8*)F->bitmap->Bits();
424bc679b60SStephan Aßmus 		uint32 bpr = F->bitmap->BytesPerRow();
425bc679b60SStephan Aßmus 		uint8* markBits = (uint8*)F->markBitmap->Bits();
426bc679b60SStephan Aßmus 		uint32 markBPR = F->markBitmap->BytesPerRow();
427bc679b60SStephan Aßmus 		int32 minX = F->Width;
428bc679b60SStephan Aßmus 		int32 minY = F->Height;
429bc679b60SStephan Aßmus 		int32 maxX = 0;
430bc679b60SStephan Aßmus 		int32 maxY = 0;
431f5e32a86SJohn Scipione 
432bc679b60SStephan Aßmus 		// Erase previous dots from bitmap,
433bc679b60SStephan Aßmus 		// but only if we're not in BDirectWindow mode,
434bc679b60SStephan Aßmus 		// since the dots will have been erased already
43598b054feSJohn Scipione 		if (info == NULL) {
43698b054feSJohn Scipione 			if (F->CurrentPoint) {
43798b054feSJohn Scipione 				for (int32 i = 0; i <  F->CurrentPoint; i++) {
438bc679b60SStephan Aßmus 					Point p = F->buffer1[i];
439bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
440bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
441bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
442bc679b60SStephan Aßmus 						*(uint32*)&bits[offset] = 0;
443bc679b60SStephan Aßmus 						if (minX > p.x)
444bc679b60SStephan Aßmus 							minX = p.x;
44598b054feSJohn Scipione 
446bc679b60SStephan Aßmus 						if (minY > p.y)
447bc679b60SStephan Aßmus 							minY = p.y;
44898b054feSJohn Scipione 
449bc679b60SStephan Aßmus 						if (maxX < p.x)
450bc679b60SStephan Aßmus 							maxX = p.x;
45198b054feSJohn Scipione 
452bc679b60SStephan Aßmus 						if (maxY < p.y)
453bc679b60SStephan Aßmus 							maxY = p.y;
454bc679b60SStephan Aßmus 					}
455bc679b60SStephan Aßmus 				}
456bc679b60SStephan Aßmus 			}
457bc679b60SStephan Aßmus 		}
458f5e32a86SJohn Scipione 
459bc679b60SStephan Aßmus 		// draw the new dots into the bitmap
460f5e32a86SJohn Scipione 		if (fCurrentPoint != 0) {
46198b054feSJohn Scipione 			if (info != NULL) {
462bc679b60SStephan Aßmus 				for (int32 i = 0; i <  fCurrentPoint; i++) {
463bc679b60SStephan Aßmus 					Point p = F->buffer2[i];
464bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
465bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
466bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
467bc679b60SStephan Aßmus 						if (fAdditive) {
468bc679b60SStephan Aßmus 							if (bits[offset + 0] < 255) {
469bc679b60SStephan Aßmus 								bits[offset + 0] += 51;
470bc679b60SStephan Aßmus 								bits[offset + 1] += 51;
471bc679b60SStephan Aßmus 								bits[offset + 2] += 51;
472bc679b60SStephan Aßmus 							}
47398b054feSJohn Scipione 						} else
474bc679b60SStephan Aßmus 							*(uint32*)&bits[offset] = 0xffffffff;
475bc679b60SStephan Aßmus 					}
476bc679b60SStephan Aßmus 				}
477bc679b60SStephan Aßmus 			} else {
478bc679b60SStephan Aßmus 				// in this version, remember the bounds rectangle
479bc679b60SStephan Aßmus 				for (int32 i = 0; i < fCurrentPoint; i++) {
480bc679b60SStephan Aßmus 					Point p = F->buffer2[i];
481bc679b60SStephan Aßmus 					if (p.x >= 0 && p.x < F->Width
482bc679b60SStephan Aßmus 						&& p.y >= 0 && p.y < F->Height) {
483bc679b60SStephan Aßmus 						int32 offset = bpr * p.y + p.x * 4;
484bc679b60SStephan Aßmus 						if (fAdditive) {
485bc679b60SStephan Aßmus 							if (bits[offset + 0] < 255) {
486bc679b60SStephan Aßmus 								bits[offset + 0] += 15;
487bc679b60SStephan Aßmus 								bits[offset + 1] += 15;
488bc679b60SStephan Aßmus 								bits[offset + 2] += 15;
489bc679b60SStephan Aßmus 							}
49098b054feSJohn Scipione 						} else
491bc679b60SStephan Aßmus 							*(uint32*)&bits[offset] = 0xffffffff;
49298b054feSJohn Scipione 
493bc679b60SStephan Aßmus 						if (minX > p.x)
494bc679b60SStephan Aßmus 							minX = p.x;
495f5e32a86SJohn Scipione 
496bc679b60SStephan Aßmus 						if (minY > p.y)
497bc679b60SStephan Aßmus 							minY = p.y;
498f5e32a86SJohn Scipione 
499bc679b60SStephan Aßmus 						if (maxX < p.x)
500bc679b60SStephan Aßmus 							maxX = p.x;
501f5e32a86SJohn Scipione 
502bc679b60SStephan Aßmus 						if (maxY < p.y)
503bc679b60SStephan Aßmus 							maxY = p.y;
504bc679b60SStephan Aßmus 					}
505bc679b60SStephan Aßmus 				}
506bc679b60SStephan Aßmus 			}
507bc679b60SStephan Aßmus 		}
508bc679b60SStephan Aßmus 
50998b054feSJohn Scipione 		if (info != NULL && info->bits != NULL) {
510bc679b60SStephan Aßmus 			uint8* screenBits = (uint8*)info->bits;
511bc679b60SStephan Aßmus 			uint32 screenBPR = info->bytesPerRow;
512bc679b60SStephan Aßmus 			int32 left = info->bounds.left;
513bc679b60SStephan Aßmus 			int32 top = info->bounds.top;
514bc679b60SStephan Aßmus 			int32 bpp = info->bits_per_pixel;
515bc679b60SStephan Aßmus 			screenBits += left * bpp + top * bpr;
516bc679b60SStephan Aßmus 
517bc679b60SStephan Aßmus 			int32 screenWidth = info->bounds.right - left;
518bc679b60SStephan Aßmus 			int32 screenHeight = info->bounds.bottom - top;
519bc679b60SStephan Aßmus 
520bc679b60SStephan Aßmus 			// redraw the previous points on screen
521bc679b60SStephan Aßmus 			// with the contents of the current bitmap
522bc679b60SStephan Aßmus 			//
523bc679b60SStephan Aßmus 			// draw the new points, erasing the bitmap as we go
52498b054feSJohn Scipione 			int32 maxPoints = max_c(F->CurrentPoint, fCurrentPoint);
525bc679b60SStephan Aßmus 			if (maxPoints > 0) {
526bc679b60SStephan Aßmus 				for (int32 i = 0; i < maxPoints; i++) {
527bc679b60SStephan Aßmus 					// copy previous points (black)
52898b054feSJohn Scipione 					if (i < F->CurrentPoint) {
529bc679b60SStephan Aßmus 						Point p = F->buffer1[i];
530bc679b60SStephan Aßmus 						if (p.x >= 0 && p.x < F->Width && p.x < screenWidth
53198b054feSJohn Scipione 							&& p.y >= 0 && p.y < F->Height
53298b054feSJohn Scipione 							&& p.y < screenHeight) {
533bc679b60SStephan Aßmus 							int32 markOffset = markBPR * p.y + p.x;
534bc679b60SStephan Aßmus 							if (markBits[markOffset] != fCurrentMarkValue) {
535bc679b60SStephan Aßmus 								int32 offset = bpr * p.y + p.x * 4;
536bc679b60SStephan Aßmus 								// copy the pixel to the screen
537bc679b60SStephan Aßmus 								uint32* src = (uint32*)&bits[offset];
538bc679b60SStephan Aßmus 								if (bpp == 32) {
53998b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
54098b054feSJohn Scipione 										+ p.x * 4;
541bc679b60SStephan Aßmus 									*(uint32*)&screenBits[screenOffset] = *src;
542bc679b60SStephan Aßmus 								} else if (bpp == 16) {
54398b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
54498b054feSJohn Scipione 										+ p.x * 2;
545bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
54698b054feSJohn Scipione 										(uint16)(((bits[offset + 2] & 0xf8)
54798b054feSJohn Scipione 											<< 8)
54898b054feSJohn Scipione 										| ((bits[offset + 1] & 0xfc) << 3)
54998b054feSJohn Scipione 										| (bits[offset] >> 3));
550bc679b60SStephan Aßmus 								} else if (bpp == 15) {
55198b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
55298b054feSJohn Scipione 										+ p.x * 2;
553bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
55498b054feSJohn Scipione 										(uint16)(((bits[offset + 2] & 0xf8)
55598b054feSJohn Scipione 											<< 7)
55698b054feSJohn Scipione 										| ((bits[offset + 1] & 0xf8) << 2)
55798b054feSJohn Scipione 										| (bits[offset] >> 3));
558bc679b60SStephan Aßmus 								} else if (bpp == 8) {
559bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x;
560bc679b60SStephan Aßmus 									screenBits[screenOffset] = bits[offset];
561bc679b60SStephan Aßmus 								}
562bc679b60SStephan Aßmus 								*src = 0;
563bc679b60SStephan Aßmus 								markBits[markOffset] = fCurrentMarkValue;
56498b054feSJohn Scipione 							}
56598b054feSJohn Scipione 							// else it means the pixel has been copied already
566bc679b60SStephan Aßmus 						}
567bc679b60SStephan Aßmus 					}
56898b054feSJohn Scipione 
56998b054feSJohn Scipione 					// copy current points (white) and erase them from the
57098b054feSJohn Scipione 					// bitmap
571bc679b60SStephan Aßmus 					if (i < fCurrentPoint) {
572bc679b60SStephan Aßmus 						Point p = F->buffer2[i];
573bc679b60SStephan Aßmus 						if (p.x >= 0 && p.x < F->Width && p.x < screenWidth
57498b054feSJohn Scipione 							&& p.y >= 0 && p.y < F->Height
57598b054feSJohn Scipione 							&& p.y < screenHeight) {
576bc679b60SStephan Aßmus 							int32 markOffset = markBPR * p.y + p.x;
577bc679b60SStephan Aßmus 							int32 offset = bpr * p.y + p.x * 4;
57898b054feSJohn Scipione 
579bc679b60SStephan Aßmus 							// copy the pixel to the screen
580bc679b60SStephan Aßmus 							uint32* src = (uint32*)&bits[offset];
581bc679b60SStephan Aßmus 							if (markBits[markOffset] != fCurrentMarkValue) {
582bc679b60SStephan Aßmus 								if (bpp == 32) {
58398b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
58498b054feSJohn Scipione 										+ p.x * 4;
585bc679b60SStephan Aßmus 									*(uint32*)&screenBits[screenOffset] = *src;
586bc679b60SStephan Aßmus 								} else if (bpp == 16) {
58798b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
58898b054feSJohn Scipione 										+ p.x * 2;
589bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
59098b054feSJohn Scipione 										(uint16)(((bits[offset + 2] & 0xf8)
59198b054feSJohn Scipione 											<< 8)
59298b054feSJohn Scipione 										| ((bits[offset + 1] & 0xfc) << 3)
59398b054feSJohn Scipione 										| (bits[offset] >> 3));
594bc679b60SStephan Aßmus 								} else if (bpp == 15) {
59598b054feSJohn Scipione 									int32 screenOffset = screenBPR * p.y
59698b054feSJohn Scipione 										+ p.x * 2;
597bc679b60SStephan Aßmus 									*(uint16*)&screenBits[screenOffset] =
59898b054feSJohn Scipione 										(uint16)(((bits[offset + 2] & 0xf8)
59998b054feSJohn Scipione 											<< 7)
60098b054feSJohn Scipione 										| ((bits[offset + 1] & 0xf8) << 2)
60198b054feSJohn Scipione 										| (bits[offset] >> 3));
602bc679b60SStephan Aßmus 								} else if (bpp == 1) {
603bc679b60SStephan Aßmus 									int32 screenOffset = screenBPR * p.y + p.x;
604bc679b60SStephan Aßmus 									screenBits[screenOffset] = bits[offset];
605bc679b60SStephan Aßmus 								}
606bc679b60SStephan Aßmus 								markBits[markOffset] = fCurrentMarkValue;
60798b054feSJohn Scipione 							}
60898b054feSJohn Scipione 							// else it means the pixel has been copied already
609bc679b60SStephan Aßmus 							*src = 0;
610bc679b60SStephan Aßmus 						}
611bc679b60SStephan Aßmus 					}
612bc679b60SStephan Aßmus 				}
613bc679b60SStephan Aßmus 			}
614bc679b60SStephan Aßmus 		} else {
615bc679b60SStephan Aßmus 			// if not in BDirectWindow mode, draw the bitmap
616bc679b60SStephan Aßmus 			BRect b(minX, minY, maxX, maxY);
617bc679b60SStephan Aßmus 			view->DrawBitmapAsync(F->bitmap, b, b);
618bc679b60SStephan Aßmus 		}
619bc679b60SStephan Aßmus 	}
620bc679b60SStephan Aßmus 
621bc679b60SStephan Aßmus 	// flip buffers
62298b054feSJohn Scipione 	F->CurrentPoint = fCurrentPoint;
623bc679b60SStephan Aßmus 	fPointBuffer = F->buffer1;
624bc679b60SStephan Aßmus 	F->buffer1 = F->buffer2;
625bc679b60SStephan Aßmus 	F->buffer2 = fPointBuffer;
62698b054feSJohn Scipione 
627bc679b60SStephan Aßmus 	if (fCurrentMarkValue == 255)
628bc679b60SStephan Aßmus 		fCurrentMarkValue = 0;
629bc679b60SStephan Aßmus 	else
630bc679b60SStephan Aßmus 		fCurrentMarkValue++;
631bc679b60SStephan Aßmus }
632bc679b60SStephan Aßmus 
63398b054feSJohn Scipione 
634bc679b60SStephan Aßmus void
_Trace(FRACTAL * F,int32 xo,int32 yo)635bc679b60SStephan Aßmus IFS::_Trace(FRACTAL* F, int32 xo, int32 yo)
636bc679b60SStephan Aßmus {
63798b054feSJohn Scipione 	int32 x;
63898b054feSJohn Scipione 	int32 y;
63998b054feSJohn Scipione 	SIMILITUDE* Current;
640bc679b60SStephan Aßmus 
64198b054feSJohn Scipione 	Current = fCurrentFractal->Components;
64298b054feSJohn Scipione 	for (int32 i = fCurrentFractal->SimilitudeCount; i; --i, Current++) {
64398b054feSJohn Scipione 		transform(Current, xo, yo, &x, &y);
644bc679b60SStephan Aßmus 		fPointBuffer->x = (UNIT * 2 + x) * F->Lx / (UNIT * 2);
645bc679b60SStephan Aßmus 		fPointBuffer->y = (UNIT * 2 - y) * F->Ly / (UNIT * 2);
646bc679b60SStephan Aßmus 		fPointBuffer++;
647bc679b60SStephan Aßmus 		fCurrentPoint++;
648bc679b60SStephan Aßmus 
649bc679b60SStephan Aßmus 		if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
650bc679b60SStephan Aßmus 			F->Depth--;
651bc679b60SStephan Aßmus 			_Trace(F, x, y);
652bc679b60SStephan Aßmus 			F->Depth++;
653bc679b60SStephan Aßmus 		}
654bc679b60SStephan Aßmus 	}
655bc679b60SStephan Aßmus }
656bc679b60SStephan Aßmus 
65798b054feSJohn Scipione 
658bc679b60SStephan Aßmus void
_RandomSimilitudes(FRACTAL * fractal,SIMILITUDE * current,int i) const65998b054feSJohn Scipione IFS::_RandomSimilitudes(FRACTAL* fractal, SIMILITUDE* current, int i) const
660bc679b60SStephan Aßmus {
66198b054feSJohn Scipione 	while (i-- > 0) {
66298b054feSJohn Scipione 		current->c_x = gauss_rand(0.0, .8, 4.0);
66398b054feSJohn Scipione 		current->c_y = gauss_rand(0.0, .8, 4.0);
66498b054feSJohn Scipione 		current->r   = gauss_rand(fractal->r_mean, fractal->dr_mean, 3.0);
66598b054feSJohn Scipione 		current->r2  = half_gauss_rand(0.0,fractal->dr2_mean, 2.0);
66698b054feSJohn Scipione 		current->A   = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
66798b054feSJohn Scipione 		current->A2  = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
66898b054feSJohn Scipione 		current++;
669bc679b60SStephan Aßmus 	}
670bc679b60SStephan Aßmus }
671bc679b60SStephan Aßmus 
67298b054feSJohn Scipione 
673bc679b60SStephan Aßmus void
_FreeBuffers(FRACTAL * f)674bc679b60SStephan Aßmus IFS::_FreeBuffers(FRACTAL* f)
675bc679b60SStephan Aßmus {
676bc679b60SStephan Aßmus 	if (f->buffer1) {
677bc679b60SStephan Aßmus 		free((void*)f->buffer1);
678bc679b60SStephan Aßmus 		f->buffer1 = (Point*)NULL;
679bc679b60SStephan Aßmus 	}
68098b054feSJohn Scipione 
681bc679b60SStephan Aßmus 	if (f->buffer2) {
682bc679b60SStephan Aßmus 		free((void*)f->buffer2);
683bc679b60SStephan Aßmus 		f->buffer2 = (Point*)NULL;
684bc679b60SStephan Aßmus 	}
685bc679b60SStephan Aßmus }
686bc679b60SStephan Aßmus 
68798b054feSJohn Scipione 
688bc679b60SStephan Aßmus void
_FreeIFS(FRACTAL * f)689bc679b60SStephan Aßmus IFS::_FreeIFS(FRACTAL* f)
690bc679b60SStephan Aßmus {
691bc679b60SStephan Aßmus 	_FreeBuffers(f);
692bc679b60SStephan Aßmus 	delete f->bitmap;
693bc679b60SStephan Aßmus 	f->bitmap = NULL;
694bc679b60SStephan Aßmus 	delete f->markBitmap;
695bc679b60SStephan Aßmus 	f->markBitmap = NULL;
696bc679b60SStephan Aßmus }
697