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_ICON1" ), 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, left, top, 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 else { 00157 mHWnd = mExternalHandle; 00158 RECT rc; 00159 GetClientRect(mHWnd, &rc); 00160 mWidth = rc.right; 00161 mHeight = rc.bottom; 00162 mLeft = rc.left; 00163 mTop = rc.top; 00164 } 00165 ShowWindow(mHWnd, SW_SHOWNORMAL); 00166 UpdateWindow(mHWnd); 00167 mName = name; 00168 mIsDepthBuffered = depthBuffer; 00169 mIsFullScreen = fullScreen; 00170 00171 /*if (!vsync) { 00172 mOldSwapIntervall = wglGetSwapIntervalEXT(); 00173 wglSwapIntervalEXT(0); 00174 } 00175 else 00176 mOldSwapIntervall = -1;*/ 00177 HDC hdc = GetDC(mHWnd); 00178 00179 LogManager::getSingleton().logMessage( 00180 LML_NORMAL, "Created Win32Window '%s' : %ix%i, %ibpp", 00181 mName.c_str(), mWidth, mHeight, mColourDepth ); 00182 00183 PIXELFORMATDESCRIPTOR pfd = { 00184 sizeof(PIXELFORMATDESCRIPTOR), 00185 1, 00186 PFD_DRAW_TO_WINDOW | 00187 PFD_SUPPORT_OPENGL | 00188 PFD_DOUBLEBUFFER, 00189 PFD_TYPE_RGBA, 00190 mColourDepth, 00191 0, 0, 0, 0, 0, 0, 00192 0, 00193 0, 00194 0, 00195 0, 0, 0, 0, 00196 32, // 32-bit z-buffer 00197 0, // no stencil buffer 00198 0, 00199 PFD_MAIN_PLANE, 00200 0, 00201 0, 0, 0}; 00202 int iPixelFormat = ChoosePixelFormat(hdc, &pfd); 00203 if (!iPixelFormat) 00204 Except(0, "ChoosePixelFormat failed", "Win32Window::create"); 00205 if (!SetPixelFormat(hdc, iPixelFormat, &pfd)) 00206 Except(0, "SetPixelFormat failed", "Win32Window::create"); 00207 00208 HGLRC glrc = wglCreateContext(hdc); 00209 if (!glrc) 00210 Except(0, "wglCreateContext", "Win32Window::create"); 00211 if (!wglMakeCurrent(hdc, glrc)) 00212 Except(0, "wglMakeCurrent", "Win32Window::create"); 00213 00214 mGlrc = glrc; 00215 mHDC = hdc; 00216 00217 mReady = true; 00218 } 00219 00220 void Win32Window::destroy(void) 00221 { 00222 if (mGlrc) { 00223 wglMakeCurrent(NULL, NULL); 00224 wglDeleteContext(mGlrc); 00225 mGlrc = NULL; 00226 } 00227 if (mHDC) { 00228 ReleaseDC(mHWnd, mHDC); 00229 mHDC = NULL; 00230 } 00231 /*if (mOldSwapIntervall >= 0) 00232 wglSwapIntervalEXT(mOldSwapIntervall);*/ 00233 if (mIsFullScreen) 00234 ChangeDisplaySettings(NULL, 0); 00235 DestroyWindow(mHWnd); 00236 mActive = false; 00237 } 00238 00239 bool Win32Window::isActive() const 00240 { 00241 return mActive; 00242 } 00243 00244 bool Win32Window::isClosed() const 00245 { 00246 return mClosed; 00247 } 00248 00249 void Win32Window::reposition(int left, int top) 00250 { 00251 // XXX FIXME 00252 } 00253 00254 void Win32Window::resize(unsigned int width, unsigned int height) 00255 { 00256 00257 mWidth = width; 00258 mHeight = height; 00259 00260 // Notify viewports of resize 00261 ViewportList::iterator it, itend; 00262 itend = mViewportList.end(); 00263 for( it = mViewportList.begin(); it != itend; ++it ) 00264 (*it).second->_updateDimensions(); 00265 // TODO - resize window 00266 } 00267 00268 void Win32Window::WindowMovedOrResized() 00269 { 00270 // TODO 00271 } 00272 00273 void Win32Window::swapBuffers(bool waitForVSync) 00274 { 00275 SwapBuffers(mHDC); 00276 } 00277 00278 void Win32Window::outputText(int x, int y, const String& text) 00279 { 00280 //deprecated 00281 } 00282 void Win32Window::writeContentsToFile(const String& filename) 00283 { 00284 ImageCodec::ImageData imgData; 00285 imgData.width = mWidth; 00286 imgData.height = mHeight; 00287 imgData.format = PF_R8G8B8; 00288 00289 // Allocate buffer 00290 uchar* pBuffer = new uchar[mWidth * mHeight * 3]; 00291 00292 // Read pixels 00293 // I love GL: it does all the locking & colour conversion for us 00294 glReadPixels(0,0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer); 00295 00296 // Wrap buffer in a chunk 00297 DataChunk chunk(pBuffer, mWidth * mHeight * 3); 00298 00299 // Need to flip the read data over in Y though 00300 Image img; 00301 img.loadRawData(chunk, mWidth, mHeight, PF_R8G8B8 ); 00302 img.flipAroundX(); 00303 00304 DataChunk chunkFlipped(img.getData(), chunk.getSize()); 00305 00306 // Get codec 00307 size_t pos = filename.find_last_of("."); 00308 String extension; 00309 if( pos == String::npos ) 00310 Except( 00311 Exception::ERR_INVALIDPARAMS, 00312 "Unable to determine image type for '" + filename + "' - invalid extension.", 00313 "Win32Window::writeContentsToFile" ); 00314 00315 while( pos != filename.length() - 1 ) 00316 extension += filename[++pos]; 00317 00318 // Get the codec 00319 Codec * pCodec = Codec::getCodec(extension); 00320 00321 // Write out 00322 pCodec->codeToFile(chunkFlipped, filename, &imgData); 00323 00324 delete [] pBuffer; 00325 } 00326 00327 // Window procedure callback 00328 // This is a static member, so applies to all windows but we store the 00329 // Win32Window instance in the window data GetWindowLog/SetWindowLog 00330 LRESULT Win32Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 00331 { 00332 Win32Window* win; 00333 00334 // look up window instance 00335 if( WM_CREATE != uMsg ) 00336 win = (Win32Window*)GetWindowLong( hWnd, 0 ); 00337 00338 switch( uMsg ) 00339 { 00340 case WM_ACTIVATE: 00341 if( WA_INACTIVE == LOWORD( wParam ) ) 00342 win->mActive = false; 00343 else 00344 win->mActive = true; 00345 break; 00346 00347 case WM_CREATE: { 00348 // Log the new window 00349 // Get CREATESTRUCT 00350 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; 00351 win = (Win32Window*)(lpcs->lpCreateParams); 00352 // Store pointer in window user data area 00353 SetWindowLong( hWnd, 0, (long)win ); 00354 win->mActive = true; 00355 00356 return 0; } 00357 break; 00358 00359 case WM_PAINT: 00360 // If we get WM_PAINT messges, it usually means our window was 00361 // comvered up, so we need to refresh it by re-showing the contents 00362 // of the current frame. 00363 if( win->mActive && win->mReady ) 00364 win->update(); 00365 break; 00366 00367 case WM_MOVE: 00368 // Move messages need to be tracked to update the screen rects 00369 // used for blitting the backbuffer to the primary 00370 // *** This doesn't need to be used to Direct3D9 *** 00371 break; 00372 00373 case WM_ENTERSIZEMOVE: 00374 // Previent rendering while moving / sizing 00375 win->mReady = false; 00376 break; 00377 00378 case WM_EXITSIZEMOVE: 00379 win->WindowMovedOrResized(); 00380 win->mReady = true; 00381 break; 00382 00383 case WM_SIZE: 00384 // Check to see if we are losing or gaining our window. Set the 00385 // active flag to match 00386 if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam ) 00387 win->mActive = false; 00388 else 00389 { 00390 win->mActive = true; 00391 if( win->mReady ) 00392 win->WindowMovedOrResized(); 00393 } 00394 break; 00395 00396 case WM_GETMINMAXINFO: 00397 // Prevent the window from going smaller than some minimu size 00398 ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; 00399 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; 00400 break; 00401 00402 case WM_CLOSE: 00403 DestroyWindow( win->mHWnd ); 00404 win->mClosed = true; 00405 return 0; 00406 } 00407 00408 return DefWindowProc( hWnd, uMsg, wParam, lParam ); 00409 } 00410 }
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:32 2004