Laboratorio di Grafica Interattiva A.A. 2002-3
Esercizio 2
Argomento
Meccanismi per simulare ripartizione in sotto-aree della finestra Glut,
primitive raster in OpenGL.
Files
Il programma partarea.c
apre una finestra divisa in tre aree, solo su una e' attivo un menu'.
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 tre diverse aree:
-
work area destinata ad ospitare la parte grafica
-
menu area destinata ad ospitare un menu'
-
input/output area destinata ad ospitare l'input digitato
dall'utente e i messaggi generati dal programma
+---------------------------------------------+
| menu area |40 pixel
| |
+---------------------------------------------+
| input/output area |20 pixel
+---------------------------------------------+
| work area |
| |quello che
| |resta
| |
| |
| |
+---------------------------------------------+
Guardate il codice.
Il programma contiene, oltre al main, le seguenti funzioni:
-
display_workarea,
display_menuarea,
display_ioarea = disegnano la scena entro
ciascuna delle tre 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 considerato nell'esercizio 1
- menu area disegna per ora un rettangolo bianco che copre
l'intera area con una scritta nera
- inout/output area disegna per ora un rettangolo blu
con una scritta gialla
-
display = usata come display callback, disegna tutta la
finestra come spiegato nelle dispense. Richiama
le funzioni di disegno delle tre sotto-aree.
-
menuecho = la funzione di gestione del menu'.
Il menu' e' attivo solo sulla menu area e la selezione di
qualunque voce provoca la scrittura nella input/output area
del numero di voce selezionato
-
motion = usata come motion callback e come passive
motion callback, guarda se il puntatore del mouse si trova in menu 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 menu area le stesse funzionalita' del menu'
realizzato per l'esercizio 1 (quinta tappa), nel modo seguente:
-
Le voci "primitiva", "attributi" e "assi"
corrispondono a tre sotto-aree della menu area.
Per adesso si possono distinguere con colori di riempimento
diversi e la scritta relativa.
-
l'area "primitiva" ha un menu' pop-up che permette di scegliere la
primitiva fra quelle disponibili in OpenGL (questo era un sottomenu'
nell'esercizio 1).
-
l'area "attributi" ha un menu' pop-up con quattro voci:
"point size", "line width", "polygon mode", "color" corrispondenti a
sottomenu', come quelli dell'esercizio 1
-
l'area "assi" simula un bottone: e' sensibile al click del mouse
(ha attiva una mouse callback) ed ogni click mostra o nasconde gli assi
cartesiani, come nell'esecizio 1
Trasferite in questo file l'esecuzione sulla scena
delle modifiche introdotte dall'utente (cambiamento della primitiva,
degli attributi, assi), dall'esercizio 1.
Gestite sulla input/output area l'"eco" delle modifiche apportate.
Per esempio quando l'utente seleziona point size = 3 fate stampare
che il point size e' stato impostato a 3.
Terza tappa
NOTA: la quarta e quinta tappa sono indipendenti dalla terza,
si possono anche svolgere prima.
Gestite l'immissione di point size e line width da tastiera.
La voce "point size" non chiama piu' un sottomenu',
ma provoca la stampa nella input/output area di un messaggio
del tipo "point size corrente e' ... immettere nuovo point size",
la disattivazione dei menu'
e l'attivazione di una keyboard callback.
A questo punto se l'utente digita un carattere cifra, la
keyboard callback lo assegna
come nuovo point size, stampa
un messaggio opportuno nella input/output area,
disabilita se stessa e riabilita i menu'.
Se l'utente digita un altro tasto, la keyboard callback
lascia il point size invariato, stampa nella input/output area
che l'operazione e' stata annullata, disabilita se stessa e riabilita
i menu'.
Per la line width vale un discorso analogo.
Consiglio: tenete una variabile globale che dica se stiamo attendendo
un point size o una line width (oppure nulla).
Questa variabile sara' assegnata nella funzione di gestione del menu'
quando viene selezionata la voce point size o line width e letta
dalla keyboard callback per decidere che cosa fare del valore
introdotto dall'utente.
Quarta 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.
Pixmap.
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).
Quinta tappa
Realizzate icone per le aree "primitiva", "attributi", "assi"
in cui e' stata ripartita la menu area.
Disegnate le icone nelle aree corrispondenti.
Eliminate il disegno provvisorio dell'immagine raster
fatto nella quarta 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") 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.
-
xpaint 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.
-
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.
Compito
Altre funzioni dall'esercizio 1
Reintegrate qui le altre funzioni realizzate per l'esercizio 1:
-
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,
questa svolgera' anche i compiti di accettazione del
nuovo point size o line width, nel caso l'opzione
corrispondente sia stata selezionata dal menu')
-
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