sdlimage.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 by the FIFE team                              *
00003  *   http://www.fifengine.net                                              *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <cassert>
00024 #include <iostream>
00025 
00026 // 3rd party library includes
00027 
00028 // FIFE includes
00029 // These includes are split up in two parts, separated by one empty line
00030 // First block: files included from the FIFE root src directory
00031 // Second block: files included from the same folder
00032 #include "util/log/logger.h"
00033 #include "util/structures/rect.h"
00034 #include "video/imagemanager.h"
00035 #include "video/renderbackend.h"
00036 
00037 #include "renderbackendsdl.h"
00038 #include "sdlblendingfunctions.h"
00039 #include "sdlimage.h"
00040 
00041 namespace FIFE {
00042     static Logger _log(LM_VIDEO);
00043 
00044     SDLImage::SDLImage(IResourceLoader* loader):
00045         Image(loader) {
00046         resetSdlimage();
00047     }
00048 
00049     SDLImage::SDLImage(const std::string& name, IResourceLoader* loader):
00050         Image(name, loader) {
00051         resetSdlimage();
00052     }
00053 
00054     SDLImage::SDLImage(SDL_Surface* surface):
00055         Image(surface) {
00056         resetSdlimage();
00057      }
00058 
00059     SDLImage::SDLImage(const std::string& name, SDL_Surface* surface):
00060         Image(name, surface) {
00061         resetSdlimage();
00062      }
00063 
00064     SDLImage::SDLImage(const uint8_t* data, uint32_t width, uint32_t height):
00065         Image(data, width, height) {
00066         resetSdlimage();
00067     }
00068 
00069     SDLImage::SDLImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
00070         Image(name, data, width, height) {
00071         resetSdlimage();
00072     }
00073 
00074     void SDLImage::resetSdlimage() {
00075         m_last_alpha = 255;
00076         m_finalized = false;
00077         m_colorkey = RenderBackend::instance()->getColorKey();
00078         m_scale_x = 1.0;
00079         m_scale_y = 1.0;
00080         m_zoom_surface = NULL;
00081     }
00082 
00083     SDLImage::~SDLImage() {
00084         if (m_zoom_surface) {
00085             SDL_FreeSurface(m_zoom_surface);
00086         }
00087     }
00088 
00089     void SDLImage::setSurface(SDL_Surface* surface) {
00090         if (m_zoom_surface) {
00091             SDL_FreeSurface(m_zoom_surface);
00092             m_zoom_surface = NULL;
00093         }
00094         reset(surface);
00095         resetSdlimage();
00096     }
00097 
00098     void SDL_BlitSurfaceWithAlpha( const SDL_Surface* src, const SDL_Rect* srcRect,
00099         SDL_Surface* dst,  SDL_Rect* dstRect, uint8_t alpha ) {
00100         if( 0 == alpha ) {
00101             return;
00102         }
00103 
00104         int32_t screenX, screenY;
00105         if( dstRect ) {
00106             screenX = dstRect->x;
00107             screenY = dstRect->y;
00108         } else {
00109             screenX = dst->clip_rect.x;
00110             screenY = dst->clip_rect.y;
00111         }
00112 
00113         int32_t width, height, tX, tY;
00114         if( srcRect ) {
00115             tX = srcRect->x;
00116             tY = srcRect->y;
00117             width = srcRect->w;
00118             height = srcRect->h;
00119         } else {
00120             tX = src->clip_rect.x;
00121             tY = src->clip_rect.y;
00122             width = src->clip_rect.w;
00123             height = src->clip_rect.h;
00124         }
00125 
00126         // Clipping.
00127         if( ( screenX >= ( dst->clip_rect.x + dst->clip_rect.w ) ) ||
00128             ( screenY >= ( dst->clip_rect.y + dst->clip_rect.h ) ) ||
00129             ( ( screenX + width ) <= dst->clip_rect.x ) ||
00130             ( ( screenY + height ) <= dst->clip_rect.y ) ) {
00131             return;
00132         }
00133 
00134         if( screenX < dst->clip_rect.x ) {
00135             int32_t dX = dst->clip_rect.x - screenX;
00136             screenX += dX;
00137             width -= dX;
00138             tX += dX;
00139         }
00140 
00141         if( ( screenX + width ) > ( dst->clip_rect.x + dst->clip_rect.w ) ) {
00142             int32_t dX = ( screenX + width ) - ( dst->clip_rect.x + dst->clip_rect.w );
00143             width -= dX;
00144         }
00145 
00146         if( screenY < dst->clip_rect.y ) {
00147             int32_t dY = dst->clip_rect.y - screenY;
00148             screenY += dY;
00149             height -= dY;
00150             tY += dY;
00151         }
00152 
00153         if( ( screenY + height ) > ( dst->clip_rect.y + dst->clip_rect.h ) ) {
00154             int32_t dY = ( screenY + height ) - ( dst->clip_rect.y + dst->clip_rect.h );
00155             height -= dY;
00156         }
00157 
00158         if( ( 0 >= height ) || ( 0 >= width ) ) {
00159             return;
00160         }
00161 
00162         SDL_LockSurface( dst );
00163 
00164         uint8_t* srcData = reinterpret_cast< uint8_t* > ( src->pixels );
00165         uint8_t* dstData = reinterpret_cast< uint8_t* > ( dst->pixels );
00166 
00167         // move data pointers to the start of the pixels we're copying
00168         srcData += tY * src->pitch  + tX * src->format->BytesPerPixel;
00169         dstData += screenY * dst->pitch + screenX * dst->format->BytesPerPixel;
00170 
00171         switch( src->format->BitsPerPixel ) {
00172             case 32: {
00173                 switch( dst->format->BitsPerPixel ) {
00174                     case 16: {
00175                         if( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) {
00176                             for( int32_t y = height; y > 0; --y ) {
00177                                 SDL_BlendRow_RGBA8_to_RGB565( srcData, dstData, alpha, width );
00178                                 srcData += src->pitch;
00179                                 dstData += dst->pitch;
00180                             }
00181                         }
00182                     }
00183                     break;
00184 
00185                     case 24: {
00186                         for( int32_t y = height; y > 0; --y ) {
00187                             SDL_BlendRow_RGBA8_to_RGB8( srcData, dstData, alpha, width );
00188                             srcData += src->pitch;
00189                             dstData += dst->pitch;
00190                         }
00191                     }
00192                     break;
00193 
00194                     case 32: {
00195                         for( int32_t y = height; y > 0; --y ) {
00196                             SDL_BlendRow_RGBA8_to_RGBA8( srcData, dstData, alpha, width );
00197                             srcData += src->pitch;
00198                             dstData += dst->pitch;
00199                         }
00200                     }
00201                     break;
00202 
00203                     default:
00204                         break;
00205                 }   
00206             }
00207             break;
00208 
00209             case 16: {
00210                 if( 0x000F == src->format->Amask ) {
00211                     if( ( 16 == dst->format->BitsPerPixel ) &&
00212                         ( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) ) {
00213                         for( int32_t y = height; y > 0; --y ) {
00214                             SDL_BlendRow_RGBA4_to_RGB565( srcData, dstData, alpha, width );
00215                             srcData += src->pitch;
00216                             dstData += dst->pitch;
00217                         }
00218                     }
00219                 }
00220             }
00221             break;
00222 
00223             default:
00224                 break;
00225         }   
00226 
00227         SDL_UnlockSurface( dst );
00228     }
00229 
00230     void zoomSurface(SDL_Surface* src, SDL_Surface* dst) {
00231         uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
00232         uint32_t* src_help_pointer = src_pointer;
00233         uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
00234 
00235         int32_t x, y, *sx_ca, *sy_ca;
00236         int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
00237         int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
00238         int32_t sx_c = 0;
00239         int32_t sy_c = 0;
00240 
00241         // Allocates memory and calculates row wide&height
00242         int32_t* sx_a = new int32_t[dst->w + 1];
00243         sx_ca = sx_a;
00244         for (x = 0; x <= dst->w; x++) {
00245             *sx_ca = sx_c;
00246             sx_ca++;
00247             sx_c &= 0xffff;
00248             sx_c += sx;
00249         }
00250 
00251         int32_t* sy_a = new int32_t[dst->h + 1];
00252         sy_ca = sy_a;
00253         for (y = 0; y <= dst->h; y++) {
00254             *sy_ca = sy_c;
00255             sy_ca++;
00256             sy_c &= 0xffff;
00257             sy_c += sy;
00258         }
00259         sy_ca = sy_a;
00260 
00261         // Transfers the image data
00262 
00263         if (SDL_MUSTLOCK(src)) {
00264             SDL_LockSurface(src);
00265         }
00266         if (SDL_MUSTLOCK(dst)) {
00267             SDL_LockSurface(dst);
00268         }
00269 
00270         for (y = 0; y < dst->h; y++) {
00271             src_pointer = src_help_pointer;
00272             sx_ca = sx_a;
00273             for (x = 0; x < dst->w; x++) {
00274                 *dst_pointer = *src_pointer;
00275                 sx_ca++;
00276                 src_pointer += (*sx_ca >> 16);
00277                 dst_pointer++;
00278             }
00279             sy_ca++;
00280             src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
00281         }
00282 
00283         if (SDL_MUSTLOCK(dst)) {
00284             SDL_UnlockSurface(dst);
00285         }
00286         if (SDL_MUSTLOCK(src)) {
00287             SDL_UnlockSurface(src);
00288         }
00289 
00290         // Free memory
00291         delete [] sx_a;
00292         delete [] sy_a;
00293     }
00294 
00295     SDL_Surface* getZoomedSurface(SDL_Surface * src, double zoomx, double zoomy) {
00296         if (src == NULL)
00297             return NULL;
00298 
00299         SDL_Surface *zoom_src;
00300         SDL_Surface *zoom_dst;
00301         int32_t dst_w = static_cast<int32_t>(round(src->w * zoomx));
00302         int32_t dst_h = static_cast<int32_t>(round(src->h * zoomy));
00303         if (dst_w < 1)
00304             dst_w = 1;
00305         if (dst_h < 1)
00306             dst_h = 1;
00307 
00308         // If source surface has no alpha channel then convert it
00309         if (src->format->Amask == 0) {
00310             zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
00311                     RMASK, GMASK,
00312                     BMASK, AMASK);
00313             SDL_BlitSurface(src, NULL, zoom_src, NULL);
00314         } else {
00315             zoom_src = src;
00316         }
00317         // Create destination surface
00318         zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_w, dst_h, 32,
00319                 zoom_src->format->Rmask, zoom_src->format->Gmask,
00320                 zoom_src->format->Bmask, zoom_src->format->Amask);
00321 
00322         // Zoom surface
00323         zoomSurface(zoom_src, zoom_dst);
00324 
00325         return zoom_dst;
00326     }
00327 
00328     bool nearlyEqual(float a, float b) {
00329         return ABS(a - b) <= 0.00001;
00330     }
00331 
00332     void SDLImage::render(const Rect& rect, uint8_t alpha, uint8_t const* /*unused rgb*/) {
00333         if (alpha == 0) {
00334             return;
00335         }
00336         validateShared();
00337         SDL_Surface* target = RenderBackend::instance()->getRenderTargetSurface();
00338         assert(target != m_surface); // can't draw on the source surface
00339 
00340         if (rect.right() < 0 || rect.x > static_cast<int32_t>(target->w) ||
00341             rect.bottom() < 0 || rect.y > static_cast<int32_t>(target->h)) {
00342             return;
00343         }
00344         finalize();
00345 
00346         SDL_Rect r;
00347         r.x = rect.x;
00348         r.y = rect.y;
00349         r.w = rect.w;
00350         r.h = rect.h;
00351 
00352         float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
00353         float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
00354         bool zoomed = false;
00355         bool equal = false;
00356 
00357         if (!nearlyEqual(scale_x, 1.0) && !nearlyEqual(scale_y, 1.0)) {
00358             zoomed = true;
00359             if(nearlyEqual(m_scale_x, scale_x) && nearlyEqual(m_scale_y, scale_y)) {
00360                 equal = true;
00361             } else {
00362                 m_scale_x = scale_x;
00363                 m_scale_y = scale_y;
00364             }
00365         }
00366 
00367         if (m_surface->format->Amask == 0) {
00368             // Image has no alpha channel. This allows us to use the per-surface alpha.
00369             if (m_last_alpha != alpha) {
00370                 m_last_alpha = alpha;
00371                 SDL_SetAlpha(m_surface, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
00372             }
00373             if (!zoomed) {
00374                 SDL_BlitSurface(m_surface, 0, target, &r);
00375             } else if (equal && m_zoom_surface) {
00376                 SDL_BlitSurface(m_zoom_surface, 0, target, &r);
00377             } else {
00378                 SDL_FreeSurface(m_zoom_surface);
00379                 m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00380                 SDL_BlitSurface(m_zoom_surface, 0, target, &r);
00381             }
00382         } else {
00383             if( 255 != alpha ) {
00384                 // Special blitting routine with alpha blending:
00385                 // dst.rgb = ( src.rgb * src.a * alpha ) + ( dst.rgb * (255 - ( src.a * alpha ) ) );
00386                 if (!zoomed) {
00387                     SDL_BlitSurfaceWithAlpha( m_surface, 0, target, &r, alpha );
00388                 } else if (equal && m_zoom_surface) {
00389                     SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, target, &r, alpha );
00390                 } else {
00391                     SDL_FreeSurface(m_zoom_surface);
00392                     m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00393                     SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, target, &r, alpha );
00394                 }
00395             } else {
00396                 if (!zoomed) {
00397                     SDL_BlitSurface(m_surface, 0, target, &r);
00398                 } else if (equal && m_zoom_surface) {
00399                     SDL_BlitSurface(m_zoom_surface, 0, target, &r);
00400                 } else {
00401                     SDL_FreeSurface(m_zoom_surface);
00402                     m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00403                     SDL_BlitSurface(m_zoom_surface, 0, target, &r);
00404                 }
00405             }
00406         }
00407     }
00408 
00409     void SDLImage::finalize() {
00410         if( m_finalized ) {
00411             return;
00412         }
00413         m_finalized = true;
00414         SDL_Surface *old_surface = m_surface;
00415         Uint32 key = SDL_MapRGB(m_surface->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
00416 
00417         if (m_surface->format->Amask == 0) {
00418             // only use color key if feature is enabled
00419             if (RenderBackend::instance()->isColorKeyEnabled()) {
00420                 SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
00421             }
00422 
00423             m_surface = SDL_DisplayFormat(m_surface);
00424         } else {
00425             RenderBackendSDL* be = static_cast<RenderBackendSDL*>(RenderBackend::instance());
00426             bool m_isalphaoptimized = be->isAlphaOptimizerEnabled();
00427             if( m_isalphaoptimized ) {
00428                 m_surface = optimize(m_surface);
00429             } else  {
00430                 SDL_SetAlpha(m_surface, SDL_SRCALPHA, 255);
00431 
00432                 // only use color key if feature is enabled
00433                 if (RenderBackend::instance()->isColorKeyEnabled()) {
00434                     SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
00435                 }
00436 
00437                 m_surface = SDL_DisplayFormatAlpha(m_surface);
00438             }
00439         }
00440         SDL_FreeSurface(old_surface);
00441     }
00442 
00443     SDL_Surface* SDLImage::optimize(SDL_Surface* src) {
00444         // The algorithm is originally by "Tim Goya" <tuxdev103@gmail.com>
00445         // Few modifications and adaptions by the FIFE team.
00446         //
00447         // It tries to determine whether an image with a alpha channel
00448         // actually uses that. Often PNGs contains an alpha channels
00449         // as they don't provide a colorkey feature(?) - so to speed
00450         // up SDL rendering we try to remove the alpha channel.
00451 
00452         // As a reminder: src->format->Amask != 0 here
00453 
00454         int32_t transparent = 0;
00455         int32_t opaque = 0;
00456         int32_t semitransparent = 0;
00457         int32_t alphasum = 0;
00458         int32_t alphasquaresum = 0;
00459         bool colors[(1 << 12)];
00460         memset(colors, 0, (1 << 12) * sizeof(bool));
00461 
00462         int32_t bpp = src->format->BytesPerPixel;
00463         if(SDL_MUSTLOCK(src)) {
00464             SDL_LockSurface(src);
00465         }
00466         /*  In the first pass through we calculate avg(alpha), avg(alpha^2)
00467             and the number of semitransparent pixels.
00468             We also try to find a useable color.
00469         */
00470         for(int32_t y = 0;y < src->h;y++) {
00471             for(int32_t x = 0;x < src->w;x++) {
00472                 Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
00473                 Uint32 mapped = 0;
00474                 switch(bpp) {
00475                     case 1:
00476                         mapped = *pixel;
00477                         break;
00478                     case 2:
00479                         mapped = *(Uint16 *)pixel;
00480                         break;
00481                     case 3:
00482 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00483                         mapped |= pixel[0] << 16;
00484                         mapped |= pixel[1] << 8;
00485                         mapped |= pixel[2] << 0;
00486 #else
00487                         mapped |= pixel[0] << 0;
00488                         mapped |= pixel[1] << 8;
00489                         mapped |= pixel[2] << 16;
00490 #endif
00491                         break;
00492                     case 4:
00493                         mapped = *(Uint32 *)pixel;
00494                         break;
00495                 }
00496                 Uint8 red, green, blue, alpha;
00497                 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
00498                 if(alpha < 16) {
00499                     transparent++;
00500                 } else if (alpha > 240) {
00501                     opaque++;
00502                     alphasum += alpha;
00503                     alphasquaresum += alpha*alpha;
00504                 } else {
00505                     semitransparent++;
00506                     alphasum += alpha;
00507                     alphasquaresum += alpha*alpha;
00508                 }
00509                 // mark the color as used.
00510                 if( alpha != 0 ) {
00511                     colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
00512                 }
00513             }
00514         }
00515         int32_t avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
00516         int32_t alphavariance = 0;
00517 
00518         if(SDL_MUSTLOCK(src)) {
00519             SDL_UnlockSurface(src);
00520         }
00521         alphasquaresum /= (opaque + semitransparent) ? (opaque + semitransparent) : 1;
00522         alphavariance = alphasquaresum - avgalpha*avgalpha;
00523         if(semitransparent > ((transparent + opaque + semitransparent) / 8)
00524            && alphavariance > 16) {
00525             FL_DBG(_log, LMsg("sdlimage")
00526                 << "Trying to alpha-optimize image. FAILED: real alpha usage. "
00527                 << " alphavariance=" << alphavariance
00528                 << " total=" << (transparent + opaque + semitransparent)
00529                 << " semitransparent=" << semitransparent
00530                 << "(" << (float(semitransparent)/(transparent + opaque + semitransparent))
00531                 << ")");
00532             return SDL_DisplayFormatAlpha(src);
00533         }
00534 
00535         // check availability of a suitable color as colorkey
00536         int32_t keycolor = -1;
00537         for(int32_t i = 0;i < (1 << 12);i++) {
00538             if(!colors[i]) {
00539                 keycolor = i;
00540                 break;
00541             }
00542         }
00543         if(keycolor == -1) {
00544             FL_DBG(_log, LMsg("sdlimage") << "Trying to alpha-optimize image. FAILED: no free color");
00545             return SDL_DisplayFormatAlpha(src);
00546         }
00547 
00548         SDL_Surface *dst = SDL_CreateRGBSurface(src->flags & ~(SDL_SRCALPHA) | SDL_SWSURFACE,
00549                                                 src->w, src->h,
00550                                                 src->format->BitsPerPixel,
00551                                                 src->format->Rmask,  src->format->Gmask,
00552                                                 src->format->Bmask, 0);
00553         bpp = dst->format->BytesPerPixel;
00554 
00555         Uint32 key = SDL_MapRGB(dst->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
00556 
00557         // if the global color key feature is disabled, then use the manually found color key
00558         if (!RenderBackend::instance()->isColorKeyEnabled()) {
00559             key = SDL_MapRGB(dst->format,
00560                             (((keycolor & 0xf00) >> 4) | 0xf),
00561                             ((keycolor & 0xf0) | 0xf),
00562                             (((keycolor & 0xf) << 4) | 0xf));
00563         }
00564 
00565         if(SDL_MUSTLOCK(src)) {
00566             SDL_LockSurface(src);
00567         }
00568         if(SDL_MUSTLOCK(dst)) {
00569             SDL_LockSurface(dst);
00570         }
00571         for(int32_t y = 0;y < dst->h;y++) {
00572             for(int32_t x = 0;x < dst->w;x++) {
00573                 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
00574                 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
00575                 Uint32 mapped = 0;
00576                 switch(bpp) {
00577                     case 1:
00578                         mapped = *srcpixel;
00579                         break;
00580                     case 2:
00581                         mapped = *(Uint16 *)srcpixel;
00582                         break;
00583                     case 3:
00584 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00585                         mapped |= srcpixel[0] << 16;
00586                         mapped |= srcpixel[1] << 8;
00587                         mapped |= srcpixel[2] << 0;
00588 #else
00589                         mapped |= srcpixel[0] << 0;
00590                         mapped |= srcpixel[1] << 8;
00591                         mapped |= srcpixel[2] << 16;
00592 #endif
00593                         break;
00594                     case 4:
00595                         mapped = *(Uint32 *)srcpixel;
00596                         break;
00597                 }
00598                 Uint8 red, green, blue, alpha;
00599                 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
00600                 if(alpha < (avgalpha / 4)) {
00601                     mapped = key;
00602                 } else {
00603                     mapped = SDL_MapRGB(dst->format, red, green, blue);
00604                 }
00605                 switch(bpp) {
00606                     case 1:
00607                         *dstpixel = mapped;
00608                         break;
00609                     case 2:
00610                         *(Uint16 *)dstpixel = mapped;
00611                         break;
00612                     case 3:
00613 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00614                         dstpixel[0] = (mapped >> 16) & 0xff;
00615                         dstpixel[1] = (mapped >> 8) & 0xff;
00616                         dstpixel[2] = (mapped >> 0) & 0xff;
00617 #else
00618                         dstpixel[0] = (mapped >> 0) & 0xff;
00619                         dstpixel[1] = (mapped >> 8) & 0xff;
00620                         dstpixel[2] = (mapped >> 16) & 0xff;
00621 #endif
00622                         break;
00623                     case 4:
00624                         *(Uint32 *)dstpixel = mapped;
00625                         break;
00626                 }
00627             }
00628         }
00629         if(SDL_MUSTLOCK(dst)) {
00630             SDL_UnlockSurface(dst);
00631         }
00632         if(SDL_MUSTLOCK(src)) {
00633             SDL_UnlockSurface(src);
00634         }
00635         // Using the per surface alpha value does not
00636         // work out for mostly transparent pixels.
00637         // Thus disabling the part here - this needs a
00638         // more complex refactoring.
00639         // if(avgalpha < 240) {
00640         //  SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
00641         //}
00642         SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
00643         SDL_Surface *convert = SDL_DisplayFormat(dst);
00644         SDL_FreeSurface(dst);
00645         FL_DBG(_log, LMsg("sdlimage ")
00646             << "Trying to alpha-optimize image. SUCCESS: colorkey is " << key);
00647         return convert;
00648     } // end optimize
00649 
00650     size_t SDLImage::getSize() {
00651         size_t zoomSize = 0;
00652         if (m_zoom_surface) {
00653             zoomSize = m_zoom_surface->h * m_zoom_surface->pitch;
00654         }
00655         if (m_surface) {
00656             zoomSize += m_surface->h * m_surface->pitch;
00657         }
00658 
00659         return zoomSize;
00660     }
00661 
00662     void SDLImage::useSharedImage(const ImagePtr& shared, const Rect& region) {
00663         if(shared->getState() != IResource::RES_LOADED) {
00664             shared->load();
00665         }
00666         SDL_Surface* src_surface = shared->getSurface();
00667         SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, region.w, region.h,
00668             src_surface->format->BitsPerPixel, src_surface->format->Rmask, src_surface->format->Gmask,
00669             src_surface->format->Bmask, src_surface->format->Amask);
00670 
00671         SDL_SetAlpha(src_surface, 0, 0);
00672         SDL_Rect srcrect = { region.x, region.y, region.w, region.h };
00673         SDL_BlitSurface(src_surface, &srcrect, surface, NULL);
00674         SDL_SetAlpha(src_surface, SDL_SRCALPHA, 0);
00675 
00676         setSurface(surface);
00677         m_shared = false; // this isn't a mistake
00678         m_subimagerect = region;
00679         m_atlas_img = shared;
00680         m_atlas_name = shared->getName();
00681         setState(IResource::RES_LOADED);
00682     }
00683 
00684     void SDLImage::forceLoadInternal() {
00685         validateShared();
00686     }
00687 
00688     void SDLImage::validateShared() {
00689         if (m_atlas_name.empty()) {
00690             return;
00691         }
00692 
00693         if (m_atlas_img->getState() == IResource::RES_NOT_LOADED ||
00694             getState() == IResource::RES_NOT_LOADED) {
00695             load();
00696         }
00697     }
00698 
00699     void SDLImage::load() {
00700         if (!m_atlas_name.empty()) {
00701             // check atlas image
00702             // if it does not exist, it is created.
00703             if (!ImageManager::instance()->exists(m_atlas_name)) {
00704                 ImagePtr newAtlas = ImageManager::instance()->create(m_atlas_name);
00705                 m_atlas_img = newAtlas;
00706             }
00707             useSharedImage(m_atlas_img , m_subimagerect);
00708         } else {
00709             Image::load();
00710         }
00711     }
00712 
00713     void SDLImage::free() {
00714         setSurface(NULL);
00715         m_state = IResource::RES_NOT_LOADED;
00716     }
00717 }