This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_gamma.c
210 lines (185 loc) · 5.91 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 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
11
12
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
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
25
/* Gamma correction support */
26
#ifdef HAVE_MATH_H
27
#include <math.h> /* Used for calculating gamma ramps */
28
29
#else
/* Math routines from uClibc: http://www.uclibc.org */
30
31
32
33
34
35
36
37
#include "math_private.h"
#include "e_sqrt.h"
#include "e_pow.h"
#include "e_log.h"
#define pow(x, y) __ieee754_pow(x, y)
#define log(x) __ieee754_log(x)
#endif
38
39
40
#include "SDL_sysvideo.h"
41
static void
42
CalculateGammaRamp(float gamma, Uint16 * ramp)
43
{
44
45
46
47
48
49
50
51
52
53
int i;
/* 0.0 gamma is all black */
if (gamma <= 0.0f) {
for (i = 0; i < 256; ++i) {
ramp[i] = 0;
}
return;
} else
/* 1.0 gamma is identity */
54
if (gamma == 1.0f) {
55
56
57
58
59
60
61
62
63
64
for (i = 0; i < 256; ++i) {
ramp[i] = (i << 8) | i;
}
return;
} else
/* Calculate a real gamma ramp */
{
int value;
gamma = 1.0f / gamma;
for (i = 0; i < 256; ++i) {
65
value = (int) (pow((double) i / 256.0, gamma) * 65535.0 + 0.5);
66
67
68
69
70
71
if (value > 65535) {
value = 65535;
}
ramp[i] = (Uint16) value;
}
}
72
}
73
static void
74
CalculateGammaFromRamp(float *gamma, Uint16 * ramp)
75
{
76
77
78
79
80
81
82
83
84
85
86
/* The following is adapted from a post by Garrett Bass on OpenGL
Gamedev list, March 4, 2000.
*/
float sum = 0.0f;
int i, count = 0;
*gamma = 1.0;
for (i = 1; i < 256; ++i) {
if ((ramp[i] != 0) && (ramp[i] != 65535)) {
double B = (double) i / 256.0;
double A = ramp[i] / 65535.0;
87
sum += (float) (log(A) / log(B));
88
89
90
91
92
93
count++;
}
}
if (count && sum > 0.0f) {
*gamma = 1.0f / (sum / count);
}
94
95
}
96
int
97
SDL_SetGamma(float red, float green, float blue)
98
{
99
Uint16 ramp[3][256];
100
101
102
103
CalculateGammaRamp(red, ramp[0]);
CalculateGammaRamp(green, ramp[1]);
CalculateGammaRamp(blue, ramp[2]);
104
105
return SDL_SetGammaRamp(ramp[0], ramp[1], ramp[2]);
106
107
108
109
110
}
/* Calculating the gamma by integrating the gamma ramps isn't exact,
so this function isn't officially supported.
*/
111
int
112
SDL_GetGamma(float *red, float *green, float *blue)
113
{
114
int succeeded;
115
Uint16 ramp[3][256];
116
117
118
119
120
121
succeeded = SDL_GetGammaRamp(ramp[0], ramp[1], ramp[2]);
if (succeeded >= 0) {
CalculateGammaFromRamp(red, ramp[0]);
CalculateGammaFromRamp(green, ramp[1]);
CalculateGammaFromRamp(blue, ramp[2]);
122
123
}
return succeeded;
124
125
}
126
int
127
128
SDL_SetGammaRamp(const Uint16 * red, const Uint16 * green,
const Uint16 * blue)
129
{
130
SDL_VideoDevice *_this = SDL_GetVideoDevice();
131
132
133
int succeeded;
/* Lazily allocate the gamma tables */
134
135
if (!SDL_CurrentDisplay.gamma) {
SDL_GetGammaRamp(NULL, NULL, NULL);
136
137
138
139
}
/* Fill the gamma table with the new values */
if (red) {
140
141
SDL_memcpy(&SDL_CurrentDisplay.gamma[0 * 256], red,
256 * sizeof(*SDL_CurrentDisplay.gamma));
142
143
}
if (green) {
144
145
SDL_memcpy(&SDL_CurrentDisplay.gamma[1 * 256], green,
256 * sizeof(*SDL_CurrentDisplay.gamma));
146
147
}
if (blue) {
148
149
SDL_memcpy(&SDL_CurrentDisplay.gamma[2 * 256], blue,
256 * sizeof(*SDL_CurrentDisplay.gamma));
150
151
152
153
}
/* Try to set the gamma ramp in the driver */
succeeded = -1;
154
155
156
if (_this && _this->SetDisplayGammaRamp) {
succeeded =
_this->SetDisplayGammaRamp(_this, SDL_CurrentDisplay.gamma);
157
} else {
158
SDL_SetError("Gamma ramp manipulation not supported");
159
160
}
return succeeded;
161
162
}
163
int
164
SDL_GetGammaRamp(Uint16 * red, Uint16 * green, Uint16 * blue)
165
{
166
SDL_VideoDevice *_this = SDL_GetVideoDevice();
167
168
/* Lazily allocate the gamma table */
169
170
171
172
173
if (!SDL_CurrentDisplay.gamma) {
size_t rampsize = (3 * 256 * sizeof(*SDL_CurrentDisplay.gamma));
SDL_CurrentDisplay.gamma = SDL_malloc(rampsize * 2);
if (!SDL_CurrentDisplay.gamma) {
174
SDL_OutOfMemory();
175
176
return -1;
}
177
if (_this && _this->GetDisplayGammaRamp) {
178
/* Get the real hardware gamma */
179
_this->GetDisplayGammaRamp(_this, SDL_CurrentDisplay.gamma);
180
181
182
183
} else {
/* Assume an identity gamma */
int i;
for (i = 0; i < 256; ++i) {
184
185
186
SDL_CurrentDisplay.gamma[0 * 256 + i] = (i << 8) | i;
SDL_CurrentDisplay.gamma[1 * 256 + i] = (i << 8) | i;
SDL_CurrentDisplay.gamma[2 * 256 + i] = (i << 8) | i;
187
188
}
}
189
190
191
SDL_CurrentDisplay.saved_gamma = SDL_CurrentDisplay.gamma + (3 * 256);
SDL_memcpy(SDL_CurrentDisplay.saved_gamma, SDL_CurrentDisplay.gamma,
rampsize);
192
193
194
195
}
/* Just copy from our internal table */
if (red) {
196
SDL_memcpy(red, &SDL_CurrentDisplay.gamma[0 * 256],
197
256 * sizeof(*red));
198
199
}
if (green) {
200
SDL_memcpy(green, &SDL_CurrentDisplay.gamma[1 * 256],
201
256 * sizeof(*green));
202
203
}
if (blue) {
204
SDL_memcpy(blue, &SDL_CurrentDisplay.gamma[2 * 256],
205
256 * sizeof(*blue));
206
207
}
return 0;
208
}
209
210
/* vi: set ts=4 sw=4 expandtab: */