aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/common/color.h
blob: 9dafdca0caa70f110459af114df1b9c057de3d18 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include "common/common_types.h"
#include "common/swap.h"
#include "common/vector_math.h"

namespace Color {

/// Convert a 1-bit color component to 8 bit
inline u8 Convert1To8(u8 value) {
    return value * 255;
}

/// Convert a 4-bit color component to 8 bit
inline u8 Convert4To8(u8 value) {
    return (value << 4) | value;
}

/// Convert a 5-bit color component to 8 bit
inline u8 Convert5To8(u8 value) {
    return (value << 3) | (value >> 2);
}

/// Convert a 6-bit color component to 8 bit
inline u8 Convert6To8(u8 value) {
    return (value << 2) | (value >> 4);
}

/// Convert a 8-bit color component to 1 bit
inline u8 Convert8To1(u8 value) {
    return value >> 7;
}

/// Convert a 8-bit color component to 4 bit
inline u8 Convert8To4(u8 value) {
    return value >> 4;
}

/// Convert a 8-bit color component to 5 bit
inline u8 Convert8To5(u8 value) {
    return value >> 3;
}

/// Convert a 8-bit color component to 6 bit
inline u8 Convert8To6(u8 value) {
    return value >> 2;
}

/**
 * Decode a color stored in RGBA8 format
 * @param bytes Pointer to encoded source color
 * @return Result color decoded as Math::Vec4<u8>
 */
inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
    return { bytes[3], bytes[2], bytes[1], bytes[0] };
}

/**
 * Decode a color stored in RGB8 format
 * @param bytes Pointer to encoded source color
 * @return Result color decoded as Math::Vec4<u8>
 */
inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
    return { bytes[2], bytes[1], bytes[0], 255 };
}

/**
 * Decode a color stored in RGB565 format
 * @param bytes Pointer to encoded source color
 * @return Result color decoded as Math::Vec4<u8>
 */
inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
    const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
    return { Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
        Convert5To8(pixel & 0x1F), 255 };
}

/**
 * Decode a color stored in RGB5A1 format
 * @param bytes Pointer to encoded source color
 * @return Result color decoded as Math::Vec4<u8>
 */
inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
    const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
    return { Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
        Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1) };
}

/**
 * Decode a color stored in RGBA4 format
 * @param bytes Pointer to encoded source color
 * @return Result color decoded as Math::Vec4<u8>
 */
inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
    const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
    return { Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
        Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF) };
}

/**
 * Decode a depth value stored in D16 format
 * @param bytes Pointer to encoded source value
 * @return Depth value as an u32
 */
inline u32 DecodeD16(const u8* bytes) {
    return *reinterpret_cast<const u16_le*>(bytes);
}

/**
 * Decode a depth value stored in D24 format
 * @param bytes Pointer to encoded source value
 * @return Depth value as an u32
 */
inline u32 DecodeD24(const u8* bytes) {
    return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
}

/**
 * Decode a depth value and a stencil value stored in D24S8 format
 * @param bytes Pointer to encoded source values
 * @return Resulting values stored as a Math::Vec2
 */
inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
    return { static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3] };
}

/**
 * Encode a color as RGBA8 format
 * @param color Source color to encode
 * @param bytes Destination pointer to store encoded color
 */
inline void EncodeRGBA8(const Math::Vec4<u8>& color, u8* bytes) {
    bytes[3] = color.r();
    bytes[2] = color.g();
    bytes[1] = color.b();
    bytes[0] = color.a();
}

/**
 * Encode a color as RGB8 format
 * @param color Source color to encode
 * @param bytes Destination pointer to store encoded color
 */
inline void EncodeRGB8(const Math::Vec4<u8>& color, u8* bytes) {
    bytes[2] = color.r();
    bytes[1] = color.g();
    bytes[0] = color.b();
}

/**
 * Encode a color as RGB565 format
 * @param color Source color to encode
 * @param bytes Destination pointer to store encoded color
 */
inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
    *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) |
        (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
}

/**
 * Encode a color as RGB5A1 format
 * @param color Source color to encode
 * @param bytes Destination pointer to store encoded color
 */
inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
    *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) |
        (Convert8To5(color.g()) << 6) | (Convert8To5(color.b()) << 1) | Convert8To1(color.a());
}

/**
 * Encode a color as RGBA4 format
 * @param color Source color to encode
 * @param bytes Destination pointer to store encoded color
 */
inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
    *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) |
        (Convert8To4(color.g()) << 8) | (Convert8To4(color.b()) << 4) | Convert8To4(color.a());
}

/**
 * Encode a 16 bit depth value as D16 format
 * @param value 16 bit source depth value to encode
 * @param bytes Pointer where to store the encoded value
 */
inline void EncodeD16(u32 value, u8* bytes) {
    *reinterpret_cast<u16_le*>(bytes) = value & 0xFFFF;
}

/**
 * Encode a 24 bit depth value as D24 format
 * @param value 24 bit source depth value to encode
 * @param bytes Pointer where to store the encoded value
 */
inline void EncodeD24(u32 value, u8* bytes) {
    bytes[0] = value & 0xFF;
    bytes[1] = (value >> 8) & 0xFF;
    bytes[2] = (value >> 16) & 0xFF;
}

/**
 * Encode a 24 bit depth and 8 bit stencil values as D24S8 format
 * @param depth 24 bit source depth value to encode
 * @param stencil 8 bit source stencil value to encode
 * @param bytes Pointer where to store the encoded value
 */
inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
    bytes[0] = depth & 0xFF;
    bytes[1] = (depth >> 8) & 0xFF;
    bytes[2] = (depth >> 16) & 0xFF;
    bytes[3] = stencil;
}

/**
 * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
 * @param depth 24 bit source depth value to encode
 * @param bytes Pointer where to store the encoded value
 * @note unused bits will not be modified
 */
inline void EncodeD24X8(u32 depth, u8* bytes) {
    bytes[0] = depth & 0xFF;
    bytes[1] = (depth >> 8) & 0xFF;
    bytes[2] = (depth >> 16) & 0xFF;
}

/**
 * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
 * @param stencil 8 bit source stencil value to encode
 * @param bytes Pointer where to store the encoded value
 * @note unused bits will not be modified
 */
inline void EncodeX24S8(u8 stencil, u8* bytes) {
    bytes[3] = stencil;
}

} // namespace