diff --git a/doc/python/magnum.trade.rst b/doc/python/magnum.trade.rst index f7d0110..67a3457 100644 --- a/doc/python/magnum.trade.rst +++ b/doc/python/magnum.trade.rst @@ -81,6 +81,13 @@ .. py:property:: magnum.trade.ImageData3D.format :raise AttributeError: If :ref:`is_compressed` is :py:`True` +.. py:property:: magnum.trade.ImageData1D.compressed_format + :raise AttributeError: If :ref:`is_compressed` is :py:`False` +.. py:property:: magnum.trade.ImageData2D.compressed_format + :raise AttributeError: If :ref:`is_compressed` is :py:`False` +.. py:property:: magnum.trade.ImageData3D.compressed_format + :raise AttributeError: If :ref:`is_compressed` is :py:`False` + .. py:property:: magnum.trade.ImageData1D.pixel_size :raise AttributeError: If :ref:`is_compressed` is :py:`True` .. py:property:: magnum.trade.ImageData2D.pixel_size diff --git a/doc/python/pages/changelog.rst b/doc/python/pages/changelog.rst index 631f3c0..3888bb0 100644 --- a/doc/python/pages/changelog.rst +++ b/doc/python/pages/changelog.rst @@ -55,6 +55,7 @@ Changelog :ref:`Matrix3.projection()` - Exposed remaining vector/scalar, exponential and other functions in the :ref:`math ` library +- Exposed the :ref:`CompressedPixelFormat` enum - Exposed :ref:`Color3.from_xyz()`, :ref:`Color3.from_linear_rgb_int()`, :ref:`Color3.to_xyz()`, :ref:`Color3.to_linear_rgb_int()` and equivalent APIs on :ref:`Color4` diff --git a/src/python/magnum/__init__.py b/src/python/magnum/__init__.py index 1ecf70d..26ff293 100644 --- a/src/python/magnum/__init__.py +++ b/src/python/magnum/__init__.py @@ -78,6 +78,7 @@ __all__ = [ 'MeshPrimitive', 'MeshIndexType', 'PixelFormat', 'PixelStorage', + 'CompressedPixelFormat', 'Image1D', 'Image2D', 'Image3D', 'ImageView1D', 'ImageView2D', 'ImageView3D', 'MutableImageView1D', 'MutableImageView2D', 'MutableImageView3D', diff --git a/src/python/magnum/magnum.cpp b/src/python/magnum/magnum.cpp index 64d63ff..0f940f9 100644 --- a/src/python/magnum/magnum.cpp +++ b/src/python/magnum/magnum.cpp @@ -304,6 +304,114 @@ void magnum(py::module_& m) { .value("DEPTH24_UNORM_STENCIL8UI", PixelFormat::Depth24UnormStencil8UI) .value("DEPTH32F_STENCIL8UI", PixelFormat::Depth32FStencil8UI); + py::enum_{m, "CompressedPixelFormat", "Format of compressed pixel data"} + .value("BC1_RGB_UNORM", CompressedPixelFormat::Bc1RGBUnorm) + .value("BC1_RGB_SRGB", CompressedPixelFormat::Bc1RGBSrgb) + .value("BC1_RGBA_UNORM", CompressedPixelFormat::Bc1RGBAUnorm) + .value("BC1_RGBA_SRGB", CompressedPixelFormat::Bc1RGBASrgb) + .value("BC2_RGBA_UNORM", CompressedPixelFormat::Bc2RGBAUnorm) + .value("BC2_RGBA_SRGB", CompressedPixelFormat::Bc2RGBASrgb) + .value("BC3_RGBA_UNORM", CompressedPixelFormat::Bc3RGBAUnorm) + .value("BC3_RGBA_SRGB", CompressedPixelFormat::Bc3RGBASrgb) + .value("BC4_R_UNORM", CompressedPixelFormat::Bc4RUnorm) + .value("BC4_R_SNORM", CompressedPixelFormat::Bc4RSnorm) + .value("BC5_RG_UNORM", CompressedPixelFormat::Bc5RGUnorm) + .value("BC5_RG_SNORM", CompressedPixelFormat::Bc5RGSnorm) + .value("BC6H_RGB_UFLOAT", CompressedPixelFormat::Bc6hRGBUfloat) + .value("BC6H_RGB_SFLOAT", CompressedPixelFormat::Bc6hRGBSfloat) + .value("BC7_RGBA_UNORM", CompressedPixelFormat::Bc7RGBAUnorm) + .value("BC7_RGBA_SRGB", CompressedPixelFormat::Bc7RGBASrgb) + .value("EAC_R11_UNORM", CompressedPixelFormat::EacR11Unorm) + .value("EAC_R11_SNORM", CompressedPixelFormat::EacR11Snorm) + .value("EAC_RG11_UNORM", CompressedPixelFormat::EacRG11Unorm) + .value("EAC_RG11_SNORM", CompressedPixelFormat::EacRG11Snorm) + .value("ETC2_RGB8_UNORM", CompressedPixelFormat::Etc2RGB8Unorm) + .value("ETC2_RGB8_SRGB", CompressedPixelFormat::Etc2RGB8Srgb) + .value("ETC2_RGB8A1_UNORM", CompressedPixelFormat::Etc2RGB8A1Unorm) + .value("ETC2_RGB8A1_SRGB", CompressedPixelFormat::Etc2RGB8A1Srgb) + .value("ETC2_RGBA8_UNORM", CompressedPixelFormat::Etc2RGBA8Unorm) + .value("ETC2_RGBA8_SRGB", CompressedPixelFormat::Etc2RGBA8Srgb) + .value("ASTC_4X4_RGBA_UNORM", CompressedPixelFormat::Astc4x4RGBAUnorm) + .value("ASTC_4X4_RGBA_SRGB", CompressedPixelFormat::Astc4x4RGBASrgb) + .value("ASTC_4X4_RGBAF", CompressedPixelFormat::Astc4x4RGBAF) + .value("ASTC_5X4_RGBA_UNORM", CompressedPixelFormat::Astc5x4RGBAUnorm) + .value("ASTC_5X4_RGBA_SRGB", CompressedPixelFormat::Astc5x4RGBASrgb) + .value("ASTC_5X4_RGBAF", CompressedPixelFormat::Astc5x4RGBAF) + .value("ASTC_5X5_RGBA_UNORM", CompressedPixelFormat::Astc5x5RGBAUnorm) + .value("ASTC_5X5_RGBA_SRGB", CompressedPixelFormat::Astc5x5RGBASrgb) + .value("ASTC_5X5_RGBAF", CompressedPixelFormat::Astc5x5RGBAF) + .value("ASTC_6X5_RGBA_UNORM", CompressedPixelFormat::Astc6x5RGBAUnorm) + .value("ASTC_6X5_RGBA_SRGB", CompressedPixelFormat::Astc6x5RGBASrgb) + .value("ASTC_6X5_RGBAF", CompressedPixelFormat::Astc6x5RGBAF) + .value("ASTC_6X6_RGBA_UNORM", CompressedPixelFormat::Astc6x6RGBAUnorm) + .value("ASTC_6X6_RGBA_SRGB", CompressedPixelFormat::Astc6x6RGBASrgb) + .value("ASTC_6X6_RGBAF", CompressedPixelFormat::Astc6x6RGBAF) + .value("ASTC_8X5_RGBA_UNORM", CompressedPixelFormat::Astc8x5RGBAUnorm) + .value("ASTC_8X5_RGBA_SRGB", CompressedPixelFormat::Astc8x5RGBASrgb) + .value("ASTC_8X5_RGBAF", CompressedPixelFormat::Astc8x5RGBAF) + .value("ASTC_8X6_RGBA_UNORM", CompressedPixelFormat::Astc8x6RGBAUnorm) + .value("ASTC_8X6_RGBA_SRGB", CompressedPixelFormat::Astc8x6RGBASrgb) + .value("ASTC_8X6_RGBAF", CompressedPixelFormat::Astc8x6RGBAF) + .value("ASTC_8X8_RGBA_UNORM", CompressedPixelFormat::Astc8x8RGBAUnorm) + .value("ASTC_8X8_RGBA_SRGB", CompressedPixelFormat::Astc8x8RGBASrgb) + .value("ASTC_8X8_RGBAF", CompressedPixelFormat::Astc8x8RGBAF) + .value("ASTC_10X5_RGBA_UNORM", CompressedPixelFormat::Astc10x5RGBAUnorm) + .value("ASTC_10X5_RGBA_SRGB", CompressedPixelFormat::Astc10x5RGBASrgb) + .value("ASTC_10X5_RGBAF", CompressedPixelFormat::Astc10x5RGBAF) + .value("ASTC_10X6_RGBA_UNORM", CompressedPixelFormat::Astc10x6RGBAUnorm) + .value("ASTC_10X6_RGBA_SRGB", CompressedPixelFormat::Astc10x6RGBASrgb) + .value("ASTC_10X6_RGBAF", CompressedPixelFormat::Astc10x6RGBAF) + .value("ASTC_10X8_RGBA_UNORM", CompressedPixelFormat::Astc10x8RGBAUnorm) + .value("ASTC_10X8_RGBA_SRGB", CompressedPixelFormat::Astc10x8RGBASrgb) + .value("ASTC_10X8_RGBAF", CompressedPixelFormat::Astc10x8RGBAF) + .value("ASTC_10X10_RGBA_UNORM", CompressedPixelFormat::Astc10x10RGBAUnorm) + .value("ASTC_10X10_RGBA_SRGB", CompressedPixelFormat::Astc10x10RGBASrgb) + .value("ASTC_10X10_RGBAF", CompressedPixelFormat::Astc10x10RGBAF) + .value("ASTC_12X10_RGBA_UNORM", CompressedPixelFormat::Astc12x10RGBAUnorm) + .value("ASTC_12X10_RGBA_SRGB", CompressedPixelFormat::Astc12x10RGBASrgb) + .value("ASTC_12X10_RGBAF", CompressedPixelFormat::Astc12x10RGBAF) + .value("ASTC_12X12_RGBA_UNORM", CompressedPixelFormat::Astc12x12RGBAUnorm) + .value("ASTC_12X12_RGBA_SRGB", CompressedPixelFormat::Astc12x12RGBASrgb) + .value("ASTC_12X12_RGBAF", CompressedPixelFormat::Astc12x12RGBAF) + .value("ASTC_3X3X3_RGBA_UNORM", CompressedPixelFormat::Astc3x3x3RGBAUnorm) + .value("ASTC_3X3X3_RGBA_SRGB", CompressedPixelFormat::Astc3x3x3RGBASrgb) + .value("ASTC_3X3X3_RGBAF", CompressedPixelFormat::Astc3x3x3RGBAF) + .value("ASTC_4X3X3_RGBA_UNORM", CompressedPixelFormat::Astc4x3x3RGBAUnorm) + .value("ASTC_4X3X3_RGBA_SRGB", CompressedPixelFormat::Astc4x3x3RGBASrgb) + .value("ASTC_4X3X3_RGBAF", CompressedPixelFormat::Astc4x3x3RGBAF) + .value("ASTC_4X4X3_RGBA_UNORM", CompressedPixelFormat::Astc4x4x3RGBAUnorm) + .value("ASTC_4X4X3_RGBA_SRGB", CompressedPixelFormat::Astc4x4x3RGBASrgb) + .value("ASTC_4X4X3_RGBAF", CompressedPixelFormat::Astc4x4x3RGBAF) + .value("ASTC_4X4X4_RGBA_UNORM", CompressedPixelFormat::Astc4x4x4RGBAUnorm) + .value("ASTC_4X4X4_RGBA_SRGB", CompressedPixelFormat::Astc4x4x4RGBASrgb) + .value("ASTC_4X4X4_RGBAF", CompressedPixelFormat::Astc4x4x4RGBAF) + .value("ASTC_5X4X4_RGBA_UNORM", CompressedPixelFormat::Astc5x4x4RGBAUnorm) + .value("ASTC_5X4X4_RGBA_SRGB", CompressedPixelFormat::Astc5x4x4RGBASrgb) + .value("ASTC_5X4X4_RGBAF", CompressedPixelFormat::Astc5x4x4RGBAF) + .value("ASTC_5X5X4_RGBA_UNORM", CompressedPixelFormat::Astc5x5x4RGBAUnorm) + .value("ASTC_5X5X4_RGBA_SRGB", CompressedPixelFormat::Astc5x5x4RGBASrgb) + .value("ASTC_5X5X4_RGBAF", CompressedPixelFormat::Astc5x5x4RGBAF) + .value("ASTC_5X5X5_RGBA_UNORM", CompressedPixelFormat::Astc5x5x5RGBAUnorm) + .value("ASTC_5X5X5_RGBA_SRGB", CompressedPixelFormat::Astc5x5x5RGBASrgb) + .value("ASTC_5X5X5_RGBAF", CompressedPixelFormat::Astc5x5x5RGBAF) + .value("ASTC_6X5X5_RGBA_UNORM", CompressedPixelFormat::Astc6x5x5RGBAUnorm) + .value("ASTC_6X5X5_RGBA_SRGB", CompressedPixelFormat::Astc6x5x5RGBASrgb) + .value("ASTC_6X5X5_RGBAF", CompressedPixelFormat::Astc6x5x5RGBAF) + .value("ASTC_6X6X5_RGBA_UNORM", CompressedPixelFormat::Astc6x6x5RGBAUnorm) + .value("ASTC_6X6X5_RGBA_SRGB", CompressedPixelFormat::Astc6x6x5RGBASrgb) + .value("ASTC_6X6X5_RGBAF", CompressedPixelFormat::Astc6x6x5RGBAF) + .value("ASTC_6X6X6_RGBA_UNORM", CompressedPixelFormat::Astc6x6x6RGBAUnorm) + .value("ASTC_6X6X6_RGBA_SRGB", CompressedPixelFormat::Astc6x6x6RGBASrgb) + .value("ASTC_6X6X6_RGBAF", CompressedPixelFormat::Astc6x6x6RGBAF) + .value("PVRTC_RGB_2PP_UNORM", CompressedPixelFormat::PvrtcRGB2bppUnorm) + .value("PVRTC_RGB_2PP_SRGB", CompressedPixelFormat::PvrtcRGB2bppSrgb) + .value("PVRTC_RGBA_2PP_UNORM", CompressedPixelFormat::PvrtcRGBA2bppUnorm) + .value("PVRTC_RGBA_2PP_SRGB", CompressedPixelFormat::PvrtcRGBA2bppSrgb) + .value("PVRTC_RGB_4PP_UNORM", CompressedPixelFormat::PvrtcRGB4bppUnorm) + .value("PVRTC_RGB_4PP_SRGB", CompressedPixelFormat::PvrtcRGB4bppSrgb) + .value("PVRTC_RGBA_4PP_UNORM", CompressedPixelFormat::PvrtcRGBA4bppUnorm) + .value("PVRTC_RGBA_4PP_SRGB", CompressedPixelFormat::PvrtcRGBA4bppSrgb); + py::class_{m, "PixelStorage", "Pixel storage parameters"} .def(py::init(), "Default constructor") diff --git a/src/python/magnum/test/test_trade.py b/src/python/magnum/test/test_trade.py index 13717b7..a8e4803 100644 --- a/src/python/magnum/test/test_trade.py +++ b/src/python/magnum/test/test_trade.py @@ -48,6 +48,9 @@ class ImageData(unittest.TestCase): self.assertEqual(image.size, Vector2i(3, 2)) self.assertIsNone(image.owner) + with self.assertRaisesRegex(AttributeError, "image is not compressed"): + image.compressed_format + def test_compressed(self): # The only way to get an image instance is through a manager importer = trade.ImporterManager().load_and_instantiate('DdsImporter') @@ -55,10 +58,9 @@ class ImageData(unittest.TestCase): image = importer.image2d(0) self.assertEqual(len(image.data), 8) self.assertTrue(image.is_compressed) - # TODO: compressed properties + self.assertEqual(image.compressed_format, CompressedPixelFormat.BC1_RGBA_UNORM) + # TODO: remaining compressed properties - # No compressed-image-related APIs exposed ATM, so just verifying the - # uncompressed ones fail properly with self.assertRaisesRegex(AttributeError, "image is compressed"): image.storage with self.assertRaisesRegex(AttributeError, "image is compressed"): diff --git a/src/python/magnum/trade.cpp b/src/python/magnum/trade.cpp index b36765a..5230bc0 100644 --- a/src/python/magnum/trade.cpp +++ b/src/python/magnum/trade.cpp @@ -246,6 +246,14 @@ template void imageData(py::class_& self) { + if(!self.isCompressed()) { + PyErr_SetString(PyExc_AttributeError, "image is not compressed"); + throw py::error_already_set{}; + } + + return self.compressedFormat(); + }, "Format of compressed pixel data") .def_property_readonly("pixel_size", [](Trade::ImageData& self) { if(self.isCompressed()) { PyErr_SetString(PyExc_AttributeError, "image is compressed");