diff --git a/client/renderSDL/CBitmapFont.cpp b/client/renderSDL/CBitmapFont.cpp index 36a29d174..9b755680d 100644 --- a/client/renderSDL/CBitmapFont.cpp +++ b/client/renderSDL/CBitmapFont.cpp @@ -125,7 +125,7 @@ void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & char posX += character.leftOffset; - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); + CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface); uint8_t bpp = surface->format->BytesPerPixel; diff --git a/client/renderSDL/CBitmapHanFont.cpp b/client/renderSDL/CBitmapHanFont.cpp index ac1684185..5476d823f 100644 --- a/client/renderSDL/CBitmapHanFont.cpp +++ b/client/renderSDL/CBitmapHanFont.cpp @@ -41,7 +41,7 @@ void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex, Rect clipRect; CSDL_Ext::getClipRect(surface, clipRect); - CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0); + CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface); uint8_t bpp = surface->format->BytesPerPixel; // start of line, may differ from 0 due to end of surface or clipped surface diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index 88e52622c..6428da2c8 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -142,7 +142,7 @@ std::shared_ptr SDLImageConst::scaleFast(const Point & size) cons float scaleX = float(size.x) / dimensions().x; float scaleY = float(size.y) / dimensions().y; - auto scaled = CSDL_Ext::scaleSurfaceFast(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); + auto scaled = CSDL_Ext::scaleSurface(surf, (int)(surf->w * scaleX), (int)(surf->h * scaleY)); if (scaled->format && scaled->format->palette) // fix color keying, because SDL loses it at this point CSDL_Ext::setColorKey(scaled, scaled->format->palette->colors[0]); diff --git a/client/renderSDL/SDL_Extensions.cpp b/client/renderSDL/SDL_Extensions.cpp index d5426089a..9a233517e 100644 --- a/client/renderSDL/SDL_Extensions.cpp +++ b/client/renderSDL/SDL_Extensions.cpp @@ -337,15 +337,16 @@ int CSDL_Ext::blit8bppAlphaTo24bppT(const SDL_Surface * src, const Rect & srcRec uint8_t *colory = (uint8_t*)src->pixels + srcy*src->pitch + srcx; uint8_t *py = (uint8_t*)dst->pixels + dstRect->y*dst->pitch + dstRect->x*bpp; - for(int y=h; y; y--, colory+=src->pitch, py+=dst->pitch) + for(int y=0; ypitch, py+=dst->pitch) { uint8_t *color = colory; uint8_t *p = py; - for(int x = w; x; x--) + for(int x = 0; x < w; ++x) { const SDL_Color &tbc = colors[*color++]; //color to blit - ColorPutter::PutColorAlphaSwitch(p, tbc.r, tbc.g, tbc.b, tbc.a); + ColorPutter::PutColorAlphaSwitch(p, tbc.r, tbc.g, tbc.b, tbc.a); + p += bpp; } } SDL_UnlockSurface(dst); @@ -422,7 +423,7 @@ static void drawLineX(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S uint8_t a = vstd::lerp(color1.a, color2.a, f); uint8_t *p = CSDL_Ext::getPxPtr(sur, x, y); - ColorPutter<4, 0>::PutColor(p, r,g,b,a); + ColorPutter<4>::PutColor(p, r,g,b,a); } } @@ -440,7 +441,7 @@ static void drawLineY(SDL_Surface * sur, int x1, int y1, int x2, int y2, const S uint8_t a = vstd::lerp(color1.a, color2.a, f); uint8_t *p = CSDL_Ext::getPxPtr(sur, x, y); - ColorPutter<4, 0>::PutColor(p, r,g,b,a); + ColorPutter<4>::PutColor(p, r,g,b,a); } } @@ -453,7 +454,7 @@ void CSDL_Ext::drawLine(SDL_Surface * sur, const Point & from, const Point & des if ( width == 0 && height == 0) { uint8_t *p = CSDL_Ext::getPxPtr(sur, from.x, from.y); - ColorPutter<4, 0>::PutColorAlpha(p, color1); + ColorPutter<4>::PutColorAlpha(p, color1); return; } @@ -524,42 +525,18 @@ void CSDL_Ext::drawBorder( SDL_Surface * sur, const Rect &r, const SDL_Color &co drawBorder(sur, r.x, r.y, r.w, r.h, color, depth); } -CSDL_Ext::TColorPutter CSDL_Ext::getPutterFor(SDL_Surface * const &dest, int incrementing) +CSDL_Ext::TColorPutter CSDL_Ext::getPutterFor(SDL_Surface * const &dest) { -#define CASE_BPP(BytesPerPixel) \ -case BytesPerPixel: \ - if(incrementing > 0) \ - return ColorPutter::PutColor; \ - else if(incrementing == 0) \ - return ColorPutter::PutColor; \ - else \ - return ColorPutter::PutColor;\ - break; - switch(dest->format->BytesPerPixel) { - CASE_BPP(2) - CASE_BPP(3) - CASE_BPP(4) + case 3: + return ColorPutter<3>::PutColor; + case 4: + return ColorPutter<4>::PutColor; default: logGlobal->error("%d bpp is not supported!", (int)dest->format->BitsPerPixel); return nullptr; } - -} - -CSDL_Ext::TColorPutterAlpha CSDL_Ext::getPutterAlphaFor(SDL_Surface * const &dest, int incrementing) -{ - switch(dest->format->BytesPerPixel) - { - CASE_BPP(2) - CASE_BPP(3) - CASE_BPP(4) - default: - logGlobal->error("%d bpp is not supported!", (int)dest->format->BitsPerPixel); - return nullptr; - } -#undef CASE_BPP } uint8_t * CSDL_Ext::getPxPtr(const SDL_Surface * const &srf, const int x, const int y) @@ -590,11 +567,10 @@ bool CSDL_Ext::isTransparent( SDL_Surface * srf, int x, int y ) void CSDL_Ext::putPixelWithoutRefresh(SDL_Surface *ekran, const int & x, const int & y, const uint8_t & R, const uint8_t & G, const uint8_t & B, uint8_t A) { uint8_t *p = getPxPtr(ekran, x, y); - getPutterFor(ekran, false)(p, R, G, B); + getPutterFor(ekran)(p, R, G, B); switch(ekran->format->BytesPerPixel) { - case 2: Channels::px<2>::a.set(p, A); break; case 3: Channels::px<3>::a.set(p, A); break; case 4: Channels::px<4>::a.set(p, A); break; } @@ -638,126 +614,24 @@ void CSDL_Ext::convertToGrayscale( SDL_Surface * surf, const Rect & rect ) { switch(surf->format->BytesPerPixel) { - case 2: convertToGrayscaleBpp<2>(surf, rect); break; case 3: convertToGrayscaleBpp<3>(surf, rect); break; case 4: convertToGrayscaleBpp<4>(surf, rect); break; } } -template -void scaleSurfaceFastInternal(SDL_Surface *surf, SDL_Surface *ret) -{ - const float factorX = static_cast(surf->w) / static_cast(ret->w); - const float factorY = static_cast(surf->h) / static_cast(ret->h); - - for(int y = 0; y < ret->h; y++) - { - for(int x = 0; x < ret->w; x++) - { - //coordinates we want to calculate - auto origX = static_cast(floor(factorX * x)); - auto origY = static_cast(floor(factorY * y)); - - // Get pointers to source pixels - uint8_t *srcPtr = (uint8_t*)surf->pixels + origY * surf->pitch + origX * bpp; - uint8_t *destPtr = (uint8_t*)ret->pixels + y * ret->pitch + x * bpp; - - memcpy(destPtr, srcPtr, bpp); - } - } -} - -SDL_Surface * CSDL_Ext::scaleSurfaceFast(SDL_Surface *surf, int width, int height) -{ - if (!surf || !width || !height) - return nullptr; - - //Same size? return copy - this should more be faster - if (width == surf->w && height == surf->h) - return copySurface(surf); - - SDL_Surface *ret = newSurface(width, height, surf); - - switch(surf->format->BytesPerPixel) - { - case 1: scaleSurfaceFastInternal<1>(surf, ret); break; - case 2: scaleSurfaceFastInternal<2>(surf, ret); break; - case 3: scaleSurfaceFastInternal<3>(surf, ret); break; - case 4: scaleSurfaceFastInternal<4>(surf, ret); break; - } - return ret; -} - -template -void scaleSurfaceInternal(SDL_Surface *surf, SDL_Surface *ret) -{ - const float factorX = float(surf->w - 1) / float(ret->w), - factorY = float(surf->h - 1) / float(ret->h); - - for(int y = 0; y < ret->h; y++) - { - for(int x = 0; x < ret->w; x++) - { - //coordinates we want to interpolate - float origX = factorX * x, - origY = factorY * y; - - float x1 = floor(origX), x2 = floor(origX+1), - y1 = floor(origY), y2 = floor(origY+1); - //assert( x1 >= 0 && y1 >= 0 && x2 < surf->w && y2 < surf->h);//All pixels are in range - - // Calculate weights of each source pixel - float w11 = ((origX - x1) * (origY - y1)); - float w12 = ((origX - x1) * (y2 - origY)); - float w21 = ((x2 - origX) * (origY - y1)); - float w22 = ((x2 - origX) * (y2 - origY)); - //assert( w11 + w12 + w21 + w22 > 0.99 && w11 + w12 + w21 + w22 < 1.01);//total weight is ~1.0 - - // Get pointers to source pixels - uint8_t *p11 = (uint8_t*)surf->pixels + int(y1) * surf->pitch + int(x1) * bpp; - uint8_t *p12 = p11 + bpp; - uint8_t *p21 = p11 + surf->pitch; - uint8_t *p22 = p21 + bpp; - // Calculate resulting channels -#define PX(X, PTR) Channels::px::X.get(PTR) - int resR = static_cast(PX(r, p11) * w11 + PX(r, p12) * w12 + PX(r, p21) * w21 + PX(r, p22) * w22); - int resG = static_cast(PX(g, p11) * w11 + PX(g, p12) * w12 + PX(g, p21) * w21 + PX(g, p22) * w22); - int resB = static_cast(PX(b, p11) * w11 + PX(b, p12) * w12 + PX(b, p21) * w21 + PX(b, p22) * w22); - int resA = static_cast(PX(a, p11) * w11 + PX(a, p12) * w12 + PX(a, p21) * w21 + PX(a, p22) * w22); - //assert(resR < 256 && resG < 256 && resB < 256 && resA < 256); -#undef PX - uint8_t *dest = (uint8_t*)ret->pixels + y * ret->pitch + x * bpp; - Channels::px::r.set(dest, resR); - Channels::px::g.set(dest, resG); - Channels::px::b.set(dest, resB); - Channels::px::a.set(dest, resA); - } - } -} - // scaling via bilinear interpolation algorithm. // NOTE: best results are for scaling in range 50%...200%. // And upscaling looks awful right now - should be fixed somehow -SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface *surf, int width, int height) +SDL_Surface * CSDL_Ext::scaleSurface(SDL_Surface * surf, int width, int height) { - if (!surf || !width || !height) + if(!surf || !width || !height) return nullptr; - if (surf->format->palette) - return scaleSurfaceFast(surf, width, height); + SDL_Surface * intermediate = SDL_ConvertSurface(surf, screen->format, 0); + SDL_Surface * ret = newSurface(width, height, intermediate); - //Same size? return copy - this should more be faster - if (width == surf->w && height == surf->h) - return copySurface(surf); - - SDL_Surface *ret = newSurface(width, height, surf); - - switch(surf->format->BytesPerPixel) - { - case 2: scaleSurfaceInternal<2>(surf, ret); break; - case 3: scaleSurfaceInternal<3>(surf, ret); break; - case 4: scaleSurfaceInternal<4>(surf, ret); break; - } + SDL_SoftStretchLinear(intermediate, nullptr, ret, nullptr); + SDL_FreeSurface(intermediate); return ret; } @@ -851,7 +725,5 @@ void CSDL_Ext::getClipRect(SDL_Surface * src, Rect & other) other = CSDL_Ext::fromSDL(rect); } -template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<2>(int, int); template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<3>(int, int); template SDL_Surface * CSDL_Ext::createSurfaceWithBpp<4>(int, int); - diff --git a/client/renderSDL/SDL_Extensions.h b/client/renderSDL/SDL_Extensions.h index 8e39ee8ac..ec3deeecc 100644 --- a/client/renderSDL/SDL_Extensions.h +++ b/client/renderSDL/SDL_Extensions.h @@ -73,8 +73,7 @@ using TColorPutterAlpha = void (*)(uint8_t *&, const uint8_t &, const uint8_t &, bool isTransparent(SDL_Surface * srf, const Point & position); //checks if surface is transparent at given position uint8_t * getPxPtr(const SDL_Surface * const & srf, const int x, const int y); - TColorPutter getPutterFor(SDL_Surface * const & dest, int incrementing); //incrementing: -1, 0, 1 - TColorPutterAlpha getPutterAlphaFor(SDL_Surface * const & dest, int incrementing); //incrementing: -1, 0, 1 + TColorPutter getPutterFor(SDL_Surface * const & dest); template int blit8bppAlphaTo24bppT(const SDL_Surface * src, const Rect & srcRect, SDL_Surface * dst, const Point & dstPoint); //blits 8 bpp surface with alpha channel to 24 bpp surface @@ -93,10 +92,7 @@ using TColorPutterAlpha = void (*)(uint8_t *&, const uint8_t &, const uint8_t &, template SDL_Surface * createSurfaceWithBpp(int width, int height); //create surface with give bits per pixels value - //scale surface to required size. - //nearest neighbour algorithm - SDL_Surface * scaleSurfaceFast(SDL_Surface * surf, int width, int height); - // bilinear filtering. Uses fallback to scaleSurfaceFast in case of indexed surfaces + // bilinear filtering. Always returns rgba surface SDL_Surface * scaleSurface(SDL_Surface * surf, int width, int height); template diff --git a/client/renderSDL/SDL_PixelAccess.h b/client/renderSDL/SDL_PixelAccess.h index ddd91a663..2cf41ff28 100644 --- a/client/renderSDL/SDL_PixelAccess.h +++ b/client/renderSDL/SDL_PixelAccess.h @@ -109,58 +109,29 @@ namespace Channels }; #endif - - template<> - struct px<2> - { - static channel_subpx<5, 0xF800, 11> r; - static channel_subpx<6, 0x07E0, 5 > g; - static channel_subpx<5, 0x001F, 0 > b; - static channel_empty a; - }; } -template +template struct ColorPutter { static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B); static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); static STRONG_INLINE void PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); - static STRONG_INLINE void PutColor(uint8_t *&ptr, const SDL_Color & Color); static STRONG_INLINE void PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count); }; -template -struct ColorPutter<2, incrementPtr> -{ - static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B); - static STRONG_INLINE void PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); - static STRONG_INLINE void PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A); - static STRONG_INLINE void PutColor(uint8_t *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color); - static STRONG_INLINE void PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count); -}; - -template -STRONG_INLINE void ColorPutter::PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color) +template +STRONG_INLINE void ColorPutter::PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color) { PutColor(ptr, Color.r, Color.g, Color.b, Color.a); } -template -STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const SDL_Color & Color) -{ - PutColor(ptr, Color.r, Color.g, Color.b); -} - -template -STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) +template +STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { switch (A) { case 0: - ptr += bpp * incrementPtr; return; case 255: PutColor(ptr, R, G, B); @@ -177,124 +148,19 @@ STRONG_INLINE void ColorPutter::PutColorAlphaSwitch(uint8_t * } } -template -STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) +template +STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) { PutColor(ptr, ((((uint32_t)R - (uint32_t)Channels::px::r.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::r.get(ptr), ((((uint32_t)G - (uint32_t)Channels::px::g.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::g.get(ptr), ((((uint32_t)B - (uint32_t)Channels::px::b.get(ptr))*(uint32_t)A) >> 8 ) + (uint32_t)Channels::px::b.get(ptr)); } - -template -STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B) +template +STRONG_INLINE void ColorPutter::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B) { - static_assert(incrementPtr >= -1 && incrementPtr <= +1, "Invalid incrementPtr value!"); - - if (incrementPtr < 0) - ptr -= bpp; - Channels::px::r.set(ptr, R); Channels::px::g.set(ptr, G); Channels::px::b.set(ptr, B); Channels::px::a.set(ptr, 255); - - if (incrementPtr > 0) - ptr += bpp; - -} - -template -STRONG_INLINE void ColorPutter::PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count) -{ - if (count) - { - uint8_t *pixel = ptr; - PutColor(ptr, Color.r, Color.g, Color.b); - - for (size_t i=0; i -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B) -{ - if(incrementPtr == -1) - ptr -= 2; - - auto * const px = (uint16_t *)ptr; - *px = (B>>3) + ((G>>2) << 5) + ((R>>3) << 11); //drop least significant bits of 24 bpp encoded color - - if(incrementPtr == 1) - ptr += 2; //bpp -} - -template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlphaSwitch(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) -{ - switch (A) - { - case 0: - ptr += 2 * incrementPtr; - return; - case 255: - PutColor(ptr, R, G, B); - return; - default: - PutColor(ptr, R, G, B, A); - return; - } -} - -template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const uint8_t & R, const uint8_t & G, const uint8_t & B, const uint8_t & A) -{ - const int rbit = 5, gbit = 6, bbit = 5; //bits per color - const int rmask = 0xF800, gmask = 0x7E0, bmask = 0x1F; - const int rshift = 11, gshift = 5, bshift = 0; - - const uint8_t r5 = (*((uint16_t *)ptr) & rmask) >> rshift, - b5 = (*((uint16_t *)ptr) & bmask) >> bshift, - g5 = (*((uint16_t *)ptr) & gmask) >> gshift; - - const uint32_t r8 = (r5 << (8 - rbit)) | (r5 >> (2*rbit - 8)), - g8 = (g5 << (8 - gbit)) | (g5 >> (2*gbit - 8)), - b8 = (b5 << (8 - bbit)) | (b5 >> (2*bbit - 8)); - - PutColor(ptr, - (((R-r8)*A) >> 8) + r8, - (((G-g8)*A) >> 8) + g8, - (((B-b8)*A) >> 8) + b8); -} - -template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorAlpha(uint8_t *&ptr, const SDL_Color & Color) -{ - PutColor(ptr, Color.r, Color.g, Color.b, Color.a); -} - -template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColor(uint8_t *&ptr, const SDL_Color & Color) -{ - PutColor(ptr, Color.r, Color.g, Color.b); -} - -template -STRONG_INLINE void ColorPutter<2, incrementPtr>::PutColorRow(uint8_t *&ptr, const SDL_Color & Color, size_t count) -{ - //drop least significant bits of 24 bpp encoded color - uint16_t pixel = (Color.b>>3) + ((Color.g>>2) << 5) + ((Color.r>>3) << 11); - - for (size_t i=0; i