PROGRAMMI

LE ORIGINI DI UN FAMOSO PROGRAMMA:
ROT

Vediamo insieme la versione Basic di un programma del package Aegis Draw


di Alessandro Prandi


   Siamo lieti di presentarvi il capostipite dei programmi dedicati alla grafica tridimensionale per Amiga, esso nasce dalla strepitosa mente di Colin French, autore anche delle versioni successive create per il package Aegis Draw. Senz'altro è interessante notare come questo Editor sia nato ancora una volta in un linguaggio tanto criticato, ma poplarissimo come il Basic. Se vi state muovendo nella grafica tridimensionale del vostro Amiga provate questo "programmino" Basic. Con ROT, questo è il nome del programma, potete creare un oggetto composto da 95 punti e da 95 poligoni colorati. Tutto quello che vi necessita sono almeno 512K ed un mouse.
   Questo programma richiede molta memoria per cui se dal vostro Workbench non vi risultano almeno 380.000 byte liberi non provate nemmeno a farlo girare. Ricordate che il file "GRAPHICS.BMAP" che si trova nel disco dell'AmigaBasic deve stare sullo stesso dischetto di ROT, spicciatevi dunque a trasferire questo file. 

Diamo una rapida occhiata al programma

   In ROT l'oggetto è composto da poligoni, come le facce di un cubo. Il poligono viene generato selezionando i punti usati per i suoi vertici. Ogni poligono deve avere almeno tre vertici ma non più di sei. Ogni poligono può avere un differente colore, ed una accurata scelta delle tonalità può produrre dei interessanti effetti d'ombra. Dopo che è stato creato un'oggetto viene disegnata una serie di riquadri (frame) ciascuno contenente l'oggetto in differenti posizioni. Questi riquadri sono catturati come immagini bitmap. Se noi diamo una rapida sequenza a questa serie di immagini otteremo un'azione animata. In ogni frame dovete specificare la rotazione e lo spostamento dell'oggetto lungo le tre assi X, Y e Z. Ad esempio incrementando la rotazione di un frame attorno all'asse Y otterrete un effetto trottola all'esecuzione dell'animazione.

L'Editing dell'oggetto

   Quando Rot viene lanciato per la prima volta compare lo schermo Editor di oggetti, da qui potete passare all'Editor Azione clickando il primo termine del menu Azione. Per ritornare indietro portarsi sul primo termine del menu Oggetto. Alla sinistra dello schermo Editor ci sono tre sezioni dedicate alla posizione dell'oggetto rispetto alle tre assi. Visto dall'alto, di lato e di fronte, Per vedere come questi si incontrano tra loro immaginate di proiettare la figura frontale e quella dall'alto finché i loro angoli non si toccano. Ora avete un mezzo cubo che circonda il vostro oggetto. Ogni rotazione applicata all'oggetto avverrà intorno al centro di questo cubo. Nei tre riquadri della parte sinistra dello schermo c'è visualizzato un cerchio che mette in evidenza il punto selezionato al momento. Molte volte due punti appaiono uno sopra l'altro, controllate che la posizione del punto sia quella realmente da voi voluta. 
   Un punto con tutte tre le cordinanate settate a zero viene considerato non esistente e quindi non viene visualizzato. Clickando in uno dei tre riquadri si cambieranno due delle tre cordinate del punto. La modifica delle due cordinate dipende dal riquadro in cui si setta il punto. Gli angoli del corrente poligono selezionato vengono evidenziati con il colore arancio. Ovviamente se non è stato scelto alcun vertice, il poligono non esiste e pertanto non verrà evidenziato niente.
   Nella parte in alto a destra dello schermo di editing dell'oggetto troviamo una serie di controlli per la gestione dei punti. In alto c'è la selezione del punto da modificare, premete il tasto del mouse quando siete posizionati sulle relative frecce e per portarvi al Punto seguente o precedente. Se volete uno spostamento più rapido posizionatevi direttamente nella barra tra le due frecce e clickate con il tasto sinistro. Per settare rapidamente tutte le cordinate al punto zero optate per la casella 'PUNTO ZERO'. In questo modo il punto diventa inesistente, fate quindi attenzione che nessun vertice dei vostri poligoni non usi questo valore come vertice.
   Più in basso troviamo un altro set di controllo per l'edit dei poligoni. Per creare un poligono bisogna selezionare i punti che ne formano i vertici. Usate l'opzione per la scelta del punto, questo verrà evidenziato nei vari riquadri, quindi premete su ' + il Pt prec.' per gestire il punto come vertice. Un poligono può avere dai tre ai sei vertici, gli angoli vengono evidenziati nei vari riquadri. Ricordate che è molto importante la sequenza nella quale selezionate i vari punti. Andate in una direzione lungo il perimetro del poligono, se vedete che gli angoli si incrociano allora saprete che i punti non sono in ordine. Selezionate 'CLR ULTIMO PT' per ripercorrere la lista dei vertici finché non avrete eliminato il problema. Per togliere l'intero poligono, non i punti, optate per 'CLR POLIGONO'.
   Nella parte inferiore destra dello schermo c'è la Palette dei colori. Il colore con il quale verrà disegnato il poligono è evidenziato da un rettangolo arancione. Per cambiare colore vi sarà sufficiente posizionarvi sul colore scelto e clickarlo. Passiamo ora alle selezioni possibili da menu. Nel menu oggetto ci sono quattro voci, EDITOR OGGETTO, CARICA OGGETTO, SALVA OGGETTO, NUOVO OGGETTO. Lasciamo per ora la prima, e quindi noterete che ci sono le possibilità di salvare una figura editata con ROT e quindi ricaricarla oppure si può cancellare l'oggetto al momento disegnato e ricominciare da capo. Ricordate che gli 'oggetti' vengono salvati con il suffisso .ROTOBJ appeso alla fine del nome del file. Quando caricate i file oggetto non servirà scrivere .ROTOBJ alla fine del nome. Se dimenticate il nome di un file potete scegliere la voce 'FILES' nel menu Rot e cercare di individuarlo mentre la lista scorre sullo schermo.

L’Editing dell’Azione

   Selezionate il primo termine del menu Azione per passare allo schermo di editing dell'azione. La parte superiore e' riservata alla rappresentazione delle figure mentre in basso troviamo una serie di parametri di controllo. A sinistra c'è la selezione del frame, posizionandosi sopra le relative frecce si passerà da un frame all'altro e scegliere con quale lavorare. In ogni frame si possono modificare le rotazioni dell'oggetto rispetto alle tre assi. Per cambiare un valore in particolare basterà clickare sopra lo '0' relativo ed immetere il numero desiderato. I valori immessi vengono controllati dal programma per assicurarsi che essi siano compresi in valori accettabili. Dopo aver inserito i valori una freccia arrancione vi indica la scritta 'Rifà Frame' per comunicarvi che il frame deve essere ridisegnato. 
   Clickando in 'Rifà Frame' si ordina al programma di ricalcolare l'immagine nel frame in modo che corrisponda ai valori da voi indicati. A questo punto potete passare al frame successivo e ripetere l'operarione, e continuate sinché tutti i 12 frame sono stati ridisegnati. Se ritornate allo schermo dell'oggetto e ridisegnate un'altra figura e quindi la riportate nello schermo delllAzione essa non comparirà nei vari frame. Per aggiornarli dovrete selezionare ciascun frame e quindi clickare su 'Rifà frame'; per evitare questa noiosa procedura potete selezionare 'Rifà tutto' ed il programma penserà a completare l'intera sequenza. Dopo aver disegnato tutti e dodici i frame premete il tasto del mouse su 'Play' per vedere l'animazione. Regolate la velocità di esecuzione agendo sull'indicatore 'Tempo'. Per rivedere la sequenza animata all'infinito selezionate 'Ripete ciclo' nel menu azione, un segno vicino alla scritta comparirà quando questa funzione sarà attivata.
   Un'altra opzione del menu Azione è quella di 'Ripete ciclo inverso'. Questa voce sta ad indicare che l'animazione partirà dal frame l e continuerà fino al 12 e poi ritornerà indietro di nuovo all'l . Questi ultimi due comandi possono essere usati anche contemporaneamente. Per fermare una sequenza animata selezionate 'Stop'. Gli altri termini contenuti nel menu Azione servono a salvare l'azione dell'oggetto, a caricarla da disco ed a cancellare l'azione corrente. Il file che viene salvato contiene solo i fattori necessari per disegnare il frame. Quando caricate un'azione selezionate 'Rifà tutto' per rigenerare i frame. Essi non vengono salvati perché occuperebero all'incirca 109K. L'operazione richiederebbe più di sei minuti per il caricamento o il save tramite l'AmigaBasic. Speriamo che i comandi BLOAD e BSAVE arrivino presto anche nel Basic Amiga. L'ultima voce del menu Azione si chiama 'Calcolo tra ...' ed ha un ruolo molto importante. Essa calcola e disegna i frame che si trovano tra due figure da voi scelte. Ad esempio se stabilite le coordinate e l'incremento di un oggetto nel frame 1 e nel frame 12 e quindi scegliete questa opzione il programma calcolera' per voi tutti i frame che vanno dal 1 al 12. Settate la rotazione su Y del frame 1 a 90 gradi e quella del frame 7 a 180. Poiché desiderate avere sei figure intermedie che partano da 90 e finiscano con 180 gradi ogni figura ruoterà di 15 gradi rispetto all'asse Y. Naturalmente potete ottenere lo stesso risultato disegnando frame per frame manualmente mentre con 'Calcolo tra ...' tutta I'operarione viene condotta automaticamente. Ricordate che il programma sceglie sempre la direzione della rotazione in modo da muovere l'oggetto attraverso l'angolo più piccolo possibile. Se settate il frame iniziale a zero gradi e quello finale a 270 gradi, l'oggetto ruotera di -90 gradi e non di +270. 

Difetti del programma

   Alla prima esecuzione delle routine AmigaBasic del programma avrete l'impressione che il computer abbia fatto tilt, visto il tempo che passa dal run all'esecuzione vera e propria. Portate solo un po' di pazienza prima di spegnere definitivamente la macchina. Infatti la seconda volta che una routine viene adoperata i tempi diventano quelli normali. Ci sono alcune parti  di ROT, come la routine di caricamento dei file, che sono così lente da farvi sospettare addirittura il peggio. Quando eseguite un'animazione con attivato il ciclo inverso può succedere che ci sia qualche sfarfallamento dell'immagine. Questo diffetto può essere causato dal basic che disegna le immagini con la bitmap nel mezzo della scansione dello schermo. Talvolta cambiare i colori di un oggetto aiuta a minimizzare questo inconveniente.
   Gli incrementi di X e Y non sono delle vere e proprie trasformazioni tridimensionali ma solo degli indicatori che servono al disegno del frame sullo schermo. Questa riduzione è necessaria per ridurre le misure delle immagini sullo schermo e principalmente per limitare la memoria richiesta per depositarle. Durante l'animazione il secondo frame si sovrappone al primo, il terzo al secondo e così via, in tal modo viene effettuata la cancellazione dei frame precedenti. Se usate un incremento troppo grande lungo l'asse X di un oggetto piuttosto largo allora noterete che parti di esso non vengono cancellate perfettamente. A questo punto o costruite un'oggetto più piccolo o diminuite l'incremento in X.
   Il programma così come lo trovate occupa tutti i 25K di Basic disponibili e molti commenti sono stati tolti dal listato per non andare oltre i limiti consentiti. Purtroppo nen c'è nemmeno lo spazio per un controllo di eventuali errori durante l'I/O del disco, per cui dovete conoscere perfettamente il nome del file da caricare, per una verifica potete usare l'opzione 'Files' nel menu ROT. 
 
 
 

GOTO main:
intro:
PRINT "                R O T               "
PRINT "                                       "
PRINT "---------------------------------------"
PRINT "                                       "
PRINT "    Note: le routine in  AmigaBasic"
PRINT "    sono molto lente la prima volta"
PRINT "    che vengono lette."
PRINT "    Siate pazienti se ROT vi sembra" 
PRINT "    troppo stressante."
RETURN

main:
  IF FRE(0)<100000& THEN CLEAR,150000&
  GOSUB init
  quit=0
  WHILE NOT(quit)
    b=MOUSE(0)
    x=MOUSE(1)
    y=MOUSE(2)
    IF b<>0 THEN
      IF objscr THEN GOSUB edobj
      IF actscr THEN GOSUB edact
    END IF
    m=MENU(0)
    i=MENU(1)
    IF m<>0 THEN GOSUB menuchk
    z$=INKEY$
    IF z$<>"" THEN GOSUB keychk
  WEND
  GOSUB cleanup
END

menuchk:
  ON m GOSUB rotmenu, objmenu, actmenu
RETURN
rotmenu:
  IF i=1 THEN GOSUB listfiles
  IF i=3 THEN quit=(-1)
  RETURN
 
objmenu:
  IF i=1 AND objscr=0 THEN
    objscr=(-1)
    actscr=0
    MENU 2,1,2
    MENU 2,2,1
    MENU 2,3,1
    MENU 2,4,1
    MENU 3,1,1
    MENU 3,2,0
    MENU 3,3,0
    MENU 3,4,0
    MENU 3,6,0
    MENU 3,7,0
    MENU 3,8,0
    GOSUB drw.objscr
  END IF
  IF i=2 THEN GOSUB loadobj
  IF i=3 THEN GOSUB saveobj
  IF i=4 THEN GOSUB newobj
RETURN

actmenu:
  IF i=1 AND actscr=0 THEN
    actscr=(-1)
    objscr=0
    MENU 3,1,2
    MENU 3,2,1
    MENU 3,3,1
    MENU 3,4,1
    MENU 3,6,1+ABS(actrpt)
    MENU 3,7,1+ABS(actrev)
    MENU 3,8,1
    MENU 2,1,1
    MENU 2,2,0
    MENU 2,3,0
    MENU 2,4,0
    FOR n=1 TO 12
      frmchg(n)=1
    NEXT
    GOSUB drw.actscr
  END IF
  IF i=2 THEN GOSUB loadact
  IF i=3 THEN GOSUB saveact
  IF i=4 THEN GOSUB newact
  IF i=6 THEN
    actrpt=NOT(actrpt)
    MENU 3,6,1+ABS(actrpt)
  END IF
  IF i=7 THEN
    actrev=NOT(actrev)
    MENU 3,7,1+ABS(actrev)
  END IF
  IF i=8 THEN GOSUB calctween
RETURN

listfiles:
  s$="File in:"
  GOSUB drw.filereq
  s$="DF0:"
  GOSUB getstring2
  IF s$<>"c" AND s$<>"C" AND s$<>"" THEN
    CLS
    FILES s$
    PRINT
    GOSUB click.continue
    IF objscr<>0 THEN
      GOSUB drw.objscr 
    ELSE
      GOSUB drw.actscr
    END IF
    GOSUB nobut
  END IF
RETURN

loadobj:
  s$="Load:" 
  GOSUB drw.filereq
  GOSUB getstring
  IF s$<>"c" AND s$<>"C" AND s$<>"" THEN
    s$=s$+".ROTOBJ"
    OPEN s$ FOR INPUT AS #1
    FOR n=0 TO 95
      FOR n2=0 TO 3
        INPUT#1,pt(n,n2)
      NEXT
    NEXT 
    FOR n=0 TO 95
      FOR n2=0 TO 6
        INPUT#1,poly(n,n2)
      NEXT
    NEXT
    FOR n=0 TO 95
      INPUT#1,polyclr(n)
    NEXT
    FOR n=0 TO 95
      INPUT#1,vrt(n)
    NEXT
    CLOSE #1
    pt=1
    poly=1
  END IF
  GOSUB drw.objscr
RETURN

saveobj:
  s$="Save:"
  GOSUB drw.filereq
  GOSUB getstring
  IF s$<>"c" AND s$<>"C" AND s$<>"" THEN
    s$=s$+".ROTOBJ"
    OPEN s$ FOR OUTPUT AS #1
    FOR n=0 TO 95
      FOR n2=0 TO 3
        PRINT#1,pt(n,n2);
      NEXT
    NEXT
    FOR n=0 TO maxpoly
      FOR n2=0 TO 6
        PRINT#1,poly(n,n2);
      NEXT
    NEXT
    FOR n=0 TO maxpoly
      PRINT#1,polyclr(n);
    NEXT
    FOR n=0 TO maxpoly
      PRINT#1,vrt(n);
    NEXT
    CLOSE #1
  END IF
  GOSUB drw.objscr
RETURN

newobj:
  s$="   Cancello l'oggetto?"
  GOSUB you.sure
  IF sure THEN
    FOR n=0 TO maxpt
      FOR n2=0 TO 2
        pt(n,n2)=0
      NEXT
    NEXT
    FOR n=0 TO maxpoly
      FOR n2=0 TO 6
        poly(n,n2)=0
      NEXT
      polyclr(n)=0
      vrt(n)=0
    NEXT
    pt=1
    poly=1
  END IF
  GOSUB drw.objscr
RETURN
 
loadact:
  s$="Load:"
  GOSUB drw.filereq
  GOSUB getstring
  IF s$<>"c" AND s$<>"C" AND s$<>"" THEN
    s$=s$+".ROTACT"
    OPEN s$ FOR INPUT AS #1
    FOR n=1 TO 12
      INPUT#1,xrot(n),yrot(n),zrot(n)
      INPUT#1,xtran(n),ytran(n),ztran(n)
    NEXT
    INPUT#1,spd,actrpt,actrev
    CLOSE#1
    frm=1
    FOR n=1 TO 12
      frmchg(n)=1
    NEXT
    GOSUB drw.frmnum
    GOSUB drw.spdnum
    GOSUB drw.factors
    GOSUB drw.update
    MENU 3,6,1+ABS(actrpt)
    MENU 3,7,1+ABS(actrev)
  END IF
  LINE (0,0)-(311,131),0,bf
  GOSUB putfrm
RETURN

saveact:
  s$="Save:"
  GOSUB drw.filereq
  GOSUB getstring
  IF s$<>"c" AND s$<>"C" AND s$<>"" THEN
    s$=s$+".ROTACT"
    OPEN s$ FOR OUTPUT AS #1
    FOR n=1 TO 12
      PRINT#1,xrot(n);yrot(n);zrot(n);
      PRINT#1,xtran(n);ytran(n);ztran(n);
    NEXT
    PRINT#1,spd;actrpt;actrev;
    CLOSE #1
  END IF
  LINE(0,0)-(311,131),0,bf
  GOSUB putfrm
RETURN

newact:
  s$="   Cancello l'azione?"
  GOSUB you.sure
  IF sure THEN
    FOR n=0 TO 12
      xrot(n)=0:yrot(n)=0:zrot(n)=0
      xtran(n)=0:ytran(n)=0:ztran(n)=0
    NEXT
    spd=20
    actrpt=0
    actrev=0
    MENU 3,6,1
    MENU 3,7,1
    frm=1
  END IF
  GOSUB drw.actscr
RETURN

calctween:
  GOSUB gettween
  IF stfrm>endfrm THEN SWAP stfrm,endfrm
  stp=endfrm-stfrm
  LINE(0,0)-(311,131),0,bf
  IF stp>1 THEN
    xrot=xrot(endfrm)-xrot(stfrm)
    IF xrot>180 THEN xrot=(360-xrot)*(-1)
    IF xrot<-180 THEN xrot=xrot+360
    stpxrot=xrot/stp
    yrot=yrot(endfrm)-yrot(stfrm)
    IF yrot>180 THEN yrot=(360-yrot)*(-1)
    IF yrot<-180 THEN yrot=yrot+360
    stpyrot=yrot/stp
    zrot=zrot(endfrm)-zrot(stfrm)
    IF zrot>180 THEN zrot=(360-zrot)*(-1)
    IF zrot<-180 THEN zrot=zrot+360
    stpzrot=zrot/stp
    xtran=xtran(endfrm)-xtran(stfrm)
    stpxtran=xtran/stp
    ytran=ytran(endfrm)-ytran(stfrm)
    stpytran=ytran/stp
    ztran=ztran(endfrm)-ztran(stfrm)
    stpztran=ztran/stp
    FOR frm=stfrm+1 TO endfrm-1
      n=frm-stfrm
      xrot(frm)=xrot(stfrm)+INT(stpxrot*n)
      IF xrot(frm)>359 THEN xrot(frm)=xrot(frm)-360
      IF xrot(frm)<0 THEN xrot(frm)=xrot(frm)+360
      yrot(frm)=yrot(stfrm)+INT(stpyrot*n)
      IF yrot(frm)>359 THEN yrot(frm)=yrot(frm)-360
      IF yrot(frm)<0 THEN yrot(frm)=yrot(frm)+360
      zrot(frm)=zrot(stfrm)+INT(stpzrot*n)
      IF zrot(frm)>359 THEN zrot(frm)=zrot(frm)-360
      IF zrot(frm)<0 THEN zrot(frm)=zrot(frm)+360
      xtran(frm)=xtran(stfrm)+INT(stpxtran*n)
      ytran(frm)=ytran(stfrm)+INT(stpytran*n)
      ztran(frm)=ztran(stfrm)+INT(stpztran*n)
      GOSUB drw.frmnum
      GOSUB drw.factors
      GOSUB high.redraw
      GOSUB drw.frame
      GOSUB getfrm
      frmchg(frm)=0
      GOSUB drw.update
      GOSUB unhigh.redraw
    NEXT
    frm=stfrm
    GOSUB drw.frmnum
    GOSUB drw.factors
  END IF
  LINE(0,0)-(311,131),0,bf
  GOSUB putfrm
RETURN

gettween:
  GOSUB drw.tweenreq
  maxchar=2
  xt=188:yt=74
  GOSUB getstring
  stfrm=VAL(s$)
  IF stfrm<1 THEN stfrm=1
  IF stfrm>12 THEN stfrm=12
  yt=82
  GOSUB getstring
  endfrm=VAL(s$)
  IF endfrm<1 THEN endfrm=1
  IF endfrm>12 THEN endfrm=12
RETURN

drw.tweenreq:
  LINE(58,48)-(254,92),0,bf
  LINE(60,50)-(252,90),3,bf
  LINE(61,51)-(251,89),2,bf
  CALL move&(rp&,76,66)
  PRINT "Calcolo intermedio"
  CALL move&(rp&,92,74)
  PRINT " Dal Frame:"
  CALL move&(rp&,108,82)
  PRINT "Al Frame:"
RETURN

drw.filereq:
  LINE(50,48)-(262,92),0,bf
  LINE(52,50)-(260,90),3,bf
  LINE(53,51)-(259,89),2,bf
  CALL move&(rp&,60,66)
  PRINT "     File Requestor"
    IF s$<>"File in:" THEN
      CALL move&(rp&,92,74)
      PRINT "('C' per uscire)"
    END IF
  CALL move&(rp&,60,82)
  PRINT s$
  xt=68+LEN(s$)*8
  yt=82
  maxchar=23-LEN(s$)
RETURN

you.sure:
  GOSUB drw.surereq
  GOSUB nobut
  answer=0
  WHILE NOT(answer)
    b=MOUSE(0)
    x=MOUSE(1)
    y=MOUSE(2)
    IF b<>0 THEN
      IF y>80 AND y<92 THEN
        IF x>75 AND x<127 THEN
          sure=(-1)
          answer=(-1)
        END IF
        IF x>187 AND x<239 THEN
          sure=0
          answer=(-1)
        END IF
      END IF
      GOSUB nobut
    END IF
  WEND
RETURN

drw.surereq:
  LINE(43,48)-(270,100),0,bf
  LINE(45,50)-(268,98),3,bf
  LINE(46,51)-(267,97),2,bf
  CALL move&(rp&,53,66)
  PRINT "     Siete sicuri!!!"
  CALL move&(rp&,53,74)
  PRINT LEFT$(s$,24)
  LINE(75,80)-(127,92),1,b
  LINE(187,80)-(239,92),1,b
  CALL move&(rp&,93,89)
  PRINT "SI"
  CALL move&(rp&,190,89)
  PRINT "  NO"
RETURN

keychk:
  RETURN

edobj:
  IF x>189 AND x<306 THEN
    IF y>24 AND y<32 THEN GOSUB ptslider
    IF y>82 AND y<90 THEN GOSUB polyslider
    IF y>36 AND y<48 THEN GOSUB zeropt
    IF y>94 AND y<106 THEN GOSUB addpt
    IF y>110 AND y<122 THEN GOSUB undopt
    IF y>126 AND y<138 THEN GOSUB delpoly
    IF y>142 AND y<171 THEN GOSUB selclr
  END IF
  IF x>3 AND x<82 AND y>3 AND y<82 THEN
    pt(pt,2)=(x-vx1)*(-1)
    pt(pt,0)=(y-vy1)*(-1)
    GOSUB drw.views
    GOSUB nobut
  END IF
  IF x>3 AND x<82 AND y>96 AND y<175 THEN
    pt(pt,2)=(x-vx2)*(-1)
    pt(pt,1)=(y-vy2)*(-1)
    GOSUB drw.views
    GOSUB nobut
  END IF
  IF x>97 AND x<176 AND y>96 AND y<175 THEN
    pt(pt,0)=x-vx3
    pt(pt,1)=(y-vy3)*(-1)
    GOSUB drw.views
    GOSUB nobut
  END IF
RETURN

zeropt:
  p=pt
  GOSUB unhigh.pt
  GOSUB erase.pt
  pt(pt,0)=0
  pt(pt,1)=0
  pt(pt,2)=0
  GOSUB drw.pt
  GOSUB high.pt
RETURN

addpt:
  IF vrt(poly)>5 THEN BEEP:RETURN
  IF pt(pt,0)=0 AND pt(pt,1)=0 AND pt(pt,2)=0 THEN RETURN
  vrt(poly)=vrt(poly)+1
  poly(poly,vrt(poly))=pt
  GOSUB drw.views
  GOSUB nobut
RETURN

undopt:
  IF vrt(poly)>0 THEN
    poly(poly,vrt(poly))=0
    vrt(poly)=vrt(poly)-1
  END IF
  GOSUB drw.views
  GOSUB nobut
RETURN

delpoly:
  IF vrt(poly)>0 THEN
    c=polyclr(poly)
    GOSUB unhigh.clr
    FOR n=0 TO vrt(poly)
      poly(poly,n)=0
    NEXT
    vrt(poly)=0
    polyclr(poly)=0
    c=polyclr(poly)
    GOSUB high.clr
  END IF
  GOSUB drw.views
  GOSUB nobut
RETURN

selclr:
  IF x>191 AND x<304 THEN
    c=INT((x-192)/14)+INT((y-143)/7)*8
    IF c<>polyclr(poly) THEN
      GOSUB high.clr
      SWAP c,polyclr(poly)
      GOSUB unhigh.clr
    END IF
  END IF
RETURN

drw.views:
  GOSUB erase.views
  p=pt
  GOSUB high.pt
  FOR p=1 TO maxpt
    GOSUB drw.pt
  NEXT
  p=pt
  t=poly
  FOR poly=1 TO maxpoly
    GOSUB drw.poly
  NEXT
  poly=t
  GOSUB high.poly
RETURN

erase.views:
  LINE(2,2)-(83,83),0,bf
  LINE(2,95)-(83,176),0,bf
  LINE(96,95)-(177,176),0,bf
RETURN

drw.pt:
  IF pt(p,0)<>0 OR pt(p,1)<>0 OR pt(p,2)<>0 THEN
    PSET(vx1-pt(p,2),vy1-pt(p,0))
    PSET(vx2-pt(p,2),vy2-pt(p,1))
    PSET(vx3+pt(p,0),vy3-pt(p,1))
  END IF
RETURN

erase.pt:
  COLOR 0
  GOSUB drw.pt
  COLOR 1
RETURN

high.pt:
  CIRCLE(vx1-pt(p,2),vy1-pt(p,0)),2,2
  CIRCLE(vx2-pt(p,2),vy2-pt(p,1)),2,2
  CIRCLE(vx3+pt(p,0),vy3-pt(p,1)),2,2
RETURN

unhigh.pt:
  CIRCLE(vx1-pt(p,2),vy1-pt(p,0)),2,0
  CIRCLE(vx2-pt(p,2),vy2-pt(p,1)),2,0
  CIRCLE(vx3+pt(p,0),vy3-pt(p,1)),2,0
RETURN

drw.poly:

 IF vrt(poly)>0 THEN
    PSET(vx1-pt(poly(poly,1),2),vy1-pt(poly(poly,1),0))
    PSET(vx2-pt(poly(poly,1),2),vy2-pt(poly(poly,1),1))
    PSET(vx3+pt(poly(poly,1),0),vy3-pt(poly(poly,1),1))
    IF vrt(poly)>1 THEN
      FOR n=2 TO vrt(poly)
        LINE(vx1-pt(poly(poly,n-1),2),vy1-pt(poly(poly,n-1),0)) -(vx1-pt(poly(poly,n),2),vy1-pt(poly(poly,n),0))
        LINE(vx2-pt(poly(poly,n-1),2),vy2-pt(poly(poly,n-1),1)) -(vx2-pt(poly(poly,n),2),vy2-pt(poly(poly,n),1))
        LINE(vx3+pt(poly(poly,n-1),0),vy3-pt(poly(poly,n-1),1)) -(vx3+pt(poly(poly,n),0),vy3-pt(poly(poly,n),1))
      NEXT
      LINE(vx1-pt(poly(poly,n-1),2),vy1-pt(poly(poly,n-1),0)) -(vx1-pt(poly(poly,1),2),vy1-pt(poly(poly,1),0))
      LINE(vx2-pt(poly(poly,n-1),2),vy2-pt(poly(poly,n-1),1)) -(vx2-pt(poly(poly,1),2),vy2-pt(poly(poly,1),1))
      LINE(vx3+pt(poly(poly,n-1),0),vy3-pt(poly(poly,n-1),1)) -(vx3+pt(poly(poly,1),0),vy3-pt(poly(poly,1),1))
    END IF
  END IF
RETURN

erase.poly:
  COLOR 3
  GOSUB drw.poly
  COLOR 1
RETURN

high.poly:
  COLOR 3
  GOSUB drw.poly
  RETURN
 
unhigh.poly:
  GOSUB drw.poly
RETURN

high.clr:
  y2=INT(c/8)
  x2=c-y2*8
  LINE(192+x2*14,143+y2*7)-(205+x2*14,149+y2*7),3,b
RETURN

unhigh.clr: 
  y2=INT(c/8)
  x2=c-y2*8
  LINE(192+x2*14,143+y2*7)-(205+x2*14,149+y2*7),0,b
RETURN

ptslider:
  IF x<197 THEN
    p=pt
    GOSUB unhigh.pt
    pt=pt-1
    IF pt<1 THEN pt=1
    p=pt
    GOSUB drw.ptnum
    GOSUB high.pt
    GOSUB nobut
  ELSEIF x>298 THEN
    p=pt
    GOSUB unhigh.pt
    pt=pt+1
    IF pt>maxpt THEN pt=maxpt
    p=pt
    GOSUB drw.ptnum
    GOSUB high.pt
    GOSUB nobut
  ELSEIF x>199 AND x<295 THEN
    p=pt
    GOSUB unhigh.pt
    pt=x-199
    p=pt
    GOSUB drw.ptnum
    GOSUB high.pt
    GOSUB nobut
  END IF
RETURN

polyslider:
  IF x<197 THEN
    c=polyclr(poly)
    GOSUB unhigh.clr
    GOSUB unhigh.poly
    poly=poly-1
    IF poly<1 THEN poly=1
    GOSUB drw.polynum
    GOSUB high.poly
    c=polyclr(poly)
    GOSUB high.clr
    GOSUB nobut
  ELSEIF x>298 THEN
    c=polyclr(poly)
    GOSUB unhigh.clr
    GOSUB unhigh.poly
    poly=poly+1
    IF poly>maxpoly THEN poly=maxpoly
    GOSUB drw.polynum
    GOSUB high.poly
    c=polyclr(poly)
    GOSUB high.clr
    GOSUB nobut
  ELSEIF x>199 AND x<295 THEN
    c=polyclr(poly)
    GOSUB unhigh.clr
    GOSUB unhigh.poly
    poly=x-199
    GOSUB drw.polynum
    GOSUB high.poly
    c=polyclr(poly)
    GOSUB high.clr
    GOSUB nobut
  END IF
RETURN

edact:
  IF x>4 AND x<122 AND y>150 AND y<158 THEN GOSUB frmslider:RETURN
  IF x>40 AND x<250 AND y>136 AND y<148 THEN GOSUB drw.frm:RETURN
  IF x>140 AND x<250 AND y>152 AND y<164 THEN GOSUB drw.allfrm:RETURN
  IF x>260 AND x<306 AND y>136 AND y<148 THEN GOSUB playbut:RETURN
  IF x>260 AND x<306 AND y>152 AND y<164 THEN GOSUB stopbut:RETURN
  IF x>263 AND x<303 AND y>178 AND y<183 THEN GOSUB spdslider:RETURN
  IF y>168 AND y<176 THEN
    IF x>92 AND x<140 THEN GOSUB mod.xrot:RETURN
    IF x>147 AND x<196 THEN GOSUB mod.yrot:RETURN
    IF x>203 AND x<252 THEN GOSUB mod.zrot:RETURN
  END IF
  IF y>177 AND y<185 THEN
    IF x>92 AND x<140 THEN GOSUB mod.xtran:RETURN
    IF x>147 AND x<196 THEN GOSUB mod.ytran:RETURN
    IF x>203 AND x<252 THEN GOSUB mod.ztran:RETURN
  END IF
RETURN

frmslider:
  IF x<12 THEN
    frm=frm-1
    IF frm<1 THEN frm=1
    GOSUB drw.frmnum
    GOSUB drw.update
    GOSUB drw.factors
    GOSUB putfrm
    GOSUB nobut
  ELSEIF x>114 THEN
    frm=frm+1
    IF frm>12 THEN frm=12
    GOSUB drw.frmnum
    GOSUB drw.update
    GOSUB drw.factors
    GOSUB putfrm
    GOSUB nobut
  ELSEIF x>16 AND x<110 THEN
    frm=INT((x-16)/8)+1
    GOSUB drw.frmnum
    GOSUB drw.update
    LINE(0,0)-(311,131),0,bf
    GOSUB drw.factors
    GOSUB putfrm
    GOSUB nobut
  END IF
RETURN

drw.frm:
  GOSUB high.redraw
  GOSUB drw.frame
  GOSUB getfrm
  frmchg(frm)=0
  GOSUB drw.update
  GOSUB unhigh.redraw
  GOSUB nobut
RETURN

drw.allfrm:
  GOSUB high.redraw2
  tfrm=frm
  FOR frm=1 TO 12
    GOSUB drw.frmnum
    GOSUB drw.factors
    GOSUB drw.frame
    GOSUB getfrm
    frmchg(frm)=0
    GOSUB drw.update
  NEXT
  frm=tfrm
  GOSUB drw.frmnum
  GOSUB drw.factors
  GOSUB putfrm
  GOSUB unhigh.redraw2
  GOSUB nobut
RETURN

playbut:
  GOSUB high.play
  GOSUB unhigh.stop
  GOSUB freeze.menu
  frminc=1
  clickstop=0
  WHILE NOT(clickstop)
    frm=frm+frminc
    IF frm>12 THEN
      IF actrev THEN
        frm=11
        frminc=(-1)
      ELSEIF actrpt THEN
        frm=1
      ELSE
        frm=1
        clickstop=(-1)
      END IF
    END IF
    IF frm<1 THEN
      IF actrpt THEN
        frm=2
        frminc=1
      ELSE
        frm=1
        clickstop=(-1)
      END IF
    END IF
    GOSUB putfrm
    GOSUB drw.frmnum
    FOR n=0 TO 39-spd
      b=MOUSE(0)
      x=MOUSE(1)
      y=MOUSE(2)
      IF b<>0 THEN
        IF x>260 AND x<306 AND y>152 AND y<164 THEN 
          clickstop=(-1)
          n=39-spd
        END IF 
        IF x>263 AND x<303 AND y>178 AND y<183 THEN 
          spd=x-263
          GOSUB drw.spdnum
        END IF
      END IF
    NEXT 
  WEND 
  GOSUB drw.factors
  GOSUB drw.update
  GOSUB unhigh.play
  GOSUB high.stop
  GOSUB unfreeze.menu
  GOSUB nobut
RETURN

stopbut:
RETURN

spdslider:
  spd=x-263
  GOSUB drw.spdnum
RETURN

mod.xrot:
  s$=STR$(xrot(frm))
  xt=108:yt=175
  maxchar=4
  numonly=1
  GOSUB getstring2
  xrot(frm)=VAL(s$)
  xrot(frm)=xrot(frm) MOD 360
  IF xrot(frm)<0 THEN xrot(frm)=xrot(frm)+360
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

mod.yrot:
  s$=STR$(yrot(frm))
  xt=164:yt=175
  maxchar=4
  numonly=1
  GOSUB getstring2
  yrot(frm)=VAL(s$)
  yrot(frm)=yrot(frm) MOD 360
  IF yrot(frm)<0 THEN yrot(frm)=yrot(frm)+360
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

mod.zrot:
  s$=STR$(zrot(frm))
  xt=220:yt=175
  maxchar=4
  numonly=1
  GOSUB getstring2
  zrot(frm)=VAL(s$)
  zrot(frm)=zrot(frm) MOD 360
  IF zrot(frm)<0 THEN zrot(frm)=zrot(frm)+360
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

mod.xtran:
  s$=STR$(xtran(frm))
  xt=108:yt=184
  maxchar=4
  numonly=1
  GOSUB getstring2
  xtran(frm)=VAL(s$)
  IF xtran(frm)<-90 THEN xtran(frm)=(-90)
  IF xtran(frm)>90 THEN xtran(frm)=90
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

mod.ytran:
  s$=STR$(ytran(frm))
  xt=164:yt=184
  maxchar=3
  numonly=1
  GOSUB getstring2
  ytran(frm)=VAL(s$)
  IF ytran(frm)<-8 THEN ytran(frm)=(-8)
  IF ytran(frm)>8 THEN ytran(frm)=8
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

mod.ztran:
  s$=STR$(ztran(frm))
  xt=220:yt=184
  maxchar=4
  numonly=1
  GOSUB getstring2
  ztran(frm)=VAL(s$)
  IF ztran(frm)<0 THEN ztran(frm)=0
  IF ztran(frm)>999 THEN ztran(frm)=999
  GOSUB drw.factors
  frmchg(frm)=1
  GOSUB drw.update
  GOSUB nobut
RETURN

drw.frame:
  GOSUB unit.matrix
  IF xrot(frm)>0 THEN GOSUB apply.xrot
  IF yrot(frm)>0 THEN GOSUB apply.yrot
  IF zrot(frm)>0 THEN GOSUB apply.zrot
  IF ztran(frm)>0 THEN GOSUB apply.ztran
  GOSUB transform.pts
  GOSUB convert2scr
  GOSUB sort.poly
  LINE(0,0)-(311,131),0,bf
  GOSUB drw.object
RETURN

matprep:
  FOR row=0 TO 3
    FOR col=0 TO 3
      tr1(row,col)=tran(row,col)
      tr2(row,col)=0
    NEXT
  NEXT
RETURN

unit.matrix:
  FOR row=0 TO 3
    FOR col=0 TO 3
      tran(row,col)=0
      IF row=col THEN tran(row,col)=1
    NEXT
  NEXT
RETURN

matmult:
  FOR row=0 TO 3
    FOR col=0 TO 3
      t=0
      FOR e1=0 TO 3
       t=t+tr1(row,e1)*tr2(e1,col)
        NEXT
      tran(row,col)=t
    NEXT
  NEXT
RETURN

apply.xrot:     'ruota l'oggetto intorno all'asse X
  GOSUB matprep
  rad=xrot(frm)*3.1416/180
  tr2(0,0)=1:tr2(3,3)=1
  tr2(1,1)=COS(rad):tr2(1,2)=SIN(rad)*(-1)
  tr2(2,1)=SIN(rad):tr2(2,2)=COS(rad)
  GOSUB matmult
RETURN

apply.yrot:     'ruota l'oggetto intorno all'asse Y
  GOSUB matprep
  rad=yrot(frm)*3.1416/180
  tr2(1,1)=1:tr2(3,3)=1
  tr2(0,0)=COS(rad):tr2(0,2)=SIN(rad)
  tr2(2,0)=SIN(rad)*(-1):tr2(2,2)=COS(rad)
  GOSUB matmult
RETURN

apply.zrot:     'ruota l'oggetto intorno all'asse Z
  GOSUB matprep
  rad=zrot(frm)*3.1416/180
  tr2(2,2)=1:tr2(3,3)=1
  tr2(0,0)=COS(rad):tr2(0,1)=SIN(rad)*(-1)
  tr2(1,0)=SIN(rad):tr2(1,1)=COS(rad)
  GOSUB matmult
RETURN

apply.ztran:     'trasporta l'oggetto lungo l'asse Z
  GOSUB matprep
  tr2(0,0)=1:tr2(1,1)=1
  tr2(2,2)=1:tr2(3,3)=1
  tr2(3,2)=ztran(frm)
  GOSUB matmult
RETURN

transform.pts:
  COLOR 1,0
  FOR p=1 TO 95
    LOCATE 1,5
    PRINT "Calcola il Punto";p
    IF pt(p,0)<>0 OR pt(p,1)<>0 OR pt(p,2)<>0 THEN
      FOR col=0 TO 3
        t=0
        FOR e1=0 TO 3
          t=t+pt(p,e1)*tran(e1,col)
        NEXT
        tpt(p,col)=t 
      NEXT 
    END IF
  NEXT
RETURN

convert2scr:     ' converte i punti sulle coordinate dello schermo
  FOR p=1 TO 95
    r=zeye/(tpt(p,2)+zeye)
    tpt(p,0)=INT(tpt(p,0)*r)+hoff
    tpt(p,1)=(INT(tpt(p,1)*r))*(-1)+voff
  NEXT
RETURN

reset.polyorder:
  FOR n=1 TO maxpoly
    polyord(n,0)=0
    polyord(n,1)=0
  NEXT
RETURN

sort.poly:
  GOSUB reset.polyorder
  FOR n=1 TO maxpoly
    LOCATE 1,16
    PRINT "Poligono"n
    IF vrt(n)>0 THEN
      t=0
      FOR n2=1 TO vrt(n)
        t=t+tpt(poly(n,n2),2)
      NEXT
      polyord(n,0)=INT(t/vrt(n))
    END IF
  NEXT
  FOR n=1 TO maxpoly
    LOCATE 1,24
    PRINT n;"di nuovo."
    IF vrt(n)>0 THEN
      t=(-100)
      p=(-1)
      FOR n2=1 TO maxpoly
        IF vrt(n2)>0 THEN
          IF polyord(n2,0)>t THEN t=polyord(n2,0):p=n2
        END IF
      NEXT
      polyord(n,1)=p
      polyord(p,0)=(-100)
    END IF
  NEXT
  COLOR 1,2
RETURN

drw.object:
  FOR n=1 TO maxpoly
    IF vrt(n)>2 THEN
      FOR n2=1 TO vrt(polyord(n,1))
        AREA(tpt(poly(polyord(n,1),n2),0)+xtran(frm),tpt(poly(polyord (n,1),n2),1)+ ytran(frm))
      NEXT
      COLOR polyclr(polyord(n,1))
      AREAFILL
    END IF
  NEXT
  COLOR 1,2
RETURN

getfrm:
  GET(hoff-64+xtran(frm),voff-58+ytran(frm))-(hoff+63+xtran(frm), voff+57+ytran(frm)),frame&((frm-1)*frmsize)
RETURN

putfrm:
  PUT(hoff-64+xtran(frm),voff-58+ytran(frm)),frame&((frm-1)*frmsize) ,PSET
RETURN

getstring:
  s$=""

getstring2:
  GOSUB freeze.menu
  GOSUB nokey
  numchar=LEN(s$)
  CALL move&(rp&,xt,yt)
  PRINT s$;
  z$=""

getstring3:
    LINE(xt+numchar*8+1,yt-7)-(xt+numchar*8+4,yt+2),3,bf
    z$=INPUT$(1)
    LINE(xt+numchar*8+1,yt-7)-(xt+numchar*8+4,yt+2),2,bf
    IF z$=CHR$(8) OR z$=CHR$(31) OR z$=CHR$(127) THEN
      IF numchar>0 THEN
        PRINT CHR$(8);" ";CHR$(8);
        numchar=numchar-1
        s$=LEFT$(s$,numchar)
      END IF
    END IF
    IF ASC(z$)>31 AND numchar<maxchar AND numonly=0 THEN
        s$=s$+z$
        PRINT z$;
        numchar=numchar+1
    END IF
    IF ASC(z$)>31 AND numchar<maxchar THEN
      IF numonly=1 THEN
        IF (z$>="0" AND z$<="9") OR z$="-" THEN
          s$=s$+z$
          PRINT z$;
          numchar=numchar+1
        END IF
      END IF
    END IF
  IF z$<>CHR$(13) THEN getstring3
  numonly=0
  GOSUB unfreeze.menu
RETURN

click.continue:
  LOCATE 22,14
  PRINT "Per continuare     "
  PRINT "  premere il tasto sinistro del mouse";
  GOSUB nobut
  b=MOUSE(0)
  WHILE b=0
    b=MOUSE(0)
  WEND
RETURN

nobut:
  b=MOUSE(0)
  WHILE b<>0
    b=MOUSE(0)
  WEND
RETURN

nokey:
  z$=INKEY$
  WHILE z$<>""
    z$=INKEY$
  WEND
RETURN

init:
  DEFINT a-p,u-z
  DECLARE FUNCTION setdrmd LIBRARY
  DECLARE FUNCTION move LIBRARY
  LIBRARY "graphics.library"
  SCREEN 1,320,200,5,1
  WINDOW 2,"Rot",(0,0)-(311,186),0,1
  WINDOW OUTPUT 2
  rp&=WINDOW(8) 'puntatore alla porta raster
  PALETTE 0,0,0,0
  PALETTE 2,0,.5,0
  PALETTE 31,0,.25,0
  PALETTE 30,.7,.7,0
  LOCATE 3,1
  GOSUB intro
  DIM pt(95,3),poly(95,6),polyclr(95),vrt(95)
  DIM xrot(12),yrot(12),zrot(12)
  DIM xtran(12),ytran(12),ztran(12),frmchg(12)
  DIM tran(3,3),tr1(3,3),tr2(3,3),tpt(95,3),polyord(95,1)
  DIM frame&(27876)
  pt=1:poly=1
  objscr=-1:actscr=0
  vx1=43:vx2=43:vx3=136
  vy1=43:vy2=135:vy3=135
  maxpt=95:maxpoly=95
  frm=1:spd=20
  frmsize=2323
  hoff=156:voff=66:zeye=440
  actrpt=0:actrev=0
  FOR n=1 TO maxpt
    pt(n,3)=1
  NEXT
  GOSUB init.menu
  COLOR 1,0
  GOSUB click.continue
  COLOR 1,2
  GOSUB drw.objscr
RETURN

init.menu:
  MENU 1,0,1,"ROT"
  MENU 1,1,1," Files "
  MENU 1,2,0,"------"
  MENU 1,3,1," Esci "
  MENU 2,0,1,"Oggetto"
  MENU 2,1,2,"  Editor Oggetto "
  MENU 2,2,1,"  Carica Oggetto "
  MENU 2,3,1,"  Salva  Oggetto "
  MENU 2,4,1,"  Nuovo  Oggetto "
  MENU 3,0,1,"Azione"
  MENU 3,1,1,"  Editor Azione "
  MENU 3,2,0,"  Carica Azione "
  MENU 3,3,0,"  Salva  Azione "
  MENU 3,4,0,"  Nuova  Azione "
  MENU 3,5,0,"----------------"
  MENU 3,6,0,"  Ripete ciclo "
  MENU 3,7,0,"  Ripete ciclo inverso"
  MENU 3,8,0,"  Calcola tra...   "
  MENU 4,0,0," "
  MENU 4,1,0," "
RETURN
 
freeze.menu:
  MENU 1,0,0
  MENU 2,0,0
  MENU 3,0,0
RETURN

unfreeze.menu:
   MENU 1,0,1
  MENU 2,0,1
  MENU 3,0,1
RETURN

cleanup:
  WINDOW CLOSE 2
  SCREEN CLOSE 1
  LIBRARY CLOSE
  PALETTE 0,0,.25,.55
  PALETTE 2,0,0,0
  MENU RESET
RETURN

drw.objscr:
  LINE(0,0)-(320,200),2,bf
  LINE(2,2)-(83,83),0,bf
  LINE(2,95)-(83,176),0,bf
  LINE(96,95)-(177,176),0,bf
  LINE(186,2)-(310,53),1,b
  LINE(186,60)-(310,176),1,b
  LINE(191,142)-(304,171),0,bf
  FOR y=0 TO 3
    FOR x=0 TO 7
      LINE(193+x*14,144+y*7)-(204+x*14,148+y*7),y*8+x,bf
    NEXT
  NEXT
  x=189:y=126:GOSUB drw.button
  y=110:GOSUB drw.button
  y=94:GOSUB drw.button
  y=36:GOSUB drw.button
  y=24:GOSUB drw.scroll
  y=82:GOSUB drw.scroll
  CALL move&(rp&,228,12):PRINT "PUNTO"
  CALL move&(rp&,236,21):PRINT "#"
  CALL move&(rp&,208,45):PRINT "Punto Zero"
  CALL move&(rp&,220,70):PRINT "POLIGONO"
  CALL move&(rp&,236,79):PRINT "#"
  CALL move&(rp&,200,103):PRINT "+ il Pt prec."
  CALL move&(rp&,200,119):PRINT "Clr ultimo Pt"
  CALL move&(rp&,192,135):PRINT " Clr Poligono"
  CALL move&(rp&,10,92):PRINT "Vertice Z"
  CALL move&(rp&,10,185):PRINT "Lato Z";
  CALL move&(rp&,96,185):PRINT "Frontale X";
  CALL move&(rp&,86,16):PRINT "X"
  CALL move&(rp&,86,109):PRINT "Y"
  x=2:y=89:GOSUB drw.leftarrow
  y=182:GOSUB drw.leftarrow
  x=89:y=2:GOSUB drw.uparrow
  y=95:GOSUB drw.uparrow
  x=166:y=182:GOSUB drw.rightarrow
  GOSUB drw.ptnum
  GOSUB drw.polynum
  GOSUB drw.views
  c=polyclr(poly)
  GOSUB high.clr
  GOSUB nobut
RETURN

drw.button:
  LINE(x,y)-(x+116,y+12),1,b
  LINE(x+2,y+13)-(x+117,y+13),0
  LINE -(x+117,y+1),0
RETURN

drw.scroll:
  LINE(x,y)-(x+116,y+8),1,b
  LINE(x+8,y)-(x+109,y+8),1,b
  LINE -(x+117,y+1),0
  COLOR 0
  AREA(x+3,y+4):AREA(x+5,y+2):AREA(x+5,y+6)
  AREAFILL
  AREA(x+112,y+2):AREA(x+112,y+6):AREA(x+114,y+4)
  AREAFILL
RETURN

drw.leftarrow:
  AREA(x,y):AREA(x+3,y-3):AREA(x+3,y+3):AREAFILL
  LINE(x,y)-(x+6,y)
RETURN

drw.rightarrow:
  AREA(x,y):AREA(x-3,y-3):AREA(x-3,y+3):AREAFILL
  LINE(x,y)-(x-6,y)
RETURN

drw.uparrow:
  AREA(x,y):AREA(x-3,y+3):AREA(x+3,y+3):AREAFILL
  LINE(x,y)-(x,y+6)
RETURN

drw.ptnum:
  LINE(199,26)-(296,30),0,bf
  LINE(198+pt,26)-(201+pt,30),3,bf
  CALL move&(rp&,244,21)
  PRINT RIGHT$("00"+STR$(pt),2)
RETURN

drw.polynum:
  LINE(199,84)-(296,88),0,bf
  LINE(198+poly,84)-(201+poly,88),3,bf
  CALL move&(rp&,244,79)
  PRINT RIGHT$("00"+STR$(poly),2)
RETURN

drw.actscr:
  LINE(0,0)-(311,131),0,bf
  LINE(0,132)-(311,186),2,bf
  x=140:y=136:GOSUB drw.button2
  y=152:GOSUB drw.button2
  x=260:y=136:GOSUB drw.button3
  y=152:GOSUB drw.button3
  LINE(260,178)-(306,183),1,b
  LINE(262,184)-(307,184),0
  LINE -(307,179),0
  LINE(4,150)-(122,158),1,b
  LINE(12,150)-(114,158),1,b
  LINE(6,159)-(123,159),0
  LINE -(123,151),0
  COLOR 0
  AREA(7,154):AREA(9,152):AREA(9,156):AREAFILL
  AREA(117,152):AREA(119,154):AREA(117,156):AREAFILL
  COLOR 1,2
  CALL move&(rp&,28,145):PRINT "FRAME #"
  CALL move&(rp&,4,175):PRINT "Rotazioni: X=     Y=     Z="
  CALL move&(rp&,4,184):PRINT "Incremento:X=     Y=     Z=";
  GOSUB unhigh.redraw
  GOSUB unhigh.redraw2
  GOSUB unhigh.play
  GOSUB high.stop
  CALL move&(rp&,264,175):PRINT "Tempo"
  GOSUB drw.frmnum
  GOSUB drw.spdnum
  GOSUB drw.update
  GOSUB drw.factors
  GOSUB putfrm
RETURN

drw.frmnum:
  LINE(15,152)-(111,156),0,bf
  LINE(7+frm*8,152)-(15+frm*8,156),3,bf
  CALL move&(rp&,84,145)
  PRINT RIGHT$("00"+STR$(frm),2)
RETURN

drw.spdnum:
  LINE(262,180)-(304,181),0,b
  LINE(261+spd,180)-(265+spd,181),3,b
RETURN

drw.update:
  LINE(115,138)-(131,146),2,bf
  IF frmchg(frm)<>0 THEN
    LINE(115,142)-(131,142),3
    LINE -(127,138),3
    LINE(131,142)-(127,146),3
  END IF
RETURN

drw.factors:
  CALL move&(rp&,108,175)
  PRINT LEFT$(STR$(xrot(frm))+"   ",4)
  CALL move&(rp&,164,175)
  PRINT LEFT$(STR$(yrot(frm))+"   ",4)
  CALL move&(rp&,220,175)
  PRINT LEFT$(STR$(zrot(frm))+"    ",4)
  CALL move&(rp&,108,184)
  PRINT LEFT$(STR$(xtran(frm))+"    ",4);
  CALL move&(rp&,164,184)
  PRINT LEFT$(STR$(ytran(frm))+"    ",4);
  CALL move&(rp&,220,184)
  PRINT LEFT$(STR$(ztran(frm))+"    ",4);
RETURN

unhigh.redraw:
  LINE(141,137)-(249,147),2,bf
  CALL move&(rp&,148,145)
  PRINT " Rifa' Frame"
RETURN

high.redraw:
  LINE(141,137)-(249,147),3,bf
  COLOR 1,3
  CALL move&(rp&,148,145)
  PRINT " Rifa' Frame"
  COLOR 1,2
RETURN

unhigh.redraw2:
  LINE(141,153)-(249,163),2,bf
  CALL move&(rp&,156,161)
  PRINT "Rifa' tutto"
RETURN

high.redraw2:
  LINE(141,153)-(249,163),3,bf
  COLOR 1,3
  CALL move&(rp&,156,161)
  PRINT "Rifa' tutto"
  COLOR 1,2
RETURN

unhigh.play:
  LINE(261,137)-(305,147),2,bf
  CALL move&(rp&,268,145)
  PRINT "Play"
RETURN

high.play:
  LINE(261,137)-(305,147),3,bf
  COLOR 1,3
  CALL move&(rp&,268,145)
  PRINT "Play"
  COLOR 1,2
RETURN

unhigh.stop:
  LINE(261,153)-(305,163),2,bf
  CALL move&(rp&,268,161)
  PRINT "Stop"
RETURN

high.stop:
  LINE(261,153)-(305,163),3,bf
  COLOR 1,3
  CALL move&(rp&,268,161)
  PRINT "Stop"
  COLOR 1,2
RETURN

drw.button2:
  LINE(x,y)-(x+110,y+12),1,b
  LINE(x+2,y+13)-(x+111,y+13),0
  LINE -(x+111,y+1),0
RETURN

drw.button3:
  LINE(x,y)-(x+46,y+12),1,b
  LINE(x+2,y+13)-(x+47,y+13),0
  LINE -(x+47,y+1),0
RETURN 
 

Settembre 1988