diff --git a/doc/python/pages/changelog.rst b/doc/python/pages/changelog.rst index a1a691a..92e2968 100644 --- a/doc/python/pages/changelog.rst +++ b/doc/python/pages/changelog.rst @@ -111,6 +111,8 @@ Changelog :ref:`platform.glfw.Application.dpi_scaling` - Exposed :ref:`platform.glfw.Application.swap_interval` and :ref:`platform.glfw.Application.main_loop_iteration` +- Exposed :ref:`trade.AbstractImporter.features` and + :ref:`trade.AbstractImporter.flags` and corresponding enums - Exposed a basic interface of :ref:`trade.AbstractImageConverter` and :ref:`trade.AbstractSceneConverter` - Exposed the whole interface of :ref:`trade.MeshData` including typed access diff --git a/src/python/magnum/test/test_trade.py b/src/python/magnum/test/test_trade.py index 57edafa..0285cfd 100644 --- a/src/python/magnum/test/test_trade.py +++ b/src/python/magnum/test/test_trade.py @@ -1018,6 +1018,11 @@ class Importer(unittest.TestCase): importer = manager.load_and_instantiate('StbImageImporter') self.assertEqual(importer.plugin, 'StbImageImporter') + self.assertEqual(importer.features, trade.ImporterFeatures.OPEN_DATA) + self.assertEqual(importer.flags, trade.ImporterFlags.NONE) + + importer.flags = trade.ImporterFlags.VERBOSE + self.assertEqual(importer.flags, trade.ImporterFlags.VERBOSE) def test_set_plugin_directory(self): manager = trade.ImporterManager() @@ -1421,6 +1426,14 @@ class Importer(unittest.TestCase): importer.image2d('A broken image') class ImageConverter(unittest.TestCase): + def test(self): + converter = trade.ImageConverterManager().load_and_instantiate('StbImageConverter') + self.assertEqual(converter.features, trade.ImageConverterFeatures.CONVERT2D_TO_FILE|trade.ImageConverterFeatures.CONVERT2D_TO_DATA) + self.assertEqual(converter.flags, trade.ImageConverterFlags.NONE) + + converter.flags = trade.ImageConverterFlags.VERBOSE + self.assertEqual(converter.flags, trade.ImageConverterFlags.VERBOSE) + def test_image2d(self): importer = trade.ImporterManager().load_and_instantiate('StbImageImporter') importer.open_file(os.path.join(os.path.dirname(__file__), 'rgb.png')) @@ -1444,6 +1457,14 @@ class ImageConverter(unittest.TestCase): converter.convert_to_file(image, os.path.join(tmp, "image.hdr")) class SceneConverter(unittest.TestCase): + def test(self): + converter = trade.SceneConverterManager().load_and_instantiate('StanfordSceneConverter') + self.assertEqual(converter.features, trade.SceneConverterFeatures.CONVERT_MESH_TO_FILE|trade.SceneConverterFeatures.CONVERT_MESH_TO_DATA) + self.assertEqual(converter.flags, trade.SceneConverterFlags.NONE) + + converter.flags = trade.SceneConverterFlags.VERBOSE + self.assertEqual(converter.flags, trade.SceneConverterFlags.VERBOSE) + def test_mesh(self): importer = trade.ImporterManager().load_and_instantiate('GltfImporter') importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf')) diff --git a/src/python/magnum/trade.cpp b/src/python/magnum/trade.cpp index c99d7dc..1cfebc5 100644 --- a/src/python/magnum/trade.cpp +++ b/src/python/magnum/trade.cpp @@ -1425,10 +1425,31 @@ void trade(py::module_& m) { void*. Leaving the name as AbstractImporter (instead of Importer) to avoid needless name differences and because in the future there *might* be pure Python importers (not now tho). */ + py::enum_ importerFeatures{m, "ImporterFeatures", "Features supported by an image converter"}; + importerFeatures + .value("OPEN_DATA", Trade::ImporterFeature::OpenData) + .value("OPEN_STATE", Trade::ImporterFeature::OpenState) + .value("FILE_CALLBACK", Trade::ImporterFeature::FileCallback) + .value("NONE", Trade::ImporterFeature{}); + corrade::enumOperators(importerFeatures); + + py::enum_ importerFlags{m, "ImporterFlags", "Importer flags"}; + importerFlags + .value("VERBOSE", Trade::ImporterFlag::Verbose) + .value("NONE", Trade::ImporterFlag{}); + corrade::enumOperators(importerFlags); + py::class_, PluginManager::AbstractPlugin> abstractImporter{m, "AbstractImporter", "Interface for importer plugins"}; corrade::plugin(abstractImporter); abstractImporter - /** @todo features */ + .def_property_readonly("features", [](Trade::AbstractImporter& self) { + return Trade::ImporterFeature(Containers::enumCastUnderlyingType(self.features())); + }, "Features supported by this importer") + .def_property("flags", [](Trade::AbstractImporter& self) { + return Trade::ImporterFlag(Containers::enumCastUnderlyingType(self.flags())); + }, [](Trade::AbstractImporter& self, Trade::ImporterFlag flags) { + self.setFlags(flags); + }, "Importer flags") .def_property_readonly("is_opened", &Trade::AbstractImporter::isOpened, "Whether any file is opened") .def("open_data", [](Trade::AbstractImporter& self, Containers::ArrayView data) { /** @todo log redirection -- but we'd need assertions to not be @@ -1525,9 +1546,46 @@ void trade(py::module_& m) { corrade::manager(importerManager); /* Image converter */ + py::enum_ imageConverterFeatures{m, "ImageConverterFeatures", "Features supported by an image converter"}; + imageConverterFeatures + .value("CONVERT1D", Trade::ImageConverterFeature::Convert1D) + .value("CONVERT2D", Trade::ImageConverterFeature::Convert2D) + .value("CONVERT3D", Trade::ImageConverterFeature::Convert3D) + .value("CONVERT_COMPRESSED1D", Trade::ImageConverterFeature::ConvertCompressed1D) + .value("CONVERT_COMPRESSED2D", Trade::ImageConverterFeature::ConvertCompressed2D) + .value("CONVERT_COMPRESSED3D", Trade::ImageConverterFeature::ConvertCompressed3D) + .value("CONVERT1D_TO_FILE", Trade::ImageConverterFeature::Convert1DToFile) + .value("CONVERT2D_TO_FILE", Trade::ImageConverterFeature::Convert2DToFile) + .value("CONVERT3D_TO_FILE", Trade::ImageConverterFeature::Convert3DToFile) + .value("CONVERT_COMPRESSED1D_TO_FILE", Trade::ImageConverterFeature::ConvertCompressed1DToFile) + .value("CONVERT_COMPRESSED2D_TO_FILE", Trade::ImageConverterFeature::ConvertCompressed2DToFile) + .value("CONVERT_COMPRESSED3D_TO_FILE", Trade::ImageConverterFeature::ConvertCompressed3DToFile) + .value("CONVERT1D_TO_DATA", Trade::ImageConverterFeature::Convert1DToData) + .value("CONVERT2D_TO_DATA", Trade::ImageConverterFeature::Convert2DToData) + .value("CONVERT3D_TO_DATA", Trade::ImageConverterFeature::Convert3DToData) + .value("CONVERT_COMPRESSED1D_TO_DATA", Trade::ImageConverterFeature::ConvertCompressed1DToData) + .value("CONVERT_COMPRESSED2D_TO_DATA", Trade::ImageConverterFeature::ConvertCompressed2DToData) + .value("CONVERT_COMPRESSED3D_TO_DATA", Trade::ImageConverterFeature::ConvertCompressed3DToData) + .value("LEVELS", Trade::ImageConverterFeature::Levels) + .value("NONE", Trade::ImageConverterFeature{}); + corrade::enumOperators(imageConverterFeatures); + + py::enum_ imageConverterFlags{m, "ImageConverterFlags", "Image converter flags"}; + imageConverterFlags + .value("VERBOSE", Trade::ImageConverterFlag::Verbose) + .value("NONE", Trade::ImageConverterFlag{}); + corrade::enumOperators(imageConverterFlags); + py::class_, PluginManager::AbstractPlugin> abstractImageConverter{m, "AbstractImageConverter", "Interface for image converter plugins"}; abstractImageConverter - /** @todo features */ + .def_property_readonly("features", [](Trade::AbstractImageConverter& self) { + return Trade::ImageConverterFeature(Containers::enumCastUnderlyingType(self.features())); + }, "Features supported by this converter") + .def_property("flags", [](Trade::AbstractImageConverter& self) { + return Trade::ImageConverterFlag(Containers::enumCastUnderlyingType(self.flags())); + }, [](Trade::AbstractImageConverter& self, Trade::ImageConverterFlag flags) { + self.setFlags(flags); + }, "Converter flags") .def("convert_to_file", checkImageConverterResult, "Convert a 1D image to a file", py::arg("image"), py::arg("filename")) .def("convert_to_file", checkImageConverterResult, "Convert a 2D image to a file", py::arg("image"), py::arg("filename")) .def("convert_to_file", checkImageConverterResult, "Convert a 3D image to a file", py::arg("image"), py::arg("filename")); @@ -1537,9 +1595,51 @@ void trade(py::module_& m) { corrade::manager(imageConverterManager); /* Scene converter */ + py::enum_ sceneConverterFeatures{m, "SceneConverterFeatures", "Features supported by a scene converter"}; + sceneConverterFeatures + .value("CONVERT_MESH", Trade::SceneConverterFeature::ConvertMesh) + .value("CONVERT_MESH_IN_PLACE", Trade::SceneConverterFeature::ConvertMeshInPlace) + .value("CONVERT_MESH_TO_FILE", Trade::SceneConverterFeature::ConvertMeshToFile) + .value("CONVERT_MESH_TO_DATA", Trade::SceneConverterFeature::ConvertMeshToData) + .value("CONVERT_MULTIPLE", Trade::SceneConverterFeature::ConvertMultiple) + .value("CONVERT_MULTIPLE_TO_FILE", Trade::SceneConverterFeature::ConvertMultipleToFile) + .value("CONVERT_MULTIPLE_TO_DATA", Trade::SceneConverterFeature::ConvertMultipleToData) + .value("ADD_SCENES", Trade::SceneConverterFeature::AddScenes) + .value("ADD_ANIMATIONS", Trade::SceneConverterFeature::AddAnimations) + .value("ADD_LIGHTS", Trade::SceneConverterFeature::AddLights) + .value("ADD_CAMERAS", Trade::SceneConverterFeature::AddCameras) + .value("ADD_SKINS2D", Trade::SceneConverterFeature::AddSkins2D) + .value("ADD_SKINS3D", Trade::SceneConverterFeature::AddSkins3D) + .value("ADD_MESHES", Trade::SceneConverterFeature::AddMeshes) + .value("ADD_MATERIALS", Trade::SceneConverterFeature::AddMaterials) + .value("ADD_TEXTURES", Trade::SceneConverterFeature::AddTextures) + .value("ADD_IMAGES1D", Trade::SceneConverterFeature::AddImages1D) + .value("ADD_IMAGES2D", Trade::SceneConverterFeature::AddImages2D) + .value("ADD_IMAGES3D", Trade::SceneConverterFeature::AddImages3D) + .value("ADD_COMPRESSED_IMAGES1D", Trade::SceneConverterFeature::AddCompressedImages1D) + .value("ADD_COMPRESSED_IMAGES2D", Trade::SceneConverterFeature::AddCompressedImages2D) + .value("ADD_COMPRESSED_IMAGES3D", Trade::SceneConverterFeature::AddCompressedImages3D) + .value("MESH_LEVELS", Trade::SceneConverterFeature::MeshLevels) + .value("IMAGE_LEVELS", Trade::SceneConverterFeature::ImageLevels) + .value("NONE", Trade::SceneConverterFeature{}); + corrade::enumOperators(sceneConverterFeatures); + + py::enum_ sceneConverterFlags{m, "SceneConverterFlags", "Scene converter flags"}; + sceneConverterFlags + .value("VERBOSE", Trade::SceneConverterFlag::Verbose) + .value("NONE", Trade::SceneConverterFlag{}); + corrade::enumOperators(sceneConverterFlags); + py::class_, PluginManager::AbstractPlugin> abstractSceneConverter{m, "AbstractSceneConverter", "Interface for scene converter plugins"}; abstractSceneConverter - /** @todo features */ + .def_property_readonly("features", [](Trade::AbstractSceneConverter& self) { + return Trade::SceneConverterFeature(Containers::enumCastUnderlyingType(self.features())); + }, "Features supported by this converter") + .def_property("flags", [](Trade::AbstractSceneConverter& self) { + return Trade::SceneConverterFlag(Containers::enumCastUnderlyingType(self.flags())); + }, [](Trade::AbstractSceneConverter& self, Trade::SceneConverterFlag flags) { + self.setFlags(flags); + }, "Converter flags") /** @todo drop std::string in favor of our own string caster */ .def("convert_to_file", [](Trade::AbstractSceneConverter& self, const Trade::MeshData& mesh, const std::string& filename) { /** @todo log redirection -- but we'd need assertions to not be