/ src / common / color.h
color.h
  1  // Copyright 2014 Citra Emulator Project
  2  // Licensed under GPLv2 or any later version
  3  // Refer to the license.txt file included.
  4  
  5  #pragma once
  6  
  7  #include <cstring>
  8  
  9  #include "common/common_types.h"
 10  #include "common/swap.h"
 11  #include "common/vector_math.h"
 12  
 13  namespace Common::Color {
 14  
 15  /// Convert a 1-bit color component to 8 bit
 16  [[nodiscard]] constexpr u8 Convert1To8(u8 value) {
 17      return value * 255;
 18  }
 19  
 20  /// Convert a 4-bit color component to 8 bit
 21  [[nodiscard]] constexpr u8 Convert4To8(u8 value) {
 22      return (value << 4) | value;
 23  }
 24  
 25  /// Convert a 5-bit color component to 8 bit
 26  [[nodiscard]] constexpr u8 Convert5To8(u8 value) {
 27      return (value << 3) | (value >> 2);
 28  }
 29  
 30  /// Convert a 6-bit color component to 8 bit
 31  [[nodiscard]] constexpr u8 Convert6To8(u8 value) {
 32      return (value << 2) | (value >> 4);
 33  }
 34  
 35  /// Convert a 8-bit color component to 1 bit
 36  [[nodiscard]] constexpr u8 Convert8To1(u8 value) {
 37      return value >> 7;
 38  }
 39  
 40  /// Convert a 8-bit color component to 4 bit
 41  [[nodiscard]] constexpr u8 Convert8To4(u8 value) {
 42      return value >> 4;
 43  }
 44  
 45  /// Convert a 8-bit color component to 5 bit
 46  [[nodiscard]] constexpr u8 Convert8To5(u8 value) {
 47      return value >> 3;
 48  }
 49  
 50  /// Convert a 8-bit color component to 6 bit
 51  [[nodiscard]] constexpr u8 Convert8To6(u8 value) {
 52      return value >> 2;
 53  }
 54  
 55  /// Averages the RGB components of a color
 56  [[nodiscard]] constexpr u8 AverageRgbComponents(const Common::Vec4<u8>& color) {
 57      return (static_cast<u32>(color.r()) + color.g() + color.b()) / 3;
 58  }
 59  
 60  /**
 61   * Decode a color stored in RGBA8 format
 62   * @param bytes Pointer to encoded source color
 63   * @return Result color decoded as Common::Vec4<u8>
 64   */
 65  [[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
 66      return {bytes[3], bytes[2], bytes[1], bytes[0]};
 67  }
 68  
 69  /**
 70   * Decode a color stored in RGB8 format
 71   * @param bytes Pointer to encoded source color
 72   * @return Result color decoded as Common::Vec4<u8>
 73   */
 74  [[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
 75      return {bytes[2], bytes[1], bytes[0], 255};
 76  }
 77  
 78  /**
 79   * Decode a color stored in RG8 (aka HILO8) format
 80   * @param bytes Pointer to encoded source color
 81   * @return Result color decoded as Common::Vec4<u8>
 82   */
 83  [[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
 84      return {bytes[1], bytes[0], 0, 255};
 85  }
 86  
 87  /**
 88   * Decode a color stored in RGB565 format
 89   * @param bytes Pointer to encoded source color
 90   * @return Result color decoded as Common::Vec4<u8>
 91   */
 92  [[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
 93      u16_le pixel;
 94      std::memcpy(&pixel, bytes, sizeof(pixel));
 95      return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
 96              Convert5To8(pixel & 0x1F), 255};
 97  }
 98  
 99  /**
100   * Decode a color stored in RGB5A1 format
101   * @param bytes Pointer to encoded source color
102   * @return Result color decoded as Common::Vec4<u8>
103   */
104  [[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
105      u16_le pixel;
106      std::memcpy(&pixel, bytes, sizeof(pixel));
107      return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
108              Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)};
109  }
110  
111  /**
112   * Decode a color stored in RGBA4 format
113   * @param bytes Pointer to encoded source color
114   * @return Result color decoded as Common::Vec4<u8>
115   */
116  [[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
117      u16_le pixel;
118      std::memcpy(&pixel, bytes, sizeof(pixel));
119      return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
120              Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)};
121  }
122  
123  /**
124   * Decode a color stored in IA8 format
125   * @param bytes Pointer to encoded source color
126   * @return Result color decoded as Common::Vec4<u8>
127   */
128  [[nodiscard]] inline Common::Vec4<u8> DecodeIA8(const u8* bytes) {
129      return {bytes[1], bytes[1], bytes[1], bytes[0]};
130  }
131  
132  /**
133   * Decode a color stored in I8 format
134   * @param bytes Pointer to encoded source color
135   * @return Result color decoded as Common::Vec4<u8>
136   */
137  [[nodiscard]] inline Common::Vec4<u8> DecodeI8(const u8* bytes) {
138      return {bytes[0], bytes[0], bytes[0], 255};
139  }
140  
141  /**
142   * Decode a color stored in A8 format
143   * @param bytes Pointer to encoded source color
144   * @return Result color decoded as Common::Vec4<u8>
145   */
146  [[nodiscard]] inline Common::Vec4<u8> DecodeA8(const u8* bytes) {
147      return {0, 0, 0, bytes[0]};
148  }
149  
150  /**
151   * Decode a color stored in IA4 format
152   * @param bytes Pointer to encoded source color
153   * @return Result color decoded as Common::Vec4<u8>
154   */
155  [[nodiscard]] inline Common::Vec4<u8> DecodeIA4(const u8* bytes) {
156      u8 i = Common::Color::Convert4To8((bytes[0] & 0xF0) >> 4);
157      u8 a = Common::Color::Convert4To8(bytes[0] & 0x0F);
158      return {i, i, i, a};
159  }
160  
161  /**
162   * Decode a depth value stored in D16 format
163   * @param bytes Pointer to encoded source value
164   * @return Depth value as an u32
165   */
166  [[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
167      u16_le data;
168      std::memcpy(&data, bytes, sizeof(data));
169      return data;
170  }
171  
172  /**
173   * Decode a depth value stored in D24 format
174   * @param bytes Pointer to encoded source value
175   * @return Depth value as an u32
176   */
177  [[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
178      return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
179  }
180  
181  /**
182   * Decode a depth value and a stencil value stored in D24S8 format
183   * @param bytes Pointer to encoded source values
184   * @return Resulting values stored as a Common::Vec2
185   */
186  [[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
187      return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
188  }
189  
190  /**
191   * Encode a color as RGBA8 format
192   * @param color Source color to encode
193   * @param bytes Destination pointer to store encoded color
194   */
195  inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) {
196      bytes[3] = color.r();
197      bytes[2] = color.g();
198      bytes[1] = color.b();
199      bytes[0] = color.a();
200  }
201  
202  /**
203   * Encode a color as RGB8 format
204   * @param color Source color to encode
205   * @param bytes Destination pointer to store encoded color
206   */
207  inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) {
208      bytes[2] = color.r();
209      bytes[1] = color.g();
210      bytes[0] = color.b();
211  }
212  
213  /**
214   * Encode a color as RG8 (aka HILO8) format
215   * @param color Source color to encode
216   * @param bytes Destination pointer to store encoded color
217   */
218  inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) {
219      bytes[1] = color.r();
220      bytes[0] = color.g();
221  }
222  
223  /**
224   * Encode a color as RGB565 format
225   * @param color Source color to encode
226   * @param bytes Destination pointer to store encoded color
227   */
228  inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) {
229      const u16_le data =
230          (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
231  
232      std::memcpy(bytes, &data, sizeof(data));
233  }
234  
235  /**
236   * Encode a color as RGB5A1 format
237   * @param color Source color to encode
238   * @param bytes Destination pointer to store encoded color
239   */
240  inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) {
241      const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) |
242                          (Convert8To5(color.b()) << 1) | Convert8To1(color.a());
243  
244      std::memcpy(bytes, &data, sizeof(data));
245  }
246  
247  /**
248   * Encode a color as RGBA4 format
249   * @param color Source color to encode
250   * @param bytes Destination pointer to store encoded color
251   */
252  inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) {
253      const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) |
254                       (Convert8To4(color.b()) << 4) | Convert8To4(color.a());
255  
256      std::memcpy(bytes, &data, sizeof(data));
257  }
258  
259  /**
260   * Encode a color as IA8 format
261   * @param color Source color to encode
262   * @param bytes Destination pointer to store encoded color
263   */
264  inline void EncodeIA8(const Common::Vec4<u8>& color, u8* bytes) {
265      bytes[1] = AverageRgbComponents(color);
266      bytes[0] = color.a();
267  }
268  
269  /**
270   * Encode a color as I8 format
271   * @param color Source color to encode
272   * @param bytes Destination pointer to store encoded color
273   */
274  inline void EncodeI8(const Common::Vec4<u8>& color, u8* bytes) {
275      bytes[0] = AverageRgbComponents(color);
276  }
277  
278  /**
279   * Encode a color as A8 format
280   * @param color Source color to encode
281   * @param bytes Destination pointer to store encoded color
282   */
283  inline void EncodeA8(const Common::Vec4<u8>& color, u8* bytes) {
284      bytes[0] = color.a();
285  }
286  
287  /**
288   * Encode a color as IA4 format
289   * @param color Source color to encode
290   * @param bytes Destination pointer to store encoded color
291   */
292  inline void EncodeIA4(const Common::Vec4<u8>& color, u8* bytes) {
293      bytes[0] = (Convert8To4(AverageRgbComponents(color)) << 4) | Convert8To4(color.a());
294  }
295  
296  /**
297   * Encode a 16 bit depth value as D16 format
298   * @param value 16 bit source depth value to encode
299   * @param bytes Pointer where to store the encoded value
300   */
301  inline void EncodeD16(u32 value, u8* bytes) {
302      const u16_le data = static_cast<u16>(value);
303      std::memcpy(bytes, &data, sizeof(data));
304  }
305  
306  /**
307   * Encode a 24 bit depth value as D24 format
308   * @param value 24 bit source depth value to encode
309   * @param bytes Pointer where to store the encoded value
310   */
311  inline void EncodeD24(u32 value, u8* bytes) {
312      bytes[0] = value & 0xFF;
313      bytes[1] = (value >> 8) & 0xFF;
314      bytes[2] = (value >> 16) & 0xFF;
315  }
316  
317  /**
318   * Encode a 24 bit depth and 8 bit stencil values as D24S8 format
319   * @param depth 24 bit source depth value to encode
320   * @param stencil 8 bit source stencil value to encode
321   * @param bytes Pointer where to store the encoded value
322   */
323  inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
324      bytes[0] = depth & 0xFF;
325      bytes[1] = (depth >> 8) & 0xFF;
326      bytes[2] = (depth >> 16) & 0xFF;
327      bytes[3] = stencil;
328  }
329  
330  /**
331   * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
332   * @param depth 24 bit source depth value to encode
333   * @param bytes Pointer where to store the encoded value
334   * @note unused bits will not be modified
335   */
336  inline void EncodeD24X8(u32 depth, u8* bytes) {
337      bytes[0] = depth & 0xFF;
338      bytes[1] = (depth >> 8) & 0xFF;
339      bytes[2] = (depth >> 16) & 0xFF;
340  }
341  
342  /**
343   * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
344   * @param stencil 8 bit source stencil value to encode
345   * @param bytes Pointer where to store the encoded value
346   * @note unused bits will not be modified
347   */
348  inline void EncodeX24S8(u8 stencil, u8* bytes) {
349      bytes[3] = stencil;
350  }
351  
352  } // namespace Common::Color