00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "bitmap._h"
00026 #include "bitmap.__h"
00027 #include "bitmap_gamma.h"
00028 #include "pixelformat.h"
00029 #include "errorlog.h"
00030 #include <assert.h>
00031 #include <math.h>
00032
00033
00034
00035 static uint32 Gamma_Lut[256];
00036 static uint32 Gamma_Lut_Inverse[256];
00037 static geFloat ComputedGamma_Lut = 0.0f;
00038
00039 static uint16 Gamma_565_RGB[1<<16];
00040 static geFloat ComputedGamma_565_RGB = 0.0f;
00041 static uint16 Gamma_4444_ARGB[1<<16];
00042 static geFloat ComputedGamma_4444_ARGB = 0.0f;
00043
00044
00045
00046 void geBitmap_Gamma_Compute_Lut(double Gamma);
00047 void geBitmap_GammaCorrect_Data_4444_ARGB(void * Bits,geBitmap_Info * pInfo);
00048 void geBitmap_GammaCorrect_Data_565_RGB(void * Bits,geBitmap_Info * pInfo);
00049 geBoolean geBitmap_GammaCorrect_Data(void * Bits,geBitmap_Info * pInfo, geBoolean Invert);
00050
00051
00052
00053 geBoolean geBitmap_Gamma_Apply(geBitmap * Bitmap,geBoolean Invert)
00054 {
00055 geBoolean Ret = GE_TRUE;
00056 geFloat Gamma;
00057
00058 assert(Bitmap);
00059
00060 Gamma = Bitmap->DriverGamma;
00061 if ( Gamma <= 0.1f )
00062 return GE_TRUE;
00063
00064
00065
00066
00067 if ( fabs(Gamma - 1.0) < 0.1 )
00068 return GE_TRUE;
00069
00070 if ( Bitmap->LockOwner )
00071 Bitmap = Bitmap->LockOwner;
00072 if ( Bitmap->LockCount || Bitmap->DataOwner )
00073 return GE_FALSE;
00074
00075 if ( ! Bitmap->DriverHandle )
00076 return GE_TRUE;
00077
00078 if ( ComputedGamma_Lut != Gamma )
00079 {
00080 geBitmap_Gamma_Compute_Lut(Gamma);
00081 }
00082
00083 if ( gePixelFormat_HasPalette(Bitmap->DriverInfo.Format) )
00084 {
00085 geBitmap_Palette * Pal;
00086 geBitmap_Info PalInfo;
00087 void * Bits;
00088 int Size;
00089 gePixelFormat Format;
00090
00091
00092
00093 assert(Bitmap->DriverInfo.Palette);
00094 Pal = Bitmap->DriverInfo.Palette;
00095
00096 if ( ! geBitmap_Palette_Lock(Pal,&Bits,&Format,&Size) )
00097 return GE_FALSE;
00098
00099 geBitmap_Palette_GetInfo(Pal,&PalInfo);
00100
00101 if ( ! geBitmap_GammaCorrect_Data(Bits,&PalInfo,Invert) )
00102 Ret = GE_FALSE;
00103
00104 geBitmap_Palette_UnLock(Pal);
00105 }
00106 else
00107 {
00108 geBitmap_Info Info;
00109 void * Bits;
00110 int mip,mipCount;
00111 geBitmap *Locks[8],*Lock;
00112
00113 assert( Bitmap->DriverInfo.MinimumMip == 0 );
00114 mipCount = Bitmap->DriverInfo.MaximumMip + 1;
00115
00116
00117
00118
00119
00120 assert(Bitmap->Driver);
00121 assert(Bitmap->DriverHandle);
00122
00123
00124
00125
00126 if ( ! geBitmap_LockForWrite(Bitmap,Locks,0,mipCount-1) )
00127 {
00128 geErrorLog_AddString(-1,"geBitmap_Gamma_Apply : LockforWrite failed", NULL);
00129 return GE_FALSE;
00130 }
00131
00132 for(mip=0;mip<mipCount;mip++)
00133 {
00134 Lock = Locks[mip];
00135
00136 if ( ! geBitmap_GetInfo(Lock,&Info,NULL) )
00137 {
00138 geErrorLog_AddString(-1,"geBitmap_Gamma_Apply : GetInfo failed", NULL);
00139 return GE_FALSE;
00140 }
00141
00142 Bits = geBitmap_GetBits(Lock);
00143 assert(Bits);
00144
00145 if ( ! geBitmap_GammaCorrect_Data(Bits,&Info,Invert) )
00146 {
00147 geErrorLog_AddString(-1,"geBitmap_Gamma_Apply : GammaCorrect_Data", NULL);
00148 Ret = GE_FALSE;
00149 }
00150 }
00151
00152 if ( ! geBitmap_UnLockArray_NoChange(Locks,mipCount) )
00153 {
00154 geErrorLog_AddString(-1,"geBitmap_Gamma_Apply : UnLock failed", NULL);
00155 return GE_FALSE;
00156 }
00157 }
00158
00159 return Ret;
00160 }
00161
00162
00163
00164 geBoolean geBitmap_GammaCorrect_Data(void * Bits,geBitmap_Info * pInfo, geBoolean Invert)
00165 {
00166 const gePixelFormat_Operations * ops;
00167 uint32 bpp,w,h,xtra,x,y;
00168 uint32 * Lut;
00169 gePixelFormat Format;
00170 gePixelFormat_Decomposer Decompose;
00171 gePixelFormat_Composer Compose;
00172 gePixelFormat_ColorGetter GetColor;
00173 gePixelFormat_ColorPutter PutColor;
00174
00175 Format = pInfo->Format;
00176 ops = gePixelFormat_GetOperations(Format);
00177 if ( ! ops )
00178 return GE_FALSE;
00179
00180 Decompose = ops->DecomposePixel;
00181 Compose = ops->ComposePixel;
00182 GetColor = ops->GetColor;
00183 PutColor = ops->PutColor;
00184
00185 assert( Compose && Decompose && GetColor && PutColor );
00186
00187 if ( ! Invert )
00188 {
00189 if ( Format == GE_PIXELFORMAT_16BIT_565_RGB )
00190 {
00191 geBitmap_GammaCorrect_Data_565_RGB(Bits,pInfo);
00192 return GE_TRUE;
00193 }
00194 else if ( Format == GE_PIXELFORMAT_16BIT_4444_ARGB )
00195 {
00196 geBitmap_GammaCorrect_Data_4444_ARGB(Bits,pInfo);
00197 return GE_TRUE;
00198 }
00199 }
00200
00201 if ( Invert )
00202 Lut = Gamma_Lut_Inverse;
00203 else
00204 Lut = Gamma_Lut;
00205
00206 bpp = ops->BytesPerPel;
00207 w = pInfo->Width;
00208 h = pInfo->Height;
00209 xtra = pInfo->Stride - w;
00210
00211 if ( pInfo->HasColorKey )
00212 {
00213 switch(bpp)
00214 {
00215 default:
00216 case 0:
00217 return GE_FALSE;
00218 case 1:
00219 {
00220 uint8 *ptr,ck;
00221 ck = (uint8)pInfo->ColorKey;
00222 ptr = Bits;
00223 for(y=h;y--;)
00224 {
00225 for(x=w;x--;)
00226 {
00227 if ( *ptr != ck )
00228 {
00229 *ptr = (uint8)Lut[*ptr];
00230 if ( *ptr == ck )
00231 *ptr ^= 1;
00232 }
00233 ptr++;
00234 }
00235 ptr += xtra;
00236 }
00237 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride ) );
00238 break;
00239 }
00240 case 2:
00241 {
00242 uint16 *ptr,ck;
00243 uint32 R,G,B,A,Pixel;
00244 ck = (uint16)pInfo->ColorKey;
00245 ptr = Bits;
00246 for(y=h;y--;)
00247 {
00248 for(x=w;x--;)
00249 {
00250 if ( *ptr == ck )
00251 {
00252 ptr++;
00253 }
00254 else
00255 {
00256 Decompose(*ptr,&R,&G,&B,&A);
00257 R = Lut[R];
00258 G = Lut[G];
00259 B = Lut[B];
00260 Pixel = Compose(R,G,B,A);
00261 if ( Pixel == ck )
00262 Pixel ^= 1;
00263 *ptr++ = (uint16)Pixel;
00264 }
00265 }
00266 ptr += xtra;
00267 }
00268 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) );
00269 break;
00270 }
00271
00272 case 3:
00273 {
00274 uint8 *ptr;
00275 uint32 R,G,B,A,Pixel,ck;
00276 ptr = Bits;
00277 xtra *= 3;
00278 ck = pInfo->ColorKey;
00279 for(y=h;y--;)
00280 {
00281 for(x=w;x--;)
00282 {
00283 Pixel = (ptr[0]<<16) + (ptr[1]<<8) + ptr[2];
00284 if ( Pixel == ck )
00285 {
00286 ptr+=3;
00287 }
00288 else
00289 {
00290 Decompose(Pixel,&R,&G,&B,&A);
00291 R = Lut[R];
00292 G = Lut[G];
00293 B = Lut[B];
00294 Pixel = Compose(R,G,B,A);
00295 if ( Pixel == ck )
00296 Pixel ^= 1;
00297 *ptr++ = (uint8)((Pixel>>16)&0xFF);
00298 *ptr++ = (uint8)((Pixel>>8)&0xFF);
00299 *ptr++ = (uint8)((Pixel)&0xFF);
00300 }
00301 }
00302 ptr += xtra;
00303 }
00304 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 3 ) );
00305 break;
00306 }
00307
00308 case 4:
00309 {
00310 uint32 *ptr,ck;
00311 uint32 R,G,B,A,Pixel;
00312 ck = pInfo->ColorKey;
00313 ptr = Bits;
00314 for(y=h;y--;)
00315 {
00316 for(x=w;x--;)
00317 {
00318 if ( *ptr == ck )
00319 {
00320 ptr++;
00321 }
00322 else
00323 {
00324 Decompose(*ptr,&R,&G,&B,&A);
00325 R = Lut[R];
00326 G = Lut[G];
00327 B = Lut[B];
00328 Pixel = Compose(R,G,B,A);
00329 if ( Pixel == ck )
00330 Pixel ^= 1;
00331 *ptr++ = Pixel;
00332 }
00333 }
00334 ptr += xtra;
00335 }
00336 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 4 ) );
00337 break;
00338 }
00339 }
00340 }
00341 else
00342 {
00343 switch(bpp)
00344 {
00345 default:
00346 case 0:
00347 return GE_FALSE;
00348 case 1:
00349 {
00350 uint8 *ptr;
00351 ptr = Bits;
00352 for(y=h;y--;)
00353 {
00354 for(x=w;x--;)
00355 {
00356 *ptr++ = (uint8)Lut[*ptr];
00357 }
00358 ptr += xtra;
00359 }
00360 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride ) );
00361 break;
00362 }
00363 case 2:
00364 {
00365 uint16 *ptr;
00366 uint32 R,G,B,A;
00367 ptr = Bits;
00368 for(y=h;y--;)
00369 {
00370 for(x=w;x--;)
00371 {
00372 Decompose(*ptr,&R,&G,&B,&A);
00373 R = Lut[R];
00374 G = Lut[G];
00375 B = Lut[B];
00376 *ptr++ = (uint16)Compose(R,G,B,A);
00377 }
00378 ptr += xtra;
00379 }
00380 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) );
00381 break;
00382 }
00383
00384 case 3:
00385 {
00386 uint8 *ptr,*ptrz;
00387 uint32 R,G,B,A;
00388 ptr = Bits;
00389 xtra *= 3;
00390 for(y=h;y--;)
00391 {
00392 for(x=w;x--;)
00393 {
00394 ptrz = ptr;
00395 GetColor(&ptrz,&R,&G,&B,&A);
00396 R = Lut[R];
00397 G = Lut[G];
00398 B = Lut[B];
00399 PutColor(&ptr,R,G,B,A);
00400 }
00401 ptr += xtra;
00402 }
00403 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 3 ) );
00404 break;
00405 }
00406
00407 case 4:
00408 {
00409 uint32 *ptr;
00410 uint32 R,G,B,A;
00411 ptr = Bits;
00412 for(y=h;y--;)
00413 {
00414 for(x=w;x--;)
00415 {
00416 Decompose(*ptr,&R,&G,&B,&A);
00417 R = Lut[R];
00418 G = Lut[G];
00419 B = Lut[B];
00420 *ptr++ = Compose(R,G,B,A);
00421 }
00422 ptr += xtra;
00423 }
00424 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 4 ) );
00425 break;
00426 }
00427 }
00428 }
00429
00430 return GE_TRUE;
00431 }
00432
00433
00434
00435 void geBitmap_GammaCorrect_Data_565_RGB(void * Bits,geBitmap_Info * pInfo)
00436 {
00437 uint32 w,h,xtra,x,y;
00438 uint16 * ptr;
00439
00440 if ( ComputedGamma_Lut != ComputedGamma_565_RGB )
00441 {
00442 uint32 r,g,b,R,G,B;
00443 uint32 ipel,opel;
00444
00445
00446 for(r=0;r<32;r++)
00447 {
00448 R = Gamma_Lut[ (r<<3) ] >> 3;
00449 for(g=0;g<64;g++)
00450 {
00451 G = Gamma_Lut[ (g<<2) ] >> 2;
00452 for(b=0;b<32;b++)
00453 {
00454 B = Gamma_Lut[ (b<<3) ] >> 3;
00455 ipel = (r<<11) + (g<<5) + b;
00456 opel = (R<<11) + (G<<5) + B;
00457 assert( opel < 65536 );
00458 Gamma_565_RGB[ipel] = (uint16)opel;
00459 }
00460 }
00461 }
00462 ComputedGamma_565_RGB = ComputedGamma_Lut;
00463 }
00464
00465 w = pInfo->Width;
00466 h = pInfo->Height;
00467 xtra = pInfo->Stride - w;
00468 ptr = Bits;
00469
00470 if ( pInfo->HasColorKey )
00471 {
00472 uint16 ck;
00473 ck = (uint16) pInfo->ColorKey;
00474
00475 for(y=h;y--;)
00476 {
00477 for(x=w;x--;)
00478 {
00479 if ( *ptr != ck )
00480 {
00481 *ptr = Gamma_565_RGB[ *ptr ];
00482 if ( *ptr == ck )
00483 *ptr ^= 1;
00484 }
00485 ptr ++;
00486 }
00487 ptr += xtra;
00488 }
00489 }
00490 else
00491 {
00492 for(y=h;y--;)
00493 {
00494 for(x=w;x--;)
00495 {
00496 *ptr++ = Gamma_565_RGB[ *ptr ];
00497 }
00498 ptr += xtra;
00499 }
00500 }
00501
00502 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) );
00503
00504 }
00505
00506 void geBitmap_GammaCorrect_Data_4444_ARGB(void * Bits,geBitmap_Info * pInfo)
00507 {
00508 uint32 w,h,xtra,x,y;
00509 uint16 * ptr;
00510
00511 if ( ComputedGamma_Lut != ComputedGamma_4444_ARGB )
00512 {
00513 uint32 r,g,b,a,R,G,B;
00514 uint32 ipel,opel;
00515
00516
00517 for(r=0;r<16;r++)
00518 {
00519 R = Gamma_Lut[r<<4] >> 4;
00520 for(g=0;g<16;g++)
00521 {
00522 G = Gamma_Lut[g<<4] >> 4;
00523 for(b=0;b<16;b++)
00524 {
00525 B = Gamma_Lut[b<<4] >> 4;
00526 for(a=0;a<16;a++)
00527 {
00528 ipel = (a<<12) + (r<<8) + (g<<4) + b;
00529 opel = (a<<12) + (R<<8) + (G<<4) + B;
00530 assert( opel < 65536 );
00531 Gamma_4444_ARGB[ipel] = (uint16)opel;
00532 }
00533 }
00534 }
00535 }
00536 ComputedGamma_4444_ARGB = ComputedGamma_Lut;
00537 }
00538
00539 w = pInfo->Width;
00540 h = pInfo->Height;
00541 xtra = pInfo->Stride - w;
00542 ptr = Bits;
00543
00544 if ( pInfo->HasColorKey )
00545 {
00546 uint16 ck;
00547 ck = (uint16) pInfo->ColorKey;
00548
00549 for(y=h;y--;)
00550 {
00551 for(x=w;x--;)
00552 {
00553 if ( *ptr != ck )
00554 {
00555 *ptr = Gamma_4444_ARGB[ *ptr ];
00556 if ( *ptr == ck )
00557 *ptr ^= 1;
00558 }
00559 ptr ++;
00560 }
00561 ptr += xtra;
00562 }
00563 }
00564 else
00565 {
00566 for(y=h;y--;)
00567 {
00568 for(x=w;x--;)
00569 {
00570 *ptr++ = Gamma_4444_ARGB[ *ptr ];
00571 }
00572 ptr += xtra;
00573 }
00574 }
00575
00576 assert( (int)(ptr) == ( ((int)Bits) + pInfo->Height * pInfo->Stride * 2 ) );
00577 }
00578
00579 void geBitmap_Gamma_Compute_Lut(double Gamma)
00580 {
00581 uint32 c=0,gc=0,lgc=0;
00582
00583 for(c=0;c<256;c++)
00584 {
00585 gc = (uint32)( 255.0 * pow( c * (1.0/255.0) , 1.0 / Gamma ) + 0.4 );
00586 if ( gc > 255 ) gc = 255;
00587 Gamma_Lut[c] = gc;
00588 assert( lgc <= gc );
00589 for(lgc;lgc<=gc;lgc++)
00590 Gamma_Lut_Inverse[lgc] = c;
00591 lgc = gc;
00592 }
00593 for(gc;gc<256;gc++)
00594 Gamma_Lut_Inverse[gc] = 255;
00595
00596 Gamma_Lut[0] = 0;
00597 Gamma_Lut_Inverse[0] = 0;
00598 Gamma_Lut[255] = 255;
00599 Gamma_Lut_Inverse[255] = 255;
00600
00601 ComputedGamma_Lut = (geFloat)Gamma;
00602 }
00603
00604