gKit2 light
shader_kit.cpp
Go to the documentation of this file.
1 
3 
4 #include <cstdio>
5 #include <cstring>
6 
7 #include <chrono>
8 
9 #include "glcore.h"
10 #include "window.h"
11 #include "files.h"
12 
13 #include "program.h"
14 #include "uniforms.h"
15 
16 #include "texture.h"
17 #include "mesh.h"
18 #include "wavefront.h"
19 
20 #include "vec.h"
21 #include "mat.h"
22 #include "orbiter.h"
23 
24 #include "text.h"
25 #include "widgets.h"
26 
27 
28 
29 // program
30 const char *program_filename;
31 GLuint program;
32 
33 // affichage des erreurs
34 std::string program_log;
35 int program_area;
36 bool program_failed;
37 
38 const char *mesh_filename;
39 Mesh mesh;
40 Point mesh_pmin;
41 Point mesh_pmax;
42 int vertex_count;
43 GLuint vao;
44 bool wireframe= false;
45 
46 std::vector<const char *> texture_filenames;
47 std::vector<GLuint> textures;
48 
49 Orbiter camera;
50 Widgets widgets;
51 
52 // application
53 size_t last_load= 0;
54 void reload_program( )
55 {
56  if(program == 0)
57  program= read_program(program_filename);
58  else
59  reload_program(program, program_filename);
60 
61  // conserve la date du fichier
62  last_load= timestamp(program_filename);
63 
64  // recupere les erreurs, si necessaire
65  program_area= program_format_errors(program, program_log);
66 
67  if(program_log.size() > 0)
68  printf("[boom]\n%s\n", program_log.c_str());
69 
70  program_failed= (program_log.size() > 0);
71 }
72 
73 
74 // cherche un fichier avec l'extension ext dans les options
75 const char *option_find( std::vector<const char *>& options, const char *ext )
76 {
77  for(unsigned int i= 0; i < (unsigned int) options.size() ; i++)
78  {
79  if(options[i] != nullptr && std::string(options[i]).rfind(ext) != std::string::npos)
80  {
81  const char *option= options[i];
82  options[i]= nullptr;
83  return option;
84  }
85  }
86 
87  return nullptr;
88 }
89 
92 int init( std::vector<const char *>& options )
93 {
94  widgets= create_widgets();
95  camera= Orbiter();
96 
97  program= 0;
98  const char *option;
99  option= option_find(options, ".glsl");
100  if(option != nullptr)
101  {
102  program_filename= option;
103  reload_program();
104  }
105 
106  vao= 0;
107  mesh_pmin= Point(normalize(Vector(-1, -1, 0)) * 2.5f);
108  mesh_pmax= Point(normalize(Vector( 1, 1, 0)) * 2.5f);
109 
110  option= option_find(options, ".obj");
111  if(option != nullptr)
112  {
113  mesh= read_mesh(option);
114  if(mesh.vertex_count() > 0)
115  {
116  mesh_filename= option;
117 
118  vao= mesh.create_buffers(mesh.has_texcoord(), mesh.has_normal(), mesh.has_color(), mesh.has_material_index());
119  vertex_count= mesh.vertex_count();
120 
121  mesh.bounds(mesh_pmin, mesh_pmax);
122  camera.lookat(mesh_pmin, mesh_pmax);
123  }
124 
125  // ou generer une erreur ?
126  }
127 
128  if(vao == 0)
129  {
130  glGenVertexArrays(1, &vao);
131  vertex_count= 3;
132  }
133 
134  // charge les textures, si necessaire
135  for(int i= 0; i < int(options.size()); i++)
136  {
137  if(options[i] == nullptr)
138  continue;
139 
140  GLuint texture= read_texture(0, options[i]);
141  if(texture > 0)
142  {
143  texture_filenames.push_back(options[i]);
144  textures.push_back(texture);
145  }
146  }
147 
148  // nettoyage
149  glUseProgram(0);
150  glBindTexture(GL_TEXTURE_2D, 0);
151  glBindVertexArray(0);
152  glBindBuffer(GL_ARRAY_BUFFER, 0);
153  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
154 
155  // etat openGL par defaut
156  glClearColor(0.2f, 0.2f, 0.2f, 1.f);
157  glClearDepth(1.f);
158 
159  glCullFace(GL_BACK);
160  glFrontFace(GL_CCW);
161  //~ glEnable(GL_CULL_FACE); // n'affiche que les faces correctement orientees...
162  glDisable(GL_CULL_FACE); // les faces mal orientees sont affichees avec des hachures oranges...
163 
164  glDepthFunc(GL_LESS);
165  glEnable(GL_DEPTH_TEST);
166 
167  return 0;
168 }
169 
170 int quit( )
171 {
172  // detruit les objets openGL
173  release_widgets(widgets);
174  release_program(program);
175  mesh.release();
176 
177  glDeleteTextures(textures.size(), textures.data());
178  return 0;
179 }
180 
181 int draw( void )
182 {
183  if(wireframe)
184  {
185  glClearColor(1, 1, 1, 1);
186  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
187  glLineWidth(2);
188  }
189  else
190  {
191  glClearColor(0.2f, 0.2f, 0.2f, 1);
192  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
193  }
194 
195  // effacer l'image
196  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
197 
198  // verification de la date du fichier source des shaders...
199  static float last_time= 0;
200  // toutes les secondes, ca suffit, pas tres malin de le faire 60 fois par seconde...
201  if(global_time() > last_time + 400)
202  {
203  if(timestamp(program_filename) != last_load)
204  // date modifiee, recharger les sources et recompiler...
205  reload_program();
206 
207  // attends le chargement et la compilation des shaders... au cas ou ce soit plus long qu'une seconde...
208  // (oui ca arrive...)
209  last_time= global_time();
210  }
211 
212  if(key_state('r'))
213  {
214  clear_key_state('r');
215  reload_program();
216  }
217 
218  // recupere les mouvements de la souris
219  int mx, my;
220  unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
221  int mousex, mousey;
222  SDL_GetMouseState(&mousex, &mousey);
223 
224  // deplace la camera
225  if(mb & SDL_BUTTON(1))
226  camera.rotation(mx, my); // tourne autour de l'objet
227  else if(mb & SDL_BUTTON(3))
228  camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height()); // deplace le point de rotation
229  else if(mb & SDL_BUTTON(2))
230  camera.move(mx); // approche / eloigne l'objet
231 
232  SDL_MouseWheelEvent wheel= wheel_event();
233  if(wheel.y != 0)
234  {
236  camera.move(8.f * wheel.y); // approche / eloigne l'objet
237  }
238 
239  // etat
240  static float time= 0;
241  static int frame= 0;
242  static int video= 0;
243  static int freeze= 0;
244  static int reset_camera= 0;
245  static int copy_camera= 0;
246  static int paste_camera= 0;
247 
248  // recupere les transformations
249  Transform model= Identity();
250  Transform view= camera.view();
251  Transform projection= camera.projection(window_width(), window_height(), 45);
253 
254  Transform mvp= projection * view * model;
255  Transform mvpInv= Inverse(mvp);
256  Transform mv= model * view;
257 
258  // temps
259  if(key_state('t'))
260  {
261  clear_key_state('t');
262  freeze= (freeze+1) % 2;
263  }
264  if(freeze == 0)
265  time= global_time();
266 
267  // affiche l'objet
268  if(program_failed == false)
269  {
270  if(key_state('w'))
271  {
272  clear_key_state('w');
273  wireframe= !wireframe;
274  }
275 
276  // configuration minimale du pipeline
277  glBindVertexArray(vao);
278  glUseProgram(program);
279 
280  // affecte une valeur aux uniforms
281  // transformations standards
282  program_uniform(program, "modelMatrix", model);
283  program_uniform(program, "modelInvMatrix", model.inverse());
284  program_uniform(program, "viewMatrix", view);
285  program_uniform(program, "viewInvMatrix", view.inverse());
286  program_uniform(program, "projectionMatrix", projection);
287  program_uniform(program, "projectionInvMatrix", projection.inverse());
288  program_uniform(program, "viewportMatrix", viewport);
289  program_uniform(program, "viewportInvMatrix", viewport.inverse());
290 
291  program_uniform(program, "mvpMatrix", mvp);
292  program_uniform(program, "mvpInvMatrix", mvpInv);
293 
294  program_uniform(program, "mvMatrix", mv);
295  program_uniform(program, "mvInvMatrix", mv.inverse());
296  program_uniform(program, "normalMatrix", mv.normal());
297 
298  // interactions
299  program_uniform(program, "viewport", vec2(window_width(), window_height()));
300  program_uniform(program, "time", time);
301  program_uniform(program, "motion", vec3(mx, my, mb & SDL_BUTTON(1)));
302  program_uniform(program, "mouse", vec3(mousex, window_height() - mousey -1, mb & SDL_BUTTON(1)));
303 
304  // textures
305  for(int i= 0; i < int(textures.size()); i++)
306  {
307  char uniform[1024];
308  sprintf(uniform, "texture%d", i);
309  program_use_texture(program, uniform, i, textures[i]);
310  }
311 
312  // go
313  glDrawArrays(GL_TRIANGLES, 0, vertex_count);
314  }
315 
316 
317  // affiche les infos...
318  begin(widgets);
319  if(program_failed)
320  {
321  label(widgets, "[error] program '%s'", program_filename);
322  begin_line(widgets);
323  text_area(widgets, 20, program_log.c_str(), program_area);
324  }
325  else
326  {
327  button(widgets, "[s] screenshot ", frame);
328  button(widgets, "capture frames", video);
329  begin_line(widgets);
330  button(widgets, "[t] freeze time", freeze);
331  button(widgets, "[f] reset camera", reset_camera);
332  button(widgets, "[c] copy/save camera", copy_camera);
333  button(widgets, "[v] paste/read camera", paste_camera);
334 
335  begin_line(widgets);
336  begin_line(widgets);
337  label(widgets, "program '%s' running...", program_filename);
338  if(mesh_filename && mesh_filename[0])
339  {
340  begin_line(widgets);
341  label(widgets, "mesh '%s', %d vertices %s %s", mesh_filename, mesh.vertex_count(),
342  mesh.texcoord_buffer_size() ? "texcoords" : "", mesh.normal_buffer_size() ? "normals" : "");
343  }
344  for(unsigned int i= 0; i < (unsigned int) texture_filenames.size(); i++)
345  {
346  begin_line(widgets);
347  label(widgets, "texture%u '%s'", i, texture_filenames[i]);
348  }
349 
350  }
351 
352  end(widgets);
353 
354  draw(widgets, window_width(), window_height());
355 
356 
357  if(frame || key_state('s'))
358  {
359  frame= 0;
360  clear_key_state('s');
361 
362  static int calls= 1;
363  printf("screenshot %d...\n", calls);
364  screenshot("shader_kit", calls++);
365  }
366 
367  if(video)
368  capture("shader_kit");
369 
370  if(copy_camera || key_state('c'))
371  {
372  copy_camera= 0;
373  clear_key_state('c');
374  camera.write_orbiter("orbiter.txt");
375  }
376  if(paste_camera || key_state('v'))
377  {
378  paste_camera= 0;
379  clear_key_state('v');
380  if(camera.read_orbiter("orbiter.txt") < 0)
381  {
382  camera= Orbiter();
383  camera.lookat(mesh_pmin, mesh_pmax);
384  }
385  }
386 
387  if(reset_camera || key_state('f'))
388  {
389  reset_camera= 0;
390  clear_key_state('f');
391 
392  camera= Orbiter();
393  camera.lookat(mesh_pmin, mesh_pmax);
394  }
395 
396  return 1;
397 }
398 
399 
400 int main( int argc, char **argv )
401 {
402  if(argc == 1)
403  {
404  printf("usage: %s shader.glsl [mesh.obj] [texture0.png [texture1.png]]\n", argv[0]);
405  return 0;
406  }
407 
408  Window window= create_window(1024, 640);
409  if(window == nullptr)
410  return 1;
411 
412  Context context= create_context(window);
413  if(context == nullptr)
414  return 1;
415 
416  // creation des objets opengl
417  std::vector<const char *> options(argv + 1, argv + argc);
418  if(init(options) < 0)
419  {
420  printf("[error] init failed.\n");
421  return 1;
422  }
423 
424  // affichage de l'application
425  run(window, draw);
426 
427  // nettoyage
428  quit();
429  release_context(context);
430  release_window(window);
431  return 0;
432 }
representation d'un objet / maillage.
Definition: mesh.h:112
std::size_t texcoord_buffer_size() const
renvoie la taille (en octets) du texcoord buffer.
Definition: mesh.h:308
GLuint create_buffers(const bool use_texcoord, const bool use_normal, const bool use_color, const bool use_material_index)
construit les buffers et le vertex array object necessaires pour dessiner l'objet avec openGL....
Definition: mesh.cpp:579
void bounds(Point &pmin, Point &pmax) const
renvoie min et max les coordonnees des extremites des positions des sommets de l'objet (boite engloba...
Definition: mesh.cpp:501
int vertex_count() const
renvoie le nombre de sommets.
Definition: mesh.h:291
void release()
detruit les objets openGL.
Definition: mesh.cpp:62
std::size_t normal_buffer_size() const
renvoie la longueur (en octets) du normal buffer.
Definition: mesh.h:303
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
Definition: orbiter.h:17
void lookat(const Point &center, const float size)
observe le point center a une distance size.
Definition: orbiter.cpp:7
int read_orbiter(const char *filename)
relit la position de l'orbiter depuis un fichier texte.
Definition: orbiter.cpp:116
void move(const float z)
rapproche / eloigne la camera du centre.
Definition: orbiter.cpp:33
Transform projection(const int width, const int height, const float fov)
fixe la projection reglee pour une image d'aspect width / height, et une demi ouverture de fov degres...
Definition: orbiter.cpp:47
void translation(const float x, const float y)
deplace le centre / le point observe.
Definition: orbiter.cpp:27
void rotation(const float x, const float y)
change le point de vue / la direction d'observation.
Definition: orbiter.cpp:21
int write_orbiter(const char *filename)
enregistre la position de l'orbiter dans un fichier texte.
Definition: orbiter.cpp:150
Transform view() const
renvoie la transformation vue.
Definition: orbiter.cpp:40
void begin(Widgets &w)
debut de la description des elements de l'interface graphique.
Definition: widgets.cpp:29
Widgets create_widgets()
cree une interface graphique. a detruire avec release_widgets( ).
Definition: widgets.cpp:12
void release_widgets(Widgets &w)
detruit l'interface graphique.
Definition: widgets.cpp:23
Context create_context(Window window)
cree et configure un contexte opengl
Definition: window.cpp:356
bool button(Widgets &w, const char *text, int &status)
Definition: widgets.cpp:155
void label(Widgets &w, const char *format,...)
cree un texte. meme fonctionnement que printf().
Definition: widgets.cpp:142
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:29
void release_window(Window window)
destruction de la fenetre.
Definition: window.cpp:325
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition: window.cpp:48
void printf(Text &text, const int px, const int py, const char *format,...)
affiche un texte a la position x, y. meme utilisation que printf().
Definition: text.cpp:140
Window create_window(const int w, const int h, const int major, const int minor, const int samples)
creation d'une fenetre pour l'application.
Definition: window.cpp:259
void release_context(Context context)
detruit le contexte openGL.
Definition: window.cpp:422
void clear_wheel_event()
desactive l'evenement.
Definition: window.cpp:116
void end(Widgets &w)
termine la description des elements de l'interface graphique.
Definition: widgets.cpp:404
int key_state(const SDL_Keycode key)
renvoie l'etat d'une touche du clavier. cf la doc SDL2 pour les codes.
Definition: window.cpp:42
void text_area(Widgets &w, const int height, const char *text, int &begin_line)
Definition: widgets.cpp:273
void begin_line(Widgets &w)
place les prochains elements sur une nouvelle ligne.
Definition: widgets.cpp:129
SDL_MouseWheelEvent wheel_event()
renvoie le dernier evenement. etat de la molette de la souris / glisser sur le pad.
Definition: window.cpp:112
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition: window.cpp:25
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition: window.cpp:128
Transform Inverse(const Transform &m)
renvoie l'inverse de la matrice.
Definition: mat.cpp:197
Transform Viewport(const float width, const float height)
renvoie la matrice representant une transformation viewport.
Definition: mat.cpp:357
Transform Identity()
construit la transformation identite.
Definition: mat.cpp:187
Vector normalize(const Vector &v)
renvoie un vecteur unitaire / longueur == 1.
Definition: vec.cpp:123
Mesh read_mesh(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
Definition: wavefront.cpp:14
int capture(const char *prefix)
Definition: texture.cpp:221
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
Definition: texture.cpp:194
GLuint read_program(const char *filename, const char *definitions)
Definition: program.cpp:204
void program_uniform(const GLuint program, const char *uniform, const std::vector< unsigned > &v)
affecte un tableau de valeurs a un uniform du shader program.
Definition: uniforms.cpp:94
int release_program(const GLuint program)
detruit les shaders et le program.
Definition: program.cpp:211
void program_use_texture(const GLuint program, const char *uniform, const int unit, const GLuint texture, const GLuint sampler)
configure le pipeline et le shader program pour utiliser une texture, et des parametres de filtrage,...
Definition: uniforms.cpp:198
GLuint read_texture(const int unit, const char *filename, const GLenum texel_type)
Definition: texture.cpp:154
int program_format_errors(const GLuint program, std::string &errors)
renvoie les erreurs de compilation.
Definition: program.cpp:366
int init(std::vector< const char * > &options)
Definition: shader_kit.cpp:92
representation d'un point 3d.
Definition: vec.h:21
representation d'une transformation, une matrice 4x4, organisee par ligne / row major.
Definition: mat.h:21
Transform normal() const
renvoie la transformation a appliquer aux normales d'un objet transforme par la matrice m.
Definition: mat.cpp:181
Transform inverse() const
renvoie l'inverse de la matrice.
Definition: mat.cpp:399
representation d'un vecteur 3d.
Definition: vec.h:59
vecteur generique, utilitaire.
Definition: vec.h:131
vecteur generique, utilitaire.
Definition: vec.h:146
int run(Window window, int(*draw)())
boucle de gestion des evenements de l'application.
Definition: window.cpp:147