Thought I would share this routine from a 2D game engine I designed several years back while learning Java. It's based on the popular "rotozoom" demo effect, but works on individual images rather than tiling them all over the screen, and is a good example of how choosing the right algorithm can pay off in terms of performance.
Code:
// rotate/scale a sprite
public void rotateSprite(Bitmap dest, int xx, int yy, int angle, float scale)
{
int duCol = (int)(Trig.sin[(1023 - angle) & 1023] * scale * 256);
int dvCol = (int)(Trig.sin[(1023 - (angle + 256)) & 1023] * scale * 256);
int duRow = -dvCol;
int dvRow = duCol;
int ww = w / 2;
int hh = h / 2;
// origin
int ox = xx + ww;
int oy = yy + hh;
// project new corners
int x0 = xx - ox;
int y0 = yy - oy;
int x1 = xx + (w - 1) - ox;
int y1 = yy - oy;
int x2 = xx - ox;
int y2 = yy + (h - 1) - oy;
int x3 = xx + (w - 1) - ox;
int y3 = yy + (h - 1) - oy;
// rotate
int newx0 = (int)(x0 * duCol + y0 * duRow) >> 8;
int newy0 = (int)(x0 * dvCol + y0 * dvRow) >> 8;
int newx1 = (int)(x1 * duCol + y1 * duRow) >> 8;
int newy1 = (int)(x1 * dvCol + y1 * dvRow) >> 8;
int newx2 = (int)(x2 * duCol + y2 * duRow) >> 8;
int newy2 = (int)(x2 * dvCol + y2 * dvRow) >> 8;
int newx3 = (int)(x3 * duCol + y3 * duRow) >> 8;
int newy3 = (int)(x3 * dvCol + y3 * dvRow) >> 8;
x0 = newx0 + xx;
y0 = newy0 + yy;
x1 = newx1 + xx;
y1 = newy1 + yy;
x2 = newx2 + xx;
y2 = newy2 + yy;
x3 = newx3 + xx;
y3 = newy3 + yy;
// find new bounding box
int bx1 = Int.min(x0, Int.min(x1, Int.min(x2, x3)));
int by1 = Int.min(y0, Int.min(y1, Int.min(y2, y3)));
int bx2 = Int.max(x0, Int.max(x1, Int.max(x2, x3)));
int by2 = Int.max(y0, Int.max(y1, Int.max(y2, y3)));
int bw = (bx2 - bx1) / 2;
int bh = (by2 - by1) / 2;
// draw the sprite
duCol = (int)(Trig.sin[angle & 1023] / scale * 256);
dvCol = (int)(Trig.sin[(angle + 256) & 1023] / scale * 256);
duRow = -dvCol;
dvRow = duCol;
int rowU = ww << 8;
int rowV = hh << 8;
rowU -= bw * duCol + bh * duRow;
rowV -= bw * dvCol + bh * dvRow;
int x, y;
for(y = by1; y <= by2; y++)
{
int u = rowU;
int v = rowV;
rowU += duRow;
rowV += dvRow;
// skip rows that are out-of-bounds
if(y < dest.ct || y > dest.cb)
continue;
int p = dest.row[y] + bx1;
for(x = bx1; x <= bx2; x++, p++)
{
int uu = u >> 8;
int vv = v >> 8;
u += duCol;
v += dvCol;
if(uu < 0 || uu >= w || vv < 0 || vv >= h)
continue;
int c = data[uu + row[vv]];
// skip columns that are out-of-bounds or transparent
if(x < dest.cl || x > dest.cr || c == 0xFFFF00FF)
continue;
// plot the pixel
dest.data[p] = c;
}
}
}