Visualization Library 2.0.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
SDLWindow.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include "vlSDL/SDLWindow.hpp"
33 #include "vlGraphics/OpenGL.hpp"
34 #include "vlGraphics/Applet.hpp"
36 #include "vlCore/Log.hpp"
37 #include "vlCore/Say.hpp"
38 #include <algorithm>
39 #include <SDL.h>
40 #include <map>
41 
42 #ifdef WIN32
43  #include <SDL_syswm.h>
44  #include <shellapi.h>
45 #endif
46 
47 using namespace vlSDL;
48 using namespace vl;
49 
50 namespace
51 {
52  SDLWindow* mSDLWindow = NULL;
53  bool mUpdateFlag = true;
54 
55  std::map<int, vl::EKey> key_translation_map;
56 
57  int key_translation_vec[] =
58  {
59  SDLK_0, vl::Key_0,
60  SDLK_1, vl::Key_1,
61  SDLK_2, vl::Key_2,
62  SDLK_3, vl::Key_3,
63  SDLK_4, vl::Key_4,
64  SDLK_5, vl::Key_5,
65  SDLK_6, vl::Key_6,
66  SDLK_7, vl::Key_7,
67  SDLK_8, vl::Key_8,
68  SDLK_9, vl::Key_9,
69 
70  SDLK_a, vl::Key_A,
71  SDLK_b, vl::Key_B,
72  SDLK_c, vl::Key_C,
73  SDLK_d, vl::Key_D,
74  SDLK_e, vl::Key_E,
75  SDLK_f, vl::Key_F,
76  SDLK_g, vl::Key_G,
77  SDLK_h, vl::Key_H,
78  SDLK_i, vl::Key_I,
79  SDLK_j, vl::Key_J,
80  SDLK_k, vl::Key_K,
81  SDLK_l, vl::Key_L,
82  SDLK_m, vl::Key_M,
83  SDLK_n, vl::Key_N,
84  SDLK_o, vl::Key_O,
85  SDLK_p, vl::Key_P,
86  SDLK_q, vl::Key_Q,
87  SDLK_r, vl::Key_R,
88  SDLK_s, vl::Key_S,
89  SDLK_t, vl::Key_T,
90  SDLK_u, vl::Key_U,
91  SDLK_v, vl::Key_V,
92  SDLK_w, vl::Key_W,
93  SDLK_x, vl::Key_X,
94  SDLK_y, vl::Key_Y,
95  SDLK_z, vl::Key_Z,
96 
97  SDLK_RETURN, vl::Key_Return,
98  SDLK_BACKSPACE, vl::Key_BackSpace,
99  SDLK_SPACE, vl::Key_Space,
100  SDLK_TAB, vl::Key_Tab,
101  SDLK_CLEAR, vl::Key_Clear,
102  SDLK_ESCAPE, vl::Key_Escape,
103  SDLK_EXCLAIM, vl::Key_Exclam,
104  SDLK_QUOTEDBL, vl::Key_QuoteDbl,
105  SDLK_HASH, vl::Key_Hash,
106  SDLK_DOLLAR, vl::Key_Dollar,
107  SDLK_AMPERSAND, vl::Key_Ampersand,
108  SDLK_QUOTE, vl::Key_Quote,
109  SDLK_LEFTPAREN, vl::Key_LeftParen,
110  SDLK_RIGHTPAREN, vl::Key_RightParen,
111  SDLK_ASTERISK, vl::Key_Asterisk,
112  SDLK_PLUS, vl::Key_Plus,
113  SDLK_COMMA, vl::Key_Comma,
114  SDLK_MINUS, vl::Key_Minus,
115  SDLK_PERIOD, vl::Key_Period,
116  SDLK_SLASH, vl::Key_Slash,
117  SDLK_COLON, vl::Key_Colon,
118  SDLK_SEMICOLON, vl::Key_Semicolon,
119  SDLK_LESS, vl::Key_Less,
120  SDLK_EQUALS, vl::Key_Equal,
121  SDLK_GREATER, vl::Key_Greater,
122  SDLK_QUESTION, vl::Key_Question,
123  SDLK_AT, vl::Key_At,
124  SDLK_LEFTBRACKET, vl::Key_LeftBracket,
125  SDLK_BACKSLASH, vl::Key_BackSlash,
126  SDLK_RIGHTBRACKET, vl::Key_RightBracket,
127  SDLK_CARET, vl::Key_Caret,
128  SDLK_UNDERSCORE, vl::Key_Underscore,
129  SDLK_BACKQUOTE, vl::Key_QuoteLeft,
130 
131  // non unicode
132 
133  SDLK_LEFT, vl::Key_Left,
134  SDLK_RIGHT, vl::Key_Right,
135  SDLK_UP, vl::Key_Up,
136  SDLK_DOWN, vl::Key_Down,
137  SDLK_LCTRL, vl::Key_LeftCtrl,
138  SDLK_RCTRL, vl::Key_RightCtrl,
139  SDLK_LSHIFT, vl::Key_LeftShift,
140  SDLK_RSHIFT, vl::Key_RightShift,
141  SDLK_LALT, vl::Key_LeftAlt,
142  SDLK_RALT, vl::Key_RightAlt,
143  SDLK_INSERT, vl::Key_Insert,
144  SDLK_DELETE, vl::Key_Delete,
145  SDLK_HOME, vl::Key_Home,
146  SDLK_END, vl::Key_End,
147  SDLK_PAGEUP, vl::Key_PageUp,
148  SDLK_PAGEDOWN, vl::Key_PageDown,
149  SDLK_PAUSE, vl::Key_Pause,
150  SDLK_PRINT, vl::Key_Print,
151  SDLK_F1, vl::Key_F1,
152  SDLK_F2, vl::Key_F2,
153  SDLK_F3, vl::Key_F3,
154  SDLK_F4, vl::Key_F4,
155  SDLK_F5, vl::Key_F5,
156  SDLK_F6, vl::Key_F6,
157  SDLK_F7, vl::Key_F7,
158  SDLK_F8, vl::Key_F8,
159  SDLK_F9, vl::Key_F9,
160  SDLK_F10, vl::Key_F10,
161  SDLK_F11, vl::Key_F11,
162  SDLK_F12, vl::Key_F12,
163  0,0
164  };
165 }
166 //-----------------------------------------------------------------------------
167 SDL_Surface* SDLWindow::mScreen = NULL;
168 //-----------------------------------------------------------------------------
170 {
171 }
172 //-----------------------------------------------------------------------------
174 {
175 }
176 //-----------------------------------------------------------------------------
177 SDLWindow::SDLWindow( const vl::String& title, const vl::OpenGLContextFormat& info, int /*x*/, int /*y*/, int width, int height)
178 {
179  initSDLWindow(title, info, width, height);
180 }
181 //-----------------------------------------------------------------------------
182 bool SDLWindow::initSDLWindow(const vl::String& title, const vl::OpenGLContextFormat& info, int x, int y, int width, int height)
183 {
184  if (mScreen || mSDLWindow)
185  {
186  vl::Log::error("SDL supports only one window at a time.\n");
187  VL_TRAP();
188  return false;
189  }
190 
191  framebuffer()->setWidth(width);
192  framebuffer()->setHeight(height);
193  mSDLWindow = this;
194 
195  // init key translation map
196  for(int i=0; key_translation_vec[i]; i+=2)
197  key_translation_map[ key_translation_vec[i] ] = (vl::EKey)key_translation_vec[i+1];
198 
199  // SDL_VIDEO_WINDOW_POS
200 
201  char win_pos[32] = {0};
202  sprintf ( win_pos, "SDL_VIDEO_WINDOW_POS=%d,%d", x, y );
203  SDL_putenv(win_pos);
204  // setenv("SDL_VIDEO_CENTERED", "YES", 0);
205 
206  // init SDL
207 
208  if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
209  {
210  printf("Unable to init SDL: %s\n", SDL_GetError());
211  return false;
212  }
213 
214  SDL_GL_SetAttribute(SDL_GL_RED_SIZE, info.rgbaBits().r());
215  SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, info.rgbaBits().g());
216  SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, info.rgbaBits().b());
217  SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, info.rgbaBits().a());
218 
219  SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, info.accumRGBABits().r());
220  SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, info.accumRGBABits().g());
221  SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, info.accumRGBABits().b());
222  SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, info.accumRGBABits().a());
223 
224  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, info.depthBufferBits());
225  SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, info.stencilBufferBits());
226 
227  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, info.doubleBuffer()?1:0);
228  SDL_GL_SetAttribute(SDL_GL_STEREO, info.stereo());
229  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, info.multisample()?1:0);
230  if (info.multisample())
231  SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, info.multisampleSamples());
232  SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, info.vSync());
233 
234  int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
235  Uint32 flags = SDL_OPENGL | (info.fullscreen() ? SDL_FULLSCREEN : 0);
236  width = width !=0 ? width : SDL_GetVideoInfo()->current_w;
237  height = height !=0 ? height : SDL_GetVideoInfo()->current_h;
238  mScreen = SDL_SetVideoMode( width, height, bpp, flags );
239  if (mScreen == 0)
240  {
241  vl::Log::print( vl::Say("\n error: SDL_SetVideoMode(%n, %n, %n, %hn) failed: %s\n") << width << height << bpp << flags << SDL_GetError() );
242  exit(1);
243  }
244 
245  // window size problem
246 
247  int viewport[4];
248  glGetIntegerv(GL_VIEWPORT, viewport);
249  VL_CHECK(viewport[0] == 0);
250  VL_CHECK(viewport[1] == 0);
251  if (viewport[2] != mScreen->w || viewport[3] != mScreen->h)
252  {
253  vl::Log::print( vl::Say("\n warning: OpenGL reported %nx%n as video size but SDL says %nx%n\n") << viewport[2] << viewport[3] << mScreen->w << mScreen->h );
254  VL_TRAP()
255  }
256 
257  // OpenGL extensions initialization
258  initGLContext();
259 
260  dispatchInitEvent();
261  dispatchResizeEvent(width, height);
262 
263  #ifndef NDEBUG
264  vl::Log::print( vl::Say("SDL screen: %n x %n x %n %s\n") << mScreen->w << mScreen->h << mScreen->format->BitsPerPixel << (info.fullscreen() ? "fullscreen" : "windowed") );
265  #endif
266 
267  SDL_EnableUNICODE(1);
268 
269  #ifdef WIN32
270  // file drag & drop support
271  SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
272  static SDL_SysWMinfo pInfo;
273  SDL_VERSION(&pInfo.version);
274  SDL_GetWMInfo(&pInfo);
275  HWND hWnd = pInfo.window;
276  DWORD ExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
277  ExStyle |= WS_EX_ACCEPTFILES;
278  SetWindowLong(hWnd, GWL_EXSTYLE, ExStyle);
279  // The SDL gurus decided not to give us this option...
280  // DWORD Style = GetWindowLong(hWnd, GWL_STYLE);
281  // Style |= WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
282  // SetWindowLong(hWnd, GWL_STYLE, Style);
283  #endif
284 
285  // mouse
286 
287  SDL_ShowCursor(true);
288  SDL_WM_GrabInput(SDL_GRAB_OFF);
289  setWindowTitle(title);
290 
291  // event cleaning
292 
293  SDL_PumpEvents();
294  SDL_Event event;
295  while ( SDL_PollEvent(&event) ) {}
296 
297  return true;
298 }
299 //-----------------------------------------------------------------------------
300 void SDLWindow::translateEvent( SDL_Event * ev )
301 {
302  vl::EKey key = vl::Key_None;
303  unsigned short unicode = 0;
304  if ( ev && (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) )
305  {
306  if( key_translation_map.find(ev->key.keysym.sym) != key_translation_map.end() )
307  key = key_translation_map[ ev->key.keysym.sym ];
308  else
309  key = vl::Key_Unknown;
310 
311  unicode = ev->key.keysym.unicode;
312  }
313 
315  //bool update = mUpdateFlag;
317  //mUpdateFlag = continuousUpdate();
318 
319  //if (update)
320  // dispatchUpdateEvent();
321 
322  if (ev->type == SDL_KEYDOWN)
323  {
324  switch(key)
325  {
326  default: break;
327 
328  case vl::Key_LeftCtrl:
329  case vl::Key_RightCtrl:
330  dispatchKeyPressEvent(unicode, vl::Key_Ctrl);
331  break;
332 
333  case vl::Key_LeftShift:
334  case vl::Key_RightShift:
335  dispatchKeyPressEvent(unicode, vl::Key_Shift);
336  break;
337 
338  case vl::Key_LeftAlt:
339  case vl::Key_RightAlt:
340  dispatchKeyPressEvent(unicode, vl::Key_Alt);
341  break;
342  }
343  dispatchKeyPressEvent(unicode, key);
344  }
345  else
346  if (ev->type == SDL_KEYUP)
347  {
348  switch(key)
349  {
350  default: break;
351 
352  case vl::Key_LeftCtrl:
353  case vl::Key_RightCtrl:
354  dispatchKeyReleaseEvent(unicode, vl::Key_Ctrl);
355  break;
356 
357  case vl::Key_LeftShift:
358  case vl::Key_RightShift:
359  dispatchKeyReleaseEvent(unicode, vl::Key_Shift);
360  break;
361 
362  case vl::Key_LeftAlt:
363  case vl::Key_RightAlt:
364  dispatchKeyReleaseEvent(unicode, vl::Key_Alt);
365  break;
366  }
367  dispatchKeyReleaseEvent(unicode, key);
368  }
369  else
370  if (ev->type == SDL_MOUSEBUTTONDOWN)
371  {
372  if (ev->button.button == SDL_BUTTON_WHEELUP)
373  dispatchMouseWheelEvent(1);
374  else
375  if (ev->button.button == SDL_BUTTON_WHEELDOWN)
376  dispatchMouseWheelEvent(-1);
377  else
378  if (ev->button.button == SDL_BUTTON_LEFT)
379  dispatchMouseDownEvent(vl::LeftButton, ev->button.x, ev->button.y);
380  else
381  if (ev->button.button == SDL_BUTTON_RIGHT)
382  dispatchMouseDownEvent(vl::RightButton, ev->button.x, ev->button.y);
383  else
384  if (ev->button.button == SDL_BUTTON_MIDDLE)
385  dispatchMouseDownEvent(vl::MiddleButton, ev->button.x, ev->button.y);
386  }
387  else
388  if (ev->type == SDL_MOUSEBUTTONUP)
389  {
390  // We only need SDL_MOUSEBUTTONDOWN's wheel messages
391  /*if (ev->button.button == SDL_BUTTON_WHEELUP)
392  mouseWheelEvent(1);
393  else
394  if (ev->button.button == SDL_BUTTON_WHEELDOWN)
395  mouseWheelEvent(-1);
396  else*/
397  if (ev->button.button == SDL_BUTTON_LEFT)
398  dispatchMouseUpEvent(vl::LeftButton, ev->button.x, ev->button.y);
399  else
400  if (ev->button.button == SDL_BUTTON_RIGHT)
401  dispatchMouseUpEvent(vl::RightButton, ev->button.x, ev->button.y);
402  else
403  if (ev->button.button == SDL_BUTTON_MIDDLE)
404  dispatchMouseUpEvent(vl::MiddleButton, ev->button.x, ev->button.y);
405  }
406  else
407  if (ev->type == SDL_MOUSEMOTION)
408  {
409  dispatchMouseMoveEvent(ev->motion.x, ev->motion.y);
410  }
411  else
412  if (ev->type == SDL_VIDEORESIZE)
413  {
414  // SDL is not able to resize OpenGL contexts
415  // resizeEvent(ev->resize.w, ev->resize.h);
416  }
417  else
418  if( ev->type == SDL_SYSWMEVENT )
419  {
420  #ifdef WIN32
421  if (ev->syswm.msg->msg == WM_DROPFILES)
422  {
423  HDROP hDrop = (HDROP) ev->syswm.msg->wParam;
424  int count = DragQueryFile(hDrop, 0xFFFFFFFF, 0, 0);
425  const int char_count = 1024;
426  std::vector<String> files;
427  for(int i=0; i<count; ++i)
428  {
429  wchar_t file_path[char_count];
430  memset(file_path, 0, char_count);
431  DragQueryFile(hDrop,i,file_path,char_count);
432  files.push_back(file_path);
433  }
434  dispatchFileDroppedEvent(files);
435  }
436  #endif
437  }
438  else
439  if (ev->type == SDL_QUIT)
440  {
441  quitApplication();
442  }
443 }
444 //-----------------------------------------------------------------------------
446 {
447  SDL_Event ev;
448  while(mSDLWindow)
449  {
450  if ( SDL_PollEvent(&ev) )
451  mSDLWindow->translateEvent(&ev);
452  else
453  {
454  if ( mUpdateFlag || mSDLWindow->continuousUpdate() )
455  {
456  mSDLWindow->dispatchUpdateEvent();
457  mUpdateFlag = false;
458  }
459  else
460  {
461  // rest for 10ms if there are not events to process, and we don't need to repaint
462  SDL_Delay(10);
463  }
464  }
465  }
466 
467  SDL_Quit();
468 }
469 //-----------------------------------------------------------------------------
471 {
472  dispatchDestroyEvent();
473  mSDLWindow = NULL;
474 }
475 //-----------------------------------------------------------------------------
477 {
478  mUpdateFlag = true;
479 }
480 //-----------------------------------------------------------------------------
482 {
483  SDL_WM_SetCaption(title.toStdString().c_str(), title.toStdString().c_str());
484 }
485 //-----------------------------------------------------------------------------
487 {
488  SDL_GL_SwapBuffers();
489 }
490 //-----------------------------------------------------------------------------
491 void SDLWindow::setPosition(int x, int y)
492 {
493  #ifdef WIN32
494  static SDL_SysWMinfo pInfo;
495  SDL_VERSION(&pInfo.version);
496  SDL_GetWMInfo(&pInfo);
497  HWND hWnd = pInfo.window;
498 
499  SetWindowPos(hWnd, 0, x, y, 0, 0, SWP_NOSIZE );
500  #endif
501 }
502 //-----------------------------------------------------------------------------
void update()
If the OpenGLContext is a widget this function requests a redraw and generates an updateEvent()...
Definition: SDLWindow.cpp:476
static SDL_Surface * mScreen
Definition: SDLWindow.hpp:96
void setPosition(int x, int y)
If the OpenGL context is a widget this function sets its position.
Definition: SDLWindow.cpp:491
A simple String formatting class.
Definition: Say.hpp:124
The String class implements an advanced UTF16 (Unicode BMP) string manipulation engine.
Definition: String.hpp:62
int multisampleSamples() const
const T_Scalar & r() const
Definition: Vector4.hpp:111
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
The SDLWindow class implements an OpenGLContext using the SDL API.
Definition: SDLWindow.hpp:58
Visualization Library main namespace.
virtual void swapBuffers()
Swaps the back and front buffers to present the last rendering.
Definition: SDLWindow.cpp:486
The SDL bindings namespace.
const T_Scalar & g() const
Definition: Vector4.hpp:112
#define VL_TRAP()
Definition: checks.hpp:70
The OpenGLContextFormat class encapsulates the settings of an OpenGL rendering context.
bool initSDLWindow(const vl::String &title, const vl::OpenGLContextFormat &info, int x=0, int y=0, int width=640, int height=480)
Definition: SDLWindow.cpp:182
const ivec4 & rgbaBits() const
static void print(const String &message)
Application message for the user.
Definition: Log.cpp:136
const ivec4 & accumRGBABits() const
const T_Scalar & b() const
Definition: Vector4.hpp:113
#define NULL
Definition: OpenGLDefs.hpp:81
String format(unsigned long long n, int base, int field, int decimals, int align, int fill, int plus, int finalizer, int eur) const
Definition: Say.cpp:532
VLSDL_EXPORT void messageLoop()
Definition: SDLWindow.cpp:445
void translateEvent(SDL_Event *ev)
Definition: SDLWindow.cpp:300
std::string toStdString() const
Returns a UTF8 encoded std::string.
Definition: String.cpp:1156
void setWindowTitle(const vl::String &)
If the OpenGL context is a top window this function sets its title.
Definition: SDLWindow.cpp:481
void quitApplication()
Quits the event loop.
Definition: SDLWindow.cpp:470
#define VL_CHECK(expr)
Definition: checks.hpp:73
const T_Scalar & a() const
Definition: Vector4.hpp:114