00001
00002
00003
00004
00005 #include "aglWindow.h"
00006
00007 #include "aglEventHandler.h"
00008 #include "global.h"
00009
00010 namespace eq
00011 {
00012
00013 AGLWindow::AGLWindow( Window* parent )
00014 : AGLWindowIF( parent )
00015 , _aglContext( 0 )
00016 , _carbonWindow( 0 )
00017 , _aglPBuffer( 0 )
00018 {
00019 }
00020
00021 AGLWindow::~AGLWindow( )
00022 {
00023 }
00024
00025 void AGLWindow::configExit( )
00026 {
00027 WindowRef window = getCarbonWindow();
00028 setCarbonWindow( 0 );
00029
00030 AGLPbuffer pbuffer = getAGLPBuffer();
00031 setAGLPBuffer( 0 );
00032
00033 if( window )
00034 {
00035 Global::enterCarbon();
00036 DisposeWindow( window );
00037 Global::leaveCarbon();
00038 }
00039 if( pbuffer )
00040 aglDestroyPBuffer( pbuffer );
00041
00042 AGLContext context = getAGLContext();
00043 if( context )
00044 {
00045 Global::enterCarbon();
00046 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) != ON )
00047 {
00048 #ifdef LEOPARD
00049 aglSetWindowRef( context, 0 );
00050 #else
00051 aglSetDrawable( context, 0 );
00052 #endif
00053 }
00054
00055 aglSetCurrentContext( 0 );
00056 aglDestroyContext( context );
00057 Global::leaveCarbon();
00058 setAGLContext( 0 );
00059 }
00060
00061 EQINFO << "Destroyed AGL window and context" << std::endl;
00062 }
00063
00064 void AGLWindow::makeCurrent() const
00065 {
00066 aglSetCurrentContext( _aglContext );
00067 }
00068
00069 void AGLWindow::swapBuffers()
00070 {
00071 aglSwapBuffers( _aglContext );
00072 }
00073
00074 bool AGLWindow::processEvent( const AGLWindowEvent& event )
00075 {
00076 if( event.type == Event::EXPOSE && _aglContext )
00077 aglUpdateContext( _aglContext );
00078
00079 return AGLWindowIF::processEvent( event );
00080 }
00081
00082 void AGLWindow::setAGLContext( AGLContext context )
00083 {
00084 _aglContext = context;
00085 }
00086
00087
00088
00089
00090
00091 bool AGLWindow::configInit( )
00092 {
00093 AGLPixelFormat pixelFormat = chooseAGLPixelFormat();
00094 if( !pixelFormat )
00095 return false;
00096
00097 AGLContext context = createAGLContext( pixelFormat );
00098 destroyAGLPixelFormat ( pixelFormat );
00099 setAGLContext( context );
00100 makeCurrent();
00101
00102 if( !context )
00103 return false;
00104
00105 return configInitAGLDrawable();
00106 }
00107
00108 AGLPixelFormat AGLWindow::chooseAGLPixelFormat()
00109 {
00110 Pipe* pipe = getPipe();
00111 EQASSERT( pipe );
00112
00113 CGDirectDisplayID displayID = pipe->getCGDisplayID();
00114
00115 Global::enterCarbon();
00116
00117 #ifdef LEOPARD
00118 CGOpenGLDisplayMask glDisplayMask =
00119 CGDisplayIDToOpenGLDisplayMask( displayID );
00120 #else
00121 GDHandle displayHandle = 0;
00122
00123 DMGetGDeviceByDisplayID( (DisplayIDType)displayID, &displayHandle, false );
00124
00125 if( !displayHandle )
00126 {
00127 _window->setErrorMessage( "Can't get display handle" );
00128 Global::leaveCarbon();
00129 return 0;
00130 }
00131 #endif
00132
00133
00134 std::vector<GLint> attributes;
00135
00136 attributes.push_back( AGL_RGBA );
00137 attributes.push_back( GL_TRUE );
00138 attributes.push_back( AGL_ACCELERATED );
00139 attributes.push_back( GL_TRUE );
00140
00141 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON &&
00142 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW )
00143
00144 attributes.push_back( AGL_FULLSCREEN );
00145
00146 #ifdef LEOPARD
00147 attributes.push_back( AGL_DISPLAY_MASK );
00148 attributes.push_back( glDisplayMask );
00149 #endif
00150
00151 const int colorSize = getIAttribute( Window::IATTR_PLANES_COLOR );
00152 if( colorSize > 0 || colorSize == AUTO )
00153 {
00154 const GLint size = colorSize > 0 ? colorSize : 8;
00155
00156 attributes.push_back( AGL_RED_SIZE );
00157 attributes.push_back( size );
00158 attributes.push_back( AGL_GREEN_SIZE );
00159 attributes.push_back( size );
00160 attributes.push_back( AGL_BLUE_SIZE );
00161 attributes.push_back( size );
00162 }
00163 const int alphaSize = getIAttribute( Window::IATTR_PLANES_ALPHA );
00164 if( alphaSize > 0 || alphaSize == AUTO )
00165 {
00166 attributes.push_back( AGL_ALPHA_SIZE );
00167 attributes.push_back( alphaSize>0 ? alphaSize : 8 );
00168 }
00169 const int depthSize = getIAttribute( Window::IATTR_PLANES_DEPTH );
00170 if( depthSize > 0 || depthSize == AUTO )
00171 {
00172 attributes.push_back( AGL_DEPTH_SIZE );
00173 attributes.push_back( depthSize>0 ? depthSize : 24 );
00174 }
00175 const int stencilSize = getIAttribute( Window::IATTR_PLANES_STENCIL );
00176 if( stencilSize > 0 || stencilSize == AUTO )
00177 {
00178 attributes.push_back( AGL_STENCIL_SIZE );
00179 attributes.push_back( stencilSize>0 ? stencilSize : 1 );
00180 }
00181 const int accumSize = getIAttribute( Window::IATTR_PLANES_ACCUM );
00182 const int accumAlpha = getIAttribute( Window::IATTR_PLANES_ACCUM_ALPHA );
00183 if( accumSize >= 0 )
00184 {
00185 attributes.push_back( AGL_ACCUM_RED_SIZE );
00186 attributes.push_back( accumSize );
00187 attributes.push_back( AGL_ACCUM_GREEN_SIZE );
00188 attributes.push_back( accumSize );
00189 attributes.push_back( AGL_ACCUM_BLUE_SIZE );
00190 attributes.push_back( accumSize );
00191 attributes.push_back( AGL_ACCUM_ALPHA_SIZE );
00192 attributes.push_back( accumAlpha >= 0 ? accumAlpha : accumSize );
00193 }
00194 else if( accumAlpha >= 0 )
00195 {
00196 attributes.push_back( AGL_ACCUM_ALPHA_SIZE );
00197 attributes.push_back( accumAlpha );
00198 }
00199
00200 const int samplesSize = getIAttribute( Window::IATTR_PLANES_SAMPLES );
00201 if( samplesSize >= 0 )
00202 {
00203 attributes.push_back( AGL_SAMPLE_BUFFERS_ARB );
00204 attributes.push_back( 1 );
00205 attributes.push_back( AGL_SAMPLES_ARB );
00206 attributes.push_back( samplesSize );
00207 }
00208
00209 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == ON ||
00210 ( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
00211 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW ))
00212 {
00213 attributes.push_back( AGL_DOUBLEBUFFER );
00214 attributes.push_back( GL_TRUE );
00215 }
00216 if( getIAttribute( Window::IATTR_HINT_STEREO ) == ON )
00217 {
00218 attributes.push_back( AGL_STEREO );
00219 attributes.push_back( GL_TRUE );
00220 }
00221
00222 attributes.push_back( AGL_NONE );
00223
00224
00225 std::vector<int> backoffAttributes;
00226 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
00227 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW )
00228
00229 backoffAttributes.push_back( AGL_DOUBLEBUFFER );
00230
00231 if( stencilSize == AUTO )
00232 backoffAttributes.push_back( AGL_STENCIL_SIZE );
00233
00234
00235 AGLPixelFormat pixelFormat = 0;
00236 while( true )
00237 {
00238 #ifdef LEOPARD
00239 pixelFormat = aglCreatePixelFormat( &attributes.front( ));
00240 #else
00241 pixelFormat = aglChoosePixelFormat( &displayHandle, 1,
00242 &attributes.front( ));
00243 #endif
00244
00245 if( pixelFormat ||
00246 backoffAttributes.empty( ))
00247
00248 break;
00249
00250
00251 const GLint attribute = backoffAttributes.back();
00252 backoffAttributes.pop_back();
00253
00254 std::vector<GLint>::iterator iter = find( attributes.begin(),
00255 attributes.end(), attribute );
00256 EQASSERT( iter != attributes.end( ));
00257
00258 attributes.erase( iter, iter+2 );
00259 }
00260
00261 if( !pixelFormat )
00262 _window->setErrorMessage( "Could not find a matching pixel format" );
00263
00264 Global::leaveCarbon();
00265 return pixelFormat;
00266 }
00267
00268 void AGLWindow::destroyAGLPixelFormat( AGLPixelFormat pixelFormat )
00269 {
00270 if( !pixelFormat )
00271 return;
00272
00273 Global::enterCarbon();
00274 aglDestroyPixelFormat( pixelFormat );
00275 Global::leaveCarbon();
00276 }
00277
00278 AGLContext AGLWindow::createAGLContext( AGLPixelFormat pixelFormat )
00279 {
00280 if( !pixelFormat )
00281 {
00282 _window->setErrorMessage( "No pixel format given" );
00283 return 0;
00284 }
00285
00286 AGLContext shareCtx = 0;
00287 const Window* shareWindow = _window->getSharedContextWindow();
00288 if( shareWindow )
00289 {
00290 const OSWindow* shareOSWindow = shareWindow->getOSWindow();
00291
00292 EQASSERT( dynamic_cast< const AGLWindow* >( shareOSWindow ));
00293 const AGLWindow* shareAGLWindow = static_cast< const AGLWindow* >(
00294 shareOSWindow );
00295 shareCtx = shareAGLWindow->getAGLContext();
00296 }
00297
00298 Global::enterCarbon();
00299 AGLContext context = aglCreateContext( pixelFormat, shareCtx );
00300
00301 if( !context )
00302 {
00303 _window->setErrorMessage( "Could not create AGL context: " +
00304 aglGetError( ));
00305 Global::leaveCarbon();
00306 return 0;
00307 }
00308
00309
00310 if( getIAttribute( Window::IATTR_HINT_SWAPSYNC ) != AUTO )
00311 {
00312 const GLint vsync =
00313 ( getIAttribute( Window::IATTR_HINT_SWAPSYNC )==OFF ? 0 : 1 );
00314 aglSetInteger( context, AGL_SWAP_INTERVAL, &vsync );
00315 }
00316
00317 aglSetCurrentContext( context );
00318
00319 Global::leaveCarbon();
00320
00321 EQINFO << "Created AGL context " << context << std::endl;
00322 return context;
00323 }
00324
00325
00326 bool AGLWindow::configInitAGLDrawable()
00327 {
00328 if( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == PBUFFER )
00329 return configInitAGLPBuffer();
00330 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON )
00331 return configInitAGLFullscreen();
00332 else
00333 return configInitAGLWindow();
00334 }
00335
00336 bool AGLWindow::configInitAGLPBuffer()
00337 {
00338 AGLContext context = getAGLContext();
00339 if( !context )
00340 {
00341 _window->setErrorMessage( "No AGLContext set" );
00342 return false;
00343 }
00344
00345
00346 const PixelViewport pvp = _window->getPixelViewport();
00347 AGLPbuffer pbuffer;
00348 if( !aglCreatePBuffer( pvp.w, pvp.h, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA,
00349 0, &pbuffer ))
00350 {
00351 _window->setErrorMessage( "Could not create PBuffer: " + aglGetError());
00352 return false;
00353 }
00354
00355
00356 if( !aglSetPBuffer( context, pbuffer, 0, 0, aglGetVirtualScreen( context )))
00357 {
00358 _window->setErrorMessage( "aglSetPBuffer failed: " + aglGetError( ));
00359 return false;
00360 }
00361
00362 setAGLPBuffer( pbuffer );
00363 return true;
00364 }
00365
00366 bool AGLWindow::configInitAGLFullscreen()
00367 {
00368 AGLContext context = getAGLContext();
00369 if( !context )
00370 {
00371 _window->setErrorMessage( "No AGLContext set" );
00372 return false;
00373 }
00374
00375 Global::enterCarbon();
00376
00377 aglEnable( context, AGL_FS_CAPTURE_SINGLE );
00378
00379 const Pipe* pipe = getPipe();
00380 EQASSERT( pipe );
00381
00382 const PixelViewport& pipePVP = pipe->getPixelViewport();
00383 const PixelViewport& windowPVP = _window->getPixelViewport();
00384 const PixelViewport& pvp = pipePVP.isValid() ? pipePVP : windowPVP;
00385
00386 #if 1
00387 if( !aglSetFullScreen( context, pvp.w, pvp.h, 0, 0 ))
00388 EQWARN << "aglSetFullScreen to " << pvp << " failed: " << aglGetError()
00389 << std::endl;
00390 #else
00391 if( !aglSetFullScreen( context, 0, 0, 0, 0 ))
00392 EQWARN << "aglSetFullScreen failed: " << aglGetError() << std::endl;
00393 #endif
00394
00395 Global::leaveCarbon();
00396 _window->setPixelViewport( pvp );
00397 return true;
00398 }
00399
00400 bool AGLWindow::configInitAGLWindow()
00401 {
00402 AGLContext context = getAGLContext();
00403 if( !context )
00404 {
00405 _window->setErrorMessage( "No AGLContext set" );
00406 return false;
00407 }
00408
00409
00410 WindowAttributes winAttributes = kWindowStandardDocumentAttributes |
00411 kWindowStandardHandlerAttribute |
00412 kWindowInWindowMenuAttribute;
00413
00414 const PixelViewport pvp = _window->getPixelViewport();
00415 const bool decoration = (getIAttribute( Window::IATTR_HINT_DECORATION ) != OFF);
00416 const int32_t menuHeight = decoration ? EQ_AGL_MENUBARHEIGHT : 0 ;
00417 Rect windowRect = { pvp.y + menuHeight, pvp.x,
00418 pvp.y + pvp.h + menuHeight,
00419 pvp.x + pvp.w };
00420 WindowRef windowRef;
00421
00422 Global::enterCarbon();
00423 const OSStatus status = CreateNewWindow( kDocumentWindowClass,
00424 winAttributes,
00425 &windowRect, &windowRef );
00426 if( status != noErr )
00427 {
00428 _window->setErrorMessage( "Could not create carbon window: " + status );
00429 Global::leaveCarbon();
00430 return false;
00431 }
00432
00433
00434 const std::string& name = _window->getName();
00435 std::stringstream windowTitle;
00436
00437 if( name.empty( ))
00438 {
00439 windowTitle << "Equalizer";
00440 #ifndef NDEBUG
00441 windowTitle << " (" << getpid() << ")";
00442 #endif;
00443 }
00444 else
00445 windowTitle << name;
00446
00447 CFStringRef title = CFStringCreateWithCString( kCFAllocatorDefault,
00448 windowTitle.str().c_str(),
00449 kCFStringEncodingMacRoman );
00450 SetWindowTitleWithCFString( windowRef, title );
00451 CFRelease( title );
00452
00453 #ifdef LEOPARD
00454 if( !aglSetWindowRef( context, windowRef ))
00455 {
00456 _window->setErrorMessage( "aglSetWindowRef failed: " + aglGetError( ));
00457 Global::leaveCarbon();
00458 return false;
00459 }
00460 #else
00461 if( !aglSetDrawable( context, GetWindowPort( windowRef )))
00462 {
00463 _window->setErrorMessage( "aglSetDrawable failed: " + aglGetError( ));
00464 Global::leaveCarbon();
00465 return false;
00466 }
00467 #endif
00468
00469
00470 ShowWindow( windowRef );
00471 Global::leaveCarbon();
00472 setCarbonWindow( windowRef );
00473
00474 return true;
00475 }
00476
00477 void AGLWindow::setCarbonWindow( WindowRef window )
00478 {
00479 EQINFO << "set Carbon window " << window << std::endl;
00480
00481 if( _carbonWindow == window )
00482 return;
00483
00484 if( _carbonWindow )
00485 exitEventHandler();
00486 _carbonWindow = window;
00487
00488 if( !window )
00489 return;
00490
00491 initEventHandler();
00492
00493 Rect rect;
00494 Global::enterCarbon();
00495 if( GetWindowBounds( window, kWindowContentRgn, &rect ) == noErr )
00496 {
00497 PixelViewport pvp;
00498 pvp.x = rect.left;
00499 pvp.y = rect.top;
00500 pvp.w = rect.right - rect.left;
00501 pvp.h = rect.bottom - rect.top;
00502
00503 _window->setPixelViewport( pvp );
00504 }
00505 Global::leaveCarbon();
00506 }
00507
00508 void AGLWindow::setAGLPBuffer( AGLPbuffer pbuffer )
00509 {
00510 EQINFO << "set AGL PBuffer " << pbuffer << std::endl;
00511
00512 if( _aglPBuffer == pbuffer )
00513 return;
00514
00515 _aglPBuffer = pbuffer;
00516
00517 if( !pbuffer )
00518 return;
00519
00520 GLint w;
00521 GLint h;
00522 GLenum target;
00523 GLenum format;
00524 GLint maxLevel;
00525
00526 if( aglDescribePBuffer( pbuffer, &w, &h, &target, &format, &maxLevel ))
00527 {
00528 EQASSERT( target == GL_TEXTURE_RECTANGLE_EXT );
00529
00530 const PixelViewport pvp( 0, 0, w, h );
00531 _window->setPixelViewport( pvp );
00532 }
00533 }
00534
00535 void AGLWindow::initEventHandler()
00536 {
00537 AGLEventHandler* handler = AGLEventHandler::get();
00538 handler->registerWindow( this );
00539 }
00540
00541 void AGLWindow::exitEventHandler()
00542 {
00543 AGLEventHandler* handler = AGLEventHandler::get();
00544 handler->deregisterWindow( this );
00545 }
00546
00547 }