📄 sdl_rleaccel.c
字号:
if(!dest)
return -1;
df = dest->format;
if(surface->format->BitsPerPixel != 32)
return -1; /* only 32bpp source supported */
/* find out whether the destination is one we support,
and determine the max size of the encoded result */
masksum = df->Rmask | df->Gmask | df->Bmask;
switch(df->BytesPerPixel) {
case 2:
/* 16bpp: only support 565 and 555 formats */
switch(masksum) {
case 0xffff:
if(df->Gmask == 0x07e0
|| df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
copy_opaque = copy_opaque_16;
copy_transl = copy_transl_565;
} else
return -1;
break;
case 0x7fff:
if(df->Gmask == 0x03e0
|| df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
copy_opaque = copy_opaque_16;
copy_transl = copy_transl_555;
} else
return -1;
break;
default:
return -1;
}
max_opaque_run = 255; /* runs stored as bytes */
/* worst case is alternating opaque and translucent pixels,
with room for alignment padding between lines */
maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
break;
case 4:
if(masksum != 0x00ffffff)
return -1; /* requires unused high byte */
copy_opaque = copy_32;
copy_transl = copy_32;
max_opaque_run = 255; /* runs stored as short ints */
/* worst case is alternating opaque and translucent pixels */
maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
break;
default:
return -1; /* anything else unsupported right now */
}
maxsize += sizeof(RLEDestFormat);
rlebuf = (Uint8 *)malloc(maxsize);
if(!rlebuf) {
SDL_OutOfMemory();
return -1;
}
{
/* save the destination format so we can undo the encoding later */
RLEDestFormat *r = (RLEDestFormat *)rlebuf;
r->BytesPerPixel = df->BytesPerPixel;
r->Rloss = df->Rloss;
r->Gloss = df->Gloss;
r->Bloss = df->Bloss;
r->Rshift = df->Rshift;
r->Gshift = df->Gshift;
r->Bshift = df->Bshift;
r->Ashift = df->Ashift;
r->Rmask = df->Rmask;
r->Gmask = df->Gmask;
r->Bmask = df->Bmask;
r->Amask = df->Amask;
}
dst = rlebuf + sizeof(RLEDestFormat);
/* Do the actual encoding */
{
int x, y;
int h = surface->h, w = surface->w;
SDL_PixelFormat *sf = surface->format;
Uint32 *src = (Uint32 *)((Uint8 *)surface->pixels + surface->offset);
Uint8 *lastline = dst; /* end of last non-blank line */
/* opaque counts are 8 or 16 bits, depending on target depth */
#define ADD_OPAQUE_COUNTS(n, m) \
if(df->BytesPerPixel == 4) { \
((Uint16 *)dst)[0] = n; \
((Uint16 *)dst)[1] = m; \
dst += 4; \
} else { \
dst[0] = n; \
dst[1] = m; \
dst += 2; \
}
/* translucent counts are always 16 bit */
#define ADD_TRANSL_COUNTS(n, m) \
(((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
for(y = 0; y < h; y++) {
int runstart, skipstart;
int blankline = 0;
/* First encode all opaque pixels of a scan line */
x = 0;
do {
int run, skip, len;
skipstart = x;
while(x < w && !ISOPAQUE(src[x], sf))
x++;
runstart = x;
while(x < w && ISOPAQUE(src[x], sf))
x++;
skip = runstart - skipstart;
if(skip == w)
blankline = 1;
run = x - runstart;
while(skip > max_opaque_run) {
ADD_OPAQUE_COUNTS(max_opaque_run, 0);
skip -= max_opaque_run;
}
len = MIN(run, max_opaque_run);
ADD_OPAQUE_COUNTS(skip, len);
dst += copy_opaque(dst, src + runstart, len, sf, df);
runstart += len;
run -= len;
while(run) {
len = MIN(run, max_opaque_run);
ADD_OPAQUE_COUNTS(0, len);
dst += copy_opaque(dst, src + runstart, len, sf, df);
runstart += len;
run -= len;
}
} while(x < w);
/* Make sure the next output address is 32-bit aligned */
dst += (unsigned long)dst & 2;
/* Next, encode all translucent pixels of the same scan line */
x = 0;
do {
int run, skip, len;
skipstart = x;
while(x < w && !ISTRANSL(src[x], sf))
x++;
runstart = x;
while(x < w && ISTRANSL(src[x], sf))
x++;
skip = runstart - skipstart;
blankline &= (skip == w);
run = x - runstart;
while(skip > max_transl_run) {
ADD_TRANSL_COUNTS(max_transl_run, 0);
skip -= max_transl_run;
}
len = MIN(run, max_transl_run);
ADD_TRANSL_COUNTS(skip, len);
dst += copy_transl(dst, src + runstart, len, sf, df);
runstart += len;
run -= len;
while(run) {
len = MIN(run, max_transl_run);
ADD_TRANSL_COUNTS(0, len);
dst += copy_transl(dst, src + runstart, len, sf, df);
runstart += len;
run -= len;
}
if(!blankline)
lastline = dst;
} while(x < w);
src += surface->pitch >> 2;
}
dst = lastline; /* back up past trailing blank lines */
ADD_OPAQUE_COUNTS(0, 0);
}
#undef ADD_OPAQUE_COUNTS
#undef ADD_TRANSL_COUNTS
/* Now that we have it encoded, release the original pixels */
if((surface->flags & SDL_PREALLOC) != SDL_PREALLOC
&& (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
free( surface->pixels );
surface->pixels = NULL;
}
/* realloc the buffer to release unused memory */
{
Uint8 *p = realloc(rlebuf, dst - rlebuf);
if(!p)
p = rlebuf;
surface->map->sw_data->aux_data = p;
}
return 0;
}
static Uint32 getpix_8(Uint8 *srcbuf)
{
return *srcbuf;
}
static Uint32 getpix_16(Uint8 *srcbuf)
{
return *(Uint16 *)srcbuf;
}
static Uint32 getpix_24(Uint8 *srcbuf)
{
if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
else
return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
}
static Uint32 getpix_32(Uint8 *srcbuf)
{
return *(Uint32 *)srcbuf;
}
typedef Uint32 (*getpix_func)(Uint8 *);
static getpix_func getpixes[4] = {
getpix_8, getpix_16, getpix_24, getpix_32
};
static int RLEColorkeySurface(SDL_Surface *surface)
{
Uint8 *rlebuf, *dst;
int maxn;
int y;
Uint8 *srcbuf, *curbuf, *lastline;
int maxsize = 0;
int skip, run;
int bpp = surface->format->BytesPerPixel;
getpix_func getpix;
Uint32 ckey, rgbmask;
int w, h;
/* calculate the worst case size for the compressed surface */
switch(bpp) {
case 1:
/* worst case is alternating opaque and transparent pixels,
starting with an opaque pixel */
maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
break;
case 2:
case 3:
/* worst case is solid runs, at most 255 pixels wide */
maxsize = surface->h * (2 * (surface->w / 255 + 1)
+ surface->w * bpp) + 2;
break;
case 4:
/* worst case is solid runs, at most 65535 pixels wide */
maxsize = surface->h * (4 * (surface->w / 65535 + 1)
+ surface->w * 4) + 4;
break;
}
rlebuf = (Uint8 *)malloc(maxsize);
if ( rlebuf == NULL ) {
SDL_OutOfMemory();
return(-1);
}
/* Set up the conversion */
srcbuf = (Uint8 *)surface->pixels+surface->offset;
curbuf = srcbuf;
maxn = bpp == 4 ? 65535 : 255;
skip = run = 0;
dst = rlebuf;
rgbmask = ~surface->format->Amask;
ckey = surface->format->colorkey & rgbmask;
lastline = dst;
getpix = getpixes[bpp - 1];
w = surface->w;
h = surface->h;
#define ADD_COUNTS(n, m) \
if(bpp == 4) { \
((Uint16 *)dst)[0] = n; \
((Uint16 *)dst)[1] = m; \
dst += 4; \
} else { \
dst[0] = n; \
dst[1] = m; \
dst += 2; \
}
for(y = 0; y < h; y++) {
int x = 0;
int blankline = 0;
do {
int run, skip, len;
int runstart;
int skipstart = x;
/* find run of transparent, then opaque pixels */
while(x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
x++;
runstart = x;
while(x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
x++;
skip = runstart - skipstart;
if(skip == w)
blankline = 1;
run = x - runstart;
/* encode segment */
while(skip > maxn) {
ADD_COUNTS(maxn, 0);
skip -= maxn;
}
len = MIN(run, maxn);
ADD_COUNTS(skip, len);
memcpy(dst, srcbuf + runstart * bpp, len * bpp);
dst += len * bpp;
run -= len;
runstart += len;
while(run) {
len = MIN(run, maxn);
ADD_COUNTS(0, len);
memcpy(dst, srcbuf + runstart * bpp, len * bpp);
dst += len * bpp;
runstart += len;
run -= len;
}
if(!blankline)
lastline = dst;
} while(x < w);
srcbuf += surface->pitch;
}
dst = lastline; /* back up bast trailing blank lines */
ADD_COUNTS(0, 0);
#undef ADD_COUNTS
/* Now that we have it encoded, release the original pixels */
if((surface->flags & SDL_PREALLOC) != SDL_PREALLOC
&& (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
free( surface->pixels );
surface->pixels = NULL;
}
/* realloc the buffer to release unused memory */
{
/* If realloc returns NULL, the original block is left intact */
Uint8 *p = realloc(rlebuf, dst - rlebuf);
if(!p)
p = rlebuf;
surface->map->sw_data->aux_data = p;
}
return(0);
}
int SDL_RLESurface(SDL_Surface *surface)
{
int retcode;
/* Clear any previous RLE conversion */
if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
SDL_UnRLESurface(surface, 1);
}
/* We don't support RLE encoding of bitmaps */
if ( surface->format->BitsPerPixel < 8 ) {
return(-1);
}
/* Lock the surface if it's in hardware */
if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
if ( video->LockHWSurface(this, surface) < 0 ) {
return(-1);
}
}
/* Encode */
if((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
retcode = RLEColorkeySurface(surface);
} else {
if((surface->flags & SDL_SRCALPHA) == SDL_SRCALPHA
&& surface->format->Amask != 0)
retcode = RLEAlphaSurface(surface);
else
retcode = -1; /* no RLE for per-surface alpha sans ckey */
}
/* Unlock the surface if it's in hardware */
if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
video->UnlockHWSurface(this, surface);
}
if(retcode < 0)
return -1;
/* The surface is now accelerated */
surface->flags |= SDL_RLEACCEL;
return(0);
}
/*
* Un-RLE a surface with pixel alpha
* This may not give back exactly the image before RLE-encoding; all
* completely transparent pixels will be lost, and colour and alpha depth
* may have been reduced (when encoding for 16bpp targets).
*/
static void UnRLEAlpha(SDL_Surface *surface)
{
Uint8 *srcbuf;
Uint32 *dst;
SDL_PixelFormat *sf = surface->format;
RLEDestFormat *df = surface->map->sw_data->aux_data;
int (*uncopy_opaque)(Uint32 *, void *, int,
RLEDestFormat *, SDL_PixelFormat *);
int (*uncopy_transl)(Uint32 *, void *, int,
RLEDestFormat *, SDL_PixelFormat *);
int w = surface->w;
int bpp = df->BytesPerPixel;
if(bpp == 2) {
uncopy_opaque = uncopy_opaque_16;
uncopy_transl = uncopy_transl_16;
} else {
uncopy_opaque = uncopy_transl = uncopy_32;
}
surface->pixels = malloc(surface->h * surface->pitch);
/* fill background with transparent pixels */
memset(surface->pixels, 0, surface->h * surface->pitch);
dst = surface->pixels;
srcbuf = (Uint8 *)(df + 1);
for(;;) {
/* copy opaque pixels */
int ofs = 0;
do {
unsigned run;
if(bpp == 2) {
ofs += srcbuf[0];
run = srcbuf[1];
srcbuf += 2;
} else {
ofs += ((Uint16 *)srcbuf)[0];
run = ((Uint16 *)srcbuf)[1];
srcbuf += 4;
}
if(run) {
srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
ofs += run;
} else if(!ofs)
return;
} while(ofs < w);
/* skip padding if needed */
if(bpp == 2)
srcbuf += (unsigned long)srcbuf & 2;
/* copy translucent pixels */
ofs = 0;
do {
unsigned run;
ofs += ((Uint16 *)srcbuf)[0];
run = ((Uint16 *)srcbuf)[1];
srcbuf += 4;
if(run) {
srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
ofs += run;
}
} while(ofs < w);
dst += surface->pitch >> 2;
}
}
void SDL_UnRLESurface(SDL_Surface *surface, int recode)
{
if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
surface->flags &= ~SDL_RLEACCEL;
if(recode && (surface->flags & SDL_PREALLOC) != SDL_PREALLOC
&& (surface->flags & SDL_HWSURFACE) != SDL_HWSURFACE) {
if((surface->flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
SDL_Rect full;
unsigned alpha_flag;
/* re-create the original surface */
surface->pixels = malloc(surface->h * surface->pitch);
/* fill it with the background colour */
SDL_FillRect(surface, NULL, surface->format->colorkey);
/* now render the encoded surface */
full.x = full.y = 0;
full.w = surface->w;
full.h = surface->h;
alpha_flag = surface->flags & SDL_SRCALPHA;
surface->flags &= ~SDL_SRCALPHA; /* opaque blit */
SDL_RLEBlit(surface, &full, surface, &full);
surface->flags |= alpha_flag;
} else
UnRLEAlpha(surface);
}
if ( surface->map && surface->map->sw_data->aux_data ) {
free(surface->map->sw_data->aux_data);
surface->map->sw_data->aux_data = NULL;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -