OpenSceneGraph/src/osgViewer/GraphicsWindowWin32.cpp

1687 lines
56 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* This file is Copyright (C) 2007 - André Garneau (andre@pixdev.com) and licensed under OSGPL.
*
* Note, some elements of GraphicsWindowWin32 have used the Producer implementation as a reference.
* These elements are licensed under OSGPL as above, with Copyright (C) 2001-2004 Don Burns.
*/
#include <osgViewer/GraphicsWindowWin32>
#include <vector>
#include <map>
#include <sstream>
#include <windowsx.h>
using namespace osgViewer;
namespace osgViewer
{
//
// Defines from the WGL_ARB_pixel_format specification document
// See http://www.opengl.org/registry/specs/ARB/wgl_pixel_format.txt
//
#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
#define WGL_DRAW_TO_WINDOW_ARB 0x2001
#define WGL_DRAW_TO_BITMAP_ARB 0x2002
#define WGL_ACCELERATION_ARB 0x2003
#define WGL_NEED_PALETTE_ARB 0x2004
#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
#define WGL_SWAP_METHOD_ARB 0x2007
#define WGL_NUMBER_OVERLAYS_ARB 0x2008
#define WGL_NUMBER_UNDERLAYS_ARB 0x2009
#define WGL_TRANSPARENT_ARB 0x200A
#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
#define WGL_SHARE_DEPTH_ARB 0x200C
#define WGL_SHARE_STENCIL_ARB 0x200D
#define WGL_SHARE_ACCUM_ARB 0x200E
#define WGL_SUPPORT_GDI_ARB 0x200F
#define WGL_SUPPORT_OPENGL_ARB 0x2010
#define WGL_DOUBLE_BUFFER_ARB 0x2011
#define WGL_STEREO_ARB 0x2012
#define WGL_PIXEL_TYPE_ARB 0x2013
#define WGL_COLOR_BITS_ARB 0x2014
#define WGL_RED_BITS_ARB 0x2015
#define WGL_RED_SHIFT_ARB 0x2016
#define WGL_GREEN_BITS_ARB 0x2017
#define WGL_GREEN_SHIFT_ARB 0x2018
#define WGL_BLUE_BITS_ARB 0x2019
#define WGL_BLUE_SHIFT_ARB 0x201A
#define WGL_ALPHA_BITS_ARB 0x201B
#define WGL_ALPHA_SHIFT_ARB 0x201C
#define WGL_ACCUM_BITS_ARB 0x201D
#define WGL_ACCUM_RED_BITS_ARB 0x201E
#define WGL_ACCUM_GREEN_BITS_ARB 0x201F
#define WGL_ACCUM_BLUE_BITS_ARB 0x2020
#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
#define WGL_DEPTH_BITS_ARB 0x2022
#define WGL_STENCIL_BITS_ARB 0x2023
#define WGL_AUX_BUFFERS_ARB 0x2024
#define WGL_NO_ACCELERATION_ARB 0x2025
#define WGL_GENERIC_ACCELERATION_ARB 0x2026
#define WGL_FULL_ACCELERATION_ARB 0x2027
#define WGL_SWAP_EXCHANGE_ARB 0x2028
#define WGL_SWAP_COPY_ARB 0x2029
#define WGL_SWAP_UNDEFINED_ARB 0x202A
#define WGL_TYPE_RGBA_ARB 0x202B
#define WGL_TYPE_COLORINDEX_ARB 0x202C
#define WGL_SAMPLE_BUFFERS_ARB 0x2041
#define WGL_SAMPLES_ARB 0x2042
//
// Entry points used from the WGL extensions
//
// BOOL wglChoosePixelFormatARB(HDC hdc,
// const int *piAttribIList,
// const FLOAT *pfAttribFList,
// UINT nMaxFormats,
// int *piFormats,
// UINT *nNumFormats);
//
typedef bool (WINAPI * WGLChoosePixelFormatARB) ( HDC, const int *, const float *, unsigned int, int *, unsigned int * );
//
// Utility class to specify the visual attributes for wglChoosePixelFormatARB() function
//
template <typename T> class WGLAttributes
{
public:
WGLAttributes() {}
~WGLAttributes() {}
void begin() { m_parameters.clear(); }
void set( const T& id, const T& value ) { add(id); add(value); }
void enable( const T& id ) { add(id); add(true); }
void disable( const T& id ) { add(id); add(false); }
void end() { add(0); }
const T* get() { return &m_parameters.front(); }
protected:
void add( const T& t ) { m_parameters.push_back(t); }
std::vector<T> m_parameters; // parameters added
private:
// No implementation for these
WGLAttributes( const WGLAttributes& );
WGLAttributes& operator=( const WGLAttributes& );
};
typedef WGLAttributes<int> WGLIntegerAttributes;
typedef WGLAttributes<float> WGLFloatAttributes;
//
// Class responsible for interfacing with the Win32 Window Manager
// The behavior of this class is specific to OSG needs and is not a
// generic Windowing interface.
//
// NOTE: This class is intended to be used by a single-thread.
// Multi-threading is not enabled for performance reasons.
// The creation/deletion of graphics windows should be done
// by a single controller thread. That thread should then
// call the checkEvents() method of all created windows periodically.
// This is the case with OSG as a "main" thread does all
// setup, update & event processing. Rendering is done (optionally) by other threads.
//
// !@todo Have a dedicated thread managed by the Win32WindowingSystem class handle the
// creation and event message processing for all windows it manages. This
// is to relieve the "main" thread from having to do this synchronously
// during frame generation. The "main" thread would only have to process
// each osgGA-type window event queue.
//
class Win32WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
{
public:
// A class representing an OpenGL rendering context
class OpenGLContext
{
public:
OpenGLContext() : _previous(0), _hdc(0), _hglrc(0), _restorePreviousOnExit(false)
{}
OpenGLContext( HDC hdc, HGLRC hglrc ) : _previous(0), _hdc(hdc), _hglrc(hglrc), _restorePreviousOnExit(false)
{}
OpenGLContext( const OpenGLContext& context )
: _previous(context._previous),
_hdc(context._hdc),
_hglrc(context._hglrc),
_restorePreviousOnExit(context._restorePreviousOnExit)
{}
~OpenGLContext();
HDC deviceContext() { return _hdc; }
bool makeCurrent( bool restorePreviousOnExit );
protected:
//
// Data members
//
HGLRC _previous; // previously current rendering context
HDC _hdc; // handle to device context
HGLRC _hglrc; // handle to OpenGL rendering context
bool _restorePreviousOnExit; // restore original context on exit
private:
// no implementation for assignment operator
OpenGLContext& operator=( const OpenGLContext& context );
};
static std::string osgGraphicsWindowClassName; //!< Name of Win32 window class used by OSG graphics window instances
Win32WindowingSystem();
~Win32WindowingSystem();
// Access the Win32 windowing system through this singleton class.
static Win32WindowingSystem* getInterface()
{
static Win32WindowingSystem* win32Interface = new Win32WindowingSystem;
return win32Interface;
}
// Return the number of screens present in the system
virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si );
// Return the resolution of specified screen
// (0,0) is returned if screen is unknown
virtual void getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height );
// Return the screen position and width/height.
// all zeros returned if screen is unknown
virtual void getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height );
// Create a graphics context with given traits
virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits );
// Register a newly created native window along with its application counterpart
// This is required to maintain a link between Windows messages and the application window object
// at event processing time
virtual void registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window );
// Unregister a window
// This is called as part of a window being torn down
virtual void unregisterWindow( HWND hwnd );
// Get the application window object associated with a native window
virtual osgViewer::GraphicsWindowWin32* getGraphicsWindowFor( HWND hwnd );
// Return a valid sample OpenGL Device Context and Rendering Context that can be used with wglXYZ extensions
virtual OpenGLContext getSampleOpenGLContext();
protected:
// Display devices present in the system
typedef std::vector<DISPLAY_DEVICE> DisplayDevices;
// Map Win32 window handles to GraphicsWindowWin32 instance
typedef std::pair< HWND, osgViewer::GraphicsWindowWin32* > WindowHandleEntry;
typedef std::map< HWND, osgViewer::GraphicsWindowWin32* > WindowHandles;
// Enumerate all display devices and return in passed container
void enumerateDisplayDevices( DisplayDevices& displayDevices ) const;
bool getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DEVMODE& deviceMode );
// Register the window class used by OSG graphics window instances
void registerWindowClass();
// Unregister the window class used by OSG graphics window instances
void unregisterWindowClass();
// Release sample GL context
void releaseSampleOpenGLContext();
// Data members
WindowHandles _activeWindows; //!< handles to active windows
HWND _dummyGLWindow; //!< dummy GL window used to provide a valid context for wglXYZ calls
HDC _dummyGLWindowDC; //!< dummy GL window device context
HGLRC _dummyGLRC; //!< dummy GL rendering context
bool _windowClassRegistered; //!< true after windowing interface has been initialized successfully
private:
// No implementation for these
Win32WindowingSystem( const Win32WindowingSystem& );
Win32WindowingSystem& operator=( const Win32WindowingSystem& );
};
//
// This is the class we need to create for pbuffers and display devices that are not attached to the desktop
// (and thus cannot have windows created on their surface).
//
// Note its not a GraphicsWindow as it won't need any of the event handling and window mapping facilities.
//
class GraphicsContextWin32 : public osg::GraphicsContext
{
public:
GraphicsContextWin32(osg::GraphicsContext::Traits* traits);
~GraphicsContextWin32();
virtual bool valid() const;
/** Realise the GraphicsContext implementation,
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual bool realizeImplementation();
/** Return true if the graphics context has been realised, and is ready to use, implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual bool isRealizedImplementation() const;
/** Close the graphics context implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual void closeImplementation();
/** Make this graphics context current implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual bool makeCurrentImplementation();
/** Make this graphics context current with specified read context implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual bool makeContextCurrentImplementation(GraphicsContext* /*readContext*/);
/** Release the graphics context.*/
virtual bool releaseContextImplementation();
/** Pure virtual, Bind the graphics context to associated texture implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext. */
virtual void bindPBufferToTextureImplementation(GLenum /*buffer*/);
/** Swap the front and back buffers implementation.
* Pure virtual - must be implemented by Concrate implementations of GraphicsContext. */
virtual void swapBuffersImplementation();
protected:
bool _valid;
};
//////////////////////////////////////////////////////////////////////////////
// Error reporting
//////////////////////////////////////////////////////////////////////////////
static void reportError( const std::string& msg, unsigned int errorCode )
{
osg::notify(osg::WARN) << "Windows System Error #" << errorCode << " : " << msg.c_str();
LPVOID lpMsgBuf;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
errorCode,
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL)!=0)
{
osg::notify(osg::WARN) << ". Reason : " << LPTSTR(lpMsgBuf) << std::endl;
::LocalFree(lpMsgBuf);
}
else
{
osg::notify(osg::WARN) << std::endl;
}
}
static void reportError( const std::string& msg )
{
osg::notify(osg::WARN) << "Error: " << msg.c_str() << std::endl;
}
//////////////////////////////////////////////////////////////////////////////
// Keyboard key mapping for Win32
//////////////////////////////////////////////////////////////////////////////
class Win32KeyboardMap
{
public:
Win32KeyboardMap()
{
_keymap[VK_ESCAPE ] = osgGA::GUIEventAdapter::KEY_Escape;
_keymap[VK_F1 ] = osgGA::GUIEventAdapter::KEY_F1;
_keymap[VK_F2 ] = osgGA::GUIEventAdapter::KEY_F2;
_keymap[VK_F3 ] = osgGA::GUIEventAdapter::KEY_F3;
_keymap[VK_F4 ] = osgGA::GUIEventAdapter::KEY_F4;
_keymap[VK_F5 ] = osgGA::GUIEventAdapter::KEY_F5;
_keymap[VK_F6 ] = osgGA::GUIEventAdapter::KEY_F6;
_keymap[VK_F7 ] = osgGA::GUIEventAdapter::KEY_F7;
_keymap[VK_F8 ] = osgGA::GUIEventAdapter::KEY_F8;
_keymap[VK_F9 ] = osgGA::GUIEventAdapter::KEY_F9;
_keymap[VK_F10 ] = osgGA::GUIEventAdapter::KEY_F10;
_keymap[VK_F11 ] = osgGA::GUIEventAdapter::KEY_F11;
_keymap[VK_F12 ] = osgGA::GUIEventAdapter::KEY_F12;
_keymap[0xc0 ] = '`';
_keymap['0' ] = '0';
_keymap['1' ] = '1';
_keymap['2' ] = '2';
_keymap['3' ] = '3';
_keymap['4' ] = '4';
_keymap['5' ] = '5';
_keymap['6' ] = '6';
_keymap['7' ] = '7';
_keymap['8' ] = '8';
_keymap['9' ] = '9';
_keymap[0xbd ] = '-';
_keymap[0xbb ] = '=';
_keymap[VK_BACK ] = osgGA::GUIEventAdapter::KEY_BackSpace;
_keymap[VK_TAB ] = osgGA::GUIEventAdapter::KEY_Tab;
_keymap['A' ] = 'A';
_keymap['B' ] = 'B';
_keymap['C' ] = 'C';
_keymap['D' ] = 'D';
_keymap['E' ] = 'E';
_keymap['F' ] = 'F';
_keymap['G' ] = 'G';
_keymap['H' ] = 'H';
_keymap['I' ] = 'I';
_keymap['J' ] = 'J';
_keymap['K' ] = 'K';
_keymap['L' ] = 'L';
_keymap['M' ] = 'M';
_keymap['N' ] = 'N';
_keymap['O' ] = 'O';
_keymap['P' ] = 'P';
_keymap['Q' ] = 'Q';
_keymap['R' ] = 'R';
_keymap['S' ] = 'S';
_keymap['T' ] = 'T';
_keymap['U' ] = 'U';
_keymap['V' ] = 'V';
_keymap['W' ] = 'W';
_keymap['X' ] = 'X';
_keymap['Y' ] = 'Y';
_keymap['Z' ] = 'Z';
_keymap[0xdb ] = '[';
_keymap[0xdd ] = ']';
_keymap[0xdc ] = '\\';
_keymap[VK_CAPITAL ] = osgGA::GUIEventAdapter::KEY_Caps_Lock;
_keymap[0xba ] = ';';
_keymap[0xde ] = '\'';
_keymap[VK_RETURN ] = osgGA::GUIEventAdapter::KEY_Return;
_keymap[VK_LSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_L;
_keymap[0xbc ] = ',';
_keymap[0xbe ] = '.';
_keymap[0xbf ] = '/';
_keymap[VK_RSHIFT ] = osgGA::GUIEventAdapter::KEY_Shift_R;
_keymap[VK_LCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_L;
_keymap[VK_LWIN ] = osgGA::GUIEventAdapter::KEY_Super_L;
_keymap[VK_SPACE ] = ' ';
_keymap[VK_LMENU ] = osgGA::GUIEventAdapter::KEY_Alt_L;
_keymap[VK_RMENU ] = osgGA::GUIEventAdapter::KEY_Alt_R;
_keymap[VK_RWIN ] = osgGA::GUIEventAdapter::KEY_Super_R;
_keymap[VK_APPS ] = osgGA::GUIEventAdapter::KEY_Menu;
_keymap[VK_RCONTROL ] = osgGA::GUIEventAdapter::KEY_Control_R;
_keymap[VK_SNAPSHOT ] = osgGA::GUIEventAdapter::KEY_Print;
_keymap[VK_SCROLL ] = osgGA::GUIEventAdapter::KEY_Scroll_Lock;
_keymap[VK_PAUSE ] = osgGA::GUIEventAdapter::KEY_Pause;
_keymap[VK_HOME ] = osgGA::GUIEventAdapter::KEY_Home;
_keymap[VK_PRIOR ] = osgGA::GUIEventAdapter::KEY_Page_Up;
_keymap[VK_END ] = osgGA::GUIEventAdapter::KEY_End;
_keymap[VK_NEXT ] = osgGA::GUIEventAdapter::KEY_Page_Down;
_keymap[VK_DELETE ] = osgGA::GUIEventAdapter::KEY_Delete;
_keymap[VK_INSERT ] = osgGA::GUIEventAdapter::KEY_Insert;
_keymap[VK_LEFT ] = osgGA::GUIEventAdapter::KEY_Left;
_keymap[VK_UP ] = osgGA::GUIEventAdapter::KEY_Up;
_keymap[VK_RIGHT ] = osgGA::GUIEventAdapter::KEY_Right;
_keymap[VK_DOWN ] = osgGA::GUIEventAdapter::KEY_Down;
_keymap[VK_NUMLOCK ] = osgGA::GUIEventAdapter::KEY_Num_Lock;
_keymap[VK_DIVIDE ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
_keymap[VK_MULTIPLY ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
_keymap[VK_SUBTRACT ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
_keymap[VK_ADD ] = osgGA::GUIEventAdapter::KEY_KP_Add;
_keymap[VK_NUMPAD7 ] = osgGA::GUIEventAdapter::KEY_KP_Home;
_keymap[VK_NUMPAD8 ] = osgGA::GUIEventAdapter::KEY_KP_Up;
_keymap[VK_NUMPAD9 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
_keymap[VK_NUMPAD4 ] = osgGA::GUIEventAdapter::KEY_KP_Left;
_keymap[VK_NUMPAD5 ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
_keymap[VK_NUMPAD6 ] = osgGA::GUIEventAdapter::KEY_KP_Right;
_keymap[VK_NUMPAD1 ] = osgGA::GUIEventAdapter::KEY_KP_End;
_keymap[VK_NUMPAD2 ] = osgGA::GUIEventAdapter::KEY_KP_Down;
_keymap[VK_NUMPAD3 ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
_keymap[VK_NUMPAD0 ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
_keymap[VK_DECIMAL ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
}
~Win32KeyboardMap() {}
int remapKey(int key)
{
KeyMap::const_iterator map = _keymap.find(key);
return map==_keymap.end() ? key : map->second;
}
protected:
typedef std::map<int, int> KeyMap;
KeyMap _keymap;
};
static Win32KeyboardMap s_win32KeyboardMap;
static int remapWin32Key(int key)
{
return s_win32KeyboardMap.remapKey(key);
}
//////////////////////////////////////////////////////////////////////////////
// Window procedure for all GraphicsWindowWin32 instances
// Dispatches the call to the actual instance
//////////////////////////////////////////////////////////////////////////////
static LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
osgViewer::GraphicsWindowWin32* window = Win32WindowingSystem::getInterface()->getGraphicsWindowFor(hwnd);
return window ? window->handleNativeWindowingEvent(hwnd, uMsg, wParam, lParam) :
::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
//////////////////////////////////////////////////////////////////////////////
// Win32WindowingSystem::OpenGLContext implementation
//////////////////////////////////////////////////////////////////////////////
Win32WindowingSystem::OpenGLContext::~OpenGLContext()
{
if (_restorePreviousOnExit && _previous!=_hglrc && !::wglMakeCurrent(_hdc, _previous))
{
reportError("Win32WindowingSystem::OpenGLContext() - Unable to restore current OpenGL rendering context", ::GetLastError());
}
_previous = 0;
_hdc = 0;
_hglrc = 0;
}
bool Win32WindowingSystem::OpenGLContext::makeCurrent( bool restorePreviousOnExit )
{
if (_hdc==0 || _hglrc==0) return false;
_previous = restorePreviousOnExit ? ::wglGetCurrentContext() : 0;
if (_hglrc==_previous) return true;
if (!::wglMakeCurrent(_hdc, _hglrc))
{
reportError("Win32WindowingSystem::OpenGLContext() - Unable to set current OpenGL rendering context", ::GetLastError());
return false;
}
_restorePreviousOnExit = restorePreviousOnExit;
return true;
}
//////////////////////////////////////////////////////////////////////////////
// Win32WindowingSystem implementation
//////////////////////////////////////////////////////////////////////////////
std::string Win32WindowingSystem::osgGraphicsWindowClassName;
Win32WindowingSystem::Win32WindowingSystem()
: _dummyGLWindow(0),
_dummyGLWindowDC(0),
_dummyGLRC(0),
_windowClassRegistered(false)
{
}
Win32WindowingSystem::~Win32WindowingSystem()
{
releaseSampleOpenGLContext();
unregisterWindowClass();
}
void Win32WindowingSystem::enumerateDisplayDevices( DisplayDevices& displayDevices ) const
{
for (unsigned int deviceNum=0;; ++deviceNum)
{
DISPLAY_DEVICE displayDevice;
displayDevice.cb = sizeof(displayDevice);
if (!::EnumDisplayDevices(NULL, deviceNum, &displayDevice, 0)) break;
// Do not track devices used for remote access (Terminal Services pseudo-displays, etc.)
if (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) continue;
//!@todo when the GraphicsContextWin32 class is implemented, remove this line
// For the time-being only return display devices that are attached to the desktop
if (!(displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)) continue;
displayDevices.push_back(displayDevice);
}
}
void Win32WindowingSystem::registerWindowClass()
{
if (_windowClassRegistered) return;
//
// Register the window class used by OSG GraphicsWindowWin32 instances
//
std::ostringstream str;
str << "OpenSceneGraph Graphics Window for Win32 [" << ::GetCurrentProcessId() << "]";
osgGraphicsWindowClassName = str.str();
WNDCLASSEX wc;
HINSTANCE hinst = ::GetModuleHandle(NULL);
wc.cbSize = sizeof(wc);
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = ::LoadIcon(hinst, "OSG_ICON");
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = 0;
wc.lpszClassName = osgGraphicsWindowClassName.c_str();
wc.hIconSm = NULL;
if (::RegisterClassEx(&wc)==0)
{
unsigned int lastError = ::GetLastError();
if (lastError!=ERROR_CLASS_ALREADY_EXISTS)
{
reportError("Win32WindowingSystem::registerWindowClass() - Unable to register window class", lastError);
return;
}
}
_windowClassRegistered = true;
}
void Win32WindowingSystem::unregisterWindowClass()
{
if (_windowClassRegistered)
{
::UnregisterClass(osgGraphicsWindowClassName.c_str(), ::GetModuleHandle(NULL));
_windowClassRegistered = false;
}
}
Win32WindowingSystem::OpenGLContext Win32WindowingSystem::getSampleOpenGLContext()
{
if (_dummyGLWindowDC) return OpenGLContext(_dummyGLWindowDC, _dummyGLRC);
registerWindowClass();
HWND hwnd = ::CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
osgGraphicsWindowClassName.c_str(),
NULL,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
0,
0,
256,
256,
NULL,
NULL,
::GetModuleHandle(NULL),
NULL);
if (hwnd==0)
{
reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create window", ::GetLastError());
return OpenGLContext();
}
//
// Set the pixel format of the window
//
PIXELFORMATDESCRIPTOR pixelFormat =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA,
24,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
24,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
HDC hdc = ::GetDC(hwnd);
if (hdc==0)
{
reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to get window device context", ::GetLastError());
::DestroyWindow(hwnd);
return OpenGLContext();
}
int pixelFormatIndex = ::ChoosePixelFormat(hdc, &pixelFormat);
if (pixelFormatIndex==0)
{
reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to choose pixel format", ::GetLastError());
::ReleaseDC(hwnd, hdc);
::DestroyWindow(hwnd);
return OpenGLContext();
}
if (!::SetPixelFormat(hdc, pixelFormatIndex, &pixelFormat))
{
reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to set pixel format", ::GetLastError());
::ReleaseDC(hwnd, hdc);
::DestroyWindow(hwnd);
return OpenGLContext();
}
HGLRC hglrc = ::wglCreateContext(hdc);
if (hglrc==0)
{
reportError("Win32WindowingSystem::getSampleOpenGLContext() - Unable to create an OpenGL rendering context", ::GetLastError());
::ReleaseDC(hwnd, hdc);
::DestroyWindow(hwnd);
return OpenGLContext();
}
_dummyGLWindow = hwnd;
_dummyGLWindowDC = hdc;
_dummyGLRC = hglrc;
return OpenGLContext(_dummyGLWindowDC, _dummyGLRC);
}
void Win32WindowingSystem::releaseSampleOpenGLContext()
{
if (_dummyGLRC)
{
::wglMakeCurrent(_dummyGLWindowDC, NULL);
::wglDeleteContext(_dummyGLRC);
_dummyGLRC = 0;
}
if (_dummyGLWindowDC)
{
::ReleaseDC(_dummyGLWindow, _dummyGLWindowDC);
_dummyGLWindowDC = 0;
}
if (_dummyGLWindow)
{
::DestroyWindow(_dummyGLWindow);
_dummyGLWindow = 0;
}
}
unsigned int Win32WindowingSystem::getNumScreens( const osg::GraphicsContext::ScreenIdentifier& si )
{
//!@todo change when implementing the GraphicsContextWin32 class.
return si.displayNum==0 ? ::GetSystemMetrics(SM_CMONITORS) : 0;
}
bool Win32WindowingSystem::getScreenInformation( const osg::GraphicsContext::ScreenIdentifier& si, DEVMODE& deviceMode )
{
if (si.displayNum>0)
{
osg::notify(osg::WARN) << "Win32WindowingSystem::getScreenInformation() - The screen identifier on the Win32 platform must always use display number 0. Value received was " << si.displayNum << std::endl;
return false;
}
DisplayDevices displayDevices;
enumerateDisplayDevices(displayDevices);
if (si.screenNum>=displayDevices.size())
{
osg::notify(osg::WARN) << "Win32WindowingSystem::getScreenInformation() - Cannot get information for screen " << si.screenNum << " because it does not exist." << std::endl;
return false;
}
deviceMode.dmSize = sizeof(deviceMode);
deviceMode.dmDriverExtra = 0;
if (!::EnumDisplaySettings(displayDevices[si.screenNum].DeviceName, ENUM_CURRENT_SETTINGS, &deviceMode))
{
std::ostringstream str;
str << "Win32WindowingSystem::getScreenInformation() - Unable to query information for screen number " << si.screenNum;
reportError(str.str(), ::GetLastError());
return false;
}
return true;
}
void Win32WindowingSystem::getScreenResolution( const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height )
{
DEVMODE deviceMode;
if (getScreenInformation(si, deviceMode))
{
width = deviceMode.dmPelsWidth;
height = deviceMode.dmPelsHeight;
}
else
{
width = 0;
height = 0;
}
}
void Win32WindowingSystem::getScreenPosition( const osg::GraphicsContext::ScreenIdentifier& si, int& originX, int& originY, unsigned int& width, unsigned int& height )
{
DEVMODE deviceMode;
if (getScreenInformation(si, deviceMode))
{
originX = deviceMode.dmPosition.x;
originY = deviceMode.dmPosition.y;
width = deviceMode.dmPelsWidth;
height = deviceMode.dmPelsHeight;
}
else
{
originX = 0;
originY = 0;
width = 0;
height = 0;
}
}
osg::GraphicsContext* Win32WindowingSystem::createGraphicsContext( osg::GraphicsContext::Traits* traits )
{
if (traits->pbuffer)
{
osg::ref_ptr<osgViewer::GraphicsContextWin32> pbuffer = new GraphicsContextWin32(traits);
if (pbuffer->valid()) return pbuffer.release();
else return 0;
}
else
{
registerWindowClass();
osg::ref_ptr<osgViewer::GraphicsWindowWin32> window = new GraphicsWindowWin32(traits);
if (window->valid()) return window.release();
else return 0;
}
}
void Win32WindowingSystem::registerWindow( HWND hwnd, osgViewer::GraphicsWindowWin32* window )
{
if (hwnd) _activeWindows.insert(WindowHandleEntry(hwnd, window));
}
//
// Unregister a window
// This is called as part of a window being torn down
//
void Win32WindowingSystem::unregisterWindow( HWND hwnd )
{
if (hwnd) _activeWindows.erase(hwnd);
}
//
// Get the application window object associated with a native window
//
osgViewer::GraphicsWindowWin32* Win32WindowingSystem::getGraphicsWindowFor( HWND hwnd )
{
WindowHandles::const_iterator entry = _activeWindows.find(hwnd);
return entry==_activeWindows.end() ? 0 : entry->second;
}
//////////////////////////////////////////////////////////////////////////////
// GraphicsWindowWin32 implementation
//////////////////////////////////////////////////////////////////////////////
GraphicsWindowWin32::GraphicsWindowWin32( osg::GraphicsContext::Traits* traits )
: _hwnd(0),
_hdc(0),
_hglrc(0),
_timeOfLastCheckEvents(-1.0),
_screenOriginX(0),
_screenOriginY(0),
_screenWidth(0),
_screenHeight(0),
_windowOriginXToRealize(0),
_windowOriginYToRealize(0),
_windowWidthToRealize(0),
_windowHeightToRealize(0),
_initialized(false),
_valid(false),
_realized(false),
_destroying(false)
{
_traits = traits;
init();
if (valid())
{
setState( new osg::State );
getState()->setContextID( osg::GraphicsContext::createNewContextID() );
Win32WindowingSystem::getInterface()->registerWindow(_hwnd, this);
}
}
GraphicsWindowWin32::~GraphicsWindowWin32()
{
close();
destroyWindow();
}
void GraphicsWindowWin32::init()
{
if (!_initialized)
{
_initialized = createWindow() != 0;
_valid = _initialized;
}
}
HWND GraphicsWindowWin32::createWindow()
{
unsigned int extendedStyle;
unsigned int windowStyle;
if (!determineWindowPositionAndStyle(_traits->windowDecoration,
_windowOriginXToRealize,
_windowOriginYToRealize,
_windowWidthToRealize,
_windowHeightToRealize,
windowStyle,
extendedStyle))
{
reportError("GraphicsWindowWin32::createWindow() - Unable to determine the window position and style");
return 0;
}
_hwnd = ::CreateWindowEx(extendedStyle,
Win32WindowingSystem::osgGraphicsWindowClassName.c_str(),
_traits->windowName.c_str(),
windowStyle,
_windowOriginXToRealize,
_windowOriginYToRealize,
_windowWidthToRealize,
_windowHeightToRealize,
NULL,
NULL,
::GetModuleHandle(NULL),
NULL);
if (_hwnd==0)
{
reportError("GraphicsWindowWin32::createWindow() - Unable to create window", ::GetLastError());
return 0;
}
_hdc = ::GetDC(_hwnd);
if (_hdc==0)
{
reportError("GraphicsWindowWin32::createWindow() - Unable to get window device context", ::GetLastError());
destroyWindow();
_hwnd = 0;
return 0;
}
//
// Set the pixel format according to traits specified
//
if (!setPixelFormat())
{
::ReleaseDC(_hwnd, _hdc);
_hdc = 0;
destroyWindow();
return 0;
}
return _hwnd;
}
void GraphicsWindowWin32::destroyWindow( bool deleteNativeWindow )
{
if (_destroying) return;
_destroying = true;
close();
if (_hdc)
{
releaseContext();
if (_hglrc)
{
::wglDeleteContext(_hglrc);
_hglrc = 0;
}
::ReleaseDC(_hwnd, _hdc);
_hdc = 0;
}
if (_hwnd)
{
Win32WindowingSystem::getInterface()->unregisterWindow(_hwnd);
if (deleteNativeWindow) ::DestroyWindow(_hwnd);
_hwnd = 0;
}
_initialized = false;
_realized = false;
_valid = false;
}
bool GraphicsWindowWin32::determineWindowPositionAndStyle( bool decorated, int& x, int& y, unsigned int& w, unsigned int& h, unsigned int& style, unsigned int& extendedStyle )
{
if (_traits==0) return false;
//
// Query the screen position and size
//
osg::GraphicsContext::ScreenIdentifier screenId(_traits->screenNum);
Win32WindowingSystem* windowManager = Win32WindowingSystem::getInterface();
windowManager->getScreenPosition(screenId, _screenOriginX, _screenOriginY, _screenWidth, _screenHeight);
if (_screenWidth==0 || _screenHeight==0) return false;
x = _traits->x + _screenOriginX;
y = _traits->y + _screenOriginY;
w = _traits->width;
h = _traits->height;
style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
extendedStyle = 0;
if (decorated)
{
style |= WS_CAPTION |
WS_SYSMENU |
WS_MINIMIZEBOX |
WS_MAXIMIZEBOX;
if (_traits->supportsResize) style |= WS_SIZEBOX;
extendedStyle = WS_EX_APPWINDOW |
WS_EX_OVERLAPPEDWINDOW |
WS_EX_ACCEPTFILES |
WS_EX_LTRREADING;
RECT corners;
corners.left = x;
corners.top = y;
corners.right = x + w - 1;
corners.bottom = y + h - 1;
//
// Determine the location of the window corners in order to have
// a client area of the requested size
//
if (!::AdjustWindowRectEx(&corners, style, FALSE, extendedStyle))
{
reportError("GraphicsWindowWin32::determineWindowPositionAndStyle() - Unable to adjust window rectangle", ::GetLastError());
return false;
}
x = corners.left;
y = corners.top;
w = corners.right - corners.left + 1;
h = corners.bottom - corners.top + 1;
}
return true;
}
bool GraphicsWindowWin32::setPixelFormat()
{
Win32WindowingSystem::OpenGLContext glContext = Win32WindowingSystem::getInterface()->getSampleOpenGLContext();
if (!glContext.makeCurrent(true)) return false;
//
// Access the entry point for the wglChoosePixelFormatARB function
//
WGLChoosePixelFormatARB wglChoosePixelFormatARB = (WGLChoosePixelFormatARB)wglGetProcAddress("wglChoosePixelFormatARB");
if (wglChoosePixelFormatARB==0)
{
reportError("GraphicsWindowWin32::setPixelFormat() - wglChoosePixelFormatARB extension not found", ::GetLastError());
return false;
}
//
// Build the specifications of the requested pixel format
//
WGLIntegerAttributes attributes;
attributes.begin();
attributes.enable(WGL_DRAW_TO_WINDOW_ARB);
attributes.enable(WGL_SUPPORT_OPENGL_ARB);
attributes.set(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
attributes.set(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
attributes.set(WGL_COLOR_BITS_ARB, _traits->red + _traits->green + _traits->blue);
attributes.set(WGL_RED_BITS_ARB, _traits->red);
attributes.set(WGL_GREEN_BITS_ARB, _traits->green);
attributes.set(WGL_BLUE_BITS_ARB, _traits->blue);
attributes.set(WGL_DEPTH_BITS_ARB, _traits->depth);
if (_traits->doubleBuffer)
{
attributes.enable(WGL_DOUBLE_BUFFER_ARB);
attributes.set(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_ARB);
}
if (_traits->alpha) attributes.set(WGL_ALPHA_BITS_ARB, _traits->alpha);
if (_traits->stencil) attributes.set(WGL_STENCIL_BITS_ARB, _traits->stencil);
if (_traits->sampleBuffers) attributes.set(WGL_SAMPLE_BUFFERS_ARB, _traits->sampleBuffers);
if (_traits->samples) attributes.set(WGL_SAMPLES_ARB, _traits->samples);
if (_traits->quadBufferStereo) attributes.enable(WGL_STEREO_ARB);
attributes.end();
//
// Choose the closest pixel format from the specified traits
//
int pixelFormatIndex = 0;
unsigned int numMatchingPixelFormats = 0;
if (!wglChoosePixelFormatARB(glContext.deviceContext(),
attributes.get(),
NULL,
1,
&pixelFormatIndex,
&numMatchingPixelFormats))
{
reportError("GraphicsWindowWin32::setPixelFormat() - Unable to choose the requested pixel format", ::GetLastError());
return false;
}
if (numMatchingPixelFormats==0)
{
reportError("GraphicsWindowWin32::setPixelFormat() - No matching pixel format found based on traits specified", ::GetLastError());
return false;
}
//
// Set the pixel format found
//
PIXELFORMATDESCRIPTOR pfd;
::memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
if (!::SetPixelFormat(_hdc, pixelFormatIndex, &pfd))
{
reportError("GraphicsWindowWin32::setPixelFormat() - Unable to set pixel format", ::GetLastError());
return false;
}
//
// Create the OpenGL rendering context associated with this window
//
_hglrc = ::wglCreateContext(_hdc);
if (_hglrc==0)
{
reportError("GraphicsWindowWin32::setPixelFormat() - Unable to create OpenGL rendering context", ::GetLastError());
return false;
}
return true;
}
void GraphicsWindowWin32::setWindowDecoration( bool decorated )
{
unsigned int windowStyle;
unsigned int extendedStyle;
//
// Determine position and size of window with/without decorations to retain the size specified in traits
//
int x, y;
unsigned int w, h;
if (!determineWindowPositionAndStyle(decorated, x, y, w, h, windowStyle, extendedStyle))
{
reportError("GraphicsWindowWin32::setWindowDecoration() - Unable to determine the window position and style");
return;
}
//
// Change the window style
//
::SetLastError(0);
unsigned int result = ::SetWindowLong(_hwnd, GWL_STYLE, windowStyle);
unsigned int error = ::GetLastError();
if (result==0 && error)
{
reportError("GraphicsWindowWin32::setWindowDecoration() - Unable to set window style", error);
return;
}
//
// Change the window extended style
//
::SetLastError(0);
result = ::SetWindowLong(_hwnd, GWL_EXSTYLE, extendedStyle);
error = ::GetLastError();
if (result==0 && error)
{
reportError("GraphicsWindowWin32::setWindowDecoration() - Unable to set window extented style", error);
return;
}
//
// Change the window position and size and realize the style changes
//
if (!::SetWindowPos(_hwnd, HWND_TOP, x, y, w, h, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_SHOWWINDOW))
{
reportError("GraphicsWindowWin32::setWindowDecoration() - Unable to set new window position and size", ::GetLastError());
return;
}
//
// Repaint the desktop to cleanup decorations removed
//
if (!decorated)
{
::InvalidateRect(NULL, NULL, TRUE);
}
}
bool GraphicsWindowWin32::realizeImplementation()
{
if (_realized) return true;
if (!_initialized)
{
init();
if (!_initialized) return false;
}
//
// Bring the window on top of other ones (including the taskbar if it covers it completely)
//
// NOTE: To cover the taskbar with a window that does not completely cover it, the HWND_TOPMOST
// Z-order must be used in the code below instead of HWND_TOP.
// @todo: This should be controlled through a flag in the traits (topMostWindow)
//
if (!::SetWindowPos(_hwnd,
HWND_TOP,
_windowOriginXToRealize,
_windowOriginYToRealize,
_windowWidthToRealize,
_windowHeightToRealize,
SWP_SHOWWINDOW))
{
reportError("GraphicsWindowWin32::realizeImplementation() - Unable to show window", ::GetLastError());
return false;
}
if (!::UpdateWindow(_hwnd))
{
reportError("GraphicsWindowWin32::realizeImplementation() - Unable to update window", ::GetLastError());
return false;
}
_realized = true;
return true;
}
bool GraphicsWindowWin32::makeCurrentImplementation()
{
if (!_realized)
{
reportError("GraphicsWindowWin32::makeCurrentImplementation() - Window not realized; cannot do makeCurrent.");
return false;
}
if (!::wglMakeCurrent(_hdc, _hglrc))
{
reportError("GraphicsWindowWin32::makeCurrentImplementation() - Unable to set current OpenGL rendering context", ::GetLastError());
return false;
}
return true;
}
bool GraphicsWindowWin32::releaseContextImplementation()
{
if (!::wglMakeCurrent(_hdc, NULL))
{
reportError("GraphicsWindowWin32::releaseContextImplementation() - Unable to release current OpenGL rendering context", ::GetLastError());
return false;
}
return true;
}
void GraphicsWindowWin32::closeImplementation()
{
destroyWindow();
_initialized = false;
_valid = false;
_realized = false;
}
void GraphicsWindowWin32::swapBuffersImplementation()
{
if (!_realized) return;
if (!::SwapBuffers(_hdc))
{
reportError("GraphicsWindowWin32::swapBuffersImplementation() - Unable to swap display buffers", ::GetLastError());
}
}
void GraphicsWindowWin32::checkEvents()
{
if (!_realized) return;
MSG msg;
while (::PeekMessage(&msg, _hwnd, NULL, NULL, PM_REMOVE))
{
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
void GraphicsWindowWin32::grabFocus()
{
if (!::SetForegroundWindow(_hwnd))
{
osg::notify(osg::WARN) << "Warning: GraphicsWindowWin32::grabFocus() - Failed grabbing the focus" << std::endl;
}
}
void GraphicsWindowWin32::grabFocusIfPointerInWindow()
{
POINT mousePos;
if (!::GetCursorPos(&mousePos))
{
reportError("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get cursor position", ::GetLastError());
return;
}
RECT windowRect;
if (!::GetWindowRect(_hwnd, &windowRect))
{
reportError("GraphicsWindowWin32::grabFocusIfPointerInWindow() - Unable to get window position", ::GetLastError());
return;
}
if (mousePos.x>=windowRect.left && mousePos.x<=windowRect.right &&
mousePos.y>=windowRect.top && mousePos.y<=windowRect.bottom)
{
grabFocus();
}
}
void GraphicsWindowWin32::adaptKey( WPARAM wParam, LPARAM lParam, int& keySymbol, unsigned int& modifierMask )
{
modifierMask = 0;
BYTE keyState[256];
if (!::GetKeyboardState(keyState))
{
keySymbol = 0;
return;
}
bool rightSide = (lParam & 0x01000000)!=0;
if (keyState[VK_SHIFT] & 0x80)
{
modifierMask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_SHIFT : osgGA::GUIEventAdapter::MODKEY_LEFT_SHIFT;
}
if (keyState[VK_CAPITAL] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
if (keyState[VK_NUMLOCK] & 0x01) modifierMask |= osgGA::GUIEventAdapter::MODKEY_NUM_LOCK;
if (keyState[VK_CONTROL] & 0x80)
{
modifierMask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_CTRL : osgGA::GUIEventAdapter::MODKEY_LEFT_CTRL;
}
if (lParam & 0x20000000)
{
modifierMask |= osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
modifierMask |= rightSide ? osgGA::GUIEventAdapter::MODKEY_RIGHT_ALT : osgGA::GUIEventAdapter::MODKEY_LEFT_ALT;
}
keySymbol = remapWin32Key(wParam);
if (keySymbol==osgGA::GUIEventAdapter::KEY_Return && rightSide)
{
keySymbol = osgGA::GUIEventAdapter::KEY_KP_Enter;
}
else if ((keySymbol & 0xff00)==0)
{
char asciiKey[2];
int numChars = ::ToAscii(wParam, (lParam>>16)&0xff, keyState, reinterpret_cast<WORD*>(asciiKey), 0);
if (numChars>0) keySymbol = asciiKey[0];
}
}
void GraphicsWindowWin32::transformMouseXY( float& x, float& y )
{
if (getEventQueue()->getUseFixedMouseInputRange())
{
osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
}
}
LRESULT GraphicsWindowWin32::handleNativeWindowingEvent( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
//!@todo adapt windows event time to osgGA event queue time for better resolution
double baseTime = _timeOfLastCheckEvents;
double eventTime = _timeOfLastCheckEvents;
double resizeTime = eventTime;
_timeOfLastCheckEvents = getEventQueue()->getTime();
switch(uMsg)
{
/////////////////
case WM_PAINT :
/////////////////
{
PAINTSTRUCT paint;
::BeginPaint(hwnd, &paint);
::EndPaint(hwnd, &paint);
}
break;
///////////////////
case WM_MOUSEMOVE :
///////////////////
{
float mx = GET_X_LPARAM(lParam);
float my = GET_Y_LPARAM(lParam);
transformMouseXY(mx, my);
getEventQueue()->mouseMotion(mx, my, eventTime);
}
break;
/////////////////////
case WM_LBUTTONDOWN :
case WM_MBUTTONDOWN :
case WM_RBUTTONDOWN :
/////////////////////
{
int button;
if (uMsg==WM_LBUTTONDOWN) button = 1;
else if (uMsg==WM_MBUTTONDOWN) button = 2;
else button = 3;
float mx = GET_X_LPARAM(lParam);
float my = GET_Y_LPARAM(lParam);
transformMouseXY(mx, my);
getEventQueue()->mouseButtonPress(mx, my, button, eventTime);
}
break;
/////////////////////
case WM_LBUTTONUP :
case WM_MBUTTONUP :
case WM_RBUTTONUP :
/////////////////////
{
int button;
if (uMsg==WM_LBUTTONUP) button = 1;
else if (uMsg==WM_MBUTTONUP) button = 2;
else button = 3;
float mx = GET_X_LPARAM(lParam);
float my = GET_Y_LPARAM(lParam);
transformMouseXY(mx, my);
getEventQueue()->mouseButtonRelease(mx, my, button, eventTime);
}
break;
////////////////////
case WM_MOUSEWHEEL :
////////////////////
getEventQueue()->mouseScroll(GET_WHEEL_DELTA_WPARAM(wParam)<0 ? osgGA::GUIEventAdapter::SCROLL_DOWN :
osgGA::GUIEventAdapter::SCROLL_UP,
eventTime);
break;
/////////////////
case WM_MOVE :
case WM_SIZE :
/////////////////
{
POINT origin;
origin.x = 0;
origin.y = 0;
::ClientToScreen(hwnd, &origin);
int windowX = origin.x - _screenOriginX;
int windowY = origin.y - _screenOriginY;
resizeTime = eventTime;
RECT clientRect;
::GetClientRect(hwnd, &clientRect);
int windowWidth;
int windowHeight;
if (clientRect.bottom==0 && clientRect.right==0)
{
//
// Window has been minimized; keep window width & height to a minimum of 1 pixel
//
windowWidth = 1;
windowHeight = 1;
}
else
{
windowWidth = clientRect.right;
windowHeight = clientRect.bottom;
}
if (windowX!=_traits->x || windowY!=_traits->y || windowWidth!=_traits->width || windowHeight!=_traits->height)
{
resized(windowX, windowY, windowWidth, windowHeight);
getEventQueue()->windowResize(windowX, windowY, windowWidth, windowHeight, resizeTime);
}
}
break;
////////////////////
case WM_KEYDOWN :
case WM_SYSKEYDOWN :
////////////////////
{
int keySymbol = 0;
unsigned int modifierMask = 0;
adaptKey(wParam, lParam, keySymbol, modifierMask);
getEventQueue()->keyPress(keySymbol, eventTime);
getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
}
break;
//////////////////
case WM_KEYUP :
case WM_SYSKEYUP :
//////////////////
{
int keySymbol = 0;
unsigned int modifierMask = 0;
adaptKey(wParam, lParam, keySymbol, modifierMask);
getEventQueue()->keyRelease(keySymbol, eventTime);
getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
}
break;
/////////////////
case WM_CLOSE :
/////////////////
::DestroyWindow(hwnd);
break;
/////////////////
case WM_DESTROY :
/////////////////
destroyWindow(false);
getEventQueue()->closeWindow(eventTime);
::PostQuitMessage(0);
break;
/////////////////
default :
/////////////////
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// GraphicsContextWin32 implementation
//////////////////////////////////////////////////////////////////////////////
GraphicsContextWin32::GraphicsContextWin32( osg::GraphicsContext::Traits* traits )
: _valid(false)
{
_traits = traits;
}
GraphicsContextWin32::~GraphicsContextWin32()
{
}
bool GraphicsContextWin32::valid() const
{
return _valid;
}
bool GraphicsContextWin32::realizeImplementation()
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::realizeImplementation() not implemented." << std::endl; return false;
}
bool GraphicsContextWin32::isRealizedImplementation() const
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::isRealizedImplementation() not implemented." << std::endl; return false;
}
void GraphicsContextWin32::closeImplementation()
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::closeImplementation() not implemented." << std::endl;
}
bool GraphicsContextWin32::makeCurrentImplementation()
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::makeCurrentImplementation() not implemented." << std::endl;
return false;
}
bool GraphicsContextWin32::makeContextCurrentImplementation( GraphicsContext* /*readContext*/ )
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::makeContextCurrentImplementation(..) not implemented." << std::endl;
return false;
}
bool GraphicsContextWin32::releaseContextImplementation()
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::releaseContextImplementation(..) not implemented." << std::endl;
return false;
}
void GraphicsContextWin32::bindPBufferToTextureImplementation( GLenum /*buffer*/ )
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32::void bindPBufferToTextureImplementation(..) not implemented." << std::endl;
}
void GraphicsContextWin32::swapBuffersImplementation()
{
osg::notify(osg::NOTICE) << "GraphicsContextWin32:: swapBuffersImplementation() not implemented." << std::endl;
}
//////////////////////////////////////////////////////////////////////////////
// Class responsible for registering the Win32 Windowing System interface
//////////////////////////////////////////////////////////////////////////////
struct RegisterWindowingSystemInterfaceProxy
{
RegisterWindowingSystemInterfaceProxy()
{
osg::GraphicsContext::setWindowingSystemInterface(Win32WindowingSystem::getInterface());
}
~RegisterWindowingSystemInterfaceProxy()
{
osg::GraphicsContext::setWindowingSystemInterface(0);
}
};
static RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
}; // namespace OsgViewer