You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

96 lines
3.6 KiB
Plaintext

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

A Fast Algorithm for Rotating Bitmaps
by
Karl Lager
According to "Tricks of the Game Programming Gurus", rotating
a bitmap in real time generally isn't done because of the complex
math involved and slow speed. However, with a few optimizations
it can be done nearly as fast as bitmap scaling.
To start with, each pixel can be given x,y coordinates. To rotate
these by an angle t about the 0 axis , the new coordinates can be
plotted as (x',y') = (x cos(t) - y sin(t), y cos(t) + x sin(t)).
( for x = right, y = down, clockwise rotations. )
To convert a pixel on screen to the bitmap, the directions would be
reversed:
(x',y') = (x cos(t) + y sin(t), y cos(t) - x sin(t);
To rotate a whole bitmap, you can plot
( for y = min_y to max_y
for x = min_x to max_x
x' = (x cos (t) + y sin(t))
y' = (y cos(t) - x cos(t))
if (x', y') is in the bounds of the bitmap,
get pixel(x',y') and plot the pixel to (x,y) on screen.
)
Now, you might want to rotate the bitmap about an arbitrary pixel(x1',y1'),
and put it to an arbitrary point on screen(x1,y1), and to do this you
could get pixel(x'+ x1', y'+ y1') and put it to (x + x1, y + y1) on screen.
To speed this procedure up, you can start by taking the trig equations
out of the inner loop. The angle doesn't change, so these calculations
should only be done once.
double cosT,sinT;
cosT = cos(t);
sinT = sin(t);
for (y = min_y - y1; y <= max_y - y1; y++)
for (x = min_x - x1; x <= max_x - x1; x++)
{ x' = (x * cosT + y * sinT);
y' = (y * cosT - x * sinT);
if (x'+ x1', y'+ y1') is in the bounds of the bitmap,
get pixel(x'+ x1', y'+ y1') and plot the pixel to
(x + x1, y + y1) on screen.
}
Since x and y are incremented by a constant value, the code can be
streamlined further by removing the multiplications from the inner loop:
double cosT,sinT;
cosT = cos(t);
sinT = sin(t);
for (y = min_y - y1; y <= max_y - y1; y++)
{ x' = (min_x-x1) * cosT + y * sinT;
y' = y * cosT - (min_x-x1) * sinT;
for (x = min_x-x1; x <= max_x - x1; x++)
{ if (x'+ x1', y'+ y1') is in the bounds of the bitmap,
get pixel(x'+ x1',y'+ y1') and plot the pixel to
(x + x1,y + y1) on screen.
x' += cosT;
y' -= sinT;
}
}
Finally, remove the extra additions from the inner loops:
double cosT,sinT;
cosT = cos(t);
sinT = sin(t);
for (y = min_y; y <= max_y; y++)
{ x' = (min_x-x1) * cosT + (y-y1) * sinT + x1';
y' = (y-y1) * cosT - (min_x-x1) * sinT + y1';
for (x = min_x; x <= max_x; x++)
{ if (x', y') is in the bounds of the bitmap,
get pixel(x', y') and plot the pixel to
(x, y) on screen.
x' += cosT;
y' -= sinT;
}
}
Thus you have gone from doing 4 transcendental functions (or 4 lookups
and 4 multiplications if you are using lookup tables) per pixel to
doing 2 additions per pixel. That's going from instructions that take
a couple hundred CPU cycles with a coprocessor or thousands without
one to instructions that take one cycle.
Further gains can be made by making your max and min values exactly
fit the bounds of the bitmap and the video screen or window.