Easy zoom-to-cursor routine

Community Forums/Showcase/Easy zoom-to-cursor routine

USNavyFish(Posted 2008) [#1]
The most important thing here is how objects are drawn to the screen. Check out the 'draw' method of my 'obj' type.


Use the Mousewheel to zoom in / out, centered upong location of cursor. Click and drag to pan. Double clicking instantly zooms full-in on the mouse cursor.


I hope it is useful to somebody!





SuperStrict

Framework BRL.GLMax2D
Import BaH.Random
Import maxgui.drivers
Import BRL.PNGLoader
Import BRL.BMPLoader


Type obj
	Global List:TList
	
	Field X:Float
	Field Y:Float
	Field Size:Float
	Field HalfSize:Float
	Field R:Int
	Field G:Int
	Field B:Int
	

	
	Method New() 
		X = Rand(0 , GW) 
		Y = Rand(0 , GH) 
		Size = Rnd(0 , 1) 
		Size = size^3
		HalfSize = Size / 2.0
		R = Rand(0,255)
		G = Rand(0,255)	
		B = Rand(0 , 255) 
		
		If Not List Then List = New TList
		
		List.AddLast(Self)
		
	End Method
	
	Method Draw(ZoomOriginX:Float,ZoomOriginY:Float,_VIEWSCALE:Float) 
		SetColor(r,g,b)
		Local drawx:Float = ( (X - ZoomOriginX  ) * _viewscale)
			Local drawy:Float = ((Y- ZoomOriginY ) * _viewscale)
		DrawRect(drawX-HalfSize,drawY-HalfSize,size+1,size+1)
	End Method
	
End Type







Global GW:Int = ClientWidth(Desktop())
Global GH:Int = ClientHeight(Desktop())
Global GHW:Float = GW/2.0
Global GHH:Float = GH/2.0


Global Dragging:Byte = 0
Global MSX:Int
Global MSY:Int
Global MPosX:Int
Global MPosY:Int
Global DoubleClickTime:Int
Global DoubleClickDelay:Int = 300

Global Viewscale:Float = 1.0
Global WorldViewOriginX:Float = GHW
Global WorldViewOriginY:Float = GHH

Global ZoomTargetX:Float = GHW
Global ZoomTargetY:Float = GHH
Global ZoomTargetScale:Float = 1
Global ZoomFactor:Float = 1.25
Global ZoomMAX:Float = 30.0
Global ZoomMin:Float = 0.50


'Global RootDir:String = CurrentDir()

	
	
AddHook EmitEventHook, EventHook
	

SetGraphicsDriver(GLMax2DDriver() ) 


?Debug
	Global GraphicsContext:TGraphics = CreateGraphics(GW , GH , 0 , 60 , Graphics_BACKBUFFER) 
?Not Debug
	Global GraphicsContext:TGraphics = CreateGraphics(GW , GH , 32 , 60 , Graphics_BACKBUFFER)
?

SetGraphics(GraphicsContext) 


HideMouse()


For Local i:Int = 0 To 3000
	Local temp:obj = New obj
Next



Local ms:Int,time:Int,dt:Float

While Not KeyHit(KEY_ESCAPE)
	'ms = MilliSecs() 
	'dt = ms - time
	'time = ms
	
	'Print 1000.0/dt
	
	
	
	Cls
	
	SetScale(1 , 1)
	SetOrigin(GHW,GHH)
	
	

	
	SetColor(255 , 255 , 0) 
	SetLineWidth(5)
		Local tempx:Float = (-WorldViewOriginX * viewscale) 
		Local tempy:Float = (-WorldViewOriginY * viewscale )
		Local tempx2:Float = tempx+(GW*viewscale)
		Local tempy2:Float = tempy+(GH*viewscale)
		
		DrawLine(tempx , tempy , tempx2 , tempy) 
		DrawLine(tempx2, tempy , tempx2 , tempy2) 
		DrawLine(Tempx2 , tempy2 , tempx , tempy2) 
		DrawLine(tempx , tempy2 , tempx , tempy) 
	SetLineWidth(1)
	SetColor(255 , 255 , 255) 
	
	
		SetViewScale() 
	
	
	For Local t:obj = EachIn Obj.List
		t.draw(WorldViewOriginX, WorldViewOriginY, viewscale) 
		
	Next
		
				
	SetScale(1 , 1) 
	SetOrigin(0 , 0)
	
	
	SetBlend(LightBlend) 
	SetAlpha(0.4) 
	SetColor(255 , 155 , 0)
	SetLineWidth(2)	

		DrawLine(MPosX- 15 , MPosY, MPosX+ 15 , MPosY) 
		DrawLine(MPosX, MPosY- 15 , MPosX, MPosY+ 15 ) 
	
			
	SetLineWidth(1)
	SetBlend(SolidBlend) 
	
	
	
	SetColor(255 , 255 , 255) 
	DrawText("SCALE:  " + viewscale , 50 , 50) 
	
	Flip 0

Wend





Function SetViewScale()
	
		
		WorldViewOriginX = ZoomTargetX
		WorldViewOriginY = ZoomTargetY
		ViewScale = ZoomTargetScale
		
		SetScale(Viewscale , Viewscale)
	
End Function






Function ZoomIn(MouseScreenX:Int , MouseScreenY:Int) 
	
	If Not (ZoomTargetScale  >= ZoomMax) 	
	
		Local mx:Float = (MouseScreenX - GHW) /ZoomTargetScale
		Local my:Float = (MouseScreenY - GHH) /ZoomTargetScale
		Local z:Float = 1.0 - (1.0/ZoomFactor)
		
		ZoomTargetX = (mx)*(z) + WorldViewOriginX
		ZoomTargetY = (my)*(z) + WorldViewOriginY
					
		If ZoomTargetX > GW
			ZoomTargetX = GW
		Else If ZoomTargetX < 0
			ZoomTargetX = 0
		EndIf
				
		If ZoomTargetY > GH
			ZoomTargetY = GH
		Else If ZoomTargetY < 0
			ZoomTargetY = 0
		EndIf
			
					
		ZoomTargetScale:* ZoomFactor
		
		If ZoomTargetScale  > ZoomMax Then ZoomTargetScale  = ZoomMax
	
	EndIf
	
	
End Function




Function ZoomOut(MouseScreenX:Int , MouseScreenY:Int)

	If Not (ZoomTargetScale  =< ZoomMin) 
	
		Local mx:Float = (MouseScreenX - GHW) / ZoomTargetScale
		Local my:Float = (MouseScreenY - GHH) / ZoomTargetScale	
		Local z:Float = 1.0 - ZoomFactor
		
		ZoomTargetX  = mx*(z)+ WorldViewOriginX
		ZoomTargetY = my*(z)+ WorldViewOriginY
	
		ZoomTargetScale:/ ZoomFactor
		
		If ZoomTargetScale < ZoomMin Then ZoomTargetScale = ZoomMin
		
	EndIf
End Function





Function DoubleClick(button:Int , MouseScreenX:Int , MouseScreenY:Int)
	ZoomTargetX = WorldViewOriginX + (MouseScreenX - GHW) / ZoomTargetScale 	
	ZoomTargetY = WorldViewOriginY + (MouseScreenY - GHH) / ZoomTargetScale
	ZoomTargetScale = ZoomMax
End Function



Function Drag(MouseScreenX:Int , MouseScreenY:Int) 
	Local dx:Float = (MouseScreenX - MSX) / viewscale
	Local dy:Float = (MouseScreenY - MSY) / viewscale
	
	WorldViewOriginX:- dx
	WorldViewOriginY:- dy
	ZoomTargetX:- dx
	ZoomTargetY:- dy
	
	MSX = MouseScreenX
	MSY = MouseScreenY
	
	If WorldViewOriginX < 0
		WorldViewOriginX = 0
		ZoomTargetX = 0
	Else If WorldViewOriginX > GW
		WorldViewOriginX = GW
		ZoomTargetX = GW
	EndIf
	
	If WorldViewOriginY < 0
		WorldViewOriginY = 0
		ZoomTargetY = 0
	Else If WorldViewOriginY > GH
		WorldViewOriginY = GH
		ZoomTargetY = GH
	EndIf	
			
	
End Function




Function EventHook:Object(ID:Int , Data:Object , Context:Object) 
	Local Event:TEvent = TEvent(data)
	If Event = Null Then Return event
	
	Select event.id
		Case EVENT_MOUSEWHEEL
				
			If Event.Data > 0
				ZoomIn(event.x,Event.Y)
			Else
				ZoomOut(event.x,Event.Y)
			EndIf
		
							
		Case EVENT_APPTERMINATE
			End
			
			
		Case EVENT_KEYDOWN
			Select Event.Data
				Case KEY_ESCAPE End
					
									
			End Select
				
	
			
	
		Case EVENT_MOUSEDOWN
				
				Local ms:Int = MilliSecs()
					If ms - DoubleClickTime =< DoubleClickDelay
						DoubleClick(event.Data , event.X , event.Y) 
						Return Null
					Else DoubleClickTime = ms
				EndIf

			Select Event.data
			
				Case 1
					Dragging = 1
					MSX = Event.X
					MSY = Event.Y
					
			
				Case 3
					Dragging = 1
					MSX = Event.X
					MSY = Event.Y
					
					
			
			End Select
			
			
		Case EVENT_MOUSEUP
			Select Event.data
				Case 1,3
					Dragging = 0
			
			End Select
			
			
		Case EVENT_MOUSEMOVE
			
			MPosx = Event.x
			MPosY = Event.y
			
			If Dragging
				Drag(event.x,event.y)
				
			EndIf			

			
End Select


End Function







plash(Posted 2008) [#2]
Really nice code you have there, it would be more appropriate in the code archives though.


markcw(Posted 2008) [#3]
Et voila!


MGE(Posted 2008) [#4]
Interesting. Can you update to use a image as the background instead?


Filax(Posted 2008) [#5]
Excellent, really usefull :)


xlsior(Posted 2008) [#6]
Nice!


Scaremonger(Posted 2008) [#7]
That will be very handy I'm sure.