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#ifdef SOURCEPP_BUILD_WITH_TBB
8#include <execution>
9#endif
10
11#include <BufferStream.h>
12
13#include "ImageFormats.h"
14
16
17#define VTFPP_FORMAT_ACCESSOR(channel, channelCaps) \
18 [[nodiscard]] constexpr auto channel() const { \
19 if constexpr (std::endian::native == std::endian::little) { \
20 return pixel.le.channel; \
21 } else { \
22 return pixel.be.channel; \
23 } \
24 } \
25 constexpr void set##channelCaps(decltype(pixel.le.channel) value) { \
26 if constexpr (std::endian::native == std::endian::little) { \
27 pixel.le.channel = value; \
28 } else { \
29 pixel.be.channel = value; \
30 } \
31 }
32
33#define VTFPP_A VTFPP_FORMAT_ACCESSOR(a, A)
34#define VTFPP_B VTFPP_FORMAT_ACCESSOR(b, B)
35#define VTFPP_G VTFPP_FORMAT_ACCESSOR(g, G)
36#define VTFPP_I VTFPP_FORMAT_ACCESSOR(i, I)
37#define VTFPP_L VTFPP_FORMAT_ACCESSOR(l, L)
38#define VTFPP_P VTFPP_FORMAT_ACCESSOR(p, P)
39#define VTFPP_Q VTFPP_FORMAT_ACCESSOR(q, Q)
40#define VTFPP_R VTFPP_FORMAT_ACCESSOR(r, R)
41#define VTFPP_U VTFPP_FORMAT_ACCESSOR(u, U)
42#define VTFPP_V VTFPP_FORMAT_ACCESSOR(v, V)
43#define VTFPP_W VTFPP_FORMAT_ACCESSOR(w, W)
44#define VTFPP_X VTFPP_FORMAT_ACCESSOR(x, X)
45
46#define VTFPP_FORMAT_ACCESSOR_BSWAP(format, channel, channelCaps) \
47 [[nodiscard]] constexpr auto channel() const { \
48 if constexpr (std::endian::native == std::endian::little) { \
49 return pixel.le.channel; \
50 } else { \
51 auto swapped = pixel.be.data; \
52 BufferStream::swap_endian(&swapped); \
53 return std::bit_cast<LE>(swapped).channel; \
54 } \
55 } \
56 constexpr void set##channelCaps(decltype(pixel.le.channel) value) { \
57 if constexpr (std::endian::native == std::endian::little) { \
58 pixel.le.channel = value; \
59 } else { \
60 auto pixelLE = std::bit_cast<LE>(pixel.be.data); \
61 pixelLE.channel = value; \
62 auto swapped = std::bit_cast<decltype(pixel.be.data)>(pixelLE); \
63 BufferStream::swap_endian(&swapped); \
64 pixel.be.data = swapped; \
65 } \
66 }
67
68#define VTFPP_A_BSWAP(format) VTFPP_FORMAT_ACCESSOR_BSWAP(format, a, A)
69#define VTFPP_B_BSWAP(format) VTFPP_FORMAT_ACCESSOR_BSWAP(format, b, B)
70#define VTFPP_G_BSWAP(format) VTFPP_FORMAT_ACCESSOR_BSWAP(format, g, G)
71#define VTFPP_R_BSWAP(format) VTFPP_FORMAT_ACCESSOR_BSWAP(format, r, R)
72#define VTFPP_X_BSWAP(format) VTFPP_FORMAT_ACCESSOR_BSWAP(format, x, X)
73
74#define VTFPP_FORMAT_INTERNAL(bo, ...) \
75 struct bo { \
76 __VA_ARGS__; \
77 }; static_assert(std::is_trivially_copyable_v<bo> && sizeof(bo) == ImageFormatDetails::bpp(FORMAT) / 8);
78
79#define VTFPP_FORMAT_LE(...) VTFPP_FORMAT_INTERNAL(LE, __VA_ARGS__)
80#define VTFPP_FORMAT_BE(...) VTFPP_FORMAT_INTERNAL(BE, __VA_ARGS__)
81
82#define VTFPP_FORMAT(format, internalFormatClasses, accessors) \
83 class format { \
84 public: \
85 static constexpr auto FORMAT = ImageFormat::format; \
86 internalFormatClasses \
87 protected: \
88 union Pixel { \
89 LE le; \
90 BE be; \
91 Pixel() { std::memset(this, 0, sizeof(Pixel)); } \
92 } pixel; \
93 public: \
94 format() = default; \
95 format(LE le) { \
96 if constexpr (std::endian::native == std::endian::little) { \
97 this->pixel.le = le; \
98 } else { \
99 BufferStream::swap_endian(&le); \
100 this->pixel.be = std::bit_cast<BE>(le); \
101 } \
102 } \
103 accessors \
104}; static_assert(std::is_trivially_copyable_v<format> && sizeof(format) == ImageFormatDetails::bpp(ImageFormat::format) / 8)
105
107 RGBA8888,
108 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
109 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
111);
112
114 ABGR8888,
115 VTFPP_FORMAT_LE(uint8_t a, b, g, r)
116 VTFPP_FORMAT_BE(uint8_t r, g, b, a),
118);
119
121 RGB888,
122 VTFPP_FORMAT_LE(uint8_t r, g, b)
123 VTFPP_FORMAT_BE(uint8_t b, g, r),
125);
126
128 BGR888,
129 VTFPP_FORMAT_LE(uint8_t b, g, r)
130 VTFPP_FORMAT_BE(uint8_t r, g, b),
132);
133
135 RGB565,
136 VTFPP_FORMAT_LE(uint16_t r : 5, g : 6, b : 5)
137 VTFPP_FORMAT_BE(uint16_t data),
139);
140
142 I8,
143 VTFPP_FORMAT_LE(uint8_t i)
144 VTFPP_FORMAT_BE(uint8_t i),
145 VTFPP_I
146);
147
149 IA88,
150 VTFPP_FORMAT_LE(uint8_t i, a)
151 VTFPP_FORMAT_BE(uint8_t a, i),
153);
154
156 P8,
157 VTFPP_FORMAT_LE(uint8_t p)
158 VTFPP_FORMAT_BE(uint8_t p),
159 VTFPP_P
160);
161
163 A8,
164 VTFPP_FORMAT_LE(uint8_t a)
165 VTFPP_FORMAT_BE(uint8_t a),
166 VTFPP_A
167);
168
171 VTFPP_FORMAT_LE(uint8_t r, g, b)
172 VTFPP_FORMAT_BE(uint8_t b, g, r),
174);
175
178 VTFPP_FORMAT_LE(uint8_t b, g, r)
179 VTFPP_FORMAT_BE(uint8_t r, g, b),
181);
182
184 ARGB8888,
185 VTFPP_FORMAT_LE(uint8_t a, r, g, b)
186 VTFPP_FORMAT_BE(uint8_t b, g, r, a),
188);
189
191 BGRA8888,
192 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
193 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
195);
196
198 BGRX8888,
199 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
200 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
202);
203
205 BGR565,
206 VTFPP_FORMAT_LE(uint16_t b : 5, g : 6, r : 5)
207 VTFPP_FORMAT_BE(uint16_t data),
209);
210
212 BGRX5551,
213 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, x : 1)
214 VTFPP_FORMAT_BE(uint16_t data),
216);
217
219 BGRA4444,
220 VTFPP_FORMAT_LE(uint16_t b : 4, g : 4, r : 4, a : 4)
221 VTFPP_FORMAT_BE(uint16_t data),
223);
224
226 BGRA5551,
227 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, a : 1)
228 VTFPP_FORMAT_BE(uint16_t data),
230);
231
233 UV88,
234 VTFPP_FORMAT_LE(uint8_t u, v)
235 VTFPP_FORMAT_BE(uint8_t v, u),
237);
238
240 UVWQ8888,
241 VTFPP_FORMAT_LE(uint8_t u, v, w, q)
242 VTFPP_FORMAT_BE(uint8_t q, w, v, u),
244);
245
248 VTFPP_FORMAT_LE(half r, g, b, a)
249 VTFPP_FORMAT_BE(half a, b, g, r),
251);
252
255 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
256 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
258);
259
261 UVLX8888,
262 VTFPP_FORMAT_LE(uint8_t u, v, l, x)
263 VTFPP_FORMAT_BE(uint8_t x, l, v, u),
265);
266
268 R32F,
269 VTFPP_FORMAT_LE(float r)
270 VTFPP_FORMAT_BE(float r),
271 VTFPP_R
272);
273
276 VTFPP_FORMAT_LE(float r, g, b)
277 VTFPP_FORMAT_BE(float b, g, r),
279);
280
283 VTFPP_FORMAT_LE(float r, g, b, a)
284 VTFPP_FORMAT_BE(float a, b, g, r),
286);
287
289 RG1616F,
290 VTFPP_FORMAT_LE(half r, g)
291 VTFPP_FORMAT_BE(half g, r),
293);
294
296 RG3232F,
297 VTFPP_FORMAT_LE(float r, g)
298 VTFPP_FORMAT_BE(float g, r),
300);
301
303 RGBX8888,
304 VTFPP_FORMAT_LE(uint8_t r, g, b, x)
305 VTFPP_FORMAT_BE(uint8_t x, b, g, r),
307);
308
311 VTFPP_FORMAT_LE(uint32_t r : 10, g : 10, b : 10, a : 2)
312 VTFPP_FORMAT_BE(uint32_t data),
314);
315
318 VTFPP_FORMAT_LE(uint32_t b : 10, g : 10, r : 10, a : 2)
319 VTFPP_FORMAT_BE(uint32_t data),
321);
322
324 R16F,
325 VTFPP_FORMAT_LE(half r)
326 VTFPP_FORMAT_BE(half r),
327 VTFPP_R
328);
329
332 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
333 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
335);
336
339 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
340 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
342);
343
346 VTFPP_FORMAT_LE(uint8_t a, b, g, r)
347 VTFPP_FORMAT_BE(uint8_t r, g, b, a),
349);
350
353 VTFPP_FORMAT_LE(uint8_t a, r, g, b)
354 VTFPP_FORMAT_BE(uint8_t b, g, r, a),
356);
357
360 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
361 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
363);
364
367 VTFPP_FORMAT_LE(uint8_t r, g, b)
368 VTFPP_FORMAT_BE(uint8_t b, g, r),
370);
371
374 VTFPP_FORMAT_LE(uint8_t b, g, r)
375 VTFPP_FORMAT_BE(uint8_t r, g, b),
377);
378
381 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, x : 1)
382 VTFPP_FORMAT_BE(uint16_t data),
384);
385
388 VTFPP_FORMAT_LE(uint8_t i)
389 VTFPP_FORMAT_BE(uint8_t i),
390 VTFPP_I
391);
392
395 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
396 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
398);
399
402 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
403 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
405);
406
409 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
410 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
412);
413
415 STRATA_R8,
416 VTFPP_FORMAT_LE(uint8_t r)
417 VTFPP_FORMAT_BE(uint8_t r),
418 VTFPP_R
419);
420
423 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
424 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
426);
427
430 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
431 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
433);
434
437 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
438 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
440);
441
442#undef VTFPP_FORMAT
443#undef VTFPP_FORMAT_BE
444#undef VTFPP_FORMAT_LE
445#undef VTFPP_FORMAT_INTERNAL
446#undef VTFPP_X_BSWAP
447#undef VTFPP_R_BSWAP
448#undef VTFPP_G_BSWAP
449#undef VTFPP_B_BSWAP
450#undef VTFPP_A_BSWAP
451#undef VTFPP_FORMAT_ACCESSOR_BSWAP
452#undef VTFPP_X
453#undef VTFPP_W
454#undef VTFPP_V
455#undef VTFPP_U
456#undef VTFPP_R
457#undef VTFPP_Q
458#undef VTFPP_P
459#undef VTFPP_L
460#undef VTFPP_I
461#undef VTFPP_G
462#undef VTFPP_B
463#undef VTFPP_A
464#undef VTFPP_FORMAT_ACCESSOR
465
466template<typename T>
467concept PixelType =
468 std::same_as<T, RGBA8888> ||
469 std::same_as<T, ABGR8888> ||
470 std::same_as<T, RGB888> ||
471 std::same_as<T, BGR888> ||
472 std::same_as<T, RGB565> ||
473 std::same_as<T, I8> ||
474 std::same_as<T, IA88> ||
475 std::same_as<T, P8> ||
476 std::same_as<T, A8> ||
477 std::same_as<T, RGB888_BLUESCREEN> ||
478 std::same_as<T, BGR888_BLUESCREEN> ||
479 std::same_as<T, ARGB8888> ||
480 std::same_as<T, BGRA8888> ||
481 std::same_as<T, BGRX8888> ||
482 std::same_as<T, BGR565> ||
483 std::same_as<T, BGRX5551> ||
484 std::same_as<T, BGRA4444> ||
485 std::same_as<T, BGRA5551> ||
486 std::same_as<T, UV88> ||
487 std::same_as<T, UVWQ8888> ||
488 std::same_as<T, RGBA16161616F> ||
489 std::same_as<T, RGBA16161616> ||
490 std::same_as<T, UVLX8888> ||
491 std::same_as<T, R32F> ||
492 std::same_as<T, RGB323232F> ||
493 std::same_as<T, RGBA32323232F> ||
494 std::same_as<T, RG1616F> ||
495 std::same_as<T, RG3232F> ||
496 std::same_as<T, RGBX8888> ||
497 std::same_as<T, RGBA1010102> ||
498 std::same_as<T, BGRA1010102> ||
499 std::same_as<T, R16F> ||
500 std::same_as<T, CONSOLE_BGRX8888_LINEAR> ||
501 std::same_as<T, CONSOLE_RGBA8888_LINEAR> ||
502 std::same_as<T, CONSOLE_ABGR8888_LINEAR> ||
503 std::same_as<T, CONSOLE_ARGB8888_LINEAR> ||
504 std::same_as<T, CONSOLE_BGRA8888_LINEAR> ||
505 std::same_as<T, CONSOLE_RGB888_LINEAR> ||
506 std::same_as<T, CONSOLE_BGR888_LINEAR> ||
507 std::same_as<T, CONSOLE_BGRX5551_LINEAR> ||
508 std::same_as<T, CONSOLE_I8_LINEAR> ||
509 std::same_as<T, CONSOLE_RGBA16161616_LINEAR> ||
510 std::same_as<T, CONSOLE_BGRX8888_LE> ||
511 std::same_as<T, CONSOLE_BGRA8888_LE> ||
512 std::same_as<T, STRATA_R8> ||
513 std::same_as<T, SOURCEPP_BGRA8888_HDR> ||
514 std::same_as<T, SOURCEPP_RGBA16161616_HDR> ||
515 std::same_as<T, SOURCEPP_CONSOLE_RGBA16161616_HDR>;
516
521template<PixelType P, typename C>
522[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, C(P::*channel)() const) {
523 if (imageData.empty() || imageData.size() % sizeof(P) != 0 || !channel) {
524 return {};
525 }
526
527 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
528 std::span outSpan{reinterpret_cast<C*>(out.data()), out.size() / sizeof(C)};
529
530 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
531 std::transform(
532#ifdef SOURCEPP_BUILD_WITH_TBB
533 std::execution::par_unseq,
534#endif
535 pixels.begin(),
536 pixels.end(),
537 outSpan.begin(),
538 [channel](P pixel) {
539 return (pixel.*channel)();
540 }
541 );
542
543 return out;
544}
545
547template<PixelType InputPixel, typename Func>
548void transformInPlace(std::span<std::byte> imageData, Func callback) {
549 if (imageData.empty()) {
550 return;
551 }
552
553 std::span<InputPixel> imageDataSpan{reinterpret_cast<InputPixel*>(imageData.data()), imageData.size() / sizeof(InputPixel)};
554 std::transform(
555#ifdef SOURCEPP_BUILD_WITH_TBB
556 std::execution::par_unseq,
557#endif
558 imageDataSpan.begin(),
559 imageDataSpan.end(),
560 imageDataSpan.begin(),
561 callback
562 );
563}
564
566template<PixelType InputPixel, PixelType OutputPixel, typename Func>
567[[nodiscard]] std::vector<std::byte> transform(std::span<const std::byte> imageData, Func callback) {
568 if (imageData.empty()) {
569 return {};
570 }
571
572 std::vector<std::byte> newData;
573 newData.resize(imageData.size() / sizeof(InputPixel) * sizeof(OutputPixel));
574 std::span newDataSpan{reinterpret_cast<OutputPixel*>(newData.data()), newData.size() / sizeof(OutputPixel)};
575
576 std::span<const InputPixel> imageDataSpan{reinterpret_cast<const InputPixel*>(imageData.data()), imageData.size() / sizeof(InputPixel)};
577 std::transform(
578#ifdef SOURCEPP_BUILD_WITH_TBB
579 std::execution::par_unseq,
580#endif
581 imageDataSpan.begin(),
582 imageDataSpan.end(),
583 newDataSpan.begin(),
584 callback
585 );
586
587 return newData;
588}
589
590} // namespace vtfpp::ImagePixel
#define VTFPP_G_BSWAP(format)
Definition ImagePixel.h:70
#define VTFPP_FORMAT(format, internalFormatClasses, accessors)
Definition ImagePixel.h:82
#define VTFPP_R
Definition ImagePixel.h:40
#define VTFPP_X_BSWAP(format)
Definition ImagePixel.h:72
#define VTFPP_L
Definition ImagePixel.h:37
#define VTFPP_U
Definition ImagePixel.h:41
#define VTFPP_I
Definition ImagePixel.h:36
#define VTFPP_W
Definition ImagePixel.h:43
#define VTFPP_FORMAT_BE(...)
Definition ImagePixel.h:80
#define VTFPP_X
Definition ImagePixel.h:44
#define VTFPP_R_BSWAP(format)
Definition ImagePixel.h:71
#define VTFPP_B
Definition ImagePixel.h:34
#define VTFPP_G
Definition ImagePixel.h:35
#define VTFPP_FORMAT_LE(...)
Definition ImagePixel.h:79
#define VTFPP_Q
Definition ImagePixel.h:39
#define VTFPP_B_BSWAP(format)
Definition ImagePixel.h:69
#define VTFPP_A_BSWAP(format)
Definition ImagePixel.h:68
#define VTFPP_A
Definition ImagePixel.h:33
#define VTFPP_V
Definition ImagePixel.h:42
#define VTFPP_P
Definition ImagePixel.h:38
std::vector< std::byte > transform(std::span< const std::byte > imageData, Func callback)
Run a parallelizable/vectorizable operation on the given image data, and return new image data.
Definition ImagePixel.h:567
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:522
void transformInPlace(std::span< std::byte > imageData, Func callback)
Run a parallelizable/vectorizable operation on the given image data.
Definition ImagePixel.h:548