gKit2 light
window.cpp
Go to the documentation of this file.
1 
3 
4 #include <cassert>
5 #include <cstdio>
6 #include <cstdio>
7 #include <cstring>
8 #include <cmath>
9 
10 #include <chrono>
11 #include <vector>
12 #include <set>
13 #include <string>
14 #include <iostream>
15 
16 #include "glcore.h"
17 #include "window.h"
18 #include "files.h"
19 
20 
21 static float aspect= 1;
22 
23 static int width= 0;
24 static int height= 0;
26 {
27  return width;
28 }
30 {
31  return height;
32 }
33 
35 {
36  int n= 0;
37  SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &n);
38  return n;
39 }
40 
41 static std::vector<unsigned char> key_states;
42 int key_state( const SDL_Keycode key )
43 {
44  SDL_Scancode code= SDL_GetScancodeFromKey(key);
45  assert((size_t) code < key_states.size());
46  return (int) key_states[code];
47 }
48 void clear_key_state( const SDL_Keycode key )
49 {
50  SDL_Scancode code= SDL_GetScancodeFromKey(key);
51  assert((size_t) code < key_states.size());
52  key_states[code]= 0;
53 }
54 
55 static SDL_KeyboardEvent last_key;
56 SDL_KeyboardEvent key_event( )
57 {
58  return last_key;
59 }
61 {
62  last_key.type= 0;
63  last_key.keysym.sym= 0;
64 }
65 
66 static SDL_TextInputEvent last_text;
67 SDL_TextInputEvent text_event( )
68 {
69  return last_text;
70 }
72 {
73  last_text.text[0]= 0;
74 }
75 
76 static std::vector<std::string> last_drops;
77 const std::vector<std::string>& drop_events( )
78 {
79  return last_drops;
80 }
81 
82 const char *drop_event( )
83 {
84  if(last_drops.empty())
85  return nullptr;
86  else
87  return last_drops.back().c_str();
88 }
89 
91 {
92  last_drops.clear();
93 }
94 
96 {
97  last_drops.clear();
98 }
99 
100 
101 static SDL_MouseButtonEvent last_button;
102 SDL_MouseButtonEvent button_event( )
103 {
104  return last_button;
105 }
107 {
108  last_button.state= 0;
109 }
110 
111 static SDL_MouseWheelEvent last_wheel;
112 SDL_MouseWheelEvent wheel_event( )
113 {
114  return last_wheel;
115 }
117 {
118  last_wheel.x= 0;
119  last_wheel.y= 0;
120 }
121 
122 
123 //
124 static std::chrono::high_resolution_clock::time_point app_start= {};
125 static std::chrono::high_resolution_clock::time_point last_time= {};
126 static float last_delta= 0;
127 
128 float global_time( )
129 {
130  std::chrono::high_resolution_clock::time_point now= std::chrono::high_resolution_clock::now();
131  last_delta= float(std::chrono::duration_cast<std::chrono::microseconds>(now - last_time).count()) / float(1000);
132  last_time= now;
133 
134  return float(std::chrono::duration_cast<std::chrono::microseconds>(now - app_start).count()) / float(1000);
135 }
136 
137 float delta_time( )
138 {
139 // pas super utile, a virer ?
140  return last_delta;
141 }
142 
143 // etat de l'application.
144 static int stop= 0;
145 
147 int run( Window window, int (*draw)() )
148 {
149  // configure openGL
150  glViewport(0, 0, width, height);
151 
152  // run
153  while(events(window))
154  {
155  // dessiner
156  if(draw() < 1)
157  stop= 1; // fermer l'application si draw() renvoie 0 ou -1...
158 
159  // presenter le resultat
160  SDL_GL_SwapWindow(window);
161  }
162 
163  return 0;
164 }
165 
166 static int event_count= 0;
167 int last_event_count( ) { return event_count; }
168 
169 
170 int events( Window window )
171 {
172  bool resize_event= false;
173 
174  // gestion des evenements
175  SDL_Event event;
176  while(SDL_PollEvent(&event))
177  {
178  switch(event.type)
179  {
180  case SDL_WINDOWEVENT:
181  // redimensionner la fenetre...
182  if(event.window.event == SDL_WINDOWEVENT_RESIZED)
183  {
184  // traite l'evenement apres la boucle...
185  resize_event= true;
186 
187  // conserve les proportions de la fenetre
188  width= event.window.data1;
189  height= event.window.data2;
190  }
191  break;
192 
193  case SDL_DROPFILE:
194  //~ printf("drop file '%s'\n", event.drop.file);
195  last_drops.push_back(std::string(event.drop.file));
196  SDL_free(event.drop.file);
197  break;
198 
199  case SDL_TEXTINPUT:
200  // conserver le dernier caractere
201  last_text= event.text;
202  break;
203 
204  case SDL_KEYDOWN:
205  // modifier l'etat du clavier
206  if((size_t) event.key.keysym.scancode < key_states.size())
207  {
208  key_states[event.key.keysym.scancode]= 1;
209  last_key= event.key; // conserver le dernier evenement
210  }
211 
212  // fermer l'application
213  if(event.key.keysym.sym == SDLK_ESCAPE)
214  stop= 1;
215  break;
216 
217  case SDL_KEYUP:
218  // modifier l'etat du clavier
219  if((size_t) event.key.keysym.scancode < key_states.size())
220  {
221  key_states[event.key.keysym.scancode]= 0;
222  last_key= event.key; // conserver le dernier evenement
223  }
224  break;
225 
226  case SDL_MOUSEBUTTONDOWN:
227  case SDL_MOUSEBUTTONUP:
228  last_button= event.button;
229  break;
230 
231  case SDL_MOUSEWHEEL:
232  last_wheel= event.wheel;
233  break;
234 
235  case SDL_QUIT:
236  stop= 1; // fermer l'application
237  break;
238  }
239  }
240 
241  if(resize_event)
242  {
243  int w= std::floor(height * aspect);
244  int h= height;
245  SDL_SetWindowSize(window, w, h);
246  glViewport(0, 0, w, h);
247 
248  //~ printf("[resize] %dx%d aspect %f -> %dx%d aspect %f\n", width, height, aspect, w, h, float(w) / float(h));
249 
250  width= w;
251  height= h;
252  }
253 
254  return 1 - stop;
255 }
256 
257 
259 Window create_window( const int w, const int h, const int major, const int minor, const int samples )
260 {
261  // init sdl
262  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
263  {
264  printf("[error] SDL_Init() failed:\n%s\n", SDL_GetError());
265  return nullptr;
266  }
267 
268  // enregistre le destructeur de sdl
269  atexit(SDL_Quit);
270 
271  // configuration openGL
272 #ifndef GK_OPENGLES
273  printf("creating window(%d, %d) openGL %d.%d, %d MSAA samples...\n", w, h, major, minor, samples);
274 
275  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
276  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
277 #ifndef GK_RELEASE
278  SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
279 #endif
280  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
281 
282  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
283  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
284 
285  if(samples > 1)
286  {
287  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
288  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
289  }
290 
291 #else
292  printf("creating window(%d, %d) openGL ES 3.0...\n", w, h);
293 
294  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
295  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
296  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
297  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
298 #endif
299 
300  // creer la fenetre
301  Window window= SDL_CreateWindow("gKit",
302  SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h,
303  SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
304  if(window == nullptr)
305  {
306  printf("[error] SDL_CreateWindow() failed.\n");
307  return nullptr;
308  }
309 
310  // recupere l'etat du clavier
311  int keys;
312  const unsigned char *state= SDL_GetKeyboardState(&keys);
313  key_states.assign(state, state + keys);
314 
315  SDL_SetWindowDisplayMode(window, nullptr);
316  SDL_StartTextInput();
317 
318  // conserve les dimensions de la fenetre
319  SDL_GetWindowSize(window, &width, &height);
320  aspect= float(width) / float(height);
321 
322  return window;
323 }
324 
325 void release_window( Window window )
326 {
327  SDL_StopTextInput();
328  SDL_DestroyWindow(window);
329 }
330 
331 
332 #ifndef NO_GLEW
333 #ifndef GK_RELEASE
334 
336 static
337 void DEBUGCALLBACK debug_print( GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length,
338  const char *message, const void *userParam )
339 {
340  static std::set<std::string> log;
341  if(log.insert(message).second == false)
342  // le message a deja ete affiche, pas la peine de recommencer 60 fois par seconde.
343  return;
344 
345  if(severity == GL_DEBUG_SEVERITY_HIGH)
346  printf("[openGL error]\n%s\n", message);
347  else if(severity == GL_DEBUG_SEVERITY_MEDIUM)
348  printf("[openGL warning]\n%s\n", message);
349  else
350  printf("[openGL message]\n%s\n", message);
351 }
352 #endif
353 #endif
354 
356 Context create_context( Window window )
357 {
358  if(window == nullptr)
359  return nullptr;
360 
361  Context context= SDL_GL_CreateContext(window);
362  if(context == nullptr)
363  {
364  printf("[error] creating openGL context.\n");
365  return nullptr;
366  }
367 
368  if(SDL_GL_SetSwapInterval(-1) != 0)
369  printf("[warning] can't set adaptive vsync...\n");
370 
371  if(SDL_GL_GetSwapInterval() != -1)
372  {
373  printf("vsync ON\n");
374  SDL_GL_SetSwapInterval(1);
375  }
376  else
377  printf("adaptive vsync ON\n");
378 
379  {
380  int n= 0;
381  SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &n);
382  if(n > 1)
383  printf("MSAA %d samples\n", n);
384  }
385 
386  //
387  app_start= std::chrono::high_resolution_clock::now();
388 
389 #ifndef NO_GLEW
390  // initialise les extensions opengl
391  glewExperimental= 1;
392  GLenum err= glewInit();
393  if(err != GLEW_OK)
394  {
395  printf("[error] loading extensions\n%s\n", glewGetErrorString(err));
396  SDL_GL_DeleteContext(context);
397  return nullptr;
398  }
399 
400  // purge les erreurs opengl generees par glew !
401  while(glGetError() != GL_NO_ERROR) {;}
402 
403 #ifndef GK_RELEASE
404  // configure l'affichage des messages d'erreurs opengl, si l'extension est disponible
405  if(GLEW_ARB_debug_output)
406  {
407  printf("debug output enabled...\n");
408  // selectionne tous les messages
409  glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE);
410  // desactive les messages du compilateur de shaders
411  glDebugMessageControlARB(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_FALSE);
412 
413  glDebugMessageCallbackARB(debug_print, NULL);
414  glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
415  }
416 #endif
417 #endif
418 
419  return context;
420 }
421 
422 void release_context( Context context )
423 {
424  SDL_GL_DeleteContext(context);
425 }
426 
427 
428 static std::string smartpath;
429 static std::string path;
430 
431 const char *smart_path( const char *filename )
432 {
433  if(exists(filename))
434  return filename;
435 
436  if(path.empty())
437  {
438  // recupere la variable d'environnement, si elle existe
439  const char *envbase= std::getenv("GKIT_BASE_PATH");
440  if(envbase != nullptr)
441  {
442  path= std::string(envbase);
443  if(!path.empty() && path[path.size() -1] != '/')
444  {
445  path.append("/"); // force un /, si necessaire
446  printf("[base path] %s\n", path.c_str());
447  }
448  }
449  }
450 
451  if(path.empty())
452  {
453  char *base= SDL_GetBasePath();
454  printf("[base path] %s\n", base);
455  path= base;
456  SDL_free(base);
457  }
458 
459  smartpath= path + filename;
460  if(exists(smartpath.c_str()))
461  return smartpath.c_str();
462 
463  smartpath= path + "../" + filename;
464  if(exists(smartpath.c_str()))
465  return smartpath.c_str();
466 
467  return filename; // echec, fichier pas trouve, renvoie quand meme le fichier original.
468  // (permet au moins d'afficher l'erreur fichier non trouve dans l'application)
469 }
SDL_MouseButtonEvent button_event()
renvoie le dernier evenement. etat des boutons de la souris.
Definition: window.cpp:102
Context create_context(Window window)
cree et configure un contexte opengl
Definition: window.cpp:356
void clear_button_event()
desactive l'evenement.
Definition: window.cpp:106
void clear_drop_events()
desactive drag/drop.
Definition: window.cpp:95
int events(Window window)
fonction interne de gestion d'evenements.
Definition: window.cpp:170
int window_height()
renvoie la hauteur de la fenetre de l'application.
Definition: window.cpp:29
SDL_TextInputEvent text_event()
renvoie le dernier evenement. saisie de texte.
Definition: window.cpp:67
void release_window(Window window)
destruction de la fenetre.
Definition: window.cpp:325
void clear_key_event()
desactive l'evenement.
Definition: window.cpp:60
SDL_KeyboardEvent key_event()
renvoie le dernier evenement. touche speciales.
Definition: window.cpp:56
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
const std::vector< std::string > & drop_events()
drag/drop. recupere tous les fichiers.
Definition: window.cpp:77
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 clear_drop_event()
desactive drag/drop.
Definition: window.cpp:90
void clear_text_event()
desactive l'evenement.
Definition: window.cpp:71
void release_context(Context context)
detruit le contexte openGL.
Definition: window.cpp:422
void clear_wheel_event()
desactive l'evenement.
Definition: window.cpp:116
const char * drop_event()
drag/drop, renvoie le dernier fichier.
Definition: window.cpp:82
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
int window_msaa()
renvoie le nombre de samples MSAA.
Definition: window.cpp:34
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
const char * smart_path(const char *filename)
renvoie le chemin(path) vers le fichier 'filename' apres l'avoir cherche dans un repertoire standard....
Definition: window.cpp:431
float delta_time()
renvoie le temps ecoule depuis la derniere frame, en millisecondes.
Definition: window.cpp:137
float global_time()
renvoie le temps ecoule depuis le lancement de l'application, en millisecondes.
Definition: window.cpp:128
float length(const Vector &v)
renvoie la longueur d'un vecteur.
Definition: vec.cpp:142
int run(Window window, int(*draw)())
boucle de gestion des evenements de l'application.
Definition: window.cpp:147