sdl2-compat: Implement brightness and gamma ramp for pysdl2 tests

From 517a1c9cd73faefe210beb3faf8d8c1877884bc1 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 25 Mar 2025 11:18:40 -0700
Subject: [PATCH] Implement brightness and gamma ramp for pysdl2 tests

---
 src/sdl2_compat.c | 110 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 80 insertions(+), 30 deletions(-)

diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index b2d3c20..425f3e2 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -208,9 +208,11 @@ do { \
 #include <SDL3/SDL_opengl_glext.h>
 
 /* !!! FIXME: collect all the properties in one place near the top of the source file */
+#define PROP_WINDOW_BRIGHTNESS "sdl2-compat.window.brightness"
 #define PROP_WINDOW_EXPECTED_WIDTH "sdl2-compat.window.expected_width"
 #define PROP_WINDOW_EXPECTED_HEIGHT "sdl2-compat.window.expected_height"
 #define PROP_WINDOW_EXPECTED_SCALE "sdl2-compat.window.expected_scale"
+#define PROP_WINDOW_GAMMA_RAMP "sdl2-compat.window.gamma_ramp"
 #define PROP_RENDERER_BATCHING "sdl2-compat.renderer.batching"
 #define PROP_RENDERER_RELATIVE_SCALING "sdl2-compat.renderer.relative-scaling"
 #define PROP_RENDERER_INTEGER_SCALE "sdl2-compat.renderer.integer_scale"
@@ -3959,16 +3961,23 @@ SDL_GameControllerAddMappingsFromRW(SDL2_RWops *rwops2, int freerw)
     return retval;
 }
 
-
-/* All gamma stuff was removed from SDL3 because it affects the whole system
-   in intrusive ways, and often didn't work on various platforms. These all
-   just return failure now. */
-
 SDL_DECLSPEC int SDLCALL
 SDL_SetWindowBrightness(SDL_Window *window, float brightness)
 {
-    SDL3_Unsupported();
-    return -1;
+    Uint16 ramp[256];
+    int status;
+
+    if (!window) {
+        SDL3_SetError("Invalid window");
+        return -1;
+    }
+
+    SDL_CalculateGammaRamp(brightness, ramp);
+    status = SDL_SetWindowGammaRamp(window, ramp, ramp, ramp);
+    if (status == 0) {
+        SDL3_SetFloatProperty(SDL3_GetWindowProperties(window), PROP_WINDOW_BRIGHTNESS, brightness);
+    }
+    return status;
 }
 
 SDL_DECLSPEC float SDLCALL
@@ -3976,15 +3985,10 @@ SDL_GetWindowBrightness(SDL_Window *window)
 {
     if (!window) {
         SDL3_SetError("Invalid window");
+        return 1.0f;
     }
-    return 1.0f;
-}
 
-SDL_DECLSPEC int SDLCALL
-SDL_SetWindowGammaRamp(SDL_Window *window, const Uint16 *r, const Uint16 *g, const Uint16 *b)
-{
-    SDL3_Unsupported();
-    return -1;
+    return SDL3_GetFloatProperty(SDL3_GetWindowProperties(window), PROP_WINDOW_BRIGHTNESS, 1.0f);
 }
 
 SDL_DECLSPEC void SDLCALL
@@ -4029,27 +4033,78 @@ SDL_CalculateGammaRamp(float gamma, Uint16 *ramp)
 }
 
 SDL_DECLSPEC int SDLCALL
-SDL_GetWindowGammaRamp(SDL_Window *window, Uint16 *red, Uint16 *blue, Uint16 *green)
+SDL_SetWindowGammaRamp(SDL_Window *window, const Uint16 *r, const Uint16 *g, const Uint16 *b)
 {
-    Uint16 *buf;
+    Uint16 *gamma;
 
     if (!window) {
         SDL3_SetError("Invalid window");
         return -1;
     }
 
-    buf = red ? red : (green ? green : blue);
-    if (buf) {
-        SDL_CalculateGammaRamp(1.0f, buf);
-        if (red && (red != buf)) {
-            SDL3_memcpy(red, buf, 256 * sizeof (Uint16));
+    gamma = (Uint16 *)SDL3_GetPointerProperty(SDL3_GetWindowProperties(window), PROP_WINDOW_GAMMA_RAMP, NULL);
+    if (!gamma) {
+        if (SDL_GetWindowGammaRamp(window, NULL, NULL, NULL) < 0) {
+            return -1;
         }
-        if (green && (green != buf)) {
-            SDL3_memcpy(green, buf, 256 * sizeof (Uint16));
+        gamma = (Uint16 *)SDL3_GetPointerProperty(SDL3_GetWindowProperties(window), PROP_WINDOW_GAMMA_RAMP, NULL);
+    }
+
+    if (r) {
+        SDL_memcpy(&gamma[0*256], r, 256*sizeof(Uint16));
+    }
+    if (g) {
+        SDL_memcpy(&gamma[1*256], g, 256*sizeof(Uint16));
+    }
+    if (b) {
+        SDL_memcpy(&gamma[2*256], b, 256*sizeof(Uint16));
+    }
+    return 0;
+}
+
+static void SDLCALL CleanupFreeableProperty(void *userdata, void *value)
+{
+    SDL3_free(value);
+}
+
+SDL_DECLSPEC int SDLCALL
+SDL_GetWindowGammaRamp(SDL_Window *window, Uint16 *red, Uint16 *blue, Uint16 *green)
+{
+    Uint16 *gamma;
+
+    if (!window) {
+        SDL3_SetError("Invalid window");
+        return -1;
+    }
+
+    gamma = (Uint16 *)SDL3_GetPointerProperty(SDL3_GetWindowProperties(window), PROP_WINDOW_GAMMA_RAMP, NULL);
+    if (!gamma) {
+        int i;
+
+        gamma = (Uint16 *)SDL3_malloc(256*3*sizeof(Uint16));
+        if (!gamma) {
+            return -1;
         }
-        if (blue && (blue != buf)) {
-            SDL3_memcpy(blue, buf, 256 * sizeof (Uint16));
+
+        /* Create an identity gamma ramp */
+        for (i = 0; i < 256; ++i) {
+            Uint16 value = (Uint16)((i << 8) | i);
+
+            gamma[0*256+i] = value;
+            gamma[1*256+i] = value;
+            gamma[2*256+i] = value;
         }
+        SDL3_SetPointerPropertyWithCleanup(SDL3_GetWindowProperties(window), PROP_WINDOW_GAMMA_RAMP, gamma, CleanupFreeableProperty, NULL);
+    }
+
+    if (red) {
+        SDL_memcpy(red, &gamma[0*256], 256*sizeof(Uint16));
+    }
+    if (green) {
+        SDL_memcpy(green, &gamma[1*256], 256*sizeof(Uint16));
+    }
+    if (blue) {
+        SDL_memcpy(blue, &gamma[2*256], 256*sizeof(Uint16));
     }
     return 0;
 }
@@ -5456,11 +5511,6 @@ SDL_IsShapedWindow(const SDL_Window *window)
 
 #define PROP_WINDOW_SHAPE_MODE_POINTER "sdl2-compat.window.shape_mode"
 
-static void SDLCALL CleanupFreeableProperty(void *userdata, void *value)
-{
-    SDL3_free(value);
-}
-
 SDL_DECLSPEC int SDLCALL
 SDL_SetWindowShape(SDL_Window *window, SDL2_Surface *shape, SDL_WindowShapeMode *shape_mode)
 {