! Clipping, scaling, zooming
integer xoffset=0,yoffset=0
real xscale=1,yscale=1
integer vl = 0,vr = 688,vb = 0,vt = 512; !Viewport (physical coordinates)
integer wl = 0,wr = 688,wb = 0,wt = 512; !Window (virtual coordinates)
real screen aspect ratio = ((vt-vb)*4)/((vr-vl)*3)
routine scale(integername x,y); !Map to device coords
x = intpt(x*xscale)+xoffset
y = intpt(y*yscale)+yoffset
end
routine align window with viewport
! Make sure scaled middle of virtual window
! maps to middle of device window
integer vx = (vl+vr)//2, vy = (vb+vt)//2
integer wx = (wl+wr)//2, wy = (wb+wt)//2
xoffset = 0; yoffset = 0; scale(wx,wy)
xoffset = vx-wx; yoffset = vy-wy
end
routine aspect ratio
real f
f = |yscale/xscale/screen aspect ratio|
if f>1 then yscale = yscale/f else xscale = xscale*f
align window with viewport
end
routine compute scalings
xscale = (vr-vl)/(wr-wl)
yscale = (vt-vb)/(wt-wb)
aspect ratio
end
routine viewport(integer x1,y1,x2,y2)
vl = x1; vb = y1; vr = x2; vt = y2
compute scalings
end
routine window(integer x1,y1,x2,y2)
wl = x1; wr = x2; wt = y2; wb = y1
compute scalings
end
routine zoom(integer tx,ty,real f)
! TX, TY are the centre of the new window
integer wx = intpt((wr-wl)/f)
integer wy = intpt((wt-wb)/f)
wl = tx-wx//2; wr = wl+wx
wb = ty-wy//2; wt = wb+wy
compute scalings
end
integerfn clipcode(integer x,y)
integer c=0
c = 1 if x<vl
c = c+2 if x>vr
c = c+4 if y<vb
c = c+8 if y>vt
result =c
end
routine clipped line(integer x1,y1,x2,y2)
integer c1 = clipcode(x1,y1)
integer c2 = clipcode(x2,y2)
integer dx,dy
routine into range(integername x,y)
y = intpt((vl-x)*dy/dx)+y and x = vl if x<vl
y = intpt((vr-x)*dy/dx)+y and x = vr if x>vr
x = intpt((vb-y)*dx/dy)+x and y = vb if y<vb
x = intpt((vt-y)*dx/dy)+x and y = vt if y>vt
end
returnunless c1&c2=0
unless c1!c2=0 start
dx = x2-x1; dy = y2-y1
into range(x1,y1)
into range(x2,y2)
finish
line(x1,y1,x2,y2)
end
routine scaled line(integer x1,y1,x2,y2)
scale(x1,y1); scale(x2,y2)
clipped line(x1,y1,x2,y2)
end
routine clipped fill(integer x1,y1,x2,y2)
integer c1 = clipcode(x1,y1)
integer c2 = clipcode(x2,y2)
routine sw(integername a,b)
integer c
c = a; a = b; b = c
end
returnunless c1&c2=0
sw(x1,x2) if x1>x2
sw(y1,y2) if y1>y2
x1 = vl if x1<vl
y1 = vb if y1<vb
x2 = vr if x2>vr
y2 = vt if y2>vt
fill(x1,y1,x2,y2)
end
routine scaled fill(integer x1,y1,x2,y2)
scale(x1,y1); scale(x2,y2)
clipped fill(x1,y1,x2,y2)
end
endoffile