A bunch of work on getting alpha blending more correct.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 06 Mar 2019 02:56:23 -0500
changeset 102d45dadba9ff2
parent 101 e7c66e433839
child 103 685c0014eda1
A bunch of work on getting alpha blending more correct.
src/SDL12_compat.c
src/SDL20_syms.h
     1.1 --- a/src/SDL12_compat.c	Wed Mar 06 02:54:33 2019 -0500
     1.2 +++ b/src/SDL12_compat.c	Wed Mar 06 02:56:23 2019 -0500
     1.3 @@ -2099,11 +2099,11 @@
     1.4          format12->alpha = 255;
     1.5      }
     1.6  
     1.7 -    if (format12->alpha != 255) {
     1.8 +    SDL_BlendMode blendmode = SDL_BLENDMODE_NONE;
     1.9 +    if ((SDL20_GetSurfaceBlendMode(surface20, &blendmode) == 0) && (blendmode == SDL_BLENDMODE_BLEND)) {
    1.10          surface12->flags |= SDL12_SRCALPHA;
    1.11      }
    1.12  
    1.13 -
    1.14      SDL20_zerop(surface12);
    1.15      flags = surface20->flags;
    1.16      #ifdef SDL_SIMD_ALIGNED
    1.17 @@ -2219,8 +2219,6 @@
    1.18          surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
    1.19      }
    1.20  
    1.21 -    SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
    1.22 -
    1.23      SDL12_Surface *surface12 = Surface20to12(surface20);
    1.24      if (!surface12) {
    1.25          SDL20_FreeSurface(surface20);
    1.26 @@ -2231,6 +2229,11 @@
    1.27  
    1.28      SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);
    1.29  
    1.30 +    if (flags12 & SDL12_SRCALPHA) {
    1.31 +        surface12->flags |= SDL12_SRCALPHA;
    1.32 +        SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
    1.33 +    }
    1.34 +
    1.35      return surface12;
    1.36  }
    1.37  
    1.38 @@ -2249,8 +2252,6 @@
    1.39          surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
    1.40      }
    1.41  
    1.42 -    SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
    1.43 -
    1.44      SDL12_Surface *surface12 = Surface20to12(surface20);
    1.45      if (!surface12) {
    1.46          SDL20_FreeSurface(surface20);
    1.47 @@ -2865,15 +2866,114 @@
    1.48      return VideoSurface12;
    1.49  }
    1.50  
    1.51 +static int
    1.52 +SaveDestAlpha(SDL12_Surface *src12, SDL12_Surface *dst12, Uint8 **retval)
    1.53 +{
    1.54 +    FIXME("This should only save the dst rect in use");
    1.55 +
    1.56 +    /* The 1.2 docs say this:
    1.57 +     * RGBA->RGBA:
    1.58 +     *     SDL_SRCALPHA set:
    1.59 +     * 	alpha-blend (using the source alpha channel) the RGB values;
    1.60 +     * 	leave destination alpha untouched. [Note: is this correct?]
    1.61 +     *
    1.62 +     * In SDL2, we change the destination alpha. We have to save it off in this case, which sucks.
    1.63 +     */
    1.64 +    Uint8 *dstalpha = NULL;
    1.65 +    const SDL_bool save_dstalpha = ((src12->flags & SDL12_SRCALPHA) && dst12->format->Amask && ((src12->format->alpha != 255) || src12->format->Amask)) ? SDL_TRUE : SDL_FALSE;
    1.66 +    if (save_dstalpha) {
    1.67 +        const int w = dst12->w;
    1.68 +        const int h = dst12->h;
    1.69 +        dstalpha = (Uint8 *) SDL_malloc(w * h);
    1.70 +        if (!dstalpha) {
    1.71 +            *retval = NULL;
    1.72 +            return SDL20_OutOfMemory();
    1.73 +        }
    1.74 +
    1.75 +        Uint8 *dptr = dstalpha;
    1.76 +        const Uint32 amask = dst12->format->Amask;
    1.77 +        const Uint32 ashift = dst12->format->Ashift;
    1.78 +        const Uint16 pitch = dst12->pitch;
    1.79 +        if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
    1.80 +            FIXME("this could be SIMD'd");
    1.81 +        }
    1.82 +        if (dst12->format->BytesPerPixel == 2) {
    1.83 +            const Uint16 *sptr = (const Uint16 *) dst12->pixels;
    1.84 +            for (int y = 0; y < h; y++) {
    1.85 +                for (int x = 0; x < w; x++) {
    1.86 +                    *(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
    1.87 +                }
    1.88 +                sptr = (Uint16 *) (((Uint8 *) sptr) + pitch);
    1.89 +            }
    1.90 +        } else if (dst12->format->BytesPerPixel == 4) {
    1.91 +            const Uint32 *sptr = (const Uint32 *) dst12->pixels;
    1.92 +            for (int y = 0; y < h; y++) {
    1.93 +                for (int x = 0; x < w; x++) {
    1.94 +                    *(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
    1.95 +                }
    1.96 +                sptr = (Uint32 *) (((Uint8 *) sptr) + pitch);
    1.97 +            }
    1.98 +        } else {
    1.99 +            FIXME("Unhandled dest alpha");
   1.100 +        }
   1.101 +    }
   1.102 +
   1.103 +    *retval = dstalpha;
   1.104 +    return 0;
   1.105 +}
   1.106 +
   1.107 +static void
   1.108 +RestoreDestAlpha(SDL12_Surface *dst12, Uint8 *dstalpha)
   1.109 +{
   1.110 +    if (dstalpha) {
   1.111 +        const int w = dst12->w;
   1.112 +        const int h = dst12->h;
   1.113 +        const Uint8 *sptr = dstalpha;
   1.114 +        const Uint32 amask = dst12->format->Amask;
   1.115 +        const Uint32 ashift = dst12->format->Ashift;
   1.116 +        const Uint16 pitch = dst12->pitch;
   1.117 +        if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
   1.118 +            FIXME("this could be SIMD'd");
   1.119 +        }
   1.120 +        if (dst12->format->BytesPerPixel == 2) {
   1.121 +            Uint16 *dptr = (Uint16 *) dst12->pixels;
   1.122 +            for (int y = 0; y < h; y++) {
   1.123 +                for (int x = 0; x < w; x++) {
   1.124 +                    dptr[x] = (Uint16) ((dptr[x] & ~amask) | ((((Uint16) *(sptr++)) << ashift) & amask));
   1.125 +                }
   1.126 +                dptr = (Uint16 *) (((Uint8 *) dptr) + pitch);
   1.127 +            }
   1.128 +        } else if (dst12->format->BytesPerPixel == 4) {
   1.129 +            Uint32 *dptr = (Uint32 *) dst12->pixels;
   1.130 +            for (int y = 0; y < h; y++) {
   1.131 +                for (int x = 0; x < w; x++) {
   1.132 +                    dptr[x] = (dptr[x] & ~amask) | ((((Uint32) *(sptr++)) << ashift) & amask);
   1.133 +                }
   1.134 +                dptr = (Uint32 *) (((Uint8 *) dptr) + pitch);
   1.135 +            }
   1.136 +        } else {
   1.137 +            FIXME("Unhandled dest alpha");
   1.138 +        }
   1.139 +        SDL_free(dstalpha);
   1.140 +    }
   1.141 +}
   1.142 +
   1.143  DECLSPEC int SDLCALL
   1.144 -SDL_UpperBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL12_Rect *dstrect12)
   1.145 +SDL_UpperBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
   1.146  {
   1.147 +    Uint8 *dstalpha;
   1.148 +    if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
   1.149 +        return -1;
   1.150 +    }
   1.151 +
   1.152      SDL_Rect srcrect20, dstrect20;
   1.153 -    const int retval = SDL20_UpperBlit(src->surface20,
   1.154 +    const int retval = SDL20_UpperBlit(src12->surface20,
   1.155                                         srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
   1.156 -                                       dst->surface20,
   1.157 +                                       dst12->surface20,
   1.158                                         dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);
   1.159  
   1.160 +    RestoreDestAlpha(dst12, dstalpha);
   1.161 +
   1.162      if (srcrect12) {
   1.163          Rect20to12(&srcrect20, srcrect12);
   1.164      }
   1.165 @@ -2886,14 +2986,21 @@
   1.166  }
   1.167  
   1.168  DECLSPEC int SDLCALL
   1.169 -SDL_LowerBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL12_Rect *dstrect12)
   1.170 +SDL_LowerBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
   1.171  {
   1.172 +    Uint8 *dstalpha;
   1.173 +    if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
   1.174 +        return -1;
   1.175 +    }
   1.176 +
   1.177      SDL_Rect srcrect20, dstrect20;
   1.178 -    const int retval = SDL20_LowerBlit(src->surface20,
   1.179 +    const int retval = SDL20_LowerBlit(src12->surface20,
   1.180                                         srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
   1.181 -                                       dst->surface20,
   1.182 +                                       dst12->surface20,
   1.183                                         dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);
   1.184  
   1.185 +    RestoreDestAlpha(dst12, dstalpha);
   1.186 +
   1.187      if (srcrect12) {
   1.188          Rect20to12(&srcrect20, srcrect12);
   1.189      }
   1.190 @@ -2913,13 +3020,7 @@
   1.191      if (SDL20_GetSurfaceAlphaMod(surface12->surface20, &surface12->format->alpha) < 0) {
   1.192          surface12->format->alpha = 255;
   1.193      }
   1.194 -
   1.195 -    if (surface12->format->alpha != 255) {
   1.196 -        surface12->flags |= SDL12_SRCALPHA;
   1.197 -    } else {
   1.198 -        surface12->flags &= ~SDL12_SRCALPHA;
   1.199 -    }
   1.200 -
   1.201 +    FIXME("Should this set SDL12_SRCALPHA on the surface?");
   1.202      return retval;
   1.203  }
   1.204  
   1.205 @@ -2957,6 +3058,11 @@
   1.206          retval = Surface20to12(surface20);
   1.207          if (!retval) {
   1.208              SDL20_FreeSurface(surface20);
   1.209 +        } else {
   1.210 +            if (flags12 & SDL12_SRCALPHA) {
   1.211 +                SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
   1.212 +                retval->flags |= SDL12_SRCALPHA;
   1.213 +            }
   1.214          }
   1.215      }
   1.216      return retval;
     2.1 --- a/src/SDL20_syms.h	Wed Mar 06 02:54:33 2019 -0500
     2.2 +++ b/src/SDL20_syms.h	Wed Mar 06 02:56:23 2019 -0500
     2.3 @@ -100,6 +100,7 @@
     2.4  SDL20_SYM(int,SetSurfaceAlphaMod,(SDL_Surface *a, Uint8 b),(a,b),return)
     2.5  SDL20_SYM(int,GetSurfaceAlphaMod,(SDL_Surface *a, Uint8 *b),(a,b),return)
     2.6  SDL20_SYM(int,SetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode b),(a,b),return)
     2.7 +SDL20_SYM(int,GetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode *b),(a,b),return)
     2.8  SDL20_SYM(SDL_Surface*,LoadBMP_RW,(SDL_RWops *a, int b),(a,b),return)
     2.9  SDL20_SYM(int,SaveBMP_RW,(SDL_Surface *a, SDL_RWops *b, int c),(a,b,c),return)
    2.10  SDL20_SYM(int,SetPaletteColors,(SDL_Palette *a, const SDL_Color *b, int c, int d),(a,b,c,d),return)