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// ReSharper disable CppDFAUnreachableFunctionCall
2// ReSharper disable CppRedundantParentheses
3// ReSharper disable CppRedundantQualifier
4
5#pragma once
6
7#include <tuple>
8
9#include <sourcepp/Math.h>
10
11namespace vtfpp {
12
91
93
100[[nodiscard]] constexpr int8_t red(ImageFormat format) {
101 switch (format) {
102 using enum ImageFormat;
103 case R32F:
104 case RG3232F:
105 case RGB323232F:
106 case RGBA32323232F:
107 return 32;
108 case R16F:
109 case RG1616F:
110 case RGBA16161616F:
111 case RGBA16161616:
113 return 16;
114 case RGBA1010102:
115 case BGRA1010102:
116 return 10;
117 case RGBA8888:
119 case ABGR8888:
121 case RGB888:
123 case BGR888:
125 case I8:
127 case IA88:
128 case P8:
131 case ARGB8888:
133 case BGRA8888:
136 case BGRX8888:
139 case UV88:
140 case UVWQ8888:
141 case UVLX8888:
142 case RGBX8888:
143 case STRATA_R8:
144 return 8;
145 case RGB565:
146 case BGR565:
147 case BGRX5551:
149 case BGRA5551:
150 return 5;
151 case BGRA4444:
152 return 4;
153 case A8:
154 case EMPTY:
155 return 0;
156 case DXT1:
157 case DXT3:
158 case DXT5:
160 case ATI2N:
161 case ATI1N:
162 case TITANFALL_BC6H:
163 case TITANFALL_BC7:
164 case STRATA_BC7:
165 case STRATA_BC6H:
169 return -1;
170 }
171 return 0;
172}
173
179[[nodiscard]] constexpr int8_t decompressedRed(ImageFormat format) {
180 // This is merely for convenience, the true size may be different depending on the data
181 switch (format) {
182 using enum ImageFormat;
183 case DXT1:
185 case DXT3:
186 case DXT5:
187 case ATI2N:
188 case ATI1N:
189 case TITANFALL_BC7:
190 case STRATA_BC7:
191 return 8;
192 case TITANFALL_BC6H:
193 case STRATA_BC6H:
197 return 16;
198 default:
199 break;
200 }
201 return red(format);
202}
203
210[[nodiscard]] constexpr int8_t green(ImageFormat format) {
211 switch (format) {
212 using enum ImageFormat;
213 case RG3232F:
214 case RGB323232F:
215 case RGBA32323232F:
216 return 32;
217 case RG1616F:
218 case RGBA16161616F:
219 case RGBA16161616:
221 return 16;
222 case RGBA1010102:
223 case BGRA1010102:
224 return 10;
225 case RGBA8888:
227 case ABGR8888:
229 case RGB888:
231 case BGR888:
235 case ARGB8888:
237 case BGRA8888:
240 case BGRX8888:
243 case UV88:
244 case UVWQ8888:
245 case UVLX8888:
246 case RGBX8888:
247 return 8;
248 case RGB565:
249 case BGR565:
250 return 6;
251 case BGRX5551:
253 case BGRA5551:
254 return 5;
255 case BGRA4444:
256 return 4;
257 case I8:
259 case IA88:
260 case P8:
261 case R32F:
262 case A8:
263 case EMPTY:
264 case R16F:
265 case STRATA_R8:
266 return 0;
267 case DXT1:
268 case DXT3:
269 case DXT5:
271 case ATI2N:
272 case ATI1N:
273 case TITANFALL_BC6H:
274 case TITANFALL_BC7:
275 case STRATA_BC7:
276 case STRATA_BC6H:
280 return -1;
281 }
282 return 0;
283}
284
290[[nodiscard]] constexpr int8_t decompressedGreen(ImageFormat format) {
291 // This is merely for convenience, the true size may be different depending on the data
292 switch (format) {
293 using enum ImageFormat;
294 case DXT1:
296 case DXT3:
297 case DXT5:
298 case ATI2N:
299 case ATI1N:
300 case TITANFALL_BC7:
301 case STRATA_BC7:
302 return 8;
303 case TITANFALL_BC6H:
304 case STRATA_BC6H:
308 return 16;
309 default:
310 break;
311 }
312 return green(format);
313}
314
321[[nodiscard]] constexpr int8_t blue(ImageFormat format) {
322 switch (format) {
323 using enum ImageFormat;
324 case RGB323232F:
325 case RGBA32323232F:
326 return 32;
327 case RGBA16161616F:
328 case RGBA16161616:
330 return 16;
331 case RGBA1010102:
332 case BGRA1010102:
333 return 10;
334 case RGBA8888:
336 case ABGR8888:
338 case RGB888:
340 case BGR888:
344 case ARGB8888:
346 case BGRA8888:
349 case BGRX8888:
352 case UVWQ8888:
353 case UVLX8888:
354 case RGBX8888:
355 return 8;
356 case RGB565:
357 case BGR565:
358 case BGRX5551:
360 case BGRA5551:
361 return 5;
362 case BGRA4444:
363 return 4;
364 case I8:
366 case IA88:
367 case P8:
368 case UV88:
369 case R32F:
370 case A8:
371 case EMPTY:
372 case RG3232F:
373 case RG1616F:
374 case R16F:
375 case STRATA_R8:
376 return 0;
377 case DXT1:
378 case DXT3:
379 case DXT5:
381 case ATI2N:
382 case ATI1N:
383 case TITANFALL_BC6H:
384 case TITANFALL_BC7:
385 case STRATA_BC7:
386 case STRATA_BC6H:
390 return -1;
391 }
392 return 0;
393}
394
400[[nodiscard]] constexpr int8_t decompressedBlue(ImageFormat format) {
401 // This is merely for convenience, the true size may be different depending on the data
402 switch (format) {
403 using enum ImageFormat;
404 case DXT1:
406 case DXT3:
407 case DXT5:
408 case ATI2N:
409 case ATI1N:
410 case TITANFALL_BC7:
411 case STRATA_BC7:
412 return 8;
413 case TITANFALL_BC6H:
414 case STRATA_BC6H:
418 return 16;
419 default:
420 break;
421 }
422 return blue(format);
423}
424
431[[nodiscard]] constexpr int8_t alpha(ImageFormat format) {
432 switch (format) {
433 using enum ImageFormat;
434 case RGBA32323232F:
435 return 32;
436 case RGBA16161616F:
437 case RGBA16161616:
439 return 16;
440 case RGBA8888:
442 case ABGR8888:
444 case IA88:
445 case A8:
446 case ARGB8888:
448 case BGRA8888:
451 case BGRX8888:
454 case UVWQ8888:
455 case UVLX8888:
456 case RGBX8888:
457 return 8;
458 case BGRA4444:
459 return 4;
460 case RGBA1010102:
461 case BGRA1010102:
462 return 2;
463 case BGRX5551:
465 case BGRA5551:
466 return 1;
467 case RGB888:
469 case BGR888:
471 case P8:
472 case I8:
476 case UV88:
477 case RGB565:
478 case BGR565:
479 case R32F:
480 case RGB323232F:
481 case EMPTY:
482 case RG3232F:
483 case RG1616F:
484 case R16F:
485 case STRATA_R8:
486 return 0;
487 case DXT1:
488 case DXT3:
489 case DXT5:
491 case ATI2N:
492 case ATI1N:
493 case TITANFALL_BC6H:
494 case TITANFALL_BC7:
495 case STRATA_BC7:
496 case STRATA_BC6H:
500 return -1;
501 }
502 return 0;
503}
504
510[[nodiscard]] constexpr int8_t decompressedAlpha(ImageFormat format) {
511 // This is merely for convenience, the true size may be different depending on the data
512 switch (format) {
513 using enum ImageFormat;
514 case DXT5:
515 case TITANFALL_BC7:
516 case STRATA_BC7:
517 return 8;
518 case DXT3:
519 return 4;
521 return 1;
522 case DXT1:
523 case ATI2N:
524 case ATI1N:
525 case TITANFALL_BC6H:
526 case STRATA_BC6H:
530 return 0;
531 default:
532 break;
533 }
534 return alpha(format);
535}
536
543[[nodiscard]] constexpr uint8_t bpp(ImageFormat format) {
544 switch (format) {
545 using enum ImageFormat;
546 case RGBA32323232F:
547 return 128;
548 case RGB323232F:
549 return 96;
550 case RGBA16161616F:
551 case RGBA16161616:
555 case RG3232F:
556 return 64;
557 case RGBA8888:
559 case ABGR8888:
561 case ARGB8888:
563 case BGRA8888:
567 case BGRX8888:
570 case UVLX8888:
571 case R32F:
572 case UVWQ8888:
573 case RGBX8888:
574 case RGBA1010102:
575 case BGRA1010102:
576 case RG1616F:
577 return 32;
578 case RGB888:
580 case BGR888:
584 return 24;
585 case RGB565:
586 case BGR565:
587 case IA88:
588 case BGRX5551:
590 case BGRA4444:
591 case BGRA5551:
592 case UV88:
593 case R16F:
594 return 16;
595 case I8:
597 case P8:
598 case A8:
599 case DXT3:
600 case DXT5:
601 case ATI2N:
602 case TITANFALL_BC6H:
603 case TITANFALL_BC7:
604 case STRATA_BC7:
605 case STRATA_BC6H:
606 case STRATA_R8:
607 return 8;
608 case ATI1N:
609 case DXT1:
611 return 4;
612 case EMPTY:
613 return 0;
614 }
615 return 0;
616}
617
626[[nodiscard]] constexpr ImageFormat containerFormat(ImageFormat format) {
627 switch (format) {
628 using enum ImageFormat;
629 case R32F:
630 case RG3232F:
631 case RGB323232F:
632 case R16F:
633 case RG1616F:
634 case RGBA16161616F:
635 case RGBA32323232F:
636 case TITANFALL_BC6H:
637 case STRATA_BC6H:
641 return RGBA32323232F;
642 case RGBA16161616:
644 case RGBA1010102:
645 case BGRA1010102:
646 return RGBA16161616;
647 case RGBA8888:
649 case ABGR8888:
651 case RGB888:
653 case BGR888:
657 case ARGB8888:
659 case BGRA8888:
662 case BGRX8888:
665 case UVWQ8888:
666 case UVLX8888:
667 case RGB565:
668 case BGR565:
669 case BGRX5551:
671 case BGRA5551:
672 case BGRA4444:
673 case I8:
675 case IA88:
676 case P8:
677 case UV88:
678 case A8:
679 case DXT1:
680 case DXT3:
681 case DXT5:
683 case ATI2N:
684 case ATI1N:
685 case RGBX8888:
686 case TITANFALL_BC7:
687 case STRATA_R8:
688 case STRATA_BC7:
689 return RGBA8888;
690 case EMPTY:
691 break;
692 }
693 return ImageFormat::EMPTY;
694}
695
701[[nodiscard]] constexpr bool large(ImageFormat format) {
703}
704
710[[nodiscard]] constexpr bool decimal(ImageFormat format) {
712}
713
719[[nodiscard]] constexpr bool compressed(ImageFormat format) {
720 return red(format) == -1;
721}
722
728[[nodiscard]] constexpr bool compressedHDR(ImageFormat format) {
729 switch (format) {
730 using enum ImageFormat;
734 return true;
735 default:
736 break;
737 }
738 return false;
739}
740
746[[nodiscard]] constexpr bool transparent(ImageFormat format) {
747 const auto a = alpha(format);
748 if (a < 0) {
749 switch (format) {
750 using enum ImageFormat;
751 case DXT3:
752 case DXT5:
754 case ATI2N:
755 case ATI1N:
756 case TITANFALL_BC6H:
757 case TITANFALL_BC7:
758 case STRATA_BC7:
759 case STRATA_BC6H:
760 return true;
761 default:
762 break;
763 }
764 return false;
765 }
766 switch (format) {
767 using enum ImageFormat;
770 return true;
771 case BGRX8888:
774 case BGRX5551:
776 case UVLX8888:
777 case RGBX8888:
778 return false;
779 default:
780 break;
781 }
782 return a != 0;
783}
784
790[[nodiscard]] constexpr bool opaque(ImageFormat format) {
791 return !transparent(format);
792}
793
799[[nodiscard]] constexpr bool console(ImageFormat format) {
800 switch (format) {
801 using enum ImageFormat;
815 return true;
816 default:
817 break;
818 }
819 return false;
820}
821
827[[nodiscard]] constexpr bool titanfall(ImageFormat format) {
828 switch (format) {
829 using enum ImageFormat;
830 case TITANFALL_BC6H:
831 case TITANFALL_BC7:
832 return true;
833 default:
834 break;
835 }
836 return false;
837}
838
844[[nodiscard]] constexpr bool strata(ImageFormat format) {
845 switch (format) {
846 using enum ImageFormat;
847 case STRATA_R8:
848 case STRATA_BC7:
849 case STRATA_BC6H:
850 return true;
851 default:
852 break;
853 }
854 return false;
855}
856
857} // namespace ImageFormatDetails
858
860
870[[nodiscard]] constexpr uint16_t getMipDim(uint8_t mip, uint16_t dim, bool addCompressedFormatPadding = false) {
871 if (!dim) {
872 return 0;
873 }
874 for (int i = 0; i < mip && dim > 1; i++) {
875 dim >>= 1;
876 }
877 if (addCompressedFormatPadding) {
879 }
880 return dim;
881}
882
891[[nodiscard]] constexpr std::pair<uint16_t, uint16_t> getMipDims(uint8_t mip, uint16_t width, uint16_t height, bool addCompressedFormatPadding = false) {
892 const auto originalWidth = width, originalHeight = height;
893 for (int i = 0; i < mip && (width > 1 || height > 1); i++) {
894 if ((width >>= 1) < 1) width = 1;
895 if ((height >>= 1) < 1) height = 1;
896 }
897 if (addCompressedFormatPadding) {
898 width += sourcepp::math::paddingForAlignment(4, width);
899 height += sourcepp::math::paddingForAlignment(4, height);
900 }
901 return {!originalWidth ? 0 : width, !originalHeight ? 0 : height};
902}
903
913[[nodiscard]] constexpr std::tuple<uint16_t, uint16_t, uint16_t> getMipDims(uint8_t mip, uint16_t width, uint16_t height, uint16_t depth, bool addCompressedFormatPadding = false) {
914 const auto originalWidth = width, originalHeight = height, originalDepth = depth;
915 for (int i = 0; i < mip && (width > 1 || height > 1 || depth > 1); i++) {
916 if ((width >>= 1) < 1) width = 1;
917 if ((height >>= 1) < 1) height = 1;
918 if ((depth >>= 1) < 1) depth = 1;
919 }
920 if (addCompressedFormatPadding) {
921 width += sourcepp::math::paddingForAlignment(4, width);
922 height += sourcepp::math::paddingForAlignment(4, height);
923 }
924 return {!originalWidth ? 0 : width, !originalHeight ? 0 : height, !originalDepth ? 0 : depth};
925}
926
936[[nodiscard]] constexpr uint8_t getMaximumMipCount(uint16_t width, uint16_t height, uint16_t depth = 1) {
937 uint8_t numMipLevels = 1;
938 if (width && height && depth) {
939 while (width > 1 || height > 1 || depth > 1) {
940 if ((width >>= 1) < 1) width = 1;
941 if ((height >>= 1) < 1) height = 1;
942 if ((depth >>= 1) < 1) depth = 1;
943 numMipLevels++;
944 }
945 }
946 return numMipLevels;
947}
948
949} // namespace ImageDimensions
950
951namespace ImageFormatDetails {
952
961[[nodiscard]] constexpr uint32_t getDataLength(ImageFormat format, uint16_t width, uint16_t height, uint16_t depth = 1) {
963 return ((width + 3) / 4) * ((height + 3) / 4) * depth * bpp(format) * 2;
964 }
965 return width * height * depth * (bpp(format) / 8);
966}
967
980[[nodiscard]] constexpr uint32_t getDataLength(ImageFormat format, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t depth = 1) {
981 uint32_t length = 0;
982 for (int i = mipCount - 1; i >= 0; i--) {
983 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
984 length += ImageFormatDetails::getDataLength(format, mipWidth, mipHeight, mipDepth) * frameCount * faceCount;
985 }
986 return length;
987}
988
1005[[nodiscard]] constexpr uint32_t getDataLengthXBOX(bool padded, ImageFormat format, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t depth = 1) {
1006 uint32_t length = 0;
1007 for (int j = 0; j < frameCount; j++) {
1008 for (int i = 0; i < mipCount; i++) {
1009 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
1010 length += ImageFormatDetails::getDataLength(format, mipWidth, mipHeight, mipDepth) * faceCount;
1011 }
1012 if (padded && j + 1 != frameCount && length > 512) {
1013 length += sourcepp::math::paddingForAlignment(512, length);
1014 }
1015 }
1016 return length;
1017}
1018
1036[[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 depth = 1) {
1037 offset = 0;
1038 length = 0;
1039 for (int i = mipCount - 1; i >= 0; i--) {
1040 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
1041 for (int j = 0; j < frameCount; j++) {
1042 for (int k = 0; k < faceCount; k++) {
1043 for (int l = 0; l < mipDepth; l++) {
1044 const auto imageSize = ImageFormatDetails::getDataLength(format, mipWidth, mipHeight);
1045 if (i == mip && j == frame && k == face && l == slice) {
1046 length = imageSize;
1047 return true;
1048 }
1049 offset += imageSize;
1050 }
1051 }
1052 }
1053 }
1054 return false;
1055}
1056
1078[[nodiscard]] constexpr bool getDataPositionXBOX(uint32_t& offset, uint32_t& length, bool padded, 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 depth = 1) {
1079 offset = 0;
1080 length = 0;
1081 for (int j = 0; j < frameCount; j++) {
1082 for (int k = 0; k < faceCount; k++) {
1083 for (int i = 0; i < mipCount; i++) {
1084 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
1085 for (int l = 0; l < mipDepth; l++) {
1086 const auto imageSize = ImageFormatDetails::getDataLength(format, mipWidth, mipHeight);
1087 if (i == mip && j == frame && k == face && l == slice) {
1088 length = imageSize;
1089 return true;
1090 }
1091 offset += imageSize;
1092 }
1093 }
1094 }
1095 if (padded && j + 1 != frameCount && offset > 512) {
1096 offset += sourcepp::math::paddingForAlignment(512, offset);
1097 }
1098 }
1099 return false;
1100}
1101
1102} // namespace ImageFormatDetails
1103
1104} // namespace vtfpp
constexpr uint16_t paddingForAlignment(uint16_t alignment, uint64_t n)
Definition Math.h:64
constexpr uint8_t getMaximumMipCount(uint16_t width, uint16_t height, uint16_t depth=1)
Calculate the largest mip count a texture with the given width, height, and depth can contain.
constexpr std::pair< uint16_t, uint16_t > getMipDims(uint8_t mip, uint16_t width, uint16_t height, bool addCompressedFormatPadding=false)
Get the width and height at a given mip level.
constexpr uint16_t getMipDim(uint8_t mip, uint16_t dim, bool addCompressedFormatPadding=false)
Get the dimension at a given mip level.
constexpr uint32_t getDataLength(ImageFormat format, uint16_t width, uint16_t height, uint16_t depth=1)
Calculate the amount of data required to store a texture with the given format and dimensions.
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 depth=1)
Find the position of a specific mip, frame, face, and slice within a texture.
constexpr int8_t decompressedGreen(ImageFormat format)
Get the number of bits of precision of the green channel in the given format regardless of compressio...
constexpr int8_t alpha(ImageFormat format)
Get the number of bits of precision of the alpha channel in the given format.
constexpr bool large(ImageFormat format)
Check if the given format is representable by RGBA8888 without losing data.
constexpr int8_t green(ImageFormat format)
Get the number of bits of precision of the green channel in the given format.
constexpr int8_t decompressedBlue(ImageFormat format)
Get the number of bits of precision of the blue channel in the given format regardless of compression...
constexpr ImageFormat containerFormat(ImageFormat format)
Find a container format for the given format, a format that is more commonly understood within this l...
constexpr bool transparent(ImageFormat format)
Check if the given format can store transparency.
constexpr uint32_t getDataLengthXBOX(bool padded, ImageFormat format, uint8_t mipCount, uint16_t frameCount, uint8_t faceCount, uint16_t width, uint16_t height, uint16_t depth=1)
Calculate the amount of data required to store an XBOX platform texture with the given format,...
constexpr int8_t decompressedRed(ImageFormat format)
Get the number of bits of precision of the red channel in the given format regardless of compression.
constexpr bool titanfall(ImageFormat format)
Check if the given format is exclusively used by Titanfall 1/2.
constexpr int8_t decompressedAlpha(ImageFormat format)
Get the number of bits of precision of the alpha channel in the given format regardless of compressio...
constexpr int8_t red(ImageFormat format)
Get the number of bits of precision of the red channel in the given format.
constexpr bool decimal(ImageFormat format)
Checks if the given format stores floating points in its channels.
constexpr uint8_t bpp(ImageFormat format)
Find the bits per pixel of the given format.
constexpr bool getDataPositionXBOX(uint32_t &offset, uint32_t &length, bool padded, 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 depth=1)
Find the position of a specific mip, frame, face, and slice within an XBOX platform texture.
constexpr bool console(ImageFormat format)
Check if the given format is exclusively used on console platforms.
constexpr bool compressedHDR(ImageFormat format)
Check if the given format is a compressed HDR format (not counting BC6H).
constexpr bool opaque(ImageFormat format)
Check if the given format cannot store transparency.
constexpr bool strata(ImageFormat format)
Check if the given format is exclusively used by Strata Source.
constexpr bool compressed(ImageFormat format)
Check if the given format is a compressed format (DXT1, DXT3, DXT5, ATI1N, ATI2N, BC7,...
constexpr int8_t blue(ImageFormat format)
Get the number of bits of precision of the blue channel in the given format.
Definition HOT.h:11