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{}; \
92 public: \
93 format() = default; \
94 format(LE le) { \
95 if constexpr (std::endian::native == std::endian::little) { \
96 this->pixel.le = le; \
97 } else { \
98 BufferStream::swap_endian(&le); \
99 this->pixel.be = std::bit_cast<BE>(le); \
100 } \
101 } \
102 accessors \
103}; static_assert(std::is_trivially_copyable_v<format> && sizeof(format) == ImageFormatDetails::bpp(ImageFormat::format) / 8)
104
106 RGBA8888,
107 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
108 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
110);
111
113 ABGR8888,
114 VTFPP_FORMAT_LE(uint8_t a, b, g, r)
115 VTFPP_FORMAT_BE(uint8_t r, g, b, a),
117);
118
120 RGB888,
121 VTFPP_FORMAT_LE(uint8_t r, g, b)
122 VTFPP_FORMAT_BE(uint8_t b, g, r),
124);
125
127 BGR888,
128 VTFPP_FORMAT_LE(uint8_t b, g, r)
129 VTFPP_FORMAT_BE(uint8_t r, g, b),
131);
132
134 RGB565,
135 VTFPP_FORMAT_LE(uint16_t r : 5, g : 6, b : 5)
136 VTFPP_FORMAT_BE(uint16_t data),
137 VTFPP_R_BSWAP(RGB565) VTFPP_G_BSWAP(RGB565) VTFPP_B_BSWAP(RGB565)
138);
139
141 I8,
142 VTFPP_FORMAT_LE(uint8_t i)
143 VTFPP_FORMAT_BE(uint8_t i),
144 VTFPP_I
145);
146
148 IA88,
149 VTFPP_FORMAT_LE(uint8_t i, a)
150 VTFPP_FORMAT_BE(uint8_t a, i),
152);
153
155 P8,
156 VTFPP_FORMAT_LE(uint8_t p)
157 VTFPP_FORMAT_BE(uint8_t p),
158 VTFPP_P
159);
160
162 A8,
163 VTFPP_FORMAT_LE(uint8_t a)
164 VTFPP_FORMAT_BE(uint8_t a),
165 VTFPP_A
166);
167
169 RGB888_BLUESCREEN,
170 VTFPP_FORMAT_LE(uint8_t r, g, b)
171 VTFPP_FORMAT_BE(uint8_t b, g, r),
173);
174
176 BGR888_BLUESCREEN,
177 VTFPP_FORMAT_LE(uint8_t b, g, r)
178 VTFPP_FORMAT_BE(uint8_t r, g, b),
180);
181
183 ARGB8888,
184 VTFPP_FORMAT_LE(uint8_t a, r, g, b)
185 VTFPP_FORMAT_BE(uint8_t b, g, r, a),
187);
188
190 BGRA8888,
191 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
192 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
194);
195
197 BGRX8888,
198 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
199 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
201);
202
204 BGR565,
205 VTFPP_FORMAT_LE(uint16_t b : 5, g : 6, r : 5)
206 VTFPP_FORMAT_BE(uint16_t data),
207 VTFPP_B_BSWAP(BGR565) VTFPP_G_BSWAP(BGR565) VTFPP_R_BSWAP(BGR565)
208);
209
211 BGRX5551,
212 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, x : 1)
213 VTFPP_FORMAT_BE(uint16_t data),
214 VTFPP_B_BSWAP(BGRX5551) VTFPP_G_BSWAP(BGRX5551) VTFPP_R_BSWAP(BGRX5551) VTFPP_X_BSWAP(BGRX5551)
215);
216
218 BGRA4444,
219 VTFPP_FORMAT_LE(uint16_t b : 4, g : 4, r : 4, a : 4)
220 VTFPP_FORMAT_BE(uint16_t data),
221 VTFPP_B_BSWAP(BGRA4444) VTFPP_G_BSWAP(BGRA4444) VTFPP_R_BSWAP(BGRA4444) VTFPP_A_BSWAP(BGRA4444)
222);
223
225 BGRA5551,
226 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, a : 1)
227 VTFPP_FORMAT_BE(uint16_t data),
228 VTFPP_B_BSWAP(BGRA5551) VTFPP_G_BSWAP(BGRA5551) VTFPP_R_BSWAP(BGRA5551) VTFPP_A_BSWAP(BGRA5551)
229);
230
232 UV88,
233 VTFPP_FORMAT_LE(uint8_t u, v)
234 VTFPP_FORMAT_BE(uint8_t v, u),
236);
237
239 UVWQ8888,
240 VTFPP_FORMAT_LE(uint8_t u, v, w, q)
241 VTFPP_FORMAT_BE(uint8_t q, w, v, u),
243);
244
246 RGBA16161616F,
247 VTFPP_FORMAT_LE(half r, g, b, a)
248 VTFPP_FORMAT_BE(half a, b, g, r),
250);
251
253 RGBA16161616,
254 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
255 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
257);
258
260 UVLX8888,
261 VTFPP_FORMAT_LE(uint8_t u, v, l, x)
262 VTFPP_FORMAT_BE(uint8_t x, l, v, u),
264);
265
267 R32F,
268 VTFPP_FORMAT_LE(float r)
269 VTFPP_FORMAT_BE(float r),
270 VTFPP_R
271);
272
274 RGB323232F,
275 VTFPP_FORMAT_LE(float r, g, b)
276 VTFPP_FORMAT_BE(float b, g, r),
278);
279
281 RGBA32323232F,
282 VTFPP_FORMAT_LE(float r, g, b, a)
283 VTFPP_FORMAT_BE(float a, b, g, r),
285);
286
288 RG1616F,
289 VTFPP_FORMAT_LE(half r, g)
290 VTFPP_FORMAT_BE(half g, r),
292);
293
295 RG3232F,
296 VTFPP_FORMAT_LE(float r, g)
297 VTFPP_FORMAT_BE(float g, r),
299);
300
302 RGBX8888,
303 VTFPP_FORMAT_LE(uint8_t r, g, b, x)
304 VTFPP_FORMAT_BE(uint8_t x, b, g, r),
306);
307
309 RGBA1010102,
310 VTFPP_FORMAT_LE(uint32_t r : 10, g : 10, b : 10, a : 2)
311 VTFPP_FORMAT_BE(uint32_t data),
312 VTFPP_R_BSWAP(RGBA1010102) VTFPP_G_BSWAP(RGBA1010102) VTFPP_B_BSWAP(RGBA1010102) VTFPP_A_BSWAP(RGBA1010102)
313);
314
316 BGRA1010102,
317 VTFPP_FORMAT_LE(uint32_t b : 10, g : 10, r : 10, a : 2)
318 VTFPP_FORMAT_BE(uint32_t data),
319 VTFPP_B_BSWAP(RGBA1010102) VTFPP_G_BSWAP(RGBA1010102) VTFPP_R_BSWAP(RGBA1010102) VTFPP_A_BSWAP(RGBA1010102)
320);
321
323 R16F,
324 VTFPP_FORMAT_LE(half r)
325 VTFPP_FORMAT_BE(half r),
326 VTFPP_R
327);
328
330 CONSOLE_BGRX8888_LINEAR,
331 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
332 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
334);
335
337 CONSOLE_RGBA8888_LINEAR,
338 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
339 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
341);
342
344 CONSOLE_ABGR8888_LINEAR,
345 VTFPP_FORMAT_LE(uint8_t a, b, g, r)
346 VTFPP_FORMAT_BE(uint8_t r, g, b, a),
348);
349
351 CONSOLE_ARGB8888_LINEAR,
352 VTFPP_FORMAT_LE(uint8_t a, r, g, b)
353 VTFPP_FORMAT_BE(uint8_t b, g, r, a),
355);
356
358 CONSOLE_BGRA8888_LINEAR,
359 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
360 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
362);
363
365 CONSOLE_RGB888_LINEAR,
366 VTFPP_FORMAT_LE(uint8_t r, g, b)
367 VTFPP_FORMAT_BE(uint8_t b, g, r),
369);
370
372 CONSOLE_BGR888_LINEAR,
373 VTFPP_FORMAT_LE(uint8_t b, g, r)
374 VTFPP_FORMAT_BE(uint8_t r, g, b),
376);
377
379 CONSOLE_BGRX5551_LINEAR,
380 VTFPP_FORMAT_LE(uint16_t b : 5, g : 5, r : 5, x : 1)
381 VTFPP_FORMAT_BE(uint16_t data),
382 VTFPP_B_BSWAP(CONSOLE_BGRX5551_LINEAR) VTFPP_G_BSWAP(CONSOLE_BGRX5551_LINEAR) VTFPP_R_BSWAP(CONSOLE_BGRX5551_LINEAR) VTFPP_X_BSWAP(CONSOLE_BGRX5551_LINEAR)
383);
384
386 CONSOLE_I8_LINEAR,
387 VTFPP_FORMAT_LE(uint8_t i)
388 VTFPP_FORMAT_BE(uint8_t i),
389 VTFPP_I
390);
391
393 CONSOLE_RGBA16161616_LINEAR,
394 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
395 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
397);
398
400 CONSOLE_BGRX8888_LE,
401 VTFPP_FORMAT_LE(uint8_t b, g, r, x)
402 VTFPP_FORMAT_BE(uint8_t x, r, g, b),
404);
405
407 CONSOLE_BGRA8888_LE,
408 VTFPP_FORMAT_LE(uint8_t b, g, r, a)
409 VTFPP_FORMAT_BE(uint8_t a, r, g, b),
411);
412
414 STRATA_R8,
415 VTFPP_FORMAT_LE(uint8_t r)
416 VTFPP_FORMAT_BE(uint8_t r),
417 VTFPP_R
418);
419
421 SOURCEPP_BGRA8888_HDR,
422 VTFPP_FORMAT_LE(uint8_t r, g, b, a)
423 VTFPP_FORMAT_BE(uint8_t a, b, g, r),
425);
426
428 SOURCEPP_RGBA16161616_HDR,
429 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
430 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
432);
433
435 SOURCEPP_CONSOLE_RGBA16161616_HDR,
436 VTFPP_FORMAT_LE(uint16_t r, g, b, a)
437 VTFPP_FORMAT_BE(uint16_t a, b, g, r),
439);
440
441#undef VTFPP_FORMAT
442#undef VTFPP_FORMAT_BE
443#undef VTFPP_FORMAT_LE
444#undef VTFPP_FORMAT_INTERNAL
445#undef VTFPP_X_BSWAP
446#undef VTFPP_R_BSWAP
447#undef VTFPP_G_BSWAP
448#undef VTFPP_B_BSWAP
449#undef VTFPP_A_BSWAP
450#undef VTFPP_FORMAT_ACCESSOR_BSWAP
451#undef VTFPP_X
452#undef VTFPP_W
453#undef VTFPP_V
454#undef VTFPP_U
455#undef VTFPP_R
456#undef VTFPP_Q
457#undef VTFPP_P
458#undef VTFPP_L
459#undef VTFPP_I
460#undef VTFPP_G
461#undef VTFPP_B
462#undef VTFPP_A
463#undef VTFPP_FORMAT_ACCESSOR
464
465template<typename T>
466concept PixelType =
467 std::same_as<T, RGBA8888> ||
468 std::same_as<T, ABGR8888> ||
469 std::same_as<T, RGB888> ||
470 std::same_as<T, BGR888> ||
471 std::same_as<T, RGB565> ||
472 std::same_as<T, I8> ||
473 std::same_as<T, IA88> ||
474 std::same_as<T, P8> ||
475 std::same_as<T, A8> ||
476 std::same_as<T, RGB888_BLUESCREEN> ||
477 std::same_as<T, BGR888_BLUESCREEN> ||
478 std::same_as<T, ARGB8888> ||
479 std::same_as<T, BGRA8888> ||
480 std::same_as<T, BGRX8888> ||
481 std::same_as<T, BGR565> ||
482 std::same_as<T, BGRX5551> ||
483 std::same_as<T, BGRA4444> ||
484 std::same_as<T, BGRA5551> ||
485 std::same_as<T, UV88> ||
486 std::same_as<T, UVWQ8888> ||
487 std::same_as<T, RGBA16161616F> ||
488 std::same_as<T, RGBA16161616> ||
489 std::same_as<T, UVLX8888> ||
490 std::same_as<T, R32F> ||
491 std::same_as<T, RGB323232F> ||
492 std::same_as<T, RGBA32323232F> ||
493 std::same_as<T, RG1616F> ||
494 std::same_as<T, RG3232F> ||
495 std::same_as<T, RGBX8888> ||
496 std::same_as<T, RGBA1010102> ||
497 std::same_as<T, BGRA1010102> ||
498 std::same_as<T, R16F> ||
499 std::same_as<T, CONSOLE_BGRX8888_LINEAR> ||
500 std::same_as<T, CONSOLE_RGBA8888_LINEAR> ||
501 std::same_as<T, CONSOLE_ABGR8888_LINEAR> ||
502 std::same_as<T, CONSOLE_ARGB8888_LINEAR> ||
503 std::same_as<T, CONSOLE_BGRA8888_LINEAR> ||
504 std::same_as<T, CONSOLE_RGB888_LINEAR> ||
505 std::same_as<T, CONSOLE_BGR888_LINEAR> ||
506 std::same_as<T, CONSOLE_BGRX5551_LINEAR> ||
507 std::same_as<T, CONSOLE_I8_LINEAR> ||
508 std::same_as<T, CONSOLE_RGBA16161616_LINEAR> ||
509 std::same_as<T, CONSOLE_BGRX8888_LE> ||
510 std::same_as<T, CONSOLE_BGRA8888_LE> ||
511 std::same_as<T, STRATA_R8> ||
512 std::same_as<T, SOURCEPP_BGRA8888_HDR> ||
513 std::same_as<T, SOURCEPP_RGBA16161616_HDR> ||
514 std::same_as<T, SOURCEPP_CONSOLE_RGBA16161616_HDR>;
515
520template<PixelType P, typename C>
521[[nodiscard]] std::vector<std::byte> extractChannelFromImageData(std::span<const std::byte> imageData, C(P::*channel)() const) {
522 if (imageData.empty() || imageData.size() % sizeof(P) != 0 || !channel) {
523 return {};
524 }
525
526 std::vector<std::byte> out(imageData.size() / sizeof(P) * sizeof(C));
527 std::span outSpan{reinterpret_cast<C*>(out.data()), out.size() / sizeof(C)};
528
529 std::span pixels{reinterpret_cast<const P*>(imageData.data()), imageData.size() / sizeof(P)};
530 std::transform(
531#ifdef SOURCEPP_BUILD_WITH_TBB
532 std::execution::par_unseq,
533#endif
534 pixels.begin(),
535 pixels.end(),
536 outSpan.begin(),
537 [channel](P pixel) {
538 return (pixel.*channel)();
539 }
540 );
541
542 return out;
543}
544
546template<PixelType InputPixel, typename Func>
547void transformInPlace(std::span<std::byte> imageData, Func callback) {
548 if (imageData.empty()) {
549 return;
550 }
551
552 std::span<InputPixel> imageDataSpan{reinterpret_cast<InputPixel*>(imageData.data()), imageData.size() / sizeof(InputPixel)};
553 std::transform(
554#ifdef SOURCEPP_BUILD_WITH_TBB
555 std::execution::par_unseq,
556#endif
557 imageDataSpan.begin(),
558 imageDataSpan.end(),
559 imageDataSpan.begin(),
560 callback
561 );
562}
563
565template<PixelType InputPixel, PixelType OutputPixel, typename Func>
566[[nodiscard]] std::vector<std::byte> transform(std::span<const std::byte> imageData, Func callback) {
567 if (imageData.empty()) {
568 return {};
569 }
570
571 std::vector<std::byte> newData;
572 newData.resize(imageData.size() / sizeof(InputPixel) * sizeof(OutputPixel));
573 std::span newDataSpan{reinterpret_cast<OutputPixel*>(newData.data()), newData.size() / sizeof(OutputPixel)};
574
575 std::span<const InputPixel> imageDataSpan{reinterpret_cast<const InputPixel*>(imageData.data()), imageData.size() / sizeof(InputPixel)};
576 std::transform(
577#ifdef SOURCEPP_BUILD_WITH_TBB
578 std::execution::par_unseq,
579#endif
580 imageDataSpan.begin(),
581 imageDataSpan.end(),
582 newDataSpan.begin(),
583 callback
584 );
585
586 return newData;
587}
588
589} // namespace vtfpp::ImagePixel
#define VTFPP_G_BSWAP(format)
Definition ImagePixel.h:70
#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:566
VTFPP_FORMAT(RGBA8888, VTFPP_FORMAT_BE(uint8_t a, b, g, r), VTFPP_R VTFPP_G VTFPP_B VTFPP_A)
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:521
void transformInPlace(std::span< std::byte > imageData, Func callback)
Run a parallelizable/vectorizable operation on the given image data.
Definition ImagePixel.h:547