From ca967dcf4ee89f99880355be00782d1cd047be6a Mon Sep 17 00:00:00 2001 From: Tim Goya Date: Sat, 18 Aug 2007 22:11:20 +0000 Subject: [PATCH] SDL: Implement lightmaps smaller than the screen size. LIGHTMAP_DIV is calculated such that the resulting lightmap size is or close to 100x75. Hopefully it isn't too grainy, but bilinear filtering is way too slow SVN-Revision: 5144 --- src/video/drawing_context.cpp | 1 - src/video/gl_lightmap.cpp | 1 - src/video/gl_lightmap.hpp | 2 + src/video/sdl_lightmap.cpp | 318 +++++++++++++++++++++++++++++++++++------- src/video/sdl_lightmap.hpp | 1 + src/video/sdl_texture.cpp | 8 ++ 6 files changed, 279 insertions(+), 52 deletions(-) diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 0a6485068..de45b4fc4 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -38,7 +38,6 @@ #include "texture.hpp" #include "texture_manager.hpp" #include "obstack/obstackpp.hpp" -#define LIGHTMAP_DIV 5 static inline int next_po2(int val) { diff --git a/src/video/gl_lightmap.cpp b/src/video/gl_lightmap.cpp index bc4c12b34..537a6a97b 100644 --- a/src/video/gl_lightmap.cpp +++ b/src/video/gl_lightmap.cpp @@ -43,7 +43,6 @@ #include "gl_texture.hpp" #include "texture_manager.hpp" #include "obstack/obstackpp.hpp" -#define LIGHTMAP_DIV 5 namespace { diff --git a/src/video/gl_lightmap.hpp b/src/video/gl_lightmap.hpp index dd5b131d5..cb707099e 100644 --- a/src/video/gl_lightmap.hpp +++ b/src/video/gl_lightmap.hpp @@ -49,6 +49,8 @@ namespace GL void get_light(const DrawingRequest& request) const; private: + static const int LIGHTMAP_DIV = 5; + SDL_Surface* screen; Texture* lightmap; int lightmap_width, lightmap_height; diff --git a/src/video/sdl_lightmap.cpp b/src/video/sdl_lightmap.cpp index 1020d0320..040189cdd 100644 --- a/src/video/sdl_lightmap.cpp +++ b/src/video/sdl_lightmap.cpp @@ -48,9 +48,6 @@ namespace SDL { screen = SDL_GetVideoSurface(); - width = screen->w; - height = screen->h; - float xfactor = (float) config->screenwidth / SCREEN_WIDTH; float yfactor = (float) config->screenheight / SCREEN_HEIGHT; if(xfactor < yfactor) @@ -64,6 +61,11 @@ namespace SDL 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)); blue_channel = (Uint8 *)malloc(width * height * sizeof(Uint8)); @@ -89,19 +91,221 @@ 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; - 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(LIGHTMAP_DIV == 1) + { + int bpp = screen->format->BytesPerPixel; + 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; + } + } + else + { + int bpp = screen->format->BytesPerPixel; + 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; + } + } + } + + 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; + 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; } + Uint32 mapped = 0; switch(bpp) { case 1: @@ -126,39 +330,30 @@ namespace SDL 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; + 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 += screen->pitch - width * bpp; + pixel += (src->pitch - blit_width * bpp) * LIGHTMAP_DIV; + loc += width - blit_width; } } - void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty) + /*void Lightmap::light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty) { int bpp = src->format->BytesPerPixel; Uint8 *pixel = (Uint8 *) src->pixels + src_rect->y * src->pitch + src_rect->x * bpp; @@ -219,7 +414,7 @@ namespace SDL pixel += src->pitch - src_rect->w * bpp; loc += width - src_rect->w; } - } + }*/ void Lightmap::draw_surface(const DrawingRequest& request) @@ -307,18 +502,29 @@ 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; + } } } } @@ -352,9 +558,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; + } } } } diff --git a/src/video/sdl_lightmap.hpp b/src/video/sdl_lightmap.hpp index ab7e1bc8d..fbde750fb 100644 --- a/src/video/sdl_lightmap.hpp +++ b/src/video/sdl_lightmap.hpp @@ -51,6 +51,7 @@ namespace SDL Uint8 *green_channel; int width, height; int numerator, denominator; + int LIGHTMAP_DIV; void light_blit(SDL_Surface *src, SDL_Rect *src_rect, int dstx, int dsty); }; diff --git a/src/video/sdl_texture.cpp b/src/video/sdl_texture.cpp index 2eb5de6cb..2f1bc97dd 100644 --- a/src/video/sdl_texture.cpp +++ b/src/video/sdl_texture.cpp @@ -69,6 +69,14 @@ namespace void getpixel(SDL_Surface *src, int srcx, int srcy, Uint8 color[4]) { int bpp = src->format->BytesPerPixel; + if(srcx == src->w) + { + srcx--; + } + if(srcy == src->h) + { + srcy--; + } Uint8 *srcpixel = (Uint8 *) src->pixels + srcy * src->pitch + srcx * bpp; Uint32 mapped = 0; switch(bpp) { -- 2.11.0