#include <fracfill.h>
Inheritance diagram for PlasmaFractalFill:
Public Member Functions | |
PlasmaFractalFill (INT32 tSeed=0, BOOL tTileable=TRUE, fixed16 tSquash=0, fixed16 tGraininess=1, fixed16 tGravity=0) | |
Constructor for a PlasmaFractalFill. | |
BOOL | DoFill (KernelBitmap *pBitmap, INT32 Dimension=0, INT32 tOx=0, INT32 tOy=0) |
Fills the 8 bit bitmap passed with the fractal requested. | |
Static Public Member Functions | |
static INT32 | GetDimension (INT32 x, INT32 y) |
Returns required dimension of virtual fractal. | |
static void | Test (KernelBitmap *pB, INT32 tSeed=0, BOOL tTileable=TRUE, fixed16 tSquash=0, fixed16 tGraininess=1, fixed16 tGravity=0) |
Private Member Functions | |
CC_DECLARE_DYNCREATE (PlasmaFractalFill) | |
BOOL | SubDivide (INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 p11, INT32 p12, INT32 p21, INT32 p22, BOOL PlotNow) |
INT32 | Adjust (INT32 pa, INT32 pb, INT32 x, INT32 y, INT32 aGraininess, INT32 aGravity) |
Linterpolates between potentials at (xa, ya, xb, yb) adding a random peturbation. | |
void | SetSeed (INT32 NewSeed) |
Sets the random number seed of our fabby platform independent random number generator. Actually the seed is 33 bits long and we only allow half those values to be set. I don't think anyone will notice though :-). | |
INT32 | GetRandom () |
Private Attributes | |
KernelBitmap * | pBitmap |
INT32 | Seed |
UINT32 | CurrentSeed |
UINT32 | CurrentSeed2 |
INT32 | EigenValue |
UINT32 | xGraininess |
UINT32 | yGraininess |
UINT32 | xGravity |
UINT32 | yGravity |
UINT32 | CoordinateMask |
INT32 | MaxPotential |
INT32 | RecursionLevel |
INT32 | Width |
INT32 | Height |
INT32 | Ox |
INT32 | Oy |
fixed16 | Squash |
BOOL | ForceCornersToZero |
BOOL | Tileable |
Definition at line 118 of file fracfill.h.
|
Constructor for a PlasmaFractalFill.
If Squash is zero, no squashing is done. If it is negative, the image is XSquashed, and if it is positive, the image is YSquashed. Squashing only works if Tileable is set (unless you want the special grey morass effect). Definition at line 441 of file fracfill.cpp. 00448 { 00449 MaxPotential = (1<<16)-1; // *** DON'T CHANGE WITHOUT CHANGING THE 00450 // EQUATE IN FastFractalAdjust 00451 00452 pBitmap = NULL; 00453 Seed = tSeed; 00454 ForceCornersToZero = (tGravity != 0); 00455 Tileable = tTileable; 00456 Squash = tSquash; 00457 00458 if (Tileable) 00459 { 00460 CoordinateMask = MAX_FRACTAL_COORD - 1; 00461 } 00462 else 00463 { 00464 CoordinateMask = 0xffffffff; 00465 } 00466 00467 xGravity = yGravity = (UINT32) (tGravity.MakeDouble() * MaxPotential); 00468 xGraininess = yGraininess = (UINT32) (tGraininess.MakeDouble() * 8 + 0.5); 00469 00470 if (Squash > 0) 00471 { 00472 xGravity = (UINT32) ( ((tGravity.MakeDouble() * MaxPotential) / Squash.MakeDouble())); 00473 xGraininess = (UINT32) ( ((tGraininess * 8 + 0.5) / Squash).MakeLong()); 00474 } 00475 else if (Squash<0) 00476 { 00477 yGravity = (UINT32) ( ((tGravity.MakeDouble() * MaxPotential) / (-Squash.MakeDouble()))); 00478 yGraininess = (UINT32) ( ((tGraininess * 8 + 0.5) / (-Squash)).MakeLong()); 00479 } 00480 00481 // Limit Graininess to prevent overflow in Adjust 00482 if ( xGraininess < 0 ) xGraininess = 0; 00483 if ( xGraininess > 0xffff ) xGraininess = 0xffff; 00484 if ( yGraininess < 0 ) yGraininess = 0; 00485 if ( yGraininess > 0xffff ) yGraininess = 0xffff; 00486 00487 }
|
|
Linterpolates between potentials at (xa, ya, xb, yb) adding a random peturbation.
Definition at line 213 of file fracfill.cpp. 00216 { 00217 // The squash term only needs to be compared against zero and this disgustingness assumes that the 00218 // representation of (fixed16)0 is hex 0 on all architectures 00219 return FastFractalAdjust(pa, pb, x, y, aGraininess, aGravity, Seed, *((INT32 *)(&Squash)), RecursionLevel); 00220 } 00221 #else 00222 { 00223 // Bodge to pseudorandomate psuedorandomiser from coords alone! 00224 UINT32 topseed=1; 00225 INT32 potential=(pa ^ (pb<<16) ^ _lrotl((UINT32)x,16)^((UINT32) y) ^ Seed ^ 0xABCD1234); 00226 UINT32 t; 00227 DoRand(potential,topseed,t); // Do an initial spin 00228 potential = _lrotl(potential,(x^(x>>5)^(x>>10)^(x>>15)^(x>>20)^(x>>25)^(x>>30)^y^(y>>5)^(y>>10)^(y>>15)^(y>>20)^(y>>25)^(y>>30)) & 31); 00229 DoRand(potential,topseed,t); // random number to potential 00230 00231 // When squashing we only peturb along the edges and the rest is pure linterp. 00232 // (effect of gravity unknown!). At the edges (because of CoordinateMask) one of 00233 // x & y is zero. We can cunningly use the logical operators to make this a quick test. 00234 if ((Squash!=0) && !(x || y)) potential = 0; 00235 00236 // The adjustment is mostly linear interpolation (linterp) (i.e. (pa+pb)/2) but we add: 00237 // 00238 // Peterbation effects: We use a random number scaled by graininess in proportion to the (y1-y2) which 00239 // simply means shifting it right by the recursion level. 00240 // 00241 // Gravitational effects: 00242 // We linterp between y1 and y2. But we want this to look like a parabola. So if xh is the midpoint: 00243 // 00244 // 2 2 2 2 00245 // p1 = a y1 p2 = a y2 ph = a yh = a (y1 + y2) /4 00246 // 00247 // 2 00248 // ph = (p1+p2)/2 - (p1+p2)/2 + a(y1+y2) /4 00249 // 00250 // 2 00251 // ph = (p1+p2)/2 - (a/4)(y1-y2) 00252 // ~~~~~~~~~~~~~ 00253 // 00254 // Thus we must subtract the underlined term to make it look like a parabola. However a is negative 00255 // and we operate using a constant offset as our potential is high in the middle and zero at the edges 00256 // (the same annoyance happens all over potential theory!) so we acually add the term. We get the squared 00257 // term by shifting right by 2xrecursion level. 00258 // 00259 00260 potential = ( ( ((INT32)(aGraininess)) * ((INT32)(potential>>17)) ) >>RecursionLevel) /*peterb*/ 00261 - (aGravity>>(RecursionLevel*2)) /*gravity*/ 00262 + (( pa + pb + 1 ) >> 1 ); /* linterp */ 00263 00264 // Clip potential to max & min 00265 if ( potential > MaxPotential ) potential = MaxPotential; 00266 if ( potential < 0 ) potential = 0; 00267 00268 //if (p!=potential) {TRACEUSER( "Alex", _T("Awooga awooga maths error\n"));} 00269 return(potential); 00270 }
|
|
|
|
Fills the 8 bit bitmap passed with the fractal requested.
0____________________D D| |D | | | ____________|_____ | | | | | | + + + + + | | | | | | | | + + + + + | | <--- The bitmap you pass (dimensions obtained from the bitmap) | Oy|___________|____| | Ox | | | 0|____________________|0 <--- Virtual fractal bitmap dimension D 0 D The area marked with plus signs is plotted. Definition at line 582 of file fracfill.cpp. 00583 { 00584 INT32 i; 00585 INT32 rnd[4]; 00586 BitmapInfo Info; 00587 00588 if ((pBitmap = theBitmap) == NULL) 00589 { 00590 ENSURE(FALSE,"PlasmaFractalFill::DoFill pBitmap is NULL"); 00591 return(FALSE); 00592 } 00593 00594 pBitmap->ActualBitmap->GetInfo(&Info); 00595 Width = Info.PixelWidth; 00596 Height = Info.PixelHeight; 00597 Ox = tOx; 00598 Oy = tOy; 00599 00600 // Dimension zero means 1:1 00601 if (Dimension==0) Dimension=GetDimension(Width,Height); 00602 00603 // Bump width and height up 00604 EigenValue = 0; 00605 while ((Dimension<<EigenValue) < MAX_FRACTAL_COORD) 00606 { 00607 EigenValue++; 00608 } 00609 00610 // This checks Width=Height and they are both MAX_FRACTAL_COORD. If all kernel bitmaps passed in 00611 // fulful this condition then on each subdivision the coordinates will be the same, so the random 00612 // peterurbation will be the same, so the bitmap will be the same. Wow! And thats the fabbiness of 00613 // psuedorandom numbers for you. 00614 if (Dimension<<EigenValue != MAX_FRACTAL_COORD) 00615 TRACE( _T("PlasmaFractalFill::DoFill only generates resolution independent bitmaps if Width==Height==2^n \n")); 00616 00617 // seed random number generator 00618 SetSeed(Seed); 00619 00620 // set corner potentials randomly 00621 for (i=0; i<4; i++) rnd[i]=(INT32)(((((UINT32)GetRandom())>>16)*(UINT32)MaxPotential+(1<<15))>>16); 00622 00623 // When we are not tiling we want to make quite sure we get enough contrast. We take the contrast range across one 00624 // diagonal and make the other diagonal have at least one minus that range. When we are tiling we make the value 00625 // either +1 or -1 00626 00627 if (Tileable && !(ForceCornersToZero)) 00628 { 00629 rnd[0]=0;// (rnd[0]>(MaxPotential/2))?MaxPotential:0; this makes them predictable 00630 } 00631 else 00632 { 00633 INT32 diagdiff1; 00634 INT32 diagdiff2; 00635 short a,b; 00636 // Calculate contrast across diagonals 00637 diagdiff1=Abs(rnd[0]-rnd[2]); 00638 diagdiff2=Abs(rnd[1]-rnd[3]); 00639 // Find smallest one 00640 if (diagdiff1<diagdiff2) 00641 { 00642 a=(rnd[0]<rnd[2])?0:2; 00643 b=2-a; // ab diagonal is 0-2 or 2-0 00644 } 00645 else 00646 { 00647 a=(rnd[1]<rnd[3])?1:3; 00648 b=4-a; // ab diagonal is 1-3 00649 } 00650 // set to how much we want to increase diagdiff by. 00651 diagdiff2=(MaxPotential-diagdiff1) /*new*/ - diagdiff2 /*current*/; 00652 if (diagdiff2>0) 00653 { 00654 rnd[a]-=diagdiff2/2; 00655 rnd[b]+=diagdiff2/2; 00656 } 00657 } 00658 00659 RecursionLevel = 0; 00660 SubDivide(0,0, MAX_FRACTAL_COORD, MAX_FRACTAL_COORD, 00661 ForceCornersToZero?0:rnd[Tileable?0:0], ForceCornersToZero?0:rnd[Tileable?0:1], 00662 ForceCornersToZero?0:rnd[Tileable?0:2], ForceCornersToZero?0:rnd[Tileable?0:3], TRUE ); 00663 00664 return(TRUE); 00665 }
|
|
Returns required dimension of virtual fractal.
This routine returns a suitable set of 'virtual fractal coordinate bounds' (i.e. a size of the theoretical fractal bitmap in pixels if it were plotted unclipped). This is a power of two. This should be used to work out the clipping calculations as the only coordinates the routines know how to deal with are of this sort. If you ask for an inordinately large fractal the return value may be smaller than the input values. Presently this value squared is larger than the physical memory capacity of the platform though You can, of course, use a smaller dimension if (for instance) memory requirements mean you must, but it must be a power of 2. Definition at line 533 of file fracfill.cpp. 00534 { 00535 INT32 Dimension=4; // Minimum 00536 while ((Dimension < MAX_FRACTAL_COORD) && (( Dimension < x) || (Dimension < y))) 00537 Dimension=Dimension<<1; 00538 return(Dimension); 00539 }
|
|
Definition at line 186 of file fracfill.cpp. 00187 { 00188 UINT32 t; 00189 DoRand(CurrentSeed, CurrentSeed2, t); 00190 return((INT32)(CurrentSeed)); 00191 }
|
|
Sets the random number seed of our fabby platform independent random number generator. Actually the seed is 33 bits long and we only allow half those values to be set. I don't think anyone will notice though :-).
Definition at line 147 of file fracfill.cpp. 00148 { 00149 CurrentSeed = (UINT32) NewSeed; 00150 CurrentSeed2 = 1; // Don't use 0 here as (0,0) has sequ length of zero 00151 }
|
|
Definition at line 290 of file fracfill.cpp. 00292 { 00293 INT32 xh, yh; 00294 INT32 ph1, ph2, p1h, p2h, phh; 00295 00296 #ifdef CRUMMYOLDCODE 00297 // First check this square is at least partially within the clip rectangle and thus is worth 00298 // subdividing. It only is NOT worth subdiving if the highest coordinate is too low, or the 00299 // lowest coordinate too high. 00300 00301 if ( (((x2>>EigenValue)-Ox)<0) || (((x1>>EigenValue)-Ox)>Width) 00302 || (((y2>>EigenValue)-Oy)<0) || (((y1>>EigenValue)-Oy)>Height) ) return (TRUE); 00303 00304 // We only ever plot the left hand corner. This implies the right most pixel never gets plotted 00305 // which is fine as the pixels go 0..n-1 and we pass n in as the first coordinate. 00306 // We use UINT32 casting to check the value is both smaller than Width and non-negative. 00307 if ( (PlotNow) && (((UINT32)((x1>>EigenValue)-Ox))<(UINT32)Width) 00308 && (((UINT32)((y1>>EigenValue)-Oy))<(UINT32)Height) ) 00309 pBitmap->PlotPixel((x1>>EigenValue)-Ox, (y1>>EigenValue)-Oy, (PixelGreyscale) ~(p11>>8)); 00310 00311 if ( ( ((x2>>EigenValue)-(x1>>EigenValue)) <2 ) && ( ((y2>>EigenValue)-(y1>>EigenValue)) <2 ) ) return(TRUE); 00312 #else 00313 // See how stupid the VCC optimiser is. OK, I'll do its job for it then. Soon no doubt I'll get round to writing 00314 // this whole thing in assembler 00315 { 00316 INT32 x1e=((x1>>EigenValue)-Ox); // one would hope the optimiser leaves the shift in CX. Oh no it doesn't... 00317 INT32 x2e=((x2>>EigenValue)-Ox); 00318 INT32 y1e=((y1>>EigenValue)-Oy); 00319 INT32 y2e=((y2>>EigenValue)-Oy); 00320 00321 // First check this square is at least partially within the clip rectangle and thus is worth 00322 // subdividing. It only is NOT worth subdiving if the highest coordinate is too low, or the 00323 // lowest coordinate too high. 00324 00325 if ( (x2e<0) || (x1e>Width) 00326 || (y2e<0) || (y1e>Height) ) return (TRUE); 00327 00328 // We only ever plot the left hand corner. This implies the right most pixel never gets plotted 00329 // which is fine as the pixels go 0..n-1 and we pass n in as the first coordinate. 00330 // We use UINT32 casting to check the value is both smaller than Width and non-negative. 00331 if ( (PlotNow) && (((UINT32)x1e)<(UINT32)Width) 00332 && (((UINT32)y1e)<(UINT32)Height) ) 00333 pBitmap->PlotPixel(x1e, y1e, (PixelGreyscale) ~(p11>>8)); 00334 00335 // we cunningly note that ((x2>>EigenValue)-(x1>>EigenValue)) = x2e-x1e 00336 if ( ( (x2e-x1e) <2 ) && ( (y2e-y1e) <2 ) ) return(TRUE); 00337 } 00338 #endif 00339 00340 // Mark the fact we are one recursion level deeper. 00341 RecursionLevel++; 00342 00343 // Calculate the midpoints 00344 xh = (x1+x2)>>1; 00345 yh = (y1+y2)>>1; 00346 00347 /* 00348 This is the way adjust is going to calculate the potential at the midpoints: 00349 00350 x1 xh x2 00351 y2__________|_________y2 00352 |p12 C|ph2 p22| 00353 | | | 00354 | 4 | 3 | 00355 | | | 00356 | | | 00357 yh|D_______E|________B|yh 00358 |p1h |phh p2h| 00359 | | | 00360 | | | 00361 | 1 | 2 | 00362 | | | 00363 y1|p11_____A|ph1___p21|y1 00364 x1 xh x2 00365 00366 Adjust splits each line (in order A, B, C, D) to find the potential at its midpoint adding a random peturbation. 00367 The point E is then calculated as the average of A, B, C & D. As we calculate the potentials at A, B, C, D, E we 00368 plot them. We can then subdivide each smaller square in the order 1, 2, 3, 4. 00369 */ 00370 00371 ph1=Adjust( p11, p21, xh & CoordinateMask, y1 & CoordinateMask, xGraininess, xGravity); 00372 p2h=Adjust( p21, p22, x2 & CoordinateMask, yh & CoordinateMask, yGraininess, yGravity); 00373 ph2=Adjust( p12, p22, xh & CoordinateMask, y2 & CoordinateMask, xGraininess, xGravity); 00374 p1h=Adjust( p11, p12, x1 & CoordinateMask, yh & CoordinateMask, yGraininess, yGravity); 00375 phh = (ph1+p2h+ph2+p1h+2)>>2; 00376 00377 // When we're at the top level under gravity we make the midpoint full potential 00378 if (RecursionLevel==1) 00379 { 00380 if (ForceCornersToZero ) 00381 { 00382 phh=MaxPotential; 00383 } 00384 else 00385 { 00386 // if it's tileable we set it to the opposite extreme. 00387 if (Tileable) phh = MaxPotential - p11; // p11==p12==p21==p22 as tileable recursion1 00388 } 00389 } 00390 00391 // Now subdivide our square into four 00392 if ( SubDivide( x1, y1, xh, yh, p11, p1h, phh, ph1, FALSE ) // This pixel's just been plotted 00393 && SubDivide( xh, y1, x2, yh, ph1, phh, p2h, p21, TRUE ) // These ones haven't 00394 && SubDivide( xh, yh, x2, y2, phh, ph2, p22, p2h, TRUE ) 00395 && SubDivide( x1, yh, xh, y2, p1h, p12, ph2, phh, TRUE )) 00396 { 00397 RecursionLevel--; 00398 return(TRUE); 00399 } 00400 else 00401 { 00402 RecursionLevel--; 00403 return(FALSE); 00404 } 00405 }
|
|
Definition at line 489 of file fracfill.cpp. 00496 { 00497 PlasmaFractalFill pf(tSeed?tSeed:rand(), tTileable, tSquash, tGraininess, tGravity); 00498 pf.DoFill(pB); 00499 }
|
|
Definition at line 168 of file fracfill.h. |
|
Definition at line 159 of file fracfill.h. |
|
Definition at line 160 of file fracfill.h. |
|
Definition at line 162 of file fracfill.h. |
|
Definition at line 180 of file fracfill.h. |
|
Definition at line 174 of file fracfill.h. |
|
Definition at line 170 of file fracfill.h. |
|
Definition at line 175 of file fracfill.h. |
|
Definition at line 176 of file fracfill.h. |
|
Definition at line 156 of file fracfill.h. |
|
Definition at line 171 of file fracfill.h. |
|
Definition at line 158 of file fracfill.h. |
|
Definition at line 178 of file fracfill.h. |
|
Definition at line 181 of file fracfill.h. |
|
Definition at line 173 of file fracfill.h. |
|
Definition at line 164 of file fracfill.h. |
|
Definition at line 166 of file fracfill.h. |
|
Definition at line 165 of file fracfill.h. |
|
Definition at line 167 of file fracfill.h. |