gKit2 light
Loading...
Searching...
No Matches
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#include "wavefront_fast.h"
20
21#include "vec.h"
22#include "mat.h"
23#include "orbiter.h"
24
25#include "color.h"
26#include "image.h"
27#include "image_hdr.h"
28
29#include "text.h"
30#include "widgets.h"
31
32
33
34// program
35const char *program_filename;
36GLuint program;
37
38// affichage des erreurs
39std::string program_log;
40int program_area;
41bool program_failed;
42
43const char *mesh_filename;
44Mesh mesh;
45Point mesh_pmin;
46Point mesh_pmax;
47int vertex_count;
48GLuint vao;
49bool wireframe= false;
50
51std::vector<const char *> texture_filenames;
52std::vector<GLuint> textures;
53
54Orbiter camera;
55Widgets widgets;
56
57// application
58size_t last_load= 0;
59void reload_program( )
60{
61 if(program == 0)
62 program= read_program(program_filename);
63 else
64 reload_program(program);
65
66 // conserve la date du fichier
67 last_load= timestamp(program_filename);
68
69 // recupere les erreurs, si necessaire
70 program_area= program_format_errors(program, program_log);
71
72 program_failed= program_errors( program );
73 if(program_failed)
74 printf("[boom]\n%s\n", program_log.c_str());
75}
76
77
78// cherche un fichier avec l'extension ext dans les options
79const char *option_find( std::vector<const char *>& options, const char *ext )
80{
81 for(unsigned i= 0; i < options.size() ; i++)
82 {
83 if(options[i] && std::string(options[i]).rfind(ext) != std::string::npos)
84 {
85 const char *option= options[i];
86 options[i]= nullptr;
87 return option;
88 }
89 }
90
91 return nullptr;
92}
93
96int init( std::vector<const char *>& options )
97{
98 widgets= create_widgets();
99 camera= Orbiter();
100
101 program= 0;
102 const char *option;
103 option= option_find(options, ".glsl");
104 if(option != nullptr)
105 {
106 program_filename= option;
107 reload_program();
108 }
109
110 vao= 0;
111 mesh_pmin= Point(normalize(Vector(-1, -1, 0)) * 2.5f);
112 mesh_pmax= Point(normalize(Vector( 1, 1, 0)) * 2.5f);
113
114 option= option_find(options, ".obj");
115 if(option != nullptr)
116 {
117 //~ mesh= read_mesh(option);
118 mesh= read_mesh_fast(option);
119 //~ mesh= read_indexed_mesh_fast(option);
120 //~ mesh= read_indexed_mesh(option);
121 if(mesh.vertex_count() > 0)
122 {
123 mesh_filename= option;
124
125 vao= mesh.create_buffers(mesh.has_texcoord(), mesh.has_normal(), mesh.has_color(), mesh.has_material_index());
126 vertex_count= mesh.vertex_count();
127
128 mesh.bounds(mesh_pmin, mesh_pmax);
129 camera.lookat(mesh_pmin, mesh_pmax);
130 }
131
132 // ou generer une erreur ?
133 }
134
135 if(vao == 0)
136 {
137 glGenVertexArrays(1, &vao);
138 vertex_count= 3;
139 }
140
141 // charge les textures, si necessaire
142 for(unsigned i= 0; i < options.size(); i++)
143 {
144 if(options[i] == nullptr)
145 continue;
146
147 GLuint texture= read_texture(0, options[i]);
148 if(texture > 0)
149 {
150 texture_filenames.push_back(options[i]);
151 textures.push_back(texture);
152 }
153 }
154
155 // nettoyage
156 glUseProgram(0);
157 glBindTexture(GL_TEXTURE_2D, 0);
158 glBindVertexArray(0);
159 glBindBuffer(GL_ARRAY_BUFFER, 0);
160 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
161
162 // etat openGL par defaut
163 glClearColor(0.2f, 0.2f, 0.2f, 1.f);
164 glClearDepth(1.f);
165
166 glCullFace(GL_BACK);
167 glFrontFace(GL_CCW);
168 //~ glEnable(GL_CULL_FACE); // n'affiche que les faces correctement orientees...
169 glDisable(GL_CULL_FACE); // les faces mal orientees sont affichees avec des hachures oranges...
170
171 glDepthFunc(GL_LESS);
172 glEnable(GL_DEPTH_TEST);
173
174 return 0;
175}
176
177int quit( )
178{
179 // detruit les objets openGL
180 release_widgets(widgets);
181 release_program(program);
182 mesh.release();
183
184 glDeleteTextures(textures.size(), textures.data());
185 return 0;
186}
187
188int draw( void )
189{
190 if(wireframe)
191 {
192 glClearColor(1, 1, 1, 1);
193 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
194 glLineWidth(2);
195 }
196 else
197 {
198 glClearColor(0.2f, 0.2f, 0.2f, 1);
199 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
200 }
201
202 // effacer l'image
203 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
204
205 // verification de la date du fichier source des shaders...
206 static float last_time= 0;
207 // toutes les secondes, ca suffit, pas tres malin de le faire 60 fois par seconde...
208 if(global_time() > last_time + 400)
209 {
210 if(timestamp(program_filename) != last_load)
211 // date modifiee, recharger les sources et recompiler...
212 reload_program();
213
214 // attends le chargement et la compilation des shaders... au cas ou ce soit plus long qu'une seconde...
215 // (oui ca arrive...)
216 last_time= global_time();
217 }
218
219 if(key_state('r'))
220 {
221 clear_key_state('r');
222 reload_program();
223 }
224
225 // recupere les mouvements de la souris
226 int mx, my;
227 unsigned int mb= SDL_GetRelativeMouseState(&mx, &my);
228 int mousex, mousey;
229 SDL_GetMouseState(&mousex, &mousey);
230
231 // deplace la camera
232 if(mb & SDL_BUTTON(1))
233 camera.rotation(mx, my); // tourne autour de l'objet
234 else if(mb & SDL_BUTTON(3))
235 camera.translation((float) mx / (float) window_width(), (float) my / (float) window_height()); // deplace le point de rotation
236 else if(mb & SDL_BUTTON(2))
237 camera.move(mx); // approche / eloigne l'objet
238
239 SDL_MouseWheelEvent wheel= wheel_event();
240 if(wheel.y != 0)
241 {
243 camera.move(8.f * wheel.y); // approche / eloigne l'objet
244 }
245
246 // etat
247 static float time= 0;
248 static int frame= 0;
249 static int zbuffer= 0;
250 static int video= 0;
251 static int freeze= 0;
252 static int reset_camera= 0;
253 static int copy_camera= 0;
254 static int paste_camera= 0;
255
256 // recupere les transformations
257 Transform model= Identity();
258 Transform view= camera.view();
259 Transform projection= camera.projection(window_width(), window_height(), 45);
261
262 Transform mvp= projection * view * model;
263 Transform mvpInv= Inverse(mvp);
264 Transform mv= model * view;
265
266 // temps
267 if(key_state('t'))
268 {
269 clear_key_state('t');
270 freeze= (freeze+1) % 2;
271 }
272 if(freeze == 0)
273 time= global_time();
274
275 // affiche l'objet
276 if(program_failed == false)
277 {
278 if(key_state('w'))
279 {
280 clear_key_state('w');
281 wireframe= !wireframe;
282 }
283
284 // configuration minimale du pipeline
285 glBindVertexArray(vao);
286 glUseProgram(program);
287
288 // affecte une valeur aux uniforms
289 // transformations standards
290 program_uniform(program, "modelMatrix", model);
291 program_uniform(program, "modelInvMatrix", model.inverse());
292 program_uniform(program, "viewMatrix", view);
293 program_uniform(program, "viewInvMatrix", view.inverse());
294 program_uniform(program, "projectionMatrix", projection);
295 program_uniform(program, "projectionInvMatrix", projection.inverse());
296 program_uniform(program, "viewportMatrix", viewport);
297 program_uniform(program, "viewportInvMatrix", viewport.inverse());
298
299 program_uniform(program, "mvpMatrix", mvp);
300 program_uniform(program, "mvpInvMatrix", mvpInv);
301
302 program_uniform(program, "mvMatrix", mv);
303 program_uniform(program, "mvInvMatrix", mv.inverse());
304 program_uniform(program, "normalMatrix", mv.normal());
305
306 program_uniform(program, "pmin", mesh_pmin);
307 program_uniform(program, "pmax", mesh_pmax);
308
309 // interactions
310 program_uniform(program, "viewport", vec2(window_width(), window_height()));
311 program_uniform(program, "time", time);
312 program_uniform(program, "motion", vec3(mx, my, mb & SDL_BUTTON(1)));
313 program_uniform(program, "mouse", vec3(mousex, window_height() - mousey -1, mb & SDL_BUTTON(1)));
314
315 // textures
316 for(unsigned i= 0; i < textures.size(); i++)
317 {
318 char uniform[1024];
319 sprintf(uniform, "texture%u", i);
320 program_use_texture(program, uniform, i, textures[i]);
321 }
322
323 // go
324 glDrawArrays(GL_TRIANGLES, 0, vertex_count);
325 }
326
327
328 // affiche les infos...
329 begin(widgets);
330 if(program_failed)
331 {
332 label(widgets, "[error] program '%s'", program_filename);
333 begin_line(widgets);
334 text_area(widgets, 20, program_log.c_str(), program_area);
335 }
336 else
337 {
338 button(widgets, "[s] screenshot ", frame);
339 button(widgets, "[z] depth screenshot", zbuffer);
340 button(widgets, "capture frames", video);
341 begin_line(widgets);
342 button(widgets, "[t] freeze time", freeze);
343 button(widgets, "[f] reset camera", reset_camera);
344 button(widgets, "[c] copy/save camera", copy_camera);
345 button(widgets, "[v] paste/read camera", paste_camera);
346
347 begin_line(widgets);
348 begin_line(widgets);
349 label(widgets, "program '%s' running...", program_filename);
350 if(mesh_filename && mesh_filename[0])
351 {
352 begin_line(widgets);
353 label(widgets, "mesh '%s', %d vertices %s %s", mesh_filename, mesh.vertex_count(),
354 mesh.texcoord_buffer_size() ? "texcoords" : "", mesh.normal_buffer_size() ? "normals" : "");
355 }
356 for(unsigned i= 0; i < texture_filenames.size(); i++)
357 {
358 begin_line(widgets);
359 label(widgets, "texture%u '%s'", i, texture_filenames[i]);
360 }
361
362 }
363
364 end(widgets);
365
366
367 if(zbuffer || key_state('z'))
368 {
369 zbuffer= 0;
370 clear_key_state('z');
371
372 frame= 1; // force un screenshot en meme temps
373 copy_camera= 1; // idem pour l'orbiter
374
375 printf("zbuffer screenshot...\n");
376
377 // recupere le zbuffer
378 Image image(window_width(), window_height());
379 std::vector<float> tmp(image.width() * image.height());
380
381 glReadBuffer(GL_BACK);
382 glReadPixels(0, 0, image.width(), image.height(), GL_DEPTH_COMPONENT, GL_FLOAT, tmp.data());
383
384 // conversion en image
385 for(unsigned i= 0; i < image.size(); i++)
386 image(i)= Color(tmp[i]);
387
388 write_image_pfm(image, "zbuffer_viewport.pfm");
389
390 // transformation dans le repere camera
391 Transform inv= Inverse( viewport * projection );
392 for(unsigned py= 0; py < image.height(); py++)
393 for(unsigned px= 0; px < image.width(); px++)
394 {
395 unsigned i= py * image.width() + px;
396 Point fragment= Point(float(px) + float(0.5), float(py) + float(0.5), tmp[i]);
397 Point p= inv( fragment );
398
399 image(i)= Color(p.z);
400 }
401
402 write_image_pfm(image, "zbuffer_camera.pfm");
403
404 // exporte une image avec un z positif...
405 for(unsigned i= 0; i < image.size(); i++)
406 image(i)= Color(std::abs(image(i).r));
407
408 write_image_pfm(image, "zbuffer_color.pfm");
409 }
410
411 //
412 draw(widgets, window_width(), window_height());
413
414 if(frame || key_state('s'))
415 {
416 frame= 0;
417 clear_key_state('s');
418
419 static int calls= 1;
420 printf("screenshot %d...\n", calls);
421 screenshot("shader_kit", calls++);
422 }
423
424 if(video)
425 capture("shader_kit");
426
427 if(copy_camera || key_state('c'))
428 {
429 copy_camera= 0;
430 clear_key_state('c');
431 camera.write_orbiter("orbiter.txt");
432 {
433 vec3 p= camera.translation();
434 vec2 r= camera.rotation();
435 printf("Translation( %f, %f, %f ) * RotationX( %f ) * RotationY( %f )\n", p.x, p.y, p.z, r.x, r.y );
436 }
437 }
438 if(paste_camera || key_state('v'))
439 {
440 paste_camera= 0;
441 clear_key_state('v');
442 if(camera.read_orbiter("orbiter.txt") < 0)
443 {
444 camera= Orbiter();
445 camera.lookat(mesh_pmin, mesh_pmax);
446 }
447 }
448
449 if(reset_camera || key_state('f'))
450 {
451 reset_camera= 0;
452 clear_key_state('f');
453
454 camera= Orbiter();
455 camera.lookat(mesh_pmin, mesh_pmax);
456 }
457
458 return 1;
459}
460
461
462int main( int argc, char **argv )
463{
464 if(argc == 1)
465 {
466 printf("usage: %s shader.glsl [mesh.obj] [texture0.png [texture1.png]]\n", argv[0]);
467 return 0;
468 }
469
470 Window window= create_window(1024, 640);
471 if(window == nullptr)
472 return 1;
473
474 Context context= create_context(window);
475 if(context == nullptr)
476 return 1;
477
478 // creation des objets opengl
479 std::vector<const char *> options(argv + 1, argv + argc);
480 if(init(options) < 0)
481 {
482 printf("[error] init failed.\n");
483 return 1;
484 }
485
486 // affichage de l'application
487 run(window, draw);
488
489 // nettoyage
490 quit();
491 release_context(context);
492 release_window(window);
493 return 0;
494}
representation d'une image.
Definition image.h:21
representation d'un objet / maillage.
Definition mesh.h:121
representation de la camera, type orbiter, placee sur une sphere autour du centre de l'objet.
Definition orbiter.h:17
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:367
bool button(Widgets &w, const char *text, int &status)
Definition widgets.cpp:155
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition window.cpp:27
void release_window(Window window)
destruction de la fenetre.
Definition window.cpp:337
int run(Window window, int(*draw)())
boucle de gestion des evenements de l'application.
Definition window.cpp:164
void clear_key_state(const SDL_Keycode key)
desactive une touche du clavier.
Definition window.cpp:69
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)
creation d'une fenetre pour l'application.
Definition window.cpp:270
void release_context(Context context)
detruit le contexte openGL.
Definition window.cpp:447
void clear_wheel_event()
desactive l'evenement.
Definition window.cpp:133
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:63
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:129
int window_width()
renvoie la largeur de la fenetre de l'application.
Definition window.cpp:23
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition window.cpp:145
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:167
Mesh read_mesh_fast(const char *filename)
charge un fichier wavefront .obj et renvoie un mesh compose de triangles non indexes....
int capture(const char *prefix)
Definition texture.cpp:205
int screenshot(const char *filename)
enregistre le contenu de la fenetre dans un fichier. doit etre de type .png / .bmp
Definition texture.cpp:178
GLuint read_program(const char *filename, const char *definitions)
Definition program.cpp:214
int release_program(const GLuint program)
Definition program.cpp:238
bool program_errors(const GLuint program)
renvoie vrai si le programme n'est pas pret.
Definition program.cpp:286
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:133
int program_format_errors(const GLuint program, std::string &errors)
renvoie les erreurs de compilation.
Definition program.cpp:393
int init(std::vector< const char * > &options)
representation d'une couleur (rgba) transparente ou opaque.
Definition color.h:14
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:67
vecteur generique, utilitaire.
Definition vec.h:152
vecteur generique, utilitaire.
Definition vec.h:169