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.