Refactor color_range to use color_t

Temporarily breaks TC/RC coloring, will fix.
This commit is contained in:
Charles Dang 2016-12-01 21:44:13 +11:00
parent 49155fadd6
commit f2ab245e8d
20 changed files with 282 additions and 284 deletions

View file

@ -1235,7 +1235,7 @@ private:
display* gui = display::get_singleton();
std::string team_name;
color_t color = color_t::from_argb_bytes(team::get_side_rgb(ai_.get_side()));
color_t color = team::get_side_rgb(ai_.get_side());
const terrain_label *res;
res = gui->labels().set_label(location, text, ai_.get_side() - 1, team_name, color);

View file

@ -26,146 +26,102 @@
#include "util.hpp"
#include <iomanip>
#include <unordered_set>
std::map<uint32_t, uint32_t> recolor_range(const color_range& new_range, const std::vector<uint32_t>& old_rgb){
std::map<uint32_t, uint32_t> map_rgb;
color_range_map recolor_range(const color_range& new_range, const std::vector<color_t>& old_rgb)
{
color_range_map map_rgb;
uint16_t new_red = (new_range.mid() & 0x00FF0000)>>16;
uint16_t new_green= (new_range.mid() & 0x0000FF00)>>8;
uint16_t new_blue = (new_range.mid() & 0x000000FF);
uint16_t max_red = (new_range.max() & 0x00FF0000)>>16;
uint16_t max_green= (new_range.max() & 0x0000FF00)>>8 ;
uint16_t max_blue = (new_range.max() & 0x000000FF) ;
uint16_t min_red = (new_range.min() & 0x00FF0000)>>16;
uint16_t min_green= (new_range.min() & 0x0000FF00)>>8 ;
uint16_t min_blue = (new_range.min() & 0x000000FF) ;
const uint16_t new_red = new_range.mid().r;
const uint16_t new_green = new_range.mid().g;
const uint16_t new_blue = new_range.mid().b;
const uint16_t max_red = new_range.max().r;
const uint16_t max_green = new_range.max().g;
const uint16_t max_blue = new_range.max().b;
const uint16_t min_red = new_range.min().r;
const uint16_t min_green = new_range.min().g;
const uint16_t min_blue = new_range.min().b;
// Map first color in vector to exact new color
uint32_t temp_rgb= old_rgb.empty() ? 0 : old_rgb[0];
uint16_t old_r=(temp_rgb & 0X00FF0000)>>16;
uint16_t old_g=(temp_rgb & 0X0000FF00)>>8;
uint16_t old_b=(temp_rgb & 0X000000FF);
uint16_t reference_avg = (( old_r + old_g + old_b) / 3);
const color_t temp_rgb = old_rgb.empty() ? color_t() : old_rgb[0];
for(std::vector< uint32_t >::const_iterator temp_rgb2 = old_rgb.begin();
temp_rgb2 != old_rgb.end(); ++temp_rgb2)
{
old_r=((*temp_rgb2) & 0X00FF0000)>>16;
old_g=((*temp_rgb2) & 0X0000FF00)>>8;
old_b=((*temp_rgb2) & 0X000000FF);
const uint16_t reference_avg = (temp_rgb.r + temp_rgb.g + temp_rgb.b) / 3;
const uint16_t old_avg = (( old_r + old_g + old_b) / 3);
// Calculate new color
uint32_t new_r, new_g, new_b;
for(const auto& old_c : old_rgb) {
const uint16_t old_avg = (old_c.r + old_c.g + old_c.b) / 3;
if(reference_avg && old_avg <= reference_avg){
float old_rat = static_cast<float>(old_avg)/reference_avg;
new_r=uint32_t( old_rat * new_red + (1 - old_rat) * min_red);
new_g=uint32_t( old_rat * new_green + (1 - old_rat) * min_green);
new_b=uint32_t( old_rat * new_blue + (1 - old_rat) * min_blue);
}else if(255 - reference_avg){
float old_rat = (255.0f - static_cast<float>(old_avg)) /
(255.0f - reference_avg);
// Calculate new color
uint32_t new_r = 0, new_g = 0, new_b = 0;
new_r=static_cast<uint32_t>( old_rat * new_red + (1 - old_rat) * max_red);
new_g=static_cast<uint32_t>( old_rat * new_green + (1 - old_rat) * max_green);
new_b=static_cast<uint32_t>( old_rat * new_blue + (1 - old_rat) * max_blue);
}else{
new_r=0; new_g=0; new_b=0; // Suppress warning
assert(false);
if(reference_avg && old_avg <= reference_avg) {
float old_ratio = static_cast<float>(old_avg) / reference_avg;
new_r = static_cast<uint32_t>(old_ratio * new_red + (1 - old_ratio) * min_red);
new_g = static_cast<uint32_t>(old_ratio * new_green + (1 - old_ratio) * min_green);
new_b = static_cast<uint32_t>(old_ratio * new_blue + (1 - old_ratio) * min_blue);
} else if(reference_avg != 255) {
float old_ratio = (255.0f - static_cast<float>(old_avg)) / (255.0f - reference_avg);
new_r = static_cast<uint32_t>(old_ratio * new_red + (1 - old_ratio) * max_red);
new_g = static_cast<uint32_t>(old_ratio * new_green + (1 - old_ratio) * max_green);
new_b = static_cast<uint32_t>(old_ratio * new_blue + (1 - old_ratio) * max_blue);
} else {
// Should never get here.
// Would imply old_avg > reference_avg = 255
}
assert(false);
}
if(new_r>255) new_r=255;
if(new_g>255) new_g=255;
if(new_b>255) new_b=255;
new_r = std::min<uint32_t>(new_r, 255);
new_g = std::min<uint32_t>(new_g, 255);
new_b = std::min<uint32_t>(new_b, 255);
uint32_t newrgb = (new_r << 16) + (new_g << 8) + (new_b );
map_rgb[*temp_rgb2]=newrgb;
map_rgb[old_c] = {static_cast<uint8_t>(new_r), static_cast<uint8_t>(new_g), static_cast<uint8_t>(new_b)};
}
return map_rgb;
}
bool string2rgb(const std::string& s, std::vector<uint32_t>& result) {
result = std::vector<uint32_t>();
std::vector<uint32_t> out;
std::vector<std::string> rgb_vec = utils::split(s);
std::vector<std::string>::iterator c=rgb_vec.begin();
while(c!=rgb_vec.end())
{
uint32_t rgb_hex;
if(c->length() != 6)
{
try {
// integer triplets, e.g. white="255,255,255"
rgb_hex = (0x00FF0000 & (std::stoi(*c++))<<16); //red
if(c!=rgb_vec.end())
{
rgb_hex += (0x0000FF00 & (std::stoi(*c++)<<8)); //green
if(c!=rgb_vec.end())
{
rgb_hex += (0x000000FF & (std::stoi(*c++)<<0)); //blue
}
}
} catch (std::invalid_argument&) {
return false;
}
} else {
// hexadecimal format, e.g. white="FFFFFF"
char* endptr;
rgb_hex = (0x00FFFFFF & strtol(c->c_str(), &endptr, 16));
if (*endptr != '\0') {
return false;
}
++c;
}
out.push_back(rgb_hex);
}
result = out;
return true;
}
std::vector<color_t> palette(const color_range& cr)
{
std::vector<color_t> temp, res;
std::unordered_set<color_t> clist;
std::vector<uint32_t> palette(color_range cr){
// generate a color palette from a color range
std::vector<uint32_t> temp,res;
std::set<uint32_t> clist;
// use blue to make master set of possible colors
for(int i=255;i!=0;i--){
int j=255-i;
uint32_t rgb = i;
temp.push_back(rgb);
rgb = (j << 16) + (j << 8) + 255;
temp.push_back(rgb);
// Use blue to make master set of possible colors
for(int i = 255; i != 0; i--) {
const int j = 255 - i;
temp.emplace_back(0,0,i);
temp.emplace_back(j,j,255);
}
// Use recolor function to generate list of possible colors.
// Could use a special function, would be more efficient,
// but harder to maintain.
std::map<uint32_t,uint32_t> cmap = recolor_range(cr,temp);
for(std::map<uint32_t,uint32_t>::const_iterator k=cmap.begin(); k!=cmap.end();++k){
clist.insert(k->second);
// Could use a special function, would be more efficient, but harder to maintain.
color_range_map cmap = recolor_range(cr, temp);
for(const auto& cm : cmap) {
clist.insert(cm.second);
}
res.push_back(cmap[255]);
for(std::set<uint32_t>::const_iterator c=clist.begin();c!=clist.end();++c){
if(*c != res[0] && *c!=0 && *c != 0x00FFFFFF){
res.push_back(*c);}
res.push_back(cmap[{0,0,255}]);
for(const auto& cs : clist) {
if(cs != res[0] && !cs.null() && cs != color_t(255, 255, 255)) {
res.push_back(cs);
}
}
return(res);
return res;
}
std::string color_range::debug() const
{
std::ostringstream o;
static const uint32_t mask = 0x00FFFFFF;
o << std::hex << std::setfill('0')
<< '{' << std::setw(6) << (mid_ & mask)
<< ',' << std::setw(6) << (max_ & mask)
<< ',' << std::setw(6) << (min_ & mask)
<< ',' << std::setw(6) << (rep_ & mask)
o << '{' << mid_.to_hex_string()
<< ',' << max_.to_hex_string()
<< ',' << min_.to_hex_string()
<< ',' << rep_.to_hex_string()
<< '}';
return o.str();

View file

@ -17,22 +17,21 @@
#ifndef COLOR_RANGE_H_INCLUDED
#define COLOR_RANGE_H_INCLUDED
#include "global.hpp"
#include "sdl/color.hpp"
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
//These macros interfere with MS VC++
#ifdef _MSC_VER
#undef max
#undef min
#endif
#include "global.hpp"
#include <map>
#include <string>
#include <vector>
#include <cstdint>
/* Convert comma separated string into rgb values.
* Return false and empty result on error.
*/
bool string2rgb(const std::string& s, std::vector<uint32_t>& result);
using color_range_map = std::unordered_map<color_t, color_t>;
/**
* A color range definition is made of four reference RGB colors, used
@ -53,73 +52,88 @@ bool string2rgb(const std::string& s, std::vector<uint32_t>& result);
class color_range
{
public:
/**
* Constructor, which expects four reference RGB colors.
* @param mid Average color shade.
* @param max Maximum (highlight) color shade
* @param min Minimum color shade
* @param rep High-contrast reference color
*/
color_range(uint32_t mid , uint32_t max = 0x00FFFFFF , uint32_t min = 0x00000000 , uint32_t rep = 0x00808080):mid_(mid),max_(max),min_(min),rep_(rep){}
/**
* Constructor, which expects four reference RGB colors.
* @param mid Average color shade.
* @param max Maximum (highlight) color shade
* @param min Minimum color shade
* @param rep High-contrast reference color
*/
color_range(color_t mid, color_t max = {255, 255, 255}, color_t min = {0, 0, 0}, color_t rep = {128, 128, 128})
: mid_(mid)
, max_(max)
, min_(min)
, rep_(rep)
{}
/**
* Constructor, which expects four reference RGB colors.
* @param v STL vector with the four reference colors in order.
*/
color_range(const std::vector<uint32_t>& v)
: mid_(v.size() ? v[0] : 0x00808080),
max_(v.size() > 1 ? v[1] : 0x00FFFFFF),
min_(v.size() > 2 ? v[2] : 0x00000000),
rep_(v.size() > 3 ? v[3] : mid_)
{
}
/**
* Constructor, which expects four reference RGB colors.
* @param v STL vector with the four reference colors in order.
*/
color_range(const std::vector<color_t>& v)
: mid_(v.size() ? v[0] : color_t(128, 128, 128))
, max_(v.size() > 1 ? v[1] : color_t(255, 255, 255))
, min_(v.size() > 2 ? v[2] : color_t(0 , 0 , 0 ))
, rep_(v.size() > 3 ? v[3] : mid_)
{}
/** Default constructor. */
color_range() : mid_(0x00808080), max_(0x00FFFFFF), min_(0x00000000), rep_(0x00808080) {}
/** Default constructor. */
color_range()
: mid_(128, 128, 128)
, max_(255, 255, 255)
, min_()
, rep_(128, 128, 128)
{}
/** Average color shade. */
uint32_t mid() const{return(mid_);}
/** Maximum color shade. */
uint32_t max() const{return(max_);}
/** Minimum color shade. */
uint32_t min() const{return(min_);}
/** High-contrast shade, intended for the minimap markers. */
uint32_t rep() const{return(rep_);}
/** Average color shade. */
color_t mid() const { return mid_; }
bool operator<(const color_range& b) const
{
if(mid_ != b.mid()) return(mid_ < b.mid());
if(max_ != b.max()) return(max_ < b.max());
if(min_ != b.min()) return(min_ < b.min());
return(rep_ < b.rep());
}
/** Maximum color shade. */
color_t max() const { return max_; }
bool operator==(const color_range& b) const
{
return(mid_ == b.mid() && max_ == b.max() && min_ == b.min() && rep_ == b.rep());
}
/** Minimum color shade. */
color_t min() const { return min_; }
/** Return a string describing the color range for debug output. */
std::string debug() const;
/** High-contrast shade, intended for the minimap markers. */
color_t rep() const { return rep_; }
bool operator==(const color_range& b) const
{
return mid_ == b.mid() && max_ == b.max() && min_ == b.min() && rep_ == b.rep();
}
bool operator<(const color_range& b) const
{
if(mid_ != b.mid()) { return mid_.to_rgba_bytes() < b.mid().to_rgba_bytes(); }
if(max_ != b.max()) { return max_.to_rgba_bytes() < b.max().to_rgba_bytes(); }
if(min_ != b.min()) { return min_.to_rgba_bytes() < b.min().to_rgba_bytes(); }
return rep_.to_rgba_bytes() < b.rep().to_rgba_bytes();
}
/** Return a string describing the color range for debug output. */
std::string debug() const;
private:
uint32_t mid_ , max_ , min_ , rep_;
color_t mid_ , max_ , min_ , rep_;
};
/**
* Creates a reference color palette from a color range.
*/
std::vector<uint32_t> palette(color_range cr);
std::vector<color_t> palette(const color_range& cr);
/**
* Converts a source palette using the specified color_range object.
* This holds the main interface for range-based team coloring. The output is
* used with the recolor_image() method to do the actual recoloring.
* @param new_rgb Specifies parameters for the conversion.
* @param old_rgb Source palette.
* @return A STL map of colors, with the keys being source palette elements, and the values
* are the result of applying the color range conversion on it.
* This holds the main interface for range-based team coloring. The output is used with the recolor_image()
* method to do the actual recoloring.
*
* @param new_rgb Specifies parameters for the conversion.
* @param old_rgb Source palette.
*
* @return A STL map of colors, with the keys being source palette elements, and the values
* are the result of applying the color range conversion on it.
*/
std::map<uint32_t, uint32_t> recolor_range(const color_range& new_rgb, const std::vector<uint32_t>& old_rgb);
color_range_map recolor_range(const color_range& new_rgb, const std::vector<color_t>& old_rgb);
#endif

View file

@ -1896,20 +1896,20 @@ void display::draw_minimap_units()
if (!preferences::minimap_movement_coding()) {
if (dc_->teams()[currentTeam_].is_enemy(side)) {
col = color_t::from_argb_bytes(game_config::color_info(preferences::enemy_color()).rep());
col = game_config::color_info(preferences::enemy_color()).rep();
} else {
if (currentTeam_ +1 == static_cast<unsigned>(side)) {
if (u->movement_left() == u->total_movement())
col = color_t::from_argb_bytes(game_config::color_info(preferences::unmoved_color()).rep());
col = game_config::color_info(preferences::unmoved_color()).rep();
else if (u->movement_left() == 0)
col = color_t::from_argb_bytes(game_config::color_info(preferences::moved_color()).rep());
col = game_config::color_info(preferences::moved_color()).rep();
else
col = color_t::from_argb_bytes(game_config::color_info(preferences::partial_color()).rep());
col = game_config::color_info(preferences::partial_color()).rep();
} else
col = color_t::from_argb_bytes(game_config::color_info(preferences::allied_color()).rep());
col = game_config::color_info(preferences::allied_color()).rep();
}
}

View file

@ -117,7 +117,7 @@ void display_chat_manager::add_chat_message(const time_t& time, const std::strin
}
color_t speaker_color = {255,255,255,SDL_ALPHA_OPAQUE};
if(side >= 1) {
speaker_color = color_t::from_argb_bytes(team::get_side_color_range(side).mid());
speaker_color = team::get_side_color_range(side).mid();
}
color_t message_color = chat_message_color;

View file

@ -31,7 +31,7 @@ std::string get_pango_color_from_id(const std::string& id)
{
const auto color = game_config::team_rgb_colors.find(id);
if(color != game_config::team_rgb_colors.end()) {
return color_t::from_argb_bytes(color->second[0]).to_hex_string();
return (color->second[0]).to_hex_string();
}
return "";

View file

@ -155,7 +155,7 @@ static std::vector<color_t> blue_white_scale_text;
std::map<std::string, color_range> team_rgb_range;
std::map<std::string, t_string> team_rgb_name;
std::map<std::string, std::vector<uint32_t>> team_rgb_colors;
std::map<std::string, std::vector<color_t>> team_rgb_colors;
std::vector<std::string> default_colors;
@ -349,10 +349,9 @@ void load_config(const config &v)
const std::string& key,
const color_t fallback)->std::vector<color_t>
{
std::vector<std::string> temp = utils::split(v[key].str());
std::vector<color_t> color_vec;
for(const auto& s : temp) {
for(const auto& s : utils::split(v[key].str())) {
try {
color_vec.push_back(color_t::from_hex_string(s));
} catch(std::invalid_argument& e) {
@ -410,41 +409,53 @@ void load_config(const config &v)
}
}
void add_color_info(const config &v)
void add_color_info(const config& v)
{
for(const config& teamC : v.child_range("color_range")) {
const config::attribute_value *a1 = teamC.get("id"),
*a2 = teamC.get("rgb");
if (!a1 || !a2) {
const config::attribute_value* a1 = teamC.get("id"), *a2 = teamC.get("rgb");
if(!a1 || !a2) {
continue;
}
std::string id = *a1;
std::vector<uint32_t> temp;
if(!string2rgb(*a2, temp)) {
std::stringstream ss;
ss << "can't parse color string:\n" << teamC.debug() << "\n";
throw config::error(ss.str());
std::vector<color_t> temp;
for(const auto& s : utils::split(*a2)) {
try {
temp.push_back(color_t::from_hex_string(s));
} catch(std::invalid_argument& e) {
std::stringstream ss;
ss << "can't parse color string:\n" << teamC.debug() << "\n";
throw config::error(ss.str());
}
}
team_rgb_range.insert(std::make_pair(id,color_range(temp)));
team_rgb_range.insert({id, color_range(temp)});
team_rgb_name[id] = teamC["name"];
LOG_NG << "registered color range '" << id << "': " << team_rgb_range[id].debug() << '\n';
// Ggenerate palette of same name;
std::vector<uint32_t> tp = palette(team_rgb_range[id]);
std::vector<color_t> tp = palette(team_rgb_range[id]);
if(tp.empty()) {
continue;
}
team_rgb_colors.insert(std::make_pair(id,tp));
team_rgb_colors.insert({id, tp});
}
for(const config &cp : v.child_range("color_palette")) {
for(const config::attribute& rgb : cp.attribute_range()) {
std::vector<uint32_t> temp;
if(!string2rgb(rgb.second, temp)) {
ERR_NG << "Invalid color palette: " << rgb.second << std::endl;
std::vector<color_t> temp;
for(const auto& s : utils::split(rgb.second)) {
try {
temp.push_back(color_t::from_hex_string(s));
} catch(std::invalid_argument& e) {
ERR_NG << "Invalid color in palette: " << s << std::endl;
}
}
team_rgb_colors.insert(std::make_pair(rgb.first, temp));
team_rgb_colors.insert({rgb.first, temp});
LOG_NG << "registered color palette: " << rgb.first << '\n';
}
}
@ -465,30 +476,34 @@ const color_range& color_info(const std::string& name)
return i->second;
}
std::vector<uint32_t> temp;
if(!string2rgb(name, temp)) {
std::vector<color_t> temp;
try {
temp.push_back(color_t::from_hex_string(name));
} catch(std::invalid_argument& e) {
throw config::error(_("Invalid color range: ") + name);
}
team_rgb_range.insert(std::make_pair(name,color_range(temp)));
team_rgb_range.insert({name, color_range(temp)});
return color_info(name);
}
const std::vector<uint32_t>& tc_info(const std::string& name)
const std::vector<color_t>& tc_info(const std::string& name)
{
auto i = team_rgb_colors.find(name);
if(i != team_rgb_colors.end()) {
return i->second;
}
std::vector<uint32_t> temp;
if(!string2rgb(name, temp)) {
static std::vector<uint32_t> stv;
std::vector<color_t> temp;
try {
temp.push_back(color_t::from_hex_string(name));
} catch(std::invalid_argument& e) {
static std::vector<color_t> stv;
ERR_NG << "Invalid color palette: " << name << std::endl;
return stv;
}
team_rgb_colors.insert(std::make_pair(name,temp));
team_rgb_colors.insert({name, temp});
return tc_info(name);
}

View file

@ -136,7 +136,7 @@ namespace game_config
extern std::map<std::string, color_range> team_rgb_range;
extern std::map<std::string, t_string> team_rgb_name;
extern std::map<std::string, std::vector<uint32_t> > team_rgb_colors;
extern std::map<std::string, std::vector<color_t>> team_rgb_colors;
extern std::vector<std::string> default_colors;
@ -166,7 +166,7 @@ namespace game_config
void load_config(const config &cfg);
void add_color_info(const config& v);
const std::vector<uint32_t>& tc_info(const std::string& name);
const std::vector<color_t>& tc_info(const std::string& name);
const color_range& color_info(const std::string& name);
/**

View file

@ -28,6 +28,7 @@
#include "gui/widgets/window.hpp"
#include "desktop/clipboard.hpp"
#include "font/text_formatting.hpp"
#include "game_events/manager.hpp"
#include "serialization/parser.hpp" // for write()
@ -603,15 +604,15 @@ void event_mode_controller::show_event(tree_view_node& node, bool is_wmi)
static stuff_list_adder add_unit_entry(stuff_list_adder& progress, const unit& u, const display_context& dc)
{
Uint32 team_color = game_config::tc_info(dc.get_team(u.side()).color())[0];
color_t team_color = game_config::tc_info(dc.get_team(u.side()).color())[0];
std::stringstream s;
s << '(' << u.get_location() << ')';
progress.widget("loc", s.str());
s.str("");
s << "<span color='#" << std::hex << team_color << std::dec;
s << "'>side=" << u.side() << "</span>";
s << font::span_color(team_color);
s << "side=" << u.side() << "</span>";
progress.widget("side", s.str(), true);
if(u.can_recruit()) {

View file

@ -19,6 +19,7 @@
#include "utils/functional.hpp"
#include "gettext.hpp"
#include "game_display.hpp"
#include "font/text_formatting.hpp"
#include "map/label.hpp"
#include "resources.hpp"
#include "gui/auxiliary/find_widget.hpp"
@ -91,9 +92,9 @@ void label_settings::pre_show(window& window) {
continue;
}
int team = std::stoi(category.substr(5)) - 1;
Uint32 which_color = game_config::tc_info(viewer.teams()[team].color())[0];
color_t which_color = game_config::tc_info(viewer.teams()[team].color())[0];
std::ostringstream sout;
sout << "<span color='#" << std::hex << which_color << "'>" << name << "</span>";
sout << font::span_color(which_color) << name << "</span>";
name = sout.str();
}

View file

@ -21,7 +21,6 @@
#include "global.hpp"
#include "color_range.hpp"
#include "config.hpp"
#include "filesystem.hpp"
#include "game_config.hpp"

View file

@ -646,12 +646,10 @@ REGISTER_MOD_PARSER(TC, args)
return nullptr;
}
std::map<Uint32, Uint32> rc_map;
color_range_map rc_map;
try {
color_range const& new_color =
game_config::color_info(team_color);
std::vector<Uint32> const& old_color =
game_config::tc_info(params[1]);
const color_range& new_color = game_config::color_info(team_color);
const std::vector<color_t>& old_color = game_config::tc_info(params[1]);
rc_map = recolor_range(new_color,old_color);
}
@ -676,12 +674,10 @@ REGISTER_MOD_PARSER(RC, args)
//
// recolor source palette to color range
//
std::map<Uint32, Uint32> rc_map;
color_range_map rc_map;
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]);
const color_range& new_color = game_config::color_info(recolor_params[1]);
const std::vector<color_t>& old_color = game_config::tc_info(recolor_params[0]);
rc_map = recolor_range(new_color,old_color);
}
@ -715,11 +711,9 @@ REGISTER_MOD_PARSER(PAL, args)
try {
std::map<Uint32, Uint32> rc_map;
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]);
color_range_map rc_map;
const std::vector<color_t>& old_palette = game_config::tc_info(remap_params[0]);
const std::vector<color_t>& new_palette =game_config::tc_info(remap_params[1]);
for(size_t i = 0; i < old_palette.size() && i < new_palette.size(); ++i) {
rc_map[old_palette[i]] = new_palette[i];

View file

@ -17,6 +17,7 @@
#ifndef IMAGE_MODIFICATIONS_HPP_INCLUDED
#define IMAGE_MODIFICATIONS_HPP_INCLUDED
#include "color_range.hpp"
#include "lua_jailbreak_exception.hpp"
#include "sdl/utils.hpp"
#include <queue>
@ -125,7 +126,7 @@ public:
* RC-map based constructor.
* @param recolor_map The palette switch map.
*/
rc_modification(const std::map<Uint32, Uint32>& recolor_map)
rc_modification(const color_range_map& recolor_map)
: rc_map_(recolor_map)
{}
virtual surface operator()(const surface& src) const;
@ -135,11 +136,11 @@ public:
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_;}
const color_range_map& map() const { return rc_map_;}
color_range_map& map() { return rc_map_;}
private:
std::map<Uint32, Uint32> rc_map_;
color_range_map rc_map_;
};
/**

View file

@ -733,7 +733,7 @@ void menu_handler::label_terrain(mouse_handler& mousehandler, bool team_only)
if (team_only) {
team_name = gui_->labels().team_name();
} else {
color = color_t::from_argb_bytes(team::get_side_rgb(gui_->viewing_side()));
color = team::get_side_rgb(gui_->viewing_side());
}
const terrain_label* res = gui_->labels().set_label(loc, label, gui_->viewing_team(), team_name, color);
if (res)

View file

@ -189,7 +189,7 @@ surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::
if (it == game_config::team_rgb_range.end()) {
col = color_t(0,0,0,0);
} else
col = color_t::from_argb_bytes(it->second.rep());
col = it->second.rep();
bool first = true;
const t_translation::ter_list& underlying_terrains = tdata.underlying_union_terrain(terrain);
@ -200,7 +200,7 @@ surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::
if (it == game_config::team_rgb_range.end())
continue;
color_t tmp = color_t::from_argb_bytes(it->second.rep());
color_t tmp = it->second.rep();
if (fogged) {
if (tmp.b < 50) tmp.b = 0;
@ -239,7 +239,7 @@ surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::
int side = (resources::gameboard ? resources::gameboard->village_owner(loc) : -1); //check needed for mp create dialog
color_t col = color_t::from_argb_bytes(game_config::team_rgb_range.find("white")->second.min());
color_t col = game_config::team_rgb_range.find("white")->second.min();
if (!fogged) {
if (side > -1) {
@ -249,11 +249,11 @@ surface getMinimap(int w, int h, const gamemap &map, const team *vw, const std::
} else {
if (vw->owns_village(loc))
col = color_t::from_argb_bytes(game_config::color_info(preferences::unmoved_color()).rep());
col = game_config::color_info(preferences::unmoved_color()).rep();
else if (vw->is_enemy(side + 1))
col = color_t::from_argb_bytes(game_config::color_info(preferences::enemy_color()).rep());
col = game_config::color_info(preferences::enemy_color()).rep();
else
col = color_t::from_argb_bytes(game_config::color_info(preferences::allied_color()).rep());
col = game_config::color_info(preferences::allied_color()).rep();
}
}
}

View file

@ -14,10 +14,11 @@
#ifndef COLOR_T_HPP_INCLUDED
#define COLOR_T_HPP_INCLUDED
#include <algorithm> // for max
#include <cstdint>
#include <ostream>
#include <string>
#include <algorithm> // for max
#include <utility>
#include <SDL.h>
@ -234,4 +235,16 @@ inline std::ostream& operator<<(std::ostream& s, const color_t& c)
return s;
}
namespace std
{
template<>
struct hash<color_t>
{
size_t operator()(const color_t& c) const
{
return c.to_rgba_bytes();
}
};
}
#endif

View file

@ -18,7 +18,6 @@
*/
#include "global.hpp"
#include "color_range.hpp"
#include "sdl/utils.hpp"
#include "sdl/rect.hpp"
@ -1052,42 +1051,47 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
return nsurf;
}
surface recolor_image(surface surf, const std::map<Uint32, Uint32>& map_rgb, bool optimize){
surface recolor_image(surface surf, const color_range_map& map_rgb, bool optimize)
{
if(surf == nullptr)
return nullptr;
if(!map_rgb.empty()){
surface nsurf(make_neutral_surface(surf));
if(nsurf == nullptr) {
std::cerr << "failed to make neutral surface\n";
return nullptr;
}
surface_lock lock(nsurf);
Uint32* beg = lock.pixels();
Uint32* end = beg + nsurf->w*surf->h;
while(beg != end) {
Uint8 alpha = (*beg) >> 24;
if(alpha){ // don't recolor invisible pixels.
// palette use only RGB channels, so remove alpha
Uint32 oldrgb = (*beg) & 0x00FFFFFF;
std::map<Uint32, Uint32>::const_iterator i = map_rgb.find(oldrgb);
if(i != map_rgb.end()){
*beg = (alpha << 24) + i->second;
}
}
++beg;
}
if(optimize) {
adjust_surface_alpha(nsurf, SDL_ALPHA_OPAQUE);
}
return nsurf;
if(map_rgb.empty()) {
return surf;
}
return surf;
surface nsurf(make_neutral_surface(surf));
if(nsurf == nullptr) {
std::cerr << "failed to make neutral surface" << std::endl;
return nullptr;
}
surface_lock lock(nsurf);
Uint32* beg = lock.pixels();
Uint32* end = beg + nsurf->w*surf->h;
while(beg != end) {
Uint8 alpha = (*beg) >> 24;
// Don't recolor invisible pixels.
if(alpha) {
// Palette use only RGB channels, so remove alpha
Uint32 oldrgb = (*beg) & 0x00FFFFFF;
auto i = map_rgb.find(color_t::from_argb_bytes(oldrgb));
if(i != map_rgb.end()) {
*beg = (alpha << 24) | i->second.to_argb_bytes();
}
}
++beg;
}
if(optimize) {
adjust_surface_alpha(nsurf, SDL_ALPHA_OPAQUE);
}
return nsurf;
}
surface brighten_image(const surface &surf, fixed_t amount, bool optimize)

View file

@ -17,6 +17,7 @@
#ifndef SDL_UTILS_INCLUDED
#define SDL_UTILS_INCLUDED
#include "color_range.hpp"
#include "sdl/color.hpp"
#include "util.hpp"
@ -252,8 +253,7 @@ surface swap_channels_image(const surface& surf, channel r, channel g, channel b
* @return A recolored surface, or a null surface if there are
* problems with the source.
*/
surface recolor_image(surface surf, const std::map<Uint32, Uint32>& map_rgb,
bool optimize=true);
surface recolor_image(surface surf, const color_range_map& map_rgb, bool optimize=true);
surface brighten_image(const surface &surf, fixed_t amount, bool optimize=true);

View file

@ -820,19 +820,19 @@ const color_range team::get_side_color_range(int side)
return(gp->second);
}
return(color_range(0x00FF0000,0x00FFFFFF,0x00000000,0x00FF0000));
return color_range({255, 0, 0}, {255, 255, 255}, {0, 0, 0}, {255, 0, 0});
}
color_t team::get_side_color(int side)
{
return color_t::from_argb_bytes(get_side_color_range(side).mid());
return get_side_color_range(side).mid();
}
color_t team::get_minimap_color(int side)
{
// Note: use mid() instead of rep() unless
// high contrast is needed over a map or minimap!
return color_t::from_argb_bytes(get_side_color_range(side).rep());
return get_side_color_range(side).rep();
}
std::string team::get_side_color_index(int side)
@ -850,7 +850,7 @@ std::string team::get_side_color_index(int side)
std::string team::get_side_highlight_pango(int side)
{
return color_t::from_argb_bytes(get_side_color_range(side + 1).mid()).to_hex_string();
return get_side_color_range(side + 1).mid().to_hex_string();
}
void team::log_recruitable() const {

View file

@ -361,9 +361,9 @@ public:
//function which, when given a 1-based side will return the color used by that side.
static const color_range get_side_color_range(int side);
static uint32_t get_side_rgb(int side) { return(get_side_color_range(side).mid()); }
static uint32_t get_side_rgb_max(int side) { return(get_side_color_range(side).max()); }
static uint32_t get_side_rgb_min(int side) { return(get_side_color_range(side).min()); }
static color_t get_side_rgb(int side) { return(get_side_color_range(side).mid()); }
static color_t get_side_rgb_max(int side) { return(get_side_color_range(side).max()); }
static color_t get_side_rgb_min(int side) { return(get_side_color_range(side).min()); }
static color_t get_side_color(int side);
static color_t get_minimap_color(int side);
static std::string get_side_color_index(int side);