/*
* SDL Graphics Extension
* Rotation routines
*
* Started 000625
*
* License: LGPL v2+ (see the file LICENSE)
* (c)1999-2003 Anders Lindström
*/
/*********************************************************************
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
*********************************************************************/
#include "SDL.h"
#include <stdio.h>
#include <math.h>
#include "sge_rotation.h"
#include "sge_surface.h"
#include "sge_blib.h"
#define SWAP(x,y,temp) temp=x;x=y;y=temp
extern Uint8 _sge_update; //Declared in sge_draw.cpp
extern Uint8 _sge_lock;
SDL_Rect sge_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy);
//==================================================================================
// Helper function to sge_transform()
// Returns the bounding box
//==================================================================================
void _calcRect(SDL_Surface *src, SDL_Surface *dst, float theta, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax)
{
Sint16 x, y, rx, ry;
// Clip to src surface
Sint16 sxmin = sge_clip_xmin(src);
Sint16 sxmax = sge_clip_xmax(src);
Sint16 symin = sge_clip_ymin(src);
Sint16 symax = sge_clip_ymax(src);
Sint16 sx[]={sxmin, sxmax, sxmin, sxmax};
Sint16 sy[]={symin, symax, symax, symin};
// We don't really need fixed-point here
// but why not?
Sint32 const istx = Sint32((sin(theta)*xscale) * 8192.0); /* Inverse transform */
Sint32 const ictx = Sint32((cos(theta)*xscale) * 8192.2);
Sint32 const isty = Sint32((sin(theta)*yscale) * 8192.0);
Sint32 const icty = Sint32((cos(theta)*yscale) * 8192.2);
//Calculate the four corner points
for(int i=0; i<4; i++){
rx = sx[i] - px;
ry = sy[i] - py;
x = Sint16(((ictx*rx - isty*ry) >> 13) + qx);
y = Sint16(((icty*ry + istx*rx) >> 13) + qy);
if(i==0){
*xmax = *xmin = x;
*ymax = *ymin = y;
}else{
if(x>*xmax)
*xmax=x;
else if(x<*xmin)
*xmin=x;
if(y>*ymax)
*ymax=y;
else if(y<*ymin)
*ymin=y;
}
}
//Better safe than sorry...
*xmin -= 1;
*ymin -= 1;
*xmax += 1;
*ymax += 1;
//Clip to dst surface
if( !dst )
return;
if( *xmin < sge_clip_xmin(dst) )
*xmin = sge_clip_xmin(dst);
if( *xmax > sge_clip_xmax(dst) )
*xmax = sge_clip_xmax(dst);
if( *ymin < sge_clip_ymin(dst) )
*ymin = sge_clip_ymin(dst);
if( *ymax > sge_clip_ymax(dst) )
*ymax = sge_clip_ymax(dst);
}
/*==================================================================================
** Rotate by angle about pivot (px,py) scale by scale and place at
** position (qx,qy).
**
** Transformation matrix application (rotated coords "R"):
**
** / rx \ / cos(theta) sin(theta) \ / dx \
** | | = | | | |
** \ ry / \ -sin(theta) cos(theta) / \ dy /
**
** => rx = cos(theta) dx + sin(theta) dy
** ry = cos(theta) dy - sin(theta) dx
** but represented as a fixed-point float using integer math
**
** Developed with the help from Terry Hancock (hancock@earthlink.net)
**
**==================================================================================*/
// First we need some macros to handle different bpp
// I'm sorry about this...
#define TRANSFORM(UintXX, DIV) \
Sint32 const src_pitch=src->pitch/DIV; \
Sint32 const dst_pitch=dst->pitch/DIV; \
UintXX const *src_row = (UintXX *)src->pixels; \
UintXX *dst_row; \
\
for (y=ymin; y<ymax; y++){ \
dy = y - qy; \
\
sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
sy = Sint32(cty*dy - stdx + my); \
\
/* Calculate pointer to dst surface */ \
dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
\
for (x=xmin; x<xmax; x++){ \
rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
ry=Sint16(sy >> 13); \
\
/* Make sure the source pixel is actually in the source image. */ \
if( (rx>=sxmin) && (rx<=sxmax) && (ry>=symin) && (ry<=symax) ) \
*(dst_row + x) = *(src_row + ry*src_pitch + rx); \
\
sx += ctx; /* Incremental transformations */ \
sy -= sty; \
} \
}
#define TRANSFORM_GENERIC \
Uint8 R, G, B, A; \
\
for (y=ymin; y<ymax; y++){ \
dy = y - qy; \
\
sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
sy = Sint32(cty*dy - stdx + my); \
\
for (x=xmin; x<xmax; x++){ \
rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
ry=Sint16(sy >> 13); \
\
/* Make sure the source pixel is actually in the source image. */ \
if( (rx>=sxmin) && (rx<=sxmax) && (ry>=symin) && (ry<=symax) ){ \
sge_GetRGBA(sge_GetPixel(src,rx,ry), src->format, &R, &G, &B, &A);\
_PutPixelX(dst,x,y,sge_MapRGBA(dst->format, R, G, B, A)); \
\
} \
sx += ctx; /* Incremental transformations */ \
sy -= sty; \
} \
}
// Interpolated transform
#define TRANSFORM_AA(UintXX, DIV) \
Sint32 const src_pitch=src->pitch/DIV; \
Sint32 const dst_pitch=dst->pitch/DIV; \
UintXX const *src_row = (UintXX *)src->pixels; \
UintXX *dst_row; \
UintXX c1, c2, c3, c4;\
Uint32 R, G, B, A=0; \
UintXX Rmask = src->format->Rmask, Gmask = src->format->Gmask, Bmask = src->format->Bmask, Amask = src->format->Amask;\
Uint32 wx, wy;\
Uint32 p1, p2, p3, p4;\
\
/*
* Interpolation:
* We calculate the distances from our point to the four nearest pixels, d1..d4.
* d(a,b) = sqrt(a²+b²) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5))
*
* 1 wx 2
* *-|-* (+ = our point at (x,y))
* | | | (* = the four nearest pixels)
* wy --+ | wx = float(x) - int(x)
* | | wy = float(y) - int(y)
* *---*
* 3 4
* d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy)
* We now want to weight each pixels importance - it's vicinity to our point:
* w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it)
*
* If the pixels have the colors c1..c4 then our point should have the color
* c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average)
* but w1+w2+w3+w4 = 4*0.707 so we might as well write it as
* c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707)
*
* But p1..p4 are fixed point so we can just divide the fixed point constant!
* 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere)
* 8192/4 = 2048
*
* 020102: I changed the fixed-point representation for the variables in the weighted average
* to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This
* does however not solve the problem with 32bit RGBA colors...
*/\
\
Sint32 const one = 2048>>6; /* 1 in Fixed-point */ \
Sint32 const two = 2*2048>>6; /* 2 in Fixed-point */ \
\
for (y=ymin; y<ymax; y++){ \
dy = y - qy; \
\
sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
sy = Sint32(cty*dy - stdx + my); \
\
/* Calculate pointer to dst surface */ \
dst_row = (UintXX *)dst->pixels + y*dst_pitch; \
\
for (x=xmin; x<xmax; x++){ \
rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
ry=Sint16(sy >> 13); \
\
/* Make sure the source pixel is actually in the source image. */ \
if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) ){ \
wx = (sx & 0x00001FFF) >>8; /* (float(x) - int(x)) / 4 */ \
wy = (sy & 0x00001FFF) >>8;\
\
p4 = wx+wy;\
p3 = one-wx+wy;\
p2 = wx+one-wy;\
p1 = two-wx-wy;\
\
c1 = *(src_row + ry*src_pitch + rx);\
c2 = *(src_row + ry*src_pitch + rx+1);\
c3 = *(src_row + (ry+1)*src_pitch + rx);\
c4 = *(src_row + (ry+1)*src_pitch + rx+1);\
\
/* Calculate the average */\
R = ((p1*(c1 & Rmask) + p2*(c2 & Rmask) + p3*(c3 & Rmask) + p4*(c4 & Rmask))>>7) & Rmask;\
G = ((p1*(c1 & Gmask) + p2*(c2 & Gmask) + p3*(c3 & Gmask) + p4*(c4 & Gmask))>>7) & Gmask;\
B = ((p1*(c1 & Bmask) + p2*(c2 & Bmask) + p3*(c3 & Bmask) + p4*(c4 & Bmask))>>7) & Bmask;\
if(Amask)\
A = ((p1*(c1 & Amask) + p2*(c2 & Amask) + p3*(c3 & Amask) + p4*(c4 & Amask))>>7) & Amask;\
\
*(dst_row + x) = R | G | B | A;\
} \
sx += ctx; /* Incremental transformations */ \
sy -= sty; \
} \
}
#define TRANSFORM_GENERIC_AA \
Uint8 R, G, B, A, R1, G1, B1, A1=0, R2, G2, B2, A2=0, R3, G3, B3, A3=0, R4, G4, B4, A4=0; \
Sint32 wx, wy, p1, p2, p3, p4;\
\
Sint32 const one = 2048; /* 1 in Fixed-point */ \
Sint32 const two = 2*2048; /* 2 in Fixed-point */ \
\
for (y=ymin; y<ymax; y++){ \
dy = y - qy; \
\
sx = Sint32(ctdx + stx*dy + mx); /* Compute source anchor points */ \
sy = Sint32(cty*dy - stdx + my); \
\
for (x=xmin; x<xmax; x++){ \
rx=Sint16(sx >> 13); /* Convert from fixed-point */ \
ry=Sint16(sy >> 13); \
\
/* Make sure the source pixel is actually in the source image. */ \
if( (rx>=sxmin) && (rx+1<=sxmax) && (ry>=symin) && (ry+1<=symax) ){ \
wx = (sx & 0x00001FFF) >> 2; /* (float(x) - int(x)) / 4 */ \
wy = (sy & 0x00001FFF) >> 2;\
\
p4 = wx+wy;\
p3 = one-wx+wy;\
p2 = wx+one-wy;\
p1 = two-wx-wy;\
\
sge_GetRGBA(sge_GetPixel(src,rx, ry), src->format, &R1, &G1, &B1, &A1);\
sge_GetRGBA(sge_GetPixel(src,rx+1,ry), src->format, &R2, &G2, &B2, &A2);\
sge_GetRGBA(sge_GetPixel(src,rx, ry+1), src->format, &R3, &G3, &B3, &A3);\
sge_GetRGBA(sge_GetPixel(src,rx+1,ry+1), src->format, &R4, &G4, &B4, &A4);\
\
/* Calculate the average */\
R = (p1*R1 + p2*R2 + p3*R3 + p4*R4)>>13;\
G = (p1*G1 + p2*G2 + p3*G3 + p4*G4)>>13;\
B = (p1*B1 + p2*B2 + p3*B3 + p4*B4)>>13;\
A = (p1*A1 + p2*A2 + p3*A3 + p4*A4)>>13;\
\
_PutPixelX(dst,x,y,sge_MapRGBA(dst->format, R, G, B, A)); \
\
} \
sx += ctx; /* Incremental transformations */ \
sy -= sty; \
} \
}
// We get better performance if AA and normal rendering is seperated into two functions (better optimization).
// sge_transform() is used as a wrapper.
SDL_Rect sge_transformNorm(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
{
Sint32 dy, sx, sy;
Sint16 x, y, rx, ry;
SDL_Rect r;
r.x = r.y = r.w = r.h = 0;
float theta = float(angle*PI/180.0); /* Convert to radians. */
// Here we use 18.13 fixed point integer math
// Sint32 should have 31 usable bits and one for sign
// 2^13 = 8192
// Check scales
Sint32 maxint = Sint32(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
if( xscale == 0 || yscale == 0)
return r;
if( 8192.0/xscale > maxint )
xscale = float(8192.0/maxint);
else if( 8192.0/xscale < -maxint )
xscale = float(-8192.0/maxint);
if( 8192.0/yscale > maxint )
yscale = float(8192.0/maxint);
else if( 8192.0/yscale < -maxint )
yscale = float(-8192.0/maxint);
// Fixed-point equivalents
Sint32 const stx = Sint32((sin(theta)/xscale) * 8192.0);
Sint32 const ctx = Sint32((cos(theta)/xscale) * 8192.0);
Sint32 const sty = Sint32((sin(theta)/yscale) * 8192.0);
Sint32 const cty = Sint32((cos(theta)/yscale) * 8192.0);
Sint32 const mx = Sint32(px*8192.0);
Sint32 const my = Sint32(py*8192.0);
// Compute a bounding rectangle
Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
_calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
// Clip to src surface
Sint16 sxmin = sge_clip_xmin(src);
Sint16 sxmax = sge_clip_xmax(src);
Sint16 symin = sge_clip_ymin(src);
Sint16 symax = sge_clip_ymax(src);
// Some terms in the transform are constant
Sint32 const dx = xmin - qx;
Sint32 const ctdx = ctx*dx;
Sint32 const stdx = sty*dx;
// Lock surfaces... hopfully less than two needs locking!
if ( SDL_MUSTLOCK(src) && _sge_lock )
if ( SDL_LockSurface(src) < 0 )
return r;
if ( SDL_MUSTLOCK(dst) && _sge_lock ){
if ( SDL_LockSurface(dst) < 0 ){
if ( SDL_MUSTLOCK(src) && _sge_lock )
SDL_UnlockSurface(src);
return r;
}
}
// Use the correct bpp
if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags&SGE_TSAFE) ){
switch( src->format->BytesPerPixel ){
case 1: { /* Assuming 8-bpp */
TRANSFORM(Uint8, 1)
}
break;
case 2: { /* Probably 15-bpp or 16-bpp */
TRANSFORM(Uint16, 2)
}
break;
case 4: { /* Probably 32-bpp */
TRANSFORM(Uint32, 4)
}
break;
}
}else{
TRANSFORM_GENERIC
}
// Unlock surfaces
if ( SDL_MUSTLOCK(src) && _sge_lock )
SDL_UnlockSurface(src);
if ( SDL_MUSTLOCK(dst) && _sge_lock )
SDL_UnlockSurface(dst);
//Return the bounding rectangle
r.x=xmin; r.y=ymin; r.w=xmax-xmin; r.h=ymax-ymin;
return r;
}
SDL_Rect sge_transformAA(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale ,Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
{
Sint32 dy, sx, sy;
Sint16 x, y, rx, ry;
SDL_Rect r;
r.x = r.y = r.w = r.h = 0;
float theta = float(angle*PI/180.0); /* Convert to radians. */
// Here we use 18.13 fixed point integer math
// Sint32 should have 31 usable bits and one for sign
// 2^13 = 8192
// Check scales
Sint32 maxint = Sint32(pow(2, sizeof(Sint32)*8 - 1 - 13)); // 2^(31-13)
if( xscale == 0 || yscale == 0)
return r;
if( 8192.0/xscale > maxint )
xscale = float(8192.0/maxint);
else if( 8192.0/xscale < -maxint )
xscale = float(-8192.0/maxint);
if( 8192.0/yscale > maxint )
yscale = float(8192.0/maxint);
else if( 8192.0/yscale < -maxint )
yscale = float(-8192.0/maxint);
// Fixed-point equivalents
Sint32 const stx = Sint32((sin(theta)/xscale) * 8192.0);
Sint32 const ctx = Sint32((cos(theta)/xscale) * 8192.0);
Sint32 const sty = Sint32((sin(theta)/yscale) * 8192.0);
Sint32 const cty = Sint32((cos(theta)/yscale) * 8192.0);
Sint32 const mx = Sint32(px*8192.0);
Sint32 const my = Sint32(py*8192.0);
// Compute a bounding rectangle
Sint16 xmin=0, xmax=dst->w, ymin=0, ymax=dst->h;
_calcRect(src, dst, theta, xscale, yscale, px, py, qx, qy, &xmin,&ymin, &xmax,&ymax);
// Clip to src surface
Sint16 sxmin = sge_clip_xmin(src);
Sint16 sxmax = sge_clip_xmax(src);
Sint16 symin = sge_clip_ymin(src);
Sint16 symax = sge_clip_ymax(src);
// Some terms in the transform are constant
Sint32 const dx = xmin - qx;
Sint32 const ctdx = ctx*dx;
Sint32 const stdx = sty*dx;
// Lock surfaces... hopfully less than two needs locking!
if ( SDL_MUSTLOCK(src) && _sge_lock )
if ( SDL_LockSurface(src) < 0 )
return r;
if ( SDL_MUSTLOCK(dst) && _sge_lock ){
if ( SDL_LockSurface(dst) < 0 ){
if ( SDL_MUSTLOCK(src) && _sge_lock )
SDL_UnlockSurface(src);
return r;
}
}
// Use the correct bpp
if( src->format->BytesPerPixel == dst->format->BytesPerPixel && src->format->BytesPerPixel != 3 && !(flags&SGE_TSAFE) ){
switch( src->format->BytesPerPixel ){
case 1: { /* Assuming 8-bpp */
//TRANSFORM_AA(Uint8, 1)
TRANSFORM_GENERIC_AA
}
break;
case 2: { /* Probably 15-bpp or 16-bpp */
TRANSFORM_AA(Uint16, 2)
}
break;
case 4: { /* Probably 32-bpp */
TRANSFORM_AA(Uint32, 4)
}
break;
}
}else{
TRANSFORM_GENERIC_AA
}
// Unlock surfaces
if ( SDL_MUSTLOCK(src) && _sge_lock )
SDL_UnlockSurface(src);
if ( SDL_MUSTLOCK(dst) && _sge_lock )
SDL_UnlockSurface(dst);
//Return the bounding rectangle
r.x=xmin; r.y=ymin; r.w=xmax-xmin; r.h=ymax-ymin;
return r;
}
SDL_Rect sge_transform(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 px, Uint16 py, Uint16 qx, Uint16 qy, Uint8 flags)
{
if(flags&SGE_TTMAP)
return sge_transform_tmap(src, dst, angle, xscale, yscale, qx, qy);
else{
if(flags&SGE_TAA)
return sge_transformAA(src, dst, angle, xscale, yscale, px, py, qx, qy, flags);
else
return sge_transformNorm(src, dst, angle, xscale, yscale, px, py, qx, qy, flags);
}
}
//==================================================================================
// Same as sge_transform() but returns an surface with the result
//==================================================================================
SDL_Surface *sge_transform_surface(SDL_Surface *src, Uint32 bcol, float angle, float xscale, float yscale, Uint8 flags)
{
float theta = float(angle*PI/180.0); /* Convert to radians. */
// Compute a bounding rectangle
Sint16 xmin=0, xmax=0, ymin=0, ymax=0;
_calcRect(src, NULL, theta, xscale, yscale, 0, 0, 0, 0, &xmin,&ymin, &xmax,&ymax);
Sint16 w = xmax-xmin+1;
Sint16 h = ymax-ymin+1;
Sint16 qx = -xmin;
Sint16 qy = -ymin;
SDL_Surface *dest;
dest = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
if(!dest)
return NULL;
sge_ClearSurface(dest,bcol); //Set background color
sge_transform(src, dest, angle, xscale, yscale, 0, 0, qx, qy, flags);
return dest;
}
//==================================================================================
// Rotate using texture mapping
//==================================================================================
SDL_Rect sge_transform_tmap(SDL_Surface *src, SDL_Surface *dst, float angle, float xscale, float yscale, Uint16 qx, Uint16 qy)
{
double rad;
double a=(sge_clip_xmax(src) - sge_clip_xmin(src))/2.0;
double b=(sge_clip_ymax(src) - sge_clip_ymin(src))/2.0;
double cosv, sinv;
//Get an exact value if possible
if(angle==0.0 || angle==360.0){
cosv=1; sinv=0;
}
else if(angle==90.0){
cosv=0; sinv=1;
}
else if(angle==180.0){
cosv=-1; sinv=0;
}
else if(angle==270.0){
cosv=0; sinv=-1;
}
else{ //Oh well
rad=angle*(PI/180.0); //Deg => rad
cosv=cos(rad); sinv=sin(rad);
}
//Precalculate as much as possible
double acosv=a*cosv*xscale, bcosv=b*cosv*yscale;
double asinv=a*sinv*xscale, bsinv=b*sinv*yscale;
/* Do the maths */
Sint16 xt[4],yt[4];
xt[0] = Sint16((-acosv+bsinv)+qx);
yt[0] = Sint16((-asinv-bcosv)+qy);
xt[1] = Sint16((acosv+bsinv)+qx);
yt[1] = Sint16((asinv-bcosv)+qy);
xt[2] = Sint16((-acosv-bsinv)+qx);
yt[2] = Sint16((-asinv+bcosv)+qy);
xt[3] = Sint16((acosv-bsinv)+qx);
yt[3] = Sint16((asinv+bcosv)+qy);
//Use a texture mapped rectangle
sge_TexturedRect(dst,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],xt[3],yt[3],src, sge_clip_xmin(src),sge_clip_ymin(src), sge_clip_xmax(src),sge_clip_ymin(src), sge_clip_xmin(src),sge_clip_ymax(src), sge_clip_xmax(src),sge_clip_ymax(src));
//Or maybe two trigons...
//sge_TexturedTrigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],src, sge_clip_xmin(src),sge_clip_ymin(src), sge_clip_xmax(src),sge_clip_ymin(src), sge_clip_xmin(src),sge_clip_ymax(src));
//sge_TexturedTrigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],src, sge_clip_xmax(src),sge_clip_ymax(src), sge_clip_xmax(src),sge_clip_ymin(src), sge_clip_xmin(src),sge_clip_ymax(src));
//For debug
//sge_Trigon(dest,xt[0],yt[0],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,255,0,0));
//sge_Trigon(dest,xt[3],yt[3],xt[1],yt[1],xt[2],yt[2],SDL_MapRGB(dest->format,0,255,0));
Sint16 xmax=xt[0], xmin=xt[0];
xmax= (xmax>xt[1])? xmax : xt[1];
xmin= (xmin<xt[1])? xmin : xt[1];
xmax= (xmax>xt[2])? xmax : xt[2];
xmin= (xmin<xt[2])? xmin : xt[2];
xmax= (xmax>xt[3])? xmax : xt[3];
xmin= (xmin<xt[3])? xmin : xt[3];
Sint16 ymax=yt[0], ymin=yt[0];
ymax= (ymax>yt[1])? ymax : yt[1];
ymin= (ymin<yt[1])? ymin : yt[1];
ymax= (ymax>yt[2])? ymax : yt[2];
ymin= (ymin<yt[2])? ymin : yt[2];
ymax= (ymax>yt[3])? ymax : yt[3];
ymin= (ymin<yt[3])? ymin : yt[3];
SDL_Rect r;
r.x=xmin; r.y=ymin; r.w=xmax-xmin+1; r.h=ymax-ymin+1;
return r;
}
//==================================================================================
// Obsolete functions
//==================================================================================
SDL_Surface *sge_rotate_scaled_surface(SDL_Surface *src, int angle, double scale, Uint32 bcol)
{
SDL_Surface *dest;
/* Create the destination surface*/
int max = int( sqrt( (src->h*src->h/2 + src->w*src->w/2) *scale + 1 ) );
dest=SDL_AllocSurface(SDL_SWSURFACE, max, max, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask );
if(!dest){SDL_SetError("SGE - Out of memory");return NULL;}
sge_ClearSurface(dest,bcol);
sge_transform(src, dest, float(angle), float(scale), float(scale), src->w/2,src->h/2, dest->w/2,dest->h/2,0);
return(dest);
}
SDL_Surface *sge_rotate_surface(SDL_Surface *src, int angle, Uint32 bcol)
{
return sge_rotate_scaled_surface(src, angle, 1.0, bcol);
}
SDL_Rect sge_rotate_xyscaled(SDL_Surface *dest, SDL_Surface *src, Sint16 x, Sint16 y, int angle, double xscale, double yscale)
{
SDL_Rect ret;
ret=sge_transform(src, dest, float(angle), float(xscale), float(yscale), src->w/2,src->h/2, x,y,0);
if(_sge_update)
sge_UpdateRect(dest,ret.x,ret.y,ret.w+1,ret.h+1);
return ret;
}
SDL_Rect sge_rotate_scaled(SDL_Surface *dest, SDL_Surface *src, Sint16 x, Sint16 y, int angle, double scale)
{
return sge_rotate_xyscaled(dest,src,x,y,angle,scale,scale);
}
SDL_Rect sge_rotate(SDL_Surface *dest, SDL_Surface *src, Sint16 x, Sint16 y, int angle)
{
return sge_rotate_xyscaled(dest,src,x,y,angle,1.0,1.0);
}