Browse Source

python: ability to pass extra attributes to meshtools.interleave().

Yay, finally it's (almost) possible to create custom meshes from pure
Python. Except that there always has to be some initial mesh to add
attributes to, and it's not yet possible to supply index data there.
next
Vladimír Vondruš 2 years ago
parent
commit
cade85c94f
  1. 4
      doc/python/magnum.meshtools.rst
  2. 5
      doc/python/magnum.trade.rst
  3. 19
      src/python/magnum/meshtools.cpp
  4. 19
      src/python/magnum/test/test_meshtools.py

4
doc/python/magnum.meshtools.rst

@ -47,6 +47,10 @@
:ref:`MeshPrimitive.LINE_LOOP`, :ref:`MeshPrimitive.TRIANGLE_STRIP` or :ref:`MeshPrimitive.LINE_LOOP`, :ref:`MeshPrimitive.TRIANGLE_STRIP` or
:ref:`MeshPrimitive.TRIANGLE_FAN` :ref:`MeshPrimitive.TRIANGLE_FAN`
.. py:function:: magnum.meshtools.interleave
:raise AssertionError: If any attribute in :p:`extra` has the data size
different from :p:`mesh` vertex count
.. py:function:: magnum.meshtools.transform2d .. py:function:: magnum.meshtools.transform2d
:raise KeyError: If :p:`mesh` doesn't have :raise KeyError: If :p:`mesh` doesn't have
:ref:`trade.MeshAttribute.POSITION` of index :p:`id` (and in morph :ref:`trade.MeshAttribute.POSITION` of index :p:`id` (and in morph

5
doc/python/magnum.trade.rst

@ -138,8 +138,9 @@
.. py:class:: magnum.trade.MeshAttributeData .. py:class:: magnum.trade.MeshAttributeData
Associates a typed data view with a name, vertex format and other mesh Associates a typed data view with a name, vertex format and other mesh
attribute properties. The data view can be either one-dimensional, for attribute properties, which can be subsequently put into a :ref:`MeshData`
example a NumPy array: instance, for example with :ref:`meshtools.interleave()`. The data view can
be either one-dimensional, for example a NumPy array:
.. ..
Just to verify the snippet below actually works (don't want the arrows Just to verify the snippet below actually works (don't want the arrows

19
src/python/magnum/meshtools.cpp

@ -169,12 +169,25 @@ void meshtools(py::module_& m) {
return MeshTools::generateIndices(mesh); return MeshTools::generateIndices(mesh);
}, "Convert a mesh to plain indexed lines or triangles", py::arg("mesh")) }, "Convert a mesh to plain indexed lines or triangles", py::arg("mesh"))
.def("interleave", [](const Trade::MeshData& mesh, MeshTools::InterleaveFlag flags) { /** @todo eugh, find a way w/o the STL vector */
.def("interleave", [](const Trade::MeshData& mesh, const std::vector<Trade::MeshAttributeData>& extra, MeshTools::InterleaveFlag flags) {
for(std::size_t i = 0; i != extra.size(); ++i) {
const Trade::MeshAttributeData& attribute = extra[i];
if(attribute.data().size() != mesh.vertexCount()) {
PyErr_Format(PyExc_AssertionError, "extra attribute %zu expected to have %u items but got %zu", i, mesh.vertexCount(), attribute.data().size());
throw py::error_already_set{};
}
}
/** @todo check that the vertices/indices aren't impl-specific if /** @todo check that the vertices/indices aren't impl-specific if
the interleaved preservation is disabled, once it's possible to the interleaved preservation is disabled, once it's possible to
test */ test */
return MeshTools::interleave(mesh, {}, flags); return MeshTools::interleave(mesh, extra, flags);
}, "Interleave mesh data", py::arg("mesh"), py::arg("flags") = MeshTools::InterleaveFlag::PreserveInterleavedAttributes) }, "Interleave mesh data", py::arg("mesh"),
#if PYBIND11_VERSION_MAJOR*100 + PYBIND11_VERSION_MINOR >= 206
py::kw_only{}, /* new in pybind11 2.6 */
#endif
py::arg("extra") = std::vector<Trade::MeshAttributeData>{},
py::arg("flags") = MeshTools::InterleaveFlag::PreserveInterleavedAttributes)
.def("copy", static_cast<Trade::MeshData(*)(const Trade::MeshData&)>(MeshTools::copy), "Make an owned copy of the mesh", py::arg("mesh")) .def("copy", static_cast<Trade::MeshData(*)(const Trade::MeshData&)>(MeshTools::copy), "Make an owned copy of the mesh", py::arg("mesh"))
/** @todo check that the indices/vertices aren't impl-specific once /** @todo check that the indices/vertices aren't impl-specific once
it's possible to test */ it's possible to test */

19
src/python/magnum/test/test_meshtools.py

@ -23,6 +23,7 @@
# DEALINGS IN THE SOFTWARE. # DEALINGS IN THE SOFTWARE.
# #
import array
import os import os
import sys import sys
import unittest import unittest
@ -211,11 +212,27 @@ class Interleave(unittest.TestCase):
# Gap after normals not removed # Gap after normals not removed
self.assertEqual(interleaved.attribute_stride(trade.MeshAttribute.POSITION), 12 + 12 + 8) self.assertEqual(interleaved.attribute_stride(trade.MeshAttribute.POSITION), 12 + 12 + 8)
interleaved_packed = meshtools.interleave(mesh, meshtools.InterleaveFlags.NONE) interleaved_packed = meshtools.interleave(mesh, flags=meshtools.InterleaveFlags.NONE)
self.assertEqual(interleaved_packed.attribute_count(), 2) self.assertEqual(interleaved_packed.attribute_count(), 2)
# Gap after normals removed # Gap after normals removed
self.assertEqual(interleaved_packed.attribute_stride(trade.MeshAttribute.POSITION), 12 + 8) self.assertEqual(interleaved_packed.attribute_stride(trade.MeshAttribute.POSITION), 12 + 8)
def test_extra(self):
interleaved = meshtools.interleave(primitives.plane_solid(), extra=[
trade.MeshAttributeData(trade.MeshAttribute.OBJECT_ID, VertexFormat.UNSIGNED_SHORT, array.array('H', [3, 176, 2, 14]))
])
self.assertEqual(interleaved.attribute_count(), 3)
self.assertTrue(interleaved.has_attribute(trade.MeshAttribute.OBJECT_ID))
self.assertEqual(interleaved.attribute_format(trade.MeshAttribute.OBJECT_ID), VertexFormat.UNSIGNED_SHORT)
self.assertEqual(list(interleaved.attribute(trade.MeshAttribute.OBJECT_ID)), [3, 176, 2, 14])
def test_extra_invalid(self):
with self.assertRaisesRegex(AssertionError, "extra attribute 1 expected to have 4 items but got 5"):
meshtools.interleave(primitives.plane_solid(), extra=[
trade.MeshAttributeData(trade.MeshAttribute.CUSTOM(33), VertexFormat.UNSIGNED_BYTE, array.array('B', [3, 176, 2, 12])),
trade.MeshAttributeData(trade.MeshAttribute.OBJECT_ID, VertexFormat.UNSIGNED_SHORT, array.array('H', [3, 176, 2, 12, 6]))
])
class Copy(unittest.TestCase): class Copy(unittest.TestCase):
def test(self): def test(self):
mesh = primitives.square_solid() mesh = primitives.square_solid()

Loading…
Cancel
Save