/* $Id$ */ /* Copyright (C) 2003 - 2009 by David White 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 color_range.cpp * Generate ranges of colors, and color palettes. * Used e.g. to color HP, XP. */ #include "color_range.hpp" #include "game_config.hpp" #include "global.hpp" #include "map.hpp" #include "serialization/string_utils.hpp" #include "util.hpp" #include #include std::map recolor_range(const color_range& new_range, const std::vector& old_rgb){ std::map map_rgb; Uint16 new_red = (new_range.mid() & 0x00FF0000)>>16; Uint16 new_green= (new_range.mid() & 0x0000FF00)>>8; Uint16 new_blue = (new_range.mid() & 0x000000FF); Uint16 max_red = (new_range.max() & 0x00FF0000)>>16; Uint16 max_green= (new_range.max() & 0x0000FF00)>>8 ; Uint16 max_blue = (new_range.max() & 0x000000FF) ; Uint16 min_red = (new_range.min() & 0x00FF0000)>>16; Uint16 min_green= (new_range.min() & 0x0000FF00)>>8 ; Uint16 min_blue = (new_range.min() & 0x000000FF) ; // Map first color in vector to exact new color Uint32 temp_rgb= old_rgb.empty() ? 0 : old_rgb[0]; Uint16 old_r=(temp_rgb & 0X00FF0000)>>16; Uint16 old_g=(temp_rgb & 0X0000FF00)>>8; Uint16 old_b=(temp_rgb & 0X000000FF); Uint16 reference_avg = (( old_r + old_g + old_b) / 3); for(std::vector< Uint32 >::const_iterator temp_rgb2 = old_rgb.begin(); temp_rgb2 != old_rgb.end(); ++temp_rgb2) { Uint16 old_r=((*temp_rgb2) & 0X00FF0000)>>16; Uint16 old_g=((*temp_rgb2) & 0X0000FF00)>>8; Uint16 old_b=((*temp_rgb2) & 0X000000FF); const Uint16 old_avg = (( old_r + old_g + old_b) / 3); // Calculate new color Uint32 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( old_rat * new_red + (1 - old_rat) * min_red); new_g=Uint32( old_rat * new_green + (1 - old_rat) * min_green); new_b=Uint32( 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); // Should never get here. // Would imply old_avg > reference_avg = 255 } if(new_r>255) new_r=255; if(new_g>255) new_g=255; if(new_b>255) new_b=255; Uint32 newrgb = (new_r << 16) + (new_g << 8) + (new_b ); map_rgb[*temp_rgb2]=newrgb; } return map_rgb; } std::vector string2rgb(std::string s){ std::vector out; std::vector rgb_vec = utils::split(s); std::vector::iterator c=rgb_vec.begin(); while(c!=rgb_vec.end()) { Uint32 rgb_hex; if(c->length() != 6) { // integer triplets, e.g. white="255,255,255" rgb_hex = (0x00FF0000 & ((lexical_cast(*c++))<<16)); //red if(c!=rgb_vec.end()) { rgb_hex += (0x0000FF00 & ((lexical_cast(*c++))<<8)); //green if(c!=rgb_vec.end()) { rgb_hex += (0x000000FF & ((lexical_cast(*c++))<<0)); //blue } } } else { // hexadecimal format, e.g. white="FFFFFF" char* endptr; rgb_hex = (0x00FFFFFF & strtol(c->c_str(), &endptr, 16)); if (*endptr != '\0') { throw bad_lexical_cast(); } c++; } out.push_back(rgb_hex); } return(out); } 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 rgb = i; temp.push_back(rgb); rgb = (j << 16) + (j << 8) + 255; temp.push_back(rgb); } // 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); } 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);} } return(res); } std::string rgb2highlight(Uint32 rgb) { std::stringstream h(""); // Must match what the escape interpreter for marked-up-text expects h << "<" << ((rgb & 0xFF0000) >> 16) << "," << ((rgb & 0x00FF00) >> 8) << "," << (rgb & 0x0000FF) << ">"; return h.str(); } int color_range::index() const { for(int i = 1; i <= gamemap::MAX_PLAYERS; ++i) { if(*this==(game_config::color_info(lexical_cast(i)))) { return i; } } return 0; }