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() {
# 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
}

2
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()

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)
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"

198
src/python/magnum/scenegraph.cpp

@ -32,61 +32,14 @@
#include <Magnum/SceneGraph/MatrixTransformation2D.h>
#include <Magnum/SceneGraph/MatrixTransformation3D.h>
#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<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();
}
};
}}
#include "Magnum/SceneGraph/Python.h"
PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphObjectHolder<T>)
PYBIND11_DECLARE_HOLDER_TYPE(T, magnum::SceneGraphFeatureHolder<T>)
#include "magnum/bootstrap.h"
namespace magnum { namespace {
template<class Transformation> class PyObject: public SceneGraph::Object<Transformation> {
public:
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} {}
template<UnsignedInt dimensions, class T> struct PyDrawable: SceneGraph::PyFeature<SceneGraph::Drawable<dimensions, T>> {
explicit PyDrawable(SceneGraph::AbstractObject<dimensions, T>& object, SceneGraph::DrawableGroup<dimensions, T>* drawables): SceneGraph::PyFeature<SceneGraph::Drawable<dimensions, T>>{object, drawables} {}
void draw(const MatrixTypeFor<dimensions, T>& transformationMatrix, SceneGraph::Camera<dimensions, T>& camera) override {
PYBIND11_OVERLOAD_PURE_NAME(
@ -98,43 +51,13 @@ template<UnsignedInt dimensions, class T> 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<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) {
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
/* Matrix transformation APIs */
.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");
}
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
.def(py::init<PyObject<Transformation>*>(),
.def(py::init_alias<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(),
"Constructor", py::arg("parent") = nullptr)
.def(py::init<SceneGraph::Scene<Transformation>*>(),
.def(py::init_alias<SceneGraph::Scene<Transformation>*>(),
"Constructor", py::arg("parent") = nullptr)
/* 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());
}, "Scene or None if the object is not a part of any scene")
.def_property("parent", [](PyObject<Transformation>& self) {
return static_cast<PyObject<Transformation>*>(self.parent());
}, [](PyObject<Transformation>& self, py::object parentobj) {
.def_property("parent", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self) {
return static_cast<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(self.parent());
}, [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self, py::object parentobj) {
SceneGraph::Object<Transformation>* parent;
if(py::isinstance<PyObject<Transformation>>(parentobj))
parent = py::cast<PyObject<Transformation>*>(parentobj);
if(py::isinstance<SceneGraph::PyObject<SceneGraph::Object<Transformation>>>(parentobj))
parent = py::cast<SceneGraph::PyObject<SceneGraph::Object<Transformation>>*>(parentobj);
else if(py::isinstance<SceneGraph::Scene<Transformation>>(parentobj))
parent = py::cast<SceneGraph::Scene<Transformation>*>(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 */
.def_property("transformation",
&PyObject<Transformation>::transformation,
&PyObject<Transformation>::setTransformation,
&SceneGraph::PyObject<SceneGraph::Object<Transformation>>::transformation,
&SceneGraph::PyObject<SceneGraph::Object<Transformation>>::setTransformation,
"Object transformation")
.def("absolute_transformation", &PyObject<Transformation>::absoluteTransformation,
.def("absolute_transformation", &SceneGraph::PyObject<SceneGraph::Object<Transformation>>::absoluteTransformation,
"Transformation relative to the root object")
.def("reset_transformation", [](PyObject<Transformation>& self) {
.def("reset_transformation", [](SceneGraph::PyObject<SceneGraph::Object<Transformation>>& self) {
self.resetTransformation();
}, "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);
}, "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);
}, "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);
}, "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);
}, "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
.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));
}, "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));
}, "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
.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);
}, "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);
}, "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));
}, "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));
}, "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));
}, "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));
}, "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));
}, "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));
}, "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
.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);
}, "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);
}, "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);
}, "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);
}, "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");
}
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
.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();
}, "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
.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)
.def_property_readonly("drawables", [](PyDrawable<dimensions, T>& self) {
return self.drawables();
}, "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);
}, "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
.def(py::init<SceneGraph::AbstractObject<dimensions, T>&>(),
.def(py::init_alias<SceneGraph::AbstractObject<dimensions, T>&>(),
"Constructor", py::arg("object"))
.def_property("aspect_ratio_policy", &SceneGraph::Camera<dimensions, T>::aspectRatioPolicy,
/* 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);
}, "Aspect ratio policy")
.def_property_readonly("camera_matrix", &SceneGraph::Camera<dimensions, T>::cameraMatrix,
"Camera matrix")
.def_property("projection_matrix", &SceneGraph::Camera<dimensions, T>::projectionMatrix,
/* 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);
}, "Projection matrix")
.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
as well. */
{
py::class_<SceneGraph::AbstractObject2D, SceneGraphObjectHolder<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::AbstractObject2D, SceneGraph::PyObjectHolder<SceneGraph::AbstractObject2D>> abstractObject2D{m, "AbstractObject2D", "Base object for two-dimensional scenes"};
py::class_<SceneGraph::AbstractObject3D, SceneGraph::PyObjectHolder<SceneGraph::AbstractObject3D>> abstractObject3D{m, "AbstractObject3D", "Base object for three-dimensional scenes"};
abstractObject(abstractObject2D);
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"};
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_);
object2D(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_);
object3D(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::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_<PyDrawable<3, Float>, SceneGraphFeatureHolder<PyDrawable<3, Float>>> drawable3D{m, "Drawable3D", "Drawable for three-dimensional float scenes"};
py::class_<SceneGraph::AbstractFeature2D, SceneGraph::PyFeatureHolder<SceneGraph::AbstractFeature2D>> feature2D{m, "AbstractFeature2D", "Base for two-dimensional float features"};
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_<PyCamera<3, Float>, SceneGraphFeatureHolder<PyCamera<3, Float>>> camera3D{m, "Camera3D", "Camera for three-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_<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<3, Float>>(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);
}

Loading…
Cancel
Save