Gamma support is back!
authorSam Lantinga <slouken@libsdl.org>
Fri, 11 Mar 2011 08:49:20 -0800
changeset 5466 006883d5fa51
parent 5465 46bd121b04a2
child 5467 1ca154e8d6a6
Gamma support is back! New API functions: SDL_SetWindowBrightness() SDL_GetWindowBrightness() SDL_SetWindowGammaRamp() SDL_GetWindowGammaRamp() SDL_CalculateGammaRamp()
VisualC/tests/testgamma/testgamma_VS2008.vcproj
VisualC/tests/testgamma/testgamma_VS2010.vcxproj
include/SDL_pixels.h
include/SDL_video.h
src/SDL_compat.c
src/video/SDL_pixels.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/cocoa/SDL_cocoavideo.m
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
src/video/windows/SDL_windowsvideo.c
src/video/windows/SDL_windowswindow.c
src/video/windows/SDL_windowswindow.h
src/video/x11/SDL_x11modes.c
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11video.h
src/video/x11/SDL_x11window.c
src/video/x11/SDL_x11window.h
test/Makefile.in
test/testgamma.c
--- a/VisualC/tests/testgamma/testgamma_VS2008.vcproj	Thu Mar 10 01:03:43 2011 -0800
+++ b/VisualC/tests/testgamma/testgamma_VS2008.vcproj	Fri Mar 11 08:49:20 2011 -0800
@@ -103,8 +103,8 @@
 			/>
 			<Tool
 				Name="VCPostBuildEventTool"
-				Description="Copy SDL"
-				CommandLine="copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll"
+				Description="Copy SDL and data files"
+				CommandLine="copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll&#x0D;&#x0A;copy $(SolutionDir)\..\test\sample.bmp $(ProjectDir)\sample.bmp"
 			/>
 		</Configuration>
 		<Configuration
@@ -195,8 +195,8 @@
 			/>
 			<Tool
 				Name="VCPostBuildEventTool"
-				Description="Copy SDL"
-				CommandLine="copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll"
+				Description="Copy SDL and data files"
+				CommandLine="copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll&#x0D;&#x0A;copy $(SolutionDir)\..\test\sample.bmp $(ProjectDir)\sample.bmp"
 			/>
 		</Configuration>
 	</Configurations>
--- a/VisualC/tests/testgamma/testgamma_VS2010.vcxproj	Thu Mar 10 01:03:43 2011 -0800
+++ b/VisualC/tests/testgamma/testgamma_VS2010.vcxproj	Fri Mar 11 08:49:20 2011 -0800
@@ -82,10 +82,11 @@
       <SubSystem>Windows</SubSystem>
     </Link>
     <PostBuildEvent>
-      <Command>copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll</Command>
+      <Command>copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll
+copy $(SolutionDir)\..\test\sample.bmp $(ProjectDir)\sample.bmp</Command>
     </PostBuildEvent>
     <PostBuildEvent>
-      <Message>Copy SDL</Message>
+      <Message>Copy SDL and data files</Message>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -125,10 +126,11 @@
       <SubSystem>Windows</SubSystem>
     </Link>
     <PostBuildEvent>
-      <Command>copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll</Command>
+      <Command>copy $(SolutionDir)\SDL\$(ConfigurationName)\SDL.dll $(TargetDir)\SDL.dll
+copy $(SolutionDir)\..\test\sample.bmp $(ProjectDir)\sample.bmp</Command>
     </PostBuildEvent>
     <PostBuildEvent>
-      <Message>Copy SDL</Message>
+      <Message>Copy SDL and data files</Message>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemGroup>
--- a/include/SDL_pixels.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/include/SDL_pixels.h	Fri Mar 11 08:49:20 2011 -0800
@@ -405,6 +405,12 @@
                                          Uint8 * r, Uint8 * g, Uint8 * b,
                                          Uint8 * a);
 
+/**
+ *  \brief Calculate a 256 entry gamma ramp for a gamma value.
+ */
+extern DECLSPEC void SDLCALL SDL_CalculateGammaRamp(float gamma, Uint16 * ramp);
+
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 /* *INDENT-OFF* */
--- a/include/SDL_video.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/include/SDL_video.h	Fri Mar 11 08:49:20 2011 -0800
@@ -605,6 +605,66 @@
 extern DECLSPEC SDL_bool SDLCALL SDL_GetWindowGrab(SDL_Window * window);
 
 /**
+ *  \brief Set the brightness (gamma correction) for a window.
+ *  
+ *  \return 0 on success, or -1 if setting the brightness isn't supported.
+ *  
+ *  \sa SDL_GetWindowBrightness()
+ *  \sa SDL_SetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowBrightness(SDL_Window * window, float brightness);
+
+/**
+ *  \brief Get the brightness (gamma correction) for a window.
+ *  
+ *  \return The last brightness value passed to SDL_SetWindowBrightness()
+ *  
+ *  \sa SDL_SetWindowBrightness()
+ */
+extern DECLSPEC float SDLCALL SDL_GetWindowBrightness(SDL_Window * window);
+
+/**
+ *  \brief Set the gamma ramp for a window.
+ *  
+ *  \param red The translation table for the red channel, or NULL.
+ *  \param green The translation table for the green channel, or NULL.
+ *  \param blue The translation table for the blue channel, or NULL.
+ *  
+ *  \return 0 on success, or -1 if gamma ramps are unsupported.
+ *  
+ *  Set the gamma translation table for the red, green, and blue channels
+ *  of the video hardware.  Each table is an array of 256 16-bit quantities,
+ *  representing a mapping between the input and output for that channel.
+ *  The input is the index into the array, and the output is the 16-bit
+ *  gamma value at that index, scaled to the output color precision.
+ *
+ *  \sa SDL_SetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_SetWindowGammaRamp(SDL_Window * window,
+                                                   const Uint16 * red,
+                                                   const Uint16 * green,
+                                                   const Uint16 * blue);
+
+/**
+ *  \brief Get the gamma ramp for a window.
+ *  
+ *  \param red   A pointer to a 256 element array of 16-bit quantities to hold 
+ *               the translation table for the red channel, or NULL.
+ *  \param green A pointer to a 256 element array of 16-bit quantities to hold 
+ *               the translation table for the green channel, or NULL.
+ *  \param blue  A pointer to a 256 element array of 16-bit quantities to hold 
+ *               the translation table for the blue channel, or NULL.
+ *   
+ *  \return 0 on success, or -1 if gamma ramps are unsupported.
+ *  
+ *  \sa SDL_SetWindowGammaRamp()
+ */
+extern DECLSPEC int SDLCALL SDL_GetWindowGammaRamp(SDL_Window * window,
+                                                   Uint16 * red,
+                                                   Uint16 * green,
+                                                   Uint16 * blue);
+
+/**
  *  \brief Destroy a window.
  */
 extern DECLSPEC void SDLCALL SDL_DestroyWindow(SDL_Window * window);
--- a/src/SDL_compat.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/SDL_compat.c	Fri Mar 11 08:49:20 2011 -0800
@@ -1702,22 +1702,34 @@
 int
 SDL_SetGamma(float red, float green, float blue)
 {
-    SDL_Unsupported();
-    return -1;
+    Uint16 red_ramp[256];
+    Uint16 green_ramp[256];
+    Uint16 blue_ramp[256];
+
+    SDL_CalculateGammaRamp(red, red_ramp);
+    if (green == red) {
+        SDL_memcpy(green_ramp, red_ramp, sizeof(red_ramp));
+    } else {
+        SDL_CalculateGammaRamp(green, green_ramp);
+    }
+    if (blue == red) {
+        SDL_memcpy(blue_ramp, red_ramp, sizeof(red_ramp));
+    } else {
+        SDL_CalculateGammaRamp(blue, blue_ramp);
+    }
+    return SDL_SetWindowGammaRamp(SDL_VideoWindow, red_ramp, green_ramp, blue_ramp);
 }
 
 int
 SDL_SetGammaRamp(const Uint16 * red, const Uint16 * green, const Uint16 * blue)
 {
-    SDL_Unsupported();
-    return -1;
+    return SDL_SetWindowGammaRamp(SDL_VideoWindow, red, green, blue);
 }
 
 int
 SDL_GetGammaRamp(Uint16 * red, Uint16 * green, Uint16 * blue)
 {
-    SDL_Unsupported();
-    return -1;
+    return SDL_GetWindowGammaRamp(SDL_VideoWindow, red, green, blue);
 }
 
 int
--- a/src/video/SDL_pixels.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/SDL_pixels.c	Fri Mar 11 08:49:20 2011 -0800
@@ -1041,4 +1041,36 @@
     }
 }
 
+void
+SDL_CalculateGammaRamp(float gamma, Uint16 * ramp)
+{
+    int i;
+
+    /* 0.0 gamma is all black */
+    if (gamma <= 0.0f) {
+        for (i = 0; i < 256; ++i) {
+            ramp[i] = 0;
+        }
+        return;
+    } else if (gamma == 1.0f) {
+        /* 1.0 gamma is identity */
+        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) {
+            value =
+                (int) (SDL_pow((double) i / 256.0, gamma) * 65535.0 + 0.5);
+            if (value > 65535) {
+                value = 65535;
+            }
+            ramp[i] = (Uint16) value;
+        }
+    }
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/SDL_sysvideo.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/SDL_sysvideo.h	Fri Mar 11 08:49:20 2011 -0800
@@ -81,6 +81,10 @@
 
     SDL_DisplayMode fullscreen_mode;
     
+    float brightness;
+    Uint16 *gamma;
+    Uint16 *saved_gamma;        /* (just offset into gamma) */
+
     SDL_Surface *surface;
     SDL_bool surface_valid;
 
@@ -184,6 +188,8 @@
     void (*MinimizeWindow) (_THIS, SDL_Window * window);
     void (*RestoreWindow) (_THIS, SDL_Window * window);
     void (*SetWindowFullscreen) (_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
+    int (*SetWindowGammaRamp) (_THIS, SDL_Window * window, const Uint16 * ramp);
+    int (*GetWindowGammaRamp) (_THIS, SDL_Window * window, Uint16 * ramp);
     void (*SetWindowGrab) (_THIS, SDL_Window * window);
     void (*DestroyWindow) (_THIS, SDL_Window * window);
     int (*CreateWindowFramebuffer) (_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch);
--- a/src/video/SDL_video.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/SDL_video.c	Fri Mar 11 08:49:20 2011 -0800
@@ -1161,6 +1161,7 @@
         }
     }
     window->flags = ((flags & CREATE_FLAGS) | SDL_WINDOW_HIDDEN);
+    window->brightness = 1.0f;
     window->next = _this->windows;
     if (_this->windows) {
         _this->windows->prev = window;
@@ -1193,6 +1194,7 @@
     window->magic = &_this->window_magic;
     window->id = _this->next_object_id++;
     window->flags = SDL_WINDOW_FOREIGN;
+    window->brightness = 1.0f;
     window->next = _this->windows;
     if (_this->windows) {
         _this->windows->prev = window;
@@ -1675,6 +1677,110 @@
     return _this->UpdateWindowFramebuffer(_this, window, rects, numrects);
 }
 
+int
+SDL_SetWindowBrightness(SDL_Window * window, float brightness)
+{
+    Uint16 ramp[256];
+    int status;
+
+    CHECK_WINDOW_MAGIC(window, -1);
+
+    SDL_CalculateGammaRamp(brightness, ramp);
+    status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
+    if (status == 0) {
+        window->brightness = brightness;
+    }
+    return status;
+}
+
+float
+SDL_GetWindowBrightness(SDL_Window * window)
+{
+    CHECK_WINDOW_MAGIC(window, 1.0f);
+
+    return window->brightness;
+}
+
+int
+SDL_SetWindowGammaRamp(SDL_Window * window, const Uint16 * red,
+                                            const Uint16 * green,
+                                            const Uint16 * blue)
+{
+    CHECK_WINDOW_MAGIC(window, -1);
+
+    if (!_this->SetWindowGammaRamp) {
+        SDL_Unsupported();
+        return -1;
+    }
+
+    if (!window->gamma) {
+        if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
+            return -1;
+        }
+    }
+
+    if (red) {
+        SDL_memcpy(&window->gamma[0*256], red, 256*sizeof(Uint16));
+    }
+    if (green) {
+        SDL_memcpy(&window->gamma[1*256], green, 256*sizeof(Uint16));
+    }
+    if (blue) {
+        SDL_memcpy(&window->gamma[2*256], blue, 256*sizeof(Uint16));
+    }
+    if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
+        return _this->SetWindowGammaRamp(_this, window, window->gamma);
+    } else {
+        return 0;
+    }
+}
+
+int
+SDL_GetWindowGammaRamp(SDL_Window * window, Uint16 * red,
+                                            Uint16 * green,
+                                            Uint16 * blue)
+{
+    CHECK_WINDOW_MAGIC(window, -1);
+
+    if (!window->gamma) {
+        int i;
+
+        window->gamma = (Uint16 *)SDL_malloc(256*6*sizeof(Uint16));
+        if (!window->gamma) {
+            SDL_OutOfMemory();
+            return -1;
+        }
+        window->saved_gamma = window->gamma + 3*256;
+
+        if (_this->GetWindowGammaRamp) {
+            if (_this->GetWindowGammaRamp(_this, window, window->gamma) < 0) {
+                return -1;
+            }
+        } else {
+            /* Create an identity gamma ramp */
+            for (i = 0; i < 256; ++i) {
+                Uint16 value = (Uint16)((i << 8) | i);
+
+                window->gamma[0*256+i] = value;
+                window->gamma[1*256+i] = value;
+                window->gamma[2*256+i] = value;
+            }
+        }
+        SDL_memcpy(window->saved_gamma, window->gamma, 3*256*sizeof(Uint16));
+    }
+
+    if (red) {
+        SDL_memcpy(red, &window->gamma[0*256], 256*sizeof(Uint16));
+    }
+    if (green) {
+        SDL_memcpy(green, &window->gamma[1*256], 256*sizeof(Uint16));
+    }
+    if (blue) {
+        SDL_memcpy(blue, &window->gamma[2*256], 256*sizeof(Uint16));
+    }
+    return 0;
+}
+
 static void
 SDL_UpdateWindowGrab(SDL_Window * window)
 {
@@ -1702,7 +1808,7 @@
 SDL_bool
 SDL_GetWindowGrab(SDL_Window * window)
 {
-    CHECK_WINDOW_MAGIC(window, 0);
+    CHECK_WINDOW_MAGIC(window, SDL_FALSE);
 
     return ((window->flags & SDL_WINDOW_INPUT_GRABBED) != 0);
 }
@@ -1745,8 +1851,12 @@
 void
 SDL_OnWindowFocusGained(SDL_Window * window)
 {
-    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
-        && _this->SetWindowGrab) {
+    if (window->gamma && _this->SetWindowGammaRamp) {
+        _this->SetWindowGammaRamp(_this, window, window->gamma);
+    }
+
+    if ((window->flags & SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN) &&
+        _this->SetWindowGrab) {
         _this->SetWindowGrab(_this, window);
     }
 }
@@ -1754,16 +1864,19 @@
 void
 SDL_OnWindowFocusLost(SDL_Window * window)
 {
-    /* If we're fullscreen on a single-head system and lose focus, minimize */
-    if ((window->flags & SDL_WINDOW_FULLSCREEN) &&
-        _this->num_displays == 1) {
-        SDL_MinimizeWindow(window);
+    if (window->gamma && _this->SetWindowGammaRamp) {
+        _this->SetWindowGammaRamp(_this, window, window->saved_gamma);
     }
 
-    if ((window->flags & (SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN))
-        && _this->SetWindowGrab) {
+    if ((window->flags & SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_FULLSCREEN) &&
+        _this->SetWindowGrab) {
         _this->SetWindowGrab(_this, window);
     }
+
+    /* If we're fullscreen on a single-head system and lose focus, minimize */
+    if ((window->flags & SDL_WINDOW_FULLSCREEN) && _this->num_displays == 1) {
+        SDL_MinimizeWindow(window);
+    }
 }
 
 SDL_Window *
@@ -1818,6 +1931,9 @@
     if (window->title) {
         SDL_free(window->title);
     }
+    if (window->gamma) {
+        SDL_free(window->gamma);
+    }
     while (window->data) {
         SDL_WindowUserData *data = window->data;
 
--- a/src/video/cocoa/SDL_cocoavideo.m	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/cocoa/SDL_cocoavideo.m	Fri Mar 11 08:49:20 2011 -0800
@@ -93,6 +93,8 @@
     device->MinimizeWindow = Cocoa_MinimizeWindow;
     device->RestoreWindow = Cocoa_RestoreWindow;
     device->SetWindowFullscreen = Cocoa_SetWindowFullscreen;
+    device->SetWindowGammaRamp = Cocoa_SetWindowGammaRamp;
+    device->GetWindowGammaRamp = Cocoa_GetWindowGammaRamp;
     device->SetWindowGrab = Cocoa_SetWindowGrab;
     device->DestroyWindow = Cocoa_DestroyWindow;
     device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
--- a/src/video/cocoa/SDL_cocoawindow.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/cocoa/SDL_cocoawindow.h	Fri Mar 11 08:49:20 2011 -0800
@@ -104,6 +104,8 @@
 extern void Cocoa_MinimizeWindow(_THIS, SDL_Window * window);
 extern void Cocoa_RestoreWindow(_THIS, SDL_Window * window);
 extern void Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
+extern int Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
+extern int Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
 extern void Cocoa_SetWindowGrab(_THIS, SDL_Window * window);
 extern void Cocoa_DestroyWindow(_THIS, SDL_Window * window);
 extern SDL_bool Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window,
--- a/src/video/cocoa/SDL_cocoawindow.m	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/cocoa/SDL_cocoawindow.m	Fri Mar 11 08:49:20 2011 -0800
@@ -856,7 +856,58 @@
     [pool release];
 }
 
-NSPoint origin;
+int
+Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
+{
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
+    const uint32_t tableSize = 256;
+    CGGammaValue redTable[tableSize];
+    CGGammaValue greenTable[tableSize];
+    CGGammaValue blueTable[tableSize];
+    uint32_t i;
+    float inv65535 = 1.0f / 65535.0f;
+
+    /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
+    for (i = 0; i < 256; i++) {
+        redTable[i] = ramp[0*256+i] * inv65535;
+        greenTable[i] = ramp[1*256+i] * inv65535;
+        blueTable[i] = ramp[2*256+i] * inv65535;
+    }
+
+    if (CGSetDisplayTransferByTable(display_id, tableSize,
+                                    redTable, greenTable, blueTable) != CGDisplayNoErr) {
+        SDL_SetError("CGSetDisplayTransferByTable()");
+        return -1;
+    }
+    return 0;
+}
+
+int
+Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
+{
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
+    const uint32_t tableSize = 256;
+    CGGammaValue redTable[tableSize];
+    CGGammaValue greenTable[tableSize];
+    CGGammaValue blueTable[tableSize];
+    uint32_t i, tableCopied;
+
+    if (CGGetDisplayTransferByTable(display_id, tableSize,
+                                    redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
+        SDL_SetError("CGGetDisplayTransferByTable()");
+        return -1;
+    }
+
+    for (i = 0; i < tableCopied; i++) {
+        ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
+        ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
+        ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
+    }
+    return 0;
+}
+
 void
 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
 {
--- a/src/video/windows/SDL_windowsvideo.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/windows/SDL_windowsvideo.c	Fri Mar 11 08:49:20 2011 -0800
@@ -125,6 +125,8 @@
     device->MinimizeWindow = WIN_MinimizeWindow;
     device->RestoreWindow = WIN_RestoreWindow;
     device->SetWindowFullscreen = WIN_SetWindowFullscreen;
+    device->SetWindowGammaRamp = WIN_SetWindowGammaRamp;
+    device->GetWindowGammaRamp = WIN_GetWindowGammaRamp;
     device->SetWindowGrab = WIN_SetWindowGrab;
     device->DestroyWindow = WIN_DestroyWindow;
     device->GetWindowWMInfo = WIN_GetWindowWMInfo;
--- a/src/video/windows/SDL_windowswindow.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/windows/SDL_windowswindow.c	Fri Mar 11 08:49:20 2011 -0800
@@ -571,6 +571,54 @@
     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS);
 }
 
+int
+WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
+{
+#ifdef _WIN32_WCE
+    SDL_Unsupported();
+    return -1;
+#else
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+    HDC hdc;
+    BOOL succeeded = FALSE;
+
+    hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+    if (hdc) {
+        succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
+        if (!succeeded) {
+            WIN_SetError("SetDeviceGammaRamp()");
+        }
+        DeleteDC(hdc);
+    }
+    return succeeded ? 0 : -1;
+#endif
+}
+
+int
+WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
+{
+#ifdef _WIN32_WCE
+    SDL_Unsupported();
+    return -1;
+#else
+    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
+    SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
+    HDC hdc;
+    BOOL succeeded = FALSE;
+
+    hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
+    if (hdc) {
+        succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
+        if (!succeeded) {
+            WIN_SetError("GetDeviceGammaRamp()");
+        }
+        DeleteDC(hdc);
+    }
+    return succeeded ? 0 : -1;
+#endif
+}
+
 void
 WIN_SetWindowGrab(_THIS, SDL_Window * window)
 {
--- a/src/video/windows/SDL_windowswindow.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/windows/SDL_windowswindow.h	Fri Mar 11 08:49:20 2011 -0800
@@ -59,6 +59,8 @@
 extern void WIN_MinimizeWindow(_THIS, SDL_Window * window);
 extern void WIN_RestoreWindow(_THIS, SDL_Window * window);
 extern void WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
+extern int WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
+extern int WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp);
 extern void WIN_SetWindowGrab(_THIS, SDL_Window * window);
 extern void WIN_DestroyWindow(_THIS, SDL_Window * window);
 extern SDL_bool WIN_GetWindowWMInfo(_THIS, SDL_Window * window,
--- a/src/video/x11/SDL_x11modes.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/x11/SDL_x11modes.c	Fri Mar 11 08:49:20 2011 -0800
@@ -47,7 +47,9 @@
     }
 
     depth = DefaultDepth(display, screen);
-    if (XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
+    if ((X11_UseDirectColorVisuals() &&
+         XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
+        XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
         XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
         XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
         return 0;
--- a/src/video/x11/SDL_x11video.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/x11/SDL_x11video.c	Fri Mar 11 08:49:20 2011 -0800
@@ -202,6 +202,7 @@
     device->MinimizeWindow = X11_MinimizeWindow;
     device->RestoreWindow = X11_RestoreWindow;
     device->SetWindowFullscreen = X11_SetWindowFullscreen;
+    device->SetWindowGammaRamp = X11_SetWindowGammaRamp;
     device->SetWindowGrab = X11_SetWindowGrab;
     device->DestroyWindow = X11_DestroyWindow;
     device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
@@ -383,4 +384,10 @@
     X11_QuitTouch(_this);
 }
 
+SDL_bool
+X11_UseDirectColorVisuals(void)
+{
+    return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
+}
+
 /* vim: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11video.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/x11/SDL_x11video.h	Fri Mar 11 08:49:20 2011 -0800
@@ -92,6 +92,8 @@
     SDL_bool selection_waiting;
 } SDL_VideoData;
 
+extern SDL_bool X11_UseDirectColorVisuals(void);
+
 #endif /* _SDL_x11video_h */
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11window.c	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/x11/SDL_x11window.c	Fri Mar 11 08:49:20 2011 -0800
@@ -175,6 +175,7 @@
             window->flags &= ~SDL_WINDOW_SHOWN;
         }
         data->visual = attrib.visual;
+        data->colormap = attrib.colormap;
     }
 
     {
@@ -316,7 +317,88 @@
     xattr.override_redirect = False;
     xattr.background_pixel = 0;
     xattr.border_pixel = 0;
-    xattr.colormap = XCreateColormap(display, RootWindow(display, screen), visual, AllocNone);
+
+    if (visual->class == DirectColor) {
+        Status status;
+        XColor *colorcells;
+        int i;
+        int ncolors;
+        int rmax, gmax, bmax;
+        int rmask, gmask, bmask;
+        int rshift, gshift, bshift;
+
+        xattr.colormap =
+            XCreateColormap(display, RootWindow(display, screen),
+                            visual, AllocAll);
+
+        /* If we can't create a colormap, then we must die */
+        if (!xattr.colormap) {
+            SDL_SetError("Could not create writable colormap");
+            return -1;
+        }
+
+        /* OK, we got a colormap, now fill it in as best as we can */
+        colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
+        if (!colorcells) {
+            SDL_OutOfMemory();
+            return -1;
+        }
+        ncolors = visual->map_entries;
+        rmax = 0xffff;
+        gmax = 0xffff;
+        bmax = 0xffff;
+
+        rshift = 0;
+        rmask = visual->red_mask;
+        while (0 == (rmask & 1)) {
+            rshift++;
+            rmask >>= 1;
+        }
+
+        gshift = 0;
+        gmask = visual->green_mask;
+        while (0 == (gmask & 1)) {
+            gshift++;
+            gmask >>= 1;
+        }
+
+        bshift = 0;
+        bmask = visual->blue_mask;
+        while (0 == (bmask & 1)) {
+            bshift++;
+            bmask >>= 1;
+        }
+
+        /* build the color table pixel values */
+        for (i = 0; i < ncolors; i++) {
+            Uint32 red = (rmax * i) / (ncolors - 1);
+            Uint32 green = (gmax * i) / (ncolors - 1);
+            Uint32 blue = (bmax * i) / (ncolors - 1);
+
+            Uint32 rbits = (rmask * i) / (ncolors - 1);
+            Uint32 gbits = (gmask * i) / (ncolors - 1);
+            Uint32 bbits = (bmask * i) / (ncolors - 1);
+
+            Uint32 pix =
+                (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
+
+            colorcells[i].pixel = pix;
+
+            colorcells[i].red = red;
+            colorcells[i].green = green;
+            colorcells[i].blue = blue;
+
+            colorcells[i].flags = DoRed | DoGreen | DoBlue;
+        }
+
+        XStoreColors(display, xattr.colormap, colorcells, ncolors);
+
+        SDL_free(colorcells);
+    } else {
+        xattr.colormap =
+            XCreateColormap(display, RootWindow(display, screen),
+                            visual, AllocNone);
+    }
 
     w = XCreateWindow(display, RootWindow(display, screen),
                       window->x, window->y, window->w, window->h,
@@ -861,6 +943,75 @@
     XFlush(display);
 }
 
+int
+X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
+{
+    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+    Display *display = data->videodata->display;
+    Visual *visual = data->visual;
+    Colormap colormap = data->colormap;
+    XColor *colorcells;
+    int ncolors;
+    int rmask, gmask, bmask;
+    int rshift, gshift, bshift;
+    int i, j;
+
+    if (visual->class != DirectColor) {
+        SDL_SetError("Window doesn't have DirectColor visual");
+        return -1;
+    }
+
+    ncolors = visual->map_entries;
+    colorcells = SDL_malloc(ncolors * sizeof(XColor));
+    if (!colorcells) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+
+    rshift = 0;
+    rmask = visual->red_mask;
+    while (0 == (rmask & 1)) {
+        rshift++;
+        rmask >>= 1;
+    }
+
+    gshift = 0;
+    gmask = visual->green_mask;
+    while (0 == (gmask & 1)) {
+        gshift++;
+        gmask >>= 1;
+    }
+
+    bshift = 0;
+    bmask = visual->blue_mask;
+    while (0 == (bmask & 1)) {
+        bshift++;
+        bmask >>= 1;
+    }
+
+    /* build the color table pixel values */
+    for (i = 0; i < ncolors; i++) {
+        Uint32 rbits = (rmask * i) / (ncolors - 1);
+        Uint32 gbits = (gmask * i) / (ncolors - 1);
+        Uint32 bbits = (bmask * i) / (ncolors - 1);
+        Uint32 pix = (rbits << rshift) | (gbits << gshift) | (bbits << bshift);
+
+        colorcells[i].pixel = pix;
+
+        colorcells[i].red = ramp[(0 * 256) + i];
+        colorcells[i].green = ramp[(1 * 256) + i];
+        colorcells[i].blue = ramp[(2 * 256) + i];
+
+        colorcells[i].flags = DoRed | DoGreen | DoBlue;
+    }
+
+    XStoreColors(display, colormap, colorcells, ncolors);
+    XFlush(display);
+    SDL_free(colorcells);
+
+    return 0;
+}
+
 void
 X11_SetWindowGrab(_THIS, SDL_Window * window)
 {
--- a/src/video/x11/SDL_x11window.h	Thu Mar 10 01:03:43 2011 -0800
+++ b/src/video/x11/SDL_x11window.h	Fri Mar 11 08:49:20 2011 -0800
@@ -29,6 +29,7 @@
     SDL_Window *window;
     Window xwindow;
     Visual *visual;
+    Colormap colormap;
 #ifndef NO_SHARED_MEMORY
     /* MIT shared memory extension information */
     SDL_bool use_mitshm;
@@ -55,6 +56,7 @@
 extern void X11_MinimizeWindow(_THIS, SDL_Window * window);
 extern void X11_RestoreWindow(_THIS, SDL_Window * window);
 extern void X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
+extern int X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp);
 extern void X11_SetWindowGrab(_THIS, SDL_Window * window);
 extern void X11_DestroyWindow(_THIS, SDL_Window * window);
 extern SDL_bool X11_GetWindowWMInfo(_THIS, SDL_Window * window,
--- a/test/Makefile.in	Thu Mar 10 01:03:43 2011 -0800
+++ b/test/Makefile.in	Fri Mar 11 08:49:20 2011 -0800
@@ -23,6 +23,7 @@
 	testerror$(EXE) \
 	testfile$(EXE) \
 	testfill$(EXE) \
+	testgamma$(EXE) \
 	testgesture$(EXE) \
 	testgl$(EXE) \
 	testgl2$(EXE) \
@@ -119,6 +120,9 @@
 testfill$(EXE): $(srcdir)/testfill.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
 
+testgamma$(EXE): $(srcdir)/testgamma.c
+	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
+ 
 testgesture$(EXE): $(srcdir)/testgesture.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS) @MATHLIB@
  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testgamma.c	Fri Mar 11 08:49:20 2011 -0800
@@ -0,0 +1,168 @@
+
+/* Bring up a window and manipulate the gamma on it */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "SDL.h"
+
+/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
+static void
+quit(int rc)
+{
+    SDL_Quit();
+    exit(rc);
+}
+
+/* This can be used as a general routine for all of the test programs */
+int
+get_video_args(char *argv[], int *w, int *h, int *bpp, Uint32 * flags)
+{
+    int i;
+
+    *w = 640;
+    *h = 480;
+    *bpp = 0;
+    *flags = SDL_SWSURFACE;
+
+    for (i = 1; argv[i]; ++i) {
+        if (strcmp(argv[i], "-width") == 0) {
+            if (argv[i + 1]) {
+                *w = atoi(argv[++i]);
+            }
+        } else if (strcmp(argv[i], "-height") == 0) {
+            if (argv[i + 1]) {
+                *h = atoi(argv[++i]);
+            }
+        } else if (strcmp(argv[i], "-bpp") == 0) {
+            if (argv[i + 1]) {
+                *bpp = atoi(argv[++i]);
+            }
+        } else if (strcmp(argv[i], "-fullscreen") == 0) {
+            *flags |= SDL_FULLSCREEN;
+        } else if (strcmp(argv[i], "-hw") == 0) {
+            *flags |= SDL_HWSURFACE;
+        } else if (strcmp(argv[i], "-hwpalette") == 0) {
+            *flags |= SDL_HWPALETTE;
+        } else
+            break;
+    }
+    return i;
+}
+
+int
+main(int argc, char *argv[])
+{
+    SDL_Surface *screen;
+    SDL_Surface *image;
+    float gamma;
+    int i;
+    int w, h, bpp;
+    Uint32 flags;
+    Uint16 ramp[256];
+    Uint16 red_ramp[256];
+    Uint32 then, timeout;
+
+    /* Check command line arguments */
+    argv += get_video_args(argv, &w, &h, &bpp, &flags);
+
+    /* Initialize SDL */
+    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
+        fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
+        return (1);
+    }
+
+    /* Initialize the display, always use hardware palette */
+    screen = SDL_SetVideoMode(w, h, bpp, flags | SDL_HWPALETTE);
+    if (screen == NULL) {
+        fprintf(stderr, "Couldn't set %dx%d video mode: %s\n",
+                w, h, SDL_GetError());
+        quit(1);
+    }
+
+    /* Set the window manager title bar */
+    SDL_WM_SetCaption("SDL gamma test", "testgamma");
+
+    /* Set the desired gamma, if any */
+    gamma = 1.0f;
+    if (*argv) {
+        gamma = (float) atof(*argv);
+    }
+    if (SDL_SetGamma(gamma, gamma, gamma) < 0) {
+        fprintf(stderr, "Unable to set gamma: %s\n", SDL_GetError());
+        quit(1);
+    }
+
+    /* Do all the drawing work */
+    image = SDL_LoadBMP("sample.bmp");
+    if (image) {
+        SDL_Rect dst;
+
+        dst.x = (screen->w - image->w) / 2;
+        dst.y = (screen->h - image->h) / 2;
+        dst.w = image->w;
+        dst.h = image->h;
+        SDL_BlitSurface(image, NULL, screen, &dst);
+        SDL_UpdateRects(screen, 1, &dst);
+    }
+
+    /* Wait a bit, handling events */
+    then = SDL_GetTicks();
+    timeout = (5 * 1000);
+    while ((SDL_GetTicks() - then) < timeout) {
+        SDL_Event event;
+
+        while (SDL_PollEvent(&event)) {
+            switch (event.type) {
+            case SDL_QUIT:     /* Quit now */
+                timeout = 0;
+                break;
+            case SDL_KEYDOWN:
+                switch (event.key.keysym.sym) {
+                case SDLK_SPACE:       /* Go longer.. */
+                    timeout += (5 * 1000);
+                    break;
+                case SDLK_UP:
+                    gamma += 0.2f;
+                    SDL_SetGamma(gamma, gamma, gamma);
+                    break;
+                case SDLK_DOWN:
+                    gamma -= 0.2f;
+                    SDL_SetGamma(gamma, gamma, gamma);
+                    break;
+                case SDLK_ESCAPE:
+                    timeout = 0;
+                    break;
+                default:
+                    break;
+                }
+                break;
+            }
+        }
+    }
+
+    /* Perform a gamma flash to red using color ramps */
+    while (gamma < 10.0) {
+        /* Increase the red gamma and decrease everything else... */
+        gamma += 0.1f;
+        SDL_CalculateGammaRamp(gamma, red_ramp);
+        SDL_CalculateGammaRamp(1.0f / gamma, ramp);
+        SDL_SetGammaRamp(red_ramp, ramp, ramp);
+    }
+    /* Finish completely red */
+    memset(red_ramp, 255, sizeof(red_ramp));
+    memset(ramp, 0, sizeof(ramp));
+    SDL_SetGammaRamp(red_ramp, ramp, ramp);
+
+    /* Now fade out to black */
+    for (i = (red_ramp[0] >> 8); i >= 0; --i) {
+        memset(red_ramp, i, sizeof(red_ramp));
+        SDL_SetGammaRamp(red_ramp, NULL, NULL);
+    }
+    SDL_Delay(1 * 1000);
+
+    SDL_Quit();
+    return (0);
+}