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;
47 for(int y = 0;y < dst->h;y++) {
48 for(int x = 0;x < dst->w;x++) {
49 Uint8 *srcpixel = (Uint8 *) src->pixels + (y * denominator / numerator) * src->pitch + (x * denominator / numerator) * bpp;
50 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
53 dstpixel[3] = srcpixel[3];
55 dstpixel[2] = srcpixel[2];
57 dstpixel[1] = srcpixel[1];
59 dstpixel[0] = srcpixel[0];
69 void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4])
71 int bpp = src->format->BytesPerPixel;
72 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
79 mapped = *(Uint16 *)srcpixel;
82 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
83 mapped |= srcpixel[0] << 16;
84 mapped |= srcpixel[1] << 8;
85 mapped |= srcpixel[2] << 0;
87 mapped |= srcpixel[0] << 0;
88 mapped |= srcpixel[1] << 8;
89 mapped |= srcpixel[2] << 16;
93 mapped = *(Uint32 *)srcpixel;
96 SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
99 void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
101 color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
102 color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
103 color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
104 color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
107 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
109 if(numerator == denominator)
116 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);
117 int bpp = dst->format->BytesPerPixel;
118 for(int y = 0;y < dst->h;y++) {
119 for(int x = 0;x < dst->w;x++) {
120 int srcx = x * denominator / numerator;
121 int srcy = y * denominator / numerator;
122 Uint8 color00[4], color01[4], color10[4], color11[4];
123 getpixel(src, srcx, srcy, color00);
124 getpixel(src, srcx + 1, srcy, color01);
125 getpixel(src, srcx, srcy + 1, color10);
126 getpixel(src, srcx + 1, srcy + 1, color11);
127 Uint8 color0[4], color1[4], color[4];
128 int remx = x * denominator % numerator;
129 merge(color0, color00, color01, remx, numerator);
130 merge(color1, color10, color11, remx, numerator);
131 int remy = y * denominator % numerator;
132 merge(color, color0, color1, remy, numerator);
133 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
134 Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
140 *(Uint16 *)dstpixel = mapped;
143 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
144 dstpixel[0] = (mapped >> 16) & 0xff;
145 dstpixel[1] = (mapped >> 8) & 0xff;
146 dstpixel[2] = (mapped >> 0) & 0xff;
148 dstpixel[0] = (mapped >> 0) & 0xff;
149 dstpixel[1] = (mapped >> 8) & 0xff;
150 dstpixel[2] = (mapped >> 16) & 0xff;
154 *(Uint32 *)dstpixel = mapped;
164 // FIXME: Horizontal and vertical line problem
166 void accumulate(SDL_Surface *src, int srcx, int srcy, int color[4], int weight)
168 if(srcx < 0 || srcy < 0 || weight == 0) {
171 int bpp = src->format->BytesPerPixel;
172 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
179 mapped = *(Uint16 *)srcpixel;
182 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
183 mapped |= srcpixel[0] << 16;
184 mapped |= srcpixel[1] << 8;
185 mapped |= srcpixel[2] << 0;
187 mapped |= srcpixel[0] << 0;
188 mapped |= srcpixel[1] << 8;
189 mapped |= srcpixel[2] << 16;
193 mapped = *(Uint32 *)srcpixel;
196 Uint8 red, green, blue, alpha;
197 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
198 color[0] += red * weight;
199 color[1] += green * weight;
200 color[2] += blue * weight;
201 color[3] += alpha * weight;
204 void accumulate_line(SDL_Surface *src, int srcy, int line[][4], int linesize, int weight, int numerator, int denominator)
206 int intpart = denominator / numerator;
207 int fractpart = denominator % numerator;
208 for(int x = 0, xe = 0, srcx = 0;x < linesize;x++) {
209 accumulate(src, srcx, srcy, line[x], (numerator - xe) * weight);
211 for(int i = 0;i < intpart - 1;i++) {
212 accumulate(src, srcx, srcy, line[x], numerator * weight);
216 if(xe >= numerator) {
220 accumulate(src, srcx, srcy, line[x], xe * weight);
224 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
226 if(numerator == denominator)
233 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);
234 int bpp = dst->format->BytesPerPixel;
235 int intpart = denominator / numerator;
236 int fractpart = denominator % numerator;
237 for(int y = 0, ye = 0, srcy = 0;y < dst->h;y++) {
239 memset(line, 0, sizeof(int) * dst->w * 4);
240 accumulate_line(src, srcy, line, dst->w, numerator - ye, numerator, denominator);
242 for(int i = 0;i < intpart - 1;i++) {
243 accumulate_line(src, srcy, line, dst->w, numerator, numerator, denominator);
247 if(ye >= numerator) {
251 accumulate_line(src, srcy, line, dst->w, ye, numerator, denominator);
252 for(int x = 0;x < dst->w;x++) {
253 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
254 Uint32 mapped = SDL_MapRGBA(dst->format, line[x][0] / (denominator * denominator), line[x][1] / (denominator * denominator), line[x][2] / (denominator * denominator), line[x][3] / (denominator * denominator));
260 *(Uint16 *)dstpixel = mapped;
263 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
264 dstpixel[0] = (mapped >> 16) & 0xff;
265 dstpixel[1] = (mapped >> 8) & 0xff;
266 dstpixel[2] = (mapped >> 0) & 0xff;
268 dstpixel[0] = (mapped >> 0) & 0xff;
269 dstpixel[1] = (mapped >> 8) & 0xff;
270 dstpixel[2] = (mapped >> 16) & 0xff;
274 *(Uint32 *)dstpixel = mapped;
284 SDL_Surface *horz_flip(SDL_Surface *src)
286 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);
287 int bpp = dst->format->BytesPerPixel;
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 + y * dst->pitch + (dst->w - x - 1) * bpp;
294 dstpixel[3] = srcpixel[3];
296 dstpixel[2] = srcpixel[2];
298 dstpixel[1] = srcpixel[1];
300 dstpixel[0] = srcpixel[0];
307 SDL_Surface *vert_flip(SDL_Surface *src)
309 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);
310 int bpp = dst->format->BytesPerPixel;
311 for(int y = 0;y < dst->h;y++) {
312 for(int x = 0;x < dst->w;x++) {
313 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
314 Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
317 dstpixel[3] = srcpixel[3];
319 dstpixel[2] = srcpixel[2];
321 dstpixel[1] = srcpixel[1];
323 dstpixel[0] = srcpixel[0];
330 const Color white(1.0, 1.0, 1.0);
332 SDL_Surface *colorize(SDL_Surface *src, const Color &color)
334 // FIXME: This is really slow
335 assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
336 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);
337 int bpp = dst->format->BytesPerPixel;
338 for(int y = 0;y < dst->h;y++) {
339 for(int x = 0;x < dst->w;x++) {
340 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
341 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
348 mapped = *(Uint16 *)srcpixel;
351 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
352 mapped |= srcpixel[0] << 16;
353 mapped |= srcpixel[1] << 8;
354 mapped |= srcpixel[2] << 0;
356 mapped |= srcpixel[0] << 0;
357 mapped |= srcpixel[1] << 8;
358 mapped |= srcpixel[2] << 16;
362 mapped = *(Uint32 *)srcpixel;
365 Uint8 red, green, blue, alpha;
366 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
367 red = (Uint8) (red * color.red);
368 green = (Uint8) (green * color.green);
369 blue = (Uint8) (blue * color.blue);
370 mapped = SDL_MapRGBA(dst->format, red, green, blue, alpha);
376 *(Uint16 *)dstpixel = mapped;
379 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
380 dstpixel[0] = (mapped >> 16) & 0xff;
381 dstpixel[1] = (mapped >> 8) & 0xff;
382 dstpixel[2] = (mapped >> 0) & 0xff;
384 dstpixel[0] = (mapped >> 0) & 0xff;
385 dstpixel[1] = (mapped >> 8) & 0xff;
386 dstpixel[2] = (mapped >> 16) & 0xff;
390 *(Uint32 *)dstpixel = mapped;
401 Texture::Texture(SDL_Surface* image)
403 texture = SDL_DisplayFormatAlpha(image);
407 float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
408 float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
409 if(xfactor < yfactor)
411 numerator = config->screenwidth;
412 denominator = SCREEN_WIDTH;
416 numerator = config->screenheight;
417 denominator = SCREEN_HEIGHT;
419 cache[white][NO_EFFECT] = scale(texture, numerator, denominator);
424 SDL_FreeSurface(texture);
427 SDL_Surface *Texture::get_transform(const Color &color, DrawingEffect effect)
429 if(cache.find(color) == cache.end())
431 cache[color][NO_EFFECT] = colorize(cache[white][NO_EFFECT], color);
433 if(cache[color][effect] == 0) {
434 assert(cache[color][NO_EFFECT]);
438 case HORIZONTAL_FLIP:
439 cache[color][HORIZONTAL_FLIP] = horz_flip(cache[color][NO_EFFECT]);
442 cache[color][VERTICAL_FLIP] = vert_flip(cache[color][NO_EFFECT]);
445 std::cerr << "Warning: transformation unknown" << std::endl;
449 return cache[color][effect];