source: OGRE/trunk/ogrenew/RenderSystems/GL/src/OgreWin32Window.cpp @ 657

Revision 657, 14.6 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

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-2005 The OGRE Team
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-----------------------------------------------------------------------------
24*/
25
26#include "OgreWin32Window.h"
27#include "OgreRoot.h"
28#include "OgreLogManager.h"
29#include "OgreRenderSystem.h"
30#include "OgreImageCodec.h"
31#include "OgreStringConverter.h"
32#include "OgreException.h"
33#include "OgreWin32GLSupport.h"
34#include "OgreWin32Context.h"
35
36namespace Ogre {
37
38        Win32Window::Win32Window(Win32GLSupport &glsupport):
39                mGLSupport(glsupport),
40                mContext(0)
41        {
42                mIsFullScreen = false;
43                mHWnd = 0;
44                mIsExternal = false;
45                mSizing = false;
46                mClosed = false;
47                mDisplayFrequency = 0;
48                mActive = false;
49        }
50
51        Win32Window::~Win32Window()
52        {
53                destroy();
54        }
55
56        void Win32Window::create(const String& name, unsigned int width, unsigned int height,
57                                                        bool fullScreen, const NameValuePairList *miscParams)
58        {
59                // destroy current window, if any
60                if (mHWnd)
61                        destroy();
62
63                HINSTANCE hInst = GetModuleHandle("RenderSystem_GL.dll");
64
65                mHWnd = 0;
66                mName = name;
67                mIsFullScreen = fullScreen;
68                mClosed = false;
69
70                // load window defaults
71                mLeft = mTop = -1; // centered
72                mWidth = width;
73                mHeight = height;
74                mDisplayFrequency = 0;
75                mIsDepthBuffered = true;
76                mColourDepth = mIsFullScreen? 32 : GetDeviceCaps(GetDC(0), BITSPIXEL);
77
78                HWND parent = 0;
79                String title = name;
80                bool vsync = false;
81                int fsaa = 0;
82                String border = "";
83                bool outerSize = false;
84
85                if(miscParams)
86                {
87                        // Get variable-length params
88                        NameValuePairList::const_iterator opt;
89                        NameValuePairList::const_iterator end = miscParams->end();
90
91                        if ((opt = miscParams->find("title")) != end)
92                                title = opt->second;
93
94                        if ((opt = miscParams->find("left")) != end)
95                                mLeft = StringConverter::parseInt(opt->second);
96
97                        if ((opt = miscParams->find("top")) != end)
98                                mTop = StringConverter::parseInt(opt->second);
99
100                        if ((opt = miscParams->find("depthBuffer")) != end)
101                                mIsDepthBuffered = StringConverter::parseBool(opt->second);
102
103                        if ((opt = miscParams->find("vsync")) != end)
104                                vsync = StringConverter::parseBool(opt->second);
105
106                        if ((opt = miscParams->find("FSAA")) != end)
107                                fsaa = StringConverter::parseUnsignedInt(opt->second);
108
109                        if ((opt = miscParams->find("externalWindowHandle")) != end)
110                        {
111                                mHWnd = (HWND)StringConverter::parseUnsignedInt(opt->second);
112                                if (mHWnd)
113                                {
114                                        mIsExternal = true;
115                                        mIsFullScreen = false;
116                                }
117                        }
118                        // window border style
119                        opt = miscParams->find("border");
120                        if(opt != miscParams->end())
121                                border = opt->second;
122                        // set outer dimensions?
123                        opt = miscParams->find("outerDimensions");
124                        if(opt != miscParams->end())
125                                outerSize = StringConverter::parseBool(opt->second);
126
127                        if (mIsFullScreen)
128                        {
129                                // only available with fullscreen
130                                if ((opt = miscParams->find("displayFrequency")) != end)
131                                        mDisplayFrequency = StringConverter::parseUnsignedInt(opt->second);
132                                if ((opt = miscParams->find("colourDepth")) != end)
133                                        mColourDepth = StringConverter::parseUnsignedInt(opt->second);
134                        }
135                        else
136                        {
137                                // incompatible with fullscreen
138                                if ((opt = miscParams->find("parentWindowHandle")) != end)
139                                        parent = (HWND)StringConverter::parseUnsignedInt(opt->second);
140                        }
141                }
142
143                if (!mIsExternal)
144                {
145                        DWORD dwStyle = WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
146                        DWORD dwStyleEx = 0;
147                        int outerw, outerh;
148
149                        if (mIsFullScreen)
150                        {
151                                dwStyle |= WS_POPUP;
152                                dwStyleEx |= WS_EX_TOPMOST;
153                                outerw = mWidth;
154                                outerh = mHeight;
155                                mLeft = mTop = 0;
156                        }
157                        else
158                        {
159                                if (border == "none")
160                                        dwStyle |= WS_POPUP;
161                                else if (border == "fixed")
162                                        dwStyle |= WS_OVERLAPPED | WS_BORDER | WS_CAPTION |
163                                        WS_SYSMENU | WS_MINIMIZEBOX;
164                                else
165                                        dwStyle |= WS_OVERLAPPEDWINDOW;
166
167                                int screenw = GetSystemMetrics(SM_CXSCREEN);
168                                int screenh = GetSystemMetrics(SM_CYSCREEN);
169
170                                if (!outerSize)
171                                {
172                                        // calculate overall dimensions for requested client area
173                                        RECT rc = { 0, 0, mWidth, mHeight };
174                                        AdjustWindowRect(&rc, dwStyle, false);
175
176                                        // clamp window dimensions to screen size
177                                        outerw = (rc.right-rc.left < screenw)? rc.right-rc.left : screenw;
178                                        outerh = (rc.bottom-rc.top < screenh)? rc.bottom-rc.top : screenh;
179                                }
180
181                                // center window if given negative coordinates
182                                if (mLeft < 0)
183                                        mLeft = (screenw - outerw) / 2;
184                                if (mTop < 0)
185                                        mTop = (screenh - outerh) / 2;
186
187                                // keep window contained in visible screen area
188                                if (mLeft > screenw - outerw)
189                                        mLeft = screenw - outerw;
190                                if (mTop > screenh - outerh)
191                                        mTop = screenh - outerh;
192                        }
193
194                        // register class and create window
195                        WNDCLASS wc = { CS_OWNDC, WndProc, 0, 0, hInst,
196                                LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
197                                (HBRUSH)GetStockObject(BLACK_BRUSH), NULL, "OgreGLWindow" };
198                        RegisterClass(&wc);
199
200                        // Pass pointer to self as WM_CREATE parameter
201                        mHWnd = CreateWindowEx(dwStyleEx, "OgreGLWindow", title.c_str(),
202                                dwStyle, mLeft, mTop, outerw, outerh, parent, 0, hInst, this);
203
204                        StringUtil::StrStreamType str;
205                        str << "Created Win32Window '"
206                                << mName << "' : " << mWidth << "x" << mHeight
207                                << ", " << mColourDepth << "bpp";
208                        LogManager::getSingleton().logMessage(LML_NORMAL, str.str());
209
210                        if (mIsFullScreen)
211                        {
212                                DEVMODE dm;
213                                dm.dmSize = sizeof(DEVMODE);
214                                dm.dmBitsPerPel = mColourDepth;
215                                dm.dmPelsWidth = mWidth;
216                                dm.dmPelsHeight = mHeight;
217                                dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
218                                if (mDisplayFrequency)
219                                {
220                                        dm.dmDisplayFrequency = mDisplayFrequency;
221                                        dm.dmFields |= DM_DISPLAYFREQUENCY;
222                                }
223                                if (ChangeDisplaySettings(&dm, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
224                                        LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettings failed");
225                        }
226                }
227
228                HDC old_hdc = wglGetCurrentDC();
229                HGLRC old_context = wglGetCurrentContext();
230
231                RECT rc;
232                // top and left represent outer window position
233                GetWindowRect(mHWnd, &rc);
234                mTop = rc.top;
235                mLeft = rc.left;
236                // width and height represent drawable area only
237                GetClientRect(mHWnd, &rc);
238                mWidth = rc.right;
239                mHeight = rc.bottom;
240
241                mHDC = GetDC(mHWnd);
242
243                if (!mGLSupport.selectPixelFormat(mHDC, mColourDepth, fsaa))
244                {
245                        if (fsaa == 0)
246                                OGRE_EXCEPT(0, "selectPixelFormat failed", "Win32Window::create");
247
248                        LogManager::getSingleton().logMessage(LML_NORMAL, "FSAA level not supported, falling back");
249                        if (!mGLSupport.selectPixelFormat(mHDC, mColourDepth, 0))
250                                OGRE_EXCEPT(0, "selectPixelFormat failed", "Win32Window::create");
251                }
252
253                mGlrc = wglCreateContext(mHDC);
254                if (!mGlrc)
255                        OGRE_EXCEPT(0, "wglCreateContext", "Win32Window::create");
256                if (!wglMakeCurrent(mHDC, mGlrc))
257                        OGRE_EXCEPT(0, "wglMakeCurrent", "Win32Window::create");
258
259                wglSwapIntervalEXT(vsync? 1 : 0);
260
261        if (old_context)
262        {
263            // Restore old context
264                    if (!wglMakeCurrent(old_hdc, old_context))
265                            OGRE_EXCEPT(0, "wglMakeCurrent() failed", "Win32Window::create");
266
267            // Share lists with old context
268                    if (!wglShareLists(old_context, mGlrc))
269                            OGRE_EXCEPT(0, "wglShareLists() failed", " Win32Window::create");
270        }
271
272                // Create RenderSystem context
273                mContext = new Win32Context(mHDC, mGlrc);
274                // Register the context with the rendersystem and associate it with this window
275                GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
276                rs->_registerContext(this, mContext);
277
278                mActive = true;
279        }
280
281        void Win32Window::destroy(void)
282        {
283                if (!mHWnd)
284                        return;
285
286                // Unregister and destroy OGRE GLContext
287                if (mContext)
288                {
289                        GLRenderSystem *rs = static_cast<GLRenderSystem*>(Root::getSingleton().getRenderSystem());
290                        rs->_unregisterContext(this);
291                        delete mContext;
292                        mContext = 0;
293                }
294                if (mGlrc)
295                {
296                        wglDeleteContext(mGlrc);
297                        mGlrc = 0;
298                }
299                if (!mIsExternal)
300                {
301                        if (mIsFullScreen)
302                                ChangeDisplaySettings(NULL, 0);
303                        DestroyWindow(mHWnd);
304                }
305                mActive = false;
306                mHDC = 0; // no release thanks to CS_OWNDC wndclass style
307                mHWnd = 0;
308        }
309
310        bool Win32Window::isVisible() const
311        {
312                return (mHWnd && !IsIconic(mHWnd));
313        }
314
315        bool Win32Window::isClosed() const
316        {
317                return mClosed;
318        }
319
320        void Win32Window::reposition(int left, int top)
321        {
322                if (mHWnd && !mIsFullScreen)
323                {
324                        SetWindowPos(mHWnd, 0, left, top, 0, 0,
325                                SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
326                }
327        }
328
329        void Win32Window::resize(unsigned int width, unsigned int height)
330        {
331                if (mHWnd && !mIsFullScreen)
332                {
333                        RECT rc = { 0, 0, width, height };
334                        AdjustWindowRect(&rc, GetWindowLong(mHWnd, GWL_STYLE), false);
335                        width = rc.right - rc.left;
336                        height = rc.bottom - rc.top;
337                        SetWindowPos(mHWnd, 0, 0, 0, width, height,
338                                SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
339                }
340        }
341
342        void Win32Window::windowMovedOrResized()
343        {
344                if (!isVisible())
345                        return;
346
347                RECT rc;
348                // top and left represent outer window position
349                GetWindowRect(mHWnd, &rc);
350                mTop = rc.top;
351                mLeft = rc.left;
352                // width and height represent drawable area only
353                GetClientRect(mHWnd, &rc);
354
355                if (mWidth == rc.right && mHeight == rc.bottom)
356                        return;
357
358                mWidth = rc.right;
359                mHeight = rc.bottom;
360
361                // Notify viewports of resize
362                ViewportList::iterator it, itend;
363                itend = mViewportList.end();
364                for( it = mViewportList.begin(); it != itend; ++it )
365                        (*it).second->_updateDimensions();
366        }
367
368        void Win32Window::swapBuffers(bool waitForVSync)
369        {
370                SwapBuffers(mHDC);
371        }
372
373        void Win32Window::writeContentsToFile(const String& filename)
374        {
375                ImageCodec::ImageData *imgData = new ImageCodec::ImageData();
376                imgData->width = mWidth;
377                imgData->height = mHeight;
378                imgData->depth = 1;
379                imgData->format = PF_BYTE_RGB;
380
381                // Allocate buffer
382                uchar* pBuffer = new uchar[mWidth * mHeight * 3];
383
384                // Read pixels
385                // I love GL: it does all the locking & colour conversion for us
386                glReadPixels(0,0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
387
388                // Wrap buffer in a memory stream
389                DataStreamPtr stream(new MemoryDataStream(pBuffer, mWidth * mHeight * 3, false));
390
391                // Need to flip the read data over in Y though
392                Image img;
393                img.loadRawData(stream, mWidth, mHeight, imgData->format );
394                img.flipAroundX();
395
396                MemoryDataStreamPtr streamFlipped(new MemoryDataStream(img.getData(), stream->size(), false));
397
398                // Get codec
399                size_t pos = filename.find_last_of(".");
400                String extension;
401                if( pos == String::npos )
402                        OGRE_EXCEPT(
403                        Exception::ERR_INVALIDPARAMS,
404                        "Unable to determine image type for '" + filename + "' - invalid extension.",
405                        "Win32Window::writeContentsToFile" );
406
407                while( pos != filename.length() - 1 )
408                        extension += filename[++pos];
409
410                // Get the codec
411                Codec * pCodec = Codec::getCodec(extension);
412
413                // Write out
414                Codec::CodecDataPtr ptr(imgData);
415                pCodec->codeToFile(streamFlipped, filename, ptr);
416
417                delete [] pBuffer;
418        }
419
420#ifdef GTP_VISIBILITY_MODIFIED_OGRE
421        uchar *Win32Window::getBufferContents(int &dimx, int &dimy)
422        {
423                dimx = mWidth;
424                dimy = mHeight;
425               
426                // Allocate buffer
427                uchar* pBuffer = new uchar[mWidth * mHeight * 3];
428
429                // Read pixels
430                // I love GL: it does all the locking & colour conversion for us
431                glReadPixels(0, 0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
432
433                return pBuffer;
434        }
435#endif // GTP_VISIBILITY_MODIFIED_OGRE
436
437        // Window procedure callback
438        // This is a static member, so applies to all windows but we store the
439        // Win32Window instance in the window data GetWindowLog/SetWindowLog
440        LRESULT Win32Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
441        {
442
443                if (uMsg == WM_CREATE)
444                {
445                        // Store pointer to Win32Window in user data area
446                        SetWindowLong(hWnd, GWL_USERDATA,
447                                (LONG)(((LPCREATESTRUCT)lParam)->lpCreateParams));
448                        return 0;
449                }
450
451                // look up window instance
452                // note: it is possible to get a WM_SIZE before WM_CREATE
453                Win32Window* win = (Win32Window*)GetWindowLong(hWnd, GWL_USERDATA);
454                if (!win)
455                        return DefWindowProc(hWnd, uMsg, wParam, lParam);
456
457                switch( uMsg )
458                {
459                case WM_ACTIVATE:
460                        if (win->mIsFullScreen)
461                        {
462                                if (LOWORD(wParam) == WA_INACTIVE)
463                                {
464                                        win->mActive = false;
465                                        ChangeDisplaySettings(NULL, 0);
466                                        ShowWindow(hWnd, SW_SHOWMINNOACTIVE);
467                                }
468                                else
469                                {
470                                        win->mActive = true;
471                                        ShowWindow(hWnd, SW_SHOWNORMAL);
472
473                                        DEVMODE dm;
474                                        dm.dmSize = sizeof(DEVMODE);
475                                        dm.dmBitsPerPel = win->mColourDepth;
476                                        dm.dmPelsWidth = win->mWidth;
477                                        dm.dmPelsHeight = win->mHeight;
478                                        dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
479                                        if (win->mDisplayFrequency)
480                                        {
481                                                dm.dmDisplayFrequency = win->mDisplayFrequency;
482                                                dm.dmFields |= DM_DISPLAYFREQUENCY;
483                                        }
484                                        ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
485                                }
486                        }
487                        break;
488
489                case WM_ENTERSIZEMOVE:
490                        win->mSizing = true;
491                        break;
492
493                case WM_EXITSIZEMOVE:
494                        win->windowMovedOrResized();
495                        win->mSizing = false;
496                        break;
497
498                case WM_MOVE:
499                case WM_SIZE:
500                        if (!win->mSizing)
501                                win->windowMovedOrResized();
502                        break;
503
504                case WM_GETMINMAXINFO:
505                        // Prevent the window from going smaller than some minimu size
506                        ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
507                        ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
508                        break;
509
510                case WM_CLOSE:
511                        win->destroy(); // will call DestroyWindow
512                        win->mClosed = true;
513                        return 0;
514                }
515
516                return DefWindowProc( hWnd, uMsg, wParam, lParam );
517        }
518
519        void Win32Window::getCustomAttribute( const String& name, void* pData )
520        {
521                if( name == "HWND" )
522                {
523                        HWND *pHwnd = (HWND*)pData;
524                        *pHwnd = getWindowHandle();
525                        return;
526                }
527        }
528
529}
Note: See TracBrowser for help on using the repository browser.