Move blit_surface from gui/widgets/helper.cpp to sdl_utils.cpp
This commit is contained in:
parent
657da51da7
commit
ab74a6bc3c
7 changed files with 139 additions and 135 deletions
|
@ -20,6 +20,7 @@
|
|||
#include "config.hpp"
|
||||
#include "font.hpp"
|
||||
#include "formula.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "image.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/widgets/helper.hpp"
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "log.hpp"
|
||||
#include "marked-up_text.hpp"
|
||||
#include "util.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#define DBG_G LOG_STREAM_INDENT(debug, gui)
|
||||
#define LOG_G LOG_STREAM_INDENT(info, gui)
|
||||
|
|
|
@ -135,136 +135,5 @@ private:
|
|||
|
||||
} // namespace
|
||||
|
||||
//! Replacement for SDL_BlitSurface.
|
||||
//!
|
||||
//! SDL_BlitSurface has problems with blitting partly transparent surfaces so
|
||||
//! this is a replacement. It ignores the SDL_SRCALPHA and SDL_SRCCOLORKEY
|
||||
//! flags. src and dst will have the SDL_RLEACCEL flag removed.
|
||||
//! The return value of SDL_BlistSurface is normally ignored so no return value.
|
||||
//! The rectangles are const and will not be modified.
|
||||
//!
|
||||
//! @param src The surface to blit.
|
||||
//! @param srcrect The size of the surface to blit, only width and height
|
||||
//! are used.
|
||||
//! @param dst The surface to blit on.
|
||||
//! @param dstrect The offset to blit the surface on, only x and y are used.
|
||||
void blit_surface(SDL_Surface* src,
|
||||
const SDL_Rect* srcrect, SDL_Surface* dst, const SDL_Rect* dstrect)
|
||||
{
|
||||
assert(src);
|
||||
assert(dst);
|
||||
assert((src->flags & SDL_RLEACCEL) == 0);
|
||||
assert((dst->flags & SDL_RLEACCEL) == 0);
|
||||
|
||||
// Get the areas to blit
|
||||
SDL_Rect dst_rect = { 0, 0, dst->w, dst->h };
|
||||
if(dstrect) {
|
||||
dst_rect.x = dstrect->x;
|
||||
dst_rect.w -= dstrect->x;
|
||||
|
||||
dst_rect.y = dstrect->y;
|
||||
dst_rect.h -= dstrect->y;
|
||||
|
||||
assert(dst_rect.x >= 0);
|
||||
assert(dst_rect.y >= 0);
|
||||
}
|
||||
|
||||
SDL_Rect src_rect = { 0, 0, src->w, src->h };
|
||||
if(srcrect && srcrect->w && srcrect->h) {
|
||||
src_rect.w = srcrect->w;
|
||||
src_rect.h = srcrect->h;
|
||||
|
||||
assert(src_rect.w <= src->w);
|
||||
assert(src_rect.h <= src->h);
|
||||
}
|
||||
|
||||
// Get the blit size limits.
|
||||
const unsigned width = minimum(src_rect.w, dst_rect.w);
|
||||
const unsigned height = minimum(src_rect.h, dst_rect.h);
|
||||
|
||||
{
|
||||
// Extra scoping used for the surface_lock.
|
||||
surface_lock src_lock(src);
|
||||
surface_lock dst_lock(dst);
|
||||
|
||||
Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
|
||||
Uint32* dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
|
||||
|
||||
for(unsigned y = 0; y < height; ++y) {
|
||||
for(unsigned x = 0; x < width; ++x) {
|
||||
|
||||
// We need to do the blitting using some optimizations
|
||||
// if the src is fully transparent we can ignore this pixel
|
||||
// if the src is fully opaque we can overwrite the destination with this pixel
|
||||
// if the destination is fully transparent we replace us with the source
|
||||
//
|
||||
// We do these optimizations between the extraction of the variables
|
||||
// to avoid creating variables not used (it might save us some cycles).
|
||||
|
||||
const Uint32 src_pixel = src_pixels[(y + src_rect.y) * src->w + (x + src_rect.x)];
|
||||
const Uint8 src_a = (src_pixel & 0xFF000000) >> 24;
|
||||
|
||||
if(!src_a) {
|
||||
// Fully transparent source, ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
const ptrdiff_t dst_offset = (y + dst_rect.y) * dst->w + (x + dst_rect.x);
|
||||
if(src_a == 255) {
|
||||
// Fully opaque source, copy
|
||||
dst_pixels[dst_offset] = src_pixel;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint32 dst_pixel = dst_pixels[dst_offset];
|
||||
Uint8 dst_a = (dst_pixel & 0xFF000000) >> 24;
|
||||
|
||||
if(!dst_a) {
|
||||
// Fully transparent destination, copy
|
||||
dst_pixels[dst_offset] = src_pixel;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint8 src_r = (src_pixel & 0x00FF0000) >> 16;
|
||||
const Uint8 src_g = (src_pixel & 0x0000FF00) >> 8;
|
||||
const Uint8 src_b = src_pixel & 0x000000FF;
|
||||
|
||||
Uint8 dst_r = (dst_pixel & 0x00FF0000) >> 16;
|
||||
Uint8 dst_g = (dst_pixel & 0x0000FF00) >> 8;
|
||||
Uint8 dst_b = dst_pixel & 0x000000FF;
|
||||
|
||||
if(dst_a == 255) {
|
||||
|
||||
// Destination fully opaque blend the source.
|
||||
dst_r = (((src_r - dst_r) * src_a) >> 8 ) + dst_r;
|
||||
dst_g = (((src_g - dst_g) * src_a) >> 8 ) + dst_g;
|
||||
dst_b = (((src_b - dst_b) * src_a) >> 8 ) + dst_b;
|
||||
|
||||
} else {
|
||||
|
||||
// Destination and source party transparent.
|
||||
|
||||
// aquired the data now do the blitting
|
||||
const unsigned tmp_a = 255 - src_a;
|
||||
|
||||
const unsigned tmp_r = 1 + (src_r * src_a) + (dst_r * tmp_a);
|
||||
dst_r = (tmp_r + (tmp_r >> 8)) >> 8;
|
||||
|
||||
const unsigned tmp_g = 1 + (src_g * src_a) + (dst_g * tmp_a);
|
||||
dst_g = (tmp_g + (tmp_g >> 8)) >> 8;
|
||||
|
||||
const unsigned tmp_b = 1 + (src_b * src_a) + (dst_b * tmp_a);
|
||||
dst_b = (tmp_b + (tmp_b >> 8)) >> 8;
|
||||
|
||||
dst_a += (((255 - dst_a) * src_a) >> 8);
|
||||
}
|
||||
|
||||
dst_pixels[dst_offset] = (dst_a << 24) | (dst_r << 16) | (dst_g << 8) | (dst_b);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gui2
|
||||
|
||||
|
|
|
@ -59,10 +59,6 @@ Uint32 decode_colour(const std::string& colour);
|
|||
|
||||
int decode_font_style(const std::string& style);
|
||||
|
||||
//! Replacement for SDL_BlitSurface.
|
||||
void blit_surface(SDL_Surface* src,
|
||||
const SDL_Rect* srcrect, SDL_Surface* dst, const SDL_Rect* dstrect);
|
||||
|
||||
} // namespace gui2
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "log.hpp"
|
||||
#include "serialization/parser.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
|
|
@ -1232,6 +1232,139 @@ surface create_compatible_surface(surface const &surf, int width, int height)
|
|||
surf->format->Rmask,surf->format->Gmask,surf->format->Bmask,surf->format->Amask);
|
||||
}
|
||||
|
||||
//! Replacement for SDL_BlitSurface.
|
||||
//!
|
||||
//! SDL_BlitSurface has problems with blitting partly transparent surfaces so
|
||||
//! this is a replacement. It ignores the SDL_SRCALPHA and SDL_SRCCOLORKEY
|
||||
//! flags. src and dst will have the SDL_RLEACCEL flag removed.
|
||||
//! The return value of SDL_BlistSurface is normally ignored so no return value.
|
||||
//! The rectangles are const and will not be modified.
|
||||
//!
|
||||
//! @param src The surface to blit.
|
||||
//! @param srcrect The size of the surface to blit, only width and height
|
||||
//! are used.
|
||||
//! @param dst The surface to blit on.
|
||||
//! @param dstrect The offset to blit the surface on, only x and y are used.
|
||||
void blit_surface(SDL_Surface* src,
|
||||
const SDL_Rect* srcrect, SDL_Surface* dst, const SDL_Rect* dstrect)
|
||||
{
|
||||
assert(src);
|
||||
assert(dst);
|
||||
assert((src->flags & SDL_RLEACCEL) == 0);
|
||||
assert((dst->flags & SDL_RLEACCEL) == 0);
|
||||
|
||||
// Get the areas to blit
|
||||
SDL_Rect dst_rect = { 0, 0, dst->w, dst->h };
|
||||
if(dstrect) {
|
||||
dst_rect.x = dstrect->x;
|
||||
dst_rect.w -= dstrect->x;
|
||||
|
||||
dst_rect.y = dstrect->y;
|
||||
dst_rect.h -= dstrect->y;
|
||||
|
||||
assert(dst_rect.x >= 0);
|
||||
assert(dst_rect.y >= 0);
|
||||
}
|
||||
|
||||
SDL_Rect src_rect = { 0, 0, src->w, src->h };
|
||||
if(srcrect && srcrect->w && srcrect->h) {
|
||||
src_rect.w = srcrect->w;
|
||||
src_rect.h = srcrect->h;
|
||||
|
||||
assert(src_rect.w <= src->w);
|
||||
assert(src_rect.h <= src->h);
|
||||
}
|
||||
|
||||
// Get the blit size limits.
|
||||
const unsigned width = minimum(src_rect.w, dst_rect.w);
|
||||
const unsigned height = minimum(src_rect.h, dst_rect.h);
|
||||
|
||||
{
|
||||
// Extra scoping used for the surface_lock.
|
||||
surface_lock src_lock(src);
|
||||
surface_lock dst_lock(dst);
|
||||
|
||||
Uint32* const src_pixels = reinterpret_cast<Uint32*>(src_lock.pixels());
|
||||
Uint32* dst_pixels = reinterpret_cast<Uint32*>(dst_lock.pixels());
|
||||
|
||||
for(unsigned y = 0; y < height; ++y) {
|
||||
for(unsigned x = 0; x < width; ++x) {
|
||||
|
||||
// We need to do the blitting using some optimizations
|
||||
// if the src is fully transparent we can ignore this pixel
|
||||
// if the src is fully opaque we can overwrite the destination with this pixel
|
||||
// if the destination is fully transparent we replace us with the source
|
||||
//
|
||||
// We do these optimizations between the extraction of the variables
|
||||
// to avoid creating variables not used (it might save us some cycles).
|
||||
|
||||
const Uint32 src_pixel = src_pixels[(y + src_rect.y) * src->w + (x + src_rect.x)];
|
||||
const Uint8 src_a = (src_pixel & 0xFF000000) >> 24;
|
||||
|
||||
if(!src_a) {
|
||||
// Fully transparent source, ignore
|
||||
continue;
|
||||
}
|
||||
|
||||
const ptrdiff_t dst_offset = (y + dst_rect.y) * dst->w + (x + dst_rect.x);
|
||||
if(src_a == 255) {
|
||||
// Fully opaque source, copy
|
||||
dst_pixels[dst_offset] = src_pixel;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint32 dst_pixel = dst_pixels[dst_offset];
|
||||
Uint8 dst_a = (dst_pixel & 0xFF000000) >> 24;
|
||||
|
||||
if(!dst_a) {
|
||||
// Fully transparent destination, copy
|
||||
dst_pixels[dst_offset] = src_pixel;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Uint8 src_r = (src_pixel & 0x00FF0000) >> 16;
|
||||
const Uint8 src_g = (src_pixel & 0x0000FF00) >> 8;
|
||||
const Uint8 src_b = src_pixel & 0x000000FF;
|
||||
|
||||
Uint8 dst_r = (dst_pixel & 0x00FF0000) >> 16;
|
||||
Uint8 dst_g = (dst_pixel & 0x0000FF00) >> 8;
|
||||
Uint8 dst_b = dst_pixel & 0x000000FF;
|
||||
|
||||
if(dst_a == 255) {
|
||||
|
||||
// Destination fully opaque blend the source.
|
||||
dst_r = (((src_r - dst_r) * src_a) >> 8 ) + dst_r;
|
||||
dst_g = (((src_g - dst_g) * src_a) >> 8 ) + dst_g;
|
||||
dst_b = (((src_b - dst_b) * src_a) >> 8 ) + dst_b;
|
||||
|
||||
} else {
|
||||
|
||||
// Destination and source party transparent.
|
||||
|
||||
// aquired the data now do the blitting
|
||||
const unsigned tmp_a = 255 - src_a;
|
||||
|
||||
const unsigned tmp_r = 1 + (src_r * src_a) + (dst_r * tmp_a);
|
||||
dst_r = (tmp_r + (tmp_r >> 8)) >> 8;
|
||||
|
||||
const unsigned tmp_g = 1 + (src_g * src_a) + (dst_g * tmp_a);
|
||||
dst_g = (tmp_g + (tmp_g >> 8)) >> 8;
|
||||
|
||||
const unsigned tmp_b = 1 + (src_b * src_a) + (dst_b * tmp_a);
|
||||
dst_b = (tmp_b + (tmp_b >> 8)) >> 8;
|
||||
|
||||
dst_a += (((255 - dst_a) * src_a) >> 8);
|
||||
}
|
||||
|
||||
dst_pixels[dst_offset] = (dst_a << 24) | (dst_r << 16) | (dst_g << 8) | (dst_b);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fill_rect_alpha(SDL_Rect &rect, Uint32 colour, Uint8 alpha, surface const &target)
|
||||
{
|
||||
if(alpha == SDL_ALPHA_OPAQUE) {
|
||||
|
|
|
@ -146,6 +146,9 @@ surface blend_surface(surface const &surf, double amount, Uint32 colour);
|
|||
surface flip_surface(surface const &surf);
|
||||
surface flop_surface(surface const &surf);
|
||||
surface create_compatible_surface(surface const &surf, int width = -1, int height = -1);
|
||||
//! Replacement for SDL_BlitSurface.
|
||||
void blit_surface(SDL_Surface* src,
|
||||
const SDL_Rect* srcrect, SDL_Surface* dst, const SDL_Rect* dstrect);
|
||||
|
||||
void fill_rect_alpha(SDL_Rect &rect, Uint32 colour, Uint8 alpha, surface const &target);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue