Skip to content

Commit

Permalink
A bunch of work on getting 2D surfaces more correct (palettes, alpha,…
Browse files Browse the repository at this point in the history
… etc).
  • Loading branch information
icculus committed Mar 3, 2019
1 parent aba9a59 commit 3af751b
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 18 deletions.
198 changes: 180 additions & 18 deletions src/SDL12_compat.c
Expand Up @@ -141,6 +141,9 @@
#define SDL12_INIT_EVENTTHREAD 0x01000000
#define SDL12_INIT_EVERYTHING 0x0000FFFF

#define SDL12_LOGPAL 1
#define SDL12_PHYSPAL 2

typedef struct SDL12_Rect
{
Sint16 x;
Expand Down Expand Up @@ -2082,8 +2085,23 @@ Surface20to12(SDL_Surface *surface20)
format12->Gmask = surface20->format->Gmask;
format12->Bmask = surface20->format->Bmask;
format12->Amask = surface20->format->Amask;
FIXME("format12->colorkey");
FIXME("format12->alpha");

if (SDL20_HasColorKey(surface20)) {
if (SDL20_GetColorKey(surface20, &format12->colorkey) == -1) {
format12->colorkey = 0;
} else {
surface12->flags |= SDL12_SRCCOLORKEY;
}
}

if (SDL20_GetSurfaceAlphaMod(surface20, &format12->alpha) == -1) {
format12->alpha = 255;
}

if (format12->alpha != 255) {
surface12->flags |= SDL12_SRCALPHA;
}


SDL20_zerop(surface12);
flags = surface20->flags;
Expand Down Expand Up @@ -2116,37 +2134,132 @@ Surface20to12(SDL_Surface *surface20)
return NULL;
}

static void
SetPalette12ForMasks(SDL12_Surface *surface12, const Uint32 Rmask, const Uint32 Gmask, const Uint32 Bmask)
{
SDL12_PixelFormat *format12 = surface12->format;
if (format12->palette && (Rmask || Bmask || Gmask)) {
#define LOSSMASKSHIFTSETUP(t) { \
format12->t##shift = 0; \
format12->t##loss = 8; \
if (t##mask) { \
Uint32 mask; \
for (mask = t##mask; !(mask & 1); mask >>= 1) { \
format12->t##shift++; \
} \
while (mask & 1) { \
format12->t##loss--; \
mask >>= 1; \
} \
} \
format12->t##mask = t##mask; \
}
LOSSMASKSHIFTSETUP(R);
LOSSMASKSHIFTSETUP(G);
LOSSMASKSHIFTSETUP(B);
#undef LOSSMASSSHIFTSETUP
format12->Amask = 0;
format12->Ashift = 0;
format12->Aloss = 8;

#define MASKSETUP(t) \
int t##w = 0, t##m = 0; \
if (t##mask) { \
t##w = 8 - format12->t##loss; \
for (int i = format12->t##loss; i > 0; i -= t##w) { \
t##m |= 1 << i; \
} \
}
MASKSETUP(R);
MASKSETUP(G);
MASKSETUP(B);
#undef MASKSETUP

const int ncolors = format12->palette->ncolors;
SDL_Color *color = format12->palette->colors;
for (int i = 0; i < ncolors; i++, color++) {
#define SETCOLOR(T, t) { \
const int x = (i & T##mask) >> format12->T##shift; \
color->t = (x << format12->T##loss) | ((x * T##m) >> T##w); \
}
SETCOLOR(R, r);
SETCOLOR(G, g);
SETCOLOR(B, b);
#undef SETCOLOR
color->a = 255;
}

SDL_PixelFormat *format20 = surface12->surface20->format;
#define UPDATEFMT20(t) \
format20->t##mask = format12->t##mask; \
format20->t##loss = format12->t##loss; \
format20->t##shift = format12->t##shift;
UPDATEFMT20(R);
UPDATEFMT20(G);
UPDATEFMT20(B);
UPDATEFMT20(A);
#undef UPDATEFMT20
}
}

DECLSPEC SDL12_Surface * SDLCALL
SDL_CreateRGBSurface(Uint32 sdl12flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
SDL_CreateRGBSurface(Uint32 flags12, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
if (depth == 8) {
Rmask = Gmask = Bmask = Amask = 0; // force a paletted surface.
// SDL 1.2 checks this.
if ((width >= 16384) || (height >= 65536)) {
SDL20_SetError("Width or height is too large");
return NULL;
}
SDL_Surface *surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);

SDL_Surface *surface20;
if (depth == 8) { // don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems.
surface20 = SDL20_CreateRGBSurface(0, width, height, depth, 0, 0, 0, 0);
} else {
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);
return NULL;
}

SDL_assert(surface12->flags == 0); // shouldn't have prealloc, rleaccel, or dontfree.
SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == 0); // shouldn't have prealloc, rleaccel, or dontfree.

SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);

return surface12;
}

DECLSPEC SDL12_Surface * SDLCALL
SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
if (depth == 8) {
Rmask = Gmask = Bmask = Amask = 0; // force a paletted surface.
if ((width >= 16384) || (height >= 65536)) {
SDL20_SetError("Width or height is too large");
return NULL;
}

SDL_Surface *surface20;
if (depth == 8) { // don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems.
surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, 0, 0, 0, 0);
} else {
surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
}
SDL_Surface *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);
return NULL;
}

SDL_assert(surface12->flags == SDL12_PREALLOC); // should _only_ have prealloc.
SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == SDL12_PREALLOC); // should _only_ have prealloc.

SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);

return surface12;
}

Expand Down Expand Up @@ -2792,10 +2905,21 @@ SDL_LowerBlit(SDL12_Surface *src, SDL12_Rect *srcrect12, SDL12_Surface *dst, SDL
}

DECLSPEC int SDLCALL
SDL_SetAlpha(SDL12_Surface * surface, Uint32 flag, Uint8 value)
SDL_SetAlpha(SDL12_Surface *surface12, Uint32 flags12, Uint8 value)
{
FIXME("write me");
return SDL20_Unsupported();
const SDL_bool addkey = (flags12 & SDL12_SRCALPHA) ? SDL_TRUE : SDL_FALSE;
const int retval = SDL20_SetSurfaceAlphaMod(surface12->surface20, addkey ? value : 255);
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;
}

return retval;
}

DECLSPEC int SDLCALL
Expand Down Expand Up @@ -3102,23 +3226,61 @@ SDL_SetColorKey(SDL12_Surface *surface12, Uint32 flag12, Uint32 key)
if (SDL20_GetColorKey(surface12->surface20, &surface12->format->colorkey) < 0) {
surface12->format->colorkey = 0;
}

if (addkey) {
surface12->flags |= SDL12_SRCCOLORKEY;
} else {
surface12->flags &= ~SDL12_SRCCOLORKEY;
}

return retval;
}

DECLSPEC int SDLCALL
SDL_SetPalette(SDL12_Surface *surface12, int flags, const SDL_Color *colors,
int firstcolor, int ncolors)
{
FIXME("write me");
return SDL20_Unsupported();
if (!surface12) {
return 0; // not an error, a no-op.
}

SDL12_Palette *palette12 = surface12->format->palette;
if (!palette12) {
return 0; // not an error, a no-op.
}

SDL_Palette *palette20 = surface12->surface20->format->palette;
SDL_assert(palette20 != NULL);

// we need to force the "unused" field to 255, since it's "alpha" in SDL2.
SDL_Color *opaquecolors = (SDL_Color *) SDL20_malloc(sizeof (SDL_Color) * ncolors);
if (!opaquecolors) {
return SDL20_OutOfMemory();
}

// don't SDL_memcpy in case the 'a' field is uninitialized and upsets
// memory tools like Valgrind.
for (int i = 0; i < ncolors; i++) {
opaquecolors[i].r = colors[i].r;
opaquecolors[i].g = colors[i].g;
opaquecolors[i].b = colors[i].b;
opaquecolors[i].a = 255;
}

const int retval = SDL20_SetPaletteColors(palette20, opaquecolors, firstcolor, ncolors);
SDL20_free(opaquecolors);

// in case this pointer changed...
palette12->colors = palette20->colors;

return retval;
}

DECLSPEC int SDLCALL
SDL_SetColors(SDL12_Surface *surface12, const SDL_Color * colors, int firstcolor,
int ncolors)
{
FIXME("write me");
return SDL20_Unsupported();
return SDL_SetPalette(surface12, SDL12_LOGPAL | SDL12_PHYSPAL, colors, firstcolor, ncolors);
}

DECLSPEC int SDLCALL
Expand Down
5 changes: 5 additions & 0 deletions src/SDL20_syms.h
Expand Up @@ -93,11 +93,16 @@ SDL20_SYM(int,LockSurface,(SDL_Surface *a),(a),return)
SDL20_SYM(void,UnlockSurface,(SDL_Surface *a),(a),)
SDL20_SYM(int,UpperBlit,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL20_SYM(int,LowerBlit,(SDL_Surface *a,const SDL_Rect *b,SDL_Surface *c, SDL_Rect *d),(a,b,c,d),return)
SDL20_SYM(SDL_bool,HasColorKey,(SDL_Surface *a),(a),return)
SDL20_SYM(int,SetColorKey,(SDL_Surface *a, int b, Uint32 c),(a,b,c),return)
SDL20_SYM(int,GetColorKey,(SDL_Surface *a, Uint32 *b),(a,b),return)
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(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)
SDL20_SYM(int,GL_LoadLibrary,(const char *a),(a),return)
SDL20_SYM_PASSTHROUGH(void *,GL_GetProcAddress,(const char *a),(a),return)
SDL20_SYM(int,GL_SetAttribute,(SDL_GLattr a, int b),(a,b),return)
Expand Down

0 comments on commit 3af751b

Please sign in to comment.