diff --git a/doc/python/conf.py b/doc/python/conf.py index 41186d8..589bc12 100644 --- a/doc/python/conf.py +++ b/doc/python/conf.py @@ -21,13 +21,14 @@ import magnum.platform.sdl2 import magnum.primitives import magnum.shaders import magnum.scenegraph +import magnum.scenetools import magnum.text import magnum.trade # So the doc see everything # TODO: use just +=, m.css should reorder this on its own corrade.__all__ = ['containers', 'pluginmanager', 'utility', 'BUILD_DEPRECATED', 'BUILD_STATIC', 'BUILD_MULTITHREADED', 'TARGET_UNIX', 'TARGET_APPLE', 'TARGET_IOS', 'TARGET_IOS_SIMULATOR', 'TARGET_WINDOWS', 'TARGET_WINDOWS_RT', 'TARGET_EMSCRIPTEN', 'TARGET_ANDROID'] -magnum.__all__ = ['math', 'gl', 'meshtools', 'platform', 'primitives', 'shaders', 'scenegraph', 'text', 'trade', 'BUILD_DEPRECATED', 'BUILD_STATIC', 'TARGET_GL', 'TARGET_GLES', 'TARGET_GLES2', 'TARGET_WEBGL', 'TARGET_EGL', 'TARGET_VK'] + magnum.__all__ +magnum.__all__ = ['math', 'gl', 'meshtools', 'platform', 'primitives', 'shaders', 'scenegraph', 'scenetools', 'text', 'trade', 'BUILD_DEPRECATED', 'BUILD_STATIC', 'TARGET_GL', 'TARGET_GLES', 'TARGET_GLES2', 'TARGET_WEBGL', 'TARGET_EGL', 'TARGET_VK'] + magnum.__all__ # hide values of the preprocessor defines to avoid confusion by assigning a # class without __repr__ to them @@ -204,6 +205,7 @@ INPUT_DOCS = [ 'magnum.math.rst', 'magnum.platform.rst', 'magnum.scenegraph.rst', + 'magnum.scenetools.rst', 'magnum.shaders.rst', 'magnum.text.rst', 'magnum.trade.rst', diff --git a/doc/python/magnum.scenetools.rst b/doc/python/magnum.scenetools.rst new file mode 100644 index 0000000..19c093d --- /dev/null +++ b/doc/python/magnum.scenetools.rst @@ -0,0 +1,40 @@ +.. + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +.. + +.. py:function:: magnum.scenetools.flatten_transformation_hierarchy2d + :raise KeyError: If :p:`field` does not exist in :p:`scene` + :raise IndexError: If :p:`field_id` negative or not less than + :ref:`trade.SceneData.field_count` + :raise AssertionError: If :p:`scene` is not 2D + :raise AssertionError: If :p:`scene` does not have + :ref:`trade.SceneField.PARENT` + +.. py:function:: magnum.scenetools.flatten_transformation_hierarchy3d + :raise KeyError: If :p:`field` does not exist in :p:`scene` + :raise IndexError: If :p:`field_id` negative or not less than + :ref:`trade.SceneData.field_count` + :raise AssertionError: If :p:`scene` is not 2D + :raise AssertionError: If :p:`scene` does not have + :ref:`trade.SceneField.PARENT` diff --git a/doc/python/pages/changelog.rst b/doc/python/pages/changelog.rst index 3770d43..949d4ef 100644 --- a/doc/python/pages/changelog.rst +++ b/doc/python/pages/changelog.rst @@ -124,7 +124,7 @@ Changelog :ref:`trade.AbstractImporter.scene()` and related importer APIs - Exposed :ref:`Color3.red()` and other convenience constructors (see :gh:`mosra/magnum-bindings#12`) -- Exposed the :ref:`text` library +- Exposed the :ref:`scenetools` and :ref:`text` libraries - Exposed the minimal interface of :ref:`utility.ConfigurationGroup` and :ref:`utility.Configuration` - Exposed :ref:`pluginmanager.AbstractManager.set_preferred_plugins()`, diff --git a/package/ci/appveyor-desktop-gles.bat b/package/ci/appveyor-desktop-gles.bat index d53486a..2cf3070 100644 --- a/package/ci/appveyor-desktop-gles.bat +++ b/package/ci/appveyor-desktop-gles.bat @@ -51,7 +51,7 @@ cmake .. ^ -DMAGNUM_WITH_MESHTOOLS=ON ^ -DMAGNUM_WITH_PRIMITIVES=ON ^ -DMAGNUM_WITH_SCENEGRAPH=ON ^ - -DMAGNUM_WITH_SCENETOOLS=OFF ^ + -DMAGNUM_WITH_SCENETOOLS=ON ^ -DMAGNUM_WITH_SHADERS=ON ^ -DMAGNUM_WITH_SHADERTOOLS=OFF ^ -DMAGNUM_WITH_TEXT=ON ^ @@ -81,6 +81,7 @@ cmake .. ^ -DMAGNUM_WITH_GLTFIMPORTER=ON ^ -DMAGNUM_WITH_GLTFSCENECONVERTER=ON ^ -DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON ^ + -DMAGNUM_WITH_PRIMITIVEIMPORTER=ON ^ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^ diff --git a/package/ci/appveyor-desktop.bat b/package/ci/appveyor-desktop.bat index c53294e..77c8560 100644 --- a/package/ci/appveyor-desktop.bat +++ b/package/ci/appveyor-desktop.bat @@ -61,7 +61,7 @@ cmake .. ^ -DMAGNUM_WITH_MESHTOOLS=ON ^ -DMAGNUM_WITH_PRIMITIVES=ON ^ -DMAGNUM_WITH_SCENEGRAPH=ON ^ - -DMAGNUM_WITH_SCENETOOLS=OFF ^ + -DMAGNUM_WITH_SCENETOOLS=ON ^ -DMAGNUM_WITH_SHADERS=ON ^ -DMAGNUM_WITH_SHADERTOOLS=OFF ^ -DMAGNUM_WITH_TEXT=ON ^ @@ -91,6 +91,7 @@ cmake .. ^ -DMAGNUM_WITH_GLTFIMPORTER=ON ^ -DMAGNUM_WITH_GLTFSCENECONVERTER=ON ^ -DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=%EXCEPT_MSVC2017% ^ + -DMAGNUM_WITH_PRIMITIVEIMPORTER=ON ^ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGECONVERTER=ON ^ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON ^ diff --git a/package/ci/unix-desktop-gles.sh b/package/ci/unix-desktop-gles.sh index 953b058..f2687b0 100755 --- a/package/ci/unix-desktop-gles.sh +++ b/package/ci/unix-desktop-gles.sh @@ -36,7 +36,7 @@ cmake .. \ -DMAGNUM_WITH_MESHTOOLS=ON \ -DMAGNUM_WITH_PRIMITIVES=ON \ -DMAGNUM_WITH_SCENEGRAPH=ON \ - -DMAGNUM_WITH_SCENETOOLS=OFF \ + -DMAGNUM_WITH_SCENETOOLS=ON \ -DMAGNUM_WITH_SHADERS=ON \ -DMAGNUM_WITH_SHADERTOOLS=OFF \ -DMAGNUM_WITH_TEXT=ON \ @@ -68,6 +68,7 @@ cmake .. \ -DMAGNUM_WITH_GLTFIMPORTER=ON \ -DMAGNUM_WITH_GLTFSCENECONVERTER=ON \ -DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON \ + -DMAGNUM_WITH_PRIMITIVEIMPORTER=ON \ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON \ diff --git a/package/ci/unix-desktop.sh b/package/ci/unix-desktop.sh index def8a23..3998e9d 100755 --- a/package/ci/unix-desktop.sh +++ b/package/ci/unix-desktop.sh @@ -35,7 +35,7 @@ cmake .. \ -DMAGNUM_WITH_MESHTOOLS=ON \ -DMAGNUM_WITH_PRIMITIVES=ON \ -DMAGNUM_WITH_SCENEGRAPH=ON \ - -DMAGNUM_WITH_SCENETOOLS=OFF \ + -DMAGNUM_WITH_SCENETOOLS=ON \ -DMAGNUM_WITH_SHADERS=ON \ -DMAGNUM_WITH_SHADERTOOLS=OFF \ -DMAGNUM_WITH_TEXT=ON \ @@ -72,6 +72,7 @@ cmake .. \ -DMAGNUM_WITH_GLTFIMPORTER=ON \ -DMAGNUM_WITH_GLTFSCENECONVERTER=ON \ -DMAGNUM_WITH_MESHOPTIMIZERSCENECONVERTER=ON \ + -DMAGNUM_WITH_PRIMITIVEIMPORTER=ON \ -DMAGNUM_WITH_STANFORDSCENECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGECONVERTER=ON \ -DMAGNUM_WITH_STBIMAGEIMPORTER=ON \ diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt index a6928ee..b7694cc 100644 --- a/src/python/CMakeLists.txt +++ b/src/python/CMakeLists.txt @@ -67,6 +67,7 @@ foreach(target magnum_meshtools magnum_primitives magnum_scenegraph + magnum_scenetools magnum_shaders magnum_platform_cgl magnum_platform_egl diff --git a/src/python/magnum/CMakeLists.txt b/src/python/magnum/CMakeLists.txt index 72b3b7b..d1729b9 100644 --- a/src/python/magnum/CMakeLists.txt +++ b/src/python/magnum/CMakeLists.txt @@ -33,6 +33,7 @@ find_package(Magnum COMPONENTS MeshTools Primitives SceneGraph + SceneTools Shaders Text Trade @@ -81,6 +82,9 @@ set(magnum_scenegraph_SRCS scenegraph.matrix.cpp scenegraph.trs.cpp) +set(magnum_scenetools_SRCS + scenetools.cpp) + set(magnum_shaders_SRCS shaders.cpp) @@ -133,6 +137,17 @@ if(NOT MAGNUM_BUILD_STATIC) LIBRARY_OUTPUT_DIRECTORY ${output_dir}/magnum) endif() + if(Magnum_SceneTools_FOUND) + pybind11_add_module(magnum_scenetools ${pybind11_add_module_SYSTEM} ${magnum_scenetools_SRCS}) + target_include_directories(magnum_scenetools PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/src/python) + target_link_libraries(magnum_scenetools PRIVATE Magnum::SceneTools) + set_target_properties(magnum_scenetools PROPERTIES + OUTPUT_NAME "scenetools" + LIBRARY_OUTPUT_DIRECTORY ${output_dir}/magnum) + endif() + if(Magnum_Shaders_FOUND) pybind11_add_module(magnum_shaders ${pybind11_add_module_SYSTEM} ${magnum_shaders_SRCS}) target_include_directories(magnum_shaders PRIVATE @@ -193,6 +208,11 @@ else() list(APPEND magnum_LIBS Magnum::SceneGraph) endif() + if(Magnum_SceneTools_FOUND) + list(APPEND magnum_SRCS ${magnum_scenetools_SRCS}) + list(APPEND magnum_LIBS Magnum::SceneTools) + endif() + if(Magnum_Shaders_FOUND) list(APPEND magnum_SRCS ${magnum_shaders_SRCS}) list(APPEND magnum_LIBS Magnum::Shaders) diff --git a/src/python/magnum/__init__.py b/src/python/magnum/__init__.py index 7bab5b6..d55ae0b 100644 --- a/src/python/magnum/__init__.py +++ b/src/python/magnum/__init__.py @@ -35,7 +35,7 @@ sys.modules['magnum.math'] = math # In case Magnum is built statically, the whole core project is put into # _magnum. Then we need to do the same as above but for all modules. -for i in ['gl', 'meshtools', 'platform', 'primitives', 'scenegraph', 'shaders', 'text', 'trade']: +for i in ['gl', 'meshtools', 'platform', 'primitives', 'scenegraph', 'scenetools', 'shaders', 'text', 'trade']: if i in globals(): sys.modules['magnum.' + i] = globals()[i] # Platform has subpackages diff --git a/src/python/magnum/bootstrap.h b/src/python/magnum/bootstrap.h index 9e81732..909ae59 100644 --- a/src/python/magnum/bootstrap.h +++ b/src/python/magnum/bootstrap.h @@ -73,6 +73,7 @@ void gl(py::module_& m); void meshtools(py::module_& m); void primitives(py::module_& m); void scenegraph(py::module_& m); +void scenetools(py::module_& m); void shaders(py::module_& m); void text(py::module_& m); void trade(py::module_& m); diff --git a/src/python/magnum/magnum.cpp b/src/python/magnum/magnum.cpp index 2e23943..64d63ff 100644 --- a/src/python/magnum/magnum.cpp +++ b/src/python/magnum/magnum.cpp @@ -527,6 +527,12 @@ PYBIND11_MODULE(_magnum, m) { magnum::primitives(primitives); #endif + #ifdef Magnum_SceneTools_FOUND + /* Depends on trade */ + py::module_ scenetools = m.def_submodule("scenetools"); + magnum::scenetools(scenetools); + #endif + #ifdef Magnum_Shaders_FOUND /* Depends on gl */ py::module_ shaders = m.def_submodule("shaders"); diff --git a/src/python/magnum/scenetools.cpp b/src/python/magnum/scenetools.cpp new file mode 100644 index 0000000..c466974 --- /dev/null +++ b/src/python/magnum/scenetools.cpp @@ -0,0 +1,138 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include /* for std::vector */ +#include +#include +#include +#include +#include +#include + +#include "magnum/bootstrap.h" + +namespace magnum { + +void scenetools(py::module_& m) { + m.doc() = "Scene manipulation and optimization tools"; + + #ifndef MAGNUM_BUILD_STATIC + /* These are a part of the same module in the static build, no need to + import (also can't import because there it's _magnum.*) */ + py::module_::import("magnum.trade"); + #endif + + m + .def("flatten_transformation_hierarchy2d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation) { + const Containers::Optional fieldId = scene.findFieldId(field); + if(!fieldId) { + PyErr_SetNone(PyExc_KeyError); + throw py::error_already_set{}; + } + if(!scene.is2D()) { + PyErr_SetString(PyExc_AssertionError, "the scene is not 2D"); + throw py::error_already_set{}; + } + if(!scene.hasField(Trade::SceneField::Parent)) { + PyErr_SetString(PyExc_AssertionError, "the scene has no hierarchy"); + throw py::error_already_set{}; + } + + /** @todo maybe do a caster for arrays, finally?! */ + std::vector out(scene.fieldSize(*fieldId)); + SceneTools::flattenTransformationHierarchy2DInto(scene, *fieldId, out, globalTransformation); + return out; + }, "Flatten a 2D transformation hierarchy for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix3{}) + .def("flatten_transformation_hierarchy2d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation) { + if(fieldId >= scene.fieldCount()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } + if(!scene.is2D()) { + PyErr_SetString(PyExc_AssertionError, "the scene is not 2D"); + throw py::error_already_set{}; + } + if(!scene.hasField(Trade::SceneField::Parent)) { + PyErr_SetString(PyExc_AssertionError, "the scene has no hierarchy"); + throw py::error_already_set{}; + } + + /** @todo maybe do a caster for arrays, finally?! */ + std::vector out(scene.fieldSize(fieldId)); + SceneTools::flattenTransformationHierarchy2DInto(scene, fieldId, out, globalTransformation); + return out; + }, "Flatten a 2D transformation hierarchy for given field ID", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix3{}) + .def("flatten_transformation_hierarchy3d", [](const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation) { + const Containers::Optional fieldId = scene.findFieldId(field); + if(!fieldId) { + PyErr_SetNone(PyExc_KeyError); + throw py::error_already_set{}; + } + if(!scene.is3D()) { + PyErr_SetString(PyExc_AssertionError, "the scene is not 3D"); + throw py::error_already_set{}; + } + if(!scene.hasField(Trade::SceneField::Parent)) { + PyErr_SetString(PyExc_AssertionError, "the scene has no hierarchy"); + throw py::error_already_set{}; + } + + /** @todo maybe do a caster for arrays, finally?! */ + std::vector out(scene.fieldSize(*fieldId)); + SceneTools::flattenTransformationHierarchy3DInto(scene, *fieldId, out, globalTransformation); + return out; + }, "Flatten a 3D transformation hierarchy for given field", py::arg("scene"), py::arg("field"), py::arg("global_transformation") = Matrix4{}) + .def("flatten_transformation_hierarchy3d", [](const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation) { + if(fieldId >= scene.fieldCount()) { + PyErr_SetNone(PyExc_IndexError); + throw py::error_already_set{}; + } + if(!scene.is3D()) { + PyErr_SetString(PyExc_AssertionError, "the scene is not 3D"); + throw py::error_already_set{}; + } + if(!scene.hasField(Trade::SceneField::Parent)) { + PyErr_SetString(PyExc_AssertionError, "the scene has no hierarchy"); + throw py::error_already_set{}; + } + + /** @todo maybe do a caster for arrays, finally?! */ + std::vector out(scene.fieldSize(fieldId)); + SceneTools::flattenTransformationHierarchy3DInto(scene, fieldId, out, globalTransformation); + return out; + }, "Flatten a 3D transformation hierarchy for given field ID", py::arg("scene"), py::arg("field_id"), py::arg("global_transformation") = Matrix4{}); +} + +} + +#ifndef MAGNUM_BUILD_STATIC +/* TODO: remove declaration when https://github.com/pybind/pybind11/pull/1863 + is released */ +extern "C" PYBIND11_EXPORT PyObject* PyInit_scenetools(); +PYBIND11_MODULE(scenetools, m) { + magnum::scenetools(m); +} +#endif diff --git a/src/python/magnum/staticconfigure.h.cmake b/src/python/magnum/staticconfigure.h.cmake index f357253..55c7aed 100644 --- a/src/python/magnum/staticconfigure.h.cmake +++ b/src/python/magnum/staticconfigure.h.cmake @@ -30,6 +30,7 @@ #cmakedefine Magnum_MeshTools_FOUND #cmakedefine Magnum_Primitives_FOUND #cmakedefine Magnum_SceneGraph_FOUND +#cmakedefine Magnum_SceneTools_FOUND #cmakedefine Magnum_Shaders_FOUND #cmakedefine Magnum_Text_FOUND #cmakedefine Magnum_Trade_FOUND diff --git a/src/python/magnum/test/test_scenetools.py b/src/python/magnum/test/test_scenetools.py new file mode 100644 index 0000000..e5704dd --- /dev/null +++ b/src/python/magnum/test/test_scenetools.py @@ -0,0 +1,119 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, +# 2020, 2021, 2022 Vladimír Vondruš +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# + +import unittest + +from corrade import containers +from magnum import * +from magnum import scenetools, trade + +class FlattenTransformationHierarchy(unittest.TestCase): + def test_2d(self): + # The only way to get a 2D scene is via PrimitiveImporter + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene = importer.scene(0) + self.assertTrue(scene.is_2d) + + transformations = scenetools.flatten_transformation_hierarchy2d(scene, trade.SceneField.MESH) + self.assertEqual(len(transformations), scene.field_size(trade.SceneField.MESH)) + self.assertEqual(transformations[0], Matrix3.translation((-4.5, -3.0))) + + def test_2d_field_id(self): + # The only way to get a 2D scene is via PrimitiveImporter + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene = importer.scene(0) + self.assertTrue(scene.is_2d) + + mesh_field = scene.field_id(trade.SceneField.MESH) + + transformations = scenetools.flatten_transformation_hierarchy2d(scene, mesh_field) + self.assertEqual(len(transformations), scene.field_size(mesh_field)) + self.assertEqual(transformations[0], Matrix3.translation((-4.5, -3.0))) + + def test_3d(self): + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene = importer.scene(1) + self.assertTrue(scene.is_3d) + + transformations = scenetools.flatten_transformation_hierarchy3d(scene, trade.SceneField.MESH) + self.assertEqual(len(transformations), scene.field_size(trade.SceneField.MESH)) + self.assertEqual(transformations[0], Matrix4.translation((-4.5, -3.0, 0.0))) + + def test_3d_field_id(self): + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene = importer.scene(1) + self.assertTrue(scene.is_3d) + + mesh_field = scene.field_id(trade.SceneField.MESH) + + transformations = scenetools.flatten_transformation_hierarchy3d(scene, mesh_field) + self.assertEqual(len(transformations), scene.field_size(mesh_field)) + self.assertEqual(transformations[0], Matrix4.translation((-4.5, -3.0, 0.0))) + + def test_field_not_found(self): + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene = importer.scene(0) + + with self.assertRaises(KeyError): + scenetools.flatten_transformation_hierarchy2d(scene, trade.SceneField.LIGHT) + with self.assertRaises(KeyError): + scenetools.flatten_transformation_hierarchy3d(scene, trade.SceneField.LIGHT) + with self.assertRaises(IndexError): + scenetools.flatten_transformation_hierarchy2d(scene, scene.field_count) + with self.assertRaises(IndexError): + scenetools.flatten_transformation_hierarchy3d(scene, scene.field_count) + + def test_not_2d_not_3d(self): + importer = trade.ImporterManager().load_and_instantiate('PrimitiveImporter') + importer.open_data(containers.ArrayView()) + + scene2d = importer.scene(0) + scene3d = importer.scene(1) + self.assertFalse(scene2d.is_3d) + self.assertFalse(scene3d.is_2d) + + with self.assertRaisesRegex(AssertionError, "the scene is not 2D"): + scenetools.flatten_transformation_hierarchy2d(scene3d, trade.SceneField.MESH) + with self.assertRaisesRegex(AssertionError, "the scene is not 2D"): + scenetools.flatten_transformation_hierarchy2d(scene3d, scene2d.field_id(trade.SceneField.MESH)) + with self.assertRaisesRegex(AssertionError, "the scene is not 3D"): + scenetools.flatten_transformation_hierarchy3d(scene2d, trade.SceneField.MESH) + with self.assertRaisesRegex(AssertionError, "the scene is not 3D"): + scenetools.flatten_transformation_hierarchy3d(scene2d, scene3d.field_id(trade.SceneField.MESH)) + + def test_no_hierarchy(self): + # TODO implement once it's possible to create / import a scene without + # the parent field + pass diff --git a/src/python/setup.py.cmake b/src/python/setup.py.cmake index a6b7e6b..39474da 100644 --- a/src/python/setup.py.cmake +++ b/src/python/setup.py.cmake @@ -42,6 +42,7 @@ extension_paths = { 'magnum.meshtools': '${magnum_meshtools_file}', 'magnum.primitives': '${magnum_primitives_file}', 'magnum.scenegraph': '${magnum_scenegraph_file}', + 'magnum.scenetools': '${magnum_scenetools_file}', 'magnum.shaders': '${magnum_shaders_file}', 'magnum.platform.cgl': '${magnum_platform_cgl_file}', 'magnum.platform.egl': '${magnum_platform_egl_file}',