Better fix to set the palette opaque, when there is also a colorkey
authorSylvain Becker <sylvain.becker@gmail.com>
Mon, 24 Feb 2020 21:57:03 +0100
changeset 135514efb3eb7a3b3
parent 13550 058a6b076676
child 13552 2f75c19fd2f2
Better fix to set the palette opaque, when there is also a colorkey
(see bug 3827)
src/video/SDL_surface.c
     1.1 --- a/src/video/SDL_surface.c	Mon Feb 24 12:07:18 2020 -0800
     1.2 +++ b/src/video/SDL_surface.c	Mon Feb 24 21:57:03 2020 +0100
     1.3 @@ -402,64 +402,6 @@
     1.4      SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
     1.5  }
     1.6  
     1.7 -
     1.8 -static void
     1.9 -SDL_ConvertSetOpaque(SDL_Surface * surface)
    1.10 -{
    1.11 -    int x, y;
    1.12 -
    1.13 -    if (!surface) {
    1.14 -        return;
    1.15 -    }
    1.16 -
    1.17 -    if (!surface->format->Amask) {
    1.18 -        return;
    1.19 -    }
    1.20 -
    1.21 -    SDL_LockSurface(surface);
    1.22 -
    1.23 -    switch (surface->format->BytesPerPixel) {
    1.24 -    case 2:
    1.25 -        {
    1.26 -            Uint16 *row, *spot;
    1.27 -            Uint16 mask = (Uint16) (surface->format->Amask);
    1.28 -
    1.29 -            row = (Uint16 *) surface->pixels;
    1.30 -            for (y = surface->h; y--;) {
    1.31 -                spot = row;
    1.32 -                for (x = surface->w; x--;) {
    1.33 -                    *spot |= mask;
    1.34 -                    ++spot;
    1.35 -                }
    1.36 -                row += surface->pitch / 2;
    1.37 -            }
    1.38 -        }
    1.39 -        break;
    1.40 -    case 3:
    1.41 -        /* FIXME */
    1.42 -        break;
    1.43 -    case 4:
    1.44 -        {
    1.45 -            Uint32 *row, *spot;
    1.46 -            Uint32 mask = surface->format->Amask;
    1.47 -
    1.48 -            row = (Uint32 *) surface->pixels;
    1.49 -            for (y = surface->h; y--;) {
    1.50 -                spot = row;
    1.51 -                for (x = surface->w; x--;) {
    1.52 -                    *spot |= mask;
    1.53 -                    ++spot;
    1.54 -                }
    1.55 -                row += surface->pitch / 4;
    1.56 -            }
    1.57 -        }
    1.58 -        break;
    1.59 -    }
    1.60 -
    1.61 -    SDL_UnlockSurface(surface);
    1.62 -}
    1.63 -
    1.64 -
    1.65  int
    1.66  SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
    1.67  {
    1.68 @@ -1023,6 +965,7 @@
    1.69      SDL_bool palette_ck_transform = SDL_FALSE;
    1.70      int palette_ck_value = 0;
    1.71      SDL_bool palette_has_alpha = SDL_FALSE;
    1.72 +    Uint8 *palette_saved_alpha = NULL;
    1.73  
    1.74      if (!surface) {
    1.75          SDL_InvalidParamError("surface");
    1.76 @@ -1084,6 +1027,40 @@
    1.77      bounds.w = surface->w;
    1.78      bounds.h = surface->h;
    1.79  
    1.80 +    /* Source surface has a palette with no real alpha (0 or OPAQUE).
    1.81 +     * Destination format has alpha.
    1.82 +     * -> set alpha channel to be opaque */
    1.83 +    if (surface->format->palette && format->Amask) {
    1.84 +        SDL_bool set_opaque = SDL_FALSE;
    1.85 +        {
    1.86 +            int i;
    1.87 +            for (i = 0; i < surface->format->palette->ncolors; i++) {
    1.88 +                Uint8 alpha_value = surface->format->palette->colors[i].a;
    1.89 +
    1.90 +                if (alpha_value != 0 && alpha_value != SDL_ALPHA_OPAQUE) {
    1.91 +                    /* Palette has at least one alpha value. Don't do anything */
    1.92 +                    set_opaque = SDL_FALSE;
    1.93 +                    palette_has_alpha = SDL_TRUE;
    1.94 +                    break;
    1.95 +                }
    1.96 +
    1.97 +                if (alpha_value == 0) {
    1.98 +                    set_opaque = SDL_TRUE;
    1.99 +                }
   1.100 +            }
   1.101 +        }
   1.102 +
   1.103 +        /* Set opaque and backup palette alpha values */
   1.104 +        if (set_opaque) {
   1.105 +            palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
   1.106 +            int i;
   1.107 +            for (i = 0; i < surface->format->palette->ncolors; i++) {
   1.108 +                palette_saved_alpha[i] = surface->format->palette->colors[i].a;
   1.109 +                surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
   1.110 +            }
   1.111 +        }
   1.112 +    }
   1.113 +
   1.114      /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
   1.115      if (copy_flags & SDL_COPY_COLORKEY) {
   1.116          if (surface->format->palette && !format->palette) {
   1.117 @@ -1096,11 +1073,20 @@
   1.118  
   1.119      ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
   1.120  
   1.121 -    /* Restore value */
   1.122 +    /* Restore colorkey alpha value */
   1.123      if (palette_ck_transform) {
   1.124          surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
   1.125      }
   1.126  
   1.127 +    /* Restore palette alpha values */
   1.128 +    if (palette_saved_alpha) {
   1.129 +        int i;
   1.130 +        for (i = 0; i < surface->format->palette->ncolors; i++) {
   1.131 +            surface->format->palette->colors[i].a = palette_saved_alpha[i];
   1.132 +        }
   1.133 +        SDL_stack_free(palette_saved_alpha);
   1.134 +    }
   1.135 +
   1.136      /* Clean up the original surface, and update converted surface */
   1.137      convert->map->info.r = copy_color.r;
   1.138      convert->map->info.g = copy_color.g;
   1.139 @@ -1181,38 +1167,6 @@
   1.140      }
   1.141      SDL_SetClipRect(convert, &surface->clip_rect);
   1.142  
   1.143 -    /* Source surface has a palette with alpha. Will need blend mode */
   1.144 -    if (palette_has_alpha == SDL_FALSE && surface->format->palette) {
   1.145 -        int i;
   1.146 -        for (i = 0; i < surface->format->palette->ncolors; i++) {
   1.147 -            Uint8 alpha_value = surface->format->palette->colors[i].a;
   1.148 -            if (alpha_value != 0 && alpha_value != SDL_ALPHA_OPAQUE) {
   1.149 -                palette_has_alpha = SDL_TRUE;
   1.150 -                break;
   1.151 -            }
   1.152 -        }
   1.153 -    }
   1.154 -
   1.155 -    /* Source surface has a palette with no alpha nor colorkey.
   1.156 -     * Destination format has alpha.
   1.157 -     * We may need to set the alpha channel to opaque. */
   1.158 -    if (surface->format->palette && format->Amask && palette_has_alpha == SDL_FALSE) {
   1.159 -        SDL_bool need_opaque = SDL_FALSE;
   1.160 -        int i;
   1.161 -        for (i = 0; i < surface->format->palette->ncolors; i++) {
   1.162 -            Uint8 alpha_value = surface->format->palette->colors[i].a;
   1.163 -            if (alpha_value == 0) {
   1.164 -                need_opaque = SDL_TRUE;
   1.165 -                break;
   1.166 -            }
   1.167 -        }
   1.168 -
   1.169 -        if (need_opaque) {
   1.170 -            SDL_ConvertSetOpaque(convert);
   1.171 -        }
   1.172 -    }
   1.173 -
   1.174 -
   1.175      /* Enable alpha blending by default if the new surface has an
   1.176       * alpha channel or alpha modulation */
   1.177      if ((surface->format->Amask && format->Amask) ||