Removed OLD_SDL1 software rendering code from SDL_Renderer
[supertux.git] / src / video / sdl / sdl_lightmap.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
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.
8 //
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.
13 //
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/>.
16
17 #include <iostream>
18
19 #include "video/sdl/sdl_lightmap.hpp"
20 #include "video/sdl/sdl_surface_data.hpp"
21 #include "video/sdl/sdl_texture.hpp"
22
23 SDLLightmap::SDLLightmap() :
24   red_channel(),
25   blue_channel(),
26   green_channel(),
27   width(),
28   height(),
29   numerator(),
30   denominator(),
31   LIGHTMAP_DIV()
32 {
33   //float xfactor = 1.0f; // FIXME: (float) config->screenwidth / SCREEN_WIDTH;
34   //float yfactor = 1.0f; // FIXME: (float) config->screenheight / SCREEN_HEIGHT;
35
36   numerator = 1;
37   denominator = 1;
38
39   /* FIXME:
40      if(xfactor < yfactor)
41      {
42      numerator = config->screenwidth;
43      denominator = SCREEN_WIDTH;
44      }
45      else
46      {
47      numerator = config->screenheight;
48      denominator = SCREEN_HEIGHT;
49      }
50   */
51
52 #ifdef OLD_SDL1
53   LIGHTMAP_DIV = 8 * numerator / denominator;
54
55   width = screen->w / LIGHTMAP_DIV;
56   height = screen->h / LIGHTMAP_DIV;
57
58   red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
59   green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
60   blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
61 #endif
62 }
63
64 SDLLightmap::~SDLLightmap()
65 {
66   free(red_channel);
67   free(green_channel);
68   free(blue_channel);
69 }
70
71 void
72 SDLLightmap::start_draw(const Color &ambient_color)
73 {
74   memset(red_channel, (Uint8) (ambient_color.red * 255), width * height * sizeof(Uint8));
75   memset(green_channel, (Uint8) (ambient_color.green * 255), width * height * sizeof(Uint8));
76   memset(blue_channel, (Uint8) (ambient_color.blue * 255), width * height * sizeof(Uint8));
77 }
78
79 void
80 SDLLightmap::end_draw()
81 {
82 }
83
84 //#define BILINEAR
85
86 #ifdef BILINEAR
87 namespace {
88
89 void merge(Uint8 color[3], Uint8 color0[3], Uint8 color1[3], int rem, int total)
90 {
91   color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
92   color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
93   color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
94 }
95
96 } // namespace
97 #endif
98
99 void
100 SDLLightmap::do_draw()
101 {
102 #ifdef OLD_SDL1
103   // FIXME: This is really slow
104   if(LIGHTMAP_DIV == 1)
105   {
106     int bpp = screen->format->BytesPerPixel;
107     if(SDL_MUSTLOCK(screen))
108     {
109       SDL_LockSurface(screen);
110     }
111     Uint8 *pixel = (Uint8 *) screen->pixels;
112     int loc = 0;
113     for(int y = 0;y < height;y++) {
114       for(int x = 0;x < width;x++, pixel += bpp, loc++) {
115         if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
116         {
117           continue;
118         }
119         Uint32 mapped = 0;
120         switch(bpp) {
121           case 1:
122             mapped = *pixel;
123             break;
124           case 2:
125             mapped = *(Uint16 *)pixel;
126             break;
127           case 3:
128 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
129             mapped |= pixel[0] << 16;
130             mapped |= pixel[1] << 8;
131             mapped |= pixel[2] << 0;
132 #else
133             mapped |= pixel[0] << 0;
134             mapped |= pixel[1] << 8;
135             mapped |= pixel[2] << 16;
136 #endif
137             break;
138           case 4:
139             mapped = *(Uint32 *)pixel;
140             break;
141         }
142         Uint8 red, green, blue, alpha;
143         SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
144         red = (red * red_channel[loc]) >> 8;
145         green = (green * green_channel[loc]) >> 8;
146         blue = (blue * blue_channel[loc]) >> 8;
147         mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
148         switch(bpp) {
149           case 1:
150             *pixel = mapped;
151             break;
152           case 2:
153             *(Uint16 *)pixel = mapped;
154             break;
155           case 3:
156 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
157             pixel[0] = (mapped >> 16) & 0xff;
158             pixel[1] = (mapped >> 8) & 0xff;
159             pixel[2] = (mapped >> 0) & 0xff;
160 #else
161             pixel[0] = (mapped >> 0) & 0xff;
162             pixel[1] = (mapped >> 8) & 0xff;
163             pixel[2] = (mapped >> 16) & 0xff;
164 #endif
165             break;
166           case 4:
167             *(Uint32 *)pixel = mapped;
168             break;
169         }
170       }
171       pixel += screen->pitch - width * bpp;
172     }
173     if(SDL_MUSTLOCK(screen))
174     {
175       SDL_UnlockSurface(screen);
176     }
177   }
178   else
179   {
180     int bpp = screen->format->BytesPerPixel;
181     if(SDL_MUSTLOCK(screen))
182     {
183       SDL_LockSurface(screen);
184     }
185     Uint8 *div_pixel = (Uint8 *) screen->pixels;
186     int loc = 0;
187     for(int y = 0;y < height;y++) {
188       for(int x = 0;x < width;x++, div_pixel += bpp * LIGHTMAP_DIV, loc++) {
189         if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
190         {
191           continue;
192         }
193         Uint8 *pixel = div_pixel;
194         for(int div_y = 0;div_y < LIGHTMAP_DIV;div_y++) {
195           for(int div_x = 0;div_x < LIGHTMAP_DIV;pixel += bpp, div_x++) {
196             Uint32 mapped = 0;
197             switch(bpp) {
198               case 1:
199                 mapped = *pixel;
200                 break;
201               case 2:
202                 mapped = *(Uint16 *)pixel;
203                 break;
204               case 3:
205 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
206                 mapped |= pixel[0] << 16;
207                 mapped |= pixel[1] << 8;
208                 mapped |= pixel[2] << 0;
209 #else
210                 mapped |= pixel[0] << 0;
211                 mapped |= pixel[1] << 8;
212                 mapped |= pixel[2] << 16;
213 #endif
214                 break;
215               case 4:
216                 mapped = *(Uint32 *)pixel;
217                 break;
218             }
219             Uint8 red, green, blue, alpha;
220             SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
221
222 #ifdef BILINEAR
223             int xinc = (x + 1 != width ? 1 : 0);
224             int yinc = (y + 1 != height ? width : 0);
225             Uint8 color00[3], color01[3], color10[3], color11[3];
226             {
227               color00[0] = red_channel[loc];
228               color00[1] = green_channel[loc];
229               color00[2] = blue_channel[loc];
230             }
231             {
232               color01[0] = red_channel[loc + xinc];
233               color01[1] = green_channel[loc + xinc];
234               color01[2] = blue_channel[loc + xinc];
235             }
236             {
237               color10[0] = red_channel[loc + yinc];
238               color10[1] = green_channel[loc + yinc];
239               color10[2] = blue_channel[loc + yinc];
240             }
241             {
242               color11[0] = red_channel[loc + yinc + xinc];
243               color11[1] = green_channel[loc + yinc + xinc];
244               color11[2] = blue_channel[loc + yinc + xinc];
245             }
246             Uint8 color0[3], color1[3], color[3];
247             merge(color0, color00, color01, div_x, LIGHTMAP_DIV);
248             merge(color1, color10, color11, div_x, LIGHTMAP_DIV);
249             merge(color, color0, color1, div_y, LIGHTMAP_DIV);
250             red = (red * color[0]) >> 8;
251             green = (green * color[1]) >> 8;
252             blue = (blue * color[2]) >> 8;
253 #else
254             red = (red * red_channel[loc]) >> 8;
255             green = (green * green_channel[loc]) >> 8;
256             blue = (blue * blue_channel[loc]) >> 8;
257 #endif
258
259             mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
260             switch(bpp) {
261               case 1:
262                 *pixel = mapped;
263                 break;
264               case 2:
265                 *(Uint16 *)pixel = mapped;
266                 break;
267               case 3:
268 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
269                 pixel[0] = (mapped >> 16) & 0xff;
270                 pixel[1] = (mapped >> 8) & 0xff;
271                 pixel[2] = (mapped >> 0) & 0xff;
272 #else
273                 pixel[0] = (mapped >> 0) & 0xff;
274                 pixel[1] = (mapped >> 8) & 0xff;
275                 pixel[2] = (mapped >> 16) & 0xff;
276 #endif
277                 break;
278               case 4:
279                 *(Uint32 *)pixel = mapped;
280                 break;
281             }
282           }
283           pixel += screen->pitch - LIGHTMAP_DIV * bpp;
284         }
285       }
286       div_pixel += (screen->pitch - width * bpp) * LIGHTMAP_DIV;
287     }
288     if(SDL_MUSTLOCK(screen))
289     {
290       SDL_UnlockSurface(screen);
291     }
292   }
293 #endif
294 }
295
296 void
297 SDLLightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
298 {
299   dstx /= LIGHTMAP_DIV;
300   dsty /= LIGHTMAP_DIV;
301   int srcx = src_rect->x / LIGHTMAP_DIV;
302   int srcy = src_rect->y / LIGHTMAP_DIV;
303   int blit_width = src_rect->w / LIGHTMAP_DIV;
304   int blit_height = src_rect->h / LIGHTMAP_DIV;
305   int bpp = src->format->BytesPerPixel;
306   if(SDL_MUSTLOCK(src))
307   {
308     SDL_LockSurface(src);
309   }
310   Uint8 *pixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
311   int loc = dsty * width + dstx;
312   for(int y = 0;y < blit_height;y++) {
313     for(int x = 0;x < blit_width;x++, pixel += bpp * LIGHTMAP_DIV, loc++) {
314       if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
315       {
316         continue;
317       }
318       if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
319       {
320         continue;
321       }
322
323       Uint32 mapped = 0;
324       switch(bpp) {
325         case 1:
326           mapped = *pixel;
327           break;
328         case 2:
329           mapped = *(Uint16 *)pixel;
330           break;
331         case 3:
332 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
333           mapped |= pixel[0] << 16;
334           mapped |= pixel[1] << 8;
335           mapped |= pixel[2] << 0;
336 #else
337           mapped |= pixel[0] << 0;
338           mapped |= pixel[1] << 8;
339           mapped |= pixel[2] << 16;
340 #endif
341           break;
342         case 4:
343           mapped = *(Uint32 *)pixel;
344           break;
345       }
346       Uint8 red, green, blue, alpha;
347       SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
348
349       if(red != 0)
350       {
351         int redsum = red_channel[loc] + (red * alpha >> 8);
352         red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
353       }
354       if(green != 0)
355       {
356         int greensum = green_channel[loc] + (green * alpha >> 8);
357         green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
358       }
359       if(blue != 0)
360       {
361         int bluesum = blue_channel[loc] + (blue * alpha >> 8);
362         blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
363       }
364     }
365     pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV;
366     loc += width - blit_width;
367   }
368   if(SDL_MUSTLOCK(src))
369   {
370     SDL_UnlockSurface(src);
371   }
372 }
373
374 /*void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
375   {
376   int bpp = src->format->BytesPerPixel;
377   if(SDL_MUSTLOCK(src))
378   {
379   SDL_LockSurface(src);
380   }
381   Uint8 *pixel = (Uint8 *) src->pixels + src_rect->y * src->pitch + src_rect->x * bpp;
382   int loc = dsty * width + dstx;
383   for(int y = 0;y < src_rect->h;y++) {
384   for(int x = 0;x < src_rect->w;x++, pixel += bpp, loc++) {
385   if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
386   {
387   continue;
388   }
389   if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
390   {
391   continue;
392   }
393
394   Uint32 mapped = 0;
395   switch(bpp) {
396   case 1:
397   mapped = *pixel;
398   break;
399   case 2:
400   mapped = *(Uint16 *)pixel;
401   break;
402   case 3:
403   #if SDL_BYTEORDER == SDL_BIG_ENDIAN
404   mapped |= pixel[0] << 16;
405   mapped |= pixel[1] << 8;
406   mapped |= pixel[2] << 0;
407   #else
408   mapped |= pixel[0] << 0;
409   mapped |= pixel[1] << 8;
410   mapped |= pixel[2] << 16;
411   #endif
412   break;
413   case 4:
414   mapped = *(Uint32 *)pixel;
415   break;
416   }
417   Uint8 red, green, blue, alpha;
418   SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
419
420   if(red != 0)
421   {
422   int redsum = red_channel[loc] + (red * alpha >> 8);
423   red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
424   }
425   if(green != 0)
426   {
427   int greensum = green_channel[loc] + (green * alpha >> 8);
428   green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
429   }
430   if(blue != 0)
431   {
432   int bluesum = blue_channel[loc] + (blue * alpha >> 8);
433   blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
434   }
435   }
436   pixel += src->pitch - src_rect->w * bpp;
437   loc += width - src_rect->w;
438   }
439   if(SDL_MUSTLOCK(src))
440   {
441   SDL_UnlockSurface(src);
442   }
443   }*/
444
445 void
446 SDLLightmap::draw_surface(const DrawingRequest& request)
447 {
448 #ifdef OLD_SDL1
449   if((request.color.red == 0.0 && request.color.green == 0.0 && request.color.blue == 0.0) || request.color.alpha == 0.0 || request.alpha == 0.0)
450   {
451     return;
452   }
453   //FIXME: support parameters request.alpha, request.angle, request.blend
454  
455   const Surface* surface = (const Surface*) request.request_data;
456   boost::shared_ptr<SDLTexture> sdltexture = boost::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
457   SDLSurfaceData *surface_data = reinterpret_cast<SDLSurfaceData *>(surface->get_surface_data());
458
459   DrawingEffect effect = request.drawing_effect;
460   if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
461
462   SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
463
464   // get and check SDL_Surface
465   if (transform == 0) {
466     std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
467     return;
468   }
469
470   SDL_Rect *src_rect = surface_data->get_src_rect(effect);
471   int dstx = (int) request.pos.x * numerator / denominator;
472   int dsty = (int) request.pos.y * numerator / denominator;
473   light_blit(transform, src_rect, dstx, dsty);
474 #endif
475 }
476
477 void
478 SDLLightmap::draw_surface_part(const DrawingRequest& request)
479 {
480 #ifdef OLD_SDL1
481   const SurfacePartRequest* surfacepartrequest
482     = (SurfacePartRequest*) request.request_data;
483
484   const Surface* surface = surfacepartrequest->surface;
485   boost::shared_ptr<SDLTexture> sdltexture = boost::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
486
487   DrawingEffect effect = request.drawing_effect;
488   if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
489
490   SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
491
492   // get and check SDL_Surface
493   if (transform == 0) {
494     std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
495     return;
496   }
497
498   int ox, oy;
499   if (effect == HORIZONTAL_FLIP)
500   {
501     ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
502   }
503   else
504   {
505     ox = surface->get_x();
506   }
507   if (effect == VERTICAL_FLIP)
508   {
509     oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
510   }
511   else
512   {
513     oy = surface->get_y();
514   }
515
516   SDL_Rect src_rect;
517   src_rect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
518   src_rect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
519   src_rect.w = (int) surfacepartrequest->size.x * numerator / denominator;
520   src_rect.h = (int) surfacepartrequest->size.y * numerator / denominator;
521   int dstx = (int) request.pos.x * numerator / denominator;
522   int dsty = (int) request.pos.y * numerator / denominator;
523   light_blit(transform, &src_rect, dstx, dsty);
524 #endif
525 }
526
527 void
528 SDLLightmap::draw_gradient(const DrawingRequest& request)
529 {
530   const GradientRequest* gradientrequest 
531     = (GradientRequest*) request.request_data;
532   const Color& top = gradientrequest->top;
533   const Color& bottom = gradientrequest->bottom;
534
535   int loc = 0;
536   for(int y = 0;y < height;++y)
537   {
538     Uint8 red = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255);
539     Uint8 green = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255);
540     Uint8 blue = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255);
541     Uint8 alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255);
542     for(int x = 0;x < width;x++, loc++) {
543       if(red != 0)
544       {
545         int redsum = red_channel[loc] + (red * alpha >> 8);
546         red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
547       }
548       if(green != 0)
549       {
550         int greensum = green_channel[loc] + (green * alpha >> 8);
551         green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
552       }
553       if(blue != 0)
554       {
555         int bluesum = blue_channel[loc] + (blue * alpha >> 8);
556         blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
557       }
558     }
559   }
560 }
561
562 void
563 SDLLightmap::draw_filled_rect(const DrawingRequest& request)
564 {
565   const FillRectRequest* fillrectrequest
566     = (FillRectRequest*) request.request_data;
567
568   int rect_x = (int) (request.pos.x * width / SCREEN_WIDTH);
569   int rect_y = (int) (request.pos.y * height / SCREEN_HEIGHT);
570   int rect_w = (int) (fillrectrequest->size.x * width / SCREEN_WIDTH);
571   int rect_h = (int) (fillrectrequest->size.y * height / SCREEN_HEIGHT);
572   Uint8 red = (Uint8) (fillrectrequest->color.red * fillrectrequest->color.alpha * 255);
573   Uint8 green = (Uint8) (fillrectrequest->color.green * fillrectrequest->color.alpha * 255);
574   Uint8 blue = (Uint8) (fillrectrequest->color.blue * fillrectrequest->color.alpha * 255);
575   if(red == 0 && green == 0 && blue == 0)
576   {
577     return;
578   }
579   for(int y = rect_y;y < rect_y + rect_h;y++) {
580     for(int x = rect_x;x < rect_x + rect_w;x++) {
581       int loc = y * width + x;
582       if(red != 0)
583       {
584         int redsum = red_channel[loc] + red;
585         red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
586       }
587       if(green != 0)
588       {
589         int greensum = green_channel[loc] + green;
590         green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
591       }
592       if(blue != 0)
593       {
594         int bluesum = blue_channel[loc] + blue;
595         blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
596       }
597     }
598   }
599 }
600
601 void
602 SDLLightmap::get_light(const DrawingRequest& request) const
603 {
604   const GetLightRequest* getlightrequest 
605     = (GetLightRequest*) request.request_data;
606
607   int x = (int) (request.pos.x * width / SCREEN_WIDTH);
608   int y = (int) (request.pos.y * height / SCREEN_HEIGHT);
609   int loc = y * width + x;
610   *(getlightrequest->color_ptr) = Color(((float)red_channel[loc])/255, ((float)green_channel[loc])/255, ((float)blue_channel[loc])/255);
611 }
612
613 /* EOF */