FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
sdlimage.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2011 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <cassert>
24 #include <iostream>
25 
26 // 3rd party library includes
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 #include "util/log/logger.h"
33 #include "util/structures/rect.h"
34 #include "video/imagemanager.h"
35 #include "video/renderbackend.h"
36 
37 #include "renderbackendsdl.h"
38 #include "sdlblendingfunctions.h"
39 #include "sdlimage.h"
40 
41 namespace FIFE {
42  static Logger _log(LM_VIDEO);
43 
44  SDLImage::SDLImage(IResourceLoader* loader):
45  Image(loader) {
46  resetSdlimage();
47  }
48 
49  SDLImage::SDLImage(const std::string& name, IResourceLoader* loader):
50  Image(name, loader) {
51  resetSdlimage();
52  }
53 
54  SDLImage::SDLImage(SDL_Surface* surface):
55  Image(surface) {
56  resetSdlimage();
57  }
58 
59  SDLImage::SDLImage(const std::string& name, SDL_Surface* surface):
60  Image(name, surface) {
61  resetSdlimage();
62  }
63 
64  SDLImage::SDLImage(const uint8_t* data, uint32_t width, uint32_t height):
65  Image(data, width, height) {
66  resetSdlimage();
67  }
68 
69  SDLImage::SDLImage(const std::string& name, const uint8_t* data, uint32_t width, uint32_t height):
70  Image(name, data, width, height) {
71  resetSdlimage();
72  }
73 
74  void SDLImage::resetSdlimage() {
75  m_last_alpha = 255;
76  m_finalized = false;
77  m_colorkey = RenderBackend::instance()->getColorKey();
78  m_scale_x = 1.0;
79  m_scale_y = 1.0;
80  m_zoom_surface = NULL;
81  }
82 
83  SDLImage::~SDLImage() {
84  if (m_zoom_surface) {
85  SDL_FreeSurface(m_zoom_surface);
86  }
87  }
88 
89  void SDLImage::setSurface(SDL_Surface* surface) {
90  if (m_zoom_surface) {
91  SDL_FreeSurface(m_zoom_surface);
92  m_zoom_surface = NULL;
93  }
94  reset(surface);
95  resetSdlimage();
96  }
97 
98  void SDL_BlitSurfaceWithAlpha( const SDL_Surface* src, const SDL_Rect* srcRect,
99  SDL_Surface* dst, SDL_Rect* dstRect, uint8_t alpha ) {
100  if( 0 == alpha ) {
101  return;
102  }
103 
104  int32_t screenX, screenY;
105  if( dstRect ) {
106  screenX = dstRect->x;
107  screenY = dstRect->y;
108  } else {
109  screenX = dst->clip_rect.x;
110  screenY = dst->clip_rect.y;
111  }
112 
113  int32_t width, height, tX, tY;
114  if( srcRect ) {
115  tX = srcRect->x;
116  tY = srcRect->y;
117  width = srcRect->w;
118  height = srcRect->h;
119  } else {
120  tX = src->clip_rect.x;
121  tY = src->clip_rect.y;
122  width = src->clip_rect.w;
123  height = src->clip_rect.h;
124  }
125 
126  // Clipping.
127  if( ( screenX >= ( dst->clip_rect.x + dst->clip_rect.w ) ) ||
128  ( screenY >= ( dst->clip_rect.y + dst->clip_rect.h ) ) ||
129  ( ( screenX + width ) <= dst->clip_rect.x ) ||
130  ( ( screenY + height ) <= dst->clip_rect.y ) ) {
131  return;
132  }
133 
134  if( screenX < dst->clip_rect.x ) {
135  int32_t dX = dst->clip_rect.x - screenX;
136  screenX += dX;
137  width -= dX;
138  tX += dX;
139  }
140 
141  if( ( screenX + width ) > ( dst->clip_rect.x + dst->clip_rect.w ) ) {
142  int32_t dX = ( screenX + width ) - ( dst->clip_rect.x + dst->clip_rect.w );
143  width -= dX;
144  }
145 
146  if( screenY < dst->clip_rect.y ) {
147  int32_t dY = dst->clip_rect.y - screenY;
148  screenY += dY;
149  height -= dY;
150  tY += dY;
151  }
152 
153  if( ( screenY + height ) > ( dst->clip_rect.y + dst->clip_rect.h ) ) {
154  int32_t dY = ( screenY + height ) - ( dst->clip_rect.y + dst->clip_rect.h );
155  height -= dY;
156  }
157 
158  if( ( 0 >= height ) || ( 0 >= width ) ) {
159  return;
160  }
161 
162  SDL_LockSurface( dst );
163 
164  uint8_t* srcData = reinterpret_cast< uint8_t* > ( src->pixels );
165  uint8_t* dstData = reinterpret_cast< uint8_t* > ( dst->pixels );
166 
167  // move data pointers to the start of the pixels we're copying
168  srcData += tY * src->pitch + tX * src->format->BytesPerPixel;
169  dstData += screenY * dst->pitch + screenX * dst->format->BytesPerPixel;
170 
171  switch( src->format->BitsPerPixel ) {
172  case 32: {
173  switch( dst->format->BitsPerPixel ) {
174  case 16: {
175  if( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) {
176  for( int32_t y = height; y > 0; --y ) {
177  SDL_BlendRow_RGBA8_to_RGB565( srcData, dstData, alpha, width );
178  srcData += src->pitch;
179  dstData += dst->pitch;
180  }
181  }
182  }
183  break;
184 
185  case 24: {
186  for( int32_t y = height; y > 0; --y ) {
187  SDL_BlendRow_RGBA8_to_RGB8( srcData, dstData, alpha, width );
188  srcData += src->pitch;
189  dstData += dst->pitch;
190  }
191  }
192  break;
193 
194  case 32: {
195  for( int32_t y = height; y > 0; --y ) {
196  SDL_BlendRow_RGBA8_to_RGBA8( srcData, dstData, alpha, width );
197  srcData += src->pitch;
198  dstData += dst->pitch;
199  }
200  }
201  break;
202 
203  default:
204  break;
205  }
206  }
207  break;
208 
209  case 16: {
210  if( 0x000F == src->format->Amask ) {
211  if( ( 16 == dst->format->BitsPerPixel ) &&
212  ( 0xFFFF == ( dst->format->Rmask | dst->format->Gmask | dst->format->Bmask ) ) ) {
213  for( int32_t y = height; y > 0; --y ) {
214  SDL_BlendRow_RGBA4_to_RGB565( srcData, dstData, alpha, width );
215  srcData += src->pitch;
216  dstData += dst->pitch;
217  }
218  }
219  }
220  }
221  break;
222 
223  default:
224  break;
225  }
226 
227  SDL_UnlockSurface( dst );
228  }
229 
230  void zoomSurface(SDL_Surface* src, SDL_Surface* dst) {
231  uint32_t* src_pointer = static_cast<uint32_t*>(src->pixels);
232  uint32_t* src_help_pointer = src_pointer;
233  uint32_t* dst_pointer = static_cast<uint32_t*>(dst->pixels);
234 
235  int32_t x, y, *sx_ca, *sy_ca;
236  int32_t sx = static_cast<int32_t>(0xffff * src->w / dst->w);
237  int32_t sy = static_cast<int32_t>(0xffff * src->h / dst->h);
238  int32_t sx_c = 0;
239  int32_t sy_c = 0;
240 
241  // Allocates memory and calculates row wide&height
242  int32_t* sx_a = new int32_t[dst->w + 1];
243  sx_ca = sx_a;
244  for (x = 0; x <= dst->w; x++) {
245  *sx_ca = sx_c;
246  sx_ca++;
247  sx_c &= 0xffff;
248  sx_c += sx;
249  }
250 
251  int32_t* sy_a = new int32_t[dst->h + 1];
252  sy_ca = sy_a;
253  for (y = 0; y <= dst->h; y++) {
254  *sy_ca = sy_c;
255  sy_ca++;
256  sy_c &= 0xffff;
257  sy_c += sy;
258  }
259  sy_ca = sy_a;
260 
261  // Transfers the image data
262 
263  if (SDL_MUSTLOCK(src)) {
264  SDL_LockSurface(src);
265  }
266  if (SDL_MUSTLOCK(dst)) {
267  SDL_LockSurface(dst);
268  }
269 
270  for (y = 0; y < dst->h; y++) {
271  src_pointer = src_help_pointer;
272  sx_ca = sx_a;
273  for (x = 0; x < dst->w; x++) {
274  *dst_pointer = *src_pointer;
275  sx_ca++;
276  src_pointer += (*sx_ca >> 16);
277  dst_pointer++;
278  }
279  sy_ca++;
280  src_help_pointer = (uint32_t*)((uint8_t*)src_help_pointer + (*sy_ca >> 16) * src->pitch);
281  }
282 
283  if (SDL_MUSTLOCK(dst)) {
284  SDL_UnlockSurface(dst);
285  }
286  if (SDL_MUSTLOCK(src)) {
287  SDL_UnlockSurface(src);
288  }
289 
290  // Free memory
291  delete [] sx_a;
292  delete [] sy_a;
293  }
294 
295  SDL_Surface* getZoomedSurface(SDL_Surface * src, double zoomx, double zoomy) {
296  if (src == NULL)
297  return NULL;
298 
299  SDL_Surface *zoom_src;
300  SDL_Surface *zoom_dst;
301  int32_t dst_w = static_cast<int32_t>(round(src->w * zoomx));
302  int32_t dst_h = static_cast<int32_t>(round(src->h * zoomy));
303  if (dst_w < 1)
304  dst_w = 1;
305  if (dst_h < 1)
306  dst_h = 1;
307 
308  // If source surface has no alpha channel then convert it
309  if (src->format->Amask == 0) {
310  zoom_src = SDL_CreateRGBSurface(SDL_SWSURFACE, src->w, src->h, 32,
311  RMASK, GMASK,
312  BMASK, AMASK);
313  SDL_BlitSurface(src, NULL, zoom_src, NULL);
314  } else {
315  zoom_src = src;
316  }
317  // Create destination surface
318  zoom_dst = SDL_CreateRGBSurface(SDL_SWSURFACE, dst_w, dst_h, 32,
319  zoom_src->format->Rmask, zoom_src->format->Gmask,
320  zoom_src->format->Bmask, zoom_src->format->Amask);
321 
322  // Zoom surface
323  zoomSurface(zoom_src, zoom_dst);
324 
325  return zoom_dst;
326  }
327 
328  bool nearlyEqual(float a, float b) {
329  return ABS(a - b) <= 0.00001;
330  }
331 
332  void SDLImage::render(const Rect& rect, uint8_t alpha, uint8_t const* /*unused rgb*/) {
333  if (alpha == 0) {
334  return;
335  }
336  validateShared();
337  SDL_Surface* target = RenderBackend::instance()->getRenderTargetSurface();
338  assert(target != m_surface); // can't draw on the source surface
339 
340  if (rect.right() < 0 || rect.x > static_cast<int32_t>(target->w) ||
341  rect.bottom() < 0 || rect.y > static_cast<int32_t>(target->h)) {
342  return;
343  }
344  finalize();
345 
346  SDL_Rect r;
347  r.x = rect.x;
348  r.y = rect.y;
349  r.w = rect.w;
350  r.h = rect.h;
351 
352  float scale_x = static_cast<float>(rect.w) / static_cast<float>(m_surface->w);
353  float scale_y = static_cast<float>(rect.h) / static_cast<float>(m_surface->h);
354  bool zoomed = false;
355  bool equal = false;
356 
357  if (!nearlyEqual(scale_x, 1.0) && !nearlyEqual(scale_y, 1.0)) {
358  zoomed = true;
359  if(nearlyEqual(m_scale_x, scale_x) && nearlyEqual(m_scale_y, scale_y)) {
360  equal = true;
361  } else {
362  m_scale_x = scale_x;
363  m_scale_y = scale_y;
364  }
365  }
366 
367  if (m_surface->format->Amask == 0) {
368  // Image has no alpha channel. This allows us to use the per-surface alpha.
369  if (m_last_alpha != alpha) {
370  m_last_alpha = alpha;
371  SDL_SetAlpha(m_surface, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
372  }
373  if (!zoomed) {
374  SDL_BlitSurface(m_surface, 0, target, &r);
375  } else if (equal && m_zoom_surface) {
376  SDL_BlitSurface(m_zoom_surface, 0, target, &r);
377  } else {
378  SDL_FreeSurface(m_zoom_surface);
379  m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
380  SDL_BlitSurface(m_zoom_surface, 0, target, &r);
381  }
382  } else {
383  if( 255 != alpha ) {
384  // Special blitting routine with alpha blending:
385  // dst.rgb = ( src.rgb * src.a * alpha ) + ( dst.rgb * (255 - ( src.a * alpha ) ) );
386  if (!zoomed) {
387  SDL_BlitSurfaceWithAlpha( m_surface, 0, target, &r, alpha );
388  } else if (equal && m_zoom_surface) {
389  SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, target, &r, alpha );
390  } else {
391  SDL_FreeSurface(m_zoom_surface);
392  m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
393  SDL_BlitSurfaceWithAlpha(m_zoom_surface, 0, target, &r, alpha );
394  }
395  } else {
396  if (!zoomed) {
397  SDL_BlitSurface(m_surface, 0, target, &r);
398  } else if (equal && m_zoom_surface) {
399  SDL_BlitSurface(m_zoom_surface, 0, target, &r);
400  } else {
401  SDL_FreeSurface(m_zoom_surface);
402  m_zoom_surface = getZoomedSurface(m_surface, m_scale_x, m_scale_y);
403  SDL_BlitSurface(m_zoom_surface, 0, target, &r);
404  }
405  }
406  }
407  }
408 
409  void SDLImage::finalize() {
410  if( m_finalized ) {
411  return;
412  }
413  m_finalized = true;
414  SDL_Surface *old_surface = m_surface;
415  Uint32 key = SDL_MapRGB(m_surface->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
416 
417  if (m_surface->format->Amask == 0) {
418  // only use color key if feature is enabled
419  if (RenderBackend::instance()->isColorKeyEnabled()) {
420  SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
421  }
422 
423  m_surface = SDL_DisplayFormat(m_surface);
424  } else {
425  RenderBackendSDL* be = static_cast<RenderBackendSDL*>(RenderBackend::instance());
426  bool m_isalphaoptimized = be->isAlphaOptimizerEnabled();
427  if( m_isalphaoptimized ) {
428  m_surface = optimize(m_surface);
429  } else {
430  SDL_SetAlpha(m_surface, SDL_SRCALPHA, 255);
431 
432  // only use color key if feature is enabled
433  if (RenderBackend::instance()->isColorKeyEnabled()) {
434  SDL_SetColorKey(m_surface, SDL_SRCCOLORKEY, key);
435  }
436 
437  m_surface = SDL_DisplayFormatAlpha(m_surface);
438  }
439  }
440  SDL_FreeSurface(old_surface);
441  }
442 
443  SDL_Surface* SDLImage::optimize(SDL_Surface* src) {
444  // The algorithm is originally by "Tim Goya" <tuxdev103@gmail.com>
445  // Few modifications and adaptions by the FIFE team.
446  //
447  // It tries to determine whether an image with a alpha channel
448  // actually uses that. Often PNGs contains an alpha channels
449  // as they don't provide a colorkey feature(?) - so to speed
450  // up SDL rendering we try to remove the alpha channel.
451 
452  // As a reminder: src->format->Amask != 0 here
453 
454  int32_t transparent = 0;
455  int32_t opaque = 0;
456  int32_t semitransparent = 0;
457  int32_t alphasum = 0;
458  int32_t alphasquaresum = 0;
459  bool colors[(1 << 12)];
460  memset(colors, 0, (1 << 12) * sizeof(bool));
461 
462  int32_t bpp = src->format->BytesPerPixel;
463  if(SDL_MUSTLOCK(src)) {
464  SDL_LockSurface(src);
465  }
466  /* In the first pass through we calculate avg(alpha), avg(alpha^2)
467  and the number of semitransparent pixels.
468  We also try to find a useable color.
469  */
470  for(int32_t y = 0;y < src->h;y++) {
471  for(int32_t x = 0;x < src->w;x++) {
472  Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
473  Uint32 mapped = 0;
474  switch(bpp) {
475  case 1:
476  mapped = *pixel;
477  break;
478  case 2:
479  mapped = *(Uint16 *)pixel;
480  break;
481  case 3:
482 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
483  mapped |= pixel[0] << 16;
484  mapped |= pixel[1] << 8;
485  mapped |= pixel[2] << 0;
486 #else
487  mapped |= pixel[0] << 0;
488  mapped |= pixel[1] << 8;
489  mapped |= pixel[2] << 16;
490 #endif
491  break;
492  case 4:
493  mapped = *(Uint32 *)pixel;
494  break;
495  }
496  Uint8 red, green, blue, alpha;
497  SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
498  if(alpha < 16) {
499  transparent++;
500  } else if (alpha > 240) {
501  opaque++;
502  alphasum += alpha;
503  alphasquaresum += alpha*alpha;
504  } else {
505  semitransparent++;
506  alphasum += alpha;
507  alphasquaresum += alpha*alpha;
508  }
509  // mark the color as used.
510  if( alpha != 0 ) {
511  colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
512  }
513  }
514  }
515  int32_t avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
516  int32_t alphavariance = 0;
517 
518  if(SDL_MUSTLOCK(src)) {
519  SDL_UnlockSurface(src);
520  }
521  alphasquaresum /= (opaque + semitransparent) ? (opaque + semitransparent) : 1;
522  alphavariance = alphasquaresum - avgalpha*avgalpha;
523  if(semitransparent > ((transparent + opaque + semitransparent) / 8)
524  && alphavariance > 16) {
525  FL_DBG(_log, LMsg("sdlimage")
526  << "Trying to alpha-optimize image. FAILED: real alpha usage. "
527  << " alphavariance=" << alphavariance
528  << " total=" << (transparent + opaque + semitransparent)
529  << " semitransparent=" << semitransparent
530  << "(" << (float(semitransparent)/(transparent + opaque + semitransparent))
531  << ")");
532  return SDL_DisplayFormatAlpha(src);
533  }
534 
535  // check availability of a suitable color as colorkey
536  int32_t keycolor = -1;
537  for(int32_t i = 0;i < (1 << 12);i++) {
538  if(!colors[i]) {
539  keycolor = i;
540  break;
541  }
542  }
543  if(keycolor == -1) {
544  FL_DBG(_log, LMsg("sdlimage") << "Trying to alpha-optimize image. FAILED: no free color");
545  return SDL_DisplayFormatAlpha(src);
546  }
547 
548  SDL_Surface *dst = SDL_CreateRGBSurface(src->flags & ~(SDL_SRCALPHA) | SDL_SWSURFACE,
549  src->w, src->h,
550  src->format->BitsPerPixel,
551  src->format->Rmask, src->format->Gmask,
552  src->format->Bmask, 0);
553  bpp = dst->format->BytesPerPixel;
554 
555  Uint32 key = SDL_MapRGB(dst->format, m_colorkey.r, m_colorkey.g, m_colorkey.b);
556 
557  // if the global color key feature is disabled, then use the manually found color key
558  if (!RenderBackend::instance()->isColorKeyEnabled()) {
559  key = SDL_MapRGB(dst->format,
560  (((keycolor & 0xf00) >> 4) | 0xf),
561  ((keycolor & 0xf0) | 0xf),
562  (((keycolor & 0xf) << 4) | 0xf));
563  }
564 
565  if(SDL_MUSTLOCK(src)) {
566  SDL_LockSurface(src);
567  }
568  if(SDL_MUSTLOCK(dst)) {
569  SDL_LockSurface(dst);
570  }
571  for(int32_t y = 0;y < dst->h;y++) {
572  for(int32_t x = 0;x < dst->w;x++) {
573  Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
574  Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
575  Uint32 mapped = 0;
576  switch(bpp) {
577  case 1:
578  mapped = *srcpixel;
579  break;
580  case 2:
581  mapped = *(Uint16 *)srcpixel;
582  break;
583  case 3:
584 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
585  mapped |= srcpixel[0] << 16;
586  mapped |= srcpixel[1] << 8;
587  mapped |= srcpixel[2] << 0;
588 #else
589  mapped |= srcpixel[0] << 0;
590  mapped |= srcpixel[1] << 8;
591  mapped |= srcpixel[2] << 16;
592 #endif
593  break;
594  case 4:
595  mapped = *(Uint32 *)srcpixel;
596  break;
597  }
598  Uint8 red, green, blue, alpha;
599  SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
600  if(alpha < (avgalpha / 4)) {
601  mapped = key;
602  } else {
603  mapped = SDL_MapRGB(dst->format, red, green, blue);
604  }
605  switch(bpp) {
606  case 1:
607  *dstpixel = mapped;
608  break;
609  case 2:
610  *(Uint16 *)dstpixel = mapped;
611  break;
612  case 3:
613 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
614  dstpixel[0] = (mapped >> 16) & 0xff;
615  dstpixel[1] = (mapped >> 8) & 0xff;
616  dstpixel[2] = (mapped >> 0) & 0xff;
617 #else
618  dstpixel[0] = (mapped >> 0) & 0xff;
619  dstpixel[1] = (mapped >> 8) & 0xff;
620  dstpixel[2] = (mapped >> 16) & 0xff;
621 #endif
622  break;
623  case 4:
624  *(Uint32 *)dstpixel = mapped;
625  break;
626  }
627  }
628  }
629  if(SDL_MUSTLOCK(dst)) {
630  SDL_UnlockSurface(dst);
631  }
632  if(SDL_MUSTLOCK(src)) {
633  SDL_UnlockSurface(src);
634  }
635  // Using the per surface alpha value does not
636  // work out for mostly transparent pixels.
637  // Thus disabling the part here - this needs a
638  // more complex refactoring.
639  // if(avgalpha < 240) {
640  // SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
641  //}
642  SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
643  SDL_Surface *convert = SDL_DisplayFormat(dst);
644  SDL_FreeSurface(dst);
645  FL_DBG(_log, LMsg("sdlimage ")
646  << "Trying to alpha-optimize image. SUCCESS: colorkey is " << key);
647  return convert;
648  } // end optimize
649 
650  size_t SDLImage::getSize() {
651  size_t zoomSize = 0;
652  if (m_zoom_surface) {
653  zoomSize = m_zoom_surface->h * m_zoom_surface->pitch;
654  }
655  if (m_surface) {
656  zoomSize += m_surface->h * m_surface->pitch;
657  }
658 
659  return zoomSize;
660  }
661 
662  void SDLImage::useSharedImage(const ImagePtr& shared, const Rect& region) {
663  if(shared->getState() != IResource::RES_LOADED) {
664  shared->load();
665  }
666  SDL_Surface* src_surface = shared->getSurface();
667  SDL_Surface* surface = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, region.w, region.h,
668  src_surface->format->BitsPerPixel, src_surface->format->Rmask, src_surface->format->Gmask,
669  src_surface->format->Bmask, src_surface->format->Amask);
670 
671  SDL_SetAlpha(src_surface, 0, 0);
672  SDL_Rect srcrect = { region.x, region.y, region.w, region.h };
673  SDL_BlitSurface(src_surface, &srcrect, surface, NULL);
674  SDL_SetAlpha(src_surface, SDL_SRCALPHA, 0);
675 
676  setSurface(surface);
677  m_shared = false; // this isn't a mistake
678  m_subimagerect = region;
679  m_atlas_img = shared;
680  m_atlas_name = shared->getName();
681  setState(IResource::RES_LOADED);
682  }
683 
684  void SDLImage::forceLoadInternal() {
685  validateShared();
686  }
687 
688  void SDLImage::validateShared() {
689  if (m_atlas_name.empty()) {
690  return;
691  }
692 
693  if (m_atlas_img->getState() == IResource::RES_NOT_LOADED ||
694  getState() == IResource::RES_NOT_LOADED) {
695  load();
696  }
697  }
698 
699  void SDLImage::load() {
700  if (!m_atlas_name.empty()) {
701  // check atlas image
702  // if it does not exist, it is created.
703  if (!ImageManager::instance()->exists(m_atlas_name)) {
704  ImagePtr newAtlas = ImageManager::instance()->create(m_atlas_name);
705  m_atlas_img = newAtlas;
706  }
707  useSharedImage(m_atlas_img , m_subimagerect);
708  } else {
709  Image::load();
710  }
711  }
712 
713  void SDLImage::free() {
714  setSurface(NULL);
715  m_state = IResource::RES_NOT_LOADED;
716  }
717 }