Conduct surface manipulation in-place when possible (#9218)

This commit is contained in:
Charles Dang 2024-08-17 20:22:44 -04:00 committed by GitHub
parent fb1232e4ea
commit 457ed4bb43
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 239 additions and 532 deletions

View file

@ -664,7 +664,7 @@ bool canvas::update_blur(const rect& screen_region, bool force)
rect read_region = screen_region;
auto setter = draw::set_render_target({});
surface s = video::read_pixels_low_res(&read_region);
s = blur_surface(s, blur_depth_);
blur_surface(s, {0, 0, s->w, s->h}, blur_depth_);
blur_texture_ = texture(s);
deferred_ = false;
return true;

View file

@ -149,29 +149,24 @@ modification_queue modification::decode(const std::string& encoded_mods)
return mods;
}
surface rc_modification::operator()(const surface& src) const
void rc_modification::operator()(surface& src) const
{
// unchecked
return recolor_image(src, rc_map_);
recolor_image(src, rc_map_);
}
surface fl_modification::operator()(const surface& src) const
void fl_modification::operator()(surface& src) const
{
surface ret = src;
if(horiz_ && vert_ ) {
// Slightly faster than doing both a flip and a flop.
ret = rotate_180_surface(ret);
src = rotate_180_surface(src);
} else if(horiz_) {
ret = flip_surface(ret);
flip_surface(src);
} else if(vert_) {
ret = flop_surface(ret);
flop_surface(src);
}
return ret;
}
surface rotate_modification::operator()(const surface& src) const
void rotate_modification::operator()(surface& src) const
{
// Convert the number of degrees to the interval [0,360].
const int normalized = degrees_ >= 0 ?
@ -180,59 +175,66 @@ surface rotate_modification::operator()(const surface& src) const
switch ( normalized )
{
case 0: return src;
case 90: return rotate_90_surface(src, true);
case 180: return rotate_180_surface(src);
case 270: return rotate_90_surface(src, false);
case 360: return src;
case 0:
return;
case 90:
src = rotate_90_surface(src, true);
return;
case 180:
src = rotate_180_surface(src);
return;
case 270:
src = rotate_90_surface(src, false);
return;
case 360:
return;
}
return rotate_any_surface(src, normalized, zoom_, offset_);
src = rotate_any_surface(src, normalized, zoom_, offset_);
}
surface gs_modification::operator()(const surface& src) const
void gs_modification::operator()(surface& src) const
{
return greyscale_image(src);
greyscale_image(src);
}
surface crop_transparency_modification::operator()(const surface& src) const
void crop_transparency_modification::operator()(surface& src) const
{
rect src_rect = get_non_transparent_portion(src);
if(src_rect.w == src->w && src_rect.h == src->h) {
return src;
return;
}
if(surface cropped = get_surface_portion(src, src_rect)) {
return cropped;
src = cropped;
} else {
ERR_DP << "Failed to either crop or scale the surface";
return nullptr;
}
}
surface bw_modification::operator()(const surface& src) const
void bw_modification::operator()(surface& src) const
{
return monochrome_image(src, threshold_);
monochrome_image(src, threshold_);
}
surface sepia_modification::operator()(const surface &src) const
void sepia_modification::operator()(surface& src) const
{
return sepia_image(src);
sepia_image(src);
}
surface negative_modification::operator()(const surface &src) const
void negative_modification::operator()(surface& src) const
{
return negative_image(src, red_, green_, blue_);
negative_image(src, red_, green_, blue_);
}
surface plot_alpha_modification::operator()(const surface& src) const
void plot_alpha_modification::operator()(surface& src) const
{
return alpha_to_greyscale(src);
alpha_to_greyscale(src);
}
surface wipe_alpha_modification::operator()(const surface& src) const
void wipe_alpha_modification::operator()(surface& src) const
{
return wipe_alpha(src);
wipe_alpha(src);
}
// TODO: Is this useful enough to move into formula/callable_objects?
@ -291,25 +293,14 @@ private:
uint32_t w, h;
};
surface adjust_alpha_modification::operator()(const surface & src) const
void adjust_alpha_modification::operator()(surface& src) const
{
if(src == nullptr) {
return nullptr;
}
if(src) {
wfl::formula new_alpha(formula_);
wfl::formula new_alpha(formula_);
surface nsurf = src.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
surface_lock lock(nsurf);
surface_lock lock(src);
uint32_t* cur = lock.pixels();
uint32_t* const end = cur + nsurf->w * src->h;
uint32_t* const end = cur + src->w * src->h;
uint32_t* const beg = cur;
while(cur != end) {
@ -321,42 +312,29 @@ surface adjust_alpha_modification::operator()(const surface & src) const
int i = cur - beg;
SDL_Point p;
p.y = i / nsurf->w;
p.x = i % nsurf->w;
p.y = i / src->w;
p.x = i % src->w;
pixel_callable px(p, pixel, nsurf->w, nsurf->h);
pixel_callable px(p, pixel, src->w, src->h);
pixel.a = std::min<unsigned>(new_alpha.evaluate(px).as_int(), 255);
*cur = (pixel.a << 24) + (pixel.r << 16) + (pixel.g << 8) + pixel.b;
++cur;
}
}
return nsurf;
}
surface adjust_channels_modification::operator()(const surface & src) const
void adjust_channels_modification::operator()(surface& src) const
{
if(src == nullptr) {
return nullptr;
}
if(src) {
wfl::formula new_red(formulas_[0]);
wfl::formula new_green(formulas_[1]);
wfl::formula new_blue(formulas_[2]);
wfl::formula new_alpha(formulas_[3]);
wfl::formula new_red(formulas_[0]);
wfl::formula new_green(formulas_[1]);
wfl::formula new_blue(formulas_[2]);
wfl::formula new_alpha(formulas_[3]);
surface nsurf = src.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
surface_lock lock(nsurf);
surface_lock lock(src);
uint32_t* cur = lock.pixels();
uint32_t* const end = cur + nsurf->w * src->h;
uint32_t* const end = cur + src->w * src->h;
uint32_t* const beg = cur;
while(cur != end) {
@ -368,10 +346,10 @@ surface adjust_channels_modification::operator()(const surface & src) const
int i = cur - beg;
SDL_Point p;
p.y = i / nsurf->w;
p.x = i % nsurf->w;
p.y = i / src->w;
p.x = i % src->w;
pixel_callable px(p, pixel, nsurf->w, nsurf->h);
pixel_callable px(p, pixel, src->w, src->h);
pixel.r = std::min<unsigned>(new_red.evaluate(px).as_int(), 255);
pixel.g = std::min<unsigned>(new_green.evaluate(px).as_int(), 255);
pixel.b = std::min<unsigned>(new_blue.evaluate(px).as_int(), 255);
@ -381,11 +359,9 @@ surface adjust_channels_modification::operator()(const surface & src) const
++cur;
}
}
return nsurf;
}
surface crop_modification::operator()(const surface& src) const
void crop_modification::operator()(surface& src) const
{
SDL_Rect area = slice_;
if(area.w == 0) {
@ -396,18 +372,10 @@ surface crop_modification::operator()(const surface& src) const
area.h = src->h;
}
/*
* Unlike other image functions cut_surface does not convert the input
* surface to a neutral surface, nor does it convert its return surface
* to an optimised surface.
*
* Since it seems to work for most cases, rather change this caller instead
* of the function signature. (The issue was discovered in bug #20876).
*/
return cut_surface(src, area);
src = cut_surface(src, area);
}
surface blit_modification::operator()(const surface& src) const
void blit_modification::operator()(surface& src) const
{
if(x_ >= src->w) {
std::stringstream sstr;
@ -443,39 +411,36 @@ surface blit_modification::operator()(const surface& src) const
throw imod_exception(sstr);
}
surface nsrc = src.clone();
SDL_Rect r {x_, y_, 0, 0};
sdl_blit(surf_, nullptr, nsrc, &r);
return nsrc;
sdl_blit(surf_, nullptr, src, &r);
}
surface mask_modification::operator()(const surface& src) const
void mask_modification::operator()(surface& src) const
{
if(src->w == mask_->w && src->h == mask_->h && x_ == 0 && y_ == 0) {
return mask_surface(src, mask_);
if(src->w == mask_->w && src->h == mask_->h && x_ == 0 && y_ == 0) {
mask_surface(src, mask_);
return;
}
SDL_Rect r {x_, y_, 0, 0};
surface new_mask(src->w, src->h);
sdl_blit(mask_, nullptr, new_mask, &r);
return mask_surface(src, new_mask);
mask_surface(src, new_mask);
}
surface light_modification::operator()(const surface& src) const {
if(src == nullptr) { return nullptr; }
void light_modification::operator()(surface& src) const
{
if(src == nullptr) { return; }
// light_surface wants a neutral surface having same dimensions
surface nsurf;
if(surf_->w != src->w || surf_->h != src->h) {
nsurf = scale_surface(surf_, src->w, src->h);
light_surface(src, scale_surface(surf_, src->w, src->h));
} else {
nsurf = surf_;
light_surface(src, surf_);
}
return light_surface(src, nsurf);
}
surface scale_modification::operator()(const surface& src) const
void scale_modification::operator()(surface& src) const
{
point size = target_size_;
@ -504,40 +469,31 @@ surface scale_modification::operator()(const surface& src) const
}
if(flags_ & SCALE_SHARP) {
return scale_surface_sharp(src, size.x, size.y);
src = scale_surface_sharp(src, size.x, size.y);
} else {
return scale_surface_legacy(src, size.x, size.y);
src = scale_surface_legacy(src, size.x, size.y);
}
}
surface xbrz_modification::operator()(const surface& src) const
void xbrz_modification::operator()(surface& src) const
{
if(z_ == 1) {
return src;
if(z_ != 1) {
src = scale_surface_xbrz(src, z_);
}
return scale_surface_xbrz(src, z_);
}
/*
* The Opacity IPF doesn't seem to work with surface-wide alpha and instead needs per-pixel alpha.
* If this is needed anywhere else it can be moved back to sdl/utils.*pp.
*/
surface o_modification::operator()(const surface& src) const
void o_modification::operator()(surface& src) const
{
surface nsurf = src.clone();
if(src) {
uint8_t alpha_mod = float_to_color(opacity_);
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
uint8_t alpha_mod = float_to_color(opacity_);
{
surface_lock lock(nsurf);
surface_lock lock(src);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w * src->h;
uint32_t* end = beg + src->w * src->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -555,40 +511,36 @@ surface o_modification::operator()(const surface& src) const
++beg;
}
}
return nsurf;
}
surface cs_modification::operator()(const surface& src) const
void cs_modification::operator()(surface& src) const
{
return((r_ != 0 || g_ != 0 || b_ != 0)
? adjust_surface_color(src, r_, g_, b_)
: src
);
if((r_ != 0 || g_ != 0 || b_ != 0)) {
adjust_surface_color(src, r_, g_, b_);
}
}
surface blend_modification::operator()(const surface& src) const
void blend_modification::operator()(surface& src) const
{
return blend_surface(src, static_cast<double>(a_), color_t(r_, g_, b_));
blend_surface(src, static_cast<double>(a_), color_t(r_, g_, b_));
}
surface bl_modification::operator()(const surface& src) const
void bl_modification::operator()(surface& src) const
{
return blur_alpha_surface(src, depth_);
blur_alpha_surface(src, depth_);
}
surface background_modification::operator()(const surface &src) const
void background_modification::operator()(surface& src) const
{
surface ret = src.clone();
SDL_FillRect(ret, nullptr, SDL_MapRGBA(ret->format, color_.r, color_.g,
color_.b, color_.a));
SDL_FillRect(ret, nullptr, SDL_MapRGBA(ret->format, color_.r, color_.g, color_.b, color_.a));
sdl_blit(src, nullptr, ret, nullptr);
return ret;
src = ret;
}
surface swap_modification::operator()(const surface &src) const
void swap_modification::operator()(surface& src) const
{
return swap_channels_image(src, red_, green_, blue_, alpha_);
swap_channels_image(src, red_, green_, blue_, alpha_);
}
namespace {

View file

@ -102,7 +102,7 @@ public:
virtual ~modification() {}
/** Applies the image-path modification on the specified surface */
virtual surface operator()(const surface& src) const = 0;
virtual void operator()(surface& src) const = 0;
/** Specifies the priority of the modification */
virtual int priority() const { return 0; }
@ -130,7 +130,7 @@ public:
rc_modification(const color_range_map& recolor_map)
: rc_map_(recolor_map)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
// The rc modification has a higher priority
virtual int priority() const { return 1; }
@ -159,7 +159,7 @@ public:
: horiz_(horiz)
, vert_(vert)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
void set_horiz(bool val) { horiz_ = val; }
void set_vert(bool val) { vert_ = val; }
@ -205,7 +205,7 @@ public:
rotate_modification(int degrees = 90, int zoom = 16, int offset = 8)
: degrees_(degrees), zoom_(zoom), offset_(offset)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
bool no_op() const { return degrees_ % 360 == 0; }
@ -221,7 +221,7 @@ private:
class gs_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
};
/**
@ -230,7 +230,7 @@ public:
class crop_transparency_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
};
/**
@ -240,7 +240,7 @@ class bw_modification : public modification
{
public:
bw_modification(int threshold): threshold_(threshold) {}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
private:
int threshold_;
};
@ -250,7 +250,7 @@ private:
*/
struct sepia_modification : modification
{
virtual surface operator()(const surface &src) const;
virtual void operator()(surface& src) const;
};
/**
@ -260,7 +260,7 @@ class negative_modification : public modification
{
public:
negative_modification(int r, int g, int b): red_(r), green_(g), blue_(b) {}
virtual surface operator()(const surface &src) const;
virtual void operator()(surface& src) const;
private:
int red_, green_, blue_;
};
@ -271,7 +271,7 @@ private:
class plot_alpha_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
};
/**
@ -280,7 +280,7 @@ public:
class wipe_alpha_modification : public modification
{
public:
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
};
/**
@ -293,7 +293,7 @@ public:
: formula_(formula)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
private:
std::string formula_;
@ -322,7 +322,7 @@ public:
}
}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
private:
std::vector<std::string> formulas_;
@ -337,7 +337,7 @@ public:
crop_modification(const SDL_Rect& slice)
: slice_(slice)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
const SDL_Rect& get_slice() const
{
@ -358,7 +358,7 @@ public:
blit_modification(const surface& surf, int x, int y)
: surf_(surf), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
const surface& get_surface() const
{
@ -391,7 +391,7 @@ public:
mask_modification(const surface& mask, int x, int y)
: mask_(mask), x_(x), y_(y)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
const surface& get_mask() const
{
@ -424,7 +424,7 @@ public:
light_modification(const surface& surf)
: surf_(surf)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
const surface& get_surface() const
{
@ -456,7 +456,7 @@ public:
, flags_(flags)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
int get_w() const { return target_size_.x; }
int get_h() const { return target_size_.y; }
@ -477,7 +477,7 @@ public:
: z_(z)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
private:
int z_;
@ -492,7 +492,7 @@ public:
o_modification(float opacity)
: opacity_(opacity)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
float get_opacity() const
{
@ -512,7 +512,7 @@ public:
cs_modification(int r, int g, int b)
: r_(r), g_(g), b_(b)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
int get_r() const { return r_; }
int get_g() const { return g_; }
@ -531,7 +531,7 @@ public:
blend_modification(int r, int g, int b, float a)
: r_(r), g_(g), b_(b), a_(a)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
int get_r() const { return r_; }
int get_g() const { return g_; }
@ -552,7 +552,7 @@ public:
bl_modification(int depth)
: depth_(depth)
{}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
int get_depth() const
{
@ -569,7 +569,7 @@ private:
struct background_modification : modification
{
background_modification(const color_t& c): color_(c) {}
virtual surface operator()(const surface &src) const;
virtual void operator()(surface& src) const;
const color_t& get_color() const
{
@ -587,7 +587,7 @@ class swap_modification : public modification
{
public:
swap_modification(channel r, channel g, channel b, channel a): red_(r), green_(g), blue_(b), alpha_(a) {}
virtual surface operator()(const surface& src) const;
virtual void operator()(surface& src) const;
private:
channel red_;
channel green_;

View file

@ -384,7 +384,8 @@ static surface load_image_file(const image::locator& loc)
static surface load_image_sub_file(const image::locator& loc)
{
surface surf = get_surface(loc.get_filename(), UNSCALED);
// Create a new surface in-memory on which to apply the modifications
surface surf = get_surface(loc.get_filename(), UNSCALED).clone();
if(surf == nullptr) {
return nullptr;
}
@ -395,7 +396,7 @@ static surface load_image_sub_file(const image::locator& loc)
modification* mod = mods.top();
try {
surf = (*mod)(surf);
std::invoke(*mod, surf);
} catch(const image::modification::imod_exception& e) {
std::ostringstream ss;
ss << "\n";
@ -428,9 +429,9 @@ static surface load_image_sub_file(const image::locator& loc)
}
// cut and hex mask, but also check and cache if empty result
surface cut(cut_surface(surf, srcrect));
surface cut = cut_surface(surf, srcrect);
bool is_empty = false;
surf = mask_surface(cut, get_hexmask(), &is_empty);
mask_surface(cut, get_hexmask(), &is_empty);
// discard empty images to free memory
if(is_empty) {
@ -438,6 +439,8 @@ static surface load_image_sub_file(const image::locator& loc)
// and it filters them out.
// A safer and more general way would be to keep only one copy of it
surf = nullptr;
} else {
surf = cut;
}
is_empty_hex_.add_to_cache(loc, is_empty);
@ -499,7 +502,8 @@ static surface apply_light(surface surf, const light_string& ls)
// if no lightmap (first char = -1) then we need the initial value
//(before the halving done for lightmap)
int m = ls[0] == -1 ? 2 : 1;
return adjust_surface_color(surf, ls[1] * m, ls[2] * m, ls[3] * m);
adjust_surface_color(surf, ls[1] * m, ls[2] * m, ls[3] * m);
return surf;
}
// check if the lightmap is already cached or need to be generated
@ -543,7 +547,8 @@ static surface apply_light(surface surf, const light_string& ls)
}
// apply the final lightmap
return light_surface(surf, lightmap);
light_surface(surf, lightmap);
return surf;
}
static surface load_from_disk(const locator& loc)
@ -586,8 +591,8 @@ void set_color_adjustment(int r, int g, int b)
static surface get_hexed(const locator& i_locator, bool skip_cache = false)
{
surface image(get_surface(i_locator, UNSCALED, skip_cache));
surface mask(get_hexmask());
surface image = get_surface(i_locator, UNSCALED, skip_cache).clone();
surface mask = get_hexmask();
// Ensure the image is the correct size by cropping and/or centering.
// TODO: this should probably be a function of sdl/utils
if(image && (image->w != mask->w || image->h != mask->h)) {
@ -618,15 +623,16 @@ static surface get_hexed(const locator& i_locator, bool skip_cache = false)
}
// hex cut tiles, also check and cache if empty result
bool is_empty = false;
surface res = mask_surface(image, mask, &is_empty, i_locator.get_filename());
mask_surface(image, mask, &is_empty, i_locator.get_filename());
is_empty_hex_.add_to_cache(i_locator, is_empty);
return res;
return image;
}
static surface get_tod_colored(const locator& i_locator, bool skip_cache = false)
{
surface img = get_surface(i_locator, HEXED, skip_cache);
return adjust_surface_color(img, red_adjust, green_adjust, blue_adjust);
surface img = get_surface(i_locator, HEXED, skip_cache).clone();
adjust_surface_color(img, red_adjust, green_adjust, blue_adjust);
return img;
}
/** translate type to a simpler one when possible */
@ -727,7 +733,7 @@ surface get_lighted_image(const image::locator& i_locator, const light_string& l
DBG_IMG << "lit surface cache miss: " << i_locator;
// not cached yet, generate it
surface res = apply_light(get_surface(i_locator, HEXED), ls);
surface res = apply_light(get_surface(i_locator, HEXED).clone(), ls);
// record the lighted surface in the corresponding variants cache
lvar[ls] = res;
@ -790,7 +796,7 @@ bool is_in_hex(const locator& i_locator)
bool is_empty_hex(const locator& i_locator)
{
if(!is_empty_hex_.in_cache(i_locator)) {
const surface surf = get_surface(i_locator, HEXED);
surface surf = get_surface(i_locator, HEXED);
// emptiness of terrain image is checked during hex cut
// so, maybe in cache now, let's recheck
if(!is_empty_hex_.in_cache(i_locator)) {

View file

@ -357,7 +357,6 @@ surface scale_surface_legacy(const surface &surf, int w, int h)
return dst;
}
surface scale_surface_sharp(const surface& surf, int w, int h)
{
// Since SDL version 1.1.5 0 is transparent, before 255 was transparent.
@ -408,27 +407,12 @@ surface scale_surface_sharp(const surface& surf, int w, int h)
return dst;
}
surface adjust_surface_color(const surface &surf, int red, int green, int blue)
void adjust_surface_color(surface& nsurf, int red, int green, int blue)
{
if(surf == nullptr)
return nullptr;
if((red == 0 && green == 0 && blue == 0)) {
surface temp = surf; // TODO: remove temp surface
return temp;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf && (red != 0 || green != 0 || blue != 0)) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -449,25 +433,14 @@ surface adjust_surface_color(const surface &surf, int red, int green, int blue)
++beg;
}
}
return nsurf;
}
surface greyscale_image(const surface &surf)
void greyscale_image(surface& nsurf)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -494,25 +467,14 @@ surface greyscale_image(const surface &surf)
++beg;
}
}
return nsurf;
}
surface monochrome_image(const surface &surf, const int threshold)
void monochrome_image(surface& nsurf, const int threshold)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -534,25 +496,14 @@ surface monochrome_image(const surface &surf, const int threshold)
++beg;
}
}
return nsurf;
}
surface sepia_image(const surface &surf)
void sepia_image(surface& nsurf)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -576,25 +527,14 @@ surface sepia_image(const surface &surf)
++beg;
}
}
return nsurf;
}
surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB)
void negative_image(surface& nsurf, const int thresholdR, const int thresholdG, const int thresholdB)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -619,25 +559,14 @@ surface negative_image(const surface &surf, const int thresholdR, const int thre
++beg;
}
}
return nsurf;
}
surface alpha_to_greyscale(const surface &surf)
void alpha_to_greyscale(surface& nsurf)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -647,25 +576,14 @@ surface alpha_to_greyscale(const surface &surf)
++beg;
}
}
return nsurf;
}
surface wipe_alpha(const surface &surf)
void wipe_alpha(surface& nsurf)
{
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
@ -674,28 +592,21 @@ surface wipe_alpha(const surface &surf)
++beg;
}
}
return nsurf;
}
surface shadow_image(const surface &surf, int scale)
void shadow_image(surface& surf, int scale)
{
if(surf == nullptr)
return nullptr;
return;
// we blur it, and reuse the neutral surface created by the blur function
surface nsurf (blur_alpha_surface(surf, 2*scale));
if(nsurf == nullptr) {
PLAIN_LOG << "failed to blur the shadow surface";
return nullptr;
}
blur_alpha_surface(surf, 2*scale);
{
surface_lock lock(nsurf);
surface_lock lock(surf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + surf->w*surf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -712,24 +623,14 @@ surface shadow_image(const surface &surf, int scale)
++beg;
}
}
return nsurf;
}
surface swap_channels_image(const surface& surf, channel r, channel g, channel b, channel a) {
if(surf == nullptr)
return nullptr;
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
}
{
void swap_channels_image(surface& nsurf, channel r, channel g, channel b, channel a)
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -754,7 +655,7 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
newRed = alpha;
break;
default:
return nullptr;
return;
}
switch (g) {
@ -771,7 +672,7 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
newGreen = alpha;
break;
default:
return nullptr;
return;
}
switch (b) {
@ -788,7 +689,7 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
newBlue = alpha;
break;
default:
return nullptr;
return;
}
switch (a) {
@ -805,7 +706,7 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
newAlpha = alpha;
break;
default:
return nullptr;
return;
}
*beg = (newAlpha << 24) | (newRed << 16) | (newGreen << 8) | newBlue;
@ -814,28 +715,20 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
++beg;
}
}
return nsurf;
}
surface recolor_image(surface surf, const color_range_map& map_rgb)
void recolor_image(surface& nsurf, const color_range_map& map_rgb)
{
if(surf == nullptr)
return nullptr;
if(nsurf == nullptr)
return;
if(map_rgb.empty()) {
return surf;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "failed to make neutral surface";
return nullptr;
return;
}
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -853,27 +746,14 @@ surface recolor_image(surface surf, const color_range_map& map_rgb)
++beg;
}
return nsurf;
}
surface brighten_image(const surface &surf, int32_t amount)
void brighten_image(surface& nsurf, int32_t amount)
{
if(surf == nullptr) {
return nullptr;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
if (amount < 0) amount = 0;
while(beg != end) {
@ -895,8 +775,6 @@ surface brighten_image(const surface &surf, int32_t amount)
++beg;
}
}
return nsurf;
}
void adjust_surface_alpha(surface& surf, uint8_t alpha_mod)
@ -908,23 +786,12 @@ void adjust_surface_alpha(surface& surf, uint8_t alpha_mod)
SDL_SetSurfaceAlphaMod(surf, alpha_mod);
}
surface adjust_surface_alpha_add(const surface &surf, int amount)
void adjust_surface_alpha_add(surface& nsurf, int amount)
{
if(surf== nullptr) {
return nullptr;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
while(beg != end) {
uint8_t alpha = (*beg) >> 24;
@ -942,28 +809,19 @@ surface adjust_surface_alpha_add(const surface &surf, int amount)
++beg;
}
}
return nsurf;
}
surface mask_surface(const surface &surf, const surface &mask, bool* empty_result, const std::string& filename)
void mask_surface(surface& nsurf, const surface& nmask, bool* empty_result, const std::string& filename)
{
if(surf == nullptr) {
if(nsurf == nullptr) {
*empty_result = true;
return nullptr;
return;
}
if(mask == nullptr) {
return surf;
if(nmask == nullptr) {
return;
}
surface nsurf = surf.clone();
surface nmask = mask.clone();
if(nsurf == nullptr || nmask == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
if (nsurf->w != nmask->w) {
if (nsurf->w != nmask->w) {
// we don't support efficiently different width.
// (different height is not a real problem)
// This function is used on all hexes and usually only for that
@ -974,7 +832,7 @@ surface mask_surface(const surface &surf, const surface &mask, bool* empty_resul
ss << nsurf->w << "x" << nsurf->h;
PLAIN_LOG << ss.str();
PLAIN_LOG << "It will not be masked, please use: "<< nmask->w << "x" << nmask->h;
return nsurf;
return;
}
bool empty = true;
@ -983,7 +841,7 @@ surface mask_surface(const surface &surf, const surface &mask, bool* empty_resul
const_surface_lock mlock(nmask);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
const uint32_t* mbeg = mlock.pixels();
const uint32_t* mend = mbeg + nmask->w*nmask->h;
@ -1012,32 +870,22 @@ surface mask_surface(const surface &surf, const surface &mask, bool* empty_resul
}
if(empty_result)
*empty_result = empty;
return nsurf;
}
bool in_mask_surface(const surface &surf, const surface &mask)
bool in_mask_surface(surface nsurf, surface nmask)
{
if(surf == nullptr) {
if(nsurf == nullptr) {
return false;
}
if(mask == nullptr){
if(nmask == nullptr){
return true;
}
if (surf->w != mask->w || surf->h != mask->h ) {
if (nsurf->w != nmask->w || nsurf->h != nmask->h ) {
// not same size, consider it doesn't fit
return false;
}
surface nsurf = surf.clone();
surface nmask = mask.clone();
if(nsurf == nullptr || nmask == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return false;
}
{
surface_lock lock(nsurf);
const_surface_lock mlock(nmask);
@ -1062,21 +910,15 @@ bool in_mask_surface(const surface &surf, const surface &mask)
return true;
}
surface light_surface(const surface &surf, const surface &lightmap)
void light_surface(surface& nsurf, const surface &lightmap)
{
if(surf == nullptr) {
return nullptr;
if(nsurf == nullptr) {
return;
}
if(lightmap == nullptr) {
return surf;
return;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
if (nsurf->w != lightmap->w) {
// we don't support efficiently different width.
// (different height is not a real problem)
@ -1084,7 +926,7 @@ surface light_surface(const surface &surf, const surface &lightmap)
// so better keep it simple and efficient for the normal case
PLAIN_LOG << "Detected an image with bad dimensions: " << nsurf->w << "x" << nsurf->h;
PLAIN_LOG << "It will not be lighted, please use: "<< lightmap->w << "x" << lightmap->h;
return nsurf;
return;
}
{
surface_lock lock(nsurf);
@ -1123,28 +965,6 @@ surface light_surface(const surface &surf, const surface &lightmap)
++lbeg;
}
}
return nsurf;
}
surface blur_surface(const surface &surf, int depth)
{
if(surf == nullptr) {
return nullptr;
}
surface res = surf.clone();
if(res == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
SDL_Rect rect {0, 0, surf->w, surf->h};
blur_surface(res, rect, depth);
return res;
}
void blur_surface(surface& surf, SDL_Rect rect, int depth)
@ -1263,17 +1083,10 @@ void blur_surface(surface& surf, SDL_Rect rect, int depth)
}
}
surface blur_alpha_surface(const surface &surf, int depth)
void blur_alpha_surface(surface& res, int depth)
{
if(surf == nullptr) {
return nullptr;
}
surface res = surf.clone();
if(res == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
return;
}
const int max_blur = 256;
@ -1406,8 +1219,6 @@ surface blur_alpha_surface(const surface &surf, int depth)
assert(static_cast<int>(queue.size()) == std::min(depth, res->h));
queue.clear();
}
return res;
}
surface cut_surface(const surface &surf, const SDL_Rect& r)
@ -1468,26 +1279,13 @@ surface cut_surface(const surface &surf, const SDL_Rect& r)
return res;
}
surface blend_surface(
const surface &surf
, const double amount
, const color_t color)
void blend_surface(surface& nsurf, const double amount, const color_t color)
{
if(surf== nullptr) {
return nullptr;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* beg = lock.pixels();
uint32_t* end = beg + nsurf->w*surf->h;
uint32_t* end = beg + nsurf->w*nsurf->h;
uint16_t ratio = amount * 256;
const uint16_t red = ratio * color.r;
@ -1506,8 +1304,6 @@ surface blend_surface(
++beg;
}
}
return nsurf;
}
/* Simplified RotSprite algorithm.
@ -1626,12 +1422,11 @@ uint32_t get_pixel(const surface& surf, const const_surface_lock& surf_lock, int
}
// Rotates a surface 180 degrees.
surface rotate_180_surface(const surface &surf)
surface rotate_180_surface(const surface& surf)
{
if ( surf == nullptr )
return nullptr;
// Work with a "neutral" surface.
surface nsurf = surf.clone();
if ( nsurf == nullptr ) {
@ -1666,12 +1461,11 @@ surface rotate_180_surface(const surface &surf)
return nsurf;
}
// Rotates a surface 90 degrees, either clockwise or counter-clockwise.
surface rotate_90_surface(const surface &surf, bool clockwise)
surface rotate_90_surface(const surface& surf, bool clockwise)
{
if ( surf == nullptr )
return nullptr;
if(surf == nullptr)
return surf;
surface dst(surf->h, surf->w); // Flipped dimensions.
@ -1680,7 +1474,7 @@ surface rotate_90_surface(const surface &surf, bool clockwise)
return nullptr;
}
{// Code block to limit the scope of the surface locks.
{
const_surface_lock src_lock(surf);
surface_lock dst_lock(dst);
@ -1702,21 +1496,9 @@ surface rotate_90_surface(const surface &surf, bool clockwise)
return dst;
}
surface flip_surface(const surface &surf)
void flip_surface(surface& nsurf)
{
if(surf == nullptr) {
return nullptr;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* const pixels = lock.pixels();
@ -1728,37 +1510,22 @@ surface flip_surface(const surface &surf)
}
}
}
return nsurf;
}
surface flop_surface(const surface &surf)
void flop_surface(surface& nsurf)
{
if(surf == nullptr) {
return nullptr;
}
surface nsurf = surf.clone();
if(nsurf == nullptr) {
PLAIN_LOG << "could not make neutral surface...";
return nullptr;
}
{
if(nsurf) {
surface_lock lock(nsurf);
uint32_t* const pixels = lock.pixels();
for(int x = 0; x != nsurf->w; ++x) {
for(int y = 0; y != nsurf->h/2; ++y) {
const int index1 = y*nsurf->w + x;
const int index2 = (nsurf->h-y-1)*surf->w + x;
const int index2 = (nsurf->h-y-1)*nsurf->w + x;
std::swap(pixels[index1],pixels[index2]);
}
}
}
return nsurf;
}
surface get_surface_portion(const surface &src, SDL_Rect &area)

View file

@ -101,18 +101,18 @@ surface scale_surface_legacy(const surface &surf, int w, int h);
*/
surface scale_surface_sharp(const surface& surf, int w, int h);
surface adjust_surface_color(const surface &surf, int r, int g, int b);
surface greyscale_image(const surface &surf);
surface monochrome_image(const surface &surf, const int threshold);
surface sepia_image(const surface &surf);
surface negative_image(const surface &surf, const int thresholdR, const int thresholdG, const int thresholdB);
surface alpha_to_greyscale(const surface & surf);
surface wipe_alpha(const surface & surf);
void adjust_surface_color(surface& surf, int r, int g, int b);
void greyscale_image(surface& surf);
void monochrome_image(surface& surf, const int threshold);
void sepia_image(surface& surf);
void negative_image(surface& surf, const int thresholdR, const int thresholdG, const int thresholdB);
void alpha_to_greyscale(surface& surf);
void wipe_alpha(surface& surf);
/** create an heavy shadow of the image, by blurring, increasing alpha and darkening */
surface shadow_image(const surface &surf, int scale = 1);
void shadow_image(surface& surf, int scale = 1);
enum channel { RED, GREEN, BLUE, ALPHA };
surface swap_channels_image(const surface& surf, channel r, channel g, channel b, channel a);
void swap_channels_image(surface& surf, channel r, channel g, channel b, channel a);
/**
* Recolors a surface using a map with source and converted palette values.
@ -121,12 +121,10 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
* @param surf The source surface.
* @param map_rgb Map of color values, with the keys corresponding to the
* source palette, and the values to the recolored palette.
* @return A recolored surface, or a null surface if there are
* problems with the source.
*/
surface recolor_image(surface surf, const color_range_map& map_rgb);
void recolor_image(surface& surf, const color_range_map& map_rgb);
surface brighten_image(const surface &surf, int32_t amount);
void brighten_image(surface& surf, int32_t amount);
/** Get a portion of the screen.
* Send nullptr if the portion is outside of the screen.
@ -139,13 +137,13 @@ surface brighten_image(const surface &surf, int32_t amount);
surface get_surface_portion(const surface &surf, SDL_Rect &rect);
void adjust_surface_alpha(surface& surf, uint8_t alpha_mod);
surface adjust_surface_alpha_add(const surface &surf, int amount);
void adjust_surface_alpha_add(surface& surf, int amount);
/** Applies a mask on a surface. */
surface mask_surface(const surface &surf, const surface &mask, bool* empty_result = nullptr, const std::string& filename = std::string());
void mask_surface(surface& surf, const surface& mask, bool* empty_result = nullptr, const std::string& filename = std::string());
/** Check if a surface fit into a mask */
bool in_mask_surface(const surface &surf, const surface &mask);
bool in_mask_surface(surface surf, surface mask);
/**
* Light surf using lightmap
@ -155,16 +153,7 @@ bool in_mask_surface(const surface &surf, const surface &mask);
* to cover the full (-256,256) spectrum.
* Should already be neutral
*/
surface light_surface(const surface &surf, const surface &lightmap);
/**
* Cross-fades a surface.
*
* @param surf The source surface.
* @param depth The depth of the blurring.
* @return A new, blurred, neutral surface.
*/
surface blur_surface(const surface &surf, int depth = 1);
void light_surface(surface& surf, const surface &lightmap);
/**
* Cross-fades a surface in place.
@ -180,9 +169,8 @@ void blur_surface(surface& surf, SDL_Rect rect, int depth = 1);
*
* @param surf The source surface.
* @param depth The depth of the blurring.
* @return A new, blurred, neutral surface.
*/
surface blur_alpha_surface(const surface &surf, int depth = 1);
void blur_alpha_surface(surface& surf, int depth = 1);
/** Cuts a rectangle from a surface. */
surface cut_surface(const surface &surf, const SDL_Rect& r);
@ -199,13 +187,8 @@ surface cut_surface(const surface &surf, const SDL_Rect& r);
* [0, 1].
* @param color The color to blend width, note its alpha
* channel is ignored.
*
* @return The blended surface.
*/
surface blend_surface(
const surface &surf
, const double amount
, const color_t color);
void blend_surface(surface& surf, const double amount, const color_t color);
/**
* Rotates a surface by any degrees.
@ -220,8 +203,7 @@ surface blend_surface(
*
* @return The rotated surface.
*/
surface rotate_any_surface(const surface& surf, float angle,
int zoom, int offset);
surface rotate_any_surface(const surface& surf, float angle, int zoom, int offset);
/**
* Rotates a surface 180 degrees.
@ -230,7 +212,7 @@ surface rotate_any_surface(const surface& surf, float angle,
*
* @return The rotated surface.
*/
surface rotate_180_surface(const surface &surf);
surface rotate_180_surface(const surface& surf);
/**
* Rotates a surface 90 degrees.
@ -241,10 +223,10 @@ surface rotate_180_surface(const surface &surf);
*
* @return The rotated surface.
*/
surface rotate_90_surface(const surface &surf, bool clockwise);
surface rotate_90_surface(const surface& surf, bool clockwise);
surface flip_surface(const surface &surf);
surface flop_surface(const surface &surf);
void flip_surface(surface& surf);
void flop_surface(surface& surf);
rect get_non_transparent_portion(const surface& surf);