A bunch of work on getting 2D surfaces more correct (palettes, alpha, etc).
authorRyan C. Gordon <icculus@icculus.org>
Sat, 02 Mar 2019 22:07:01 -0500
changeset 1006384c83ea0e8
parent 99 db10b95d4059
child 101 e7c66e433839
A bunch of work on getting 2D surfaces more correct (palettes, alpha, etc).
src/SDL12_compat.c
src/SDL20_syms.h
     1.1 --- a/src/SDL12_compat.c	Sat Mar 02 08:19:49 2019 -0500
     1.2 +++ b/src/SDL12_compat.c	Sat Mar 02 22:07:01 2019 -0500
     1.3 @@ -141,6 +141,9 @@
     1.4  #define SDL12_INIT_EVENTTHREAD 0x01000000
     1.5  #define SDL12_INIT_EVERYTHING  0x0000FFFF
     1.6  
     1.7 +#define SDL12_LOGPAL 1
     1.8 +#define SDL12_PHYSPAL 2
     1.9 +
    1.10  typedef struct SDL12_Rect
    1.11  {
    1.12      Sint16 x;
    1.13 @@ -2082,8 +2085,23 @@
    1.14      format12->Gmask = surface20->format->Gmask;
    1.15      format12->Bmask = surface20->format->Bmask;
    1.16      format12->Amask = surface20->format->Amask;
    1.17 -    FIXME("format12->colorkey");
    1.18 -    FIXME("format12->alpha");
    1.19 +
    1.20 +    if (SDL20_HasColorKey(surface20)) {
    1.21 +        if (SDL20_GetColorKey(surface20, &format12->colorkey) == -1) {
    1.22 +            format12->colorkey = 0;
    1.23 +        } else {
    1.24 +            surface12->flags |= SDL12_SRCCOLORKEY;
    1.25 +        }
    1.26 +    }
    1.27 +
    1.28 +    if (SDL20_GetSurfaceAlphaMod(surface20, &format12->alpha) == -1) {
    1.29 +        format12->alpha = 255;
    1.30 +    }
    1.31 +
    1.32 +    if (format12->alpha != 255) {
    1.33 +        surface12->flags |= SDL12_SRCALPHA;
    1.34 +    }
    1.35 +
    1.36  
    1.37      SDL20_zerop(surface12);
    1.38      flags = surface20->flags;
    1.39 @@ -2116,37 +2134,132 @@
    1.40      return NULL;
    1.41  }
    1.42  
    1.43 +static void
    1.44 +SetPalette12ForMasks(SDL12_Surface *surface12, const Uint32 Rmask, const Uint32 Gmask, const Uint32 Bmask)
    1.45 +{
    1.46 +    SDL12_PixelFormat *format12 = surface12->format;
    1.47 +    if (format12->palette && (Rmask || Bmask || Gmask)) {
    1.48 +        #define LOSSMASKSHIFTSETUP(t) { \
    1.49 +            format12->t##shift = 0; \
    1.50 +            format12->t##loss = 8; \
    1.51 +            if (t##mask) { \
    1.52 +                Uint32 mask; \
    1.53 +                for (mask = t##mask; !(mask & 1); mask >>= 1) { \
    1.54 +                    format12->t##shift++; \
    1.55 +                } \
    1.56 +                while (mask & 1) { \
    1.57 +                    format12->t##loss--; \
    1.58 +                    mask >>= 1; \
    1.59 +                } \
    1.60 +            } \
    1.61 +            format12->t##mask = t##mask; \
    1.62 +        }
    1.63 +        LOSSMASKSHIFTSETUP(R);
    1.64 +        LOSSMASKSHIFTSETUP(G);
    1.65 +        LOSSMASKSHIFTSETUP(B);
    1.66 +        #undef LOSSMASSSHIFTSETUP
    1.67 +        format12->Amask = 0;
    1.68 +        format12->Ashift = 0;
    1.69 +        format12->Aloss = 8;
    1.70 +
    1.71 +        #define MASKSETUP(t) \
    1.72 +            int t##w = 0, t##m = 0; \
    1.73 +            if (t##mask) { \
    1.74 +            t##w = 8 - format12->t##loss; \
    1.75 +            for (int i = format12->t##loss; i > 0; i -= t##w) { \
    1.76 +                t##m |= 1 << i; \
    1.77 +            } \
    1.78 +        }
    1.79 +        MASKSETUP(R);
    1.80 +        MASKSETUP(G);
    1.81 +        MASKSETUP(B);
    1.82 +        #undef MASKSETUP
    1.83 +
    1.84 +        const int ncolors = format12->palette->ncolors;
    1.85 +        SDL_Color *color = format12->palette->colors;
    1.86 +        for (int i = 0; i < ncolors; i++, color++) {
    1.87 +            #define SETCOLOR(T, t) { \
    1.88 +                const int x = (i & T##mask) >> format12->T##shift; \
    1.89 +                color->t = (x << format12->T##loss) | ((x * T##m) >> T##w); \
    1.90 +            }
    1.91 +            SETCOLOR(R, r);
    1.92 +            SETCOLOR(G, g);
    1.93 +            SETCOLOR(B, b);
    1.94 +            #undef SETCOLOR
    1.95 +            color->a = 255;
    1.96 +        }
    1.97 +
    1.98 +        SDL_PixelFormat *format20 = surface12->surface20->format;
    1.99 +        #define UPDATEFMT20(t) \
   1.100 +            format20->t##mask = format12->t##mask; \
   1.101 +            format20->t##loss = format12->t##loss; \
   1.102 +            format20->t##shift = format12->t##shift;
   1.103 +        UPDATEFMT20(R);
   1.104 +        UPDATEFMT20(G);
   1.105 +        UPDATEFMT20(B);
   1.106 +        UPDATEFMT20(A);
   1.107 +        #undef UPDATEFMT20
   1.108 +    }
   1.109 +}
   1.110 +
   1.111  DECLSPEC SDL12_Surface * SDLCALL
   1.112 -SDL_CreateRGBSurface(Uint32 sdl12flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   1.113 +SDL_CreateRGBSurface(Uint32 flags12, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   1.114  {
   1.115 -    if (depth == 8) {
   1.116 -        Rmask = Gmask = Bmask = Amask = 0;  // force a paletted surface.
   1.117 +    // SDL 1.2 checks this.
   1.118 +    if ((width >= 16384) || (height >= 65536)) {
   1.119 +        SDL20_SetError("Width or height is too large");
   1.120 +        return NULL;
   1.121      }
   1.122 -    SDL_Surface *surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
   1.123 +
   1.124 +    SDL_Surface *surface20;
   1.125 +    if (depth == 8) {  // don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems.
   1.126 +        surface20 = SDL20_CreateRGBSurface(0, width, height, depth, 0, 0, 0, 0);
   1.127 +    } else {
   1.128 +        surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
   1.129 +    }
   1.130 +
   1.131 +    SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
   1.132 +
   1.133      SDL12_Surface *surface12 = Surface20to12(surface20);
   1.134      if (!surface12) {
   1.135          SDL20_FreeSurface(surface20);
   1.136          return NULL;
   1.137      }
   1.138  
   1.139 -    SDL_assert(surface12->flags == 0);  // shouldn't have prealloc, rleaccel, or dontfree.
   1.140 +    SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == 0);  // shouldn't have prealloc, rleaccel, or dontfree.
   1.141 +
   1.142 +    SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);
   1.143 +
   1.144      return surface12;
   1.145  }
   1.146  
   1.147  DECLSPEC SDL12_Surface * SDLCALL
   1.148  SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   1.149  {
   1.150 -    if (depth == 8) {
   1.151 -        Rmask = Gmask = Bmask = Amask = 0;  // force a paletted surface.
   1.152 +    if ((width >= 16384) || (height >= 65536)) {
   1.153 +        SDL20_SetError("Width or height is too large");
   1.154 +        return NULL;
   1.155      }
   1.156 -    SDL_Surface *surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
   1.157 +
   1.158 +    SDL_Surface *surface20;
   1.159 +    if (depth == 8) {  // don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems.
   1.160 +        surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, 0, 0, 0, 0);
   1.161 +    } else {
   1.162 +        surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
   1.163 +    }
   1.164 +
   1.165 +    SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
   1.166 +
   1.167      SDL12_Surface *surface12 = Surface20to12(surface20);
   1.168      if (!surface12) {
   1.169          SDL20_FreeSurface(surface20);
   1.170          return NULL;
   1.171      }
   1.172  
   1.173 -    SDL_assert(surface12->flags == SDL12_PREALLOC);  // should _only_ have prealloc.
   1.174 +    SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == SDL12_PREALLOC);  // should _only_ have prealloc.
   1.175 +
   1.176 +    SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);
   1.177 +
   1.178      return surface12;
   1.179  }
   1.180  
   1.181 @@ -2792,10 +2905,21 @@
   1.182  }
   1.183  
   1.184  DECLSPEC int SDLCALL
   1.185 -SDL_SetAlpha(SDL12_Surface * surface, Uint32 flag, Uint8 value)
   1.186 +SDL_SetAlpha(SDL12_Surface *surface12, Uint32 flags12, Uint8 value)
   1.187  {
   1.188 -    FIXME("write me");
   1.189 -    return SDL20_Unsupported();
   1.190 +    const SDL_bool addkey = (flags12 & SDL12_SRCALPHA) ? SDL_TRUE : SDL_FALSE;
   1.191 +    const int retval = SDL20_SetSurfaceAlphaMod(surface12->surface20, addkey ? value : 255);
   1.192 +    if (SDL20_GetSurfaceAlphaMod(surface12->surface20, &surface12->format->alpha) < 0) {
   1.193 +        surface12->format->alpha = 255;
   1.194 +    }
   1.195 +
   1.196 +    if (surface12->format->alpha != 255) {
   1.197 +        surface12->flags |= SDL12_SRCALPHA;
   1.198 +    } else {
   1.199 +        surface12->flags &= ~SDL12_SRCALPHA;
   1.200 +    }
   1.201 +
   1.202 +    return retval;
   1.203  }
   1.204  
   1.205  DECLSPEC int SDLCALL
   1.206 @@ -3102,6 +3226,13 @@
   1.207      if (SDL20_GetColorKey(surface12->surface20, &surface12->format->colorkey) < 0) {
   1.208          surface12->format->colorkey = 0;
   1.209      }
   1.210 +
   1.211 +    if (addkey) {
   1.212 +        surface12->flags |= SDL12_SRCCOLORKEY;
   1.213 +    } else {
   1.214 +        surface12->flags &= ~SDL12_SRCCOLORKEY;
   1.215 +    }
   1.216 +
   1.217      return retval;
   1.218  }
   1.219  
   1.220 @@ -3109,16 +3240,47 @@
   1.221  SDL_SetPalette(SDL12_Surface *surface12, int flags, const SDL_Color *colors,
   1.222                 int firstcolor, int ncolors)
   1.223  {
   1.224 -    FIXME("write me");
   1.225 -    return SDL20_Unsupported();
   1.226 +    if (!surface12) {
   1.227 +        return 0;  // not an error, a no-op.
   1.228 +    }
   1.229 +
   1.230 +    SDL12_Palette *palette12 = surface12->format->palette;
   1.231 +    if (!palette12) {
   1.232 +        return 0;  // not an error, a no-op.
   1.233 +    }
   1.234 +
   1.235 +    SDL_Palette *palette20 = surface12->surface20->format->palette;
   1.236 +    SDL_assert(palette20 != NULL);
   1.237 +
   1.238 +    // we need to force the "unused" field to 255, since it's "alpha" in SDL2.
   1.239 +    SDL_Color *opaquecolors = (SDL_Color *) SDL20_malloc(sizeof (SDL_Color) * ncolors);
   1.240 +    if (!opaquecolors) {
   1.241 +        return SDL20_OutOfMemory();
   1.242 +    }
   1.243 +
   1.244 +    // don't SDL_memcpy in case the 'a' field is uninitialized and upsets
   1.245 +    //  memory tools like Valgrind.
   1.246 +    for (int i = 0; i < ncolors; i++) {
   1.247 +        opaquecolors[i].r = colors[i].r;
   1.248 +        opaquecolors[i].g = colors[i].g;
   1.249 +        opaquecolors[i].b = colors[i].b;
   1.250 +        opaquecolors[i].a = 255;
   1.251 +    }
   1.252 +
   1.253 +    const int retval = SDL20_SetPaletteColors(palette20, opaquecolors, firstcolor, ncolors);
   1.254 +    SDL20_free(opaquecolors);
   1.255 +
   1.256 +    // in case this pointer changed...
   1.257 +    palette12->colors = palette20->colors;
   1.258 +
   1.259 +    return retval;
   1.260  }
   1.261  
   1.262  DECLSPEC int SDLCALL
   1.263  SDL_SetColors(SDL12_Surface *surface12, const SDL_Color * colors, int firstcolor,
   1.264                int ncolors)
   1.265  {
   1.266 -    FIXME("write me");
   1.267 -    return SDL20_Unsupported();
   1.268 +    return SDL_SetPalette(surface12, SDL12_LOGPAL | SDL12_PHYSPAL, colors, firstcolor, ncolors);
   1.269  }
   1.270  
   1.271  DECLSPEC int SDLCALL
     2.1 --- a/src/SDL20_syms.h	Sat Mar 02 08:19:49 2019 -0500
     2.2 +++ b/src/SDL20_syms.h	Sat Mar 02 22:07:01 2019 -0500
     2.3 @@ -93,11 +93,16 @@
     2.4  SDL20_SYM(void,UnlockSurface,(SDL_Surface *a),(a),)
     2.5  SDL20_SYM(int,UpperBlit,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
     2.6  SDL20_SYM(int,LowerBlit,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
     2.7 +SDL20_SYM(SDL_bool,HasColorKey,(SDL_Surface *a),(a),return)
     2.8  SDL20_SYM(int,SetColorKey,(SDL_Surface *a, int b, Uint32 c),(a,b,c),return)
     2.9  SDL20_SYM(int,GetColorKey,(SDL_Surface *a, Uint32 *b),(a,b),return)
    2.10  SDL20_SYM(void,FreeSurface,(SDL_Surface *a),(a),)
    2.11 +SDL20_SYM(int,SetSurfaceAlphaMod,(SDL_Surface *a, Uint8 b),(a,b),return)
    2.12 +SDL20_SYM(int,GetSurfaceAlphaMod,(SDL_Surface *a, Uint8 *b),(a,b),return)
    2.13 +SDL20_SYM(int,SetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode b),(a,b),return)
    2.14  SDL20_SYM(SDL_Surface*,LoadBMP_RW,(SDL_RWops *a, int b),(a,b),return)
    2.15  SDL20_SYM(int,SaveBMP_RW,(SDL_Surface *a, SDL_RWops *b, int c),(a,b,c),return)
    2.16 +SDL20_SYM(int,SetPaletteColors,(SDL_Palette *a, const SDL_Color *b, int c, int d),(a,b,c,d),return)
    2.17  SDL20_SYM(int,GL_LoadLibrary,(const char *a),(a),return)
    2.18  SDL20_SYM_PASSTHROUGH(void *,GL_GetProcAddress,(const char *a),(a),return)
    2.19  SDL20_SYM(int,GL_SetAttribute,(SDL_GLattr a, int b),(a,b),return)