Laboratorio di Grafica Interattiva A.A. 2003-4
Esercizio 2
Argomento
Meccanismi per simulare ripartizione in sotto-aree della finestra Glut,
primitive raster in OpenGL, inserimento di punti in OpenGL.
Files
Il programma partarea.c
apre una finestra divisa in due aree.
Si compila con lo stesso makefile che e' stato
usato nell'esercizio precedente.
Per compilare un programma chiamato xxx.c
digitare make PROG=xxx.
Un'immagine RGB di esempio:
casetta.rgb.
Il file pixmap.h definisce le classi
Pixmap e PixmapReader
I file rgb_read.h e rgb_read.c definiscono la classe
RGBreader
Per spiegazioni su queste classi vedere le dispense "Introduzione
al C++" e piu' avanti in questo file.
Esercitazione guidata
Prima tappa
Provate a compilare ed eseguire.
Il programma simula la ripartizione della finestra
Glut in due diverse aree:
-
work area destinata ad ospitare la parte grafica
-
toolbar area destinata a simulare una toolbar con dei bottoni
+---------------------------------------------+
| toolbar area |40 pixel
| |
+---------------------------------------------+
| work area |
| |quello che
| |resta
| |
| |
| |
+---------------------------------------------+
Guardate il codice.
Il programma contiene, oltre al main, le seguenti funzioni:
-
display_work,
display_toolbar = disegnano la scena entro
ciascuna delle due aree. Prendono come parametri
l'estensione dell'area, che viene assegnata come
viewport corrente prima di disegnare.
- work area disegna la stessa primitiva
del file primitiv.c dell'esercizio 1
- toolbar area disegna per ora un rettangolo bianco che copre
l'intera area con una scritta nera
-
display = usata come display callback, disegna tutta la
finestra come spiegato nelle dispense. Richiama
le funzioni di disegno delle due sotto-aree.
-
menuecho = la funzione (stupida) di gestione del menu'.
Il menu' e' attivo solo sulla work area.
-
motion = usata come motion callback e come passive
motion callback, guarda se il puntatore del mouse si trova in work area:
- se si', attacca il menu' al bottone destro del mouse
- se no, lo stacca
-
menustatus = usata come menu status callback, se il menu'
e' in uso disabilita le motion e passive motion callback,
altrimenti le abilita.
Seconda tappa
Implementate nella toolbar area una serie di bottoni per la
scelta della primitiva grafica da applicare in work area e per la scelta
della presenza/assenza degli assi.
Nel modo seguente:
-
I vari tipi di primitive e gli assi
corrispondono ciascuno a una sotto-area della toolbar area.
Per adesso si possono distinguere con colori di riempimento
diversi e la scritta relativa:
GL_POINTS, GL_LINES,... ASSI.
-
Ciascuna sotto-area simula un bottone: e' sensibile al click del mouse
(ha attiva una mouse callback) ed ogni click:
- per i bottoni-primitiva, cambia il tipo di primitiva nella work area
- per gli assi, mostra o nasconde gli assi cartesiani,
come nell'esecizio 1
Terza tappa
Fate disegnare ad OpenGL una primitiva raster.
Per adesso potete farla disegnare dove volete, anche nella
work area.
Occorre caricare un'immagine raster da file,
memorizzarla, prima di passarla ad OpenGL per il disegno.
-
La classe C++ Pixmap definita nel file pixmap.h
implementa la struttura dati per una pixmap.
Contiene l'array di pixel e le sue dimensioni larghezza, altezza.
-
La classe astratta PixmapReader definita anch'essa nel file
pixmap.h definisce l'interfaccia di un generico lettore
di pixmap, cioe' qualcosa capace di leggere un'immagine da file e
memorizzarla dentro un oggetto di classe Pixmap.
-
La sottoclasse RGBreader definita nei file
rgb_read.h e rgb_read.c implementa un lettore
di pixmap che legge da file in formato RGB.
La spiegazione di queste classi si trova nelle dispense
"Introduzione al C++" e nei commenti all'interno dei file sorgenti.
Per caricare un'immagine:
- creare un oggetto di classe Pixmap
- creare un lettore di pixmap di classe RGBreader
- usare quest'ultimo per leggere la pixmap da file.
Esempio:
class Pixmap * my_image;
my_image = new Pixmap();
class PixmapReader * my_reader;
my_reader = new RGBreader();
my_reader->readPixmap("casetta.rgb",my_image);
oppure prima aprire il file (fd = fopen(...)) e poi
chiamare my_reader->readPixmap(fd,my_image);.
Per disegnare l'immagine caricata:
- se readPixmap ritorna 1 significa che l'immagine
e' stata letta con successo, allora si puo' procedere
- informare OpenGL che le righe della matrice non sono
allineate a 4 byte (default)
- impostare il pixel zoom (se si desidera scalare l'immagine)
- impostare la raster position
- disegnare l'immagine
Esempio:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(2.0,2.0); /* se la vogliamo doppia */
glRasterPos2i(0,0); /* se la vogliamo agganciare nell'origine */
glDrawPixels(my_image->w,my_image->h,
GL_RGB, GL_UNSIGNED_BYTE, my_image->pixels);
Il vostro programma dovra' portare in testa le inclusioni dei file
"pixmap.h" e "rgb_read.h" ed essere compilato linkandolo assieme
a rgb_read.c, nel makefile occorre aggiungere:
xxxx: rgb_read.c rgb_read.h pixmap.h xxxx.c
$(CC) -g $(INCLUDE) rgb_read.c xxxx.c $(FLAGS) $(LIBS) -o xxxx
con al posto di xxxx il nome del vostro file.
IMPORTANTE:
quelli che appaiono come spazi multipli (a inizio linea)
devono essere un solo carattere tabulazione!
Allora per compilare digitare make xxxx (se il file e'
xxxx.c).
Quarta tappa
Realizzate icone per i "bottoni" della toolbar area e
disegnatele nelle aree corrispondenti.
Ogni bottone avra' due icone: una che corrisponde a
"tipo di primitiva attivo" / "assi visualizzati"
e l'altra corrispondente a "tipo di primitiva non attivo" /
"assi non visualizzati".
Usatele alternativamente
nella sotto-area bottone realizzata, a seconda dello stato corrente.
Eliminate il disegno provvisorio dell'immagine raster
fatto nella terza tappa.
Per creare un file RGB con una nuova immagine sotto Linux sono forniti
alcuni tool un po' rudimentali ma utili allo scopo:
-
xv permette di catturare immagini ritagliando zone di
schermo (funzione "grab") e salvarle in vari formati tra cui RGB.
Permette di cambiare i colori (opzione "color editor" dal
menu' "windows", funziona solo se l'immagine e' a 8 bit,
se e' a 24 bit e' prima necessario passare a 8 bit)
e varie altre modifiche a un'immagine.
Inoltre puo' leggere immagini esistenti in molti formati e
convertirle in RGB.
Nota: alla partenza per fare apparire la finestra di comandi premere
il tasto destro del mouse.
-
xfig permette di disegnare un'immagine vector e poi
convertirla in un formato raster (funzione "export"). Non esporta
in RGB, ma si puo' esportare per es. in GIF e poi convertire in RGB con
xv.
-
xpaint [nota: non so se e' incluso nella nuova
distribuzione] permette di disegnare un'immagine raster ex novo
o editare pixel per pixel un'immagine esistente.
Tratta diversi formati di file ma NON il formato RGB, quindi l'immagine
andra' salvata per es. in GIF e poi convertita in RGB con xv.
-
gimp [nota: dovrebbe essere incluso nella nuova
distribuzione invece di xpaint]
permette di creare, editare, convertire immagini.
E' molto potente anche se non e' semplice da usare.
Quinta tappa
Permettete all'utente di introdurre i vertici della primitiva
cliccando sulla work area.
-
All'inizio il programma non ha nessuna primitiva
-
Scegliendo una primitiva dalla toolbar area, l'utente entra in
modalita' "immissione di vertici"
-
In questa modalita' ogni pressione del bottone sinistro del mouse
all'interno della work area aggiunge un vertice alla primitiva,
che inizialmente non ha vertici.
-
L'immissione di vertici termina premendo il bottone destro
del mouse (si conclude la primitiva) oppure premendo
il tasto "ESC" (la primitiva viene cancellata).
Durante l'immissione deve essere mostrata in ogni momento
la parte della primitiva che e' gia' stata formata
e (se ha senso secondo il tipo di primitiva) una "previsione"
di quella che si aggiungerebbe se l'utente premesse
il bottone del mouse nella posizione in cui si trova ora.
-
Durante l'immissione di vertici, ogni altra interazione
con l'utente e' disabilitata, viene
riabilitata quando la primitiva e' stata conclusa o cancellata.
-
Il programma puo' memorizzare fino a 5 diverse primitive,
ciascuna delle quali puo' avere fino a 20 vertici.
Si consiglia di definire una classe C++ che implementi il tipo
"primitiva" e contenga le coordinate dei vertici in array
e il numero di vertici presenti. Implementare:
- costruttore che crea primitiva con 0 vertici
- funzione che aggiunge un vertice alla primitiva
Compito
Altre funzioni dall'esercizio 1
Reintegrate qui le altre funzioni realizzate per l'esercizio 1:
-
nel menu' della work area i comandi per cambiare gli attributi
(spessore di linea, colore ecc.) come nell'esercizio 1,
per il momento agendo su tutte le primitive presenti
(la prossima volta li faremo agire solo su una primitiva
selezionata)
-
uscita dal programma digitando "q", "Q" o "ESC"
in qualsiasi momento ed in qualunque area si trovi il mouse
(occorre avere una keyboard callback sempre attiva)
-
assi cartesiani tratteggiati
-
conservazione dell'aspect ratio sulla sola work area
(va gestita nella display callback quando si calcola
l'estensione della viewport ristretta, non piu' nella reshape
callback)
-
(facoltativo) scelta degli stili di linea e trame di riempimento