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