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;
80 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
87 mapped = *(Uint16 *)srcpixel;
90 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
91 mapped |= srcpixel[0] << 16;
92 mapped |= srcpixel[1] << 8;
93 mapped |= srcpixel[2] << 0;
95 mapped |= srcpixel[0] << 0;
96 mapped |= srcpixel[1] << 8;
97 mapped |= srcpixel[2] << 16;
101 mapped = *(Uint32 *)srcpixel;
104 SDL_GetRGBA(mapped, src->format, &color[0], &color[1], &color[2], &color[3]);
107 void merge(Uint8 color[4], Uint8 color0[4], Uint8 color1[4], int rem, int total)
109 color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
110 color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
111 color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
112 color[3] = (color0[3] * (total - rem) + color1[3] * rem) / total;
115 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
117 if(numerator == denominator)
124 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);
125 int bpp = dst->format->BytesPerPixel;
126 for(int y = 0;y < dst->h;y++) {
127 for(int x = 0;x < dst->w;x++) {
128 int srcx = x * denominator / numerator;
129 int srcy = y * denominator / numerator;
130 Uint8 color00[4], color01[4], color10[4], color11[4];
131 getpixel(src, srcx, srcy, color00);
132 getpixel(src, srcx + 1, srcy, color01);
133 getpixel(src, srcx, srcy + 1, color10);
134 getpixel(src, srcx + 1, srcy + 1, color11);
135 Uint8 color0[4], color1[4], color[4];
136 int remx = x * denominator % numerator;
137 merge(color0, color00, color01, remx, numerator);
138 merge(color1, color10, color11, remx, numerator);
139 int remy = y * denominator % numerator;
140 merge(color, color0, color1, remy, numerator);
141 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
142 Uint32 mapped = SDL_MapRGBA(dst->format, color[0], color[1], color[2], color[3]);
148 *(Uint16 *)dstpixel = mapped;
151 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
152 dstpixel[0] = (mapped >> 16) & 0xff;
153 dstpixel[1] = (mapped >> 8) & 0xff;
154 dstpixel[2] = (mapped >> 0) & 0xff;
156 dstpixel[0] = (mapped >> 0) & 0xff;
157 dstpixel[1] = (mapped >> 8) & 0xff;
158 dstpixel[2] = (mapped >> 16) & 0xff;
162 *(Uint32 *)dstpixel = mapped;
172 // FIXME: Horizontal and vertical line problem
174 void accumulate(SDL_Surface *src, int srcx, int srcy, int color[4], int weight)
176 if(srcx < 0 || srcy < 0 || weight == 0) {
179 int bpp = src->format->BytesPerPixel;
180 Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
187 mapped = *(Uint16 *)srcpixel;
190 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
191 mapped |= srcpixel[0] << 16;
192 mapped |= srcpixel[1] << 8;
193 mapped |= srcpixel[2] << 0;
195 mapped |= srcpixel[0] << 0;
196 mapped |= srcpixel[1] << 8;
197 mapped |= srcpixel[2] << 16;
201 mapped = *(Uint32 *)srcpixel;
204 Uint8 red, green, blue, alpha;
205 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
206 color[0] += red * weight;
207 color[1] += green * weight;
208 color[2] += blue * weight;
209 color[3] += alpha * weight;
212 void accumulate_line(SDL_Surface *src, int srcy, int line[][4], int linesize, int weight, int numerator, int denominator)
214 int intpart = denominator / numerator;
215 int fractpart = denominator % numerator;
216 for(int x = 0, xe = 0, srcx = 0;x < linesize;x++) {
217 accumulate(src, srcx, srcy, line[x], (numerator - xe) * weight);
219 for(int i = 0;i < intpart - 1;i++) {
220 accumulate(src, srcx, srcy, line[x], numerator * weight);
224 if(xe >= numerator) {
228 accumulate(src, srcx, srcy, line[x], xe * weight);
232 SDL_Surface *scale(SDL_Surface *src, int numerator, int denominator)
234 if(numerator == denominator)
241 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);
242 int bpp = dst->format->BytesPerPixel;
243 int intpart = denominator / numerator;
244 int fractpart = denominator % numerator;
245 for(int y = 0, ye = 0, srcy = 0;y < dst->h;y++) {
247 memset(line, 0, sizeof(int) * dst->w * 4);
248 accumulate_line(src, srcy, line, dst->w, numerator - ye, numerator, denominator);
250 for(int i = 0;i < intpart - 1;i++) {
251 accumulate_line(src, srcy, line, dst->w, numerator, numerator, denominator);
255 if(ye >= numerator) {
259 accumulate_line(src, srcy, line, dst->w, ye, numerator, denominator);
260 for(int x = 0;x < dst->w;x++) {
261 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
262 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));
268 *(Uint16 *)dstpixel = mapped;
271 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
272 dstpixel[0] = (mapped >> 16) & 0xff;
273 dstpixel[1] = (mapped >> 8) & 0xff;
274 dstpixel[2] = (mapped >> 0) & 0xff;
276 dstpixel[0] = (mapped >> 0) & 0xff;
277 dstpixel[1] = (mapped >> 8) & 0xff;
278 dstpixel[2] = (mapped >> 16) & 0xff;
282 *(Uint32 *)dstpixel = mapped;
292 SDL_Surface *horz_flip(SDL_Surface *src)
294 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);
295 int bpp = dst->format->BytesPerPixel;
296 for(int y = 0;y < dst->h;y++) {
297 for(int x = 0;x < dst->w;x++) {
298 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
299 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + (dst->w - x - 1) * bpp;
302 dstpixel[3] = srcpixel[3];
304 dstpixel[2] = srcpixel[2];
306 dstpixel[1] = srcpixel[1];
308 dstpixel[0] = srcpixel[0];
315 SDL_Surface *vert_flip(SDL_Surface *src)
317 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);
318 int bpp = dst->format->BytesPerPixel;
319 for(int y = 0;y < dst->h;y++) {
320 for(int x = 0;x < dst->w;x++) {
321 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
322 Uint8 *dstpixel = (Uint8 *) dst->pixels + (dst->h - y - 1) * dst->pitch + x * bpp;
325 dstpixel[3] = srcpixel[3];
327 dstpixel[2] = srcpixel[2];
329 dstpixel[1] = srcpixel[1];
331 dstpixel[0] = srcpixel[0];
338 SDL_Surface *colorize(SDL_Surface *src, const Color &color)
340 // FIXME: This is really slow
341 assert(color.red != 1.0 || color.green != 1.0 || color.blue != 1.0);
342 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);
343 int bpp = dst->format->BytesPerPixel;
344 for(int y = 0;y < dst->h;y++) {
345 for(int x = 0;x < dst->w;x++) {
346 Uint8 *srcpixel = (Uint8 *) src->pixels + y * src->pitch + x * bpp;
347 Uint8 *dstpixel = (Uint8 *) dst->pixels + y * dst->pitch + x * bpp;
354 mapped = *(Uint16 *)srcpixel;
357 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
358 mapped |= srcpixel[0] << 16;
359 mapped |= srcpixel[1] << 8;
360 mapped |= srcpixel[2] << 0;
362 mapped |= srcpixel[0] << 0;
363 mapped |= srcpixel[1] << 8;
364 mapped |= srcpixel[2] << 16;
368 mapped = *(Uint32 *)srcpixel;
371 Uint8 red, green, blue, alpha;
372 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
373 red = (Uint8) (red * color.red);
374 green = (Uint8) (green * color.green);
375 blue = (Uint8) (blue * color.blue);
376 mapped = SDL_MapRGBA(dst->format, red, green, blue, alpha);
382 *(Uint16 *)dstpixel = mapped;
385 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
386 dstpixel[0] = (mapped >> 16) & 0xff;
387 dstpixel[1] = (mapped >> 8) & 0xff;
388 dstpixel[2] = (mapped >> 0) & 0xff;
390 dstpixel[0] = (mapped >> 0) & 0xff;
391 dstpixel[1] = (mapped >> 8) & 0xff;
392 dstpixel[2] = (mapped >> 16) & 0xff;
396 *(Uint32 *)dstpixel = mapped;
407 Texture::Texture(SDL_Surface* image)
409 texture = SDL_DisplayFormatAlpha(image);
410 //width = texture->w;
411 //height = texture->h;
412 int numerator, denominator;
413 float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
414 float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
415 if(xfactor < yfactor)
417 numerator = config->screenwidth;
418 denominator = SCREEN_WIDTH;
422 numerator = config->screenheight;
423 denominator = SCREEN_HEIGHT;
425 cache[NO_EFFECT][Color::WHITE] = scale(texture, numerator, denominator);
430 SDL_FreeSurface(texture);
433 SDL_Surface *Texture::get_transform(const Color &color, DrawingEffect effect)
435 if(cache[NO_EFFECT][color] == 0) {
436 assert(cache[NO_EFFECT][Color::WHITE]);
437 cache[NO_EFFECT][color] = colorize(cache[NO_EFFECT][Color::WHITE], color);
439 if(cache[effect][color] == 0) {
440 assert(cache[NO_EFFECT][color]);
444 case HORIZONTAL_FLIP:
445 cache[HORIZONTAL_FLIP][color] = horz_flip(cache[NO_EFFECT][color]);
448 cache[VERTICAL_FLIP][color] = vert_flip(cache[NO_EFFECT][color]);
454 return cache[effect][color];