let progname$="wiggb" let scrsize=.5 let sketch=1 def rsmall=1 def rlarge=3 def x(u,v)= (rlarge+rsmall*cos(v))*cos(u) def y(u,v)= (rlarge+rsmall*cos(v))*sin(u) def z(u,v)= rsmall*sin(v) + .5*sin(6*u+shift) !!!!!!! basic parameters !!!!!!!!!!!!!!!!!! let a = 0 ! bounds let b = 2*pi ! a < u < b let c = 0 ! c < v < d let d = 2*pi let n= 64 ! grid mesh to divide rectangle [a,b] x [c,d] let m= 24 let du=(b-a)/n let dv=(d-c)/m call eye(6,3,2) ! eyeball point call lightbulb(6,6,6) ! light source - used for shading of grid patches let zoom = 3 ! quick way to resize things let xmin=-1.5 * zoom ! 2dim screen rectangle let xmax= 1.5 * zoom ! it lies on plane with normal set by eye let ymin= -1 * zoom let ymax= 1 * zoom let zmin= -8 * zoom ! only effects distance calculations let zmax= 8 * zoom ! used by paint storage routines let xaxis=1.75 * zoom ! endpoints of axis and position of labels let yaxis=1.5 * zoom let zaxis=1 * zoom let numcon=16 ! number of contour planes let maxcon=zaxis ! largest contour plane let mincon=-zaxis ! smallest contour plane ! other global variables are objq,maxq,ys,zs,xpix,ypix,pix,mode$ ! color names (see sub init) !!!!!!!!!!!!!!!!!!!!! arrays option base 0 ! arrays start with 0 dim xscrn(2),yscrn(2),zscrn(2) ! unit orthogonal vectors of screen plane dim bulb(2) ! light source dim index(1),scratch(1) ! used by sort dim object$(1) sub redimension(maxpics) mat redim object$(maxpics),index(maxpics),scratch(maxpics) end sub ! call redimension(1) to free up memory !!!!!!!!!!!!!!!!!!!!!!!! !!! 3 - dim routines !!! !!!!!!!!!!!!!!!!!!!!!!!! def xs(a,b,c) ! transform into screen coordinates: xs,ys,zs let ys = a*yscrn[0]+b*yscrn[1]+c*yscrn[2] ! exploits side effect let zs = a*zscrn[0]+b*zscrn[1]+c*zscrn[2] ! ys and zs are passed let xs = a*xscrn[0]+b*xscrn[1]+c*xscrn[2] ! as global variables end def def norm(a()) = sqr(dot(a,a)) sub normalize(a()) local norma let norma=norm(a()) if norma <>0 then mat a=(1/norma)*a end sub sub eye(a,b,c) ! Finds xscrn,yscrn orthogonal to (a,b,c) and such let xscrn[0]=-b ! that the z-axis is straight up and down. let xscrn[1]= a ! zscrn points to eye let xscrn[2]= 0 ! This makes z-axis straight up and down. let yscrn[0]= -a let yscrn[1]= -b let yscrn[2]= (a*a + b*b)/c ! needs c not equal zero let zscrn[0]=a let zscrn[1]=b let zscrn[2]=c call normalize(xscrn) call normalize(yscrn) call normalize(zscrn) end sub sub lightbulb(a,b,c) ! bulb is used to determine hue of grid patches let bulb(0)=a ! if bulb perpindicular to patch use bright let bulb(1)=b ! colors, otherwise use darker let bulb(2)=c call normalize(bulb) end sub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!! initialize graphics !!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sub init set mode "vga" when error in open #1 : screen 0,scrsize,0,scrsize ! in case #1 already open use close #1 open #1 : screen 0,scrsize,0,scrsize end when window #1 set window xmin,xmax,ymin,ymax set background color "white" clear let black=0 let green=3 let blue=10 let yellow=13 let red=14 let white=15 set color mix(0) 1,1,1 ! background=white set color mix(1) 0,1/3,0 ! dark green set color mix(2) 0,2/3,0 set color mix(3) 1/3,2/3,0 set color mix(4) 0,1,0 set color mix(5) 1/3,1,0 set color mix(6) 2/3,1,0 ! light green set color mix(7) 0,0,1/3 ! dark blue set color mix(8) 0,0,2/3 set color mix(9) 0,1/3,2/3 set color mix(10) 0,0,1 set color mix(11) 0,1/3,1 set color mix(12) 0,2/3,1 ! light blue set color mix(13) 1,1,0 ! yellow set color mix(14) 1,0,0 ! red set color mix(15) 0,0,0 ! white=black end sub def gethue(side,intensity) if side > 0 then let gethue=int(7+5.99*intensity) ! blue 7-12 else let gethue=int(1+5.99*intensity) ! green 1-6 end if end def !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!! paint routines !!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! let xpix=640 ! two bytes each packb uses signed so clip ok let ypix=480 ! object$(q) = type distance pointx pointy hue let zpix=256*256 ! where type,hue one byte, others two bytes def type$(q) =object$(q)[1:1] sub settype(q,a$) !!!!! should be called first!!!! let object$(q)[1:1]=a$ ! g(rid),l(ine),t(ext),s(kip) if len(object$(q))<8 then let object$(q)=object$(q) & "1234567" ! this ensures packb and unpackb work correctly end sub def distance(q)=unpackb(object$(q),9,16) ! unsigned - no clip protect sub setdistance(q,w) local temp let temp=(w-zmin)*zpix/(zmax-zmin) ! convert to pixel coord call packb(object$(q),9,16,temp) end sub def pointx(q) =unpackb(object$(q),25,-16) ! signed integer sub setpointx(q,w) local temp let temp=(w-xmin)*xpix/(xmax-xmin) ! convert to pixel coord call packb(object$(q),25,-16,temp) end sub def pointy(q) =unpackb(object$(q),41,-16) sub setpointy(q,w) local temp, temp$ let temp=(w-ymin)*ypix/(ymax-ymin) ! convert to pixel coord call packb(object$(q),41,-16,temp) end sub def hue(q) =unpackb(object$(q)[8:8],1,8) sub sethue(q,w) let object$(q)[8:8]=chr$(w) end sub def text$(q) =object$(q)[9:100] sub settext(q,a$) let object$(q)[9:100]=a$ end sub sub paint(minq,maxq) local q,xpt1,xpt2,xpt3,xpt4,ypt1,ypt2,ypt3,ypt4,indq set text justify "center","half" set window 1,xpix,1,ypix ! fake pixel coordinates for q=minq to maxq let indq=index(q) select case type$(indq) case "g" ! grid let xpt1=pointx(indq) let ypt1=pointy(indq) let xpt2=pointx(indq+1) let ypt2=pointy(indq+1) let xpt3=pointx(indq+m+2) let ypt3=pointy(indq+m+2) let xpt4=pointx(indq+m+1) let ypt4=pointy(indq+m+1) set color hue(indq) plot area: xpt1,ypt1 ; xpt2,ypt2 ; xpt3,ypt3 ; xpt4,ypt4 set color red plot xpt1,ypt1 ; xpt2,ypt2 ; xpt3,ypt3 ; xpt4,ypt4 ; xpt1,ypt1 case "l" ! line set color yellow plot pointx(indq),pointy(indq);pointx(indq+1),pointy(indq+1) case "s" ! skip - no plotting -outer grid & end of lines case "t" ! text set color white plot text, at pointx(indq),pointy(indq) : text$(indq) end select ! call savescr(q) next q set window xmin,xmax,ymin,ymax ! standard coordinates end sub !!!!!!!!!!!!!! line, text, and axis routines !!!!!!!!!!!!! sub loadsegment(x1,y1,z1,x2,y2,z2,n) local q,dx,dy,dz,x,y,z,qstart,qfinish,temp1,temp2 let dx=(x2-x1)/n ! loads line segment from point1 to point2 let dy=(y2-y1)/n ! broken into n subsegments let dz=(z2-z1)/n let x=x1 let y=y1 let z=z1 let qstart=objq let qfinish=objq+n for q=qstart to qfinish call settype(q,"l") ! line call setpointx(q,xs(x,y,z)) call setpointy(q,ys) let temp1=zs let temp2=xs(x+dx,y+dy,z+dz) let temp2=zs call setdistance(q,.5*(temp1+temp2)+fudge) let x=x+dx let y=y+dy let z=z+dz next q call settype(qfinish,"s") ! skip - don't plot anything at end of segment let objq=qfinish+1 end sub sub loadtext(a,b,c,label$) ! loads label$ at point (a,b,c) call settype(objq,"t") ! text call setpointx(objq,xs(a,b,c)) call setpointy(objq,ys) call setdistance(objq,zs) call settext(objq,label$) let objq=objq+1 end sub sub loadaxis(a,b,c) call loadsegment(-a,0,0,a,0,0,n+m) call loadsegment(0,-b,0,0,b,0,n+m) call loadsegment(0,0,-c,0,0,c,n+m) call loadtext(0,0,c,"Z") call loadtext(0,b,0,"Y") call loadtext(a,0,0,"X") end sub !!!!!!!!!!!! load surface grid !!!!!!!!!!!!!! sub loadgrid local u,v,i,j,u1,u2,u3,v1,v2,v3,side,intensity,normal(2) let u=a for i=0 to n let v=c for j=0 to m call settype(objq,"g") if i=n or j=m then call settype(objq,"s") ! don't draw last row-col call setpointx(objq,xs(x(u,v),y(u,v),z(u,v))) call setpointy(objq,ys) call setdistance(objq,zs) let u1=x(u+du,v)-x(u,v) let u2=y(u+du,v)-y(u,v) let u3=z(u+du,v)-z(u,v) let v1=x(u,v+dv)-x(u,v) let v2=y(u,v+dv)-y(u,v) let v3=z(u,v+dv)-z(u,v) let normal(0)=u2*v3-u3*v2 ! cross product let normal(1)=u3*v1-u1*v3 let normal(2)=u1*v2-u2*v1 call normalize(normal()) ! unit normal vector to patch let side=dot(normal,zscrn) ! sign determines which side we see let intensity=abs(dot(normal,bulb)) ! intensity call sethue(objq,gethue(side,intensity)) let v=v+dv let objq=objq+1 next j let u=u+du next i end sub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!! contour routines !!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! def between(a,b,x) if a<=b then if (a<=x) and (x<=b) then let between=1 else let between=0 else if (b<=x) and (x<=a) then let between=1 else let between=0 end if end def sub loadcontourarray local i,u,v,x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4 local mn,mx,k,ck,dck,scalar,p1,p2,q1,q2,temp let dck= (maxcon-mincon)/(numcon-1) let u=a for i=0 to n-1 let v=c for j=0 to m-1 let x1=x(u,v) let y1=y(u,v) let z1=z(u,v) let x2=x(u+du,v) let y2=y(u+du,v) let z2=z(u+du,v) let x3=x(u+du,v+dv) let y3=y(u+du,v+dv) let z3=z(u+du,v+dv) let x4=x(u,v+dv) let y4=y(u,v+dv) let z4=z(u,v+dv) let mx=max(z1,max(z2,max(z3,z4))) let mn=min(z1,min(z2,min(z3,z4))) for ck=mincon to maxcon step dck if between(mx,mn,ck)=1 then let p1,p2,q1,q2=0 if between(z1,z2,ck)=1 then let scaler=(ck-z1)/(z2-z1) let p1=x1+scaler*(x2-x1) let p2=y1+scaler*(y2-y1) if between(z2,z3,ck)=1 then let scaler=(ck-z2)/(z3-z2) let q1=x2+scaler*(x3-x2) let q2=y2+scaler*(y3-y2) else if between(z3,z4,ck)=1 then let scaler=(ck-z3)/(z4-z3) let q1=x3+scaler*(x4-x3) let q2=y3+scaler*(y4-y3) else let scaler=(ck-z4)/(z1-z4) let q1=x4+scaler*(x1-x4) let q2=y4+scaler*(y1-y4) end if else if between(z2,z3,ck)=1 then let scaler=(ck-z2)/(z3-z2) let p1=x2+scaler*(x3-x2) let p2=y2+scaler*(y3-y2) if between(z3,z4,ck)=1 then let scaler=(ck-z3)/(z4-z3) let q1=x3+scaler*(x4-x3) let q2=y3+scaler*(y4-y3) else let scaler=(ck-z4)/(z1-z4) let q1=x4+scaler*(x1-x4) let q2=y4+scaler*(y1-y4) end if else if between(z3,z4,ck)=1 then let scaler=(ck-z3)/(z4-z3) let p1=x3+scaler*(x4-x3) let p2=y3+scaler*(y4-y3) let scaler=(ck-z4)/(z1-z4) let q1=x4+scaler*(x1-x4) let q2=y4+scaler*(y1-y4) end if ! essentially loadsegment(p1,p2,ck,q1,q2,ck,1) ! with a little fudge= .25(du+dv) call settype(objq,"l") let temp=xs(x1,y1,z1) ! dummy call to get zs call setdistance(objq,zs +.25*(du+dv)) ! just in front of grid call setpointx(objq,xs(p1,p2,ck)) call setpointy(objq,ys) let objq=objq+1 call settype(objq,"s") call setpointx(objq,xs(q1,q2,ck)) call setpointy(objq,ys) let objq=objq+1 end if next ck let v=v+dv next j let u=u+du next i end sub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!! sorting !!!!!!!!!!!!!!! sub loadindex(index(),n) local i for i=0 to n let index(i)=i next i end sub sub merge(index(),p,m,q,scratch()) local i,j,k let i=p let j=m+1 let k=p do until i=m+1 or j=q+1 if distance(index(i))< distance(index(j)) then let scratch(k)=index(i) let i=i+1 else let scratch(k)=index(j) let j=j+1 end if let k=k+1 loop if i=m+1 then do until j=q+1 let scratch(k)=index(j) let j=j+1 let k=k+1 loop else do until i=m+1 let scratch(k)=index(i) let i=i+1 let k=k+1 loop end if for i=p to q let index(i)=scratch(i) next i end sub ! merge sub sort(index(),p,q,scratch()) local m if (q-p)<2 then call merge(index,p,p,q,scratch) else let m=int(p+(q-p)/2) call sort(index,p,m,scratch) call sort(index,m+1,q,scratch) call merge(index,p,m,q,scratch) end if end sub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!! pbmplus save screen !!!!! !! globals : ppmflip, progname$! !! ppmnumb, #80, colormix$ !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! dim colormix$(0 to 15) sub getcolormix local point,r,g,b for point=0 to 15 ask color mix (point) r,g,b let colormix$(point)=using$("# # #", 3*r,3*g,3*b) next point end sub sub initppm ! save first file of transparent gifs, writes progname10.ppm local x,y,a$,px,py,xmin,xmax,ymin,ymax,point ask window xmin,xmax,ymin,ymax ! save window coordinates ask pixels px,py set window 1,px,1,py call getcolormix open #77 : name progname$&"10.ppm", create "newold" erase #77 print #77: "P3",px,py,3 ! P3=ppm, width, height, max rgb 0-3 open #78 : name "temp0.tmp", create "newold" ! scratch file erase #78 for y= py to 1 step -1 for x= 1 to px box keep x,x,y,y in a$ let point = min(1,ord(a$[9:9]))+ 2*min(1,ord(a$[10:10])) let point = point + 4*min(1,ord(a$[11:11]))+8*min(1,ord(a$[12:12])) print #77: colormix$(point) print #78: colormix$(point) next x next y set window xmin,xmax,ymin,ymax ! restore window coordinates close #77 close #78 open #80 : name progname$&".scr", create "newold" erase #80 ! writes an animator script file print #80 : ">OUTPUT " & progname$&".gif" print #80 : ">WIDTH ";px print #80 : ">HEIGHT ";py print #80 : ">NSLOOP" print #80 : ">FRAME NOTHING" print #80 : "FILE "; progname$&"10.gif" print #80 : "TRANS #000000" ! black = transparent color print #80 : "TIME 0" print #80 : "VER 0" print #80 : "HOR 0" let ppmnumb=10 let ppmflip=0 end sub sub moreppm ! keeps track of transparent color, writes prognamexx.ppm local x,y,a$,b$,px,py,xmin,xmax,ymin,ymax,point ask window xmin,xmax,ymin,ymax ! save window coordinates ask pixels px,py set window 1,px,1,py let ppmnumb=ppmnumb+1 open #77 : name progname$&str$(ppmnumb)&".ppm", create "newold" erase #77 print #77: "P3",px,py,3 ! P3=ppm, width, height, max rgb 0-3 open #78 : name "temp"&str$(ppmflip)&".tmp", create "newold" ! old scratch let ppmflip=1-ppmflip open #79 : name "temp"&str$(ppmflip)&".tmp", create "newold" ! new scratch erase #79 for y= py to 1 step -1 for x= 1 to px box keep x,x,y,y in a$ let point = min(1,ord(a$[9:9]))+ 2*min(1,ord(a$[10:10])) let point = point + 4*min(1,ord(a$[11:11]))+8*min(1,ord(a$[12:12])) let a$=colormix$(point) print #79: a$ ! put screen pix into new scratch line input #78: b$ ! get old scratch value if a$=b$ then print #77: "0 0 0" ! put transparent color into file else print #77: a$ ! put new screen value into file end if next x next y set window xmin,xmax,ymin,ymax ! restore window coordinates close #77 close #78 close #79 print #80 : ">FRAME NOTHING" ! animator script file print #80 : "FILE "; progname$&str$(ppmnumb)&".gif" print #80 : "TRANS" print #80 : "TIME" end sub sub closeppm ! clean up temporary files when error in close #80 unsave "temp0.tmp" unsave "temp1.tmp" use end when end sub sub saveppm if sketch=1 then exit sub if ppmnumb=0 then call initppm else call moreppm end if end sub sub saveppmx ! saves cur win to pbmplus file progname$.ppm, 480x640 1 minute 2.2MB local x,y,a$,px,py,xmin,xmax,ymin,ymax,point ask window xmin,xmax,ymin,ymax ! save window coordinates ask pixels px,py set window 1,px,1,py call getcolormix open #77 : name ppm$&".ppm", create "newold" erase #77 print #77: "P3",px,py,3 ! P3=ppm, width, height, max rgb 0-3 for y= py to 1 step -1 for x= 1 to px box keep x,x,y,y in a$ let point = min(1,ord(a$[9:9]))+ 2*min(1,ord(a$[10:10])) let point = point + 4*min(1,ord(a$[11:11]))+8*min(1,ord(a$[12:12])) print #77: colormix$(point) next x next y set window xmin,xmax,ymin,ymax ! restore window coordinates close #77 end sub !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!! main program !!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! let dshift=2*pi/8 let shift=-dshift let ppmnumb=0 do let shift=shift+dshift call redimension(4000) let objq=0 call loadgrid ! load in grid let maxq=objq-1 call loadindex(index,maxq) ! must be done for paint even if no sort call sort(index,0,maxq,scratch) ! sort call init ! initiate graphics call paint(0,maxq) ! do the drawing call saveppm loop until shift>=2*pi call closeppm ! clean up set mode "history" ! exit program in text mode ! sound 600,1 end !!! end of main program