The Battle for Wesnoth  1.15.1+dev
color_range.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Generate ranges of colors, and color palettes.
18  * Used e.g. to color HP, XP.
19  */
20 
21 #include "color_range.hpp"
22 
23 #include "map/map.hpp"
24 
25 #include <iomanip>
26 #include <unordered_set>
27 
28 color_range_map recolor_range(const color_range& new_range, const std::vector<color_t>& old_rgb)
29 {
30  color_range_map map_rgb;
31 
32  const uint16_t new_red = new_range.mid().r;
33  const uint16_t new_green = new_range.mid().g;
34  const uint16_t new_blue = new_range.mid().b;
35 
36  const uint16_t max_red = new_range.max().r;
37  const uint16_t max_green = new_range.max().g;
38  const uint16_t max_blue = new_range.max().b;
39 
40  const uint16_t min_red = new_range.min().r;
41  const uint16_t min_green = new_range.min().g;
42  const uint16_t min_blue = new_range.min().b;
43 
44  // Map first color in vector to exact new color
45  const color_t temp_rgb = old_rgb.empty() ? color_t() : old_rgb[0];
46 
47  const uint16_t reference_avg = (temp_rgb.r + temp_rgb.g + temp_rgb.b) / 3;
48 
49  for(const auto& old_c : old_rgb) {
50  const uint16_t old_avg = (old_c.r + old_c.g + old_c.b) / 3;
51 
52  // Calculate new color
53  uint32_t new_r = 0, new_g = 0, new_b = 0;
54 
55  if(reference_avg && old_avg <= reference_avg) {
56  float old_ratio = static_cast<float>(old_avg) / reference_avg;
57 
58  new_r = static_cast<uint32_t>(old_ratio * new_red + (1 - old_ratio) * min_red);
59  new_g = static_cast<uint32_t>(old_ratio * new_green + (1 - old_ratio) * min_green);
60  new_b = static_cast<uint32_t>(old_ratio * new_blue + (1 - old_ratio) * min_blue);
61  } else if(reference_avg != 255) {
62  float old_ratio = (255.0f - static_cast<float>(old_avg)) / (255.0f - reference_avg);
63 
64  new_r = static_cast<uint32_t>(old_ratio * new_red + (1 - old_ratio) * max_red);
65  new_g = static_cast<uint32_t>(old_ratio * new_green + (1 - old_ratio) * max_green);
66  new_b = static_cast<uint32_t>(old_ratio * new_blue + (1 - old_ratio) * max_blue);
67  } else {
68  // Should never get here.
69  // Would imply old_avg > reference_avg = 255
70  assert(false);
71  }
72 
73  new_r = std::min<uint32_t>(new_r, 255);
74  new_g = std::min<uint32_t>(new_g, 255);
75  new_b = std::min<uint32_t>(new_b, 255);
76 
77  map_rgb[old_c] = {static_cast<uint8_t>(new_r), static_cast<uint8_t>(new_g), static_cast<uint8_t>(new_b)};
78  }
79 
80  return map_rgb;
81 }
82 
83 std::vector<color_t> palette(const color_range& cr)
84 {
85  std::vector<color_t> temp, res;
86  std::unordered_set<color_t> clist;
87 
88  // Use blue to make master set of possible colors
89  for(int i = 255; i != 0; i--) {
90  const int j = 255 - i;
91 
92  temp.emplace_back(static_cast<uint8_t>(0), static_cast<uint8_t>(0), static_cast<uint8_t>(i));
93  temp.emplace_back(static_cast<uint8_t>(j), static_cast<uint8_t>(j), static_cast<uint8_t>(255));
94  }
95 
96  // Use recolor function to generate list of possible colors.
97  // Could use a special function, would be more efficient, but harder to maintain.
98  color_range_map cmap = recolor_range(cr, temp);
99  for(const auto& cm : cmap) {
100  clist.insert(cm.second);
101  }
102 
103  res.push_back(cmap[{0,0,255}]);
104 
105  for(const auto& cs : clist) {
106  if(cs != res[0] && !cs.null() && cs != color_t(255, 255, 255)) {
107  res.push_back(cs);
108  }
109  }
110 
111  return res;
112 }
113 
114 std::string color_range::debug() const
115 {
116  std::ostringstream o;
117 
118  o << '{' << mid_.to_hex_string()
119  << ',' << max_.to_hex_string()
120  << ',' << min_.to_hex_string()
121  << ',' << rep_.to_hex_string()
122  << '}';
123 
124  return o.str();
125 }
color_t min() const
Minimum color shade.
Definition: color_range.hpp:93
std::vector< color_t > palette(const color_range &cr)
Creates a reference color palette from a color range.
Definition: color_range.cpp:83
color_t min_
uint8_t r
Red value.
Definition: color.hpp:177
color_t mid_
color_range_map recolor_range(const color_range &new_range, const std::vector< color_t > &old_rgb)
Converts a source palette using the specified color_range object.
Definition: color_range.cpp:28
std::unordered_map< color_t, color_t > color_range_map
Definition: color_range.hpp:32
color_t max() const
Maximum color shade.
Definition: color_range.hpp:90
std::size_t i
Definition: function.cpp:933
color_t max_
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:97
A color range definition is made of four reference RGB colors, used for calculating conversions from ...
Definition: color_range.hpp:50
std::string debug() const
Return a string describing the color range for debug output.
color_t rep_
uint8_t g
Green value.
Definition: color.hpp:180
uint8_t b
Blue value.
Definition: color.hpp:183
color_t mid() const
Average color shade.
Definition: color_range.hpp:87