From 9b7f3c46c7af577336bb512424c1270631de071d Mon Sep 17 00:00:00 2001 From: avolkov Date: Thu, 10 Nov 2005 00:33:29 +0000 Subject: [PATCH] supporting StampFill for 32bpp images; optional support for alpha fonts (via 32bpp) git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1977 8092fc87-c524-0410-9efc-e669fe64eaf9 --- .../sc2code/libs/graphics/sdl/3do_getbody.c | 89 +++++++---- sc2/src/sc2code/libs/graphics/sdl/canvas.c | 139 ++++++++++++++++-- sc2/src/sc2code/libs/graphics/sdl/scalemmx.h | 3 + sc2/src/sc2code/libs/graphics/tfb_draw.c | 2 + sc2/src/sc2code/libs/graphics/tfb_draw.h | 2 + 5 files changed, 201 insertions(+), 34 deletions(-) diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c index 4290c45dd..82e10caa8 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c @@ -113,6 +113,8 @@ processFontChar (FRAMEPTR FramePtr, SDL_Surface *surf, int charInd) Uint32 p; SDL_Color colors[256]; SDL_Surface *new_surf; + SDL_PixelFormat* srcfmt = surf->format; + SDL_PixelFormat* dstfmt; GetPixelFn getpix; PutPixelFn putpix; @@ -120,13 +122,21 @@ processFontChar (FRAMEPTR FramePtr, SDL_Surface *surf, int charInd) INDEX_SET (FramePtr->TypeIndexAndFlags, charInd); // XXX: Is this still relevant? +//#define ALPHA_FONTS + SDL_LockSurface (surf); - // convert 32-bit png font to indexed +#if defined(ALPHA_FONTS) + // convert png font to truecolor + alpha + new_surf = TFB_DrawCanvas_New_TrueColor (surf->w, surf->h, TRUE); +#else // indexed fonts + // convert 32-bit png font to indexed new_surf = SDL_CreateRGBSurface (SDL_SWSURFACE, surf->w, surf->h, 8, 0, 0, 0, 0); +#endif + dstfmt = new_surf->format; getpix = getpixel_for (surf); putpix = putpixel_for (new_surf); @@ -135,15 +145,29 @@ processFontChar (FRAMEPTR FramePtr, SDL_Surface *surf, int charInd) for (x = 0; x < surf->w; ++x) { p = getpix (surf, x, y); - SDL_GetRGBA (p, surf->format, &r, &g, &b, &a); + SDL_GetRGBA (p, srcfmt, &r, &g, &b, &a); +#if defined(ALPHA_FONTS) + if (!srcfmt->Amask) + { // produce alpha from intensity (Y component) + // using a fast approximation + // contributions to Y are: R=2, G=4, B=1 + a = (((int)r << 1) + ((int)g << 2) + b) / 7; + } + // normalize font pixel + putpix (new_surf, x, y, SDL_MapRGBA (dstfmt, + 255, 255, 255, a)); + +#else // indexed fonts if (r == 0 && g == 0 && b == 0) putpix (new_surf, x, y, 0); else putpix (new_surf, x, y, 1); +#endif } } +#if !defined(ALPHA_FONTS) colors[0].r = 0; colors[0].g = 0; colors[0].b = 0; @@ -156,6 +180,7 @@ processFontChar (FRAMEPTR FramePtr, SDL_Surface *surf, int charInd) SDL_SetColors (new_surf, colors, 0, 256); SDL_SetColorKey (new_surf, SDL_SRCCOLORKEY, 0); +#endif SDL_UnlockSurface (surf); SDL_FreeSurface (surf); @@ -355,6 +380,7 @@ FRAMEPTR Build_Font_Effect (FRAMEPTR FramePtr, Uint32 from, Uint32 to, BYTE type int x, y; int width, height; Uint32 color, clear; + Uint32 srcmask, threshold; BYTE from_r, from_g, from_b, from_a; BYTE to_r, to_g, to_b, to_a; TFB_Image *tfbImg, *tfbOrigImg; @@ -362,14 +388,17 @@ FRAMEPTR Build_Font_Effect (FRAMEPTR FramePtr, Uint32 from, Uint32 to, BYTE type PutPixelFn putpix; GetPixelFn getpix; - width = GetFrameWidth (FramePtr); - height = GetFrameHeight (FramePtr); - NewFrame = CaptureDrawable (CreateDrawable ((CREATE_FLAGS)RAM_DRAWABLE, - (SIZE)width, (SIZE)height, 1)); tfbOrigImg = FramePtr->image; OrigImg = (SDL_Surface *)tfbOrigImg->NormalImg; SDL_LockSurface (OrigImg); + width = OrigImg->w; + height = OrigImg->h; + NewFrame = CaptureDrawable (CreateDrawable ((CREATE_FLAGS)RAM_DRAWABLE, + (SIZE)width, (SIZE)height, 1)); + NewFrame->Bounds = FramePtr->Bounds; + NewFrame->HotSpot = FramePtr->HotSpot; + tfbImg = NewFrame->image; img = (SDL_Surface *)tfbImg->NormalImg; SDL_LockSurface (img); @@ -389,19 +418,24 @@ FRAMEPTR Build_Font_Effect (FRAMEPTR FramePtr, Uint32 from, Uint32 to, BYTE type clear = SDL_MapRGBA (img->format, 0, 0, 0, 0); TFB_DrawCanvas_SetTransparentColor (img, 0, 0, 0, FALSE); - for (y = 0; y < 2; y++) - for (x = 0; x < width; x++) - putpix (img, x, y, clear); +#if defined(ALPHA_FONTS) + srcmask = OrigImg->format->Amask; + threshold = (srcmask >> 1) & srcmask; +#else // indexed fonts + srcmask = 255; + threshold = 0; // any index != 0 +#endif - width--; if (type == GRADIENT_EFFECT) { int clrstep_r, clrstep_g, clrstep_b, clrstep_a; - clrstep_r = (to_r - from_r) / (height - 5); - clrstep_g = (to_g - from_g) / (height - 5); - clrstep_b = (to_b - from_b) / (height - 5); - clrstep_a = (to_a - from_a) / (height - 5); - for (; y < height - 1; y++) + + clrstep_r = (to_r - from_r) / (height - 1); + clrstep_g = (to_g - from_g) / (height - 1); + clrstep_b = (to_b - from_b) / (height - 1); + clrstep_a = (to_a - from_a) / (height - 1); + + for (y = 0; y < height; y++) { color = SDL_MapRGBA (img->format, from_r, from_g, from_b, from_a); from_r += clrstep_r; @@ -409,41 +443,46 @@ FRAMEPTR Build_Font_Effect (FRAMEPTR FramePtr, Uint32 from, Uint32 to, BYTE type from_b += clrstep_b; from_a += clrstep_a; for (x = 0; x < width; x++) - if (getpix (OrigImg, x, y) == 1) + { + Uint32 p = getpix (OrigImg, x, y); + + if ((p & srcmask) > threshold) putpix (img, x, y, color); else putpix (img, x, y, clear); - putpix (img, x, y, clear); + } } } else if (type == ALTERNATE_EFFECT) { Uint32 color1, color2; + color1 = SDL_MapRGBA (img->format, from_r, from_g, from_b, from_a); color2 = SDL_MapRGBA (img->format, to_r, to_g, to_b, to_a); - for (; y < height - 1; y++) + + for (y = 0; y < height; y++) { for (x = 0; x < width; x++) - if (getpix (OrigImg, x, y) == 1) + { + Uint32 p = getpix (OrigImg, x, y); + + if ((p & srcmask) > threshold) { color = ((y & 0x01) ^ (x & 0x01)) ? color2 : color1; putpix (img, x, y, color); } else putpix (img, x, y, clear); - putpix (img, x, y, clear); + } } } - width++; - for (x = 0; x < width; x++) - putpix (img, x, y, clear); SDL_UnlockSurface (img); SDL_UnlockSurface (OrigImg); - NewFrame->HotSpot = FramePtr->HotSpot; - return (NewFrame); + return (NewFrame); } + // Generate a pixel (in the correct format to be applied to FramePtr) from the // r,g,b,a values supplied Uint32 frame_mapRGBA (FRAMEPTR FramePtr,Uint8 r, Uint8 g, Uint8 b, Uint8 a) diff --git a/sc2/src/sc2code/libs/graphics/sdl/canvas.c b/sc2/src/sc2code/libs/graphics/sdl/canvas.c index 09a596590..371fe9ed6 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/canvas.c +++ b/sc2/src/sc2code/libs/graphics/sdl/canvas.c @@ -103,6 +103,83 @@ TFB_DrawCanvas_Image (TFB_Image *img, int x, int y, int scale, TFB_Palette *pale UnlockMutex (img->mutex); } +void +TFB_DrawCanvas_Fill (TFB_Canvas source, int width, int height, + Uint32 fillcolor, TFB_Canvas target) +{ + SDL_Surface *src = (SDL_Surface *)source; + SDL_Surface *dst = (SDL_Surface *)target; + const SDL_PixelFormat *srcfmt = src->format; + SDL_PixelFormat *dstfmt = dst->format; + const int bpp = dstfmt->BytesPerPixel; + const int sp = src->pitch, dp = dst->pitch; + const int slen = sp / bpp, dlen = dp / bpp; + const int dsrc = slen - width, ddst = dlen - width; + + Uint32 *src_p = (Uint32 *)src->pixels; + Uint32 *dst_p = (Uint32 *)dst->pixels; + int x, y; + + if (srcfmt->BytesPerPixel != 4 || dstfmt->BytesPerPixel != 4) + { + fprintf (stderr, "TFB_DrawCanvas_Fill: Unsupported surface formats: " + "%d bytes/pixel source, %d bytes/pixel destination\n", + (int)srcfmt->BytesPerPixel, (int)dstfmt->BytesPerPixel); + return; + } + + if ((src->flags & SDL_SRCALPHA) && srcfmt->Amask) + { // alpha-based fill + Uint32 amask = srcfmt->Amask; + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x, ++src_p, ++dst_p) + { + *dst_p = (*src_p & amask) | fillcolor; + } + dst_p += ddst; + src_p += dsrc; + } + } + else if (src->flags & SDL_SRCCOLORKEY) + { // colorkey-based fill + Uint32 srckey = srcfmt->colorkey; + Uint32 dstkey = srckey; + Uint32 notmask = ~srcfmt->Amask; + + if (src->flags & SDL_RLEACCEL) + { + fprintf (stderr, "TFB_DrawCanvas_Fill: Unsupported source " + "surface format: SDL_RLEACCEL\n"); + return; + } + + if (dstkey == fillcolor) + { // color collision, must switch colorkey + if (dstkey != 0) + // new colorkey is black (0,0,0) + dstkey = 0; + else + // new colorkey is grey (1/2,1/2,1/2) + dstkey = SDL_MapRGB (dstfmt, 127, 127, 127); + } + SDL_SetColorKey (dst, SDL_SRCCOLORKEY, dstkey); + + for (y = 0; y < height; ++y) + { + for (x = 0; x < width; ++x, ++src_p, ++dst_p) + { + Uint32 p = *src_p & notmask; + + *dst_p = (p == srckey) ? dstkey : p; + } + dst_p += ddst; + src_p += dsrc; + } + } +} + void TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int g, int b, TFB_Canvas target) { @@ -110,6 +187,7 @@ TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int SDL_Surface *surf; int i; SDL_Color pal[256]; + EXTENT prevextent = img->extent; if (img == 0) { @@ -137,16 +215,59 @@ TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int r, int surf = img->NormalImg; pSrcRect = NULL; } - - for (i = 0; i < 256; i++) - { - pal[i].r = r; - pal[i].g = g; - pal[i].b = b; - } - SDL_SetColors (surf, pal, 0, 256); - SDL_BlitSurface(surf, pSrcRect, (NativeCanvas) target, &targetRect); + if (surf->format->palette) + { // set palette for fill-stamp + for (i = 0; i < 256; i++) + { + pal[i].r = r; + pal[i].g = g; + pal[i].b = b; + } + SDL_SetColors (surf, pal, 0, 256); + } + else + { // fill the non-transparent parts of the image with fillcolor + SDL_Surface *src = img->NormalImg; + SDL_Surface *newfill = img->FilledImg; + BOOLEAN force = FALSE; + + // prepare the filled image + if (!newfill) + { + newfill = SDL_CreateRGBSurface (SDL_SWSURFACE, + src->w, src->h, + surf->format->BitsPerPixel, + surf->format->Rmask, + surf->format->Gmask, + surf->format->Bmask, + surf->format->Amask); + force = TRUE; + } + + if (force || + prevextent.height != img->extent.height || + prevextent.width != img->extent.width || + img->last_fill.r != r || + img->last_fill.g != g || + img->last_fill.b != b) + { // image or fillcolor changed - regenerate + TFB_DrawCanvas_Fill (surf, img->extent.width, img->extent.height, + SDL_MapRGBA (newfill->format, r, g, b, 0), newfill); + // important to keep alpha=0 in fillcolor + // -- we process alpha ourselves + } + + // cache filled image if possible + img->last_fill.r = r; + img->last_fill.g = g; + img->last_fill.b = b; + img->FilledImg = newfill; + + surf = newfill; + } + + SDL_BlitSurface (surf, pSrcRect, (NativeCanvas) target, &targetRect); UnlockMutex (img->mutex); } diff --git a/sc2/src/sc2code/libs/graphics/sdl/scalemmx.h b/sc2/src/sc2code/libs/graphics/sdl/scalemmx.h index 099e298a9..99d25aded 100755 --- a/sc2/src/sc2code/libs/graphics/sdl/scalemmx.h +++ b/sc2/src/sc2code/libs/graphics/sdl/scalemmx.h @@ -76,6 +76,9 @@ extern Uint64 mmx_YUV_threshold; # undef HAVE_PREFETCH #endif +#if defined(_MSC_VER) && (_MSC_VER >= 1300) +# pragma warning( disable : 4799 ) +#endif static inline void SCALE_(PlatInit) (void) diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.c b/sc2/src/sc2code/libs/graphics/tfb_draw.c index ca26bdb9f..07017ebff 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.c +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.c @@ -289,6 +289,7 @@ TFB_DrawImage_New (TFB_Canvas canvas) img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO); img->ScaledImg = NULL; img->MipmapImg = NULL; + img->FilledImg = NULL; img->colormap_index = -1; img->last_scale_type = -1; TFB_DrawCanvas_GetExtent (canvas, &img->extent); @@ -314,6 +315,7 @@ TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha) img->mutex = CreateMutex ("image lock", SYNC_CLASS_VIDEO); img->ScaledImg = NULL; img->MipmapImg = NULL; + img->FilledImg = NULL; img->colormap_index = -1; img->last_scale_type = -1; img->Palette = NULL; diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.h b/sc2/src/sc2code/libs/graphics/tfb_draw.h index 1d68f2792..2d82bdcc0 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.h +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.h @@ -53,9 +53,11 @@ typedef struct tfb_image TFB_Canvas NormalImg; TFB_Canvas ScaledImg; TFB_Canvas MipmapImg; + TFB_Canvas FilledImg; TFB_Palette *Palette; int colormap_index; int last_scale_type; + TFB_Palette last_fill; EXTENT extent; Mutex mutex; BOOLEAN dirty;