Browse Source

python: expose mesh-to-mesh and in-place mesh conversion.

Needs to fetch MeshOptimizer on the CIs for testing this as there's no
other plugin with these features right now.
next
Vladimír Vondruš 3 years ago
parent
commit
cdfd79571f
  1. 8
      doc/python/magnum.trade.rst
  2. 1
      package/ci/appveyor-desktop-gles.bat
  3. 4
      package/ci/appveyor-desktop.bat
  4. 6
      package/ci/appveyor.yml
  5. 28
      package/ci/circleci.yml
  6. 1
      package/ci/unix-desktop-gles.sh
  7. 1
      package/ci/unix-desktop.sh
  8. 58
      src/python/magnum/test/test_trade.py
  9. 18
      src/python/magnum/trade.cpp

8
doc/python/magnum.trade.rst

@ -500,8 +500,14 @@
raising an exception. See particular function documentation for detailed raising an exception. See particular function documentation for detailed
behavior. behavior.
.. py:function:: magnum.trade.AbstractSceneConverter.convert
:raise RuntimeError: If conversion fails
.. py:function:: magnum.trade.AbstractSceneConverter.convert_in_place
:raise RuntimeError: If conversion fails
.. py:function:: magnum.trade.AbstractSceneConverter.convert_to_file .. py:function:: magnum.trade.AbstractSceneConverter.convert_to_file
:raise RuntimeError: If scene conversion fails :raise RuntimeError: If conversion fails
For compatibility with :ref:`os.path`, on Windows this function converts For compatibility with :ref:`os.path`, on Windows this function converts
all backslashes in :p:`filename` to forward slashes before passing it to all backslashes in :p:`filename` to forward slashes before passing it to

1
package/ci/appveyor-desktop-gles.bat

@ -78,6 +78,7 @@ cmake .. ^
-DMAGNUM_BUILD_STATIC=%BUILD_STATIC% ^ -DMAGNUM_BUILD_STATIC=%BUILD_STATIC% ^
-DMAGNUM_WITH_DDSIMPORTER=ON ^ -DMAGNUM_WITH_DDSIMPORTER=ON ^
-DMAGNUM_WITH_GLTFIMPORTER=ON ^ -DMAGNUM_WITH_GLTFIMPORTER=ON ^
-DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON ^
-DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^
-DMAGNUM_WITH_STBIMAGECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGECONVERTER=ON ^
-DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^

4
package/ci/appveyor-desktop.bat

@ -12,6 +12,9 @@ rem currently disabled -- https://github.com/catchorg/Catch2/issues/1113
if "%COMPILER%" == "msvc-clang" if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2022" set COMPILER_EXTRA=-DCMAKE_CXX_COMPILER="C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/bin/clang-cl.exe" -DCMAKE_LINKER="C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/bin/lld-link.exe" -DCMAKE_CXX_FLAGS="-m64 /EHsc" if "%COMPILER%" == "msvc-clang" if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2022" set COMPILER_EXTRA=-DCMAKE_CXX_COMPILER="C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/bin/clang-cl.exe" -DCMAKE_LINKER="C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/bin/lld-link.exe" -DCMAKE_CXX_FLAGS="-m64 /EHsc"
if "%COMPILER%" == "msvc-clang" if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2019" set COMPILER_EXTRA=-DCMAKE_CXX_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/Llvm/bin/clang-cl.exe" -DCMAKE_LINKER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/Llvm/bin/lld-link.exe" -DCMAKE_CXX_FLAGS="-m64 /EHsc" if "%COMPILER%" == "msvc-clang" if "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2019" set COMPILER_EXTRA=-DCMAKE_CXX_COMPILER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/Llvm/bin/clang-cl.exe" -DCMAKE_LINKER="C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/Llvm/bin/lld-link.exe" -DCMAKE_CXX_FLAGS="-m64 /EHsc"
set EXCEPT_MSVC2017=ON
IF "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2017" set EXCEPT_MSVC2017=OFF
rem Build pybind11. Downloaded in the appveyor.yml script. rem Build pybind11. Downloaded in the appveyor.yml script.
cd pybind11-%PYBIND% || exit /b cd pybind11-%PYBIND% || exit /b
mkdir -p build && cd build || exit /b mkdir -p build && cd build || exit /b
@ -85,6 +88,7 @@ cmake .. ^
-DMAGNUM_BUILD_STATIC=%BUILD_STATIC% ^ -DMAGNUM_BUILD_STATIC=%BUILD_STATIC% ^
-DMAGNUM_WITH_DDSIMPORTER=ON ^ -DMAGNUM_WITH_DDSIMPORTER=ON ^
-DMAGNUM_WITH_GLTFIMPORTER=ON ^ -DMAGNUM_WITH_GLTFIMPORTER=ON ^
-DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=%EXCEPT_MSVC2017% ^
-DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^
-DMAGNUM_WITH_STBIMAGECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGECONVERTER=ON ^
-DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^

6
package/ci/appveyor.yml

@ -123,6 +123,12 @@ install:
- IF "%TARGET%" == "desktop" 7z x glfw-3.2.1.bin.WIN64.zip && ren glfw-3.2.1.bin.WIN64 glfw && mkdir deps && mkdir deps\lib && mkdir deps\bin && mkdir deps\include && xcopy /e glfw\include\* deps\include\ - IF "%TARGET%" == "desktop" 7z x glfw-3.2.1.bin.WIN64.zip && ren glfw-3.2.1.bin.WIN64 glfw && mkdir deps && mkdir deps\lib && mkdir deps\bin && mkdir deps\include && xcopy /e glfw\include\* deps\include\
- IF "%TARGET%" == "desktop" IF "%COMPILER:~0,4%" == "msvc" copy glfw\lib-vc2015\glfw3.dll deps\bin\ && copy glfw\lib-vc2015\glfw3dll.lib deps\lib\glfw3.lib - IF "%TARGET%" == "desktop" IF "%COMPILER:~0,4%" == "msvc" copy glfw\lib-vc2015\glfw3.dll deps\bin\ && copy glfw\lib-vc2015\glfw3dll.lib deps\lib\glfw3.lib
# meshoptimizer for MSVC 2022, 2019 and clang-cl; MinGW. MSVC 2017 doesn't work
# with the 2019 build unfortunately, and can't build it because of
# https://github.com/actions/runner-images/issues/3294
- IF "%COMPILER:~0,4%" == "msvc" appveyor DownloadFile https://ci.magnum.graphics/meshoptimizer-0.18-windows-2019-debug.zip && 7z x meshoptimizer-0.18-windows-2019-debug.zip -o%APPVEYOR_BUILD_FOLDER%\deps
- IF "%COMPILER%" == "mingw" appveyor DownloadFile https://ci.magnum.graphics/meshoptimizer-0.18-windows-mingw.zip && 7z x meshoptimizer-0.18-windows-mingw.zip -o%APPVEYOR_BUILD_FOLDER%\deps
build_script: build_script:
- IF "%TARGET%" == "desktop" IF "%COMPILER:~0,4%" == "msvc" call package\ci\appveyor-desktop.bat - IF "%TARGET%" == "desktop" IF "%COMPILER:~0,4%" == "msvc" call package\ci\appveyor-desktop.bat
- IF "%TARGET%" == "desktop-gles" call package\ci\appveyor-desktop-gles.bat - IF "%TARGET%" == "desktop-gles" call package\ci\appveyor-desktop-gles.bat

28
package/ci/circleci.yml

@ -128,6 +128,23 @@ commands:
wget https://ci.magnum.graphics/swiftshader-gles-r5464.a6940c8e6e-<< parameters.build >>.zip wget https://ci.magnum.graphics/swiftshader-gles-r5464.a6940c8e6e-<< parameters.build >>.zip
unzip swiftshader-gles-r5464.a6940c8e6e-<< parameters.build >>.zip unzip swiftshader-gles-r5464.a6940c8e6e-<< parameters.build >>.zip
install-meshoptimizer:
steps:
- run:
name: Install meshoptimizer
# few commits after 0.14 with a fix for old Apple Clang
command: |
export MESHOPTIMIZER_VERSION=97c52415c6d29f297a76482ddde22f739292446d
mkdir -p $HOME/meshoptimizer && cd $HOME/meshoptimizer
wget -nc --no-check-certificate https://github.com/zeux/meshoptimizer/archive/$MESHOPTIMIZER_VERSION.tar.gz
tar --strip-components=1 -xzf $MESHOPTIMIZER_VERSION.tar.gz
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DCMAKE_INSTALL_PREFIX=$HOME/deps \
-G Ninja
ninja install
build: build:
parameters: parameters:
script: script:
@ -172,6 +189,7 @@ jobs:
- install-cmake-3_4 - install-cmake-3_4
- install-python-3_6 - install-python-3_6
- install-pybind11 - install-pybind11
- install-meshoptimizer
- build: - build:
script: unix-desktop.sh script: unix-desktop.sh
- lcov - lcov
@ -193,6 +211,7 @@ jobs:
- install-cmake-3_4 - install-cmake-3_4
- install-python-3_6 - install-python-3_6
- install-pybind11 - install-pybind11
- install-meshoptimizer
- install-swiftshader-gles: - install-swiftshader-gles:
build: ubuntu-16.04 build: ubuntu-16.04
- build: - build:
@ -216,6 +235,7 @@ jobs:
- install-cmake-3_4 - install-cmake-3_4
- install-python-3_6 - install-python-3_6
- install-pybind11 - install-pybind11
- install-meshoptimizer
- install-swiftshader-gles: - install-swiftshader-gles:
build: ubuntu-16.04 build: ubuntu-16.04
- build: - build:
@ -240,6 +260,7 @@ jobs:
- install-cmake-3_4 - install-cmake-3_4
- install-python-3_6 - install-python-3_6
- install-pybind11 - install-pybind11
- install-meshoptimizer
- build: - build:
script: unix-desktop.sh script: unix-desktop.sh
- lcov - lcov
@ -251,7 +272,8 @@ jobs:
PLATFORM_GL_API: CGL PLATFORM_GL_API: CGL
steps: steps:
- install-base-macos: - install-base-macos:
extra: sdl2 glfw numpy pybind11 extra: sdl2 glfw wget numpy pybind11
- install-meshoptimizer
- build: - build:
script: unix-desktop.sh script: unix-desktop.sh
- lcov - lcov
@ -268,6 +290,7 @@ jobs:
extra: sdl2 glfw wget numpy pybind11 extra: sdl2 glfw wget numpy pybind11
- install-swiftshader-gles: - install-swiftshader-gles:
build: macos-10.15 build: macos-10.15
- install-meshoptimizer
- build: - build:
script: unix-desktop-gles.sh script: unix-desktop-gles.sh
- lcov - lcov
@ -281,7 +304,8 @@ jobs:
PLATFORM_GL_API: CGL PLATFORM_GL_API: CGL
steps: steps:
- install-base-macos: - install-base-macos:
extra: sdl2 glfw numpy pybind11 extra: sdl2 glfw wget numpy pybind11
- install-meshoptimizer
- build: - build:
script: unix-desktop.sh script: unix-desktop.sh
- lcov - lcov

1
package/ci/unix-desktop-gles.sh

@ -65,6 +65,7 @@ cmake .. \
-DMAGNUM_BUILD_STATIC=$BUILD_STATIC \ -DMAGNUM_BUILD_STATIC=$BUILD_STATIC \
-DMAGNUM_WITH_DDSIMPORTER=ON \ -DMAGNUM_WITH_DDSIMPORTER=ON \
-DMAGNUM_WITH_GLTFIMPORTER=ON \ -DMAGNUM_WITH_GLTFIMPORTER=ON \
-DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON \
-DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \
-DMAGNUM_WITH_STBIMAGECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGECONVERTER=ON \
-DMAGNUM_WITH_STBIMAGEIMPORTER=ON \ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON \

1
package/ci/unix-desktop.sh

@ -69,6 +69,7 @@ cmake .. \
-DMAGNUM_BUILD_STATIC=$BUILD_STATIC \ -DMAGNUM_BUILD_STATIC=$BUILD_STATIC \
-DMAGNUM_WITH_DDSIMPORTER=ON \ -DMAGNUM_WITH_DDSIMPORTER=ON \
-DMAGNUM_WITH_GLTFIMPORTER=ON \ -DMAGNUM_WITH_GLTFIMPORTER=ON \
-DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON \
-DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \
-DMAGNUM_WITH_STBIMAGECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGECONVERTER=ON \
-DMAGNUM_WITH_STBIMAGEIMPORTER=ON \ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON \

58
src/python/magnum/test/test_trade.py

@ -1466,6 +1466,62 @@ class SceneConverter(unittest.TestCase):
self.assertEqual(converter.flags, trade.SceneConverterFlags.VERBOSE) self.assertEqual(converter.flags, trade.SceneConverterFlags.VERBOSE)
def test_mesh(self): def test_mesh(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh('Indexed mesh')
converter_manager = converter = trade.SceneConverterManager()
if 'MeshOptimizerSceneConverter' not in converter_manager.plugin_list:
self.skipTest("MeshOptimizerSceneConverter plugin not available")
converter = trade.SceneConverterManager().load_and_instantiate('MeshOptimizerSceneConverter')
converted_mesh = converter.convert(mesh)
self.assertEqual(converted_mesh.index_count, mesh.index_count)
def test_mesh_failed(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh('Non-indexed mesh')
converter_manager = converter = trade.SceneConverterManager()
if 'MeshOptimizerSceneConverter' not in converter_manager.plugin_list:
self.skipTest("MeshOptimizerSceneConverter plugin not available")
converter = trade.SceneConverterManager().load_and_instantiate('MeshOptimizerSceneConverter')
with self.assertRaisesRegex(RuntimeError, "conversion failed"):
converted_mesh = converter.convert(mesh)
def test_mesh_in_place(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh('Indexed mesh')
converter_manager = converter = trade.SceneConverterManager()
if 'MeshOptimizerSceneConverter' not in converter_manager.plugin_list:
self.skipTest("MeshOptimizerSceneConverter plugin not available")
converter = trade.SceneConverterManager().load_and_instantiate('MeshOptimizerSceneConverter')
converter.convert_in_place(mesh)
self.assertEqual(mesh.index_count, 3)
def test_mesh_in_place_failed(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh('Non-indexed mesh')
converter_manager = converter = trade.SceneConverterManager()
if 'MeshOptimizerSceneConverter' not in converter_manager.plugin_list:
self.skipTest("MeshOptimizerSceneConverter plugin not available")
converter = trade.SceneConverterManager().load_and_instantiate('MeshOptimizerSceneConverter')
with self.assertRaisesRegex(RuntimeError, "conversion failed"):
converter.convert_in_place(mesh)
def test_mesh_to_file(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter') importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf')) importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh(1) mesh = importer.mesh(1)
@ -1476,7 +1532,7 @@ class SceneConverter(unittest.TestCase):
converter.convert_to_file(mesh, os.path.join(tmp, "mesh.ply")) converter.convert_to_file(mesh, os.path.join(tmp, "mesh.ply"))
self.assertTrue(os.path.exists(os.path.join(tmp, "mesh.ply"))) self.assertTrue(os.path.exists(os.path.join(tmp, "mesh.ply")))
def test_mesh_failed(self): def test_mesh_to_file_failed(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter') importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf')) importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh(1) mesh = importer.mesh(1)

18
src/python/magnum/trade.cpp

@ -1640,6 +1640,24 @@ void trade(py::module_& m) {
}, [](Trade::AbstractSceneConverter& self, Trade::SceneConverterFlag flags) { }, [](Trade::AbstractSceneConverter& self, Trade::SceneConverterFlag flags) {
self.setFlags(flags); self.setFlags(flags);
}, "Converter flags") }, "Converter flags")
.def("convert", [](Trade::AbstractSceneConverter& self, const Trade::MeshData& mesh) {
/** @todo log redirection -- but we'd need assertions to not be
part of that so when it dies, the user can still see why */
Containers::Optional<Trade::MeshData> out = self.convert(mesh);
if(!out) {
PyErr_SetString(PyExc_RuntimeError, "conversion failed");
throw py::error_already_set{};
}
return out;
}, "Convert a mesh", py::arg("mesh"))
.def("convert_in_place", [](Trade::AbstractSceneConverter& self, Trade::MeshData& mesh) {
/** @todo log redirection -- but we'd need assertions to not be
part of that so when it dies, the user can still see why */
if(!self.convertInPlace(mesh)) {
PyErr_SetString(PyExc_RuntimeError, "conversion failed");
throw py::error_already_set{};
}
}, "Convert a mesh", py::arg("mesh"))
/** @todo drop std::string in favor of our own string caster */ /** @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) { .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 /** @todo log redirection -- but we'd need assertions to not be

Loading…
Cancel
Save