From 5d973366778c08c2ad42b1b69846c17625ab512d Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 17 Jun 2006 06:45:14 +0000 Subject: [PATCH] Finished palettized display handling. Added support for surface palette sharing. --- include/SDL_compat.h | 6 +- include/SDL_pixels.h | 118 ++++++++++++-- include/SDL_video.h | 34 ++-- src/SDL_compat.c | 97 +++++------- src/video/SDL_RLEaccel.c | 10 +- src/video/SDL_bmp.c | 2 +- src/video/SDL_pixels.c | 260 +++++++++++++++---------------- src/video/SDL_pixels_c.h | 3 - src/video/SDL_renderer_sw.c | 12 +- src/video/SDL_surface.c | 173 ++++++++++++++------ src/video/SDL_sysvideo.h | 2 +- src/video/SDL_video.c | 65 ++++---- src/video/dummy/SDL_nullrender.c | 15 +- 13 files changed, 458 insertions(+), 339 deletions(-) diff --git a/include/SDL_compat.h b/include/SDL_compat.h index 6418220f7..a42a3e262 100644 --- a/include/SDL_compat.h +++ b/include/SDL_compat.h @@ -148,9 +148,9 @@ extern DECLSPEC SDL_GrabMode SDLCALL SDL_WM_GrabInput(SDL_GrabMode mode); extern DECLSPEC int SDLCALL SDL_SetPalette(SDL_Surface * surface, int flags, const SDL_Color * colors, int firstcolor, int ncolors); -extern DECLSPEC int SDLCALL SDL_SetScreenColors(SDL_Surface * screen, - const SDL_Color * colors, - int firstcolor, int ncolors); +extern DECLSPEC int SDLCALL SDL_SetColors(SDL_Surface * surface, + const SDL_Color * colors, + int firstcolor, int ncolors); extern DECLSPEC int SDLCALL SDL_GetWMInfo(SDL_SysWMinfo * info); extern DECLSPEC Uint8 SDLCALL SDL_GetAppState(void); extern DECLSPEC void SDLCALL SDL_WarpMouse(Uint16 x, Uint16 y); diff --git a/include/SDL_pixels.h b/include/SDL_pixels.h index d4af56960..e4c921ab6 100644 --- a/include/SDL_pixels.h +++ b/include/SDL_pixels.h @@ -195,11 +195,24 @@ typedef struct SDL_Color } SDL_Color; #define SDL_Colour SDL_Color -typedef struct SDL_Palette +typedef struct SDL_Palette SDL_Palette; +typedef int (*SDL_PaletteChangedFunc) (void *userdata, SDL_Palette * palette); + +typedef struct SDL_PaletteWatch +{ + SDL_PaletteChangedFunc callback; + void *userdata; + struct SDL_PaletteWatch *next; +} SDL_PaletteWatch; + +struct SDL_Palette { int ncolors; SDL_Color *colors; -} SDL_Palette; + + int refcount; + SDL_PaletteWatch *watch; +}; /* Everything in the pixel format structure is read-only */ typedef struct SDL_PixelFormat @@ -226,23 +239,96 @@ typedef struct SDL_PixelFormat Uint8 alpha; } SDL_PixelFormat; -/* - * Convert one of the enumerated formats above to a bpp and RGBA masks. - * Returns SDL_TRUE, or SDL_FALSE if the conversion wasn't possible. +/** + * \fn SDL_bool SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, Uint32 * Rmask, Uint32 * Gmask, Uint32 * Bmask, Uint32 * Amask) + * + * \brief Convert one of the enumerated pixel formats to a bpp and RGBA masks. + * + * \return SDL_TRUE, or SDL_FALSE if the conversion wasn't possible. + * + * \sa SDL_MasksToPixelFormatEnum() */ -extern DECLSPEC SDL_bool SDL_PixelFormatEnumToMasks(Uint32 format, int *bpp, - Uint32 * Rmask, - Uint32 * Gmask, - Uint32 * Bmask, - Uint32 * Amask); +extern DECLSPEC SDL_bool SDLCALL SDL_PixelFormatEnumToMasks(Uint32 format, + int *bpp, + Uint32 * Rmask, + Uint32 * Gmask, + Uint32 * Bmask, + Uint32 * Amask); -/* - * Convert a bpp and RGBA masks to one of the enumerated formats above. - * Returns SDL_PixelFormat_Unknown if the conversion wasn't possible. +/** + * \fn Uint32 SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) + * + * \brief Convert a bpp and RGBA masks to an enumerated pixel format. + * + * \return The pixel format, or SDL_PixelFormat_Unknown if the conversion wasn't possible. + * + * \sa SDL_PixelFormatEnumToMasks() + */ +extern DECLSPEC Uint32 SDLCALL SDL_MasksToPixelFormatEnum(int bpp, + Uint32 Rmask, + Uint32 Gmask, + Uint32 Bmask, + Uint32 Amask); + +/** + * \fn SDL_Palette *SDL_AllocPalette(int ncolors) + * + * \brief Create a palette structure with the specified number of color entries. + * + * \return A new palette, or NULL if there wasn't enough memory + * + * \note The palette entries are initialized to white. + * + * \sa SDL_FreePalette() + */ +extern DECLSPEC SDL_Palette *SDLCALL SDL_AllocPalette(int ncolors); + +/** + * \fn int SDL_AddPaletteWatch(SDL_Palette *palette, SDL_PaletteChangedFunc callback, void *userdata) + * + * \brief Add a callback function which is called when the palette changes. + * + * \sa SDL_DelPaletteWatch() + */ +extern DECLSPEC int SDLCALL SDL_AddPaletteWatch(SDL_Palette * palette, + SDL_PaletteChangedFunc + callback, void *userdata); + +/** + * \fn void SDL_DelPaletteWatch(SDL_Palette *palette, SDL_PaletteChangedFunc callback, void *userdata) + * + * \brief Remove a callback function previously added with SDL_AddPaletteWatch() + * + * \sa SDL_AddPaletteWatch() + */ +extern DECLSPEC void SDLCALL SDL_DelPaletteWatch(SDL_Palette * palette, + SDL_PaletteChangedFunc + callback, void *userdata); + +/** + * \fn int SDL_SetPaletteColors(SDL_Palette *palette, const SDL_Colors *colors, int firstcolor, int numcolors) + * + * \brief Set a range of colors in a palette. + * + * \param palette The palette to modify + * \param colors An array of colors to copy into the palette + * \param firstcolor The index of the first palette entry to modify + * \param ncolors The number of entries to modify + * + * \return 0 on success, or -1 if not all of the colors could be set + */ +extern DECLSPEC int SDLCALL SDL_SetPaletteColors(SDL_Palette * palette, + const SDL_Color * colors, + int firstcolor, int ncolors); + +/** + * \fn void SDL_FreePalette(SDL_Palette *palette) + * + * \brief Free a palette created with SDL_AllocPalette() + * + * \sa SDL_AllocPalette() */ -extern DECLSPEC Uint32 SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, - Uint32 Gmask, Uint32 Bmask, - Uint32 Amask); +extern DECLSPEC void SDLCALL SDL_FreePalette(SDL_Palette * palette); /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/include/SDL_video.h b/include/SDL_video.h index cf9d880fd..a8bc6a351 100644 --- a/include/SDL_video.h +++ b/include/SDL_video.h @@ -252,6 +252,9 @@ typedef struct SDL_Surface int pitch; /* Read-only */ void *pixels; /* Read-write */ + /* texture associated with the surface, if any */ + SDL_TextureID textureID; + /* information needed for surfaces requiring locks */ int locked; void *lock_data; @@ -1066,25 +1069,6 @@ extern DECLSPEC int SDLCALL SDL_SetGammaRamp(const Uint16 * red, extern DECLSPEC int SDLCALL SDL_GetGammaRamp(Uint16 * red, Uint16 * green, Uint16 * blue); -/* - * Sets a portion of the colormap for the given 8-bit surface. If 'surface' - * is not a palettized surface, this function does nothing, returning 0. - * If all of the colors were set as passed to SDL_SetColors(), it will - * return 1. If not all the color entries were set exactly as given, - * it will return 0, and you should look at the surface palette to - * determine the actual color palette. - * - * When 'surface' is the surface associated with the current display, the - * display colormap will be updated with the requested colors. If - * SDL_HWPALETTE was set in SDL_SetVideoMode() flags, SDL_SetColors() - * will always return 1, and the palette is guaranteed to be set the way - * you desire, even if the window colormap has to be warped or run under - * emulation. - */ -extern DECLSPEC int SDLCALL SDL_SetColors(SDL_Surface * surface, - const SDL_Color * colors, - int firstcolor, int ncolors); - /* * Maps an RGB triple to an opaque pixel value for a given pixel format */ @@ -1138,6 +1122,18 @@ extern DECLSPEC SDL_Surface *SDLCALL SDL_CreateRGBSurfaceFromTexture(SDL_TextureID textureID); extern DECLSPEC void SDLCALL SDL_FreeSurface(SDL_Surface * surface); +/** + * \fn int SDL_SetSurfacePalette(SDL_Surface *surface, SDL_Palette *palette) + * + * \brief Set the palette used by a surface. + * + * \return 0, or -1 if the surface format doesn't use a palette. + * + * \note A single palette can be shared with many surfaces. + */ +extern DECLSPEC int SDLCALL SDL_SetSurfacePalette(SDL_Surface * surface, + SDL_Palette * palette); + /* * SDL_LockSurface() sets up a surface for directly accessing the pixels. * Between calls to SDL_LockSurface()/SDL_UnlockSurface(), you can write diff --git a/src/SDL_compat.c b/src/SDL_compat.c index a6164c624..0b1b24363 100644 --- a/src/SDL_compat.c +++ b/src/SDL_compat.c @@ -204,7 +204,25 @@ SDL_CompatEventFilter(const SDL_Event * event) break; } } - return orig_eventfilter(event); + if (orig_eventfilter) { + return orig_eventfilter(event); + } else { + return 1; + } +} + +static int +SDL_VideoPaletteChanged(void *userdata, SDL_Palette * palette) +{ + if (userdata == SDL_ShadowSurface) { + /* If the shadow palette changed, make the changes visible */ + if (!SDL_VideoSurface->format->palette) { + SDL_UpdateRect(SDL_ShadowSurface, 0, 0, 0, 0); + } + } + if (userdata == SDL_VideoSurface) { + return SDL_SetDisplayPalette(palette->colors, 0, palette->ncolors); + } } SDL_Surface * @@ -233,7 +251,9 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) SDL_ShadowSurface = NULL; } if (SDL_VideoSurface) { - SDL_FreeSurface(SDL_ShadowSurface); + SDL_DelPaletteWatch(SDL_VideoSurface->format->palette, + SDL_VideoPaletteChanged, NULL); + SDL_FreeSurface(SDL_VideoSurface); SDL_VideoSurface = NULL; } SDL_DestroyWindow(SDL_VideoWindow); @@ -380,11 +400,11 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) SDL_VideoSurface->flags |= SDL_HWPALETTE; SDL_DitherColors(SDL_VideoSurface->format->palette->colors, SDL_VideoSurface->format->BitsPerPixel); - SDL_SetTexturePalette(SDL_VideoTexture, - SDL_VideoSurface->format->palette->colors, 0, - SDL_VideoSurface->format->palette->ncolors); - SDL_SetDisplayPalette(SDL_VideoSurface->format->palette->colors, 0, - SDL_VideoSurface->format->palette->ncolors); + SDL_AddPaletteWatch(SDL_VideoSurface->format->palette, + SDL_VideoPaletteChanged, NULL); + SDL_SetPaletteColors(SDL_VideoSurface->format->palette, + SDL_VideoSurface->format->palette->colors, 0, + SDL_VideoSurface->format->palette->ncolors); } /* Create a shadow surface if necessary */ @@ -415,8 +435,13 @@ SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags) /* 8-bit SDL_ShadowSurface surfaces report that they have exclusive palette */ if (SDL_ShadowSurface->format->palette) { SDL_ShadowSurface->flags |= SDL_HWPALETTE; - SDL_DitherColors(SDL_ShadowSurface->format->palette->colors, - SDL_ShadowSurface->format->BitsPerPixel); + if (SDL_VideoSurface->format->palette) { + SDL_SetSurfacePalette(SDL_ShadowSurface, + SDL_VideoSurface->format->palette); + } else { + SDL_DitherColors(SDL_ShadowSurface->format->palette->colors, + SDL_ShadowSurface->format->BitsPerPixel); + } } } SDL_PublicSurface = @@ -656,55 +681,15 @@ SDL_SetPalette(SDL_Surface * surface, int flags, const SDL_Color * colors, } int -SDL_SetScreenColors(SDL_Surface * screen, const SDL_Color * colors, - int firstcolor, int ncolors) +SDL_SetColors(SDL_Surface * surface, const SDL_Color * colors, int firstcolor, + int ncolors) { - SDL_Palette *pal; - int gotall; - int palsize; - - /* Verify the parameters */ - pal = screen->format->palette; - if (!pal) { - return 0; /* not a palettized surface */ - } - gotall = 1; - palsize = 1 << screen->format->BitsPerPixel; - if (ncolors > (palsize - firstcolor)) { - ncolors = (palsize - firstcolor); - gotall = 0; - } - - if (screen == SDL_ShadowSurface) { - SDL_Palette *vidpal; - - vidpal = SDL_VideoSurface->format->palette; - if (vidpal && vidpal->ncolors == pal->ncolors) { - /* This is a shadow surface, and the physical - * framebuffer is also indexed. Propagate the - * changes to its logical palette so that - * updates are always identity blits - */ - SDL_memcpy(vidpal->colors + firstcolor, colors, - ncolors * sizeof(*colors)); - } - if (SDL_VideoSurface->flags & SDL_HWPALETTE) { - /* Set the physical palette */ - screen = SDL_VideoSurface; - } else { - SDL_UpdateRect(screen, 0, 0, 0, 0); - } - } - - if (screen == SDL_VideoSurface) { - SDL_SetTexturePalette(SDL_VideoTexture, - SDL_VideoSurface->format->palette->colors, 0, - SDL_VideoSurface->format->palette->ncolors); - SDL_SetDisplayPalette(SDL_VideoSurface->format->palette->colors, 0, - SDL_VideoSurface->format->palette->ncolors); + if (SDL_SetPaletteColors + (surface->format->palette, colors, firstcolor, ncolors) == 0) { + return 1; + } else { + return 0; } - - return gotall; } int diff --git a/src/video/SDL_RLEaccel.c b/src/video/SDL_RLEaccel.c index f7ccd93eb..3101dcf18 100644 --- a/src/video/SDL_RLEaccel.c +++ b/src/video/SDL_RLEaccel.c @@ -1618,8 +1618,7 @@ RLEAlphaSurface(SDL_Surface * surface) #undef ADD_TRANSL_COUNTS /* Now that we have it encoded, release the original pixels */ - if ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC - && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) { + if (!(surface->flags & SDL_PREALLOC) && !(surface->flags & SDL_HWSURFACE)) { SDL_free(surface->pixels); surface->pixels = NULL; } @@ -1784,8 +1783,7 @@ RLEColorkeySurface(SDL_Surface * surface) #undef ADD_COUNTS /* Now that we have it encoded, release the original pixels */ - if ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC - && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) { + if (!(surface->flags & SDL_PREALLOC) && !(surface->flags & SDL_HWSURFACE)) { SDL_free(surface->pixels); surface->pixels = NULL; } @@ -1936,8 +1934,8 @@ SDL_UnRLESurface(SDL_Surface * surface, int recode) if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { surface->flags &= ~SDL_RLEACCEL; - if (recode && (surface->flags & SDL_PREALLOC) != SDL_PREALLOC - && (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) { + if (recode && !(surface->flags & SDL_PREALLOC) + && !(surface->flags & SDL_HWSURFACE)) { if ((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) { SDL_Rect full; unsigned alpha_flag; diff --git a/src/video/SDL_bmp.c b/src/video/SDL_bmp.c index e2fe336ff..364f3c027 100644 --- a/src/video/SDL_bmp.c +++ b/src/video/SDL_bmp.c @@ -222,7 +222,7 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc) SDL_RWread(src, &palette->colors[i].b, 1, 1); SDL_RWread(src, &palette->colors[i].g, 1, 1); SDL_RWread(src, &palette->colors[i].r, 1, 1); - palette->colors[i].unused = 0; + palette->colors[i].unused = SDL_ALPHA_OPAQUE; } } else { for (i = 0; i < (int) biClrUsed; ++i) { diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c index ba50924e6..7f1d9d01c 100644 --- a/src/video/SDL_pixels.c +++ b/src/video/SDL_pixels.c @@ -215,6 +215,126 @@ SDL_MasksToPixelFormatEnum(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, return SDL_PixelFormat_Unknown; } + +SDL_Palette * +SDL_AllocPalette(int ncolors) +{ + SDL_Palette *palette; + + palette = (SDL_Palette *) SDL_malloc(sizeof(*palette)); + if (!palette) { + SDL_OutOfMemory(); + return NULL; + } + palette->colors = + (SDL_Color *) SDL_malloc(ncolors * sizeof(*palette->colors)); + if (!palette->colors) { + SDL_free(palette); + return NULL; + } + palette->ncolors = ncolors; + palette->watch = NULL; + palette->refcount = 1; + + SDL_memset(palette->colors, 0xFF, ncolors * sizeof(*palette->colors)); + + return palette; +} + +int +SDL_AddPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback, + void *userdata) +{ + SDL_PaletteWatch *watch; + + if (!palette) { + return -1; + } + + watch = (SDL_PaletteWatch *) SDL_malloc(sizeof(*watch)); + if (!watch) { + SDL_OutOfMemory(); + return -1; + } + + watch->callback = callback; + watch->userdata = userdata; + watch->next = palette->watch; + palette->watch = watch; + ++palette->refcount; + return 0; +} + +void +SDL_DelPaletteWatch(SDL_Palette * palette, SDL_PaletteChangedFunc callback, + void *userdata) +{ + SDL_PaletteWatch *prev, *watch; + + if (!palette) { + return; + } + + for (prev = NULL, watch = palette->watch; watch; + prev = watch, watch = watch->next) { + if (watch->callback == callback && watch->userdata == userdata) { + if (prev) { + prev->next = watch->next; + } else { + palette->watch = watch->next; + } + SDL_free(watch); + SDL_FreePalette(palette); + return; + } + } +} + +int +SDL_SetPaletteColors(SDL_Palette * palette, const SDL_Color * colors, + int firstcolor, int ncolors) +{ + SDL_PaletteWatch *watch; + int status = 0; + + /* Verify the parameters */ + if (!palette) { + return -1; + } + if (ncolors > (palette->ncolors - firstcolor)) { + ncolors = (palette->ncolors - firstcolor); + status = -1; + } + + if (colors != (palette->colors + firstcolor)) { + SDL_memcpy(palette->colors + firstcolor, colors, + ncolors * sizeof(*colors)); + } + + for (watch = palette->watch; watch; watch = watch->next) { + if (watch->callback(watch->userdata, palette) < 0) { + status = -1; + } + } + + return status; +} + +void +SDL_FreePalette(SDL_Palette * palette) +{ + if (!palette) { + return; + } + if (--palette->refcount > 0) { + return; + } + if (palette->colors) { + SDL_free(palette->colors); + } + SDL_free(palette); +} + /* * Allocate a pixel format structure and fill it according to the given info. */ @@ -238,7 +358,6 @@ SDL_AllocFormat(int bpp, format->BitsPerPixel = bpp; format->BytesPerPixel = (bpp + 7) / 8; if (Rmask || Bmask || Gmask) { /* Packed pixels with custom mask */ - format->palette = NULL; format->Rshift = 0; format->Rloss = 8; if (Rmask) { @@ -303,119 +422,9 @@ SDL_AllocFormat(int bpp, format->Bmask = 0; format->Amask = 0; } - if (bpp <= 8) { /* Palettized mode */ - int ncolors = 1 << bpp; -#ifdef DEBUG_PALETTE - fprintf(stderr, "bpp=%d ncolors=%d\n", bpp, ncolors); -#endif - format->palette = (SDL_Palette *) SDL_malloc(sizeof(SDL_Palette)); - if (format->palette == NULL) { - SDL_FreeFormat(format); - SDL_OutOfMemory(); - return (NULL); - } - (format->palette)->ncolors = ncolors; - (format->palette)->colors = (SDL_Color *) SDL_malloc((format-> - palette)-> - ncolors * - sizeof - (SDL_Color)); - if ((format->palette)->colors == NULL) { - SDL_FreeFormat(format); - SDL_OutOfMemory(); - return (NULL); - } - if (Rmask || Bmask || Gmask) { - /* create palette according to masks */ - int i; - int Rm = 0, Gm = 0, Bm = 0; - int Rw = 0, Gw = 0, Bw = 0; -#ifdef ENABLE_PALETTE_ALPHA - int Am = 0, Aw = 0; -#endif - if (Rmask) { - Rw = 8 - format->Rloss; - for (i = format->Rloss; i > 0; i -= Rw) - Rm |= 1 << i; - } -#ifdef DEBUG_PALETTE - fprintf(stderr, "Rw=%d Rm=0x%02X\n", Rw, Rm); -#endif - if (Gmask) { - Gw = 8 - format->Gloss; - for (i = format->Gloss; i > 0; i -= Gw) - Gm |= 1 << i; - } -#ifdef DEBUG_PALETTE - fprintf(stderr, "Gw=%d Gm=0x%02X\n", Gw, Gm); -#endif - if (Bmask) { - Bw = 8 - format->Bloss; - for (i = format->Bloss; i > 0; i -= Bw) - Bm |= 1 << i; - } -#ifdef DEBUG_PALETTE - fprintf(stderr, "Bw=%d Bm=0x%02X\n", Bw, Bm); -#endif -#ifdef ENABLE_PALETTE_ALPHA - if (Amask) { - Aw = 8 - format->Aloss; - for (i = format->Aloss; i > 0; i -= Aw) - Am |= 1 << i; - } -# ifdef DEBUG_PALETTE - fprintf(stderr, "Aw=%d Am=0x%02X\n", Aw, Am); -# endif -#endif - for (i = 0; i < ncolors; ++i) { - int r, g, b; - r = (i & Rmask) >> format->Rshift; - r = (r << format->Rloss) | ((r * Rm) >> Rw); - format->palette->colors[i].r = r; - - g = (i & Gmask) >> format->Gshift; - g = (g << format->Gloss) | ((g * Gm) >> Gw); - format->palette->colors[i].g = g; - - b = (i & Bmask) >> format->Bshift; - b = (b << format->Bloss) | ((b * Bm) >> Bw); - format->palette->colors[i].b = b; - -#ifdef ENABLE_PALETTE_ALPHA - a = (i & Amask) >> format->Ashift; - a = (a << format->Aloss) | ((a * Am) >> Aw); - format->palette->colors[i].unused = a; -#else - format->palette->colors[i].unused = SDL_ALPHA_OPAQUE; -#endif - } - } else if (ncolors == 2) { - /* Create a black and white bitmap palette */ - format->palette->colors[0].r = 0xFF; - format->palette->colors[0].g = 0xFF; - format->palette->colors[0].b = 0xFF; - format->palette->colors[1].r = 0x00; - format->palette->colors[1].g = 0x00; - format->palette->colors[1].b = 0x00; - } else { - /* Create an empty palette */ - SDL_memset((format->palette)->colors, 0xFF, - (format->palette)->ncolors * sizeof(SDL_Color)); - } - } - return (format); -} + format->palette = NULL; -SDL_PixelFormat * -SDL_ReallocFormat(SDL_Surface * surface, int bpp, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) -{ - if (surface->format) { - SDL_FreeFormat(surface->format); - SDL_FormatChanged(surface); - } - surface->format = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask); - return surface->format; + return (format); } /* @@ -439,15 +448,10 @@ SDL_FormatChanged(SDL_Surface * surface) void SDL_FreeFormat(SDL_PixelFormat * format) { - if (format) { - if (format->palette) { - if (format->palette->colors) { - SDL_free(format->palette->colors); - } - SDL_free(format->palette); - } - SDL_free(format); + if (!format) { + return; } + SDL_free(format); } /* @@ -695,10 +699,6 @@ MapNto1(SDL_PixelFormat * src, SDL_PixelFormat * dst, int *identical) SDL_Color colors[256]; SDL_Palette *pal = dst->palette; - /* SDL_DitherColors does not initialize the 'unused' component of colors, - but Map1to1 compares it against pal, so we should initialize it. */ - SDL_memset(colors, 0xFF, sizeof(colors)); - dithered.ncolors = 256; SDL_DitherColors(colors, 8); dithered.colors = colors; @@ -768,14 +768,8 @@ SDL_MapSurface(SDL_Surface * src, SDL_Surface * dst) switch (dstfmt->BytesPerPixel) { case 1: /* Palette --> Palette */ - /* If both SDL_HWSURFACE, assume have same palette */ - if (((src->flags & SDL_HWSURFACE) == SDL_HWSURFACE) && - ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE)) { - map->identity = 1; - } else { - map->table = Map1to1(srcfmt->palette, - dstfmt->palette, &map->identity); - } + map->table = + Map1to1(srcfmt->palette, dstfmt->palette, &map->identity); if (!map->identity) { if (map->table == NULL) { return (-1); diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h index 53a63537e..3d0520454 100644 --- a/src/video/SDL_pixels_c.h +++ b/src/video/SDL_pixels_c.h @@ -29,9 +29,6 @@ extern SDL_PixelFormat *SDL_AllocFormat(int bpp, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); -extern SDL_PixelFormat *SDL_ReallocFormat(SDL_Surface * surface, int bpp, - Uint32 Rmask, Uint32 Gmask, - Uint32 Bmask, Uint32 Amask); extern void SDL_FormatChanged(SDL_Surface * surface); extern void SDL_FreeFormat(SDL_PixelFormat * format); diff --git a/src/video/SDL_renderer_sw.c b/src/video/SDL_renderer_sw.c index 34b1b87c6..5ae3301cf 100644 --- a/src/video/SDL_renderer_sw.c +++ b/src/video/SDL_renderer_sw.c @@ -178,6 +178,7 @@ SDL_SW_CreateRenderer(SDL_Window * window, Uint32 flags) SDL_SW_DestroyRenderer(renderer); return NULL; } + SDL_SetSurfacePalette(data->screens[i], window->display->palette); } data->current_screen = 0; data->target = data->screens[0]; @@ -248,8 +249,8 @@ SDL_SW_SetTexturePalette(SDL_Renderer * renderer, SDL_Texture * texture, { SDL_Surface *surface = (SDL_Surface *) texture->driverdata; - SDL_SetColors(surface, colors, firstcolor, ncolors); - return 0; + return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, + ncolors); } static int @@ -314,7 +315,12 @@ static void SDL_SW_SelectRenderTexture(SDL_Renderer * renderer, SDL_Texture * texture) { SDL_SW_RenderData *data = (SDL_SW_RenderData *) renderer->driverdata; - data->target = (SDL_Surface *) texture->driverdata; + + if (texture) { + data->target = (SDL_Surface *) texture->driverdata; + } else { + data->target = data->screens[data->current_screen]; + } } static void diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 191de5f77..c029605b0 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -47,20 +47,21 @@ SDL_CreateRGBSurface(Uint32 flags, /* Next time I write a library like SDL, I'll use int for size. :) */ if (width >= 16384 || height >= 65536) { SDL_SetError("Width or height is too large"); - return (NULL); + return NULL; } /* Allocate the surface */ surface = (SDL_Surface *) SDL_malloc(sizeof(*surface)); if (surface == NULL) { SDL_OutOfMemory(); - return (NULL); + return NULL; } - surface->flags = 0; + SDL_zerop(surface); + surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask); - if (surface->format == NULL) { - SDL_free(surface); - return (NULL); + if (!surface->format) { + SDL_FreeSurface(surface); + return NULL; } if (Amask) { surface->flags |= SDL_SRCALPHA; @@ -68,16 +69,69 @@ SDL_CreateRGBSurface(Uint32 flags, surface->w = width; surface->h = height; surface->pitch = SDL_CalculatePitch(surface); - surface->pixels = NULL; - surface->locked = 0; - surface->map = NULL; SDL_SetClipRect(surface, NULL); - SDL_FormatChanged(surface); + + if (surface->format->BitsPerPixel <= 8) { + SDL_Palette *palette = + SDL_AllocPalette((1 << surface->format->BitsPerPixel)); + if (!palette) { + SDL_FreeSurface(surface); + return NULL; + } + if (Rmask || Bmask || Gmask) { + const SDL_PixelFormat *format = surface->format; + + /* create palette according to masks */ + int i; + int Rm = 0, Gm = 0, Bm = 0; + int Rw = 0, Gw = 0, Bw = 0; + + if (Rmask) { + Rw = 8 - format->Rloss; + for (i = format->Rloss; i > 0; i -= Rw) + Rm |= 1 << i; + } + if (Gmask) { + Gw = 8 - format->Gloss; + for (i = format->Gloss; i > 0; i -= Gw) + Gm |= 1 << i; + } + if (Bmask) { + Bw = 8 - format->Bloss; + for (i = format->Bloss; i > 0; i -= Bw) + Bm |= 1 << i; + } + for (i = 0; i < palette->ncolors; ++i) { + int r, g, b; + r = (i & Rmask) >> format->Rshift; + r = (r << format->Rloss) | ((r * Rm) >> Rw); + palette->colors[i].r = r; + + g = (i & Gmask) >> format->Gshift; + g = (g << format->Gloss) | ((g * Gm) >> Gw); + palette->colors[i].g = g; + + b = (i & Bmask) >> format->Bshift; + b = (b << format->Bloss) | ((b * Bm) >> Bw); + palette->colors[i].b = b; + } + } else if (palette->ncolors == 2) { + /* Create a black and white bitmap palette */ + palette->colors[0].r = 0xFF; + palette->colors[0].g = 0xFF; + palette->colors[0].b = 0xFF; + palette->colors[1].r = 0x00; + palette->colors[1].g = 0x00; + palette->colors[1].b = 0x00; + } + SDL_SetSurfacePalette(surface, palette); + SDL_FreePalette(palette); + } /* Get the pixels */ if (surface->w && surface->h) { surface->pixels = SDL_malloc(surface->h * surface->pitch); - if (surface->pixels == NULL) { + if (!surface->pixels) { SDL_FreeSurface(surface); SDL_OutOfMemory(); return NULL; @@ -88,17 +142,18 @@ SDL_CreateRGBSurface(Uint32 flags, /* Allocate an empty mapping */ surface->map = SDL_AllocBlitMap(); - if (surface->map == NULL) { + if (!surface->map) { SDL_FreeSurface(surface); - return (NULL); + return NULL; } + SDL_FormatChanged(surface); /* The surface is ready to go */ surface->refcount = 1; #ifdef CHECK_LEAKS ++surfaces_allocated; #endif - return (surface); + return surface; } /* @@ -157,47 +212,64 @@ SDL_CreateRGBSurfaceFromTexture(SDL_TextureID textureID) surface->flags |= SDL_HWSURFACE; surface->w = w; surface->h = h; - surface->lock_data = (void *) textureID; SDL_SetClipRect(surface, NULL); } } + if (surface) { + surface->textureID = textureID; + } return surface; } -/* - * Set the palette in a blittable surface - */ +static int +SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette) +{ + SDL_Surface *surface = (SDL_Surface *) userdata; + + if (surface->textureID) { + if (SDL_SetTexturePalette + (surface->textureID, palette->colors, 0, palette->ncolors) < 0) { + SDL_GetTexturePalette(surface->textureID, palette->colors, 0, + palette->ncolors); + return -1; + } + } + SDL_FormatChanged(surface); + + return 0; +} + int -SDL_SetColors(SDL_Surface * surface, const SDL_Color * colors, int firstcolor, - int ncolors) +SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette) { - SDL_Palette *pal; - int gotall; - int palsize; + if (!surface || !surface->format) { + SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface"); + return -1; + } - /* Verify the parameters */ - pal = surface->format->palette; - if (!pal) { - return 0; /* not a palettized surface */ + if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) { + SDL_SetError + ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format"); + return -1; } - gotall = 1; - palsize = 1 << surface->format->BitsPerPixel; - if (ncolors > (palsize - firstcolor)) { - ncolors = (palsize - firstcolor); - gotall = 0; + + if (surface->format->palette == palette) { + return 0; } - if (colors != (pal->colors + firstcolor)) { - SDL_memcpy(pal->colors + firstcolor, colors, - ncolors * sizeof(*colors)); + if (surface->format->palette) { + SDL_DelPaletteWatch(surface->format->palette, + SDL_SurfacePaletteChanged, surface); } - SDL_FormatChanged(surface); - if (surface->flags & (SDL_SHADOW_SURFACE | SDL_SCREEN_SURFACE)) { - gotall &= SDL_SetScreenColors(surface, colors, firstcolor, ncolors); + surface->format->palette = palette; + + if (surface->format->palette) { + SDL_AddPaletteWatch(surface->format->palette, + SDL_SurfacePaletteChanged, surface); } - return gotall; + return 0; } /* @@ -729,8 +801,8 @@ SDL_LockSurface(SDL_Surface * surface) /* Perform the lock */ if (surface->flags & SDL_HWSURFACE) { if (SDL_LockTexture - ((SDL_TextureID) surface->lock_data, NULL, 1, - &surface->pixels, &surface->pitch) < 0) { + (surface->textureID, NULL, 1, &surface->pixels, + &surface->pitch) < 0) { return (-1); } } @@ -760,13 +832,13 @@ SDL_UnlockSurface(SDL_Surface * surface) /* Unlock hardware or accelerated surfaces */ if (surface->flags & SDL_HWSURFACE) { - SDL_UnlockTexture((SDL_TextureID) surface->lock_data); - } else { - /* Update RLE encoded surface with new data */ - if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { - surface->flags &= ~SDL_RLEACCEL; /* stop lying */ - SDL_RLESurface(surface); - } + SDL_UnlockTexture(surface->textureID); + } + + /* Update RLE encoded surface with new data */ + if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { + surface->flags &= ~SDL_RLEACCEL; /* stop lying */ + SDL_RLESurface(surface); } } @@ -894,6 +966,7 @@ SDL_FreeSurface(SDL_Surface * surface) SDL_UnRLESurface(surface, 0); } if (surface->format) { + SDL_SetSurfacePalette(surface, NULL); SDL_FreeFormat(surface->format); surface->format = NULL; } @@ -902,8 +975,8 @@ SDL_FreeSurface(SDL_Surface * surface) surface->map = NULL; } /* Should we destroy the texture too? - if (surface->flags & SDL_HWSURFACE) { - SDL_DestroyTexture((SDL_TextureID)surface->lock_data); + if (surface->textureID) { + SDL_DestroyTexture(surface->textureID); } */ if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) { diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 39167fdec..61b42ff2a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -146,7 +146,7 @@ struct SDL_VideoDisplay SDL_DisplayMode *display_modes; SDL_DisplayMode desktop_mode; SDL_DisplayMode current_mode; - SDL_Palette palette; + SDL_Palette *palette; int num_render_drivers; SDL_RenderDriver *render_drivers; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index fb16e673b..46524236d 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -517,7 +517,7 @@ SDL_SetDisplayMode(const SDL_DisplayMode * mode) { SDL_VideoDisplay *display; SDL_DisplayMode display_mode; - int i; + int i, ncolors; if (!_this) { SDL_SetError("Video subsystem has not been initialized"); @@ -560,26 +560,24 @@ SDL_SetDisplayMode(const SDL_DisplayMode * mode) return 0; } + /* Set up a palette, if necessary */ if (SDL_ISPIXELFORMAT_INDEXED(display_mode.format)) { - display->palette.ncolors = - (1 << SDL_BITSPERPIXEL(display_mode.format)); - display->palette.colors = - (SDL_Color *) SDL_realloc(display->palette.colors, - display->palette.ncolors * - sizeof(*display->palette.colors)); - if (!display->palette.colors) { - SDL_OutOfMemory(); - return -1; - } - SDL_memset(display->palette.colors, 0xff, - display->palette.ncolors * - sizeof(*display->palette.colors)); + ncolors = (1 << SDL_BITSPERPIXEL(display_mode.format)); } else { - if (display->palette.colors) { - SDL_free(display->palette.colors); + ncolors = 0; + } + if ((!ncolors && display->palette) || (ncolors && !display->palette) + || (ncolors != display->palette->ncolors)) { + if (display->palette) { + SDL_FreePalette(display->palette); + display->palette = NULL; + } + if (ncolors) { + display->palette = SDL_AllocPalette(ncolors); + if (!display->palette) { + return -1; + } } - display->palette.colors = NULL; - display->palette.ncolors = 0; } return _this->SetDisplayMode(_this, &display_mode); @@ -589,31 +587,27 @@ int SDL_SetDisplayPalette(const SDL_Color * colors, int firstcolor, int ncolors) { SDL_Palette *palette; + int status = 0; if (!_this) { SDL_SetError("Video subsystem has not been initialized"); return -1; } - - palette = &SDL_CurrentDisplay.palette; - if (!palette->ncolors) { + if (!SDL_CurrentDisplay.palette) { SDL_SetError("Display mode does not have a palette"); return -1; } - if (firstcolor < 0 || (firstcolor + ncolors) > palette->ncolors) { - SDL_SetError("Palette indices are out of range"); - return -1; - } - - SDL_memcpy(&palette->colors[firstcolor], colors, - ncolors * sizeof(*colors)); + status = + SDL_SetPaletteColors(SDL_CurrentDisplay.palette, colors, firstcolor, + ncolors); if (_this->SetDisplayPalette) { - return _this->SetDisplayPalette(_this, palette); - } else { - return 0; + if (_this->SetDisplayPalette(_this, palette) < 0) { + status = -1; + } } + return status; } int @@ -626,7 +620,7 @@ SDL_GetDisplayPalette(SDL_Color * colors, int firstcolor, int ncolors) return -1; } - palette = &SDL_CurrentDisplay.palette; + palette = SDL_CurrentDisplay.palette; if (!palette->ncolors) { SDL_SetError("Display mode does not have a palette"); return -1; @@ -1717,10 +1711,9 @@ SDL_VideoQuit(void) SDL_free(display->windows); display->windows = NULL; } - if (display->palette.colors) { - SDL_free(display->palette.colors); - display->palette.colors = NULL; - display->palette.ncolors = 0; + if (display->palette) { + SDL_FreePalette(display->palette); + display->palette = NULL; } } _this->VideoQuit(_this); diff --git a/src/video/dummy/SDL_nullrender.c b/src/video/dummy/SDL_nullrender.c index e0c17a9af..e9d009a20 100644 --- a/src/video/dummy/SDL_nullrender.c +++ b/src/video/dummy/SDL_nullrender.c @@ -106,16 +106,7 @@ SDL_DUMMY_CreateRenderer(SDL_Window * window, Uint32 flags) SDL_DUMMY_DestroyRenderer(renderer); return NULL; } - - /* If the display has a palette, use it for the window surfaces */ - if (window->display->palette.ncolors) { - SDL_PixelFormat *format = data->surface->format; - if (format->palette->colors) { - SDL_free(format->palette->colors); - } - SDL_free(format->palette); - format->palette = &window->display->palette; - } + SDL_SetSurfacePalette(data->surface, window->display->palette); return renderer; } @@ -178,8 +169,8 @@ SDL_DUMMY_RenderPresent(SDL_Renderer * renderer) if (SDL_getenv("SDL_VIDEO_DUMMY_SAVE_FRAMES")) { char file[128]; - SDL_snprintf(file, sizeof(file), "SDL_frame-%8.8d.bmp", - ++frame_number); + SDL_snprintf(file, sizeof(file), "SDL_window%d-%8.8d.bmp", + renderer->window->id, ++frame_number); SDL_SaveBMP(surface, file); } }