00001
00002 #define SMOOTH_WRAP (GE_FALSE)
00003
00004
00005
00006 #include "Fire.h"
00007 #include "genesis.h"
00008 #include "ram.h"
00009 #include "gebmutil.h"
00010 #include "proceng.h"
00011 #include "procutil.h"
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <assert.h>
00015 #include <math.h>
00016
00017 #ifdef DO_TIMER
00018 #include "timer.h"
00019 TIMER_VARS(Fire);
00020 TIMER_VARS(Fire_Smooth);
00021 TIMER_VARS(Fire_UnLock);
00022 TIMER_VARS(Fire_Rands);
00023 #endif
00024
00025 #define BM_WIDTH (128)
00026 #define BM_HEIGHT (128)
00027
00028 #define SeedLines (1)
00029
00030 geBoolean FireAnimator_CreateFire(Procedural * Proc);
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #define myrand(max) ProcUtil_Rand(max)
00041
00042
00043
00044 Procedural *Fire_Create(geBitmap **ppBitmap, const char *ParmStart);
00045 void Fire_Destroy(Procedural *Proc);
00046 geBoolean Fire_Animate(Procedural *Fire, float ElapsedTime);
00047
00048 static Procedural_Table Fire_Table =
00049 {
00050 Procedurals_Version,Procedurals_Tag,
00051 "Fire",
00052 Fire_Create,
00053 Fire_Destroy,
00054 Fire_Animate
00055 };
00056
00057 Procedural_Table * Fire_GetProcedural_Table(void)
00058 {
00059 return &Fire_Table;
00060 }
00061
00062
00063
00064 typedef struct Procedural
00065 {
00066 geBitmap * Bitmap;
00067 uint32 Frame;
00068 geBoolean DoJets;
00069 } Procedural;
00070
00071
00072
00073 Procedural *Fire_Create(geBitmap **ppBitmap, const char *ParmStart)
00074 {
00075 Procedural * P;
00076
00077 P = geRam_Allocate(sizeof(Procedural));
00078 if ( ! P )
00079 return NULL;
00080 assert(P);
00081 memset(P,0,sizeof(Procedural));
00082
00083 P->Frame = 0;
00084
00085 if ( strlen(ParmStart) < 10 )
00086 {
00087 ParmStart = "F, pow, 400,280,200,530, 0.3,0.6,1.0,0.8";
00088
00089 }
00090
00091 if ( ! *ppBitmap )
00092 {
00093 *ppBitmap = geBitmap_Create(BM_WIDTH,BM_HEIGHT,1, GE_PIXELFORMAT_8BIT_PAL);
00094 if ( ! *ppBitmap )
00095 {
00096 geRam_Free(P);
00097 return NULL;
00098 }
00099 }
00100 else
00101 {
00102 geBitmap_CreateRef(*ppBitmap);
00103 }
00104
00105 if ( ! geBitmap_SetFormat(*ppBitmap,GE_PIXELFORMAT_8BIT_PAL,GE_TRUE,255,NULL) )
00106 {
00107 geRam_Free(P);
00108 return NULL;
00109 }
00110
00111 geBitmap_ClearMips(*ppBitmap);
00112
00113 geBitmap_SetPreferredFormat(*ppBitmap,GE_PIXELFORMAT_16BIT_4444_ARGB);
00114
00115 P->Bitmap = *ppBitmap;
00116
00117 {
00118 char ParmWork[100];
00119 char *ptr;
00120 int len;
00121 strncpy(ParmWork,ParmStart,100);
00122 ptr = strtok(ParmWork," \t\n\r,");
00123 if ( toupper(*ptr) == 'T' )
00124 P->DoJets = 1;
00125 else
00126 P->DoJets = atol(ptr);
00127 ptr = strtok(NULL," \t\n\r,");
00128 len = (int)(ptr - ParmWork);
00129 ParmStart += len;
00130 }
00131
00132 if ( ! ProcUtil_SetPaletteFromString(P->Bitmap,(char **)&ParmStart) )
00133 {
00134 geRam_Free(P);
00135 return NULL;
00136 }
00137
00138 assert( SeedLines == 1 ||SeedLines == 2 );
00139
00140 #ifdef DO_TIMER
00141 timerFP = fopen("q:\\timer.log","at+");
00142 Timer_Start();
00143 #endif
00144
00145 return P;
00146 }
00147
00148 void Fire_Destroy(Procedural * P)
00149 {
00150 if ( ! P )
00151 return;
00152
00153 #ifdef DO_TIMER
00154 Timer_Stop();
00155 if ( timerFP )
00156 {
00157 TIMER_REPORT(Fire);
00158 TIMER_REPORT(Fire_Smooth);
00159 TIMER_REPORT(Fire_UnLock);
00160 TIMER_REPORT(Fire_Rands);
00161 }
00162 #endif
00163
00164 if ( P->Bitmap )
00165 geBitmap_Destroy(&(P->Bitmap));
00166
00167 geRam_Free(P);
00168 }
00169
00170 geBoolean Fire_Animate(Procedural * P,float time)
00171 {
00172
00173 #ifdef DO_TIMER
00174 TIMER_P(Fire);
00175 #endif
00176
00177 if ( ! FireAnimator_CreateFire(P) )
00178 return GE_FALSE;
00179
00180 #ifdef DO_TIMER
00181 TIMER_Q(Fire);
00182 TIMER_COUNT();
00183 #endif
00184
00185 P->Frame ++;
00186
00187 return GE_TRUE;
00188 }
00189
00190 geBoolean FireAnimator_CreateFire(Procedural * Proc)
00191 {
00192 geBitmap *FireLock=NULL;
00193 geBitmap_Info FireInfo;
00194 uint8 *FireBits,*bPtr;
00195 int x,y,w,h,s;
00196 geBitmap *Bitmap;
00197
00198 Bitmap = Proc->Bitmap;
00199 assert(Bitmap);
00200
00201 geBitmap_SetGammaCorrection(Bitmap, 1.0f, GE_FALSE);
00202
00203 if ( ! geBitmap_LockForWriteFormat(Bitmap,&FireLock,0,0,GE_PIXELFORMAT_8BIT_PAL) )
00204 goto fail;
00205
00206 if ( ! geBitmap_GetInfo(FireLock,&FireInfo,NULL) )
00207 goto fail;
00208
00209 FireBits = geBitmap_GetBits(FireLock);
00210
00211 if ( ! FireBits )
00212 goto fail;
00213
00214 w = FireInfo.Width;
00215 h = FireInfo.Height;
00216 s = FireInfo.Stride;
00217
00218 if ( Proc->Frame == 0 )
00219 memset(FireBits,0,s*h);
00220
00221 #ifdef DO_TIMER
00222 TIMER_P(Fire_Rands);
00223 #endif
00224
00225 {
00226 int r;
00227 uint8 * bPtr;
00228 bPtr = FireBits + (h - SeedLines)*s;
00229
00230 memset(bPtr,0,s* SeedLines);
00231 for(r=20*SeedLines;r--;)
00232 {
00233 x = myrand(s*SeedLines);
00234 bPtr[x] = 254;
00235 }
00236 }
00237
00238 #if 1 // clear some points to avoid static junk
00239 {
00240 int r;
00241 uint8 * bPtr;
00242 for(y=0;y<h;y++)
00243 {
00244 bPtr = FireBits + y*s;
00245 for(r=10;r--;)
00246 {
00247 x = myrand(w);
00248 if ( bPtr[x] )
00249 {
00250 bPtr[x] -= ((bPtr[x])>>4) + 1;
00251 }
00252 }
00253 }
00254 }
00255 #endif
00256
00257 #ifdef DO_TIMER
00258 TIMER_Q(Fire_Rands);
00259 #endif
00260
00261 if ( Proc->DoJets )
00262 {
00263 uint8 *pbPtr,*ppbPtr;
00264 int a;
00265 int randval,randbits;
00266
00267
00268
00269 randbits = 0;
00270
00271 if ( SeedLines < 2 )
00272 {
00273 memcpy(FireBits + (h-2)*s,FireBits + (h-1)*s,s);
00274 }
00275
00276 bPtr = FireBits + s;
00277 for(y=h-3;y--;)
00278 {
00279 pbPtr = bPtr + s;
00280 ppbPtr = pbPtr + s;
00281 for(x=w;x--;)
00282 {
00283 a = (bPtr[-1] + pbPtr[0] + pbPtr[1] + pbPtr[-1] + pbPtr[-2] +
00284 ppbPtr[0] + ppbPtr[1] + ppbPtr[-1])>>3;
00285 if ( a )
00286 {
00287 if ( ! randbits )
00288 {
00289 randval = myrand(1024);
00290 randbits = 10;
00291 }
00292 switch( randval & 1 )
00293 {
00294 case 0:
00295 *bPtr = (a + pbPtr[1])>>1;
00296 break;
00297 case 1:
00298 *bPtr = (a + pbPtr[-1])>>1;
00299 break;
00300 }
00301 randval >>= 1;
00302 randbits --;
00303 }
00304 else
00305 {
00306 *bPtr = 0;
00307 }
00308 bPtr++;
00309 pbPtr++;
00310 ppbPtr++;
00311 }
00312 bPtr += s - w;
00313 }
00314 }
00315 else
00316 {
00317
00318 #ifdef DO_TIMER
00319 TIMER_P(Fire_Smooth);
00320 #endif
00321
00322 FireInfo.Height --;
00323 if ( ! geBitmapUtil_SmoothBits(&FireInfo,FireBits + s,FireBits,2,SMOOTH_WRAP) )
00324 goto fail;
00325
00326 #ifdef DO_TIMER
00327 TIMER_Q(Fire_Smooth);
00328 #endif
00329 }
00330
00331
00332 {
00333 uint8 *sPtr;
00334 int passes,MaxY;
00335
00336 passes = 2;
00337
00338 if ( Proc->DoJets )
00339 MaxY = 4;
00340 else
00341 MaxY = 2;
00342
00343 while(passes--)
00344 {
00345 for(y=1;y<= MaxY;y++)
00346 {
00347 bPtr = FireBits + (h-y)*s;
00348 sPtr = bPtr - s;
00349 *bPtr++ = (bPtr[0] + bPtr[1] + sPtr[0] + sPtr[1])>>2;
00350 sPtr++;
00351 for(x=w-2;x--;)
00352 {
00353 *bPtr++ = (bPtr[0] + bPtr[1] + bPtr[-1] + sPtr[0] + sPtr[1] + sPtr[-1] + sPtr[-2] + sPtr[2])>>3;
00354 sPtr++;
00355 }
00356 *bPtr++ = (bPtr[0] + bPtr[-1] + sPtr[0] + sPtr[-1])>>2;
00357 sPtr++;
00358 }
00359 }
00360 }
00361
00362 #ifdef DO_TIMER
00363 TIMER_P(Fire_UnLock);
00364 #endif
00365
00366 if ( ! geBitmap_UnLock(FireLock) )
00367 goto fail;
00368
00369 #ifdef DO_TIMER
00370 TIMER_Q(Fire_UnLock);
00371 #endif
00372
00373 return GE_TRUE;
00374 fail:
00375
00376 if ( FireLock ) geBitmap_UnLock(FireLock);
00377
00378 return GE_FALSE;
00379 }
00380