Hi All,
I present below my code for realtime pixmap panning/zooming:
Essentially, I needed to implement a "Ken Burns" effect on arbitarily lage bitmaps, and render them to a pixmap which is them dumped to the screen.
The code is not without some limitations. The maximum zoom is to a 1:1 pixel level (by design), and there is absolutly no error checking at run time (as I use my authoring application to ensure that I don't go over the bounds of the pixmap).
Speed is achieved by reading directly from one pixmap and writing to the other. Since the destination pixmap (bg) has a direct 1:1 relation to the screen, I can speed up by getting the pointer to (0,0) and only ever increasing it.
GetRectFast() takes it's parameters as (x,y,width,height) from within the source bitmap, which can be any arbitary size, and scales the bitmap to fit on the screen by pixel skipping. Since the image is in motion, there is no real need to perform some sort of pixel averaging over the skipped pixels.
GetRect() is used by the authoring application to ensure that pixmap coordinates are valid and have the correct aspect ratio.
This code could stand futher refinement, and a few more options, but as it stands it suits my needs well.
Enjoy!
Neil
I present below my code for realtime pixmap panning/zooming:
Type PixmapZoomer Field bg:TPixmap ' Background to render into Field pm:TPixmap ' Loaded pixmap Field width:Int,height:Int Field aspectRatio:Float Field iWidth:Int,iHeight:Int Field scale:Float Const FPS=60 Function Create:PixmapZoomer(width:Int,height:Int,filename:String="") Local pz:PixmapZoomer=New PixmapZoomer pz.width=width pz.height=height pz.bg=CreatePixmap(width,height,PF_RGB888) If filename<>"" pz.Load fileName EndIf Return pz End Function Method Load(fileName:String) Local q:TPixmap=LoadPixmap(fileName) pm=ConvertPixmap(q,PF_RGB888) iWidth=PixmapWidth(pm) iHeight=PixmapHeight(pm) aspectRatio=Float(width)/Float(height) scale=Float(width)/Float(iWidth) End Method Method GetCorrectWidth:Int(height:Int) Return Int(Float(height)*aspectRatio) End Method Method GetCorrectHeight:Int(width:Int) Return Int(Float(width)/aspectRatio) End Method Method Perform(r1:rect,r2:rect,t:Int) ' Zoom pm from r1 to r2 in time t(millisecs) Local nSteps:Float=(t*FPS)/1000 Local xStep:Float=Float(r2.x-r1.x)/nSteps Local yStep:Float=Float(r2.y-r1.y)/nSteps Local wStep:Float=Float(r2.width-r1.width)/nSteps Local hStep:Float=Float(r2.height-r1.height)/nSteps Local x:Float,y:Float,w:Float,h:Float x=Float(r1.x) y=Float(r1.y) w=Float(r1.width) h=Float(r1.height) For Local i:Int=0 To nSteps GetRectFast x,y,w,h DrawPixmap bg,0,0 Flip x:+xStep y:+yStep w:+wStep h:+hStep Next End Method Method GetRect(sx:Int,sy:Int,sWidth:Int,sHeight:Int) If pm=Null Then Return If sWidth>iWidth And sHeight>iHeight sWidth=iWidth sHeight=GetCorrectHeight(sWidth) If sHeight>iHeight Then sHeight=iHeight sWidth=GetCorrectWidth(sHeight) EndIf ElseIf sWidth>iWidth Or sHeight=0 sWidth=iWidth sHeight=GetCorrectHeight(sWidth) If sHeight>iHeight Then sHeight=iHeight sWidth=GetCorrectWidth(sHeight) EndIf ElseIf sHeight>iHeight Or sWidth=0 sHeight=iHeight sWidth=GetCorrectWidth(sHeight) If sWidth>iWidth Then sWidth=iWidth sHeight=GetCorrectHeight(sWidth) EndIf EndIf GetRectFast sx,sy,sWidth,sHeight End Method Method GetRectFast(sx:Int,sy:Int,sWidth:Int,sHeight:Int) Local endY:Int=sy+sHeight-1 Local endX:Int=sx+sWidth-1 Local yStep:Float=sHeight/Float(height) Local xStep:Float=sWidth/Float(width) Local pixel:Byte Ptr Local pixel2:Byte Ptr Local pitch2:Int=bg.pitch Local bgXStart:Byte Ptr Local y:Float=sy Local x:Float bgXStart=bg.PixelPtr(0,0) pixel2=bgXStart While y<=endY x=sx While x<=endX pixel=pm.PixelPtr(x,y) pixel2[0]=pixel[0] pixel2[1]=pixel[1] pixel2[2]=pixel[2] x:+xStep pixel2:+3 Wend y:+yStep Wend End Method End Type
Essentially, I needed to implement a "Ken Burns" effect on arbitarily lage bitmaps, and render them to a pixmap which is them dumped to the screen.
The code is not without some limitations. The maximum zoom is to a 1:1 pixel level (by design), and there is absolutly no error checking at run time (as I use my authoring application to ensure that I don't go over the bounds of the pixmap).
Speed is achieved by reading directly from one pixmap and writing to the other. Since the destination pixmap (bg) has a direct 1:1 relation to the screen, I can speed up by getting the pointer to (0,0) and only ever increasing it.
GetRectFast() takes it's parameters as (x,y,width,height) from within the source bitmap, which can be any arbitary size, and scales the bitmap to fit on the screen by pixel skipping. Since the image is in motion, there is no real need to perform some sort of pixel averaging over the skipped pixels.
GetRect() is used by the authoring application to ensure that pixmap coordinates are valid and have the correct aspect ratio.
This code could stand futher refinement, and a few more options, but as it stands it suits my needs well.
Enjoy!
Neil