OSDLGLTexture.cc

Go to the documentation of this file.
00001 #include "OSDLGLTexture.h"
00002 
00003 #include "OSDLSurface.h"    // for Surface
00004 #include "OSDLVideo.h"      // for VideoModule::SoftwareSurface
00005 
00006 
00007 #ifdef OSDL_USES_CONFIG_H
00008 #include <OSDLConfig.h>     // for OSDL_USES_OPENGL and al 
00009 #endif // OSDL_USES_CONFIG_H
00010 
00011 #ifdef OSDL_HAVE_OPENGL
00012 #include "SDL_opengl.h"     // for GL functions
00013 #endif // OSDL_HAVE_OPENGL
00014 
00015 
00016 
00017 using std::string ;
00018 
00019 
00020 using namespace Ceylan ;
00021 using namespace Ceylan::Log ;
00022 using namespace Ceylan::Maths ;
00023 
00024 using namespace OSDL::Video::OpenGL ;
00025 
00026 
00027 GLTexture::TextureMode GLTexture::CurrentTextureMode = TwoDim ;
00028 
00029 
00030 
00031 GLTextureException::GLTextureException( const std::string & reason ) throw() :
00032     OpenGLException( reason )
00033 {
00034 
00035 }
00036 
00037                     
00038 GLTextureException::~GLTextureException() throw()
00039 {
00040 
00041 }
00042 
00043 
00044 
00045 
00046 GLTexture::GLTexture( const std::string imageFilename, 
00047     Textureflavour flavour ) 
00048         throw( GLTextureException ) :
00049     _source( 0 ),
00050     _id( 0 )
00051 {
00052 
00053 #if OSDL_USES_OPENGL
00054     
00055     Surface * loaded ;
00056     
00057     try
00058     {
00059     
00060         loaded = & Surface::LoadImage( imageFilename, 
00061             /* convertToDisplay */ false ) ;
00062             
00063     }
00064     catch( const TwoDimensional::ImageException & e )
00065     {
00066     
00067         throw GLTextureException( 
00068             "GLTexture constructor : unable to load source image from file "
00069             + imageFilename + " : " + e.toString() ) ;
00070     }
00071     
00072     upload( *loaded, flavour ) ;
00073     
00074     // Texture not wanted any more, in all cases (it has been copied) :
00075     delete loaded ;
00076 
00077 #else // OSDL_USES_OPENGL
00078 
00079     throw GLTextureException( "OpenGL support not available." ) ;
00080     
00081 #endif // OSDL_USES_OPENGL
00082         
00083 }
00084 
00085 
00086 
00087 GLTexture::GLTexture( Surface & sourceSurface, Textureflavour flavour ) 
00088         throw( GLTextureException ) :
00089     _source( 0 )
00090 {
00091 
00092     upload( sourceSurface, flavour ) ;
00093     
00094 }
00095 
00096 
00097 
00098 GLTexture::~GLTexture() throw()
00099 {
00100 
00101 #if OSDL_USES_OPENGL
00102 
00103     if ( _id != 0 )
00104         glDeleteTextures( 1, & _id ) ;
00105         
00106     if ( _source != 0 )
00107         delete _source ;
00108 
00109 #endif // OSDL_USES_OPENGL
00110         
00111 }
00112 
00113 
00114 
00115 bool GLTexture::canBeUploaded() const throw()
00116 {
00117 
00118     return ( _source != 0 ) ;
00119     
00120 }
00121 
00122 
00123 void GLTexture::upload() throw( GLTextureException )
00124 {
00125 
00126 
00127 #if OSDL_USES_OPENGL
00128 
00129     if ( ! canBeUploaded() )
00130         throw GLTextureException( "GLTexture::upload : "
00131             "texture cannot be uploaded into OpenGL context." ) ;
00132             
00133     // @todo    
00134     // if ( OpenGLContext::ContextCanBeLost ) ... else..
00135 
00136 #else // OSDL_USES_OPENGL
00137 
00138     throw GLTextureException( "OpenGL support not available." ) ;
00139     
00140 #endif // OSDL_USES_OPENGL
00141     
00142 }
00143 
00144 
00145 const string GLTexture::toString( Ceylan::VerbosityLevels level ) const throw()
00146 {
00147 
00148     string res = "OpenGL texture, " ;
00149     
00150     if ( _id == 0 )
00151         res += "which has no OpenGL identifier" ;
00152     else
00153         res += "whose OpenGL identifier is " + Ceylan::toString( _id ) ;
00154     
00155     if ( _source == 0 )
00156         res += ", and which has no available internal surface "
00157             "kept for reload." ;
00158     else
00159         res += ", which owns an internal surface, "
00160             "kept for reloading purposes." ;
00161     
00162     return res ;        
00163         
00164 }
00165     
00166 
00167 
00168 // Static section.
00169 
00170 
00171 GLTexture::TextureMode GLTexture::GetTextureMode() throw()
00172 {
00173 
00174     return CurrentTextureMode ;
00175     
00176 }
00177 
00178 
00179 void GLTexture::SetTextureMode( TextureMode newMode ) throw()
00180 {
00181 
00182     CurrentTextureMode = newMode ;
00183     
00184 }
00185 
00186 
00187 
00188 void GLTexture::SetTextureFlavour( Textureflavour flavour ) 
00189     throw( GLTextureException )
00190 {
00191 
00192 #if OSDL_USES_OPENGL
00193 
00194     switch( flavour )
00195     {
00196     
00197         case None:
00198             return ;
00199             break ;
00200         
00201         
00202         case Basic:
00203         
00204             /*
00205              * Minifying function : weighted average of the four closest 
00206              * texture elements.
00207              *
00208              */
00209             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ) ;
00210             
00211             /*
00212              * Magnifying function : weighted average of the four closest
00213              * texture elements.
00214              *
00215              */
00216             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ) ;
00217     
00218             /*
00219              * Wrap parameter for texture coordinate s : clamped to the range
00220              * [0,1].
00221              *
00222              */
00223             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ) ;
00224             
00225             /*
00226              * Wrap parameter for texture coordinate t : clamped to the 
00227              * range [0,1].
00228              *
00229              */
00230             glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ) ;
00231             
00232             break ;     
00233     
00234     
00235         default:
00236             LogPlug::warning( 
00237                 "GLTexture::SetTextureFlavour : unknown flavour : "
00238                 + Ceylan::toString( flavour ) + "." ) ;
00239             break ; 
00240             
00241     }
00242 
00243 #else // OSDL_USES_OPENGL
00244 
00245     throw GLTextureException( "OpenGL support not available." ) ;
00246     
00247 #endif // OSDL_USES_OPENGL
00248     
00249 }
00250 
00251 
00252 
00253 void GLTexture::upload( Surface & sourceSurface, 
00254     Textureflavour flavour ) throw( GLTextureException ) 
00255 {
00256 
00257 #if OSDL_USES_OPENGL
00258 
00259     /*
00260 inspiration :   
00261 GLuint loadTextureCK(char *filepath, int ckr, int ckg, int ckb){
00262   GLuint texture;
00263   SDL_Surface *imagesurface;
00264   SDL_Surface *tmpsurface;
00265   Uint32 colorkey;
00266   int w, h;
00267 
00268   imagesurface = SDL_LoadBMP(filepath);
00269   if (!imagesurface)
00270     return 0;
00271 
00272   w = imagesurface->w;
00273   h = imagesurface->h;
00274 
00275   // create temporary surface with the correct OpenGL format
00276   tmpsurface = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32,
00277 (use Pixels::getRecommendedColorMask)                                    );
00278   if (!tmpsurface)
00279     return 0;
00280 
00281   // set colour key
00282   colorkey = SDL_MapRGBA(tmpsurface->format, ckr, ckg, ckb, 0);
00283   SDL_FillRect(tmpsurface, NULL, colorkey);
00284 
00285   colorkey = SDL_MapRGBA(imagesurface->format, ckr, ckg, ckb, 0);
00286   SDL_SetColorKey(imagesurface, SDL_SRCCOLORKEY, colorkey);
00287 
00288   SDL_BlitSurface(imagesurface, NULL, tmpsurface, NULL);
00289 
00290   // create OpenGL texture
00291   glGenTextures(1, &texture);
00292   glBindTexture(GL_TEXTURE_2D, texture);
00293   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 
00294                0, GL_RGBA, GL_UNSIGNED_BYTE, tmpsurface->pixels);
00295   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00296   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00297 
00298   SDL_FreeSurface(imagesurface);
00299   SDL_FreeSurface(tmpsurface);
00300 
00301   return texture;
00302     
00303     
00304     
00305     */
00306 
00307 
00308 /*
00309     // Inspired from Gabriel Gambetta's routine.
00310 
00311 void OGLVideoDriver::initPixelFormats (void)
00312 {
00313     #ifdef __APPLE__
00314         m_pPixelFormat.nBPP = 24;
00315         m_pPixelFormat.nAMask = 0x00000000;
00316         m_pPixelFormat.nRMask = 0x00FF0000;
00317         m_pPixelFormat.nGMask = 0x0000FF00;
00318         m_pPixelFormat.nBMask = 0x000000FF;
00319 
00320         m_pPixelFormatAlpha.nBPP = 32;
00321         m_pPixelFormatAlpha.nAMask = 0x000000FF;
00322         m_pPixelFormatAlpha.nRMask = 0xFF000000;
00323         m_pPixelFormatAlpha.nGMask = 0x00FF0000;
00324         m_pPixelFormatAlpha.nBMask = 0x0000FF00;
00325     #else
00326         m_pPixelFormat.nBPP = 24;
00327         m_pPixelFormat.nAMask = 0x00000000;
00328         m_pPixelFormat.nRMask = 0x000000FF;
00329         m_pPixelFormat.nGMask = 0x0000FF00;
00330         m_pPixelFormat.nBMask = 0x00FF0000;
00331 
00332         m_pPixelFormatAlpha.nBPP = 32;
00333         m_pPixelFormatAlpha.nAMask = 0xFF000000;
00334         m_pPixelFormatAlpha.nRMask = 0x000000FF;
00335         m_pPixelFormatAlpha.nGMask = 0x0000FF00;
00336         m_pPixelFormatAlpha.nBMask = 0x00FF0000;
00337     #endif
00338 }
00339 
00340 I convert all my surfaces to that format, and later...
00341 
00342 
00343     byte* pData;
00344     int nPitch;
00345 
00346     pSurf->lock(pRect, &pData, &nPitch);
00347 
00348     int nPitchBytes = nPitch;
00349     int nPitchMod = nPitch % nChannels;
00350     nPitch /= nChannels;
00351 
00352     static const int lModToAlign[4] = { 1, 2, 4, 8 };
00353     glPixelStorei(GL_UNPACK_ALIGNMENT, lModToAlign[nPitchMod]);
00354     glPixelStorei(GL_UNPACK_ROW_LENGTH, nPitch);
00355 
00356     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, nW, nH, nFormat,
00357 GL_UNSIGNED_BYTE, pData);
00358 
00359     pSurf->unlock();
00360 
00361 */
00362 
00363 
00364 /*
00365 
00366 
00367 
00368 
00369 #include "SDL.h"
00370 #include "SDL_endian.h"
00371 #include "SDL_opengl.h"
00372 
00373 int main(int, char**)
00374 {
00375     SDL_Init(SDL_INIT_EVERYTHING);
00376     SDL_SetVideoMode(400, 400, 0, SDL_OPENGL);
00377 
00378     // some.bmp is a red ship with a black backround
00379     SDL_Surface* original = SDL_LoadBMP("some.bmp");
00380 
00381     // We set a black colorkey for the ship
00382     SDL_SetColorKey(original, SDL_SRCCOLORKEY, 0);
00383 
00384     // We create a surface with known format to pass to opengl
00385     SDL_Surface* withalpha = SDL_CreateRGBSurface(
00386         SDL_SWSURFACE,
00387         original->w,
00388         original->h,
00389         32,
00390         SDL_SwapBE32(0xff000000),
00391         SDL_SwapBE32(0x00ff0000),
00392         SDL_SwapBE32(0x0000ff00),
00393         SDL_SwapBE32(0x000000ff));
00394 
00395     // We blit one on top of the other, but withalpha keeps
00396     // a transparent black in the backround
00397     // We should flip the texture so it has the origin in the bottom,
00398     // as opengl expects, but we flip coordinates instead
00399     SDL_BlitSurface(original, NULL, withalpha, NULL);
00400     SDL_FreeSurface(original);
00401 
00402     // The sky is blue
00403     glClearColor(0, 0, 1, 0);
00404     glClear(GL_COLOR_BUFFER_BIT);
00405     glEnable(GL_TEXTURE_2D);
00406     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
00407 
00408     // We enable skipping transparent texels
00409     glAlphaFunc(GL_GREATER, 0);
00410     glEnable(GL_ALPHA_TEST);
00411 
00412     GLuint texName = 0;
00413     glGenTextures(1, &texName);
00414     glBindTexture(GL_TEXTURE_2D, texName);
00415     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00416     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00417     glTexImage2D(
00418         GL_TEXTURE_2D,
00419         0,
00420         GL_RGBA,
00421         withalpha->w,
00422         withalpha->h,
00423         0,
00424         GL_RGBA,
00425         GL_UNSIGNED_BYTE,
00426         withalpha->pixels);
00427     SDL_FreeSurface(withalpha);
00428 
00429     glBegin(GL_QUADS); {
00430         glTexCoord2d(0, 0);
00431         glVertex2d(-0.8, +0.8);
00432         glTexCoord2d(0, 1);
00433         glVertex2d(-0.8, -0.8);
00434         glTexCoord2d(1, 1);
00435         glVertex2d(+0.8, -0.8);
00436         glTexCoord2d(1, 0);
00437         glVertex2d(+0.8, +0.8);
00438     }glEnd();
00439     SDL_GL_SwapBuffers();
00440 
00441     // You should see a red ship over a blue backround
00442     SDL_Delay(1000);
00443     SDL_Quit();
00444     return 0;
00445 }
00446 
00447 
00448 */
00449 
00450 
00451     // Inspired from Stephane Marchesin's routine.
00452     
00453     SDL_Surface * sourceInternal = & sourceSurface.getSDLSurface() ;
00454     
00455     /*
00456      * No alpha blending, no RLE acceleration should be used, and 
00457      * overall alpha is set to full transparency.
00458      *
00459      * 
00460      */
00461 
00462     // Colorkey not managed.
00463     
00464     // Saves the alpha blending attributes :
00465     Flags savedFlags = sourceInternal->flags & ( 
00466         Surface::AlphaBlendingBlit | Surface::RLEColorkeyBlitAvailable ) ;
00467         
00468     Pixels::ColorElement savedAlpha = sourceInternal->format->alpha ;
00469     
00470     bool mustModifyOverallAlpha = static_cast<bool>( 
00471         savedFlags & Surface::AlphaBlendingBlit ) ;
00472     
00473     if ( mustModifyOverallAlpha ) 
00474         SDL_SetAlpha( sourceInternal, 0, 0 ) ;
00475     
00476     Length width  = sourceInternal->w ;
00477     Length height = sourceInternal->h ;
00478     
00479     // To avoid having transparent surfaces, use 0 for AlphaMask ?
00480     SDL_Surface * convertedSurface = SDL_CreateRGBSurface(
00481         VideoModule::SoftwareSurface, 
00482         width, height, 32 /* bits per pixel */,
00483         RedMask, GreenMask, BlueMask, AlphaMask ) ;
00484     
00485     if ( convertedSurface == 0 )
00486         throw GLTextureException( 
00487             "GLTexture::upload : RGB surface creation failed." ) ;
00488         
00489          
00490     int res = SDL_BlitSurface( sourceInternal, 0, convertedSurface, 0 ) ;
00491 
00492     // Restores the alpha blending attributes :
00493     if ( mustModifyOverallAlpha ) 
00494         SDL_SetAlpha( sourceInternal, savedFlags, savedAlpha ) ;
00495     
00496     if ( res != 0 )
00497     {
00498         SDL_FreeSurface( convertedSurface ) ;
00499         throw GLTextureException( "GLTexture::upload : blit failed (returned "
00500             + Ceylan::toString( res ) + ")." ) ;
00501     }
00502 
00503     
00504     // Generates a new name for this texture :
00505     glGenTextures( 1, & _id ) ;
00506     
00507     glBindTexture( GL_TEXTURE_2D, _id ) ;
00508     
00509     // Apply the wanted settings :
00510     SetTextureFlavour( flavour ) ;
00511     
00512     if ( IsAPowerOfTwo( width ) && IsAPowerOfTwo( height ) )
00513         glTexImage2D( 
00514             /* mandatory */ GL_TEXTURE_2D, 
00515             /* level : base image */  0, 
00516             /* number of color components */ GL_RGBA, 
00517             width, 
00518             height, 
00519             /* border */ 0, 
00520             /* pixel format */ GL_RGBA, 
00521             /* pixel data type */ GL_UNSIGNED_BYTE, 
00522             convertedSurface->pixels ) ;
00523     else
00524         gluBuild2DMipmaps( 
00525             /* mandatory */ GL_TEXTURE_2D, 
00526             /* number of color components */ GL_RGBA, 
00527             width, 
00528             height,
00529             /* pixel format */ GL_RGBA, 
00530             /* pixel data type */ GL_UNSIGNED_BYTE, 
00531             convertedSurface->pixels ) ;
00532             
00533     SDL_FreeSurface( convertedSurface ) ;
00534 
00535 #else // OSDL_USES_OPENGL
00536 
00537     throw GLTextureException( "OpenGL support not available." ) ;
00538     
00539 #endif // OSDL_USES_OPENGL
00540 
00541 }   
00542 

Generated on Fri Mar 30 14:46:59 2007 for OSDL by  doxygen 1.5.1