Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/GL/src/OgreWin32Window.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 16.6 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29
30#include "OgreWin32Window.h"
31#include "OgreRoot.h"
32#include "OgreLogManager.h"
33#include "OgreRenderSystem.h"
34#include "OgreImageCodec.h"
35#include "OgreStringConverter.h"
36#include "OgreException.h"
37#include "OgreWin32GLSupport.h"
38#include "OgreWin32Context.h"
39#include "OgreWindowEventUtilities.h"
40
41namespace Ogre {
42
43        Win32Window::Win32Window(Win32GLSupport &glsupport):
44                mGLSupport(glsupport),
45                mContext(0)
46        {
47                mIsFullScreen = false;
48                mHWnd = 0;
49                mGlrc = 0;
50                mIsExternal = false;
51                mIsExternalGLControl = false;
52                mIsExternalGLContext = false;
53                mSizing = false;
54                mClosed = false;
55                mDisplayFrequency = 0;
56                mActive = false;
57        }
58
59        Win32Window::~Win32Window()
60        {
61                destroy();
62        }
63
64        void Win32Window::create(const String& name, unsigned int width, unsigned int height,
65                                                        bool fullScreen, const NameValuePairList *miscParams)
66        {
67                // destroy current window, if any
68                if (mHWnd)
69                        destroy();
70
71#ifdef OGRE_STATIC_LIB
72                HINSTANCE hInst = GetModuleHandle( NULL );
73#else
74                HINSTANCE hInst = GetModuleHandle("RenderSystem_GL.dll");
75#endif
76
77                mHWnd = 0;
78                mName = name;
79                mIsFullScreen = fullScreen;
80                mClosed = false;
81
82                // load window defaults
83                mLeft = mTop = -1; // centered
84                mWidth = width;
85                mHeight = height;
86                mDisplayFrequency = 0;
87                mIsDepthBuffered = true;
88                mColourDepth = mIsFullScreen? 32 : GetDeviceCaps(GetDC(0), BITSPIXEL);
89
90                HWND parent = 0;
91                String title = name;
92                bool vsync = false;
93                int fsaa = 0;
94                String border;
95                bool outerSize = false;
96
97                if(miscParams)
98                {
99                        // Get variable-length params
100                        NameValuePairList::const_iterator opt;
101                        NameValuePairList::const_iterator end = miscParams->end();
102
103                        if ((opt = miscParams->find("title")) != end)
104                                title = opt->second;
105
106                        if ((opt = miscParams->find("left")) != end)
107                                mLeft = StringConverter::parseInt(opt->second);
108
109                        if ((opt = miscParams->find("top")) != end)
110                                mTop = StringConverter::parseInt(opt->second);
111
112                        if ((opt = miscParams->find("depthBuffer")) != end)
113                                mIsDepthBuffered = StringConverter::parseBool(opt->second);
114
115                        if ((opt = miscParams->find("vsync")) != end)
116                                vsync = StringConverter::parseBool(opt->second);
117
118                        if ((opt = miscParams->find("FSAA")) != end)
119                                fsaa = StringConverter::parseUnsignedInt(opt->second);
120
121                        if ((opt = miscParams->find("externalWindowHandle")) != end)
122                        {
123                                mHWnd = (HWND)StringConverter::parseUnsignedInt(opt->second);
124                                if (mHWnd)
125                                {
126                                        mIsExternal = true;
127                                        mIsFullScreen = false;
128                                }
129
130                                if ((opt = miscParams->find("externalGLControl")) != end) {
131                                  mIsExternalGLControl = StringConverter::parseBool(opt->second);
132                                }
133                        }
134                        if ((opt = miscParams->find("externalGLContext")) != end)
135                        {
136                                mGlrc = (HGLRC)StringConverter::parseUnsignedLong(opt->second);
137                                if( mGlrc )
138                                        mIsExternalGLContext = true;
139                        }
140
141                        // window border style
142                        opt = miscParams->find("border");
143                        if(opt != miscParams->end())
144                                border = opt->second;
145                        // set outer dimensions?
146                        opt = miscParams->find("outerDimensions");
147                        if(opt != miscParams->end())
148                                outerSize = StringConverter::parseBool(opt->second);
149
150                        // only available with fullscreen
151                        if ((opt = miscParams->find("displayFrequency")) != end)
152                                mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
153                        if ((opt = miscParams->find("colourDepth")) != end)
154                                mColourDepth = StringConverter::parseUnsignedInt(opt->second);
155
156                        // incompatible with fullscreen
157                        if ((opt = miscParams->find("parentWindowHandle")) != end)
158                                parent = (HWND)StringConverter::parseUnsignedInt(opt->second);
159                }
160
161                if (!mIsExternal)
162                {
163                        DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
164                        DWORD dwStyleEx = 0;
165                        int outerw, outerh;
166
167                        if (mIsFullScreen)
168                        {
169                                dwStyle |= WS_POPUP;
170                                dwStyleEx |= WS_EX_TOPMOST;
171                                outerw = mWidth;
172                                outerh = mHeight;
173                                mLeft = mTop = 0;
174                        }
175                        else
176                        {
177                                if (parent)
178                                {
179                                        dwStyle |= WS_CHILD;
180                                }
181                                else
182                                {
183                                        if (border == "none")
184                                                dwStyle |= WS_POPUP;
185                                        else if (border == "fixed")
186                                                dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
187                                                WS_SYSMENU | WS_MINIMIZEBOX;
188                                        else
189                                                dwStyle |= WS_OVERLAPPEDWINDOW;
190                                }
191
192                                int screenw = GetSystemMetrics(SM_CXSCREEN);
193                                int screenh = GetSystemMetrics(SM_CYSCREEN);
194
195                                if (!outerSize)
196                                {
197                                        // calculate overall dimensions for requested client area
198                                        RECT rc = { 0, 0, mWidth, mHeight };
199                                        AdjustWindowRect(&rc, dwStyle, false);
200
201                                        // clamp window dimensions to screen size
202                                        outerw = (rc.right-rc.left < screenw)? rc.right-rc.left : screenw;
203                                        outerh = (rc.bottom-rc.top < screenh)? rc.bottom-rc.top : screenh;
204                                }
205
206                                // center window if given negative coordinates
207                                if (mLeft < 0)
208                                        mLeft = (screenw - outerw) / 2;
209                                if (mTop < 0)
210                                        mTop = (screenh - outerh) / 2;
211
212                                // keep window contained in visible screen area
213                                if (mLeft > screenw - outerw)
214                                        mLeft = screenw - outerw;
215                                if (mTop > screenh - outerh)
216                                        mTop = screenh - outerh;
217                        }
218
219                        // register class and create window
220                        WNDCLASS wc = { CS_OWNDC, WindowEventUtilities::_WndProc, 0, 0, hInst,
221                                LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
222                                (HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "OgreGLWindow" };
223                        RegisterClass(&wc);
224
225                        // Pass pointer to self as WM_CREATE parameter
226                        mHWnd = CreateWindowEx(dwStyleEx, "OgreGLWindow", title.c_str(),
227                                dwStyle, mLeft, mTop, outerw, outerh, parent, 0, hInst, this);
228
229                        WindowEventUtilities::_addRenderWindow(this);
230
231                        StringUtil::StrStreamType str;
232                        str << "Created Win32Window '"
233                                << mName << "' : " << mWidth << "x" << mHeight
234                                << ", " << mColourDepth << "bpp";
235                        LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
236
237                        if (mIsFullScreen)
238                        {
239                                DEVMODE dm;
240                                dm.dmSize = sizeof(DEVMODE);
241                                dm.dmBitsPerPel = mColourDepth;
242                                dm.dmPelsWidth = mWidth;
243                                dm.dmPelsHeight = mHeight;
244                                dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
245                                if (mDisplayFrequency)
246                                {
247                                        dm.dmDisplayFrequency = mDisplayFrequency;
248                                        dm.dmFields |= DM_DISPLAYFREQUENCY;
249                                        if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
250                                        {
251                                                LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
252                                                dm.dmFields ^= DM_DISPLAYFREQUENCY;
253                                        }
254                                }
255                                if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
256                                        LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
257                        }
258                }
259
260                HDC old_hdc = wglGetCurrentDC();
261                HGLRC old_context = wglGetCurrentContext();
262
263                RECT rc;
264                // top and left represent outer window position
265                GetWindowRect(mHWnd, &rc);
266                mTop = rc.top;
267                mLeft = rc.left;
268                // width and height represent drawable area only
269                GetClientRect(mHWnd, &rc);
270                mWidth = rc.right;
271                mHeight = rc.bottom;
272
273                mHDC = GetDC(mHWnd);
274
275                if (!mIsExternalGLControl)
276                {
277                        if (!mGLSupport.selectPixelFormat(mHDC, mColourDepth, fsaa))
278                        {
279                                if (fsaa == 0)
280                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "selectPixelFormat failed", "Win32Window::create");
281
282                                LogManager::getSingleton().logMessage(LML_NORMAL, "FSAA level not supported, falling back");
283                                if (!mGLSupport.selectPixelFormat(mHDC, mColourDepth, 0))
284                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "selectPixelFormat failed", "Win32Window::create");
285                        }
286                }
287                if (!mIsExternalGLContext)
288                {
289                        mGlrc = wglCreateContext(mHDC);
290                        if (!mGlrc)
291                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "wglCreateContext", "Win32Window::create");
292                }
293                if (!wglMakeCurrent(mHDC, mGlrc))
294                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "wglMakeCurrent", "Win32Window::create");
295
296                // Do not change vsync if the external window has the OpenGL control
297                if (!mIsExternalGLControl) {
298                        // Don't use wglew as if this is the first window, we won't have initialised yet
299                        PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT = 
300                                (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
301                        if (_wglSwapIntervalEXT)
302                                _wglSwapIntervalEXT(vsync? 1 : 0);
303                }
304
305        if (old_context && old_context != mGlrc)
306        {
307            // Restore old context
308                    if (!wglMakeCurrent(old_hdc, old_context))
309                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "wglMakeCurrent() failed", "Win32Window::create");
310
311            // Share lists with old context
312                    if (!wglShareLists(old_context, mGlrc))
313                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "wglShareLists() failed", " Win32Window::create");
314        }
315
316                // Create RenderSystem context
317                mContext = new Win32Context(mHDC, mGlrc);
318
319                mActive = true;
320        }
321
322        void Win32Window::setFullscreen(bool fullScreen, unsigned int width, unsigned int height)
323        {
324                if (mIsFullScreen != fullScreen || width != mWidth || height != mHeight)
325                {
326                        mIsFullScreen = fullScreen;
327                        DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN;
328
329                        if (mIsFullScreen)
330                        {
331                                dwStyle |= WS_POPUP;
332
333                                DEVMODE dm;
334                                dm.dmSize = sizeof(DEVMODE);
335                                dm.dmBitsPerPel = mColourDepth;
336                                dm.dmPelsWidth = width;
337                                dm.dmPelsHeight = height;
338                                dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
339                                if (mDisplayFrequency)
340                                {
341                                        dm.dmDisplayFrequency = mDisplayFrequency;
342                                        dm.dmFields |= DM_DISPLAYFREQUENCY;
343                                        if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
344                                        {
345                                                LogManager::getSingleton().logMessage(LML_NORMAL, "ChangeDisplaySettings with user display frequency failed");
346                                                dm.dmFields ^= DM_DISPLAYFREQUENCY;
347                                        }
348                                }
349                                else
350                                {
351                                        // try a few
352                                        dm.dmDisplayFrequency = 100;
353                                        dm.dmFields |= DM_DISPLAYFREQUENCY;
354                                        if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
355                                        {
356                                                dm.dmDisplayFrequency = 75;
357                                                if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)
358                                                {
359                                                        dm.dmFields ^= DM_DISPLAYFREQUENCY;
360                                                }
361                                        }
362
363                                }
364                                if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
365                                        LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
366
367                                SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
368                                SetWindowPos(mHWnd, HWND_TOPMOST, 0, 0, width, height,
369                                        SWP_NOACTIVATE);
370                                mWidth = width;
371                                mHeight = height;
372
373
374                        }
375                        else
376                        {
377                                dwStyle |= WS_OVERLAPPEDWINDOW;
378
379                                // drop out of fullscreen
380                                ChangeDisplaySettings(NULL, 0);
381
382                                // calculate overall dimensions for requested client area
383                                RECT rc = { 0, 0, width, height };
384                                AdjustWindowRect(&rc, dwStyle, false);
385                                unsigned int winWidth = rc.right - rc.left;
386                                unsigned int winHeight = rc.bottom - rc.top;
387
388                                int screenw = GetSystemMetrics(SM_CXSCREEN);
389                                int screenh = GetSystemMetrics(SM_CYSCREEN);
390                                int left = (screenw - winWidth) / 2;
391                                int top = (screenh - winHeight) / 2;
392
393
394                                SetWindowLong(mHWnd, GWL_STYLE, dwStyle);
395                                SetWindowPos(mHWnd, HWND_NOTOPMOST, left, top, winWidth, winHeight,
396                                        SWP_DRAWFRAME | SWP_FRAMECHANGED | SWP_NOACTIVATE);
397                                mWidth = width;
398                                mHeight = height;
399
400                        }
401
402                }
403        }
404
405        void Win32Window::destroy(void)
406        {
407                if (!mHWnd)
408                        return;
409
410                // Unregister and destroy OGRE GLContext
411                delete mContext;
412
413                if (!mIsExternalGLContext && mGlrc)
414                {
415                        wglDeleteContext(mGlrc);
416                        mGlrc = 0;
417                }
418                if (!mIsExternal)
419                {
420                        WindowEventUtilities::_removeRenderWindow(this);
421
422                        if (mIsFullScreen)
423                                ChangeDisplaySettings(NULL, 0);
424                        DestroyWindow(mHWnd);
425                }
426                else
427                {
428                        // just release the DC
429                        ReleaseDC(mHWnd, mHDC);
430                }
431
432                mActive = false;
433                mClosed = true;
434                mHDC = 0; // no release thanks to CS_OWNDC wndclass style
435                mHWnd = 0;
436        }
437
438        bool Win32Window::isVisible() const
439        {
440                return (mHWnd && !IsIconic(mHWnd));
441        }
442
443        bool Win32Window::isClosed() const
444        {
445                return mClosed;
446        }
447
448        void Win32Window::reposition(int left, int top)
449        {
450                if (mHWnd && !mIsFullScreen)
451                {
452                        SetWindowPos(mHWnd, 0, left, top, 0, 0,
453                                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
454                }
455        }
456
457        void Win32Window::resize(unsigned int width, unsigned int height)
458        {
459                if (mHWnd && !mIsFullScreen)
460                {
461                        RECT rc = { 0, 0, width, height };
462                        AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
463                        width = rc.right - rc.left;
464                        height = rc.bottom - rc.top;
465                        SetWindowPos(mHWnd, 0, 0, 0, width, height,
466                                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
467                }
468        }
469
470        void Win32Window::windowMovedOrResized()
471        {
472                if (!isVisible())
473                        return;
474
475                RECT rc;
476                // top and left represent outer window position
477                GetWindowRect(mHWnd, &rc);
478                mTop = rc.top;
479                mLeft = rc.left;
480                // width and height represent drawable area only
481                GetClientRect(mHWnd, &rc);
482
483                if (mWidth == rc.right && mHeight == rc.bottom)
484                        return;
485
486                mWidth = rc.right;
487                mHeight = rc.bottom;
488
489                // Notify viewports of resize
490                ViewportList::iterator it, itend;
491                itend = mViewportList.end();
492                for( it = mViewportList.begin(); it != itend; ++it )
493                        (*it).second->_updateDimensions();
494        }
495
496        void Win32Window::swapBuffers(bool waitForVSync)
497        {
498          if (!mIsExternalGLControl) {
499                SwapBuffers(mHDC);
500          }
501        }
502
503        void Win32Window::writeContentsToFile(const String& filename)
504        {
505                ImageCodec::ImageData *imgData = new ImageCodec::ImageData();
506                imgData->width = mWidth;
507                imgData->height = mHeight;
508                imgData->depth = 1;
509                imgData->format = PF_BYTE_RGB;
510
511                // Allocate buffer
512                uchar* pBuffer = new uchar[mWidth * mHeight * 3];
513
514                // Switch context if different from current one
515                RenderSystem* rsys = Root::getSingleton().getRenderSystem();
516                rsys->_setViewport(this->getViewport(0));
517
518                // Must change the packing to ensure no overruns!
519                glPixelStorei(GL_PACK_ALIGNMENT, 1);
520
521                // Read pixels
522                // I love GL: it does all the locking & colour conversion for us
523                if (mIsFullScreen)
524                        glReadBuffer(GL_FRONT);
525                glReadPixels(0,0, mWidth, mHeight, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
526
527                // restore default alignment
528                glPixelStorei(GL_PACK_ALIGNMENT, 4);
529
530                // Wrap buffer in a memory stream
531                DataStreamPtr stream(new MemoryDataStream(pBuffer, mWidth * mHeight * 3, false));
532
533                // Need to flip the read data over in Y though
534                Image img;
535                img.loadRawData(stream, mWidth, mHeight, imgData->format );
536                img.flipAroundX();
537
538                MemoryDataStreamPtr streamFlipped(new MemoryDataStream(img.getData(), stream->size(), false));
539
540                // Get codec
541                size_t pos = filename.find_last_of(".");
542                String extension;
543                if( pos == String::npos )
544                        OGRE_EXCEPT(
545                        Exception::ERR_INVALIDPARAMS, 
546                        "Unable to determine image type for '" + filename + "' - invalid extension.",
547                        "Win32Window::writeContentsToFile" );
548
549                while( pos != filename.length() - 1 )
550                        extension += filename[++pos];
551
552                // Get the codec
553                Codec * pCodec = Codec::getCodec(extension);
554
555                // Write out
556                Codec::CodecDataPtr ptr(imgData);
557                pCodec->codeToFile(streamFlipped, filename, ptr);
558
559                delete [] pBuffer;
560        }
561
562        void Win32Window::getCustomAttribute( const String& name, void* pData )
563        {
564                if( name == "GLCONTEXT" ) {
565                        *static_cast<GLContext**>(pData) = mContext;
566                        return;
567                } else if( name == "WINDOW" )
568                {
569                        HWND *pHwnd = (HWND*)pData;
570                        *pHwnd = getWindowHandle();
571                        return;
572                } 
573        }
574
575        void Win32Window::setActive( bool state )
576        {
577                mActive = state;
578
579                if( mIsFullScreen )
580                {
581                        if( state == false )
582                        {       //Restore Desktop
583                                ChangeDisplaySettings(NULL, 0);
584                                ShowWindow(mHWnd, SW_SHOWMINNOACTIVE);
585                        }
586                        else
587                        {       //Restore App
588                                ShowWindow(mHWnd, SW_SHOWNORMAL);
589
590                                DEVMODE dm;
591                                dm.dmSize = sizeof(DEVMODE);
592                                dm.dmBitsPerPel = mColourDepth;
593                                dm.dmPelsWidth = mWidth;
594                                dm.dmPelsHeight = mHeight;
595                                dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
596                                if (mDisplayFrequency)
597                                {
598                                        dm.dmDisplayFrequency = mDisplayFrequency;
599                                        dm.dmFields |= DM_DISPLAYFREQUENCY;
600                                }
601                                ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
602                        }
603                }
604        }
605}
Note: See TracBrowser for help on using the repository browser.