Added gamma table support to X11. Also now supports DirectColor visuals.
authorBob Pendleton <bob@pendleton.com>
Wed, 25 Jul 2007 21:22:55 +0000
changeset 2214 e7164a4dac62
parent 2213 59a667370c57
child 2215 23a2cb765052
Added gamma table support to X11. Also now supports DirectColor visuals.
src/video/x11/SDL_x11gamma.c
src/video/x11/SDL_x11gamma.h
src/video/x11/SDL_x11window.c
--- a/src/video/x11/SDL_x11gamma.c	Tue Jul 24 18:46:45 2007 +0000
+++ b/src/video/x11/SDL_x11gamma.c	Wed Jul 25 21:22:55 2007 +0000
@@ -29,32 +29,50 @@
 {
     Display *display;
     int scrNum;
+    Colormap colormap;
     XStandardColormap cmap;
     Visual visual;
 } cmapTableEntry;
 
 cmapTableEntry *cmapTable = NULL;
 
+/* To reduce the overhead as much as possible lets do as little as
+   possible. When we do have to create a colormap keep track of it and
+   reuse it. We're going to do this for both DirectColor and
+   PseudoColor colormaps. */
+
+Colormap
+X11_LookupColormap(Display * display, int scrNum, VisualID vid)
+{
+    int i;
+
+    for (i = 0; i < numCmaps; i++) {
+        if (cmapTable[i].display == display &&
+            cmapTable[i].scrNum == scrNum &&
+            cmapTable[i].cmap.visualid == vid) {
+            return cmapTable[i].cmap.colormap;
+        }
+    }
+
+    return 0;
+}
+
+
 void
-X11_TrackColormap(Display * display, int scrNum,
+X11_TrackColormap(Display * display, int scrNum, Colormap colormap,
                   XStandardColormap * cmap, Visual * visual)
 {
     int i;
     cmapTableEntry *newTable = NULL;
 
-    /* only tracking DirectColor colormaps because they're the only ones
-       with gamma ramps */
-    if (DirectColor != visual->class) {
-        return;
-    }
-
-    /* search the table to find out if we already have this one. We only
-       want one entry for each display, screen number, visualid
-       combination */
+    /* search the table to find out if we already have this one. We
+       only want one entry for each display, screen number, visualid,
+       and colormap combination */
     for (i = 0; i < numCmaps; i++) {
         if (cmapTable[i].display == display &&
             cmapTable[i].scrNum == scrNum &&
-            cmapTable[i].cmap.visualid == cmap->visualid) {
+            cmapTable[i].cmap.visualid == cmap->visualid &&
+            cmapTable[i].cmap.colormap == colormap) {
             return;
         }
     }
@@ -75,20 +93,146 @@
 
     cmapTable[numCmaps].display = display;
     cmapTable[numCmaps].scrNum = scrNum;
+    cmapTable[numCmaps].colormap = colormap;
     SDL_memcpy(&cmapTable[numCmaps].cmap, cmap, sizeof(XStandardColormap));
     SDL_memcpy(&cmapTable[numCmaps].visual, visual, sizeof(Visual));
 
     numCmaps++;
 }
 
+/* The problem is that you have to have at least one DirectColor
+   colormap before you can set the gamma ramps or read the gamma
+   ramps. If the application has created a DirectColor window then the
+   cmapTable will have at least one colormap in it and everything is
+   cool. If not, then we just fail  */
+
 int
 X11_SetDisplayGammaRamp(_THIS, Uint16 * ramp)
 {
-    return -1;
+    Display *display;
+    Colormap colormap;
+    XColor *colorcells;
+    int ncolors;
+    int i;
+    int j;
+
+    int rmax, gmax, bmax;
+    int rmul, gmul, bmul;
+
+    for (j = 0; j < numCmaps; j++) {
+        if (cmapTable[j].visual.class == DirectColor) {
+            display = cmapTable[j].display;
+            colormap = cmapTable[j].colormap;
+            ncolors = cmapTable[j].visual.map_entries;
+
+            colorcells = SDL_malloc(ncolors * sizeof(XColor));
+            if (NULL == colorcells) {
+                SDL_SetError("out of memory in X11_SetDisplayGammaRamp");
+                return -1;
+            }
+
+            rmax = cmapTable[j].cmap.red_max + 1;
+            gmax = cmapTable[j].cmap.blue_max + 1;
+            bmax = cmapTable[j].cmap.green_max + 1;
+
+            rmul = cmapTable[j].cmap.red_mult;
+            gmul = cmapTable[j].cmap.blue_mult;
+            bmul = cmapTable[j].cmap.green_mult;
+
+            /* build the color table pixel values */
+            for (i = 0; i < ncolors; i++) {
+                Uint32 red = (rmax * i) / ncolors;
+                Uint32 green = (gmax * i) / ncolors;
+                Uint32 blue = (bmax * i) / ncolors;
+
+                colorcells[i].pixel =
+                    (red * rmul) | (green * gmul) | (blue * bmul);
+                colorcells[i].flags = DoRed | DoGreen | DoBlue;
+
+                colorcells[i].red = ramp[(0 * 256) + i];
+                colorcells[i].green = ramp[(1 * 256) + i];
+                colorcells[i].blue = ramp[(2 * 256) + i];
+            }
+
+            XStoreColors(display, colormap, colorcells, ncolors);
+            XFlush(display);
+            SDL_free(colorcells);
+        }
+    }
+
+    return 0;
 }
 
 int
 X11_GetDisplayGammaRamp(_THIS, Uint16 * ramp)
 {
-    return -1;
+    Display *display;
+    Colormap colormap;
+    XColor *colorcells;
+    int ncolors;
+    int dc;
+    int i;
+
+    int rmax, gmax, bmax;
+    int rmul, gmul, bmul;
+
+    /* find the first DirectColor colormap and use it to get the gamma
+       ramp */
+
+    dc = -1;
+    for (i = 0; i < numCmaps; i++) {
+        if (cmapTable[i].visual.class == DirectColor) {
+            dc = i;
+            break;
+        }
+    }
+
+    if (dc < 0) {
+        return -1;
+    }
+
+    /* there is at least one DirectColor colormap in the cmapTable,
+       let's just get the entries from that colormap */
+
+    display = cmapTable[dc].display;
+    colormap = cmapTable[dc].colormap;
+    ncolors = cmapTable[dc].visual.map_entries;
+    colorcells = SDL_malloc(ncolors * sizeof(XColor));
+    if (NULL == colorcells) {
+        SDL_SetError("out of memory in X11_GetDisplayGammaRamp");
+        return -1;
+    }
+
+    rmax = cmapTable[dc].cmap.red_max + 1;
+    gmax = cmapTable[dc].cmap.blue_max + 1;
+    bmax = cmapTable[dc].cmap.green_max + 1;
+
+    rmul = cmapTable[dc].cmap.red_mult;
+    gmul = cmapTable[dc].cmap.blue_mult;
+    bmul = cmapTable[dc].cmap.green_mult;
+
+    /* build the color table pixel values */
+    for (i = 0; i < ncolors; i++) {
+        Uint32 red = (rmax * i) / ncolors;
+        Uint32 green = (gmax * i) / ncolors;
+        Uint32 blue = (bmax * i) / ncolors;
+
+        colorcells[i].pixel = (red * rmul) | (green * gmul) | (blue * bmul);
+    }
+
+    XQueryColors(display, colormap, colorcells, ncolors);
+
+    /* prepare the values to be returned. Note that SDL assumes that
+       gamma ramps are always 3 * 256 entries long with the red entries
+       in the first 256 elements, the green in the second 256 elements
+       and the blue in the last 256 elements */
+
+    for (i = 0; i < ncolors; i++) {
+        ramp[(0 * 256) + i] = colorcells[i].red;
+        ramp[(1 * 256) + i] = colorcells[i].green;
+        ramp[(2 * 256) + i] = colorcells[i].blue;
+    }
+
+    SDL_free(colorcells);
+    return 0;
 }
--- a/src/video/x11/SDL_x11gamma.h	Tue Jul 24 18:46:45 2007 +0000
+++ b/src/video/x11/SDL_x11gamma.h	Wed Jul 25 21:22:55 2007 +0000
@@ -24,8 +24,11 @@
 #ifndef _SDL_x11gamma_h
 #define _SDL_x11gamma_h
 
+extern Colormap X11_LookupColormap(Display * display, int scrNum,
+                                   VisualID vid);
 extern void X11_TrackColormap(Display * display, int scrNum,
-                              XStandardColormap * cmap, Visual * visual);
+                              Colormap colormap, XStandardColormap * cmap,
+                              Visual * visual);
 
 extern int X11_SetDisplayGammaRamp(_THIS, Uint16 * ramp);
 extern int X11_GetDisplayGammaRamp(_THIS, Uint16 * ramp);
--- a/src/video/x11/SDL_x11window.c	Tue Jul 24 18:46:45 2007 +0000
+++ b/src/video/x11/SDL_x11window.c	Wed Jul 25 21:22:55 2007 +0000
@@ -181,46 +181,92 @@
     }
     xattr.background_pixel = 0;
     xattr.border_pixel = 0;
+
     if (visual->class == DirectColor || visual->class == PseudoColor) {
         int nmaps;
+        XStandardColormap cmap;
         XStandardColormap *stdmaps;
+        XColor *colorcells;
+        Colormap colormap;
         Bool found = False;
+        int i;
+        int ncolors;
+        int rmax, gmax, bmax;
+        int rmul, gmul, bmul;
 
-        /* check to see if the colormap we need already exists */
-        if (0 != XGetRGBColormaps(data->display,
-                                  RootWindow(data->display,
-                                             displaydata->screen), &stdmaps,
-                                  &nmaps, XA_RGB_BEST_MAP)) {
-            int i;
-            for (i = 0; i < nmaps; i++) {
-                if (stdmaps[i].visualid == visual->visualid) {
-                    xattr.colormap = stdmaps[i].colormap;
-                    X11_TrackColormap(data->display, displaydata->screen,
-                                      &stdmaps[i], visual);
-                    found = True;
-                    break;
+        if (colormap =
+            X11_LookupColormap(data->display, displaydata->screen,
+                               visual->visualid)) {
+            xattr.colormap = colormap;
+        } else {
+            /* check to see if the colormap we need already exists */
+            if (0 != XGetRGBColormaps(data->display,
+                                      RootWindow(data->display,
+                                                 displaydata->screen),
+                                      &stdmaps, &nmaps, XA_RGB_BEST_MAP)) {
+                for (i = 0; i < nmaps; i++) {
+                    if (stdmaps[i].visualid == visual->visualid) {
+                        SDL_memcpy(&cmap, &stdmaps[i],
+                                   sizeof(XStandardColormap));
+                        found = True;
+                        break;
+                    }
                 }
+                XFree(stdmaps);
             }
-            XFree(stdmaps);
-        }
 
-        /* it doesn't exist, so create it */
-        if (!found) {
-            int max = visual->map_entries - 1;
-            XStandardColormap *cmap =
-                XmuStandardColormap(data->display, displaydata->screen,
-                                    visual->visualid, depth,
-                                    XA_RGB_BEST_MAP, None,
-                                    max, max, max);
-            if (NULL != cmap && cmap->visualid == visual->visualid) {
-                xattr.colormap = cmap->colormap;
-                X11_TrackColormap(data->display, displaydata->screen, cmap,
-                                  visual);
-            } else {
-                SDL_SetError
-                    ("Couldn't create window:XA_RGB_BEST_MAP not found");
+            /* it doesn't exist, so create it */
+            if (!found) {
+                int max = visual->map_entries - 1;
+                stdmaps =
+                    XmuStandardColormap(data->display, displaydata->screen,
+                                        visual->visualid, depth,
+                                        XA_RGB_BEST_MAP, None, max, max, max);
+                if (NULL == stdmaps || stdmaps->visualid != visual->visualid) {
+                    SDL_SetError
+                        ("Couldn't create window:XA_RGB_BEST_MAP not found and could not be created");
+                    return -1;
+                }
+                SDL_memcpy(&cmap, stdmaps, sizeof(XStandardColormap));
+            }
+
+            /* OK, we have the best color map, now copy it for use by the
+               program */
+
+            colorcells = SDL_malloc(visual->map_entries * sizeof(XColor));
+            if (NULL == colorcells) {
+                SDL_SetError("out of memory in X11_CreateWindow");
                 return -1;
             }
+            ncolors = visual->map_entries;
+            rmax = cmap.red_max + 1;
+            gmax = cmap.blue_max + 1;
+            bmax = cmap.green_max + 1;
+
+            rmul = cmap.red_mult;
+            gmul = cmap.blue_mult;
+            bmul = cmap.green_mult;
+
+            /* build the color table pixel values */
+            for (i = 0; i < ncolors; i++) {
+                Uint32 red = (rmax * i) / ncolors;
+                Uint32 green = (gmax * i) / ncolors;
+                Uint32 blue = (bmax * i) / ncolors;
+
+                colorcells[i].pixel =
+                    (red * rmul) | (green * gmul) | (blue * bmul);
+            }
+            XQueryColors(data->display, cmap.colormap, colorcells, ncolors);
+            colormap = XCreateColormap(data->display,
+                                       RootWindow(data->display,
+                                                  displaydata->screen),
+                                       visual, AllocAll);
+            XStoreColors(data->display, colormap, colorcells, ncolors);
+            SDL_free(colorcells);
+
+            xattr.colormap = colormap;
+            X11_TrackColormap(data->display, displaydata->screen, colormap,
+                              &cmap, visual);
         }
     } else {
         xattr.colormap =