Salut à tous !
J’avance doucement dans la conversion des tutoriels de NeHe vers GtkGLExtmm. On peut trouver tous ce qu’il faut pour s’en sortir sur Internet, mais c’est tout de même épars et on risque régulièrement de faire fausse route. Du coup, je pense proposer aux responsables de la page de Developez.com des tutoriels de NeHe de stocker mes codes, cela fera un exemple pour ceux qui voudraient se lancer dans l’aventure. Autant que le temps que je passe à m’en sortir serve à d’autres.
Pour l’instant, je me pose des questions sur la bonne utilisation de la fonction « create_gl_context() ». Dans la mesure où je cherche à faire en sorte que le code n’en fasse pas plus que nécessaire, je ne l’utilise que dans le contrôleur de l’évènement « realize », c’est-à-dire, si j’ai bien tout compris, à l’initialisation de la fenêtre. Dans mes sources, il s’agit de la procédure « on_realize_event », dont la définition se trouve dans le fichier « src/fenetre.hpp » et l’implémentation dans le fichier « src/fenetre.cpp ».
Le code fonctionne sans problème, mais je voudrais m’assurer que je ne fais pas fausse route, dans la mesure où le tutoriel officiel, par exemple dans l’horloge basée sur Cairo, appelle « create_cairo_context() » dans le contrôleur de l’évènement « expose ». Cela dit, je soupçonne le tutoriel de faire ainsi pour limiter le nombre de lignes de codes (il n’est alors pas besoin de contrôleur pour l’évènement « realize »).
Donc, est-il possible de confirmer que l’on peut appeler la fonction « create_gl_context() » une seule fois et ensuite utiliser ce contexte à chaque fois qu’il en est besoin ?
Je gère le code à l’aide de CMake, je fournis ici fichier « CMakelists.txt » associé, qui est situé dans le répertoire racine du projet. Toutes les sources du code sont tous regroupés dans un sous-répertoire nommé « src ».
Fichier « CMakeLists.txt » :
Fichier « src/erreurs.hpp » :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 ## Génération des tutoriels OpenGL de NeHe version OpenGL. cmake_minimum_required(VERSION 2.6) project(Tutoriel1 CXX) # Répertoire où placer lexécutable. set(EXECUTABLE_OUTPUT_PATH bin/${CMAKE_BUILD_TYPE}) # Nom de lexécutable. set(EXECUTABLE_NAME tutoriel1) find_package(PkgConfig) pkg_check_modules(Glibmm glibmm-2.4>=2.4.0) pkg_check_modules(GTKmm gtkmm-2.4>=2.4.0) pkg_check_modules(GLExtmm gtkglextmm-1.2>=1.2.0) link_directories( ${Glibmm_LIBRARY_DIRS} ${GTKmm_LIBRARY_DIRS} ${GLExtmm_LIBRARY_DIRS} ) include_directories( ${Glibmm_INCLUDE_DIRS} ${GTKmm_INCLUDE_DIRS} ${GLExtmm_INCLUDE_DIRS} ) file( GLOB_RECURSE source_files src/* ) add_executable( ${EXECUTABLE_NAME} ${source_files} ) target_link_libraries( ${EXECUTABLE_NAME} ${Glibmm_LIBRARIES} ${GTKmm_LIBRARIES} ${GLExtmm_LIBRARIES} )
Fichier « src/fenetre.hpp » :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 #ifndef ERREURS_HPP #define ERREURS_HPP /* * Exceptions pour la gestions des erreurs. */ #include <exception> #include <sstream> /* Espace de nommage pour la gestion des erreurs. */ namespace Erreurs { /* -- Erreurs provoquées par linterface graphique. ---------------------- */ class ErreurInterface: public std::exception { public: /* Constructeur par défaut. */ ErreurInterface () throw () {} /* Destructeur. */ virtual ~ErreurInterface () throw () {} /* Génére le message derreur. */ virtual const char* what () const throw () { /* Le message derreur. */ std::stringstream message; message << "une erreur sest produite dans linterface graphique."; return message.str().c_str(); } }; /* -- Erreurs lors de la création du contexte OpenGL. -------------------- */ class ErreurCreationContexte: public ErreurInterface { public: /* Constructeur par défaut. */ ErreurCreationContexte () throw () {} /* Destructeur. */ virtual ~ErreurCreationContexte () throw () {} /* Génère le message derreur. */ virtual const char* what () const throw () { /* Le message derreur. */ std::stringstream message; message << "impossible de créer un contexte OpenGL."; return message.str().c_str(); } }; /* -- Erreurs à lobtention du contexte OpenGL. -------------------------- */ class ErreurObtentionContexte: public ErreurInterface { public: /* Constructeur par défaut. */ ErreurObtentionContexte () throw () {} /* Destructeur. */ virtual ~ErreurObtentionContexte () throw () {} /* Génère le message derreur. */ virtual const char* what () const throw () { /* Le message derreur. */ std::stringstream message; message << "impossible dobtenir le contexte OpenGL."; return message.str().c_str(); } }; } #endif // #ifndef ERREURS_HPP
Fichier « src/fenetre.cpp » :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 #ifndef FENETRE_HPP #define FENETRE_HPP /* * Définitions des classes gérants le fenêtrage OpenGL. */ #include <gtkmm/window.h> #include <gtkmm/drawingarea.h> #include <gtkglmm.h> #include "erreurs.hpp" /* Espace de nommage pour la gestion de linterface. */ namespace Interface { /* Classe pour la zone de rendu OpenGL. */ class GlDrawingArea: public Gtk::DrawingArea, public Gtk::GL::Widget<GlDrawingArea> { private: /* Indique si on se trouve en mode plein écran. */ bool pleinEcran; public: GlDrawingArea (); virtual ~GlDrawingArea (); protected: /* -- Controlleurs: */ /* À linitialisation de la fenêtre. */ virtual void on_realize (); /* À la demande daffichage. */ virtual bool on_expose_event (GdkEventExpose* event); /* Au changement de taille de la fenêtre. */ virtual bool on_configure_event (GdkEventConfigure* event); }; /* ----------------------------------------------------------------------- */ /* Classe pour la fenetre principale. */ class Fenetre: public Gtk::Window { public: Fenetre (); virtual ~Fenetre(); private: /* -- Composants membres : */ /* Zone de rendu OpenGL. */ GlDrawingArea zoneRendu; }; } #endif // #ifndef FENETRE_HPP
Fichier « src/main.cpp » :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 /* * Implémentations du fenêtrage OpenGL. */ #include <glibmm/error.h> #include <cstdlib> #include <GL/gl.h> #include <GL/glu.h> #include <sstream> #include "fenetre.hpp" /* -- Constructeur par défaut de GlDrawingArea. -------------------------- */ Interface::GlDrawingArea::GlDrawingArea (): Gtk::DrawingArea (), pleinEcran (true) { /* Configuration dOpenGL */ Glib::RefPtr<Gdk::GL::Config> configuration; /* Tente douvrir une espace à double tampon. */ configuration = Gdk::GL::Config::create(Gdk::GL::MODE_RGBA | Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_DOUBLE); if (!configuration) { g_warning("Impossible de configurer OpenGL en mode double tampon, tente le mode simple tampon.\n"); /* Tente de configurer un tampon simple. */ configuration = Gdk::GL::Config::create(Gdk::GL::MODE_RGBA | Gdk::GL::MODE_DEPTH); if (!configuration) { g_critical("Impossible de configurer OpenGL.\n"); std::exit(-2); } } /* Donne accès à OpenGL au composant. */ set_gl_capability(configuration); } /* -- Destructeur de GlDrawingArea. -------------------------------------- */ Interface::GlDrawingArea::~GlDrawingArea () { } /* -- Initialisation du contexte OpenGL. --------------------------------- */ void Interface::GlDrawingArea::on_realize () { Gtk::Widget::on_realize(); if (!create_gl_context()) throw Erreurs::ErreurCreationContexte (); /* Fenêtre OpenGL. */ Glib::RefPtr<Gdk::GL::Window> fenetreGl = get_gl_window(); if (!fenetreGl) throw Erreurs::ErreurObtentionContexte (); fenetreGl->gl_begin(get_gl_context()); /* Permet un joli ombrage. */ glShadeModel(GL_SMOOTH); /* Fond noir. */ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); /* Mis en place du tampon de profondeur. */ glClearDepth(1.0f); /* Mis en place du test de profondeur. */ glEnable(GL_DEPTH_TEST); /* Le type de test de profondeur . */ glDepthFunc(GL_LEQUAL); /* Très jolis calculs de perspective. */ glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); fenetreGl->gl_end(); } /* -- À la demande daffichage de GlDrawingArea. ------------------------ */ bool Interface::GlDrawingArea::on_expose_event (GdkEventExpose* event) { /* Fenêtre OpenGL. */ Glib::RefPtr<Gdk::GL::Window> fenetreGl = get_gl_window(); if (!fenetreGl) throw Erreurs::ErreurObtentionContexte (); fenetreGl->gl_begin(get_gl_context()); // glClear(GL_COLOR_BUFFER_BIT); /* Vide l'écran et le Z-Buffer (Depth Buffer : contient les informations de profondeur de chaque pixel). */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Repositionne la caméra. */ glLoadIdentity(); /* Bouge de 1.5 unités vers la gauche et de 6.0 unités vers l'intérieur de l'écran. */ glTranslatef(-1.5f,0.0f,-6.0f); /* Dessiner un Triangle. */ glBegin(GL_TRIANGLES); /* Point du haut. */ glVertex3f( 0.0f, 1.0f, 0.0f); /* Point en bas à gauche. */ glVertex3f(-1.0f,-1.0f, 0.0f); /* Point en bas à droite */ glVertex3f( 1.0f,-1.0f, 0.0f); /* Le dessin du Triangle est fini */ glEnd(); /* Bouge de 3.0f unités vers la droite. */ glTranslatef(3.0f,0.0f,0.0f); /* Dessin d'un quadrilatère. */ glBegin(GL_QUADS); /* Haut Gauche. */ glVertex3f(-1.0f, 1.0f, 0.0f); /* Haut Droite. */ glVertex3f( 1.0f, 1.0f, 0.0f); /* Bas Droite. */ glVertex3f( 1.0f,-1.0f, 0.0f); /* Bas Gauche. */ glVertex3f(-1.0f,-1.0f, 0.0f); glEnd(); fenetreGl->gl_end(); fenetreGl->swap_buffers(); return Gtk::Widget::on_expose_event(event); } /* -- Lorsque la fenêtre est redimensionnée. ----------------------------- */ bool Interface::GlDrawingArea::on_configure_event (GdkEventConfigure* event) { /* Fenêtre OpenGL. */ Glib::RefPtr<Gdk::GL::Window> fenetreGl = get_gl_window(); if (!fenetreGl) throw Erreurs::ErreurObtentionContexte (); fenetreGl->gl_begin(get_gl_context()); /* Choisir la matrice de projection. */ glMatrixMode(GL_PROJECTION); /* Remettre a zéro de la matrice de projection. */ glLoadIdentity(); /* Calculer le ratio pour la perspective de la fenêtre. */ gluPerspective(45.0f, static_cast<GLfloat>(get_width()) / static_cast<GLfloat>(get_height()), 0.1f,100.0f); /* Choisir la matrice de modélisation. */ glMatrixMode(GL_MODELVIEW); /* Remetre à zéro la matrice de modélisation. */ glLoadIdentity(); fenetreGl->gl_end(); return Gtk::Widget::on_configure_event(event); } /* -- Constructeur par défaut de la fenêtre. ----------------------------- */ Interface::Fenetre::Fenetre (): Gtk::Window (), zoneRendu () { set_title("Tutoriel 1"); set_default_size(640, 480); set_border_width(2); add(zoneRendu); show_all_children(); } /* -- Destructeur de la fenêtre. ----------------------------------------- */ Interface::Fenetre::~Fenetre () { }
Par ailleurs, si vous avez des remarques sur la façon de faire, n’hésitez pas : j’essaye de trouver les meilleures pratiques.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 /* * Premier tutoriel : création dune fenêtre avec une zone OpenGL. */ #include <iostream> #include <gtkmm/main.h> #include <gtkglmm.h> #include <sstream> #include <glibmm/error.h> #include <exception> #include "erreurs.hpp" #include "fenetre.hpp" /* * Principale fonction du programme. * Entrées : * argc Nombre darguments. * argv Valeures des arguments. * Retourne : * 0 si tout sest bien passé. * -1 en cas derreur venant de la GLib ou de ses dérivés. * -2 en cas derreur en provenance dOpenGL. * -3 en cas derreur en provenance de la bibliothèque standard. * -4 en cas derreur non standard. */ int main (int argc, char** argv) { try { /* Boucle dévènements. */ const Gtk::Main kit(argc, argv); Gtk::GL::init(argc, argv); /* Fenêtre principale. */ Interface::Fenetre principale; kit.run(principale); return 0; } catch(const Glib::Error &ex) { /* Message derreur. */ std::ostringstream message; message << "Erreur venant de GLib : " << ex.what() << '\n'; g_warning(message.str().c_str()); return -1; } catch (const Erreurs::ErreurInterface &e) { /* Message derreur. */ std::stringstream message; message << "Erreur de contexte OpenGL : " << e.what() << '\n'; g_critical(message.str().c_str()); return -2; } catch (const std::exception &e) { /* Message derreur. */ std::stringstream message; message << "Erreur venant de la bibliothèque standard : " << e.what() << '\n'; g_critical(message.str().c_str()); return -3; } catch (...) { g_critical("Exception non-standard.\n"); return -4; } }
À bientôt.
Le Farfadet Spatial
Partager