Main Page | Alphabetical List | Compound List | File List | Compound Members | File Members

bitmap_gamma.c

Go to the documentation of this file.
00001 /****************************************************************************************/
00002 /*  Bitmap_Gamma.c                                                                      */
00003 /*                                                                                      */
00004 /*  Author: Charles Bloom                                                               */
00005 /*  Description:  The Bitmap_Gamma_Apply function                                       */
00006 /*                                      Fast Gamma correction routines for various pixel formats                        */
00007 /*                                                                                      */
00008 /*  The contents of this file are subject to the Genesis3D Public License               */
00009 /*  Version 1.01 (the "License"); you may not use this file except in                   */
00010 /*  compliance with the License. You may obtain a copy of the License at                */
00011 /*  http://www.genesis3d.com                                                            */
00012 /*                                                                                      */
00013 /*  Software distributed under the License is distributed on an "AS IS"                 */
00014 /*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
00015 /*  the License for the specific language governing rights and limitations              */
00016 /*  under the License.                                                                  */
00017 /*                                                                                      */
00018 /*  The Original Code is Genesis3D, released March 25, 1999.                            */
00019 /*Genesis3D Version 1.1 released November 15, 1999                            */
00020 /*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
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 ) // assume they meant 1.0f
00062                 return GE_TRUE;
00063 
00064         // Gamma only works on driver data
00065 
00066         // do-nothing gamma:
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 )   // nothing to do
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                 // gamma correct the palette
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                 // old: work directly on the driver bits so that
00117                 //              we don't get any DriverDataChanged or Modified[mip] flags !
00118                 // new: just use UnLock_NoChange
00119 
00120                 assert(Bitmap->Driver);
00121                 assert(Bitmap->DriverHandle);
00122 
00123                 //if ( mipCount > 1 ) ; true, but pointless
00124                 //      assert(mipCount == 4);
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                 // compute 565 lookup table
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                 // compute 4444 lookup table
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 /*}{*******************************************************/

Generated on Tue Sep 30 12:35:18 2003 for GTestAndEngine by doxygen 1.3.2