00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <SDL_image.h>
00023 #include <cmath>
00024 #include "../sdl/sdlstretch.h"
00025 #include "surface.h"
00026 #include "blitter.h"
00027 #include "../basegfx.h"
00028 #include "../basestrm.h"
00029 #include "../misc.h"
00030 #include "../messaginghub.h"
00031 #include <iostream>
00032
00033 DI_Color::DI_Color() {
00034 r = 0;
00035 g = 0;
00036 b = 0;
00037 }
00038
00039 DI_Color::DI_Color(const SDL_Color& c) {
00040 *this = c;
00041 }
00042
00043 DI_Color::DI_Color(Uint32 c) {
00044 *this = c;
00045 }
00046
00047 DI_Color::DI_Color(Uint8 r, Uint8 g, Uint8 b) {
00048 *this = (Uint32)((r << 16) | (g << 8) | b);
00049 }
00050
00051 DI_Color& DI_Color::operator=(const SDL_Color& c) {
00052 r = c.r;
00053 g = c.g;
00054 b = c.b;
00055
00056 return *this;
00057 }
00058
00059 DI_Color& DI_Color::operator=(Uint32 c) {
00060 r = (c >> 16) & 0xFF;
00061 g = (c >> 8) & 0xFF;
00062 b = c & 0xFF;
00063
00064 return *this;
00065 }
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 SDLmm::PixelFormat* Surface::default8bit = NULL;
00076 SDLmm::PixelFormat* Surface::default32bit = NULL;
00077
00078 void Surface::SetScreen( SDL_Surface* screen )
00079 {
00080 if ( screen && screen->format->BitsPerPixel == 32 )
00081 default32bit = new SDLmm::PixelFormat ( screen->format );
00082 }
00083
00084
00085 Surface Surface::Duplicate() const
00086 {
00087 Surface new_surface(CreateSurface(*this));
00088
00089 megaBlitter<ColorTransform_None, ColorMerger_PlainOverwrite, SourcePixelSelector_Plain, TargetPixelSelector_All>(*this, new_surface, SPoint(0,0), nullParam, nullParam, nullParam, nullParam);
00090
00091 new_surface.Blit(*this);
00092 return new_surface;
00093 }
00094
00095
00096 void writeDefaultPixelFormat ( SDLmm::PixelFormat pf, tnstream& stream )
00097 {
00098 stream.writeInt( 1 );
00099 stream.writeInt(pf.BitsPerPixel()) ;
00100 stream.writeInt(pf.BytesPerPixel()) ;
00101 stream.writeInt(pf.Rmask()) ;
00102 stream.writeInt(pf.Gmask()) ;
00103 stream.writeInt(pf.Bmask()) ;
00104 stream.writeInt(pf.Amask()) ;
00105 stream.writeInt(pf.Rshift()) ;
00106 stream.writeInt(pf.Gshift()) ;
00107 stream.writeInt(pf.Bshift()) ;
00108 stream.writeInt(pf.Ashift()) ;
00109 stream.writeInt(pf.Rloss()) ;
00110 stream.writeInt(pf.Gloss()) ;
00111 stream.writeInt(pf.Bloss()) ;
00112 stream.writeInt(pf.Aloss()) ;
00113 stream.writeInt(pf.colorkey()) ;
00114 stream.writeInt(pf.alpha()) ;
00115 }
00116
00117 SDL_PixelFormat* readSDLPixelFormat( tnstream& stream )
00118 {
00119 SDL_PixelFormat* pf = new SDL_PixelFormat;
00120 int version = stream.readInt();
00121 if ( version != 1 )
00122 throw tinvalidversion( stream.getLocation(), 1, version );
00123
00124 pf->BitsPerPixel = stream.readInt();
00125 pf->BytesPerPixel = stream.readInt();
00126 pf->Rmask = stream.readInt();
00127 pf->Gmask = stream.readInt();
00128 pf->Bmask = stream.readInt();
00129 pf->Amask = stream.readInt();
00130 pf->Rshift = stream.readInt();
00131 pf->Gshift = stream.readInt();
00132 pf->Bshift = stream.readInt();
00133 pf->Ashift = stream.readInt();
00134 pf->Rloss = stream.readInt();
00135 pf->Gloss = stream.readInt();
00136 pf->Bloss = stream.readInt();
00137 pf->Aloss = stream.readInt();
00138 pf->colorkey = stream.readInt();
00139 pf->alpha = stream.readInt();
00140 return pf;
00141 }
00142
00143
00144
00145 Surface::Surface( SDL_Surface *surface) : SDLmm::Surface ( surface ), pixelDataPointer(NULL)
00146 {
00147 if ( me )
00148 convert();
00149 }
00150
00151 void Surface::convert()
00152 {
00153 if ( GetPixelFormat().BitsPerPixel() == 24 ) {
00154 Surface s = Surface::createSurface(w(), h(), 32 );
00155 s.Blit( *this );
00156 if ( flags() & SDL_SRCCOLORKEY )
00157 s.SetColorKey( SDL_SRCCOLORKEY, GetPixelFormat().colorkey() );
00158 *this = s;
00159 }
00160
00161 if ( default32bit && GetPixelFormat().BytesPerPixel() == 4 ) {
00162 if ( default32bit->Rmask() != GetPixelFormat().Rmask() || default32bit->Gmask() != GetPixelFormat().Gmask() || default32bit->Bmask() != GetPixelFormat().Bmask() ) {
00163 SDL_Surface *tmp;
00164 if ( flags() & SDL_SRCALPHA )
00165 tmp = SDL_DisplayFormatAlpha(me);
00166 else
00167 tmp = SDL_DisplayFormat(me);
00168
00169 if ( !tmp )
00170 return;
00171
00172 SetSurface(tmp);
00173 }
00174 }
00175
00176 }
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 Surface::Surface(const SDLmm::Surface& other) : SDLmm::Surface ( other ), pixelDataPointer(NULL)
00199 {
00200 if ( me )
00201 convert();
00202 }
00203
00204
00205 void Surface::readDefaultPixelFormat ( tnstream& stream )
00206 {
00207 default8bit = new SDLmm::PixelFormat( readSDLPixelFormat( stream ) );
00208 default32bit = new SDLmm::PixelFormat( readSDLPixelFormat( stream ) );
00209 }
00210
00211 void Surface::writeDefaultPixelFormat ( tnstream& stream )
00212 {
00213 ::writeDefaultPixelFormat( GetPixelFormat(),stream );
00214 }
00215
00216 const int surfaceVersion = 2;
00217
00218 void Surface::write ( tnstream& stream ) const
00219 {
00220 if ( !valid() ) {
00221 stream.writeWord( 16974 );
00222 stream.writeWord ( 1 );
00223 stream.writeChar ( 0 );
00224 stream.writeWord ( 0 );
00225 stream.writeWord ( 0 );
00226 return;
00227 }
00228 stream.writeWord( 16974 );
00229 stream.writeWord ( 1 );
00230 stream.writeChar ( 0 );
00231 stream.writeWord ( w() );
00232 stream.writeWord ( h() );
00233 stream.writeInt( surfaceVersion );
00234
00235 SDLmm::PixelFormat pf = GetPixelFormat();
00236
00237 stream.writeChar ( pf.BitsPerPixel() );
00238 stream.writeChar ( pf.BytesPerPixel() );
00239 stream.writeInt ( GetPixelFormat().colorkey());
00240 stream.writeInt( flags() );
00241 if ( pf.BytesPerPixel() == 1 ) {
00242 for ( int y = 0; y < h(); ++y )
00243 stream.writedata( ((char*)me->pixels) + y*pitch(), w() );
00244
00245
00246
00247
00248
00249 } else {
00250 SDLmm::PixelFormat pf = GetPixelFormat();
00251 stream.writeInt(pf.Rmask()) ;
00252 stream.writeInt(pf.Gmask()) ;
00253 stream.writeInt(pf.Bmask()) ;
00254 stream.writeInt(pf.Amask()) ;
00255 for ( int y = 0; y < h(); ++y ) {
00256 for ( int x = 0; x < w(); ++x )
00257 stream.writeInt( GetPixel(x,y));
00258
00259 }
00260 }
00261
00262 }
00263
00264
00265 void Surface::read ( tnstream& stream )
00266 {
00267 trleheader hd;
00268
00269 hd.id = stream.readWord();
00270 hd.size = stream.readWord();
00271 hd.rle = stream.readChar();
00272 hd.x = stream.readWord();
00273 hd.y = stream.readWord();
00274
00275 if ( hd.x == 0 && hd.y == 0 ) {
00276 SetSurface( NULL );
00277 return;
00278 }
00279
00280 if (hd.id == 16973) {
00281 char *pnter = new char [ hd.size + sizeof(hd) ];
00282 memcpy( pnter, &hd, sizeof(hd));
00283 char* q = pnter + sizeof(hd);
00284
00285 stream.readdata( q, hd.size);
00286
00287 char* uncomp = (char*) uncompress_rlepict ( pnter );
00288 pixelDataPointer = uncomp;
00289
00290
00291 delete[] pnter;
00292
00293 SetSurface( SDL_CreateRGBSurfaceFrom(uncomp+4, hd.x+1, hd.y+1, 8, hd.x+1, 0, 0, 0, 0 ));
00294 SetColorKey( SDL_SRCCOLORKEY, 255 );
00295 assignDefaultPalette();
00296 }
00297 else {
00298 if (hd.id == 16974) {
00299 int version = stream.readInt();
00300 if ( version > surfaceVersion )
00301 throw tinvalidversion( stream.getLocation(), version, surfaceVersion );
00302
00303 stream.readChar();
00304 int bytesPerPixel = stream.readChar();
00305 int colorkey = stream.readInt();
00306 int flags = stream.readInt();
00307 if ( bytesPerPixel == 1 ) {
00308 SDL_Surface* s = SDL_CreateRGBSurface ( SDL_SWSURFACE, hd.x, hd.y, 8, 0xff, 0xff, 0xff, 0xff );
00309 Uint8* p = (Uint8*)( s->pixels );
00310 for ( int y = 0; y < hd.y; ++y )
00311 stream.readdata( p + y*s->pitch, hd.x );
00312
00313
00314
00315
00316 SetSurface( s );
00317 assignDefaultPalette();
00318
00319 } else {
00320 int Rmask = stream.readInt();
00321 int Gmask = stream.readInt();
00322 int Bmask = stream.readInt();
00323 int Amask = stream.readInt();
00324
00325 SDL_Surface* s = SDL_CreateRGBSurface ( SDL_SWSURFACE, hd.x, hd.y, 32, Rmask, Gmask, Bmask, Amask );
00326 Uint32* p = (Uint32*)( s->pixels );
00327 for ( int y = 0; y < hd.y; ++y ) {
00328 for ( int x = 0; x< hd.x; ++x )
00329 *(p++) = stream.readInt();
00330 }
00331 SetSurface( s );
00332 }
00333 if ( flags & SDL_SRCCOLORKEY )
00334 SetColorKey( SDL_SRCCOLORKEY, colorkey );
00335
00336 if ( flags & SDL_SRCALPHA )
00337 SetAlpha ( SDL_SRCALPHA, GetPixelFormat().alpha());
00338 else
00339 SetAlpha ( 0, SDL_ALPHA_OPAQUE);
00340
00341 } else {
00342
00343
00344 SDL_Surface* s = SDL_CreateRGBSurface( SDL_SWSURFACE, hd.id+1, hd.size+1, 8, 0,0,0,0 );
00345
00346 for ( int y = 0; y <= hd.size; ++y ) {
00347 char* pixeldata = (char*)(s->pixels) + y * s->pitch;
00348 if ( y == 0 ) {
00349 memcpy ( pixeldata, ((char*)&hd) + 4, sizeof ( hd ) - 4);
00350 char* q = pixeldata + sizeof(hd) - 4;
00351 stream.readdata ( q, s->w - sizeof(hd) + 4 );
00352 } else {
00353 stream.readdata ( pixeldata, s->w );
00354 }
00355 }
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365 SetSurface( s );
00366 SetColorKey( SDL_SRCCOLORKEY, 255 );
00367 assignDefaultPalette();
00368 }
00369 }
00370 convert();
00371 }
00372
00373 void Surface::readImageFile( tnstream& stream )
00374 {
00375 SetSurface( IMG_Load_RW( SDL_RWFromStream ( &stream ), true ));
00376 convert();
00377 }
00378
00379
00380 Surface Surface::createSurface( int width, int height, SDLmm::Color color )
00381 {
00382 Surface s = createSurface ( width, height, 8, color );
00383 s.SetColorKey( SDL_SRCCOLORKEY, 255 );
00384 return s;
00385 }
00386
00387 Surface Surface::createSurface( int width, int height, int depth, SDLmm::Color color )
00388 {
00389 assert ( depth == 32 || depth == 8 );
00390
00391 SDL_Surface* surf = NULL;
00392 if ( depth == 32 && default32bit ) {
00393 int rmask = default32bit->Rmask();
00394 int gmask = default32bit->Gmask();
00395 int bmask = default32bit->Bmask();
00396 int amask = ~(rmask | gmask | bmask );
00397 surf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, depth, rmask, gmask, bmask, amask );
00398 } else
00399 surf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, depth, 0xff, 0xff00, 0xff0000, 0xff000000 );
00400
00401 Surface s ( surf );
00402 if ( depth == 32 )
00403 s.Fill(color);
00404 else {
00405 s.Fill(color & 0xff );
00406 s.assignDefaultPalette();
00407 }
00408
00409 return s;
00410 }
00411
00412 void Surface::FillTransparent()
00413 {
00414 if ( GetPixelFormat().BitsPerPixel() == 32 ) {
00415 Fill( 0 );
00416 } else {
00417 Fill( GetPixelFormat().colorkey() );
00418 }
00419 }
00420
00421
00422 void Surface::assignDefaultPalette()
00423 {
00424 if ( me && GetPixelFormat().BytesPerPixel() == 1 ) {
00425 SDL_Color spal[256];
00426 memset ( spal, 0, 256* sizeof(SDL_Color));
00427 for ( int i = 0; i < 256; i++ ) {
00428 spal[i].r = pal[i][0] * 4;;
00429 spal[i].g = pal[i][1] * 4;;
00430 spal[i].b = pal[i][2] * 4;;
00431 }
00432 SDL_SetColors ( me, spal, 0, 256 );
00433 }
00434 }
00435
00436
00437 void Surface::assignPalette(SDL_Color* colors, int startColor, int colorNum )
00438 {
00439 if ( me )
00440 SDL_SetColors ( me, colors, startColor, colorNum );
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450 void Surface::strech ( int width, int height )
00451 {
00452 if ( width != w() || height != h() ) {
00453 SDL_Surface* s;
00454 if( GetPixelFormat().BytesPerPixel() == 1 )
00455 s = SDL_CreateRGBSurface ( SDL_SWSURFACE, width, height, 8, 0,0,0,0 );
00456 else
00457 s = SDL_CreateRGBSurface ( SDL_SWSURFACE, width, height, 32, 0xff, 0xff00, 0xff0000, 0xff000000 );
00458
00459 SDL_StretchSurface( me,0,0,w()-1,h()-1, s, 0,0,width-1, height-1);
00460
00461 SetSurface(s);
00462 if( GetPixelFormat().BytesPerPixel() == 1 ) {
00463 assignDefaultPalette();
00464 detectColorKey();
00465 }
00466 }
00467 }
00468
00469 bool Surface::hasAlpha()
00470 {
00471 if ( GetPixelFormat().BitsPerPixel() > 8 ) {
00472 for ( int y = 0; y < h(); ++y )
00473 for ( int x = 0; x < w(); ++x )
00474 if ( (GetPixel(x,y) >> GetPixelFormat().Ashift()) != SDL_ALPHA_OPAQUE ) {
00475
00476 return true;
00477 }
00478
00479
00480 }
00481 return false;
00482 }
00483
00484
00485
00486 void Surface::detectColorKey ( bool RLE )
00487 {
00488
00489
00490 if ( GetPixelFormat().BitsPerPixel() > 8 )
00491 if ( hasAlpha() )
00492 return;
00493
00494 int flags = SDL_SRCCOLORKEY;
00495 if ( RLE )
00496 flags |= SDL_RLEACCEL;
00497
00498 SetAlpha ( 0, 0 );
00499
00500 if ( GetPixelFormat().BitsPerPixel() > 8 ) {
00501 SetColorKey( flags, GetPixel(0,0) & ( GetPixelFormat().Rmask() | GetPixelFormat().Gmask() | GetPixelFormat().Bmask()));
00502 } else
00503 SetColorKey( flags, GetPixel(0,0));
00504
00505 }
00506
00507
00508 bool Surface::isTransparent( SDLmm::Color col ) const
00509 {
00510 if ( flags() & SDL_SRCCOLORKEY )
00511 return (col & (GetPixelFormat().Rmask() | GetPixelFormat().Gmask() | GetPixelFormat().Bmask())) == GetPixelFormat().colorkey();
00512 else {
00513 if ( GetPixelFormat().BitsPerPixel() == 8 )
00514 return false;
00515 else {
00516 if ( ((col & GetPixelFormat().Amask()) >> GetPixelFormat().Ashift()) < opaque/2)
00517 return true;
00518 else
00519 return false;
00520 }
00521 }
00522 }
00523
00524 Surface::~Surface()
00525 {
00526
00527
00528
00529
00530
00531 }
00532
00533
00534
00535
00536 Surface& getFieldMask()
00537 {
00538 static Surface* mask8 = NULL;
00539 if ( !mask8 ) {
00540 try {
00541 tnfilestream st ( "largehex.pcx", tnstream::reading );
00542 RWOPS_Handler rwo ( SDL_RWFromStream( &st ) );
00543 mask8 = new Surface ( IMG_LoadPCX_RW ( rwo.Get() ));
00544 rwo.Close();
00545
00546 assert ( mask8->GetPixelFormat().BitsPerPixel() == 8);
00547 mask8->SetColorKey( SDL_SRCCOLORKEY, 0 );
00548 }
00549 catch ( tfileerror err ) {
00550 fatalError( "could not access " + err.getFileName() );
00551 }
00552
00553 }
00554 return *mask8;
00555
00556 }
00557
00558
00559 template<int pixelsize>
00560 class ColorMerger_MaskApply : public ColorMerger_AlphaHandler<pixelsize>
00561 {
00562 int alphamask;
00563 typedef typename PixelSize2Type<pixelsize>::PixelType PixelType;
00564 protected:
00565
00566 void init( const Surface& srf )
00567 {
00568 alphamask = ~(srf.GetPixelFormat().Amask());
00569 ColorMerger_AlphaHandler<pixelsize>::init(srf);
00570 }
00571
00572
00573 void assign ( PixelType src, PixelType* dest )
00574 {
00575 if ( !isOpaque(src ) )
00576 *dest &= alphamask;
00577 };
00578
00579 public:
00580 ColorMerger_MaskApply( NullParamType npt = nullParam )
00581 {}
00582 ;
00583 };
00584
00585
00586 void applyFieldMask( Surface& s, int x, int y, bool detecColorKey )
00587 {
00588 if ( s.GetPixelFormat().BitsPerPixel() == 8 ) {
00589
00590 MegaBlitter<1,1,ColorTransform_None,ColorMerger_AlphaOverwrite> blitter;
00591 blitter.blit( getFieldMask(), s, SPoint(0,0) );
00592 s.detectColorKey ( );
00593 } else {
00594 if ( detecColorKey ) {
00595 s.Blit( getFieldMask() );
00596 s.detectColorKey ( );
00597 } else {
00598 MegaBlitter<1,4,ColorTransform_None,ColorMerger_MaskApply> blitter;
00599 blitter.blit( getFieldMask(), s, SPoint(0,0) );
00600 }
00601 }
00602 }
00603
00604 void applyLegacyFieldMask( Surface& s, int x, int y, bool detectColorKey )
00605 {
00606 static Surface* mask32 = NULL;
00607 if ( !mask32 ) {
00608 Surface& mask8 = getFieldMask();
00609
00610 mask32 = new Surface ( Surface::createSurface( mask8.w(), mask8.h(), 32 ));
00611 for ( int y = 0; y < mask8.h(); ++y ) {
00612 Uint8* s = ((Uint8*) mask8.pixels()) + mask8.pitch() * y;
00613 Uint32* d = (Uint32*) ((Uint8*)(mask32->pixels()) + mask32->pitch() * y);
00614 for ( int x = 0; x < mask8.w(); ++x, ++s, ++d)
00615 if ( *s == 0 )
00616 *d = 0;
00617 else
00618 *d = 0xfffefefe;
00619 }
00620
00621 mask32->SetColorKey( SDL_SRCCOLORKEY, 0 );
00622
00623 }
00624 if ( s.GetPixelFormat().BitsPerPixel() == 8 ) {
00625
00626 MegaBlitter<1,1,ColorTransform_None,ColorMerger_AlphaOverwrite> blitter;
00627 blitter.blit( getFieldMask(), s, SPoint(0,0) );
00628 s.detectColorKey ( );
00629 } else {
00630 if ( !detectColorKey || s.hasAlpha() ) {
00631 MegaBlitter<1,4,ColorTransform_None,ColorMerger_MaskApply> blitter;
00632 blitter.blit( getFieldMask(), s, SPoint(0,0) );
00633 } else {
00634 s.Blit( *mask32 );
00635 s.detectColorKey ( );
00636 }
00637 }
00638 }
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 Surface rotateSurface( Surface& s, int degrees )
00668 {
00669 SurfaceLock sl1 ( s );
00670
00671 Surface dest = s.Duplicate();
00672
00673 SurfaceLock sl2( dest );
00674
00675 if ( s.GetPixelFormat().BitsPerPixel() == 8 )
00676 dest.Fill ( 255 );
00677 else {
00678 dest.Fill(0xfefefe);
00679 }
00680 dest.detectColorKey();
00681
00682 for ( int y = 0; y < s.h(); y++ ) {
00683 for ( int x = 0; x < s.w(); x++ ) {
00684 SPoint newpos = getPixelRotationLocation( SPoint(x,y), s.w(),s.h(), degrees );
00685
00686 if ( newpos.x >= 0 && newpos.y >= 0 && newpos.x < s.w() && newpos.y < s.h() )
00687 dest.SetPixel( x, y, s.GetPixel ( newpos ));
00688 }
00689 }
00690
00691 return dest;
00692 }
00693
00694
00695 void* Surface::toBGI() const
00696 {
00697 void* p = asc_malloc( imagesize(1,1,w(),h()) );
00698 char* c = (char*) p;
00699 Uint16* ww = (Uint16*) p;
00700 ww[0] = w()-1;
00701 ww[1] = h()-1;
00702 c += 4;
00703 for ( int y = 0; y < h(); ++y )
00704 for ( int x = 0; x < w(); ++x )
00705 *c++ = GetPixel(x,y);
00706 return p;
00707 }
00708
00709 int Surface::getMemoryFootprint() const
00710 {
00711 int size = sizeof(*this);
00712
00713 const SDL_Surface* s = getBaseSurface();
00714 if ( s ) {
00715 size += sizeof( SDL_Surface );
00716 if ( s->format ) {
00717 size += sizeof( SDL_PixelFormat );
00718 if ( s->format->palette )
00719 size += sizeof ( SDL_Palette ) + s->format->palette->ncolors * sizeof(SDL_Color);
00720 }
00721 size += s->h * s->pitch;
00722 }
00723 return size;
00724 }
00725
00726
00727 void Surface::ColorKey2AlphaChannel()
00728 {
00729 Lock();
00730 for ( int y = 0; y < h(); ++y ) {
00731 char* cp = (char*) pixels();
00732 cp += y * pitch();
00733 int* ip = (int*) cp;
00734 for ( int x = 0; x < w(); ++x, ++ip )
00735 if ( (*ip & ~(0xff << GetPixelFormat().Ashift())) == GetPixelFormat().colorkey())
00736 *ip &= ~(Surface::transparent << GetPixelFormat().Ashift());
00737 }
00738 GetSurface()->flags &= ~SDL_SRCCOLORKEY;
00739 Unlock();
00740 }
00741