2 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
3 * Copyright 2006-2014, Haiku, Inc. All rights reserved.
5 * Distributed under the terms of the MIT License.
8 * Stephan Aßmus, superstippi@gmx.de
9 * Massimino Pascal, Pascal.Massimon@ens.fr
10 * John Scipione, jscipione@gmail.com
13 /*! When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
35 #define random() ya_random()
36 #define RAND_MAX 0xFFFFFFFF
38 #define FLOAT_TO_INT(x) (int32)((float)(UNIT)*(x))
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
45 // already seeded by screenhack.c TODO: ?!? is it?
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.
52 #define VECTOR_SIZE 55
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
76 register int ret
= a
[i1
] + a
[i2
];
78 if (++i1
>= VECTOR_SIZE
)
81 if (++i2
>= VECTOR_SIZE
)
89 ya_rand_init(unsigned int seed
)
95 gettimeofday(&tp
, &tzp
);
97 seed
= (999*tp
.tv_sec
) + (1001*tp
.tv_usec
) + (1003 * getpid());
101 for (i
= 1; i
< VECTOR_SIZE
; i
++) {
102 seed
= a
[i
-1]*1001 + seed
*999;
106 i1
= a
[0] % VECTOR_SIZE
;
107 i2
= (i1
+ 024) % VECTOR_SIZE
;
113 gauss_rand(float c
, float A
, float S
)
115 float y
= (float) LRAND() / MAXRAND
;
116 y
= A
* (1.0 - exp(-y
* y
* S
)) / (1.0 - exp(-S
));
125 half_gauss_rand(float c
, float A
, float S
)
127 float y
= (float) LRAND() / MAXRAND
;
128 y
= A
* (1.0 - exp(-y
* y
* S
)) / (1.0 - exp(-S
));
135 transform(SIMILITUDE
* Similitude
, int32 xo
, int32 yo
, int32
* x
, int32
* y
)
140 xo
= xo
- Similitude
->Cx
;
141 xo
= (xo
* Similitude
->R
) / UNIT
;
142 yo
= yo
- Similitude
->Cy
;
143 yo
= (yo
* Similitude
->R
) / UNIT
;
145 xx
= xo
- Similitude
->Cx
;
146 xx
= (xx
* Similitude
->R2
) / UNIT
;
147 yy
= -yo
- Similitude
->Cy
;
148 yy
= (yy
* Similitude
->R2
) / UNIT
;
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
;
158 IFS::IFS(BRect bounds
)
161 fCurrentFractal(NULL
),
167 if (!bounds
.IsValid())
170 ya_rand_init(system_time());
176 fRoot
= (FRACTAL
*)calloc(1, sizeof(FRACTAL
));
182 _FreeBuffers(Fractal
);
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;
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;
202 Fractal
->Depth
= MAX_DEPTH_4
;
203 Fractal
->r_mean
= 0.5;
204 Fractal
->dr_mean
= 0.4;
205 Fractal
->dr2_mean
= 0.3;
209 Fractal
->Depth
= MAX_DEPTH_5
;
210 Fractal
->r_mean
= 0.5;
211 Fractal
->dr_mean
= 0.4;
212 Fractal
->dr2_mean
= 0.3;
216 Fractal
->SimilitudeCount
= i
;
217 Fractal
->MaxPoint
= Fractal
->SimilitudeCount
- 1;
218 for (i
= 0; i
<= Fractal
->Depth
+ 2; ++i
)
219 Fractal
->MaxPoint
*= Fractal
->SimilitudeCount
;
221 if ((Fractal
->buffer1
= (Point
*)calloc(Fractal
->MaxPoint
,
222 sizeof(Point
))) == NULL
) {
226 if ((Fractal
->buffer2
= (Point
*)calloc(Fractal
->MaxPoint
,
227 sizeof(Point
))) == NULL
) {
233 Fractal
->Width
= bounds
.IntegerWidth() / 2 + 1;
234 Fractal
->Height
= bounds
.IntegerHeight() / 2 + 1;
236 Fractal
->Width
= bounds
.IntegerWidth() + 1;
237 Fractal
->Height
= bounds
.IntegerHeight() + 1;
239 Fractal
->CurrentPoint
= 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;
245 _RandomSimilitudes(Fractal
, Fractal
->Components
, 5 * MAX_SIMILITUDE
);
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
);
254 // allocation checked
255 if (Fractal
->bitmap
!= NULL
&& Fractal
->bitmap
->IsValid())
256 memset(Fractal
->bitmap
->Bits(), 0, Fractal
->bitmap
->BitsLength());
258 delete Fractal
->bitmap
;
259 Fractal
->bitmap
= NULL
;
262 if (Fractal
->markBitmap
!= NULL
&& Fractal
->markBitmap
->IsValid()) {
263 memset(Fractal
->markBitmap
->Bits(), 0,
264 Fractal
->markBitmap
->BitsLength());
266 delete Fractal
->markBitmap
;
267 Fractal
->markBitmap
= NULL
;
282 IFS::Draw(BView
* view
, const buffer_info
* info
, int32 frames
)
304 if (F
->buffer1
== NULL
)
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;
320 S1
= S
+ F
->SimilitudeCount
;
321 S2
= S1
+ F
->SimilitudeCount
;
322 S3
= S2
+ F
->SimilitudeCount
;
323 S4
= S3
+ F
->SimilitudeCount
;
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
;
334 if (frame
== frames
- 1)
335 _DrawFractal(view
, info
);
337 if (F
->Count
>= 1000 / F
->Speed
) {
339 S1
= S
+ F
->SimilitudeCount
;
340 S2
= S1
+ F
->SimilitudeCount
;
341 S3
= S2
+ F
->SimilitudeCount
;
342 S4
= S3
+ F
->SimilitudeCount
;
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
;
354 _RandomSimilitudes(F
, F
->Components
+ 3 * F
->SimilitudeCount
,
356 _RandomSimilitudes(F
, F
->Components
+ 4 * F
->SimilitudeCount
,
367 IFS::SetAdditive(bool additive
)
369 fAdditive
= additive
;
374 IFS::SetSpeed(int32 speed
)
376 if (fRoot
&& speed
> 0 && speed
<= 12)
377 fRoot
->Speed
= speed
;
382 IFS::_DrawFractal(BView
* view
, const buffer_info
* info
)
392 SIMILITUDE
* Similitude
;
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
);
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
));
403 Current
->R
= FLOAT_TO_INT(Current
->r
);
404 Current
->R2
= FLOAT_TO_INT(Current
->r2
);
409 fPointBuffer
= F
->buffer2
;
410 for (Current
= F
->Components
, i
= F
->SimilitudeCount
; i
; --i
, Current
++) {
413 for (Similitude
= F
->Components
, j
= F
->SimilitudeCount
; j
;
415 if (Similitude
== Current
)
418 transform(Similitude
, xo
, yo
, &x
, &y
);
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
;
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
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;
460 // draw the new dots into the bitmap
461 if (fCurrentPoint
!= 0) {
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;
469 if (bits
[offset
+ 0] < 255) {
470 bits
[offset
+ 0] += 51;
471 bits
[offset
+ 1] += 51;
472 bits
[offset
+ 2] += 51;
475 *(uint32
*)&bits
[offset
] = 0xffffffff;
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;
486 if (bits
[offset
+ 0] < 255) {
487 bits
[offset
+ 0] += 15;
488 bits
[offset
+ 1] += 15;
489 bits
[offset
+ 2] += 15;
492 *(uint32
*)&bits
[offset
] = 0xffffffff;
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
;
518 int32 screenWidth
= info
->bounds
.right
- left
;
519 int32 screenHeight
= info
->bounds
.bottom
- top
;
521 // redraw the previous points on screen
522 // with the contents of the current bitmap
524 // draw the new points, erasing the bitmap as we go
525 int32 maxPoints
= max_c(F
->CurrentPoint
, fCurrentPoint
);
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
];
540 int32 screenOffset
= screenBPR
* p
.y
542 *(uint32
*)&screenBits
[screenOffset
] = *src
;
543 } else if (bpp
== 16) {
544 int32 screenOffset
= screenBPR
* p
.y
546 *(uint16
*)&screenBits
[screenOffset
] =
547 (uint16
)(((bits
[offset
+ 2] & 0xf8)
549 | ((bits
[offset
+ 1] & 0xfc) << 3)
550 | (bits
[offset
] >> 3));
551 } else if (bpp
== 15) {
552 int32 screenOffset
= screenBPR
* p
.y
554 *(uint16
*)&screenBits
[screenOffset
] =
555 (uint16
)(((bits
[offset
+ 2] & 0xf8)
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
];
564 markBits
[markOffset
] = fCurrentMarkValue
;
566 // else it means the pixel has been copied already
570 // copy current points (white) and erase them from the
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;
580 // copy the pixel to the screen
581 uint32
* src
= (uint32
*)&bits
[offset
];
582 if (markBits
[markOffset
] != fCurrentMarkValue
) {
584 int32 screenOffset
= screenBPR
* p
.y
586 *(uint32
*)&screenBits
[screenOffset
] = *src
;
587 } else if (bpp
== 16) {
588 int32 screenOffset
= screenBPR
* p
.y
590 *(uint16
*)&screenBits
[screenOffset
] =
591 (uint16
)(((bits
[offset
+ 2] & 0xf8)
593 | ((bits
[offset
+ 1] & 0xfc) << 3)
594 | (bits
[offset
] >> 3));
595 } else if (bpp
== 15) {
596 int32 screenOffset
= screenBPR
* p
.y
598 *(uint16
*)&screenBits
[screenOffset
] =
599 (uint16
)(((bits
[offset
+ 2] & 0xf8)
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
];
607 markBits
[markOffset
] = fCurrentMarkValue
;
609 // else it means the pixel has been copied already
616 // if not in BDirectWindow mode, draw the bitmap
617 BRect
b(minX
, minY
, maxX
, maxY
);
618 view
->DrawBitmapAsync(F
->bitmap
, b
, b
);
623 F
->CurrentPoint
= fCurrentPoint
;
624 fPointBuffer
= F
->buffer1
;
625 F
->buffer1
= F
->buffer2
;
626 F
->buffer2
= fPointBuffer
;
628 if (fCurrentMarkValue
== 255)
629 fCurrentMarkValue
= 0;
636 IFS::_Trace(FRACTAL
* F
, int32 xo
, int32 yo
)
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);
650 if (F
->Depth
&& ((x
- xo
) >> 4) && ((y
- yo
) >> 4)) {
660 IFS::_RandomSimilitudes(FRACTAL
* fractal
, SIMILITUDE
* current
, int i
) const
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);
675 IFS::_FreeBuffers(FRACTAL
* f
)
678 free((void*)f
->buffer1
);
679 f
->buffer1
= (Point
*)NULL
;
683 free((void*)f
->buffer2
);
684 f
->buffer2
= (Point
*)NULL
;
690 IFS::_FreeIFS(FRACTAL
* f
)
695 delete f
->markBitmap
;
696 f
->markBitmap
= NULL
;