The Battle for Wesnoth  1.19.5+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 __cpp_lib_span
29 #include <span>
30 #endif
31 
32 namespace
33 {
34 #ifdef __cpp_lib_span
35 std::vector<color_t> recolor_range_impl(const color_range& new_range, std::span<const 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<uint32_t>(255u, old_ratio * mid_c.r + (1 - old_ratio) * min_c.r),
61  std::min<uint32_t>(255u, old_ratio * mid_c.g + (1 - old_ratio) * min_c.g),
62  std::min<uint32_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<uint32_t>(255u, old_ratio * mid_c.r + (1 - old_ratio) * max_c.r),
69  std::min<uint32_t>(255u, old_ratio * mid_c.g + (1 - old_ratio) * max_c.g),
70  std::min<uint32_t>(255u, old_ratio * mid_c.b + (1 - old_ratio) * max_c.b)
71  );
72  }
73  }
74 
75  return clist;
76 }
77 
78 constexpr auto base_palette = []() {
79  // Two entries per color, except on the first iteration.
80  std::array<color_t, (255 * 2) - 1> res;
81  std::size_t index = 0;
82 
83  // Use blue to make master set of possible colors
84  for(uint8_t i = 255u; i != 0; --i) {
85  res[index++] = {0, 0, i};
86 
87  // Avoid duplicate entries on the first pass when i == j
88  if(uint8_t j = 255u - i; j != 0) {
89  res[index++] = {j, j, 255};
90  }
91  }
92 
93  return res;
94 }();
95 
96 } // end anon namespace
97 
98 color_range_map recolor_range(const color_range& new_range, const std::vector<color_t>& old_rgb)
99 {
100  auto new_rgb = recolor_range_impl(new_range, old_rgb);
101  assert(new_rgb.size() == old_rgb.size());
102 
103  color_range_map res;
104  for(std::size_t i = 0; i < new_rgb.size(); ++i) {
105  res[old_rgb[i]] = new_rgb[i];
106  }
107 
108  return res;
109 }
110 
111 std::vector<color_t> palette(const color_range& cr)
112 {
113  return recolor_range_impl(cr, base_palette);
114 }
115 
116 std::string color_range::debug() const
117 {
118  std::ostringstream o;
119 
120  o << '{' << mid_.to_hex_string()
121  << ',' << max_.to_hex_string()
122  << ',' << min_.to_hex_string()
123  << ',' << rep_.to_hex_string()
124  << '}';
125 
126  return o.str();
127 }
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.
Definition: color_range.cpp:98
std::unordered_map< color_t, color_t > color_range_map
Definition: color_range.hpp:30
std::size_t i
Definition: function.cpp:1028
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:88