1 // $Id: sdl_texture.cpp 4063 2006-07-21 21:05:23Z anmaster $
4 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program 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
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include "sdl_texture.hpp"
24 #include "gameconfig.hpp"
36 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
38 if(numerator == denominator)
45 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);
46 int bpp = dst->format->BytesPerPixel;
55 for(int y = 0;y < dst->h;y++) {
56 for(int x = 0;x < dst->w;x++) {
57 Uint8 *srcpixel = (Uint8 *) src->pixels + (y * denominator / numerator) * src->pitch + (x * denominator / numerator) * bpp;
58 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
61 dstpixel[3] = srcpixel[3];
63 dstpixel[2] = srcpixel[2];
65 dstpixel[1] = srcpixel[1];
67 dstpixel[0] = srcpixel[0];
73 SDL_UnlockSurface(dst);
77 SDL_UnlockSurface(src);
79 if(!src->format->Amask)
81 if(src->flags & SDL_SRCALPHA)
83 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
85 if(src->flags & SDL_SRCCOLORKEY)
87 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
96 void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4])
98 int bpp = src->format->BytesPerPixel;
107 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
114 mapped = *(Uint16 *)srcpixel;
117 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
118 mapped |= srcpixel[0] << 16;
119 mapped |= srcpixel[1] << 8;
120 mapped |= srcpixel[2] << 0;
122 mapped |= srcpixel[0] << 0;
123 mapped |= srcpixel[1] << 8;
124 mapped |= srcpixel[2] << 16;
128 mapped = *(Uint32 *)srcpixel;
131 SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
134 void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
136 color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
137 color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
138 color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
139 color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
142 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
144 if(numerator == denominator)
151 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);
152 int bpp = dst->format->BytesPerPixel;
153 if(SDL_MUSTLOCK(src))
155 SDL_LockSurface(src);
157 if(SDL_MUSTLOCK(dst))
159 SDL_LockSurface(dst);
161 for(int y = 0;y < dst->h;y++) {
162 for(int x = 0;x < dst->w;x++) {
163 int srcx = x * denominator / numerator;
164 int srcy = y * denominator / numerator;
165 Uint8 color00[4], color01[4], color10[4], color11[4];
166 getpixel(src, srcx, srcy, color00);
167 getpixel(src, srcx + 1, srcy, color01);
168 getpixel(src, srcx, srcy + 1, color10);
169 getpixel(src, srcx + 1, srcy + 1, color11);
170 Uint8 color0[4], color1[4], color[4];
171 int remx = x * denominator % numerator;
172 merge(color0, color00, color01, remx, numerator);
173 merge(color1, color10, color11, remx, numerator);
174 int remy = y * denominator % numerator;
175 merge(color, color0, color1, remy, numerator);
176 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
177 Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
183 *(Uint16 *)dstpixel = mapped;
186 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
187 dstpixel[0] = (mapped >> 16) & 0xff;
188 dstpixel[1] = (mapped >> 8) & 0xff;
189 dstpixel[2] = (mapped >> 0) & 0xff;
191 dstpixel[0] = (mapped >> 0) & 0xff;
192 dstpixel[1] = (mapped >> 8) & 0xff;
193 dstpixel[2] = (mapped >> 16) & 0xff;
197 *(Uint32 *)dstpixel = mapped;
202 if(SDL_MUSTLOCK(dst))
204 SDL_UnlockSurface(dst);
206 if(SDL_MUSTLOCK(src))
208 SDL_UnlockSurface(src);
210 if(!src->format->Amask)
212 if(src->flags & SDL_SRCALPHA)
214 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
216 if(src->flags & SDL_SRCCOLORKEY)
218 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
226 SDL_Surface *horz_flip(SDL_Surface *src)
228 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);
229 int bpp = dst->format->BytesPerPixel;
230 if(SDL_MUSTLOCK(src))
232 SDL_LockSurface(src);
234 if(SDL_MUSTLOCK(dst))
236 SDL_LockSurface(dst);
238 for(int y = 0;y < dst->h;y++) {
239 for(int x = 0;x < dst->w;x++) {
240 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
241 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + (dst->w - x - 1) * bpp;
244 dstpixel[3] = srcpixel[3];
246 dstpixel[2] = srcpixel[2];
248 dstpixel[1] = srcpixel[1];
250 dstpixel[0] = srcpixel[0];
254 if(SDL_MUSTLOCK(dst))
256 SDL_UnlockSurface(dst);
258 if(SDL_MUSTLOCK(src))
260 SDL_UnlockSurface(src);
262 if(!src->format->Amask)
264 if(src->flags & SDL_SRCALPHA)
266 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
268 if(src->flags & SDL_SRCCOLORKEY)
270 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
276 SDL_Surface *vert_flip(SDL_Surface *src)
278 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);
279 int bpp = dst->format->BytesPerPixel;
280 if(SDL_MUSTLOCK(src))
282 SDL_LockSurface(src);
284 if(SDL_MUSTLOCK(dst))
286 SDL_LockSurface(dst);
288 for(int y = 0;y < dst->h;y++) {
289 for(int x = 0;x < dst->w;x++) {
290 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
291 Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
294 dstpixel[3] = srcpixel[3];
296 dstpixel[2] = srcpixel[2];
298 dstpixel[1] = srcpixel[1];
300 dstpixel[0] = srcpixel[0];
304 if(SDL_MUSTLOCK(dst))
306 SDL_UnlockSurface(dst);
308 if(SDL_MUSTLOCK(src))
310 SDL_UnlockSurface(src);
312 if(!src->format->Amask)
314 if(src->flags & SDL_SRCALPHA)
316 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
318 if(src->flags & SDL_SRCCOLORKEY)
320 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
326 SDL_Surface *colorize(SDL_Surface *src, const Color &color)
328 // FIXME: This is really slow
329 assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
330 int red = (int) (color.red * 256);
331 int green = (int) (color.green * 256);
332 int blue = (int) (color.blue * 256);
333 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);
334 int bpp = dst->format->BytesPerPixel;
335 if(SDL_MUSTLOCK(src))
337 SDL_LockSurface(src);
339 if(SDL_MUSTLOCK(dst))
341 SDL_LockSurface(dst);
343 for(int y = 0;y < dst->h;y++) {
344 for(int x = 0;x < dst->w;x++) {
345 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
346 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
353 mapped = *(Uint16 *)srcpixel;
356 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
357 mapped |= srcpixel[0] << 16;
358 mapped |= srcpixel[1] << 8;
359 mapped |= srcpixel[2] << 0;
361 mapped |= srcpixel[0] << 0;
362 mapped |= srcpixel[1] << 8;
363 mapped |= srcpixel[2] << 16;
367 mapped = *(Uint32 *)srcpixel;
370 if(src->format->Amask || !(src->flags & SDL_SRCCOLORKEY) || mapped != src->format->colorkey)
373 SDL_GetRGBA(mapped, src->format, &r, &g, &b, &a);
374 mapped = SDL_MapRGBA(dst->format, (r * red) >> 8, (g * green) >> 8, (b * blue) >> 8, a);
381 *(Uint16 *)dstpixel = mapped;
384 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
385 dstpixel[0] = (mapped >> 16) & 0xff;
386 dstpixel[1] = (mapped >> 8) & 0xff;
387 dstpixel[2] = (mapped >> 0) & 0xff;
389 dstpixel[0] = (mapped >> 0) & 0xff;
390 dstpixel[1] = (mapped >> 8) & 0xff;
391 dstpixel[2] = (mapped >> 16) & 0xff;
395 *(Uint32 *)dstpixel = mapped;
400 if(SDL_MUSTLOCK(dst))
402 SDL_UnlockSurface(dst);
404 if(SDL_MUSTLOCK(src))
406 SDL_UnlockSurface(src);
408 if(!src->format->Amask)
410 if(src->flags & SDL_SRCALPHA)
412 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, src->format->alpha);
414 if(src->flags & SDL_SRCCOLORKEY)
416 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, src->format->colorkey);
422 SDL_Surface *optimize(SDL_Surface *src)
424 if(!src->format->Amask)
426 return SDL_DisplayFormat(src);
432 int semitransparent = 0;
434 int squaredalphasum = 0;
435 bool colors[(1 << 12)];
436 memset(colors, 0, (1 << 12) * sizeof(bool));
438 int bpp = src->format->BytesPerPixel;
439 if(SDL_MUSTLOCK(src))
441 SDL_LockSurface(src);
443 for(int y = 0;y < src->h;y++) {
444 for(int x = 0;x < src->w;x++) {
445 Uint8 *pixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
452 mapped = *(Uint16 *)pixel;
455 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
456 mapped |= pixel[0] << 16;
457 mapped |= pixel[1] << 8;
458 mapped |= pixel[2] << 0;
460 mapped |= pixel[0] << 0;
461 mapped |= pixel[1] << 8;
462 mapped |= pixel[2] << 16;
466 mapped = *(Uint32 *)pixel;
469 Uint8 red, green, blue, alpha;
470 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
475 else if (alpha > 240)
479 squaredalphasum += alpha * alpha;
484 squaredalphasum += alpha * alpha;
488 colors[((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0) >> 4)] = true;
492 if(SDL_MUSTLOCK(src))
494 SDL_UnlockSurface(src);
496 int avgalpha = (opaque + semitransparent) ? alphasum / (opaque + semitransparent) : 0;
497 int avgsquaredalpha = (opaque + semitransparent) ? squaredalphasum / (opaque + semitransparent) : 0;
498 int alphavariance = avgsquaredalpha - avgalpha * avgalpha;
499 if(semitransparent > ((transparent + opaque + semitransparent) / 8) && alphavariance > 16)
501 return SDL_DisplayFormatAlpha(src);
504 for(int i = 0;i < (1 << 12);i++)
513 return SDL_DisplayFormatAlpha(src);
515 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);
516 bpp = dst->format->BytesPerPixel;
517 Uint32 key = SDL_MapRGB(dst->format, (((keycolor & 0xf00) >> 4) | 0xf), ((keycolor & 0xf0) | 0xf), (((keycolor & 0xf) << 4) | 0xf));
518 if(SDL_MUSTLOCK(src))
520 SDL_LockSurface(src);
522 if(SDL_MUSTLOCK(dst))
524 SDL_LockSurface(dst);
526 for(int y = 0;y < dst->h;y++) {
527 for(int x = 0;x < dst->w;x++) {
528 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
529 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
536 mapped = *(Uint16 *)srcpixel;
539 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
540 mapped |= srcpixel[0] << 16;
541 mapped |= srcpixel[1] << 8;
542 mapped |= srcpixel[2] << 0;
544 mapped |= srcpixel[0] << 0;
545 mapped |= srcpixel[1] << 8;
546 mapped |= srcpixel[2] << 16;
550 mapped = *(Uint32 *)srcpixel;
553 Uint8 red, green, blue, alpha;
554 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
555 if(alpha < (avgalpha / 4))
561 mapped = SDL_MapRGB(dst->format, red, green, blue);
568 *(Uint16 *)dstpixel = mapped;
571 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
572 dstpixel[0] = (mapped >> 16) & 0xff;
573 dstpixel[1] = (mapped >> 8) & 0xff;
574 dstpixel[2] = (mapped >> 0) & 0xff;
576 dstpixel[0] = (mapped >> 0) & 0xff;
577 dstpixel[1] = (mapped >> 8) & 0xff;
578 dstpixel[2] = (mapped >> 16) & 0xff;
582 *(Uint32 *)dstpixel = mapped;
587 if(SDL_MUSTLOCK(dst))
589 SDL_UnlockSurface(dst);
591 if(SDL_MUSTLOCK(src))
593 SDL_UnlockSurface(src);
597 SDL_SetAlpha(dst, SDL_SRCALPHA | SDL_RLEACCEL, avgalpha);
599 SDL_SetColorKey(dst, SDL_SRCCOLORKEY | SDL_RLEACCEL, key);
600 SDL_Surface *convert = SDL_DisplayFormat(dst);
601 SDL_FreeSurface(dst);
609 Texture::Texture(SDL_Surface* image)
611 texture = optimize(image);
612 //width = texture->w;
613 //height = texture->h;
614 int numerator, denominator;
615 float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
616 float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
617 if(xfactor < yfactor)
619 numerator = config->screenwidth;
620 denominator = SCREEN_WIDTH;
624 numerator = config->screenheight;
625 denominator = SCREEN_HEIGHT;
627 cache[NO_EFFECT][Color::WHITE] = scale(texture, numerator, denominator);
632 SDL_FreeSurface(texture);
635 SDL_Surface *Texture::get_transform(const Color &color, DrawingEffect effect)
637 if(cache[NO_EFFECT][color] == 0) {
638 assert(cache[NO_EFFECT][Color::WHITE]);
639 cache[NO_EFFECT][color] = colorize(cache[NO_EFFECT][Color::WHITE], color);
641 if(cache[effect][color] == 0) {
642 assert(cache[NO_EFFECT][color]);
646 case HORIZONTAL_FLIP:
647 cache[HORIZONTAL_FLIP][color] = horz_flip(cache[NO_EFFECT][color]);
650 cache[VERTICAL_FLIP][color] = vert_flip(cache[NO_EFFECT][color]);
656 return cache[effect][color];