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
85
87
94[[nodiscard]] constexpr int8_t red(ImageFormat format) {
95 switch (format) {
96 using enum ImageFormat;
97 case R32F:
98 case RG3232F:
99 case RGB323232F:
100 case RGBA32323232F:
101 return 32;
102 case R16F:
103 case RG1616F:
104 case RGBA16161616F:
105 case RGBA16161616:
107 return 16;
108 case RGBA1010102:
109 case BGRA1010102:
110 return 10;
111 case RGBA8888:
113 case ABGR8888:
115 case RGB888:
117 case BGR888:
119 case I8:
121 case IA88:
122 case P8:
125 case ARGB8888:
127 case BGRA8888:
130 case BGRX8888:
133 case UV88:
134 case UVWQ8888:
135 case UVLX8888:
136 case RGBX8888:
137 case STRATA_R8:
138 return 8;
139 case RGB565:
140 case BGR565:
141 case BGRX5551:
143 case BGRA5551:
144 return 5;
145 case BGRA4444:
146 return 4;
147 case A8:
148 case EMPTY:
149 return 0;
150 case DXT1:
151 case DXT3:
152 case DXT5:
154 case ATI2N:
155 case ATI1N:
156 case TFALL2_BC6H:
157 case TFALL2_BC7:
158 case STRATA_BC7:
159 case STRATA_BC6H:
160 return -1;
161 }
162 return 0;
163}
164
170[[nodiscard]] constexpr int8_t decompressedRed(ImageFormat format) {
171 // This is merely for convenience, the true size may be different depending on the data
172 switch (format) {
173 using enum ImageFormat;
174 case DXT1:
176 case DXT3:
177 case DXT5:
178 case ATI2N:
179 case ATI1N:
180 case TFALL2_BC7:
181 case STRATA_BC7:
182 return 8;
183 case TFALL2_BC6H:
184 case STRATA_BC6H:
185 return 16;
186 default:
187 break;
188 }
189 return red(format);
190}
191
198[[nodiscard]] constexpr int8_t green(ImageFormat format) {
199 switch (format) {
200 using enum ImageFormat;
201 case RG3232F:
202 case RGB323232F:
203 case RGBA32323232F:
204 return 32;
205 case RG1616F:
206 case RGBA16161616F:
207 case RGBA16161616:
209 return 16;
210 case RGBA1010102:
211 case BGRA1010102:
212 return 10;
213 case RGBA8888:
215 case ABGR8888:
217 case RGB888:
219 case BGR888:
223 case ARGB8888:
225 case BGRA8888:
228 case BGRX8888:
231 case UV88:
232 case UVWQ8888:
233 case UVLX8888:
234 case RGBX8888:
235 return 8;
236 case RGB565:
237 case BGR565:
238 return 6;
239 case BGRX5551:
241 case BGRA5551:
242 return 5;
243 case BGRA4444:
244 return 4;
245 case I8:
247 case IA88:
248 case P8:
249 case R32F:
250 case A8:
251 case EMPTY:
252 case R16F:
253 case STRATA_R8:
254 return 0;
255 case DXT1:
256 case DXT3:
257 case DXT5:
259 case ATI2N:
260 case ATI1N:
261 case TFALL2_BC6H:
262 case TFALL2_BC7:
263 case STRATA_BC7:
264 case STRATA_BC6H:
265 return -1;
266 }
267 return 0;
268}
269
275[[nodiscard]] constexpr int8_t decompressedGreen(ImageFormat format) {
276 // This is merely for convenience, the true size may be different depending on the data
277 switch (format) {
278 using enum ImageFormat;
279 case DXT1:
281 case DXT3:
282 case DXT5:
283 case ATI2N:
284 case ATI1N:
285 case TFALL2_BC7:
286 case STRATA_BC7:
287 return 8;
288 case TFALL2_BC6H:
289 case STRATA_BC6H:
290 return 16;
291 default:
292 break;
293 }
294 return green(format);
295}
296
303[[nodiscard]] constexpr int8_t blue(ImageFormat format) {
304 switch (format) {
305 using enum ImageFormat;
306 case RGB323232F:
307 case RGBA32323232F:
308 return 32;
309 case RGBA16161616F:
310 case RGBA16161616:
312 return 16;
313 case RGBA1010102:
314 case BGRA1010102:
315 return 10;
316 case RGBA8888:
318 case ABGR8888:
320 case RGB888:
322 case BGR888:
326 case ARGB8888:
328 case BGRA8888:
331 case BGRX8888:
334 case UVWQ8888:
335 case UVLX8888:
336 case RGBX8888:
337 return 8;
338 case RGB565:
339 case BGR565:
340 case BGRX5551:
342 case BGRA5551:
343 return 5;
344 case BGRA4444:
345 return 4;
346 case I8:
348 case IA88:
349 case P8:
350 case UV88:
351 case R32F:
352 case A8:
353 case EMPTY:
354 case RG3232F:
355 case RG1616F:
356 case R16F:
357 case STRATA_R8:
358 return 0;
359 case DXT1:
360 case DXT3:
361 case DXT5:
363 case ATI2N:
364 case ATI1N:
365 case TFALL2_BC6H:
366 case TFALL2_BC7:
367 case STRATA_BC7:
368 case STRATA_BC6H:
369 return -1;
370 }
371 return 0;
372}
373
379[[nodiscard]] constexpr int8_t decompressedBlue(ImageFormat format) {
380 // This is merely for convenience, the true size may be different depending on the data
381 switch (format) {
382 using enum ImageFormat;
383 case DXT1:
385 case DXT3:
386 case DXT5:
387 case ATI2N:
388 case ATI1N:
389 case TFALL2_BC7:
390 case STRATA_BC7:
391 return 8;
392 case TFALL2_BC6H:
393 case STRATA_BC6H:
394 return 16;
395 default:
396 break;
397 }
398 return blue(format);
399}
400
407[[nodiscard]] constexpr int8_t alpha(ImageFormat format) {
408 switch (format) {
409 using enum ImageFormat;
410 case RGBA32323232F:
411 return 32;
412 case RGBA16161616F:
413 case RGBA16161616:
415 return 16;
416 case RGBA8888:
418 case ABGR8888:
420 case IA88:
421 case A8:
422 case ARGB8888:
424 case BGRA8888:
427 case BGRX8888:
430 case UVWQ8888:
431 case UVLX8888:
432 case RGBX8888:
433 return 8;
434 case BGRA4444:
435 return 4;
436 case RGBA1010102:
437 case BGRA1010102:
438 return 2;
439 case BGRX5551:
441 case BGRA5551:
442 return 1;
443 case RGB888:
445 case BGR888:
447 case P8:
448 case I8:
452 case UV88:
453 case RGB565:
454 case BGR565:
455 case R32F:
456 case RGB323232F:
457 case EMPTY:
458 case RG3232F:
459 case RG1616F:
460 case R16F:
461 case STRATA_R8:
462 return 0;
463 case DXT1:
464 case DXT3:
465 case DXT5:
467 case ATI2N:
468 case ATI1N:
469 case TFALL2_BC6H:
470 case TFALL2_BC7:
471 case STRATA_BC7:
472 case STRATA_BC6H:
473 return -1;
474 }
475 return 0;
476}
477
483[[nodiscard]] constexpr int8_t decompressedAlpha(ImageFormat format) {
484 // This is merely for convenience, the true size may be different depending on the data
485 switch (format) {
486 using enum ImageFormat;
487 case DXT5:
488 case TFALL2_BC7:
489 case STRATA_BC7:
490 return 8;
491 case DXT3:
492 return 4;
494 return 1;
495 case DXT1:
496 case ATI2N:
497 case ATI1N:
498 case TFALL2_BC6H:
499 case STRATA_BC6H:
500 return 0;
501 default:
502 break;
503 }
504 return alpha(format);
505}
506
513[[nodiscard]] constexpr uint8_t bpp(ImageFormat format) {
514 switch (format) {
515 using enum ImageFormat;
516 case RGBA32323232F:
517 return 128;
518 case RGB323232F:
519 return 96;
520 case RGBA16161616F:
521 case RGBA16161616:
523 case RG3232F:
524 return 64;
525 case RGBA8888:
527 case ABGR8888:
529 case ARGB8888:
531 case BGRA8888:
534 case BGRX8888:
537 case UVLX8888:
538 case R32F:
539 case UVWQ8888:
540 case RGBX8888:
541 case RGBA1010102:
542 case BGRA1010102:
543 case RG1616F:
544 return 32;
545 case RGB888:
547 case BGR888:
551 return 24;
552 case RGB565:
553 case BGR565:
554 case IA88:
555 case BGRX5551:
557 case BGRA4444:
558 case BGRA5551:
559 case UV88:
560 case R16F:
561 return 16;
562 case I8:
564 case P8:
565 case A8:
566 case DXT3:
567 case DXT5:
568 case ATI2N:
569 case TFALL2_BC6H:
570 case TFALL2_BC7:
571 case STRATA_BC7:
572 case STRATA_BC6H:
573 case STRATA_R8:
574 return 8;
575 case ATI1N:
576 case DXT1:
578 return 4;
579 case EMPTY:
580 return 0;
581 }
582 return 0;
583}
584
593[[nodiscard]] constexpr ImageFormat containerFormat(ImageFormat format) {
594 switch (format) {
595 using enum ImageFormat;
596 case R32F:
597 case RG3232F:
598 case RGB323232F:
599 case R16F:
600 case RG1616F:
601 case RGBA16161616F:
602 case RGBA32323232F:
603 case TFALL2_BC6H:
604 case STRATA_BC6H:
605 return RGBA32323232F;
606 case RGBA16161616:
608 case RGBA1010102:
609 case BGRA1010102:
610 return RGBA16161616;
611 case RGBA8888:
613 case ABGR8888:
615 case RGB888:
617 case BGR888:
621 case ARGB8888:
623 case BGRA8888:
626 case BGRX8888:
629 case UVWQ8888:
630 case UVLX8888:
631 case RGB565:
632 case BGR565:
633 case BGRX5551:
635 case BGRA5551:
636 case BGRA4444:
637 case I8:
639 case IA88:
640 case P8:
641 case UV88:
642 case A8:
643 case DXT1:
644 case DXT3:
645 case DXT5:
647 case ATI2N:
648 case ATI1N:
649 case RGBX8888:
650 case TFALL2_BC7:
651 case STRATA_R8:
652 case STRATA_BC7:
653 return RGBA8888;
654 case EMPTY:
655 break;
656 }
657 return ImageFormat::EMPTY;
658}
659
665[[nodiscard]] constexpr bool large(ImageFormat format) {
667}
668
674[[nodiscard]] constexpr bool decimal(ImageFormat format) {
676}
677
683[[nodiscard]] constexpr bool compressed(ImageFormat format) {
684 return red(format) == -1;
685}
686
692[[nodiscard]] constexpr bool transparent(ImageFormat format) {
693 const auto a = alpha(format);
694 if (a < 0) {
695 switch (format) {
696 using enum ImageFormat;
697 case DXT3:
698 case DXT5:
700 case ATI2N:
701 case ATI1N:
702 case TFALL2_BC6H:
703 case TFALL2_BC7:
704 case STRATA_BC7:
705 case STRATA_BC6H:
706 return true;
707 default:
708 break;
709 }
710 return false;
711 }
712 switch (format) {
713 using enum ImageFormat;
716 return true;
717 case BGRX8888:
720 case BGRX5551:
722 case UVLX8888:
723 case RGBX8888:
724 return false;
725 default:
726 break;
727 }
728 return a != 0;
729}
730
736[[nodiscard]] constexpr bool opaque(ImageFormat format) {
737 return !transparent(format);
738}
739
745[[nodiscard]] constexpr bool console(ImageFormat format) {
746 switch (format) {
747 using enum ImageFormat;
760 return true;
761 default:
762 break;
763 }
764 return false;
765}
766
767} // namespace ImageFormatDetails
768
770
780[[nodiscard]] constexpr uint16_t getMipDim(uint8_t mip, uint16_t dim, bool addCompressedFormatPadding = false) {
781 if (!dim) {
782 dim = 1;
783 }
784 for (int i = 0; i < mip && dim > 1; i++) {
785 dim >>= 1;
786 }
787 if (addCompressedFormatPadding) {
789 }
790 return dim;
791}
792
801[[nodiscard]] constexpr std::pair<uint16_t, uint16_t> getMipDims(uint8_t mip, uint16_t width, uint16_t height, bool addCompressedFormatPadding = false) {
802 for (int i = 0; i < mip && (width > 1 || height > 1); i++) {
803 if ((width >>= 1) < 1) width = 1;
804 if ((height >>= 1) < 1) height = 1;
805 }
806 if (addCompressedFormatPadding) {
807 width += sourcepp::math::paddingForAlignment(4, width);
808 height += sourcepp::math::paddingForAlignment(4, height);
809 }
810 return {width, height};
811}
812
822[[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) {
823 for (int i = 0; i < mip && (width > 1 || height > 1 || depth > 1); i++) {
824 if ((width >>= 1) < 1) width = 1;
825 if ((height >>= 1) < 1) height = 1;
826 if ((depth >>= 1) < 1) depth = 1;
827 }
828 if (addCompressedFormatPadding) {
829 width += sourcepp::math::paddingForAlignment(4, width);
830 height += sourcepp::math::paddingForAlignment(4, height);
831 }
832 return {width, height, depth};
833}
834
844[[nodiscard]] constexpr uint8_t getMaximumMipCount(uint16_t width, uint16_t height, uint16_t depth = 1) {
845 uint8_t numMipLevels = 1;
846 if (width && height && depth) {
847 while (width > 1 || height > 1 || depth > 1) {
848 if ((width >>= 1) < 1) width = 1;
849 if ((height >>= 1) < 1) height = 1;
850 if ((depth >>= 1) < 1) depth = 1;
851 numMipLevels++;
852 }
853 }
854 return numMipLevels;
855}
856
857} // namespace ImageDimensions
858
859namespace ImageFormatDetails {
860
869[[nodiscard]] constexpr uint32_t getDataLength(ImageFormat format, uint16_t width, uint16_t height, uint16_t depth = 1) {
870 if (ImageFormatDetails::compressed(format)) {
871 return ((width + 3) / 4) * ((height + 3) / 4) * depth * bpp(format) * 2;
872 }
873 return width * height * depth * (bpp(format) / 8);
874}
875
888[[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) {
889 uint32_t length = 0;
890 for (int i = mipCount - 1; i >= 0; i--) {
891 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
892 length += ImageFormatDetails::getDataLength(format, mipWidth, mipHeight, mipDepth) * frameCount * faceCount;
893 }
894 return length;
895}
896
913[[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) {
914 uint32_t length = 0;
915 for (int j = 0; j < frameCount; j++) {
916 for (int i = 0; i < mipCount; i++) {
917 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
918 length += ImageFormatDetails::getDataLength(format, mipWidth, mipHeight, mipDepth) * faceCount;
919 }
920 if (padded && j + 1 != frameCount && length > 512) {
921 length += sourcepp::math::paddingForAlignment(512, length);
922 }
923 }
924 return length;
925}
926
944[[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) {
945 offset = 0;
946 length = 0;
947 for (int i = mipCount - 1; i >= 0; i--) {
948 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
949 for (int j = 0; j < frameCount; j++) {
950 for (int k = 0; k < faceCount; k++) {
951 for (int l = 0; l < mipDepth; l++) {
952 const auto imageSize = ImageFormatDetails::getDataLength(format, mipWidth, mipHeight);
953 if (i == mip && j == frame && k == face && l == slice) {
954 length = imageSize;
955 return true;
956 }
957 offset += imageSize;
958 }
959 }
960 }
961 }
962 return false;
963}
964
986[[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) {
987 offset = 0;
988 length = 0;
989 for (int j = 0; j < frameCount; j++) {
990 for (int k = 0; k < faceCount; k++) {
991 for (int i = 0; i < mipCount; i++) {
992 const auto [mipWidth, mipHeight, mipDepth] = ImageDimensions::getMipDims(i, width, height, depth);
993 for (int l = 0; l < mipDepth; l++) {
994 const auto imageSize = ImageFormatDetails::getDataLength(format, mipWidth, mipHeight);
995 if (i == mip && j == frame && k == face && l == slice) {
996 length = imageSize;
997 return true;
998 }
999 offset += imageSize;
1000 }
1001 }
1002 }
1003 if (padded && j + 1 != frameCount && offset > 512) {
1004 offset += sourcepp::math::paddingForAlignment(512, offset);
1005 }
1006 }
1007 return false;
1008}
1009
1010} // namespace ImageFormatDetails
1011
1012} // namespace vtfpp
constexpr uint16_t paddingForAlignment(uint16_t alignment, uint64_t n)
Definition Math.h:61
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 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 opaque(ImageFormat format)
Check if the given format cannot store transparency.
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