Browse Source

python: expose SceneGraph Python wrapping helpers.

Those will get used by 3rd party code, so need to be installed.
pull/2/head
Vladimír Vondruš 7 years ago
parent
commit
fde6102a8d
  1. 5
      package/archlinux/PKGBUILD
  2. 2
      src/CMakeLists.txt
  3. 30
      src/Magnum/CMakeLists.txt
  4. 30
      src/Magnum/SceneGraph/CMakeLists.txt
  5. 115
      src/Magnum/SceneGraph/Python.h
  6. 4
      src/python/magnum/CMakeLists.txt
  7. 198
      src/python/magnum/scenegraph.cpp

5
package/archlinux/PKGBUILD

@ -40,6 +40,11 @@ check() {
} }
package() { package() {
# Helper headers
cd "$_rootdir/build"
DESTDIR="$pkgdir/" ninja install
# Native and python packages
cd "$_rootdir/build/src/python" cd "$_rootdir/build/src/python"
python setup.py install --root="$pkgdir" --prefix=/usr python setup.py install --root="$pkgdir" --prefix=/usr
} }

2
src/CMakeLists.txt

@ -25,6 +25,8 @@
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON) set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
add_subdirectory(Magnum)
if(WITH_PYTHON) if(WITH_PYTHON)
add_subdirectory(python) add_subdirectory(python)
endif() endif()

30
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š <mosra@centrum.cz>
#
# 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()

30
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š <mosra@centrum.cz>
#
# 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()

115
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š <mosra@centrum.cz>
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 <memory> /* :( */
#include <pybind11/pybind11.h>
#include <Corrade/Utility/Assert.h>
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<Transformation>* parent) {
auto self = new PyObject<Transformation>{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<class T> struct PyObjectHolder: std::unique_ptr<T> {
explicit PyObjectHolder(T* object): std::unique_ptr<T>{object} {
CORRADE_INTERNAL_ASSERT(object);
if(object->parent()) pybind11::cast(object).inc_ref();
}
};
template<class T> struct PyFeatureHolder: std::unique_ptr<T> {
explicit PyFeatureHolder(T* object): std::unique_ptr<T>{object} {
CORRADE_INTERNAL_ASSERT(object);
pybind11::cast(object).inc_ref();
}
};
/* Hey this needs docs. */
template<class Object> class PyObject: public Object {
public:
template<class ...Args> explicit PyObject(Args&&... args): Object{std::forward<Args>(args)...} {}
PyObject(const PyObject<Object>&) = delete;
PyObject(PyObject<Object>&&) = delete;
PyObject<Object>& operator=(const PyObject<Object>&) = delete;
PyObject<Object>& operator=(PyObject<Object>&&) = 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 Feature> class PyFeature: public Feature {
public:
template<class ...Args> explicit PyFeature(Args&&... args): Feature{std::forward<Args>(args)...} {}
PyFeature(const PyFeature<Feature>&) = delete;
PyFeature(PyFeature<Feature>&&) = delete;
PyFeature<Feature>& operator=(const PyFeature<Feature>&) = delete;
PyFeature<Feature>& operator=(PyFeature<Feature>&&) = 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<Containers::LinkedListItem<SceneGraph::AbstractFeature<Feature::Dimensions, typename Feature::Type>, SceneGraph::AbstractObject<Feature::Dimensions, typename Feature::Type>>&>(*this);
CORRADE_INTERNAL_ASSERT(listItem.list());
listItem.list()->features().cut(this);
pybind11::cast(this).dec_ref();
}
};
}}
PYBIND11_DECLARE_HOLDER_TYPE(T, Magnum::SceneGraph::PyObjectHolder<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, Magnum::SceneGraph::PyFeatureHolder<T>)
#endif

4
src/python/magnum/CMakeLists.txt

@ -86,7 +86,9 @@ if(Magnum_SceneGraph_FOUND)
scenegraph.cpp) scenegraph.cpp)
pybind11_add_module(magnum_scenegraph ${magnum_scenegraph_SRCS}) 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) target_link_libraries(magnum_scenegraph PRIVATE Magnum::SceneGraph)
set_target_properties(magnum_scenegraph PROPERTIES set_target_properties(magnum_scenegraph PROPERTIES
FOLDER "python" FOLDER "python"

198
src/python/magnum/scenegraph.cpp

@ -32,61 +32,14 @@
#include <Magnum/SceneGraph/MatrixTransformation2D.h> #include <Magnum/SceneGraph/MatrixTransformation2D.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h> #include <Magnum/SceneGraph/MatrixTransformation3D.h>
#include "magnum/bootstrap.h" #include "Magnum/SceneGraph/Python.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<Transformation>* parent) {
auto self = new PyObject<Transformation>{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<class T> struct SceneGraphObjectHolder: std::unique_ptr<T> {
explicit SceneGraphObjectHolder(T* object): std::unique_ptr<T>{object} {
CORRADE_INTERNAL_ASSERT(object);
if(object->parent()) py::cast(object).inc_ref();
}
};
template<class T> struct SceneGraphFeatureHolder: std::unique_ptr<T> {
explicit SceneGraphFeatureHolder(T* object): std::unique_ptr<T>{object} {
CORRADE_INTERNAL_ASSERT(object);
py::cast(object).inc_ref();
}
};
}}
PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphObjectHolder<T>) #include "magnum/bootstrap.h"
PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphFeatureHolder<T>)
namespace magnum { namespace { namespace magnum { namespace {
template<class Transformation> class PyObject: public SceneGraph::Object<Transformation> { template<UnsignedInt dimensions, class T> struct PyDrawable: SceneGraph::PyFeature<SceneGraph::Drawable<dimensions, T>> {
public: explicit PyDrawable(SceneGraph::AbstractObject<dimensions, T>& object, SceneGraph::DrawableGroup<dimensions, T>* drawables): SceneGraph::PyFeature<SceneGraph::Drawable<dimensions, T>>{object, drawables} {}
PyObject(SceneGraph::Object<Transformation>* parent): SceneGraph::Object<Transformation>{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<Transformation>::parent());
SceneGraph::Object<Transformation>::setParent(nullptr);
py::cast(this).dec_ref();
}
};
template<UnsignedInt dimensions, class T> struct PyDrawable: SceneGraph::Drawable<dimensions, T> {
explicit PyDrawable(SceneGraph::AbstractObject<dimensions, T>& object, SceneGraph::DrawableGroup<dimensions, T>* drawables): SceneGraph::Drawable<dimensions, T>{object, drawables} {}
void draw(const MatrixTypeFor<dimensions, T>& transformationMatrix, SceneGraph::Camera<dimensions, T>& camera) override { void draw(const MatrixTypeFor<dimensions, T>& transformationMatrix, SceneGraph::Camera<dimensions, T>& camera) override {
PYBIND11_OVERLOAD_PURE_NAME( PYBIND11_OVERLOAD_PURE_NAME(
@ -98,43 +51,13 @@ template<UnsignedInt dimensions, class T> struct PyDrawable: SceneGraph::Drawabl
camera 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<Containers::LinkedListItem<SceneGraph::AbstractFeature<dimensions, T>, SceneGraph::AbstractObject<dimensions, T>>&>(*this);
CORRADE_INTERNAL_ASSERT(listItem.list());
listItem.list()->features().cut(this);
py::cast(this).dec_ref();
}
};
template<UnsignedInt dimensions, class T> struct PyCamera: SceneGraph::Camera<dimensions, T> {
explicit PyCamera(SceneGraph::AbstractObject<dimensions, T>& object): SceneGraph::Camera<dimensions, T>{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<Containers::LinkedListItem<SceneGraph::AbstractFeature<dimensions, T>, SceneGraph::AbstractObject<dimensions, T>>&>(*this);
CORRADE_INTERNAL_ASSERT(listItem.list());
listItem.list()->features().cut(this);
py::cast(this).dec_ref();
}
}; };
template<class Transformation> void scene(py::class_<SceneGraph::Scene<Transformation>>& c) { template<class Transformation> void scene(py::class_<SceneGraph::Scene<Transformation>>& c) {
c.def(py::init(), "Constructor"); c.def(py::init(), "Constructor");
} }
template<UnsignedInt dimensions, class T> void abstractObject(py::class_<SceneGraph::AbstractObject<dimensions, T>, SceneGraphObjectHolder<SceneGraph::AbstractObject<dimensions, T>>>& c) { template<UnsignedInt dimensions, class T> void abstractObject(py::class_<SceneGraph::AbstractObject<dimensions, T>, SceneGraph::PyObjectHolder<SceneGraph::AbstractObject<dimensions, T>>>& c) {
c c
/* Matrix transformation APIs */ /* Matrix transformation APIs */
.def("transformation_matrix", &SceneGraph::AbstractObject<dimensions, T>::transformationMatrix, .def("transformation_matrix", &SceneGraph::AbstractObject<dimensions, T>::transformationMatrix,
@ -143,23 +66,23 @@ template<UnsignedInt dimensions, class T> void abstractObject(py::class_<SceneGr
"Transformation matrix relative to the root object"); "Transformation matrix relative to the root object");
} }
template<UnsignedInt dimensions, class T, class Transformation> void object(py::class_<PyObject<Transformation>, SceneGraph::AbstractObject<dimensions, T>, SceneGraphObjectHolder<PyObject<Transformation>>>& c) { template<UnsignedInt dimensions, class T, class Transformation> void object(py::class_<SceneGraph::Object<Transformation>, SceneGraph::PyObject<SceneGraph::Object<Transformation>>, SceneGraph::AbstractObject<dimensions, T>, SceneGraph::PyObjectHolder<SceneGraph::Object<Transformation>>>& c) {
c c
.def(py::init<PyObject<Transformation>*>(), .def(py::init_alias<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(),
"Constructor", py::arg("parent") = nullptr) "Constructor", py::arg("parent") = nullptr)
.def(py::init<SceneGraph::Scene<Transformation>*>(), .def(py::init_alias<SceneGraph::Scene<Transformation>*>(),
"Constructor", py::arg("parent") = nullptr) "Constructor", py::arg("parent") = nullptr)
/* Properties */ /* Properties */
.def_property_readonly("scene", [](PyObject<Transformation>& self) { .def_property_readonly("scene", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self) {
return static_cast<SceneGraph::Scene<Transformation>*>(self.scene()); return static_cast<SceneGraph::Scene<Transformation>*>(self.scene());
}, "Scene or None if the object is not a part of any scene") }, "Scene or None if the object is not a part of any scene")
.def_property("parent", [](PyObject<Transformation>& self) { .def_property("parent", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self) {
return static_cast<PyObject<Transformation>*>(self.parent()); return static_cast<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(self.parent());
}, [](PyObject<Transformation>& self, py::object parentobj) { }, [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, py::object parentobj) {
SceneGraph::Object<Transformation>* parent; SceneGraph::Object<Transformation>* parent;
if(py::isinstance<PyObject<Transformation>>(parentobj)) if(py::isinstance<SceneGraph::PyObject<SceneGraph::Object<Transformation>>>(parentobj))
parent = py::cast<PyObject<Transformation>*>(parentobj); parent = py::cast<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(parentobj);
else if(py::isinstance<SceneGraph::Scene<Transformation>>(parentobj)) else if(py::isinstance<SceneGraph::Scene<Transformation>>(parentobj))
parent = py::cast<SceneGraph::Scene<Transformation>*>(parentobj); parent = py::cast<SceneGraph::Scene<Transformation>*>(parentobj);
else if(py::isinstance<py::none>(parentobj)) else if(py::isinstance<py::none>(parentobj))
@ -176,78 +99,78 @@ template<UnsignedInt dimensions, class T, class Transformation> void object(py::
/* Transformation APIs common to all implementations */ /* Transformation APIs common to all implementations */
.def_property("transformation", .def_property("transformation",
&PyObject<Transformation>::transformation, &SceneGraph::PyObject<SceneGraph::Object<Transformation>>::transformation,
&PyObject<Transformation>::setTransformation, &SceneGraph::PyObject<SceneGraph::Object<Transformation>>::setTransformation,
"Object transformation") "Object transformation")
.def("absolute_transformation", &PyObject<Transformation>::absoluteTransformation, .def("absolute_transformation", &SceneGraph::PyObject<SceneGraph::Object<Transformation>>::absoluteTransformation,
"Transformation relative to the root object") "Transformation relative to the root object")
.def("reset_transformation", [](PyObject<Transformation>& self) { .def("reset_transformation", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self) {
self.resetTransformation(); self.resetTransformation();
}, "Reset the transformation") }, "Reset the transformation")
.def("transform", [](PyObject<Transformation>& self, const typename Transformation::DataType& transformation) { .def("transform", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const typename Transformation::DataType& transformation) {
self.transform(transformation); self.transform(transformation);
}, "Transform the object") }, "Transform the object")
.def("transform_local", [](PyObject<Transformation>& self, const typename Transformation::DataType& transformation) { .def("transform_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const typename Transformation::DataType& transformation) {
self.transformLocal(transformation); self.transformLocal(transformation);
}, "Transform the object as a local transformation") }, "Transform the object as a local transformation")
.def("translate", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("translate", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.translate(vector); self.translate(vector);
}, "Translate the object") }, "Translate the object")
.def("translate_local", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("translate_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.translateLocal(vector); self.translateLocal(vector);
}, "Translate the object as a local transformation"); }, "Translate the object as a local transformation");
} }
template<UnsignedInt dimensions, class T, class Transformation> void object2D(py::class_<PyObject<Transformation>, SceneGraph::AbstractObject<dimensions, T>, SceneGraphObjectHolder<PyObject<Transformation>>>& c) { template<UnsignedInt dimensions, class T, class Transformation> void object2D(py::class_<SceneGraph::Object<Transformation>, SceneGraph::PyObject<SceneGraph::Object<Transformation>>, SceneGraph::AbstractObject<dimensions, T>, SceneGraph::PyObjectHolder<SceneGraph::Object<Transformation>>>& c) {
c c
.def("rotate", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotate(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotate(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object") }, "Rotate the object")
.def("rotate_local", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object as a local transformation"); }, "Rotate the object as a local transformation");
} }
template<UnsignedInt dimensions, class T, class Transformation> void object3D(py::class_<PyObject<Transformation>, SceneGraph::AbstractObject<dimensions, T>, SceneGraphObjectHolder<PyObject<Transformation>>>& c) { template<UnsignedInt dimensions, class T, class Transformation> void object3D(py::class_<SceneGraph::Object<Transformation>, SceneGraph::PyObject<SceneGraph::Object<Transformation>>, SceneGraph::AbstractObject<dimensions, T>, SceneGraph::PyObjectHolder<SceneGraph::Object<Transformation>>>& c) {
c c
.def("rotate", [](PyObject<Transformation>& self, const Radd angle, const Math::Vector3<typename Transformation::DataType::Type>& normalizedAxis) { .def("rotate", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle, const Math::Vector3<typename Transformation::DataType::Type>& normalizedAxis) {
self.rotate(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle), normalizedAxis); self.rotate(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle), normalizedAxis);
}, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis")) }, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis"))
.def("rotate_local", [](PyObject<Transformation>& self, const Radd angle, const Math::Vector3<typename Transformation::DataType::Type>& normalizedAxis) { .def("rotate_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle, const Math::Vector3<typename Transformation::DataType::Type>& normalizedAxis) {
self.rotateLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle), normalizedAxis); self.rotateLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle), normalizedAxis);
}, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis")) }, "Rotate the object as a local transformation", py::arg("angle"), py::arg("normalized_axis"))
.def("rotate_x", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_x", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateX(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateX(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around X axis") }, "Rotate the object around X axis")
.def("rotate_x_local", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_x_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateXLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateXLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around X axis as a local transformation") }, "Rotate the object around X axis as a local transformation")
.def("rotate_y", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_y", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateY(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateY(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around Y axis") }, "Rotate the object around Y axis")
.def("rotate_y_local", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_y_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateYLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateYLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around Y axis as a local transformation") }, "Rotate the object around Y axis as a local transformation")
.def("rotate_z", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_z", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateZ(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateZ(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around Z axis") }, "Rotate the object around Z axis")
.def("rotate_z_local", [](PyObject<Transformation>& self, const Radd angle) { .def("rotate_z_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const Radd angle) {
self.rotateZLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle)); self.rotateZLocal(static_cast<Math::Rad<typename Transformation::DataType::Type>>(angle));
}, "Rotate the object around Z axis as a local transformation"); }, "Rotate the object around Z axis as a local transformation");
} }
template<UnsignedInt dimensions, class T, class Transformation> void objectScale(py::class_<PyObject<Transformation>, SceneGraph::AbstractObject<dimensions, T>, SceneGraphObjectHolder<PyObject<Transformation>>>& c) { template<UnsignedInt dimensions, class T, class Transformation> void objectScale(py::class_<SceneGraph::Object<Transformation>, SceneGraph::PyObject<SceneGraph::Object<Transformation>>, SceneGraph::AbstractObject<dimensions, T>, SceneGraph::PyObjectHolder<SceneGraph::Object<Transformation>>>& c) {
c c
.def("scale", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("scale", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.scale(vector); self.scale(vector);
}, "Scale the object") }, "Scale the object")
.def("scale_local", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("scale_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.scaleLocal(vector); self.scaleLocal(vector);
}, "Scale the object as a local transformation") }, "Scale the object as a local transformation")
.def("reflect", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("reflect", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.reflect(vector); self.reflect(vector);
}, "Reflect the object") }, "Reflect the object")
.def("reflect_local", [](PyObject<Transformation>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) { .def("reflect_local", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, const VectorTypeFor<dimensions, typename Transformation::DataType::Type>& vector) {
self.reflectLocal(vector); self.reflectLocal(vector);
}, "Reflect the object as a local transformation"); }, "Reflect the object as a local transformation");
} }
@ -272,39 +195,39 @@ template<class PyFeature, UnsignedInt dimensions, class Feature, class T> void f
}, "Remove a feature from the group"); }, "Remove a feature from the group");
} }
template<UnsignedInt dimensions, class T, class Feature> void feature(py::class_<Feature, SceneGraphFeatureHolder<Feature>>& c) { template<UnsignedInt dimensions, class T> void feature(py::class_<SceneGraph::AbstractFeature<dimensions, T>, SceneGraph::PyFeatureHolder<SceneGraph::AbstractFeature<dimensions, T>>>& c) {
c c
.def_property_readonly("object", [](Feature& self) -> SceneGraph::AbstractObject<dimensions, T>& { .def_property_readonly("object", [](SceneGraph::AbstractFeature<dimensions, T>& self) -> SceneGraph::AbstractObject<dimensions, T>& {
return self.object(); return self.object();
}, "Object holding this feature"); }, "Object holding this feature");
} }
template<UnsignedInt dimensions, class T> void drawable(py::class_<PyDrawable<dimensions, T>, SceneGraphFeatureHolder<PyDrawable<dimensions, T>>>& c) { template<UnsignedInt dimensions, class T> void drawable(py::class_<SceneGraph::Drawable<dimensions, T>, SceneGraph::AbstractFeature<dimensions, T>, PyDrawable<dimensions, T>, SceneGraph::PyFeatureHolder<SceneGraph::Drawable<dimensions, T>>>& c) {
c c
.def(py::init<SceneGraph::AbstractObject<dimensions, T>&, SceneGraph::DrawableGroup<dimensions, T>*>(), .def(py::init_alias<SceneGraph::AbstractObject<dimensions, T>&, SceneGraph::DrawableGroup<dimensions, T>*>(),
"Constructor", py::arg("object"), py::arg("drawables") = nullptr) "Constructor", py::arg("object"), py::arg("drawables") = nullptr)
.def_property_readonly("drawables", [](PyDrawable<dimensions, T>& self) { .def_property_readonly("drawables", [](PyDrawable<dimensions, T>& self) {
return self.drawables(); return self.drawables();
}, "Group containing this drawable") }, "Group containing this drawable")
.def("draw", [](PyDrawable<dimensions, T>& self, const MatrixTypeFor<dimensions, T>& transformationMatrix, PyCamera<dimensions, T>& camera) { .def("draw", [](PyDrawable<dimensions, T>& self, const MatrixTypeFor<dimensions, T>& transformationMatrix, SceneGraph::Camera<dimensions, T>& camera) {
self.draw(transformationMatrix, camera); self.draw(transformationMatrix, camera);
}, "Draw the object using given camera", py::arg("transformation_matrix"), py::arg("camera")); }, "Draw the object using given camera", py::arg("transformation_matrix"), py::arg("camera"));
} }
template<UnsignedInt dimensions, class T> void camera(py::class_<PyCamera<dimensions, T>, SceneGraphFeatureHolder<PyCamera<dimensions, T>>>& c) { template<UnsignedInt dimensions, class T> void camera(py::class_<SceneGraph::Camera<dimensions, T>, SceneGraph::AbstractFeature<dimensions, T>, SceneGraph::PyFeature<SceneGraph::Camera<dimensions, T>>, SceneGraph::PyFeatureHolder<SceneGraph::Camera<dimensions, T>>>& c) {
c c
.def(py::init<SceneGraph::AbstractObject<dimensions, T>&>(), .def(py::init_alias<SceneGraph::AbstractObject<dimensions, T>&>(),
"Constructor", py::arg("object")) "Constructor", py::arg("object"))
.def_property("aspect_ratio_policy", &SceneGraph::Camera<dimensions, T>::aspectRatioPolicy, .def_property("aspect_ratio_policy", &SceneGraph::Camera<dimensions, T>::aspectRatioPolicy,
/* Using a lambda because the setter has method chaining */ /* Using a lambda because the setter has method chaining */
[](PyCamera<dimensions, T>& self, SceneGraph::AspectRatioPolicy policy) { [](SceneGraph::Camera<dimensions, T>& self, SceneGraph::AspectRatioPolicy policy) {
self.setAspectRatioPolicy(policy); self.setAspectRatioPolicy(policy);
}, "Aspect ratio policy") }, "Aspect ratio policy")
.def_property_readonly("camera_matrix", &SceneGraph::Camera<dimensions, T>::cameraMatrix, .def_property_readonly("camera_matrix", &SceneGraph::Camera<dimensions, T>::cameraMatrix,
"Camera matrix") "Camera matrix")
.def_property("projection_matrix", &SceneGraph::Camera<dimensions, T>::projectionMatrix, .def_property("projection_matrix", &SceneGraph::Camera<dimensions, T>::projectionMatrix,
/* Using a lambda because the setter has method chaining */ /* Using a lambda because the setter has method chaining */
[](PyCamera<dimensions, T>& self, const MatrixTypeFor<dimensions, T>& matrix) { [](SceneGraph::Camera<dimensions, T>& self, const MatrixTypeFor<dimensions, T>& matrix) {
self.setProjectionMatrix(matrix); self.setProjectionMatrix(matrix);
}, "Projection matrix") }, "Projection matrix")
.def("projection_size", &SceneGraph::Camera<dimensions, T>::projectionSize, .def("projection_size", &SceneGraph::Camera<dimensions, T>::projectionSize,
@ -320,8 +243,8 @@ void scenegraph(py::module& m) {
/* Abstract objects. Returned from feature.object, so need to be registered /* Abstract objects. Returned from feature.object, so need to be registered
as well. */ as well. */
{ {
py::class_<SceneGraph::AbstractObject2D, SceneGraphObjectHolder<SceneGraph::AbstractObject2D>> abstractObject2D{m, "AbstractObject2D", "Base object for two-dimensional scenes"}; py::class_<SceneGraph::AbstractObject2D, SceneGraph::PyObjectHolder<SceneGraph::AbstractObject2D>> abstractObject2D{m, "AbstractObject2D", "Base object for two-dimensional scenes"};
py::class_<SceneGraph::AbstractObject3D, SceneGraphObjectHolder<SceneGraph::AbstractObject3D>> abstractObject3D{m, "AbstractObject3D", "Base object for three-dimensional scenes"}; py::class_<SceneGraph::AbstractObject3D, SceneGraph::PyObjectHolder<SceneGraph::AbstractObject3D>> abstractObject3D{m, "AbstractObject3D", "Base object for three-dimensional scenes"};
abstractObject(abstractObject2D); abstractObject(abstractObject2D);
abstractObject(abstractObject3D); abstractObject(abstractObject3D);
} }
@ -337,12 +260,12 @@ void scenegraph(py::module& m) {
py::class_<SceneGraph::Scene<SceneGraph::MatrixTransformation3D>> scene3D_{matrix, "Scene3D", "Three-dimensional scene with matrix-based transformation implementation"}; py::class_<SceneGraph::Scene<SceneGraph::MatrixTransformation3D>> scene3D_{matrix, "Scene3D", "Three-dimensional scene with matrix-based transformation implementation"};
scene(scene3D_); scene(scene3D_);
py::class_<PyObject<SceneGraph::MatrixTransformation2D>, SceneGraph::AbstractObject2D, SceneGraphObjectHolder<PyObject<SceneGraph::MatrixTransformation2D>>> object2D_{matrix, "Object2D", "Two-dimensional object with matrix-based transformation implementation"}; py::class_<SceneGraph::Object<SceneGraph::MatrixTransformation2D>, SceneGraph::PyObject<SceneGraph::Object<SceneGraph::MatrixTransformation2D>>, SceneGraph::AbstractObject2D, SceneGraph::PyObjectHolder<SceneGraph::Object<SceneGraph::MatrixTransformation2D>>> object2D_{matrix, "Object2D", "Two-dimensional object with matrix-based transformation implementation"};
object(object2D_); object(object2D_);
object2D(object2D_); object2D(object2D_);
objectScale(object2D_); objectScale(object2D_);
py::class_<PyObject<SceneGraph::MatrixTransformation3D>, SceneGraph::AbstractObject3D, SceneGraphObjectHolder<PyObject<SceneGraph::MatrixTransformation3D>>> object3D_{matrix, "Object3D", "Three-dimensional object with matrix-based transformation implementation"}; py::class_<SceneGraph::Object<SceneGraph::MatrixTransformation3D>, SceneGraph::PyObject<SceneGraph::Object<SceneGraph::MatrixTransformation3D>>, SceneGraph::AbstractObject3D, SceneGraph::PyObjectHolder<SceneGraph::Object<SceneGraph::MatrixTransformation3D>>> object3D_{matrix, "Object3D", "Three-dimensional object with matrix-based transformation implementation"};
object(object3D_); object(object3D_);
object3D(object3D_); object3D(object3D_);
objectScale(object3D_); objectScale(object3D_);
@ -358,21 +281,22 @@ void scenegraph(py::module& m) {
py::class_<SceneGraph::DrawableGroup2D> drawableGroup2D{m, "DrawableGroup2D", "Group of drawables for two-dimensional float scenes"}; py::class_<SceneGraph::DrawableGroup2D> drawableGroup2D{m, "DrawableGroup2D", "Group of drawables for two-dimensional float scenes"};
py::class_<SceneGraph::DrawableGroup3D> drawableGroup3D{m, "DrawableGroup3D", "Group of drawables for three-dimensional float scenes"}; py::class_<SceneGraph::DrawableGroup3D> drawableGroup3D{m, "DrawableGroup3D", "Group of drawables for three-dimensional float scenes"};
py::class_<PyDrawable<2, Float>, SceneGraphFeatureHolder<PyDrawable<2, Float>>> drawable2D{m, "Drawable2D", "Drawable for two-dimensional float scenes"}; py::class_<SceneGraph::AbstractFeature2D, SceneGraph::PyFeatureHolder<SceneGraph::AbstractFeature2D>> feature2D{m, "AbstractFeature2D", "Base for two-dimensional float features"};
py::class_<PyDrawable<3, Float>, SceneGraphFeatureHolder<PyDrawable<3, Float>>> drawable3D{m, "Drawable3D", "Drawable for three-dimensional float scenes"}; py::class_<SceneGraph::AbstractFeature3D, SceneGraph::PyFeatureHolder<SceneGraph::AbstractFeature3D>> feature3D{m, "AbstractFeature3D", "Base for three-dimensional float features"};
feature(feature2D);
feature(feature3D);
py::class_<SceneGraph::Drawable2D, SceneGraph::AbstractFeature2D, PyDrawable<2, Float>, SceneGraph::PyFeatureHolder<SceneGraph::Drawable2D>> drawable2D{m, "Drawable2D", "Drawable for two-dimensional float scenes"};
py::class_<SceneGraph::Drawable3D, SceneGraph::AbstractFeature3D, PyDrawable<3, Float>, SceneGraph::PyFeatureHolder<SceneGraph::Drawable3D>> drawable3D{m, "Drawable3D", "Drawable for three-dimensional float scenes"};
py::class_<PyCamera<2, Float>, SceneGraphFeatureHolder<PyCamera<2, Float>>> camera2D{m, "Camera2D", "Camera for two-dimensional float scenes"}; py::class_<SceneGraph::Camera2D, SceneGraph::AbstractFeature2D, SceneGraph::PyFeature<SceneGraph::Camera2D>, SceneGraph::PyFeatureHolder<SceneGraph::Camera2D>> camera2D{m, "Camera2D", "Camera for two-dimensional float scenes"};
py::class_<PyCamera<3, Float>, SceneGraphFeatureHolder<PyCamera<3, Float>>> camera3D{m, "Camera3D", "Camera for three-dimensional float scenes"}; py::class_<SceneGraph::Camera3D, SceneGraph::AbstractFeature3D, SceneGraph::PyFeature<SceneGraph::Camera3D>, SceneGraph::PyFeatureHolder<SceneGraph::Camera3D>> camera3D{m, "Camera3D", "Camera for three-dimensional float scenes"};
featureGroup<PyDrawable<2, Float>>(drawableGroup2D); featureGroup<PyDrawable<2, Float>>(drawableGroup2D);
featureGroup<PyDrawable<3, Float>>(drawableGroup3D); featureGroup<PyDrawable<3, Float>>(drawableGroup3D);
feature<2, Float>(drawable2D);
feature<3, Float>(drawable3D);
drawable(drawable2D); drawable(drawable2D);
drawable(drawable3D); drawable(drawable3D);
feature<2, Float>(camera2D);
feature<3, Float>(camera3D);
camera(camera2D); camera(camera2D);
camera(camera3D); camera(camera3D);
} }

Loading…
Cancel
Save