SourcePP
Several modern C++20 libraries for sanely parsing Valve's formats.
Loading...
Searching...
No Matches
ImageFormats.h
Go to the documentation of this file.
1#pragma once
2
3#include <sourcepp/Math.h>
4
5namespace vtfpp {
6
7enum class ImageFormat : int32_t {
8 // region Universal Formats
9 RGBA8888 = 0,
11 RGB888,
12 BGR888,
13 RGB565,
14 I8,
15 IA88,
16 P8,
17 A8,
22 DXT1,
23 DXT3,
24 DXT5,
26 BGR565,
31 UV88,
36 R32F,
39 // endregion
40
41 // region Alien Swarm & Beyond Formats
42 RG1616F,
43 RG3232F,
45 EMPTY,
46 ATI2N,
47 ATI1N,
50 R16F,
51 // endregion
52
53 // region Console Formats
66 // endregion
67
68 // region Strata Source Formats
69 R8 = 69,
70 BC7,
71 BC6H,
72 // endregion
73};
74
75namespace ImageFormatDetails {
76
77[[nodiscard]] constexpr int8_t red(ImageFormat format) {
78 switch (format) {
79 using enum ImageFormat;
80 case R32F:
81 case RG3232F:
82 case RGB323232F:
83 case RGBA32323232F:
84 return 32;
85 case R16F:
86 case RG1616F:
87 case RGBA16161616F:
88 case RGBA16161616:
90 return 16;
91 case RGBA1010102:
92 case BGRA1010102:
93 return 10;
94 case RGBA8888:
96 case ABGR8888:
98 case RGB888:
100 case BGR888:
102 case I8:
104 case IA88:
105 case P8:
108 case ARGB8888:
110 case BGRA8888:
113 case BGRX8888:
116 case UV88:
117 case UVWQ8888:
118 case UVLX8888:
119 case RGBX8888:
120 case R8:
121 return 8;
122 case RGB565:
123 case BGR565:
124 case BGRX5551:
126 case BGRA5551:
127 return 5;
128 case BGRA4444:
129 return 4;
130 case A8:
131 case EMPTY:
132 return 0;
133 case DXT1:
134 case DXT3:
135 case DXT5:
137 case ATI2N:
138 case ATI1N:
139 case BC7:
140 case BC6H:
141 return -1;
142 }
143 return 0;
144}
145
146[[nodiscard]] constexpr int8_t decompressedRed(ImageFormat format) {
147 // This is merely for convenience, the true size may be different depending on the data
148 switch (format) {
149 using enum ImageFormat;
150 case DXT1:
152 case DXT3:
153 case DXT5:
154 case ATI2N:
155 case ATI1N:
156 case BC7:
157 return 8;
158 case BC6H:
159 return 16;
160 default:
161 break;
162 }
163 return red(format);
164}
165
166[[nodiscard]] constexpr int8_t green(ImageFormat format) {
167 switch (format) {
168 using enum ImageFormat;
169 case RG3232F:
170 case RGB323232F:
171 case RGBA32323232F:
172 return 32;
173 case RG1616F:
174 case RGBA16161616F:
175 case RGBA16161616:
177 return 16;
178 case RGBA1010102:
179 case BGRA1010102:
180 return 10;
181 case RGBA8888:
183 case ABGR8888:
185 case RGB888:
187 case BGR888:
191 case ARGB8888:
193 case BGRA8888:
196 case BGRX8888:
199 case UV88:
200 case UVWQ8888:
201 case UVLX8888:
202 case RGBX8888:
203 return 8;
204 case RGB565:
205 case BGR565:
206 return 6;
207 case BGRX5551:
209 case BGRA5551:
210 return 5;
211 case BGRA4444:
212 return 4;
213 case I8:
215 case IA88:
216 case P8:
217 case R32F:
218 case A8:
219 case EMPTY:
220 case R16F:
221 case R8:
222 return 0;
223 case DXT1:
224 case DXT3:
225 case DXT5:
227 case ATI2N:
228 case ATI1N:
229 case BC7:
230 case BC6H:
231 return -1;
232 }
233 return 0;
234}
235
236[[nodiscard]] constexpr int8_t decompressedGreen(ImageFormat format) {
237 // This is merely for convenience, the true size may be different depending on the data
238 switch (format) {
239 using enum ImageFormat;
240 case DXT1:
242 case DXT3:
243 case DXT5:
244 case ATI2N:
245 case ATI1N:
246 case BC7:
247 return 8;
248 case BC6H:
249 return 16;
250 default:
251 break;
252 }
253 return green(format);
254}
255
256[[nodiscard]] constexpr int8_t blue(ImageFormat format) {
257 switch (format) {
258 using enum ImageFormat;
259 case RGB323232F:
260 case RGBA32323232F:
261 return 32;
262 case RGBA16161616F:
263 case RGBA16161616:
265 return 16;
266 case RGBA1010102:
267 case BGRA1010102:
268 return 10;
269 case RGBA8888:
271 case ABGR8888:
273 case RGB888:
275 case BGR888:
279 case ARGB8888:
281 case BGRA8888:
284 case BGRX8888:
287 case UVWQ8888:
288 case UVLX8888:
289 case RGBX8888:
290 return 8;
291 case RGB565:
292 case BGR565:
293 case BGRX5551:
295 case BGRA5551:
296 return 5;
297 case BGRA4444:
298 return 4;
299 case I8:
301 case IA88:
302 case P8:
303 case UV88:
304 case R32F:
305 case A8:
306 case EMPTY:
307 case RG3232F:
308 case RG1616F:
309 case R16F:
310 case R8:
311 return 0;
312 case DXT1:
313 case DXT3:
314 case DXT5:
316 case ATI2N:
317 case ATI1N:
318 case BC7:
319 case BC6H:
320 return -1;
321 }
322 return 0;
323}
324
325[[nodiscard]] constexpr int8_t decompressedBlue(ImageFormat format) {
326 // This is merely for convenience, the true size may be different depending on the data
327 switch (format) {
328 using enum ImageFormat;
329 case DXT1:
331 case DXT3:
332 case DXT5:
333 case ATI2N:
334 case ATI1N:
335 case BC7:
336 return 8;
337 case BC6H:
338 return 16;
339 default:
340 break;
341 }
342 return blue(format);
343}
344
345[[nodiscard]] constexpr int8_t alpha(ImageFormat format) {
346 switch (format) {
347 using enum ImageFormat;
348 case RGBA32323232F:
349 return 32;
350 case RGBA16161616F:
351 case RGBA16161616:
353 return 16;
354 case RGBA8888:
356 case ABGR8888:
358 case IA88:
359 case ARGB8888:
361 case BGRA8888:
364 case BGRX8888:
367 case UVWQ8888:
368 case UVLX8888:
369 case RGBX8888:
370 return 8;
371 case BGRA4444:
372 return 4;
373 case RGBA1010102:
374 case BGRA1010102:
375 return 2;
376 case BGRX5551:
378 case BGRA5551:
379 return 1;
380 case RGB888:
382 case BGR888:
384 case P8:
385 case I8:
389 case UV88:
390 case RGB565:
391 case BGR565:
392 case R32F:
393 case RGB323232F:
394 case A8:
395 case EMPTY:
396 case RG3232F:
397 case RG1616F:
398 case R16F:
399 case R8:
400 return 0;
401 case DXT1:
402 case DXT3:
403 case DXT5:
405 case ATI2N:
406 case ATI1N:
407 case BC7:
408 case BC6H:
409 return -1;
410 }
411 return 0;
412}
413
414[[nodiscard]] constexpr int8_t decompressedAlpha(ImageFormat format) {
415 // This is merely for convenience, the true size may be different depending on the data
416 switch (format) {
417 using enum ImageFormat;
418 case DXT5:
419 case BC7:
420 return 8;
421 case DXT3:
422 return 4;
424 return 1;
425 case DXT1:
426 case ATI2N:
427 case ATI1N:
428 case BC6H:
429 return 0;
430 default:
431 break;
432 }
433 return alpha(format);
434}
435
436[[nodiscard]] constexpr uint8_t bpp(ImageFormat format) {
437 switch (format) {
438 using enum ImageFormat;
439 case RGBA32323232F:
440 return 128;
441 case RGB323232F:
442 return 96;
443 case RGBA16161616F:
444 case RGBA16161616:
446 case RG3232F:
447 return 64;
448 case RGBA8888:
450 case ABGR8888:
452 case ARGB8888:
454 case BGRA8888:
457 case BGRX8888:
460 case UVLX8888:
461 case R32F:
462 case UVWQ8888:
463 case RGBX8888:
464 case RGBA1010102:
465 case BGRA1010102:
466 case RG1616F:
467 return 32;
468 case RGB888:
470 case BGR888:
474 return 24;
475 case RGB565:
476 case BGR565:
477 case IA88:
478 case BGRX5551:
480 case BGRA4444:
481 case BGRA5551:
482 case UV88:
483 case R16F:
484 return 16;
485 case I8:
487 case P8:
488 case A8:
489 case DXT3:
490 case DXT5:
491 case BC7:
492 case BC6H:
493 case ATI2N:
494 case R8:
495 return 8;
496 case ATI1N:
497 case DXT1:
499 return 4;
500 case EMPTY:
501 return 0;
502 }
503 return 0;
504}
505
506[[nodiscard]] constexpr ImageFormat containerFormat(ImageFormat format) {
507 switch (format) {
508 using enum ImageFormat;
509 case R32F:
510 case RG3232F:
511 case RGB323232F:
512 case R16F:
513 case RG1616F:
514 case RGBA16161616F:
515 case RGBA32323232F:
516 case BC6H:
517 return RGBA32323232F;
518 case RGBA16161616:
520 case RGBA1010102:
521 case BGRA1010102:
522 return RGBA16161616;
523 case RGBA8888:
525 case ABGR8888:
527 case RGB888:
529 case BGR888:
533 case ARGB8888:
535 case BGRA8888:
538 case BGRX8888:
541 case UVWQ8888:
542 case UVLX8888:
543 case RGB565:
544 case BGR565:
545 case BGRX5551:
547 case BGRA5551:
548 case BGRA4444:
549 case I8:
551 case IA88:
552 case P8:
553 case UV88:
554 case A8:
555 case DXT1:
556 case DXT3:
557 case DXT5:
559 case ATI2N:
560 case ATI1N:
561 case RGBX8888:
562 case R8:
563 case BC7:
564 return RGBA8888;
565 case EMPTY:
566 break;
567 }
568 return ImageFormat::EMPTY;
569}
570
571[[nodiscard]] constexpr bool large(ImageFormat format) {
573}
574
575[[nodiscard]] constexpr bool decimal(ImageFormat format) {
577}
578
579[[nodiscard]] constexpr bool compressed(ImageFormat format) {
580 return red(format) == -1;
581}
582
583[[nodiscard]] constexpr bool transparent(ImageFormat format) {
584 const auto a = alpha(format);
585 if (a < 0) {
586 switch (format) {
587 using enum ImageFormat;
588 case DXT3:
589 case DXT5:
591 case ATI2N:
592 case ATI1N:
593 case BC7:
594 case BC6H:
595 return true;
596 default:
597 break;
598 }
599 return false;
600 }
601 switch (format) {
602 using enum ImageFormat;
605 return true;
606 case BGRX8888:
609 case BGRX5551:
611 case UVLX8888:
612 case RGBX8888:
613 return false;
614 default:
615 break;
616 }
617 return a != 0;
618}
619
620[[nodiscard]] constexpr bool opaque(ImageFormat format) {
621 return !transparent(format);
622}
623
624} // namespace ImageFormatDetails
625
626namespace ImageDimensions {
627
628[[nodiscard]] constexpr uint32_t getMipDim(uint8_t mip, uint16_t dim) {
629 for (int i = 0; i < mip; i++) {
630 dim /= 2;
631 }
632 return dim;
633}
634
635[[nodiscard]] constexpr uint8_t getRecommendedMipCountForDims(ImageFormat format, uint16_t width, uint16_t height) {
636 // Note that compressed formats need 4x4 pixel blocks
638 const auto log2 = std::bit_width(width > height ? height : width);
639 if (!ImageFormatDetails::compressed(format)) {
640 return log2;
641 }
642 // Eliminate 2x2, 1x1
643 return log2 - 2 > 1 ? log2 - 2 : 1;
644 }
645
646 uint8_t maxMipCount = 1;
647 if (ImageFormatDetails::compressed(format)) {
648 while (width > 0 && height > 0 && width % 4 == 0 && height % 4 == 0) {
649 width /= 2;
650 height /= 2;
651 maxMipCount++;
652 }
653 } else {
654 while (width > 0 && height > 0 && width % 2 == 0 && height % 2 == 0) {
655 width /= 2;
656 height /= 2;
657 maxMipCount++;
658 }
659 }
660 return maxMipCount;
661}
662
663[[nodiscard]] constexpr uint8_t getActualMipCountForDimsOnConsole(uint16_t width, uint16_t height) {
664 if (width == 0 || height == 0) {
665 return 0;
666 }
667 uint8_t numMipLevels = 1;
668 while (true) {
669 if (width == 1 && height == 1) {
670 break;
671 }
672 width >>= 1;
673 if (width < 1) {
674 width = 1;
675 }
676 height >>= 1;
677 if (height < 1) {
678 height = 1;
679 }
680 numMipLevels += 1;
681 }
682 return numMipLevels;
683}
684
685} // namespace ImageDimensions
686
687namespace ImageFormatDetails {
688
689[[nodiscard]] constexpr uint32_t getDataLength(ImageFormat format, uint16_t width, uint16_t height, uint16_t sliceCount = 1) {
690 switch(format) {
691 using enum ImageFormat;
692 case DXT3:
693 case DXT5:
694 case ATI2N:
695 case BC7:
696 case BC6H:
697 case ATI1N:
698 case DXT1:
700 return ((((width + 3) / 4) < 1) ? 1 : ((width + 3) / 4)) * ((((height + 3) / 4) < 1) ? 1 : ((height + 3) / 4)) * sliceCount * bpp(format) * 2;
701 default:
702 break;
703 }
704 return width * height * sliceCount * (bpp(format) / 8);
705}
706
707[[nodiscard]] constexpr uint32_t getDataLength(ImageFormat format, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t sliceCount = 1) {
708 uint32_t length = 0;
709 for (int mip = mipCount - 1; mip >= 0; mip--) {
710 length += ImageFormatDetails::getDataLength(format, ImageDimensions::getMipDim(mip, width), ImageDimensions::getMipDim(mip, height), sliceCount) * frameCount * faceCount;
711 }
712 return length;
713}
714
715[[nodiscard]] constexpr bool getDataPosition(uint32_t& offset, uint32_t& length, ImageFormat format, uint8_t mip, uint8_t mipCount, uint16_t frame, uint16_t frameCount, uint8_t face, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t slice = 0, uint16_t sliceCount = 1) {
716 offset = 0;
717 length = 0;
718 for (int i = mipCount - 1; i >= 0; i--) {
719 for (int j = 0; j < frameCount; j++) {
720 for (int k = 0; k < faceCount; k++) {
721 for (int l = 0; l < sliceCount; l++) {
722 const auto imageSize = ImageFormatDetails::getDataLength(format, ImageDimensions::getMipDim(i, width), ImageDimensions::getMipDim(i, height));
723 if (i == mip && j == frame && k == face && l == slice) {
724 length = imageSize;
725 return true;
726 } else {
727 offset += imageSize;
728 }
729 }
730 }
731 }
732 }
733 return false;
734}
735
736} // namespace ImageFormatDetails
737
738} // namespace vtfpp
constexpr bool isPowerOf2(std::unsigned_integral auto n)
Definition: Math.h:43
constexpr uint32_t getMipDim(uint8_t mip, uint16_t dim)
Definition: ImageFormats.h:628
constexpr uint8_t getActualMipCountForDimsOnConsole(uint16_t width, uint16_t height)
Definition: ImageFormats.h:663
constexpr uint8_t getRecommendedMipCountForDims(ImageFormat format, uint16_t width, uint16_t height)
Definition: ImageFormats.h:635
constexpr int8_t decompressedGreen(ImageFormat format)
Definition: ImageFormats.h:236
constexpr int8_t alpha(ImageFormat format)
Definition: ImageFormats.h:345
constexpr bool large(ImageFormat format)
Definition: ImageFormats.h:571
constexpr int8_t green(ImageFormat format)
Definition: ImageFormats.h:166
constexpr int8_t decompressedBlue(ImageFormat format)
Definition: ImageFormats.h:325
constexpr ImageFormat containerFormat(ImageFormat format)
Definition: ImageFormats.h:506
constexpr uint32_t getDataLength(ImageFormat format, uint16_t width, uint16_t height, uint16_t sliceCount=1)
Definition: ImageFormats.h:689
constexpr bool transparent(ImageFormat format)
Definition: ImageFormats.h:583
constexpr int8_t decompressedRed(ImageFormat format)
Definition: ImageFormats.h:146
constexpr int8_t decompressedAlpha(ImageFormat format)
Definition: ImageFormats.h:414
constexpr bool getDataPosition(uint32_t &offset, uint32_t &length, ImageFormat format, uint8_t mip, uint8_t mipCount, uint16_t frame, uint16_t frameCount, uint8_t face, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t slice=0, uint16_t sliceCount=1)
Definition: ImageFormats.h:715
constexpr int8_t red(ImageFormat format)
Definition: ImageFormats.h:77
constexpr bool decimal(ImageFormat format)
Definition: ImageFormats.h:575
constexpr uint8_t bpp(ImageFormat format)
Definition: ImageFormats.h:436
constexpr bool opaque(ImageFormat format)
Definition: ImageFormats.h:620
constexpr bool compressed(ImageFormat format)
Definition: ImageFormats.h:579
constexpr int8_t blue(ImageFormat format)
Definition: ImageFormats.h:256
ImageFormat
Definition: ImageFormats.h:7