/*************************************************************************
 *      MICRO PAINT.C                           release 2
 *
 *
 * RELEASE 1:
 *
 * Programma di esempio sull'uso di Intuition, a corredo del corso di
 * programmazione in C su Amiga. Nell'articolo 'corso di c, parte 5,6
 * e' contenuta una dettagliata discussione di questo programma e delle
 * funzioni utilizzate.
 *
 *
 * RELEASE 2:
 *
 * Questa e' una versione del programma usato come esempio della puntata
 * 7 del corso, con le seguenti modifiche rispetto alla versione 1:
 *
 * - Il programma utilizza uno schermo 320x200 a 32 colori, per potere
 *   fare esperimenti sulla palette (tavolozza) dei colori.
 *
 * - La finestra e' ora di tipo GIMMEZEROZERO, in modo da non scrivere
 *   sopra i bordi, ma solo all'INTERNO della finestra.
 *   Le x,y dei comandi grafici sono ora ovviamente letti
 *   dalle variabili GZZMouseX, GZZMouseY della struct Window, perche'
 *   le coordinate MouseX, MouseY contenute nei messaggi sono sempre
 *   relative al vertice superiore sinistro ESTERNO della finestra.
 *
 * - Il menu di selezione dei colori e' stato sostituito con una voce di
 *   selezione della palette, come applicazione della funzione
 *
 *              selezione_colori()
 *
 *   che viene cosi' usata sia per modificare i colori correnti dello
 *   schermo che per selezionare il colore desiderato dalla tavolozza.
 *
 * - Le dimensioni dei menu sono state ritoccate in modo da entrare in
 *   uno schermo in bassa risoluzione.
 *
 *
 * - E' stato leggermente modificato il sistema di gestione degli
 *   eventi MOUSEMOVE per migliorare le reazioni del programma a
 *   movimenti bruschi del mouse.
 *
 * Il programma ora, oltre che compilato, va linkato con il codice
 * oggetto di colori.c, che contiene la definizione di selezione_colori().
 *
 * Entrambi i programmi vanno, per gli utenti con il MANX AZTEC C,
 * compilati a 32 bit (+l) e linkati con la c32.lib.
 *
 *************************************************************************/

/*
 Definizione di alcune costanti per aumentare la leggibilita'
 Corrispondono ai menu ed alle voci all'interno  dei menu.
 */

/* Indici dei menu e delle voci nei menu */
#define PROGETTO        0

#define NUOVO           0
#define FINE            1


#define DISEGNO         1

#define MANOLIBERA      0
#define LINEA           1
#define RETTANGOLO      2
#define ELLISSE         3


#define COLORI          2

/* Macro che trasforma in positivo il valore passato */
#define ABS(x) ((x)>0 ? (x): -(x))

/* Comandi alle nostre funzioni grafiche */
#define INIZIO          1
#define MUOVI           2
#define TERMINA         3
#define UNDO            255

/* Stato delle funzioni grafiche */
#define IN_CORSO        1
#define FINITO          255


/* Inclusione dei files di supporto. */
#include <intuition/intuition.h>


/** Dichiarazione e descrizione delle strutture usate nel programma. **/

/* Descrizione del set di caratteri da usare nel nostro schermo. */

struct TextAttr TOPAZ80 = {
        "topaz.font",           /* Nome del set di caratteri */
        8,                      /* Altezza dei caratteri */
        0,                      /* Stile (0 = nessuno) */
        0                       /* Flags (ROM/DISK: 0=ROM) */
        };


/* Questa e' la descrizione del nuovo schermo che vogliamo aprire. */

struct NewScreen nuovo_schermo = {
        0,0,            /* Origine X,Y dello schermo sul display */
        320,200,        /* Larghezza, altezza dello schermo */
        5,              /* 32 COLORI */
        0,1,            /* Registri colore usati per i dettagli ed i
                           blocchi, qui NERO, BIANCO */
        NULL,           /* FLAGS */
        CUSTOMSCREEN,   /* Non e' uno schermo standard di sistema, quindi
                           va specificato CUSTOM.. */
        &TOPAZ80,       /* Puntatore alla struttura TextAttr per Topaz 8 */
        "Micro Paint",
                        /* Titolo dello schermo, compare nella barra */
        NULL,           /* Puntatore al primo custom gadget, non usato */
        NULL            /* Puntatore ad una bitmap 'gia'pronta'. Non usato */
                        
        };              /* Fine della struct NewScreen */


/*
 Descrizione di una struttura di tipo NewWindow. Contiene i parametri della
 finestra desiderata.
 */  

struct NewWindow nuova_finestra = {

        0,0,            /* Origine XY della finestra rispetto all'angolo
                           superiore sinistro dello schermo */
        320,200,        /* Larghezza e altezza della finestra */
        0,1,            /* Penne (registri colore) da usare per dettagli
                           e blocchi. Qui NERO,BIANCO */

                        /* IDCMP Flags */
        CLOSEWINDOW+    /* Chiusura della finestra */
        MOUSEBUTTONS+   /* Pressione/rilascio del tasto sinistro del mouse */
        MOUSEMOVE+      /* Movimento del mouse */
        MENUPICK,       /* Selezione di un menu */

                        /* Window Flags, non confondere coi precedenti! */
        WINDOWSIZING+   /* Voglio il gadget di ridimensionamento */
        WINDOWDRAG+     /*  ""          ""  di spostamento */
        WINDOWDEPTH+    /*  ""          ""  di 'profondita' */
        REPORTMOUSE+    /* Voglio che Int. controlli i movimenti del mouse */
        WINDOWCLOSE+    /* Voglio il gadget di chiusura finestra */
        ACTIVATE+       /* Voglio che la finestra si attivi dopo l'apertura */
        NOCAREREFRESH+  /* Non mi interessa sapere se la finestra e' stata
                           danneggiata e va ridisegnata (e'l'unica
                           finestra sul nostro schermo) */
        GIMMEZEROZERO,  /* Dammi coordinate escludendo i bordi */

        NULL,           /* Puntatore al primo gadget 'custom', per noi 0 */
        NULL,           /* Puntatore all'immagine del CheckMark */
        "Micro Paint",  /* Nome che compare nella barra superiore della f. */
        NULL,           /* Puntatore allo schermo. PER ORA nullo */
        NULL,           /* Eventuale bitmap 'fuori schermo' */
        15,15,          /* Minima larghezza e altezza, */
        -1,-1,          /* Massima larghezza e altezza,*/
        CUSTOMSCREEN    /* Tipo di schermo su cui andra'. */
        };              /* Fine descrizione della struttura NewWindow */



/************************************************************************
 Definizione delle strutture necessarie per i menu. I menu creati
 hanno il seguente aspetto:

 ----------------------------------------
 Progetto       Disegno         Colori
 ----------------------------------------
 Cancella       Mano Libera     Palette
 Fine           Linea           ---------
 ------         Rettangolo      
                Ellisse         
                ------------

 *****************************************************************/

/***** Strutture per il menu COLORI ******************************/
/* Ridotto alla sola voce PALETTE */

struct IntuiText testo4 = {
        0,1,JAM1,
        0,0,
        NULL,
        (UBYTE *)"Palette",
        NULL
        };

struct MenuItem voce_menu1 = {
        NULL,
        0,0,
        110,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
        0xfe,
        (APTR)&testo4,
        NULL,
        'p',
        NULL,
        MENUNULL
        };




/**** Questa struttura e' la testata del menu COLORI *******/
struct Menu menu2 = {
        NULL,           /* Puntatore al Menu successivo (questo e' l'ultimo) */
        180,0,          /* XY del menu rispetto all'angolo sup.sin. schermo */
        55,0,           /* Dimensioni del box di selezione del titolo */
        MENUENABLED,    /* Menu flags, questo menu e' attivo, e le sue voci
                           sono selezionabili.  */
        "Colori",       /* Titolo del menu, compare nella barra dello schermo*/
        &voce_menu1     /* Puntatore alla prima voce di questo menu */
};




/***** Strutture per il menu' DISEGNO ******************************/

struct IntuiText testo5 = {
        0,1,JAM1,
        19,0,
        NULL,
        (UBYTE *)"Ellisse",
        NULL
};

struct MenuItem voce_menu8 = {
        NULL,
        0,24,
        145,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
        0xf7,
        (APTR)&testo5,
        NULL,
        'e',
        NULL,
        MENUNULL
};




struct IntuiText testo6 = {
        0,1,JAM1,
        19,0,
        NULL,
        (UBYTE *)"Rettangolo",
        NULL
};

struct MenuItem voce_menu7 = {
        &voce_menu8,
        0,16,
        145,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
        0xfb,
        (APTR)&testo6,
        NULL,
        'r',
        NULL,
        MENUNULL
};




struct IntuiText testo7 = {
        0,1,JAM1,
        19,0,
        NULL,
        (UBYTE *)"Linea",
        NULL
};

struct MenuItem voce_menu6 = {
        &voce_menu7,
        0,8,
        145,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT,
        0xfd,
        (APTR)&testo7,
        NULL,
        'l',
        NULL,
        MENUNULL
};




struct IntuiText testo8 = {
        0,1,JAM1,
        19,0,
        NULL,
        (UBYTE *)"Mano Libera",
        NULL
};

struct MenuItem voce_menu5 = {
        &voce_menu6,
        0,0,
        145,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP+CHECKIT+CHECKED,
        0xfe,
        (APTR)&testo8,
        NULL,
        'm',
        NULL,
        MENUNULL
};




struct Menu menu1 = {
        &menu2,
        90,0,
        63,0,
        MENUENABLED,
        "Disegno",
        &voce_menu5
};



/***** Strutture per il menu PROGETTO ***************************/

struct IntuiText testo9 = {
        0,1,JAM1,
        0,0,
        NULL,
        (UBYTE *)"Fine",
        NULL
};


struct MenuItem voce_menu10 = {
        NULL,
        0,8,
        92,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
        0,
        (APTR)&testo9,
        NULL,
        'f',
        NULL,
        MENUNULL
};



struct IntuiText testo10 = {
        0,1,JAM1,
        0,0,
        NULL,
        (UBYTE *)"Nuovo",
        NULL
};

struct MenuItem voce_menu9 = {
        &voce_menu10,
        0,0,
        92,8,
        ITEMTEXT+COMMSEQ+ITEMENABLED+HIGHCOMP,
        0,
        (APTR)&testo10,
        NULL,
        'n',
        NULL,
        MENUNULL
};



struct Menu menu0 = {
        &menu1,
        0,0,
        75,0,
        MENUENABLED,
        "Progetto",
        &voce_menu9
};

/*********************************************************************
 Fine delle definizioni per i menu'.. (phew!).
 ********************************************************************/



/* Dichiarazione delle variabili 'puntatore a libreria'. */

struct IntuitionBase *IntuitionBase;
struct GfxBase  *GfxBase;


/* Dichiarazione del tipo di valori ritornati dalle funzioni usate. */

extern struct Screen *OpenScreen();
extern struct Window *OpenWindow();
extern struct IntuiMessage *GetMsg();

/*
 Dichiarazione delle variabili che usiamo per immagazzinare i puntatori
 ritornati dall'apertura dello schermo e della finestra.
 */

struct Screen *schermo;
struct Window *finestra;
struct RastPort *RP;


/*****************************************************************
 Dichiarazione delle variabili usate nella gestione degli eventi,
 che ci vengono spediti da Intuition come IntuiMessages.
 *****************************************************************/

struct IntuiMessage *messaggio; /* Puntatore al messaggio ricevuto */
SHORT   x,y;                    /* Posizione del mouse */
ULONG   classe;                 /* Classe del messaggio ricevuto */
USHORT  codice;                 /* Codice del messaggio ricevuto */

BOOL    continua;               /* Flag. FALSE quando stiamo per uscire */
USHORT  pulsante;               /* Stato del pulsante sin Mouse */



/**** punti estremi del tratto per le routines grafiche ****/
SHORT   x1,y1;
SHORT   x2,y2;



/*********************************************************************
 *                      FUNZIONI GRAFICHE
 *
 * Qui di seguito compaiono i moduli che eseguono i comandi grafici.
 * Per espandere il programma, aggiungendo nuove funzioni, basta 
 * inserire le nuove funzioni qui sotto, aggiungere le voci corrispon- 
 * denti nei menu ed inserire i puntatori alle nuove funzioni nella 
 * tabella che compare piu' sotto.
 *
 *********************************************************************/

#define MAX_COMANDI 5

/* Stato della funzione grafica attiva. */
USHORT  stato;



/*********************************************************************
 * Disegna a mano libera con il mouse. 
 *********************************************************************/
void mano_libera (comando)

        UBYTE comando;

        {
        /* Disegna un punto alla posizione corrente del mouse */
        WritePixel (RP,x,y);

        return();
        }


/*********************************************************************
 * Traccia delle linee rette con il mouse.
 *********************************************************************/
void linea (comando)

        UBYTE comando;

        {
        switch (comando)
                {
                case INIZIO:
                        /* Memorizza il punto iniziale della linea */
                        x2 = x1 = x;
                        y2 = y1 = y;

                        /* Usa un tratto 'cancellabile' */
                        SetDrMd (RP,COMPLEMENT);

                        /* Segnala che un comando e' in esecuzione */
                        stato = IN_CORSO;

                        break;

                case MUOVI:
                        /* Cancella la linea precedente */
                        Move (RP,x1,y1);
                        Draw (RP,x2,y2);

                        /* Memorizza la nuova posizione */
                        x2 = x;
                        y2 = y;

                        /* Disegna una linea fino al nuovo punto */
                        Move (RP,x1,y1);
                        Draw (RP,x2,y2);

                        break;

                case TERMINA:

                        /* Usa un tratto non cancellabile */
                        SetDrMd (RP,JAM1);

                        /* Disegna la linea definitiva */
                        Move (RP,x1,y1);
                        Draw (RP,x2,y2);

                        stato = FINITO;

                        break;
                default:
                        break;
                }

        return();
        }


/*********************************************************************
 * Traccia dei rettangoli con il mouse.
 *********************************************************************/
void rettangolo (comando)
        UBYTE comando;
        {

        static SHORT disegna;
        
        switch (comando)
                {
                case INIZIO:
                        /* Memorizza il punto iniziale del rettangolo */
                        x2 = x1 = x;
                        y2 = y1 = y;

                        /* Usa un tratto 'cancellabile' */
                        SetDrMd (RP,COMPLEMENT);

                        /* Segnala che un comando e' in esecuzione */
                        stato = IN_CORSO;

                        break;

                case MUOVI:
                        /* Cancella il rett. precedente */
                        RectFill (RP,x1,y1,x2,y2);

                        /*
                         Memorizza la nuova posizione. Consente solo un
                         movimento verso destra e verso il basso. (BUG!)
                         */
                        if (x > x1) x2 = x;
                        if (y > y1) y2 = y;

                        /* Disegna un rett. fino al nuovo punto */
                        RectFill (RP,x1,y1,x2,y2);

                        break;

                case TERMINA:

                        /* Usa un tratto non cancellabile */
                        SetDrMd (RP,JAM1);

                        /* Disegna il rett. definitivo */
                        RectFill (RP,x1,y1,x2,y2);

                        stato = FINITO;

                        break;
                default:
                        break;
                }
        return();
        }

/*********************************************************************
 * Traccia ellissi/cerchi con il mouse.
 * NB: Il comando grafico DrawEllipse e' L.E.N.T.O!
 *********************************************************************/

void ellisse (comando)
        UBYTE comando;
        {
        switch (comando)
                {
                case INIZIO:
                        /* Memorizza il centro dell'ellisse */
                        x1 = x;
                        y1 = y;

                        /* parti con un raggio minimo */
                        x2 = 0;
                        y2 = 0;

                        /* Usa un tratto 'cancellabile' */
                        SetDrMd (RP,COMPLEMENT);

                        /* disegna il primo punto */
                        DrawEllipse (RP,x1,y1,x2,y2);

                        /* Segnala che un comando e' in esecuzione */
                        stato = IN_CORSO;

                        break;

                case MUOVI:
                        /* Cancella l'ell. precedente */
                        DrawEllipse (RP,x1,y1,x2,y2);

                        /*
                         usiamo le stesse variabili per memorizzare i
                         raggi delle ellissi, come distanza del mouse
                         dal centro.
                         */
                        x2 = ABS(x-x1);
                        y2 = ABS(y-y1);

                        /* Disegna un'ell. con i nuovi raggi */
                        DrawEllipse (RP,x1,y1,x2,y2);

                        break;

                case TERMINA:

                        /* Usa un tratto non cancellabile */
                        SetDrMd (RP,JAM1);

                        /* Disegna l'ellisse definitiva */
                        DrawEllipse (RP,x1,y1,x2,y2);

                        stato = FINITO;

                        break;
                default:
                        break;
                }
        return();
        }

/**** ...... altre funzioni andranno qui...... ***/

void nulla (comando)
        UBYTE comando;
        {
        return();
        }




/* Array di puntatori alle funzioni implementate (o quasi) */

long (*comandi_grafici [MAX_COMANDI]) () =
        {
        mano_libera,
        linea,
        rettangolo,
        ellisse,
        nulla
        };

/* Puntatore alla funzione correntemente attiva */
void (*comando)() = mano_libera;



/*********************************************************************
 *                      scelta_menu ()
 *
 * Decodifica un evento di selezione di una voce dai menu e agisce.
 * Si sarebbe potuto farlo in main() all'interno del ciclo di gestione
 * degli eventi, ma avrebbe portato allla scrittura di troppi switch()
 * nidificati ed il programma sarebbe diventato poco leggibile.
 *
 *********************************************************************/


scelta_menu (menu,voce)
        ULONG   menu;
        USHORT  voce;
        {

        /* Memorizza flags mentre la UserPort della finestra e' chiusa */
        LONG    eventi_usati;   

        switch (menu)
                {

                /* PROGETTO = 0: costante #definita all'inizio.. */
                case PROGETTO:

                        /* Termina il comando corrente */
                        if (stato != FINITO) (*comando) (TERMINA);

                        switch (voce)
                                {

                                case NUOVO:

                                        /* Cancella tutta la finestra */
                                        SetRast (RP,0);

                                        /* Ri-disegna il contorno */
                                        RefreshWindowFrame (finestra);

                                        break;

                                case FINE:

                                        /* Causa uscita dal loop eventi */
                                        continua = FALSE;
                                        break;

                                default:
                                        break;

                                } /* fine voci in PROGETTO */
                        break;


                case DISEGNO:
                        /*
                         Nessun switch(), perche' la meccanica e'
                         la stessa per tutte le voci del menu.
                         */
                        
                        /* Termina il comando corrente */
                        if (stato != FINITO)    (*comando) (TERMINA);

                        /* Attiva il comando scelto */
                        if (voce < MAX_COMANDI)
                                comando  = comandi_grafici[voce];
                        break;



/**************************************************************************

                        MODIFICA IMPORTANTE !!

        Implementazione della funzione selezione_colori()

 **************************************************************************/


                case COLORI:
                        /* Memorizza gli eventi scelti per ricezione */
                        eventi_usati = finestra->IDCMPFlags;

                        /*
                         * Chiudi la porta, per evitare che si accumulino
                         * messaggi mandati da Intuition mentre siamo via.
                         */
                        ModifyIDCMP (finestra,NULL);

                        /*
                         Apri la finestra Palette e attendi mentre noi
                         pasticciamo con i gadgets ed i colori.
                         All'uscita setta la penna corrente al colore
                         selezionato. NB: dovremmo controllare che
                         il valore ritornato non segnali errori.
                         */
                        SetAPen (RP, selezione_colori(schermo,1));

                        /* Ripristina la cassetta postale */
                        ModifyIDCMP (finestra,eventi_usati);
                        break;

                } /* fine switch (menu) */

        return();
        } /* fine scelta_menu() */




/*********************************************************************
 *                      main()
 * Funzione principale e punto d'ingresso nel programma.
 *
 * Apre le risorse (librerie, schermo finestra),
 * esegue in un ciclo di attesa_eventi-decodifica-azione,       
 * rilascia le risorse utilizzate ed esce.
 *
 *********************************************************************/

main () {

        BOOL    mouse_mosso;


        /* Apertura delle librerie usate. Qualsiasi versione va bene. */

        IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library",0);
        if (IntuitionBase == NULL) goto pulizia;

        GfxBase = (struct GfxBase *) OpenLibrary ("graphics.library",0);
        if (GfxBase == NULL) goto pulizia;


        /* Apertura dello schermo. */ 
        schermo = OpenScreen (&nuovo_schermo);
        if (schermo == NULL) goto pulizia;

        /* Mettiamo in nuova_finestra il puntatore allo schermo */
        nuova_finestra.Screen = schermo;

        /* Possiamo ora aprire la finestra. */
        finestra = OpenWindow (&nuova_finestra);
        if (finestra == NULL) goto pulizia;

        /* Recuperiamo il puntatore alla RastPort della finestra. */
        RP = finestra->RPort;

        /* Attacchiamo i nostri menu alla finestra */
        SetMenuStrip (finestra, &menu0);

        /* Scegliamo una 'penna' bianca, registro colore 1 nella palette. */
        SetAPen (RP,1);

        /* Selezioniano la voce 'mano libera' */
        scelta_menu (DISEGNO, MANOLIBERA);



/*************************************************************************
 *      Attesa e decodifica dei messaggi mandati da Intuition.
 *
 *      NOTA BENE :
 *
 *      E' stato portato all'ESTERNO del loop di decodifica dei
 *      messaggi la gestione dell'evento MOUSEMOVE, per fare si'
 *      che operazioni grafiche intensive vengano eseguite in periodi
 *      di carico nulli.
 *
 *      Ora, muovendo il mouse in maniera brusca, il progranna dovrebbe
 *      rispondere piu' prontamente, anche se verranno 'saltati' eventi
 *      intermedi tra le posizioni estreme di ogni movimento veloce.
 *
 *      Questo e' un bene per il S.O., per l'utente non dovrebbe portare
 *      problemi, tranne nel modo 'mano libera', che dara' un tratto
 *      piu' 'punteggiato'.
 *
 *************************************************************************/


continua = TRUE;
while (continua)
        {
        /* Attesa di un evento */
        Wait (1 << finestra->UserPort->mp_SigBit);

        /* Estrazione componenti del messaggio e replica */
        mouse_mosso = FALSE;

        while (messaggio = GetMsg(finestra->UserPort))
                {

                /* Copia i campi che ci interessano  */
                classe = messaggio->Class;
                codice = messaggio->Code;

                /* Leggi le coordinate relative al margine INTERNO */
                x = finestra->GZZMouseX;
                y = finestra->GZZMouseY;
        
                /* Rimanda il messaggio al mittente */
                ReplyMsg (messaggio);

                /* Decodifica in base al tipo di evento. */

                switch (classe)
                        {
                        case MENUPICK:
                                /* esegue la decodifica in una funzione */
                                scelta_menu (MENUNUM (codice), ITEMNUM (codice));
                                break;

                        case MOUSEBUTTONS:
                                /* Registra lo stato del pulsante mouse */
                                pulsante = codice;

                                /* Inizia il comando corrente */
                                switch (pulsante)
                                        {
                                        /* lancia il comando corrente */
                                        case SELECTDOWN:
                                                (*comando)(INIZIO);
                                                break;

                                        /* Termina il comando corrente */
                                        case SELECTUP:
                                                (*comando)(TERMINA);
                                                break;

                                        default:
                                                break;
                                        }
                                break;

                        case MOUSEMOVE:
                                /* Segnala l'evento, lo gestiamo dopo. */
                                if (pulsante==SELECTDOWN)
                                        mouse_mosso = TRUE;
                                break;

                        case CLOSEWINDOW:
                                /* Termina il comando corrente */
                                if (stato != FINITO)
                                        (*comando) (TERMINA);

                                /* Segnala che usciamo dal loop */
                                continua = FALSE;
                                break;

                        default:
                                break;
                        } /* fine switch () */
                } /* fine while() */

        /* Trasmetti il movimento al comando attivo */
        if (mouse_mosso) (*comando) (MUOVI);
        
        } /* fine while (continua) */
        /* */

pulizia:

        ClearMenuStrip (finestra);
        if (finestra != NULL)   CloseWindow (finestra);
        if (schermo != NULL)    CloseScreen (schermo);
        if (GfxBase != NULL)    CloseLibrary (GfxBase);
        if (IntuitionBase != NULL) CloseLibrary (IntuitionBase);

        exit (0);

        } /* fine della definizione di main() */
