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, 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 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 // TODO 00276 } 00277 00278 void Win32Window::swapBuffers(bool waitForVSync) 00279 { 00280 SwapBuffers(mHDC); 00281 } 00282 00283 void Win32Window::outputText(int x, int y, const String& text) 00284 { 00285 //deprecated 00286 } 00287 void Win32Window::writeContentsToFile(const String& filename) 00288 { 00289 ImageCodec::ImageData imgData; 00290 imgData.width = mWidth; 00291 imgData.height = mHeight; 00292 imgData.format = PF_R8G8B8; 00293 00294 // Allocate buffer 00295 uchar* pBuffer = new uchar[mWidth * mHeight * 3]; 00296 00297 // Read pixels 00298 // I love GL: it does all the locking & colour conversion for us 00299 glReadPixels(0,0, mWidth-1, mHeight-1, GL_RGB, GL_UNSIGNED_BYTE, pBuffer); 00300 00301 // Wrap buffer in a chunk 00302 DataChunk chunk(pBuffer, mWidth * mHeight * 3); 00303 00304 // Need to flip the read data over in Y though 00305 Image img; 00306 img.loadRawData(chunk, mWidth, mHeight, PF_R8G8B8 ); 00307 img.flipAroundX(); 00308 00309 DataChunk chunkFlipped(img.getData(), chunk.getSize()); 00310 00311 // Get codec 00312 size_t pos = filename.find_last_of("."); 00313 String extension; 00314 if( pos == String::npos ) 00315 Except( 00316 Exception::ERR_INVALIDPARAMS, 00317 "Unable to determine image type for '" + filename + "' - invalid extension.", 00318 "Win32Window::writeContentsToFile" ); 00319 00320 while( pos != filename.length() - 1 ) 00321 extension += filename[++pos]; 00322 00323 // Get the codec 00324 Codec * pCodec = Codec::getCodec(extension); 00325 00326 // Write out 00327 pCodec->codeToFile(chunkFlipped, filename, &imgData); 00328 00329 delete [] pBuffer; 00330 } 00331 00332 // Window procedure callback 00333 // This is a static member, so applies to all windows but we store the 00334 // Win32Window instance in the window data GetWindowLog/SetWindowLog 00335 LRESULT Win32Window::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 00336 { 00337 Win32Window* win; 00338 00339 // look up window instance 00340 if( WM_CREATE != uMsg ) 00341 win = (Win32Window*)GetWindowLong( hWnd, 0 ); 00342 00343 switch( uMsg ) 00344 { 00345 case WM_ACTIVATE: 00346 if( WA_INACTIVE == LOWORD( wParam ) ) 00347 win->mActive = false; 00348 else 00349 win->mActive = true; 00350 break; 00351 00352 case WM_CREATE: { 00353 // Log the new window 00354 // Get CREATESTRUCT 00355 LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam; 00356 win = (Win32Window*)(lpcs->lpCreateParams); 00357 // Store pointer in window user data area 00358 SetWindowLong( hWnd, 0, (long)win ); 00359 win->mActive = true; 00360 00361 return 0; } 00362 break; 00363 00364 case WM_PAINT: 00365 // If we get WM_PAINT messges, it usually means our window was 00366 // comvered up, so we need to refresh it by re-showing the contents 00367 // of the current frame. 00368 if( win->mActive && win->mReady ) 00369 win->update(); 00370 break; 00371 00372 case WM_MOVE: 00373 // Move messages need to be tracked to update the screen rects 00374 // used for blitting the backbuffer to the primary 00375 // *** This doesn't need to be used to Direct3D9 *** 00376 break; 00377 00378 case WM_ENTERSIZEMOVE: 00379 // Previent rendering while moving / sizing 00380 win->mReady = false; 00381 break; 00382 00383 case WM_EXITSIZEMOVE: 00384 win->WindowMovedOrResized(); 00385 win->mReady = true; 00386 break; 00387 00388 case WM_SIZE: 00389 // Check to see if we are losing or gaining our window. Set the 00390 // active flag to match 00391 if( SIZE_MAXHIDE == wParam || SIZE_MINIMIZED == wParam ) 00392 win->mActive = false; 00393 else 00394 { 00395 win->mActive = true; 00396 if( win->mReady ) 00397 win->WindowMovedOrResized(); 00398 } 00399 break; 00400 00401 case WM_GETMINMAXINFO: 00402 // Prevent the window from going smaller than some minimu size 00403 ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; 00404 ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; 00405 break; 00406 00407 case WM_CLOSE: 00408 DestroyWindow( win->mHWnd ); 00409 win->mClosed = true; 00410 return 0; 00411 } 00412 00413 return DefWindowProc( hWnd, uMsg, wParam, lParam ); 00414 } 00415 }
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:55 2004