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