How to capture a rotated image

BlitzMax Forums/BlitzMax Beginners Area/How to capture a rotated image

Here is code to rotate an image in software:

'Software rotation demo

Strict
SetGraphicsDriver(GLMax2DDriver())
Graphics 640,480,0

'Prepare pixmaps
Local BackgroundPixmap:TPixmap=LoadPixmap("Background.jpg")
If PixmapFormat(BackgroundPixmap)<>PF_RGBA8888 Then BackgroundPixmap=ConvertPixmap(BackgroundPixmap,PF_RGBA8888)
Local SourcePixmap:TPixmap=LoadPixmap("RotoZoom.jpg")
If PixmapFormat(SourcePixmap)<>PF_RGBA8888 Then SourcePixmap=ConvertPixmap(SourcePixmap,PF_RGBA8888)
Local DestPixmap:TPixmap=CreatePixmap(640,480,PF_RGBA8888,4)
Local SourcePixelsPerRow=PixmapPitch(SourcePixmap)/4
Local DestPixelsPerRow=PixmapPitch(DestPixmap)/4
Local OpWidth:Int=PixmapWidth(SourcePixmap) 'Width of operation
Local OpHeight:Int=PixmapHeight(SourcePixmap) 'Height of operation
Local OpWidth2:Int=OpWidth/2
Local OpHeight2:Int=OpHeight/2
Local XCenter:Int'=OpWidth/2
Local YCenter:Int'=OpHeight/2

'Dummy alpha values
For Local aa:Int=0 To OpHeight-1
	For Local bb:Int=0 To OpWidth-1
		WritePixel(SourcePixmap,bb,aa,(ReadPixel(SourcePixmap,bb,aa)&$00FFFFFF)|(Int(bb*(256.0/OpWidth)) Shl 24)) 'Make alpha to see effect if image doesn't have one
	Next
Next

'Set up variables
Local PixmapWin:TPixmap=CreateStaticPixmap(PixmapPixelPtr(DestPixmap,0,0),OpWidth-1,OpHeight-1,SourcePixelsPerRow*4,PF_RGBA8888)
Local Angle:Float=0
Local Magnification:Float=1.0
Local Y_UAdd:Float,Y_VAdd:Float,X_UAdd:Float,X_VAdd:Float
Local Y_U:Float,Y_V:Float,X_U:Float,X_V:Float
Local SourceBase:Int Ptr=Int Ptr(PixmapPixelPtr(SourcePixmap,0,0))
Local DestBase:Int Ptr
Local SourcePixel:Int,DestPixel:Int
Local Xpos:Int,YPos:Int
Local Red:Int,Green:Int,Blue:Int
Local Alpha:Float
Local AlphaMask:Int=$000000FF

'Demo
Repeat
	'Interaction/autorotate
	If MouseDown(1) Then Magnification:+0.01
	If MouseDown(2) Or KeyHit(KEY_SPACE) Then Magnification:-0.01
	Angle:+1
	If Angle>=360 Then Angle:-360
	If Angle<0 Then Angle:+360

	'Setup
	Y_UAdd=Cos(Angle+90)*Magnification
	Y_VAdd=Sin(Angle+90)*Magnification
	X_UAdd=Cos(Angle)*Magnification
	X_VAdd=Sin(Angle)*Magnification
	XCenter=MouseX()
	YCenter=MouseY()
	Y_U=-(Y_UAdd*OpHeight2)-(X_UAdd*OpWidth2)
	Y_V=-(Y_VAdd*OpHeight2)-(X_VAdd*OpWidth2)
	
	'Draw it
	PixmapWin.Paste(BackgroundPixmap,0,0) 'Draw background
	DestBase=Int Ptr(PixmapPixelPtr(DestPixmap,0,0)) 'reset top left
	For Local Y:Int=0 To OpHeight-1
		X_U=Y_U
		X_V=Y_V
		For Local X:Int=0 To OpWidth-1
			XPos=XCenter+Int(X_U)
			YPos=YCenter+Int(X_V)
			If XPos>=0 And XPos<OpWidth 'clip x
				If YPos>0 And YPos<OpHeight 'clip y
					'SourcePixel=( SourceBase + XPos + (YPos*SourcePixelsPerRow) )[0] 'Read full pixel, clipped
					SourcePixel=ReadPixel(SourcePixmap,Xpos,Ypos)
					SourcePixel=(SourcePixel Shl 8) | (SourcePixel Shr 24) 'Convert ARGB to RGBA if using ReadPixel()
					
					Alpha=(SourcePixel & AlphaMask)/256.0
					Red=(SourcePixel Shr 24) * Alpha
					Green=((SourcePixel Shl 8) Shr 24) * Alpha
					Blue=((SourcePixel Shl 16) Shr 24) * Alpha
					Alpha=1.0-Alpha
					DestPixel=DestBase[X] 'Read full pixel
					Red:+((DestPixel Shr 24) * Alpha)
					Green:+(((DestPixel Shl 8) Shr 24) * Alpha)
					Blue:+(((DestPixel Shl 16) Shr 24) * Alpha)
					DestBase[X]=(Red Shl 24) | (Green Shl 16) | (Blue Shl 8) 'Plot RGBA
				EndIf
			EndIf
			X_U:+X_UAdd
			X_V:+X_VAdd
		Next
		DestBase:+DestPixelsPerRow 'next row
		Y_U:+Y_UAdd
		Y_V:+Y_VAdd
	Next
	DrawPixmap PixmapWin,0,0
	Flip 1
Until KeyHit(KEY_ESCAPE)

As from this thread about it (refer there if you find any issues)
http://www.blitzbasic.com/Community/posts.php?topic=59342

Feel free to use as you wish. I used ReadPixel to read the bitmap but otherwise am writing using direct pointer access which is probably the fastest way. There might possibly be faster algorithms out there but this is pretty reasonable and runs at several frames per second on my machine. Note that a lot of the time, however, is taken to do DrawPixmap(). That command is only to let you look at what has been output and is not needed for rotating the pixmap. To test speed, take that out and call the routine a number of times checking the millisecs elapsed.

You don't need the background pixmap - it's just pasting a background image into the pixmap before drawing the rotate image on top of it.

It supports alpha blending using the alpha channel and also doubles as a zoom operation - just like the oldschool `rotozoomers`! The only thing it doesn't do is antialiasing. You could render it at twice the size to a pixmap and then do your own simple `filtering`, combining the contents of a 2x2 pixel area and average it into one destination color.

Btw in OpenGL if your screen is 32-bit with an alpha channel you CAN read the backbuffer's alpha channel, so long as when you draw the object you only use SOLIDBLEND (ie no blending or masking or alphablend) and writing to the destination alpha is enabled. I use writing to the alpha channel in my blobby-objects engine.