SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
ImagePixel.h
Go to the documentation of this file.
1#pragma once
2
3#include <bit>
4#include <concepts>
5#include <cstring>
6
7#include <BufferStream.h>
8
9#include "ImageFormats.h"
10
12
13namespace detail {
14
15#define VTFPP_FORMAT_CHECK(format, bo) \
16 static_assert(std::is_trivially_copyable_v<format##_##bo> && sizeof(format##_##bo) == ImageFormatDetails::bpp(ImageFormat::format) / 8)
17
18#define VTFPP_FORMAT(format, bo, ...) \
19 struct format##_##bo { \
20 static constexpr auto FORMAT = ImageFormat::format; \
21 __VA_ARGS__; \
22 }; VTFPP_FORMAT_CHECK(format, bo)
23
24#define VTFPP_FORMAT_INHERITED(format, parent) \
25 struct format##_LE : parent##_LE { \
26 static constexpr auto FORMAT = ImageFormat::format; \
27 }; VTFPP_FORMAT_CHECK(format, LE); \
28 struct format##_BE : parent##_BE { \
29 static constexpr auto FORMAT = ImageFormat::format; \
30 }; VTFPP_FORMAT_CHECK(format, BE)
31
32VTFPP_FORMAT(RGBA8888, LE, uint8_t r, g, b, a);
33VTFPP_FORMAT(RGBA8888, BE, uint8_t a, b, g, r);
34
35VTFPP_FORMAT(ABGR8888, LE, uint8_t a, b, g, r);
36VTFPP_FORMAT(ABGR8888, BE, uint8_t r, g, b, a);
37
38VTFPP_FORMAT(RGB888, LE, uint8_t r, g, b);
39VTFPP_FORMAT(RGB888, BE, uint8_t b, g, r);
40
42
43VTFPP_FORMAT(BGR888, LE, uint8_t b, g, r);
44VTFPP_FORMAT(BGR888, BE, uint8_t r, g, b);
45
47
48VTFPP_FORMAT(RGB565, LE, uint16_t r : 5, g : 6, b : 5);
49VTFPP_FORMAT(RGB565, BE, uint16_t data);
50
51VTFPP_FORMAT(I8, LE, uint8_t i);
52VTFPP_FORMAT(I8, BE, uint8_t i);
53
54VTFPP_FORMAT(IA88, LE, uint8_t i, a);
55VTFPP_FORMAT(IA88, BE, uint8_t a, i);
56
57VTFPP_FORMAT(P8, LE, uint8_t p);
58VTFPP_FORMAT(P8, BE, uint8_t p);
59
60VTFPP_FORMAT(A8, LE, uint8_t a);
61VTFPP_FORMAT(A8, BE, uint8_t a);
62
63VTFPP_FORMAT(ARGB8888, LE, uint8_t a, r, g, b);
64VTFPP_FORMAT(ARGB8888, BE, uint8_t b, g, r, a);
65
66VTFPP_FORMAT(BGRA8888, LE, uint8_t b, g, r, a);
67VTFPP_FORMAT(BGRA8888, BE, uint8_t a, r, g, b);
68
69VTFPP_FORMAT(BGRX8888, LE, uint8_t b, g, r, x);
70VTFPP_FORMAT(BGRX8888, BE, uint8_t x, r, g, b);
71
72VTFPP_FORMAT(BGR565, LE, uint16_t b : 5, g : 6, r : 5);
73VTFPP_FORMAT(BGR565, BE, uint16_t data);
74
75VTFPP_FORMAT(BGRX5551, LE, uint16_t b : 5, g : 5, r : 5, x : 1);
76VTFPP_FORMAT(BGRX5551, BE, uint16_t data);
77
78VTFPP_FORMAT(BGRA4444, LE, uint16_t b : 4, g : 4, r : 4, a : 4);
79VTFPP_FORMAT(BGRA4444, BE, uint16_t data);
80
81VTFPP_FORMAT(BGRA5551, LE, uint16_t b : 5, g : 5, r : 5, a : 1);
82VTFPP_FORMAT(BGRA5551, BE, uint16_t data);
83
84VTFPP_FORMAT(UV88, LE, uint8_t u, v);
85VTFPP_FORMAT(UV88, BE, uint8_t v, u);
86
87VTFPP_FORMAT(UVWQ8888, LE, uint8_t u, v, w, q);
88VTFPP_FORMAT(UVWQ8888, BE, uint8_t q, w, v, u);
89
90VTFPP_FORMAT(RGBA16161616F, LE, half r, g, b, a);
91VTFPP_FORMAT(RGBA16161616F, BE, half a, b, g, r);
92
93VTFPP_FORMAT(RGBA16161616, LE, uint16_t r, g, b, a);
94VTFPP_FORMAT(RGBA16161616, BE, uint16_t a, b, g, r);
95
96VTFPP_FORMAT(UVLX8888, LE, uint8_t u, v, l, x);
97VTFPP_FORMAT(UVLX8888, BE, uint8_t x, l, v, u);
98
99VTFPP_FORMAT(R32F, LE, float r);
100VTFPP_FORMAT(R32F, BE, float r);
101
102VTFPP_FORMAT(RGB323232F, LE, float r, g, b);
103VTFPP_FORMAT(RGB323232F, BE, float b, g, r);
104
105VTFPP_FORMAT(RGBA32323232F, LE, float r, g, b, a);
106VTFPP_FORMAT(RGBA32323232F, BE, float a, b, g, r);
107
108VTFPP_FORMAT(RG1616F, LE, half r, g);
109VTFPP_FORMAT(RG1616F, BE, half g, r);
110
111VTFPP_FORMAT(RG3232F, LE, float r, g);
112VTFPP_FORMAT(RG3232F, BE, float g, r);
113
114VTFPP_FORMAT(RGBX8888, LE, uint8_t r, g, b, x);
115VTFPP_FORMAT(RGBX8888, BE, uint8_t x, b, g, r);
116
117VTFPP_FORMAT(RGBA1010102, LE, uint32_t r : 10, g : 10, b : 10, a : 2);
118VTFPP_FORMAT(RGBA1010102, BE, uint32_t data);
119
120VTFPP_FORMAT(BGRA1010102, LE, uint32_t b : 10, g : 10, r : 10, a : 2);
121VTFPP_FORMAT(BGRA1010102, BE, uint32_t data);
122
123VTFPP_FORMAT(R16F, LE, half r);
124VTFPP_FORMAT(R16F, BE, half r);
125
127
129
131
133
135
137
139
141
143
145
147
149
150VTFPP_FORMAT(STRATA_R8, LE, uint8_t r);
151VTFPP_FORMAT(STRATA_R8, BE, uint8_t r);
152
153#undef VTFPP_FORMAT_INHERITED
154#undef VTFPP_FORMAT
155#undef VTFPP_FORMAT_CHECK
156
157} // namespace detail
158
159#define VTFPP_FORMAT_ACCESSOR(channel) \
160 [[nodiscard]] constexpr auto channel() const { \
161 if constexpr (std::endian::native == std::endian::little) { \
162 return pixel.le.channel; \
163 } else { \
164 return pixel.be.channel; \
165 } \
166 } \
167 constexpr void set##_##channel(decltype(pixel.le.channel) value) { \
168 if constexpr (std::endian::native == std::endian::little) { \
169 pixel.le.channel = value; \
170 } else { \
171 pixel.be.channel = value; \
172 } \
173 }
174
175#define VTFPP_FORMAT_ACCESSOR_BSWAP(format, channel) \
176 [[nodiscard]] constexpr auto channel() const { \
177 if constexpr (std::endian::native == std::endian::little) { \
178 return pixel.le.channel; \
179 } else { \
180 auto swapped = pixel.be.data; \
181 BufferStream::swap_endian(&swapped); \
182 return std::bit_cast<detail::format##_LE>(swapped).channel; \
183 } \
184 } \
185 constexpr void set##_##channel(decltype(pixel.le.channel) value) { \
186 if constexpr (std::endian::native == std::endian::little) { \
187 pixel.le.channel = value; \
188 } else { \
189 auto pixelLE = std::bit_cast<detail::format##_LE>(pixel.be.data); \
190 pixelLE.channel = value; \
191 auto swapped = std::bit_cast<decltype(pixel.be.data)>(pixelLE); \
192 BufferStream::swap_endian(&swapped); \
193 pixel.be.data = swapped; \
194 } \
195 }
196
197#define VTFPP_FORMAT(format, accessors) \
198 class format { \
199 protected: \
200 union Pixel { \
201 detail::format##_LE le; \
202 detail::format##_BE be; \
203 Pixel() { std::memset(this, 0, sizeof(Pixel)); } \
204 } pixel; \
205 public: \
206 static constexpr auto FORMAT = ImageFormat::format; \
207 format(detail::format##_LE le) { \
208 if constexpr (std::endian::native == std::endian::little) { \
209 this->pixel.le = le; \
210 } else { \
211 BufferStream::swap_endian(&le); \
212 this->pixel.be = std::bit_cast<detail::format##_BE>(le); \
213 } \
214 } \
215 accessors \
216}; static_assert(std::is_trivially_copyable_v<format> && sizeof(format) == ImageFormatDetails::bpp(ImageFormat::format) / 8)
217
263
264#undef VTFPP_FORMAT
265#undef VTFPP_FORMAT_ACCESSOR_BSWAP
266#undef VTFPP_FORMAT_ACCESSOR
267
268template<typename T>
269concept PixelType =
270 std::same_as<T, RGBA8888> ||
271 std::same_as<T, ABGR8888> ||
272 std::same_as<T, RGB888> ||
273 std::same_as<T, BGR888> ||
274 std::same_as<T, RGB565> ||
275 std::same_as<T, I8> ||
276 std::same_as<T, IA88> ||
277 std::same_as<T, P8> ||
278 std::same_as<T, A8> ||
279 std::same_as<T, RGB888_BLUESCREEN> ||
280 std::same_as<T, BGR888_BLUESCREEN> ||
281 std::same_as<T, ARGB8888> ||
282 std::same_as<T, BGRA8888> ||
283 std::same_as<T, BGRX8888> ||
284 std::same_as<T, BGR565> ||
285 std::same_as<T, BGRX5551> ||
286 std::same_as<T, BGRA4444> ||
287 std::same_as<T, BGRA5551> ||
288 std::same_as<T, UV88> ||
289 std::same_as<T, UVWQ8888> ||
290 std::same_as<T, RGBA16161616F> ||
291 std::same_as<T, RGBA16161616> ||
292 std::same_as<T, UVLX8888> ||
293 std::same_as<T, R32F> ||
294 std::same_as<T, RGB323232F> ||
295 std::same_as<T, RGBA32323232F> ||
296 std::same_as<T, RG1616F> ||
297 std::same_as<T, RG3232F> ||
298 std::same_as<T, RGBX8888> ||
299 std::same_as<T, RGBA1010102> ||
300 std::same_as<T, BGRA1010102> ||
301 std::same_as<T, R16F> ||
302 std::same_as<T, CONSOLE_BGRX8888_LINEAR> ||
303 std::same_as<T, CONSOLE_RGBA8888_LINEAR> ||
304 std::same_as<T, CONSOLE_ABGR8888_LINEAR> ||
305 std::same_as<T, CONSOLE_ARGB8888_LINEAR> ||
306 std::same_as<T, CONSOLE_BGRA8888_LINEAR> ||
307 std::same_as<T, CONSOLE_RGB888_LINEAR> ||
308 std::same_as<T, CONSOLE_BGR888_LINEAR> ||
309 std::same_as<T, CONSOLE_BGRX5551_LINEAR> ||
310 std::same_as<T, CONSOLE_I8_LINEAR> ||
311 std::same_as<T, CONSOLE_RGBA16161616_LINEAR> ||
312 std::same_as<T, CONSOLE_BGRX8888_LE> ||
313 std::same_as<T, CONSOLE_BGRA8888_LE> ||
314 std::same_as<T, STRATA_R8>;
315
320template<PixelType P, typename C>
321[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, C(P::*channel)() const) {
322 if (imageData.empty() || imageData.size() % sizeof(P) != 0 || !channel) {
323 return {};
324 }
325
326 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
327
328 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
329 BufferStream stream{out, false};
330 // todo: tbb
331 for (const auto& pixel : pixels) {
332 stream << (pixel.*channel)();
333 }
334 return out;
335}
336
337} // namespace vtfpp::ImagePixel
#define VTFPP_FORMAT_ACCESSOR_BSWAP(format, channel)
Definition ImagePixel.h:175
#define VTFPP_FORMAT(format, bo,...)
Definition ImagePixel.h:18
#define VTFPP_FORMAT_ACCESSOR(channel)
Definition ImagePixel.h:159
#define VTFPP_FORMAT_INHERITED(format, parent)
Definition ImagePixel.h:24
std::vector< std::byte > extractChannelFromImageData(std::span< const std::byte > imageData, C(P::*channel)() const)
Extracts a single channel from the given image data.
Definition ImagePixel.h:321