FIFE
2008.0
|
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 }