Abbiamo detto che una finestra creata da Glut e' "monolitica" cioe' gestita come un pezzo unico:
Non e' possibile strutturare la finestra in sotto-aree
indipendenti, cioe' ciascuna con sua funzione di ridisegnamento,
sue callback per gli eventi, suoi menu' pop-up, diversi
da quelli delle altre sotto-aree.
Pero' si puo' simulare.
La struttura della finestra in sotto-aree e' gestita interamente dal programmatore, ad "insaputa" di Glut.
Esempio: finestra divisa verticalmente in due parti uguali
+-----------------+ +--------+--------+ | | | | | | | | | | | finestra |h | area1 | area2 |h | | | | | | | | | | +-----------------+ +--------+--------+ w w/2 w/2
Un diverso comportamento per area1 e area2 si simula sfruttando il fatto che e' possibile cambiare dinamicamente la viewport, le callback registrate e i menu'.
La finestra ha sempre un'unica display callback, la quale
La viewport e' sempre mantenuta a tutta finestra tranne al passo 2. La viewport e' parte dello stato di OpenGL e si legge con
Esattamente come disegnare in una viewport normale. Occorre: assegnare matrici projection e modelview, impostare attributi, definire primitive.
Richiamare glViewport con i valori salvati nell'array wp.
Cambiare la callback o il menu' al volo quando il puntatore del mouse passa da una sotto-area all'altra.
Si registra come motion callback e come passive potion callback una funzione f(int x, int y) che esegua le seguenti operazioni:
Verifica a quale area appartiene la posizione corrente del mouse (x,y)
Nell'esempio appartiene ad area1 se x<w/2 e ad area2 altrimenti,
dove w e' la larghezza della viewport globale (l'intera finestra).
Per ciascun tipo di evento XXXX considerato nel programma,
registra con glXXXXFunc la funzione callback desiderata per
l'area in questione.
Se nell'area l'evento XXXX non prevede callback,
registra la funzione nulla NULL
Per ciascun bottone del mouse considerato nel programma per menu' pop-up:
Staccare e attaccare menu' mentre questi sono in uso (cioe' visibili
ovvero "popped-up") provoca errore.
Per evitare questo, occorre disabilitare motion e passive motion
callback mentre i menu' sono in uso.
A tale scopo si registra come menu status callback una funzione
g(int s, int x, int y) che:
Esistono due formati grafici:
Le primitive OpenGL viste finora (definite come
liste di vertici tra glBegin e glEnd) sono vector.
I vertici sono dati in spazio di coordinate di modellazione.
Le primitive vector subiscono una serie di trasformazioni e alla fine
vengono tradotte in formato vector per essere disegnate.
L'accuratezza di definizione delle primitive vector e' virtualmente
infinita (limite la precisione floating point di macchina).
L'accuratezza di definizione dell'immagine
raster che viene fuori dipende dalla dimensione della viewport
(piu' grande = piu' accurata).
OpenGL ha anche primitive raster.
Le primitive raster sono matrici che vengono
disegnate sulla finestra di output cosi' come sono
(un elemento della matrice = un pixel)
senza sottostare alla serie trasformazioni in cui
incorrono le primitive vector.
L'accuratezza di definizione e' fissata, limitata
dalle dimensioni della matrice (numero di righe e colonne).
A seconda del valore contenuto nella matrice per ogni pixel, le primitive raster si differenziano in bitmap e pixmap.
Il valore memorizzato per ogni pixel e' binario (1 bit):
Esempi di bitmap sono quelle per le font dei caratteri.
Il valore memorizzato per ogni pixel e' un colore, che puo' essere specificato in vari modi:
E' compito del programmatore memorizzare la bitmap/pixmap in una struttura dati opportuna che OpenGL possa "capire".
La bitmap o pixmap deve essere memorizzata in un array unidimensionale dove:
Esempio: matrice 5 righe e 3 colonne
+---+---+---+---+---+ | 0 | 1 | 2 | 3 | 4 | +---+---+---+---+---+ | 5 | 6 | 7 | 8 | 9 | +---+---+---+---+---+ | 10| 11| 12| 13| 14| +---+---+---+---+---+diventa array di 15 elementi in fila
+---+---+---+---+---+---+---+-- | 0 | 1 | 2 | 3 | 4 | 5 | 6 | .... +---+---+---+---+---+---+---+--L'elemento di posto (i,j) nella matrice si trova alla posizione i+w*j nell'array dove w e' il numero di colorre (larghezza).
Consideriamo per esempio una pixmap con valori RGB:
struct OnePixel { unsigned int r, g, b; };Struttura dati per pixmap di dimensioni larga w pixel ed alta h pixel
struct OnePixel * pixels;dove pixels e' un array dinamico da allocare a dimensione w*h e poi riempire con i valori.
Il disegno di una primitiva raster e' influenzato da due variabili di stato OpenGL:
raster position =
il punto di aggancio dove disegnare una primitiva raster.
Il punto di aggancio e' dato in coordinate di modellazione
cioe' lo stesso sistema di coordinate in cui sono dati i vertici
delle primitive vector.
Come per i vertici, le coordinate della raster position
sono soggette a tutta la catena di trasformazioni.
Si assegna con la funzione glRasterPos
che esiste in varie versioni, come glVertex.
pixel zoom =
i fattori di scala (sx,sy) con cui disegnare
le primitive raster.
Si assegna con la funzione glPixelZoom(float sx, float sy).
Con fattori (1,1) un elemento della bitmap/pixmap
diventa un pixel su schermo,
con fattori (2,2) un elemento della bitmap/pixmap
diventa 2x2 pixel su schermo ecc.
Fattori negativi capovolgono l'immagine,
fattori non interi causano approssimazione.
Il punto di aggancio resta invariato (e' sempre la
raster position corrente).
In genere prima di disegnare primitive raster e' necessario chiamare
E' possibile
Per leggere: glReadPixels(x, y, w, h, formato, tipo, pixels)
Per disegnare: glDrawPixels(w, h, formato, tipo, pixels)
Per copiare: glCopyPixels(x, y, w, h, GL_COLOR)
Le bitmap sono state progettate allo scopo principale di disegnare font di caratteri. Percio' il disegno di una bitmap prevede:
glBitmap(w, h, x0, y0, x1, y1, pixels)
Per scrivere con glBitmap uno dovrebbe prima definire bitmap per tutte le lettere dell'alfabeto. Glut offre bitmap gia' definite per alcune font e una funzione piu' comoda per disegnare caratteri.
glutBitmapCharacter(font, carattere);
Esempio di funzione che scrive una stringa a partire dalla posizione raster corrente:
void displayString(char * s) { int i; for (i=0; s[i]!='\0'; i++) glutBitmapCharacter(GLUT_BITMAP_8_BY_13, s[i]); }