00001
00002 #include "bumpmap.h"
00003 #include "genesis.h"
00004 #include "bitmap.h"
00005 #include "ram.h"
00006 #include <math.h>
00007 #include <Assert.h>
00008 #include <string.h>
00009
00010
00011
00012 Procedural *BumpMap_Create(geBitmap **ppBitmap, const char *ParmStart);
00013 void BumpMap_Destroy(Procedural *Proc);
00014 geBoolean BumpMap_Animate(Procedural *BumpMap, float ElapsedTime);
00015
00016 static Procedural_Table BumpMap_Table =
00017 {
00018 Procedurals_Version,Procedurals_Tag,
00019 "BumpMap",
00020 BumpMap_Create,
00021 BumpMap_Destroy,
00022 BumpMap_Animate
00023 };
00024
00025 Procedural_Table * BumpMap_GetProcedural_Table(void)
00026 {
00027 return &BumpMap_Table;
00028 }
00029
00030
00031
00032 typedef struct Procedural
00033 {
00034 uint32 Frame;
00035 geBitmap * Bitmap;
00036 } Procedural;
00037
00038 geBoolean BumpMap_CreateFromHeightMap(geBitmap * HeightMap,geBitmap * BumpMap);
00039 geBoolean BumpMap_ComputePalette(geBitmap *BumpMap, geVec3d *Horizontal,geVec3d * Vertical, geVec3d *Pos, geVec3d *LightPos);
00040
00041
00042
00043 Procedural *BumpMap_Create(geBitmap **ppBitmap, const char *ParmStart)
00044 {
00045 Procedural * P;
00046 geBitmap * HeightMap;
00047
00048 assert(ppBitmap);
00049
00050 if ( ! *ppBitmap )
00051 return NULL;
00052
00053 P = geRam_Allocate(sizeof(Procedural));
00054 if ( ! P )
00055 return NULL;
00056 assert(P);
00057 memset(P,0,sizeof(Procedural));
00058
00059 P->Frame = 0;
00060
00061 P->Bitmap = *ppBitmap;
00062
00063 if ( geBitmap_ClearMips(P->Bitmap) )
00064 {
00065 if ( geBitmap_SetColorKey(P->Bitmap,GE_FALSE,0,GE_FALSE) )
00066 {
00067 HeightMap = geBitmap_Create(geBitmap_Width(P->Bitmap),geBitmap_Height(P->Bitmap),1,GE_PIXELFORMAT_8BIT_GRAY);
00068 if ( HeightMap )
00069 {
00070 if ( geBitmap_BlitBitmap(P->Bitmap,HeightMap) )
00071 {
00072 if ( BumpMap_CreateFromHeightMap(HeightMap,P->Bitmap) )
00073 {
00074 geBitmap_Destroy(&HeightMap);
00075 return P;
00076 }
00077 }
00078 geBitmap_Destroy(&HeightMap);
00079 }
00080 }
00081 }
00082
00083 geRam_Free(P);
00084 return NULL;
00085 }
00086
00087 void BumpMap_Destroy(Procedural * P)
00088 {
00089 if ( ! P )
00090 return;
00091 geRam_Free(P);
00092 }
00093
00094 geBoolean BumpMap_Animate(Procedural * P,float time)
00095 {
00096 geVec3d Pos,LightPos,Horizontal,Vertical;
00097 geBoolean Ret;
00098
00099
00100
00101 Horizontal.X = 1.0f;
00102 Horizontal.Y = 0.0f;
00103 Horizontal.Z = 0.0f;
00104 Vertical.X = 0.0f;
00105 Vertical.Y = 1.0f;
00106 Vertical.Z = 0.0f;
00107 Pos.X = 0.0f;
00108 Pos.Y = 0.0f;
00109 Pos.Z = 0.0f;
00110 LightPos.X = (geFloat)(100.0f * cos(P->Frame * 0.05f));
00111 LightPos.Y = (geFloat)(100.0f * sin(P->Frame * 0.05f));
00112 LightPos.Z = 100.0f;
00113
00114 Ret = BumpMap_ComputePalette(P->Bitmap, &Horizontal,&Vertical, &Pos, &LightPos );
00115
00116 P->Frame ++;
00117 return Ret;
00118 }
00119
00120
00121
00122 #define PI ((double)3.14159265358979323846)
00123 #define TWOPI (2.0*PI)
00124 #define PIOVER2 (PI*0.5)
00125
00126 static int BumpTableInited = 0;
00127 static float BumpTableX[256];
00128 static float BumpTableY[256];
00129 static float BumpTableZ[256];
00130
00131 geBoolean BumpMap_InitTables(void)
00132 {
00133 int p;
00134 double theta,phi;
00135
00136 if ( BumpTableInited )
00137 return GE_TRUE;
00138 BumpTableInited = 1;
00139
00140 for(p=0;p<256;p++)
00141 {
00142 theta = ((double)(p>>4) + 0.5)*PIOVER2/16.0;
00143 phi = ((double)(p&0x0F) + 0.5)*TWOPI/16.0;
00144
00145 assert( theta >= 0.0 && theta <= PIOVER2 );
00146 assert( phi >= 0.0 && phi <= TWOPI );
00147
00148 BumpTableX[p] = (float)( sin(theta) * cos(phi));
00149 BumpTableY[p] = (float)( sin(theta) * sin(phi));
00150 BumpTableZ[p] = (float) cos(theta);
00151 }
00152 return GE_TRUE;
00153 }
00154
00155 geBoolean BumpMap_CreateFromHeightMap(geBitmap * HeightMap,geBitmap * BumpMap)
00156 {
00157 geBitmap *HeightLock=NULL,*BumpLock=NULL;
00158 uint8 *HeightBits,*BumpBits;
00159 geBitmap_Info HeightInfo,BumpInfo;
00160 int w,h;
00161
00162 assert(HeightMap && BumpMap);
00163
00164 if ( ! geBitmap_SetFormat(BumpMap,GE_PIXELFORMAT_8BIT_PAL,GE_TRUE,255,NULL) )
00165 goto fail;
00166
00167 if ( ! geBitmap_LockForRead(HeightMap,&HeightLock,0,0,GE_PIXELFORMAT_8BIT_GRAY,0,0) )
00168 goto fail;
00169
00170 if ( ! geBitmap_GetInfo(HeightLock,&HeightInfo,NULL) )
00171 goto fail;
00172
00173 w = HeightInfo.Width;
00174 h = HeightInfo.Height;
00175
00176 {
00177 geBitmap_Palette * Pal;
00178 Pal = geBitmap_Palette_Create(GE_PIXELFORMAT_32BIT_ARGB,256);
00179 if ( ! Pal )
00180 goto fail;
00181 if ( ! geBitmap_SetPalette(BumpMap,Pal) )
00182 goto fail;
00183 geBitmap_Palette_Destroy(&Pal);
00184 }
00185
00186 if ( ! geBitmap_LockForWriteFormat(BumpMap,&BumpLock,0,0,GE_PIXELFORMAT_8BIT_PAL) )
00187 goto fail;
00188
00189 if ( ! geBitmap_GetInfo(BumpLock,&BumpInfo,NULL) )
00190 goto fail;
00191
00192 HeightBits = geBitmap_GetBits(HeightLock);
00193 BumpBits = geBitmap_GetBits(BumpLock);
00194
00195 if ( ! HeightBits || ! BumpBits )
00196 goto fail;
00197
00198 {
00199 int x,y,bs,hs;
00200 uint8 *hp,*bp;
00201
00202 hp = HeightBits;
00203 bp = BumpBits;
00204 hs = HeightInfo.Stride;
00205 bs = BumpInfo.Stride;
00206
00207 for(y=0;y<(h-1);y++)
00208 {
00209 for(x=0;x<(w-1);x++)
00210 {
00211 int NW,SW,NE,SE,vx,vy;
00212 double scale,nX,nY,nZ;
00213 double theta,phi;
00214 int _theta,_phi;
00215
00216 NW = hp[0];
00217 SW = hp[hs];
00218 hp++;
00219 NE = hp[0];
00220 SE = hp[hs];
00221
00222 vx = ((NW - NE) + (SW - SE) + 1)>>1;
00223 vy = ((NW - SW) + (NE - SE) + 1)>>1;
00224
00225 scale = 1.0 / ( 1 + vx*vx + vy*vy );
00226 scale = sqrt(scale);
00227
00228 nX = scale*vx;
00229 nY = scale*vy;
00230 nZ = scale;
00231
00232
00233
00234
00235
00236 theta = acos(nZ);
00237 if ( fabs(nX) > fabs(nY) )
00238 {
00239 double cosphi;
00240 cosphi = nX / sin(theta);
00241 if ( cosphi > 1.0 )
00242 phi = 0.0;
00243 else if ( cosphi < -1.0 )
00244 phi = PI;
00245 else
00246 phi = acos( cosphi );
00247
00248 if ( nY < 0.0 )
00249 phi = TWOPI - phi;
00250 }
00251 else
00252 {
00253 double sinphi;
00254 sinphi = nY / sin(theta);
00255 if ( sinphi > 1.0 )
00256 phi = PIOVER2;
00257 else if ( sinphi < -1.0 )
00258 phi = - PIOVER2;
00259 else
00260 phi = asin( sinphi );
00261
00262 if ( nX < 0.0 )
00263 phi = PI - phi;
00264 if ( phi < 0.0 )
00265 phi += TWOPI;
00266 }
00267
00268 assert( theta >= 0.0 && theta <= PIOVER2 );
00269 assert( phi >= 0.0 && phi <= TWOPI );
00270
00271 theta = theta * 16.0 / (PIOVER2);
00272 phi = phi * 16.0 / (TWOPI);
00273
00274
00275 _theta = (int)theta;
00276 _phi = (int)phi;
00277 assert( (_theta & 0xF) == _theta );
00278 assert( (_phi & 0xF) == _phi );
00279
00280 *bp++ = (_theta << 4) | _phi;
00281 }
00282
00283 *bp = bp[-1];
00284 bp++;
00285 hp++;
00286
00287 hp += hs - w;
00288 bp += bs - w;
00289 }
00290
00291 for(x=0;x<w;x++)
00292 {
00293 bp[x] = bp[x - bs];
00294 }
00295 }
00296
00297 if ( ! geBitmap_UnLock(BumpLock) )
00298 goto fail;
00299 if ( ! geBitmap_UnLock(HeightLock) )
00300 goto fail;
00301
00302 if ( ! BumpMap_InitTables() )
00303 goto fail;
00304
00305 geBitmap_SetPreferredFormat(BumpMap,GE_PIXELFORMAT_8BIT_PAL);
00306
00307 return GE_TRUE;
00308
00309 fail:
00310
00311 if ( BumpLock ) geBitmap_UnLock(BumpLock);
00312 if ( HeightLock ) geBitmap_UnLock(HeightLock);
00313
00314 return GE_FALSE;
00315 }
00316
00317 geBoolean BumpMap_ComputePalette(geBitmap *BumpMap, geVec3d *pPlaneX,geVec3d *pPlaneY, geVec3d *pPos, geVec3d *pLightPos)
00318 {
00319 geBitmap_Palette *Pal;
00320 geVec3d LightRelPos,PlaneZ;
00321 geFloat LightDist;
00322 void * PalData = NULL;
00323 gePixelFormat PalFormat;
00324 int PalSize;
00325
00326 assert(BumpMap && pPlaneX && pPlaneY && pPos && pLightPos);
00327 assert( geVec3d_DotProduct(pPlaneX,pPlaneY) == 0.0f );
00328
00329 geBitmap_SetGammaCorrection(BumpMap, 1.0f, GE_FALSE);
00330
00331 geVec3d_Subtract(pLightPos ,pPos,&LightRelPos );
00332 geVec3d_CrossProduct(pPlaneX,pPlaneY,&PlaneZ);
00333 geVec3d_Normalize(pPlaneX);
00334 geVec3d_Normalize(pPlaneY);
00335 geVec3d_Normalize(&PlaneZ);
00336 LightDist = geVec3d_Normalize(&LightRelPos);
00337
00338 if ( ! (Pal = geBitmap_GetPalette(BumpMap)) )
00339 goto fail;
00340
00341
00342
00343 if ( ! geBitmap_Palette_Lock(Pal,&PalData, &PalFormat, &PalSize) )
00344 goto fail;
00345 if ( PalSize < 256 )
00346 goto fail;
00347
00348 {
00349 int p,c;
00350 uint8 * PalPtr;
00351 float LightX,LightY,LightZ;
00352
00353 LightX = geVec3d_DotProduct(&LightRelPos,pPlaneX) * 250.0f;
00354 LightY = geVec3d_DotProduct(&LightRelPos,pPlaneY) * 250.0f;
00355 LightZ = geVec3d_DotProduct(&LightRelPos,&PlaneZ) * 250.0f;
00356
00357 PalPtr = PalData;
00358 for(p=0;p<256;p++)
00359 {
00360
00361 c = (int)(LightX * BumpTableX[p] + LightY * BumpTableY[p] + LightZ * BumpTableZ[p]);
00362 if ( c < 0 )
00363 c = 0;
00364
00365 assert( c <= 255 );
00366
00367 gePixelFormat_PutColor(PalFormat,&PalPtr,c,c,c,0xFF);
00368 }
00369 assert( ((uint32)PalPtr - (uint32)PalData) == 256 * gePixelFormat_BytesPerPel(PalFormat) );
00370 }
00371
00372 PalData = NULL;
00373
00374 if ( ! geBitmap_Palette_UnLock(Pal) )
00375 return GE_FALSE;
00376
00377 Pal = geBitmap_GetPalette(BumpMap);
00378 if ( ! Pal )
00379 return GE_FALSE;
00380 if ( ! geBitmap_SetPalette(BumpMap,Pal) )
00381 return GE_FALSE;
00382
00383 return GE_TRUE;
00384
00385 fail:
00386
00387 if ( PalData )
00388 geBitmap_Palette_UnLock(Pal);
00389
00390 return GE_FALSE;
00391 }