Browse Source

python: expose scene-related APIs in AbstractSceneConverter.

next
Vladimír Vondruš 3 years ago
parent
commit
05fad9ccdd
  1. 12
      doc/python/magnum.trade.rst
  2. 93
      src/python/magnum/test/test_trade.py
  3. 42
      src/python/magnum/trade.cpp

12
doc/python/magnum.trade.rst

@ -612,6 +612,9 @@
.. py:property:: magnum.trade.AbstractSceneConverter.mesh_count
:raise AssertionError: If no conversion is in progress
.. py:property:: magnum.trade.AbstractSceneConverter.scene_count
:raise AssertionError: If no conversion is in progress
.. py:function:: magnum.trade.AbstractSceneConverter.add
:raise AssertionError: If no conversion is in progress
:raise RuntimeError: If adding the data fails
@ -620,6 +623,15 @@
:raise AssertionError: If no conversion is in progress
:raise AssertionError: If :p:`attribute` is not custom
.. py:function:: magnum.trade.AbstractSceneConverter.set_default_scene
:raise AssertionError: If no conversion is in progress
:raise AssertionError: If :p:`id` is negative or not less than
:ref:`scene_count`
.. py:function:: magnum.trade.AbstractSceneConverter.set_scene_field_name
:raise AssertionError: If no conversion is in progress
:raise AssertionError: If :p:`field` is not custom
.. py:function:: magnum.trade.AbstractSceneConverter.add_importer_contents
:raise AssertionError: If no conversion is in progress
:raise RuntimeError: If adding the importer contents fails

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

@ -31,7 +31,7 @@ import unittest
from corrade import containers, pluginmanager
from magnum import *
from magnum import primitives, trade
from magnum import primitives, scenetools, trade
import magnum
class ImageData(unittest.TestCase):
@ -1840,6 +1840,87 @@ class SceneConverter(unittest.TestCase):
with self.assertRaisesRegex(AssertionError, "not a custom attribute"):
converter.set_mesh_attribute_name(trade.MeshAttribute.POSITION, 'foo')
def test_batch_add_scene(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'scene.gltf'))
scene = importer.scene("A default scene that's empty")
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
with tempfile.TemporaryDirectory() as tmp:
filename = os.path.join(tmp, "scene.gltf")
converter.begin_file(filename)
converter.add(scene, "A default scene that's empty")
converter.end_file()
with open(filename, 'r') as f:
self.assertIn("A default scene that's empty", f.read())
def test_batch_set_default_scene(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'scene.gltf'))
scene = importer.scene("A default scene that's empty")
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
with tempfile.TemporaryDirectory() as tmp:
filename = os.path.join(tmp, "scene.gltf")
converter.begin_file(filename)
converter.add(scene, "A default scene that's empty")
converter.set_default_scene(0)
converter.end_file()
with open(filename, 'r') as f:
self.assertIn('"scene": 0', f.read())
def test_batch_set_default_scene_out_of_range(self):
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
with tempfile.TemporaryDirectory() as tmp:
filename = os.path.join(tmp, "scene.gltf")
converter.begin_file(filename)
with self.assertRaisesRegex(AssertionError, "index 1 out of range for 0 scenes"):
converter.set_default_scene(1)
def test_batch_set_scene_field_name(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'scene.gltf'))
# Keep only the single custom numeric attribute in the scene (plus
# hierarchy and transformation that's required by glTF)
# TODO clean up once there's a possibility to create scenes from
# scratch
scene = scenetools.filter_only_fields(importer.scene("A scene"), [
trade.SceneField.PARENT,
trade.SceneField.TRANSLATION,
importer.scene_field_for_name('aNumber'),
])
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
with tempfile.TemporaryDirectory() as tmp:
filename = os.path.join(tmp, "scene.gltf")
converter.begin_file(filename)
converter.set_scene_field_name(importer.scene_field_for_name('aNumber'), 'aNumber')
converter.add(scene)
converter.end_file()
with open(filename, 'r') as f:
self.assertIn('"aNumber":', f.read())
def test_batch_set_scene_field_name_not_custom(self):
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
with tempfile.TemporaryDirectory() as tmp:
filename = os.path.join(tmp, "scene.gltf")
converter.begin_file(filename)
with self.assertRaisesRegex(AssertionError, "not a custom field"):
converter.set_scene_field_name(trade.SceneField.SCALING, 'foo')
def test_batch_add_importer_contents(self):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'two-meshes.gltf'))
@ -1908,6 +1989,8 @@ class SceneConverter(unittest.TestCase):
importer = trade.ImporterManager().load_and_instantiate('GltfImporter')
importer.open_file(os.path.join(os.path.dirname(__file__), 'mesh.gltf'))
mesh = importer.mesh('Custom mesh attribute')
importer.open_file(os.path.join(os.path.dirname(__file__), 'scene.gltf'))
scene = importer.scene("A default scene that's empty")
converter = trade.SceneConverterManager().load_and_instantiate('GltfSceneConverter')
self.assertFalse(converter.is_converting)
@ -1920,6 +2003,14 @@ class SceneConverter(unittest.TestCase):
converter.add(mesh)
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.set_mesh_attribute_name(trade.MeshAttribute.CUSTOM(1), 'foobar')
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.scene_count
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.add(scene)
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.set_default_scene(0)
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.set_scene_field_name(trade.SceneField.CUSTOM(1), 'foobar')
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):
converter.add_importer_contents(importer)
with self.assertRaisesRegex(AssertionError, "no conversion in progress"):

42
src/python/magnum/trade.cpp

@ -1826,6 +1826,48 @@ void trade(py::module_& m) {
throw py::error_already_set{};
}
}, "End converting a scene to a file")
.def("set_default_scene", [](Trade::AbstractSceneConverter& self, const UnsignedInt id) {
if(!self.isConverting()) {
PyErr_SetString(PyExc_AssertionError, "no conversion in progress");
throw py::error_already_set{};
}
if(id >= self.sceneCount()) {
PyErr_Format(PyExc_AssertionError, "index %u out of range for %u scenes", id, self.sceneCount());
throw py::error_already_set{};
}
self.setDefaultScene(id);
}, "Set default scene", py::arg("id"))
.def_property_readonly("scene_count", [](Trade::AbstractSceneConverter& self) {
if(!self.isConverting()) {
PyErr_SetString(PyExc_AssertionError, "no conversion in progress");
throw py::error_already_set{};
}
return self.sceneCount();
}, "Count of added scenes")
/** @todo drop std::string in favor of our own string caster */
.def("add", [](Trade::AbstractSceneConverter& self, const Trade::SceneData& scene, const std::string& name) {
if(!self.isConverting()) {
PyErr_SetString(PyExc_AssertionError, "no conversion in progress");
throw py::error_already_set{};
}
if(const Containers::Optional<UnsignedInt> out = self.add(scene, name))
return *out;
PyErr_SetString(PyExc_RuntimeError, "adding the scene failed");
throw py::error_already_set{};
}, "Add a scene", py::arg("scene"), py::arg("name") = std::string{})
.def("set_scene_field_name", [](Trade::AbstractSceneConverter& self, const Trade::SceneField field, const std::string& name) {
if(!Trade::isSceneFieldCustom(field)) {
PyErr_SetString(PyExc_AssertionError, "not a custom field");
throw py::error_already_set{};
}
if(!self.isConverting()) {
PyErr_SetString(PyExc_AssertionError, "no conversion in progress");
throw py::error_already_set{};
}
self.setSceneFieldName(field, name);
}, "Set name of a custom scene field", py::arg("field"), py::arg("name"))
.def_property_readonly("mesh_count", [](Trade::AbstractSceneConverter& self) {
if(!self.isConverting()) {
PyErr_SetString(PyExc_AssertionError, "no conversion in progress");

Loading…
Cancel
Save