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