OSDLSurface.cc

Go to the documentation of this file.
00001 #include "OSDLSurface.h"
00002 
00003 #include "OSDLTypes.h"              // for Flags
00004 #include "OSDLVideo.h"
00005 #include "OSDLVideoTypes.h"         // for BitsPerPixel
00006 
00007 #include "OSDLVideoTypes.h"         // for Length, etc.
00008 #include "OSDLUprightRectangle.h"   // for UprightRectangle
00009 #include "OSDLPoint2D.h"            // for Point2D
00010 #include "OSDLLine.h"               // for Line : drawHorizontal, etc.
00011 #include "OSDLFixedFont.h"          // for printBasic
00012 #include "OSDLConic.h"              // for drawCircle, drawEllipse
00013 #include "OSDLPixel.h"              // for getColorMasks, ColorMask, etc.
00014 #include "OSDLPolygon.h"            // for drawPie
00015 #include "OSDLWidget.h"             // for Widget
00016 #include "OSDLUtils.h"              // for getBackendLastError
00017 
00018 #include "Ceylan.h"                 // for Ceylan::Uint8, etc.
00019 
00020 #include "SDL_rotozoom.h"           // for zoom, rotozoom
00021 
00022 #include <cassert>                  // for assert
00023 
00024 
00025 /*
00026  * Always remember to access the width and the height of a Surface thanks 
00027  * to their dedicated methods (getWidth/getHeight) since the '_width' and
00028  * '_height' attributes, inherited from  UprightRectangle, are never 
00029  * updated : the values are to be read directly from the internal 
00030  * back-end surface.
00031  *
00032  */
00033 
00034 using std::string ;
00035 using std::list ;
00036 
00037 using namespace Ceylan ;
00038 using namespace Ceylan::Log ;
00039 
00040 using namespace OSDL::Video ;
00041 using namespace OSDL::Video::TwoDimensional ;
00042 
00043 
00044 using TwoDimensional::UprightRectangle ;
00045 
00046 
00047 #ifdef OSDL_USES_CONFIG_H
00048 #include <OSDLConfig.h>     // for OSDL_DEBUG_* and al 
00049 #endif // OSDL_USES_CONFIG_H
00050 
00051 
00052 
00053 SurfaceEvent::SurfaceEvent( Ceylan::EventSource & source ) throw() : 
00054     Ceylan::Event( source )
00055 {
00056 
00057 }
00058 
00059 
00060 SurfaceEvent::~SurfaceEvent() throw()
00061 {
00062 
00063 }
00064 
00065 
00066 
00067 VideoMemoryLostException::VideoMemoryLostException( 
00068         const std::string & message ) throw() :
00069     VideoException( message ) 
00070 {
00071 
00072 }
00073 
00074 
00075 VideoMemoryLostException::VideoMemoryLostException() throw() :
00076     VideoException( "Video memory lost, content needs to be reblitted" ) 
00077 {
00078 
00079 }
00080     
00081     
00082 VideoMemoryLostException::~VideoMemoryLostException() throw()
00083 {
00084 
00085 }
00086 
00087 
00088 
00089 /*
00090  * These flags can be used for all Surfaces.
00091  *
00092  * @note They are defined relatively as SDL back-end.
00093  *
00094  */
00095 
00096 const Ceylan::Flags Surface::Software                 = SDL_SWSURFACE   ;
00097 const Ceylan::Flags Surface::Hardware                 = SDL_HWSURFACE   ;
00098 const Ceylan::Flags Surface::AsynchronousBlit         = SDL_ASYNCBLIT   ;
00099 const Ceylan::Flags Surface::ExclusivePalette         = SDL_HWPALETTE   ;
00100 const Ceylan::Flags Surface::HardwareAcceleratedBlit  = SDL_HWACCEL     ;
00101 const Ceylan::Flags Surface::ColorkeyBlit             = SDL_SRCCOLORKEY ;
00102 const Ceylan::Flags Surface::RLEColorkeyBlit          = SDL_RLEACCEL    ;
00103 const Ceylan::Flags Surface::AlphaBlendingBlit        = SDL_SRCALPHA    ;
00104 const Ceylan::Flags Surface::Preallocated             = SDL_PREALLOC    ;
00105 
00106 
00107 // Private flag.
00108 const Ceylan::Flags Surface::RLEColorkeyBlitAvailable = SDL_RLEACCELOK  ;
00109 
00110 
00111 /*
00112  * These flags can only be used for display Surfaces.
00113  *
00114  * @note SDL_OPENGLBLIT has been deprecated.
00115  *
00116  */
00117 
00118 const Ceylan::Flags Surface::AnyPixelFormat = SDL_ANYFORMAT  ;
00119 const Ceylan::Flags Surface::DoubleBuffered = SDL_DOUBLEBUF  ;
00120 const Ceylan::Flags Surface::FullScreen     = SDL_FULLSCREEN ;
00121 const Ceylan::Flags Surface::OpenGL         = SDL_OPENGL     ;
00122 const Ceylan::Flags Surface::Resizable      = SDL_RESIZABLE  ;
00123     
00124 
00125 const Length Surface::graphAbscissaOffset   = 10 ;
00126 const Length Surface::graphOrdinateOffset   = 15 ;
00127 
00128 const Length Surface::captionAbscissaOffset = 5  ;
00129 const Length Surface::captionOrdinateOffset = 10 ;
00130     
00131     
00132     
00133 #ifdef OSDL_COUNT_INSTANCES
00134 
00135 #define CHECKPOINT(message) Ceylan::checkpoint( message )
00136 
00137 #else // OSDL_COUNT_INSTANCES
00138 
00139 #define CHECKPOINT(message) 
00140 
00141 #endif // OSDL_COUNT_INSTANCES
00142  
00143  
00144 Surface::Surface( SDL_Surface & surface, DisplayType displayType ) throw() : 
00145     UprightRectangle( 0, 0, 0, 0 ),
00146     EventSource(),
00147     Lockable(),
00148     _surface( & surface ), 
00149     _displayType( displayType ),
00150     _mustBeLocked( false ),
00151     _needsRedraw( true )  
00152 {
00153 
00154 #if OSDL_DEBUG_WIDGET
00155 
00156     CHECKPOINT( "Surface constructor from SDL surface." ) ; 
00157     
00158     LogPlug::trace( "Surface constructor from SDL surface." ) ;
00159      
00160 #endif // OSDL_DEBUG_WIDGET
00161 
00162 }
00163 
00164 
00165 Surface::Surface( Flags flags, Length width, Length height, BitsPerPixel depth,
00166     Pixels::ColorMask redMask, Pixels::ColorMask greenMask,
00167     Pixels::ColorMask blueMask, Pixels::ColorMask alphaMask ) 
00168             throw( VideoException ) :
00169         UprightRectangle( 0, 0, 
00170             /* width and height not stored, computed from surface : */ 0, 0 ),
00171         EventSource(),
00172         Lockable(),
00173         _surface( 0 ),
00174         _displayType( BackBuffer ),
00175         _mustBeLocked( false ),
00176         _needsRedraw( true )  
00177 {
00178 
00179 
00180 #if OSDL_DEBUG_WIDGET
00181 
00182     CHECKPOINT( "Surface constructor with full flags." ) ;
00183     
00184     LogPlug::trace( "Surface constructor with flags = " 
00185         + Ceylan::toString( flags, /* bit field */ true ) 
00186         + ", with width = "       + Ceylan::toString( width ) 
00187         + ", with height = "      + Ceylan::toString( height )
00188         + ", with color depth = " + Ceylan::toNumericalString( depth ) 
00189         + ", with specified red mask = "    + Ceylan::toHexString( redMask ) 
00190         + ", with specified green mask = "  + Ceylan::toHexString( greenMask ) 
00191         + ", with specified blue mask = "   + Ceylan::toHexString( blueMask ) 
00192         + ", with specified alpha mask = "  + Ceylan::toHexString( alphaMask )  
00193         + "." ) ; 
00194         
00195 #endif // OSDL_DEBUG_WIDGET
00196 
00197     
00198     if ( alphaMask != 0 )
00199     {
00200         flags |= AlphaBlendingBlit ;
00201         // All other color masks have thus been specified.
00202     }   
00203     else 
00204     {
00205     
00206         // Here alpha mask is zero.
00207         
00208         /*
00209          * All other masks are zero too ? 
00210          * Choose them according to endianess, then :
00211          *
00212          */
00213         if ( redMask == 0 && greenMask == 0 && blueMask == 0 )
00214             Pixels::getRecommendedColorMasks( redMask, greenMask, 
00215                 blueMask, alphaMask ) ;
00216             
00217     }
00218         
00219 #if OSDL_DEBUG_WIDGET
00220 
00221     LogPlug::trace( "Surface constructor : actual surface flags are " 
00222         + Ceylan::toString( flags, /* bit field */ true ) 
00223         + ", red mask is "   + Ceylan::toHexString( redMask )  
00224         + ", green mask is " + Ceylan::toHexString( greenMask )  
00225         + ", blue mask is "  + Ceylan::toHexString( blueMask ) 
00226         + ", alpha mask is " + Ceylan::toHexString( alphaMask ) ) ;
00227         
00228 #endif // OSDL_DEBUG_WIDGET
00229     
00230     _surface = SDL_CreateRGBSurface( flags, width, height, depth, 
00231         redMask, greenMask, blueMask, alphaMask ) ;
00232     
00233     if ( _surface == 0 )
00234         throw VideoException( "Blank surface constructor failed (width = " 
00235             + Ceylan::toString( width ) 
00236             + ", height = " + Ceylan::toString( height ) + ") : " 
00237             + Utils::getBackendLastError() ) ; 
00238             
00239 }
00240 
00241 
00242 
00243 /*
00244  * Protected Surface constructor only supposed to be called on very 
00245  * special cases.   
00246  *
00247  */         
00248 Surface::Surface() throw() :
00249     UprightRectangle( 0, 0, 0, 0 ),
00250     EventSource(),
00251     _surface( 0 ),
00252     _displayType( BackBuffer ),
00253     _mustBeLocked( false ),
00254     _needsRedraw( true )  
00255 {
00256 
00257     
00258     // Empty surface.
00259 
00260 #if OSDL_DEBUG_WIDGET
00261     CHECKPOINT( "Empty Surface constructor." ) ;
00262     LogPlug::trace( "Empty Surface constructor." ) ;
00263 #endif // OSDL_DEBUG_WIDGET
00264 
00265 }           
00266     
00267                         
00268 Surface::~Surface() throw()
00269 {
00270 
00271 #if OSDL_DEBUG_WIDGET
00272 
00273     CHECKPOINT( "Surface destructor." ) ;
00274     LogPlug::trace( "Surface destructor, " 
00275         + Ceylan::toString( _listeners.size() ) + " widget(s) registered." ) ;
00276         
00277 #endif // OSDL_DEBUG_WIDGET
00278     
00279     Ceylan::EventListener * widget ;
00280     
00281     // Do not use iterators for this delete task !
00282     
00283     /*
00284      * Listeners will be removed one by one thanks to unsubscribeFrom calls :
00285      * this is because it is rather unusual that sources detach themselves 
00286      * for listeners, it is usually the opposite.
00287      *
00288      */
00289     
00290     while ( ! _listeners.empty() )
00291     {
00292     
00293         widget = _listeners.back() ;
00294         widget->unsubscribeFrom( *this ) ;
00295         
00296         /*
00297          * Do not use : '_listeners.pop_back() ;' since this widget has 
00298          * already been removed thanks to the call to unsubscribeFrom : it 
00299          * would pop next listener !
00300          *
00301          */
00302         delete widget ;
00303         
00304     }
00305     
00306     // Never let invalid structures in the way :
00307     _listeners.clear() ;
00308     
00309     // Do not deallocate if screen surface :
00310     if ( _displayType == BackBuffer )
00311         flush() ;
00312     
00313 }
00314 
00315 
00316 Clonable & Surface::clone() const throw( ClonableException )
00317 {
00318     
00319     
00320     if ( _surface != 0 )
00321     {
00322     
00323 #ifdef OSDL_USE_DEPRECATED_CLONING
00324         
00325         // Previous implementation :
00326         
00327         // Retrieve the state of this source surface :
00328         Pixels::ColorMask redMask, greenMask, blueMask, alphaMask ;     
00329         Pixels::getCurrentColorMasks( getPixelFormat(), 
00330             redMask, greenMask, blueMask, alphaMask ) ;
00331         
00332         // Create a similar but blank surface :
00333         SDL_Surface * copied = SDL_CreateRGBSurface( getFlags(), 
00334             getWidth(), getHeight(), getBitsPerPixel(), 
00335             redMask, greenMask, blueMask, alphaMask ) ;
00336          
00337         /*
00338          * Blit the source content onto it :
00339          *
00340          * "The blit function should not be called on a locked surface" : 
00341          * which one ?
00342          * Supposing it is the target surface, 'copied', which is not locked.
00343          *
00344          */
00345          
00346         int returned = SDL_BlitSurface( _surface, 0, copied, 0 ) ;
00347         if ( returned != 0 )
00348             throw ClonableException( "Surface::clone : blit failed (returned " 
00349                 + Ceylan::toString( returned ) + ") : " 
00350                 + Utils::getBackendLastError() + "." ) ;
00351         
00352         
00353         /*
00354          * Ensures that the clone has a colorkey if the original has it :
00355          *
00356             if ( copied... )
00357                 copied.setColorKey( [...] ) ;
00358          *
00359          */
00360          
00361 #endif // OSDL_USE_DEPRECATED_CLONING
00362         
00363         
00364         // Far better and simpler version :
00365         SDL_Surface * copied = SDL_ConvertSurface( _surface, 
00366             & getPixelFormat(), getFlags() ) ;
00367         
00368         
00369         if ( copied == 0 )
00370             throw ClonableException( 
00371                 "Surface::clone : creation of clone surface failed : " 
00372                 + Utils::getBackendLastError() + "." ) ;
00373                  
00374         return * new Surface( * copied, 
00375             /* clones cannot be a screen surface */ BackBuffer ) ;
00376         
00377     }
00378     else
00379     {
00380         LogPlug::warning( "Surface::clone : cloning a mostly blank surface." ) ;
00381         return * new Surface() ; 
00382     }   
00383         
00384 }
00385 
00386 
00387 SDL_Surface & Surface::getSDLSurface() const throw()
00388 {
00389 
00390     // addRef   
00391     return * _surface ;
00392     
00393 }
00394 
00395 
00396 void Surface::setSDLSurface( SDL_Surface & newSurface, 
00397     DisplayType displayType ) throw()
00398 {
00399             
00400     // Free any previously held surface, and replace it with the provided one.
00401     flush() ;
00402             
00403     _surface = & newSurface ;
00404     _displayType = displayType ;
00405     
00406 }
00407 
00408 
00409 Surface::DisplayType Surface::getDisplayType() const throw()
00410 {
00411 
00412     return _displayType ;
00413     
00414 }
00415 
00416 
00417 void Surface::setDisplayType( DisplayType newDisplayType ) throw()
00418 {
00419 
00420     _displayType = newDisplayType ;
00421     
00422 }
00423 
00424 
00425 Ceylan::Flags Surface::getFlags() const throw()
00426 {
00427 
00428     return _surface->flags ;
00429     
00430 }
00431 
00432 
00433 void Surface::setFlags( Flags newFlags ) throw()
00434 {
00435 
00436     // Use with caution : internal SDL_Surface not changed.
00437     _surface->flags = newFlags ;
00438     
00439 }
00440 
00441 
00442 void Surface::convertToDisplay( bool alphaChannelWanted ) 
00443     throw( VideoException )
00444 {
00445 
00446     if ( _surface == 0 )
00447         throw VideoException( 
00448             "Surface::convertToDisplay : no available internal surface." ) ;
00449         
00450     SDL_Surface * old = _surface ;
00451     
00452     if ( alphaChannelWanted )
00453         _surface = SDL_DisplayFormatAlpha( old ) ;
00454     else
00455         _surface = SDL_DisplayFormat( old ) ;
00456 
00457     SDL_FreeSurface( old ) ;
00458     
00459     if ( _surface == 0 )
00460         throw VideoException( 
00461             "Surface::convertToDisplay : conversion failed." ) ;        
00462                 
00463 }
00464 
00465 
00466 void Surface::setAlpha( Flags flags, Pixels::ColorElement newAlpha ) 
00467     throw( VideoException )
00468 {
00469 
00470     if ( SDL_SetAlpha( _surface, flags, newAlpha ) != 0 )
00471         throw VideoException( "Surface::setAlpha failed : " 
00472             + Utils::getBackendLastError() ) ;
00473              
00474 }
00475 
00476 
00477 void Surface::setColorKey( Flags flags, Pixels::PixelColor keyPixelColor )
00478     throw( VideoException )
00479 {
00480 
00481     if ( SDL_SetColorKey( _surface, flags, keyPixelColor ) != 0 )
00482         throw VideoException( "Surface::setColorKey (pixel color) failed : "
00483             + Utils::getBackendLastError() ) ; 
00484             
00485 }
00486 
00487 
00488 void Surface::setColorKey( Flags flags, Pixels::ColorDefinition keyColorDef ) 
00489     throw( VideoException )
00490 {
00491 
00492     Pixels::PixelColor keyPixelColor = 
00493         Pixels::convertColorDefinitionToPixelColor( getPixelFormat(),
00494             keyColorDef ) ;
00495         
00496     if ( SDL_SetColorKey( _surface, flags, keyPixelColor ) != 0 )
00497         throw VideoException( 
00498             "Surface::setColorKey (color definition) failed : "
00499             + Utils::getBackendLastError() ) ; 
00500             
00501 }
00502 
00503 
00504 void Surface::convertFromColorKeyToAlphaChannel() throw( VideoException )
00505 {
00506     
00507     if ( ( getFlags() & ColorkeyBlit ) == 0 )
00508         throw VideoException( "Surface::convertFromColorKeyToAlphaChannel : "
00509             "this surface does not use color key apparently : " 
00510             + toString( Ceylan::low ) ) ;
00511             
00512     convertToDisplay( /* alphaChannelWanted */ true ) ;
00513             
00514 }
00515 
00516 
00517 bool Surface::setPalette( Palette & newPalette, ColorCount startingColorIndex,
00518     ColorCount numberOfColors, Flags targettedPalettes ) throw() 
00519 {
00520 
00521     if ( numberOfColors == 0 )
00522     {
00523     
00524         if ( newPalette.getNumberOfColors() > startingColorIndex )
00525         {
00526             numberOfColors = 
00527                 newPalette.getNumberOfColors() - startingColorIndex ;
00528         }       
00529         else
00530         {
00531             LogPlug::error( 
00532                 "Surface::setPalette : starting index out of bounds." );
00533             return false ;
00534         }
00535             
00536     }
00537     else if ( startingColorIndex + numberOfColors >
00538         newPalette.getNumberOfColors() )
00539     {
00540         LogPlug::error( 
00541             "Surface::setPalette : too many color indexes, out of bounds." );
00542         return false ;
00543     }   
00544 
00545     return static_cast<bool>( SDL_SetPalette( _surface, targettedPalettes, 
00546         newPalette.getColorDefinitions(), startingColorIndex, 
00547         numberOfColors ) ) ;
00548         
00549 }
00550                     
00551 
00552 Pixels::PixelFormat & Surface::getPixelFormat() const throw()
00553 {
00554 
00555     if ( _surface->format == 0 )
00556         Ceylan::emergencyShutdown( "Surface::getPixelFormat called "
00557             "whereas no pixel format available." ) ;
00558     
00559     return * _surface->format ;
00560     
00561 }
00562 
00563 
00564 void Surface::setPixelFormat( Pixels::PixelFormat & newFormat ) throw() 
00565 {
00566     _surface->format = & newFormat ;
00567 }
00568 
00569 
00570 bool Surface::fill( Pixels::ColorDefinition colorDef ) throw()
00571 {
00572 
00573 #if OSDL_DEBUG_SURFACE
00574 
00575     LogPlug::trace( "Surface::fill in rectangular area from [" 
00576         + Ceylan::toString( _x ) + ";" 
00577         + Ceylan::toString( _y ) + "] to [" 
00578         + Ceylan::toString( _x + getWidth() ) + ";" 
00579         + Ceylan::toString( _y + getHeight() ) + "]" ) ;
00580          
00581 #endif // OSDL_DEBUG_SURFACE
00582     
00583     // Ignores clipping area :
00584     return drawBox( /* the surface *is* an UprightRectangle */ *this,
00585         colorDef, /* filled */ true ) ;
00586         
00587 }
00588 
00589 
00590 bool Surface::clear() throw()
00591 {
00592 
00593     return fill( /* clear color */ Pixels::Black ) ;
00594     
00595 }
00596 
00597 
00598 Surface & Surface::flipVertical() const throw()
00599 {    
00600 
00601     SDL_Surface * result = SDL_CreateRGBSurface( 
00602         _surface->flags, 
00603         _surface->w, 
00604         _surface->h,
00605         _surface->format->BytesPerPixel * 8, 
00606         _surface->format->Rmask, 
00607         _surface->format->Gmask,
00608         _surface->format->Bmask,
00609         _surface->format->Amask ) ;
00610          
00611     BytesPerPixel bpp = _surface->format->BytesPerPixel ;
00612     
00613     Ceylan::Uint16 scanline = _surface->pitch ;
00614     
00615     Ceylan::Uint8 * src  = 
00616         reinterpret_cast<Ceylan::Uint8 *>( _surface->pixels ) ;
00617         
00618     Ceylan::Uint8 * target =
00619         reinterpret_cast<Ceylan::Uint8 *>( result->pixels ) + scanline - bpp ;
00620   
00621     const Coordinate height = result->h ;
00622     const Coordinate width  = result->w ;
00623     
00624     /*
00625      * Line by line, stores the copied pixel from right to left in target
00626      * surface :
00627      *
00628      */
00629     
00630     for ( Coordinate y = 0; y < height; y++ )
00631         for ( Coordinate x = 0; x < width; x++ )
00632             ::memcpy( target + ( ( scanline * y ) - ( x * bpp ) ),
00633                 src + ( ( scanline * y ) + ( x * bpp ) ), bpp ) ;
00634                 
00635     return * new Surface( * result ) ;
00636     
00637 }
00638 
00639 
00640 Surface & Surface::flipHorizontal() const throw()
00641 {
00642 
00643     SDL_Surface * result = SDL_CreateRGBSurface( 
00644         _surface->flags, 
00645         _surface->w, 
00646         _surface->h,
00647         _surface->format->BytesPerPixel * 8, 
00648         _surface->format->Rmask, 
00649         _surface->format->Gmask,
00650         _surface->format->Bmask, 
00651         _surface->format->Amask ) ;
00652 
00653     Ceylan::Uint16 scanline = _surface->pitch ;
00654 
00655     Ceylan::Uint8 * src    =
00656         reinterpret_cast<Ceylan::Uint8 *>( _surface->pixels ) ;
00657         
00658     Ceylan::Uint8 * target = 
00659         reinterpret_cast<Ceylan::Uint8 *>( result->pixels ) 
00660             + result->pitch * ( result->h - 1 ) ;
00661 
00662     const Coordinate height = result->h ;
00663   
00664     // Changes simply the order of the lines :
00665     
00666     for ( Coordinate y = 0; y < height; y++ )
00667         ::memcpy ( target - ( scanline * y ), 
00668             src + ( scanline * y ), scanline ) ;
00669 
00670     return * new Surface( * result ) ;
00671 
00672 }
00673 
00674 
00675 string Surface::describePixelAt( Coordinate x, Coordinate y ) throw()
00676 {
00677 
00678     string res = "Pixel at [" + Ceylan::toString( x ) + ";" 
00679         + Ceylan::toString( y ) + "] : " ;
00680     
00681     lock() ;
00682     PixelColor p = getPixelColorAt( x, y ) ;
00683     unlock() ;
00684     
00685     res += "pixel color is " + Ceylan::toHexString( p ) + " : " ;
00686     
00687     return res + Pixels::toString( p, getPixelFormat() ) ;
00688     
00689 }
00690 
00691 
00692 Pitch Surface::getPitch() const throw()
00693 {
00694 
00695     return  _surface->pitch ;
00696     
00697 }
00698 
00699 
00700 void Surface::setPitch( Pitch newPitch ) throw() 
00701 {
00702 
00703     _surface->pitch = newPitch ;
00704     
00705 }
00706 
00707 
00708 Length Surface::getWidth() const throw() 
00709 {
00710 
00711     return _surface->w ;
00712     
00713 }
00714 
00715 
00716 void Surface::setWidth( Length newWidth ) throw()
00717 {
00718 
00719     resize( newWidth, getHeight() ) ;
00720     
00721 }
00722 
00723 
00724 Length Surface::getHeight() const throw()
00725 {
00726 
00727     return _surface->h ;
00728 }
00729 
00730 
00731 
00732 void Surface::setHeight( Length newHeight ) throw()
00733 {
00734 
00735     resize( getWidth(), newHeight ) ;
00736     
00737 }
00738 
00739 
00740 void Surface::resize( Length newWidth, Length newHeight, bool scaleContent )
00741     throw() 
00742 {   
00743     
00744     if ( ( newWidth == getWidth() ) && ( newHeight == getHeight() ) )
00745         return ;
00746         
00747     // Retrieve the state of this current surface :
00748     Pixels::ColorMask redMask, greenMask, blueMask, alphaMask ; 
00749         
00750     Pixels::getCurrentColorMasks( getPixelFormat(), 
00751         redMask, greenMask, blueMask, alphaMask ) ;
00752         
00753     // Create a similar surface whose size is the requested one  :
00754     SDL_Surface * resized = SDL_CreateRGBSurface( getFlags(), 
00755         newWidth, newHeight, getBitsPerPixel(), 
00756             redMask, greenMask, blueMask, alphaMask ) ;
00757     
00758     // Cannot throw exception since inherited setWidth/Height methods cannot :
00759     if ( resized == 0 )
00760         Ceylan::emergencyShutdown( 
00761             "Surface::resize : creation of newer internal surface failed : "
00762             + Utils::getBackendLastError() ) ; 
00763 
00764     
00765     // Needed to fix colorkey afterwards (copied exactly as is) :
00766     Flags colorKeyFlags = getFlags() & ( ColorkeyBlit | RLEColorkeyBlit ) ;
00767     Pixels::PixelColor colorkey = _surface->format->colorkey ;
00768     
00769     // Fixing per-alpha settings :
00770     resized->format->alpha = _surface->format->alpha ;
00771     
00772     // @todo : fix other alpha settings (if any) and maybe lock as well ?
00773     
00774     Surface * zoomed ;
00775     
00776     if ( scaleContent )
00777     {
00778     
00779         try
00780         {
00781         
00782             zoomed = & zoom( 
00783                 static_cast<Ceylan::Maths::Real>( newWidth )  / getWidth(),
00784                 static_cast<Ceylan::Maths::Real>( newHeight ) / getHeight(),
00785                 VideoModule::GetAntiAliasingState() ) ;
00786                 
00787         }
00788         catch( const VideoException & e )
00789         {
00790             Ceylan::emergencyShutdown( 
00791                 "Surface::resize : creation of scaled surface failed : "
00792                 + e.toString() ) ;      
00793         }   
00794         
00795     }
00796     
00797     SDL_FreeSurface( _surface ) ;
00798     
00799     _surface = resized ;
00800     
00801     setColorKey( colorKeyFlags, colorkey ) ;
00802     
00803     if ( scaleContent )
00804     {
00805     
00806         try
00807         {
00808     
00809             zoomed->blitTo( * this ) ;
00810             delete zoomed ;
00811 
00812         }
00813         catch( const VideoException & e )
00814         {
00815             Ceylan::emergencyShutdown( 
00816                 "Surface::resize : blit of scaled surface failed : "
00817                 + e.toString() ) ;      
00818         }   
00819         
00820     }
00821     else
00822     {
00823         setRedrawState( true ) ;    
00824     }
00825     
00826     
00827 }
00828 
00829 
00830 BitsPerPixel Surface::getBitsPerPixel() const throw()
00831 {
00832 
00833     return _surface->format->BitsPerPixel ;
00834     
00835 }
00836 
00837 
00838 void Surface::setBitsPerPixel( BitsPerPixel newBitsPerPixel ) throw() 
00839 {
00840 
00841     _surface->format->BitsPerPixel = newBitsPerPixel ;
00842     
00843     // SDL surface's BytesPerPixel left untouched.
00844     
00845 }
00846 
00847 
00848 BytesPerPixel Surface::getBytesPerPixel() const throw()
00849 {
00850 
00851     return _surface->format->BytesPerPixel ;
00852     
00853 }
00854 
00855 
00856 void Surface::setBytesPerPixel( BytesPerPixel newBytesPerPixel ) throw() 
00857 {
00858 
00859     _surface->format->BytesPerPixel = newBytesPerPixel ;
00860     
00861     // SDL surface's BitsPerPixel left untouched.
00862     
00863 }
00864 
00865 
00866 void * Surface::getPixels() const throw() 
00867 {
00868 
00869     return _surface->pixels ;
00870         
00871 }
00872 
00873 
00874 
00875 void Surface::setPixels( void * newPixels ) throw()
00876 {
00877 
00878     _surface->pixels = newPixels ;
00879     
00880 }
00881 
00882 
00883 
00884 
00885 // Proxy methods section.
00886 
00887 
00888 Pixels::PixelColor Surface::getPixelColorAt( Coordinate x, Coordinate y ) const 
00889     throw( VideoException )
00890 {
00891 
00892     return Pixels::getPixelColor( *this, x, y ) ;
00893       
00894 }
00895 
00896 
00897 Pixels::ColorDefinition Surface::getColorDefinitionAt( 
00898     Coordinate x, Coordinate y ) const throw( VideoException )
00899 {
00900 
00901     return Pixels::convertPixelColorToColorDefinition( getPixelFormat(),
00902         Pixels::getPixelColor( *this, x, y ) ) ;  
00903         
00904 }
00905 
00906 
00907 
00908 void Surface::putRGBAPixelAt( Coordinate x, Coordinate y,
00909         ColorElement red, ColorElement green, ColorElement blue, 
00910         ColorElement alpha, 
00911         bool blending, bool clipping, bool locking ) throw( VideoException ) 
00912 {
00913 
00914     Pixels::putRGBAPixel( *this, x, y, red, green, blue, alpha, 
00915         blending, clipping, locking ) ;
00916     
00917 }
00918 
00919 
00920 
00921 void Surface::putColorDefinitionAt( Coordinate x, Coordinate y,
00922         ColorDefinition colorDef, 
00923         bool blending, bool clipping, bool locking ) throw( VideoException ) 
00924 {
00925 
00926     Pixels::putRGBAPixel( *this, x, y, colorDef.r, colorDef.g, colorDef.b,
00927         colorDef.unused, blending, clipping, locking ) ;
00928         
00929 }
00930 
00931 
00932 void Surface::putPixelColorAt( Coordinate x, Coordinate y,
00933         PixelColor convertedColor, ColorElement alpha,
00934         bool blending, bool clipping, bool locking ) throw( VideoException ) 
00935 {
00936 
00937     Pixels::putPixelColor( *this, x, y, convertedColor, alpha, 
00938         blending, clipping, locking ) ;
00939         
00940 }
00941 
00942 
00943 
00944 bool Surface::setAlphaForColor( Pixels::ColorDefinition colorDef,
00945     Pixels::ColorElement newAlpha ) throw()
00946 {
00947     
00948 #if OSDL_DEBUG_COLOR
00949 
00950     LogPlug::trace( 
00951         "Surface::setAlphaForColor : scanning for color definition " 
00952         + Pixels::toString( colorDef ) 
00953         + ", so that its alpha coordinate gets replaced by "
00954         + Ceylan::toNumericalString( newAlpha ) ) ;
00955         
00956 #endif // OSDL_DEBUG_COLOR
00957         
00958     /*
00959      * Useless if surface has no alpha coordinate (maybe the alpha mask 
00960      * could be checked too) :  
00961      *
00962      */
00963     if ( ( getFlags() & AlphaBlendingBlit ) == 0 )
00964         return false ;
00965     
00966     ColorDefinition currentDef ;
00967         
00968     lock() ;
00969     
00970     Length height = getHeight() ;
00971     Length width  = getWidth() ;
00972     
00973     for ( Coordinate y = 0; y < height; y++ )
00974         for ( Coordinate x = 0; x < width; x++ )
00975         {
00976                 
00977             currentDef = getColorDefinitionAt( x, y ) ;
00978             
00979             // Replace the pixel with a new alpha only if RGB matches :
00980             if ( Pixels::areEqual( currentDef, colorDef, 
00981                 /* use alpha */ false ) )
00982             {   
00983             
00984 #if OSDL_DEBUG_PIXEL
00985                 if ( x % 20 == 0 && y % 20 == 0 )
00986                     LogPlug::debug( 
00987                         "Surface::setAlphaForColor : replacing alpha of " 
00988                         + Pixels::toString( currentDef ) + " with new alpha = " 
00989                         + Ceylan::toNumericalString( newAlpha ) + " at ["
00990                         + Ceylan::toString( x ) + ";" + Ceylan::toString( y ) 
00991                         + "]" ) ;
00992 #endif // OSDL_DEBUG_PIXEL
00993                     
00994                 currentDef.unused = newAlpha ;
00995                 
00996                 putColorDefinitionAt( x, y, currentDef, 
00997                     /* no blending since put alpha must not be modified */ 
00998                         false ) ;
00999                 
01000 #if OSDL_DEBUG_PIXEL
01001 
01002                 // Re-read to check modification :
01003                 if ( x % 20 == 0 && y % 20 == 0 )
01004                 {
01005                 
01006                     ColorDefinition readDef = getColorDefinitionAt( x, y ) ;
01007                     
01008                     if ( ! Pixels::areEqual( readDef, currentDef, 
01009                             /* use alpha */ true ) )
01010                         LogPlug::error( "Surface::setAlphaForColor : "
01011                             "alpha replacement failed : expecting " 
01012                             + Pixels::toString( readDef ) 
01013                             + ", read " + Pixels::toString( currentDef ) ) ;
01014                 }
01015                 
01016 #endif // OSDL_DEBUG_PIXEL
01017                     
01018             }
01019             else
01020             {
01021             
01022                 /*
01023                 if ( x % 10 == 0 && y % 10 == 0 )
01024                     LogPlug::debug( "Surface::setAlphaForColor : pixel in ["
01025                         + Ceylan::toString( x ) + ";" + Ceylan::toString( y ) 
01026                         + "], whose color definition is " 
01027                         + Pixels::toString( currentDef ) 
01028                         + ", does not match." ) ;
01029                 */
01030             }
01031         
01032         }
01033         
01034     unlock() ;
01035     
01036     return true ;
01037         
01038 }
01039 
01040 
01041 bool Surface::drawHorizontalLine( Coordinate xStart, Coordinate xStop,
01042     Coordinate y, Pixels::ColorElement red, Pixels::ColorElement green, 
01043     Pixels::ColorElement blue, Pixels::ColorElement alpha ) throw()
01044 {
01045 
01046     return Line::drawHorizontal( *this,  xStart, xStop, y, 
01047         red, green, blue, alpha ) ;
01048         
01049 }
01050 
01051 
01052 bool Surface::drawHorizontalLine( Coordinate xStart, Coordinate xStop,
01053     Coordinate y, Pixels::PixelColor actualColor ) throw()
01054 {
01055 
01056     return Line::drawHorizontal( *this,  xStart, xStop, y, actualColor ) ;
01057     
01058 }
01059 
01060 
01061 bool Surface::drawHorizontalLine( Coordinate xStart, Coordinate xStop,
01062     Coordinate y, Pixels::ColorDefinition colorDef ) throw()
01063 {
01064 
01065     return Line::drawHorizontal( *this,  xStart, xStop, y, colorDef ) ;
01066     
01067 }
01068 
01069 
01070 
01071 bool Surface::drawVerticalLine( Coordinate x, Coordinate yStart, 
01072     Coordinate yStop, Pixels::ColorElement red, Pixels::ColorElement green, 
01073     Pixels::ColorElement blue, Pixels::ColorElement alpha) throw()
01074 {
01075 
01076     return Line::drawVertical( *this,  x, yStart, yStop, 
01077         red, green, blue, alpha ) ;
01078         
01079 }
01080     
01081     
01082 bool Surface::drawVerticalLine( Coordinate x, Coordinate yStart,
01083      Coordinate yStop, Pixels::ColorDefinition colorDef ) throw()
01084 {
01085 
01086     return Line::drawVertical( *this,  x, yStart, yStop, colorDef ) ;
01087     
01088 }
01089 
01090     
01091     
01092 bool Surface::drawLine( Coordinate xStart, Coordinate yStart,
01093     Coordinate xStop, Coordinate yStop, 
01094     Pixels::ColorElement red, Pixels::ColorElement green, 
01095     Pixels::ColorElement blue, Pixels::ColorElement alpha ) throw()
01096 {
01097 
01098     return Line::draw( *this, xStart, yStart, xStop, yStop, 
01099         red, green, blue, alpha ) ;
01100         
01101 }
01102 
01103 
01104 bool Surface::drawLine( Coordinate xStart, Coordinate yStart,
01105         Coordinate xStop, Coordinate yStop, Pixels::ColorDefinition colorDef )
01106     throw()
01107 {
01108 
01109     return Line::draw( *this, xStart, yStart, xStop, yStop, colorDef ) ;
01110     
01111 }
01112 
01113 
01114 bool Surface::drawCross( const Point2D & center, 
01115     Pixels::ColorDefinition colorDef, Length squareEdge ) throw() 
01116 {
01117 
01118     return Line::drawCross( *this, center, colorDef, squareEdge ) ;
01119     
01120 }
01121 
01122 
01123 bool Surface::drawCross( Coordinate xCenter, Coordinate yCenter,
01124     Pixels::ColorDefinition colorDef, Length squareEdge ) throw() 
01125 {
01126 
01127     return Line::drawCross( *this, xCenter, yCenter, colorDef, squareEdge ) ;
01128     
01129 }
01130     
01131 
01132 bool Surface::drawEdges( Pixels::ColorDefinition edgeColor, Length edgeWidth )
01133     throw() 
01134 {
01135     
01136     Coordinate xmin = 0 ;
01137     Coordinate xmax = getWidth() - 1 ;
01138     
01139     Coordinate ymin = 0 ;
01140     Coordinate ymax = getHeight() - 1 ;
01141     
01142     while ( edgeWidth != 0 )
01143     {
01144     
01145         if ( ! drawVerticalLine( xmin, ymin, ymax, edgeColor ) )
01146             return false ;
01147             
01148         if ( ! drawVerticalLine( xmax, ymin, ymax, edgeColor ) )
01149             return false ;
01150             
01151         if ( ! drawHorizontalLine( xmin, xmax, ymin, edgeColor ) )
01152             return false ;
01153             
01154         if ( ! drawHorizontalLine( xmin, xmax, ymax, edgeColor ) )
01155             return false ;
01156                 
01157         edgeWidth-- ;
01158         
01159         xmin++ ;
01160         xmax -- ;
01161         
01162         ymin++ ;
01163         ymax-- ;
01164     }
01165     
01166     return true ;
01167     
01168 }
01169 
01170 
01171 bool Surface::drawBox( const UprightRectangle & rectangle, 
01172         Pixels::ColorElement red, Pixels::ColorElement green, 
01173         Pixels::ColorElement blue, Pixels::ColorElement alpha, bool filled ) 
01174     throw()
01175 {
01176 
01177     return rectangle.draw( *this, red, green, blue, alpha, filled ) ;
01178     
01179 }
01180     
01181     
01182 bool Surface::drawBox( const UprightRectangle & rectangle, 
01183     Pixels::ColorDefinition colorDef, bool filled ) throw()
01184 {
01185 
01186     return rectangle.draw( *this, colorDef, filled ) ;
01187     
01188 }
01189     
01190 
01191 
01192 bool Surface::drawCircle( Coordinate xCenter, Coordinate yCenter, 
01193     Length radius, Pixels::ColorElement red, Pixels::ColorElement green, 
01194     Pixels::ColorElement blue, Pixels::ColorElement alpha,
01195     bool filled, bool blended ) throw()
01196 {
01197 
01198     return TwoDimensional::drawCircle( *this, xCenter, yCenter, radius, 
01199         red, green, blue, alpha, filled, blended ) ;
01200                 
01201 }
01202 
01203 
01204 bool Surface::drawCircle( Coordinate xCenter, Coordinate yCenter, 
01205     Length radius, Pixels::ColorDefinition colorDef, 
01206     bool filled, bool blended ) throw()
01207 {
01208 
01209     return TwoDimensional::drawCircle( *this, xCenter, yCenter, radius, 
01210         colorDef, filled, blended ) ;
01211                         
01212 }
01213 
01214 
01215 bool Surface::drawDiscWithEdge( Coordinate xCenter, Coordinate yCenter, 
01216     Length outerRadius, Length innerRadius, 
01217     Pixels::ColorDefinition ringColorDef, 
01218     Pixels::ColorDefinition discColorDef, bool blended ) throw()
01219 {
01220 
01221     return TwoDimensional::drawDiscWithEdge( *this, xCenter, yCenter,
01222         outerRadius, innerRadius, ringColorDef, discColorDef, blended ) ;       
01223         
01224 }   
01225                     
01226 
01227 bool Surface::drawEllipse( Coordinate xCenter, Coordinate yCenter, 
01228     Length horizontalRadius, Length verticalRadius,
01229     Pixels::ColorElement red, Pixels::ColorElement green, 
01230     Pixels::ColorElement blue, Pixels::ColorElement alpha, bool filled ) throw()
01231 {
01232 
01233     return TwoDimensional::drawEllipse( *this, xCenter, yCenter,
01234         horizontalRadius, verticalRadius, red, green, blue, alpha, filled ) ;   
01235             
01236 }
01237 
01238 
01239 bool Surface::drawEllipse( Coordinate xCenter, Coordinate yCenter, 
01240     Length horizontalRadius, Length verticalRadius,
01241     Pixels::ColorDefinition colorDef, bool filled ) throw()
01242 {
01243 
01244     return TwoDimensional::drawEllipse( *this, xCenter, yCenter,
01245         horizontalRadius, verticalRadius, colorDef, filled ) ;      
01246         
01247 }
01248 
01249 
01250 
01251 bool Surface::drawPie( Coordinate xCenter, Coordinate yCenter, Length radius, 
01252     Ceylan::Maths::AngleInDegrees angleStart, 
01253     Ceylan::Maths::AngleInDegrees angleStop,
01254     Pixels::ColorElement red, Pixels::ColorElement green, 
01255     Pixels::ColorElement blue, Pixels::ColorElement alpha ) throw() 
01256 {
01257 
01258     return TwoDimensional::drawPie( *this, xCenter, yCenter, radius, 
01259         angleStart, angleStop, red, green, blue, alpha ) ;
01260         
01261 }
01262 
01263 
01264 bool Surface::drawPie( Coordinate xCenter, Coordinate yCenter, Length radius, 
01265     Ceylan::Maths::AngleInDegrees angleStart, 
01266     Ceylan::Maths::AngleInDegrees angleStop, 
01267     Pixels::ColorDefinition colorDef ) throw()      
01268 {
01269 
01270     return TwoDimensional::drawPie( *this, xCenter, yCenter, 
01271         radius, angleStart, angleStop, colorDef ) ;
01272         
01273 }
01274 
01275 
01276 
01277 bool Surface::drawTriangle( Coordinate x1, Coordinate y1, 
01278         Coordinate x2, Coordinate y2, Coordinate x3, Coordinate y3,
01279         Pixels::ColorElement red, Pixels::ColorElement green, 
01280         Pixels::ColorElement blue, Pixels::ColorElement alpha, bool filled ) 
01281     throw()
01282 {
01283 
01284     return TwoDimensional::drawTriangle( *this, x1, y1, x2, y2, x3, y3, 
01285         red, green, blue, alpha, filled ) ;
01286         
01287 }       
01288 
01289 
01290 
01291 bool Surface::drawTriangle( Coordinate x1, Coordinate y1, 
01292     Coordinate x2, Coordinate y2, Coordinate x3, Coordinate y3,
01293     Pixels::ColorDefinition colorDef, bool filled ) throw()
01294 {
01295 
01296     return TwoDimensional::drawTriangle( *this, x1, y1, x2, y2, x3, y3,
01297         colorDef, filled ) ;
01298         
01299 }   
01300 
01301 
01302     
01303 bool Surface::drawTriangle( const Point2D & p1, const Point2D & p2, 
01304         const Point2D & p3, 
01305         Pixels::ColorElement red, Pixels::ColorElement green, 
01306         Pixels::ColorElement blue, Pixels::ColorElement alpha, bool filled ) 
01307     throw()
01308 {
01309 
01310     return TwoDimensional::drawTriangle( *this, p1, p2, p3, 
01311         red, green, blue, alpha, filled ) ;
01312         
01313 }   
01314     
01315     
01316 
01317 bool Surface::drawTriangle( const Point2D & p1, const Point2D & p2, 
01318     const Point2D & p3, Pixels::ColorDefinition colorDef, bool filled ) throw()
01319 {
01320 
01321     return TwoDimensional::drawTriangle( *this, p1, p2, p3, 
01322         colorDef, filled ) ;
01323         
01324 }   
01325     
01326     
01327     
01328 bool Surface::drawPolygon( const list<Point2D *> summits, 
01329     Coordinate x, Coordinate y,
01330     Pixels::ColorDefinition colorDef, bool filled ) throw()
01331 {
01332 
01333     return TwoDimensional::drawPolygon( *this, summits, x, y, 
01334         colorDef, filled ) ;
01335             
01336 }
01337 
01338 
01339 
01340 bool Surface::drawPolygon( const list<Point2D *> summits, 
01341     Coordinate x, Coordinate y,
01342     Pixels::ColorElement red, Pixels::ColorElement green, 
01343     Pixels::ColorElement blue, Pixels::ColorElement alpha, bool filled ) throw()
01344 {
01345 
01346     return TwoDimensional::drawPolygon( *this, summits, x, y, 
01347         red, green, blue, alpha, filled ) ;
01348         
01349 }
01350 
01351 
01352 
01353 bool Surface::drawGrid( Length columnStride, Length rowStride,
01354     Pixels::ColorDefinition lineColor, 
01355     bool fillBackground, Pixels::ColorDefinition backColor ) throw()
01356 {
01357 
01358     // Take into account the grid line itself :
01359     columnStride++ ;
01360     rowStride++ ; 
01361     
01362     if ( fillBackground )
01363     {
01364         if ( fill( backColor ) == false )
01365             return false ;
01366     }
01367     
01368     Length xBorder = getWidth() ;
01369     Length yBorder = getHeight() ;
01370 
01371     Coordinate x = 0 ;
01372     
01373     // Draw columns :
01374     while ( x < xBorder )
01375     {
01376         if ( ! drawVerticalLine( x, 0, yBorder, lineColor ) )
01377             return false ;
01378         x += columnStride ;
01379     }
01380 
01381     Coordinate y = 0 ;
01382     
01383     // Draw rows :
01384     while ( y < yBorder )
01385     {
01386         if ( ! drawHorizontalLine( 0, xBorder, y, lineColor ) )
01387             return false ;
01388         y += rowStride ;
01389     }
01390     
01391     return true ;
01392         
01393 }
01394     
01395     
01396                     
01397                                     
01398 bool Surface::printText( const std::string & text, Coordinate x, Coordinate y, 
01399     Pixels::ColorElement red, Pixels::ColorElement green, 
01400     Pixels::ColorElement blue, Pixels::ColorElement alpha ) throw() 
01401 {
01402 
01403     return Text::printBasic( text, *this, x, y, red, green, blue, alpha ) ;
01404     
01405 }
01406 
01407 
01408 
01409 bool Surface::printText( const std::string & text, Coordinate x, Coordinate y, 
01410     ColorDefinition colorDef ) throw()  
01411 {
01412 
01413     return Text::printBasic( text, *this, x, y, colorDef ) ;
01414     
01415 }
01416 
01417 
01418 bool Surface::blitTo( Surface & targetSurface ) const throw( VideoException )
01419 {
01420 
01421     return blitTo( targetSurface, 0, 0 ) ;
01422     
01423 }
01424 
01425 
01426 bool Surface::blitTo( Surface & targetSurface, Coordinate x, Coordinate y ) 
01427     const throw( VideoException )
01428 {
01429 
01430 #if OSDL_DEBUG_WIDGET
01431 
01432     LogPlug::trace( "Surface::blitTo : blitting to [" + Ceylan::toString( x )
01433         + ";" + Ceylan::toString( y ) + "]."  ) ; 
01434         
01435 #endif // OSDL_DEBUG_WIDGET
01436 
01437 
01438 #if OSDL_DEBUG
01439 
01440     if ( isLocked() )
01441         throw VideoException( "Surface::blitTo with no source rectangle called "
01442             "whereas surface is locked." ) ;
01443             
01444 #endif // OSDL_DEBUG
01445 
01446     SDL_Rect destinationRect ;
01447     
01448     destinationRect.x = x ;
01449     destinationRect.y = y ;
01450     // destinationRect width and height do not matter for SDL_BlitSurface.
01451     
01452     switch( SDL_BlitSurface( & getSDLSurface(), /* sourceRectangle */ 0, 
01453         & targetSurface.getSDLSurface(), & destinationRect ) )
01454     {
01455     
01456         case 0:
01457             // Success.
01458             return true ;
01459             break ;
01460                 
01461         case -2:
01462             /*
01463              * VideoMemoryLostException is a child class of VideoException, 
01464              * no special message to deliver :
01465              *
01466              */
01467             throw VideoMemoryLostException() ;
01468             break ;
01469     
01470         case -1:
01471             throw VideoException( 
01472                 "Surface::blitTo with no source rectangle : error in blit, " 
01473                 + Utils::getBackendLastError() ) ;
01474             break ;
01475     
01476         default:
01477             LogPlug::error( "Unexpected returned value in Surface::blitTo "
01478                 "with no source rectangle." ) ;
01479             return false ;  
01480             break ;
01481     }
01482                     
01483     return false ;  
01484         
01485 }
01486 
01487 
01488 
01489 bool Surface::blitTo( Surface & targetSurface, 
01490     const TwoDimensional::Point2D & location ) const throw( VideoException )
01491 {
01492 
01493     return blitTo( targetSurface, location.getX(), location.getY() ) ;
01494     
01495 }
01496 
01497 
01498 
01499 bool Surface::blitTo( Surface & targetSurface, 
01500         const TwoDimensional::UprightRectangle & sourceRectangle,
01501         const TwoDimensional::Point2D & destinationLocation ) 
01502     const throw( VideoException )
01503 {
01504 
01505 #if OSDL_DEBUG
01506 
01507     if ( isLocked() )
01508         throw VideoException( "Surface::blitTo with source rectangle called "
01509             "whereas surface is locked." ) ;
01510             
01511 #endif // OSDL_DEBUG
01512 
01513 
01514 #if OSDL_DEBUG_BLIT
01515 
01516     LogPlug::debug( "Surface::blitTo with source rectangle = " 
01517         + sourceRectangle.toString() + " and destination location = " 
01518         + destinationLocation.toString() ) ;
01519     
01520 #endif // OSDL_DEBUG_BLIT
01521     
01522     SDL_Rect destinationRect ;
01523     
01524     destinationRect.x = destinationLocation.getX() ;
01525     destinationRect.y = destinationLocation.getY() ;
01526     // destinationRect width and height do not matter for SDL_BlitSurface.
01527     
01528     switch( SDL_BlitSurface( & getSDLSurface(), sourceRectangle.toSDLRect(), 
01529         & targetSurface.getSDLSurface(), & destinationRect ) )
01530     {
01531     
01532         case 0:
01533             // Success.
01534             return true ;
01535             break ;
01536                 
01537         case -2:
01538             // VideoMemoryLostException is a child class of VideoException :
01539             throw VideoMemoryLostException() ;
01540             break ;
01541     
01542         case -1:
01543             throw VideoException( 
01544                 "Surface::blitTo with source rectangle : error in blit, " 
01545                 + Utils::getBackendLastError() ) ;
01546             break ;
01547     
01548         default:
01549             LogPlug::error( "Unexpected returned value in Surface::blitTo "
01550                 "with source rectangle." ) ;
01551             return false ;  
01552             break ;
01553     }
01554     
01555     return false ;
01556         
01557 }
01558     
01559     
01560     
01561 Surface & Surface::zoom( Ceylan::Maths::Real abscissaZoomFactor, 
01562         Ceylan::Maths::Real ordinateZoomFactor, bool antialiasing ) 
01563     const throw( VideoException )
01564 {
01565 
01566     // Antialiasing not supported with flipping :
01567     if ( abscissaZoomFactor < 0 || ordinateZoomFactor < 0 )
01568         antialiasing = false ;
01569     
01570     SDL_Surface * res = ::zoomSurface( 
01571         const_cast<SDL_Surface *>( _surface ), 
01572         abscissaZoomFactor,
01573          ordinateZoomFactor,
01574         antialiasing ? SMOOTHING_ON : SMOOTHING_OFF ) ;
01575     
01576     if ( res == 0 )
01577         throw VideoException( "Surface::zoom : unable to zoom surface." ) ;
01578     
01579     // Creates a new back-buffer surface :
01580     return * new Surface( *res ) ;
01581         
01582 }
01583     
01584                     
01585 Surface & Surface::rotoZoom( Ceylan::Maths::AngleInDegrees angle, 
01586         Ceylan::Maths::Real zoomFactor, bool antialiasing ) 
01587     const throw( VideoException )
01588 {
01589 
01590     return rotoZoom( angle, zoomFactor, zoomFactor, antialiasing ) ;
01591     
01592 }
01593                         
01594                                         
01595 Surface & Surface::rotoZoom( 
01596         Ceylan::Maths::AngleInDegrees angle, 
01597         Ceylan::Maths::Real abscissaZoomFactor,
01598         Ceylan::Maths::Real ordinateZoomFactor,
01599         bool antialiasing ) 
01600     const throw( VideoException )
01601 {
01602 
01603     // Antialiasing not supported with flipping :
01604     if ( abscissaZoomFactor < 0 || ordinateZoomFactor < 0 )
01605         antialiasing = false ;
01606     
01607     SDL_Surface * res = ::rotozoomSurfaceXY( 
01608         const_cast<SDL_Surface *>( _surface ), angle, abscissaZoomFactor,
01609         ordinateZoomFactor, antialiasing ? SMOOTHING_ON : SMOOTHING_OFF ) ;
01610     
01611     if ( res == 0 )
01612         throw VideoException( 
01613             "Surface::rotoZoom : unable to rotozoom surface." ) ;
01614     
01615     return * new Surface( *res ) ;
01616 
01617 }
01618 
01619     
01620                         
01621 UprightRectangle & Surface::getClippingArea() const throw() 
01622 {
01623     return * new UprightRectangle( _surface->clip_rect ) ;
01624 }
01625                         
01626         
01627                     
01628 void Surface::setClippingArea( UprightRectangle & newClippingArea ) throw() 
01629 {   
01630 
01631     TwoDimensional::Point2D corner = newClippingArea.getUpperLeftCorner() ;
01632     
01633     _surface->clip_rect.x = corner.getX() ; 
01634     _surface->clip_rect.y = corner.getY() ;
01635      
01636     _surface->clip_rect.w = newClippingArea.getWidth() ; 
01637     _surface->clip_rect.h = newClippingArea.getHeight() ; 
01638     
01639 }
01640 
01641 
01642 
01643 
01644 // Another proxy-method section.
01645 
01646 
01647 void Surface::loadImage( const string & filename, bool blitOnly,
01648         bool convertToDisplayFormat, bool convertWithAlpha ) 
01649     throw( TwoDimensional::ImageException )
01650 {
01651 
01652     TwoDimensional::Image::Load( *this, filename, blitOnly, 
01653         convertToDisplayFormat, convertWithAlpha  ) ; 
01654         
01655 }
01656 
01657 
01658 void Surface::loadJPG( const string & filename, bool blitOnly,
01659         bool convertToDisplayFormat, bool convertWithAlpha ) 
01660     throw( TwoDimensional::ImageException )
01661 {
01662 
01663     TwoDimensional::Image::LoadJPG( *this, filename, blitOnly, 
01664         convertToDisplayFormat, convertWithAlpha  ) ; 
01665         
01666 }
01667 
01668 
01669 void Surface::loadPNG( const string & filename, bool blitOnly,
01670         bool convertToDisplayFormat, bool convertWithAlpha ) 
01671     throw( TwoDimensional::ImageException )
01672 {
01673 
01674     TwoDimensional::Image::LoadPNG( *this, filename, blitOnly, 
01675         convertToDisplayFormat, convertWithAlpha  ) ; 
01676         
01677 }
01678 
01679 
01680 void Surface::loadBMP( const string & filename, bool blitOnly,
01681         bool convertToDisplayFormat, bool convertWithAlpha ) 
01682     throw( TwoDimensional::ImageException )
01683 {
01684 
01685     TwoDimensional::Image::LoadBMP( *this, filename, blitOnly, 
01686         convertToDisplayFormat, convertWithAlpha  ) ; 
01687         
01688 }
01689 
01690 
01691 void Surface::loadGIF( const string & filename, bool blitOnly,
01692         bool convertToDisplayFormat, bool convertWithAlpha ) 
01693     throw( TwoDimensional::ImageException )
01694 {
01695 
01696     TwoDimensional::Image::LoadGIF( *this, filename, blitOnly, 
01697         convertToDisplayFormat, convertWithAlpha  ) ; 
01698         
01699 }
01700 
01701 
01702 void Surface::loadLBM( const string & filename, bool blitOnly,
01703         bool convertToDisplayFormat, bool convertWithAlpha ) 
01704     throw( TwoDimensional::ImageException )
01705 {
01706 
01707     TwoDimensional::Image::LoadLBM( *this, filename, blitOnly, 
01708         convertToDisplayFormat, convertWithAlpha  ) ; 
01709         
01710 }
01711 
01712 
01713 void Surface::loadPCX( const string & filename, bool blitOnly,
01714         bool convertToDisplayFormat, bool convertWithAlpha ) 
01715     throw( TwoDimensional::ImageException )
01716 {
01717 
01718     TwoDimensional::Image::LoadPCX( *this, filename, blitOnly, 
01719         convertToDisplayFormat, convertWithAlpha  ) ; 
01720         
01721 }
01722 
01723 
01724 void Surface::loadPNM( const string & filename, bool blitOnly,
01725         bool convertToDisplayFormat, bool convertWithAlpha ) 
01726     throw( TwoDimensional::ImageException )
01727 {
01728 
01729     TwoDimensional::Image::LoadPNM( *this, filename, blitOnly, 
01730         convertToDisplayFormat, convertWithAlpha  ) ; 
01731         
01732 }
01733 
01734 
01735 void Surface::loadTGA( const string & filename, bool blitOnly,
01736         bool convertToDisplayFormat, bool convertWithAlpha ) 
01737     throw( TwoDimensional::ImageException )
01738 {
01739 
01740     TwoDimensional::Image::LoadTGA( *this, filename, blitOnly, 
01741         convertToDisplayFormat, convertWithAlpha  ) ; 
01742         
01743 }
01744 
01745 
01746 void Surface::loadXPM( const string & filename, bool blitOnly,
01747         bool convertToDisplayFormat, bool convertWithAlpha ) 
01748     throw( TwoDimensional::ImageException )
01749 {
01750 
01751     TwoDimensional::Image::LoadXPM( *this, filename, blitOnly, 
01752         convertToDisplayFormat, convertWithAlpha  ) ;
01753          
01754 }
01755 
01756 
01757 void Surface::savePNG( const std::string & filename, bool overwrite ) 
01758     throw( TwoDimensional::ImageException )
01759 {
01760 
01761     TwoDimensional::Image::SavePNG( *this, filename, overwrite ) ;
01762     
01763 }
01764 
01765 
01766 void Surface::saveBMP( const std::string & filename, bool overwrite ) 
01767     throw( TwoDimensional::ImageException )
01768 {
01769 
01770     if ( ( overwrite == false ) && Ceylan::System::File::Exists( filename ) )
01771         throw TwoDimensional::ImageException( 
01772             "Surface::saveBMP : target file " + filename 
01773             + " already exists, and overwrite mode is off." ) ;
01774             
01775     if ( SDL_SaveBMP( _surface, filename.c_str() ) == -1 ) 
01776         throw TwoDimensional::ImageException( 
01777             "Surface::saveBMP : unable to save image : " 
01778             + Utils::getBackendLastError() ) ;
01779 }
01780 
01781                     
01782 void Surface::update() throw( VideoException )
01783 {
01784 
01785 #if OSDL_DEBUG_WIDGET
01786     LogPlug::trace( "Surface::update" ) ; 
01787 #endif // OSDL_DEBUG_WIDGET
01788 
01789 
01790 #if OSDL_DEBUG
01791     if ( isLocked() )
01792         throw VideoException( 
01793             "Surface::update called whereas surface is locked." ) ;
01794 #endif // OSDL_DEBUG
01795 
01796     // Updates the internal video buffer before display :
01797     redraw() ;
01798 
01799     switch( _displayType )
01800     {
01801     
01802     
01803         case BackBuffer:
01804             LogPlug::warning( "Surface::update requested on a "
01805                 "non-screen surface ! (nothing done)" ) ;           
01806             break ;
01807     
01808     
01809         case ClassicalScreenSurface:
01810 #if OSDL_DEBUG_WIDGET
01811             LogPlug::trace( 
01812                 "Surface::update : flipping classical screen buffer" ) ; 
01813 #endif // OSDL_DEBUG_WIDGET
01814         
01815             // Double-buffered : flip, others : update the whole rectangle.
01816             if ( SDL_Flip( _surface ) != 0 )
01817                 throw VideoException( 
01818                     "Surface::update : unable to flip classical screen : "
01819                     + Utils::getBackendLastError() ) ;
01820         
01821             /*
01822              * If a rectangle area was known to include all changes in the
01823              * screen surface, we could use :
01824              *
01825                 
01826             if ( _surface->flags & SDL_DOUBLEBUF ) 
01827             {
01828                 SDL_Flip(_surface) ;
01829             } 
01830             else 
01831             {
01832                 SDL_UpdateRects( _surface, 1, & area ) ;
01833             }
01834         
01835              *
01836              */
01837             break ;
01838         
01839         
01840         case OpenGLScreenSurface:
01841 #if OSDL_DEBUG_WIDGET
01842             LogPlug::trace( 
01843                 "Surface::update : flipping OpenGL screen buffer" ) ; 
01844 #endif // OSDL_DEBUG_WIDGET
01845             
01846             // What to do if OpenGL without double buffering is used ?
01847             SDL_GL_SwapBuffers() ;
01848             break ;
01849         
01850         
01851         default:
01852             LogPlug::error( 
01853                 "Surface::update : unknown display type, nothing done." ) ; 
01854             break ;
01855             
01856     }       
01857         
01858 }
01859 
01860 
01861 void Surface::updateRectangles( const list<UprightRectangle *> & listRects )
01862     throw( VideoException )
01863 {
01864 
01865     /*
01866      * Does not use SDL_UpdateRects for efficiency reasons 
01867      * (avoid too many structure conversions).
01868      *
01869      */
01870     
01871     for ( list<UprightRectangle *>::const_iterator it = listRects.begin() ; 
01872         it != listRects.end() ; it++ )
01873     {
01874         
01875 #if OSDL_DEBUG      
01876         if ( *it == 0 )
01877         {
01878             LogPlug::error( "Surface::updateRectangles : "
01879                 "null pointer in rectangle list." ) ;
01880             break ;
01881         }   
01882 #endif // OSDL_DEBUG
01883         
01884         updateRectangle( * (*it) ) ;
01885      
01886     }
01887 
01888 }
01889             
01890                     
01891 void Surface::updateRectangle( const UprightRectangle & rect ) 
01892     throw( VideoException ) 
01893 {   
01894 
01895     updateRectangle( rect.getUpperLeftAbscissa(), 
01896         rect.getUpperLeftOrdinate(), rect.getWidth(), rect.getHeight() ) ;
01897             
01898 }
01899 
01900 
01901 void Surface::updateRectangle( Coordinate x, Coordinate y, 
01902     Length width, Length height ) throw( VideoException ) 
01903 {   
01904 
01905 #if OSDL_DEBUG
01906     if ( isLocked() )
01907         LogPlug::error( 
01908             "Surface::updateRectangle() called whereas surface is locked." ) ;
01909 #endif // OSDL_DEBUG
01910     
01911     if ( _displayType != BackBuffer )
01912     {
01913         SDL_UpdateRect( _surface, x, y, width, height ) ;
01914     }   
01915     else
01916     {
01917         throw VideoException( 
01918             "Surface::updateRectangle requested on a non-screen surface" ) ;
01919     }
01920         
01921 }
01922     
01923     
01924 void Surface::setRedrawState( bool needsToBeRedrawn ) throw()
01925 {
01926 
01927     _needsRedraw = needsToBeRedrawn ;
01928     
01929 }
01930 
01931     
01932 bool Surface::getRedrawState() const throw()
01933 {
01934 
01935     return _needsRedraw ;
01936     
01937 }
01938 
01939     
01940 void Surface::redraw() throw()
01941 {
01942 
01943 
01944     /*
01945      * Far too verbose :
01946      
01947 #if OSDL_DEBUG_WIDGET
01948     LogPlug::trace( "Surface::redraw : needs redraw attribute is " 
01949         + Ceylan::toString(_needsRedraw ) + "." ) ; 
01950 #endif // OSDL_DEBUG_WIDGET
01951 
01952     *
01953     */
01954     
01955     if ( getRedrawState() )
01956     {
01957         
01958         // First redraw thyself :   
01959         redrawInternal() ;
01960     
01961         // Then request the sub-components to do so recursively :
01962         RedrawRequestEvent redrawEvent( *this ) ;
01963     
01964         /*
01965          * This code relies on notifyAllListeners order, which uses a 
01966          * classic iterator, from front to back of listeners list, 
01967          * therefore from bottom to top-level widgets.
01968          *
01969          */
01970         notifyAllListeners( redrawEvent ) ;
01971     
01972         setRedrawState( false ) ;
01973         
01974     }
01975     
01976     // Do nothing if _needsRedraw is false. 
01977     
01978 }
01979 
01980 
01981 void Surface::redrawInternal() throw()
01982 {
01983 
01984 #if OSDL_DEBUG_WIDGET
01985     LogPlug::trace( "Surface::redrawInternal (non overriden version)" ) ; 
01986 #endif // OSDL_DEBUG_WIDGET
01987 
01988     /*
01989      * Meant to be overriden if needed (filled with background color, 
01990      * background image blitted, etc.)
01991      *
01992      */
01993          
01994 }
01995     
01996                     
01997 bool Surface::isInternalSurfaceAvailable() const throw()
01998 {
01999 
02000     return _surface ;
02001     
02002 }
02003 
02004 
02005 void Surface::addWidget( TwoDimensional::Widget & widget ) 
02006     throw( VideoException )
02007 {
02008 
02009 #if OSDL_DEBUG_WIDGET
02010     LogPlug::trace( "Surface::addWidget : adding " + widget.toString() ) ; 
02011 #endif // OSDL_DEBUG_WIDGET
02012 
02013     /*
02014      * Relies on event source implementation, which add new listeners to 
02015      * back of list (push_back), which means for widgets, the top level.
02016      *
02017      */
02018      
02019     try
02020     {
02021         add( /* a listener */ widget ) ;
02022     }
02023     catch( const Ceylan::EventException & e )
02024     {
02025         throw VideoException( 
02026             "Surface::addWidget : unable to add new listener widget : "
02027             + e.toString() ) ;
02028     }
02029     
02030 }
02031 
02032 
02033 Surface & Surface::getWidgetRenderTarget() throw()  
02034 {
02035 
02036     /*
02037      * For simple surfaces (and widgets), subwidgets should target 
02038      * this surface :
02039      *
02040      */
02041     return *this ;
02042     
02043 }   
02044 
02045     
02046 void Surface::putWidgetToFront( TwoDimensional::Widget & widget ) 
02047     throw( VideoException )
02048 {
02049 
02050     /*
02051      * Reorders _listeners list, inherited from EventSource, so that 
02052      * the widget is at top level, i.e. in last position of the list (back).
02053      *
02054      */
02055     _listeners.remove( & widget ) ;
02056     
02057     // Put this widget in last slot (top-level) :
02058     _listeners.push_back( & widget ) ;  
02059      
02060 }
02061 
02062                     
02063 void Surface::putWidgetToBack( TwoDimensional::Widget & widget ) 
02064     throw( VideoException )
02065 {
02066 
02067     /*
02068      * Reorders _listeners list, inherited from EventSource, so that 
02069      * the widget is at bottom level, i.e. in first position of the list 
02070      * (front).
02071      *
02072      */
02073     _listeners.remove( & widget ) ;
02074     
02075     // Put this widget in last (bottom-level) slot :
02076     _listeners.push_front( & widget ) ; 
02077 
02078 }
02079 
02080 
02081 void Surface::centerMousePosition() throw()
02082 {
02083 
02084     setMousePosition( getWidth() / 2, getHeight() / 2 ) ;
02085     
02086 }
02087 
02088 
02089 void Surface::setMousePosition( Coordinate newX, Coordinate newY ) throw() 
02090 {
02091 
02092 #if OSDL_DEBUG
02093 
02094     if ( _displayType == BackBuffer )
02095     {
02096         Ceylan::emergencyShutdown( 
02097             "Surface::setMousePosition called on a non-screen surface." ) ;
02098     }
02099     
02100 #endif // OSDL_DEBUG
02101     
02102     SDL_WarpMouse( newX, newY ) ;
02103     
02104 }
02105 
02106                                         
02107 bool Surface::mustBeLocked() const throw() 
02108 {
02109 
02110     // Not stored once for all, since may change during the surface life ?
02111     return SDL_MUSTLOCK( _surface ) ;
02112      
02113 }
02114 
02115 
02116 void Surface::preUnlock() throw()
02117 {
02118 
02119     /*
02120      * Lockable framework ensures it is called only if necessary 
02121      * (i.e. only if 'must be locked') :
02122      *
02123      */
02124     SDL_UnlockSurface( _surface ) ;
02125     
02126 }
02127 
02128 
02129 void Surface::postLock() throw()
02130 {
02131     
02132     /*
02133      * Lockable framework ensures it is called only if necessary 
02134      * (i.e. only if 'must be locked') :
02135      *
02136      */
02137     SDL_LockSurface( _surface ) ;
02138 
02139 }
02140 
02141 
02142 Ceylan::System::Size Surface::getSizeInMemory() const throw()
02143 {
02144 
02145     Ceylan::System::Size currentSize = sizeof( Surface ) ;
02146     
02147     if ( _surface != 0 )
02148     {
02149     
02150         currentSize += sizeof( SDL_Surface ) ;
02151 
02152         // PixelFormat are supposed never shared :
02153         if ( _surface->format != 0 )
02154         {
02155         
02156             currentSize += sizeof( SDL_PixelFormat ) ;
02157             
02158             if ( _surface->format->palette != 0 )
02159             {
02160                 currentSize += sizeof( SDL_Palette ) ;
02161                 currentSize += _surface->format->palette->ncolors 
02162                     * sizeof( SDL_Color ) ;
02163             }   
02164             
02165             if ( _surface->pixels != 0 )
02166                 currentSize +=  _surface->w * _surface->h *
02167                     _surface->format->BytesPerPixel ;
02168                         
02169         }
02170         // else : count might be wrong.
02171     }
02172 
02173     // Do not count same pointed block more than once !
02174          
02175     return currentSize ;
02176     
02177 }
02178 
02179 
02180 bool Surface::displayData( const Ceylan::Maths::IntegerData * dataArray,
02181     Ceylan::Uint32 dataCount,
02182     Pixels::ColorDefinition pencilColor, Pixels::ColorDefinition captionColor,
02183     Pixels::ColorDefinition backgroundColor,
02184     const string & caption, const UprightRectangle * inBox ) throw()
02185 {
02186     
02187     // No debug requested by default :
02188 #define OSDL_DEBUG_DISPLAY_DATA 0
02189 
02190     Coordinate x, y ;
02191     Length width, height ;
02192         
02193     if ( inBox == 0 )
02194     {
02195         x = 0 ;
02196         y = 0 ;
02197         width  = getWidth() ;
02198         height = getHeight() ;
02199     }
02200     else
02201     {
02202     
02203         /*
02204          * This absurd copy is a bit clumsy, but it allows to avoid making
02205          * a new rectangle in the other branch.
02206          *
02207          */
02208                 
02209         x      = inBox->getUpperLeftAbscissa() ;
02210         y      = inBox->getUpperLeftOrdinate() ;
02211         width  = inBox->getWidth() ;
02212         height = inBox->getHeight() ;
02213     }
02214     
02215     UprightRectangle drawingArea( x, y, width, height ) ;
02216     
02217 #if OSDL_DEBUG_DISPLAY_DATA
02218     LogPlug::debug( "Drawing area will be : " + drawingArea.toString() ) ;
02219 #endif // OSDL_DEBUG_DISPLAY_DATA
02220             
02221     // Draw first the background :  
02222     drawBox( drawingArea, backgroundColor, /* filled */ true ) ;
02223     
02224     // Then draw its border with pencil color : 
02225     drawBox( drawingArea, pencilColor, /* filled */ false ) ;
02226     
02227     
02228     // Now draw the curve : 
02229     
02230     // Abscissa : one pixel corresponds to one value.
02231     Coordinate xstart = drawingArea.getUpperLeftAbscissa() 
02232         + graphAbscissaOffset ; 
02233     
02234     Coordinate xmax = drawingArea.getUpperLeftAbscissa() 
02235         + drawingArea.getWidth() - graphAbscissaOffset ;
02236     Coordinate xstop ;
02237      
02238     
02239     /*
02240      * Number of pixel in abscissa for each sample 
02241      * (auto-adjust to largest possible) :
02242      *
02243      */
02244     Coordinate stride = static_cast<Coordinate>( 
02245         Ceylan::Maths::Floor( static_cast<Ceylan::Float32>( 
02246             ( drawingArea.getWidth() - 2 * graphAbscissaOffset ) 
02247                 / static_cast<Ceylan::Float32>( dataCount ) ) ) ) ;
02248         
02249 #if OSDL_DEBUG_DISPLAY_DATA
02250     LogPlug::debug( "Abscissa stride is " 
02251         + Ceylan::toString( stride ) + "." ) ;  
02252 #endif // OSDL_DEBUG_DISPLAY_DATA
02253     
02254     if ( stride < 1 )
02255     {
02256         LogPlug::error( 
02257             "Surface::displayData : available width too small to draw." ) ;
02258         return false ;
02259     }   
02260     
02261     
02262     if ( xstart + static_cast<Coordinate>( dataCount ) > xmax )
02263     {
02264         LogPlug::warning( 
02265             "Surface::displayData : graph will be truncated to x = "
02266             + Ceylan::toString( xmax ) + " (insufficient width)." ) ;
02267         xstop = xmax ;  
02268     }
02269     else
02270     {
02271         xstop = xstart + stride * dataCount ;       
02272     }
02273     
02274     
02275     if ( xstart > xstop )
02276     {
02277     
02278         LogPlug::error( 
02279             "Surface::displayData : available width too small to draw." ) ;
02280         return false ;
02281     }   
02282 
02283     
02284     // Searching for extremas :
02285     
02286     Ceylan::Maths::IntegerData maxData = dataArray[ 0 ] ;
02287     Ceylan::Maths::IntegerData minData = dataArray[ 0 ] ;
02288     
02289     for ( Ceylan::Uint32 i = 1; i < dataCount; i++ )
02290     {
02291     
02292         if ( dataArray[i] > maxData )
02293             maxData = dataArray[i] ;
02294             
02295         if ( dataArray[i] < minData )
02296             minData = dataArray[i] ;
02297             
02298     }
02299     
02300     
02301 #if OSDL_DEBUG_DISPLAY_DATA
02302     LogPlug::debug( "Dynamic range from " + Ceylan::toString( minData ) 
02303         + " to " + Ceylan::toString( maxData ) + "." ) ;
02304 #endif // OSDL_DEBUG_DISPLAY_DATA
02305     
02306     Ceylan::Maths::IntegerData ordinateDrawRange = 
02307         drawingArea.getHeight() - 2 * graphOrdinateOffset ;
02308     
02309     if ( ordinateDrawRange < 0 )
02310     {
02311         LogPlug::error( "Surface::displayData : height too small to draw." ) ;
02312         return false ;
02313     }   
02314     
02315     Ceylan::Float32 yScaleFactor ;
02316     
02317     if ( maxData != minData )
02318         yScaleFactor = static_cast<Ceylan::Float32>( ordinateDrawRange ) 
02319             / ( maxData - minData ) ;
02320     else
02321         yScaleFactor = 1 ;
02322     
02323         
02324 #if OSDL_DEBUG_DISPLAY_DATA
02325 
02326     LogPlug::debug( "Ordinate scale factor is " 
02327         + Ceylan::toString( yScaleFactor ) 
02328         + " (" + Ceylan::toString( ordinateDrawRange ) 
02329         + " / " + Ceylan::toString( maxData - minData ) + ")." ) ;
02330             
02331 #endif // OSDL_DEBUG_DISPLAY_DATA
02332     
02333     Coordinate yplotBase = drawingArea.getUpperLeftOrdinate() 
02334         + drawingArea.getHeight() - graphOrdinateOffset ;
02335     
02336     //LogPlug::debug( "yplotBase is " + Ceylan::toString( yplotBase ) ) ;
02337     
02338     Ceylan::Uint32 dataCurrent = 0 ;
02339 
02340     Coordinate xplot = xstart ;
02341     
02342     Coordinate yplotPrevious = yplotBase ;
02343     Coordinate yplot ;
02344     
02345     while ( xplot < xstop )
02346     {
02347         yplot = static_cast<Coordinate>( 
02348             ( dataArray[ dataCurrent ] - minData ) * yScaleFactor ) ;
02349         
02350         drawLine( xplot, yplotPrevious, xplot+1, yplotBase - yplot, 
02351             pencilColor ) ;
02352         yplotPrevious = yplotBase - yplot ;
02353     
02354         /*
02355          * LogPlug::debug( "yplotPrevious is " 
02356             + Ceylan::toString( yplotPrevious ) ) ;
02357          *
02358          */
02359         
02360         dataCurrent++ ;
02361         xplot += stride ;
02362         
02363     }
02364     
02365     /*
02366      * These are not real axes 
02367      * (they are not set so that they are y=0 for example) :
02368      *
02369      */
02370     
02371     ColorDefinition axisColor = Pixels::Ivory ;
02372     
02373     drawHorizontalLine( xstart, xstop, yplotBase, axisColor ) ;
02374     drawVerticalLine( xstart, yplotBase, 
02375         drawingArea.getUpperLeftOrdinate() + graphOrdinateOffset, axisColor ) ;
02376     
02377     /*
02378      * LogPlug::debug( "Last y plotted was " 
02379         + Ceylan::toString( yplotPrevious ) + "." ) ;
02380      *
02381      */
02382     
02383     if( caption.size() > 0 )
02384         printText( caption, 
02385             drawingArea.getUpperLeftAbscissa() + captionAbscissaOffset, 
02386             drawingArea.getUpperLeftOrdinate() + drawingArea.getHeight() 
02387                 - captionOrdinateOffset,
02388             captionColor ) ;
02389 
02390     return true ;
02391     
02392 }
02393     
02394          
02395 const string Surface::toString( Ceylan::VerbosityLevels level ) const throw()
02396 {
02397 
02398     std::list<string> surfaceList ;
02399 
02400     switch( _displayType )
02401     {
02402     
02403     
02404         case BackBuffer:
02405             surfaceList.push_back( "This is a back buffer surface." ) ;
02406             break ;
02407     
02408         
02409         case ClassicalScreenSurface:
02410             surfaceList.push_back( "This is a classical screen surface." ) ;
02411             break ;
02412         
02413         case OpenGLScreenSurface:   
02414             surfaceList.push_back( "This is an OpenGL screen surface." ) ;
02415             break ;
02416         
02417         default:
02418             surfaceList.push_back( 
02419                 "This is a surface of unknown type (abnormal)." ) ;
02420             break ;
02421         
02422     }
02423             
02424     surfaceList.push_back( "Dimensions : ( width = " 
02425         + Ceylan::toString( getWidth() ) + " ; height = "
02426         + getHeight() + " )" ) ; 
02427     
02428     if ( level == Ceylan::low )
02429         return "Surface description : " 
02430             + Ceylan::formatStringList( surfaceList ) ;
02431         
02432     surfaceList.push_back( "Pitch : " + Ceylan::toString( getPitch() ) ) ;
02433     
02434     surfaceList.push_back( "Pixel format : bits per pixel = " 
02435         + Ceylan::toString( 
02436             static_cast<Ceylan::Uint16>( getBitsPerPixel() ) ) ) ;
02437     
02438     surfaceList.push_back( "Video flags : " + InterpretFlags( getFlags() ) ) ;
02439     
02440         
02441     surfaceList.push_back( "Clipping area : " 
02442         + UprightRectangle( _surface->clip_rect ).toString( level ) ) ;
02443 
02444     surfaceList.push_back( "Size in memory : " 
02445         + Ceylan::toString( getSizeInMemory() ) + " bytes" ) ;
02446         
02447     /*
02448      * surfaceList.push_back( "Reference count : " 
02449         + Ceylan::toString( _refcount ) ) ;
02450      *
02451      */
02452     
02453     surfaceList.push_back( "Widget relationship : " 
02454         + EventSource::toString( level ) ) ;
02455     
02456     
02457     return "Surface description : " + Ceylan::formatStringList( surfaceList ) ;
02458     
02459 }
02460 
02461 
02462 
02463 Surface & Surface::LoadImage( const std::string & filename,
02464         bool convertToDisplayFormat, bool convertWithAlpha ) 
02465     throw( TwoDimensional::ImageException )
02466 {
02467 
02468     Surface * toLoad = new Surface() ;
02469     
02470     try 
02471     {
02472         toLoad->loadImage( filename, /* blitOnly */ false, 
02473             convertToDisplayFormat, convertWithAlpha ) ;
02474     } 
02475     catch( const TwoDimensional::ImageException & e )
02476     {
02477         delete toLoad ;
02478         throw ;
02479     }
02480         
02481     return * toLoad ;
02482     
02483 }
02484     
02485     
02486 string Surface::InterpretFlags( Flags flags ) throw() 
02487 {
02488 
02489 
02490     /*
02491      * Indicates surely that these flags corresponds to a screen surface :
02492      * (sufficient but not necessary) 
02493      *
02494      */
02495         
02496     std::list<string> res ;
02497     
02498     if ( flags & ( AnyPixelFormat | DoubleBuffered 
02499         | FullScreen | OpenGL | SDL_OPENGLBLIT ) )
02500     {
02501     
02502         res.push_back( "This surface should be a display surface." ) ;
02503         
02504         if ( flags & AnyPixelFormat )
02505             res.push_back( 
02506                 "Allows any pixel format for the display surface." ) ;
02507         else
02508             res.push_back( "Only specified pixel format "
02509                 "is accepted for the display surface." ) ;
02510 
02511         if ( flags & DoubleBuffered )
02512             res.push_back( "Display surface is double buffered." ) ;
02513         else
02514             res.push_back( "Display surface is not double buffered." ) ;
02515         
02516         if ( flags & FullScreen )
02517             res.push_back( "Display surface is fullscreen." ) ;
02518         else
02519             res.push_back( "Display surface is in windowed mode "
02520                 "(not full screen)." ) ;
02521         
02522         if ( flags & OpenGL )
02523             res.push_back( "Display surface has an OpenGL context." ) ;
02524         else
02525             res.push_back( "Display surface has no OpenGL context." ) ;
02526         
02527         if ( flags & SDL_OPENGLBLIT )
02528             res.push_back( 
02529                 "Display surface supports OpenGL blitting (deprecated)." ) ;
02530             
02531         /*
02532          * Ignore if SDL_OPENGLBLIT is not used : avoid useless publicity 
02533          * for bad habits.
02534          * 
02535         
02536         else
02537             res.push_back( 
02538                 "Display surface does not support OpenGL blitting." ) ;
02539          *
02540          */
02541          
02542         if ( flags & Resizable )
02543             res.push_back( "Display surface is resizable." ) ;
02544         else
02545             res.push_back( "Display surface is not resizable." ) ;
02546     
02547     }
02548     else
02549     {
02550         res.push_back( "No flag dedicated to display surfaces "
02551             "is used for this surface." ) ;
02552     }       
02553     
02554     
02555     if ( flags & Software )
02556         res.push_back( "Surface is to be stored in system memory." ) ;
02557     else
02558         res.push_back( 
02559             "Surface is not required to be stored in system memory." ) ;
02560         
02561         
02562     if ( flags & Hardware )
02563         res.push_back( "Surface is to be stored in video memory." ) ;
02564     else
02565         res.push_back( 
02566             "Surface is not required to be stored in video memory." ) ;
02567         
02568         
02569     if ( flags & AsynchronousBlit )
02570         res.push_back( "Surface should use asynchronous blits if possible." ) ;
02571     else
02572         res.push_back( 
02573             "Surface is not required to use asynchronous blits if possible." ) ;
02574             
02575                     
02576     if ( flags & ExclusivePalette )
02577         res.push_back( "Surface should have an exclusive palette." ) ;
02578     else
02579         res.push_back( "Surface has not an exclusive palette." ) ;
02580         
02581         
02582     if ( flags & HardwareAcceleratedBlit )
02583         res.push_back( "Surface is to use hardware-accelerated blits." ) ;
02584     else
02585         res.push_back( 
02586             "Surface is not required to use hardware-accelerated blits." ) ;
02587         
02588         
02589     if ( flags & ColorkeyBlit )
02590         res.push_back( "Surface is to use colorkey blitting." ) ;
02591     else
02592         res.push_back( "Surface is not required to use colorkey blitting." ) ;
02593         
02594         
02595     if ( flags & RLEColorkeyBlit )
02596         res.push_back( "Surface is to use RLE-accelerated colorkey blits." ) ;
02597     else
02598         res.push_back( 
02599             "Surface is not required to use RLE-accelerated colorkey blits." ) ;
02600         
02601         
02602     if ( flags & AlphaBlendingBlit )
02603         res.push_back( "Surface is to use alpha blending blits." ) ;
02604     else
02605         res.push_back( 
02606             "Surface is not required to use alpha blending blits." ) ;
02607         
02608         
02609     if ( flags & Preallocated )
02610         res.push_back( "Surface is to use preallocated memory." ) ;
02611     else
02612         res.push_back( "Surface is not required to use preallocated memory." ) ;
02613         
02614         
02615     return "The specified surface flags, whose value is " 
02616         + Ceylan::toString( flags, /* bit field */ true ) 
02617         + ", means : " + Ceylan::formatStringList( res ) ;
02618         
02619 }
02620 
02621 
02622 
02623 
02624 Offset Surface::getOffset() const throw()
02625 {
02626 
02627     return  _surface->offset ;
02628     
02629 }
02630 
02631 
02632 void Surface::setOffset( Offset offset ) throw()
02633 {
02634 
02635      _surface->offset = offset ;
02636      
02637 }
02638     
02639 
02640 
02641 void Surface::flush() throw() 
02642 {
02643     
02644     if ( _surface != 0 )
02645     {
02646 
02647 #if OSDL_DEBUG_SURFACE
02648         LogPlug::trace( "Surface::flush : flushing surface." ) ;
02649 #endif // OSDL_DEBUG_SURFACE
02650 
02651         if ( _displayType != BackBuffer )
02652             inconsistencyDetected( 
02653                 "Surface::flush : trying to delete a screen surface." ) ;
02654         
02655         SDL_FreeSurface( _surface ) ;
02656         _surface = 0 ;
02657         
02658     }   
02659 }
02660 
02661 
02662 
02663 void Surface::inconsistencyDetected( const string & message ) const throw() 
02664 {
02665 
02666     Ceylan::emergencyShutdown( "Incoherence detected in OSDL Surface : "
02667         + message ) ;
02668         
02669 }
02670 
02671 
02672 Surface::Surface( const Surface & source ) throw() :
02673     TwoDimensional::UprightRectangle( 0, 0, 0, 0 ),
02674     Ceylan::EventSource(),
02675     Ceylan::Lockable(),
02676     Ceylan::SmartResource(),
02677     _surface( 0 ), 
02678     _displayType( BackBuffer ), 
02679     _mustBeLocked( false ),
02680     _needsRedraw( true ) 
02681 {
02682 
02683     // Not implemented on purpose, use clone() instead !
02684     Ceylan::emergencyShutdown( 
02685         "Surface copy constructor called, whereas should never be used." ) ;
02686         
02687 }
02688 
02689 
02690 
02691 std::ostream & operator << ( std::ostream & os, Surface & s ) throw()
02692 {
02693     return os << s.toString() ;
02694 }
02695 

Generated on Fri Mar 30 14:47:00 2007 for OSDL by  doxygen 1.5.1