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