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