00001 #include "OSDLUprightRectangle.h"
00002
00003 #include "OSDLPoint2D.h"
00004 #include "OSDLSurface.h"
00005
00006 #include "Ceylan.h"
00007
00008 #include "SDL_gfxPrimitives.h"
00009
00010
00011 #ifdef OSDL_USES_CONFIG_H
00012 #include <OSDLConfig.h>
00013 #endif // OSDL_USES_CONFIG_H
00014
00015
00016 using std::string ;
00017
00018 using namespace Ceylan::Log ;
00019
00020 using namespace OSDL::Video ;
00021 using namespace OSDL::Video::TwoDimensional ;
00022
00023
00024
00025
00026 UprightRectangle::UprightRectangle( const Point2D & upperLeftCorner,
00027 const Point2D & lowerRightCorner ) throw( VideoException ) :
00028 _x( upperLeftCorner.getX() ),
00029 _y( upperLeftCorner.getY() ),
00030 _width( static_cast<Length>(
00031 lowerRightCorner.getX() - upperLeftCorner.getX() ) ),
00032 _height( static_cast<Length>(
00033 lowerRightCorner.getY() - upperLeftCorner.getY() ) )
00034 {
00035
00036 if ( lowerRightCorner.getX() < upperLeftCorner.getX() )
00037 throw VideoException(
00038 "UprightRectangle constructor : width is negative ("
00039 + Ceylan::toString( static_cast<Ceylan::SignedLongInteger>(
00040 lowerRightCorner.getX() - upperLeftCorner.getX() ) )
00041 + ")." ) ;
00042
00043 if ( lowerRightCorner.getY() < upperLeftCorner.getY() )
00044 throw VideoException(
00045 "UprightRectangle constructor : height is negative ("
00046 + Ceylan::toString( static_cast<Ceylan::SignedLongInteger>(
00047 lowerRightCorner.getY() - upperLeftCorner.getY() ) )
00048 + " )." ) ;
00049
00050 }
00051
00052
00053 UprightRectangle::UprightRectangle( const Point2D & upperLeftCorner,
00054 Length width, Length height ) throw() :
00055 _x( upperLeftCorner.getX() ),
00056 _y( upperLeftCorner.getY() ),
00057 _width( width ),
00058 _height( height )
00059 {
00060
00061 }
00062
00063
00064 UprightRectangle::UprightRectangle( Coordinate x, Coordinate y,
00065 Length width, Length height ) throw() :
00066 _x( x ),
00067 _y( y ),
00068 _width( width ),
00069 _height( height )
00070 {
00071
00072 }
00073
00074
00075 UprightRectangle::UprightRectangle( const SDL_Rect & source ) throw() :
00076 _x( source.x ),
00077 _y( source.y ),
00078 _width( source.w ),
00079 _height( source.h )
00080 {
00081
00082 }
00083
00084
00085
00086 UprightRectangle::~UprightRectangle() throw()
00087 {
00088
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 Point2D UprightRectangle::getUpperLeftCorner() const throw()
00099 {
00100
00101 return Point2D( _x, _y ) ;
00102
00103 }
00104
00105
00106 void UprightRectangle::setUpperLeftCorner( Point2D & newUpperLeftCorner )
00107 throw()
00108 {
00109
00110 _x = newUpperLeftCorner.getX() ;
00111 _y = newUpperLeftCorner.getY() ;
00112
00113 }
00114
00115
00116
00117 Coordinate UprightRectangle::getUpperLeftAbscissa() const throw()
00118 {
00119
00120 return _x ;
00121
00122 }
00123
00124
00125 void UprightRectangle::setUpperLeftAbscissa( Coordinate newAbscissa ) throw()
00126 {
00127
00128 _x = newAbscissa ;
00129
00130 }
00131
00132
00133
00134 Coordinate UprightRectangle::getUpperLeftOrdinate() const throw()
00135 {
00136
00137 return _y ;
00138
00139 }
00140
00141
00142 void UprightRectangle::setUpperLeftOrdinate( Coordinate newOrdinate ) throw()
00143 {
00144
00145 _y = newOrdinate ;
00146
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 Point2D UprightRectangle::getLowerRightCorner() const throw()
00156 {
00157
00158 return Point2D( static_cast<Coordinate>( _x + getWidth() ),
00159 static_cast<Coordinate>( _y + getHeight() ) ) ;
00160
00161 }
00162
00163
00164 void UprightRectangle::setLowerRightCorner( Point2D & newLowerRightCorner )
00165 throw( VideoException )
00166 {
00167
00168 if ( newLowerRightCorner.getX() < _x || newLowerRightCorner.getY() < _y )
00169 throw VideoException( "UprightRectangle::setLowerRightCorner : "
00170 "misplaced lower right corner given ("
00171 + newLowerRightCorner.toString()
00172 + ") for rectangle : " + toString() ) ;
00173
00174 _width = newLowerRightCorner.getX() - _x ;
00175 _height = newLowerRightCorner.getY() - _y ;
00176
00177 }
00178
00179
00180
00181 Coordinate UprightRectangle::getLowerRightAbscissa() const throw()
00182 {
00183
00184 return _x + getWidth() ;
00185
00186 }
00187
00188
00189 void UprightRectangle::setLowerRightAbscissa( Coordinate newAbscissa )
00190 throw( VideoException )
00191 {
00192
00193 if ( newAbscissa < _x )
00194 throw VideoException( "UprightRectangle::setLowerRightAbscissa : "
00195 "misplaced lower right corner given (abscissa is "
00196 + Ceylan::toString( newAbscissa )
00197 + ") for rectangle : " + toString() ) ;
00198
00199 _width = newAbscissa - _x ;
00200
00201 }
00202
00203
00204
00205 Coordinate UprightRectangle::getLowerRightOrdinate() const throw()
00206 {
00207
00208 return _y + getHeight() ;
00209
00210 }
00211
00212
00213 void UprightRectangle::setLowerRightOrdinate( Coordinate newOrdinate )
00214 throw( VideoException )
00215 {
00216
00217 if ( newOrdinate < _y )
00218 throw VideoException( "UprightRectangle::setLowerRightOrdinate : "
00219 "misplaced lower right corner given (ordinate is "
00220 + Ceylan::toString( newOrdinate )
00221 + ") for rectangle : " + toString() ) ;
00222
00223 _height = newOrdinate - _y ;
00224
00225 }
00226
00227
00228
00229
00230
00231 Length UprightRectangle::getWidth() const throw()
00232 {
00233
00234 return _width ;
00235
00236 }
00237
00238
00239 void UprightRectangle::setWidth( Length newWidth ) throw()
00240 {
00241
00242 _width = newWidth ;
00243
00244 }
00245
00246
00247
00248 Length UprightRectangle::getHeight() const throw()
00249 {
00250
00251 return _height ;
00252
00253 }
00254
00255
00256 void UprightRectangle::setHeight( Length newHeight ) throw()
00257 {
00258
00259 _height = newHeight ;
00260
00261 }
00262
00263
00264
00265 bool UprightRectangle::draw( Surface & target,
00266 ColorElement red, ColorElement blue, ColorElement green,
00267 ColorElement alpha, bool filled ) const throw()
00268 {
00269
00270 return draw( target, Pixels::convertRGBAToColorDefinition(
00271 red, green, blue, alpha ), filled ) ;
00272
00273 }
00274
00275
00276 bool UprightRectangle::draw( Surface & target,
00277 Pixels::ColorDefinition colorDef, bool filled ) const throw()
00278 {
00279
00280
00281 #if OSDL_DEBUG_RECTANGLES
00282
00283 LogPlug::trace( "Drawing a " + ( filled ? string( "" ) : string( "non " ) )
00284 + "filled rectangle from ["
00285 + Ceylan::toString( _x ) + ";" + Ceylan::toString( _y )
00286 + "] to ["
00287 + Ceylan::toString( _x + getWidth() ) + ";"
00288 + Ceylan::toString( _y + getHeight() )
00289 + "] with color " + Pixels::toString( colorDef ) ) ;
00290
00291 #endif // OSDL_DEBUG_RECTANGLES
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 if ( filled )
00303 {
00304
00305 return ( ::boxColor( & target.getSDLSurface(), _x, _y,
00306 _x + getWidth() - 1, _y + getHeight() - 1,
00307 Pixels::convertColorDefinitionToRawPixelColor( colorDef ) ) == 0 ) ;
00308
00309 }
00310 else
00311 {
00312
00313 return ( ::rectangleColor( & target.getSDLSurface(), _x, _y,
00314 _x + getWidth() - 1, _y + getHeight() - 1,
00315 Pixels::convertColorDefinitionToRawPixelColor( colorDef ) ) == 0 ) ;
00316
00317 }
00318
00319 }
00320
00321
00322
00323 bool UprightRectangle::drawWithRoundedCorners( Surface & target,
00324 Length edgeWidth, Pixels::ColorDefinition edgeColorDef,
00325 Pixels::ColorDefinition backgroundColorDef ) const throw()
00326 {
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 Length radius ;
00347
00348 try
00349 {
00350 radius = computeRadiusForRoundRectangle( edgeWidth ) ;
00351 }
00352 catch( const VideoException & e )
00353 {
00354 LogPlug::error(
00355 "UprightRectangle::drawWithRoundedCorners : nothing drawn : "
00356 + e.toString() ) ;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369 Surface * disc ;
00370
00371 Pixels::ColorMask redMask, greenMask, blueMask, alphaMask ;
00372
00373 Pixels::getCurrentColorMasks( target.getPixelFormat(),
00374 redMask, greenMask, blueMask, alphaMask ) ;
00375
00376 if ( ( edgeColorDef.unused != Pixels::AlphaOpaque )
00377 || ( backgroundColorDef.unused != Pixels::AlphaOpaque ) )
00378 {
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 bool alphaShiftModified = false ;
00405 Ceylan::Uint8 alphaShift = 0 ;
00406
00407 if ( alphaMask == 0 )
00408 {
00409
00410 alphaShiftModified = true ;
00411
00412
00413 alphaMask = 0xff000000 ;
00414
00415 if ( alphaMask & ( redMask | greenMask | blueMask ) )
00416 {
00417
00418
00419
00420
00421
00422
00423 alphaMask = 0x000000ff ;
00424
00425 if ( alphaMask & ( redMask | greenMask | blueMask ) )
00426 {
00427 LogPlug::error(
00428 "UprightRectangle::drawWithRoundedCorners : "
00429 "unable to correct alpha, blit will be opaque." ) ;
00430 alphaMask = 0 ;
00431 }
00432 else
00433 {
00434
00435
00436
00437
00438
00439 }
00440 }
00441 else
00442 {
00443
00444
00445
00446
00447
00448
00449 alphaShift = 24 ;
00450
00451 }
00452 }
00453
00454
00455 #if OSDL_DEBUG_RECTANGLES
00456
00457 LogPlug::trace(
00458 "UprightRectangle::drawWithRoundedCorners : alpha mask is : "
00459 + Ceylan::toString( alphaMask, true )
00460 + ", alpha shift is : "
00461 + Ceylan::toNumericalString( alphaShift ) ) ;
00462
00463 #endif // OSDL_DEBUG_RECTANGLES
00464
00465 disc = new Surface( Surface::Software | Surface::AlphaBlendingBlit,
00466 2 * radius, 2 * radius, 32,
00467 redMask, greenMask, blueMask, alphaMask ) ;
00468
00469 if ( alphaShiftModified )
00470 disc->getPixelFormat().Ashift = alphaShift ;
00471
00472 }
00473 else
00474 {
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 disc = new Surface( Surface::Software | Surface::ColorkeyBlit,
00487 2 * radius, 2 * radius, target.getBitsPerPixel(),
00488 redMask, greenMask, blueMask, 0 ) ;
00489
00490
00491
00492
00493
00494
00495
00496 ColorDefinition colorKey = Pixels::selectColorDifferentFrom(
00497 edgeColorDef, backgroundColorDef ) ;
00498
00499 disc->setColorKey( Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00500 colorKey ) ;
00501
00502 disc->fill( colorKey ) ;
00503
00504 }
00505
00506
00507 #if OSDL_DEBUG_RECTANGLES
00508
00509 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00510 "Pixel format of target surface is : "
00511 + Pixels::toString( target.getPixelFormat() ) ) ;
00512
00513 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00514 "Pixel format of disc surface is : "
00515 + Pixels::toString( disc->getPixelFormat() ) ) ;
00516
00517 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00518 "Center of disc location in target rectangle surface after creation : "
00519 + disc->describePixelAt( radius, radius )
00520 + " in " + disc->toString() ) ;
00521
00522 disc->savePNG( "disc-after-creation.png" ) ;
00523
00524 #endif // OSDL_DEBUG_RECTANGLES
00525
00526 if ( ! disc->drawDiscWithEdge(
00527 radius,
00528 radius,
00529 radius,
00530 radius - edgeWidth -1,
00531 edgeColorDef,
00532 backgroundColorDef,
00533 false ) )
00534 return false ;
00535
00536 #if OSDL_DEBUG_RECTANGLES
00537
00538 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00539 "Center of disc location in target rectangle surface after drawing : "
00540 + disc->describePixelAt( radius, radius )
00541 + " in " + disc->toString() ) ;
00542
00543 disc->savePNG( "disc-after-drawing.png" ) ;
00544
00545 #endif // OSDL_DEBUG_RECTANGLES
00546
00547
00548
00549
00550
00551
00552
00553
00554 try
00555 {
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565 UprightRectangle rectangleCorner( 0, 1, radius, radius ) ;
00566 Point2D drawingPoint( _x, _y + 1 ) ;
00567
00568 if ( ! disc->blitTo( target, rectangleCorner, drawingPoint ) )
00569 return false ;
00570
00571
00572
00573
00574
00575 rectangleCorner.setUpperLeftAbscissa( radius + 1 ) ;
00576
00577 drawingPoint.setX( _x + getWidth() - radius + 1 ) ;
00578 if ( ! disc->blitTo( target, rectangleCorner, drawingPoint ) )
00579 return false ;
00580
00581
00582
00583
00584
00585 rectangleCorner.setUpperLeftOrdinate( radius ) ;
00586
00587 drawingPoint.setY( _y + getHeight() - radius ) ;
00588 if ( ! disc->blitTo( target, rectangleCorner, drawingPoint ) )
00589 return false ;
00590
00591
00592 rectangleCorner.setUpperLeftAbscissa( 0 ) ;
00593 drawingPoint.setX( _x ) ;
00594 if ( ! disc->blitTo( target, rectangleCorner, drawingPoint ) )
00595 return false ;
00596
00597 #if OSDL_DEBUG_RECTANGLES
00598
00599 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00600 "Point in blitted disc on target surface : "
00601 + target.describePixelAt( _x + radius / 2, _y + radius / 2 ) ) ;
00602
00603 #endif // OSDL_DEBUG_RECTANGLES
00604
00605 }
00606 catch( const VideoException & e )
00607 {
00608 delete disc ;
00609 return false ;
00610 }
00611
00612 delete disc ;
00613
00614
00615
00616
00617 UprightRectangle longerInnerRectangle( _x + edgeWidth + 1, _y + radius + 1,
00618 getWidth() - 2 * edgeWidth - 1, getHeight() - 2 * radius - 1 ) ;
00619
00620 longerInnerRectangle.draw( target, backgroundColorDef, true ) ;
00621
00622 UprightRectangle topInnerRectangle( _x + radius, _y + edgeWidth + 2,
00623 getWidth() - 2 * radius + 1, radius - edgeWidth - 1 ) ;
00624 topInnerRectangle.draw( target, backgroundColorDef, true ) ;
00625
00626 UprightRectangle bottomInnerRectangle( _x + radius,
00627 _y + getHeight() - radius, getWidth() - 2 * radius + 1,
00628 radius - edgeWidth ) ;
00629
00630 bottomInnerRectangle.draw( target, backgroundColorDef, true ) ;
00631
00632 #if OSDL_DEBUG_RECTANGLES
00633
00634 LogPlug::trace( "UprightRectangle::drawWithRoundedCorners : "
00635 "Point in blitted rectangle on target surface : "
00636 + target.describePixelAt( _x + getWidth() / 2,
00637 _y + getHeight() / 2 ) ) ;
00638
00639 #endif // OSDL_DEBUG_RECTANGLES
00640
00641
00642
00643
00644
00645
00646 UprightRectangle rectangle( _x + radius, _y + 1,
00647 getWidth() - 2 * radius + 1, edgeWidth + 1 ) ;
00648 rectangle.draw( target, edgeColorDef, true ) ;
00649
00650
00651
00652
00653 rectangle.setUpperLeftOrdinate( _y + getHeight() - edgeWidth ) ;
00654 rectangle.draw( target, edgeColorDef, true ) ;
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668 rectangle.setUpperLeftAbscissa( _x ) ;
00669 rectangle.setWidth( edgeWidth + 1 ) ;
00670 rectangle.setUpperLeftOrdinate( _y + radius + 1 ) ;
00671 rectangle.setHeight( getHeight() - 2 * radius - 1 ) ;
00672 rectangle.draw( target, edgeColorDef, true ) ;
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684 rectangle.setUpperLeftAbscissa( _x + getWidth() - edgeWidth ) ;
00685 rectangle.setWidth( edgeWidth ) ;
00686 rectangle.setUpperLeftOrdinate( _y + radius + 1 ) ;
00687 rectangle.draw( target, edgeColorDef, true ) ;
00688
00689 return true ;
00690
00691 }
00692
00693
00694 Length UprightRectangle::computeRadiusForRoundRectangle( Length edgeWidth )
00695 const throw( VideoException )
00696 {
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708 Length min = edgeWidth + 1 ;
00709
00710 Length max = Ceylan::Maths::Min<Length>( getWidth(), getHeight() ) / 2 ;
00711
00712 if ( min > max )
00713 throw VideoException(
00714 "UprightRectangle::computeRadiusForRoundRectangle : "
00715 "no radius could be found for edge width = "
00716 + Ceylan::toString( edgeWidth ) + " and " + toString() ) ;
00717
00718
00719 return ( min + max ) / 2 ;
00720
00721 }
00722
00723
00724 SDL_Rect * UprightRectangle::toSDLRect() const throw( VideoException )
00725 {
00726
00727 SDL_Rect * res = new SDL_Rect() ;
00728
00729 #if OSDL_DEBUG
00730
00731 if ( res == 0 )
00732 throw VideoException(
00733 "UprightRectangle::toSDLRect() : not enough memory." ) ;
00734
00735 #endif // OSDL_DEBUG
00736
00737 res->x = _x ;
00738 res->y = _y ;
00739 res->w = getWidth() ;
00740 res->h = getHeight() ;
00741
00742 return res ;
00743
00744 }
00745
00746
00747 const string UprightRectangle::toString( Ceylan::VerbosityLevels level )
00748 const throw()
00749 {
00750
00751 return "Rectangle whose upper-left corner is "
00752 + Point2D( _x, _y ).toString( level )
00753 + " ( width = " + Ceylan::toString( getWidth() )
00754 + " ; height = " + Ceylan::toString( getHeight() ) + " )" ;
00755
00756 }
00757
00758
00759 bool operator == ( const UprightRectangle & first,
00760 const UprightRectangle & second ) throw()
00761 {
00762
00763 if ( first._x != second._x )
00764 return false ;
00765
00766 if ( first._y != second._y )
00767 return false ;
00768
00769 if ( first.getWidth() != second.getWidth() )
00770 return false ;
00771
00772 if ( first.getHeight() != second.getHeight() )
00773 return false ;
00774
00775 return true ;
00776
00777 }
00778
00779
00780 bool operator != ( const UprightRectangle & first,
00781 const UprightRectangle & second ) throw()
00782 {
00783
00784 return ! ( first == second ) ;
00785
00786 }
00787
00788
00789 std::ostream & operator << ( std::ostream & os, UprightRectangle & rect )
00790 throw()
00791 {
00792
00793 return os << rect.toString() ;
00794
00795 }
00796