PDA

View Full Version : fast image rotation



peterbone
28-06-2004, 03:22 PM
I need to make a sprite that will be loaded as a bitmap and it can then be moved around and rotated by the user. It will also be drawn with transparent regions.
At the moment I'm doing this by creating a rotated bitmap of the original loaded bitmap and drawing it to the screen every time the sprite is moved. Because It has transparent regions it also has to create a mask bitmap every time it's drawn too - using scanlines to check if each pixel is the transparent colour. This is very slow.
I can't create preloaded bitmaps of each rotation angle because there are too many possible angles.
So has anyone got a good way of doing it. Flash seems to do it very fast. I could load the pixels into an array when the bitmap is loaded, which might speed up the rotation algorithm but then drawing it on the screen would be slow.

Thanks

Peter

Paulius
30-06-2004, 10:12 AM
I think Flash does calculations with vectors, it still should go slow with many objects, and trying to rotate larger images with CPU in any orientation in real time is suicidal even on today?¢_Ts hardware.

I can't create preloaded bitmaps of each rotation angle because there are too many possible angles.Do you really need rotations in any angle? You could calculate rotated bitmaps with approximate angles say every 30 degrees and perhaps less for larger images on startup. A better alternative would be to take advantage of hardware acceleration with OpenGl or Direct3D to make you're rotations practically free without sacrificeing quallity.

Harry Hunt
30-06-2004, 01:07 PM
With medium-sized sprites, 16 angles is all you need to get fluid rotation and you can easily pre-process that. Apart from that you might want to consider using hardware acceleration.
If you absolutely have/want to use GDI, try doing it with scanlines and assembler. Might even work in real-time.

peterbone
30-06-2004, 02:30 PM
yes, I do need any angle.

I've managed to work out a way of doing it quickly and I've made a demo
http://atlas.walagata.com/w/peterbone/sprite_rotate.zip
Sorry that the demo is slightly surreal! I don't have a wide selection of images on my computer.

I realized that the thing that really slows down a rotate bitmap routine is that it has to call scanline for each pixel of the rotated bitmap. So what I did was store the original bitmap in a 2D array for quick pixel access and then the routine can create a bitmap of the rotated image very quickly because it only has to call scanline for each row.
I also combined the mask creation (for transparency) with the rotate image routine so it creates it at the same time.
Anyway tell me what you think.

Peter

BTW it should work with 8bit sprite bitmaps as well as 24bit but the colours go wrong. Please tell me if you work out what's causing it. Thanks.

Momor
29-07-2004, 03:59 PM
File not found error :cry:

peterbone
02-08-2004, 02:48 PM
sorry, I've put it back now. The rotation routine now supports scale and flip. This makes the demo project even more surreal!
http://atlas.walagata.com/w/peterbone/sprite_rotate.zip

Momor
08-08-2004, 10:14 AM
hehe ok I got it !

I have 2 advices:

1/ Get rid of the timer !! It's an horrible component which can't go under 20 ms of accuracy.

Instead I strongly suggest you to use the Application.onIdle event.

To show you a bit the difference, look at this new version : http://momorproductions.free.fr/temp/sprite_rotate_idle.zip

2/ I think the rotation could be boosted by a complete change of the algorithm (sorry :( ).

Your current algorithm is the following:

- Compute the destination bounding box size (Rwi, Rht)
- For each pixel of the bounding box:
- Reverse compute the original pixel in the original bitmap
- if not out of the bitmap, draw the pixel to the destination bitmap, otherwise draw transparent


Here is the algorithm I suggest:

- Compute the A,B,C,D coordinates of the destination polygon
- For each scanline of the destination polygon:
- Compute onScreen XStart and XEnd coordinates
- Compute the corresponding (XOriginalStart, YOriginalStart) and (XOriginalEnd, YOriginalEnd) coordinates in the original bitmap
- Make a linear interpolation from Start to End to fill the scanline

This latest algorithm as a new benefit : it allows a generic deformation (zoom, rotation, stretch ...)

I hope this helps !!!

peterbone
11-08-2004, 04:51 PM
Thanks for your feedback.
I don't quite get the onIdle method. How are you controlling the speed? The point of a TTimer is that it makes it run the same speed on any computer. Also, your version uses 100% of the processor!
I like your algorithm because the linear interpolation can be done by pre-calculating an increment value so that all you're doing is incrementing for each pixel. However, I don't need stretch and I'm not sure I can be bothered to re-write it.

Peter

Momor
11-08-2004, 06:57 PM
The OnIdle method gives you 100% of the CPU idle time, so that's not really 100% of the CPU.

To control the speed, you can either:

1- make some sleep() call in your game loop
2- make all your movements time based : instead of making

x:=x+5;

write something like


x:=x+TimedValue(5);

Where TimedValue() is a function which ponderates the input value by the frame rendering time.

peterbone
13-08-2004, 10:06 AM
What does everyone else think about this? What's wrong with poor little TTimer?

Peter

Alimonster
13-08-2004, 12:27 PM
What does everyone else think about this? What's wrong with poor little TTimer?

Peter
TTimer uses the WM_TIMER message, and ends up only guaranteeing 55msecs resolution - so if you set the timer interval to 33, for example (1000/33 = 30 updates per second), you'll actually only get 18 updates (1000 / 55). It's not recommended if you want higher resolution.

Use another method - make your own threaded timer, maybe, use Application.OnIdle, and look at QueryPerformanceCounter or timeBeginPeriod&timeGetTime.