;Coded by *Kronos* the Wizard 4 - Mar - 1996
;Instructions:
;Left mouse button & drag = rotate
;Right mouse button & drag = scale
;caveat: the first line of the window remains dirty because of a bug in the
;WCls instruction (not mine; ask Acid Software).
#AXIS=0 ;1=On (if you wanna view the axis)
#WIDTH=320 ;width of the screen
#HEIGHT=256 ;height of the screen
#NUMPTS=8 ;number of points of the poligon
#NUMEDGES=12 ;number of edges of the poligon
NEWTYPE.pt ;a point (wow!) is obviously made of 3 coords (x,y,z)
x.f
y.f
z.f
End NEWTYPE
NEWTYPE.ed ;an edge is (start_vertex, end_vertex)
stver.w
enver.w
End NEWTYPE
Dim vertex.pt(#NUMPTS) ;here go points
Dim edge.ed(#NUMEDGES) ;this is filled with edges
Restore ptdat ;initialize arrays
For k.w=0 To #NUMPTS-1
Read vertex(k)\x
Read vertex(k)\y
Read vertex(k)\z
Next k
Restore edgedat
For k=0 To #NUMEDGES-1
Read edge(k)\stver
Read edge(k)\enver
Next k
;This Statement gets three parameters: the two angles a and b and the vertex
;number. It rotates the selected vertex around axis Z and X with angles a and
;b respectively.
Statement RotZX{a.f,b.f,n.w}
SHARED vertex.pt()
x.f=vertex(n)\x
y.f=vertex(n)\y
z.f=vertex(n)\z
vertex(n)\x=x*Cos(a)+y*Sin(a)*Cos(b)+z*Sin(a)*Sin(b)
vertex(n)\y=-x*Sin(a)+y*Cos(a)*Cos(b)+z*Cos(a)*Sin(b)
vertex(n)\z=-y*Sin(b)+z*Cos(b)
End Statement
;The following routine has two points (x,y,z) as parameters: it projects
;them on the 2-dimensional screen and draws the line connecting them.
;Because Blitz2 doesn't allow more than 6 parameters per Statement I had
;to Share the line pattern linpat.w. The dashed lines are obtained by
;assigning the 16-bit value $F0F0 to the LinePtrn field of the RastPort
;and by using the graphics.library routines Move and Draw instead of the
;built-in Blitz2 Line instruction.
;I use the variables cospi6 and sinpi6 loaded respectively with the cosine
;and the sine of 30 deg (instead of calculating them every time the Statement
;is called) to speed up computing.
Statement ProjLine{x1.f,y1.f,z1.f,x2.f,y2.f,z2.f}
SHARED vertex(),edge(),cospi6.f,sinpi6.f,*rp.RastPort,linpat.w
stpx.f=y1*cospi6-x1*cospi6+#WIDTH/2
stpy.f=y1*sinpi6+x1*sinpi6-z1+#HEIGHT/2
enpx.f=y2*cospi6-x2*cospi6+#WIDTH/2
enpy.f=y2*sinpi6+x2*sinpi6-z2+#HEIGHT/2
*rp\LinePtrn=linpat
*rp\linpatcnt=15
*rp\Flags=*rp\Flags|#FRST_DOT
Move_ *rp,stpx,stpy
Draw_ *rp,enpx,enpy
End Statement
;This Statement cycles through edges and draws the poligon.
Statement DrawAll{}
SHARED vertex(),edge.ed(),cospi6.f,sinpi6.f,linpat.w,*rp
;This is a trick to recognize the hidden vertex (only if you have one hidden
;vertex at a time): it's the one with the most negative sum of its three
;coords.
totmin.f=0
For k.w=0 To #NUMPTS-1
If totmin>vertex(k)\x+vertex(k)\y+vertex(k)\z
totmin=vertex(k)\x+vertex(k)\y+vertex(k)\z
totver.w=k
EndIf
Next k
WCls
cospi6.f=Cos(Pi/6)
sinpi6.f=Sin(Pi/6)
CNIF #AXIS=1
linpat.w=$FFFF
SetAPen_ *rp,2
ProjLine{0,0,0,80,0,0} ;X axis
SetAPen_ *rp,3
ProjLine{0,0,0,0,80,0} ;Y axis
SetAPen_ *rp,4
ProjLine{0,0,0,0,0,80} ;Z axis
CEND
SetAPen_ *rp,1
For k=0 To #NUMEDGES-1
linpat.w=$FFFF
;If the current edge departs from the hidden vertex then the line is dashed
If edge(k)\stver=totver OR edge(k)\enver=totver Then linpat=$F0F0
vx1.f=vertex(edge(k)\stver)\x
vy1.f=vertex(edge(k)\stver)\y
vz1.f=vertex(edge(k)\stver)\z
vx2.f=vertex(edge(k)\enver)\x
vy2.f=vertex(edge(k)\enver)\y
vz2.f=vertex(edge(k)\enver)\z
ProjLine{vx1,vy1,vz1,vx2,vy2,vz2} ;project and draw
Next k
End Statement
;Begin
flags.l=#WFLG_CLOSEGADGET|#WFLG_ACTIVATE|#WFLG_SMART_REFRESH|#WFLG_RMBTRAP|#WFLG_GIMMEZEROZERO
Screen 0,0,0,#WIDTH,#HEIGHT,3,0,"3DRot",0,1
Window 0,0,0,#WIDTH,#HEIGHT,flags,"3DRotation by *Kronos* the Wizard",0,1
*rp.RastPort=RastPort(0)
restart:
ev.l=WaitEvent
If ev=$200 OR EventWindow<>0 Then Goto bye
omx.w=WMouseX
omy.w=WMouseY
;This is the main loop.
Repeat
nmx.w=WMouseX
nmy.w=WMouseY
If nmx<>omx OR nmy<>omy ;if mouse position has changed...
Select Joyb(0)
Case 1 ;if left mouse button
;To make the rotation relative to the mouse starting point (when the user
;pressed the left button) and not to its absolute position on the screen,
;I subtract the starting position omx from the new one nmx and then I
;multiply the resulting quantity with the fraction of 360 deg represented
;by one pixel.
anglez.f=(nmx-omx)*((2*Pi)/#WIDTH) ;rot around third coord (z)
anglex.f=(nmy-omy)*((2*Pi)/#HEIGHT) ;rot around first coord (x)
For k.w=0 To #NUMPTS-1
RotZX{anglez,anglex,k} ;rotates all vertices
Next k
DrawAll{} ;and then draw the entire poligon
Case 2 ;if right mouse button
;The scaling factor scalefac depends on the mouse distance from the origin:
;this is why I compute the radius (squared) r2 of a circle centered in the
;origin of the axis (the center of the screen). Here also, as I did before
;for the rotation part, I use the mouse position relative to the starting
;point.
r2.w=((nmx-#WIDTH/2)^2+(nmy-#HEIGHT/2)^2)-((omx-#WIDTH/2)^2+(omy-#HEIGHT/2)^2)
If r2>0
scalefac.f=1.1
Else
scalefac.f=0.9
EndIf
For k.w=0 To #NUMPTS-1 ;scale all vertices
vertex(k)\x=vertex(k)\x*scalefac
vertex(k)\y=vertex(k)\y*scalefac
vertex(k)\z=vertex(k)\z*scalefac
Next k
DrawAll{} ;and draw the entire poligon
End Select
omx=nmx
omy=nmy
EndIf
Until Joyb(0)=0 ;until user releases the mouse button
Goto restart
bye:
Free Window 0
Free Screen 0
End
ptdat: ;vertex coords (x, y, z)
Data.f -100,-100,-100
Data.f -100,100,-100
Data.f 100,100,-100
Data.f 100,-100,-100
Data.f -100,-100,100
Data.f -100,100,100
Data.f 100,100,100
Data.f 100,-100,100
edgedat: ;edge=(start_vertex, end_vertex)
Data.w 0,1,1,2,2,3,3,0,4,5,5,6,6,7,7,4,0,4,1,5,2,6,3,7