📄 rleaccel.c
字号:
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) { GAL_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; GAL_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 & GAL_PREALLOC) != GAL_PREALLOC && (surface->flags & GAL_HWSURFACE) != GAL_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(GAL_BYTEORDER == GAL_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(GAL_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 ) { GAL_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 & GAL_PREALLOC) != GAL_PREALLOC && (surface->flags & GAL_HWSURFACE) != GAL_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 GAL_RLESurface(GAL_Surface *surface){ int retcode; /* Clear any previous RLE conversion */ if ( (surface->flags & GAL_RLEACCEL) == GAL_RLEACCEL ) { GAL_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 & (GAL_HWSURFACE|GAL_ASYNCBLIT) ) { GAL_VideoDevice *video = current_video; GAL_VideoDevice *this = current_video;#if 0 if ( video->LockHWSurface(this, surface) < 0 ) { return(-1); }#endif } /* Encode */ if((surface->flags & GAL_SRCCOLORKEY) == GAL_SRCCOLORKEY) { retcode = RLEColorkeySurface(surface); } else { if((surface->flags & GAL_SRCALPHA) == GAL_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 & (GAL_HWSURFACE|GAL_ASYNCBLIT) ) { GAL_VideoDevice *video = current_video; GAL_VideoDevice *this = current_video;#if 0 video->UnlockHWSurface(this, surface);#endif } if(retcode < 0) return -1; /* The surface is now accelerated */ surface->flags |= GAL_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(GAL_Surface *surface){ Uint8 *srcbuf; Uint32 *dst; GAL_PixelFormat *sf = surface->format; RLEDestFormat *df = surface->map->sw_data->aux_data; int (*uncopy_opaque)(Uint32 *, void *, int, RLEDestFormat *, GAL_PixelFormat *); int (*uncopy_transl)(Uint32 *, void *, int, RLEDestFormat *, GAL_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 GAL_UnRLESurface(GAL_Surface *surface, int recode){ if ( (surface->flags & GAL_RLEACCEL) == GAL_RLEACCEL ) { surface->flags &= ~GAL_RLEACCEL; if(recode && (surface->flags & GAL_PREALLOC) != GAL_PREALLOC && (surface->flags & GAL_HWSURFACE) != GAL_HWSURFACE) { if((surface->flags & GAL_SRCCOLORKEY) == GAL_SRCCOLORKEY) { GAL_Rect full; unsigned alpha_flag; /* re-create the original surface */ surface->pixels = malloc(surface->h * surface->pitch); /* fill it with the background colour */ GAL_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 & GAL_SRCALPHA; surface->flags &= ~GAL_SRCALPHA; /* opaque blit */ GAL_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 + -