The Battle for Wesnoth  1.19.2+dev
color_range.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
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 <array>
25 #include <cassert>
26 #include <sstream>
27 
28 #ifdef HAVE_CXX20
29 #include <span>
30 #endif
31 
32 namespace
33 {
34 #ifdef HAVE_CXX20
35 std::vector<color_t> recolor_range_impl(const color_range& new_range, std::span<color_t> old_rgb)
36 #else
37 template<typename Container>
38 std::vector<color_t> recolor_range_impl(const color_range& new_range, const Container& old_rgb)
39 #endif
40 {
41  std::vector<color_t> clist;
42  clist.reserve(old_rgb.size());
43 
44  const color_t mid_c = new_range.mid();
45  const color_t max_c = new_range.max();
46  const color_t min_c = new_range.min();
47 
48  // Map first color in vector to exact new color
49  const uint8_t reference_avg = old_rgb.empty()
50  ? 255u
51  : (old_rgb[0].r + old_rgb[0].g + old_rgb[0].b) / 3;
52 
53  for(const color_t& old_c : old_rgb) {
54  const uint8_t old_avg = (old_c.r + old_c.g + old_c.b) / 3;
55 
56  if(reference_avg && old_avg <= reference_avg) {
57  float old_ratio = static_cast<float>(old_avg) / reference_avg;
58 
59  clist.emplace_back(
60  std::min<uint8_t>(255u, old_ratio * mid_c.r + (1 - old_ratio) * min_c.r),
61  std::min<uint8_t>(255u, old_ratio * mid_c.g + (1 - old_ratio) * min_c.g),
62  std::min<uint8_t>(255u, old_ratio * mid_c.b + (1 - old_ratio) * min_c.b)
63  );
64  } else if(reference_avg != 255) {
65  float old_ratio = (255.0f - static_cast<float>(old_avg)) / (255.0f - reference_avg);
66 
67  clist.emplace_back(
68  std::min<uint8_t>(255u, old_ratio * mid_c.r + (1 - old_ratio) * max_c.r),
69  std::min<uint8_t>(255u, old_ratio * mid_c.g + (1 - old_ratio) * max_c.r),
70  std::min<uint8_t>(255u, old_ratio * mid_c.b + (1 - old_ratio) * max_c.r)
71  );
72  } else {
73  // Should never get here. Would imply old_avg > reference_avg = 255
74  assert(false);
75  }
76  }
77 
78  return clist;
79 }
80 
81 constexpr auto base_palette = []() {
82  // Two entries per color, except on the first iteration.
83  std::array<color_t, (255 * 2) - 1> res;
84  std::size_t index = 0;
85 
86  // Use blue to make master set of possible colors
87  for(uint8_t i = 255u; i != 0; --i) {
88  res[index++] = {0, 0, i};
89 
90  // Avoid duplicate entries on the first pass when i == j
91  if(uint8_t j = 255u - i; j != 0) {
92  res[index++] = {j, j, 255};
93  }
94  }
95 
96  return res;
97 }();
98 
99 } // end anon namespace
100 
101 color_range_map recolor_range(const color_range& new_range, const std::vector<color_t>& old_rgb)
102 {
103  auto new_rgb = recolor_range_impl(new_range, old_rgb);
104  assert(new_rgb.size() == old_rgb.size());
105 
106  color_range_map res;
107  for(std::size_t i = 0; i < new_rgb.size(); ++i) {
108  res[old_rgb[i]] = new_rgb[i];
109  }
110 
111  return res;
112 }
113 
114 std::vector<color_t> palette(const color_range& cr)
115 {
116  return recolor_range_impl(cr, base_palette);
117 }
118 
119 std::string color_range::debug() const
120 {
121  std::ostringstream o;
122 
123  o << '{' << mid_.to_hex_string()
124  << ',' << max_.to_hex_string()
125  << ',' << min_.to_hex_string()
126  << ',' << rep_.to_hex_string()
127  << '}';
128 
129  return o.str();
130 }
A color range definition is made of four reference RGB colors, used for calculating conversions from ...
Definition: color_range.hpp:49
color_t max() const
Maximum color shade.
Definition: color_range.hpp:88
color_t max_
color_t min_
color_t mid_
color_t mid() const
Average color shade.
Definition: color_range.hpp:85
color_t rep_
color_t min() const
Minimum color shade.
Definition: color_range.hpp:91
std::string debug() const
Return a string describing the color range for debug output.
std::vector< color_t > palette(const color_range &cr)
Creates a reference color palette from a color range.
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.
std::unordered_map< color_t, color_t > color_range_map
Definition: color_range.hpp:30
std::size_t i
Definition: function.cpp:968
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:84