1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
12 *
13 * This file is Copyright (C) 2007 - Andre Garneau (andre@pixdev.com) and licensed under OSGPL.
14 *
15 * Some elements of GraphicsWindowWin32 have used the Producer implementation as a reference.
16 * These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004 Don Burns.
17 */
18
19 #include <osgViewer/api/Win32/GraphicsWindowWin32>
20 #include <osgViewer/api/Win32/PixelBufferWin32>
21 #include <osgViewer/View>
22
23 #include <osg/GL>
24 #include <osg/DeleteHandler>
25 #include <osg/ApplicationUsage>
26
27 #include <vector>
28 #include <map>
29 #include <sstream>
30 #include <windowsx.h>
31
32 #define MOUSEEVENTF_FROMTOUCH 0xFF515700
33
34 #if(WINVER < 0x0601)
35 // Provide Declarations for Multitouch
36
37 #define WM_TOUCH 0x0240
38
39 /*
40 * Touch Input defines and functions
41 */
42
43 /*
44 * Touch input handle
45 */
46 DECLARE_HANDLE(HTOUCHINPUT);
47
48 typedef struct tagTOUCHINPUT {
49 LONG x;
50 LONG y;
51 HANDLE hSource;
52 DWORD dwID;
53 DWORD dwFlags;
54 DWORD dwMask;
55 DWORD dwTime;
56 ULONG_PTR dwExtraInfo;
57 DWORD cxContact;
58 DWORD cyContact;
59 } TOUCHINPUT, *PTOUCHINPUT;
60 typedef TOUCHINPUT const * PCTOUCHINPUT;
61
62
63 /*
64 * Conversion of touch input coordinates to pixels
65 */
66 #define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
67
68 /*
69 * Touch input flag values (TOUCHINPUT.dwFlags)
70 */
71 #define TOUCHEVENTF_MOVE 0x0001
72 #define TOUCHEVENTF_DOWN 0x0002
73 #define TOUCHEVENTF_UP 0x0004
74 #define TOUCHEVENTF_INRANGE 0x0008
75 #define TOUCHEVENTF_PRIMARY 0x0010
76 #define TOUCHEVENTF_NOCOALESCE 0x0020
77 #define TOUCHEVENTF_PEN 0x0040
78 #define TOUCHEVENTF_PALM 0x0080
79
80 #endif
81
82 typedef
83 BOOL
84 (WINAPI GetTouchInputInfoFunc)(
85 HTOUCHINPUT hTouchInput, // input event handle; from touch message lParam
86 UINT cInputs, // number of elements in the array
87 PTOUCHINPUT pInputs, // array of touch inputs
88 int cbSize); // sizeof(TOUCHINPUT)
89
90 typedef
91 BOOL
92 (WINAPI CloseTouchInputHandleFunc(
93 HTOUCHINPUT hTouchInput)); // input event handle; from touch message lParam
94
95 typedef
96 BOOL
97 (WINAPI RegisterTouchWindowFunc(
98 HWND hwnd,
99 ULONG ulFlags));
100
101 // Declared static in order to get Header File clean
102 static RegisterTouchWindowFunc *registerTouchWindowFunc = NULL;
103 static CloseTouchInputHandleFunc *closeTouchInputHandleFunc = NULL;
104 static GetTouchInputInfoFunc *getTouchInputInfoFunc = NULL;
105
106 using namespace osgViewer;
107
108 namespace osgViewer
109 {
110
111 static osg::ApplicationUsageProxy GraphicsWindowWin32_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND on/off","Enable/disable duplicate makeCurrentContext call used as workaround for WinXP/NVidia/MultiView/MulitThread isues (pre 178.13 drivers).");
112
113 //
114 // Defines from the WGL_ARB_pixel_format specification document
115 // See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
116 //
117
118 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
119 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
120 #define WGL_DRAW_TO_BITMAP_ARB 0x2002
121 #define WGL_ACCELERATION_ARB 0x2003
122 #define WGL_NEED_PALETTE_ARB 0x2004
123 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
124 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
125 #define WGL_SWAP_METHOD_ARB 0x2007
126 #define WGL_NUMBER_OVERLAYS_ARB 0x2008
127 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009
128 #define WGL_TRANSPARENT_ARB 0x200A
129 #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
130 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
131 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
132 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
133 #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
134 #define WGL_SHARE_DEPTH_ARB 0x200C
135 #define WGL_SHARE_STENCIL_ARB 0x200D
136 #define WGL_SHARE_ACCUM_ARB 0x200E
137 #define WGL_SUPPORT_GDI_ARB 0x200F
138 #define WGL_SUPPORT_OPENGL_ARB 0x2010
139 #define WGL_DOUBLE_BUFFER_ARB 0x2011
140 #define WGL_STEREO_ARB 0x2012
141 #define WGL_PIXEL_TYPE_ARB 0x2013
142 #define WGL_COLOR_BITS_ARB 0x2014
143 #define WGL_RED_BITS_ARB 0x2015
144 #define WGL_RED_SHIFT_ARB 0x2016
145 #define WGL_GREEN_BITS_ARB 0x2017
146 #define WGL_GREEN_SHIFT_ARB 0x2018
147 #define WGL_BLUE_BITS_ARB 0x2019
148 #define WGL_BLUE_SHIFT_ARB 0x201A
149 #define WGL_ALPHA_BITS_ARB 0x201B
150 #define WGL_ALPHA_SHIFT_ARB 0x201C
151 #define WGL_ACCUM_BITS_ARB 0x201D
152 #define WGL_ACCUM_RED_BITS_ARB 0x201E
153 #define WGL_ACCUM_GREEN_BITS_ARB 0x201F
154 #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
155 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
156 #define WGL_DEPTH_BITS_ARB 0x2022
157 #define WGL_STENCIL_BITS_ARB 0x2023
158 #define WGL_AUX_BUFFERS_ARB 0x2024
159 #define WGL_NO_ACCELERATION_ARB 0x2025
160 #define WGL_GENERIC_ACCELERATION_ARB 0x2026
161 #define WGL_FULL_ACCELERATION_ARB 0x2027
162 #define WGL_SWAP_EXCHANGE_ARB 0x2028
163 #define WGL_SWAP_COPY_ARB 0x2029
164 #define WGL_SWAP_UNDEFINED_ARB 0x202A
165 #define WGL_TYPE_RGBA_ARB 0x202B
166 #define WGL_TYPE_COLORINDEX_ARB 0x202C
167 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
168 #define WGL_SAMPLES_ARB 0x2042
169
170 #ifndef WGL_ARB_create_context
171 #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
172 #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
173 #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
174 #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
175 #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093
176 #define WGL_CONTEXT_FLAGS_ARB 0x2094
177 #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
178 #define ERROR_INVALID_VERSION_ARB 0x2095
179 #endif
180
181 #ifndef WGL_ARB_create_context
182 #define WGL_ARB_create_context 1
183 #ifdef WGL_WGLEXT_PROTOTYPES
184 extern HGLRC WINAPI wglCreateContextAttribsARB (HDC, HGLRC, const int *);
185 #endif /* WGL_WGLEXT_PROTOTYPES */
186 typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList);
187 #endif
188
189 //
190 // Entry points used from the WGL extensions
191 //
192 // BOOL wglChoosePixelFormatARB(HDC hdc,
193 // const int *piAttribIList,
194 // const FLOAT *pfAttribFList,
195 // UINT nMaxFormats,
196 // int *piFormats,
197 // UINT *nNumFormats);
198 //
199
200 typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * );
201
202 //
203 // Utility class to specify the visual attributes for wglChoosePixelFormatARB() function
204 //
205
206 template <typename T> class WGLAttributes
207 {
208 public:
209
WGLAttributes()210 WGLAttributes() {}
~WGLAttributes()211 ~WGLAttributes() {}
212
begin()213 void begin() { m_parameters.clear(); }
set(const T & id,const T & value)214 void set( const T& id, const T& value ) { add(id); add(value); }
enable(const T & id)215 void enable( const T& id ) { add(id); add(true); }
disable(const T & id)216 void disable( const T& id ) { add(id); add(false); }
end()217 void end() { add(0); }
218
get() const219 const T* get() const { return &m_parameters.front(); }
220
221 protected:
222
add(const T & t)223 void add( const T& t ) { m_parameters.push_back(t); }
224
225 std::vector<T> m_parameters; // parameters added
226
227 private:
228
229 // No implementation for these
230 WGLAttributes( const WGLAttributes& );
231 WGLAttributes& operator=( const WGLAttributes& );
232 };
233
234 typedef WGLAttributes<int> WGLIntegerAttributes;
235 typedef WGLAttributes<float> WGLFloatAttributes;
236
237 //
238 // Class responsible for interfacing with the Win32 Window Manager
239 // The behavior of this class is specific to OSG needs and is not a
240 // generic Windowing interface.
241 //
242 // NOTE: This class is intended to be used by a single-thread.
243 // Multi-threading is not enabled for performance reasons.
244 // The creation/deletion of graphics windows should be done
245 // by a single controller thread. That thread should then
246 // call the checkEvents() method of all created windows periodically.
247 // This is the case with OSG as a "main" thread does all
248 // setup, update & event processing. Rendering is done (optionally) by other threads.
249 //
250 // !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the
251 // creation and event message processing for all windows it manages. This
252 // is to relieve the "main" thread from having to do this synchronously
253 // during frame generation. The "main" thread would only have to process
254 // each osgGA-type window event queue.
255 //
256
257 class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
258 {
259 public:
260
261 // A class representing an OpenGL rendering context
262 class OpenGLContext
263 {
264 public:
265
OpenGLContext()266 OpenGLContext()
267 : _previousHdc(0),
268 _previousHglrc(0),
269 _hwnd(0),
270 _hdc(0),
271 _hglrc(0),
272 _restorePreviousOnExit(false)
273 {}
274
OpenGLContext(HWND hwnd,HDC hdc,HGLRC hglrc)275 OpenGLContext( HWND hwnd, HDC hdc, HGLRC hglrc )
276 : _previousHdc(0),
277 _previousHglrc(0),
278 _hwnd(hwnd),
279 _hdc(hdc),
280 _hglrc(hglrc),
281 _restorePreviousOnExit(false)
282 {}
283
284 ~OpenGLContext();
285
set(HWND hwnd,HDC hdc,HGLRC hglrc)286 void set( HWND hwnd, HDC hdc, HGLRC hglrc )
287 {
288 _hwnd = hwnd;
289 _hdc = hdc;
290 _hglrc = hglrc;
291 }
292
deviceContext()293 HDC deviceContext() { return _hdc; }
294
295 bool makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit );
296
297 protected:
298
299 //
300 // Data members
301 //
302
303 HDC _previousHdc; // previously HDC to restore rendering context on
304 HGLRC _previousHglrc; // previously current rendering context
305 HWND _hwnd; // handle to OpenGL window
306 HDC _hdc; // handle to device context
307 HGLRC _hglrc; // handle to OpenGL rendering context
308 bool _restorePreviousOnExit; // restore original context on exit
309
310 private:
311
312 // no implementation for these
313 OpenGLContext( const OpenGLContext& );
314 OpenGLContext& operator=( const OpenGLContext& );
315 };
316
317 static std::string osgGraphicsWindowWithCursorClass; //!< Name of Win32 window class (with cursor) used by OSG graphics window instances
318 static std::string osgGraphicsWindowWithoutCursorClass; //!< Name of Win32 window class (without cursor) used by OSG graphics window instances
319
320 Win32WindowingSystem();
321 ~Win32WindowingSystem();
322
323 // Access the Win32 windowing system through this singleton class.
getInterface()324 static Win32WindowingSystem* getInterface()
325 {
326 static Win32WindowingSystem* win32Interface = new Win32WindowingSystem;
327 return win32Interface;
328 }
329
330 // Return the number of screens present in the system
331 virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si );
332
333 // Return the resolution of specified screen
334 // (0,0) is returned if screen is unknown
335 virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution );
336
337 // Return the bits per pixel of specified screen
338 // (0) is returned if screen is unknown
339 virtual void getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel );
340
341 // Set the resolution for given screen
342 virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution );
343
344 // Enumerates available resolutions
345 virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolution);
346
347 // Return the screen position and width/height.
348 // all zeros returned if screen is unknown
349 virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height );
350
351 // Create a graphics context with given traits
352 virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits );
353
354 // Register a newly created native window along with its application counterpart
355 // This is required to maintain a link between Windows messages and the application window object
356 // at event processing time
357 virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window );
358
359 // Unregister a window
360 // This is called as part of a window being torn down
361 virtual void unregisterWindow( HWND hwnd );
362
363 // Get the application window object associated with a native window
364 virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd );
365
366 // Return a valid sample OpenGL Device Context and current rendering context that can be used with wglXYZ extensions
367 virtual bool getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY );
368
369 protected:
370
371 // Display devices present in the system
372 typedef std::vector<DISPLAY_DEVICE> DisplayDevices;
373
374 // Map Win32 window handles to GraphicsWindowWin32 instance
375 typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* > WindowHandleEntry;
376 typedef std::map< HWND, osgViewer::GraphicsWindowWin32* > WindowHandles;
377
378 // Enumerate all display devices and return in passed container
379 void enumerateDisplayDevices( DisplayDevices& displayDevices ) const;
380
381 // Get the screen device current mode information
382 bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
383
384 // Change the screen settings (resolution, refresh rate, etc.)
385 bool changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode );
386
387 // Register the window classes used by OSG graphics window instances
388 void registerWindowClasses();
389
390 // Unregister the window classes used by OSG graphics window instances
391 void unregisterWindowClasses();
392
393 // Data members
394 WindowHandles _activeWindows; //!< handles to active windows
395 bool _windowClassesRegistered; //!< true after window classes have been registered
396
397 private:
398
399 // No implementation for these
400 Win32WindowingSystem( const Win32WindowingSystem& );
401 Win32WindowingSystem& operator=( const Win32WindowingSystem& );
402 };
403
404 ///////////////////////////////////////////////////////////////////////////////
405 // Check if window dimensions have changed w.r.t stored values
406 //////////////////////////////////////////////////////////////////////////////
areWindowDimensionsChanged(HWND hwnd,int screenOriginX,int screenOriginY,int & windowX,int & windowY,int & windowWidth,int & windowHeight)407 static bool areWindowDimensionsChanged(HWND hwnd, int screenOriginX, int screenOriginY, int& windowX, int& windowY, int& windowWidth, int& windowHeight)
408 {
409 POINT origin;
410 origin.x = 0;
411 origin.y = 0;
412
413 ::ClientToScreen(hwnd, &origin);
414
415 int new_windowX = origin.x - screenOriginX;
416 int new_windowY = origin.y - screenOriginY;
417
418 RECT clientRect;
419 ::GetClientRect(hwnd, &clientRect);
420
421 int new_windowWidth = (clientRect.right == 0) ? 1 : clientRect.right;
422 int new_windowHeight = (clientRect.bottom == 0) ? 1 : clientRect.bottom;
423
424 if ((new_windowX != windowX) || (new_windowY != windowY) || (new_windowWidth != windowWidth) || (new_windowHeight != windowHeight))
425 {
426 windowX = new_windowX;
427 windowY = new_windowY;
428 windowWidth = new_windowWidth;
429 windowHeight = new_windowHeight;
430
431 return true;
432 }
433 else
434 {
435 return false;
436 }
437 }
438
439 ///////////////////////////////////////////////////////////////////////////////
440 // Error reporting
441 //////////////////////////////////////////////////////////////////////////////
442
reportError(const std::string & msg)443 static void reportError( const std::string& msg )
444 {
445 OSG_WARN << "Error: " << msg.c_str() << std::endl;
446 }
447
reportError(const std::string & msg,unsigned int errorCode)448 static void reportError( const std::string& msg, unsigned int errorCode )
449 {
450 //
451 // Some APIs are documented as returning the error in ::GetLastError but apparently do not
452 // Skip "Reason" field if the errorCode is still success
453 //
454
455 if (errorCode==0)
456 {
457 reportError(msg);
458 return;
459 }
460
461 OSG_WARN << "Windows Error #" << errorCode << ": " << msg.c_str();
462
463 LPVOID lpMsgBuf;
464
465 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
466 NULL,
467 errorCode,
468 0, // Default language
469 (LPTSTR) &lpMsgBuf,
470 0,
471 NULL)!=0)
472 {
473 OSG_WARN << ". Reason: " << LPTSTR(lpMsgBuf) << std::endl;
474 ::LocalFree(lpMsgBuf);
475 }
476 else
477 {
478 OSG_WARN << std::endl;
479 }
480 }
481
reportErrorForScreen(const std::string & msg,const osg::GraphicsContext::ScreenIdentifier & si,unsigned int errorCode)482 static void reportErrorForScreen( const std::string& msg, const osg::GraphicsContext::ScreenIdentifier& si, unsigned int errorCode )
483 {
484 std::ostringstream str;
485
486 str << "[Screen #" << si.screenNum << "] " << msg;
487 reportError(str.str(), errorCode);
488 }
489
490 //////////////////////////////////////////////////////////////////////////////
491 // Keyboard key mapping for Win32
492 //////////////////////////////////////////////////////////////////////////////
493
494 class Win32KeyboardMap
495 {
496 public:
497
Win32KeyboardMap()498 Win32KeyboardMap()
499 {
500 _keymap[VK_ESCAPE ] = osgGA::GUIEventAdapter::KEY_Escape;
501 _keymap[VK_F1 ] = osgGA::GUIEventAdapter::KEY_F1;
502 _keymap[VK_F2 ] = osgGA::GUIEventAdapter::KEY_F2;
503 _keymap[VK_F3 ] = osgGA::GUIEventAdapter::KEY_F3;
504 _keymap[VK_F4 ] = osgGA::GUIEventAdapter::KEY_F4;
505 _keymap[VK_F5 ] = osgGA::GUIEventAdapter::KEY_F5;
506 _keymap[VK_F6 ] = osgGA::GUIEventAdapter::KEY_F6;
507 _keymap[VK_F7 ] = osgGA::GUIEventAdapter::KEY_F7;
508 _keymap[VK_F8 ] = osgGA::GUIEventAdapter::KEY_F8;
509 _keymap[VK_F9 ] = osgGA::GUIEventAdapter::KEY_F9;
510 _keymap[VK_F10 ] = osgGA::GUIEventAdapter::KEY_F10;
511 _keymap[VK_F11 ] = osgGA::GUIEventAdapter::KEY_F11;
512 _keymap[VK_F12 ] = osgGA::GUIEventAdapter::KEY_F12;
513 _keymap[0xc0 ] = osgGA::GUIEventAdapter::KEY_Backquote;
514 _keymap['0' ] = osgGA::GUIEventAdapter::KEY_0;
515 _keymap['1' ] = osgGA::GUIEventAdapter::KEY_1;
516 _keymap['2' ] = osgGA::GUIEventAdapter::KEY_2;
517 _keymap['3' ] = osgGA::GUIEventAdapter::KEY_3;
518 _keymap['4' ] = osgGA::GUIEventAdapter::KEY_4;
519 _keymap['5' ] = osgGA::GUIEventAdapter::KEY_5;
520 _keymap['6' ] = osgGA::GUIEventAdapter::KEY_6;
521 _keymap['7' ] = osgGA::GUIEventAdapter::KEY_7;
522 _keymap['8' ] = osgGA::GUIEventAdapter::KEY_8;
523 _keymap['9' ] = osgGA::GUIEventAdapter::KEY_9;
524 _keymap[0xbd ] = osgGA::GUIEventAdapter::KEY_Minus;
525 _keymap[0xbb ] = osgGA::GUIEventAdapter::KEY_Equals;
526 _keymap[VK_BACK ] = osgGA::GUIEventAdapter::KEY_BackSpace;
527 _keymap[VK_TAB ] = osgGA::GUIEventAdapter::KEY_Tab;
528 _keymap['A' ] = osgGA::GUIEventAdapter::KEY_A;
529 _keymap['B' ] = osgGA::GUIEventAdapter::KEY_B;
530 _keymap['C' ] = osgGA::GUIEventAdapter::KEY_C;
531 _keymap['D' ] = osgGA::GUIEventAdapter::KEY_D;
532 _keymap['E' ] = osgGA::GUIEventAdapter::KEY_E;
533 _keymap['F' ] = osgGA::GUIEventAdapter::KEY_F;
534 _keymap['G' ] = osgGA::GUIEventAdapter::KEY_G;
535 _keymap['H' ] = osgGA::GUIEventAdapter::KEY_H;
536 _keymap['I' ] = osgGA::GUIEventAdapter::KEY_I;
537 _keymap['J' ] = osgGA::GUIEventAdapter::KEY_J;
538 _keymap['K' ] = osgGA::GUIEventAdapter::KEY_K;
539 _keymap['L' ] = osgGA::GUIEventAdapter::KEY_L;
540 _keymap['M' ] = osgGA::GUIEventAdapter::KEY_M;
541 _keymap['N' ] = osgGA::GUIEventAdapter::KEY_N;
542 _keymap['O' ] = osgGA::GUIEventAdapter::KEY_O;
543 _keymap['P' ] = osgGA::GUIEventAdapter::KEY_P;
544 _keymap['Q' ] = osgGA::GUIEventAdapter::KEY_Q;
545 _keymap['R' ] = osgGA::GUIEventAdapter::KEY_R;
546 _keymap['S' ] = osgGA::GUIEventAdapter::KEY_S;
547 _keymap['T' ] = osgGA::GUIEventAdapter::KEY_T;
548 _keymap['U' ] = osgGA::GUIEventAdapter::KEY_U;
549 _keymap['V' ] = osgGA::GUIEventAdapter::KEY_V;
550 _keymap['W' ] = osgGA::GUIEventAdapter::KEY_W;
551 _keymap['X' ] = osgGA::GUIEventAdapter::KEY_X;
552 _keymap['Y' ] = osgGA::GUIEventAdapter::KEY_Y;
553 _keymap['Z' ] = osgGA::GUIEventAdapter::KEY_Z;
554 _keymap[0xdb ] = osgGA::GUIEventAdapter::KEY_Leftbracket;
555 _keymap[0xdd ] = osgGA::GUIEventAdapter::KEY_Rightbracket;
556 _keymap[0xdc ] = osgGA::GUIEventAdapter::KEY_Backslash;
557 _keymap[VK_CAPITAL ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
558 _keymap[0xba ] = osgGA::GUIEventAdapter::KEY_Semicolon;
559 _keymap[0xde ] = osgGA::GUIEventAdapter::KEY_Quote;
560 _keymap[VK_RETURN ] = osgGA::GUIEventAdapter::KEY_Return;
561 _keymap[VK_LSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_L;
562 _keymap[0xbc ] = osgGA::GUIEventAdapter::KEY_Comma;
563 _keymap[0xbe ] = osgGA::GUIEventAdapter::KEY_Period;
564 _keymap[0xbf ] = osgGA::GUIEventAdapter::KEY_Slash;
565 _keymap[VK_RSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_R;
566 _keymap[VK_LCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_L;
567 _keymap[VK_LWIN ] = osgGA::GUIEventAdapter::KEY_Super_L;
568 _keymap[VK_SPACE ] = osgGA::GUIEventAdapter::KEY_Space;
569 _keymap[VK_LMENU ] = osgGA::GUIEventAdapter::KEY_Alt_L;
570 _keymap[VK_RMENU ] = osgGA::GUIEventAdapter::KEY_Alt_R;
571 _keymap[VK_RWIN ] = osgGA::GUIEventAdapter::KEY_Super_R;
572 _keymap[VK_APPS ] = osgGA::GUIEventAdapter::KEY_Menu;
573 _keymap[VK_RCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_R;
574 _keymap[VK_SNAPSHOT ] = osgGA::GUIEventAdapter::KEY_Print;
575 _keymap[VK_SCROLL ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
576 _keymap[VK_PAUSE ] = osgGA::GUIEventAdapter::KEY_Pause;
577 _keymap[VK_HOME ] = osgGA::GUIEventAdapter::KEY_Home;
578 _keymap[VK_PRIOR ] = osgGA::GUIEventAdapter::KEY_Page_Up;
579 _keymap[VK_END ] = osgGA::GUIEventAdapter::KEY_End;
580 _keymap[VK_NEXT ] = osgGA::GUIEventAdapter::KEY_Page_Down;
581 _keymap[VK_DELETE ] = osgGA::GUIEventAdapter::KEY_Delete;
582 _keymap[VK_INSERT ] = osgGA::GUIEventAdapter::KEY_Insert;
583 _keymap[VK_LEFT ] = osgGA::GUIEventAdapter::KEY_Left;
584 _keymap[VK_UP ] = osgGA::GUIEventAdapter::KEY_Up;
585 _keymap[VK_RIGHT ] = osgGA::GUIEventAdapter::KEY_Right;
586 _keymap[VK_DOWN ] = osgGA::GUIEventAdapter::KEY_Down;
587 _keymap[VK_NUMLOCK ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
588 _keymap[VK_DIVIDE ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
589 _keymap[VK_MULTIPLY ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
590 _keymap[VK_SUBTRACT ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
591 _keymap[VK_ADD ] = osgGA::GUIEventAdapter::KEY_KP_Add;
592 _keymap[VK_NUMPAD7 ] = osgGA::GUIEventAdapter::KEY_KP_Home;
593 _keymap[VK_NUMPAD8 ] = osgGA::GUIEventAdapter::KEY_KP_Up;
594 _keymap[VK_NUMPAD9 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
595 _keymap[VK_NUMPAD4 ] = osgGA::GUIEventAdapter::KEY_KP_Left;
596 _keymap[VK_NUMPAD5 ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
597 _keymap[VK_NUMPAD6 ] = osgGA::GUIEventAdapter::KEY_KP_Right;
598 _keymap[VK_NUMPAD1 ] = osgGA::GUIEventAdapter::KEY_KP_End;
599 _keymap[VK_NUMPAD2 ] = osgGA::GUIEventAdapter::KEY_KP_Down;
600 _keymap[VK_NUMPAD3 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
601 _keymap[VK_NUMPAD0 ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
602 _keymap[VK_DECIMAL ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
603 _keymap[VK_CLEAR ] = osgGA::GUIEventAdapter::KEY_Clear;
604 }
605
~Win32KeyboardMap()606 ~Win32KeyboardMap() {}
607
remapKey(int key)608 int remapKey(int key)
609 {
610 KeyMap::const_iterator map = _keymap.find(key);
611 return map==_keymap.end() ? key : map->second;
612 }
613
614 protected:
615
616 typedef std::map<int, int> KeyMap;
617 KeyMap _keymap;
618 };
619
620 static Win32KeyboardMap s_win32KeyboardMap;
remapWin32Key(int key)621 static int remapWin32Key(int key)
622 {
623 return s_win32KeyboardMap.remapKey(key);
624 }
625
626 //////////////////////////////////////////////////////////////////////////////
627 // Window procedure for all GraphicsWindowWin32 instances
628 // Dispatches the call to the actual instance
629 //////////////////////////////////////////////////////////////////////////////
630
WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)631 static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
632 {
633 osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
634 return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
635 ::DefWindowProc(hwnd, uMsg, wParam, lParam);
636 }
637
638 //////////////////////////////////////////////////////////////////////////////
639 // Win32WindowingSystem::OpenGLContext implementation
640 //////////////////////////////////////////////////////////////////////////////
641
~OpenGLContext()642 Win32WindowingSystem::OpenGLContext::~OpenGLContext()
643 {
644 if (_restorePreviousOnExit && _previousHglrc!=_hglrc && !::wglMakeCurrent(_previousHdc, _previousHglrc))
645 {
646 reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError());
647 }
648
649 _previousHdc = 0;
650 _previousHglrc = 0;
651
652 if (_hglrc)
653 {
654 ::wglMakeCurrent(_hdc, NULL);
655 ::wglDeleteContext(_hglrc);
656 _hglrc = 0;
657 }
658
659 if (_hdc)
660 {
661 ::ReleaseDC(_hwnd, _hdc);
662 _hdc = 0;
663 }
664
665 if (_hwnd)
666 {
667 ::DestroyWindow(_hwnd);
668 _hwnd = 0;
669 }
670 }
671
makeCurrent(HDC restoreOnHdc,bool restorePreviousOnExit)672 bool Win32WindowingSystem::OpenGLContext::makeCurrent( HDC restoreOnHdc, bool restorePreviousOnExit )
673 {
674 if (_hdc==0 || _hglrc==0) return false;
675
676 _previousHglrc = restorePreviousOnExit ? ::wglGetCurrentContext() : 0;
677 _previousHdc = restoreOnHdc;
678
679 if (_hglrc==_previousHglrc) return true;
680
681 if (!::wglMakeCurrent(_hdc, _hglrc))
682 {
683 reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError());
684 return false;
685 }
686
687 _restorePreviousOnExit = restorePreviousOnExit;
688
689 return true;
690 }
691
692 //////////////////////////////////////////////////////////////////////////////
693 // Win32WindowingSystem implementation
694 //////////////////////////////////////////////////////////////////////////////
695
696 std::string Win32WindowingSystem::osgGraphicsWindowWithCursorClass;
697 std::string Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass;
698
Win32WindowingSystem()699 Win32WindowingSystem::Win32WindowingSystem()
700 : _windowClassesRegistered(false)
701 {
702 // Detect presence of runtime support for multitouch
703 HMODULE hModule = LoadLibrary("user32");
704 if (hModule)
705 {
706 registerTouchWindowFunc = (RegisterTouchWindowFunc *) GetProcAddress( hModule, "RegisterTouchWindow");
707 closeTouchInputHandleFunc = (CloseTouchInputHandleFunc *) GetProcAddress( hModule, "CloseTouchInputHandle");
708 getTouchInputInfoFunc = (GetTouchInputInfoFunc *) GetProcAddress( hModule, "GetTouchInputInfo");
709
710 if (!(registerTouchWindowFunc && closeTouchInputHandleFunc && getTouchInputInfoFunc))
711 {
712 registerTouchWindowFunc = NULL;
713 closeTouchInputHandleFunc = NULL;
714 getTouchInputInfoFunc = NULL;
715 FreeLibrary( hModule);
716 }
717 }
718 }
719
~Win32WindowingSystem()720 Win32WindowingSystem::~Win32WindowingSystem()
721 {
722 if (osg::Referenced::getDeleteHandler())
723 {
724 osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
725 osg::Referenced::getDeleteHandler()->flushAll();
726 }
727
728 unregisterWindowClasses();
729 }
730
enumerateDisplayDevices(DisplayDevices & displayDevices) const731 void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const
732 {
733 for (unsigned int deviceNum=0;; ++deviceNum)
734 {
735 DISPLAY_DEVICE displayDevice;
736 displayDevice.cb = sizeof(displayDevice);
737
738 if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break;
739
740 // Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
741 if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
742
743 // Only return display devices that are attached to the desktop
744 if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
745
746 displayDevices.push_back(displayDevice);
747 }
748 }
749
registerWindowClasses()750 void Win32WindowingSystem::registerWindowClasses()
751 {
752 if (_windowClassesRegistered) return;
753
754 //
755 // Register the window classes used by OSG GraphicsWindowWin32 instances
756 //
757
758 std::ostringstream str;
759 str << "OSG Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]";
760
761 osgGraphicsWindowWithCursorClass = str.str() + "{ with cursor }";
762 osgGraphicsWindowWithoutCursorClass = str.str() + "{ without cursor }";
763
764 WNDCLASSEX wc;
765
766 HINSTANCE hinst = ::GetModuleHandle(NULL);
767
768 //
769 // First class: class for OSG Graphics Window with a cursor enabled
770 //
771
772 wc.cbSize = sizeof(wc);
773 wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
774 wc.lpfnWndProc = WindowProc;
775 wc.cbClsExtra = 0;
776 wc.cbWndExtra = 0;
777 wc.hInstance = hinst;
778 wc.hIcon = ::LoadIcon(hinst, "OSG_ICON");
779 wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
780 wc.hbrBackground = NULL;
781 wc.lpszMenuName = 0;
782 wc.lpszClassName = osgGraphicsWindowWithCursorClass.c_str();
783 wc.hIconSm = NULL;
784
785 if (::RegisterClassEx(&wc)==0)
786 {
787 unsigned int lastError = ::GetLastError();
788 if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
789 {
790 reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register first window class", lastError);
791 return;
792 }
793 }
794
795 //
796 // Second class: class for OSG Graphics Window without a cursor
797 //
798
799 wc.hCursor = NULL;
800 wc.lpszClassName = osgGraphicsWindowWithoutCursorClass.c_str();
801
802 if (::RegisterClassEx(&wc)==0)
803 {
804 unsigned int lastError = ::GetLastError();
805 if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
806 {
807 reportError("Win32WindowingSystem::registerWindowClasses() - Unable to register second window class", lastError);
808 return;
809 }
810 }
811
812 _windowClassesRegistered = true;
813 }
814
unregisterWindowClasses()815 void Win32WindowingSystem::unregisterWindowClasses()
816 {
817 if (_windowClassesRegistered)
818 {
819 ::UnregisterClass(osgGraphicsWindowWithCursorClass.c_str(), ::GetModuleHandle(NULL));
820 ::UnregisterClass(osgGraphicsWindowWithoutCursorClass.c_str(), ::GetModuleHandle(NULL));
821 _windowClassesRegistered = false;
822 }
823 }
824
getSampleOpenGLContext(OpenGLContext & context,HDC windowHDC,int windowOriginX,int windowOriginY)825 bool Win32WindowingSystem::getSampleOpenGLContext( OpenGLContext& context, HDC windowHDC, int windowOriginX, int windowOriginY )
826 {
827 context.set(0, 0, 0);
828
829 registerWindowClasses();
830
831 HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
832 osgGraphicsWindowWithoutCursorClass.c_str(),
833 NULL,
834 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
835 windowOriginX,
836 windowOriginY,
837 1,
838 1,
839 NULL,
840 NULL,
841 ::GetModuleHandle(NULL),
842 NULL);
843 if (hwnd==0)
844 {
845 reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError());
846 return false;
847 }
848
849 //
850 // Set the pixel format of the window
851 //
852
853 PIXELFORMATDESCRIPTOR pixelFormat =
854 {
855 sizeof(PIXELFORMATDESCRIPTOR),
856 1,
857 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
858 PFD_TYPE_RGBA,
859 24,
860 0, 0, 0, 0, 0, 0, 0, 0,
861 0, 0, 0, 0, 0,
862 24,
863 0,
864 0,
865 PFD_MAIN_PLANE,
866 0,
867 0, 0, 0
868 };
869
870 HDC hdc = ::GetDC(hwnd);
871 if (hdc==0)
872 {
873 reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError());
874 ::DestroyWindow(hwnd);
875 return false;
876 }
877
878 int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
879 if (pixelFormatIndex==0)
880 {
881 reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError());
882 ::ReleaseDC(hwnd, hdc);
883 ::DestroyWindow(hwnd);
884 return false;
885 }
886
887 if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat))
888 {
889 reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError());
890 ::ReleaseDC(hwnd, hdc);
891 ::DestroyWindow(hwnd);
892 return false;
893 }
894
895 HGLRC hglrc = ::wglCreateContext(hdc);
896 if (hglrc==0)
897 {
898 reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError());
899 ::ReleaseDC(hwnd, hdc);
900 ::DestroyWindow(hwnd);
901 return false;
902 }
903
904 context.set(hwnd, hdc, hglrc);
905
906 if (!context.makeCurrent(windowHDC, true)) return false;
907
908 return true;
909 }
910
getNumScreens(const osg::GraphicsContext::ScreenIdentifier & si)911 unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
912 {
913 return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0;
914 }
915
getScreenInformation(const osg::GraphicsContext::ScreenIdentifier & si,DISPLAY_DEVICE & displayDevice,DEVMODE & deviceMode)916 bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
917 {
918 if (si.displayNum>0)
919 {
920 OSG_WARN << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
921 return false;
922 }
923
924 DisplayDevices displayDevices;
925 enumerateDisplayDevices(displayDevices);
926
927 if (si.screenNum>=static_cast<int>(displayDevices.size()))
928 {
929 OSG_WARN << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
930 return false;
931 }
932
933 displayDevice = displayDevices[si.screenNum];
934
935 deviceMode.dmSize = sizeof(deviceMode);
936 deviceMode.dmDriverExtra = 0;
937
938 if (!::EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
939 {
940 std::ostringstream str;
941 str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum;
942 reportError(str.str(), ::GetLastError());
943 return false;
944 }
945
946 return true;
947 }
948
getScreenSettings(const osg::GraphicsContext::ScreenIdentifier & si,osg::GraphicsContext::ScreenSettings & resolution)949 void Win32WindowingSystem::getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution )
950 {
951 DISPLAY_DEVICE displayDevice;
952 DEVMODE deviceMode;
953
954 if (!getScreenInformation(si, displayDevice, deviceMode))
955 deviceMode.dmFields = 0; // Set the fields to 0 so that it says 'nothing'.
956
957 // Get resolution
958 if ((deviceMode.dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != 0) {
959 resolution.width = deviceMode.dmPelsWidth;
960 resolution.height = deviceMode.dmPelsHeight;
961 } else {
962 resolution.width = 0;
963 resolution.height = 0;
964 }
965
966 // Get refersh rate
967 if ((deviceMode.dmFields & DM_DISPLAYFREQUENCY) != 0) {
968 resolution.refreshRate = deviceMode.dmDisplayFrequency;
969 if (resolution.refreshRate == 0 || resolution.refreshRate == 1) {
970 // Windows specific: 0 and 1 represent the hhardware's default refresh rate.
971 // If someone knows how to get this refresh rate (in Hz)...
972 OSG_NOTICE << "Win32WindowingSystem::getScreenSettings() is not fully implemented (cannot retrieve the hardware's default refresh rate)."<<std::endl;
973 resolution.refreshRate = 0;
974 }
975 } else
976 resolution.refreshRate = 0;
977
978 // Get bits per pixel for color buffer
979 if ((deviceMode.dmFields & DM_BITSPERPEL) != 0)
980 resolution.colorDepth = deviceMode.dmBitsPerPel;
981 else
982 resolution.colorDepth = 0;
983 }
984
getScreenColorDepth(const osg::GraphicsContext::ScreenIdentifier & si,unsigned int & dmBitsPerPel)985 void Win32WindowingSystem::getScreenColorDepth( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& dmBitsPerPel )
986 {
987 DISPLAY_DEVICE displayDevice;
988 DEVMODE deviceMode;
989
990 if (getScreenInformation(si, displayDevice, deviceMode))
991 {
992 dmBitsPerPel = deviceMode.dmBitsPerPel;
993 }
994 else
995 {
996 dmBitsPerPel = 0;
997 }
998 }
999
changeScreenSettings(const osg::GraphicsContext::ScreenIdentifier & si,DISPLAY_DEVICE & displayDevice,DEVMODE & deviceMode)1000 bool Win32WindowingSystem::changeScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, DISPLAY_DEVICE& displayDevice, DEVMODE& deviceMode )
1001 {
1002 //
1003 // Start by testing if the change would be successful (without applying it)
1004 //
1005
1006 unsigned int result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, CDS_TEST, NULL);
1007 if (result==DISP_CHANGE_SUCCESSFUL)
1008 {
1009 result = ::ChangeDisplaySettingsEx(displayDevice.DeviceName, &deviceMode, NULL, 0, NULL);
1010 if (result==DISP_CHANGE_SUCCESSFUL) return true;
1011 }
1012
1013 std::string msg = "Win32WindowingSystem::changeScreenSettings() - Unable to change the screen settings.";
1014
1015 switch( result )
1016 {
1017 case DISP_CHANGE_BADMODE : msg += " The specified graphics mode is not supported."; break;
1018 case DISP_CHANGE_FAILED : msg += " The display driver failed the specified graphics mode."; break;
1019 case DISP_CHANGE_RESTART : msg += " The computer must be restarted for the graphics mode to work."; break;
1020 default : break;
1021 }
1022
1023 reportErrorForScreen(msg, si, result);
1024 return false;
1025 }
1026
setScreenSettings(const osg::GraphicsContext::ScreenIdentifier & si,const osg::GraphicsContext::ScreenSettings & resolution)1027 bool Win32WindowingSystem::setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si, const osg::GraphicsContext::ScreenSettings & resolution )
1028 {
1029 DISPLAY_DEVICE displayDevice;
1030 DEVMODE deviceMode;
1031
1032 if (!getScreenInformation(si, displayDevice, deviceMode)) return false;
1033
1034 deviceMode.dmFields = 0;
1035 // Set resolution
1036 if (resolution.width>0 && resolution.height>0) {
1037 deviceMode.dmFields |= DM_PELSWIDTH | DM_PELSHEIGHT;
1038 deviceMode.dmPelsWidth = static_cast<DWORD>(resolution.width);
1039 deviceMode.dmPelsHeight = static_cast<DWORD>(resolution.height);
1040 }
1041 // Set refersh rate
1042 if (resolution.refreshRate>0) {
1043 deviceMode.dmFields |= DM_DISPLAYFREQUENCY;
1044 deviceMode.dmDisplayFrequency = static_cast<DWORD>(resolution.refreshRate);
1045 }
1046 // Set bits per pixel for color buffer
1047 if (resolution.colorDepth>0) {
1048 deviceMode.dmFields |= DM_BITSPERPEL;
1049 deviceMode.dmBitsPerPel = static_cast<DWORD>(resolution.colorDepth);
1050 }
1051
1052 return changeScreenSettings(si, displayDevice, deviceMode);
1053 }
1054
enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier & si,osg::GraphicsContext::ScreenSettingsList & resolutionList)1055 void Win32WindowingSystem::enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettingsList & resolutionList) {
1056 resolutionList.clear();
1057
1058 if (si.displayNum>0)
1059 {
1060 OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
1061 return;
1062 }
1063
1064 DisplayDevices displayDevices;
1065 enumerateDisplayDevices(displayDevices);
1066
1067 if (si.screenNum>=static_cast<int>(displayDevices.size()))
1068 {
1069 OSG_WARN << "Win32WindowingSystem::enumerateScreenSettings() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
1070 return;
1071 }
1072
1073 DISPLAY_DEVICE displayDevice = displayDevices[si.screenNum];
1074
1075 // Do the enumeration
1076 DEVMODE deviceMode;
1077 static const unsigned int MAX_RESOLUTIONS = 4046; // Upper limit to avoid infinite (= very long) loop.
1078 for (unsigned int i=0; i<MAX_RESOLUTIONS; ++i)
1079 {
1080 if (!::EnumDisplaySettings(displayDevice.DeviceName, i, &deviceMode))
1081 break;
1082 deviceMode.dmSize = sizeof(deviceMode);
1083 deviceMode.dmDriverExtra = 0;
1084 resolutionList.push_back(osg::GraphicsContext::ScreenSettings(deviceMode.dmPelsWidth, deviceMode.dmPelsHeight, deviceMode.dmDisplayFrequency, deviceMode.dmBitsPerPel));
1085 }
1086 }
1087
getScreenPosition(const osg::GraphicsContext::ScreenIdentifier & si,int & originX,int & originY,unsigned int & width,unsigned int & height)1088 void Win32WindowingSystem::getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height )
1089 {
1090 DISPLAY_DEVICE displayDevice;
1091 DEVMODE deviceMode;
1092
1093 if (getScreenInformation(si, displayDevice, deviceMode))
1094 {
1095 originX = deviceMode.dmPosition.x;
1096 originY = deviceMode.dmPosition.y;
1097 width = deviceMode.dmPelsWidth;
1098 height = deviceMode.dmPelsHeight;
1099 }
1100 else
1101 {
1102 originX = 0;
1103 originY = 0;
1104 width = 0;
1105 height = 0;
1106 }
1107 }
1108
createGraphicsContext(osg::GraphicsContext::Traits * traits)1109 osg::GraphicsContext* Win32WindowingSystem::createGraphicsContext( osg::GraphicsContext::Traits* traits )
1110 {
1111 if (traits->pbuffer)
1112 {
1113 osg::ref_ptr<osgViewer::PixelBufferWin32> pbuffer = new PixelBufferWin32(traits);
1114 if (pbuffer->valid()) return pbuffer.release();
1115 else return 0;
1116 }
1117 else
1118 {
1119 registerWindowClasses();
1120
1121 osg::ref_ptr<osgViewer::GraphicsWindowWin32> window = new GraphicsWindowWin32(traits);
1122 if (window->valid()) return window.release();
1123 else return 0;
1124 }
1125 }
1126
registerWindow(HWND hwnd,osgViewer::GraphicsWindowWin32 * window)1127 void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window )
1128 {
1129 if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window));
1130 }
1131
1132 //
1133 // Unregister a window
1134 // This is called as part of a window being torn down
1135 //
1136
unregisterWindow(HWND hwnd)1137 void Win32WindowingSystem::unregisterWindow( HWND hwnd )
1138 {
1139 if (hwnd) _activeWindows.erase(hwnd);
1140 }
1141
1142 //
1143 // Get the application window object associated with a native window
1144 //
1145
getGraphicsWindowFor(HWND hwnd)1146 osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd )
1147 {
1148 WindowHandles::const_iterator entry = _activeWindows.find(hwnd);
1149 return entry==_activeWindows.end() ? 0 : entry->second;
1150 }
1151
1152 //////////////////////////////////////////////////////////////////////////////
1153 // GraphicsWindowWin32 implementation
1154 //////////////////////////////////////////////////////////////////////////////
1155
GraphicsWindowWin32(osg::GraphicsContext::Traits * traits)1156 GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits )
1157 : _currentCursor(0),
1158 _windowProcedure(0),
1159 _timeOfLastCheckEvents(-1.0),
1160 _screenOriginX(0),
1161 _screenOriginY(0),
1162 _screenWidth(0),
1163 _screenHeight(0),
1164 _windowOriginXToRealize(0),
1165 _windowOriginYToRealize(0),
1166 _windowWidthToRealize(0),
1167 _windowHeightToRealize(0),
1168 _initialized(false),
1169 _valid(false),
1170 _realized(false),
1171 _ownsWindow(true),
1172 _closeWindow(false),
1173 _destroyWindow(false),
1174 _destroying(false),
1175 _mouseCursor(InheritCursor),
1176 _appMouseCursor(LeftArrowCursor),
1177 _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues( false )
1178 {
1179 _traits = traits;
1180 if (_traits->useCursor) setCursor(LeftArrowCursor);
1181 else setCursor(NoCursor);
1182
1183 init();
1184
1185 if (valid())
1186 {
1187 setState( new osg::State );
1188 getState()->setGraphicsContext(this);
1189
1190 if (_traits.valid() && _traits->sharedContext.valid())
1191 {
1192 getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
1193 incrementContextIDUsageCount( getState()->getContextID() );
1194 }
1195 else
1196 {
1197 getState()->setContextID( osg::GraphicsContext::createNewContextID() );
1198 }
1199 }
1200 }
1201
~GraphicsWindowWin32()1202 GraphicsWindowWin32::~GraphicsWindowWin32()
1203 {
1204 close();
1205 destroyWindow();
1206 }
1207
init()1208 void GraphicsWindowWin32::init()
1209 {
1210 if (_initialized) return;
1211
1212 // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
1213
1214 WindowData *windowData = _traits.valid() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1215 HWND windowHandle = windowData ? windowData->_hwnd : 0;
1216
1217 _ownsWindow = windowHandle==0;
1218 _closeWindow = false;
1219 _destroyWindow = false;
1220 _destroying = false;
1221
1222 _initialized = _ownsWindow ? createWindow() : setWindow(windowHandle);
1223 _valid = _initialized;
1224
1225 int windowX = 0, windowY = 0, windowWidth = 0, windowHeight = 0;
1226 if (_traits.valid())
1227 {
1228 windowX = _traits->x;
1229 windowY = _traits->y;
1230 windowWidth = _traits->width;
1231 windowHeight = _traits->height;
1232 }
1233
1234 if (areWindowDimensionsChanged(_hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight))
1235 {
1236 resized(windowX, windowY, windowWidth, windowHeight);
1237 }
1238
1239 // make sure the event queue has the correct window rectangle size and input range
1240 getEventQueue()->syncWindowRectangleWithGraphicsContext();
1241
1242 // 2008/10/03
1243 // Few days ago NVidia released WHQL certified drivers ver 178.13.
1244 // These drivers (as well as former beta ver 177.92) were free from the bug described below.
1245 // So it looks like its high time to make the workaround inactive by default.
1246 // If you happen to still use earlier drivers and have problems consider changing to new ones or
1247 // activate OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND macro def through CMake advanced vars.
1248 #ifdef OSG_MULTIMONITOR_MULTITHREAD_WIN32_NVIDIA_WORKAROUND
1249
1250 // 2008/05/12
1251 // Workaround for Bugs in NVidia drivers for windows XP / multithreaded / dualview / multicore CPU
1252 // affects GeForce 6x00, 7x00, 8x00 boards (others were not tested) driver versions 174.xx - 175.xx
1253 // pre 174.xx had other issues so reverting is not an option (statitistics, fbo)
1254 // drivers release 175.16 is the latest currently available
1255 //
1256 // When using OpenGL in threaded app ( main thread sets up context / renderer thread draws using it )
1257 // first wglMakeCurrent seems to not work right and screw OpenGL context driver data:
1258 // 1: successive drawing shows a number of artifacts in TriangleStrips and TriangleFans
1259 // 2: weird behaviour of FramBufferObjects (glGenFramebuffer generates already generated ids ...)
1260 // Looks like repeating wglMakeCurrent call fixes all these issues
1261 // wglMakeCurrent call can impact performance so I try to minimize number of
1262 // wglMakeCurrent calls by checking current HDC and GL context
1263 // and repeat wglMakeCurrent only when they change for current thread
1264
1265 _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = true;
1266 #endif
1267
1268 const char* str = getenv("OSG_WIN32_NV_MULTIMON_MULTITHREAD_WORKAROUND");
1269 if (str)
1270 {
1271 _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues = (strcmp(str, "on")==0 || strcmp(str, "ON")==0 || strcmp(str, "On")==0 );
1272 }
1273 }
1274
createWindow()1275 bool GraphicsWindowWin32::createWindow()
1276 {
1277 unsigned int extendedStyle;
1278 unsigned int windowStyle;
1279
1280 if (!determineWindowPositionAndStyle(_traits->screenNum,
1281 _traits->x,
1282 _traits->y,
1283 _traits->width,
1284 _traits->height,
1285 _traits->windowDecoration,
1286 _windowOriginXToRealize,
1287 _windowOriginYToRealize,
1288 _windowWidthToRealize,
1289 _windowHeightToRealize,
1290 windowStyle,
1291 extendedStyle))
1292 {
1293 reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
1294 return false;
1295 }
1296
1297 _hwnd = ::CreateWindowEx(extendedStyle,
1298 _traits->useCursor ? Win32WindowingSystem::osgGraphicsWindowWithCursorClass.c_str() :
1299 Win32WindowingSystem::osgGraphicsWindowWithoutCursorClass.c_str(),
1300 _traits->windowName.c_str(),
1301 windowStyle,
1302 _windowOriginXToRealize,
1303 _windowOriginYToRealize,
1304 _windowWidthToRealize,
1305 _windowHeightToRealize,
1306 NULL,
1307 NULL,
1308 ::GetModuleHandle(NULL),
1309 NULL);
1310 if (_hwnd==0)
1311 {
1312 reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create window", _traits->screenNum, ::GetLastError());
1313 return false;
1314 }
1315
1316 _hdc = ::GetDC(_hwnd);
1317 if (_hdc==0)
1318 {
1319 reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1320 destroyWindow();
1321 _hwnd = 0;
1322 return false;
1323 }
1324
1325 //
1326 // Set the pixel format according to traits specified
1327 //
1328
1329 if (!setPixelFormat())
1330 {
1331 ::ReleaseDC(_hwnd, _hdc);
1332 _hdc = 0;
1333 destroyWindow();
1334 return false;
1335 }
1336
1337 //
1338 // Create the OpenGL rendering context associated with this window
1339 //
1340
1341 _hglrc = createContextImplementation();
1342 if (_hglrc==0)
1343 {
1344 reportErrorForScreen("GraphicsWindowWin32::createWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1345 ::ReleaseDC(_hwnd, _hdc);
1346 _hdc = 0;
1347 destroyWindow();
1348 return false;
1349 }
1350
1351 Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1352
1353 if (registerTouchWindowFunc)
1354 (*registerTouchWindowFunc)( _hwnd, 0);
1355 return true;
1356 }
1357
setWindow(HWND handle)1358 bool GraphicsWindowWin32::setWindow( HWND handle )
1359 {
1360 if (_initialized)
1361 {
1362 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Window already created; it cannot be changed", _traits->screenNum, ::GetLastError());
1363 return false;
1364 }
1365
1366 if (handle==0)
1367 {
1368 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Invalid window handle passed", _traits->screenNum, ::GetLastError());
1369 return false;
1370 }
1371
1372 _hwnd = handle;
1373 if (_hwnd==0)
1374 {
1375 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to retrieve native window handle", _traits->screenNum, ::GetLastError());
1376 return false;
1377 }
1378
1379 _hdc = ::GetDC(_hwnd);
1380 if (_hdc==0)
1381 {
1382 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to get window device context", _traits->screenNum, ::GetLastError());
1383 _hwnd = 0;
1384 return false;
1385 }
1386
1387 //
1388 // Check if we must set the pixel format of the inherited window
1389 //
1390
1391 if (!setPixelFormat())
1392 {
1393 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to set the inherited window pixel format", _traits->screenNum, ::GetLastError());
1394 ::ReleaseDC(_hwnd, _hdc);
1395 _hdc = 0;
1396 _hwnd = 0;
1397 return false;
1398 }
1399
1400 _hglrc = createContextImplementation();
1401 if (_hglrc==0)
1402 {
1403 reportErrorForScreen("GraphicsWindowWin32::setWindow() - Unable to create OpenGL rendering context", _traits->screenNum, ::GetLastError());
1404 ::ReleaseDC(_hwnd, _hdc);
1405 _hdc = 0;
1406 _hwnd = 0;
1407 return false;
1408 }
1409
1410 WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
1411
1412 if (!windowData || windowData->_installEventHandler)
1413 {
1414 if (!registerWindowProcedure())
1415 {
1416 ::wglDeleteContext(_hglrc);
1417 _hglrc = 0;
1418 ::ReleaseDC(_hwnd, _hdc);
1419 _hdc = 0;
1420 _hwnd = 0;
1421 return false;
1422 }
1423 }
1424
1425 Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1426
1427 _initialized = true;
1428 _valid = true;
1429
1430 return true;
1431 }
1432
destroyWindow(bool deleteNativeWindow)1433 void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
1434 {
1435 if (_destroying) return;
1436 _destroying = true;
1437
1438 if (_graphicsThread && _graphicsThread->isRunning())
1439 {
1440 // find all the viewers that might own use this graphics context
1441 osg::GraphicsContext::Cameras cameras = getCameras();
1442 for(osg::GraphicsContext::Cameras::iterator it=cameras.begin(); it!=cameras.end(); ++it)
1443 {
1444 osgViewer::View* view = dynamic_cast<osgViewer::View*>((*it)->getView());
1445 osgViewer::ViewerBase* viewerBase = view ? view->getViewerBase() : 0;
1446 if (viewerBase && viewerBase->areThreadsRunning())
1447 {
1448 viewerBase->stopThreading();
1449 }
1450 }
1451 }
1452
1453 if (_hdc)
1454 {
1455 releaseContext();
1456
1457 if (_hglrc)
1458 {
1459 ::wglDeleteContext(_hglrc);
1460 _hglrc = 0;
1461 }
1462
1463 ::ReleaseDC(_hwnd, _hdc);
1464 _hdc = 0;
1465 }
1466
1467 (void)unregisterWindowProcedure();
1468
1469 if (_hwnd)
1470 {
1471 Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1472 if (_ownsWindow && deleteNativeWindow) ::DestroyWindow(_hwnd);
1473 _hwnd = 0;
1474 }
1475
1476 _initialized = false;
1477 _realized = false;
1478 _valid = false;
1479 _destroying = false;
1480 }
1481
registerWindow()1482 void GraphicsWindowWin32::registerWindow()
1483 {
1484 Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
1485 }
1486
unregisterWindow()1487 void GraphicsWindowWin32::unregisterWindow()
1488 {
1489 Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
1490 }
1491
registerWindowProcedure()1492 bool GraphicsWindowWin32::registerWindowProcedure()
1493 {
1494 ::SetLastError(0);
1495 _windowProcedure = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(WindowProc));
1496 unsigned int error = ::GetLastError();
1497
1498 if (_windowProcedure==0 && error)
1499 {
1500 reportErrorForScreen("GraphicsWindowWin32::registerWindowProcedure() - Unable to register window procedure", _traits->screenNum, error);
1501 return false;
1502 }
1503
1504 return true;
1505 }
1506
unregisterWindowProcedure()1507 bool GraphicsWindowWin32::unregisterWindowProcedure()
1508 {
1509 if (_windowProcedure==0 || _hwnd==0) return true;
1510
1511 ::SetLastError(0);
1512 WNDPROC wndProc = (WNDPROC)::SetWindowLongPtr(_hwnd, GWLP_WNDPROC, LONG_PTR(_windowProcedure));
1513 unsigned int error = ::GetLastError();
1514
1515 if (wndProc==0 && error)
1516 {
1517 reportErrorForScreen("GraphicsWindowWin32::unregisterWindowProcedure() - Unable to unregister window procedure", _traits->screenNum, error);
1518 return false;
1519 }
1520
1521 _windowProcedure = 0;
1522
1523 return true;
1524 }
1525
determineWindowPositionAndStyle(unsigned int screenNum,int clientAreaX,int clientAreaY,unsigned int clientAreaWidth,unsigned int clientAreaHeight,bool decorated,int & x,int & y,unsigned int & w,unsigned int & h,unsigned int & style,unsigned int & extendedStyle)1526 bool GraphicsWindowWin32::determineWindowPositionAndStyle( unsigned int screenNum,
1527 int clientAreaX,
1528 int clientAreaY,
1529 unsigned int clientAreaWidth,
1530 unsigned int clientAreaHeight,
1531 bool decorated,
1532 int& x,
1533 int& y,
1534 unsigned int& w,
1535 unsigned int& h,
1536 unsigned int& style,
1537 unsigned int& extendedStyle )
1538 {
1539 if (_traits==0) return false;
1540
1541 //
1542 // Query the screen position and size
1543 //
1544
1545 osg::GraphicsContext::ScreenIdentifier screenId(screenNum);
1546 Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface();
1547
1548 windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
1549 if (_screenWidth==0 || _screenHeight==0) return false;
1550
1551 x = clientAreaX + _screenOriginX;
1552 y = clientAreaY + _screenOriginY;
1553 w = clientAreaWidth;
1554 h = clientAreaHeight;
1555
1556 style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
1557
1558 extendedStyle = 0;
1559
1560 if (decorated)
1561 {
1562 style |= WS_CAPTION |
1563 WS_SYSMENU |
1564 WS_MINIMIZEBOX |
1565 WS_MAXIMIZEBOX;
1566
1567 if (_traits->supportsResize) style |= WS_SIZEBOX;
1568
1569 extendedStyle = WS_EX_APPWINDOW |
1570 WS_EX_OVERLAPPEDWINDOW |
1571 WS_EX_ACCEPTFILES |
1572 WS_EX_LTRREADING;
1573
1574 RECT corners;
1575
1576 corners.left = x;
1577 corners.top = y;
1578 corners.right = x + w - 1;
1579 corners.bottom = y + h - 1;
1580
1581 //
1582 // Determine the location of the window corners in order to have
1583 // a client area of the requested size
1584 //
1585
1586 if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
1587 {
1588 reportErrorForScreen("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", _traits->screenNum, ::GetLastError());
1589 return false;
1590 }
1591
1592 x = corners.left;
1593 y = corners.top;
1594 w = corners.right - corners.left + 1;
1595 h = corners.bottom - corners.top + 1;
1596 }
1597
1598 return true;
1599 }
1600
PreparePixelFormatSpecifications(const osg::GraphicsContext::Traits & traits,WGLIntegerAttributes & attributes,bool allowSwapExchangeARB)1601 static void PreparePixelFormatSpecifications( const osg::GraphicsContext::Traits& traits,
1602 WGLIntegerAttributes& attributes,
1603 bool allowSwapExchangeARB )
1604 {
1605 attributes.begin();
1606
1607 attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
1608 attributes.enable(WGL_SUPPORT_OPENGL_ARB);
1609
1610 attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
1611 attributes.set(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
1612
1613 attributes.set(WGL_COLOR_BITS_ARB, traits.red + traits.green + traits.blue);
1614 attributes.set(WGL_RED_BITS_ARB, traits.red);
1615 attributes.set(WGL_GREEN_BITS_ARB, traits.green);
1616 attributes.set(WGL_BLUE_BITS_ARB, traits.blue);
1617 attributes.set(WGL_DEPTH_BITS_ARB, traits.depth);
1618
1619 if (traits.doubleBuffer)
1620 {
1621 attributes.enable(WGL_DOUBLE_BUFFER_ARB);
1622
1623 switch ( traits.swapMethod )
1624 {
1625 case osg::DisplaySettings::SWAP_COPY:
1626 attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_COPY_ARB);
1627 break;
1628 case osg::DisplaySettings::SWAP_EXCHANGE:
1629 attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1630 break;
1631 case osg::DisplaySettings::SWAP_UNDEFINED:
1632 attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_UNDEFINED_ARB);
1633 break;
1634 case osg::DisplaySettings::SWAP_DEFAULT:
1635 // Wojtek Lewandowski 2010-09-28:
1636 // Keep backward compatibility if no method is selected via traits
1637 // and let wglSwapExchangeARB flag select swap method.
1638 // However, I would rather remove this flag because its
1639 // now redundant to Traits::swapMethod and it looks like
1640 // WGL_SWAP_EXCHANGE_ARB is the GL default when no WGL_SWAP attrib is given.
1641 // To be precise: At least on Windows 7 and Nvidia it seems to be a default.
1642 if ( allowSwapExchangeARB )
1643 attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
1644 break;
1645 }
1646 }
1647
1648 if (traits.alpha) attributes.set(WGL_ALPHA_BITS_ARB, traits.alpha);
1649 if (traits.stencil) attributes.set(WGL_STENCIL_BITS_ARB, traits.stencil);
1650 if (traits.sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, traits.sampleBuffers);
1651 if (traits.samples) attributes.set(WGL_SAMPLES_ARB, traits.samples);
1652
1653 if (traits.quadBufferStereo) attributes.enable(WGL_STEREO_ARB);
1654
1655 attributes.end();
1656 }
1657
ChooseMatchingPixelFormat(HDC hdc,int screenNum,const WGLIntegerAttributes & formatSpecifications,osg::GraphicsContext::Traits * _traits)1658 static int ChooseMatchingPixelFormat( HDC hdc, int screenNum, const WGLIntegerAttributes& formatSpecifications ,osg::GraphicsContext::Traits* _traits)
1659 {
1660 //
1661 // Access the entry point for the wglChoosePixelFormatARB function
1662 //
1663
1664 WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
1665 if (wglChoosePixelFormatARB==0)
1666 {
1667 // = openGLContext.getTraits()
1668 reportErrorForScreen("ChooseMatchingPixelFormat() - wglChoosePixelFormatARB extension not found, trying GDI", screenNum, ::GetLastError());
1669 PIXELFORMATDESCRIPTOR pixelFormat = {
1670 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1671 1, // version number
1672 PFD_DRAW_TO_WINDOW | // support window
1673 PFD_SUPPORT_OPENGL | // support OpenGL
1674 (_traits->doubleBuffer ? PFD_DOUBLEBUFFER : NULL) | // double buffered ?
1675 (_traits->swapMethod == osg::DisplaySettings::SWAP_COPY ? PFD_SWAP_COPY : NULL) |
1676 (_traits->swapMethod == osg::DisplaySettings::SWAP_EXCHANGE ? PFD_SWAP_EXCHANGE : NULL),
1677 PFD_TYPE_RGBA, // RGBA type
1678 _traits->red + _traits->green + _traits->blue, // color depth
1679 _traits->red ,0, _traits->green ,0, _traits->blue, 0, // shift bits ignored
1680 _traits->alpha, // alpha buffer ?
1681 0, // shift bit ignored
1682 0, // no accumulation buffer
1683 0, 0, 0, 0, // accum bits ignored
1684 _traits->depth, // 32 or 16 bit z-buffer ?
1685 _traits->stencil, // stencil buffer ?
1686 0, // no auxiliary buffer
1687 PFD_MAIN_PLANE, // main layer
1688 0, // reserved
1689 0, 0, 0 // layer masks ignored
1690 };
1691 int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
1692 if (pixelFormatIndex == 0)
1693 {
1694 reportErrorForScreen("ChooseMatchingPixelFormat() - GDI ChoosePixelFormat Failed.", screenNum, ::GetLastError());
1695 return -1;
1696 }
1697
1698 ::DescribePixelFormat(hdc, pixelFormatIndex ,sizeof(PIXELFORMATDESCRIPTOR),&pixelFormat);
1699 if (((pixelFormat.dwFlags & PFD_GENERIC_FORMAT) != 0) && ((pixelFormat.dwFlags & PFD_GENERIC_ACCELERATED) == 0))
1700 {
1701 OSG_WARN << "Rendering in software: pixelFormatIndex " << pixelFormatIndex << std::endl;
1702 }
1703 return pixelFormatIndex;
1704 }
1705
1706 int pixelFormatIndex = 0;
1707 unsigned int numMatchingPixelFormats = 0;
1708
1709 if (!wglChoosePixelFormatARB(hdc,
1710 formatSpecifications.get(),
1711 NULL,
1712 1,
1713 &pixelFormatIndex,
1714 &numMatchingPixelFormats))
1715 {
1716 reportErrorForScreen("ChooseMatchingPixelFormat() - Unable to choose the requested pixel format", screenNum, ::GetLastError());
1717 return -1;
1718 }
1719
1720 return numMatchingPixelFormats==0 ? -1 : pixelFormatIndex;
1721 }
1722
setPixelFormat()1723 bool GraphicsWindowWin32::setPixelFormat()
1724 {
1725 Win32WindowingSystem::OpenGLContext openGLContext;
1726 if (!Win32WindowingSystem::getInterface()->getSampleOpenGLContext(openGLContext, _hdc, _screenOriginX, _screenOriginY)) return false;
1727
1728 //
1729 // Build the specifications of the requested pixel format
1730 //
1731
1732 WGLIntegerAttributes formatSpecs;
1733 ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);
1734
1735 //
1736 // Choose the closest matching pixel format from the specified traits
1737 //
1738
1739 int pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1740
1741 if (pixelFormatIndex<0)
1742 {
1743 unsigned int bpp;
1744 Win32WindowingSystem::getInterface()->getScreenColorDepth(*_traits.get(), bpp);
1745 if (bpp < 32) {
1746 OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Display setting is not 32 bit colors, "
1747 << bpp
1748 << " bits per pixel on screen #"
1749 << _traits->screenNum
1750 << std::endl;
1751
1752 _traits->red = bpp / 4; //integer divide, determine minimum number of bits we will accept
1753 _traits->green = bpp / 4;
1754 _traits->blue = bpp / 4;
1755 ::PreparePixelFormatSpecifications(*_traits, formatSpecs, true);// try again with WGL_SWAP_METHOD_ARB
1756 pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1757 }
1758 }
1759 if (pixelFormatIndex<0)
1760 {
1761 ::PreparePixelFormatSpecifications(*_traits, formatSpecs, false);
1762 pixelFormatIndex = ::ChooseMatchingPixelFormat(openGLContext.deviceContext(), _traits->screenNum, formatSpecs,_traits.get());
1763 if (pixelFormatIndex<0)
1764 {
1765 reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", _traits->screenNum, 0);
1766 return false;
1767 }
1768
1769 OSG_INFO << "GraphicsWindowWin32::setPixelFormat() - Found a matching pixel format but without the WGL_SWAP_METHOD_ARB specification for screen #"
1770 << _traits->screenNum
1771 << std::endl;
1772 }
1773
1774 //
1775 // Set the pixel format found
1776 //
1777
1778 PIXELFORMATDESCRIPTOR pfd;
1779 ::memset(&pfd, 0, sizeof(pfd));
1780 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
1781 pfd.nVersion = 1;
1782
1783 if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
1784 {
1785 reportErrorForScreen("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", _traits->screenNum, ::GetLastError());
1786 return false;
1787 }
1788
1789 return true;
1790 }
1791
createContextImplementation()1792 HGLRC GraphicsWindowWin32::createContextImplementation()
1793 {
1794 HGLRC context( NULL );
1795
1796 if( OSG_GL3_FEATURES )
1797 {
1798 OSG_NOTIFY( osg::INFO ) << "GL3: Attempting to create OpenGL3 context." << std::endl;
1799 OSG_NOTIFY( osg::INFO ) << "GL3: version: " << _traits->glContextVersion << std::endl;
1800 OSG_NOTIFY( osg::INFO ) << "GL3: context flags: " << _traits->glContextFlags << std::endl;
1801 OSG_NOTIFY( osg::INFO ) << "GL3: profile: " << _traits->glContextProfileMask << std::endl;
1802
1803 Win32WindowingSystem::OpenGLContext openGLContext;
1804 if( !Win32WindowingSystem::getInterface()->getSampleOpenGLContext( openGLContext, _hdc, _screenOriginX, _screenOriginY ) )
1805 {
1806 reportErrorForScreen( "GL3: Can't create sample context.",
1807 _traits->screenNum, ::GetLastError() );
1808 }
1809 else
1810 {
1811 PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB =
1812 ( PFNWGLCREATECONTEXTATTRIBSARBPROC ) wglGetProcAddress( "wglCreateContextAttribsARB" );
1813 if( wglCreateContextAttribsARB==0 )
1814 {
1815 reportErrorForScreen( "GL3: wglCreateContextAttribsARB not available.",
1816 _traits->screenNum, ::GetLastError() );
1817 }
1818 else
1819 {
1820 unsigned int idx( 0 );
1821 int attribs[ 16 ];
1822
1823 unsigned int major = 1, minor = 0;
1824 if( !_traits->getContextVersion(major, minor) || major<3 )
1825 {
1826 OSG_NOTIFY( osg::WARN ) << "GL3: Non-GL3 version number: " << _traits->glContextVersion << std::endl;
1827 }
1828
1829 attribs[ idx++ ] = WGL_CONTEXT_MAJOR_VERSION_ARB;
1830 attribs[ idx++ ] = major;
1831 attribs[ idx++ ] = WGL_CONTEXT_MINOR_VERSION_ARB;
1832 attribs[ idx++ ] = minor;
1833 if( _traits->glContextFlags != 0 )
1834 {
1835 attribs[ idx++ ] = WGL_CONTEXT_FLAGS_ARB;
1836 attribs[ idx++ ] = _traits->glContextFlags;
1837 }
1838 if( _traits->glContextProfileMask != 0 )
1839 {
1840 attribs[ idx++ ] = WGL_CONTEXT_PROFILE_MASK_ARB;
1841 attribs[ idx++ ] = _traits->glContextProfileMask;
1842 }
1843 attribs[ idx++ ] = 0;
1844
1845 context = wglCreateContextAttribsARB( _hdc, 0, attribs );
1846 if( context == NULL )
1847 {
1848 reportErrorForScreen( "GL3: wglCreateContextAttribsARB returned NULL.",
1849 _traits->screenNum, ::GetLastError() );
1850 }
1851 else
1852 {
1853 OSG_NOTIFY( osg::INFO ) << "GL3: context created successfully." << std::endl;
1854 }
1855 }
1856 }
1857 }
1858
1859 // TBD insert GL ES 2 suppurt, if required for Win32.
1860
1861 // If platform context creation fails for any reason,
1862 // we'll create a standard context. This means you could
1863 // build OSG for GL3, have the context creation fail
1864 // (because you have the wrong driver), and end up with
1865 // a GL3 context. Something else will likely fail down
1866 // the line, as the GL3-built OSG will assume GL3 features
1867 // are present.
1868 //
1869 // This is also the typical path for GL 1/2 context creation.
1870 if( context == NULL )
1871 context = ::wglCreateContext(_hdc);
1872
1873 return( context );
1874 }
1875
setWindowDecorationImplementation(bool decorated)1876 bool GraphicsWindowWin32::setWindowDecorationImplementation( bool decorated )
1877 {
1878 unsigned int windowStyle;
1879 unsigned int extendedStyle;
1880
1881 //
1882 // Determine position and size of window with/without decorations to retain the size specified in traits
1883 //
1884
1885 int x, y;
1886 unsigned int w, h;
1887
1888 if (!determineWindowPositionAndStyle(_traits->screenNum,
1889 _traits->x,
1890 _traits->y,
1891 _traits->width,
1892 _traits->height,
1893 decorated,
1894 x,
1895 y,
1896 w,
1897 h,
1898 windowStyle,
1899 extendedStyle))
1900 {
1901 reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style", _traits->screenNum, 0);
1902 return false;
1903 }
1904
1905 //
1906 // Change the window style
1907 //
1908
1909 ::SetLastError(0);
1910 unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
1911 unsigned int error = ::GetLastError();
1912 if (result==0 && error)
1913 {
1914 reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", _traits->screenNum, error);
1915 return false;
1916 }
1917
1918 //
1919 // Change the window extended style
1920 //
1921
1922 ::SetLastError(0);
1923 result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
1924 error = ::GetLastError();
1925 if (result==0 && error)
1926 {
1927 reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", _traits->screenNum, error);
1928 return false;
1929 }
1930
1931 //
1932 // Change the window position and size and realize the style changes
1933 //
1934
1935 if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
1936 {
1937 reportErrorForScreen("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
1938 return false;
1939 }
1940
1941 //
1942 // Force a repaint of the desktop
1943 //
1944
1945 ::InvalidateRect(NULL, NULL, TRUE);
1946
1947 return true;
1948 }
1949
realizeImplementation()1950 bool GraphicsWindowWin32::realizeImplementation()
1951 {
1952 if (_realized) return true;
1953
1954 if (!_initialized)
1955 {
1956 init();
1957 if (!_initialized) return false;
1958 }
1959
1960 if (_traits.valid() && (_traits->sharedContext.valid() || _traits->vsync || _traits->swapGroupEnabled))
1961 {
1962 // make context current so we can test capabilities and set up context sharing
1963 struct RestoreContext
1964 {
1965 RestoreContext()
1966 {
1967 _hdc = wglGetCurrentDC();
1968 _hglrc = wglGetCurrentContext();
1969 }
1970 ~RestoreContext()
1971 {
1972 wglMakeCurrent(_hdc,_hglrc);
1973 }
1974 protected:
1975 HDC _hdc;
1976 HGLRC _hglrc;
1977 } restoreContext;
1978
1979 _realized = true;
1980 bool result = makeCurrent();
1981 _realized = false;
1982
1983 if (!result)
1984 {
1985 return false;
1986 }
1987
1988 // set up sharing of contexts if required
1989 GraphicsHandleWin32* graphicsHandleWin32 = dynamic_cast<GraphicsHandleWin32*>(_traits->sharedContext.get());
1990 if (graphicsHandleWin32)
1991 {
1992 if (!wglShareLists(graphicsHandleWin32->getWGLContext(), getWGLContext()))
1993 {
1994 reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to share OpenGL context", _traits->screenNum, ::GetLastError());
1995 return false;
1996 }
1997 }
1998
1999 // if vysnc should be on then enable it.
2000 if (_traits->vsync)
2001 {
2002 setSyncToVBlank(_traits->vsync);
2003 }
2004
2005 // If the swap group is active then enable it.
2006 if (_traits->swapGroupEnabled)
2007 {
2008 setSwapGroup(_traits->swapGroupEnabled, _traits->swapGroup, _traits->swapBarrier);
2009 }
2010 }
2011
2012 if (_ownsWindow)
2013 {
2014 //
2015 // Bring the window on top of other ones (including the taskbar if it covers it completely)
2016 //
2017 // NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
2018 // Z-order must be used in the code below instead of HWND_TOP.
2019 // @todo: This should be controlled through a flag in the traits (topMostWindow)
2020 //
2021
2022 if (!::SetWindowPos(_hwnd,
2023 HWND_TOP,
2024 _windowOriginXToRealize,
2025 _windowOriginYToRealize,
2026 _windowWidthToRealize,
2027 _windowHeightToRealize,
2028 SWP_SHOWWINDOW))
2029 {
2030 reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to show window", _traits->screenNum, ::GetLastError());
2031 return false;
2032 }
2033
2034 if (!::UpdateWindow(_hwnd))
2035 {
2036 reportErrorForScreen("GraphicsWindowWin32::realizeImplementation() - Unable to update window", _traits->screenNum, ::GetLastError());
2037 return false;
2038 }
2039 }
2040
2041 _realized = true;
2042
2043 // make sure the event queue has the correct window rectangle size and input range
2044 getEventQueue()->syncWindowRectangleWithGraphicsContext();
2045
2046 return true;
2047 }
2048
makeCurrentImplementation()2049 bool GraphicsWindowWin32::makeCurrentImplementation()
2050 {
2051 if (!_realized)
2052 {
2053 reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.", _traits->screenNum, 0);
2054 return false;
2055 }
2056
2057 if( _applyWorkaroundForMultimonitorMultithreadNVidiaWin32Issues )
2058 {
2059 if( ::wglGetCurrentDC() != _hdc ||
2060 ::wglGetCurrentContext() != _hglrc )
2061 {
2062 if (!::wglMakeCurrent(_hdc, _hglrc))
2063 {
2064 reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2065 return false;
2066 }
2067 }
2068 }
2069
2070 if (!::wglMakeCurrent(_hdc, _hglrc))
2071 {
2072 reportErrorForScreen("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2073 return false;
2074 }
2075
2076 return true;
2077 }
2078
releaseContextImplementation()2079 bool GraphicsWindowWin32::releaseContextImplementation()
2080 {
2081 if (!::wglMakeCurrent(_hdc, NULL))
2082 {
2083 reportErrorForScreen("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", _traits->screenNum, ::GetLastError());
2084 return false;
2085 }
2086
2087 return true;
2088 }
2089
closeImplementation()2090 void GraphicsWindowWin32::closeImplementation()
2091 {
2092 destroyWindow();
2093
2094 _initialized = false;
2095 _valid = false;
2096 _realized = false;
2097 }
2098
swapBuffersImplementation()2099 void GraphicsWindowWin32::swapBuffersImplementation()
2100 {
2101 if (!_realized) return;
2102 if (!::SwapBuffers(_hdc) && ::GetLastError() != 0)
2103 {
2104 reportErrorForScreen("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", _traits->screenNum, ::GetLastError());
2105 }
2106 }
2107
checkEvents()2108 bool GraphicsWindowWin32::checkEvents()
2109 {
2110 if (!_realized) return false;
2111
2112 MSG msg;
2113 while (::PeekMessage(&msg, _hwnd, 0, 0, PM_REMOVE))
2114 {
2115 ::TranslateMessage(&msg);
2116 ::DispatchMessage(&msg);
2117 }
2118
2119 if (_closeWindow)
2120 {
2121 _closeWindow = false;
2122 close();
2123 }
2124
2125 if (_destroyWindow)
2126 {
2127 _destroyWindow = false;
2128 destroyWindow(false);
2129 }
2130
2131 return !(getEventQueue()->empty());
2132 }
2133
grabFocus()2134 void GraphicsWindowWin32::grabFocus()
2135 {
2136 if (!::SetForegroundWindow(_hwnd))
2137 {
2138 OSG_WARN << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
2139 }
2140 }
2141
grabFocusIfPointerInWindow()2142 void GraphicsWindowWin32::grabFocusIfPointerInWindow()
2143 {
2144 POINT mousePos;
2145 if (!::GetCursorPos(&mousePos))
2146 {
2147 reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", _traits->screenNum, ::GetLastError());
2148 return;
2149 }
2150
2151 RECT windowRect;
2152 if (!::GetWindowRect(_hwnd, &windowRect))
2153 {
2154 reportErrorForScreen("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", _traits->screenNum, ::GetLastError());
2155 return;
2156 }
2157
2158 if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
2159 mousePos.y>=windowRect.top && mousePos.y<=windowRect.bottom)
2160 {
2161 grabFocus();
2162 }
2163 }
2164
requestWarpPointer(float x,float y)2165 void GraphicsWindowWin32::requestWarpPointer( float x, float y )
2166 {
2167 if (!_realized)
2168 {
2169 OSG_INFO<<"GraphicsWindowWin32::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
2170 return;
2171 }
2172
2173 #if 0
2174 RECT windowRect;
2175 if (!::GetWindowRect(_hwnd, &windowRect))
2176 {
2177 reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to get window rectangle", _traits->screenNum, ::GetLastError());
2178 return;
2179 }
2180
2181 if (!::SetCursorPos(windowRect.left + x, windowRect.top + y))
2182 {
2183 reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2184 return;
2185 }
2186 #else
2187 // MIKEC: NEW CODE
2188 POINT pt;
2189 pt.x = (LONG)x;
2190 pt.y = (LONG)y;
2191
2192 // convert point in client area coordinates to screen coordinates
2193 if (!::ClientToScreen(_hwnd, &pt))
2194 {
2195 reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to convert cursor position to screen coordinates", _traits->screenNum, ::GetLastError());
2196 }
2197 if (!::SetCursorPos(pt.x, pt.y))
2198 {
2199 reportErrorForScreen("GraphicsWindowWin32::requestWarpPointer() - Unable to set cursor position", _traits->screenNum, ::GetLastError());
2200 return;
2201 }
2202 #endif
2203
2204 getEventQueue()->mouseWarped(x,y);
2205 }
2206
setWindowRectangleImplementation(int x,int y,int width,int height)2207 bool GraphicsWindowWin32::setWindowRectangleImplementation(int x, int y, int width, int height)
2208 {
2209 unsigned int windowStyle;
2210 unsigned int extendedStyle;
2211
2212 //
2213 // Determine position and size of window with/without decorations to retain the size specified in traits
2214 //
2215
2216 int wx, wy;
2217 unsigned int ww, wh;
2218
2219 if (!determineWindowPositionAndStyle(_traits->screenNum,
2220 x,
2221 y,
2222 width,
2223 height,
2224 _traits->windowDecoration,
2225 wx,
2226 wy,
2227 ww,
2228 wh,
2229 windowStyle,
2230 extendedStyle))
2231 {
2232 reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to determine the window position and style", _traits->screenNum, 0);
2233 return false;
2234 }
2235
2236 if (!::SetWindowPos(_hwnd, HWND_TOP, wx, wy, ww, wh, SWP_SHOWWINDOW | SWP_FRAMECHANGED))
2237 {
2238 reportErrorForScreen("GraphicsWindowWin32::setWindowRectangleImplementation() - Unable to set new window position and size", _traits->screenNum, ::GetLastError());
2239 return false;
2240 }
2241 return true;
2242 }
2243
setWindowName(const std::string & name)2244 void GraphicsWindowWin32::setWindowName( const std::string & name )
2245 {
2246 _traits->windowName = name;
2247 SetWindowText(_hwnd, name.c_str());
2248 }
2249
useCursor(bool cursorOn)2250 void GraphicsWindowWin32::useCursor( bool cursorOn )
2251 {
2252 if (_traits.valid())
2253 _traits->useCursor = cursorOn;
2254
2255 // note, we are using setCursorImpl to set the cursor, so we can use
2256 // _appMouseCursor to cache the current mouse-cursor
2257 setCursorImpl(cursorOn ? _appMouseCursor : NoCursor);
2258 }
2259
setCursor(MouseCursor mouseCursor)2260 void GraphicsWindowWin32::setCursor( MouseCursor mouseCursor )
2261 {
2262 _appMouseCursor = mouseCursor;
2263 setCursorImpl(mouseCursor);
2264 }
2265
setCursorImpl(MouseCursor mouseCursor)2266 void GraphicsWindowWin32::setCursorImpl( MouseCursor mouseCursor )
2267 {
2268 if (_mouseCursor != mouseCursor)
2269 {
2270 _mouseCursor = mouseCursor;
2271 HCURSOR newCursor = getOrCreateCursor( mouseCursor);
2272 if (newCursor == _currentCursor) return;
2273
2274 _currentCursor = newCursor;
2275 _traits->useCursor = (_currentCursor != NULL) && (_mouseCursor != NoCursor);
2276
2277 PostMessage(_hwnd, WM_SETCURSOR, 0, 0);
2278 }
2279 }
2280
getOrCreateCursor(MouseCursor mouseCursor)2281 HCURSOR GraphicsWindowWin32::getOrCreateCursor(MouseCursor mouseCursor)
2282 {
2283 std::map<MouseCursor,HCURSOR>::iterator i = _mouseCursorMap.find(mouseCursor);
2284 if (i != _mouseCursorMap.end()) return i->second;
2285
2286 switch (mouseCursor) {
2287 case NoCursor:
2288 _mouseCursorMap[mouseCursor] = NULL;
2289 break;
2290 case RightArrowCursor:
2291 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2292 break;
2293 case LeftArrowCursor:
2294 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_ARROW);
2295 break;
2296 case InfoCursor:
2297 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL);
2298 break;
2299 case DestroyCursor:
2300 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2301 break;
2302 case HelpCursor:
2303 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HELP );
2304 break;
2305 case CycleCursor:
2306 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_NO );
2307 break;
2308 case SprayCursor:
2309 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEALL );
2310 break;
2311 case WaitCursor:
2312 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_WAIT);
2313 break;
2314 case TextCursor:
2315 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_IBEAM );
2316 break;
2317 case CrosshairCursor:
2318 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_CROSS );
2319 break;
2320 case UpDownCursor:
2321 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENS );
2322 break;
2323 case LeftRightCursor:
2324 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2325 break;
2326 case TopSideCursor:
2327 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2328 break;
2329 case BottomSideCursor:
2330 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_UPARROW );
2331 break;
2332 case LeftSideCursor:
2333 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE);
2334 break;
2335 case RightSideCursor:
2336 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZEWE );
2337 break;
2338 case TopLeftCorner:
2339 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2340 break;
2341 case TopRightCorner:
2342 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2343 break;
2344 case BottomRightCorner:
2345 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENWSE );
2346 break;
2347 case BottomLeftCorner:
2348 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_SIZENESW );
2349 break;
2350 case HandCursor:
2351 _mouseCursorMap[mouseCursor] = LoadCursor( NULL, IDC_HAND );
2352 break;
2353 default:
2354 break;
2355 }
2356
2357 return _mouseCursorMap[mouseCursor];
2358 }
2359
setSwapGroup(bool on,GLuint group,GLuint barrier)2360 void GraphicsWindowWin32::setSwapGroup(bool on, GLuint group, GLuint barrier)
2361 {
2362 if (_traits.valid())
2363 {
2364 _traits->swapGroupEnabled = on;
2365 _traits->swapGroup = group;
2366 _traits->swapBarrier = barrier;
2367 }
2368
2369 typedef BOOL (GL_APIENTRY *PFNWGLJOINSWAPGROUPNVPROC) (HDC hDC, GLuint group);
2370 PFNWGLJOINSWAPGROUPNVPROC wglJoinSwapGroupNV = (PFNWGLJOINSWAPGROUPNVPROC)wglGetProcAddress( "wglJoinSwapGroupNV" );
2371
2372 typedef BOOL (GL_APIENTRY *PFNWGLBINDSWAPBARRIERNVPROC) (GLuint group, GLuint barrier);
2373 PFNWGLBINDSWAPBARRIERNVPROC wglBindSwapBarrierNV = (PFNWGLBINDSWAPBARRIERNVPROC)wglGetProcAddress( "wglBindSwapBarrierNV" );
2374
2375 if ((!wglJoinSwapGroupNV) || (!wglBindSwapBarrierNV))
2376 {
2377 OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV(bool, GLuint, GLuint) not supported" << std::endl;
2378 return;
2379 }
2380
2381 int swapGroup = (on ? group : 0);
2382 BOOL resultJoin = wglJoinSwapGroupNV(_hdc, swapGroup);
2383 OSG_INFO << "GraphicsWindowWin32::wglJoinSwapGroupNV (" << swapGroup << ") returned " << resultJoin << std::endl;
2384
2385 int swapBarrier = (on ? barrier : 0);
2386 BOOL resultBind = wglBindSwapBarrierNV(swapGroup, swapBarrier);
2387 OSG_INFO << "GraphicsWindowWin32::wglBindSwapBarrierNV (" << swapGroup << ", " << swapBarrier << ") returned " << resultBind << std::endl;
2388 }
2389
setSyncToVBlank(bool on)2390 void GraphicsWindowWin32::setSyncToVBlank( bool on )
2391 {
2392 if (_traits.valid())
2393 {
2394 _traits->vsync = on;
2395 }
2396
2397 //#if 0
2398 // we ought to properly check if the extension is listed as supported rather than just
2399 // if the function pointer resolves through wglGetProcAddress, but in practice everything
2400 // supports this extension
2401 typedef BOOL (GL_APIENTRY *PFNWGLSWAPINTERVALFARPROC)( int );
2402 PFNWGLSWAPINTERVALFARPROC wglSwapIntervalEXT = 0;
2403
2404 wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
2405 if( wglSwapIntervalEXT )
2406 {
2407 int swapInterval = (on ? 1 : 0);
2408 wglSwapIntervalEXT(swapInterval);
2409 OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank " << (on ? "on" : "off") << std::endl;
2410 }
2411 else
2412 {
2413 OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not supported" << std::endl;
2414 }
2415 //#else
2416 // OSG_INFO << "GraphicsWindowWin32::setSyncToVBlank(bool) not yet implemented."<< std::endl;
2417 //#endif
2418 }
2419
adaptKey(WPARAM wParam,LPARAM lParam,int & keySymbol,unsigned int & modifierMask,int & unmodifiedKeySymbol)2420 void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask, int& unmodifiedKeySymbol)
2421 {
2422 modifierMask = 0;
2423
2424 bool rightSide = (lParam & 0x01000000)!=0;
2425 int virtualKey = ::MapVirtualKeyEx((lParam>>16) & 0xff, 3, ::GetKeyboardLayout(0));
2426
2427 BYTE keyState[256];
2428
2429 if (virtualKey==0 || !::GetKeyboardState(keyState))
2430 {
2431 keySymbol = 0;
2432 return;
2433 }
2434
2435 switch (virtualKey)
2436 {
2437 //////////////////
2438 case VK_LSHIFT :
2439 //////////////////
2440
2441 modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
2442 break;
2443
2444 //////////////////
2445 case VK_RSHIFT :
2446 //////////////////
2447
2448 modifierMask |= osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT;
2449 break;
2450
2451 //////////////////
2452 case VK_CONTROL :
2453 case VK_LCONTROL :
2454 //////////////////
2455
2456 virtualKey = rightSide ? VK_RCONTROL : VK_LCONTROL;
2457 modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
2458 break;
2459
2460 //////////////////
2461 case VK_MENU :
2462 case VK_LMENU :
2463 //////////////////
2464
2465 virtualKey = rightSide ? VK_RMENU : VK_LMENU;
2466 modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
2467 break;
2468
2469 //////////////////
2470 default :
2471 //////////////////
2472
2473 virtualKey = wParam;
2474 break;
2475 }
2476
2477 if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
2478 if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
2479
2480 keySymbol = remapWin32Key(virtualKey);
2481
2482 if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
2483 {
2484 keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
2485 }
2486
2487 unmodifiedKeySymbol = keySymbol;
2488
2489 if ((keySymbol & 0xff00)==0)
2490 {
2491 char asciiKey[2];
2492 int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
2493 if (numChars>0) keySymbol = asciiKey[0];
2494 }
2495 }
2496
transformMouseXY(float & x,float & y)2497 void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
2498 {
2499 if (getEventQueue()->getUseFixedMouseInputRange())
2500 {
2501 osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
2502
2503 x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
2504 y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
2505 }
2506 }
2507
handleNativeWindowingEvent(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)2508 LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
2509 {
2510 if ((GetMessageExtraInfo() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) return TRUE;
2511
2512 //!@todo adapt windows event time to osgGA event queue time for better resolution
2513 double eventTime = getEventQueue()->getTime();
2514 _timeOfLastCheckEvents = eventTime;
2515
2516 switch(uMsg)
2517 {
2518 // Wojtek Lewandowski 2010-09-28:
2519 // All web docs on Windows Aero and OpenGL compatibiltiy
2520 // suggest WM_ERASEBKGND should be handled with non NULL value return.
2521 // This sugesstion may be irrelevant for our window class
2522 // as default brush pattern is not set so erase flag is forwarded to WM_PAINT
2523 // and gets ignored when WM_PAINT is handled.
2524 // But it will certainly be safer and not make things worse
2525 // if we handle this message to be sure everything is done as suggested.
2526 case WM_ERASEBKGND :
2527 return TRUE;
2528 break;
2529
2530 /////////////////
2531 case WM_PAINT :
2532 /////////////////
2533
2534 if (_ownsWindow)
2535 {
2536 PAINTSTRUCT paint;
2537 ::BeginPaint(hwnd, &paint);
2538 ::EndPaint(hwnd, &paint);
2539 requestRedraw();
2540 }
2541 break;
2542
2543 ///////////////////
2544 case WM_MOUSEMOVE :
2545 ///////////////////
2546
2547 {
2548 float mx = GET_X_LPARAM(lParam);
2549 float my = GET_Y_LPARAM(lParam);
2550 transformMouseXY(mx, my);
2551 getEventQueue()->mouseMotion(mx, my, eventTime);
2552 }
2553 break;
2554
2555 /////////////////////
2556 case WM_LBUTTONDOWN :
2557 case WM_MBUTTONDOWN :
2558 case WM_RBUTTONDOWN :
2559 /////////////////////
2560
2561 {
2562 ::SetCapture(hwnd);
2563
2564 int button;
2565
2566 if (uMsg==WM_LBUTTONDOWN) button = 1;
2567 else if (uMsg==WM_MBUTTONDOWN) button = 2;
2568 else button = 3;
2569
2570 _capturedMouseButtons.insert(button);
2571
2572 float mx = GET_X_LPARAM(lParam);
2573 float my = GET_Y_LPARAM(lParam);
2574 transformMouseXY(mx, my);
2575 getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
2576 }
2577 break;
2578
2579 /////////////////////
2580 case WM_LBUTTONUP :
2581 case WM_MBUTTONUP :
2582 case WM_RBUTTONUP :
2583 /////////////////////
2584
2585 {
2586 int button;
2587
2588 if (uMsg==WM_LBUTTONUP) button = 1;
2589 else if (uMsg==WM_MBUTTONUP) button = 2;
2590 else button = 3;
2591
2592 _capturedMouseButtons.erase(button);
2593
2594 if(_capturedMouseButtons.empty())
2595 ::ReleaseCapture();
2596
2597 float mx = GET_X_LPARAM(lParam);
2598 float my = GET_Y_LPARAM(lParam);
2599 transformMouseXY(mx, my);
2600 getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
2601 }
2602 break;
2603
2604 ///////////////////////
2605 case WM_LBUTTONDBLCLK :
2606 case WM_MBUTTONDBLCLK :
2607 case WM_RBUTTONDBLCLK :
2608 ///////////////////////
2609
2610 {
2611 ::SetCapture(hwnd);
2612
2613 int button;
2614
2615 if (uMsg==WM_LBUTTONDBLCLK) button = 1;
2616 else if (uMsg==WM_MBUTTONDBLCLK) button = 2;
2617 else button = 3;
2618
2619 _capturedMouseButtons.insert(button);
2620
2621 float mx = GET_X_LPARAM(lParam);
2622 float my = GET_Y_LPARAM(lParam);
2623 transformMouseXY(mx, my);
2624 getEventQueue()->mouseDoubleButtonPress(mx, my, button, eventTime);
2625 }
2626 break;
2627
2628 ////////////////////
2629 case WM_MOUSEWHEEL :
2630 ////////////////////
2631
2632 getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
2633 osgGA::GUIEventAdapter::SCROLL_UP,
2634 eventTime);
2635 break;
2636
2637 /////////////////
2638 case WM_MOVE :
2639 case WM_SIZE :
2640 /////////////////
2641
2642 {
2643 int windowX=_traits->x, windowY=_traits->y, windowWidth=_traits->width, windowHeight=_traits->height;
2644 if (areWindowDimensionsChanged(hwnd, _screenOriginX, _screenOriginY, windowX, windowY, windowWidth, windowHeight))
2645 {
2646 resized(windowX, windowY, windowWidth, windowHeight);
2647 getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, eventTime);
2648
2649 // request redraw if window size was changed
2650 if (windowWidth!=_traits->width || windowHeight!=_traits->height)
2651 requestRedraw();
2652 }
2653 }
2654 break;
2655
2656 ////////////////////
2657 case WM_KEYDOWN :
2658 case WM_SYSKEYDOWN :
2659 ////////////////////
2660
2661 {
2662 int keySymbol = 0;
2663 int unmodifiedKeySymbol = 0;
2664 unsigned int modifierMask = 0;
2665 adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2666 _keyMap[std::make_pair(keySymbol,unmodifiedKeySymbol)] = true;
2667 //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2668 getEventQueue()->keyPress(keySymbol, eventTime, unmodifiedKeySymbol);
2669 }
2670 break;
2671
2672 //////////////////
2673 case WM_KEYUP :
2674 case WM_SYSKEYUP :
2675 //////////////////
2676
2677 {
2678 int keySymbol = 0;
2679 int unmodifiedKeySymbol = 0;
2680 unsigned int modifierMask = 0;
2681 adaptKey(wParam, lParam, keySymbol, modifierMask, unmodifiedKeySymbol);
2682 _keyMap[std::make_pair(keySymbol, unmodifiedKeySymbol)] = false;
2683 //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
2684 getEventQueue()->keyRelease(keySymbol, eventTime, unmodifiedKeySymbol);
2685 }
2686 break;
2687
2688 ///////////////////
2689 case WM_SETCURSOR :
2690 ///////////////////
2691 //The cursor is only modified in response to the WM_SETCURSOR message if the mouse cursor isn't set to
2692 //InheritCursor. InheritCursor lets the user manage the cursor externally.
2693 if (_mouseCursor != InheritCursor)
2694 {
2695 if (_traits->useCursor)
2696 ::SetCursor( _currentCursor);
2697 else
2698 ::SetCursor(NULL);
2699 return TRUE;
2700 }
2701 break;
2702
2703 ///////////////////
2704 case WM_SETFOCUS :
2705 ///////////////////
2706 // Check keys and send a message if the key is pressed when the
2707 // focus comes back to the window.
2708 // I don't really like this hard-coded loop, but the key codes
2709 // (VK_* constants) seem to go from 0x08 to 0xFE so it should be
2710 // ok. See winuser.h for the key codes.
2711 for (unsigned int i = 0x08; i < 0xFF; i++)
2712 {
2713 // Wojciech Lewandowski: 2011/09/12
2714 // Skip CONTROL | MENU | SHIFT tests because we are polling exact left or right keys
2715 // above return press for both right and left so we may end up with incosistent
2716 // modifier mask if we report left control & right control while only right was pressed
2717 LONG rightSideCode = 0;
2718 switch( i )
2719 {
2720 case VK_CONTROL:
2721 case VK_SHIFT:
2722 case VK_MENU:
2723 continue;
2724
2725 case VK_RCONTROL:
2726 case VK_RSHIFT:
2727 case VK_RMENU:
2728 rightSideCode = 0x01000000;
2729 }
2730 if ((::GetAsyncKeyState(i) & 0x8000) != 0)
2731 {
2732 // Compute lParam because subsequent adaptKey will rely on correct lParam
2733 UINT scanCode = ::MapVirtualKeyEx( i, 0, ::GetKeyboardLayout(0));
2734 // Set Extended Key bit + Scan Code + 30 bit to indicate key was set before sending message
2735 // See Windows SDK help on WM_KEYDOWN for explanation
2736 LONG lParam = rightSideCode | ( ( scanCode & 0xFF ) << 16 ) | (1 << 30);
2737 ::SendMessage(hwnd, WM_KEYDOWN, i, lParam );
2738 }
2739 }
2740 break;
2741
2742 ///////////////////
2743 case WM_KILLFOCUS :
2744 ///////////////////
2745
2746 // Release all keys that were pressed when the window lost focus.
2747 for (std::map<std::pair<int, int>, bool>::iterator key = _keyMap.begin();
2748 key != _keyMap.end(); ++key)
2749 {
2750 if (key->second)
2751 {
2752 getEventQueue()->keyRelease(key->first.first, key->first.second);
2753 key->second = false;
2754 }
2755 }
2756
2757 _capturedMouseButtons.clear();
2758
2759 break;
2760
2761 ///////////////////
2762 case WM_NCHITTEST :
2763 ///////////////////
2764 {
2765 LONG_PTR result = _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2766 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2767
2768 switch(result)
2769 {
2770 case HTLEFT:
2771 case HTRIGHT:
2772 setCursorImpl(LeftRightCursor);
2773 break;
2774 case HTTOP:
2775 case HTBOTTOM:
2776 setCursorImpl(UpDownCursor);
2777 break;
2778 case HTTOPLEFT:
2779 setCursorImpl(TopLeftCorner);
2780 break;
2781 case HTTOPRIGHT:
2782 setCursorImpl(TopRightCorner);
2783 break;
2784 case HTBOTTOMLEFT:
2785 setCursorImpl(BottomLeftCorner);
2786 break;
2787 case HTBOTTOMRIGHT:
2788 case HTGROWBOX:
2789 setCursorImpl(BottomRightCorner);
2790 break;
2791 case HTSYSMENU:
2792 case HTCAPTION:
2793 case HTMAXBUTTON:
2794 case HTMINBUTTON:
2795 case HTCLOSE:
2796 case HTHELP:
2797 setCursorImpl(LeftArrowCursor);
2798 break;
2799
2800 default:
2801 if (_traits->useCursor && _appMouseCursor != InheritCursor)
2802 setCursorImpl(_appMouseCursor);
2803 break;
2804 }
2805 return result;
2806 }
2807 break;
2808
2809 /////////////////
2810 case WM_CLOSE :
2811 /////////////////
2812
2813 getEventQueue()->closeWindow(eventTime);
2814 break;
2815
2816 /////////////////
2817 case WM_DESTROY :
2818 /////////////////
2819
2820 _destroyWindow = true;
2821 if (_ownsWindow)
2822 {
2823 ::PostQuitMessage(0);
2824 }
2825 break;
2826
2827 //////////////
2828 case WM_QUIT :
2829 //////////////
2830
2831 _closeWindow = true;
2832 return wParam;
2833
2834 //////////////
2835 case WM_TOUCH:
2836 /////////////
2837 {
2838 unsigned int numInputs = (unsigned int) wParam;
2839 TOUCHINPUT* ti = new TOUCHINPUT[numInputs];
2840 osg::ref_ptr<osgGA::GUIEventAdapter> osg_event(NULL);
2841 if(getTouchInputInfoFunc && (*getTouchInputInfoFunc)((HTOUCHINPUT)lParam, numInputs, ti, sizeof(TOUCHINPUT)))
2842 {
2843 // For each contact, dispatch the message to the appropriate message handler.
2844 for(unsigned int i=0; i< numInputs; ++i)
2845 {
2846 if(ti[i].dwFlags & TOUCHEVENTF_DOWN)
2847 {
2848 if (!osg_event) {
2849 osg_event = getEventQueue()->touchBegan( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100 , ti[i].y/100);
2850 } else {
2851 osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_BEGAN, ti[i].x / 100, ti[i].y/100);
2852 }
2853 }
2854 else if(ti[i].dwFlags & TOUCHEVENTF_MOVE)
2855 {
2856 if (!osg_event) {
2857 osg_event = getEventQueue()->touchMoved( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x/ 100, ti[i].y/ 100);
2858 } else {
2859 osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_MOVED, ti[i].x / 100, ti[i].y/100);
2860 }
2861 }
2862 else if(ti[i].dwFlags & TOUCHEVENTF_UP)
2863 {
2864 // No double tap detection with RAW TOUCH Events, sorry.
2865 if (!osg_event) {
2866 osg_event = getEventQueue()->touchEnded( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x/ 100, ti[i].y/ 100, 1);
2867 } else {
2868 osg_event->addTouchPoint( ti[i].dwID, osgGA::GUIEventAdapter::TOUCH_ENDED, ti[i].x / 100, ti[i].y/100);
2869 }
2870 }
2871 }
2872 }
2873 if (closeTouchInputHandleFunc)
2874 (*closeTouchInputHandleFunc)((HTOUCHINPUT)lParam);
2875 delete [] ti;
2876 }
2877 break;
2878
2879 /////////////////
2880 default :
2881 /////////////////
2882
2883 if (_ownsWindow) return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
2884 break;
2885 }
2886
2887 if (_ownsWindow) return 0;
2888
2889 return _windowProcedure==0 ? ::DefWindowProc(hwnd, uMsg, wParam, lParam) :
2890 ::CallWindowProc(_windowProcedure, hwnd, uMsg, wParam, lParam);
2891 }
2892
2893
2894 //////////////////////////////////////////////////////////////////////////////
2895 // Class responsible for registering the Win32 Windowing System interface
2896 //////////////////////////////////////////////////////////////////////////////
2897
2898 struct RegisterWindowingSystemInterfaceProxy
2899 {
RegisterWindowingSystemInterfaceProxyosgViewer::RegisterWindowingSystemInterfaceProxy2900 RegisterWindowingSystemInterfaceProxy()
2901 {
2902 osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
2903 }
2904
~RegisterWindowingSystemInterfaceProxyosgViewer::RegisterWindowingSystemInterfaceProxy2905 ~RegisterWindowingSystemInterfaceProxy()
2906 {
2907 if (osg::Referenced::getDeleteHandler())
2908 {
2909 osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
2910 osg::Referenced::getDeleteHandler()->flushAll();
2911 }
2912
2913 osg::GraphicsContext::setWindowingSystemInterface(0);
2914 }
2915 };
2916
2917 static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
2918
2919 } // namespace OsgViewer
2920
2921
2922 // declare C entry point for static compilation.
graphicswindow_Win32(void)2923 extern "C" void OSGVIEWER_EXPORT graphicswindow_Win32(void)
2924 {
2925 osg::GraphicsContext::setWindowingSystemInterface(osgViewer::Win32WindowingSystem::getInterface());
2926 }
2927
2928
raiseWindow()2929 void GraphicsWindowWin32::raiseWindow()
2930 {
2931
2932 SetWindowPos(_hwnd, HWND_TOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2933 SetWindowPos(_hwnd, HWND_NOTOPMOST, _traits->x, _traits->y, _traits->width, _traits->height, SWP_NOMOVE|SWP_NOSIZE);
2934
2935 }
2936
2937