Heavily rewrote the way image path functions are analyzed...
...when loading images. Now all of them are C++ functors, and, except for ~RC()/~TC(), they are accumulable and applied in a left-to-right order from WML/C++. This seems to have little, if any, performance impact in -O0+debug, -O2+profiling and -O3 builds for me compared to the former implementation. A test with gprof reports in average 0.0 seconds spent in image::load_image_sub_file() for both implementations unless I'm misinterpreting the data. Tested in an AMD Athlon X2 Dual-core QL-62 on Debian lenny, non-stock kernel 2.6.28.1 (SMP, model optimizations) running on native 64-bit mode with the first scenario of HttT and a lot of hyperactive gryphons and undead. 2 GB of RAM, 3.74 GB of swap. The compiler is GNU g++ 4.3.2.
This commit is contained in:
parent
a17b244d90
commit
92620bdd06
8 changed files with 522 additions and 176 deletions
|
@ -12,3 +12,12 @@ The release team should empty this file after each release.
|
|||
|
||||
***
|
||||
|
||||
The image path functions (~RC(), ~TC(), ~FL() et al) parsing has been heavily
|
||||
modified. Now all functions in a path are stacked in a left-to-right order, with
|
||||
the sole exceptions of ~RC() and ~TC(), which continue to be non-accumulable.
|
||||
|
||||
Additionally, a new note-worthy image path function, ~SCALE(width,height), was
|
||||
introduced; it scales graphics, of course.
|
||||
|
||||
***
|
||||
|
||||
|
|
11
changelog
11
changelog
|
@ -12,10 +12,13 @@ Version 1.5.8+svn:
|
|||
* Graphics:
|
||||
* Removed the black background from some remaining old portraits
|
||||
* New portrait for Dwarf Thunderer, Dwarf Dragonguard, Human Pikeman, Dwarf Fighter, Dwarf Lord, Dwarf Guard.
|
||||
* New image-path functions:
|
||||
* SCALE(W,H): scale down an image to the specified width (W) and height (H)
|
||||
for rendering. Negative or null (zero) numbers are ignored when scaling
|
||||
in the respective direction.
|
||||
* Image-path functions:
|
||||
* All image path functions except RC() and TC() can now be stacked
|
||||
correctly and the order of precedence is from left to right. This
|
||||
may impact performance slightly.
|
||||
* New function, SCALE(W,H): scale down an image to the specified width
|
||||
(W) and height (H) for rendering. Negative or null (zero) numbers are
|
||||
ignored when scaling in the respective direction.
|
||||
* Restructured portraits directory to be based on unit types rather than authors,
|
||||
added an authors file for recording portrait credits.
|
||||
* Language and i18n:
|
||||
|
|
|
@ -151,6 +151,7 @@ SET(libwesnoth-game_STAT_SRC
|
|||
font.cpp
|
||||
hotkeys.cpp
|
||||
image.cpp
|
||||
image_function.cpp
|
||||
key.cpp
|
||||
language.cpp
|
||||
loadscreen.cpp
|
||||
|
|
|
@ -349,6 +349,7 @@ libwesnoth_a_SOURCES = \
|
|||
font.cpp \
|
||||
hotkeys.cpp \
|
||||
image.cpp \
|
||||
image_function.cpp \
|
||||
key.cpp \
|
||||
language.cpp \
|
||||
loadscreen.cpp \
|
||||
|
|
|
@ -74,6 +74,7 @@ libwesnoth_sources = Split("""
|
|||
generic_event.cpp
|
||||
hotkeys.cpp
|
||||
image.cpp
|
||||
image_function.cpp
|
||||
key.cpp
|
||||
language.cpp
|
||||
loadscreen.cpp
|
||||
|
|
369
src/image.cpp
369
src/image.cpp
|
@ -23,8 +23,10 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "foreach.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "image.hpp"
|
||||
#include "image_function.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#include "SDL_image.h"
|
||||
|
@ -348,167 +350,224 @@ surface locator::load_image_sub_file() const
|
|||
}
|
||||
|
||||
if(val_.modifications_.size()){
|
||||
// ~FL() arguments
|
||||
bool xflip = false;
|
||||
bool yflip = false;
|
||||
// ~GS() status
|
||||
bool greyscale = false;
|
||||
// ~CROP() status
|
||||
bool slice = false;
|
||||
SDL_Rect slice_rect = { 0,0,0,0 };
|
||||
// ~SCALE() status
|
||||
bool scale = false;
|
||||
int scale_w = 0, scale_h = 0;
|
||||
// ~RC() and ~TC() status
|
||||
bool rc = false;
|
||||
// ~CS() arguments
|
||||
int cs_r = 0, cs_g = 0, cs_b = 0;
|
||||
// ~BL() arguments
|
||||
unsigned blur = 0;
|
||||
// ~O()
|
||||
static const fixed_t opacity_unchanged = ftofxp(-1.0f);
|
||||
static const fixed_t opacity_full = ftofxp(1.0f);
|
||||
fixed_t opacity = opacity_unchanged;
|
||||
// The RC functor is very special; it must be applied
|
||||
// before anything else, and it is not accumulative.
|
||||
rc_function rc;
|
||||
// The FL functor is delayed until the end of the sequence.
|
||||
// This allows us to ignore things like ~FL(horiz)~FL(horiz)
|
||||
fl_function fl;
|
||||
// Regular functors
|
||||
std::vector< image::function_base* > functor_queue;
|
||||
|
||||
std::map<Uint32, Uint32> recolor_map;
|
||||
std::vector<std::string> modlist = utils::paranthetical_split(val_.modifications_,'~');
|
||||
for(std::vector<std::string>::const_iterator i=modlist.begin();
|
||||
i!= modlist.end();i++){
|
||||
std::vector<std::string> tmpmod = utils::paranthetical_split(*i);
|
||||
std::vector<std::string>::const_iterator j=tmpmod.begin();
|
||||
const std::vector<std::string> modlist = utils::paranthetical_split(val_.modifications_,'~');
|
||||
|
||||
foreach(const std::string& s, modlist) {
|
||||
const std::vector<std::string> tmpmod = utils::paranthetical_split(s);
|
||||
std::vector<std::string>::const_iterator j = tmpmod.begin();
|
||||
while(j!= tmpmod.end()){
|
||||
std::string function=*j++;
|
||||
if(j==tmpmod.end()){
|
||||
const std::string function = *j++;
|
||||
if(j == tmpmod.end()){
|
||||
if(function.size()){
|
||||
ERR_DP << "error parsing image modifications: "
|
||||
<< val_.modifications_<< "\n";
|
||||
}
|
||||
break;
|
||||
}
|
||||
std::string field = *j++;
|
||||
const std::string field = *j++;
|
||||
|
||||
// ~TC() is the only function which is an alias to another one,
|
||||
// so it must be out of the if-elseif chain.
|
||||
/** @todo: move RC functionality into a different method
|
||||
* that is called by both functions to avoid the
|
||||
* unneeded load of string comparison.
|
||||
*/
|
||||
if("TC" == function){
|
||||
// Team color (TC), a subset of RC's functionality
|
||||
if("TC" == function) {
|
||||
std::vector<std::string> param = utils::split(field,',');
|
||||
if(param.size() < 2)
|
||||
if(param.size() < 2) {
|
||||
ERR_DP << "too few arguments passed to the ~TC() function\n";
|
||||
break;
|
||||
}
|
||||
|
||||
int side_n = lexical_cast_default<int>(param[0], -1);
|
||||
std::string team_color;
|
||||
if (side_n < 1) {
|
||||
ERR_DP << "invalid team (" << side_n << ") passed to the ~TC() function\n";
|
||||
break;
|
||||
} else if (side_n < static_cast<int>(team_colors.size())) {
|
||||
}
|
||||
else if (side_n < static_cast<int>(team_colors.size())) {
|
||||
team_color = team_colors[side_n - 1];
|
||||
} else {
|
||||
// this side is not inialized use default "n"
|
||||
team_color = lexical_cast<std::string>(side_n);
|
||||
}
|
||||
|
||||
if(game_config::tc_info(param[1]).size()){
|
||||
function="RC";
|
||||
field = param[1] + ">" + team_color;
|
||||
}
|
||||
}
|
||||
|
||||
if("RC" == function){ // Re-color range/palette function
|
||||
rc = true;
|
||||
std::vector<std::string> recolor=utils::split(field,'>'); // recolor palette to range
|
||||
if(recolor.size()>1){
|
||||
std::map<Uint32, Uint32> tmp_map;
|
||||
else {
|
||||
// This side is not initialized; use default "n"
|
||||
try {
|
||||
color_range const& new_color = game_config::color_info(recolor[1]);
|
||||
std::vector<Uint32> const& old_color = game_config::tc_info(recolor[0]);
|
||||
tmp_map = recolor_range(new_color,old_color);
|
||||
} catch (config::error& e) {
|
||||
ERR_DP << "caught config::error... " << e.message << std::endl;
|
||||
team_color = lexical_cast<std::string>(side_n);
|
||||
} catch(bad_lexical_cast const&) {
|
||||
ERR_DP << "bad things happen\n";
|
||||
}
|
||||
for(std::map<Uint32, Uint32>::const_iterator tmp = tmp_map.begin(); tmp!= tmp_map.end(); tmp++){
|
||||
recolor_map[tmp->first] = tmp->second;
|
||||
}
|
||||
|
||||
//
|
||||
// Pass parameters for RC functor
|
||||
//
|
||||
if(game_config::tc_info(param[1]).size()){
|
||||
try {
|
||||
color_range const& new_color =
|
||||
game_config::color_info(team_color);
|
||||
std::vector<Uint32> const& old_color =
|
||||
game_config::tc_info(param[1]);
|
||||
|
||||
rc.map() = recolor_range(new_color,old_color);
|
||||
}
|
||||
} else {
|
||||
std::vector<std::string> remap = utils::split(field,'='); // recolor palette to new palette
|
||||
if(remap.size() > 1) {
|
||||
std::map<Uint32, Uint32> tmp_map;
|
||||
catch(config::error const& e) {
|
||||
ERR_DP
|
||||
<< "caught config::error while processing TC: "
|
||||
<< e.message
|
||||
<< '\n';
|
||||
ERR_DP
|
||||
<< "bailing out from TC\n";
|
||||
rc.map().clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ERR_DP
|
||||
<< "could not load TC info for '" << param[1] << "' palette\n";
|
||||
ERR_DP
|
||||
<< "bailing out from TC\n";
|
||||
rc.map().clear();
|
||||
}
|
||||
|
||||
}
|
||||
// Palette recolor (RC)
|
||||
else if("RC" == function) {
|
||||
const std::vector<std::string> recolor_params = utils::split(field,'>');
|
||||
if(recolor_params.size()>1){
|
||||
//
|
||||
// recolor source palette to color range
|
||||
//
|
||||
try {
|
||||
color_range const& new_color =
|
||||
game_config::color_info(recolor_params[1]);
|
||||
std::vector<Uint32> const& old_color =
|
||||
game_config::tc_info(recolor_params[0]);
|
||||
|
||||
rc.map() = recolor_range(new_color,old_color);
|
||||
}
|
||||
catch (config::error& e) {
|
||||
ERR_DP
|
||||
<< "caught config::error while processing color-range RC: "
|
||||
<< e.message
|
||||
<< '\n';
|
||||
ERR_DP
|
||||
<< "bailing out from RC\n";
|
||||
rc.map().clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
//
|
||||
// try to recolor source palette to target palette (palette switch)
|
||||
//
|
||||
const std::vector<std::string> remap_params = utils::split(field,'=');
|
||||
if(remap_params.size() > 1) {
|
||||
try {
|
||||
std::vector<Uint32> const& old_palette = game_config::tc_info(remap[0]);
|
||||
std::vector<Uint32> const& new_palette = game_config::tc_info(remap[1]);
|
||||
std::vector<Uint32> const& old_palette =
|
||||
game_config::tc_info(remap_params[0]);
|
||||
std::vector<Uint32> const& new_palette =
|
||||
game_config::tc_info(remap_params[1]);
|
||||
|
||||
for(size_t i = 0; i < old_palette.size() && i < new_palette.size(); ++i) {
|
||||
tmp_map[old_palette[i]] = new_palette[i];
|
||||
rc.map()[old_palette[i]] = new_palette[i];
|
||||
}
|
||||
} catch(config::error& e) {
|
||||
ERR_DP << "caught config::error... " << e.message << '\n';
|
||||
}
|
||||
for(std::map<Uint32, Uint32>::const_iterator tmp = tmp_map.begin(); tmp!= tmp_map.end(); tmp++){
|
||||
recolor_map[tmp->first] = tmp->second;
|
||||
catch(config::error& e) {
|
||||
ERR_DP
|
||||
<< "caught config::error while processing palette switch RC: "
|
||||
<< e.message
|
||||
<< '\n';
|
||||
ERR_DP
|
||||
<< "bailing out from RC\n";
|
||||
rc.map().clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if("FL" == function){ // Flip layer
|
||||
// Flip-flop (FL)
|
||||
else if("FL" == function) {
|
||||
if(field.empty() || field.find("horiz") != std::string::npos) {
|
||||
xflip = !xflip;
|
||||
fl.toggle_horiz();
|
||||
}
|
||||
if(field.find("vert") != std::string::npos) {
|
||||
yflip = !yflip;
|
||||
fl.toggle_vert();
|
||||
}
|
||||
}
|
||||
else if("GS" == function){ // Grayscale image
|
||||
greyscale=true;
|
||||
// Grayscale (GS)
|
||||
else if("GS" == function) {
|
||||
functor_queue.push_back(new gs_function());
|
||||
}
|
||||
else if("CS" == function) { // Color-shift image
|
||||
// Color-shift (CS)
|
||||
else if("CS" == function) {
|
||||
std::vector<std::string> const factors = utils::split(field, ',');
|
||||
const size_t s = factors.size();
|
||||
if(s) {
|
||||
cs_r = lexical_cast_default<int>(factors[0]);
|
||||
int r = 0, g = 0, b = 0;
|
||||
|
||||
r = lexical_cast_default<int>(factors[0]);
|
||||
if( s > 1 ) {
|
||||
cs_g = lexical_cast_default<int>(factors[1]);
|
||||
g = lexical_cast_default<int>(factors[1]);
|
||||
}
|
||||
if( s > 2 ) {
|
||||
cs_b = lexical_cast_default<int>(factors[2]);
|
||||
b = lexical_cast_default<int>(factors[2]);
|
||||
}
|
||||
if( lg::info.dont_log(lg::display) == false && s > 3 ) {
|
||||
lg::info(lg::display) << "ignoring extra "
|
||||
<< s-3
|
||||
<< " arguments to ~CS() function\n";
|
||||
}
|
||||
} else {
|
||||
INFO_DP << "no arguments passed to ~CS() function\n";
|
||||
|
||||
functor_queue.push_back(new cs_function(r,g,b));
|
||||
}
|
||||
else {
|
||||
INFO_DP << "no arguments passed to the ~CS() function\n";
|
||||
}
|
||||
}
|
||||
else if("CROP" == function){ // Slice image
|
||||
// Crop/slice (CROP)
|
||||
else if("CROP" == function) {
|
||||
std::vector<std::string> const& slice_params = utils::split(field, ',', utils::STRIP_SPACES);
|
||||
if(slice_params.empty() != true) {
|
||||
slice = true;
|
||||
slice_rect.x = lexical_cast_default<Sint16, const std::string&>(slice_params[0]);
|
||||
if(slice_params.size() > 1)
|
||||
const size_t s = slice_params.size();
|
||||
if(s) {
|
||||
SDL_Rect slice_rect = { 0, 0, 0, 0 };
|
||||
|
||||
slice_rect.x = lexical_cast_default<Sint16, const std::string&>(slice_params[0]);
|
||||
if(s > 1) {
|
||||
slice_rect.y = lexical_cast_default<Sint16, const std::string&>(slice_params[1]);
|
||||
if(slice_params.size() > 2)
|
||||
slice_rect.w = lexical_cast_default<Uint16, const std::string&>(slice_params[2]);
|
||||
if(slice_params.size() > 3)
|
||||
slice_rect.h = lexical_cast_default<Uint16, const std::string&>(slice_params[3]);
|
||||
}
|
||||
}
|
||||
else if("SCALE" == function) { // Scale image
|
||||
std::vector<std::string> const& scale_params = utils::split(field, ',', utils::STRIP_SPACES);
|
||||
if(scale_params.empty()) {
|
||||
ERR_DP << "no arguments passed to the ~SCALE() function\n";
|
||||
} else {
|
||||
scale = true;
|
||||
scale_w = lexical_cast_default<int, const std::string&>(scale_params[0]);
|
||||
if(scale_params.size() > 1) {
|
||||
scale_h = lexical_cast_default<int, const std::string&>(scale_params[1]);
|
||||
}
|
||||
if(s > 2) {
|
||||
slice_rect.w = lexical_cast_default<Uint16, const std::string&>(slice_params[2]);
|
||||
}
|
||||
if(s > 3) {
|
||||
slice_rect.h = lexical_cast_default<Uint16, const std::string&>(slice_params[3]);
|
||||
}
|
||||
|
||||
functor_queue.push_back(new crop_function(slice_rect));
|
||||
}
|
||||
else {
|
||||
ERR_DP << "no arguments passed to the ~CROP() function\n";
|
||||
}
|
||||
}
|
||||
else if("BL" == function) { // Blur
|
||||
blur = std::max<int>(0, lexical_cast_default<int>(field));
|
||||
// Scale (SCALE)
|
||||
else if("SCALE" == function) {
|
||||
std::vector<std::string> const& scale_params = utils::split(field, ',', utils::STRIP_SPACES);
|
||||
const size_t s = scale_params.size();
|
||||
if(s) {
|
||||
int w = 0, h = 0;
|
||||
|
||||
w = lexical_cast_default<int, const std::string&>(scale_params[0]);
|
||||
if(s > 1) {
|
||||
h = lexical_cast_default<int, const std::string&>(scale_params[1]);
|
||||
}
|
||||
|
||||
functor_queue.push_back(new scale_function(w, h));
|
||||
}
|
||||
else {
|
||||
ERR_DP << "no arguments passed to the ~SCALE() function\n";
|
||||
}
|
||||
}
|
||||
else if("O" == function) { // Whole-surface opacity change
|
||||
// Gaussian-like blur (BL)
|
||||
else if("BL" == function) {
|
||||
const int depth = std::max<int>(0, lexical_cast_default<int>(field));
|
||||
functor_queue.push_back(new bl_function(depth));
|
||||
}
|
||||
// Opacity-shift (O)
|
||||
else if("O" == function) {
|
||||
const std::string::size_type p100_pos = field.find('%');
|
||||
float num = 0.0f;
|
||||
if(p100_pos == std::string::npos)
|
||||
|
@ -519,82 +578,48 @@ surface locator::load_image_sub_file() const
|
|||
num = lexical_cast_default<float,const std::string&>(parsed_field);
|
||||
num /= 100.0f;
|
||||
}
|
||||
opacity = ftofxp(num);
|
||||
functor_queue.push_back(new o_function(num));
|
||||
}
|
||||
//
|
||||
// ~R(), ~G() and ~B() are the children of ~CS(). Merely syntatic sugar.
|
||||
// Hence they are at the end of the evaluation.
|
||||
//
|
||||
// Red component color-shift (R)
|
||||
else if("R" == function) {
|
||||
cs_r = lexical_cast_default<int>(field);
|
||||
const int r = lexical_cast_default<int>(field);
|
||||
functor_queue.push_back(new cs_function(r,0,0));
|
||||
}
|
||||
// Green component color-shift (G)
|
||||
else if("G" == function) {
|
||||
cs_g = lexical_cast_default<int>(field);
|
||||
const int g = lexical_cast_default<int>(field);
|
||||
functor_queue.push_back(new cs_function(0,g,0));
|
||||
}
|
||||
// Blue component color-shift (B)
|
||||
else if("B" == function) {
|
||||
cs_b = lexical_cast_default<int>(field);
|
||||
const int b = lexical_cast_default<int>(field);
|
||||
functor_queue.push_back(new cs_function(0,0,b));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(rc) {
|
||||
surf = recolor_image(surf,recolor_map);
|
||||
}
|
||||
if(slice) {
|
||||
// yummy, a slice of surface! this needs to get done
|
||||
// before any other geometric transformations
|
||||
if(slice_rect.w == 0) {
|
||||
slice_rect.w = surf->w;
|
||||
}
|
||||
if(slice_rect.h == 0) {
|
||||
slice_rect.h = surf->h;
|
||||
}
|
||||
if(slice_rect.x < 0) {
|
||||
ERR_DP << "start X coordinate of SECTION function is negative - truncating to zero\n";
|
||||
slice_rect.x = 0;
|
||||
}
|
||||
if(slice_rect.y < 0) {
|
||||
ERR_DP << "start Y coordinate of SECTION function is negative - truncating to zero\n";
|
||||
slice_rect.y = 0;
|
||||
}
|
||||
surf = cut_surface(surf, slice_rect);
|
||||
}
|
||||
if(xflip) {
|
||||
surf = flip_surface(surf);
|
||||
}
|
||||
if(yflip) {
|
||||
surf = flop_surface(surf);
|
||||
}
|
||||
if(scale) {
|
||||
const int old_w = surf->w;
|
||||
const int old_h = surf->h;
|
||||
if(scale_w <= 0) {
|
||||
if(scale_w < 0) {
|
||||
ERR_DP << "width of SCALE is negative - resetting to original width\n";
|
||||
}
|
||||
scale_w = old_w;
|
||||
}
|
||||
if(scale_h <= 0) {
|
||||
if(scale_h < 0) {
|
||||
ERR_DP << "height of SCALE is negative - resetting to original height\n";
|
||||
}
|
||||
scale_h = old_h;
|
||||
}
|
||||
|
||||
if(scale_w != old_w || scale_h != old_h) {
|
||||
surf = scale_surface(surf, scale_w, scale_h);
|
||||
if(!rc.no_op()) {
|
||||
surf = rc(surf);
|
||||
}
|
||||
|
||||
if(!fl.no_op()) {
|
||||
surf = fl(surf);
|
||||
}
|
||||
|
||||
foreach(function_base* f, functor_queue) {
|
||||
if(f == NULL) {
|
||||
ERR_DP << "somebody set up us the bomb\n";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(cs_r || cs_g || cs_b) {
|
||||
surf = adjust_surface_colour(surf, cs_r, cs_g, cs_b);
|
||||
}
|
||||
if(greyscale) {
|
||||
surf = greyscale_image(surf);
|
||||
}
|
||||
if(opacity != opacity_unchanged && opacity != opacity_full) {
|
||||
surf = adjust_surface_alpha(surf, opacity);
|
||||
}
|
||||
if(blur) {
|
||||
surf = blur_alpha_surface(surf, blur);
|
||||
surf = (*f)(surf);
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
|
||||
return surf;
|
||||
}
|
||||
|
||||
|
|
114
src/image_function.cpp
Normal file
114
src/image_function.cpp
Normal file
|
@ -0,0 +1,114 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2009 by Ignacio R. Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "image_function.hpp"
|
||||
#include "log.hpp"
|
||||
|
||||
#define ERR_DP LOG_STREAM(err, display)
|
||||
|
||||
namespace image {
|
||||
|
||||
surface rc_function::operator()(const surface& src) const
|
||||
{
|
||||
// unchecked
|
||||
return recolor_image(src, rc_map_);
|
||||
}
|
||||
|
||||
surface fl_function::operator()(const surface& src) const
|
||||
{
|
||||
surface ret = src;
|
||||
|
||||
if(horiz_) {
|
||||
ret = flip_surface(ret);
|
||||
}
|
||||
|
||||
if(vert_) {
|
||||
ret = flop_surface(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
surface gs_function::operator()(const surface& src) const
|
||||
{
|
||||
return greyscale_image(src);
|
||||
}
|
||||
|
||||
surface crop_function::operator()(const surface& src) const
|
||||
{
|
||||
SDL_Rect area = slice_;
|
||||
if(area.w == 0) {
|
||||
area.w = src->w;
|
||||
}
|
||||
if(area.h == 0) {
|
||||
area.h = src->h;
|
||||
}
|
||||
if(area.x < 0) {
|
||||
ERR_DP << "start X coordinate of SECTION function is negative - truncating to zero\n";
|
||||
area.x = 0;
|
||||
}
|
||||
if(area.y < 0) {
|
||||
ERR_DP << "start Y coordinate of SECTION function is negative - truncating to zero\n";
|
||||
area.y = 0;
|
||||
}
|
||||
return cut_surface(src, area);
|
||||
}
|
||||
|
||||
surface scale_function::operator()(const surface& src) const
|
||||
{
|
||||
const int old_w = src->w;
|
||||
const int old_h = src->h;
|
||||
int w = w_;
|
||||
int h = h_;
|
||||
|
||||
if(w <= 0) {
|
||||
if(w < 0) {
|
||||
ERR_DP << "width of SCALE is negative - resetting to original width\n";
|
||||
}
|
||||
w = old_w;
|
||||
}
|
||||
if(h <= 0) {
|
||||
if(h < 0) {
|
||||
ERR_DP << "height of SCALE is negative - resetting to original height\n";
|
||||
}
|
||||
h = old_h;
|
||||
}
|
||||
|
||||
return(
|
||||
(w != old_w || h != old_h) ?
|
||||
scale_surface(src, w, h) :
|
||||
src
|
||||
);
|
||||
}
|
||||
|
||||
surface o_function::operator()(const surface& src) const
|
||||
{
|
||||
return adjust_surface_alpha(src, ftofxp(opacity_));
|
||||
}
|
||||
|
||||
surface cs_function::operator()(const surface& src) const
|
||||
{
|
||||
return(
|
||||
(r_ != 0 || g_ != 0 || b_ != 0) ?
|
||||
adjust_surface_colour(src, r_, g_, b_) :
|
||||
src
|
||||
);
|
||||
}
|
||||
|
||||
surface bl_function::operator()(const surface& src) const
|
||||
{
|
||||
return blur_alpha_surface(src, depth_);
|
||||
}
|
||||
|
||||
} /* end namespace image */
|
192
src/image_function.hpp
Normal file
192
src/image_function.hpp
Normal file
|
@ -0,0 +1,192 @@
|
|||
/* $Id$ */
|
||||
/*
|
||||
Copyright (C) 2009 by Ignacio R. Morelle <shadowm2006@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
or at your option any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/** @file image_function.hpp */
|
||||
|
||||
#ifndef IMAGE_FUNCTION_HPP_INCLUDED
|
||||
#define IMAGE_FUNCTION_HPP_INCLUDED
|
||||
|
||||
#include "sdl_utils.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace image {
|
||||
/**
|
||||
* Base abstract class for an image-path function
|
||||
* It actually just enforces the operator()() protocol.
|
||||
*/
|
||||
class function_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Applies the image-path function on the specified surface.
|
||||
*/
|
||||
virtual surface operator()(const surface& src) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recolor (RC) function.
|
||||
* It is used both for palette switches (e.g. "~RC(pal1=pal2)")
|
||||
* color-range-based recoloring (also known as TC, e.g. "~RC(magenta>teal)")
|
||||
* and team-based recoloring (e.g. "~TC(1,magenta)").
|
||||
*/
|
||||
class rc_function : public function_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default construcotr.
|
||||
*/
|
||||
rc_function()
|
||||
: rc_map_()
|
||||
{}
|
||||
/**
|
||||
* RC-map based constructor.
|
||||
* @param recolor_map The palette switch map.
|
||||
*/
|
||||
rc_function(const std::map<Uint32, Uint32>& recolor_map)
|
||||
: rc_map_(recolor_map)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
bool no_op() const { return rc_map_.empty(); }
|
||||
|
||||
const std::map<Uint32, Uint32>& map() const { return rc_map_;}
|
||||
std::map<Uint32, Uint32>& map() { return rc_map_;}
|
||||
|
||||
private:
|
||||
std::map<Uint32, Uint32> rc_map_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Mirror (FL) function.
|
||||
*/
|
||||
class fl_function : public function_base
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param horiz Horizontal mirror flag.
|
||||
* @param vert Vertical mirror flag.
|
||||
*/
|
||||
fl_function(bool horiz = false, bool vert = false)
|
||||
: horiz_(horiz)
|
||||
, vert_(vert)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
void set_horiz(bool val) { horiz_ = val; }
|
||||
void set_vert(bool val) { vert_ = val; }
|
||||
bool get_horiz() const { return horiz_; }
|
||||
bool get_vert() const { return vert_; }
|
||||
/** Toggle horizontal mirror flag.
|
||||
* @return The new flag state after toggling. */
|
||||
bool toggle_horiz() { return((horiz_ = !horiz_)); }
|
||||
/** Toggle vertical mirror flag.
|
||||
* @return The new flag state after toggling. */
|
||||
bool toggle_vert() { return((vert_ = !vert_)); }
|
||||
|
||||
bool no_op() const { return ((!horiz_) && (!vert_)); }
|
||||
|
||||
private:
|
||||
bool horiz_;
|
||||
bool vert_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Grayscale (GS) function.
|
||||
*/
|
||||
class gs_function : public function_base
|
||||
{
|
||||
public:
|
||||
gs_function() {}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Crop (CROP) function.
|
||||
*/
|
||||
class crop_function : public function_base
|
||||
{
|
||||
public:
|
||||
crop_function(const SDL_Rect& slice)
|
||||
: slice_(slice)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
private:
|
||||
SDL_Rect slice_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Scale (SCALE) function.
|
||||
*/
|
||||
class scale_function : public function_base
|
||||
{
|
||||
public:
|
||||
scale_function(int width, int height)
|
||||
: w_(width), h_(height)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
private:
|
||||
int w_, h_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Opacity (O) function
|
||||
*/
|
||||
class o_function : public function_base
|
||||
{
|
||||
public:
|
||||
o_function(float opacity)
|
||||
: opacity_(opacity)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
private:
|
||||
float opacity_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Color-shift (CS, R, G, B) function.
|
||||
*/
|
||||
class cs_function : public function_base
|
||||
{
|
||||
public:
|
||||
cs_function(int r, int g, int b)
|
||||
: r_(g), g_(g), b_(b)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
private:
|
||||
int r_, g_, b_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gaussian-like blur (BL) function.
|
||||
*/
|
||||
class bl_function : public function_base
|
||||
{
|
||||
public:
|
||||
bl_function(int depth)
|
||||
: depth_(depth)
|
||||
{}
|
||||
virtual surface operator()(const surface& src) const;
|
||||
|
||||
private:
|
||||
int depth_;
|
||||
};
|
||||
|
||||
} /* end namespace image */
|
||||
|
||||
#endif /* !defined(IMAGE_FUNCTION_HPP_INCLUDED) */
|
Loading…
Add table
Reference in a new issue