src/video/SDL_gamma.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. CalculateGammaRamp
  2. CalculateGammaFromRamp
  3. SDL_SetGamma
  4. SDL_GetGamma
  5. SDL_SetGammaRamp
  6. SDL_GetGammaRamp

   1 /*
   2     SDL - Simple DirectMedia Layer
   3     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
   4 
   5     This library is free software; you can redistribute it and/or
   6     modify it under the terms of the GNU Library General Public
   7     License as published by the Free Software Foundation; either
   8     version 2 of the License, or (at your option) any later version.
   9 
  10     This library is distributed in the hope that it will be useful,
  11     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13     Library General Public License for more details.
  14 
  15     You should have received a copy of the GNU Library General Public
  16     License along with this library; if not, write to the Free
  17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 
  19     Sam Lantinga
  20     slouken@devolution.com
  21 */
  22 
  23 #ifdef SAVE_RCSID
  24 static char rcsid =
  25  "@(#) $Id: SDL_gamma.c,v 1.1.2.12 2001/02/10 07:20:05 hercules Exp $";
  26 #endif
  27 
  28 /* Gamma correction support */
  29 
  30 #define USE_MATH_H      /* Used for calculating gamma ramps */
  31 
  32 #ifdef USE_MATH_H
  33 #include <math.h>
  34 #endif
  35 #include <stdlib.h>
  36 
  37 #include "SDL_error.h"
  38 #include "SDL_sysvideo.h"
  39 
  40 #ifdef USE_MATH_H
  41 static void CalculateGammaRamp(float gamma, Uint16 *ramp)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         int i;
  44 
  45         /* 0.0 gamma is all black */
  46         if ( gamma <= 0.0 ) {
  47                 for ( i=0; i<256; ++i ) {
  48                         ramp[i] = 0;
  49                 }
  50                 return;
  51         } else
  52         /* 1.0 gamma is identity */
  53         if ( gamma == 1.0 ) {
  54                 for ( i=0; i<256; ++i ) {
  55                         ramp[i] = (i << 8) | i;
  56                 }
  57                 return;
  58         } else
  59         /* Calculate a real gamma ramp */
  60         { int value;
  61                 gamma = 1.0f / gamma;
  62                 for ( i=0; i<256; ++i ) {
  63                         value = (int)(pow((double)i/256.0, gamma)*65535.0+0.5);
  64                         if ( value > 65535 ) {
  65                                 value = 65535;
  66                         }
  67                         ramp[i] = (Uint16)value;
  68                 }
  69         }
  70 }
  71 static void CalculateGammaFromRamp(float *gamma, Uint16 *ramp)
     /* [<][>][^][v][top][bottom][index][help] */
  72 {
  73         /* The following is adapted from a post by Garrett Bass on OpenGL
  74            Gamedev list, March 4, 2000.
  75          */
  76         float sum = 0.0;
  77         int i, count = 0;
  78 
  79         *gamma = 1.0;
  80         for ( i = 1; i < 256; ++i ) {
  81             if ( (ramp[i] != 0) && (ramp[i] != 65535) ) {
  82                 double B = (double)i / 256.0;
  83                 double A = ramp[i] / 65535.0;
  84                 sum += (float) ( log(A) / log(B) );
  85                 count++;
  86             }
  87         }
  88         if ( count && sum ) {
  89                 *gamma = 1.0f / (sum / count);
  90         }
  91 }
  92 #endif /* USE_MATH_H */
  93 
  94 int SDL_SetGamma(float red, float green, float blue)
     /* [<][>][^][v][top][bottom][index][help] */
  95 {
  96         int succeeded;
  97         SDL_VideoDevice *video = current_video;
  98         SDL_VideoDevice *this  = current_video; 
  99 
 100         succeeded = -1;
 101 #ifdef USE_MATH_H
 102         /* Prefer using SetGammaRamp(), as it's more flexible */
 103         {
 104                 Uint16 ramp[3][256];
 105 
 106                 CalculateGammaRamp(red, ramp[0]);
 107                 CalculateGammaRamp(green, ramp[1]);
 108                 CalculateGammaRamp(blue, ramp[2]);
 109                 succeeded = SDL_SetGammaRamp(ramp[0], ramp[1], ramp[2]);
 110         }
 111 #else
 112         SDL_SetError("Gamma correction not supported");
 113 #endif
 114         if ( (succeeded < 0) && video->SetGamma ) {
 115                 SDL_ClearError();
 116                 succeeded = video->SetGamma(this, red, green, blue);
 117         }
 118         return succeeded;
 119 }
 120 
 121 /* Calculating the gamma by integrating the gamma ramps isn't exact,
 122    so this function isn't officially supported.
 123 */
 124 int SDL_GetGamma(float *red, float *green, float *blue)
     /* [<][>][^][v][top][bottom][index][help] */
 125 {
 126         int succeeded;
 127         SDL_VideoDevice *video = current_video;
 128         SDL_VideoDevice *this  = current_video; 
 129 
 130         succeeded = -1;
 131 #ifdef USE_MATH_H
 132         /* Prefer using GetGammaRamp(), as it's more flexible */
 133         {
 134                 Uint16 ramp[3][256];
 135 
 136                 succeeded = SDL_GetGammaRamp(ramp[0], ramp[1], ramp[2]);
 137                 if ( succeeded >= 0 ) {
 138                         CalculateGammaFromRamp(red, ramp[0]);
 139                         CalculateGammaFromRamp(green, ramp[1]);
 140                         CalculateGammaFromRamp(blue, ramp[2]);
 141                 }
 142         }
 143 #else
 144         SDL_SetError("Gamma correction not supported");
 145 #endif
 146         if ( (succeeded < 0) && video->GetGamma ) {
 147                 SDL_ClearError();
 148                 succeeded = video->GetGamma(this, red, green, blue);
 149         }
 150         return succeeded;
 151 }
 152 
 153 int SDL_SetGammaRamp(Uint16 *red, Uint16 *green, Uint16 *blue)
     /* [<][>][^][v][top][bottom][index][help] */
 154 {
 155         int succeeded;
 156         SDL_VideoDevice *video = current_video;
 157         SDL_VideoDevice *this  = current_video; 
 158         SDL_Surface *screen = SDL_PublicSurface;
 159 
 160         /* Verify the screen parameter */
 161         if ( !screen ) {
 162                 SDL_SetError("No video mode has been set");
 163                 return -1;
 164         }
 165 
 166         /* Lazily allocate the gamma tables */
 167         if ( ! video->gamma ) {
 168                 SDL_GetGammaRamp(0, 0, 0);
 169         }
 170 
 171         /* Fill the gamma table with the new values */
 172         if ( red ) {
 173                 memcpy(&video->gamma[0*256], red, 256*sizeof(*video->gamma));
 174         }
 175         if ( green ) {
 176                 memcpy(&video->gamma[1*256], green, 256*sizeof(*video->gamma));
 177         }
 178         if ( blue ) {
 179                 memcpy(&video->gamma[2*256], blue, 256*sizeof(*video->gamma));
 180         }
 181 
 182         /* Gamma correction always possible on split palettes */
 183         if ( (screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) {
 184                 SDL_Palette *pal = screen->format->palette;
 185 
 186                 /* If physical palette has been set independently, use it */
 187                 if(video->physpal)
 188                         pal = video->physpal;
 189                       
 190                 SDL_SetPalette(screen, SDL_PHYSPAL,
 191                                pal->colors, 0, pal->ncolors);
 192                 return 0;
 193         }
 194 
 195         /* Try to set the gamma ramp in the driver */
 196         succeeded = -1;
 197         if ( video->SetGammaRamp ) {
 198                 succeeded = video->SetGammaRamp(this, video->gamma);
 199         } else {
 200                 SDL_SetError("Gamma ramp manipulation not supported");
 201         }
 202         return succeeded;
 203 }
 204 
 205 int SDL_GetGammaRamp(Uint16 *red, Uint16 *green, Uint16 *blue)
     /* [<][>][^][v][top][bottom][index][help] */
 206 {
 207         SDL_VideoDevice *video = current_video;
 208         SDL_VideoDevice *this  = current_video; 
 209 
 210         /* Lazily allocate the gamma table */
 211         if ( ! video->gamma ) {
 212                 video->gamma = malloc(3*256*sizeof(*video->gamma));
 213                 if ( ! video->gamma ) {
 214                         SDL_OutOfMemory();
 215                         return -1;
 216                 }
 217                 if ( video->GetGammaRamp ) {
 218                         /* Get the real hardware gamma */
 219                         video->GetGammaRamp(this, video->gamma);
 220                 } else {
 221                         /* Assume an identity gamma */
 222                         int i;
 223                         for ( i=0; i<256; ++i ) {
 224                                 video->gamma[0*256+i] = (i << 8) | i;
 225                                 video->gamma[1*256+i] = (i << 8) | i;
 226                                 video->gamma[2*256+i] = (i << 8) | i;
 227                         }
 228                 }
 229         }
 230 
 231         /* Just copy from our internal table */
 232         if ( red ) {
 233                 memcpy(red, &video->gamma[0*256], 256*sizeof(*red));
 234         }
 235         if ( green ) {
 236                 memcpy(green, &video->gamma[1*256], 256*sizeof(*green));
 237         }
 238         if ( blue ) {
 239                 memcpy(blue, &video->gamma[2*256], 256*sizeof(*blue));
 240         }
 241         return 0;
 242 }

/* [<][>][^][v][top][bottom][index][help] */