OpenGL e Glut ============= CALLBACK ASSOCIATE AD UNA FINESTRA La lista delle callback disponibili per una finestra e' nel file precedente. Qui si fanno alcuni esempi di come registrare callback associate a una finestra e che cosa devono fare tali funzioni. Display callback (chiamata dal sistema quando viene ridisegnata la finestra): /* definizione funzione f */ void f(void) { } /* associazione di f come display callback della finestra corrente */ glutDisplayFunc(f); Idle callback (chiamata dal sistema "continuamente"): /* definizione funzione f */ void f(void) { glutPostRedisplay(); } /* associazione di f come idle callback della finestra corrente */ glutIdleFunc(f); Nota: f non esegue il rendering, si limita a rendere noto a glut che la scena necessita redisegnamento; la scena sara' ridisegnata da glut chiamando la display callback. Questo meccanismo permette di redisegnare una volta sola nel caso che il redisegmaneto sia necessario anche per altre cause. Keyboard callback (chiamata dal sistema quando premo un tasto della tastiera sulla finsetra): /* definizione funzione f. c = carattere premuto, x,y = posizione del cursore quando e' stato premuto (in pixel) */ void f(unsigned char c, int x, int y) { printf("key %c pressed at (%d,%d)\n",c,x,y); } /* associazione di f come keyboard callback della finestra corrente */ glutKeyboardFunc(f); Special callback (chiamata dal sistema quando premo un tasto speciale sulla finsetra): /* definizione funzione f. k = codice del tasto speciale premuto (Glut ha una serie di #define che danno nomi simbolici ai tasti speciali), x,y = posizione del cursore quando e' stato premuto */ void f(int k, int x, int y) { if (k == GLUT_KEY_INSERT) printf("INSERT key pressed at (%d,%d)\n",x,y); } /* associazione di f come special callback della finestra corrente */ glutSpecialFunc(f); Mouse callback (chiamata da Glut quando schiaccio o rilascio un bottone del mouse): /* definizione funzione f. b = numero bottone interessato, s = stato (giu' o su), x,y = posizione del mouse */ void f(int b, int s, int x, int y) { printf("Button %d is %s at (%d,%d)\n", b, ((s==GLUT_DOWN) ? "down" : "up"), x, y); } /* associazione di f come mouse callback della finestra corrente */ glutMouseFunc(f); Motion e Passive Motion callback (chiamata da Glut quando muovo il mouse tenendo il bottone premuto o rilasciato, rispettivamente): /* definizione funzione f */ void f(int x, int y) { printf("Button motion at (%d,%d)\n", x, y); } /* associazione di f come motion o passive motion callback */ glutMotionFunc(f); oppure glutPassiveMotionFunc(f); Visibility callback (chiamata da Glut quando lo stato della finestra passa da visibile a invisibile o viceversa): /* definizione funzione f. s = stato attuale (GLUT_VISIBLE o GLUT_NOT_VISIBLE). questo esempio sospende animazione se finestra non visibile */ void f(int s) { if (s==GLUT_VISIBLE) glutIdleFunc(); else glutIdleFunc(NULL); /* nessuna funzione idle */ } /* associazione di f come visibility callback */ glutVisibilityFunc(f); Timer callback (chiamata da Glut dopo intervallo di tempo prestabilito): /* definizione funzione f. v = valore che specifico quando associo la callback */ void f (int v) /* associazione di f come timer callback. k (in millisecondi) = intervallo di tempo dopo il quale deve essere chiamata f, v = valore che viene passato da Glut a f quando la chiama */ glutTimerFunc(k,f,v); Entry callback (chiamata da Glut quando il mouse entra od esce dalla finestra): /* definizione funzione f. s = stato attuale (GLUT_ENTERED o GLUT_LEFT) */ void f (int s) { if (s==GLUT_ENTERED) else } /* associazione di f come entry callback */ glutEntryFunc(f); GESTIONE DI MENU' Glut fornisce supporto per gestione di menu' pop-up a cascata. Pop-up: menu' che appare sovrapposto alla finestra quando premo un tasto del mouse sullo sfondo della finestra, e scompare quando rilascio il bottone. Seleziono le voci scorrendo con il mouse premuto. A cascata: ad una voce di un menu' puo' essere associato un sottomenu' che appare quando scorro con il mouse su quella voce. Per creare un menu': my_menu = glutCreateMenu (f); glutAddMenuEntry("voce 1", 1); glutAddMenuEntry("voce 2", 2); glutAttachMenu(GLUT_RIGHT_BUTTON); dove la funzione f e' definita a parte come: void f (int v) { switch (v) { case 1: case 2: } } ed e' quella che viene chiamata automaticamente da Glut quando l'utente seleziona una delle voci del menu', passando come valore il numero d'ordine della voce selezionata. Spiegazione delle istruzioni: int glutCreateMenu(); crea un menu' gestito dalla funzione , ritorna un identificatore per il menu'. Il menu' appena creato diventa il menu' corrente, tutte le successive istruzioni di manipolazione di menu' si riferiscono al menu' corrente. void glutAddMenuEntry(,); aggiunge una voce al menu' corrente. = stringa da mostrare all'utente, = valore da passare alla funzione di gestione del menu' quando l'utente seleziona quella voce. void glutAttachMenu(); associa il menu' corrente al bottone indicato del mouse: il menu' pop-up apparira' quando viene schiacciato quel bottone. Callback per i menu': E' utile sapere se l'utente sta utilizzando i menu' pop-up, in modo da disattivare funzioni costose (es. animazione) mentre l'utente li usa. La Menu Status callback e' chiamata da Glut quando visualizza o devisualizza un menu' pop-up. /* esempio di funzione callback che sospende animazione mentre qualche menu' e' in uso. status = GLUT_MENU_IN_USE se qualche menu' e' popped-up, altrimenti GLUT_MENU_NOT_IN_USE, x,y = coordinate del mouse quando il menu' e' stato invocato o rilasciato */ void f(int status, int x, int y) { if (status==GLUT_MENU_IN_USE) glutIdleFunc(NULL); else glutIdleFunc(); } /* associazione di f come menu status callback */ glutMenuStatusFunc(f); Menu' annidati: In alternativa a voci di menu' associate a valori interi (che saranno passati alla funzione di gestione del menu'), posso definire voci di menu' con associati sottomenu', che appariranno quando scorro col mouse su quella voce. void glutAddSubMenu(,); aggiunge al menu' corrente una voce che mostra la stringa e invoca il sottomenu' quando selezionata ( e' l'identificatore ritornato da glutCreateMenu quando ho creato il sottomenu') Se un menu' e' attaccato come sottomenu' di un altro, non ha bisogno di essere associato ad un bottone del mouse con glutAttachMenu. Esempio: submenu = glutCreateMenu(f1); glutAddMenuEntry(...) /* aggiunge entry a submenu */ mainmenu = glutCreateMenu(f2); glutAddMenuEntry(...) /* aggiunge entry a mainmenu */ glutAddSubMenu("chiama sottomenu",submenu); glutAttachMenu(GLUT_LEFT_BUTTON); Altre funzioni utili: glutSetMenu(); int glutGetMenu(void); assegna e ritorna il menu' corrente. void glutDestroyMenu(); funzioni per cambiare il contenuto delle voci .... (ved. manuale) VISUALIZZAZIONE DI TESTO In OpenGL e' possibile rendere testo, ma non direttamente, bensi' usando primitive grafiche per realizzare i vari caratteri: - stroke fonts (ogni carattere e' un insieme di linee) - bitmap fonts (ogni carattere e' una bitmap) E' compito del programmatore definire le font, posizionare le i caratteri di una parola uno di seguito all'altro ecc. Glut fornisce font sia stroke che bitmap predefinite e funzioni di piu' alto livello per rendere testo. Entrambe sono realizzate internamente mediante primitive OpenGL e quindi il modo in cui sono rese dipende dallo stato corrente di OpenGL (es. posso cambiarne il colore con glColor...). Una font stroke e' "geometria", immersa nella scena modellata e soggetta alle stesse trasformazioni (puo' scalata, essere ruotata ecc.). Adatta per rendere scritte che sono parte della scena (l'insegna sulla porta...). E' piu' lenta. Una font bitmap viene resa sempre rivolta verso l'utente, colorando i pixel della finestra in accordo allo schema definito dalla bitmap. E' veloce. Adatto per annotare l'immagine della scena (es. mostrare una didascalia...). Testo stroke GlutStrokeCharacter(,); = una delle predefinite: GLUT_STROKE_ROMAN, GLUT_STROKE_MONO_ROMAN = codice ASCII del carattere (da 32 a 127) Teso bitmap glutBitMapCharacter(,); = una delle predefinite: GLUT_BITMAP_8_BY_13, GLUT_BITMAP_9_BY_15, GLUT_BITMAP_TIMES_RIMAN, ... scrive il carattere alla posizione attuale sulla finestra, che puo' essere settata con glRasterPos2i(x,y) con x,y = coordinate in pixel. Glut avanza automaticamente la posizione dopo ogni carattere. Esempio per scrivere stringa s: glRasterPos2i(x,y); for (i=0;s[i]!='\0';i++) { glutBitMapCharacter(,s[i]); }