X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fvideo%2Fsdl_lightmap.cpp;h=51e13b937908f3c35985bd7b879e0c4a8555338c;hb=c3c41a343669d375aaa674c7f3ac35f08f24703e;hp=0d19c489fe821b472418b59410fa3fb8f513f64f;hpb=20efd7620620892d92b1c7df124c3a0c8df22a82;p=supertux.git diff --git a/src/video/sdl_lightmap.cpp b/src/video/sdl_lightmap.cpp index 0d19c489f..51e13b937 100644 --- a/src/video/sdl_lightmap.cpp +++ b/src/video/sdl_lightmap.cpp @@ -30,6 +30,7 @@ #include "glutil.hpp" #include "sdl_lightmap.hpp" #include "sdl_texture.hpp" +#include "sdl_surface_data.hpp" #include "drawing_context.hpp" #include "drawing_request.hpp" #include "renderer.hpp" @@ -47,8 +48,29 @@ namespace SDL { screen = SDL_GetVideoSurface(); - width = screen->w; - height = screen->h; + //float xfactor = 1.0f; // FIXME: (float) config->screenwidth / SCREEN_WIDTH; + //float yfactor = 1.0f; // FIXME: (float) config->screenheight / SCREEN_HEIGHT; + + numerator = 1; + denominator = 1; + + /* FIXME: + if(xfactor < yfactor) + { + numerator = config->screenwidth; + denominator = SCREEN_WIDTH; + } + else + { + numerator = config->screenheight; + denominator = SCREEN_HEIGHT; + } + */ + + LIGHTMAP_DIV = 8 * numerator / denominator; + + width = screen->w / LIGHTMAP_DIV; + height = screen->h / LIGHTMAP_DIV; red_channel = (Uint8 *)malloc(width * height * sizeof(Uint8)); green_channel = (Uint8 *)malloc(width * height * sizeof(Uint8)); @@ -75,19 +97,241 @@ namespace SDL { } +//#define BILINEAR + +#ifdef BILINEAR + namespace + { + void merge(Uint8 color[3], Uint8 color0[3], Uint8 color1[3], int rem, int total) + { + color[0] = (color0[0] * (total - rem) + color1[0] * rem) / total; + color[1] = (color0[1] * (total - rem) + color1[1] * rem) / total; + color[2] = (color0[2] * (total - rem) + color1[2] * rem) / total; + } + } +#endif + void Lightmap::do_draw() { // FIXME: This is really slow - int bpp = screen->format->BytesPerPixel; - for(int y = 0;y < height;y++) { - for(int x = 0;x < width;x++) { - int loc = y * width + x; - if(red_channel[loc] == 255 && green_channel[loc] == 255 && blue_channel[loc] == 255) + if(LIGHTMAP_DIV == 1) + { + int bpp = screen->format->BytesPerPixel; + if(SDL_MUSTLOCK(screen)) + { + SDL_LockSurface(screen); + } + Uint8 *pixel = (Uint8 *) screen->pixels; + int loc = 0; + for(int y = 0;y < height;y++) { + for(int x = 0;x < width;x++, pixel += bpp, loc++) { + if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff) + { + continue; + } + Uint32 mapped = 0; + switch(bpp) { + case 1: + mapped = *pixel; + break; + case 2: + mapped = *(Uint16 *)pixel; + break; + case 3: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + mapped |= pixel[0] << 16; + mapped |= pixel[1] << 8; + mapped |= pixel[2] << 0; +#else + mapped |= pixel[0] << 0; + mapped |= pixel[1] << 8; + mapped |= pixel[2] << 16; +#endif + break; + case 4: + mapped = *(Uint32 *)pixel; + break; + } + Uint8 red, green, blue, alpha; + SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha); + red = (red * red_channel[loc]) >> 8; + green = (green * green_channel[loc]) >> 8; + blue = (blue * blue_channel[loc]) >> 8; + mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha); + switch(bpp) { + case 1: + *pixel = mapped; + break; + case 2: + *(Uint16 *)pixel = mapped; + break; + case 3: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + pixel[0] = (mapped >> 16) & 0xff; + pixel[1] = (mapped >> 8) & 0xff; + pixel[2] = (mapped >> 0) & 0xff; +#else + pixel[0] = (mapped >> 0) & 0xff; + pixel[1] = (mapped >> 8) & 0xff; + pixel[2] = (mapped >> 16) & 0xff; +#endif + break; + case 4: + *(Uint32 *)pixel = mapped; + break; + } + } + pixel += screen->pitch - width * bpp; + } + if(SDL_MUSTLOCK(screen)) + { + SDL_UnlockSurface(screen); + } + } + else + { + int bpp = screen->format->BytesPerPixel; + if(SDL_MUSTLOCK(screen)) + { + SDL_LockSurface(screen); + } + Uint8 *div_pixel = (Uint8 *) screen->pixels; + int loc = 0; + for(int y = 0;y < height;y++) { + for(int x = 0;x < width;x++, div_pixel += bpp * LIGHTMAP_DIV, loc++) { + if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff) + { + continue; + } + Uint8 *pixel = div_pixel; + for(int div_y = 0;div_y < LIGHTMAP_DIV;div_y++) { + for(int div_x = 0;div_x < LIGHTMAP_DIV;pixel += bpp, div_x++) { + Uint32 mapped = 0; + switch(bpp) { + case 1: + mapped = *pixel; + break; + case 2: + mapped = *(Uint16 *)pixel; + break; + case 3: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + mapped |= pixel[0] << 16; + mapped |= pixel[1] << 8; + mapped |= pixel[2] << 0; +#else + mapped |= pixel[0] << 0; + mapped |= pixel[1] << 8; + mapped |= pixel[2] << 16; +#endif + break; + case 4: + mapped = *(Uint32 *)pixel; + break; + } + Uint8 red, green, blue, alpha; + SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha); + +#ifdef BILINEAR + int xinc = (x + 1 != width ? 1 : 0); + int yinc = (y + 1 != height ? width : 0); + Uint8 color00[3], color01[3], color10[3], color11[3]; + { + color00[0] = red_channel[loc]; + color00[1] = green_channel[loc]; + color00[2] = blue_channel[loc]; + } + { + color01[0] = red_channel[loc + xinc]; + color01[1] = green_channel[loc + xinc]; + color01[2] = blue_channel[loc + xinc]; + } + { + color10[0] = red_channel[loc + yinc]; + color10[1] = green_channel[loc + yinc]; + color10[2] = blue_channel[loc + yinc]; + } + { + color11[0] = red_channel[loc + yinc + xinc]; + color11[1] = green_channel[loc + yinc + xinc]; + color11[2] = blue_channel[loc + yinc + xinc]; + } + Uint8 color0[3], color1[3], color[3]; + merge(color0, color00, color01, div_x, LIGHTMAP_DIV); + merge(color1, color10, color11, div_x, LIGHTMAP_DIV); + merge(color, color0, color1, div_y, LIGHTMAP_DIV); + red = (red * color[0]) >> 8; + green = (green * color[1]) >> 8; + blue = (blue * color[2]) >> 8; +#else + red = (red * red_channel[loc]) >> 8; + green = (green * green_channel[loc]) >> 8; + blue = (blue * blue_channel[loc]) >> 8; +#endif + + mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha); + switch(bpp) { + case 1: + *pixel = mapped; + break; + case 2: + *(Uint16 *)pixel = mapped; + break; + case 3: +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + pixel[0] = (mapped >> 16) & 0xff; + pixel[1] = (mapped >> 8) & 0xff; + pixel[2] = (mapped >> 0) & 0xff; +#else + pixel[0] = (mapped >> 0) & 0xff; + pixel[1] = (mapped >> 8) & 0xff; + pixel[2] = (mapped >> 16) & 0xff; +#endif + break; + case 4: + *(Uint32 *)pixel = mapped; + break; + } + } + pixel += screen->pitch - LIGHTMAP_DIV * bpp; + } + } + div_pixel += (screen->pitch - width * bpp) * LIGHTMAP_DIV; + } + if(SDL_MUSTLOCK(screen)) + { + SDL_UnlockSurface(screen); + } + } + } + + void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty) + { + dstx /= LIGHTMAP_DIV; + dsty /= LIGHTMAP_DIV; + int srcx = src_rect->x / LIGHTMAP_DIV; + int srcy = src_rect->y / LIGHTMAP_DIV; + int blit_width = src_rect->w / LIGHTMAP_DIV; + int blit_height = src_rect->h / LIGHTMAP_DIV; + int bpp = src->format->BytesPerPixel; + if(SDL_MUSTLOCK(src)) + { + SDL_LockSurface(src); + } + Uint8 *pixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp; + int loc = dsty * width + dstx; + for(int y = 0;y < blit_height;y++) { + for(int x = 0;x < blit_width;x++, pixel += bpp * LIGHTMAP_DIV, loc++) { + if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height) + { + continue; + } + if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff) { continue; } - Uint8 *pixel = (Uint8 *) screen->pixels + y * screen->pitch + x * bpp; + Uint32 mapped = 0; switch(bpp) { case 1: @@ -112,55 +356,55 @@ namespace SDL break; } Uint8 red, green, blue, alpha; - SDL_GetRGBA(mapped, screen->format, &red, &green, &blue, &alpha); - red = (red * red_channel[loc]) / 255; - green = (green * green_channel[loc]) / 255; - blue = (blue * blue_channel[loc]) / 255; - mapped = SDL_MapRGBA(screen->format, red, green, blue, alpha); - switch(bpp) { - case 1: - *pixel = mapped; - break; - case 2: - *(Uint16 *)pixel = mapped; - break; - case 3: -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - pixel[0] = (mapped >> 16) & 0xff; - pixel[1] = (mapped >> 8) & 0xff; - pixel[2] = (mapped >> 0) & 0xff; -#else - pixel[0] = (mapped >> 0) & 0xff; - pixel[1] = (mapped >> 8) & 0xff; - pixel[2] = (mapped >> 16) & 0xff; -#endif - break; - case 4: - *(Uint32 *)pixel = mapped; - break; + SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha); + + if(red != 0) + { + int redsum = red_channel[loc] + (red * alpha >> 8); + red_channel[loc] = redsum & ~0xff ? 0xff : redsum; + } + if(green != 0) + { + int greensum = green_channel[loc] + (green * alpha >> 8); + green_channel[loc] = greensum & ~0xff ? 0xff : greensum; + } + if(blue != 0) + { + int bluesum = blue_channel[loc] + (blue * alpha >> 8); + blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum; } } + pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV; + loc += width - blit_width; + } + if(SDL_MUSTLOCK(src)) + { + SDL_UnlockSurface(src); } } - void Lightmap::light_blit(SDL_Surface *src, int dstx, int dsty, - int srcx, int srcy, int blit_width, int blit_height) + /*void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty) { - for(int y = 0;y < blit_height;y++) { - for(int x = 0;x < blit_width;x++) { + int bpp = src->format->BytesPerPixel; + if(SDL_MUSTLOCK(src)) + { + SDL_LockSurface(src); + } + Uint8 *pixel = (Uint8 *) src->pixels + src_rect->y * src->pitch + src_rect->x * bpp; + int loc = dsty * width + dstx; + for(int y = 0;y < src_rect->h;y++) { + for(int x = 0;x < src_rect->w;x++, pixel += bpp, loc++) { if(x + dstx < 0 || y + dsty < 0 || x + dstx >= width || y + dsty >= height) { continue; } - int loc = (y + dsty) * width + (x + dstx); - if(red_channel[loc] == 255 && green_channel[loc] == 255 && blue_channel[loc]) + if(red_channel[loc] == 0xff && green_channel[loc] == 0xff && blue_channel[loc] == 0xff) { continue; } - Uint8 *pixel = (Uint8 *) src->pixels + (y + srcy) * src->pitch + (x + srcx) * src->format->BytesPerPixel; Uint32 mapped = 0; - switch(src->format->BytesPerPixel) { + switch(bpp) { case 1: mapped = *pixel; break; @@ -185,12 +429,30 @@ namespace SDL Uint8 red, green, blue, alpha; SDL_GetRGBA(mapped, src->format, &red, &green, &blue, &alpha); - red_channel[loc] = std::min(red_channel[loc] + (red * alpha / 255), 255); - green_channel[loc] = std::min(green_channel[loc] + (green * alpha / 255), 255); - blue_channel[loc] = std::min(blue_channel[loc] + (blue * alpha / 255), 255); + if(red != 0) + { + int redsum = red_channel[loc] + (red * alpha >> 8); + red_channel[loc] = redsum & ~0xff ? 0xff : redsum; + } + if(green != 0) + { + int greensum = green_channel[loc] + (green * alpha >> 8); + green_channel[loc] = greensum & ~0xff ? 0xff : greensum; + } + if(blue != 0) + { + int bluesum = blue_channel[loc] + (blue * alpha >> 8); + blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum; + } } + pixel += src->pitch - src_rect->w * bpp; + loc += width - src_rect->w; } - } + if(SDL_MUSTLOCK(src)) + { + SDL_UnlockSurface(src); + } + }*/ void Lightmap::draw_surface(const DrawingRequest& request) @@ -203,6 +465,8 @@ namespace SDL const Surface* surface = (const Surface*) request.request_data; SDL::Texture *sdltexture = dynamic_cast(surface->get_texture()); + SDL::SurfaceData *surface_data = reinterpret_cast(surface->get_surface_data()); + DrawingEffect effect = request.drawing_effect; if (surface->get_flipx()) effect = HORIZONTAL_FLIP; @@ -214,45 +478,10 @@ namespace SDL return; } - int ox, oy; - if (effect == HORIZONTAL_FLIP) - { - ox = sdltexture->get_texture_width() - surface->get_x() - surface->get_width(); - } - else - { - ox = surface->get_x(); - } - if (effect == VERTICAL_FLIP) - { - oy = sdltexture->get_texture_height() - surface->get_y() - surface->get_height(); - } - else - { - oy = surface->get_y(); - } - - int numerator, denominator; - float xfactor = (float) config->screenwidth / SCREEN_WIDTH; - float yfactor = (float) config->screenheight / SCREEN_HEIGHT; - if(xfactor < yfactor) - { - numerator = config->screenwidth; - denominator = SCREEN_WIDTH; - } - else - { - numerator = config->screenheight; - denominator = SCREEN_HEIGHT; - } - + SDL_Rect *src_rect = surface_data->get_src_rect(effect); int dstx = (int) request.pos.x * numerator / denominator; int dsty = (int) request.pos.y * numerator / denominator; - int srcx = ox * numerator / denominator; - int srcy = oy * numerator / denominator; - int blit_width = surface->get_width() * numerator / denominator; - int blit_height = surface->get_height() * numerator / denominator; - light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height); + light_blit(transform, src_rect, dstx, dsty); } void @@ -263,6 +492,7 @@ namespace SDL const Surface* surface = surfacepartrequest->surface; SDL::Texture *sdltexture = dynamic_cast(surface->get_texture()); + DrawingEffect effect = request.drawing_effect; if (surface->get_flipx()) effect = HORIZONTAL_FLIP; @@ -292,27 +522,14 @@ namespace SDL oy = surface->get_y(); } - int numerator, denominator; - float xfactor = (float) config->screenwidth / SCREEN_WIDTH; - float yfactor = (float) config->screenheight / SCREEN_HEIGHT; - if(xfactor < yfactor) - { - numerator = config->screenwidth; - denominator = SCREEN_WIDTH; - } - else - { - numerator = config->screenheight; - denominator = SCREEN_HEIGHT; - } - + SDL_Rect src_rect; + src_rect.x = (ox + (int) surfacepartrequest->source.x) * numerator / denominator; + src_rect.y = (oy + (int) surfacepartrequest->source.y) * numerator / denominator; + src_rect.w = (int) surfacepartrequest->size.x * numerator / denominator; + src_rect.h = (int) surfacepartrequest->size.y * numerator / denominator; int dstx = (int) request.pos.x * numerator / denominator; int dsty = (int) request.pos.y * numerator / denominator; - int srcx = (ox + (int) surfacepartrequest->source.x) * numerator / denominator; - int srcy = (oy + (int) surfacepartrequest->source.y) * numerator / denominator; - int blit_width = (int) surfacepartrequest->size.x * numerator / denominator; - int blit_height = (int) surfacepartrequest->size.y * numerator / denominator; - light_blit(transform, dstx, dsty, srcx, srcy, blit_width, blit_height); + light_blit(transform, &src_rect, dstx, dsty); } void @@ -323,32 +540,34 @@ namespace SDL const Color& top = gradientrequest->top; const Color& bottom = gradientrequest->bottom; + int loc = 0; for(int y = 0;y < height;++y) { - Uint8 r = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255); - Uint8 g = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255); - Uint8 b = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255); - // FIXME - //Uint8 a = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255); - for(int x = 0;x < width;x++) { - int loc = y * width + x; - red_channel[loc] = std::min(red_channel[loc] + r, 255); - green_channel[loc] = std::min(green_channel[loc] + g, 255); - blue_channel[loc] = std::min(blue_channel[loc] + b, 255); + Uint8 red = (Uint8)((((float)(top.red-bottom.red)/(0-height)) * y + top.red) * 255); + Uint8 green = (Uint8)((((float)(top.green-bottom.green)/(0-height)) * y + top.green) * 255); + Uint8 blue = (Uint8)((((float)(top.blue-bottom.blue)/(0-height)) * y + top.blue) * 255); + Uint8 alpha = (Uint8)((((float)(top.alpha-bottom.alpha)/(0-height)) * y + top.alpha) * 255); + for(int x = 0;x < width;x++, loc++) { + if(red != 0) + { + int redsum = red_channel[loc] + (red * alpha >> 8); + red_channel[loc] = redsum & ~0xff ? 0xff : redsum; + } + if(green != 0) + { + int greensum = green_channel[loc] + (green * alpha >> 8); + green_channel[loc] = greensum & ~0xff ? 0xff : greensum; + } + if(blue != 0) + { + int bluesum = blue_channel[loc] + (blue * alpha >> 8); + blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum; + } } } } void - Lightmap::draw_text(const DrawingRequest& /*request*/) - { - //const TextRequest* textrequest = (TextRequest*) request.request_data; - - //textrequest->font->draw(textrequest->text, request.pos, - // textrequest->alignment, request.drawing_effect, request.alpha); - } - - void Lightmap::draw_filled_rect(const DrawingRequest& request) { const FillRectRequest* fillrectrequest @@ -368,9 +587,21 @@ namespace SDL for(int y = rect_y;y < rect_y + rect_h;y++) { for(int x = rect_x;x < rect_x + rect_w;x++) { int loc = y * width + x; - red_channel[loc] = std::min(red_channel[loc] + red, 255); - green_channel[loc] = std::min(green_channel[loc] + green, 255); - blue_channel[loc] = std::min(blue_channel[loc] + blue, 255); + if(red != 0) + { + int redsum = red_channel[loc] + red; + red_channel[loc] = redsum & ~0xff ? 0xff : redsum; + } + if(green != 0) + { + int greensum = green_channel[loc] + green; + green_channel[loc] = greensum & ~0xff ? 0xff : greensum; + } + if(blue != 0) + { + int bluesum = blue_channel[loc] + blue; + blue_channel[loc] = bluesum & ~0xff ? 0xff : bluesum; + } } } }