1 // sous mac 
  2 // g++ -I/usr/local/include/ -lglfw -lGLEW -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_imgcodecs main6.cpp -framework OpenGL -omain6
  3 // ./main6
  4 
  5 // sous linux   
  6 // g++ -I/usr/local/include/ -I/public/ig/glm/ -c main6.cpp  -omain6.o
  7 // g++ -I/usr/local main6.o -lglfw  -lGLEW  -lGL -lopencv_core -lopencv_imgproc -lopencv_highgui  -lopencv_imgcodecs -omain6
  8 // ./main6
  9 
 10 // Inclut les en-têtes standards
 11 #include <stdio.h>
 12 #include <string>
 13 #include <vector>
 14 #include <iostream>
 15 #include <fstream>
 16 #include <algorithm>
 17 using namespace std;
 18 
 19 #include <stdlib.h>
 20 #include <string.h>
 21 
 22 #include <GL/glew.h>
 23 #include <GLFW/glfw3.h>
 24 
 25 #ifdef __APPLE__
 26 #include <OpenGL/gl.h>
 27 #else
 28 #include <GL/gl.h>
 29 #endif
 30 
 31 #include <opencv2/core/core.hpp>
 32 #include <opencv2/highgui/highgui.hpp>
 33 using namespace cv;
 34 
 35 #define GLM_FORCE_RADIANS
 36 #include <glm/glm.hpp>
 37 #include <glm/gtc/matrix_transform.hpp>
 38 #include <glm/gtc/type_ptr.hpp>
 39 
 40 using namespace glm;
 41 
 42 
 43 // Le nombre de donnees
 44 const int N = 12;
 45 
 46 // Avec 3 parties dans le VBO ca commence a etre complique. On va stocker la taille
 47 // des 3 parties dans des variables pour plus facilement calculer les decallages
 48 long vertexSize, colorSize, texCoordSize;
 49 
 50 // Les donnees sous forme de pointeur. Il faudra donc faire un malloc
 51 // pour allouer de l'espace avant de mettre des donnees dedans
 52 GLfloat *g_vertex_buffer_data   = NULL;
 53 GLfloat *g_vertex_color_data    = NULL;
 54 GLfloat *g_vertex_texcoord_data = NULL;
 55 
 56 // l'angle de rotation de la camera autour du modele
 57 float angleRot = 0.0f;
 58 
 59 // LA fenetre
 60 GLFWwindow* window; 
 61 
 62 // La texture d'alphabet
 63 GLuint texId;
 64 
 65 // la vitesse initiale
 66 float speed = 0.0; 
 67 
 68 // La taille de notre fenetre
 69 int winWidth  = 800;
 70 int winHeight = 400;
 71 
 72 // La taille de notre texture
 73 int texWidth  = -1;
 74 int texHeight = -1;
 75 
 76 // This will identify our vertex buffer (VBO)
 77 GLuint vertexbuffer;
 78 
 79 // Identifiant de notre VAO
 80 GLuint vertexArrayID;
 81 
 82 // identifiant de notre programme de shaders
 83 GLuint programID;
 84 
 85 
 86 // stocke les variables uniformes qui seront communes a tous les vertex dessines
 87 GLint uniform_proj, uniform_view, uniform_model, uniform_texture;
 88 
 89 
 90 // Charge une texture et retourne l'identifiant openGL
 91 GLuint LoadTexture(string fileName){
 92   GLuint tId = -1;
 93   // On utilise OpenCV pour charger l'image
 94   Mat image = imread(fileName, CV_LOAD_IMAGE_UNCHANGED);
 95 
 96   // On va utiliser des TEXTURE_RECTANGLE au lieu de classiques TEXTURE_2D
 97   // car avec ca les coordonnees de texture s'exprime en pixels  et non en coordoonnes homogenes (0.0...1.0)
 98   // En effet la texture est composee de lettres et symbole que nous voudrons extraire... or la position et
 99   // taille de ces symboles dans la texture sont connuees en "pixels". Ca sera donc plus facile 
100 
101   //comme d'hab on fait generer un numero unique(ID) par OpenGL
102   glGenTextures(1, &tId);
103 
104   texWidth  = image.cols;
105   texHeight = image.rows;
106 
107   glBindTexture(GL_TEXTURE_RECTANGLE, tId);
108     // on envoie les pixels a la carte graphique
109     glTexImage2D(GL_TEXTURE_RECTANGLE, 
110                  0,           // mipmap level => Attention pas de mipmap dans les textures rectangle
111                  GL_RGBA,     // internal color format
112                  image.cols, 
113                  image.rows, 
114                  0,           // border width in pixels
115                  GL_BGRA,     // input file format. Arg le png code les canaux dans l'autre sens
116                  GL_UNSIGNED_BYTE, // image data type
117                  image.ptr());
118     // On peut donner des indication a opengl sur comment la texture sera utilisee 
119     glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
120     glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
121     glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
122     glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
123 
124   // INTERDIT sur les textures rectangle!
125   //glGenerateMipmap(GL_TEXTURE_2D);
126   glBindTexture(GL_TEXTURE_RECTANGLE, 0);
127 
128   return tId;
129 }
130 
131 
132 // Charge un programme de shaders, le compile et recupere dedans des pointeurs vers
133 // les variables homogenes que nous voudront mettre a jour plus tard, a chaque dessin 
134 GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path){
135 
136   // Create the shaders
137   GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
138   GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
139 
140   // Read the Vertex Shader code from the file
141   string VertexShaderCode;
142   ifstream VertexShaderStream(vertex_file_path, ios::in);
143   if(VertexShaderStream.is_open()){
144     string Line = "";
145     while(getline(VertexShaderStream, Line))
146       VertexShaderCode += "\n" + Line;
147     VertexShaderStream.close();
148   }else{
149     printf("Impossible to open %s. Are you in the right directory ? Don't forget to read the FAQ !\n", vertex_file_path);
150     getchar();
151     return 0;
152   }
153 
154   // Read the Fragment Shader code from the file
155   string FragmentShaderCode;
156   ifstream FragmentShaderStream(fragment_file_path, ios::in);
157   if(FragmentShaderStream.is_open()){
158     string Line = "";
159     while(getline(FragmentShaderStream, Line))
160       FragmentShaderCode += "\n" + Line;
161     FragmentShaderStream.close();
162   }
163 
164   GLint Result = GL_FALSE;
165   int InfoLogLength;
166 
167 
168   // Compile Vertex Shader
169   printf("Compiling shader : %s\n", vertex_file_path);
170   char const * VertexSourcePointer = VertexShaderCode.c_str();
171   glShaderSource(VertexShaderID, 1, &VertexSourcePointer , NULL);
172   glCompileShader(VertexShaderID);
173 
174   // Check Vertex Shader
175   glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
176   glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
177   if ( InfoLogLength > 0 ){
178     vector<char> VertexShaderErrorMessage(InfoLogLength+1);
179     glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
180     printf("%s\n", &VertexShaderErrorMessage[0]);
181   }
182 
183 
184 
185   // Compile Fragment Shader
186   printf("Compiling shader : %s\n", fragment_file_path);
187   char const * FragmentSourcePointer = FragmentShaderCode.c_str();
188   glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer , NULL);
189   glCompileShader(FragmentShaderID);
190 
191   // Check Fragment Shader
192   glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
193   glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
194   if ( InfoLogLength > 0 ){
195     vector<char> FragmentShaderErrorMessage(InfoLogLength+1);
196     glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
197     printf("%s\n", &FragmentShaderErrorMessage[0]);
198   }
199 
200 
201   // Link the program
202   printf("Linking program\n");
203   GLuint progID = glCreateProgram();
204   glAttachShader(progID, VertexShaderID);
205   glAttachShader(progID, FragmentShaderID);
206   glLinkProgram(progID);
207 
208 
209   // Check the program
210   glGetProgramiv(progID, GL_LINK_STATUS, &Result);
211   glGetProgramiv(progID, GL_INFO_LOG_LENGTH, &InfoLogLength);
212   if ( InfoLogLength > 0 ){
213     vector<char> ProgramErrorMessage(InfoLogLength+1);
214     glGetProgramInfoLog(progID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
215     printf("%s\n", &ProgramErrorMessage[0]);
216   }
217 
218   
219   glDetachShader(progID, VertexShaderID);
220   glDetachShader(progID, FragmentShaderID);
221   
222   glDeleteShader(VertexShaderID);
223   glDeleteShader(FragmentShaderID);
224 
225   return progID;
226 }
227 
228 
229 void generateData(float texw, float texh){
230   vertexSize   = 9*5*N*sizeof(GLfloat);
231   colorSize    = 9*5*N*sizeof(GLfloat);
232   texCoordSize = 3*2*5*N*sizeof(GLfloat);
233 
234   if (g_vertex_buffer_data != NULL)
235     free(g_vertex_buffer_data);
236 
237   if (g_vertex_color_data!= NULL)
238     free(g_vertex_color_data);
239   
240   if (g_vertex_texcoord_data!= NULL)
241     free(g_vertex_texcoord_data);
242 
243   g_vertex_buffer_data   = (GLfloat*)malloc(vertexSize);
244   g_vertex_color_data    = (GLfloat*)malloc(colorSize);
245   g_vertex_texcoord_data = (GLfloat*)malloc(texCoordSize);
246 
247   for (int i=0; i<N; i++){
248     float r = (500+rand()%500)/1000.0; 
249     g_vertex_buffer_data[ 0+i*9*5] = 0.0;
250     g_vertex_buffer_data[ 1+i*9*5] = 0.0;
251     g_vertex_buffer_data[ 2+i*9*5] = 0.0;
252 
253     g_vertex_buffer_data[ 3+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
254     g_vertex_buffer_data[ 4+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
255     g_vertex_buffer_data[ 5+i*9*5] = r/5.0;
256 
257     g_vertex_buffer_data[ 6+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
258     g_vertex_buffer_data[ 7+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
259     g_vertex_buffer_data[ 8+i*9*5] = r/5.0;
260 
261 
262     g_vertex_buffer_data[ 9+i*9*5] = 0.0;
263     g_vertex_buffer_data[10+i*9*5] = 0.0;
264     g_vertex_buffer_data[11+i*9*5] = 0.0;
265 
266     g_vertex_buffer_data[12+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
267     g_vertex_buffer_data[13+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
268     g_vertex_buffer_data[14+i*9*5] = r/5.0;
269 
270     g_vertex_buffer_data[15+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
271     g_vertex_buffer_data[16+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
272     g_vertex_buffer_data[17+i*9*5] = 0.0;
273 
274 
275     g_vertex_buffer_data[18+i*9*5] = 0.0;
276     g_vertex_buffer_data[19+i*9*5] = 0.0;
277     g_vertex_buffer_data[20+i*9*5] = 0.0;
278 
279     g_vertex_buffer_data[21+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
280     g_vertex_buffer_data[22+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
281     g_vertex_buffer_data[23+i*9*5] = r/5.0;
282 
283     g_vertex_buffer_data[24+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
284     g_vertex_buffer_data[25+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
285     g_vertex_buffer_data[26+i*9*5] = 0.0;    
286 
287 
288     g_vertex_buffer_data[27+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
289     g_vertex_buffer_data[28+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
290     g_vertex_buffer_data[29+i*9*5] = r/5.0;
291 
292     g_vertex_buffer_data[30+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
293     g_vertex_buffer_data[31+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
294     g_vertex_buffer_data[32+i*9*5] = r/5.0;
295 
296     g_vertex_buffer_data[33+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
297     g_vertex_buffer_data[34+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
298     g_vertex_buffer_data[35+i*9*5] = 0.0;    
299 
300     g_vertex_buffer_data[36+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
301     g_vertex_buffer_data[37+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
302     g_vertex_buffer_data[38+i*9*5] = r/5.0;
303 
304     g_vertex_buffer_data[39+i*9*5] = 0.0+r*cos((2*i+0)*M_PI/(N));
305     g_vertex_buffer_data[40+i*9*5] = 0.0+r*sin((2*i+0)*M_PI/(N));
306     g_vertex_buffer_data[41+i*9*5] = 0.0;
307 
308     g_vertex_buffer_data[42+i*9*5] = 0.0+r*cos((2*i+1.9)*M_PI/(N));
309     g_vertex_buffer_data[43+i*9*5] = 0.0+r*sin((2*i+1.9)*M_PI/(N));
310     g_vertex_buffer_data[44+i*9*5] = 0.0;    
311 
312 
313     g_vertex_color_data[ 0+i*9*5] = 0.0;
314     g_vertex_color_data[ 1+i*9*5] = 0.0;
315     g_vertex_color_data[ 2+i*9*5] = 1.0;
316 
317     g_vertex_color_data[ 3+i*9*5] = 0.5;
318     g_vertex_color_data[ 4+i*9*5] = 0.0;
319     g_vertex_color_data[ 5+i*9*5] = 0.0;
320 
321     g_vertex_color_data[ 6+i*9*5] = 1.0;
322     g_vertex_color_data[ 7+i*9*5] = 0.0;
323     g_vertex_color_data[ 8+i*9*5] = 0.0;
324 
325     g_vertex_color_data[ 9+i*9*5] = 0.5;
326     g_vertex_color_data[10+i*9*5] = 0.0;
327     g_vertex_color_data[11+i*9*5] = 1.0;
328 
329     g_vertex_color_data[12+i*9*5] = 0.5;
330     g_vertex_color_data[13+i*9*5] = 0.0;
331     g_vertex_color_data[14+i*9*5] = 0.0;
332 
333     g_vertex_color_data[15+i*9*5] = 0.5;
334     g_vertex_color_data[16+i*9*5] = 0.0;
335     g_vertex_color_data[17+i*9*5] = 0.0;    
336 
337     g_vertex_color_data[18+i*9*5] = 1.0;
338     g_vertex_color_data[19+i*9*5] = 0.0;
339     g_vertex_color_data[20+i*9*5] = 1.0;
340 
341     g_vertex_color_data[21+i*9*5] = 1.0;
342     g_vertex_color_data[22+i*9*5] = 0.0;
343     g_vertex_color_data[23+i*9*5] = 0.0;
344 
345     g_vertex_color_data[24+i*9*5] = 1.0;
346     g_vertex_color_data[25+i*9*5] = 0.0;
347     g_vertex_color_data[26+i*9*5] = 0.0;    
348 
349     g_vertex_color_data[27+i*9*5] = 1.0;
350     g_vertex_color_data[28+i*9*5] = 0.0;
351     g_vertex_color_data[29+i*9*5] = 0.0;    
352 
353     g_vertex_color_data[30+i*9*5] = 0.5;
354     g_vertex_color_data[31+i*9*5] = 0.0;
355     g_vertex_color_data[32+i*9*5] = 0.0;
356 
357     g_vertex_color_data[33+i*9*5] = 1.0;
358     g_vertex_color_data[34+i*9*5] = 0.0;
359     g_vertex_color_data[35+i*9*5] = 0.0;  
360 
361     g_vertex_color_data[36+i*9*5] = 0.5;
362     g_vertex_color_data[37+i*9*5] = 0.0;
363     g_vertex_color_data[38+i*9*5] = 0.0;    
364 
365     g_vertex_color_data[39+i*9*5] = 0.5;
366     g_vertex_color_data[40+i*9*5] = 0.0;
367     g_vertex_color_data[41+i*9*5] = 0.0;
368 
369     g_vertex_color_data[42+i*9*5] = 1.0;
370     g_vertex_color_data[43+i*9*5] = 0.0;
371     g_vertex_color_data[44+i*9*5] = 0.0;  
372 
373 
374     // on doit maintenant generer des coordonnees de texture pour chaque vertex. 
375     // Meme ceux qu'on ne veux pas texturer ! La prochaine fois on fera 2 programmes "shader"
376     // avec 2 VBO, 2 VAO, etc. 
377     g_vertex_texcoord_data[ 0+i*6*5] = 0.0;
378     g_vertex_texcoord_data[ 1+i*6*5] = 0.0;
379 
380     g_vertex_texcoord_data[ 2+i*6*5] = 0.0;
381     g_vertex_texcoord_data[ 3+i*6*5] = 0.0;
382 
383     g_vertex_texcoord_data[ 4+i*6*5] = 0.0;
384     g_vertex_texcoord_data[ 5+i*6*5] = 0.0;
385 
386     g_vertex_texcoord_data[ 6+i*6*5] = 0.0;
387     g_vertex_texcoord_data[ 7+i*6*5] = 0.0;
388 
389     g_vertex_texcoord_data[ 8+i*6*5] = 0.0;
390     g_vertex_texcoord_data[ 9+i*6*5] = 0.0;
391 
392     g_vertex_texcoord_data[10+i*6*5] = 0.0;
393     g_vertex_texcoord_data[11+i*6*5] = 0.0;
394 
395     g_vertex_texcoord_data[12+i*6*5] = 0.0;
396     g_vertex_texcoord_data[13+i*6*5] = 0.0;
397 
398     g_vertex_texcoord_data[14+i*6*5] = 0.0;
399     g_vertex_texcoord_data[15+i*6*5] = 0.0;
400 
401     g_vertex_texcoord_data[16+i*6*5] = 0.0;
402     g_vertex_texcoord_data[17+i*6*5] = 0.0;
403 
404     g_vertex_texcoord_data[18+i*6*5] = 0.0;
405     g_vertex_texcoord_data[19+i*6*5] = 0.0;
406 
407     g_vertex_texcoord_data[20+i*6*5] = texw;
408     g_vertex_texcoord_data[21+i*6*5] = 0.0;
409 
410     g_vertex_texcoord_data[22+i*6*5] = 0.0;
411     g_vertex_texcoord_data[23+i*6*5] = texh;
412 
413     g_vertex_texcoord_data[24+i*6*5] = texw;
414     g_vertex_texcoord_data[25+i*6*5] = 0.0;
415 
416     g_vertex_texcoord_data[26+i*6*5] = texw;
417     g_vertex_texcoord_data[27+i*6*5] = texh;
418 
419     g_vertex_texcoord_data[28+i*6*5] = 0.0;
420     g_vertex_texcoord_data[29+i*6*5] = texh;
421   }
422 }
423 
424 
425 void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
426 {
427     // on teste si la touche E est pressee et si c'est le cas on re-genere des donnees
428     if (key== GLFW_KEY_E && action == GLFW_PRESS){
429       
430       generateData(texWidth, texHeight);
431       // ici on n'envoie que les sommets car on souhaite garder les memes couleurs ... et le nombre
432       // n'a pas change !
433       glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
434       glBufferSubData(GL_ARRAY_BUFFER, 0,                            vertexSize, g_vertex_buffer_data);
435       glBindBuffer(GL_ARRAY_BUFFER, 0);
436     } else if (key== GLFW_KEY_LEFT && action == GLFW_PRESS ){
437       speed = speed - 1.0/256.0;
438     } else if (key== GLFW_KEY_RIGHT && action == GLFW_PRESS){
439       speed = speed + 1.0/256.0;
440     } else if ((key== GLFW_KEY_UP || key== GLFW_KEY_DOWN) && action == GLFW_PRESS){
441       speed = 0.0;
442     } 
443 
444 }
445 
446 
447 void initOpenGL(){
448   // Enable depth test
449   glEnable(GL_DEPTH_TEST);
450   // Accept fragment if it closer to the camera than the former one
451   glDepthFunc(GL_LESS);
452   glDepthRange(-1, 1);
453 
454   // creation du glVertexAttribPointer
455   glGenVertexArrays(1, &vertexArrayID);
456   glBindVertexArray(vertexArrayID);
457 
458 
459   // Generate 1 buffer, put the resulting identifier in vertexbuffer
460   glGenBuffers(1, &vertexbuffer);
461 
462   // The following commands will talk about our 'vertexbuffer' buffer
463   glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
464     // Only allocqte memory. Do not send yet our vertices to OpenGL.
465     glBufferData(GL_ARRAY_BUFFER, vertexSize+colorSize+texCoordSize, 0, GL_STATIC_DRAW);
466 
467     // send vertices in the first part of the buffer
468     glBufferSubData(GL_ARRAY_BUFFER, 0,                            vertexSize, g_vertex_buffer_data);
469 
470     // send colors in the second part of the buffer
471     glBufferSubData(GL_ARRAY_BUFFER, vertexSize, colorSize, g_vertex_color_data);
472 
473     // send tex coords in the third part of the buffer
474     glBufferSubData(GL_ARRAY_BUFFER, vertexSize+colorSize, texCoordSize, g_vertex_texcoord_data);
475   
476     // ici les commandes stockees "une fois pour toute" dans le VAO 
477     // avant on faisait ca a chaque dessin
478     glVertexAttribPointer(
479        0,                  // attribute 0. No particular reason for 0, but must match the layout in the shader.
480        3,                  // size
481        GL_FLOAT,           // type
482        GL_FALSE,           // normalized?
483        0,                  // stride
484        (void*)0            // array buffer offset
485     );
486     glEnableVertexAttribArray(0);
487 
488     glVertexAttribPointer( // same thing for the colors
489       1, 
490       3, 
491       GL_FLOAT, 
492       GL_FALSE, 
493       0, 
494       (void*)vertexSize);
495     glEnableVertexAttribArray(1);
496 
497     glVertexAttribPointer(
498       2, 
499       2, 
500       GL_FLOAT, 
501       GL_FALSE, 
502       0, 
503       (void*)(vertexSize+colorSize));
504     glEnableVertexAttribArray(2);
505 
506   glBindBuffer(GL_ARRAY_BUFFER, 0);
507 
508   // on desactive le VAO a la fin de l'initialisation
509   glBindVertexArray (0);
510 }
511 
512 
513 GLFWwindow *initMainwindow(){
514   // Nous allons apprendre a lire une texture de "symboles" generee a partir d'un outil comme :
515   // https://evanw.github.io/font-texture-generator/
516 
517   glfwWindowHint(GLFW_SAMPLES, 4); // 4x antialiasing
518   glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); // On veut OpenGL 3.3
519   glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
520   glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Pour rendre MacOS heureux ; ne devrait pas être nécessaire
521   glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // On ne veut pas l'ancien OpenGL
522   glfwWindowHint(GLFW_DEPTH_BITS, 24);
523 
524   // Ouvre une fenêtre et crée son contexte OpenGl
525   GLFWwindow *win = glfwCreateWindow( winWidth, winHeight, "Main 06", NULL, NULL);
526   if( win == NULL ){
527       fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are maybe not 3.3 compatible. \n" );
528       glfwTerminate();
529   }
530 
531   // 
532   glfwMakeContextCurrent(win); 
533   
534   // Assure que l'on peut capturer la touche d'échappement 
535   glfwSetInputMode(win, GLFW_STICKY_KEYS, GL_TRUE);
536 
537   // active une callback = une fonction appellee automatiquement quand un evenement arrive 
538   glfwSetKeyCallback(win, key_callback);
539 
540   return win;
541 }
542 
543 
544 void draw(){
545   angleRot = (angleRot+M_PI*speed);
546 
547   // clear before every draw 
548   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
549 
550   // Use our shader
551   glUseProgram(programID); 
552 
553   //  matrice de projection proportionelle a la taille de la fenetre
554   mat4 projectionMatrix = ortho( -1.0f, 1.0f, -1.0f*winHeight/winWidth, 1.0f*winHeight/winWidth, -3.f, 3.f );
555   mat4 viewMatrix       = lookAt(
556                                 vec3(1.5*cos(angleRot), 1.5*sin(angleRot), -0.35), // where is the camara
557                                 vec3(0, 0, 0.1), //where it looks
558                                 vec3(0, 0, 1.0) // head is up
559                               );
560   mat4 modelMatrix      = mat4(1.0);
561 
562   glUniformMatrix4fv(uniform_proj,  1, GL_FALSE, value_ptr(projectionMatrix));
563   glUniformMatrix4fv(uniform_view,  1, GL_FALSE, value_ptr(viewMatrix));
564   glUniformMatrix4fv(uniform_model, 1, GL_FALSE, value_ptr(modelMatrix));
565 
566   // La texture aussi est donnee en variable uniforme. On lui donne le No 0
567   glUniform1i(uniform_texture, 0);
568 
569   // on re-active le VAO avant d'envoyer les buffers
570   glBindVertexArray(vertexArrayID);
571 
572   // On active la texture 0
573   glActiveTexture(GL_TEXTURE0);
574 
575   // Verrouillage de la texture
576   glBindTexture(GL_TEXTURE_RECTANGLE, texId);
577 
578   // Draw the triangle(s) !
579   glDrawArrays(GL_TRIANGLES, 0, vertexSize/(3*sizeof(float))); // Starting from vertex 0; 6 vertices total -> 2 triangles
580   
581   // Déverrouillage de la texture
582   glBindTexture(GL_TEXTURE_RECTANGLE, 0);
583 
584   // on desactive le VAO a la fin du dessin
585   glBindVertexArray (0);
586 
587   // on desactive les shaders
588   glUseProgram(0);
589 
590   // Swap buffers
591   glfwSwapBuffers(window);
592   glfwPollEvents();
593 }
594 
595 
596 int main(){
597   // Initialise GLFW
598   if( !glfwInit() ) {
599       fprintf( stderr, "Failed to initialize GLFW\n" );
600       return -1;
601   }
602 
603   window = initMainwindow();
604   
605   // Initialise GLEW
606   glewExperimental=true; // Nécessaire dans le profil de base
607   if (glewInit() != GLEW_OK) {
608       fprintf(stderr, "Failed to initialize GLEW\n");
609       return -1;
610   }
611   
612   texId = LoadTexture("font.png");
613   
614   generateData(texWidth, texHeight);
615 
616   initOpenGL();
617 
618   programID = LoadShaders( "SimpleVertexShader6.vertexshader", "SimpleFragmentShader6.fragmentshader" );
619   uniform_proj    = glGetUniformLocation(progID, "projectionMatrix");
620   uniform_view    = glGetUniformLocation(progID, "viewMatrix");
621   uniform_model   = glGetUniformLocation(progID, "modelMatrix");
622   uniform_texture = glGetUniformLocation(progID, "loctexture");
623 
624   double before = glfwGetTime();
625   int cpt = 0;
626   do{
627     draw();
628     cpt++;
629 
630     // On a fait 100 dessins, il est temps de voir combien de temps cela a pris
631     // et quel est le taux de raffraichissement 
632     if (cpt==100) {
633       double after = glfwGetTime();
634       cout << 100.0/(after-before) << "Hz"<<endl;
635       before = after;
636       cpt=0;
637     }
638   } // Vérifie si on a appuyé sur la touche échap (ESC) ou si la fenêtre a été fermée
639   while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 );
640 }