00001 #include "OSDLOpenGL.h"
00002
00003 #include "OSDLVideo.h"
00004 #include "OSDLUtils.h"
00005
00006
00007 #include "Ceylan.h"
00008
00009
00010 #ifdef OSDL_USES_CONFIG_H
00011 #include <OSDLConfig.h>
00012 #endif // OSDL_USES_CONFIG_H
00013
00014 #ifdef OSDL_HAVE_OPENGL
00015 #include "SDL_opengl.h"
00016 #endif // OSDL_HAVE_OPENGL
00017
00018
00019
00020 using std::string ;
00021
00022 #include <list>
00023 using std::list ;
00024
00025
00026 using namespace OSDL::Video::OpenGL ;
00027 using namespace OSDL::Video::OpenGL::GLU ;
00028
00029 using namespace Ceylan::Log ;
00030
00031
00032
00033
00034
00035
00036 #if CEYLAN_DETECTED_LITTLE_ENDIAN
00037
00038 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::RedMask = 0x000000ff ;
00039 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::GreenMask = 0x0000ff00 ;
00040 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::BlueMask = 0x00ff0000 ;
00041 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::AlphaMask = 0xff000000 ;
00042
00043
00044 #else // CEYLAN_DETECTED_LITTLE_ENDIAN
00045
00046 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::RedMask = 0xff000000 ;
00047 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::GreenMask = 0x00ff0000 ;
00048 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::BlueMask = 0x0000ff00 ;
00049 OSDL::Video::Pixels::ColorMask OSDL::Video::OpenGL::AlphaMask = 0x000000ff ;
00050
00051 #endif // CEYLAN_DETECTED_LITTLE_ENDIAN
00052
00053
00054
00055
00056 OpenGLException::OpenGLException( const std::string & reason ) throw() :
00057 VideoException( reason )
00058 {
00059
00060 }
00061
00062
00063 OpenGLException::~OpenGLException() throw()
00064 {
00065
00066 }
00067
00068
00069 const bool OpenGLContext::ContextCanBeLost =
00070 Ceylan::System::openGLContextsCanBeLost() ;
00071
00072 const bool OpenGLContext::ContextIsLostOnResize =
00073 Ceylan::System::openGLContextsLostOnResize() ;
00074
00075 const bool OpenGLContext::ContextIsLostOnApplicationSwitch =
00076 Ceylan::System::openGLContextsLostOnApplicationSwitch() ;
00077
00078 const bool OpenGLContext::ContextIsLostOnColorDepthChange =
00079 Ceylan::System::openGLContextsLostOnColorDepthChange() ;
00080
00081
00082
00083 const GLLength OpenGLContext::DefaultOrthographicWidth = 1000.0f ;
00084
00085 const GLCoordinate OpenGLContext::DefaultNearClippingPlaneFor2D = -1.0f ;
00086 const GLCoordinate OpenGLContext::DefaultFarClippingPlaneFor2D = 1.0f ;
00087 const GLCoordinate OpenGLContext::DefaultNearClippingPlaneFor3D = 1.0f ;
00088 const GLCoordinate OpenGLContext::DefaultFarClippingPlaneFor3D = 100000.0f ;
00089
00090
00091
00092 OpenGLContext::OpenGLContext( OpenGL::Flavour flavour )
00093 throw( OpenGLException ) :
00094 _flavour( OpenGL::None ),
00095 _redSize( 0 ),
00096 _greenSize( 0 ),
00097 _blueSize( 0 ),
00098 _viewportWidth( 0 ),
00099 _viewportHeight( 0 ),
00100 _projectionMode( Orthographic ),
00101 _projectionWidth( DefaultOrthographicWidth ),
00102 _nearClippingPlane( DefaultNearClippingPlaneFor2D ),
00103 _farClippingPlane( DefaultFarClippingPlaneFor2D )
00104 {
00105
00106 selectFlavour( flavour ) ;
00107
00108 }
00109
00110
00111
00112 OpenGLContext::~OpenGLContext() throw()
00113 {
00114
00115 }
00116
00117
00118
00119
00120 void OpenGLContext::selectFlavour( Flavour flavour
00121 ) throw( OpenGLException )
00122 {
00123
00124 _flavour = flavour ;
00125
00126 if ( VideoModule::IsDisplayInitialized() )
00127 LogPlug::warning(
00128 "OpenGLContext::selectFlavour : display is already initialized." ) ;
00129
00130 switch( flavour )
00131 {
00132
00133 case None:
00134
00135 return ;
00136 break ;
00137
00138 case OpenGLFor2D:
00139 set2DFlavour( ) ;
00140 break ;
00141
00142 case OpenGLFor3D:
00143 set3DFlavour( ) ;
00144 break ;
00145
00146 default:
00147 LogPlug::error(
00148 "OpenGLContext:selectFlavour : unknown flavour selected, "
00149 "defaulting to None." ) ;
00150 return ;
00151 break ;
00152
00153 }
00154
00155 }
00156
00157
00158
00159 void OpenGLContext::set2DFlavour() throw( OpenGLException )
00160 {
00161
00162
00163 setFullScreenAntialiasingStatus( true ) ;
00164
00165
00166
00167 setOrthographicProjection( DefaultOrthographicWidth,
00168 DefaultNearClippingPlaneFor2D, DefaultFarClippingPlaneFor2D ) ;
00169
00170 setDoubleBufferStatus( true ) ;
00171
00172 }
00173
00174
00175
00176 void OpenGLContext::set3DFlavour() throw( OpenGLException )
00177 {
00178
00179 setFullScreenAntialiasingStatus( true ) ;
00180
00181 setDoubleBufferStatus( true ) ;
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 LogPlug::warning( "OpenGLContext::set3DFlavour : not implemented yet." ) ;
00194
00195 }
00196
00197
00198
00199 void OpenGLContext::blank() throw( OpenGLException )
00200 {
00201
00202 LogPlug::warning( "OpenGLContext::blank not implemented yet." ) ;
00203
00204 }
00205
00206
00207
00208 void OpenGLContext::reload() throw( OpenGLException )
00209 {
00210
00211 LogPlug::warning( "OpenGLContext::blank not implemented yet." ) ;
00212
00213 }
00214
00215
00216
00217 Ceylan::Uint8 OpenGLContext::getColorDepth(
00218 OSDL::Video::BitsPerPixel & redSize,
00219 OSDL::Video::BitsPerPixel & greenSize,
00220 OSDL::Video::BitsPerPixel & blueSize )
00221 const throw( OpenGLException )
00222 {
00223
00224
00225
00226 int value ;
00227
00228 SDL_GL_GetAttribute( SDL_GL_RED_SIZE, & value ) ;
00229 redSize = static_cast<OSDL::Video::BitsPerPixel>( value ) ;
00230
00231 SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, & value ) ;
00232 greenSize = static_cast<OSDL::Video::BitsPerPixel>( value ) ;
00233
00234 SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, & value ) ;
00235 blueSize = static_cast<OSDL::Video::BitsPerPixel>( value ) ;
00236
00237 return redSize + greenSize + blueSize ;
00238
00239 }
00240
00241
00242 void OpenGLContext::setColorDepth( BitsPerPixel plannedBpp )
00243 throw( OpenGLException )
00244 {
00245
00246
00247
00248 int rgbSize[ 3 ] ;
00249
00250 switch( plannedBpp )
00251 {
00252
00253 case 8:
00254 rgbSize[0] = 3 ;
00255 rgbSize[1] = 3 ;
00256 rgbSize[2] = 2 ;
00257 break ;
00258
00259 case 15:
00260 case 16:
00261 rgbSize[0] = 5 ;
00262 rgbSize[1] = 5 ;
00263 rgbSize[2] = 5 ;
00264 break ;
00265
00266 default:
00267 rgbSize[0] = 8 ;
00268 rgbSize[1] = 8 ;
00269 rgbSize[2] = 8 ;
00270 break ;
00271 }
00272
00273 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, rgbSize[0] ) ;
00274 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, rgbSize[1] ) ;
00275 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, rgbSize[2] ) ;
00276
00277 }
00278
00279
00280 void OpenGLContext::setColorDepth(
00281 OSDL::Video::BitsPerPixel redSize,
00282 OSDL::Video::BitsPerPixel greenSize,
00283 OSDL::Video::BitsPerPixel blueSize )
00284 throw( OpenGLException )
00285 {
00286
00287 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, redSize ) ;
00288 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, greenSize ) ;
00289 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, blueSize ) ;
00290
00291 }
00292
00293
00294
00295 bool OpenGLContext::getDoubleBufferStatus() throw( OpenGLException )
00296 {
00297
00298 int value ;
00299
00300 if ( SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, & value ) != 0 )
00301 throw OpenGLException(
00302 "OpenGLContext::getDoubleBufferStatus : error occurred, "
00303 + Utils::getBackendLastError() ) ;
00304
00305 return ( value != 0 ) ;
00306
00307 }
00308
00309
00310 bool OpenGLContext::setDoubleBufferStatus( bool newStatus )
00311 throw( OpenGLException )
00312 {
00313
00314 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, newStatus ) ;
00315
00316 return getDoubleBufferStatus() ;
00317
00318 }
00319
00320
00321 void OpenGLContext::setShadingModel( ShadingModel newShadingModel )
00322 throw( OpenGLException )
00323 {
00324
00325 switch( newShadingModel )
00326 {
00327
00328 case Flat:
00329 glShadeModel( GL_FLAT ) ;
00330 break ;
00331
00332 case Smooth:
00333 glShadeModel( GL_SMOOTH ) ;
00334 break ;
00335
00336 default:
00337 throw OpenGLException( "OpenGLContext::setShadingModel : "
00338 "unknown shading model specified." ) ;
00339 break ;
00340
00341 }
00342
00343 switch ( glGetError() )
00344 {
00345
00346 case GL_NO_ERROR:
00347 break ;
00348
00349 case GL_INVALID_ENUM:
00350 throw OpenGLException( "OpenGLContext::setShadingModel : "
00351 "unexpected value for shading model." ) ;
00352 break ;
00353
00354 case GL_INVALID_OPERATION:
00355 throw OpenGLException( "OpenGLContext::setShadingModel : "
00356 "incorrectly executed between the execution of glBegin and "
00357 "the corresponding execution of glEnd." ) ;
00358 break ;
00359
00360 default:
00361 throw OpenGLException( "OpenGLContext::setShadingModel : "
00362 "unexpected error reported." ) ;
00363 break ;
00364
00365 }
00366
00367 }
00368
00369
00370 void OpenGLContext::setCullingStatus( bool newStatus ) throw()
00371 {
00372
00373 if ( newStatus )
00374 glEnable( GL_CULL_FACE ) ;
00375 else
00376 glDisable( GL_CULL_FACE ) ;
00377
00378 }
00379
00380
00381 void OpenGLContext::setCulling( CulledFacet culledFacet,
00382 FrontOrientation frontOrientation, bool autoEnable )
00383 throw( OpenGLException )
00384 {
00385
00386 switch( culledFacet )
00387 {
00388
00389 case Front:
00390 glCullFace( GL_FRONT ) ;
00391 break ;
00392
00393 case Back:
00394 glCullFace( GL_BACK ) ;
00395 break ;
00396
00397 case FrontAndBack:
00398 glCullFace( GL_FRONT_AND_BACK ) ;
00399 break ;
00400 }
00401
00402
00403 switch ( glGetError() )
00404 {
00405
00406 case GL_NO_ERROR:
00407 break ;
00408
00409 case GL_INVALID_ENUM:
00410 throw OpenGLException( "OpenGLContext::setCulling (facet) : "
00411 "unexpected culled facet selection." ) ;
00412 break ;
00413
00414 case GL_INVALID_OPERATION:
00415 throw OpenGLException( "OpenGLContext::setCulling (facet) : "
00416 "incorrectly executed between the execution of glBegin and "
00417 "the corresponding execution of glEnd." ) ;
00418 break ;
00419
00420 default:
00421 throw OpenGLException( "OpenGLContext::setCulling (facet) : "
00422 "unexpected error reported." ) ;
00423 break ;
00424
00425 }
00426
00427
00428 switch( frontOrientation )
00429 {
00430
00431 case Clockwise:
00432 glFrontFace( GL_CW ) ;
00433 break ;
00434
00435 case CounterClockwise:
00436 glFrontFace( GL_CCW ) ;
00437 break ;
00438
00439 }
00440
00441
00442 switch ( glGetError() )
00443 {
00444
00445 case GL_NO_ERROR:
00446 break ;
00447
00448 case GL_INVALID_ENUM:
00449 throw OpenGLException( "OpenGLContext::setCulling : (orientation)"
00450 "unexpected front orientation selection." ) ;
00451 break ;
00452
00453 case GL_INVALID_OPERATION:
00454 throw OpenGLException( "OpenGLContext::setCulling : (orientation)"
00455 "incorrectly executed between the execution of glBegin and "
00456 "the corresponding execution of glEnd." ) ;
00457 break ;
00458
00459 default:
00460 throw OpenGLException( "OpenGLContext::setCulling (orientation) : "
00461 "unexpected error reported." ) ;
00462 break ;
00463
00464 }
00465
00466
00467 if ( autoEnable )
00468 setCullingStatus( true ) ;
00469
00470 }
00471
00472
00473 void OpenGLContext::setFullScreenAntialiasingStatus( bool newStatus,
00474 Ceylan::Uint8 samplesPerPixelNumber ) throw( OpenGLException )
00475 {
00476
00477 if ( newStatus )
00478 {
00479 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS,
00480 1 ) ;
00481
00482 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES,
00483 samplesPerPixelNumber ) ;
00484
00485 }
00486 else
00487 {
00488 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 0 ) ;
00489 }
00490
00491 }
00492
00493
00494 void OpenGLContext::setDepthBufferStatus( bool newStatus ) throw()
00495 {
00496
00497 if ( newStatus )
00498 glEnable( GL_DEPTH_TEST ) ;
00499 else
00500 glDisable( GL_DEPTH_TEST ) ;
00501
00502 }
00503
00504
00505 void OpenGLContext::setDepthBufferSize( Ceylan::Uint8 bitsNumber,
00506 bool autoEnable ) throw( OpenGLException )
00507 {
00508
00509 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, bitsNumber ) ;
00510
00511 if ( autoEnable )
00512 setDepthBufferStatus( true ) ;
00513
00514 }
00515
00516
00517 void OpenGLContext::setViewPort( Length width, Length height,
00518 const TwoDimensional::Point2D & lowerLeftCorner ) throw( OpenGLException )
00519 {
00520
00521 _viewportWidth = width ;
00522 _viewportHeight = height ;
00523
00524 glViewport( lowerLeftCorner.getX(), lowerLeftCorner.getY(),
00525 width, height ) ;
00526
00527 switch ( glGetError() )
00528 {
00529
00530 case GL_NO_ERROR:
00531 break ;
00532
00533 case GL_INVALID_VALUE:
00534 throw OpenGLException( "OpenGLContext::setViewPort : "
00535 "either width or height is negative." ) ;
00536 break ;
00537
00538 case GL_INVALID_OPERATION:
00539 throw OpenGLException( "OpenGLContext::setViewPort : "
00540 "incorrectly executed between the execution of glBegin and "
00541 "the corresponding execution of glEnd." ) ;
00542 break ;
00543
00544 default:
00545 throw OpenGLException( "OpenGLContext::setViewPort : "
00546 "unexpected error reported." ) ;
00547 break ;
00548
00549 }
00550
00551
00552 updateProjection() ;
00553
00554 }
00555
00556
00557 void OpenGLContext::setOrthographicProjection( GLLength width,
00558 GLCoordinate near, GLCoordinate far ) throw ( OpenGLException )
00559 {
00560
00561 _projectionMode = Orthographic ;
00562 _projectionWidth = width ;
00563
00564 glMatrixMode( GL_PROJECTION ) ;
00565 glLoadIdentity() ;
00566
00567
00568
00569 GLCoordinate right = width / 2 ;
00570
00571
00572 GLCoordinate top = ( width * _viewportHeight ) / ( 2 * _viewportWidth ) ;
00573
00574 glOrtho( -right, right,
00575 -top, top,
00576 near, far ) ;
00577
00578 switch ( glGetError() )
00579 {
00580
00581 case GL_NO_ERROR:
00582 break ;
00583
00584 case GL_INVALID_OPERATION:
00585 throw OpenGLException( "OpenGLContext::setOrthographicProjection : "
00586 "incorrectly executed between the execution of glBegin and "
00587 "the corresponding execution of glEnd." ) ;
00588 break ;
00589
00590 default:
00591 LogPlug::warning( "OpenGLContext::setOrthographicProjection : "
00592 "unexpected error reported." ) ;
00593 break ;
00594
00595 }
00596
00597 }
00598
00599
00600 void OpenGLContext::clearViewport() throw( OpenGLException )
00601 {
00602
00603 glClear( GL_COLOR_BUFFER_BIT ) ;
00604
00605 switch ( glGetError() )
00606 {
00607
00608 case GL_NO_ERROR:
00609 break ;
00610
00611 case GL_INVALID_VALUE:
00612 throw OpenGLException( "OpenGLContext::clearViewport : "
00613 "invalid bit in specified clear mask." ) ;
00614 break ;
00615
00616 case GL_INVALID_OPERATION:
00617 throw OpenGLException( "OpenGLContext::clearViewport : "
00618 "incorrectly executed between the execution of glBegin and "
00619 "the corresponding execution of glEnd." ) ;
00620 break ;
00621
00622 default:
00623 LogPlug::warning( "OpenGLContext::clearViewport : "
00624 "unexpected error reported." ) ;
00625 break ;
00626
00627 }
00628
00629 }
00630
00631
00632 void OpenGLContext::clearDepthBuffer() throw( OpenGLException )
00633 {
00634
00635 glClear( GL_DEPTH_BUFFER_BIT ) ;
00636
00637 switch ( glGetError() )
00638 {
00639 case GL_NO_ERROR:
00640 break ;
00641
00642 case GL_INVALID_VALUE:
00643 throw OpenGLException( "OpenGLContext::clearDepthBuffer : "
00644 "invalid bit in specified clear mask." ) ;
00645 break ;
00646
00647 case GL_INVALID_OPERATION:
00648 throw OpenGLException( "OpenGLContext::clearDepthBuffer : "
00649 "incorrectly executed between the execution of glBegin and "
00650 "the corresponding execution of glEnd." ) ;
00651 break ;
00652
00653 default:
00654 LogPlug::warning( "OpenGLContext::clearDepthBuffer : "
00655 "unexpected error reported." ) ;
00656 break ;
00657
00658 }
00659
00660 }
00661
00662
00663 const string OpenGLContext::toString( Ceylan::VerbosityLevels level )
00664 const throw()
00665 {
00666
00667 std::list<string> res ;
00668
00669 res.push_back( "OpenGL context whose current selected flavour is "
00670 + ToString( _flavour ) + "." ) ;
00671
00672 OSDL::Video::BitsPerPixel redSize, greenSize, blueSize ;
00673
00674 BitsPerPixel bpp = getColorDepth( redSize, greenSize, blueSize ) ;
00675 res.push_back( "Overall bit per pixel is "
00676 + Ceylan::toNumericalString( bpp ) + "." ) ;
00677
00678 res.push_back( "Red component size : "
00679 + Ceylan::toNumericalString( redSize ) + " bits." ) ;
00680
00681 res.push_back( "Green component size : "
00682 + Ceylan::toNumericalString( greenSize ) + " bits." ) ;
00683
00684 res.push_back( "Blue component size : "
00685 + Ceylan::toNumericalString( blueSize ) + " bits." ) ;
00686
00687
00688
00689 return "Current OpenGL state is :" + Ceylan::formatStringList( res ) ;
00690
00691 }
00692
00693
00694 string OpenGLContext::ToString( OpenGL::Flavour flavour ) throw()
00695 {
00696
00697 switch( flavour )
00698 {
00699
00700 case OpenGL::None:
00701 return "no OpenGL" ;
00702 break ;
00703
00704 case OpenGL::OpenGLFor2D:
00705 return "OpenGL for 2D" ;
00706 break ;
00707
00708 case OpenGL::OpenGLFor3D:
00709 return "OpenGL for 3D" ;
00710 break ;
00711
00712 case OpenGL::Reload:
00713 return "reload OpenGL context" ;
00714 break ;
00715
00716 default:
00717 return "unknown flavour (" + Ceylan::toString( flavour )
00718 + "), which is abnormal)" ;
00719 break ;
00720
00721 }
00722
00723 }
00724
00725
00726
00727 void OpenGLContext::updateProjection() throw( OpenGLException )
00728 {
00729
00730 switch ( _projectionMode )
00731 {
00732
00733 case Orthographic:
00734
00735 setOrthographicProjection( _projectionWidth,
00736 _nearClippingPlane, _farClippingPlane ) ;
00737 break ;
00738
00739 default:
00740 throw OpenGLException( "OpenGLContext::updateProjection : "
00741 "not implemented for current projection." ) ;
00742 break ;
00743
00744 }
00745
00746 }
00747
00748