diff --git a/src/python/magnum/gl.cpp b/src/python/magnum/gl.cpp index 3b18cc7..844f023 100644 --- a/src/python/magnum/gl.cpp +++ b/src/python/magnum/gl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include "corrade/PyArrayView.h" #include "corrade/EnumOperators.h" @@ -37,6 +38,12 @@ namespace magnum { namespace { +struct PyMesh: GL::Mesh { + explicit PyMesh(GL::MeshPrimitive primitive): GL::Mesh(primitive) {} + + std::vector buffers; +}; + void gl(py::module& m) { py::module::import("corrade.containers"); @@ -189,6 +196,52 @@ void gl(py::module& m) { returning a raw pointer from functions makes pybind wrap it in an unique_ptr, which would cause double-free / memory corruption later */ py::setattr(m, "default_framebuffer", py::cast(GL::defaultFramebuffer, py::return_value_policy::reference)); + + /* Mesh */ + py::enum_{m, "MeshPrimitive", "Mesh primitive type"} + .value("POINTS", GL::MeshPrimitive::Points) + .value("LINES", GL::MeshPrimitive::Lines) + .value("LINE_LOOP", GL::MeshPrimitive::LineLoop) + .value("LINE_STRIP", GL::MeshPrimitive::LineStrip) + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + .value("LINES_ADJACENCY", GL::MeshPrimitive::LinesAdjacency) + .value("LINE_STRIP_ADJACENCY", GL::MeshPrimitive::LineStripAdjacency) + #endif + .value("TRIANGLES", GL::MeshPrimitive::Triangles) + .value("TRIANGLE_STRIP", GL::MeshPrimitive::TriangleStrip) + .value("TRIANGLE_FAN", GL::MeshPrimitive::TriangleFan) + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + .value("TRIANGLES_ADJACENCY", GL::MeshPrimitive::TrianglesAdjacency) + .value("TRIANGLE_STRIP_ADJACENCY", GL::MeshPrimitive::TriangleStripAdjacency) + .value("PATCHES", GL::MeshPrimitive::Patches) + #endif + ; + + py::class_{m, "Mesh", "Mesh"} + .def(py::init(), "Constructor", py::arg("primitive") = GL::MeshPrimitive::Triangles) + .def_property_readonly("id", &GL::Mesh::id, "OpenGL vertex array ID") + .def_property("primitive", &GL::Mesh::primitive, static_cast(&GL::Mesh::setPrimitive), "Primitive type") + /** @todo generic primitive overload */ + /* Have to use a lambda because it returns GL::Mesh which is not + tracked (unlike PyMesh) */ + .def_property("count", &GL::Mesh::count, [](PyMesh& self, UnsignedInt count) { + self.setCount(count); + }, "Vertex/index count") + + /* Using lambdas to avoid method chaining getting into signatures */ + + .def("add_vertex_buffer", [](PyMesh& self, GL::Buffer& buffer, GLintptr offset, GLsizei stride, const GL::DynamicAttribute& attribute) { + self.addVertexBuffer(buffer, offset, stride, attribute); + + /* Keep a reference to the buffer to avoid it being deleted before + the mesh */ + self.buffers.emplace_back(py::detail::get_object_handle(&buffer, py::detail::get_type_info(typeid(GL::Buffer))), true); + }, "Add vertex buffer", py::arg("buffer"), py::arg("offset"), py::arg("stride"), py::arg("attribute")) + .def("draw", [](PyMesh& self, GL::AbstractShaderProgram& shader) { + self.draw(shader); + }, "Draw the mesh") + /** @todo more */ + ; } }} diff --git a/src/python/magnum/test/test_gl_gl.py b/src/python/magnum/test/test_gl_gl.py index 0d4fc4f..6a27831 100644 --- a/src/python/magnum/test/test_gl_gl.py +++ b/src/python/magnum/test/test_gl_gl.py @@ -23,6 +23,7 @@ # DEALINGS IN THE SOFTWARE. # +import sys import unittest # setUpModule gets called before everything else, skipping if GL tests can't @@ -49,3 +50,27 @@ class DefaultFramebuffer(GLTestCase): def test(self): # Using it should not crash, leak or cause double-free issues self.assertTrue(gl.default_framebuffer is not None) + +class Mesh(GLTestCase): + def test_init(self): + a = gl.Mesh(gl.MeshPrimitive.LINE_LOOP) + self.assertNotEqual(a.id, 0) + self.assertEqual(a.primitive, gl.MeshPrimitive.LINE_LOOP) + + def test_set_count(self): + a = gl.Mesh() + a.count = 15 + self.assertEqual(a.count, 15) + + def test_add_buffer(self): + buffer = gl.Buffer() + buffer_refcount = sys.getrefcount(buffer) + + # Adding a buffer to the mesh should increase its ref count + mesh = gl.Mesh() + mesh.add_vertex_buffer(buffer, 0, 8, gl.Attribute(gl.Attribute.Kind.GENERIC, 2, gl.Attribute.Components.TWO, gl.Attribute.DataType.FLOAT)) + self.assertEqual(sys.getrefcount(buffer), buffer_refcount + 1) + + # Deleting the mesh should decrease it again + del mesh + self.assertEqual(sys.getrefcount(buffer), buffer_refcount)