From 5331f3cd3decd868129f930398dfadd485d92d79 Mon Sep 17 00:00:00 2001 From: avolkov Date: Wed, 26 Jan 2005 23:55:49 +0000 Subject: [PATCH] New image rotation code git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1488 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/src/sc2code/libs/gfxlib.h | 1 + sc2/src/sc2code/libs/graphics/drawable.c | 44 + .../sc2code/libs/graphics/sdl/3do_getbody.c | 2 +- sc2/src/sc2code/libs/graphics/sdl/canvas.c | 99 ++ sc2/src/sc2code/libs/graphics/sdl/rotozoom.c | 1000 +++++++++++++++++ sc2/src/sc2code/libs/graphics/sdl/rotozoom.h | 95 ++ sc2/src/sc2code/libs/graphics/tfb_draw.c | 30 +- sc2/src/sc2code/libs/graphics/tfb_draw.h | 6 + 8 files changed, 1275 insertions(+), 2 deletions(-) create mode 100644 sc2/src/sc2code/libs/graphics/sdl/rotozoom.c create mode 100644 sc2/src/sc2code/libs/graphics/sdl/rotozoom.h diff --git a/sc2/src/sc2code/libs/gfxlib.h b/sc2/src/sc2code/libs/gfxlib.h index 060d1c185..5fa4305ba 100644 --- a/sc2/src/sc2code/libs/gfxlib.h +++ b/sc2/src/sc2code/libs/gfxlib.h @@ -245,6 +245,7 @@ extern FRAME SetRelFrameIndex (FRAME Frame, SIZE FrameOffs); extern FRAME SetEquFrameIndex (FRAME DstFrame, FRAME SrcFrame); extern FRAME IncFrameIndex (FRAME Frame); extern FRAME DecFrameIndex (FRAME Frame); +extern DRAWABLE RotateFrame (FRAME Frame, COUNT angle); extern FRAME CaptureDrawable (DRAWABLE Drawable); extern DRAWABLE ReleaseDrawable (FRAME Frame); diff --git a/sc2/src/sc2code/libs/graphics/drawable.c b/sc2/src/sc2code/libs/graphics/drawable.c index 91cef0748..c3dada8be 100644 --- a/sc2/src/sc2code/libs/graphics/drawable.c +++ b/sc2/src/sc2code/libs/graphics/drawable.c @@ -18,6 +18,9 @@ #include "gfxintrn.h" #include "misc.h" +#include "tfb_draw.h" +#include "units.h" +#include "libs/mathlib.h" FRAMEPTR _CurFramePtr; @@ -201,3 +204,44 @@ GetFrameHot (FRAMEPTR FramePtr) return (MAKE_HOT_SPOT (0, 0)); } +DRAWABLE +RotateFrame (FRAMEPTR Frame, COUNT angle) +{ + DRAWABLE Drawable; + FRAMEPTR RotFramePtr; + SIZE dx, dy; + SIZE d; + COUNT organg; + + Drawable = _request_drawable (1, RAM_DRAWABLE, WANT_PIXMAP, 0, 0); + if (!Drawable) + return 0; + RotFramePtr = CaptureDrawable (Drawable); + if (!RotFramePtr) + { + FreeDrawable (Drawable); + return 0; + } + + RotFramePtr->image = TFB_DrawImage_New_Rotated ( + Frame->image, -ANGLE_TO_DEGREES (angle)); + SetFrameBounds (RotFramePtr, RotFramePtr->image->extent.width, + RotFramePtr->image->extent.height); + + /* now we need to rotate the hot-spot, eww */ + dx = Frame->HotSpot.x - (GetFrameWidth (Frame) / 2); + dy = Frame->HotSpot.y - (GetFrameHeight (Frame) / 2); + d = square_root ((long)dx*dx + (long)dy*dy); + if (d != 0) + { + organg = ARCTAN (dx, dy); + dx = COSINE (organg + angle, d); + dy = SINE (organg + angle, d); + } + RotFramePtr->HotSpot.x = (GetFrameWidth (RotFramePtr) / 2) + dx; + RotFramePtr->HotSpot.y = (GetFrameHeight (RotFramePtr) / 2) + dy; + + ReleaseDrawable (RotFramePtr); + + return Drawable; +} diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c index 9a8253bbe..ba0d5ff74 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_getbody.c @@ -732,7 +732,7 @@ _request_drawable (COUNT NumFrames, DRAWABLE_TYPE DrawableType, { TFB_Image *Image; - if (DrawableType == RAM_DRAWABLE + if (DrawableType == RAM_DRAWABLE && imgw > 0 && imgh > 0 && (Image = TFB_DrawImage_New (TFB_DrawCanvas_New_TrueColor (imgw, imgh, FALSE)))) { FramePtr->image = Image; diff --git a/sc2/src/sc2code/libs/graphics/sdl/canvas.c b/sc2/src/sc2code/libs/graphics/sdl/canvas.c index 353fe38e8..adf3b1ec1 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/canvas.c +++ b/sc2/src/sc2code/libs/graphics/sdl/canvas.c @@ -3,6 +3,7 @@ #include "libs/graphics/gfx_common.h" #include "libs/graphics/sdl/primitives.h" #include "libs/graphics/tfb_draw.h" +#include "rotozoom.h" #include "options.h" #include "types.h" @@ -240,6 +241,12 @@ TFB_DrawCanvas_New_ScaleTarget (TFB_Canvas canvas, TFB_Canvas oldcanvas, int typ src->format->Amask); if (src->format->palette) TFB_DrawCanvas_SetTransparentIndex (newsurf, TFB_DrawCanvas_GetTransparentIndex (src), FALSE); + else + { + int r, g, b; + if (TFB_DrawCanvas_GetTransparentColor (src, &r, &g, &b)) + TFB_DrawCanvas_SetTransparentColor (newsurf, r, g, b, FALSE); + } } } else @@ -259,6 +266,40 @@ TFB_DrawCanvas_New_ScaleTarget (TFB_Canvas canvas, TFB_Canvas oldcanvas, int typ return newsurf; } +TFB_Canvas +TFB_DrawCanvas_New_RotationTarget (TFB_Canvas src_canvas, int angle) +{ + SDL_Surface *src = (SDL_Surface *)src_canvas; + SDL_Surface *newsurf; + EXTENT size; + + TFB_DrawCanvas_GetRotatedExtent (src_canvas, angle, &size); + + newsurf = SDL_CreateRGBSurface (SDL_SWSURFACE, + size.width, size.height, + src->format->BitsPerPixel, + src->format->Rmask, + src->format->Gmask, + src->format->Bmask, + src->format->Amask); + if (!newsurf) + { + fprintf(stderr, "TFB_DrawCanvas_New_RotationTarget() INTERNAL PANIC:" + "Failed to create TFB_Canvas: %s", SDL_GetError()); + exit (-1); + } + if (src->format->palette) + TFB_DrawCanvas_SetTransparentIndex (newsurf, TFB_DrawCanvas_GetTransparentIndex (src), FALSE); + else + { + int r, g, b; + if (TFB_DrawCanvas_GetTransparentColor (src, &r, &g, &b)) + TFB_DrawCanvas_SetTransparentColor (newsurf, r, g, b, FALSE); + } + + return newsurf; +} + void TFB_DrawCanvas_Delete (TFB_Canvas canvas) { @@ -357,6 +398,23 @@ TFB_DrawCanvas_SetTransparentIndex (TFB_Canvas canvas, int index, BOOLEAN rleacc } } +BOOLEAN +TFB_DrawCanvas_GetTransparentColor (TFB_Canvas canvas, int *r, int *g, int *b) +{ + if (!TFB_DrawCanvas_IsPaletted (canvas) + && (((SDL_Surface *)canvas)->flags & SDL_SRCCOLORKEY) ) + { + Uint8 ur, ug, ub; + int colorkey = ((SDL_Surface *)canvas)->format->colorkey; + SDL_GetRGB (colorkey, ((SDL_Surface *)canvas)->format, &ur, &ug, &ub); + *r = ur; + *g = ug; + *b = ub; + return TRUE; + } + return FALSE; +} + void TFB_DrawCanvas_SetTransparentColor (TFB_Canvas canvas, int r, int g, int b, BOOLEAN rleaccel) { @@ -404,6 +462,15 @@ TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, TFB_Canvas src_mipmap, in size->height = 1; } +void +TFB_DrawCanvas_GetExtent (TFB_Canvas canvas, PEXTENT size) +{ + SDL_Surface *src = (SDL_Surface *)canvas; + + size->width = src->w; + size->height = src->h; +} + void TFB_DrawCanvas_Rescale_Nearest (TFB_Canvas src_canvas, TFB_Canvas dest_canvas, EXTENT size) { @@ -930,3 +997,35 @@ TFB_DrawCanvas_GetLine (TFB_Canvas canvas, int line) SDL_Surface* surf = (SDL_Surface *)canvas; return (uint8*)surf->pixels + surf->pitch * line; } + +void +TFB_DrawCanvas_Rotate (TFB_Canvas src_canvas, TFB_Canvas dst_canvas, int angle, EXTENT size) +{ + SDL_Surface *src = (SDL_Surface *)src_canvas; + SDL_Surface *dst = (SDL_Surface *)dst_canvas; + int ret; + + if (size.width > dst->w || size.height > dst->h) + { + fprintf (stderr, "TFB_DrawCanvas_Rotate: Tried to rotate image to size %d %d when dst_canvas has only dimensions of %d %d! Failing.\n", + size.width, size.height, dst->w, dst->h); + return; + } + + ret = rotateSurface (src, dst, angle, 0); + if (ret != 0) + { + fprintf (stderr, "TFB_DrawCanvas_Rotate: WARNING: actual rotation func returned failure\n"); + } +} + +void +TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src_canvas, int angle, PEXTENT size) +{ + int dstw, dsth; + SDL_Surface *src = (SDL_Surface *)src_canvas; + + rotozoomSurfaceSize (src->w, src->h, angle, 1, &dstw, &dsth); + size->height = dsth; + size->width = dstw; +} diff --git a/sc2/src/sc2code/libs/graphics/sdl/rotozoom.c b/sc2/src/sc2code/libs/graphics/sdl/rotozoom.c new file mode 100644 index 000000000..070f011c4 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/rotozoom.c @@ -0,0 +1,1000 @@ +/* + + rotozoom.c - rotozoomer for 32bit or 8bit surfaces + LGPL (c) A. Schiffler + + Note by sc2 developers: + Taken from SDL_gfx library and modified, original code can be downloaded + from http://www.ferzkopp.net/Software/SDL_gfx-2.0/ + +*/ + +#ifdef GFXMODULE_SDL + +#include +#include +#include "misc.h" +#include "port.h" +#include "rotozoom.h" + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* + + 32bit Zoomer with optional anti-aliasing by bilinear interpolation. + + Zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface. + +*/ + +int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth) +{ + int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2, sstep; + tColorRGBA *c00, *c01, *c10, *c11; + tColorRGBA *sp, *csp, *dp; + int sgap, dgap; + + /* + * Variable setup + */ + if (smooth) { + /* + * For interpolation: assume source dimension is one pixel + */ + /* + * smaller to avoid overflow on right and bottom edge. + */ + sx = (int) (65536.0 * (float) (src->w - 1) / (float) dst->w); + sy = (int) (65536.0 * (float) (src->h - 1) / (float) dst->h); + } else { + sx = (int) (65536.0 * (float) src->w / (float) dst->w); + sy = (int) (65536.0 * (float) src->h / (float) dst->h); + } + + /* + * Allocate memory for row increments + */ + if ((sax = (int *) alloca((dst->w + 1) * sizeof(Uint32))) == NULL) { + return (-1); + } + if ((say = (int *) alloca((dst->h + 1) * sizeof(Uint32))) == NULL) { + return (-1); + } + + /* + * Precalculate row increments + */ + csx = 0; + csax = sax; + for (x = 0; x <= dst->w; x++) { + *csax = csx; + csax++; + csx &= 0xffff; + csx += sx; + } + csy = 0; + csay = say; + for (y = 0; y <= dst->h; y++) { + *csay = csy; + csay++; + csy &= 0xffff; + csy += sy; + } + + /* + * Pointer setup + */ + sp = csp = (tColorRGBA *) src->pixels; + dp = (tColorRGBA *) dst->pixels; + sgap = src->pitch - src->w * 4; + dgap = dst->pitch - dst->w * 4; + + /* + * Switch between interpolating and non-interpolating code + */ + if (smooth) { + + /* + * Interpolating Zoom + */ + + /* + * Scan destination + */ + csay = say; + for (y = 0; y < dst->h; y++) { + /* + * Setup color source pointers + */ + c00 = csp; + c01 = csp; + c01++; + c10 = (tColorRGBA *) ((Uint8 *) csp + src->pitch); + c11 = c10; + c11++; + csax = sax; + for (x = 0; x < dst->w; x++) { + + /* + * Interpolate colors + */ + ex = (*csax & 0xffff); + ey = (*csay & 0xffff); + t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff; + t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff; + dp->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff; + t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff; + dp->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff; + t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff; + dp->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff; + t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff; + dp->a = (((t2 - t1) * ey) >> 16) + t1; + + /* + * Advance source pointers + */ + csax++; + sstep = (*csax >> 16); + c00 += sstep; + c01 += sstep; + c10 += sstep; + c11 += sstep; + /* + * Advance destination pointer + */ + dp++; + } + /* + * Advance source pointer + */ + csay++; + csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch); + /* + * Advance destination pointers + */ + dp = (tColorRGBA *) ((Uint8 *) dp + dgap); + } + + } else { + + /* + * Non-Interpolating Zoom + */ + + csay = say; + for (y = 0; y < dst->h; y++) { + sp = csp; + csax = sax; + for (x = 0; x < dst->w; x++) { + /* + * Draw + */ + *dp = *sp; + /* + * Advance source pointers + */ + csax++; + sp += (*csax >> 16); + /* + * Advance destination pointer + */ + dp++; + } + /* + * Advance source pointer + */ + csay++; + csp = (tColorRGBA *) ((Uint8 *) csp + (*csay >> 16) * src->pitch); + /* + * Advance destination pointers + */ + dp = (tColorRGBA *) ((Uint8 *) dp + dgap); + } + + } + + return (0); +} + +/* + + 8bit Zoomer without smoothing. + + Zoomes 8bit palette/Y 'src' surface to 'dst' surface. + +*/ + +int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst) +{ + Uint32 sx, sy, *sax, *say, *csax, *csay, csx, csy; + int x, y; + Uint8 *sp, *dp, *csp; + int dgap; + + /* + * Variable setup + */ + sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w); + sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h); + + /* + * Allocate memory for row increments + */ + if ((sax = (Uint32 *) alloca(dst->w * sizeof(Uint32))) == NULL) { + return (-1); + } + if ((say = (Uint32 *) alloca(dst->h * sizeof(Uint32))) == NULL) { + return (-1); + } + + /* + * Precalculate row increments + */ + csx = 0; + csax = sax; + for (x = 0; x < dst->w; x++) { + csx += sx; + *csax = (csx >> 16); + csx &= 0xffff; + csax++; + } + csy = 0; + csay = say; + for (y = 0; y < dst->h; y++) { + csy += sy; + *csay = (csy >> 16); + csy &= 0xffff; + csay++; + } + + csx = 0; + csax = sax; + for (x = 0; x < dst->w; x++) { + csx += (*csax); + csax++; + } + csy = 0; + csay = say; + for (y = 0; y < dst->h; y++) { + csy += (*csay); + csay++; + } + + /* + * Pointer setup + */ + sp = csp = (Uint8 *) src->pixels; + dp = (Uint8 *) dst->pixels; + dgap = dst->pitch - dst->w; + + /* + * Draw + */ + csay = say; + for (y = 0; y < dst->h; y++) { + csax = sax; + sp = csp; + for (x = 0; x < dst->w; x++) { + /* + * Draw + */ + *dp = *sp; + /* + * Advance source pointers + */ + sp += (*csax); + csax++; + /* + * Advance destination pointer + */ + dp++; + } + /* + * Advance source pointer (for row) + */ + csp += ((*csay) * src->pitch); + csay++; + /* + * Advance destination pointers + */ + dp += dgap; + } + + return (0); +} + +/* + + 32bit Rotozoomer with optional anti-aliasing by bilinear interpolation. + + Rotates and zoomes 32bit RGBA/ABGR 'src' surface to 'dst' surface. + +*/ + +void transformSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos, int smooth) +{ + int x, y, t1, t2, dx, dy, xd, yd, sdx, sdy, ax, ay, ex, ey, sw, sh; + tColorRGBA c00, c01, c10, c11; + tColorRGBA *pc, *sp; + int gap; + + /* + * Variable setup + */ + xd = ((src->w - dst->w) << 15); + yd = ((src->h - dst->h) << 15); + ax = (cx << 16) - (icos * cx); + ay = (cy << 16) - (isin * cx); + sw = src->w - 1; + sh = src->h - 1; + pc = dst->pixels; + gap = dst->pitch - dst->w * 4; + + /* + * Switch between interpolating and non-interpolating code + */ + if (smooth) { + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (sdx >> 16); + dy = (sdy >> 16); + if ((dx >= -1) && (dy >= -1) && (dx < src->w) && (dy < src->h)) { + if ((dx >= 0) && (dy >= 0) && (dx < sw) && (dy < sh)) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + c00 = *sp; + sp += 1; + c01 = *sp; + sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch); + sp -= 1; + c10 = *sp; + sp += 1; + c11 = *sp; + } else if ((dx == sw) && (dy == sh)) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + c00 = *sp; + c01 = *sp; + c10 = *sp; + c11 = *sp; + } else if ((dx == -1) && (dy == -1)) { + sp = (tColorRGBA *) (src->pixels); + c00 = *sp; + c01 = *sp; + c10 = *sp; + c11 = *sp; + } else if ((dx == -1) && (dy == sh)) { + sp = (tColorRGBA *) (src->pixels); + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + c00 = *sp; + c01 = *sp; + c10 = *sp; + c11 = *sp; + } else if ((dx == sw) && (dy == -1)) { + sp = (tColorRGBA *) (src->pixels); + sp += dx; + c00 = *sp; + c01 = *sp; + c10 = *sp; + c11 = *sp; + } else if (dx == -1) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + c00 = *sp; + c01 = *sp; + c10 = *sp; + sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch); + c11 = *sp; + } else if (dy == -1) { + sp = (tColorRGBA *) (src->pixels); + sp += dx; + c00 = *sp; + c01 = *sp; + c10 = *sp; + sp += 1; + c11 = *sp; + } else if (dx == sw) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + c00 = *sp; + c01 = *sp; + sp = (tColorRGBA *) ((Uint8 *) sp + src->pitch); + c10 = *sp; + c11 = *sp; + } else if (dy == sh) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + c00 = *sp; + sp += 1; + c01 = *sp; + c10 = *sp; + c11 = *sp; + } + /* + * Interpolate colors + */ + ex = (sdx & 0xffff); + ey = (sdy & 0xffff); + t1 = ((((c01.r - c00.r) * ex) >> 16) + c00.r) & 0xff; + t2 = ((((c11.r - c10.r) * ex) >> 16) + c10.r) & 0xff; + pc->r = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.g - c00.g) * ex) >> 16) + c00.g) & 0xff; + t2 = ((((c11.g - c10.g) * ex) >> 16) + c10.g) & 0xff; + pc->g = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.b - c00.b) * ex) >> 16) + c00.b) & 0xff; + t2 = ((((c11.b - c10.b) * ex) >> 16) + c10.b) & 0xff; + pc->b = (((t2 - t1) * ey) >> 16) + t1; + t1 = ((((c01.a - c00.a) * ex) >> 16) + c00.a) & 0xff; + t2 = ((((c11.a - c10.a) * ex) >> 16) + c10.a) & 0xff; + pc->a = (((t2 - t1) * ey) >> 16) + t1; + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *) ((Uint8 *) pc + gap); + } + } else { + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (short) (sdx >> 16); + dy = (short) (sdy >> 16); + if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { + sp = (tColorRGBA *) ((Uint8 *) src->pixels + src->pitch * dy); + sp += dx; + *pc = *sp; + } + sdx += icos; + sdy += isin; + pc++; + } + pc = (tColorRGBA *) ((Uint8 *) pc + gap); + } + } +} + +/* + + 8bit Rotozoomer without smoothing + + Rotates and zoomes 8bit palette/Y 'src' surface to 'dst' surface. + +*/ + +void transformSurfaceY(SDL_Surface * src, SDL_Surface * dst, int cx, int cy, int isin, int icos) +{ + int x, y, dx, dy, xd, yd, sdx, sdy, ax, ay, sw, sh; + tColorY *pc, *sp; + int gap; + + /* + * Variable setup + */ + xd = ((src->w - dst->w) << 15); + yd = ((src->h - dst->h) << 15); + ax = (cx << 16) - (icos * cx); + ay = (cy << 16) - (isin * cx); + sw = src->w - 1; + sh = src->h - 1; + pc = dst->pixels; + gap = dst->pitch - dst->w; + /* + * Clear surface to colorkey + */ + memset(pc, (unsigned char) (src->format->colorkey & 0xff), dst->pitch * dst->h); + /* + * Iterate through destination surface + */ + for (y = 0; y < dst->h; y++) { + dy = cy - y; + sdx = (ax + (isin * dy)) + xd; + sdy = (ay - (icos * dy)) + yd; + for (x = 0; x < dst->w; x++) { + dx = (short) (sdx >> 16); + dy = (short) (sdy >> 16); + if ((dx >= 0) && (dy >= 0) && (dx < src->w) && (dy < src->h)) { + sp = (tColorY *) (src->pixels); + sp += (src->pitch * dy + dx); + *pc = *sp; + } + sdx += icos; + sdy += isin; + pc++; + } + pc += gap; + } +} + +/* + + rotozoomSurface() + + Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface. + 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1 + then the destination 32bit surface is anti-aliased. If the surface is not 8bit + or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +*/ + +#define VALUE_LIMIT 0.001 + + +/* Local rotozoom-size function with trig result return */ + +void rotozoomSurfaceSizeTrig(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight, + double *canglezoom, double *sanglezoom) +{ + double x, y, cx, cy, sx, sy; + double radangle; + int dstwidthhalf, dstheighthalf; + + /* + * Determine destination width and height by rotating a centered source box + */ + radangle = angle * (M_PI / 180.0); + *sanglezoom = sin(radangle); + *canglezoom = cos(radangle); + *sanglezoom *= zoom; + *canglezoom *= zoom; + x = width / 2; + y = height / 2; + cx = *canglezoom * x; + cy = *canglezoom * y; + sx = *sanglezoom * x; + sy = *sanglezoom * y; + dstwidthhalf = MAX((int) + ceil(MAX(MAX(MAX(fabs(cx + sy), fabs(cx - sy)), fabs(-cx + sy)), fabs(-cx - sy))), 1); + dstheighthalf = MAX((int) + ceil(MAX(MAX(MAX(fabs(sx + cy), fabs(sx - cy)), fabs(-sx + cy)), fabs(-sx - cy))), 1); + *dstwidth = 2 * dstwidthhalf; + *dstheight = 2 * dstheighthalf; +} + + +/* Publically available rotozoom-size function */ + +void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight) +{ + double dummy_sanglezoom, dummy_canglezoom; + + rotozoomSurfaceSizeTrig(width, height, angle, zoom, dstwidth, dstheight, &dummy_sanglezoom, &dummy_canglezoom); +} + + +/* Publically available rotozoom function */ + +SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth) +{ + SDL_Surface *rz_src; + SDL_Surface *rz_dst; + double zoominv; + double sanglezoom, canglezoom, sanglezoominv, canglezoominv; + int dstwidthhalf, dstwidth, dstheighthalf, dstheight; + int is32bit; + int i, src_converted; + + /* + * Sanity check + */ + if (src == NULL) + return (NULL); + + /* + * Determine if source surface is 32bit or 8bit + */ + is32bit = (src->format->BitsPerPixel == 32); + if ((is32bit) || (src->format->BitsPerPixel == 8)) { + /* + * Use source surface 'as is' + */ + rz_src = src; + src_converted = 0; + } else { + /* + * New source surface is 32bit with a defined RGBA ordering + */ + rz_src = + SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + SDL_BlitSurface(src, NULL, rz_src, NULL); + src_converted = 1; + is32bit = 1; + } + + /* + * Sanity check zoom factor + */ + if (zoom < VALUE_LIMIT) { + zoom = VALUE_LIMIT; + } + zoominv = 65536.0 / (zoom * zoom); + + /* + * Check if we have a rotozoom or just a zoom + */ + if (fabs(angle) > VALUE_LIMIT) { + + /* + * Angle!=0: full rotozoom + */ + /* + * ----------------------- + */ + + /* Determine target size */ + rotozoomSurfaceSizeTrig(rz_src->w, rz_src->h, angle, zoom, &dstwidth, &dstheight, &canglezoom, &sanglezoom); + + /* + * Calculate target factors from sin/cos and zoom + */ + sanglezoominv = sanglezoom; + canglezoominv = canglezoom; + sanglezoominv *= zoominv; + canglezoominv *= zoominv; + + /* Calculate half size */ + dstwidthhalf = dstwidth / 2; + dstheighthalf = dstheight / 2; + + /* + * Alloc space to completely contain the rotated surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0); + } + + /* + * Lock source surface + */ + SDL_LockSurface(rz_src); + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the rotation (using alpha) + */ + transformSurfaceRGBA(rz_src, rz_dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv), smooth); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the rotation + */ + transformSurfaceY(rz_src, rz_dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv)); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey); + } + /* + * Unlock source surface + */ + SDL_UnlockSurface(rz_src); + + } else { + + /* + * Angle=0: Just a zoom + */ + /* + * -------------------- + */ + + /* + * Calculate target size + */ + zoomSurfaceSize(rz_src->w, rz_src->h, zoom, zoom, &dstwidth, &dstheight); + + /* + * Alloc space to completely contain the zoomed surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0); + } + + /* + * Lock source surface + */ + SDL_LockSurface(rz_src); + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the zooming (using alpha) + */ + zoomSurfaceRGBA(rz_src, rz_dst, smooth); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the zooming + */ + zoomSurfaceY(rz_src, rz_dst); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, rz_src->format->colorkey); + } + /* + * Unlock source surface + */ + SDL_UnlockSurface(rz_src); + } + + /* + * Cleanup temp surface + */ + if (src_converted) { + SDL_FreeSurface(rz_src); + } + + /* + * Return destination surface + */ + return (rz_dst); +} + +/* Publically available rotate function */ + +int rotateSurface(SDL_Surface *src, SDL_Surface *dst, double angle, int smooth) +{ + double zoominv; + double sanglezoom, canglezoom, sanglezoominv, canglezoominv; + int dstwidthhalf, dstwidth, dstheighthalf, dstheight; + int is32bit; + int i; + + /* Sanity check */ + if (!src || !dst) + return -1; + if (src->format->BitsPerPixel != dst->format->BitsPerPixel) + return -1; + + /* Determine if source surface is 32bit or 8bit */ + is32bit = (src->format->BitsPerPixel == 32); + + zoominv = 65536.0; + + /* Check if we have to rotate anything */ + if (fabs(angle) <= VALUE_LIMIT) + { + SDL_BlitSurface(src, NULL, dst, NULL); + return 0; + } + + /* Determine target size */ + rotozoomSurfaceSizeTrig(src->w, src->h, angle, 1, &dstwidth, &dstheight, &canglezoom, &sanglezoom); + + /* + * Calculate target factors from sin/cos and zoom + */ + sanglezoominv = sanglezoom; + canglezoominv = canglezoom; + sanglezoominv *= zoominv; + canglezoominv *= zoominv; + + /* Calculate half size */ + dstwidthhalf = dstwidth / 2; + dstheighthalf = dstheight / 2; + + /* Check if the rotated surface will fit destination */ + if (dst->w < dstwidth || dst->h < dstheight) + return -1; + + /* Lock source surface */ + SDL_LockSurface(src); + SDL_LockSurface(dst); + /* Check which kind of surface we have */ + if (is32bit) + { /* Call the 32bit transformation routine to do the rotation (using alpha) */ + transformSurfaceRGBA(src, dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv), smooth); + } + else + { + /* Copy palette info */ + for (i = 0; i < src->format->palette->ncolors; i++) + dst->format->palette->colors[i] = src->format->palette->colors[i]; + dst->format->palette->ncolors = src->format->palette->ncolors; + /* Call the 8bit transformation routine to do the rotation */ + transformSurfaceY(src, dst, dstwidthhalf, dstheighthalf, + (int) (sanglezoominv), (int) (canglezoominv)); + } + /* Unlock source surface */ + SDL_UnlockSurface(dst); + SDL_UnlockSurface(src); + + return 0; +} + +/* + + zoomSurface() + + Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface. + 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1 + then the destination 32bit surface is anti-aliased. If the surface is not 8bit + or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +*/ + +#define VALUE_LIMIT 0.001 + +void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight) +{ + /* + * Sanity check zoom factors + */ + if (zoomx < VALUE_LIMIT) { + zoomx = VALUE_LIMIT; + } + if (zoomy < VALUE_LIMIT) { + zoomy = VALUE_LIMIT; + } + + /* + * Calculate target size + */ + *dstwidth = (int) ((double) width * zoomx); + *dstheight = (int) ((double) height * zoomy); + if (*dstwidth < 1) { + *dstwidth = 1; + } + if (*dstheight < 1) { + *dstheight = 1; + } +} + +SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth) +{ + SDL_Surface *rz_src; + SDL_Surface *rz_dst; + int dstwidth, dstheight; + int is32bit; + int i, src_converted; + + /* + * Sanity check + */ + if (src == NULL) + return (NULL); + + /* + * Determine if source surface is 32bit or 8bit + */ + is32bit = (src->format->BitsPerPixel == 32); + if ((is32bit) || (src->format->BitsPerPixel == 8)) { + /* + * Use source surface 'as is' + */ + rz_src = src; + src_converted = 0; + } else { + /* + * New source surface is 32bit with a defined RGBA ordering + */ + rz_src = + SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + SDL_BlitSurface(src, NULL, rz_src, NULL); + src_converted = 1; + is32bit = 1; + } + + /* Get size if target */ + zoomSurfaceSize(rz_src->w, rz_src->h, zoomx, zoomy, &dstwidth, &dstheight); + + /* + * Alloc space to completely contain the zoomed surface + */ + rz_dst = NULL; + if (is32bit) { + /* + * Target surface is 32bit with source RGBA/ABGR ordering + */ + rz_dst = + SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 32, + rz_src->format->Rmask, rz_src->format->Gmask, + rz_src->format->Bmask, rz_src->format->Amask); + } else { + /* + * Target surface is 8bit + */ + rz_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dstwidth, dstheight, 8, 0, 0, 0, 0); + } + + /* + * Lock source surface + */ + SDL_LockSurface(rz_src); + /* + * Check which kind of surface we have + */ + if (is32bit) { + /* + * Call the 32bit transformation routine to do the zooming (using alpha) + */ + zoomSurfaceRGBA(rz_src, rz_dst, smooth); + /* + * Turn on source-alpha support + */ + SDL_SetAlpha(rz_dst, SDL_SRCALPHA, 255); + } else { + /* + * Copy palette and colorkey info + */ + for (i = 0; i < rz_src->format->palette->ncolors; i++) { + rz_dst->format->palette->colors[i] = rz_src->format->palette->colors[i]; + } + rz_dst->format->palette->ncolors = rz_src->format->palette->ncolors; + /* + * Call the 8bit transformation routine to do the zooming + */ + zoomSurfaceY(rz_src, rz_dst); + SDL_SetColorKey(rz_dst, SDL_SRCCOLORKEY, rz_src->format->colorkey); + } + /* + * Unlock source surface + */ + SDL_UnlockSurface(rz_src); + + /* + * Cleanup temp surface + */ + if (src_converted) { + SDL_FreeSurface(rz_src); + } + + /* + * Return destination surface + */ + return (rz_dst); +} + +#endif diff --git a/sc2/src/sc2code/libs/graphics/sdl/rotozoom.h b/sc2/src/sc2code/libs/graphics/sdl/rotozoom.h new file mode 100644 index 000000000..ceedb7731 --- /dev/null +++ b/sc2/src/sc2code/libs/graphics/sdl/rotozoom.h @@ -0,0 +1,95 @@ +/* + + rotozoom.h - rotozoomer for 32bit or 8bit surfaces + LGPL (c) A. Schiffler + + Note by sc2 developers: + Taken from SDL_gfx library and modified, original code can be downloaded + from http://www.ferzkopp.net/Software/SDL_gfx-2.0/ + +*/ + + +#ifndef ROTOZOOM_H +#define ROTOZOOM_H + +#include +#ifndef M_PI +#define M_PI 3.141592654 +#endif + +#include "SDL.h" + + +/* ---- Defines */ + +#define SMOOTHING_OFF 0 +#define SMOOTHING_ON 1 + +/* ---- Structures */ + +typedef struct tColorRGBA { + Uint8 r; + Uint8 g; + Uint8 b; + Uint8 a; +} tColorRGBA; + +typedef struct tColorY { + Uint8 y; +} tColorY; + + +/* ---- Prototypes */ + +/* + zoomSurfaceRGBA() + + Zoom the src surface into dst. The zoom amount is determined + by the dimensions of src and dst + +*/ +int zoomSurfaceRGBA(SDL_Surface * src, SDL_Surface * dst, int smooth); + +/* + + rotozoomSurface() + + Rotates and zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface. + 'angle' is the rotation in degrees. 'zoom' a scaling factor. If 'smooth' is 1 + then the destination 32bit surface is anti-aliased. If the surface is not 8bit + or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +*/ + +SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, + int smooth); + +int rotateSurface(SDL_Surface * src, SDL_Surface * dst, double angle, + int smooth); + +/* Returns the size of the target surface for a rotozoomSurface() call */ + +void rotozoomSurfaceSize(int width, int height, double angle, double zoom, + int *dstwidth, int *dstheight); + +/* + + zoomSurface() + + Zoomes a 32bit or 8bit 'src' surface to newly created 'dst' surface. + 'zoomx' and 'zoomy' are scaling factors for width and height. If 'smooth' is 1 + then the destination 32bit surface is anti-aliased. If the surface is not 8bit + or 32bit RGBA/ABGR it will be converted into a 32bit RGBA format on the fly. + +*/ + +SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, + int smooth); + +/* Returns the size of the target surface for a zoomSurface() call */ + +void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, + int *dstwidth, int *dstheight); + +#endif diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.c b/sc2/src/sc2code/libs/graphics/tfb_draw.c index 2f5b50ac8..d67bfc2bd 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.c +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.c @@ -291,6 +291,7 @@ TFB_DrawImage_New (TFB_Canvas canvas) img->MipmapImg = NULL; img->colormap_index = -1; img->last_scale_type = -1; + TFB_DrawCanvas_GetExtent (canvas, &img->extent); img->Palette = TFB_DrawCanvas_ExtractPalette (canvas); @@ -316,12 +317,39 @@ TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha) img->colormap_index = -1; img->last_scale_type = -1; img->Palette = NULL; - + img->extent.width = w; + img->extent.height = h; + img->NormalImg = TFB_DrawCanvas_New_ForScreen (w, h, withalpha); return img; } +TFB_Image * +TFB_DrawImage_New_Rotated (TFB_Image *img, int angle) +{ + TFB_Canvas dst; + EXTENT size; + + /* sanity check */ + if (!img->NormalImg) + { + fprintf (stderr, "TFB_DrawImage_New_Rotated: source canvas is NULL! Failing.\n"); + return NULL; + } + + TFB_DrawCanvas_GetRotatedExtent (img->NormalImg, angle, &size); + dst = TFB_DrawCanvas_New_RotationTarget (img->NormalImg, angle); + if (!dst) + { + fprintf (stderr, "TFB_DrawImage_New_Rotated: rotation target canvas not created! Failing.\n"); + return NULL; + } + TFB_DrawCanvas_Rotate (img->NormalImg, dst, angle, size); + + return TFB_DrawImage_New (dst); +} + void TFB_DrawImage_Delete (TFB_Image *image) { diff --git a/sc2/src/sc2code/libs/graphics/tfb_draw.h b/sc2/src/sc2code/libs/graphics/tfb_draw.h index 4baec5301..d868a5e6f 100644 --- a/sc2/src/sc2code/libs/graphics/tfb_draw.h +++ b/sc2/src/sc2code/libs/graphics/tfb_draw.h @@ -86,6 +86,7 @@ void TFB_FlushPaletteCache (void); TFB_Image *TFB_DrawImage_New (TFB_Canvas canvas); TFB_Image *TFB_DrawImage_CreateForScreen (int w, int h, BOOLEAN withalpha); +TFB_Image *TFB_DrawImage_New_Rotated (TFB_Image *img, int angle); void TFB_DrawImage_Delete (TFB_Image *image); void TFB_DrawImage_FixScaling (TFB_Image *image, int target, int type); @@ -98,11 +99,15 @@ TFB_Canvas TFB_DrawCanvas_New_TrueColor (int w, int h, BOOLEAN hasalpha); TFB_Canvas TFB_DrawCanvas_New_ForScreen (int w, int h, BOOLEAN withalpha); TFB_Canvas TFB_DrawCanvas_New_Paletted (int w, int h, TFB_Palette *palette, int transparent_index); TFB_Canvas TFB_DrawCanvas_New_ScaleTarget (TFB_Canvas canvas, TFB_Canvas oldcanvas, int type, int last_type); +TFB_Canvas TFB_DrawCanvas_New_RotationTarget (TFB_Canvas src, int angle); TFB_Canvas TFB_DrawCanvas_ToScreenFormat (TFB_Canvas canvas); BOOLEAN TFB_DrawCanvas_IsPaletted (TFB_Canvas canvas); void TFB_DrawCanvas_Rescale_Nearest (TFB_Canvas src, TFB_Canvas dst, EXTENT size); void TFB_DrawCanvas_Rescale_Trilinear (TFB_Canvas src, TFB_Canvas dst, TFB_Canvas mipmap, EXTENT size); void TFB_DrawCanvas_GetScaledExtent (TFB_Canvas src_canvas, TFB_Canvas src_mipmap, int scale, PEXTENT size); +void TFB_DrawCanvas_Rotate (TFB_Canvas src, TFB_Canvas dst, int angle, EXTENT size); +void TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src, int angle, PEXTENT size); +void TFB_DrawCanvas_GetExtent (TFB_Canvas canvas, PEXTENT size); void TFB_DrawCanvas_Delete (TFB_Canvas canvas); @@ -115,6 +120,7 @@ TFB_Palette *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas); void TFB_DrawCanvas_SetPalette (TFB_Canvas target, TFB_Palette *palette); int TFB_DrawCanvas_GetTransparentIndex (TFB_Canvas canvas); void TFB_DrawCanvas_SetTransparentIndex (TFB_Canvas canvas, int i, BOOLEAN rleaccel); +BOOLEAN TFB_DrawCanvas_GetTransparentColor (TFB_Canvas canvas, int *r, int *g, int *b); void TFB_DrawCanvas_SetTransparentColor (TFB_Canvas canvas, int r, int g, int b, BOOLEAN rleaccel); void TFB_DrawCanvas_Initialize (void); void TFB_DrawCanvas_GetScreenFormat (TFB_PixelFormat *fmt);