From fde6102a8deab2e9c71e71d5ca59335d96e4b9a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 31 May 2019 10:59:36 +0200 Subject: [PATCH] python: expose SceneGraph Python wrapping helpers. Those will get used by 3rd party code, so need to be installed. --- package/archlinux/PKGBUILD | 5 + src/CMakeLists.txt | 2 + src/Magnum/CMakeLists.txt | 30 ++++ src/Magnum/SceneGraph/CMakeLists.txt | 30 ++++ src/Magnum/SceneGraph/Python.h | 115 ++++++++++++++++ src/python/magnum/CMakeLists.txt | 4 +- src/python/magnum/scenegraph.cpp | 198 +++++++++------------------ 7 files changed, 246 insertions(+), 138 deletions(-) create mode 100644 src/Magnum/CMakeLists.txt create mode 100644 src/Magnum/SceneGraph/CMakeLists.txt create mode 100644 src/Magnum/SceneGraph/Python.h diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD index ac81d3c..643e338 100644 --- a/package/archlinux/PKGBUILD +++ b/package/archlinux/PKGBUILD @@ -40,6 +40,11 @@ check() { } package() { + # Helper headers + cd "$_rootdir/build" + DESTDIR="$pkgdir/" ninja install + + # Native and python packages cd "$_rootdir/build/src/python" python setup.py install --root="$pkgdir" --prefix=/usr } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d4cfd14..645fe60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,8 @@ set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON) +add_subdirectory(Magnum) + if(WITH_PYTHON) add_subdirectory(python) endif() diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt new file mode 100644 index 0000000..daf72b9 --- /dev/null +++ b/src/Magnum/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 +# 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. +# + +find_package(Magnum COMPONENTS SceneGraph) + +if(Magnum_SceneGraph_FOUND) + add_subdirectory(SceneGraph) +endif() diff --git a/src/Magnum/SceneGraph/CMakeLists.txt b/src/Magnum/SceneGraph/CMakeLists.txt new file mode 100644 index 0000000..26a34b8 --- /dev/null +++ b/src/Magnum/SceneGraph/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# This file is part of Magnum. +# +# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 +# 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. +# + +if(WITH_PYTHON) + add_custom_target(MagnumSceneGraphPython SOURCES Python.h) + set_target_properties(MagnumSceneGraphPython PROPERTIES FOLDER "Magnum/SceneGraph") + install(FILES Python.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/SceneGraph) +endif() diff --git a/src/Magnum/SceneGraph/Python.h b/src/Magnum/SceneGraph/Python.h new file mode 100644 index 0000000..e5cdcbd --- /dev/null +++ b/src/Magnum/SceneGraph/Python.h @@ -0,0 +1,115 @@ +#ifndef Magnum_SceneGraph_Python_h +#define Magnum_SceneGraph_Python_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 + 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 +#include + +namespace Magnum { namespace SceneGraph { + +/* This is a variant of https://github.com/pybind/pybind11/issues/1389. If the + object has a parent, its refcount gets increased in order to avoid it being + deleted by Python too soon. The refcount gets decreased when the parent is + removed again or the parent gets deleted. I thought this would be doable + inside py::init() as + + .def(py::init([](SceneGraph::Scene* parent) { + auto self = new PyObject{parent}; + if(parent) py::cast(self).inc_ref(); + return self; + })) + + but FOR SOME REASON py::cast(self) inside py::init() returns a different + underlying PyObject pointer, so it only leads to crashes. */ + +template struct PyObjectHolder: std::unique_ptr { + explicit PyObjectHolder(T* object): std::unique_ptr{object} { + CORRADE_INTERNAL_ASSERT(object); + if(object->parent()) pybind11::cast(object).inc_ref(); + } +}; + +template struct PyFeatureHolder: std::unique_ptr { + explicit PyFeatureHolder(T* object): std::unique_ptr{object} { + CORRADE_INTERNAL_ASSERT(object); + pybind11::cast(object).inc_ref(); + } +}; + +/* Hey this needs docs. */ + +template class PyObject: public Object { + public: + template explicit PyObject(Args&&... args): Object{std::forward(args)...} {} + + PyObject(const PyObject&) = delete; + PyObject(PyObject&&) = delete; + + PyObject& operator=(const PyObject&) = delete; + PyObject& operator=(PyObject&&) = delete; + + private: + void doErase() override { + /* When deleting a parent, disconnect this from the parent instead + of deleting it. Deletion is then handled by Python itself. */ + CORRADE_INTERNAL_ASSERT(Object::parent()); + Object::setParent(nullptr); + pybind11::cast(this).dec_ref(); + } +}; + +template class PyFeature: public Feature { + public: + template explicit PyFeature(Args&&... args): Feature{std::forward(args)...} {} + + PyFeature(const PyFeature&) = delete; + PyFeature(PyFeature&&) = delete; + + PyFeature& operator=(const PyFeature&) = delete; + PyFeature& operator=(PyFeature&&) = delete; + + private: + void doErase() override { + /* When deleting the holder object, disconnect this from that + object instead of deleting it. This makes it rather useless, but + better than having dangling memory or double deletion. This is + of course not allowed by the C++ API due to private inheritance + so we have to reinterpret self as the list instead. UGLY. */ + auto& listItem = reinterpret_cast, SceneGraph::AbstractObject>&>(*this); + + CORRADE_INTERNAL_ASSERT(listItem.list()); + listItem.list()->features().cut(this); + pybind11::cast(this).dec_ref(); + } +}; + +}} + +PYBIND11_DECLARE_HOLDER_TYPE(T, Magnum::SceneGraph::PyObjectHolder) +PYBIND11_DECLARE_HOLDER_TYPE(T, Magnum::SceneGraph::PyFeatureHolder) + +#endif diff --git a/src/python/magnum/CMakeLists.txt b/src/python/magnum/CMakeLists.txt index 35966f5..1bd5500 100644 --- a/src/python/magnum/CMakeLists.txt +++ b/src/python/magnum/CMakeLists.txt @@ -86,7 +86,9 @@ if(Magnum_SceneGraph_FOUND) scenegraph.cpp) pybind11_add_module(magnum_scenegraph ${magnum_scenegraph_SRCS}) - target_include_directories(magnum_scenegraph PRIVATE ${PROJECT_SOURCE_DIR}/src/python) + target_include_directories(magnum_scenegraph PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/src/python) target_link_libraries(magnum_scenegraph PRIVATE Magnum::SceneGraph) set_target_properties(magnum_scenegraph PROPERTIES FOLDER "python" diff --git a/src/python/magnum/scenegraph.cpp b/src/python/magnum/scenegraph.cpp index 2744649..2bd4152 100644 --- a/src/python/magnum/scenegraph.cpp +++ b/src/python/magnum/scenegraph.cpp @@ -32,61 +32,14 @@ #include #include -#include "magnum/bootstrap.h" - -/* This is a variant of https://github.com/pybind/pybind11/issues/1389. If the - object has a parent, its refcount gets increased in order to avoid it being - deleted by Python too soon. The refcount gets decreased when the parent is - removed again or the parent gets deleted. I thought this would be doable - inside py::init() as - - .def(py::init([](SceneGraph::Scene* parent) { - auto self = new PyObject{parent}; - if(parent) py::cast(self).inc_ref(); - return self; - })) - - but FOR SOME REASON py::cast(self) inside py::init() returns a different - underlying PyObject pointer, so it only leads to crashes. */ -namespace magnum { namespace { - -template struct SceneGraphObjectHolder: std::unique_ptr { - explicit SceneGraphObjectHolder(T* object): std::unique_ptr{object} { - CORRADE_INTERNAL_ASSERT(object); - if(object->parent()) py::cast(object).inc_ref(); - } -}; - -template struct SceneGraphFeatureHolder: std::unique_ptr { - explicit SceneGraphFeatureHolder(T* object): std::unique_ptr{object} { - CORRADE_INTERNAL_ASSERT(object); - py::cast(object).inc_ref(); - } -}; - -}} +#include "Magnum/SceneGraph/Python.h" -PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphObjectHolder) -PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphFeatureHolder) +#include "magnum/bootstrap.h" namespace magnum { namespace { -template class PyObject: public SceneGraph::Object { - public: - PyObject(SceneGraph::Object* parent): SceneGraph::Object{parent} {} - - private: - void doErase() override { - /* When deleting a parent, disconnect this from the parent instead - of deleting it. Deletion is then handled by Python itself. */ - CORRADE_INTERNAL_ASSERT(SceneGraph::Object::parent()); - SceneGraph::Object::setParent(nullptr); - py::cast(this).dec_ref(); - } -}; - -template struct PyDrawable: SceneGraph::Drawable { - explicit PyDrawable(SceneGraph::AbstractObject& object, SceneGraph::DrawableGroup* drawables): SceneGraph::Drawable{object, drawables} {} +template struct PyDrawable: SceneGraph::PyFeature> { + explicit PyDrawable(SceneGraph::AbstractObject& object, SceneGraph::DrawableGroup* drawables): SceneGraph::PyFeature>{object, drawables} {} void draw(const MatrixTypeFor& transformationMatrix, SceneGraph::Camera& camera) override { PYBIND11_OVERLOAD_PURE_NAME( @@ -98,43 +51,13 @@ template struct PyDrawable: SceneGraph::Drawabl camera ); } - - void doErase() override { - /* When deleting the holder object, disconnect this from that - object instead of deleting it. This makes it rather useless, but - better than having dangling memory or double deletion. This is of - course not allowed by the C++ API due to private inheritance so we - have to reinterpret self as the list instead. UGLY: */ - auto& listItem = reinterpret_cast, SceneGraph::AbstractObject>&>(*this); - - CORRADE_INTERNAL_ASSERT(listItem.list()); - listItem.list()->features().cut(this); - py::cast(this).dec_ref(); - } -}; - -template struct PyCamera: SceneGraph::Camera { - explicit PyCamera(SceneGraph::AbstractObject& object): SceneGraph::Camera{object} {} - - void doErase() override { - /* When deleting the holder object, disconnect this from that - object instead of deleting it. This makes it rather useless, but - better than having dangling memory or double deletion. This is of - course not allowed by the C++ API due to private inheritance so we - have to reinterpret self as the list instead. UGLY: */ - auto& listItem = reinterpret_cast, SceneGraph::AbstractObject>&>(*this); - - CORRADE_INTERNAL_ASSERT(listItem.list()); - listItem.list()->features().cut(this); - py::cast(this).dec_ref(); - } }; template void scene(py::class_>& c) { c.def(py::init(), "Constructor"); } -template void abstractObject(py::class_, SceneGraphObjectHolder>>& c) { +template void abstractObject(py::class_, SceneGraph::PyObjectHolder>>& c) { c /* Matrix transformation APIs */ .def("transformation_matrix", &SceneGraph::AbstractObject::transformationMatrix, @@ -143,23 +66,23 @@ template void abstractObject(py::class_ void object(py::class_, SceneGraph::AbstractObject, SceneGraphObjectHolder>>& c) { +template void object(py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject, SceneGraph::PyObjectHolder>>& c) { c - .def(py::init*>(), + .def(py::init_alias>*>(), "Constructor", py::arg("parent") = nullptr) - .def(py::init*>(), + .def(py::init_alias*>(), "Constructor", py::arg("parent") = nullptr) /* Properties */ - .def_property_readonly("scene", [](PyObject& self) { + .def_property_readonly("scene", [](SceneGraph::PyObject>& self) { return static_cast*>(self.scene()); }, "Scene or None if the object is not a part of any scene") - .def_property("parent", [](PyObject& self) { - return static_cast*>(self.parent()); - }, [](PyObject& self, py::object parentobj) { + .def_property("parent", [](SceneGraph::PyObject>& self) { + return static_cast>*>(self.parent()); + }, [](SceneGraph::PyObject>& self, py::object parentobj) { SceneGraph::Object* parent; - if(py::isinstance>(parentobj)) - parent = py::cast*>(parentobj); + if(py::isinstance>>(parentobj)) + parent = py::cast>*>(parentobj); else if(py::isinstance>(parentobj)) parent = py::cast*>(parentobj); else if(py::isinstance(parentobj)) @@ -176,78 +99,78 @@ template void object(py:: /* Transformation APIs common to all implementations */ .def_property("transformation", - &PyObject::transformation, - &PyObject::setTransformation, + &SceneGraph::PyObject>::transformation, + &SceneGraph::PyObject>::setTransformation, "Object transformation") - .def("absolute_transformation", &PyObject::absoluteTransformation, + .def("absolute_transformation", &SceneGraph::PyObject>::absoluteTransformation, "Transformation relative to the root object") - .def("reset_transformation", [](PyObject& self) { + .def("reset_transformation", [](SceneGraph::PyObject>& self) { self.resetTransformation(); }, "Reset the transformation") - .def("transform", [](PyObject& self, const typename Transformation::DataType& transformation) { + .def("transform", [](SceneGraph::PyObject>& self, const typename Transformation::DataType& transformation) { self.transform(transformation); }, "Transform the object") - .def("transform_local", [](PyObject& self, const typename Transformation::DataType& transformation) { + .def("transform_local", [](SceneGraph::PyObject>& self, const typename Transformation::DataType& transformation) { self.transformLocal(transformation); }, "Transform the object as a local transformation") - .def("translate", [](PyObject& self, const VectorTypeFor& vector) { + .def("translate", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.translate(vector); }, "Translate the object") - .def("translate_local", [](PyObject& self, const VectorTypeFor& vector) { + .def("translate_local", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.translateLocal(vector); }, "Translate the object as a local transformation"); } -template void object2D(py::class_, SceneGraph::AbstractObject, SceneGraphObjectHolder>>& c) { +template void object2D(py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject, SceneGraph::PyObjectHolder>>& c) { c - .def("rotate", [](PyObject& self, const Radd angle) { + .def("rotate", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotate(static_cast>(angle)); }, "Rotate the object") - .def("rotate_local", [](PyObject& self, const Radd angle) { + .def("rotate_local", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateLocal(static_cast>(angle)); }, "Rotate the object as a local transformation"); } -template void object3D(py::class_, SceneGraph::AbstractObject, SceneGraphObjectHolder>>& c) { +template void object3D(py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject, SceneGraph::PyObjectHolder>>& c) { c - .def("rotate", [](PyObject& self, const Radd angle, const Math::Vector3& normalizedAxis) { + .def("rotate", [](SceneGraph::PyObject>& self, const Radd angle, const Math::Vector3& normalizedAxis) { self.rotate(static_cast>(angle), normalizedAxis); }, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis")) - .def("rotate_local", [](PyObject& self, const Radd angle, const Math::Vector3& normalizedAxis) { + .def("rotate_local", [](SceneGraph::PyObject>& self, const Radd angle, const Math::Vector3& normalizedAxis) { self.rotateLocal(static_cast>(angle), normalizedAxis); }, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis")) - .def("rotate_x", [](PyObject& self, const Radd angle) { + .def("rotate_x", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateX(static_cast>(angle)); }, "Rotate the object around X axis") - .def("rotate_x_local", [](PyObject& self, const Radd angle) { + .def("rotate_x_local", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateXLocal(static_cast>(angle)); }, "Rotate the object around X axis as a local transformation") - .def("rotate_y", [](PyObject& self, const Radd angle) { + .def("rotate_y", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateY(static_cast>(angle)); }, "Rotate the object around Y axis") - .def("rotate_y_local", [](PyObject& self, const Radd angle) { + .def("rotate_y_local", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateYLocal(static_cast>(angle)); }, "Rotate the object around Y axis as a local transformation") - .def("rotate_z", [](PyObject& self, const Radd angle) { + .def("rotate_z", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateZ(static_cast>(angle)); }, "Rotate the object around Z axis") - .def("rotate_z_local", [](PyObject& self, const Radd angle) { + .def("rotate_z_local", [](SceneGraph::PyObject>& self, const Radd angle) { self.rotateZLocal(static_cast>(angle)); }, "Rotate the object around Z axis as a local transformation"); } -template void objectScale(py::class_, SceneGraph::AbstractObject, SceneGraphObjectHolder>>& c) { +template void objectScale(py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject, SceneGraph::PyObjectHolder>>& c) { c - .def("scale", [](PyObject& self, const VectorTypeFor& vector) { + .def("scale", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.scale(vector); }, "Scale the object") - .def("scale_local", [](PyObject& self, const VectorTypeFor& vector) { + .def("scale_local", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.scaleLocal(vector); }, "Scale the object as a local transformation") - .def("reflect", [](PyObject& self, const VectorTypeFor& vector) { + .def("reflect", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.reflect(vector); }, "Reflect the object") - .def("reflect_local", [](PyObject& self, const VectorTypeFor& vector) { + .def("reflect_local", [](SceneGraph::PyObject>& self, const VectorTypeFor& vector) { self.reflectLocal(vector); }, "Reflect the object as a local transformation"); } @@ -272,39 +195,39 @@ template void f }, "Remove a feature from the group"); } -template void feature(py::class_>& c) { +template void feature(py::class_, SceneGraph::PyFeatureHolder>>& c) { c - .def_property_readonly("object", [](Feature& self) -> SceneGraph::AbstractObject& { + .def_property_readonly("object", [](SceneGraph::AbstractFeature& self) -> SceneGraph::AbstractObject& { return self.object(); }, "Object holding this feature"); } -template void drawable(py::class_, SceneGraphFeatureHolder>>& c) { +template void drawable(py::class_, SceneGraph::AbstractFeature, PyDrawable, SceneGraph::PyFeatureHolder>>& c) { c - .def(py::init&, SceneGraph::DrawableGroup*>(), + .def(py::init_alias&, SceneGraph::DrawableGroup*>(), "Constructor", py::arg("object"), py::arg("drawables") = nullptr) .def_property_readonly("drawables", [](PyDrawable& self) { return self.drawables(); }, "Group containing this drawable") - .def("draw", [](PyDrawable& self, const MatrixTypeFor& transformationMatrix, PyCamera& camera) { + .def("draw", [](PyDrawable& self, const MatrixTypeFor& transformationMatrix, SceneGraph::Camera& camera) { self.draw(transformationMatrix, camera); }, "Draw the object using given camera", py::arg("transformation_matrix"), py::arg("camera")); } -template void camera(py::class_, SceneGraphFeatureHolder>>& c) { +template void camera(py::class_, SceneGraph::AbstractFeature, SceneGraph::PyFeature>, SceneGraph::PyFeatureHolder>>& c) { c - .def(py::init&>(), + .def(py::init_alias&>(), "Constructor", py::arg("object")) .def_property("aspect_ratio_policy", &SceneGraph::Camera::aspectRatioPolicy, /* Using a lambda because the setter has method chaining */ - [](PyCamera& self, SceneGraph::AspectRatioPolicy policy) { + [](SceneGraph::Camera& self, SceneGraph::AspectRatioPolicy policy) { self.setAspectRatioPolicy(policy); }, "Aspect ratio policy") .def_property_readonly("camera_matrix", &SceneGraph::Camera::cameraMatrix, "Camera matrix") .def_property("projection_matrix", &SceneGraph::Camera::projectionMatrix, /* Using a lambda because the setter has method chaining */ - [](PyCamera& self, const MatrixTypeFor& matrix) { + [](SceneGraph::Camera& self, const MatrixTypeFor& matrix) { self.setProjectionMatrix(matrix); }, "Projection matrix") .def("projection_size", &SceneGraph::Camera::projectionSize, @@ -320,8 +243,8 @@ void scenegraph(py::module& m) { /* Abstract objects. Returned from feature.object, so need to be registered as well. */ { - py::class_> abstractObject2D{m, "AbstractObject2D", "Base object for two-dimensional scenes"}; - py::class_> abstractObject3D{m, "AbstractObject3D", "Base object for three-dimensional scenes"}; + py::class_> abstractObject2D{m, "AbstractObject2D", "Base object for two-dimensional scenes"}; + py::class_> abstractObject3D{m, "AbstractObject3D", "Base object for three-dimensional scenes"}; abstractObject(abstractObject2D); abstractObject(abstractObject3D); } @@ -337,12 +260,12 @@ void scenegraph(py::module& m) { py::class_> scene3D_{matrix, "Scene3D", "Three-dimensional scene with matrix-based transformation implementation"}; scene(scene3D_); - py::class_, SceneGraph::AbstractObject2D, SceneGraphObjectHolder>> object2D_{matrix, "Object2D", "Two-dimensional object with matrix-based transformation implementation"}; + py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject2D, SceneGraph::PyObjectHolder>> object2D_{matrix, "Object2D", "Two-dimensional object with matrix-based transformation implementation"}; object(object2D_); object2D(object2D_); objectScale(object2D_); - py::class_, SceneGraph::AbstractObject3D, SceneGraphObjectHolder>> object3D_{matrix, "Object3D", "Three-dimensional object with matrix-based transformation implementation"}; + py::class_, SceneGraph::PyObject>, SceneGraph::AbstractObject3D, SceneGraph::PyObjectHolder>> object3D_{matrix, "Object3D", "Three-dimensional object with matrix-based transformation implementation"}; object(object3D_); object3D(object3D_); objectScale(object3D_); @@ -358,21 +281,22 @@ void scenegraph(py::module& m) { py::class_ drawableGroup2D{m, "DrawableGroup2D", "Group of drawables for two-dimensional float scenes"}; py::class_ drawableGroup3D{m, "DrawableGroup3D", "Group of drawables for three-dimensional float scenes"}; - py::class_, SceneGraphFeatureHolder>> drawable2D{m, "Drawable2D", "Drawable for two-dimensional float scenes"}; - py::class_, SceneGraphFeatureHolder>> drawable3D{m, "Drawable3D", "Drawable for three-dimensional float scenes"}; + py::class_> feature2D{m, "AbstractFeature2D", "Base for two-dimensional float features"}; + py::class_> feature3D{m, "AbstractFeature3D", "Base for three-dimensional float features"}; + feature(feature2D); + feature(feature3D); + + py::class_, SceneGraph::PyFeatureHolder> drawable2D{m, "Drawable2D", "Drawable for two-dimensional float scenes"}; + py::class_, SceneGraph::PyFeatureHolder> drawable3D{m, "Drawable3D", "Drawable for three-dimensional float scenes"}; - py::class_, SceneGraphFeatureHolder>> camera2D{m, "Camera2D", "Camera for two-dimensional float scenes"}; - py::class_, SceneGraphFeatureHolder>> camera3D{m, "Camera3D", "Camera for three-dimensional float scenes"}; + py::class_, SceneGraph::PyFeatureHolder> camera2D{m, "Camera2D", "Camera for two-dimensional float scenes"}; + py::class_, SceneGraph::PyFeatureHolder> camera3D{m, "Camera3D", "Camera for three-dimensional float scenes"}; featureGroup>(drawableGroup2D); featureGroup>(drawableGroup3D); - feature<2, Float>(drawable2D); - feature<3, Float>(drawable3D); drawable(drawable2D); drawable(drawable3D); - feature<2, Float>(camera2D); - feature<3, Float>(camera3D); camera(camera2D); camera(camera3D); }