Bitmap rotation

• 01-07-2006
dwks
Bitmap rotation
How do you rotate a bitmap image? Rotating each pixel doesn't work. There must be a way, because The GIMP can do it.

I'm using the SDL.
• 01-07-2006
If you don't mind using a module you could use
http://freshmeat.net/projects/sge/

The important part of that article is the multiplication matrix it gives.
• 01-07-2006
dwks
Thanks. I'll see if I can get it to work.
• 01-07-2006
Shamino
Do you mean rotating the actual texture on the surface it is applied to, or rotating the surface?
• 01-08-2006
VirtualAce
Rotate the quad that the texture uses.
• 01-10-2006
dwks
What do you mean?
• 01-11-2006
VirtualAce
Think:
* What is the difference between a normal bitmap and a rotated one?
* What happens to the bounding rectangle of the bitmap when you rotate the bitmap?
* What is the difference between a rotated quadrilateral in 3D graphics and a bounding rectangle of a bitmap?

You can rotate a bitmap many ways. If you really want to use 2D and not 3D vertices in that you want to rotate a blitted bitmap you can do this:

1. Set texture coords for each corner of the box.
2. Compute the new bounding box after rotation.
3. Polyfill the box using linear interpolation.
4. Figure out the x,y coords of pixel.
5. Figure out the u,v coords of texel.

Essentially linear interpolate for x,y and u,v.

Pixel(x,y,Texture[u][v]);

To do a polyfill:

1. Create two arrays called leftside and rightside and clear to -1.
2. Start at the top of the figure.
3. Find the next vertex in either direction.
4. If vertex is lower than prev, it goes in leftside array
5. If vertex is higher than prev, it goes in rightside array.
6. Compute x's and u,v for leftside and rightside at point P on a line between CurVertex and NextVertex using formula for slope.
7. Save x's in leftside and rightside accordingly and increment a y line counter.
8. When done, start at y coord for top and set loopcounter to 0.
9. Draw textured line from leftside[loopcounter] to rightside[loopcounter]
10. Increment y and loop counter and check for loopcounter>y line counter.
11. If true, exit, else goto 9.

This is a simple old-school polygon fill algo used in many older DOS 3D games. It only works on convex shapes.

This will draw a bitmap w/o rotation and scaling.

Code:

``` DWORD dwTexOffset=0; UINT uCurX=Texture.X; UINT uCurY=Texture.Y; DWORD dwPixelOffset=(uCurY*Screen.Width)+uCurX; DWORD dwStartPixelOffset=dwPixelOffset; DWORD dwWidthCounter=0; DWORD dwHeightCounter=0; do {   DWORD dwPixelColor=Texture[dwTexOffset];   if (dwPixelColor!=Texture.dwTransparent)            SetPixel(dwPixelOffset,Texture[dwTexOffset];   dwTexOffset++;   dwPixelOffset++;   dwWidthCounter++;   if (dwWidthCounter>TextureWidth)   {     dwStartPixelOffset+=Screen.Width;     dwPixelOffset=dwStartPixelOffset;     dwWidthCounter=0;     dwHeightCounter++;   } } while (dwHeightCounter<TextureHeight);```
This code is best suited for assembly. You can use inline or pure. I'll write an inline version here.

Code:

```void BitBltEx(WORD uX, WORD uY,                     DWORD *pSurface,                     DWORD *pTexture,                     DWORD dwTexWidth,DWORD dwTexHeight,                     DWORD dwSurfWidth,                     DWORD dwTransColor) {   // (ESP-4)  DWORD dwTexOffset=0;   // (ESP-8)  DWORD dwPixelOffset;   // (ESP-12) DWORD dwStartPixelOffset;   // (ESP-16) DWORD dwWidthCounter=0;   //Height counter not needed since LOOP decrements ECX   _asm {                 ;Allocate stack space for local variables       sub esp,16       ;dwTexOffset=0;       mov [esp-4],0       ;Compute surface offset       mov  eax,uY       mov  ebx,dwSurfWidth       mul  eax,ebx       add  eax,uX       mov [esp-8],eax       mov [esp-12],eax       ;Zero out counters       mov [esp-16],0       ;Set up pointers       mov esi,[pTexture]       mov edi,[pSurface]       add edi,[esp-8]       ;Setup loop       LOOPSTART:       mov ecx,dwTexHeight       ;Blit one pixel if cur pixel is not trans       ;Retrieve current pixel       lodsd       cmp eax,dwTransColor       jne  NOBLIT       ;BLIT here       movsd       NOBLIT:       //Increment counters       //esi and edi auto-increment according to direction flag       //on movsd       inc [esp-16]       cmp [esp-16],dwTexWidth       jb  SAMELINE       add [esp-12],dwSurfWidth       mov eax,[esp-12]       mov [esp-8],eax       mov [esp-16],0       SAMELINE:       LOOP LOOPSTART         ;clean up stack       add esp,16   } }```
The assembly version could be sped up but my asm is a bit rusty.
This should work if you can get a pointer to surface memory and texture memory. However, I'm sure SDL provides a much better way. This is really old-school 2D BitBlts here.

Use the asm at your own risk. I wrote it here while looking at the C version, so I'm sure it has some bugs. I did refer to the IA32 Tech Ref for some of the instructions. For the most part it should give you the general idea.

Neither of these functions accounts for clipping to a bounding area.