1 // Copyright Timothy Goya 2007.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 #include <unison/video/sdl/Blitters.hpp>
7 #include <unison/video/Surface.hpp>
15 unsigned char add_saturate(unsigned char lhs, int rhs)
36 /*SDL_Surface *Blitters::optimize(const Surface &src)
38 bool colors[(1 << 12)];
39 memset(colors, 0, (1 << 12) * sizeof(bool));
42 Color *iter = dst.get_pixels();
43 for(unsigned int y = 0;y < dst.get_size().y;y++)
45 for(unsigned int x = 0;x < dst.get_size().x;x++, iter++)
47 unsigned char oldalpha = iter->alpha;
48 unsigned char newalpha = oldalpha & 0x80 ? 0xff : 0x00;
49 iter->alpha = newalpha;
50 int error = oldalpha - newalpha;
51 if(x != dst.get_size().x - 1)
53 (iter + 1)->alpha = add_saturate((iter + 1)->alpha, error * 7 / 16);
55 if(y != dst.get_size().y - 1)
59 (iter + dst.get_size().x - 1)->alpha = add_saturate((iter + dst.get_size().x - 1)->alpha, error * 3 / 16);
61 (iter + dst.get_size().x)->alpha = add_saturate((iter + dst.get_size().x)->alpha, error * 5 / 16);
62 if(x != dst.get_size().x - 1)
64 (iter + dst.get_size().x + 1)->alpha = add_saturate((iter + dst.get_size().x + 1)->alpha, error * 1 / 16);
69 colors[((iter->red & 0xf0) << 4) | (iter->green & 0xf0) | ((iter->blue & 0xf0) >> 4)] = true;
75 for(int i = 0;i < (1 << 12);i++)
85 SDL_Surface *converted = create_sdl_surface_from(src);
86 SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
87 SDL_FreeSurface(converted);
91 Color key(((keycolor & 0xf00) >> 4) | 0xf, (keycolor & 0x0f0) | 0xf, ((keycolor & 0x00f) << 4) | 0xf);
93 Color *end = dst.get_pixels() + dst.get_size().x * dst.get_size().y;
94 for(iter = dst.get_pixels();iter != end;++iter)
96 if(iter->alpha == 0x00)
102 SDL_Surface *converted = create_sdl_surface_from(dst);
103 SDL_SetColorKey(converted, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(converted->format, key.red, key.green, key.blue));
104 SDL_Surface *optimized = SDL_DisplayFormat(converted);
105 SDL_FreeSurface(converted);
108 SDL_Surface *Blitters::optimize(const Surface &src)
110 unsigned int transparent = 0;
111 unsigned int opaque = 0;
112 unsigned int semitransparent = 0;
113 unsigned int alphasum = 0;
114 unsigned int squaredalphasum = 0;
115 bool colors[(1 << 12)];
116 memset(colors, 0, (1 << 12) * sizeof(bool));
118 const Color *src_end = src.get_pixels() + src.get_size().x * src.get_size().y;
119 for(const Color *iter = src.get_pixels();iter != src_end;++iter)
125 else if(iter->alpha > 240)
128 alphasum += iter->alpha;
129 squaredalphasum += iter->alpha * iter->alpha;
134 squaredalphasum += iter->alpha * iter->alpha;
138 colors[((iter->red & 0xf0) << 4) | (iter->green & 0xf0) | ((iter->blue & 0xf0) >> 4)] = true;
142 unsigned int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
143 unsigned int avgsquaredalpha = (opaque + semitransparent) ? squaredalphasum / (opaque + semitransparent) : 0;
144 unsigned int alphavariance = avgsquaredalpha - avgalpha * avgalpha;
145 if(semitransparent > ((transparent + opaque + semitransparent) / 8) && alphavariance > 16)
147 SDL_Surface *converted = create_sdl_surface_from(src);
148 SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
149 SDL_FreeSurface(converted);
154 for(int i = 0;i < (1 << 12);i++)
164 SDL_Surface *converted = create_sdl_surface_from(src);
165 SDL_Surface *optimized = SDL_DisplayFormatAlpha(converted);
166 SDL_FreeSurface(converted);
170 Color key(((keycolor & 0xf00) >> 4) | 0xf, (keycolor & 0x0f0) | 0xf, ((keycolor & 0x00f) << 4) | 0xf);
171 Surface dst(src.get_size());
172 Color *dst_end = dst.get_pixels() + dst.get_size().x * dst.get_size().y;
173 const Color *src_iter = src.get_pixels();
174 Color *dst_iter = dst.get_pixels();
175 for(;dst_iter != dst_end;++dst_iter, ++src_iter)
177 *dst_iter = (src_iter->alpha < avgalpha / 4) ? key : *src_iter;
180 SDL_Surface *converted = create_sdl_surface_from(dst);
183 SDL_SetAlpha(converted, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
185 SDL_SetColorKey(converted, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(converted->format, key.red, key.green, key.blue));
186 SDL_Surface *optimized = SDL_DisplayFormat(converted);
187 SDL_FreeSurface(converted);
191 void Blitters::blit_upper(SDL_Surface *src, Rect src_rect, SDL_Surface *dst, Point dst_pos, void (*blit_lower)(SDL_Surface *, const Rect &, SDL_Surface *, const Point &))
196 if(src_rect == Rect())
198 src_rect.size.x = src->w;
199 src_rect.size.y = src->h;
203 if(src_rect.size.x < (unsigned int) -dst_pos.x)
207 src_rect.pos.x += -dst_pos.x;
208 src_rect.size.x += dst_pos.x;
213 if(src_rect.size.y < (unsigned int) -dst_pos.y)
217 src_rect.pos.y += -dst_pos.y;
218 src_rect.size.y += dst_pos.y;
221 if(src_rect.pos.x < 0)
223 if(src_rect.size.x < (unsigned int) -src_rect.pos.x)
227 src_rect.size.x += src_rect.pos.x;
230 if(src_rect.pos.y < 0)
232 if(src_rect.size.y < (unsigned int) -src_rect.pos.y)
236 src_rect.size.y += src_rect.pos.y;
239 if(src_rect.get_right() > src->w)
241 src_rect.size.x = src->w - src_rect.pos.x;
243 if(src_rect.get_bottom() > src->h)
245 src_rect.size.y = src->h - src_rect.pos.y;
247 if(int(dst_pos.x + src_rect.size.x) > dst->w)
249 src_rect.size.x = dst->w - dst_pos.x;
251 if(int(dst_pos.y + src_rect.size.y) > dst->h)
253 src_rect.size.y = dst->h - dst_pos.y;
255 blit_lower(src, src_rect, dst, dst_pos);
258 void Blitters::blit_lower_none(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
260 SDL_Rect sdl_src_rect = {src_rect.pos.x, src_rect.pos.y, src_rect.size.x, src_rect.size.y};
261 SDL_Rect sdl_dst_rect = {dst_pos.x, dst_pos.y, 0, 0};
263 Uint8 alpha = src->format->alpha;
264 SDL_SetAlpha(src, 0, 0);
265 SDL_BlitSurface(src, &sdl_src_rect, dst, &sdl_dst_rect);
266 SDL_SetAlpha(src, SDL_SRCALPHA | SDL_RLEACCEL, alpha);
269 void Blitters::blit_lower_mask(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
271 if(SDL_MUSTLOCK(src))
273 SDL_LockSurface(src);
275 if(SDL_MUSTLOCK(dst))
277 SDL_LockSurface(dst);
279 int src_bpp = src->format->BytesPerPixel;
280 int dst_bpp = dst->format->BytesPerPixel;
281 Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
282 Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
283 for(unsigned int y = 0;y < src_rect.size.y;y++)
285 for(unsigned int x = 0;x < src_rect.size.x;x++)
287 Uint32 src_mapped = 0;
290 src_mapped = *src_pixel;
293 src_mapped = *(Uint16 *)src_pixel;
296 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
297 src_mapped |= src_pixel[0] << 16;
298 src_mapped |= src_pixel[1] << 8;
299 src_mapped |= src_pixel[2] << 0;
301 src_mapped |= src_pixel[0] << 0;
302 src_mapped |= src_pixel[1] << 8;
303 src_mapped |= src_pixel[2] << 16;
307 src_mapped = *(Uint32 *)src_pixel;
310 Uint8 src_red, src_green, src_blue, src_alpha;
311 SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
314 Uint32 blend_mapped = SDL_MapRGBA(dst->format, src_red, src_green, src_blue, src_alpha);
317 *dst_pixel = blend_mapped;
320 *(Uint16 *)dst_pixel = blend_mapped;
323 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
324 dst_pixel[0] = (blend_mapped >> 16) & 0xff;
325 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
326 dst_pixel[2] = (blend_mapped >> 0) & 0xff;
328 dst_pixel[0] = (blend_mapped >> 0) & 0xff;
329 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
330 dst_pixel[2] = (blend_mapped >> 16) & 0xff;
334 *(Uint32 *)dst_pixel = blend_mapped;
338 src_pixel += src_bpp;
339 dst_pixel += dst_bpp;
341 src_pixel += src->pitch - src_rect.size.x * src_bpp;
342 dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
344 if(SDL_MUSTLOCK(dst))
346 SDL_UnlockSurface(dst);
348 if(SDL_MUSTLOCK(src))
350 SDL_UnlockSurface(src);
354 void Blitters::blit_lower_alpha(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
356 SDL_Rect sdl_src_rect = {src_rect.pos.x, src_rect.pos.y, src_rect.size.x, src_rect.size.y};
357 SDL_Rect sdl_dst_rect = {dst_pos.x, dst_pos.y, 0, 0};
359 SDL_BlitSurface(src, &sdl_src_rect, dst, &sdl_dst_rect);
362 void Blitters::blit_lower_add(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
364 if(SDL_MUSTLOCK(src))
366 SDL_LockSurface(src);
368 if(SDL_MUSTLOCK(dst))
370 SDL_LockSurface(dst);
372 int src_bpp = src->format->BytesPerPixel;
373 int dst_bpp = dst->format->BytesPerPixel;
374 Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
375 Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
376 for(unsigned int y = 0;y < src_rect.size.y;y++)
378 for(unsigned int x = 0;x < src_rect.size.x;x++)
380 Uint32 src_mapped = 0;
383 src_mapped = *src_pixel;
386 src_mapped = *(Uint16 *)src_pixel;
389 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
390 src_mapped |= src_pixel[0] << 16;
391 src_mapped |= src_pixel[1] << 8;
392 src_mapped |= src_pixel[2] << 0;
394 src_mapped |= src_pixel[0] << 0;
395 src_mapped |= src_pixel[1] << 8;
396 src_mapped |= src_pixel[2] << 16;
400 src_mapped = *(Uint32 *)src_pixel;
403 Uint8 src_red, src_green, src_blue, src_alpha;
404 SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
405 Uint32 dst_mapped = 0;
408 dst_mapped = *dst_pixel;
411 dst_mapped = *(Uint16 *)dst_pixel;
414 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
415 dst_mapped |= dst_pixel[0] << 16;
416 dst_mapped |= dst_pixel[1] << 8;
417 dst_mapped |= dst_pixel[2] << 0;
419 dst_mapped |= dst_pixel[0] << 0;
420 dst_mapped |= dst_pixel[1] << 8;
421 dst_mapped |= dst_pixel[2] << 16;
425 dst_mapped = *(Uint32 *)dst_pixel;
428 Uint8 dst_red, dst_green, dst_blue, dst_alpha;
429 SDL_GetRGBA(dst_mapped, dst->format, &dst_red, &dst_green, &dst_blue, &dst_alpha);
430 Uint8 blend_red = src_red, blend_green = src_green, blend_blue = src_blue, blend_alpha = src_alpha;
431 if(src_red != 0 && dst_red != 0xff)
433 int redsum = dst_red + src_red * src_alpha / 0xff;
434 blend_red = redsum & ~0xff ? 0xff : redsum;
439 if(src_green != 0 && dst_green != 0xff)
441 int greensum = dst_green + src_green * src_alpha / 0xff;
442 blend_green = greensum & ~0xff ? 0xff : greensum;
444 if(src_blue != 0 && dst_blue != 0xff)
446 int bluesum = dst_blue + src_blue * src_alpha / 0xff;
447 blend_blue = bluesum & ~0xff ? 0xff : bluesum;
449 if(src_red != blend_red || src_green != blend_green || src_blue != blend_blue || src_alpha != blend_alpha)
451 Uint32 blend_mapped = SDL_MapRGBA(dst->format, blend_red, blend_green, blend_blue, blend_alpha);
454 *dst_pixel = blend_mapped;
457 *(Uint16 *)dst_pixel = blend_mapped;
460 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
461 dst_pixel[0] = (blend_mapped >> 16) & 0xff;
462 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
463 dst_pixel[2] = (blend_mapped >> 0) & 0xff;
465 dst_pixel[0] = (blend_mapped >> 0) & 0xff;
466 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
467 dst_pixel[2] = (blend_mapped >> 16) & 0xff;
471 *(Uint32 *)dst_pixel = blend_mapped;
475 src_pixel += src_bpp;
476 dst_pixel += dst_bpp;
478 src_pixel += src->pitch - src_rect.size.x * src_bpp;
479 dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
481 if(SDL_MUSTLOCK(dst))
483 SDL_UnlockSurface(dst);
485 if(SDL_MUSTLOCK(src))
487 SDL_UnlockSurface(src);
491 void Blitters::blit_lower_mod(SDL_Surface *src, const Rect &src_rect, SDL_Surface *dst, const Point &dst_pos)
493 if(SDL_MUSTLOCK(src))
495 SDL_LockSurface(src);
497 if(SDL_MUSTLOCK(dst))
499 SDL_LockSurface(dst);
501 int src_bpp = src->format->BytesPerPixel;
502 int dst_bpp = dst->format->BytesPerPixel;
503 Uint8 *src_pixel = (Uint8 *)src->pixels + src_rect.pos.y * src->pitch + src_rect.pos.x * src_bpp;
504 Uint8 *dst_pixel = (Uint8 *)dst->pixels + dst_pos.y * dst->pitch + dst_pos.x * dst_bpp;
505 for(unsigned int y = 0;y < src_rect.size.y;y++)
507 for(unsigned int x = 0;x < src_rect.size.x;x++)
509 Uint32 src_mapped = 0;
512 src_mapped = *src_pixel;
515 src_mapped = *(Uint16 *)src_pixel;
518 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
519 src_mapped |= src_pixel[0] << 16;
520 src_mapped |= src_pixel[1] << 8;
521 src_mapped |= src_pixel[2] << 0;
523 src_mapped |= src_pixel[0] << 0;
524 src_mapped |= src_pixel[1] << 8;
525 src_mapped |= src_pixel[2] << 16;
529 src_mapped = *(Uint32 *)src_pixel;
532 Uint8 src_red, src_green, src_blue, src_alpha;
533 SDL_GetRGBA(src_mapped, src->format, &src_red, &src_green, &src_blue, &src_alpha);
534 Uint32 dst_mapped = 0;
537 dst_mapped = *dst_pixel;
540 dst_mapped = *(Uint16 *)dst_pixel;
543 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
544 dst_mapped |= dst_pixel[0] << 16;
545 dst_mapped |= dst_pixel[1] << 8;
546 dst_mapped |= dst_pixel[2] << 0;
548 dst_mapped |= dst_pixel[0] << 0;
549 dst_mapped |= dst_pixel[1] << 8;
550 dst_mapped |= dst_pixel[2] << 16;
554 dst_mapped = *(Uint32 *)dst_pixel;
557 Uint8 dst_red, dst_green, dst_blue, dst_alpha;
558 SDL_GetRGBA(dst_mapped, dst->format, &dst_red, &dst_green, &dst_blue, &dst_alpha);
559 Uint8 blend_red, blend_green, blend_blue, blend_alpha;
560 blend_red = dst_red * src_red / 0xff;
561 blend_green = dst_green * src_green / 0xff;
562 blend_blue = dst_blue * src_blue / 0xff;
563 blend_alpha = dst_alpha * src_alpha / 0xff;
564 if(src_red != blend_red || src_green != blend_green || src_blue != blend_blue || src_alpha != blend_alpha)
566 Uint32 blend_mapped = SDL_MapRGBA(dst->format, blend_red, blend_green, blend_blue, blend_alpha);
569 *dst_pixel = blend_mapped;
572 *(Uint16 *)dst_pixel = blend_mapped;
575 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
576 dst_pixel[0] = (blend_mapped >> 16) & 0xff;
577 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
578 dst_pixel[2] = (blend_mapped >> 0) & 0xff;
580 dst_pixel[0] = (blend_mapped >> 0) & 0xff;
581 dst_pixel[1] = (blend_mapped >> 8) & 0xff;
582 dst_pixel[2] = (blend_mapped >> 16) & 0xff;
586 *(Uint32 *)dst_pixel = blend_mapped;
590 src_pixel += src_bpp;
591 dst_pixel += dst_bpp;
593 src_pixel += src->pitch - src_rect.size.x * src_bpp;
594 dst_pixel += dst->pitch - src_rect.size.x * dst_bpp;
596 if(SDL_MUSTLOCK(dst))
598 SDL_UnlockSurface(dst);
600 if(SDL_MUSTLOCK(src))
602 SDL_UnlockSurface(src);