Claudio Rocchini, Visual Computing Group OpenGL + MFC Claudio Rocchini 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Introduzione Vedremo come si realizza una applicazione OpenGL in ambiente Windows, utilizzando le Microsoft Foundation Class. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group MFC Le Microsoft Foundation Class formano la nota libreria di sviluppo di applicazioni per ambiente Windows. Vedremo come siano state realizzate delle opportune chiamate di libreria per l’interfacciamento di OpenGL. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OpenGL OpenGL è il famoso standard per la visualizzazione grafica bi e tridimensionale. E’ supportato da tutte le piattaforme. Le schede grafiche di ultima generazione lo implementano in hardware. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Cenni su OpenGL (1) Una introduzione ad OpenGL e’ fuori dagli scopi di questa presentazione. Ne evidenzieremo le caratteristiche necessarie all’interfacciamento con il sistema a finestre. http://www.opengl.org 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Cenni su OpenGL (2) I comandi di OpenGL sottintendono un contesto grafico di default, la seguente serie di comandi visualizza un triangolo: glBegin(GL_TRIANGLES); glVertex3f(0,0,-10); glVertex3f(10,0,-10); glVertex3f(0,10,-10); glEnd(); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Cenni su OpenGL (3) In ogni applicazione Windows si puo’ definire un contesto OpenGL corrente che riceve i comandi grafici. Un applicazione multifinestra puo’ alternare vari contesti grafici OpenGL. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group MFC+OpenGL Una volta costruita una applicazione standard MFC sono necessarie alcune aggiunte per l’utilizzo di OpenGL all’interno di una finestra. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Punti principali Scelta del formato pixel. Creazione di un contesto OpenGL (GLRC). Creazione di un Device contest (DC) associato ad una finestra. Collegamento fra GLRC e DC. 12/11/2018 Claudio Rocchini, Visual Computing Group
Inclusione file header Aggiungere nel file header della view: #include <GL\\gl.h> #include <GL\\glu.h> 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Inclusione librerie File di Libreria aggiuntivi 12/11/2018 Claudio Rocchini, Visual Computing Group
Dati aggiuntivi della View I seguenti dati sono aggiunti alla classe view: CPalette m_cPalette; // Palette Personale CPalette *m_pOldPalette; // Vecchia Palette CClientDC *m_pDC; // DC della finestra HGLRC m_hrc; // Contesto OpenGL 12/11/2018 Claudio Rocchini, Visual Computing Group
Dati per multifinestra In caso di gestione multifinestra e’ necessario aggiunge alla view il seguente: // IL proprietario del contesto GL static CGlwrapperView * m_glOwner; Nel file …view.cpp si dichiara: CGlwrapperView * CGlwrapperView::m_glOwner = 0; 12/11/2018 Claudio Rocchini, Visual Computing Group
Inizializzazione variabili // E’ importante ricordarsi di inizializzare le variabili nel costruttore della classe. CGlwrapperView::CGlwrapperView() { m_pOldPalette = 0; m_pDC = 0; m_hrc = 0; } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Funzione di switch inline BOOL SetGL() { if(m_glOwner!=this) { if(!wglMakeCurrent(m_pDC->GetSafeHdc(),m_hrc)) { AfxMessageBox("GlMakeCurrent Error"); return FALSE; } m_glOwner = this; return TRUE; 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Messaggi e Virtual Attraverso il Class Wizard e’ necessario inserire alcuni gestori di messaggi 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Gestori necessari I gestori necessari sono: Create PrecreateWindow(*) OnDraw(*) OnSize OnEraseBkgnd OnDestroy (*) Gia’ dichiarati dall’Application Wizard 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Create (1/5) //Creazione finestra if( !CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext) ) return FALSE; 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Create (2/5) // Creazione DC (Contesto grafico standard) m_pDC = new CClientDC(this); ASSERT(m_pDC != NULL); // Setta il pixel format e crea la palette if (!SetupPixelFormat(m_pDC)) return FALSE; 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Create (3/5) // Creazione palette (se necessaria) if( CreateRGBPalette(m_pDC,m_cPalette) ) { m_pOldPalette = m_pD->SelectPalette( &m_cPalette, FALSE); m_pDC->RealizePalette(); } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Create (4/5) // Crea e setta il contesto OPENGL m_hrc = wglCreateContext( m_pDC->GetSafeHdc()); if(m_hrc==NULL) { AfxMessageBox("OpenGL contest fail"); return FALSE; } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Create (5/5) // Inizializzazioni GL SetGL(); InitGL(); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Gestione palette La palette serve solo in caso di schermo a 256 colori(obsoleto). Si realizza tramite le specifiche della Microsoft. Si puo’ scaricare l’implementazione di default dal sito: vcg.iei.pi.cnr.it/˜rocchini/corso.html 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Pixel Format (1/2) Prima di inizializzare OpenGL e’ necessario settare il tipo di supporto pixel, che comprende: Numero di pixel colore Profondita’ z-buffer Tipo di buffer (singolo/doppio) … I settaggi vengono inseriti nella struttura PIXELFORMATDESCRIPTOR. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Pixel Format(2/2) // Esempio di codice di richiesta di formato if ( (pixelformat = ChoosePixelFormat(pDC->GetSafeHdc(), &pfd)) == 0 ) { AfxMessageBox("ChoosePixelFormat failed"); return FALSE; } if (SetPixelFormat(pDC->GetSafeHdc(), pixelformat, &pfd) == FALSE) AfxMessageBox("SetPixelFormat failed"); 12/11/2018 Claudio Rocchini, Visual Computing Group
Inizializzazioni OpenGL Le inizializzazioni di OpenGL non fanno parte del sistema di finestre, ma sono state citate perche’ indispensabili per la visualizzazione della finestra OpenGl (per evitare l’effetto “finestra nera”). 12/11/2018 Claudio Rocchini, Visual Computing Group
Esempi di settaggi OpenGL glClearDepth(1.0f); glShadeModel( GL_SMOOTH ); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glDisable(GL_CULL_FACE); glEnable(GL_LIGHT0); fv4[0]=0.1f; fv4[1]=0.1f; fv4[2]=0.1f; fv4[3]=1.0f; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fv4); glLightfv(GL_LIGHT0, GL_POSITION, fv4); glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4); glEnable(GL_LIGHTING); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnDestroy (1/2) Alla fine dell’utilizzo delle strutture OpenGl e’ importante chiamare le funzioni di rilascio delle risorse. Queste funzioni devono essere chiamate subito prima la distruzione della finestra View. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnDestroy (2/2) void CGlwrapperView::OnDestroy() { SetGL(); glFinish(); wglMakeCurrent(NULL, NULL); if (m_hrc) ::wglDeleteContext(m_hrc); if (m_pOldPalette) m_pDC->SelectPalette(m_pOldPalette, FALSE); if (m_pDC) delete m_pDC; m_glOwner = NULL; CView::OnDestroy(); } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group PreCreateWindow // Lo stile della finestra deve contenere le seguenti specifiche: BOOL CGlwrapperView::PreCreateWindow( CREATESTRUCT& cs) { cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CS_OWNDC; return CView::PreCreateWindow(cs); } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Erase Background // Questa callback impedisce al sistema di disegnare lo sfondo bianco di defalt: BOOL CGlwrapperView::OnEraseBkgnd(CDC* pDC) { return TRUE; } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnSize (1/3) OnSize e’ chiamata alla creazione della Finestra e ad ogni cambiamento di dimensione. Si deve occupare di comunicare ad OpenGL l’effettiva dimensione della finestra (viewport) Deve settare il tipo di proiezione di visualizzazione (ortogonale/prospettica) 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnSize (2/3) void CGlwrapperView::OnSize(UINT nType, int cx, int cy) { CView::OnSize(nType, cx, cy); if(cx!=0 && cy!=0) … gestione dimensione… } 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnSize (3/3) const float fNearP = 0.1f; const float fFarP = 20.0f; const float fPAngle = 45.0f; SetGL(); glViewport(0, 0, cx, cy); GLfloat fAspect; if (cy) fAspect = GLfloat(cx)/cy; else fAspect = 1.0f; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fPAngle, fAspect, fNearP, fFarP); glMatrixMode(GL_MODELVIEW); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnDraw, introduzione OnDraw, finalmente, visualizza effettivamente il contesto OpenGl. Deve contenere il codice utente per la visualizzazione 12/11/2018 Claudio Rocchini, Visual Computing Group
OnDraw, sezione critica (1/2) OpenGL e intrinsecamente asincrono, vale a dire che la visualizzazione continua in parallelo con il programma. E’ possibile che il sistema chiami più volte OnDraw, prima che la visualizzazione sia terminata. 12/11/2018 Claudio Rocchini, Visual Computing Group
OnDraw, sezione critica (2/2) void CGlwrapperView::OnDraw(CDC* pDC) { if(pDC==NULL) return; static BOOL bBusy = FALSE; if(bBusy) return; bBusy = TRUE; … SEZIONE PRINCIPALE… bBusy = FALSE; } 12/11/2018 Claudio Rocchini, Visual Computing Group
OnDraw, sezione principale SetGL(); // Setta il contesto corrente // Cancellazione buffer glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); … COMANDI UTENTE… glFinish(); SwapBuffers(wglGetCurrentDC()); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnDraw Ottimizzata SetGL(); // Setta il contesto corrente glLoadIdentity(); … COMANDI UTENTE… glFinish(); SwapBuffers(wglGetCurrentDC()); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group OnDraw, comandi utente Esempio di comandi utente (visualizzazione triangolo): glBegin(GL_TRIANGLES); glVertex3f(0,0,-10); glVertex3f(10,0,-10); glVertex3f(0,10,-10); glEnd(); 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Applicazione L’applicazione e’ finalmente pronta per essere compilata ed eseguita. 12/11/2018 Claudio Rocchini, Visual Computing Group
Un comodo tool: Trackball Nel sito web del corso e’ possibile scaricare il sorgente del programma, che comprende la classe Trackball per La manipolazione della vista. 12/11/2018 Claudio Rocchini, Visual Computing Group
Visualizzazioni animate, intro La visualizzazione della finestra OpenGl avviene su richiesta del sistema, quando e’ necessario ridisegnarne il contenuto. In alcune applicazioni e’ necessario invece ridisegnare la finestra OpenGL su richiesta dell’applicazione. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Animazioni, il Timer Una prima possibilità è quella di usare un timer (classe Ctimer), che periodicamente genera il messaggio WM_TIMER. Il messaggio può essere gestito dall’applicazione per generare animazioni. Questa soluzione non è però efficace; infatti il timer non è affidabile per intervalli inferiori al secondo. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Animazioni, OnIdle Una soluzione migliore è l’utilizzo della funzione OnIdle, della classe Applicazione. Tale funzione viene chiamata tutte le volte che il sistema ha finito le sue operazioni. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Esercizi Scaricare lo scheletro di applicazione glwrapper, oppure rigenerarlo da zero e: Visualizzare grafici di funzioni da R2 a R. Visualizzare oggetti animati nel tempo, utilizzando Onidle Realizzare una versione di graphedit visualizzata in OpenGL. 12/11/2018 Claudio Rocchini, Visual Computing Group
Claudio Rocchini, Visual Computing Group Contatti Claudio Rocchini Visual Computing Group Istituto Elaborazione Informazione Area della Ricerca di Pisa Email: rocchini@iei.pi.cnr.it Tel: 050-3152926 12/11/2018 Claudio Rocchini, Visual Computing Group