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