@@ -120,7 +120,8 @@ inline void register_python(py::module_& m) {
120120
121121 ImageFormatDetails
122122 .def (" get_data_length" , py::overload_cast<ImageFormat, uint16_t , uint16_t , uint16_t >(&getDataLength), py::arg (" format" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice_count" ) = 1 )
123- .def (" get_data_length_extended" , py::overload_cast<ImageFormat, uint8_t , uint16_t , uint8_t , uint16_t , uint16_t , uint16_t >(&getDataLength), py::arg (" format" ), py::arg (" mip_count" ), py::arg (" frame_count" ), py::arg (" face_count" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice_count" ));
123+ .def (" get_data_length_extended" , py::overload_cast<ImageFormat, uint8_t , uint16_t , uint8_t , uint16_t , uint16_t , uint16_t >(&getDataLength), py::arg (" format" ), py::arg (" mip_count" ), py::arg (" frame_count" ), py::arg (" face_count" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice_count" ) = 1 )
124+ .def (" get_data_length_xbox" , &getDataLengthXBOX, py::arg (" padded" ), py::arg (" format" ), py::arg (" mip_count" ), py::arg (" frame_count" ), py::arg (" face_count" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice_count" ) = 1 );
124125
125126 ImageFormatDetails.def (" get_data_position" , [](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 ) -> std::pair<uint32_t , uint32_t > {
126127 uint32_t offset, length;
@@ -129,6 +130,14 @@ inline void register_python(py::module_& m) {
129130 }
130131 return {0 , 0 };
131132 }, py::arg (" format" ), py::arg (" mip" ), py::arg (" mip_count" ), py::arg (" frame" ), py::arg (" frame_count" ), py::arg (" face" ), py::arg (" face_count" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice" ) = 0 , py::arg (" slice_count" ) = 1 );
133+
134+ ImageFormatDetails.def (" get_data_position_xbox" , [](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 sliceCount = 1 ) -> std::pair<uint32_t , uint32_t > {
135+ uint32_t offset, length;
136+ if (getDataPositionXbox (offset, length, padded, format, mip, mipCount, frame, frameCount, face, faceCount, width, height, slice, sliceCount)) {
137+ return {offset, length};
138+ }
139+ return {0 , 0 };
140+ }, py::arg (" padded" ), py::arg (" format" ), py::arg (" mip" ), py::arg (" mip_count" ), py::arg (" frame" ), py::arg (" frame_count" ), py::arg (" face" ), py::arg (" face_count" ), py::arg (" width" ), py::arg (" height" ), py::arg (" slice" ) = 0 , py::arg (" slice_count" ) = 1 );
132141 }
133142
134143 {
@@ -250,6 +259,16 @@ inline void register_python(py::module_& m) {
250259 // Skip extractChannelFromImageData, difficult to bind
251260 }
252261
262+ {
263+ using namespace ImageQuantize ;
264+ auto ImageQuantize = vtfpp.def_submodule (" ImageQuantize" );
265+
266+ ImageQuantize.def (" convert_p8_image_data_to_bgra8888" , [](const py::bytes& paletteData, const py::bytes& imageData) {
267+ const auto d = convertP8ImageDataToBGRA8888 ({static_cast <const std::byte*>(paletteData.data ()), paletteData.size ()}, {static_cast <const std::byte*>(imageData.data ()), imageData.size ()});
268+ return py::bytes{d.data (), d.size ()};
269+ }, py::arg (" palette_data" ), py::arg (" image_data" ));
270+ }
271+
253272 auto cPPL = py::class_<PPL>(vtfpp, " PPL" );
254273
255274 py::class_<PPL::Image>(cPPL, " Image" )
@@ -366,6 +385,9 @@ inline void register_python(py::module_& m) {
366385 .def (" bake_to_file" , py::overload_cast<const std::string&, const std::string&>(&TTX::bake, py::const_), py::arg (" tth_path" ), py::arg (" ttz_path" ));
367386
368387 vtfpp.attr (" VTF_SIGNATURE" ) = VTF_SIGNATURE;
388+ vtfpp.attr (" XTF_SIGNATURE" ) = XTF_SIGNATURE;
389+ vtfpp.attr (" VTFX_SIGNATURE" ) = VTFX_SIGNATURE;
390+ vtfpp.attr (" VTF3_SIGNATURE" ) = VTF3_SIGNATURE;
369391
370392 py::enum_<CompressionMethod>(vtfpp, " CompressionMethod" , py::is_arithmetic ())
371393 .value (" DEFLATE" , CompressionMethod::DEFLATE)
@@ -378,6 +400,8 @@ inline void register_python(py::module_& m) {
378400 py::enum_<Resource::Type>(cResource, " Type" )
379401 .value (" UNKNOWN" , Resource::TYPE_UNKNOWN)
380402 .value (" THUMBNAIL_DATA" , Resource::TYPE_THUMBNAIL_DATA)
403+ .value (" PALETTE_DATA" , Resource::TYPE_PALETTE_DATA)
404+ .value (" FALLBACK_DATA" , Resource::TYPE_FALLBACK_DATA)
381405 .value (" PARTICLE_SHEET_DATA" , Resource::TYPE_PARTICLE_SHEET_DATA)
382406 .value (" HOTSPOT_DATA" , Resource::TYPE_HOTSPOT_DATA)
383407 .value (" IMAGE_DATA" , Resource::TYPE_IMAGE_DATA)
@@ -433,6 +457,11 @@ inline void register_python(py::module_& m) {
433457 .value (" CLAMP_U" , VTF::FLAG_V2_CLAMP_U)
434458 .export_values ();
435459
460+ py::enum_<VTF::FlagsXBOX>(cVTF, " FlagsXBOX" , py::is_flag ())
461+ .value (" CACHEABLE" , VTF::FLAG_XBOX_CACHEABLE)
462+ .value (" UNFILTERABLE_OK" , VTF::FLAG_XBOX_UNFILTERABLE_OK)
463+ .export_values ();
464+
436465 py::enum_<VTF::FlagsV3>(cVTF, " FlagsV3" , py::is_flag ())
437466 .value (" LOAD_ALL_MIPS" , VTF::FLAG_V3_LOAD_ALL_MIPS)
438467 .value (" VERTEX_TEXTURE" , VTF::FLAG_V3_VERTEX_TEXTURE)
@@ -470,6 +499,7 @@ inline void register_python(py::module_& m) {
470499 py::enum_<VTF::Platform>(cVTF, " Platform" )
471500 .value (" UNKNOWN" , VTF::PLATFORM_UNKNOWN)
472501 .value (" PC" , VTF::PLATFORM_PC)
502+ .value (" XBOX" , VTF::PLATFORM_XBOX)
473503 .value (" X360" , VTF::PLATFORM_X360)
474504 .value (" PS3_ORANGEBOX" , VTF::PLATFORM_PS3_ORANGEBOX)
475505 .value (" PS3_PORTAL2" , VTF::PLATFORM_PS3_PORTAL2)
@@ -495,7 +525,8 @@ inline void register_python(py::module_& m) {
495525 .def_rw (" compression_method" , &VTF::CreationOptions::compressionMethod)
496526 .def_rw (" bumpmap_scale" , &VTF::CreationOptions::bumpMapScale)
497527 .def_rw (" gamma_correction" , &VTF::CreationOptions::gammaCorrection)
498- .def_rw (" invert_green_channel" , &VTF::CreationOptions::invertGreenChannel);
528+ .def_rw (" invert_green_channel" , &VTF::CreationOptions::invertGreenChannel)
529+ .def_rw (" xbox_mip_scale" , &VTF::CreationOptions::xboxMipScale);
499530
500531 cVTF
501532 .def_ro_static (" FLAGS_MASK_V0" , &VTF::FLAGS_MASK_V0)
@@ -557,6 +588,9 @@ inline void register_python(py::module_& m) {
557588 .def_prop_ro (" thumbnail_format" , &VTF::getThumbnailFormat)
558589 .def_prop_ro (" thumbnail_width" , &VTF::getThumbnailWidth)
559590 .def_prop_ro (" thumbnail_height" , &VTF::getThumbnailHeight)
591+ .def_prop_ro (" fallback_width" , &VTF::getFallbackWidth)
592+ .def_prop_ro (" fallback_height" , &VTF::getFallbackHeight)
593+ .def_prop_ro (" fallback_mip_count" , &VTF::getFallbackMipCount)
560594 // Skipping getResources, don't want to do the same hack as in SHT here, it's way more expensive
561595 .def (" get_resource" , &VTF::getResource, py::arg (" type" ), py::rv_policy::reference_internal)
562596 .def (" get_particle_sheet_frame_data_raw" , [](const VTF& self, uint32_t shtSequenceID, uint32_t shtFrame, uint8_t shtBounds = 0 , uint8_t mip = 0 , uint16_t frame = 0 , uint8_t face = 0 , uint16_t slice = 0 ) -> std::tuple<uint16_t , uint16_t , py::bytes> {
@@ -626,13 +660,35 @@ inline void register_python(py::module_& m) {
626660 .def (" set_thumbnail" , [](VTF& self, const py::bytes& imageData, ImageFormat format, uint16_t width, uint16_t height, float quality = ImageConversion::DEFAULT_COMPRESSED_QUALITY) {
627661 return self.setThumbnail ({static_cast <const std::byte*>(imageData.data ()), imageData.size ()}, format, width, height, quality);
628662 }, py::arg (" image_data" ), py::arg (" format" ), py::arg (" width" ), py::arg (" height" ), py::arg (" quality" ) = ImageConversion::DEFAULT_COMPRESSED_QUALITY)
663+ .def (" set_thumbnail_from_file" , py::overload_cast<const std::string&, float >(&VTF::setThumbnail), py::arg (" image_path" ), py::arg (" quality" ) = ImageConversion::DEFAULT_COMPRESSED_QUALITY)
629664 .def (" compute_thumbnail" , &VTF::computeThumbnail, py::arg (" filter" ) = ImageConversion::ResizeFilter::DEFAULT, py::arg (" quality" ) = ImageConversion::DEFAULT_COMPRESSED_QUALITY)
630665 .def (" remove_thumbnail" , &VTF::removeThumbnail)
631666 .def (" save_thumbnail" , [](const VTF& self, ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) {
632667 const auto d = self.saveThumbnailToFile (fileFormat);
633668 return py::bytes{d.data (), d.size ()};
634669 }, py::arg (" file_format" ) = ImageConversion::FileFormat::DEFAULT)
635670 .def (" save_thumbnail_to_file" , py::overload_cast<const std::string&, ImageConversion::FileFormat>(&VTF::saveThumbnailToFile, py::const_), py::arg (" image_path" ), py::arg (" file_format" ) = ImageConversion::FileFormat::DEFAULT)
671+ .def (" has_fallback_data" , &VTF::hasFallbackData)
672+ .def (" get_fallback_data_raw" , [](const VTF& self, uint8_t mip = 0 , uint16_t frame = 0 , uint8_t face = 0 ) {
673+ const auto d = self.getFallbackDataRaw (mip, frame, face);
674+ return py::bytes{d.data (), d.size ()};
675+ }, py::arg (" mip" ) = 0 , py::arg (" frame" ) = 0 , py::arg (" face" ) = 0 )
676+ .def (" get_fallback_data_as" , [](const VTF& self, ImageFormat newFormat, uint8_t mip = 0 , uint16_t frame = 0 , uint8_t face = 0 ) {
677+ const auto d = self.getFallbackDataAs (newFormat, mip, frame, face);
678+ return py::bytes{d.data (), d.size ()};
679+ }, py::arg (" new_format" ), py::arg (" mip" ) = 0 , py::arg (" frame" ) = 0 , py::arg (" face" ) = 0 )
680+ .def (" get_fallback_data_as_rgba8888" , [](const VTF& self, uint8_t mip = 0 , uint16_t frame = 0 , uint8_t face = 0 ) {
681+ const auto d = self.getFallbackDataAsRGBA8888 (mip, frame, face);
682+ return py::bytes{d.data (), d.size ()};
683+ }, py::arg (" mip" ) = 0 , py::arg (" frame" ) = 0 , py::arg (" face" ) = 0 )
684+ .def (" compute_fallback" , &VTF::computeFallback, py::arg (" filter" ) = ImageConversion::ResizeFilter::DEFAULT)
685+ .def (" remove_fallback" , &VTF::removeFallback)
686+ .def (" save_fallback" , [](const VTF& self, uint8_t mip = 0 , uint16_t frame = 0 , uint8_t face = 0 , ImageConversion::FileFormat fileFormat = ImageConversion::FileFormat::DEFAULT) {
687+ const auto d = self.saveFallbackToFile (mip, frame, face, fileFormat);
688+ return py::bytes{d.data (), d.size ()};
689+ }, py::arg (" mip" ) = 0 , py::arg (" frame" ) = 0 , py::arg (" face" ) = 0 , py::arg (" file_format" ) = ImageConversion::FileFormat::DEFAULT)
690+ .def (" save_fallback_to_file" , py::overload_cast<const std::string&, uint8_t , uint16_t , uint8_t , ImageConversion::FileFormat>(&VTF::saveFallbackToFile, py::const_), py::arg (" image_path" ), py::arg (" mip" ) = 0 , py::arg (" frame" ) = 0 , py::arg (" face" ) = 0 , py::arg (" file_format" ) = ImageConversion::FileFormat::DEFAULT)
691+ .def_prop_rw (" xbox_mip_scale" , &VTF::getXBOXMipScale, &VTF::setXBOXMipScale)
636692 .def (" bake" , [](const VTF& self) {
637693 const auto d = self.bake ();
638694 return py::bytes{d.data (), d.size ()};
0 commit comments