00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <vlWin32/Win32Context.hpp>
00033 #include <vlCore/Log.hpp>
00034 #include <vlCore/Say.hpp>
00035
00036 using namespace vl;
00037 using namespace vlWin32;
00038
00039
00040 Win32Context::~Win32Context()
00041 {
00042 }
00043
00044 void Win32Context::shareOpenGLResources(HGLRC hGLRC)
00045 {
00046 if (hwnd() && mHDC && mHGLRC)
00047 wglShareLists(hglrc(), hGLRC);
00048 }
00049
00050 void Win32Context::makeCurrent()
00051 {
00052 if (mHDC && mHGLRC)
00053 wglMakeCurrent(mHDC, mHGLRC);
00054 }
00055
00056 void Win32Context::update()
00057 {
00058 if (hwnd())
00059 PostMessage(hwnd(), WM_PAINT, 0, 0);
00060 }
00061
00062 void Win32Context::quitApplication()
00063 {
00064 PostQuitMessage(0);
00065 }
00066
00067 void Win32Context::setMouseVisible(bool visible)
00068 {
00069 mMouseVisible = visible;
00070 if (visible)
00071 while(ShowCursor(TRUE ) < 0) {}
00072 else
00073 while(ShowCursor(FALSE) >= 0) {}
00074 }
00075
00076 void Win32Context::setPosition(int x, int y)
00077 {
00078 if (hwnd())
00079 SetWindowPos(hwnd(), 0, x, y, 0, 0, SWP_NOSIZE );
00080 }
00081
00082 void Win32Context::setSize(int w, int h)
00083 {
00084 if (hwnd())
00085 {
00086 RECT windowRect = { 0, 0, w, h };
00087 AdjustWindowRectEx(&windowRect, (DWORD)GetWindowLongPtr(hwnd(), GWL_STYLE), 0, (DWORD)GetWindowLongPtr(hwnd(), GWL_EXSTYLE) );
00088
00089 int cx = windowRect.right - windowRect.left;
00090 int cy = windowRect.bottom - windowRect.top;
00091 SetWindowPos(hwnd(), 0, 0, 0, cx, cy, SWP_NOMOVE );
00092 }
00093 }
00094
00095 void Win32Context::setWindowSize(int w, int h)
00096 {
00097
00098
00099
00100 SetWindowPos(hwnd(), 0, 0, 0, w, h, SWP_NOMOVE);
00101 }
00102
00103 vl::ivec2 Win32Context::position() const
00104 {
00105 RECT r = {0,0,0,0};
00106 if (hwnd())
00107 GetWindowRect(hwnd(), &r);
00108 return vl::ivec2(r.left,r.top);
00109 }
00110
00111 vl::ivec2 Win32Context::windowSize() const
00112 {
00113 RECT r = {0,0,0,0};
00114 if (hwnd())
00115 GetWindowRect(hwnd(), &r);
00116 return vl::ivec2(r.right - r.left, r.bottom - r.top);
00117 }
00118
00119 vl::ivec2 Win32Context::size() const
00120 {
00121 RECT r = {0,0,0,0};
00122 if (hwnd())
00123 GetClientRect(hwnd(), &r);
00124 return vl::ivec2(r.right - r.left, r.bottom - r.top);
00125
00126 }
00127
00128 void Win32Context::setWindowTitle(const String& title)
00129 {
00130 if (hwnd())
00131 SetWindowText(hwnd(), (wchar_t*)title.ptr());
00132 }
00133
00134 void Win32Context::show()
00135 {
00136 if (hwnd())
00137 ShowWindow(hwnd(), SW_SHOW);
00138 }
00139
00140 void Win32Context::hide()
00141 {
00142 if (hwnd())
00143 ShowWindow(hwnd(), SW_HIDE);
00144 }
00145
00146 void Win32Context::getFocus()
00147 {
00148 if (hwnd())
00149 SetFocus(hwnd());
00150 }
00151
00152 void Win32Context::setMousePosition(int x, int y)
00153 {
00154 if (hwnd())
00155 {
00156 POINT pt = {x, y};
00157 ClientToScreen( hwnd(), &pt );
00158 SetCursorPos(pt.x, pt.y);
00159 }
00160 }
00161
00162 void Win32Context::swapBuffers()
00163 {
00164 if(hwnd() && hdc())
00165 SwapBuffers(hdc());
00166 }
00167
00168 bool Win32Context::setFullscreen(bool fullscreen_on)
00169 {
00170 if (!hwnd())
00171 return false;
00172
00173 if (fullscreen_on == fullscreen())
00174 return true;
00175
00176 if (!fullscreen_on)
00177 {
00178 SetWindowLongPtr(hwnd(), GWL_STYLE, mNormFlags);
00179
00180 if (!((mNormFlags & WS_MAXIMIZE) || (mNormFlags & WS_MINIMIZE)))
00181 {
00182 setPosition(mNormPosit.x(),mNormPosit.y());
00183 setSize(mNormSize.x(), mNormSize.y());
00184 }
00185
00186 SetWindowPos(hwnd(), 0, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE);
00187
00188
00189 ChangeDisplaySettings(NULL, 0);
00190 }
00191 else
00192 {
00193 DEVMODE devmode;
00194 EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&devmode);
00195
00196
00197
00198
00199 devmode.dmBitsPerPel = openglContextInfo().bitsPerPixel();
00200 devmode.dmFields |= DM_BITSPERPEL;
00201
00202 mNormFlags = (unsigned int)GetWindowLongPtr(hwnd(), GWL_STYLE);
00203 mNormPosit = position();
00204 mNormSize = size();
00205
00206 switch( ChangeDisplaySettings(&devmode, CDS_FULLSCREEN) )
00207 {
00208 case DISP_CHANGE_SUCCESSFUL:
00209 {
00210 RECT windowRect = { 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight };
00211 SetWindowLongPtr(hwnd(), GWL_STYLE, WS_POPUP | WS_VISIBLE );
00212 AdjustWindowRectEx(&windowRect, (DWORD)GetWindowLongPtr(hwnd(), GWL_STYLE), 0, (DWORD)GetWindowLongPtr(hwnd(), GWL_EXSTYLE) );
00213 SetWindowPos(hwnd(), HWND_TOP, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_FRAMECHANGED );
00214 break;
00215 }
00216 #if(_WIN32_WINNT >= 0x0501)
00217 case DISP_CHANGE_BADDUALVIEW:
00218 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_BADDUALVIEW", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00219 return false;
00220 #endif
00221 case DISP_CHANGE_BADFLAGS:
00222 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_BADFLAGS", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00223 return false;
00224 case DISP_CHANGE_BADMODE:
00225 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_BADMODE", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00226 return false;
00227 case DISP_CHANGE_BADPARAM:
00228 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_BADPARAM", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00229 return false;
00230 case DISP_CHANGE_FAILED:
00231 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_FAILED", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00232 return false;
00233 case DISP_CHANGE_NOTUPDATED:
00234 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_NOTUPDATED", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00235 return false;
00236 case DISP_CHANGE_RESTART:
00237 MessageBox(NULL, L"Full-screen mode switch failed: DISP_CHANGE_RESTART", L"Win32Context::setFullscreen() error!", MB_OK | MB_ICONEXCLAMATION);
00238 return false;
00239 default:
00240 return false;
00241 }
00242 }
00243
00244 mFullscreen = fullscreen_on;
00245 update();
00246 return true;
00247 }
00248
00249 bool Win32Context::initWin32GLContext(HGLRC share_context, const vl::String& title, const vl::OpenGLContextFormat& fmt, int x, int y, int width, int height)
00250 {
00251 class InOutContract
00252 {
00253 Win32Context* mContext;
00254
00255 public:
00256 bool mOK;
00257
00258 InOutContract(Win32Context* context): mContext(context), mOK(true)
00259 {
00260 cleanup();
00261 }
00262
00263 ~InOutContract()
00264 {
00265 if (!mOK)
00266 cleanup();
00267 }
00268
00269 void cleanup()
00270 {
00271
00272 if (mContext->mHDC)
00273 {
00274 DeleteDC(mContext->mHDC);
00275 mContext->mHDC = NULL;
00276 }
00277
00278
00279 if (mContext->mHGLRC)
00280 {
00281 if ( wglDeleteContext(mContext->mHGLRC) == FALSE )
00282 {
00283 MessageBox(NULL, L"OpenGL context cleanup failed.\n"
00284 L"The handle either doesn't specify a valid context or the context is being used by another thread.",
00285 L"Win32Context::init() error!", MB_OK);
00286 mOK = false;
00287 }
00288 mContext->mHGLRC = NULL;
00289 }
00290 }
00291 } contract(this);
00292
00293 if (!contract.mOK)
00294 return false;
00295
00296 framebuffer()->setWidth(width);
00297 framebuffer()->setHeight(height);
00298
00299 if (!hwnd())
00300 {
00301 MessageBox(NULL, L"Cannot create OpenGL context: null HWND.", L"Win32Context::init() error!", MB_OK);
00302 return contract.mOK = false;
00303 }
00304
00305 setWindowTitle(title);
00306
00307 VL_CHECK(mHDC == NULL);
00308 mHDC = ::GetDC(hwnd());
00309 if (!mHDC)
00310 {
00311 MessageBox(NULL, L"Device context acquisition failed.", L"Win32Context::init() error!", MB_OK);
00312 return contract.mOK = false;
00313 }
00314
00315 int pixel_format_index = vlWin32::choosePixelFormat(fmt);
00316 if (pixel_format_index == -1)
00317 {
00318 MessageBox(NULL, L"No suitable pixel fmt found.", L"Win32Context::init() error!", MB_OK);
00319 return contract.mOK = false;
00320 }
00321
00322 if (SetPixelFormat(mHDC, pixel_format_index, NULL) == FALSE)
00323 {
00324 MessageBox(NULL, L"Pixel fmt setup failed.", L"Win32Context::init() error!", MB_OK);
00325 return contract.mOK = false;
00326 }
00327
00328
00329
00330 if (wglCreateContextAttribsARB && mContextAttribs.size() > 1)
00331 {
00332
00333 VL_CHECK(mContextAttribs.back() == 0);
00334
00335 mHGLRC = wglCreateContextAttribsARB(mHDC, 0, &mContextAttribs[0]);
00336 }
00337 else
00338 {
00339
00340 mHGLRC = wglCreateContext(mHDC);
00341 }
00342
00343 if (!mHGLRC)
00344 {
00345 MessageBox(NULL, L"OpenGL rendering context creation failed.", L"Win32Context::init() error!", MB_OK);
00346 return contract.mOK = false;
00347 }
00348
00349
00350
00351 if( !initGLContext() )
00352 return contract.mOK = false;
00353
00354 if (fmt.multisample() && !Has_GL_ARB_multisample)
00355 vl::Log::error("WGL_ARB_multisample not supported.\n");
00356
00357 dispatchInitEvent();
00358
00359 setPosition(x, y);
00360
00361 setSize(width, height);
00362
00363 if (Has_GL_EXT_swap_control)
00364 wglSwapIntervalEXT( fmt.vSync() ? 1 : 0 );
00365
00366 if (share_context)
00367 shareOpenGLResources(share_context);
00368
00369 if (fmt.fullscreen())
00370 setFullscreen(true);
00371
00372 return contract.mOK = true;
00373 }
00374
00375 void Win32Context::setContextAttribs(const int* attribs, int size)
00376 {
00377 mContextAttribs.resize(size);
00378 for(int i = 0; i < size; ++i)
00379 mContextAttribs[ i ] = attribs[ i ];
00380 }
00381
00382 namespace vlWin32
00383 {
00384 extern bool registerClass();
00385 extern const wchar_t* gWin32WindowClassName;
00386 }
00387
00388 int vlWin32::choosePixelFormat(const vl::OpenGLContextFormat& fmt, bool verbose)
00389 {
00390 if (!registerClass())
00391 return false;
00392
00393
00394
00395
00396 HWND hWnd = CreateWindowEx(
00397 WS_EX_APPWINDOW | WS_EX_ACCEPTFILES,
00398 gWin32WindowClassName,
00399 L"Temp GL Window",
00400 WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
00401 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
00402 NULL, NULL, GetModuleHandle(NULL), NULL);
00403
00404 if (!hWnd)
00405 {
00406 if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create window.", L"Visualization Library error", MB_OK);
00407 return -1;
00408 }
00409
00410 HDC hDC = GetDC(hWnd);
00411 if (!hDC)
00412 {
00413 if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create HDC.", L"Visualization Library error", MB_OK);
00414 DestroyWindow(hWnd);
00415 return -1;
00416 }
00417
00418 PIXELFORMATDESCRIPTOR pfd;
00419 memset(&pfd, 0, sizeof(pfd));
00420 pfd.nSize = sizeof(pfd);
00421 pfd.nVersion = 1;
00422 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
00423 pfd.dwFlags |= fmt.doubleBuffer() ? PFD_DOUBLEBUFFER : 0;
00424 pfd.dwFlags |= fmt.stereo() ? PFD_STEREO : 0;
00425 pfd.iPixelType = PFD_TYPE_RGBA;
00426 pfd.cColorBits = 0;
00427 pfd.cRedBits = (BYTE)fmt.rgbaBits().r();
00428 pfd.cGreenBits = (BYTE)fmt.rgbaBits().g();
00429 pfd.cBlueBits = (BYTE)fmt.rgbaBits().b();
00430 pfd.cAlphaBits = (BYTE)fmt.rgbaBits().a();
00431 pfd.cAccumRedBits = (BYTE)fmt.accumRGBABits().r();
00432 pfd.cAccumGreenBits = (BYTE)fmt.accumRGBABits().g();
00433 pfd.cAccumBlueBits = (BYTE)fmt.accumRGBABits().b();
00434 pfd.cAccumAlphaBits = (BYTE)fmt.accumRGBABits().a();
00435 pfd.cDepthBits = (BYTE)fmt.depthBufferBits();
00436 pfd.cStencilBits = (BYTE)fmt.stencilBufferBits();
00437 pfd.iLayerType = PFD_MAIN_PLANE;
00438
00439 int pixel_format_index = ChoosePixelFormat(hDC, &pfd);
00440
00441 if (pixel_format_index == 0)
00442 {
00443 if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not choose temporary format.", L"Visualization Library error", MB_OK);
00444 DeleteDC(hDC);
00445 DestroyWindow(hWnd);
00446 return -1;
00447 }
00448
00449 if (SetPixelFormat(hDC, pixel_format_index, &pfd) == FALSE)
00450 {
00451 if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not set temporary format.", L"Visualization Library error", MB_OK);
00452 DeleteDC(hDC);
00453 DestroyWindow(hWnd);
00454 return -1;
00455 }
00456
00457
00458 HGLRC hGLRC = wglCreateContext(hDC);
00459 if (!hGLRC)
00460 {
00461 if (verbose) MessageBox(NULL, L"choosePixelFormat() critical failure: could not create temporary OpenGL context.", L"Visualization Library error", MB_OK);
00462 DeleteDC(hDC);
00463 DestroyWindow(hWnd);
00464 return -1;
00465 }
00466
00467 wglMakeCurrent(hDC, hGLRC);
00468
00469 if (!initializeOpenGL())
00470 {
00471 fprintf(stderr, "Error initializing OpenGL!\n");
00472 DeleteDC(hDC);
00473 DestroyWindow(hWnd);
00474 return -1;
00475 }
00476
00477
00478
00479 int samples = 0;
00480 if(Has_WGL_ARB_pixel_format && fmt.multisample())
00481 {
00482 float fAttributes[] = { 0, 0 };
00483 int iAttributes[] =
00484 {
00485
00486 WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
00487 WGL_SAMPLES_ARB, -1,
00488
00489 WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
00490 WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
00491 WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
00492
00493 WGL_RED_BITS_ARB, pfd.cRedBits,
00494 WGL_GREEN_BITS_ARB, pfd.cGreenBits,
00495 WGL_BLUE_BITS_ARB, pfd.cBlueBits,
00496 WGL_ALPHA_BITS_ARB, pfd.cAlphaBits,
00497
00498 WGL_ACCUM_RED_BITS_ARB, pfd.cAccumRedBits,
00499 WGL_ACCUM_GREEN_BITS_ARB, pfd.cAccumGreenBits,
00500 WGL_ACCUM_BLUE_BITS_ARB, pfd.cAccumBlueBits,
00501 WGL_ACCUM_ALPHA_BITS_ARB, pfd.cAccumAlphaBits,
00502
00503 WGL_DEPTH_BITS_ARB, pfd.cDepthBits,
00504 WGL_DOUBLE_BUFFER_ARB, fmt.doubleBuffer() ? GL_TRUE : GL_FALSE,
00505
00506 WGL_STENCIL_BITS_ARB, pfd.cStencilBits,
00507
00508 WGL_STEREO_ARB, fmt.stereo() ? GL_TRUE : GL_FALSE,
00509 0,0
00510 };
00511
00512 for(samples = fmt.multisampleSamples(); samples > 1; samples/=2)
00513 {
00514
00515 iAttributes[3] = samples;
00516 pixel_format_index = -1;
00517 UINT num_formats = 0;
00518 if ( wglChoosePixelFormatARB(hDC,iAttributes,fAttributes,1,&pixel_format_index,&num_formats) && num_formats >= 1 )
00519 break;
00520 else
00521 pixel_format_index = -1;
00522 }
00523 }
00524
00525
00526 if ( wglDeleteContext(hGLRC) == FALSE )
00527 if (verbose) MessageBox(NULL, L"Error deleting temporary OpenGL context, wglDeleteContext(hGLRC) failed.", L"Visualization Library error", MB_OK);
00528 DeleteDC(hDC);
00529 DestroyWindow(hWnd);
00530
00531 if (verbose)
00532 {
00533 if(pixel_format_index == -1)
00534 vl::Log::error("No suitable pixel format found.\n");
00535 else
00536 {
00537
00538 #if defined(DEBUG) || !defined(NDEBUG)
00539 DescribePixelFormat(hDC, pixel_format_index, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
00540 vl::Log::debug(" --- vlWin32::choosePixelFormat() ---\n");
00541
00542
00543 vl::Log::debug( vl::Say("RGBA Bits = %n %n %n %n\n") << pfd.cRedBits << pfd.cGreenBits << pfd.cBlueBits << pfd.cAlphaBits);
00544 vl::Log::debug( vl::Say("Depth Bits = %n\n") << pfd.cDepthBits );
00545 vl::Log::debug( vl::Say("Stencil Bits = %n \n") << pfd.cStencilBits);
00546 vl::Log::debug( vl::Say("Double Buffer = %s\n") << (pfd.dwFlags & PFD_DOUBLEBUFFER ? "Yes" : "No") );
00547 vl::Log::debug( vl::Say("Stereo = %s\n") << (pfd.dwFlags & PFD_STEREO ? "Yes" : "No") );
00548 vl::Log::debug( vl::Say("Samples = %n\n") << samples );
00549 vl::Log::debug("\n");
00550 #endif
00551 }
00552 }
00553
00554 return pixel_format_index;
00555 }
00556