00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <iostream>
00018
00019 #include "video/sdl/sdl_lightmap.hpp"
00020 #include "video/sdl/sdl_surface_data.hpp"
00021 #include "video/sdl/sdl_texture.hpp"
00022
00023 SDLLightmap::SDLLightmap() :
00024 screen(),
00025 red_channel(),
00026 blue_channel(),
00027 green_channel(),
00028 width(),
00029 height(),
00030 numerator(),
00031 denominator(),
00032 LIGHTMAP_DIV()
00033 {
00034 screen = SDL_GetVideoSurface();
00035
00036
00037
00038
00039 numerator = 1;
00040 denominator = 1;
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055 LIGHTMAP_DIV = 8 * numerator / denominator;
00056
00057 width = screen->w / LIGHTMAP_DIV;
00058 height = screen->h / LIGHTMAP_DIV;
00059
00060 red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
00061 green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
00062 blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8));
00063 }
00064
00065 SDLLightmap::~SDLLightmap()
00066 {
00067 free(red_channel);
00068 free(green_channel);
00069 free(blue_channel);
00070 }
00071
00072 void
00073 SDLLightmap::start_draw(const Color &ambient_color)
00074 {
00075 memset(red_channel, (Uint8) (ambient_color.red * 255), width * height * sizeof(Uint8));
00076 memset(green_channel, (Uint8) (ambient_color.green * 255), width * height * sizeof(Uint8));
00077 memset(blue_channel, (Uint8) (ambient_color.blue * 255), width * height * sizeof(Uint8));
00078 }
00079
00080 void
00081 SDLLightmap::end_draw()
00082 {
00083 }
00084
00085
00086
00087 #ifdef BILINEAR
00088 namespace {
00089
00090 void merge(Uint8 color[3], Uint8 color0[3], Uint8 color1[3], int rem, int total)
00091 {
00092 color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total;
00093 color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total;
00094 color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total;
00095 }
00096
00097 }
00098 #endif
00099
00100 void
00101 SDLLightmap::do_draw()
00102 {
00103
00104 if(LIGHTMAP_DIV == 1)
00105 {
00106 int bpp = screen->format->BytesPerPixel;
00107 if(SDL_MUSTLOCK(screen))
00108 {
00109 SDL_LockSurface(screen);
00110 }
00111 Uint8 *pixel = (Uint8 *) screen->pixels;
00112 int loc = 0;
00113 for(int y = 0;y < height;y++) {
00114 for(int x = 0;x < width;x++, pixel += bpp, loc++) {
00115 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
00116 {
00117 continue;
00118 }
00119 Uint32 mapped = 0;
00120 switch(bpp) {
00121 case 1:
00122 mapped = *pixel;
00123 break;
00124 case 2:
00125 mapped = *(Uint16 *)pixel;
00126 break;
00127 case 3:
00128 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00129 mapped |= pixel[0] << 16;
00130 mapped |= pixel[1] << 8;
00131 mapped |= pixel[2] << 0;
00132 #else
00133 mapped |= pixel[0] << 0;
00134 mapped |= pixel[1] << 8;
00135 mapped |= pixel[2] << 16;
00136 #endif
00137 break;
00138 case 4:
00139 mapped = *(Uint32 *)pixel;
00140 break;
00141 }
00142 Uint8 red, green, blue, alpha;
00143 SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
00144 red = (red * red_channel[loc]) >> 8;
00145 green = (green * green_channel[loc]) >> 8;
00146 blue = (blue * blue_channel[loc]) >> 8;
00147 mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
00148 switch(bpp) {
00149 case 1:
00150 *pixel = mapped;
00151 break;
00152 case 2:
00153 *(Uint16 *)pixel = mapped;
00154 break;
00155 case 3:
00156 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00157 pixel[0] = (mapped >> 16) & 0xff;
00158 pixel[1] = (mapped >> 8) & 0xff;
00159 pixel[2] = (mapped >> 0) & 0xff;
00160 #else
00161 pixel[0] = (mapped >> 0) & 0xff;
00162 pixel[1] = (mapped >> 8) & 0xff;
00163 pixel[2] = (mapped >> 16) & 0xff;
00164 #endif
00165 break;
00166 case 4:
00167 *(Uint32 *)pixel = mapped;
00168 break;
00169 }
00170 }
00171 pixel += screen->pitch - width * bpp;
00172 }
00173 if(SDL_MUSTLOCK(screen))
00174 {
00175 SDL_UnlockSurface(screen);
00176 }
00177 }
00178 else
00179 {
00180 int bpp = screen->format->BytesPerPixel;
00181 if(SDL_MUSTLOCK(screen))
00182 {
00183 SDL_LockSurface(screen);
00184 }
00185 Uint8 *div_pixel = (Uint8 *) screen->pixels;
00186 int loc = 0;
00187 for(int y = 0;y < height;y++) {
00188 for(int x = 0;x < width;x++, div_pixel += bpp * LIGHTMAP_DIV, loc++) {
00189 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
00190 {
00191 continue;
00192 }
00193 Uint8 *pixel = div_pixel;
00194 for(int div_y = 0;div_y < LIGHTMAP_DIV;div_y++) {
00195 for(int div_x = 0;div_x < LIGHTMAP_DIV;pixel += bpp, div_x++) {
00196 Uint32 mapped = 0;
00197 switch(bpp) {
00198 case 1:
00199 mapped = *pixel;
00200 break;
00201 case 2:
00202 mapped = *(Uint16 *)pixel;
00203 break;
00204 case 3:
00205 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00206 mapped |= pixel[0] << 16;
00207 mapped |= pixel[1] << 8;
00208 mapped |= pixel[2] << 0;
00209 #else
00210 mapped |= pixel[0] << 0;
00211 mapped |= pixel[1] << 8;
00212 mapped |= pixel[2] << 16;
00213 #endif
00214 break;
00215 case 4:
00216 mapped = *(Uint32 *)pixel;
00217 break;
00218 }
00219 Uint8 red, green, blue, alpha;
00220 SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha);
00221
00222 #ifdef BILINEAR
00223 int xinc = (x + 1 != width ? 1 : 0);
00224 int yinc = (y + 1 != height ? width : 0);
00225 Uint8 color00[3], color01[3], color10[3], color11[3];
00226 {
00227 color00[0] = red_channel[loc];
00228 color00[1] = green_channel[loc];
00229 color00[2] = blue_channel[loc];
00230 }
00231 {
00232 color01[0] = red_channel[loc + xinc];
00233 color01[1] = green_channel[loc + xinc];
00234 color01[2] = blue_channel[loc + xinc];
00235 }
00236 {
00237 color10[0] = red_channel[loc + yinc];
00238 color10[1] = green_channel[loc + yinc];
00239 color10[2] = blue_channel[loc + yinc];
00240 }
00241 {
00242 color11[0] = red_channel[loc + yinc + xinc];
00243 color11[1] = green_channel[loc + yinc + xinc];
00244 color11[2] = blue_channel[loc + yinc + xinc];
00245 }
00246 Uint8 color0[3], color1[3], color[3];
00247 merge(color0, color00, color01, div_x, LIGHTMAP_DIV);
00248 merge(color1, color10, color11, div_x, LIGHTMAP_DIV);
00249 merge(color, color0, color1, div_y, LIGHTMAP_DIV);
00250 red = (red * color[0]) >> 8;
00251 green = (green * color[1]) >> 8;
00252 blue = (blue * color[2]) >> 8;
00253 #else
00254 red = (red * red_channel[loc]) >> 8;
00255 green = (green * green_channel[loc]) >> 8;
00256 blue = (blue * blue_channel[loc]) >> 8;
00257 #endif
00258
00259 mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha);
00260 switch(bpp) {
00261 case 1:
00262 *pixel = mapped;
00263 break;
00264 case 2:
00265 *(Uint16 *)pixel = mapped;
00266 break;
00267 case 3:
00268 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00269 pixel[0] = (mapped >> 16) & 0xff;
00270 pixel[1] = (mapped >> 8) & 0xff;
00271 pixel[2] = (mapped >> 0) & 0xff;
00272 #else
00273 pixel[0] = (mapped >> 0) & 0xff;
00274 pixel[1] = (mapped >> 8) & 0xff;
00275 pixel[2] = (mapped >> 16) & 0xff;
00276 #endif
00277 break;
00278 case 4:
00279 *(Uint32 *)pixel = mapped;
00280 break;
00281 }
00282 }
00283 pixel += screen->pitch - LIGHTMAP_DIV * bpp;
00284 }
00285 }
00286 div_pixel += (screen->pitch - width * bpp) * LIGHTMAP_DIV;
00287 }
00288 if(SDL_MUSTLOCK(screen))
00289 {
00290 SDL_UnlockSurface(screen);
00291 }
00292 }
00293 }
00294
00295 void
00296 SDLLightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty)
00297 {
00298 dstx /= LIGHTMAP_DIV;
00299 dsty /= LIGHTMAP_DIV;
00300 int srcx = src_rect->x / LIGHTMAP_DIV;
00301 int srcy = src_rect->y / LIGHTMAP_DIV;
00302 int blit_width = src_rect->w / LIGHTMAP_DIV;
00303 int blit_height = src_rect->h / LIGHTMAP_DIV;
00304 int bpp = src->format->BytesPerPixel;
00305 if(SDL_MUSTLOCK(src))
00306 {
00307 SDL_LockSurface(src);
00308 }
00309 Uint8 *pixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp;
00310 int loc = dsty * width + dstx;
00311 for(int y = 0;y < blit_height;y++) {
00312 for(int x = 0;x < blit_width;x++, pixel += bpp * LIGHTMAP_DIV, loc++) {
00313 if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height)
00314 {
00315 continue;
00316 }
00317 if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff)
00318 {
00319 continue;
00320 }
00321
00322 Uint32 mapped = 0;
00323 switch(bpp) {
00324 case 1:
00325 mapped = *pixel;
00326 break;
00327 case 2:
00328 mapped = *(Uint16 *)pixel;
00329 break;
00330 case 3:
00331 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
00332 mapped |= pixel[0] << 16;
00333 mapped |= pixel[1] << 8;
00334 mapped |= pixel[2] << 0;
00335 #else
00336 mapped |= pixel[0] << 0;
00337 mapped |= pixel[1] << 8;
00338 mapped |= pixel[2] << 16;
00339 #endif
00340 break;
00341 case 4:
00342 mapped = *(Uint32 *)pixel;
00343 break;
00344 }
00345 Uint8 red, green, blue, alpha;
00346 SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha);
00347
00348 if(red != 0)
00349 {
00350 int redsum = red_channel[loc] + (red * alpha >> 8);
00351 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
00352 }
00353 if(green != 0)
00354 {
00355 int greensum = green_channel[loc] + (green * alpha >> 8);
00356 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
00357 }
00358 if(blue != 0)
00359 {
00360 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
00361 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
00362 }
00363 }
00364 pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV;
00365 loc += width - blit_width;
00366 }
00367 if(SDL_MUSTLOCK(src))
00368 {
00369 SDL_UnlockSurface(src);
00370 }
00371 }
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 void
00445 SDLLightmap::draw_surface(const DrawingRequest& request)
00446 {
00447 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)
00448 {
00449 return;
00450 }
00451
00452
00453 const Surface* surface = (const Surface*) request.request_data;
00454 boost::shared_ptr<SDLTexture> sdltexture = boost::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
00455 SDLSurfaceData *surface_data = reinterpret_cast<SDLSurfaceData *>(surface->get_surface_data());
00456
00457 DrawingEffect effect = request.drawing_effect;
00458 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
00459
00460 SDL_Surface *transform = sdltexture->get_transform(request.color, effect);
00461
00462
00463 if (transform == 0) {
00464 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
00465 return;
00466 }
00467
00468 SDL_Rect *src_rect = surface_data->get_src_rect(effect);
00469 int dstx = (int) request.pos.x * numerator / denominator;
00470 int dsty = (int) request.pos.y * numerator / denominator;
00471 light_blit(transform, src_rect, dstx, dsty);
00472 }
00473
00474 void
00475 SDLLightmap::draw_surface_part(const DrawingRequest& request)
00476 {
00477 const SurfacePartRequest* surfacepartrequest
00478 = (SurfacePartRequest*) request.request_data;
00479
00480 const Surface* surface = surfacepartrequest->surface;
00481 boost::shared_ptr<SDLTexture> sdltexture = boost::dynamic_pointer_cast<SDLTexture>(surface->get_texture());
00482
00483 DrawingEffect effect = request.drawing_effect;
00484 if (surface->get_flipx()) effect = HORIZONTAL_FLIP;
00485
00486 SDL_Surface *transform = sdltexture->get_transform(Color(1.0, 1.0, 1.0), effect);
00487
00488
00489 if (transform == 0) {
00490 std::cerr << "Warning: Tried to draw NULL surface, skipped draw" << std::endl;
00491 return;
00492 }
00493
00494 int ox, oy;
00495 if (effect == HORIZONTAL_FLIP)
00496 {
00497 ox = sdltexture->get_texture_width() - surface->get_x() - (int) surfacepartrequest->size.x;
00498 }
00499 else
00500 {
00501 ox = surface->get_x();
00502 }
00503 if (effect == VERTICAL_FLIP)
00504 {
00505 oy = sdltexture->get_texture_height() - surface->get_y() - (int) surfacepartrequest->size.y;
00506 }
00507 else
00508 {
00509 oy = surface->get_y();
00510 }
00511
00512 SDL_Rect src_rect;
00513 src_rect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator;
00514 src_rect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator;
00515 src_rect.w = (int) surfacepartrequest->size.x * numerator / denominator;
00516 src_rect.h = (int) surfacepartrequest->size.y * numerator / denominator;
00517 int dstx = (int) request.pos.x * numerator / denominator;
00518 int dsty = (int) request.pos.y * numerator / denominator;
00519 light_blit(transform, &src_rect, dstx, dsty);
00520 }
00521
00522 void
00523 SDLLightmap::draw_gradient(const DrawingRequest& request)
00524 {
00525 const GradientRequest* gradientrequest
00526 = (GradientRequest*) request.request_data;
00527 const Color& top = gradientrequest->top;
00528 const Color& bottom = gradientrequest->bottom;
00529
00530 int loc = 0;
00531 for(int y = 0;y < height;++y)
00532 {
00533 Uint8 red = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255);
00534 Uint8 green = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255);
00535 Uint8 blue = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255);
00536 Uint8 alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255);
00537 for(int x = 0;x < width;x++, loc++) {
00538 if(red != 0)
00539 {
00540 int redsum = red_channel[loc] + (red * alpha >> 8);
00541 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
00542 }
00543 if(green != 0)
00544 {
00545 int greensum = green_channel[loc] + (green * alpha >> 8);
00546 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
00547 }
00548 if(blue != 0)
00549 {
00550 int bluesum = blue_channel[loc] + (blue * alpha >> 8);
00551 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
00552 }
00553 }
00554 }
00555 }
00556
00557 void
00558 SDLLightmap::draw_filled_rect(const DrawingRequest& request)
00559 {
00560 const FillRectRequest* fillrectrequest
00561 = (FillRectRequest*) request.request_data;
00562
00563 int rect_x = (int) (request.pos.x * width / SCREEN_WIDTH);
00564 int rect_y = (int) (request.pos.y * height / SCREEN_HEIGHT);
00565 int rect_w = (int) (fillrectrequest->size.x * width / SCREEN_WIDTH);
00566 int rect_h = (int) (fillrectrequest->size.y * height / SCREEN_HEIGHT);
00567 Uint8 red = (Uint8) (fillrectrequest->color.red * fillrectrequest->color.alpha * 255);
00568 Uint8 green = (Uint8) (fillrectrequest->color.green * fillrectrequest->color.alpha * 255);
00569 Uint8 blue = (Uint8) (fillrectrequest->color.blue * fillrectrequest->color.alpha * 255);
00570 if(red == 0 && green == 0 && blue == 0)
00571 {
00572 return;
00573 }
00574 for(int y = rect_y;y < rect_y + rect_h;y++) {
00575 for(int x = rect_x;x < rect_x + rect_w;x++) {
00576 int loc = y * width + x;
00577 if(red != 0)
00578 {
00579 int redsum = red_channel[loc] + red;
00580 red_channel[loc] = redsum & ~0xff ? 0xff : redsum;
00581 }
00582 if(green != 0)
00583 {
00584 int greensum = green_channel[loc] + green;
00585 green_channel[loc] = greensum & ~0xff ? 0xff : greensum;
00586 }
00587 if(blue != 0)
00588 {
00589 int bluesum = blue_channel[loc] + blue;
00590 blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum;
00591 }
00592 }
00593 }
00594 }
00595
00596 void
00597 SDLLightmap::get_light(const DrawingRequest& request) const
00598 {
00599 const GetLightRequest* getlightrequest
00600 = (GetLightRequest*) request.request_data;
00601
00602 int x = (int) (request.pos.x * width / SCREEN_WIDTH);
00603 int y = (int) (request.pos.y * height / SCREEN_HEIGHT);
00604 int loc = y * width + x;
00605 *(getlightrequest->color_ptr) = Color(((float)red_channel[loc])/255, ((float)green_channel[loc])/255, ((float)blue_channel[loc])/255);
00606 }
00607
00608