Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreWin32Window.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 
00026 #include "OgreWin32Window.h"
00027 #include "OgreLogManager.h"
00028 #include "OgreRenderSystem.h"
00029 #include "OgreImageCodec.h"
00030 #include "OgreException.h"
00031 
00032 
00033 namespace Ogre {
00034 
00035     Win32Window::Win32Window()
00036     {
00037         mIsFullScreen = false;
00038         mHWnd = 0;
00039         mActive = false;
00040         mReady = false;
00041         mClosed = false;
00042         mExternalHandle = NULL;
00043     }
00044 
00045     Win32Window::~Win32Window()
00046     {
00047         destroy();
00048     }
00049 
00050     void Win32Window::create(const String& name, unsigned int width, unsigned int height, unsigned int colourDepth,
00051                            bool fullScreen, int left, int top, bool depthBuffer,
00052                            void* miscParam, ...)
00053     {
00054         HWND parentHWnd;
00055         HINSTANCE hInst = GetModuleHandle("RenderSystem_GL.dll");
00056         long tempPtr;
00057 
00058         // Get variable-length params
00059         // miscParam[0] = parent HWND
00060         // miscParam[1] = bool vsync
00061         // miscParam[2] = int displayFrequency
00062 
00063         va_list marker;
00064         va_start( marker, depthBuffer );
00065 
00066         tempPtr = va_arg( marker, long );
00067         Win32Window* parentRW = reinterpret_cast<Win32Window*>(tempPtr);
00068         if( parentRW == NULL )
00069             parentHWnd = 0;
00070         else
00071             parentHWnd = parentRW->getWindowHandle();
00072 
00073         tempPtr = va_arg( marker, long );
00074         bool vsync = (tempPtr != 0);
00075 
00076         tempPtr = va_arg( marker, long );
00077         unsigned int displayFrequency = static_cast<unsigned int>(tempPtr);
00078 
00079         va_end( marker );
00080 
00081         // Destroy current window if any
00082         if( mHWnd )
00083             destroy();
00084 
00085         if (fullScreen)
00086         {
00087             mColourDepth = colourDepth;
00088         }
00089         else 
00090         {
00091             // Get colour depth from display
00092             mColourDepth = GetDeviceCaps(GetDC(0), BITSPIXEL);
00093         }
00094 
00095         if (!mExternalHandle) {
00096             mWidth = width;
00097             mHeight = height;
00098             if (!fullScreen)
00099             {
00100                 if (!left && (unsigned)GetSystemMetrics(SM_CXSCREEN) > mWidth)
00101                 {
00102                     mLeft = (GetSystemMetrics(SM_CXSCREEN) / 2) - (mWidth / 2);
00103                 }
00104                 else
00105                 {
00106                     mLeft = left;
00107                 }
00108                 if (!top && (unsigned)GetSystemMetrics(SM_CYSCREEN) > mHeight)
00109                 {
00110                     mTop = (GetSystemMetrics(SM_CYSCREEN) / 2) - (mHeight / 2);
00111                 }
00112                 else
00113                 {
00114                     mTop = top;
00115                 }
00116             }
00117             else
00118             {
00119                 mTop = mLeft = 0;
00120             }
00121 
00122             // Register the window class
00123 
00124             WNDCLASS wndClass = { CS_HREDRAW | CS_VREDRAW, WndProc, 0, 4, hInst,
00125                 LoadIcon( NULL, IDI_APPLICATION ),
00126                 LoadCursor( NULL, IDC_ARROW ),
00127                 (HBRUSH)GetStockObject( BLACK_BRUSH ), NULL,
00128                 TEXT(name.c_str()) };
00129             RegisterClass( &wndClass );
00130 
00131             // Create our main window
00132             // Pass pointer to self
00133             HWND hWnd = CreateWindowEx(fullScreen?WS_EX_TOPMOST:0, TEXT(name.c_str()), TEXT(name.c_str()),
00134                 (fullScreen?WS_POPUP:WS_OVERLAPPEDWINDOW)|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, mLeft, mTop,
00135                 width, height, 0L, 0L, hInst, this);
00136             mHWnd = hWnd;
00137 
00138             RECT rc;
00139             GetClientRect(mHWnd,&rc);
00140             mWidth = rc.right;
00141             mHeight = rc.bottom;
00142 
00143             if (fullScreen) {
00144                 DEVMODE DevMode;
00145                 DevMode.dmSize = sizeof(DevMode);
00146                 DevMode.dmBitsPerPel = mColourDepth;
00147                 DevMode.dmPelsWidth = mWidth;
00148                 DevMode.dmPelsHeight = mHeight;
00149                 DevMode.dmDisplayFrequency = displayFrequency;
00150                 DevMode.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFREQUENCY;
00151                 if (ChangeDisplaySettings(&DevMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
00152                     LogManager::getSingleton().logMessage(LML_CRITICAL, "ChangeDisplaySettingsEx");
00153 
00154                 
00155             }
00156 
00157         }
00158         else {
00159             mHWnd = mExternalHandle;
00160             RECT rc;
00161             GetClientRect(mHWnd, &rc);
00162             mWidth = rc.right;
00163             mHeight = rc.bottom;
00164             mLeft = rc.left;
00165             mTop = rc.top;
00166         }
00167         ShowWindow(mHWnd, SW_SHOWNORMAL);
00168         UpdateWindow(mHWnd);
00169         mName = name;
00170         mIsDepthBuffered = depthBuffer;
00171         mIsFullScreen = fullScreen;
00172 
00173         
00174         HDC hdc = GetDC(mHWnd);
00175 
00176         LogManager::getSingleton().logMessage(
00177             LML_NORMAL, "Created Win32Window '%s' : %ix%i, %ibpp",
00178             mName.c_str(), mWidth, mHeight, mColourDepth );
00179 
00180         
00181         PIXELFORMATDESCRIPTOR pfd = {
00182             sizeof(PIXELFORMATDESCRIPTOR),
00183             1,
00184             PFD_DRAW_TO_WINDOW |
00185             PFD_SUPPORT_OPENGL |
00186             PFD_DOUBLEBUFFER,
00187             PFD_TYPE_RGBA,
00188             mColourDepth,
00189             0, 0, 0, 0, 0, 0,
00190             0,
00191             0,
00192             0,
00193             0, 0, 0, 0,
00194             32,                  // 32-bit depth-buffer (will be emulated in 16-bit colour mode)
00195             8,                   // 8-bit stencil buffer
00196             0,
00197             PFD_MAIN_PLANE,
00198             0,
00199             0, 0, 0};
00200         int iPixelFormat = ChoosePixelFormat(hdc, &pfd);
00201         if (!iPixelFormat)
00202             Except(0, "ChoosePixelFormat failed", "Win32Window::create");
00203         if (!SetPixelFormat(hdc, iPixelFormat, &pfd))
00204             Except(0, "SetPixelFormat failed", "Win32Window::create");
00205 
00206         HGLRC glrc = wglCreateContext(hdc);
00207         if (!glrc)
00208             Except(0, "wglCreateContext", "Win32Window::create");
00209         if (!wglMakeCurrent(hdc, glrc))
00210             Except(0, "wglMakeCurrent", "Win32Window::create");
00211         
00212         mGlrc = glrc;
00213         mHDC = hdc;
00214 
00215         mOldSwapIntervall = wglGetSwapIntervalEXT();
00216         if (vsync) 
00217             wglSwapIntervalEXT(1);
00218         else
00219             wglSwapIntervalEXT(0);
00220 
00221         mReady = true;
00222     }
00223 
00224     void Win32Window::destroy(void)
00225     {
00226         wglSwapIntervalEXT(mOldSwapIntervall);
00227         if (mGlrc) {
00228             wglMakeCurrent(NULL, NULL);
00229             wglDeleteContext(mGlrc);
00230             mGlrc = NULL;
00231         }
00232         if (mHDC) {
00233             ReleaseDC(mHWnd, mHDC);
00234             mHDC = NULL;
00235         }
00236         if (mIsFullScreen)
00237         {
00238             ChangeDisplaySettings(NULL, 0);
00239         }
00240     DestroyWindow(mHWnd);
00241         mActive = false;
00242     }
00243 
00244     bool Win32Window::isActive() const
00245     {
00246         return mActive;
00247     }
00248 
00249     bool Win32Window::isClosed() const
00250     {
00251         return mClosed;
00252     }
00253 
00254     void Win32Window::reposition(int left, int top)
00255     {
00256         // XXX FIXME
00257     }
00258 
00259     void Win32Window::resize(unsigned int width, unsigned int height)
00260     {
00261 
00262         mWidth = width;
00263         mHeight = height;
00264 
00265         // Notify viewports of resize
00266         ViewportList::iterator it, itend;
00267         itend = mViewportList.end();
00268         for( it = mViewportList.begin(); it != itend; ++it )
00269             (*it).second->_updateDimensions();
00270         // TODO - resize window
00271     }
00272 
00273     void Win32Window::windowMovedOrResized()
00274     {
00275         RECT temprect;
00276         ::GetClientRect(getWindowHandle(),&temprect);
00277         resize(temprect.right-temprect.left,temprect.bottom-temprect.top);
00278         // TODO
00279     }
00280 
00281     void Win32Window::swapBuffers(bool waitForVSync)
00282     {
00283         SwapBuffers(mHDC);
00284     }
00285 
00286     void Win32Window::writeContentsToFile(const String& filename)
00287     {
00288         ImageCodec::ImageData imgData;
00289         imgData.width = mWidth;
00290         imgData.height = mHeight;
00291         imgData.format = PF_R8G8B8;
00292 
00293         // Allocate buffer 
00294         uchar* pBuffer = new uchar[mWidth * mHeight * 3];
00295 
00296         // Read pixels
00297         // I love GL: it does all the locking & colour conversion for us
00298         glReadPixels(0,0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer);
00299 
00300         // Wrap buffer in a chunk
00301         DataChunk chunk(pBuffer, mWidth * mHeight * 3);
00302 
00303         // Need to flip the read data over in Y though
00304         Image img;
00305         img.loadRawData(chunk, mWidth, mHeight, PF_R8G8B8 );
00306         img.flipAroundX();
00307 
00308         DataChunk chunkFlipped(img.getData(), chunk.getSize());
00309 
00310         // Get codec 
00311         size_t pos = filename.find_last_of(".");
00312         String extension;
00313         if( pos == String::npos )
00314             Except(
00315             Exception::ERR_INVALIDPARAMS, 
00316             "Unable to determine image type for '" + filename + "' - invalid extension.",
00317             "Win32Window::writeContentsToFile" );
00318 
00319         while( pos != filename.length() - 1 )
00320             extension += filename[++pos];
00321 
00322         // Get the codec
00323         Codec * pCodec = Codec::getCodec(extension);
00324 
00325         // Write out
00326         pCodec->codeToFile(chunkFlipped, filename, &imgData);
00327 
00328         delete [] pBuffer;
00329     }
00330 
00331     // Window procedure callback
00332     // This is a static member, so applies to all windows but we store the
00333     // Win32Window instance in the window data GetWindowLog/SetWindowLog
00334     LRESULT Win32Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
00335     {
00336         Win32Window* win;
00337 
00338         // look up window instance
00339         if( WM_CREATE != uMsg )
00340             win = (Win32Window*)GetWindowLong( hWnd, 0 );
00341 
00342         switch( uMsg )
00343         {
00344         case WM_ACTIVATE:
00345             if( WA_INACTIVE == LOWORD( wParam ) )
00346                 win->mActive = false;
00347             else
00348                 win->mActive = true;
00349             break;
00350 
00351         case WM_CREATE: {
00352             // Log the new window
00353             // Get CREATESTRUCT
00354             LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
00355             win = (Win32Window*)(lpcs->lpCreateParams);
00356             // Store pointer in window user data area
00357             SetWindowLong( hWnd, 0, (long)win );
00358             win->mActive = true;
00359 
00360             return 0; }
00361             break;
00362 
00363         case WM_PAINT:
00364             // If we get WM_PAINT messges, it usually means our window was
00365             // comvered up, so we need to refresh it by re-showing the contents
00366             // of the current frame.
00367             if( win->mActive && win->mReady )
00368                 win->update();
00369             break;
00370 
00371         case WM_MOVE:
00372             // Move messages need to be tracked to update the screen rects
00373             // used for blitting the backbuffer to the primary
00374             // *** This doesn't need to be used to Direct3D9 ***
00375             break;
00376 
00377         case WM_ENTERSIZEMOVE:
00378             // Previent rendering while moving / sizing
00379             win->mReady = false;
00380             break;
00381 
00382         case WM_EXITSIZEMOVE:
00383             win->windowMovedOrResized();
00384             win->mReady = true;
00385             break;
00386 
00387         case WM_SIZE:
00388             // Check to see if we are losing or gaining our window.  Set the 
00389             // active flag to match
00390             if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam )
00391                 win->mActive = false;
00392             else
00393             {
00394                 win->mActive = true;
00395                 if( win->mReady )
00396                     win->windowMovedOrResized();
00397             }
00398             break;
00399 
00400         case WM_GETMINMAXINFO:
00401             // Prevent the window from going smaller than some minimu size
00402             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100;
00403             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100;
00404             break;
00405 
00406         case WM_CLOSE:
00407             DestroyWindow( win->mHWnd );
00408             win->mClosed = true;
00409             return 0;
00410         }
00411 
00412         return DefWindowProc( hWnd, uMsg, wParam, lParam );
00413     }
00414 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:51 2004