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 : fRoot(NULL), 151 fAdditive(false), 152 fCurrentMarkValue(1) 153 { 154 ya_rand_init(system_time()); 155 156 int i; 157 FRACTAL *Fractal; 158 159 if (fRoot == NULL) { 160 fRoot = (FRACTAL*) calloc(1, sizeof (FRACTAL)); 161 if (fRoot == NULL) 162 return; 163 } 164 Fractal = fRoot; 165 166 _FreeBuffers(Fractal); 167 i = (NRAND(4)) + 2; // Number of centers 168 switch (i) { 169 case 3: 170 Fractal->Depth = fAdditive ? MAX_DEPTH_3 + 1 : MAX_DEPTH_3; 171 Fractal->r_mean = .6; 172 Fractal->dr_mean = .4; 173 Fractal->dr2_mean = .3; 174 break; 175 176 case 4: 177 Fractal->Depth = MAX_DEPTH_4; 178 Fractal->r_mean = .5; 179 Fractal->dr_mean = .4; 180 Fractal->dr2_mean = .3; 181 break; 182 183 case 5: 184 Fractal->Depth = MAX_DEPTH_5; 185 Fractal->r_mean = .5; 186 Fractal->dr_mean = .4; 187 Fractal->dr2_mean = .3; 188 break; 189 190 default: 191 case 2: 192 Fractal->Depth = fAdditive ? MAX_DEPTH_2 + 1 : MAX_DEPTH_2; 193 Fractal->r_mean = .7; 194 Fractal->dr_mean = .3; 195 Fractal->dr2_mean = .4; 196 break; 197 } 198 // fprintf( stderr, "N=%d\n", i ); 199 Fractal->Nb_Simi = i; 200 Fractal->Max_Pt = Fractal->Nb_Simi - 1; 201 for (i = 0; i <= Fractal->Depth + 2; ++i) 202 Fractal->Max_Pt *= Fractal->Nb_Simi; 203 204 if ((Fractal->buffer1 = (Point *) calloc(Fractal->Max_Pt, 205 sizeof (Point))) == NULL) { 206 _FreeIFS(Fractal); 207 return; 208 } 209 if ((Fractal->buffer2 = (Point *) calloc(Fractal->Max_Pt, 210 sizeof (Point))) == NULL) { 211 _FreeIFS(Fractal); 212 return; 213 } 214 Fractal->Speed = 6; 215 #if HALF 216 Fractal->Width = bounds.IntegerWidth() / 2 + 1; 217 Fractal->Height = bounds.IntegerHeight() / 2 + 1; 218 #else 219 Fractal->Width = bounds.IntegerWidth() + 1; 220 Fractal->Height = bounds.IntegerHeight() + 1; 221 #endif 222 Fractal->Cur_Pt = 0; 223 Fractal->Count = 0; 224 Fractal->Lx = (Fractal->Width - 1) / 2; 225 Fractal->Ly = (Fractal->Height - 1) / 2; 226 Fractal->Col = NRAND(Fractal->Width * Fractal->Height - 1) + 1; 227 228 _RandomSimis(Fractal, Fractal->Components, 5 * MAX_SIMI); 229 230 delete Fractal->bitmap; 231 Fractal->bitmap = new (nothrow) BBitmap(BRect(0.0, 0.0, 232 Fractal->Width - 1, 233 Fractal->Height - 1), 234 0, 235 B_RGB32); 236 delete Fractal->markBitmap; 237 Fractal->markBitmap = new (nothrow) BBitmap(BRect(0.0, 0.0, 238 Fractal->Width - 1, 239 Fractal->Height - 1), 240 0, 241 B_GRAY8); 242 // Allocation checked 243 if (Fractal->bitmap != NULL && Fractal->bitmap->IsValid()) { 244 memset(Fractal->bitmap->Bits(), 0, Fractal->bitmap->BitsLength()); 245 } else { 246 delete Fractal->bitmap; 247 Fractal->bitmap = NULL; 248 } 249 if (Fractal->markBitmap != NULL && Fractal->markBitmap->IsValid()) { 250 memset(Fractal->markBitmap->Bits(), 0, Fractal->markBitmap->BitsLength()); 251 } else { 252 delete Fractal->markBitmap; 253 Fractal->markBitmap = NULL; 254 } 255 } 256 257 // destructor 258 IFS::~IFS() 259 { 260 if (fRoot != NULL) { 261 _FreeIFS(fRoot); 262 free((void*) fRoot); 263 } 264 } 265 266 // Draw 267 void 268 IFS::Draw(BView* view, const buffer_info* info, int32 frames) 269 { 270 //bigtime_t now = system_time(); 271 int i; 272 float u, uu, v, vv, u0, u1, u2, u3; 273 SIMI *S, *S1, *S2, *S3, *S4; 274 FRACTAL *F; 275 276 if (fRoot == NULL) 277 return; 278 F = fRoot; 279 if (F->buffer1 == NULL) 280 return; 281 282 //if (frames > 1) 283 // printf("skipping %ld frames\n", frames); 284 285 // do this as many times as necessary to calculate the missing frames 286 // so the animation doesn't jerk when we miss a few frames 287 for (int32 frame = 0; frame < frames; frame++) { 288 289 u = (float) (F->Count) * (float) (F->Speed) / 1000.0; 290 uu = u * u; 291 v = 1.0 - u; 292 vv = v * v; 293 u0 = vv * v; 294 u1 = 3.0 * vv * u; 295 u2 = 3.0 * v * uu; 296 u3 = u * uu; 297 298 S = F->Components; 299 S1 = S + F->Nb_Simi; 300 S2 = S1 + F->Nb_Simi; 301 S3 = S2 + F->Nb_Simi; 302 S4 = S3 + F->Nb_Simi; 303 304 for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) { 305 S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x; 306 S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y; 307 S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r; 308 S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2; 309 S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A; 310 S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2; 311 } 312 313 //bigtime_t beforeDraw = system_time(); 314 if (frame == frames - 1) 315 _DrawFractal(view, info); 316 317 //bigtime_t draw = system_time() - beforeDraw; 318 319 if (F->Count >= 1000 / F->Speed) { 320 S = F->Components; 321 S1 = S + F->Nb_Simi; 322 S2 = S1 + F->Nb_Simi; 323 S3 = S2 + F->Nb_Simi; 324 S4 = S3 + F->Nb_Simi; 325 326 for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) { 327 S2->c_x = 2.0 * S4->c_x - S3->c_x; 328 S2->c_y = 2.0 * S4->c_y - S3->c_y; 329 S2->r = 2.0 * S4->r - S3->r; 330 S2->r2 = 2.0 * S4->r2 - S3->r2; 331 S2->A = 2.0 * S4->A - S3->A; 332 S2->A2 = 2.0 * S4->A2 - S3->A2; 333 334 *S1 = *S4; 335 } 336 _RandomSimis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi); 337 338 _RandomSimis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi); 339 340 F->Count = 0; 341 } else 342 F->Count++; 343 // F->Col++; 344 //bigtime_t finish = (system_time() - now) - draw; 345 //if (info) 346 //printf("draw: %lld\nnon-draw: %lld\n\n", draw, finish); 347 } 348 349 } 350 351 // SetAdditive 352 void 353 IFS::SetAdditive(bool additive) 354 { 355 fAdditive = additive; 356 } 357 358 // SetSpeed 359 void 360 IFS::SetSpeed(int32 speed) 361 { 362 if (fRoot && speed > 0 && speed <= 12) 363 fRoot->Speed = speed; 364 } 365 366 // Draw 367 void 368 IFS::_DrawFractal(BView* view, const buffer_info* info) 369 { 370 FRACTAL* F = fRoot; 371 int i, j; 372 int32 x, y, xo, yo; 373 SIMI* Cur, *Simi; 374 375 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) { 376 Cur->Cx = FLOAT_TO_INT(Cur->c_x); 377 Cur->Cy = FLOAT_TO_INT(Cur->c_y); 378 379 Cur->Ct = FLOAT_TO_INT(cos(Cur->A)); 380 Cur->St = FLOAT_TO_INT(sin(Cur->A)); 381 Cur->Ct2 = FLOAT_TO_INT(cos(Cur->A2)); 382 Cur->St2 = FLOAT_TO_INT(sin(Cur->A2)); 383 384 Cur->R = FLOAT_TO_INT(Cur->r); 385 Cur->R2 = FLOAT_TO_INT(Cur->r2); 386 } 387 388 389 fCurrentPoint = 0; 390 fCurrentFractal = F; 391 fPointBuffer = F->buffer2; 392 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) { 393 xo = Cur->Cx; 394 yo = Cur->Cy; 395 for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) { 396 if (Simi == Cur) 397 continue; 398 transform(Simi, xo, yo, &x, &y); 399 _Trace(F, x, y); 400 } 401 } 402 403 if (F->bitmap != NULL && F->markBitmap != NULL) { 404 uint8* bits = (uint8*)F->bitmap->Bits(); 405 uint32 bpr = F->bitmap->BytesPerRow(); 406 uint8* markBits = (uint8*)F->markBitmap->Bits(); 407 uint32 markBPR = F->markBitmap->BytesPerRow(); 408 int32 minX = F->Width; 409 int32 minY = F->Height; 410 int32 maxX = 0; 411 int32 maxY = 0; 412 // Erase previous dots from bitmap, 413 // but only if we're not in BDirectWindow mode, 414 // since the dots will have been erased already 415 if (!info) { 416 if (F->Cur_Pt) { 417 for (int32 i = 0; i < F->Cur_Pt; i++) { 418 Point p = F->buffer1[i]; 419 if (p.x >= 0 && p.x < F->Width 420 && p.y >= 0 && p.y < F->Height) { 421 int32 offset = bpr * p.y + p.x * 4; 422 *(uint32*)&bits[offset] = 0; 423 if (minX > p.x) 424 minX = p.x; 425 if (minY > p.y) 426 minY = p.y; 427 if (maxX < p.x) 428 maxX = p.x; 429 if (maxY < p.y) 430 maxY = p.y; 431 } 432 } 433 } 434 } 435 // draw the new dots into the bitmap 436 if (fCurrentPoint) { 437 if (info) { 438 for (int32 i = 0; i < fCurrentPoint; i++) { 439 Point p = F->buffer2[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 if (fAdditive) { 444 if (bits[offset + 0] < 255) { 445 bits[offset + 0] += 51; 446 bits[offset + 1] += 51; 447 bits[offset + 2] += 51; 448 } 449 } else { 450 *(uint32*)&bits[offset] = 0xffffffff; 451 } 452 } 453 } 454 } else { 455 // in this version, remember the bounds rectangle 456 for (int32 i = 0; i < fCurrentPoint; i++) { 457 Point p = F->buffer2[i]; 458 if (p.x >= 0 && p.x < F->Width 459 && p.y >= 0 && p.y < F->Height) { 460 int32 offset = bpr * p.y + p.x * 4; 461 if (fAdditive) { 462 if (bits[offset + 0] < 255) { 463 bits[offset + 0] += 15; 464 bits[offset + 1] += 15; 465 bits[offset + 2] += 15; 466 } 467 } else { 468 *(uint32*)&bits[offset] = 0xffffffff; 469 } 470 if (minX > p.x) 471 minX = p.x; 472 if (minY > p.y) 473 minY = p.y; 474 if (maxX < p.x) 475 maxX = p.x; 476 if (maxY < p.y) 477 maxY = p.y; 478 } 479 } 480 } 481 } 482 if (info && info->bits) { 483 484 uint8* screenBits = (uint8*)info->bits; 485 uint32 screenBPR = info->bytesPerRow; 486 int32 left = info->bounds.left; 487 int32 top = info->bounds.top; 488 int32 bpp = info->bits_per_pixel; 489 screenBits += left * bpp + top * bpr; 490 491 int32 screenWidth = info->bounds.right - left; 492 int32 screenHeight = info->bounds.bottom - top; 493 494 //printf("using BDirectWindow (%p %dx%d)\n", this, F->Width, F->Height); 495 // redraw the previous points on screen 496 // with the contents of the current bitmap 497 // 498 // draw the new points, erasing the bitmap as we go 499 int32 maxPoints = max_c(F->Cur_Pt, fCurrentPoint); 500 if (maxPoints > 0) { 501 502 // BScreen screen(B_MAIN_SCREEN_ID); 503 // screen.WaitForRetrace(); 504 505 for (int32 i = 0; i < maxPoints; i++) { 506 // copy previous points (black) 507 if (i < F->Cur_Pt) { 508 Point p = F->buffer1[i]; 509 if (p.x >= 0 && p.x < F->Width && p.x < screenWidth 510 && p.y >= 0 && p.y < F->Height && p.y < screenHeight) { 511 int32 markOffset = markBPR * p.y + p.x; 512 if (markBits[markOffset] != fCurrentMarkValue) { 513 int32 offset = bpr * p.y + p.x * 4; 514 // copy the pixel to the screen 515 uint32* src = (uint32*)&bits[offset]; 516 if (bpp == 32) { 517 int32 screenOffset = screenBPR * p.y + p.x * 4; 518 *(uint32*)&screenBits[screenOffset] = *src; 519 } else if (bpp == 16) { 520 int32 screenOffset = screenBPR * p.y + p.x * 2; 521 *(uint16*)&screenBits[screenOffset] = 522 (uint16)(((bits[offset + 2] & 0xf8) << 8) | 523 ((bits[offset + 1] & 0xfc) << 3) | 524 (bits[offset] >> 3)); 525 } else if (bpp == 15) { 526 int32 screenOffset = screenBPR * p.y + p.x * 2; 527 *(uint16*)&screenBits[screenOffset] = 528 (uint16)(((bits[offset + 2] & 0xf8) << 7) | 529 ((bits[offset + 1] & 0xf8) << 2) | 530 (bits[offset] >> 3)); 531 } else if (bpp == 8) { 532 int32 screenOffset = screenBPR * p.y + p.x; 533 screenBits[screenOffset] = bits[offset]; 534 } 535 *src = 0; 536 markBits[markOffset] = fCurrentMarkValue; 537 } // else it means the pixel has been copied already 538 } 539 } 540 // copy current points (white) and erase them from the bitmap 541 if (i < fCurrentPoint) { 542 Point p = F->buffer2[i]; 543 if (p.x >= 0 && p.x < F->Width && p.x < screenWidth 544 && p.y >= 0 && p.y < F->Height && p.y < screenHeight) { 545 int32 markOffset = markBPR * p.y + p.x; 546 int32 offset = bpr * p.y + p.x * 4; 547 // copy the pixel to the screen 548 uint32* src = (uint32*)&bits[offset]; 549 if (markBits[markOffset] != fCurrentMarkValue) { 550 if (bpp == 32) { 551 int32 screenOffset = screenBPR * p.y + p.x * 4; 552 *(uint32*)&screenBits[screenOffset] = *src; 553 } else if (bpp == 16) { 554 int32 screenOffset = screenBPR * p.y + p.x * 2; 555 *(uint16*)&screenBits[screenOffset] = 556 (uint16)(((bits[offset + 2] & 0xf8) << 8) | 557 ((bits[offset + 1] & 0xfc) << 3) | 558 (bits[offset] >> 3)); 559 } else if (bpp == 15) { 560 int32 screenOffset = screenBPR * p.y + p.x * 2; 561 *(uint16*)&screenBits[screenOffset] = 562 (uint16)(((bits[offset + 2] & 0xf8) << 7) | 563 ((bits[offset + 1] & 0xf8) << 2) | 564 (bits[offset] >> 3)); 565 } else if (bpp == 1) { 566 int32 screenOffset = screenBPR * p.y + p.x; 567 screenBits[screenOffset] = bits[offset]; 568 } 569 markBits[markOffset] = fCurrentMarkValue; 570 } // else it means the pixel has been copied already 571 *src = 0; 572 } 573 } 574 } 575 } 576 } else { 577 //printf("using BView (%p %dx%d)\n", this, F->Width, F->Height); 578 // if not in BDirectWindow mode, draw the bitmap 579 BRect b(minX, minY, maxX, maxY); 580 view->DrawBitmapAsync(F->bitmap, b, b); 581 } 582 } 583 584 // flip buffers 585 F->Cur_Pt = fCurrentPoint; 586 fPointBuffer = F->buffer1; 587 F->buffer1 = F->buffer2; 588 F->buffer2 = fPointBuffer; 589 if (fCurrentMarkValue == 255) 590 fCurrentMarkValue = 0; 591 else 592 fCurrentMarkValue++; 593 } 594 595 // _Trace 596 void 597 IFS::_Trace(FRACTAL* F, int32 xo, int32 yo) 598 { 599 int32 x, y, i; 600 SIMI* Cur; 601 602 Cur = fCurrentFractal->Components; 603 for (i = fCurrentFractal->Nb_Simi; i; --i, Cur++) { 604 transform(Cur, xo, yo, &x, &y); 605 // fPointBuffer->x = F->Lx + (x * F->Lx / (UNIT * 2)); 606 // fPointBuffer->y = F->Ly - (y * F->Ly / (UNIT * 2)); 607 fPointBuffer->x = (UNIT * 2 + x) * F->Lx / (UNIT * 2); 608 fPointBuffer->y = (UNIT * 2 - y) * F->Ly / (UNIT * 2); 609 fPointBuffer++; 610 fCurrentPoint++; 611 612 if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) { 613 F->Depth--; 614 _Trace(F, x, y); 615 F->Depth++; 616 } 617 } 618 } 619 620 // _RandomSimis 621 void 622 IFS::_RandomSimis(FRACTAL* f, SIMI* cur, int i) const 623 { 624 while (i--) { 625 cur->c_x = gauss_rand(0.0, .8, 4.0); 626 cur->c_y = gauss_rand(0.0, .8, 4.0); 627 cur->r = gauss_rand(f->r_mean, f->dr_mean, 3.0); 628 cur->r2 = half_gauss_rand(0.0,f->dr2_mean, 2.0); 629 cur->A = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0); 630 cur->A2 = gauss_rand(0.0, 360.0, 4.0) * (M_PI / 180.0); 631 cur++; 632 } 633 } 634 635 // _FreeBuffers 636 void 637 IFS::_FreeBuffers(FRACTAL *f) 638 { 639 if (f->buffer1) { 640 free((void*) f->buffer1); 641 f->buffer1 = (Point*)NULL; 642 } 643 if (f->buffer2) { 644 free((void*) f->buffer2); 645 f->buffer2 = (Point*)NULL; 646 } 647 } 648 649 // _FreeIFS 650 void 651 IFS::_FreeIFS(FRACTAL* f) 652 { 653 _FreeBuffers(f); 654 delete f->bitmap; 655 f->bitmap = NULL; 656 delete f->markBitmap; 657 f->markBitmap = NULL; 658 } 659 660 661 662