From e26418567922da3563b6aebe57412c6e1e6e63d0 Mon Sep 17 00:00:00 2001 From: Bob Pendleton Date: Wed, 25 Jul 2007 21:22:55 +0000 Subject: [PATCH] Added gamma table support to X11. Also now supports DirectColor visuals. --- src/video/x11/SDL_x11gamma.c | 170 +++++++++++++++++++++++++++++++--- src/video/x11/SDL_x11gamma.h | 5 +- src/video/x11/SDL_x11window.c | 106 +++++++++++++++------ 3 files changed, 237 insertions(+), 44 deletions(-) diff --git a/src/video/x11/SDL_x11gamma.c b/src/video/x11/SDL_x11gamma.c index 405764a8d..1d7f6d5d9 100644 --- a/src/video/x11/SDL_x11gamma.c +++ b/src/video/x11/SDL_x11gamma.c @@ -29,32 +29,50 @@ typedef struct { 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 @@ X11_TrackColormap(Display * display, int scrNum, 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; } diff --git a/src/video/x11/SDL_x11gamma.h b/src/video/x11/SDL_x11gamma.h index 31dd4a478..bc2ec1da1 100644 --- a/src/video/x11/SDL_x11gamma.h +++ b/src/video/x11/SDL_x11gamma.h @@ -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); diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 7c99559e9..02ed06129 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -181,46 +181,92 @@ X11_CreateWindow(_THIS, SDL_Window * window) } 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; + + 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); + } - /* 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; + /* 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)); } - 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"); + /* 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 =