Skip to content

Commit

Permalink
A bunch of work on getting alpha blending more correct.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Mar 6, 2019
1 parent d3532bc commit 7c1b74c
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 19 deletions.
144 changes: 125 additions & 19 deletions src/SDL12_compat.c
Expand Up @@ -2099,11 +2099,11 @@ Surface20to12(SDL_Surface *surface20)
format12->alpha = 255;
}

if (format12->alpha != 255) {
SDL_BlendMode blendmode = SDL_BLENDMODE_NONE;
if ((SDL20_GetSurfaceBlendMode(surface20, &blendmode) == 0) && (blendmode == SDL_BLENDMODE_BLEND)) {
surface12->flags |= SDL12_SRCALPHA;
}


SDL20_zerop(surface12);
flags = surface20->flags;
#ifdef SDL_SIMD_ALIGNED
Expand Down Expand Up @@ -2219,8 +2219,6 @@ SDL_CreateRGBSurface(Uint32 flags12, int width, int height, int depth, Uint32 Rm
surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
}

SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);

SDL12_Surface *surface12 = Surface20to12(surface20);
if (!surface12) {
SDL20_FreeSurface(surface20);
Expand All @@ -2231,6 +2229,11 @@ SDL_CreateRGBSurface(Uint32 flags12, int width, int height, int depth, Uint32 Rm

SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);

if (flags12 & SDL12_SRCALPHA) {
surface12->flags |= SDL12_SRCALPHA;
SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
}

return surface12;
}

Expand All @@ -2249,8 +2252,6 @@ SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pit
surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
}

SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);

SDL12_Surface *surface12 = Surface20to12(surface20);
if (!surface12) {
SDL20_FreeSurface(surface20);
Expand Down Expand Up @@ -2865,15 +2866,114 @@ SDL_GetVideoSurface(void)
return VideoSurface12;
}

static int
SaveDestAlpha(SDL12_Surface *src12, SDL12_Surface *dst12, Uint8 **retval)
{
FIXME("This should only save the dst rect in use");

/* The 1.2 docs say this:
* RGBA->RGBA:
* SDL_SRCALPHA set:
* alpha-blend (using the source alpha channel) the RGB values;
* leave destination alpha untouched. [Note: is this correct?]
*
* In SDL2, we change the destination alpha. We have to save it off in this case, which sucks.
*/
Uint8 *dstalpha = NULL;
const SDL_bool save_dstalpha = ((src12->flags & SDL12_SRCALPHA) && dst12->format->Amask && ((src12->format->alpha != 255) || src12->format->Amask)) ? SDL_TRUE : SDL_FALSE;
if (save_dstalpha) {
const int w = dst12->w;
const int h = dst12->h;
dstalpha = (Uint8 *) SDL_malloc(w * h);
if (!dstalpha) {
*retval = NULL;
return SDL20_OutOfMemory();
}

Uint8 *dptr = dstalpha;
const Uint32 amask = dst12->format->Amask;
const Uint32 ashift = dst12->format->Ashift;
const Uint16 pitch = dst12->pitch;
if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
FIXME("this could be SIMD'd");
}
if (dst12->format->BytesPerPixel == 2) {
const Uint16 *sptr = (const Uint16 *) dst12->pixels;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
*(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
}
sptr = (Uint16 *) (((Uint8 *) sptr) + pitch);
}
} else if (dst12->format->BytesPerPixel == 4) {
const Uint32 *sptr = (const Uint32 *) dst12->pixels;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
*(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
}
sptr = (Uint32 *) (((Uint8 *) sptr) + pitch);
}
} else {
FIXME("Unhandled dest alpha");
}
}

*retval = dstalpha;
return 0;
}

static void
RestoreDestAlpha(SDL12_Surface *dst12, Uint8 *dstalpha)
{
if (dstalpha) {
const int w = dst12->w;
const int h = dst12->h;
const Uint8 *sptr = dstalpha;
const Uint32 amask = dst12->format->Amask;
const Uint32 ashift = dst12->format->Ashift;
const Uint16 pitch = dst12->pitch;
if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
FIXME("this could be SIMD'd");
}
if (dst12->format->BytesPerPixel == 2) {
Uint16 *dptr = (Uint16 *) dst12->pixels;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
dptr[x] = (Uint16) ((dptr[x] & ~amask) | ((((Uint16) *(sptr++)) << ashift) & amask));
}
dptr = (Uint16 *) (((Uint8 *) dptr) + pitch);
}
} else if (dst12->format->BytesPerPixel == 4) {
Uint32 *dptr = (Uint32 *) dst12->pixels;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
dptr[x] = (dptr[x] & ~amask) | ((((Uint32) *(sptr++)) << ashift) & amask);
}
dptr = (Uint32 *) (((Uint8 *) dptr) + pitch);
}
} else {
FIXME("Unhandled dest alpha");
}
SDL_free(dstalpha);
}
}

DECLSPEC int SDLCALL
SDL_UpperBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL12_Rect *dstrect12)
SDL_UpperBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
{
Uint8 *dstalpha;
if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
return -1;
}

SDL_Rect srcrect20, dstrect20;
const int retval = SDL20_UpperBlit(src->surface20,
const int retval = SDL20_UpperBlit(src12->surface20,
srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
dst->surface20,
dst12->surface20,
dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);

RestoreDestAlpha(dst12, dstalpha);

if (srcrect12) {
Rect20to12(&srcrect20, srcrect12);
}
Expand All @@ -2886,14 +2986,21 @@ SDL_UpperBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL
}

DECLSPEC int SDLCALL
SDL_LowerBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL12_Rect *dstrect12)
SDL_LowerBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
{
Uint8 *dstalpha;
if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
return -1;
}

SDL_Rect srcrect20, dstrect20;
const int retval = SDL20_LowerBlit(src->surface20,
const int retval = SDL20_LowerBlit(src12->surface20,
srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
dst->surface20,
dst12->surface20,
dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);

RestoreDestAlpha(dst12, dstalpha);

if (srcrect12) {
Rect20to12(&srcrect20, srcrect12);
}
Expand All @@ -2913,13 +3020,7 @@ SDL_SetAlpha(SDL12_Surface *surface12, Uint32 flags12, Uint8 value)
if (SDL20_GetSurfaceAlphaMod(surface12->surface20, &surface12->format->alpha) < 0) {
surface12->format->alpha = 255;
}

if (surface12->format->alpha != 255) {
surface12->flags |= SDL12_SRCALPHA;
} else {
surface12->flags &= ~SDL12_SRCALPHA;
}

FIXME("Should this set SDL12_SRCALPHA on the surface?");
return retval;
}

Expand Down Expand Up @@ -2957,6 +3058,11 @@ SDL_ConvertSurface(SDL12_Surface *src12, const SDL12_PixelFormat *format12, Uint
retval = Surface20to12(surface20);
if (!retval) {
SDL20_FreeSurface(surface20);
} else {
if (flags12 & SDL12_SRCALPHA) {
SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
retval->flags |= SDL12_SRCALPHA;
}
}
}
return retval;
Expand Down
1 change: 1 addition & 0 deletions src/SDL20_syms.h
Expand Up @@ -100,6 +100,7 @@ SDL20_SYM(void,FreeSurface,(SDL_Surface *a),(a),)
SDL20_SYM(int,SetSurfaceAlphaMod,(SDL_Surface *a, Uint8 b),(a,b),return)
SDL20_SYM(int,GetSurfaceAlphaMod,(SDL_Surface *a, Uint8 *b),(a,b),return)
SDL20_SYM(int,SetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode b),(a,b),return)
SDL20_SYM(int,GetSurfaceBlendMode,(SDL_Surface *a, SDL_BlendMode *b),(a,b),return)
SDL20_SYM(SDL_Surface*,LoadBMP_RW,(SDL_RWops *a, int b),(a,b),return)
SDL20_SYM(int,SaveBMP_RW,(SDL_Surface *a, SDL_RWops *b, int c),(a,b,c),return)
SDL20_SYM(int,SetPaletteColors,(SDL_Palette *a, const SDL_Color *b, int c, int d),(a,b,c,d),return)
Expand Down

0 comments on commit 7c1b74c

Please sign in to comment.