1 // $Id: sdl_lightmap.cpp 5063 2007-05-27 11:32:00Z matzeb $
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.
25 #include <SDL_image.h>
31 #include "sdl_lightmap.hpp"
32 #include "sdl_texture.hpp"
33 #include "drawing_context.hpp"
34 #include "drawing_request.hpp"
35 #include "renderer.hpp"
36 #include "surface.hpp"
39 #include "gameconfig.hpp"
40 #include "texture.hpp"
41 #include "texture_manager.hpp"
42 #include "obstack/obstackpp.hpp"
48 screen = SDL_GetVideoSurface();
53 red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
54 green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
55 blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
66 Lightmap::start_draw(const Color &ambient_color)
68 memset(red_channel, (Uint8) (ambient_color.red * 255), width * height * sizeof(Uint8));
69 memset(green_channel, (Uint8) (ambient_color.green * 255), width * height * sizeof(Uint8));
70 memset(blue_channel, (Uint8) (ambient_color.blue * 255), width * height * sizeof(Uint8));
81 // FIXME: This is really slow
82 int bpp = screen->format->BytesPerPixel;
83 Uint8 *pixel = (Uint8 *) screen->pixels;
85 for(int y = 0;y < height;y++) {
86 for(int x = 0;x < width;x++, pixel += bpp, loc++) {
87 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
97 mapped = *(Uint16 *)pixel;
100 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
101 mapped |= pixel[0] << 16;
102 mapped |= pixel[1] << 8;
103 mapped |= pixel[2] << 0;
105 mapped |= pixel[0] << 0;
106 mapped |= pixel[1] << 8;
107 mapped |= pixel[2] << 16;
111 mapped = *(Uint32 *)pixel;
114 Uint8 red, green, blue, alpha;
115 SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
116 red = (red * red_channel[loc]) >> 8;
117 green = (green * green_channel[loc]) >> 8;
118 blue = (blue * blue_channel[loc]) >> 8;
119 mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
125 *(Uint16 *)pixel = mapped;
128 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
129 pixel[0] = (mapped >> 16) & 0xff;
130 pixel[1] = (mapped >> 8) & 0xff;
131 pixel[2] = (mapped >> 0) & 0xff;
133 pixel[0] = (mapped >> 0) & 0xff;
134 pixel[1] = (mapped >> 8) & 0xff;
135 pixel[2] = (mapped >> 16) & 0xff;
139 *(Uint32 *)pixel = mapped;
143 pixel += screen->pitch - width * bpp;
147 void Lightmap::light_blit(SDL_Surface *src, int dstx, int dsty,
148 int srcx, int srcy, int blit_width, int blit_height)
150 int bpp = src->format->BytesPerPixel;
151 Uint8 *pixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
152 int loc = dsty * width + dstx;
153 for(int y = 0;y < blit_height;y++) {
154 for(int x = 0;x < blit_width;x++, pixel += bpp, loc++) {
155 if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
159 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
170 mapped = *(Uint16 *)pixel;
173 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
174 mapped |= pixel[0] << 16;
175 mapped |= pixel[1] << 8;
176 mapped |= pixel[2] << 0;
178 mapped |= pixel[0] << 0;
179 mapped |= pixel[1] << 8;
180 mapped |= pixel[2] << 16;
184 mapped = *(Uint32 *)pixel;
187 Uint8 red, green, blue, alpha;
188 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
192 int redsum = red_channel[loc] + (red * alpha >> 8);
193 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
197 int greensum = green_channel[loc] + (green * alpha >> 8);
198 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
202 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
203 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
206 pixel += src->pitch - blit_width * bpp;
207 loc += width - blit_width;
212 Lightmap::draw_surface(const DrawingRequest& request)
214 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)
218 //FIXME: support parameters request.alpha, request.angle, request.blend
220 const Surface* surface = (const Surface*) request.request_data;
221 SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
222 DrawingEffect effect = request.drawing_effect;
223 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
225 SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
227 // get and check SDL_Surface
228 if (transform == 0) {
229 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
234 if (effect == HORIZONTAL_FLIP)
236 ox = sdltexture->get_texture_width() - surface->get_x() - surface->get_width();
240 ox = surface->get_x();
242 if (effect == VERTICAL_FLIP)
244 oy = sdltexture->get_texture_height() - surface->get_y() - surface->get_height();
248 oy = surface->get_y();
251 int numerator, denominator;
252 float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
253 float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
254 if(xfactor < yfactor)
256 numerator = config->screenwidth;
257 denominator = SCREEN_WIDTH;
261 numerator = config->screenheight;
262 denominator = SCREEN_HEIGHT;
265 int dstx = (int) request.pos.x * numerator / denominator;
266 int dsty = (int) request.pos.y * numerator / denominator;
267 int srcx = ox * numerator / denominator;
268 int srcy = oy * numerator / denominator;
269 int blit_width = surface->get_width() * numerator / denominator;
270 int blit_height = surface->get_height() * numerator / denominator;
271 light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height);
275 Lightmap::draw_surface_part(const DrawingRequest& request)
277 const SurfacePartRequest* surfacepartrequest
278 = (SurfacePartRequest*) request.request_data;
280 const Surface* surface = surfacepartrequest->surface;
281 SDL::Texture *sdltexture = dynamic_cast<SDL::Texture *>(surface->get_texture());
282 DrawingEffect effect = request.drawing_effect;
283 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
285 SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
287 // get and check SDL_Surface
288 if (transform == 0) {
289 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
294 if (effect == HORIZONTAL_FLIP)
296 ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
300 ox = surface->get_x();
302 if (effect == VERTICAL_FLIP)
304 oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
308 oy = surface->get_y();
311 int numerator, denominator;
312 float xfactor = (float) config->screenwidth / SCREEN_WIDTH;
313 float yfactor = (float) config->screenheight / SCREEN_HEIGHT;
314 if(xfactor < yfactor)
316 numerator = config->screenwidth;
317 denominator = SCREEN_WIDTH;
321 numerator = config->screenheight;
322 denominator = SCREEN_HEIGHT;
325 int dstx = (int) request.pos.x * numerator / denominator;
326 int dsty = (int) request.pos.y * numerator / denominator;
327 int srcx = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
328 int srcy = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
329 int blit_width = (int) surfacepartrequest->size.x * numerator / denominator;
330 int blit_height = (int) surfacepartrequest->size.y * numerator / denominator;
331 light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height);
335 Lightmap::draw_gradient(const DrawingRequest& request)
337 const GradientRequest* gradientrequest
338 = (GradientRequest*) request.request_data;
339 const Color& top = gradientrequest->top;
340 const Color& bottom = gradientrequest->bottom;
342 for(int y = 0;y < height;++y)
344 Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255);
345 Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255);
346 Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255);
348 //Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255);
349 for(int x = 0;x < width;x++) {
350 int loc = y * width + x;
351 red_channel[loc] = std::min(red_channel[loc] + r, 255);
352 green_channel[loc] = std::min(green_channel[loc] + g, 255);
353 blue_channel[loc] = std::min(blue_channel[loc] + b, 255);
359 Lightmap::draw_text(const DrawingRequest& /*request*/)
361 //const TextRequest* textrequest = (TextRequest*) request.request_data;
363 //textrequest->font->draw(textrequest->text, request.pos,
364 // textrequest->alignment, request.drawing_effect, request.alpha);
368 Lightmap::draw_filled_rect(const DrawingRequest& request)
370 const FillRectRequest* fillrectrequest
371 = (FillRectRequest*) request.request_data;
373 int rect_x = (int) (request.pos.x * width / SCREEN_WIDTH);
374 int rect_y = (int) (request.pos.y * height / SCREEN_HEIGHT);
375 int rect_w = (int) (fillrectrequest->size.x * width / SCREEN_WIDTH);
376 int rect_h = (int) (fillrectrequest->size.y * height / SCREEN_HEIGHT);
377 Uint8 red = (Uint8) (fillrectrequest->color.red * fillrectrequest->color.alpha * 255);
378 Uint8 green = (Uint8) (fillrectrequest->color.green * fillrectrequest->color.alpha * 255);
379 Uint8 blue = (Uint8) (fillrectrequest->color.blue * fillrectrequest->color.alpha * 255);
380 if(red == 0 && green == 0 && blue == 0)
384 for(int y = rect_y;y < rect_y + rect_h;y++) {
385 for(int x = rect_x;x < rect_x + rect_w;x++) {
386 int loc = y * width + x;
387 red_channel[loc] = std::min(red_channel[loc] + red, 255);
388 green_channel[loc] = std::min(green_channel[loc] + green, 255);
389 blue_channel[loc] = std::min(blue_channel[loc] + blue, 255);
395 Lightmap::get_light(const DrawingRequest& request) const
397 const GetLightRequest* getlightrequest
398 = (GetLightRequest*) request.request_data;
400 int x = (int) (request.pos.x * width / SCREEN_WIDTH);
401 int y = (int) (request.pos.y * height / SCREEN_HEIGHT);
402 int loc = y * width + x;
403 *(getlightrequest->color_ptr) = Color(((float)red_channel[loc])/255, ((float)green_channel[loc])/255, ((float)blue_channel[loc])/255);