2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "supertux/gameconfig.hpp"
20 #include "supertux/main.hpp"
21 #include "video/color.hpp"
22 #include "video/sdl/sdl_texture.hpp"
32 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
34 if(numerator == denominator)
41 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
42 int bpp = dst->format->BytesPerPixel;
51 for(int y = 0;y < dst->h;y++) {
52 for(int x = 0;x < dst->w;x++) {
53 Uint8 *srcpixel = (Uint8 *) src->pixels + (y * denominator / numerator) * src->pitch + (x * denominator / numerator) * bpp;
54 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
57 dstpixel[3] = srcpixel[3];
59 dstpixel[2] = srcpixel[2];
61 dstpixel[1] = srcpixel[1];
63 dstpixel[0] = srcpixel[0];
69 SDL_UnlockSurface(dst);
73 SDL_UnlockSurface(src);
75 if(!src->format->Amask)
77 if(src->flags & SDL_SRCALPHA)
79 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
81 if(src->flags & SDL_SRCCOLORKEY)
83 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
92 void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4])
94 int bpp = src->format->BytesPerPixel;
103 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
110 mapped = *(Uint16 *)srcpixel;
113 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
114 mapped |= srcpixel[0] << 16;
115 mapped |= srcpixel[1] << 8;
116 mapped |= srcpixel[2] << 0;
118 mapped |= srcpixel[0] << 0;
119 mapped |= srcpixel[1] << 8;
120 mapped |= srcpixel[2] << 16;
124 mapped = *(Uint32 *)srcpixel;
127 SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
130 void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
132 color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
133 color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
134 color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
135 color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
138 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
140 if(numerator == denominator)
147 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w * numerator / denominator, src->h * numerator / denominator, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
148 int bpp = dst->format->BytesPerPixel;
149 if(SDL_MUSTLOCK(src))
151 SDL_LockSurface(src);
153 if(SDL_MUSTLOCK(dst))
155 SDL_LockSurface(dst);
157 for(int y = 0;y < dst->h;y++) {
158 for(int x = 0;x < dst->w;x++) {
159 int srcx = x * denominator / numerator;
160 int srcy = y * denominator / numerator;
161 Uint8 color00[4], color01[4], color10[4], color11[4];
162 getpixel(src, srcx, srcy, color00);
163 getpixel(src, srcx + 1, srcy, color01);
164 getpixel(src, srcx, srcy + 1, color10);
165 getpixel(src, srcx + 1, srcy + 1, color11);
166 Uint8 color0[4], color1[4], color[4];
167 int remx = x * denominator % numerator;
168 merge(color0, color00, color01, remx, numerator);
169 merge(color1, color10, color11, remx, numerator);
170 int remy = y * denominator % numerator;
171 merge(color, color0, color1, remy, numerator);
172 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
173 Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
179 *(Uint16 *)dstpixel = mapped;
182 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
183 dstpixel[0] = (mapped >> 16) & 0xff;
184 dstpixel[1] = (mapped >> 8) & 0xff;
185 dstpixel[2] = (mapped >> 0) & 0xff;
187 dstpixel[0] = (mapped >> 0) & 0xff;
188 dstpixel[1] = (mapped >> 8) & 0xff;
189 dstpixel[2] = (mapped >> 16) & 0xff;
193 *(Uint32 *)dstpixel = mapped;
198 if(SDL_MUSTLOCK(dst))
200 SDL_UnlockSurface(dst);
202 if(SDL_MUSTLOCK(src))
204 SDL_UnlockSurface(src);
206 if(!src->format->Amask)
208 if(src->flags & SDL_SRCALPHA)
210 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
212 if(src->flags & SDL_SRCCOLORKEY)
214 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
222 SDL_Surface *horz_flip(SDL_Surface *src)
224 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
225 int bpp = dst->format->BytesPerPixel;
226 if(SDL_MUSTLOCK(src))
228 SDL_LockSurface(src);
230 if(SDL_MUSTLOCK(dst))
232 SDL_LockSurface(dst);
234 for(int y = 0;y < dst->h;y++) {
235 for(int x = 0;x < dst->w;x++) {
236 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
237 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + (dst->w - x - 1) * bpp;
240 dstpixel[3] = srcpixel[3];
242 dstpixel[2] = srcpixel[2];
244 dstpixel[1] = srcpixel[1];
246 dstpixel[0] = srcpixel[0];
250 if(SDL_MUSTLOCK(dst))
252 SDL_UnlockSurface(dst);
254 if(SDL_MUSTLOCK(src))
256 SDL_UnlockSurface(src);
258 if(!src->format->Amask)
260 if(src->flags & SDL_SRCALPHA)
262 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
264 if(src->flags & SDL_SRCCOLORKEY)
266 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
272 SDL_Surface *vert_flip(SDL_Surface *src)
274 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
275 int bpp = dst->format->BytesPerPixel;
276 if(SDL_MUSTLOCK(src))
278 SDL_LockSurface(src);
280 if(SDL_MUSTLOCK(dst))
282 SDL_LockSurface(dst);
284 for(int y = 0;y < dst->h;y++) {
285 for(int x = 0;x < dst->w;x++) {
286 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
287 Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
290 dstpixel[3] = srcpixel[3];
292 dstpixel[2] = srcpixel[2];
294 dstpixel[1] = srcpixel[1];
296 dstpixel[0] = srcpixel[0];
300 if(SDL_MUSTLOCK(dst))
302 SDL_UnlockSurface(dst);
304 if(SDL_MUSTLOCK(src))
306 SDL_UnlockSurface(src);
308 if(!src->format->Amask)
310 if(src->flags & SDL_SRCALPHA)
312 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
314 if(src->flags & SDL_SRCCOLORKEY)
316 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
322 SDL_Surface *colorize(SDL_Surface *src, const Color &color)
324 // FIXME: This is really slow
325 assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
326 int red = (int) (color.red * 256);
327 int green = (int) (color.green * 256);
328 int blue = (int) (color.blue * 256);
329 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags, src->w, src->h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, src->format->Amask);
330 int bpp = dst->format->BytesPerPixel;
331 if(SDL_MUSTLOCK(src))
333 SDL_LockSurface(src);
335 if(SDL_MUSTLOCK(dst))
337 SDL_LockSurface(dst);
339 for(int y = 0;y < dst->h;y++) {
340 for(int x = 0;x < dst->w;x++) {
341 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
342 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
349 mapped = *(Uint16 *)srcpixel;
352 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
353 mapped |= srcpixel[0] << 16;
354 mapped |= srcpixel[1] << 8;
355 mapped |= srcpixel[2] << 0;
357 mapped |= srcpixel[0] << 0;
358 mapped |= srcpixel[1] << 8;
359 mapped |= srcpixel[2] << 16;
363 mapped = *(Uint32 *)srcpixel;
366 if(src->format->Amask || !(src->flags & SDL_SRCCOLORKEY) || mapped != src->format->colorkey)
369 SDL_GetRGBA(mapped, src->format, &r, &g, &b, &a);
370 mapped = SDL_MapRGBA(dst->format, (r * red) >> 8, (g * green) >> 8, (b * blue) >> 8, a);
377 *(Uint16 *)dstpixel = mapped;
380 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
381 dstpixel[0] = (mapped >> 16) & 0xff;
382 dstpixel[1] = (mapped >> 8) & 0xff;
383 dstpixel[2] = (mapped >> 0) & 0xff;
385 dstpixel[0] = (mapped >> 0) & 0xff;
386 dstpixel[1] = (mapped >> 8) & 0xff;
387 dstpixel[2] = (mapped >> 16) & 0xff;
391 *(Uint32 *)dstpixel = mapped;
396 if(SDL_MUSTLOCK(dst))
398 SDL_UnlockSurface(dst);
400 if(SDL_MUSTLOCK(src))
402 SDL_UnlockSurface(src);
404 if(!src->format->Amask)
406 if(src->flags & SDL_SRCALPHA)
408 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
410 if(src->flags & SDL_SRCCOLORKEY)
412 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
418 SDL_Surface *optimize(SDL_Surface *src)
420 if(!src->format->Amask)
422 return SDL_DisplayFormat(src);
428 int semitransparent = 0;
430 int squaredalphasum = 0;
431 bool colors[(1 << 12)];
432 memset(colors, 0, (1 << 12) * sizeof(bool));
434 int bpp = src->format->BytesPerPixel;
435 if(SDL_MUSTLOCK(src))
437 SDL_LockSurface(src);
439 for(int y = 0;y < src->h;y++) {
440 for(int x = 0;x < src->w;x++) {
441 Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
448 mapped = *(Uint16 *)pixel;
451 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
452 mapped |= pixel[0] << 16;
453 mapped |= pixel[1] << 8;
454 mapped |= pixel[2] << 0;
456 mapped |= pixel[0] << 0;
457 mapped |= pixel[1] << 8;
458 mapped |= pixel[2] << 16;
462 mapped = *(Uint32 *)pixel;
465 Uint8 red, green, blue, alpha;
466 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
471 else if (alpha > 240)
475 squaredalphasum += alpha * alpha;
480 squaredalphasum += alpha * alpha;
484 colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
488 if(SDL_MUSTLOCK(src))
490 SDL_UnlockSurface(src);
492 int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
493 int avgsquaredalpha = (opaque + semitransparent) ? squaredalphasum / (opaque + semitransparent) : 0;
494 int alphavariance = avgsquaredalpha - avgalpha * avgalpha;
495 if(semitransparent > ((transparent + opaque + semitransparent) / 8) && alphavariance > 16)
497 return SDL_DisplayFormatAlpha(src);
500 for(int i = 0;i < (1 << 12);i++)
509 return SDL_DisplayFormatAlpha(src);
511 SDL_Surface *dst = SDL_CreateRGBSurface(src->flags & ~(SDL_SRCALPHA), src->w, src->h, src->format->BitsPerPixel, src->format->Rmask, src->format->Gmask, src->format->Bmask, 0);
512 bpp = dst->format->BytesPerPixel;
513 Uint32 key = SDL_MapRGB(dst->format, (((keycolor & 0xf00) >> 4) | 0xf), ((keycolor & 0xf0) | 0xf), (((keycolor & 0xf) << 4) | 0xf));
514 if(SDL_MUSTLOCK(src))
516 SDL_LockSurface(src);
518 if(SDL_MUSTLOCK(dst))
520 SDL_LockSurface(dst);
522 for(int y = 0;y < dst->h;y++) {
523 for(int x = 0;x < dst->w;x++) {
524 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
525 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
532 mapped = *(Uint16 *)srcpixel;
535 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
536 mapped |= srcpixel[0] << 16;
537 mapped |= srcpixel[1] << 8;
538 mapped |= srcpixel[2] << 0;
540 mapped |= srcpixel[0] << 0;
541 mapped |= srcpixel[1] << 8;
542 mapped |= srcpixel[2] << 16;
546 mapped = *(Uint32 *)srcpixel;
549 Uint8 red, green, blue, alpha;
550 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
551 if(alpha < (avgalpha / 4))
557 mapped = SDL_MapRGB(dst->format, red, green, blue);
564 *(Uint16 *)dstpixel = mapped;
567 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
568 dstpixel[0] = (mapped >> 16) & 0xff;
569 dstpixel[1] = (mapped >> 8) & 0xff;
570 dstpixel[2] = (mapped >> 0) & 0xff;
572 dstpixel[0] = (mapped >> 0) & 0xff;
573 dstpixel[1] = (mapped >> 8) & 0xff;
574 dstpixel[2] = (mapped >> 16) & 0xff;
578 *(Uint32 *)dstpixel = mapped;
583 if(SDL_MUSTLOCK(dst))
585 SDL_UnlockSurface(dst);
587 if(SDL_MUSTLOCK(src))
589 SDL_UnlockSurface(src);
593 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
595 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
596 SDL_Surface *convert = SDL_DisplayFormat(dst);
597 SDL_FreeSurface(dst);
603 SDLTexture::SDLTexture(SDL_Surface* image) :
606 texture = optimize(image);
607 //width = texture->w;
608 //height = texture->h;
611 //FIXME: float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
612 //FIXME: float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
614 if(xfactor < yfactor)
616 numerator = config->screenwidth;
617 denominator = SCREEN_WIDTH;
621 numerator = config->screenheight;
622 denominator = SCREEN_HEIGHT;
625 cache[NO_EFFECT][Color::WHITE] = scale(texture, numerator, denominator);
628 SDLTexture::~SDLTexture()
630 SDL_FreeSurface(texture);
634 SDLTexture::get_transform(const Color &color, DrawingEffect effect)
636 if(cache[NO_EFFECT][color] == 0) {
637 assert(cache[NO_EFFECT][Color::WHITE]);
638 cache[NO_EFFECT][color] = colorize(cache[NO_EFFECT][Color::WHITE], color);
640 if(cache[effect][color] == 0) {
641 assert(cache[NO_EFFECT][color]);
645 case HORIZONTAL_FLIP:
646 cache[HORIZONTAL_FLIP][color] = horz_flip(cache[NO_EFFECT][color]);
649 cache[VERTICAL_FLIP][color] = vert_flip(cache[NO_EFFECT][color]);
655 return cache[effect][color];