diff options
Diffstat (limited to 'apps/plugins/sdl/src/video/SDL_gamma.c')
-rw-r--r-- | apps/plugins/sdl/src/video/SDL_gamma.c | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/video/SDL_gamma.c b/apps/plugins/sdl/src/video/SDL_gamma.c new file mode 100644 index 0000000000..4fd037019f --- /dev/null +++ b/apps/plugins/sdl/src/video/SDL_gamma.c | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 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 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* Gamma correction support */ | ||
25 | |||
26 | #ifdef HAVE_MATH_H | ||
27 | #include <math.h> /* Used for calculating gamma ramps */ | ||
28 | #else | ||
29 | /* Math routines from uClibc: http://www.uclibc.org */ | ||
30 | #include "math_private.h" | ||
31 | #include "e_sqrt.h" | ||
32 | #include "e_pow.h" | ||
33 | #include "e_log.h" | ||
34 | #define pow(x, y) __ieee754_pow(x, y) | ||
35 | #define log(x) __ieee754_log(x) | ||
36 | #endif | ||
37 | |||
38 | #include "SDL_sysvideo.h" | ||
39 | |||
40 | |||
41 | static void CalculateGammaRamp(float gamma, Uint16 *ramp) | ||
42 | { | ||
43 | int i; | ||
44 | |||
45 | /* 0.0 gamma is all black */ | ||
46 | if ( gamma <= 0.0f ) { | ||
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.0f ) { | ||
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) | ||
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.0f; | ||
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 > 0.0f ) { | ||
89 | *gamma = 1.0f / (sum / count); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | int SDL_SetGamma(float red, float green, float blue) | ||
94 | { | ||
95 | int succeeded; | ||
96 | SDL_VideoDevice *video = current_video; | ||
97 | SDL_VideoDevice *this = current_video; | ||
98 | |||
99 | succeeded = -1; | ||
100 | /* Prefer using SetGammaRamp(), as it's more flexible */ | ||
101 | { | ||
102 | Uint16 ramp[3][256]; | ||
103 | |||
104 | CalculateGammaRamp(red, ramp[0]); | ||
105 | CalculateGammaRamp(green, ramp[1]); | ||
106 | CalculateGammaRamp(blue, ramp[2]); | ||
107 | succeeded = SDL_SetGammaRamp(ramp[0], ramp[1], ramp[2]); | ||
108 | } | ||
109 | if ( (succeeded < 0) && video->SetGamma ) { | ||
110 | SDL_ClearError(); | ||
111 | succeeded = video->SetGamma(this, red, green, blue); | ||
112 | } | ||
113 | return succeeded; | ||
114 | } | ||
115 | |||
116 | /* Calculating the gamma by integrating the gamma ramps isn't exact, | ||
117 | so this function isn't officially supported. | ||
118 | */ | ||
119 | int SDL_GetGamma(float *red, float *green, float *blue) | ||
120 | { | ||
121 | int succeeded; | ||
122 | SDL_VideoDevice *video = current_video; | ||
123 | SDL_VideoDevice *this = current_video; | ||
124 | |||
125 | succeeded = -1; | ||
126 | /* Prefer using GetGammaRamp(), as it's more flexible */ | ||
127 | { | ||
128 | Uint16 ramp[3][256]; | ||
129 | |||
130 | succeeded = SDL_GetGammaRamp(ramp[0], ramp[1], ramp[2]); | ||
131 | if ( succeeded >= 0 ) { | ||
132 | CalculateGammaFromRamp(red, ramp[0]); | ||
133 | CalculateGammaFromRamp(green, ramp[1]); | ||
134 | CalculateGammaFromRamp(blue, ramp[2]); | ||
135 | } | ||
136 | } | ||
137 | if ( (succeeded < 0) && video->GetGamma ) { | ||
138 | SDL_ClearError(); | ||
139 | succeeded = video->GetGamma(this, red, green, blue); | ||
140 | } | ||
141 | return succeeded; | ||
142 | } | ||
143 | |||
144 | int SDL_SetGammaRamp(const Uint16 *red, const Uint16 *green, const Uint16 *blue) | ||
145 | { | ||
146 | int succeeded; | ||
147 | SDL_VideoDevice *video = current_video; | ||
148 | SDL_VideoDevice *this = current_video; | ||
149 | SDL_Surface *screen = SDL_PublicSurface; | ||
150 | |||
151 | /* Verify the screen parameter */ | ||
152 | if ( !screen ) { | ||
153 | SDL_SetError("No video mode has been set"); | ||
154 | return -1; | ||
155 | } | ||
156 | |||
157 | /* Lazily allocate the gamma tables */ | ||
158 | if ( ! video->gamma ) { | ||
159 | SDL_GetGammaRamp(0, 0, 0); | ||
160 | } | ||
161 | |||
162 | /* Fill the gamma table with the new values */ | ||
163 | if ( red ) { | ||
164 | SDL_memcpy(&video->gamma[0*256], red, 256*sizeof(*video->gamma)); | ||
165 | } | ||
166 | if ( green ) { | ||
167 | SDL_memcpy(&video->gamma[1*256], green, 256*sizeof(*video->gamma)); | ||
168 | } | ||
169 | if ( blue ) { | ||
170 | SDL_memcpy(&video->gamma[2*256], blue, 256*sizeof(*video->gamma)); | ||
171 | } | ||
172 | |||
173 | /* Gamma correction always possible on split palettes */ | ||
174 | if ( (screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) { | ||
175 | SDL_Palette *pal = screen->format->palette; | ||
176 | |||
177 | /* If physical palette has been set independently, use it */ | ||
178 | if(video->physpal) | ||
179 | pal = video->physpal; | ||
180 | |||
181 | SDL_SetPalette(screen, SDL_PHYSPAL, | ||
182 | pal->colors, 0, pal->ncolors); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /* Try to set the gamma ramp in the driver */ | ||
187 | succeeded = -1; | ||
188 | if ( video->SetGammaRamp ) { | ||
189 | succeeded = video->SetGammaRamp(this, video->gamma); | ||
190 | } else { | ||
191 | SDL_SetError("Gamma ramp manipulation not supported"); | ||
192 | } | ||
193 | return succeeded; | ||
194 | } | ||
195 | |||
196 | int SDL_GetGammaRamp(Uint16 *red, Uint16 *green, Uint16 *blue) | ||
197 | { | ||
198 | SDL_VideoDevice *video = current_video; | ||
199 | SDL_VideoDevice *this = current_video; | ||
200 | |||
201 | /* Lazily allocate the gamma table */ | ||
202 | if ( ! video->gamma ) { | ||
203 | video->gamma = SDL_malloc(3*256*sizeof(*video->gamma)); | ||
204 | if ( ! video->gamma ) { | ||
205 | SDL_OutOfMemory(); | ||
206 | return -1; | ||
207 | } | ||
208 | if ( video->GetGammaRamp ) { | ||
209 | /* Get the real hardware gamma */ | ||
210 | video->GetGammaRamp(this, video->gamma); | ||
211 | } else { | ||
212 | /* Assume an identity gamma */ | ||
213 | int i; | ||
214 | for ( i=0; i<256; ++i ) { | ||
215 | video->gamma[0*256+i] = (i << 8) | i; | ||
216 | video->gamma[1*256+i] = (i << 8) | i; | ||
217 | video->gamma[2*256+i] = (i << 8) | i; | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | /* Just copy from our internal table */ | ||
223 | if ( red ) { | ||
224 | SDL_memcpy(red, &video->gamma[0*256], 256*sizeof(*red)); | ||
225 | } | ||
226 | if ( green ) { | ||
227 | SDL_memcpy(green, &video->gamma[1*256], 256*sizeof(*green)); | ||
228 | } | ||
229 | if ( blue ) { | ||
230 | SDL_memcpy(blue, &video->gamma[2*256], 256*sizeof(*blue)); | ||
231 | } | ||
232 | return 0; | ||
233 | } | ||