FIFE 2008.0
sdlimage.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
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/renderbackend.h"
00035 
00036 #include "renderbackendsdl.h"
00037 #include "sdlblendingfunctions.h"
00038 #include "sdlimage.h"
00039 
00040 namespace FIFE {
00041     static Logger _log(LM_VIDEO);
00042 
00043     SDLImage::SDLImage(SDL_Surface* surface):
00044         Image(surface) {
00045         resetSdlimage();
00046      }
00047 
00048     SDLImage::SDLImage(const uint8_t* data, unsigned int width, unsigned int height):
00049         Image(data, width, height) {
00050         resetSdlimage();
00051     }
00052 
00053     void SDLImage::resetSdlimage() {
00054         m_last_alpha = 255;
00055         m_finalized = false;
00056         m_isalphaoptimized = false;
00057         m_colorkey = RenderBackend::instance()->getColorKey();
00058         m_scale_x = 1.0;
00059         m_scale_y = 1.0;
00060         m_zoom_surface = NULL;
00061     }
00062 
00063     SDLImage::~SDLImage() {
00064         if (m_zoom_surface) {
00065             SDL_FreeSurface(m_zoom_surface);
00066         }
00067     }
00068 
00069     void SDL_BlitSurfaceWithAlpha( const SDL_Surface* src, const SDL_Rect* srcRect,
00070         SDL_Surface* dst,  SDL_Rect* dstRect, unsigned char alpha ) {
00071         if( 0 == alpha ) {
00072             return;
00073         }
00074 
00075         int screenX, screenY;
00076         if( dstRect ) {
00077             screenX = dstRect->x;
00078             screenY = dstRect->y;
00079         } else {
00080             screenX = dst->clip_rect.x;
00081             screenY = dst->clip_rect.y;
00082         }
00083 
00084         int width, height, tX, tY;
00085         if( srcRect ) {
00086             tX = srcRect->x;
00087             tY = srcRect->y;
00088             width = srcRect->w;
00089             height = srcRect->h;
00090         } else {
00091             tX = src->clip_rect.x;
00092             tY = src->clip_rect.y;
00093             width = src->clip_rect.w;
00094             height = src->clip_rect.h;
00095         }
00096 
00097         // Clipping.
00098         if( ( screenX >= ( dst->clip_rect.x + dst->clip_rect.w ) ) ||
00099             ( screenY >= ( dst->clip_rect.y + dst->clip_rect.h ) ) ||
00100             ( ( screenX + width ) <= dst->clip_rect.x ) ||
00101             ( ( screenY + height ) <= dst->clip_rect.y ) ) {
00102             return;
00103         }
00104 
00105         if( screenX < dst->clip_rect.x ) {
00106             int dX = dst->clip_rect.x - screenX;
00107             screenX += dX;
00108             width -= dX;
00109             tX += dX;
00110         }
00111 
00112         if( ( screenX + width ) > ( dst->clip_rect.x + dst->clip_rect.w ) ) {
00113             int dX = ( screenX + width ) - ( dst->clip_rect.x + dst->clip_rect.w );
00114             width -= dX;
00115         }
00116 
00117         if( screenY < dst->clip_rect.y ) {
00118             int dY = dst->clip_rect.y - screenY;
00119             screenY += dY;
00120             height -= dY;
00121             tY += dY;
00122         }
00123 
00124         if( ( screenY + height ) > ( dst->clip_rect.y + dst->clip_rect.h ) ) {
00125             int dY = ( screenY + height ) - ( dst->clip_rect.y + dst->clip_rect.h );
00126             height -= dY;
00127         }
00128 
00129         if( ( 0 >= height ) || ( 0 >= width ) ) {
00130             return;
00131         }
00132 
00133         SDL_LockSurface( dst );
00134 
00135         unsigned char* srcData = reinterpret_cast< unsigned char* > ( src->pixels );
00136         unsigned char* dstData = reinterpret_cast< unsigned char* > ( dst->pixels );
00137 
00138         // move data pointers to the start of the pixels we're copying
00139         srcData += tY * src->pitch  + tX * src->format->BytesPerPixel;
00140         dstData += screenY * dst->pitch + screenX * dst->format->BytesPerPixel;
00141 
00142         switch( src->format->BitsPerPixel ) {
00143             case 32: {
00144                 switch( dst->format->BitsPerPixel ) {
00145                     case 16: {
00146                         if( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) {
00147                             for( int y = height; y > 0; --y ) {
00148                                 SDL_BlendRow_RGBA8_to_RGB565( srcData, dstData, alpha, width );
00149                                 srcData += src->pitch;
00150                                 dstData += dst->pitch;
00151                             }
00152                         }
00153                     }
00154                     break;
00155 
00156                     case 24: {
00157                         for( int y = height; y > 0; --y ) {
00158                             SDL_BlendRow_RGBA8_to_RGB8( srcData, dstData, alpha, width );
00159                             srcData += src->pitch;
00160                             dstData += dst->pitch;
00161                         }
00162                     }
00163                     break;
00164 
00165                     case 32: {
00166                         for( int y = height; y > 0; --y ) {
00167                             SDL_BlendRow_RGBA8_to_RGBA8( srcData, dstData, alpha, width );
00168                             srcData += src->pitch;
00169                             dstData += dst->pitch;
00170                         }
00171                     }
00172                     break;
00173 
00174                     default:
00175                         break;
00176                 }   
00177             }
00178             break;
00179 
00180             case 16: {
00181                 if( 0x000F == src->format->Amask ) {
00182                     if( ( 16 == dst->format->BitsPerPixel ) &&
00183                         ( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) ) {
00184                         for( int y = height; y > 0; --y ) {
00185                             SDL_BlendRow_RGBA4_to_RGB565( srcData, dstData, alpha, width );
00186                             srcData += src->pitch;
00187                             dstData += dst->pitch;
00188                         }
00189                     }
00190                 }
00191             }
00192             break;
00193 
00194             default:
00195                 break;
00196         }   
00197 
00198         SDL_UnlockSurface( dst );
00199     }
00200 
00201     void zoomSurface(SDL_Surface* src, SDL_Surface* dst) {
00202         SDL_Color* src_pointer = (SDL_Color*)src->pixels;
00203         SDL_Color* src_help_pointer = src_pointer;
00204         SDL_Color* dst_pointer = (SDL_Color*)dst->pixels;
00205 
00206         int x, y, *sx_ca, *sy_ca;
00207         int dst_gap = dst->pitch - dst->w * dst->format->BytesPerPixel;
00208         int sx = static_cast<int>(0xffff * src->w / dst->w);
00209         int sy = static_cast<int>(0xffff * src->h / dst->h);
00210         int sx_c = 0;
00211         int sy_c = 0;
00212 
00213         // Allocates memory and calculates row wide&height
00214         int* sx_a = (int*)malloc((dst->w + 1) * sizeof(Uint32));
00215         if (sx_a == NULL) {
00216             return;
00217         } else {
00218             sx_ca = sx_a;
00219             for (x = 0; x <= dst->w; x++) {
00220                 *sx_ca = sx_c;
00221                 sx_ca++;
00222                 sx_c &= 0xffff;
00223                 sx_c += sx;
00224             }
00225         }
00226         int* sy_a = (int*)malloc((dst->h + 1) * sizeof(Uint32));
00227         if (sy_a == NULL) {
00228             free(sx_a);
00229             return;
00230         } else {
00231             sy_ca = sy_a;
00232             for (y = 0; y <= dst->h; y++) {
00233                 *sy_ca = sy_c;
00234                 sy_ca++;
00235                 sy_c &= 0xffff;
00236                 sy_c += sy;
00237             }
00238             sy_ca = sy_a;
00239         }
00240 
00241         // Transfers the image data
00242 
00243         if(SDL_MUSTLOCK(src))
00244             SDL_LockSurface(src);
00245         if(SDL_MUSTLOCK(dst))
00246             SDL_LockSurface(dst);
00247 
00248         for (y = 0; y < dst->h; y++) {
00249             src_pointer = src_help_pointer;
00250             sx_ca = sx_a;
00251             for (x = 0; x < dst->w; x++) {
00252                 *dst_pointer = *src_pointer;
00253                 sx_ca++;
00254                 src_pointer += (*sx_ca >> 16);
00255                 dst_pointer++;
00256             }
00257             sy_ca++;
00258             src_help_pointer = (SDL_Color*)((Uint8*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
00259             dst_pointer = (SDL_Color*)((Uint8*)dst_pointer + dst_gap);
00260         }
00261 
00262         if(SDL_MUSTLOCK(dst))
00263             SDL_UnlockSurface(dst);
00264         if(SDL_MUSTLOCK(src))
00265             SDL_UnlockSurface(src);
00266 
00267         // Free memory
00268         free(sx_a);
00269         free(sy_a);
00270     }
00271 
00272     SDL_Surface* getZoomedSurface(SDL_Surface * src, double zoomx, double zoomy) {
00273         if (src == NULL)
00274             return NULL;
00275 
00276         SDL_Surface *zoom_src;
00277         SDL_Surface *zoom_dst;
00278         int dst_w = static_cast<int>(round(src->w * zoomx));
00279         int dst_h = static_cast<int>(round(src->h * zoomy));
00280         if (dst_w < 1)
00281             dst_w = 1;
00282         if (dst_h < 1)
00283             dst_h = 1;
00284 
00285         // If source surface has no alpha channel then convert it
00286         if (src->format->Amask == 0) {
00287             zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
00288                     RMASK, GMASK,
00289                     BMASK, AMASK);
00290             SDL_BlitSurface(src, NULL, zoom_src, NULL);
00291         } else {
00292             zoom_src = src;
00293         }
00294         // Create destination surface
00295         zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_w, dst_h, 32,
00296                 zoom_src->format->Rmask, zoom_src->format->Gmask,
00297                 zoom_src->format->Bmask, zoom_src->format->Amask);
00298 
00299         // Zoom surface
00300         zoomSurface(zoom_src, zoom_dst);
00301 
00302         return zoom_dst;
00303     }
00304 
00305     bool nearlyEqual(float a, float b) {
00306         return ABS(a - b) <= 0.00001;
00307     }
00308 
00309     void SDLImage::render(const Rect& rect, SDL_Surface* screen, unsigned char alpha) {
00310         if (alpha == 0) {
00311             return;
00312         }
00313 
00314         if (rect.right() < 0 || rect.x > static_cast<int>(screen->w) || rect.bottom() < 0 || rect.y > static_cast<int>(screen->h)) {
00315             return;
00316         }
00317         finalize();
00318 
00319         SDL_Surface* surface = screen;
00320         SDL_Rect r;
00321         r.x = rect.x;
00322         r.y = rect.y;
00323         r.w = rect.w;
00324         r.h = rect.h;
00325 
00326         float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
00327         float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
00328         bool zoomed = false;
00329         bool equal = false;
00330 
00331         if (!nearlyEqual(scale_x, 1.0) && !nearlyEqual(scale_y, 1.0)) {
00332             zoomed = true;
00333             if(nearlyEqual(m_scale_x, scale_x) && nearlyEqual(m_scale_y, scale_y)) {
00334                 equal = true;
00335             } else {
00336                 m_scale_x = scale_x;
00337                 m_scale_y = scale_y;
00338             }
00339         }
00340 
00341         if (m_surface->format->Amask == 0) {
00342             // Image has no alpha channel. This allows us to use the per-surface alpha.
00343             if (m_last_alpha != alpha) {
00344                 m_last_alpha = alpha;
00345                 SDL_SetAlpha(m_surface, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
00346             }
00347             if (!zoomed) {
00348                 SDL_BlitSurface(m_surface, 0, surface, &r);
00349             } else if (equal && m_zoom_surface) {
00350                 SDL_BlitSurface(m_zoom_surface, 0, surface, &r);
00351             } else {
00352                 SDL_FreeSurface(m_zoom_surface);
00353                 m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00354                 SDL_BlitSurface(m_zoom_surface, 0, surface, &r);
00355             }
00356         } else {
00357             if( 255 != alpha ) {
00358                 // Special blitting routine with alpha blending:
00359                 // dst.rgb = ( src.rgb * src.a * alpha ) + ( dst.rgb * (255 - ( src.a * alpha ) ) );
00360                 if (!zoomed) {
00361                     SDL_BlitSurfaceWithAlpha( m_surface, 0, surface, &r, alpha );
00362                 } else if (equal && m_zoom_surface) {
00363                     SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, surface, &r, alpha );
00364                 } else {
00365                     SDL_FreeSurface(m_zoom_surface);
00366                     m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00367                     SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, surface, &r, alpha );
00368                 }
00369             } else {
00370                 if (!zoomed) {
00371                     SDL_BlitSurface(m_surface, 0, surface, &r);
00372                 } else if (equal && m_zoom_surface) {
00373                     SDL_BlitSurface(m_zoom_surface, 0, surface, &r);
00374                 } else {
00375                     SDL_FreeSurface(m_zoom_surface);
00376                     m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
00377                     SDL_BlitSurface(m_zoom_surface, 0, surface, &r);
00378                 }
00379             }
00380         }
00381     }
00382 
00383     void SDLImage::finalize() {
00384         if( m_finalized ) {
00385             return;
00386         }
00387         m_finalized = true;
00388         SDL_Surface *old_surface = m_surface;
00389         Uint32 key = SDL_MapRGB(m_surface->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
00390 
00391         if (m_surface->format->Amask == 0) {
00392             // only use color key if feature is enabled
00393             if (RenderBackend::instance()->isColorKeyEnabled()) {
00394                 SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
00395             }
00396 
00397             m_surface = SDL_DisplayFormat(m_surface);
00398         } else {
00399             RenderBackendSDL* be = static_cast<RenderBackendSDL*>(RenderBackend::instance());
00400             m_isalphaoptimized = be->isAlphaOptimizerEnabled();
00401             if( m_isalphaoptimized ) {
00402                 m_surface = optimize(m_surface);
00403             } else  {
00404                 SDL_SetAlpha(m_surface, SDL_SRCALPHA, 255);
00405 
00406                 // only use color key if feature is enabled
00407                 if (RenderBackend::instance()->isColorKeyEnabled()) {
00408                     SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
00409                 }
00410 
00411                 m_surface = SDL_DisplayFormatAlpha(m_surface);
00412             }
00413         }
00414         SDL_FreeSurface(old_surface);
00415     }
00416 
00417     SDL_Surface* SDLImage::optimize(SDL_Surface* src) {
00418         // The algorithm is originally by "Tim Goya" <tuxdev103@gmail.com>
00419         // Few modifications and adaptions by the FIFE team.
00420         //
00421         // It tries to determine whether an image with a alpha channel
00422         // actually uses that. Often PNGs contains an alpha channels
00423         // as they don't provide a colorkey feature(?) - so to speed
00424         // up SDL rendering we try to remove the alpha channel.
00425 
00426         // As a reminder: src->format->Amask != 0 here
00427 
00428         int transparent = 0;
00429         int opaque = 0;
00430         int semitransparent = 0;
00431         int alphasum = 0;
00432         int alphasquaresum = 0;
00433         bool colors[(1 << 12)];
00434         memset(colors, 0, (1 << 12) * sizeof(bool));
00435 
00436         int bpp = src->format->BytesPerPixel;
00437         if(SDL_MUSTLOCK(src)) {
00438             SDL_LockSurface(src);
00439         }
00440         /*  In the first pass through we calculate avg(alpha), avg(alpha^2)
00441             and the number of semitransparent pixels.
00442             We also try to find a useable color.
00443         */
00444         for(int y = 0;y < src->h;y++) {
00445             for(int x = 0;x < src->w;x++) {
00446                 Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
00447                 Uint32 mapped = 0;
00448                 switch(bpp) {
00449                     case 1:
00450                         mapped = *pixel;
00451                         break;
00452                     case 2:
00453                         mapped = *(Uint16 *)pixel;
00454                         break;
00455                     case 3:
00456 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00457                         mapped |= pixel[0] << 16;
00458                         mapped |= pixel[1] << 8;
00459                         mapped |= pixel[2] << 0;
00460 #else
00461                         mapped |= pixel[0] << 0;
00462                         mapped |= pixel[1] << 8;
00463                         mapped |= pixel[2] << 16;
00464 #endif
00465                         break;
00466                     case 4:
00467                         mapped = *(Uint32 *)pixel;
00468                         break;
00469                 }
00470                 Uint8 red, green, blue, alpha;
00471                 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
00472                 if(alpha < 16) {
00473                     transparent++;
00474                 } else if (alpha > 240) {
00475                     opaque++;
00476                     alphasum += alpha;
00477                     alphasquaresum += alpha*alpha;
00478                 } else {
00479                     semitransparent++;
00480                     alphasum += alpha;
00481                     alphasquaresum += alpha*alpha;
00482                 }
00483                 // mark the color as used.
00484                 if( alpha != 0 ) {
00485                     colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
00486                 }
00487             }
00488         }
00489         int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
00490         int alphavariance = 0;
00491 
00492         if(SDL_MUSTLOCK(src)) {
00493             SDL_UnlockSurface(src);
00494         }
00495         alphasquaresum /= (opaque + semitransparent) ? (opaque + semitransparent) : 1;
00496         alphavariance = alphasquaresum - avgalpha*avgalpha;
00497         if(semitransparent > ((transparent + opaque + semitransparent) / 8)
00498            && alphavariance > 16) {
00499             FL_DBG(_log, LMsg("sdlimage")
00500                 << "Trying to alpha-optimize image. FAILED: real alpha usage. "
00501                 << " alphavariance=" << alphavariance
00502                 << " total=" << (transparent + opaque + semitransparent)
00503                 << " semitransparent=" << semitransparent
00504                 << "(" << (float(semitransparent)/(transparent + opaque + semitransparent))
00505                 << ")");
00506             return SDL_DisplayFormatAlpha(src);
00507         }
00508 
00509         // check availability of a suitable color as colorkey
00510         int keycolor = -1;
00511         for(int i = 0;i < (1 << 12);i++) {
00512             if(!colors[i]) {
00513                 keycolor = i;
00514                 break;
00515             }
00516         }
00517         if(keycolor == -1) {
00518             FL_DBG(_log, LMsg("sdlimage") << "Trying to alpha-optimize image. FAILED: no free color");
00519             return SDL_DisplayFormatAlpha(src);
00520         }
00521 
00522         SDL_Surface *dst = SDL_CreateRGBSurface(src->flags & ~(SDL_SRCALPHA) | SDL_SWSURFACE,
00523                                                 src->w, src->h,
00524                                                 src->format->BitsPerPixel,
00525                                                 src->format->Rmask,  src->format->Gmask,
00526                                                 src->format->Bmask, 0);
00527         bpp = dst->format->BytesPerPixel;
00528 
00529         Uint32 key = SDL_MapRGB(dst->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
00530 
00531         // if the global color key feature is disabled, then use the manually found color key
00532         if (!RenderBackend::instance()->isColorKeyEnabled()) {
00533             key = SDL_MapRGB(dst->format,
00534                             (((keycolor & 0xf00) >> 4) | 0xf),
00535                             ((keycolor & 0xf0) | 0xf),
00536                             (((keycolor & 0xf) << 4) | 0xf));
00537         }
00538 
00539         if(SDL_MUSTLOCK(src)) {
00540             SDL_LockSurface(src);
00541         }
00542         if(SDL_MUSTLOCK(dst)) {
00543             SDL_LockSurface(dst);
00544         }
00545         for(int y = 0;y < dst->h;y++) {
00546             for(int x = 0;x < dst->w;x++) {
00547                 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
00548                 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
00549                 Uint32 mapped = 0;
00550                 switch(bpp) {
00551                     case 1:
00552                         mapped = *srcpixel;
00553                         break;
00554                     case 2:
00555                         mapped = *(Uint16 *)srcpixel;
00556                         break;
00557                     case 3:
00558 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00559                         mapped |= srcpixel[0] << 16;
00560                         mapped |= srcpixel[1] << 8;
00561                         mapped |= srcpixel[2] << 0;
00562 #else
00563                         mapped |= srcpixel[0] << 0;
00564                         mapped |= srcpixel[1] << 8;
00565                         mapped |= srcpixel[2] << 16;
00566 #endif
00567                         break;
00568                     case 4:
00569                         mapped = *(Uint32 *)srcpixel;
00570                         break;
00571                 }
00572                 Uint8 red, green, blue, alpha;
00573                 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
00574                 if(alpha < (avgalpha / 4)) {
00575                     mapped = key;
00576                 } else {
00577                     mapped = SDL_MapRGB(dst->format, red, green, blue);
00578                 }
00579                 switch(bpp) {
00580                     case 1:
00581                         *dstpixel = mapped;
00582                         break;
00583                     case 2:
00584                         *(Uint16 *)dstpixel = mapped;
00585                         break;
00586                     case 3:
00587 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00588                         dstpixel[0] = (mapped >> 16) & 0xff;
00589                         dstpixel[1] = (mapped >> 8) & 0xff;
00590                         dstpixel[2] = (mapped >> 0) & 0xff;
00591 #else
00592                         dstpixel[0] = (mapped >> 0) & 0xff;
00593                         dstpixel[1] = (mapped >> 8) & 0xff;
00594                         dstpixel[2] = (mapped >> 16) & 0xff;
00595 #endif
00596                         break;
00597                     case 4:
00598                         *(Uint32 *)dstpixel = mapped;
00599                         break;
00600                 }
00601             }
00602         }
00603         if(SDL_MUSTLOCK(dst)) {
00604             SDL_UnlockSurface(dst);
00605         }
00606         if(SDL_MUSTLOCK(src)) {
00607             SDL_UnlockSurface(src);
00608         }
00609         // Using the per surface alpha value does not
00610         // work out for mostly transparent pixels.
00611         // Thus disabling the part here - this needs a
00612         // more complex refactoring.
00613         // if(avgalpha < 240) {
00614         //  SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
00615         //}
00616         SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
00617         SDL_Surface *convert = SDL_DisplayFormat(dst);
00618         SDL_FreeSurface(dst);
00619         FL_DBG(_log, LMsg("sdlimage ")
00620             << "Trying to alpha-optimize image. SUCCESS: colorkey is " << key);
00621         return convert;
00622     } // end optimize
00623 
00624     bool SDLImage::putPixel(int x, int y, int r, int g, int b, int a) {
00625         if ((x < 0) || (x >= m_surface->w) || (y < 0) || (y >= m_surface->h)) {
00626             return false;
00627         }
00628 
00629         int bpp = m_surface->format->BytesPerPixel;
00630         SDL_LockSurface(m_surface);
00631         Uint8* p = (Uint8*)m_surface->pixels + y * m_surface->pitch + x * bpp;
00632         Uint32 pixel = SDL_MapRGB(m_surface->format, r, g, b);
00633         switch(bpp)
00634         {
00635             case 1:
00636                 *p = pixel;
00637                 break;
00638 
00639             case 2:
00640                 *(Uint16 *)p = pixel;
00641                 break;
00642 
00643             case 3:
00644                 if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
00645                     p[0] = (pixel >> 16) & 0xff;
00646                     p[1] = (pixel >> 8) & 0xff;
00647                     p[2] = pixel & 0xff;
00648                 }
00649                 else {
00650                     p[0] = pixel & 0xff;
00651                     p[1] = (pixel >> 8) & 0xff;
00652                     p[2] = (pixel >> 16) & 0xff;
00653                 }
00654                 break;
00655 
00656             case 4:
00657                 *(Uint32 *)p = pixel;
00658                 break;
00659         }
00660         SDL_UnlockSurface(m_surface);
00661         return true;
00662     }
00663 
00664     void SDLImage::drawLine(const Point& p1, const Point& p2, int r, int g, int b, int a) {
00665         // Draw a line with Bresenham, imitated from guichan
00666         int x1 = p1.x;
00667         int x2 = p2.x;
00668         int y1 = p1.y;
00669         int y2 = p2.y;
00670         int dx = ABS(x2 - x1);
00671         int dy = ABS(y2 - y1);
00672 
00673         if (dx > dy) {
00674             if (x1 > x2) {
00675                 // swap x1, x2
00676                 x1 ^= x2;
00677                 x2 ^= x1;
00678                 x1 ^= x2;
00679 
00680                 // swap y1, y2
00681                 y1 ^= y2;
00682                 y2 ^= y1;
00683                 y1 ^= y2;
00684             }
00685 
00686             if (y1 < y2) {
00687                 int y = y1;
00688                 int p = 0;
00689 
00690                 for (int x = x1; x <= x2; x++) {
00691                     putPixel(x, y, r, g, b, a);
00692                     p += dy;
00693                     if (p * 2 >= dx) {
00694                         y++;
00695                         p -= dx;
00696                     }
00697                 }
00698             }
00699             else {
00700                 int y = y1;
00701                 int p = 0;
00702 
00703                 for (int x = x1; x <= x2; x++) {
00704                     putPixel(x, y, r, g, b, a);
00705 
00706                     p += dy;
00707                     if (p * 2 >= dx) {
00708                         y--;
00709                         p -= dx;
00710                     }
00711                 }
00712             }
00713         }
00714         else {
00715             if (y1 > y2) {
00716                 // swap y1, y2
00717                 y1 ^= y2;
00718                 y2 ^= y1;
00719                 y1 ^= y2;
00720 
00721                 // swap x1, x2
00722                 x1 ^= x2;
00723                 x2 ^= x1;
00724                 x1 ^= x2;
00725             }
00726 
00727             if (x1 < x2) {
00728                 int x = x1;
00729                 int p = 0;
00730 
00731                 for (int y = y1; y <= y2; y++) {
00732                     putPixel(x, y, r, g, b, a);
00733                     p += dx;
00734                     if (p * 2 >= dy) {
00735                         x++;
00736                         p -= dy;
00737                     }
00738                 }
00739             }
00740             else {
00741                 int x = x1;
00742                 int p = 0;
00743 
00744                 for (int y = y1; y <= y2; y++) {
00745                     putPixel(x, y, r, g, b, a);
00746                     p += dx;
00747                     if (p * 2 >= dy) {
00748                         x--;
00749                         p -= dy;
00750                     }
00751                 }
00752             }
00753         }
00754     }
00755 
00756     void SDLImage::drawTriangle(const Point& p1, const Point& p2, const Point& p3, int r, int g, int b, int a) {
00757         drawLine(p1, p2, r, g, b, a);
00758         drawLine(p2, p3, r, g, b, a);
00759         drawLine(p3, p1, r, g, b, a);
00760     }
00761 
00762     void SDLImage::drawRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00763         Point p1, p2, p3, p4;
00764 
00765         p1.x = p.x;
00766         p1.y = p.y;
00767         p2.x = p.x+w;
00768         p2.y = p.y;
00769         p3.x = p.x+w;
00770         p3.y = p.y+h;
00771         p4.x = p.x;
00772         p4.y = p.y+h;
00773 
00774         drawLine(p1, p2, r, g, b, a);
00775         drawLine(p2, p3, r, g, b, a);
00776         drawLine(p3, p4, r, g, b, a);
00777         drawLine(p4, p1, r, g, b, a);
00778     }
00779 
00780     void SDLImage::fillRectangle(const Point& p, uint16_t w, uint16_t h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
00781         SDL_Rect rect;
00782         rect.x = p.x;
00783         rect.y = p.y;
00784         rect.w = w;
00785         rect.h = h;
00786 
00787         Uint32 color = SDL_MapRGBA(m_surface->format, r, g, b, a);
00788         SDL_FillRect(m_surface, &rect, color);
00789     }
00790 
00791     void SDLImage::drawQuad(const Point& p1, const Point& p2, const Point& p3, const Point& p4, int r, int g, int b, int a) {
00792         drawLine(p1, p2, r, g, b, a);
00793         drawLine(p2, p3, r, g, b, a);
00794         drawLine(p3, p4, r, g, b, a);
00795         drawLine(p4, p1, r, g, b, a);
00796     }
00797 
00798     void SDLImage::drawVertex(const Point& p, const uint8_t size, int r, int g, int b, int a){
00799         Point p1 = Point(p.x-size, p.y+size);
00800         Point p2 = Point(p.x+size, p.y+size);
00801         Point p3 = Point(p.x+size, p.y-size);
00802         Point p4 = Point(p.x-size, p.y-size);
00803 
00804         drawLine(p1, p2, r, g, b, a);
00805         drawLine(p2, p3, r, g, b, a);
00806         drawLine(p3, p4, r, g, b, a);
00807         drawLine(p4, p1, r, g, b, a);
00808     }
00809 
00810     void SDLImage::drawLightPrimitive(const Point& p, uint8_t intensity, float radius, int subdivisions, float xstretch, float ystretch, uint8_t red, uint8_t green, uint8_t blue) {
00811     }
00812 
00813     void SDLImage::saveImage(const std::string& filename) {
00814         if(m_surface) {
00815             const unsigned int swidth = getWidth();
00816             const unsigned int sheight = getHeight();
00817             SDL_Surface *surface = NULL;
00818 
00819             surface = SDL_CreateRGBSurface(SDL_SWSURFACE, swidth,
00820                 sheight, 24,
00821                 RMASK, GMASK, BMASK, 0);
00822 
00823             if(surface == NULL) {
00824                 return;
00825             }
00826 
00827             SDL_BlitSurface(m_surface, NULL, surface, NULL);
00828 
00829             saveAsPng(filename, *surface);
00830             SDL_FreeSurface(surface);
00831         }
00832     }
00833 
00834     void SDLImage::setClipArea(const Rect& cliparea, bool clear) {
00835         SDL_Rect rect;
00836         rect.x = cliparea.x;
00837         rect.y = cliparea.y;
00838         rect.w = cliparea.w;
00839         rect.h = cliparea.h;
00840         SDL_SetClipRect(m_surface, &rect);
00841         if (clear) {
00842             SDL_FillRect(m_surface, &rect, 0x00);
00843         }
00844     }
00845 }
 All Classes Namespaces Functions Variables Enumerations Enumerator