diff --git a/src/ai/formula/function_table.cpp b/src/ai/formula/function_table.cpp index 33674c6bcc99..6a29ece85ed9 100644 --- a/src/ai/formula/function_table.cpp +++ b/src/ai/formula/function_table.cpp @@ -1235,7 +1235,7 @@ class debug_label_function : public function_expression { 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); diff --git a/src/color_range.cpp b/src/color_range.cpp index 9bac83600098..896d6963f0f3 100644 --- a/src/color_range.cpp +++ b/src/color_range.cpp @@ -26,146 +26,102 @@ #include "util.hpp" #include +#include -std::map recolor_range(const color_range& new_range, const std::vector& old_rgb){ - std::map map_rgb; +color_range_map recolor_range(const color_range& new_range, const std::vector& old_rgb) +{ + color_range_map map_rgb; + + 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; - 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 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); - - 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 old_avg = (( old_r + old_g + old_b) / 3); - // Calculate new color - uint32_t new_r, new_g, new_b; - - if(reference_avg && old_avg <= reference_avg){ - float old_rat = static_cast(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(old_avg)) / - (255.0f - reference_avg); - - new_r=static_cast( old_rat * new_red + (1 - old_rat) * max_red); - new_g=static_cast( old_rat * new_green + (1 - old_rat) * max_green); - new_b=static_cast( old_rat * new_blue + (1 - old_rat) * max_blue); - }else{ - new_r=0; new_g=0; new_b=0; // Suppress warning - assert(false); + const color_t temp_rgb = old_rgb.empty() ? color_t() : old_rgb[0]; + + const uint16_t reference_avg = (temp_rgb.r + temp_rgb.g + temp_rgb.b) / 3; + + for(const auto& old_c : old_rgb) { + const uint16_t old_avg = (old_c.r + old_c.g + old_c.b) / 3; + + // Calculate new color + uint32_t new_r = 0, new_g = 0, new_b = 0; + + if(reference_avg && old_avg <= reference_avg) { + float old_ratio = static_cast(old_avg) / reference_avg; + + new_r = static_cast(old_ratio * new_red + (1 - old_ratio) * min_red); + new_g = static_cast(old_ratio * new_green + (1 - old_ratio) * min_green); + new_b = static_cast(old_ratio * new_blue + (1 - old_ratio) * min_blue); + } else if(reference_avg != 255) { + float old_ratio = (255.0f - static_cast(old_avg)) / (255.0f - reference_avg); + + new_r = static_cast(old_ratio * new_red + (1 - old_ratio) * max_red); + new_g = static_cast(old_ratio * new_green + (1 - old_ratio) * max_green); + new_b = static_cast(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(new_r, 255); + new_g = std::min(new_g, 255); + new_b = std::min(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(new_r), static_cast(new_g), static_cast(new_b)}; } return map_rgb; } -bool string2rgb(const std::string& s, std::vector& result) { - result = std::vector(); - std::vector out; - std::vector rgb_vec = utils::split(s); - std::vector::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 palette(const color_range& cr) +{ + std::vector temp, res; + std::unordered_set clist; -std::vector palette(color_range cr){ -// generate a color palette from a color range - std::vector temp,res; - std::set 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 cmap = recolor_range(cr,temp); - for(std::map::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::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(); diff --git a/src/color_range.hpp b/src/color_range.hpp index 606f7547e351..c4e90ee89669 100644 --- a/src/color_range.hpp +++ b/src/color_range.hpp @@ -17,22 +17,21 @@ #ifndef COLOR_RANGE_H_INCLUDED #define COLOR_RANGE_H_INCLUDED +#include "global.hpp" +#include "sdl/color.hpp" + +#include +#include +#include +#include + //These macros interfere with MS VC++ #ifdef _MSC_VER #undef max #undef min #endif -#include "global.hpp" -#include -#include -#include -#include - -/* Convert comma separated string into rgb values. - * Return false and empty result on error. - */ -bool string2rgb(const std::string& s, std::vector& result); +using color_range_map = std::unordered_map; /** * A color range definition is made of four reference RGB colors, used @@ -53,73 +52,88 @@ bool string2rgb(const std::string& s, std::vector& 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 v STL vector with the four reference colors in order. - */ - color_range(const std::vector& 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_) - { - } - - /** Default constructor. */ - color_range() : mid_(0x00808080), max_(0x00FFFFFF), min_(0x00000000), rep_(0x00808080) {} - - /** 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_);} - - 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()); - } - - bool operator==(const color_range& b) const - { - return(mid_ == b.mid() && max_ == b.max() && min_ == b.min() && rep_ == b.rep()); - } - - /** Return a string describing the color range for debug output. */ - std::string debug() const; + /** + * 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& 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_(128, 128, 128) + , max_(255, 255, 255) + , min_() + , rep_(128, 128, 128) + {} + + /** Average color shade. */ + color_t mid() const { return mid_; } + + /** Maximum color shade. */ + color_t max() const { return max_; } + + /** Minimum color shade. */ + color_t min() const { return min_; } + + /** 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 palette(color_range cr); +std::vector 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 recolor_range(const color_range& new_rgb, const std::vector& old_rgb); +color_range_map recolor_range(const color_range& new_rgb, const std::vector& old_rgb); #endif diff --git a/src/display.cpp b/src/display.cpp index 05dd37c150ad..85af4eaabad9 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -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(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(); } } diff --git a/src/display_chat_manager.cpp b/src/display_chat_manager.cpp index 709705dcfa4a..24e2253a3635 100644 --- a/src/display_chat_manager.cpp +++ b/src/display_chat_manager.cpp @@ -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; diff --git a/src/font/text_formatting.cpp b/src/font/text_formatting.cpp index a6185722f50d..f8887466e135 100644 --- a/src/font/text_formatting.cpp +++ b/src/font/text_formatting.cpp @@ -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 ""; diff --git a/src/game_config.cpp b/src/game_config.cpp index 72e33f5af9ce..e7803af6a508 100644 --- a/src/game_config.cpp +++ b/src/game_config.cpp @@ -155,7 +155,7 @@ static std::vector blue_white_scale_text; std::map team_rgb_range; std::map team_rgb_name; -std::map> team_rgb_colors; +std::map> team_rgb_colors; std::vector default_colors; @@ -349,10 +349,9 @@ void load_config(const config &v) const std::string& key, const color_t fallback)->std::vector { - std::vector temp = utils::split(v[key].str()); std::vector 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 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 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 tp = palette(team_rgb_range[id]); + std::vector 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 temp; - if(!string2rgb(rgb.second, temp)) { - ERR_NG << "Invalid color palette: " << rgb.second << std::endl; + std::vector 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 temp; - if(!string2rgb(name, temp)) { + std::vector 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& tc_info(const std::string& name) +const std::vector& tc_info(const std::string& name) { auto i = team_rgb_colors.find(name); if(i != team_rgb_colors.end()) { return i->second; } - std::vector temp; - if(!string2rgb(name, temp)) { - static std::vector stv; + std::vector temp; + try { + temp.push_back(color_t::from_hex_string(name)); + } catch(std::invalid_argument& e) { + static std::vector 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); } diff --git a/src/game_config.hpp b/src/game_config.hpp index 0a6198902085..81e5da1bdf16 100644 --- a/src/game_config.hpp +++ b/src/game_config.hpp @@ -136,7 +136,7 @@ namespace game_config extern std::map team_rgb_range; extern std::map team_rgb_name; - extern std::map > team_rgb_colors; + extern std::map> team_rgb_colors; extern std::vector 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& tc_info(const std::string& name); + const std::vector& tc_info(const std::string& name); const color_range& color_info(const std::string& name); /** diff --git a/src/gui/dialogs/gamestate_inspector.cpp b/src/gui/dialogs/gamestate_inspector.cpp index 6271994e11b2..3e2ae0a0e58e 100644 --- a/src/gui/dialogs/gamestate_inspector.cpp +++ b/src/gui/dialogs/gamestate_inspector.cpp @@ -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 << "side=" << u.side() << ""; + s << font::span_color(team_color); + s << "side=" << u.side() << ""; progress.widget("side", s.str(), true); if(u.can_recruit()) { diff --git a/src/gui/dialogs/label_settings.cpp b/src/gui/dialogs/label_settings.cpp index 9aa5dcc4c534..a68f825da799 100644 --- a/src/gui/dialogs/label_settings.cpp +++ b/src/gui/dialogs/label_settings.cpp @@ -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 << "" << name << ""; + sout << font::span_color(which_color) << name << ""; name = sout.str(); } diff --git a/src/image.cpp b/src/image.cpp index e3e0169f4a14..6faa49396a3b 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -21,7 +21,6 @@ #include "global.hpp" -#include "color_range.hpp" #include "config.hpp" #include "filesystem.hpp" #include "game_config.hpp" diff --git a/src/image_modifications.cpp b/src/image_modifications.cpp index 0c102b05cc8c..a4c2382f7e5d 100644 --- a/src/image_modifications.cpp +++ b/src/image_modifications.cpp @@ -646,12 +646,10 @@ REGISTER_MOD_PARSER(TC, args) return nullptr; } - std::map rc_map; + color_range_map rc_map; try { - color_range const& new_color = - game_config::color_info(team_color); - std::vector const& old_color = - game_config::tc_info(params[1]); + const color_range& new_color = game_config::color_info(team_color); + const std::vector& 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 rc_map; + color_range_map rc_map; try { - color_range const& new_color = - game_config::color_info(recolor_params[1]); - std::vector 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& 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 rc_map; - std::vector const& old_palette = - game_config::tc_info(remap_params[0]); - std::vector const& new_palette = - game_config::tc_info(remap_params[1]); + color_range_map rc_map; + const std::vector& old_palette = game_config::tc_info(remap_params[0]); + const std::vector& 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]; diff --git a/src/image_modifications.hpp b/src/image_modifications.hpp index 750849bdeeb3..ebecc34eb8b6 100644 --- a/src/image_modifications.hpp +++ b/src/image_modifications.hpp @@ -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 @@ -125,7 +126,7 @@ class rc_modification : public modification * RC-map based constructor. * @param recolor_map The palette switch map. */ - rc_modification(const std::map& 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 @@ class rc_modification : public modification bool no_op() const { return rc_map_.empty(); } - const std::map& map() const { return rc_map_;} - std::map& map() { return rc_map_;} + const color_range_map& map() const { return rc_map_;} + color_range_map& map() { return rc_map_;} private: - std::map rc_map_; + color_range_map rc_map_; }; /** diff --git a/src/menu_events.cpp b/src/menu_events.cpp index fde165e70313..8850c363b286 100644 --- a/src/menu_events.cpp +++ b/src/menu_events.cpp @@ -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) diff --git a/src/minimap.cpp b/src/minimap.cpp index da466d0c98a7..f67ee2763eb9 100644 --- a/src/minimap.cpp +++ b/src/minimap.cpp @@ -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(); } } } diff --git a/src/sdl/color.hpp b/src/sdl/color.hpp index 1cbd60e4d827..37af74eedab0 100644 --- a/src/sdl/color.hpp +++ b/src/sdl/color.hpp @@ -14,10 +14,11 @@ #ifndef COLOR_T_HPP_INCLUDED #define COLOR_T_HPP_INCLUDED +#include // for max #include #include #include -#include // for max +#include #include @@ -234,4 +235,16 @@ inline std::ostream& operator<<(std::ostream& s, const color_t& c) return s; } +namespace std +{ + template<> + struct hash + { + size_t operator()(const color_t& c) const + { + return c.to_rgba_bytes(); + } + }; +} + #endif diff --git a/src/sdl/utils.cpp b/src/sdl/utils.cpp index 1ff6e0434834..1ce46cee7003 100644 --- a/src/sdl/utils.cpp +++ b/src/sdl/utils.cpp @@ -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& 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; - } + if(map_rgb.empty()) { + return surf; + } - surface_lock lock(nsurf); - Uint32* beg = lock.pixels(); - Uint32* end = beg + nsurf->w*surf->h; + surface nsurf(make_neutral_surface(surf)); + if(nsurf == nullptr) { + std::cerr << "failed to make neutral surface" << std::endl; + return nullptr; + } - while(beg != end) { - Uint8 alpha = (*beg) >> 24; + surface_lock lock(nsurf); + Uint32* beg = lock.pixels(); + Uint32* end = beg + nsurf->w*surf->h; - if(alpha){ // don't recolor invisible pixels. - // palette use only RGB channels, so remove alpha - Uint32 oldrgb = (*beg) & 0x00FFFFFF; - std::map::const_iterator i = map_rgb.find(oldrgb); - if(i != map_rgb.end()){ - *beg = (alpha << 24) + i->second; - } + 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); - } + ++beg; + } - return nsurf; + if(optimize) { + adjust_surface_alpha(nsurf, SDL_ALPHA_OPAQUE); } - return surf; + + return nsurf; } surface brighten_image(const surface &surf, fixed_t amount, bool optimize) diff --git a/src/sdl/utils.hpp b/src/sdl/utils.hpp index a50c39afe0ab..da24fddc8843 100644 --- a/src/sdl/utils.hpp +++ b/src/sdl/utils.hpp @@ -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& 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); diff --git a/src/team.cpp b/src/team.cpp index 738e81333132..76c6670ae885 100644 --- a/src/team.cpp +++ b/src/team.cpp @@ -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 { diff --git a/src/team.hpp b/src/team.hpp index 9894be3c23b9..142970a159ec 100644 --- a/src/team.hpp +++ b/src/team.hpp @@ -361,9 +361,9 @@ class team //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);