The Battle for Wesnoth  1.19.10+dev
color_range.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2025
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 "utils/span.hpp"
25 
26 #include <array>
27 #include <cassert>
28 #include <sstream>
29 
30 namespace
31 {
32 std::vector<color_t> recolor_range_impl(const color_range& new_range, utils::span<const color_t> old_rgb)
33 {
34  std::vector<color_t> clist;
35  clist.reserve(old_rgb.size());
36 
37  const color_t mid_c = new_range.mid();
38  const color_t max_c = new_range.max();
39  const color_t min_c = new_range.min();
40 
41  // Map first color in vector to exact new color
42  const uint8_t reference_avg = old_rgb.empty()
43  ? 255u
44  : (old_rgb[0].r + old_rgb[0].g + old_rgb[0].b) / 3;
45 
46  for(const color_t& old_c : old_rgb) {
47  const uint8_t old_avg = (old_c.r + old_c.g + old_c.b) / 3;
48 
49  if(reference_avg && old_avg <= reference_avg) {
50  float old_ratio = static_cast<float>(old_avg) / reference_avg;
51 
52  clist.emplace_back(
53  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.r + (1 - old_ratio) * min_c.r)),
54  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.g + (1 - old_ratio) * min_c.g)),
55  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.b + (1 - old_ratio) * min_c.b))
56  );
57  } else if(reference_avg != 255) {
58  float old_ratio = (255.0f - static_cast<float>(old_avg)) / (255.0f - reference_avg);
59 
60  clist.emplace_back(
61  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.r + (1 - old_ratio) * max_c.r)),
62  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.g + (1 - old_ratio) * max_c.g)),
63  std::min(255u, static_cast<uint32_t>(old_ratio * mid_c.b + (1 - old_ratio) * max_c.b))
64  );
65  }
66  }
67 
68  return clist;
69 }
70 
71 constexpr auto base_palette = []() {
72  // Two entries per color, except on the first iteration.
73  std::array<color_t, (255 * 2) - 1> res;
74  std::size_t index = 0;
75 
76  // Use blue to make master set of possible colors
77  for(uint8_t i = 255u; i != 0; --i) {
78  res[index++] = {0, 0, i};
79 
80  // Avoid duplicate entry on the first pass when j == 0
81  if(uint8_t j = 255u - i; j != 0) {
82  res[index++] = {j, j, 255};
83  }
84  }
85 
86  return res;
87 }();
88 
89 } // end anon namespace
90 
91 color_range_map recolor_range(const color_range& new_range, const std::vector<color_t>& old_rgb)
92 {
93  auto new_rgb = recolor_range_impl(new_range, old_rgb);
94  assert(new_rgb.size() == old_rgb.size());
95 
96  color_range_map res;
97  for(std::size_t i = 0; i < new_rgb.size(); ++i) {
98  res[old_rgb[i]] = new_rgb[i];
99  }
100 
101  return res;
102 }
103 
104 std::vector<color_t> palette(const color_range& cr)
105 {
106  return recolor_range_impl(cr, base_palette);
107 }
108 
109 std::string color_range::debug() const
110 {
111  std::ostringstream o;
112 
113  o << '{' << mid_.to_hex_string()
114  << ',' << max_.to_hex_string()
115  << ',' << min_.to_hex_string()
116  << ',' << rep_.to_hex_string()
117  << '}';
118 
119  return o.str();
120 }
constexpr bool empty() const noexcept
Definition: span.hpp:363
constexpr size_type size() const noexcept
Definition: span.hpp:355
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:91
std::unordered_map< color_t, color_t > color_range_map
Definition: color_range.hpp:30
std::size_t i
Definition: function.cpp:1030
std::size_t index(std::string_view 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:61
std::string to_hex_string() const
Returns the stored color in rrggbb hex format.
Definition: color.cpp:88