Ok, I had some time to mess with your code and found it doesn't work. It looks fine when only the X is being drawn, but when you're zooming in with all kinds of things drawn around the outside, you notice a definite deceleration.
i thought about it for a while and realized something. If you stretch the world (or shrink the viewport) so that only 90% of the original shows after the first iteration, then on the second iteration, to appear a consistent speed, 90% of the screen from the result of the first iteration needs to be showing.
So instead of decreasing the original viewport linearly 90%, 80%, 70% etc. You need to decrease it exponentially. 90%, 81%, 72.9% etc...
After a bit of thinking, I finally came up with a formula.
X(i)=a*(p^i)
X(i) is the point after i iterations. a is the original position of the point. p is a scaler.
So the idea is, in order to move from a to b in n number of iterations, you need to calculate the value of p in such a way that when i=1 then X(i) = a and when i=n then X(i) = b.
Here's the nifty little formula for that.
p = (b/a)^(1/n)
There's only a few restrictions. One is that the center of the rectangle you are zooming into must be translated to the center of the world before the calculations are performed, which means everything must be translated back afterwards.
Another is that b cannot be 0. That can only happen if the rectangle you are zooming into has either 0 width or 0 height.
Here is an example of zooming with the above method. I have drawn a bunch of polygons around the screen to give a little better perspective of what's going on. On part of the screen is a bunch of concentric circles which marks the bullseye of where I want to zoom into.
As you can see, the zooming appears very consistent.
i thought about it for a while and realized something. If you stretch the world (or shrink the viewport) so that only 90% of the original shows after the first iteration, then on the second iteration, to appear a consistent speed, 90% of the screen from the result of the first iteration needs to be showing.
So instead of decreasing the original viewport linearly 90%, 80%, 70% etc. You need to decrease it exponentially. 90%, 81%, 72.9% etc...
After a bit of thinking, I finally came up with a formula.
X(i)=a*(p^i)
X(i) is the point after i iterations. a is the original position of the point. p is a scaler.
So the idea is, in order to move from a to b in n number of iterations, you need to calculate the value of p in such a way that when i=1 then X(i) = a and when i=n then X(i) = b.
Here's the nifty little formula for that.
p = (b/a)^(1/n)
There's only a few restrictions. One is that the center of the rectangle you are zooming into must be translated to the center of the world before the calculations are performed, which means everything must be translated back afterwards.
Another is that b cannot be 0. That can only happen if the rectangle you are zooming into has either 0 width or 0 height.
Here is an example of zooming with the above method. I have drawn a bunch of polygons around the screen to give a little better perspective of what's going on. On part of the screen is a bunch of concentric circles which marks the bullseye of where I want to zoom into.
As you can see, the zooming appears very consistent.
SuperStrict Graphics 800,600 Type TEntity 'for making shapes on the screen Field numsides:Int Field x:Double Field y:Double Field radius:Double End Type Global List:TList = CreateList() For Local i:Int = 1 To 100 'create a bunch of randomly placed, randomly shaped objects Local Entity:TEntity = New TEntity Entity.x = Rnd(800)-400 entity.y = Rnd(600)-300 Entity.radius = Rnd(.1,50) entity.numsides = Rand(3,8) List.Addlast(Entity) Next For Local i:Int = 1 To 20 'create a "Bullseye" shape for where we're going to zoom to Local Entity:TEntity = New TEntity Entity.x = 70 Entity.y = 65 Entity.numsides = 20 Entity.Radius = i List.AddLast(Entity) Next SetOrigin 400,300 'Make 0,0 at the center of the screen While Not KeyHit(KEY_ESCAPE) And Not AppTerminate() Cls Drawobjects(-400,-300,400,300) SetColor 255,255,0 DrawText "Press Z to zoom",10,10 SetColor 255,255,255 Flip If KeyHit(KEY_Z) Then zoom(50,50,90,80,600) Wend Function DrawObjects(x1:Double,y1:Double,x2:Double,y2:Double) 'Goes through the list and draws onto the World coordinates For Local Entity:TEntity = EachIn List Local Angle:Double = 360.0/Double(Entity.numsides) Local ox:Double = Entity.Radius + Entity.X Local oy:Double = Entity.y While Angle < 361 Local x:Int = Cos(Angle)*Entity.Radius+Entity.x Local y:Int = Sin(Angle)*Entity.Radius+Entity.y Line(ox,oy,x,y,x1,y1,x2,y2) Angle :+ 360.0/Double(Entity.numsides) ox=x oy=y Wend Next End Function Function Line(sx:Double,sy:Double,ex:Double,ey:Double,x1:Double,y1:Double,x2:Double,y2:Double)' translate from world coordinates to screen and renders Local cx:Double = (x2-x1)/Double(2)+x1 Local cy:Double = (y2-y1)/Double(2)+y1 Local sxs:Int = (sx-cx)/(x2-x1)*800 Local sys:Int = (sy-cy)/(y2-y1)*600 Local exs:Int = (ex-cx)/(x2-x1)*800 Local eys:Int = (ey-cy)/(y2-y1)*600 DrawLine sxs,sys,exs,eys End Function 'zx1, zy1, zx2, zy2 is the rectangle we are zooming into Function Zoom(zx1:Double,zy1:Double,zx2:Double,zy2:Double,frames:Int) Local cx:Double = (zx2-zx1)/2.0 'the distance from the edge to the center of the zooming rect Local cy:Double = (zy2-zy1)/2.0 Local tx:Double = cx+zx1 'distance from the center of the zooming rect to the world origin Local ty:Double = cy+zy1 Local px:Double = (cx/400.0)^(Double(1)/Double(frames)) 'calculate the scalar for zooming Local py:Double = (cy/300.0)^(Double(1)/Double(frames)) Local ptx:Double = (cx/(400.0+tx))^(Double(1)/Double(frames))'calculate the scaler for translating Local pty:Double = (cy/(300.0+tx))^(Double(1)/Double(frames)) For Local i:Int = 1 To frames Local nx1:Double = Double(-400)*(px^Double(i)) 'corner relative to rect center Local nx2:Double = -nx1 'opposite corner are negative of each other Local ny1:Double = Double(-300)*(py^Double(i)) Local ny2:Double = -ny1 Local ntx:Double = -((400.0+tx)*(ptx^Double(i))-tx) 'Where the corner of the screen is after translating Local nty:Double = -((300.0+ty)*(pty^Double(i))-ty) Local nsx:Double = ntx-nx1 'The amount needed to translate the current viewport from the zooming rect to the world coordinates Local nsy:Double = nty-ny1 Cls drawobjects(nx1+nsx,ny1+nsy,nx2+nsx,ny2+nsy) 'draw objects at current viewport dimentions Flip Next WaitKey() End Function