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 "video/sdl/sdl_lightmap.hpp"
20 #include "video/sdl/sdl_surface_data.hpp"
21 #include "video/sdl/sdl_texture.hpp"
23 SDLLightmap::SDLLightmap() :
33 //float xfactor = 1.0f; // FIXME: (float) config->screenwidth / SCREEN_WIDTH;
34 //float yfactor = 1.0f; // FIXME: (float) config->screenheight / SCREEN_HEIGHT;
42 numerator = config->screenwidth;
43 denominator = SCREEN_WIDTH;
47 numerator = config->screenheight;
48 denominator = SCREEN_HEIGHT;
53 LIGHTMAP_DIV = 8 * numerator / denominator;
55 width = screen->w / LIGHTMAP_DIV;
56 height = screen->h / LIGHTMAP_DIV;
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));
64 SDLLightmap::~SDLLightmap()
72 SDLLightmap::start_draw(const Color &ambient_color)
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));
80 SDLLightmap::end_draw()
89 void merge(Uint8 color[3], Uint8 color0[3], Uint8 color1[3], int rem, int total)
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;
100 SDLLightmap::do_draw()
103 // FIXME: This is really slow
104 if(LIGHTMAP_DIV == 1)
106 int bpp = screen->format->BytesPerPixel;
107 if(SDL_MUSTLOCK(screen))
109 SDL_LockSurface(screen);
111 Uint8 *pixel = (Uint8 *) screen->pixels;
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)
125 mapped = *(Uint16 *)pixel;
128 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
129 mapped |= pixel[0] << 16;
130 mapped |= pixel[1] << 8;
131 mapped |= pixel[2] << 0;
133 mapped |= pixel[0] << 0;
134 mapped |= pixel[1] << 8;
135 mapped |= pixel[2] << 16;
139 mapped = *(Uint32 *)pixel;
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);
153 *(Uint16 *)pixel = mapped;
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;
161 pixel[0] = (mapped >> 0) & 0xff;
162 pixel[1] = (mapped >> 8) & 0xff;
163 pixel[2] = (mapped >> 16) & 0xff;
167 *(Uint32 *)pixel = mapped;
171 pixel += screen->pitch - width * bpp;
173 if(SDL_MUSTLOCK(screen))
175 SDL_UnlockSurface(screen);
180 int bpp = screen->format->BytesPerPixel;
181 if(SDL_MUSTLOCK(screen))
183 SDL_LockSurface(screen);
185 Uint8 *div_pixel = (Uint8 *) screen->pixels;
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)
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++) {
202 mapped = *(Uint16 *)pixel;
205 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
206 mapped |= pixel[0] << 16;
207 mapped |= pixel[1] << 8;
208 mapped |= pixel[2] << 0;
210 mapped |= pixel[0] << 0;
211 mapped |= pixel[1] << 8;
212 mapped |= pixel[2] << 16;
216 mapped = *(Uint32 *)pixel;
219 Uint8 red, green, blue, alpha;
220 SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
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];
227 color00[0] = red_channel[loc];
228 color00[1] = green_channel[loc];
229 color00[2] = blue_channel[loc];
232 color01[0] = red_channel[loc + xinc];
233 color01[1] = green_channel[loc + xinc];
234 color01[2] = blue_channel[loc + xinc];
237 color10[0] = red_channel[loc + yinc];
238 color10[1] = green_channel[loc + yinc];
239 color10[2] = blue_channel[loc + yinc];
242 color11[0] = red_channel[loc + yinc + xinc];
243 color11[1] = green_channel[loc + yinc + xinc];
244 color11[2] = blue_channel[loc + yinc + xinc];
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;
254 red = (red * red_channel[loc]) >> 8;
255 green = (green * green_channel[loc]) >> 8;
256 blue = (blue * blue_channel[loc]) >> 8;
259 mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
265 *(Uint16 *)pixel = mapped;
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;
273 pixel[0] = (mapped >> 0) & 0xff;
274 pixel[1] = (mapped >> 8) & 0xff;
275 pixel[2] = (mapped >> 16) & 0xff;
279 *(Uint32 *)pixel = mapped;
283 pixel += screen->pitch - LIGHTMAP_DIV * bpp;
286 div_pixel += (screen->pitch - width * bpp) * LIGHTMAP_DIV;
288 if(SDL_MUSTLOCK(screen))
290 SDL_UnlockSurface(screen);
297 SDLLightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
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))
308 SDL_LockSurface(src);
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)
318 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
329 mapped = *(Uint16 *)pixel;
332 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
333 mapped |= pixel[0] << 16;
334 mapped |= pixel[1] << 8;
335 mapped |= pixel[2] << 0;
337 mapped |= pixel[0] << 0;
338 mapped |= pixel[1] << 8;
339 mapped |= pixel[2] << 16;
343 mapped = *(Uint32 *)pixel;
346 Uint8 red, green, blue, alpha;
347 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
351 int redsum = red_channel[loc] + (red * alpha >> 8);
352 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
356 int greensum = green_channel[loc] + (green * alpha >> 8);
357 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
361 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
362 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
365 pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV;
366 loc += width - blit_width;
368 if(SDL_MUSTLOCK(src))
370 SDL_UnlockSurface(src);
374 /*void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
376 int bpp = src->format->BytesPerPixel;
377 if(SDL_MUSTLOCK(src))
379 SDL_LockSurface(src);
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)
389 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
400 mapped = *(Uint16 *)pixel;
403 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
404 mapped |= pixel[0] << 16;
405 mapped |= pixel[1] << 8;
406 mapped |= pixel[2] << 0;
408 mapped |= pixel[0] << 0;
409 mapped |= pixel[1] << 8;
410 mapped |= pixel[2] << 16;
414 mapped = *(Uint32 *)pixel;
417 Uint8 red, green, blue, alpha;
418 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
422 int redsum = red_channel[loc] + (red * alpha >> 8);
423 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
427 int greensum = green_channel[loc] + (green * alpha >> 8);
428 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
432 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
433 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
436 pixel += src->pitch - src_rect->w * bpp;
437 loc += width - src_rect->w;
439 if(SDL_MUSTLOCK(src))
441 SDL_UnlockSurface(src);
446 SDLLightmap::draw_surface(const DrawingRequest& request)
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)
453 //FIXME: support parameters request.alpha, request.angle, request.blend
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());
459 DrawingEffect effect = request.drawing_effect;
460 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
462 SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
464 // get and check SDL_Surface
465 if (transform == 0) {
466 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
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);
478 SDLLightmap::draw_surface_part(const DrawingRequest& request)
481 const SurfacePartRequest* surfacepartrequest
482 = (SurfacePartRequest*) request.request_data;
484 const Surface* surface = surfacepartrequest->surface;
485 boost::shared_ptr<SDLTexture> sdltexture = boost::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
487 DrawingEffect effect = request.drawing_effect;
488 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
490 SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
492 // get and check SDL_Surface
493 if (transform == 0) {
494 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
499 if (effect == HORIZONTAL_FLIP)
501 ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
505 ox = surface->get_x();
507 if (effect == VERTICAL_FLIP)
509 oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
513 oy = surface->get_y();
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);
528 SDLLightmap::draw_gradient(const DrawingRequest& request)
530 const GradientRequest* gradientrequest
531 = (GradientRequest*) request.request_data;
532 const Color& top = gradientrequest->top;
533 const Color& bottom = gradientrequest->bottom;
536 for(int y = 0;y < height;++y)
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++) {
545 int redsum = red_channel[loc] + (red * alpha >> 8);
546 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
550 int greensum = green_channel[loc] + (green * alpha >> 8);
551 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
555 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
556 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
563 SDLLightmap::draw_filled_rect(const DrawingRequest& request)
565 const FillRectRequest* fillrectrequest
566 = (FillRectRequest*) request.request_data;
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)
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;
584 int redsum = red_channel[loc] + red;
585 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
589 int greensum = green_channel[loc] + green;
590 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
594 int bluesum = blue_channel[loc] + blue;
595 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
602 SDLLightmap::get_light(const DrawingRequest& request) const
604 const GetLightRequest* getlightrequest
605 = (GetLightRequest*) request.request_data;
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);