00001
00002
00003
00004
00005
00006
00007 #include "Plasma.h"
00008 #include "genesis.h"
00009 #include "ram.h"
00010 #include "gebmutil.h"
00011 #include "errorlog.h"
00012 #include "proceng.h"
00013 #include "procutil.h"
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <assert.h>
00017 #include <math.h>
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #define SIZE_SCALE (150.0)
00034
00035 #define R_PAL_STEP (0.07)
00036 #define G_PAL_STEP (0.05)
00037 #define B_PAL_STEP (0.1)
00038
00039
00040
00041
00042
00043 #ifdef DO_TIMER
00044 #include "timer.h"
00045
00046 TIMER_VARS(Plasma);
00047 #endif
00048
00049 #define BM_CREATE_WIDTH (128)
00050 #define BM_CREATE_HEIGHT (128)
00051 #define BM_MAX_WIDTH (128)
00052 #define BM_MAX_HEIGHT (128)
00053 #define BM_MIN_WIDTH (128)
00054 #define BM_MIN_HEIGHT (128)
00055
00056
00057
00058
00059 #define TAB_WIDTH (BM_MAX_WIDTH * 2)
00060 #define TAB_HEIGHT (BM_MAX_HEIGHT* 2)
00061
00062 geBoolean PlasmaAnimator_CreatePalette(Procedural * Proc, double time);
00063 geBoolean PlasmaAnimator_CreatePlasma(Procedural * Proc, double time);
00064
00065
00066
00067 Procedural *Plasma_Create(geBitmap **ppBitmap, const char *ParmStart);
00068 void Plasma_Destroy(Procedural *Proc);
00069 geBoolean Plasma_Animate(Procedural *Plasma, float ElapsedTime);
00070
00071 static Procedural_Table Plasma_Table =
00072 {
00073 Procedurals_Version,Procedurals_Tag,
00074 "Plasma",
00075 Plasma_Create,
00076 Plasma_Destroy,
00077 Plasma_Animate
00078 };
00079
00080 Procedural_Table * Plasma_GetProcedural_Table(void)
00081 {
00082 return &Plasma_Table;
00083 }
00084
00085
00086
00087 typedef struct Procedural
00088 {
00089 geBitmap * Bitmap;
00090 geBoolean PlasmaPalette,Displacer;
00091 geBitmap * DisplaceOriginal;
00092
00093 double circle1,circle2,circle3,circle4,
00094 circle5,circle6,circle7,circle8;
00095 double roll;
00096 double R,G,B;
00097 double CircleScale;
00098 double RollStep;
00099 } Procedural;
00100
00101
00102
00103 Procedural *Plasma_Create(geBitmap **ppBitmap, const char *ParmStart)
00104 {
00105 Procedural * P;
00106 geBoolean DoAlpha = GE_FALSE;
00107
00108 P = geRam_Allocate(sizeof(Procedural));
00109 if ( ! P )
00110 return NULL;
00111 assert(P);
00112 memset(P,0,sizeof(Procedural));
00113
00114 if ( ! *ppBitmap )
00115 {
00116 *ppBitmap = geBitmap_Create(BM_CREATE_WIDTH,BM_CREATE_HEIGHT,1, GE_PIXELFORMAT_8BIT_PAL);
00117 if ( ! *ppBitmap )
00118 {
00119 geRam_Free(P);
00120 return NULL;
00121 }
00122 }
00123 else
00124 {
00125 if ( ! geBitmap_SetFormat(*ppBitmap,GE_PIXELFORMAT_8BIT_PAL,GE_FALSE,0,NULL) )
00126 {
00127 geRam_Free(P);
00128 return NULL;
00129 }
00130
00131 geBitmap_ClearMips(*ppBitmap);
00132 geBitmap_CreateRef(*ppBitmap);
00133 }
00134
00135 if (geBitmap_Width( *ppBitmap) > BM_MAX_WIDTH ||
00136 geBitmap_Height(*ppBitmap) > BM_MAX_HEIGHT ||
00137 geBitmap_Width( *ppBitmap) < BM_MIN_WIDTH ||
00138 geBitmap_Height(*ppBitmap) < BM_MIN_HEIGHT )
00139 {
00140 geErrorLog_AddString(-1,"Plasm_Create : target Bitmap width not in supported ranged", NULL);
00141 geRam_Free(P);
00142 return NULL;
00143 }
00144
00145 P->Bitmap = *ppBitmap;
00146
00147 if ( ! ParmStart || strlen(ParmStart) < 10 )
00148 {
00149 P->PlasmaPalette = GE_TRUE;
00150
00151 if ( ! PlasmaAnimator_CreatePalette(P,0.0) )
00152 {
00153 geRam_Free(P);
00154 return NULL;
00155 }
00156
00157 P->CircleScale = 1.0;
00158 P->RollStep = 1.0;
00159
00160 #if 0
00161 P->R = 1.0/6.0*PI;
00162 P->G = 3.0/6.0*PI;
00163 P->B = 5.0/6.0*PI;
00164 #else
00165 P->R = (rand() % 6)/6.0*PI;
00166 P->G = (rand() % 6)/6.0*PI;
00167 P->B = (rand() % 6)/6.0*PI;
00168 #endif
00169 }
00170 else
00171 {
00172 char * pstr;
00173 char ParmWork[1024];
00174
00175 P->PlasmaPalette = GE_FALSE;
00176
00177 strcpy(ParmWork,ParmStart);
00178 pstr = strtok(ParmWork," ,\n\r\r");
00179
00180 P->CircleScale = atof(pstr);
00181 pstr = strtok(NULL," ,\n\r\r");
00182
00183 P->RollStep = atof(pstr);
00184 pstr = strtok(NULL," ,\n\r\r");
00185
00186 DoAlpha = ((toupper(*pstr) == 'T') ? GE_TRUE : atol(pstr));
00187 pstr = strtok(NULL," ,\n\r\r");
00188
00189 P->Displacer = ((toupper(*pstr) == 'T') ? GE_TRUE : atol(pstr));
00190 pstr = strtok(NULL," ,\n\r\r");
00191
00192 if ( ! P->Displacer )
00193 {
00194 ParmStart += (int)(pstr - ParmWork);
00195
00196 if ( ! ProcUtil_SetPaletteFromString(P->Bitmap,(char **)&ParmStart) )
00197 {
00198 geBitmap_Destroy(&(P->Bitmap));
00199 geRam_Free(P);
00200 return NULL;
00201 }
00202 }
00203 }
00204
00205 if ( P->Displacer )
00206 {
00207 P->DisplaceOriginal = geBitmap_Create(BM_CREATE_WIDTH,BM_CREATE_HEIGHT,1, GE_PIXELFORMAT_8BIT_PAL);
00208 if ( ! P->DisplaceOriginal )
00209 {
00210 geBitmap_Destroy(&(P->Bitmap));
00211 geRam_Free(P);
00212 return NULL;
00213 }
00214 geBitmap_BlitBitmap(P->Bitmap,P->DisplaceOriginal);
00215 }
00216
00217 if ( DoAlpha )
00218 {
00219
00220
00221
00222 if ( ! geBitmap_SetPreferredFormat(P->Bitmap,GE_PIXELFORMAT_16BIT_4444_ARGB) )
00223 return GE_FALSE;
00224 }
00225
00226 P->circle1 = ( rand() % 10 ) * 0.1;
00227 P->circle2 = ( rand() % 10 ) * 0.1;
00228 P->circle3 = ( rand() % 10 ) * 0.1;
00229 P->circle4 = ( rand() % 10 ) * 0.1;
00230 P->circle5 = ( rand() % 10 ) * 0.1;
00231 P->circle6 = ( rand() % 10 ) * 0.1;
00232 P->circle7 = ( rand() % 10 ) * 0.1;
00233 P->circle8 = ( rand() % 10 ) * 0.1;
00234
00235 #ifdef DO_TIMER
00236 timerFP = fopen("q:\\timer.log","at+");
00237 Timer_Start();
00238 #endif
00239
00240 return P;
00241 }
00242
00243 void Plasma_Destroy(Procedural * P)
00244 {
00245 if ( ! P )
00246 return;
00247
00248 if ( P->Bitmap )
00249 geBitmap_Destroy(&(P->Bitmap));
00250
00251 if ( P->DisplaceOriginal )
00252 geBitmap_Destroy(&(P->DisplaceOriginal));
00253
00254 #ifdef DO_TIMER
00255 Timer_Stop();
00256 if ( timerFP )
00257 {
00258 TIMER_REPORT(Plasma);
00259 }
00260 #endif
00261
00262 geRam_Free(P);
00263 }
00264
00265 geBoolean Plasma_Animate(Procedural * P,float time)
00266 {
00267 assert(P && P->Bitmap);
00268
00269 #ifdef DO_TIMER
00270 TIMER_P(Plasma);
00271 #endif
00272
00273 if ( P->PlasmaPalette )
00274 {
00275 if ( ! PlasmaAnimator_CreatePalette(P,time) )
00276 return GE_FALSE;
00277 }
00278
00279 if ( ! PlasmaAnimator_CreatePlasma(P,time) )
00280 return GE_FALSE;
00281
00282 #ifdef DO_TIMER
00283 TIMER_Q(Plasma);
00284 TIMER_COUNT();
00285 #endif
00286
00287 return GE_TRUE;
00288 }
00289
00290 geBoolean PlasmaAnimator_CreatePalette(Procedural *P,double time)
00291 {
00292 geBitmap_Palette *Pal;
00293 void * PalData = NULL;
00294 gePixelFormat PalFormat;
00295 int PalSize;
00296
00297 if ( ! (Pal = geBitmap_GetPalette(P->Bitmap)) )
00298 {
00299
00300 Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_ARGB,256);
00301 if ( ! Pal )
00302 goto fail;
00303
00304 if ( ! geBitmap_SetPalette(P->Bitmap,Pal) )
00305 goto fail;
00306
00307 geBitmap_Palette_Destroy(&Pal);
00308
00309 if ( ! (Pal = geBitmap_GetPalette(P->Bitmap)) )
00310 return GE_FALSE;
00311 }
00312
00313 if ( ! geBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
00314 goto fail;
00315 if ( PalSize < 256 )
00316 goto fail;
00317
00318 {
00319 int p,r,g,b;
00320 uint8 * PalPtr;
00321 double R,G,B;
00322 float u;
00323
00324 R = P->R;
00325 G = P->G;
00326 B = P->B;
00327
00328 PalPtr = PalData;
00329 for(p=0;p<256;p++)
00330 {
00331 u = (float)((PI/128.0) * p);
00332
00333
00334
00335 #define mycol(u,a) (int)((cos((u)+(a))+1)*127.0)
00336
00337 r = mycol(u,R);
00338 g = mycol(u,G);
00339 b = mycol(u,B);
00340
00341 gePixelFormat_PutColor(PalFormat,&PalPtr,r,g,b,0xFF);
00342 }
00343
00344 P->R += R_PAL_STEP * time * 30.0;
00345 P->G -= G_PAL_STEP * time * 30.0;
00346 P->B += B_PAL_STEP * time * 30.0;
00347 }
00348
00349 PalData = NULL;
00350
00351 if ( ! geBitmap_Palette_UnLock(Pal) )
00352 return GE_FALSE;
00353
00354 return GE_TRUE;
00355
00356 fail:
00357
00358 if ( PalData )
00359 geBitmap_Palette_UnLock(Pal);
00360
00361 return GE_FALSE;
00362 }
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 static uint8 tab1[TAB_WIDTH * TAB_HEIGHT];
00379 static uint8 tab2[TAB_WIDTH * TAB_HEIGHT];
00380 static uint8 sintab1[256];
00381 static signed char dtable[256];
00382 static int calculated = 0;
00383
00384 void CalculateTables(Procedural * Proc)
00385 {
00386 int x,y;
00387 uint8 *ptab1,*ptab2;
00388 if ( calculated )
00389 return;
00390 calculated = 1;
00391 ptab1 = tab1;
00392 ptab2 = tab2;
00393 for(y=0;y<TAB_HEIGHT;y++)
00394 {
00395 for(x=0;x<TAB_WIDTH;x++)
00396 {
00397 double d_to_center,r,dx,dy;
00398
00399 #if 1 // TILE the texture correctly!
00400 #if 0
00401 dx = (x%128);
00402 dy = (y%128);
00403 dx = 64.0 - dx;
00404 dy = 64.0 - dy;
00405 #else
00406 dx = SIZE_SCALE * sin(x*PI/128.0);
00407 dy = SIZE_SCALE * cos(y*PI/128.0);
00408 #endif
00409 #else
00410 dx = (TAB_WIDTH *0.5) - x;
00411 dy = (TAB_HEIGHT*0.5) - y;
00412 #endif
00413
00414 #if 0 // <> weak anti-alias
00415 dx += (( rand() % 50 ) * 0.01);
00416 dy += (( rand() % 50 ) * 0.01);
00417 r = (( rand() % 50 ) * 0.01);
00418 #else
00419 r = 0.4;
00420 #endif
00421
00422 d_to_center = sqrt( 16.0 + dx*dx + dy*dy ) - 4.0;
00423 *ptab1++ = (uint8)(d_to_center * 5.0 + r );
00424 *ptab2++= (uint8)((sin(d_to_center/9.5)+1.0)*90.0 + r);
00425 }
00426 }
00427
00428 for(x=0;x<256;x++)
00429 {
00430 sintab1[x] = (uint8)((sin(x/(5.0*9.5))+1.0)*90.0 + 0.5);
00431 dtable[x] = (signed char)(sin(x*2.0*PI/256) * 16.0);
00432 }
00433 }
00434
00435 int DoCircle(double * pCircle, double step, int w, int doCos);
00436
00437 geBoolean PlasmaAnimator_CreatePlasma(Procedural * Proc,double time)
00438 {
00439 geBitmap *PlasmaLock=NULL;
00440 geBitmap_Info PlasmaInfo;
00441 uint8 *Bits,*bptr;
00442 int x,y,w,h,s;
00443 geBitmap *Bitmap;
00444
00445 Bitmap = Proc->Bitmap;
00446 assert(Bitmap);
00447
00448 CalculateTables(Proc);
00449
00450 geBitmap_SetGammaCorrection(Bitmap, 1.0f, GE_FALSE);
00451
00452 if ( ! geBitmap_LockForWriteFormat(Bitmap,&PlasmaLock,0,0,GE_PIXELFORMAT_8BIT_PAL) )
00453 goto fail;
00454
00455 if ( ! geBitmap_GetInfo(PlasmaLock,&PlasmaInfo,NULL) )
00456 goto fail;
00457
00458 Bits = geBitmap_GetBits(PlasmaLock);
00459
00460 if ( ! Bits )
00461 goto fail;
00462
00463 w = PlasmaInfo.Width;
00464 h = PlasmaInfo.Height;
00465 s = PlasmaInfo.Stride;
00466
00467
00468
00469
00470 {
00471 int x1,y1,x2,y2,
00472 x3,y3,x4,y4,
00473 o1,o2,o3,o4;
00474 uint8 *ptab1,*ptab2;
00475 uint8 roll;
00476 double CircleScale;
00477
00478 CircleScale = Proc->CircleScale * time * 2.0;
00479
00480 x1 = DoCircle(&(Proc->circle1),0.3 * CircleScale,w,1);
00481 y1 = DoCircle(&(Proc->circle2),0.2 * CircleScale,h,0);
00482 y2 = DoCircle(&(Proc->circle4),0.1 * CircleScale,h,1);
00483 x2 = DoCircle(&(Proc->circle3),0.85 * CircleScale,w,0);
00484 x3 = DoCircle(&(Proc->circle5),0.4 * CircleScale,w,1);
00485 y3 = DoCircle(&(Proc->circle6),0.15 * CircleScale,h,0);
00486 x4 = DoCircle(&(Proc->circle7),0.35 * CircleScale,w,1);
00487 y4 = DoCircle(&(Proc->circle8),0.05 * CircleScale,h,0);
00488
00489 o1 = x1 + TAB_WIDTH*y1;
00490 o2 = x2 + TAB_WIDTH*y2;
00491 o3 = x3 + TAB_WIDTH*y3;
00492 o4 = x4 + TAB_WIDTH*y4;
00493
00494 roll = (uint8)( Proc->roll + 0.5);
00495 Proc->roll += Proc->RollStep * time * 30.0;
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 if ( Proc->Displacer )
00506 {
00507 geBitmap *Source,*SourceLock;
00508 geBitmap_Info SourceInfo;
00509 void * SourceBits;
00510 int ss;
00511 uint8 * sptr;
00512
00513
00514 Source = Proc->DisplaceOriginal;
00515 assert(Source);
00516
00517 if ( ! geBitmap_LockForReadNative(Source,&SourceLock,0,0) )
00518 goto fail;
00519
00520 if ( ! geBitmap_GetInfo(SourceLock,&SourceInfo,NULL) )
00521 goto fail;
00522
00523 if ( ! (SourceBits = geBitmap_GetBits(SourceLock)) )
00524 goto fail;
00525
00526 assert( SourceInfo.Width == w);
00527 assert( SourceInfo.Height == h);
00528 ss = SourceInfo.Stride;
00529
00530 bptr = Bits;
00531 sptr = SourceBits;
00532 for(y=0;y<h;y++)
00533 {
00534 ptab1 = tab1 + TAB_WIDTH*y;
00535 ptab2 = tab2 + TAB_WIDTH*y;
00536 for(x=0;x<w;x++)
00537 {
00538 int o,sx;
00539 o = ptab1[o1] + ptab2[o2] + ptab2[o3] + ptab2[o4];
00540 o = (o + roll)&0xFF;
00541 o = dtable[o];
00542 ptab1++;
00543 ptab2++;
00544
00545 sx = x + o;
00546 if ( sx < 0 ) sx += w;
00547 else if ( sx >= w ) sx -= w;
00548 assert( sx >= 0 && sx < w );
00549 *bptr++ = sptr[sx];
00550 }
00551 bptr += (s-w);
00552 sptr += ss;
00553 }
00554
00555 geBitmap_UnLock(SourceLock);
00556 }
00557 else
00558 {
00559
00560
00561 bptr = Bits;
00562 if ( PlasmaInfo.HasColorKey )
00563 {
00564 uint8 CK,pel;
00565 CK = (uint8)PlasmaInfo.ColorKey;
00566 if ( CK > 200 )
00567 {
00568 for(y=0;y<h;y++)
00569 {
00570 ptab1 = tab1 + TAB_WIDTH*y;
00571 ptab2 = tab2 + TAB_WIDTH*y;
00572 for(x=w;x--;)
00573 {
00574 pel = roll + ptab1[o1] +
00575 ptab2[o2] + ptab2[o3] + ptab2[o4];
00576
00577 *bptr++ = pel%CK;
00578 ptab1++;
00579 ptab2++;
00580 }
00581 bptr += (s-w);
00582 }
00583 }
00584 else
00585 {
00586 for(y=0;y<h;y++)
00587 {
00588 ptab1 = tab1 + TAB_WIDTH*y;
00589 ptab2 = tab2 + TAB_WIDTH*y;
00590 for(x=w;x--;)
00591 {
00592 pel = roll + ptab1[o1] +
00593 ptab2[o2] + ptab2[o3] + ptab2[o4];
00594
00595 if ( pel == CK )
00596 pel ^= 1;
00597
00598 *bptr++ = pel;
00599 ptab1++;
00600 ptab2++;
00601 }
00602 bptr += (s-w);
00603 }
00604 }
00605 }
00606 else
00607 {
00608 for(y=0;y<h;y++)
00609 {
00610 ptab1 = tab1 + TAB_WIDTH*y;
00611 ptab2 = tab2 + TAB_WIDTH*y;
00612 for(x=w;x--;)
00613 {
00614 *bptr++ = roll + ptab1[o1] +
00615 ptab2[o2] + ptab2[o3] + ptab2[o4];
00616 ptab1++;
00617 ptab2++;
00618 }
00619 bptr += (s-w);
00620 }
00621 }
00622 }
00623 }
00624
00625
00626
00627
00628
00629
00630 if ( ! geBitmap_UnLock(PlasmaLock) )
00631 goto fail;
00632
00633 return GE_TRUE;
00634 fail:
00635
00636 if ( PlasmaLock ) geBitmap_UnLock(PlasmaLock);
00637
00638 return GE_FALSE;
00639 }
00640
00641
00642 int DoCircle(double * pCircle, double step, int w, int doCos)
00643 {
00644 double cp,c,cn;
00645 double xp,x,xn;
00646 int ix,ixp,ixn;
00647
00648 w--;
00649
00650
00651
00652
00653 c = *pCircle;
00654 cp = c - step;
00655 cn = c + step;
00656
00657 *pCircle += step;
00658
00659 if ( doCos )
00660 {
00661 x = w*0.5*(1.0 + cos(c));
00662 xp = w*0.5*(1.0 + cos(cp));
00663 xn = w*0.5*(1.0 + cos(cn));
00664 }
00665 else
00666 {
00667 x = w*0.5*(1.0 + sin(c));
00668 xp = w*0.5*(1.0 + sin(cp));
00669 xn = w*0.5*(1.0 + sin(cn));
00670 }
00671
00672 ixn = (int)xn;
00673 ixp = (int)xp;
00674
00675 if ( ixp == ixn )
00676 {
00677 ix = ixp;
00678 }
00679 else
00680 {
00681 x += ( rand() % 50 ) * 0.01;
00682 ix = (int)((x + ixp + ixn)*(1.0/3.0));
00683 }
00684
00685 assert( ix >= 0 && ix <= w );
00686
00687 return ix;
00688 }