00001 #include "OSDLGLTexture.h"
00002
00003 #include "OSDLOpenGL.h"
00004 #include "OSDLVideo.h"
00005 #include "OSDLSurface.h"
00006
00007
00008 #ifdef OSDL_USES_CONFIG_H
00009 #include <OSDLConfig.h>
00010 #endif // OSDL_USES_CONFIG_H
00011
00012 #if OSDL_ARCH_NINTENDO_DS
00013 #include "OSDLConfigForNintendoDS.h"
00014 #endif // OSDL_ARCH_NINTENDO_DS
00015
00016
00017 #if OSDL_USES_SDL
00018 #include "SDL.h"
00019 #endif // OSDL_USES_SDL
00020
00021
00022 #ifdef OSDL_HAVE_OPENGL
00023 #include "SDL_opengl.h"
00024 #endif // OSDL_HAVE_OPENGL
00025
00026
00027
00028
00029 #include "OSDLIncludeCorrecter.h"
00030
00031 using std::string ;
00032
00033 using namespace Ceylan ;
00034 using namespace Ceylan::Log ;
00035 using namespace Ceylan::Maths ;
00036
00037 using namespace OSDL::Video ;
00038 using namespace OSDL::Video::OpenGL ;
00039
00040
00041 GLTexture::TextureDimensionality GLTexture::CurrentTextureDimensionality =
00042 TwoDim ;
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 #if OSDL_VERBOSE_VIDEO_MODULE
00056
00057 #define LOG_DEBUG_TEXTURE(message) LogPlug::debug(message)
00058 #define LOG_TRACE_TEXTURE(message) LogPlug::trace(message)
00059 #define LOG_WARNING_TEXTURE(message) LogPlug::warning(message)
00060
00061 #else // OSDL_VERBOSE_VIDEO_MODULE
00062
00063 #define LOG_DEBUG_TEXTURE(message)
00064 #define LOG_TRACE_TEXTURE(message)
00065 #define LOG_WARNING_TEXTURE(message)
00066
00067 #endif // OSDL_VERBOSE_VIDEO_MODULE
00068
00069
00070
00071 GLTextureException::GLTextureException( const std::string & reason ) throw():
00072 OpenGLException( reason )
00073 {
00074
00075 }
00076
00077
00078 GLTextureException::~GLTextureException() throw()
00079 {
00080
00081 }
00082
00083
00084
00085
00086 GLTexture::GLTexture( const std::string imageFilename, TextureFlavour flavour )
00087 throw( GLTextureException ):
00088 _source( 0 ),
00089 _id( 0 ),
00090 _flavour( flavour ),
00091 _width( 0 ),
00092 _height( 0 )
00093 {
00094
00095 #if OSDL_USES_OPENGL
00096
00097 LOG_DEBUG_TEXTURE( "Constructing a GLTexture from file " + imageFilename ) ;
00098
00099 Surface * loaded ;
00100
00101 try
00102 {
00103
00104 loaded = & Surface::LoadImage( imageFilename,
00105 false ) ;
00106
00107 }
00108 catch( const TwoDimensional::ImageException & e )
00109 {
00110
00111 throw GLTextureException(
00112 "GLTexture constructor: unable to load source image from file '"
00113 + imageFilename + "': " + e.toString() ) ;
00114 }
00115
00116 upload( *loaded ) ;
00117
00118
00119 delete loaded ;
00120
00121 #else // OSDL_USES_OPENGL
00122
00123 throw GLTextureException( "GLTexture constructor: "
00124 "OpenGL support not available." ) ;
00125
00126 #endif // OSDL_USES_OPENGL
00127
00128 }
00129
00130
00131
00132 GLTexture::GLTexture( Surface & sourceSurface, TextureFlavour flavour )
00133 throw( GLTextureException ):
00134 _source( 0 ),
00135 _id( 0 ),
00136 _flavour( flavour ),
00137 _width( 0 ),
00138 _height( 0 )
00139 {
00140
00141 LOG_DEBUG_TEXTURE( "Constructing a GLTexture from a surface" ) ;
00142
00143 upload( sourceSurface ) ;
00144
00145 }
00146
00147
00148
00149 GLTexture::~GLTexture() throw()
00150 {
00151
00152 #if OSDL_USES_OPENGL
00153
00154 LOG_DEBUG_TEXTURE( "Deleting a GLTexture" ) ;
00155
00156 if ( _id != 0 )
00157 glDeleteTextures( 1, & _id ) ;
00158
00159 if ( _source != 0 )
00160 delete _source ;
00161
00162 #endif // OSDL_USES_OPENGL
00163
00164 }
00165
00166
00167
00168 bool GLTexture::canBeUploaded() const throw()
00169 {
00170
00171 return ( _source != 0 ) ;
00172
00173 }
00174
00175
00176
00177 void GLTexture::upload() throw( GLTextureException )
00178 {
00179
00180 #if OSDL_USES_OPENGL
00181
00182 LOG_DEBUG_TEXTURE( "GLTexture::upload" ) ;
00183
00184 if ( ! canBeUploaded() )
00185 throw GLTextureException( "GLTexture::upload: "
00186 "texture cannot be uploaded into OpenGL context." ) ;
00187
00188
00189
00190
00191 #else // OSDL_USES_OPENGL
00192
00193 throw GLTextureException( "GLTexture::upload failed: "
00194 "OpenGL support not available." ) ;
00195
00196 #endif // OSDL_USES_OPENGL
00197
00198 }
00199
00200
00201
00202 const string GLTexture::toString( Ceylan::VerbosityLevels level ) const throw()
00203 {
00204
00205 string res = "OpenGL texture, " ;
00206
00207 if ( _id == 0 )
00208 res += "which has no OpenGL identifier" ;
00209 else
00210 res += "whose OpenGL identifier is " + Ceylan::toString( _id ) ;
00211
00212 if ( _source == 0 )
00213 res += ", and which has no available internal surface "
00214 "kept for reload." ;
00215 else
00216 res += ", which owns an internal surface, "
00217 "kept for reloading purposes." ;
00218
00219 res += " Its current size (width x height) is "
00220 + Ceylan::toString( _width ) + "x"
00221 + Ceylan::toString( _height ) + " pixels" ;
00222
00223 return res ;
00224
00225 }
00226
00227
00228
00229
00230
00231
00232 GLTexture::TextureDimensionality GLTexture::GetTextureDimensionality() throw()
00233 {
00234
00235 return CurrentTextureDimensionality ;
00236
00237 }
00238
00239
00240
00241 void GLTexture::SetTextureDimensionality(
00242 TextureDimensionality newDimensionality ) throw()
00243 {
00244
00245 CurrentTextureDimensionality = newDimensionality ;
00246
00247 }
00248
00249
00250
00251 void GLTexture::SetTextureFlavour( TextureFlavour textureFlavour )
00252 throw( GLTextureException )
00253 {
00254
00255 #if OSDL_USES_OPENGL
00256
00257 LogPlug::trace( "GLTexture::SetTextureFlavour" ) ;
00258
00259 switch( textureFlavour )
00260 {
00261
00262
00263 case None:
00264 return ;
00265 break ;
00266
00267
00268 case Basic:
00269
00270 LogPlug::trace( "GLTexture::SetTextureFlavour: Basic" ) ;
00271
00272
00273
00274
00275
00276
00277 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) ;
00278
00279
00280
00281
00282
00283
00284 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ;
00285
00286
00287
00288
00289
00290
00291 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ) ;
00292
00293
00294
00295
00296
00297
00298 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ) ;
00299
00300 break ;
00301
00302
00303 case For2D:
00304
00305 LogPlug::trace( "GLTexture::SetTextureFlavour: For2D" ) ;
00306
00307
00308 OpenGLContext::EnableFeature( GL_TEXTURE_2D ) ;
00309
00310 GLTexture::SetTextureDimensionality( GLTexture::TwoDim ) ;
00311
00312
00313
00314
00315
00316 SetTextureEnvironmentParameter( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
00317 GL_MODULATE ) ;
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ;
00330
00331
00332
00333
00334
00335
00336 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ) ;
00337
00338
00339
00340
00341
00342
00343 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ) ;
00344
00345
00346
00347
00348
00349
00350 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ) ;
00351
00352 break ;
00353
00354
00355 default:
00356 throw GLTextureException(
00357 "GLTexture::SetTextureFlavour: unknown texture flavour: "
00358 + Ceylan::toString( textureFlavour ) + "." ) ;
00359 break ;
00360
00361 }
00362
00363 #else // OSDL_USES_OPENGL
00364
00365 throw GLTextureException( "GLTexture::SetTextureFlavour failed: "
00366 "OpenGL support not available." ) ;
00367
00368 #endif // OSDL_USES_OPENGL
00369
00370 }
00371
00372
00373
00374 void GLTexture::SetTextureEnvironmentParameter(
00375 GLEnumeration targetEnvironment,
00376 GLEnumeration environmentParameter,
00377 GLfloat parameterValue )
00378 throw( GLTextureException )
00379 {
00380
00381 #if OSDL_USES_OPENGL
00382
00383 glTexEnvf( targetEnvironment, environmentParameter, parameterValue ) ;
00384
00385
00386 #if OSDL_CHECK_OPENGL_CALLS
00387
00388 switch ( glGetError() )
00389 {
00390
00391 case GL_NO_ERROR:
00392 break ;
00393
00394 case GL_INVALID_ENUM:
00395 throw GLTextureException(
00396 "GLTexture::SetTextureEnvironmentParameter: "
00397 "invalid enumeration." ) ;
00398 break ;
00399
00400 case GL_INVALID_VALUE:
00401 throw GLTextureException(
00402 "GLTexture::SetTextureEnvironmentParameter: "
00403 "invalid enumeration." ) ;
00404 break ;
00405
00406 case GL_INVALID_OPERATION:
00407 throw GLTextureException(
00408 "GLTexture::SetTextureEnvironmentParameter: "
00409 "incorrectly executed between the execution of glBegin and "
00410 "the corresponding execution of glEnd." ) ;
00411 break ;
00412
00413 default:
00414 throw GLTextureException(
00415 "GLTexture::SetTextureEnvironmentParameter: "
00416 "unexpected error reported." ) ;
00417 break ;
00418
00419 }
00420
00421 #endif // OSDL_CHECK_OPENGL_CALLS
00422
00423
00424 #else // OSDL_USES_OPENGL
00425
00426 throw GLTextureException(
00427 "GLTexture::SetTextureEnvironmentParameter failed: "
00428 "no OpenGL support available" ) ;
00429
00430 #endif // OSDL_USES_OPENGL
00431
00432 }
00433
00434
00435
00436 void GLTexture::SetTextureEnvironmentParameter(
00437 GLEnumeration targetEnvironment,
00438 GLEnumeration environmentParameter,
00439 const GLfloat * parameterValues )
00440 throw( GLTextureException )
00441 {
00442
00443 #if OSDL_USES_OPENGL
00444
00445 glTexEnvfv( targetEnvironment, environmentParameter, parameterValues ) ;
00446
00447
00448 #if OSDL_CHECK_OPENGL_CALLS
00449
00450 switch ( glGetError() )
00451 {
00452
00453 case GL_NO_ERROR:
00454 break ;
00455
00456 case GL_INVALID_ENUM:
00457 throw GLTextureException(
00458 "GLTexture::SetTextureEnvironmentParameter: "
00459 "invalid enumeration." ) ;
00460 break ;
00461
00462 case GL_INVALID_VALUE:
00463 throw GLTextureException(
00464 "GLTexture::SetTextureEnvironmentParameter: "
00465 "invalid enumeration." ) ;
00466 break ;
00467
00468 case GL_INVALID_OPERATION:
00469 throw GLTextureException(
00470 "GLTexture::SetTextureEnvironmentParameter: "
00471 "incorrectly executed between the execution of glBegin and "
00472 "the corresponding execution of glEnd." ) ;
00473 break ;
00474
00475 default:
00476 throw GLTextureException(
00477 "GLTexture::SetTextureEnvironmentParameter: "
00478 "unexpected error reported." ) ;
00479 break ;
00480
00481 }
00482
00483 #endif // OSDL_CHECK_OPENGL_CALLS
00484
00485
00486 #else // OSDL_USES_OPENGL
00487
00488 throw GLTextureException(
00489 "GLTexture::SetTextureEnvironmentParameter failed: "
00490 "no OpenGL support available" ) ;
00491
00492 #endif // OSDL_USES_OPENGL
00493
00494 }
00495
00496
00497
00498
00499
00500
00501
00502 void GLTexture::upload( Surface & sourceSurface ) throw( GLTextureException )
00503 {
00504
00505 #if OSDL_USES_OPENGL
00506
00507
00508 LogPlug::trace( "GLTexture::upload" ) ;
00509
00510 _width = sourceSurface.getWidth() ;
00511 _height = sourceSurface.getHeight() ;
00512
00513
00514
00515
00516 try
00517 {
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 Flags savedFlags = sourceSurface.getFlags() & (
00529 Surface::AlphaBlendingBlit | Surface::RLEColorkeyBlitAvailable ) ;
00530
00531
00532 Pixels::ColorElement savedAlpha = sourceSurface.getPixelFormat().alpha ;
00533
00534 bool mustModifyOverallAlpha =
00535 ( ( savedFlags & Surface::AlphaBlendingBlit ) != 0 ) ;
00536
00537 if ( mustModifyOverallAlpha )
00538 sourceSurface.setAlpha( 0,
00539 AlphaTransparent ) ;
00540
00541 Length width = sourceSurface.getWidth() ;
00542 Length height = sourceSurface.getHeight() ;
00543
00544
00545
00546
00547 Surface & convertedSurface = * new Surface(
00548 VideoModule::SoftwareSurface, width, height, 32 ,
00549 RedMask, GreenMask, BlueMask, AlphaMask ) ;
00550
00551 sourceSurface.blitTo( convertedSurface ) ;
00552
00553
00554
00555 if ( mustModifyOverallAlpha )
00556 sourceSurface.setAlpha( savedFlags,
00557 savedAlpha ) ;
00558
00559
00560
00561 glGenTextures( 1, & _id ) ;
00562
00563 #if OSDL_CHECK_OPENGL_CALLS
00564
00565 switch ( glGetError() )
00566 {
00567
00568 case GL_NO_ERROR:
00569 break ;
00570
00571 case GL_INVALID_VALUE:
00572 throw OpenGLException(
00573 "GLTexture::upload failed (glGenTextures): "
00574 "invalid number of requested names." ) ;
00575 break ;
00576
00577 case GL_INVALID_OPERATION:
00578 throw OpenGLException(
00579 "GLTexture::upload failed (glGenTextures): "
00580 "incorrectly executed between the execution of glBegin and "
00581 "the corresponding execution of glEnd." ) ;
00582 break ;
00583
00584 default:
00585 LogPlug::warning( "GLTexture::upload failed (glGenTextures): "
00586 "unexpected error reported." ) ;
00587 break ;
00588
00589 }
00590
00591 #endif // OSDL_CHECK_OPENGL_CALLS
00592
00593 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ) ;
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607 glBindTexture( GL_TEXTURE_2D,
00608 _id ) ;
00609
00610
00611 SetTextureFlavour( _flavour ) ;
00612
00613
00614 #if OSDL_CHECK_OPENGL_CALLS
00615
00616 switch ( glGetError() )
00617 {
00618
00619 case GL_NO_ERROR:
00620 break ;
00621
00622 case GL_INVALID_ENUM:
00623 throw OpenGLException(
00624 "GLTexture::upload failed (glBindTexture): "
00625 "target is not an allowed value." ) ;
00626 break ;
00627
00628 case GL_INVALID_OPERATION:
00629 throw OpenGLException(
00630 "GLTexture::upload failed (glBindTexture): "
00631 "wrong dimensionality or incorrectly executed between "
00632 "the execution of glBegin and the corresponding execution "
00633 "of glEnd." ) ;
00634 break ;
00635
00636 default:
00637 LogPlug::warning( "GLTexture::upload failed (glBindTexture): "
00638 "unexpected error reported." ) ;
00639 break ;
00640
00641 }
00642
00643 #endif // OSDL_CHECK_OPENGL_CALLS
00644
00645 if ( IsAPowerOfTwo( width ) && IsAPowerOfTwo( height ) )
00646 {
00647
00648
00649 LogPlug::trace( "GLTexture::upload: glTexImage2D with "
00650 + Ceylan::toString( width ) + "x"
00651 + Ceylan::toString( height ) ) ;
00652
00653
00654 glTexImage2D(
00655 GL_TEXTURE_2D,
00656 0,
00657 GL_RGBA,
00658 width,
00659 height,
00660 0,
00661 GL_RGBA,
00662 GL_UNSIGNED_BYTE,
00663 convertedSurface.getPixels() ) ;
00664
00665 #if OSDL_CHECK_OPENGL_CALLS
00666
00667 switch ( glGetError() )
00668 {
00669
00670 case GL_NO_ERROR:
00671 break ;
00672
00673 case GL_INVALID_ENUM:
00674 throw OpenGLException(
00675 "GLTexture::upload failed (glTexImage2D): "
00676 "invalid enum." ) ;
00677 break ;
00678
00679 case GL_INVALID_VALUE:
00680 throw OpenGLException(
00681 "GLTexture::upload failed (glTexImage2D): "
00682 "invalid value." ) ;
00683 break ;
00684
00685 case GL_INVALID_OPERATION:
00686 throw OpenGLException(
00687 "GLTexture::upload failed (glTexImage2D): "
00688 "incorrectly executed between the execution of "
00689 "glBegin and the corresponding execution of glEnd." ) ;
00690 break ;
00691
00692 default:
00693 throw OpenGLException(
00694 "GLTexture::upload failed (glTexImage2D): "
00695 "unexpected error reported." ) ;
00696 break ;
00697
00698 }
00699
00700 #endif // OSDL_CHECK_OPENGL_CALLS
00701
00702 }
00703 else
00704 {
00705
00706 LogPlug::trace( "GLTexture::upload: gluBuild2DMipmaps" ) ;
00707
00708
00709 GLU::Int res = gluBuild2DMipmaps(
00710 GL_TEXTURE_2D,
00711 GL_RGBA,
00712 width,
00713 height,
00714 GL_RGBA,
00715 GL_UNSIGNED_BYTE,
00716 convertedSurface.getPixels() ) ;
00717
00718 #if OSDL_CHECK_OPENGL_CALLS
00719
00720 switch ( res )
00721 {
00722
00723 case 0:
00724
00725 break ;
00726
00727 case GLU_INVALID_ENUM:
00728 throw OpenGLException(
00729 "GLTexture::upload failed (gluBuild2DMipmaps): "
00730 "invalid enum." ) ;
00731 break ;
00732
00733 case GLU_INVALID_VALUE:
00734 throw OpenGLException(
00735 "GLTexture::upload failed (gluBuild2DMipmaps): "
00736 "invalid value." ) ;
00737 break ;
00738
00739 default:
00740 throw OpenGLException(
00741 "GLTexture::upload failed (gluBuild2DMipmaps): "
00742 "unexpected error reported." ) ;
00743 break ;
00744
00745 }
00746
00747 #endif // OSDL_CHECK_OPENGL_CALLS
00748
00749 }
00750
00751 delete & convertedSurface ;
00752
00753 }
00754 catch( const VideoException & e )
00755 {
00756
00757 throw GLTextureException( "GLTexture::upload failed: "
00758 + e.toString() ) ;
00759
00760 }
00761
00762
00763 #else // OSDL_USES_OPENGL
00764
00765 throw GLTextureException( "GLTexture::upload failed: "
00766 ", altough OpenGL support not available." ) ;
00767
00768 #endif // OSDL_USES_OPENGL
00769
00770 }
00771