Skip to content

Commit

Permalink
python: expose remaining primitives.
Browse files Browse the repository at this point in the history
  • Loading branch information
mosra committed Oct 19, 2019
1 parent 70fe4e8 commit e334cc1
Show file tree
Hide file tree
Showing 2 changed files with 321 additions and 1 deletion.
100 changes: 99 additions & 1 deletion src/python/magnum/primitives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,25 @@
*/

#include <pybind11/pybind11.h>
#include <Magnum/Math/Color.h>
#include <Magnum/Primitives/Axis.h>
#include <Magnum/Primitives/Capsule.h>
#include <Magnum/Primitives/Circle.h>
#include <Magnum/Primitives/Cone.h>
#include <Magnum/Primitives/Crosshair.h>
#include <Magnum/Primitives/Cube.h>
#include <Magnum/Primitives/Cylinder.h>
#include <Magnum/Primitives/Gradient.h>
#include <Magnum/Primitives/Grid.h>
#include <Magnum/Primitives/Icosphere.h>
#include <Magnum/Primitives/Line.h>
#include <Magnum/Primitives/Plane.h>
#include <Magnum/Primitives/Square.h>
#include <Magnum/Primitives/UVSphere.h>
#include <Magnum/Trade/MeshData2D.h>
#include <Magnum/Trade/MeshData3D.h>

#include "corrade/EnumOperators.h"
#include "magnum/bootstrap.h"

namespace magnum {
Expand All @@ -42,17 +56,101 @@ void primitives(py::module& m) {
py::module::import("magnum.trade");
#endif

py::enum_<Primitives::CapsuleTextureCoords>{m, "CapsuleTextureCoords", "Whether to generate capsule texture coordinates"}
.value("DONT_GENERATE", Primitives::CapsuleTextureCoords::DontGenerate)
.value("GENERATE", Primitives::CapsuleTextureCoords::Generate);

py::enum_<Primitives::CircleTextureCoords>{m, "CircleTextureCoords", "Whether to generate circle texture coordinates"}
.value("DONT_GENERATE", Primitives::CircleTextureCoords::DontGenerate)
.value("GENERATE", Primitives::CircleTextureCoords::Generate);

py::enum_<Primitives::ConeFlag> coneFlags{m, "ConeFlags", "Cone flags"};
coneFlags.value("GENERATE_TEXTURE_COORDS", Primitives::ConeFlag::GenerateTextureCoords)
.value("CAP_END", Primitives::ConeFlag::CapEnd)
.value("NONE", Primitives::ConeFlag{});
corrade::enumOperators(coneFlags);

py::enum_<Primitives::CylinderFlag> cylinderFlags{m, "CylinderFlags", "Cylinder flags"};
cylinderFlags.value("GENERATE_TEXTURE_COORDS", Primitives::CylinderFlag::GenerateTextureCoords)
.value("CAP_ENDS", Primitives::CylinderFlag::CapEnds)
.value("NONE", Primitives::CylinderFlag{});
corrade::enumOperators(cylinderFlags);

py::enum_<Primitives::GridFlag> gridFlags{m, "GridFlags", "Grid flags"};
gridFlags.value("GENERATE_TEXTURE_COORDS", Primitives::GridFlag::GenerateTextureCoords)
.value("GENERATE_NORMALS", Primitives::GridFlag::GenerateNormals)
.value("NONE", Primitives::GridFlag{});
corrade::enumOperators(gridFlags);

py::enum_<Primitives::PlaneTextureCoords>{m, "PlaneTextureCoords", "Whether to generate plane texture coordinates"}
.value("DONT_GENERATE", Primitives::PlaneTextureCoords::DontGenerate)
.value("GENERATE", Primitives::PlaneTextureCoords::Generate);

py::enum_<Primitives::SquareTextureCoords>{m, "SquareTextureCoords", "Whether to generate square texture coordinates"}
.value("DONT_GENERATE", Primitives::SquareTextureCoords::DontGenerate)
.value("GENERATE", Primitives::SquareTextureCoords::Generate);

py::enum_<Primitives::UVSphereTextureCoords>{m, "UVSphereTextureCoords", "Whether to generate UV sphere texture coordinates"}
.value("DONT_GENERATE", Primitives::UVSphereTextureCoords::DontGenerate)
.value("GENERATE", Primitives::UVSphereTextureCoords::Generate);

m
.def("axis2d", Primitives::axis2D, "2D axis")
.def("axis3d", Primitives::axis3D, "3D axis")

.def("capsule2d_wireframe", Primitives::capsule2DWireframe, "Wireframe 2D capsule", py::arg("hemisphere_rings"), py::arg("cylinder_rings"), py::arg("half_length"))
.def("capsule3d_solid", Primitives::capsule3DSolid, "Solid 3D capsule", py::arg("hemisphere_rings"), py::arg("cylinder_rings"), py::arg("segments"), py::arg("half_length"), py::arg("texture_coords") = Primitives::CapsuleTextureCoords::DontGenerate)
.def("capsule3d_wireframe", Primitives::capsule3DWireframe, "Wireframe 3D capsule", py::arg("hemisphere_rings"), py::arg("cylinder_rings"), py::arg("segments"), py::arg("half_length"))

.def("circle2d_solid", Primitives::circle2DSolid, "Solid 2D circle", py::arg("segments"), py::arg("texture_coords") = Primitives::CircleTextureCoords::DontGenerate)
.def("circle2d_wireframe", Primitives::circle2DWireframe, "Wireframe 2D circle", py::arg("segments"))
.def("circle3d_solid", Primitives::circle3DSolid, "Solid 3D circle", py::arg("segments"), py::arg("texture_coords") = Primitives::CircleTextureCoords::DontGenerate)
.def("circle3d_wireframe", Primitives::circle3DWireframe, "Wireframe 3D circle", py::arg("segments"))

.def("cone_solid", [](UnsignedInt rings, UnsignedInt segments, Float halfLength, Primitives::ConeFlag flags) {
return Primitives::coneSolid(rings, segments, halfLength, flags);
}, "Solid 3D cone", py::arg("rings"), py::arg("segments"), py::arg("half_length"), py::arg("flags") = Primitives::ConeFlag{})
.def("cone_wireframe", Primitives::coneWireframe, "Wireframe 3D cone", py::arg("segments"), py::arg("half_length"))

.def("crosshair2d", Primitives::crosshair2D, "2D crosshair")
.def("crosshair3d", Primitives::crosshair3D, "3D crosshair")

.def("cube_solid", Primitives::cubeSolid, "Solid 3D cube")
.def("cube_solid_strip", Primitives::cubeSolidStrip, "Solid 3D cube as a single strip")
.def("cube_wireframe", Primitives::cubeWireframe, "Wireframe 3D cube")

.def("cylinder_solid", [](UnsignedInt rings, UnsignedInt segments, Float halfLength, Primitives::CylinderFlag flags) {
return Primitives::cylinderSolid(rings, segments, halfLength, flags);
}, "Solid 3D cylinder", py::arg("rings"), py::arg("segments"), py::arg("half_length"), py::arg("flags") = Primitives::CylinderFlag{})
.def("cylinder_wireframe", Primitives::cylinderWireframe, "Wireframe 3D cylinder", py::arg("rings"), py::arg("segments"), py::arg("half_length"))

.def("gradient2d", Primitives::gradient2D, "2D square with a gradient", py::arg("a"), py::arg("color_a"), py::arg("b"), py::arg("color_b"))
.def("gradient2d_horizontal", Primitives::gradient2DHorizontal, "2D square with a horizontal gradient", py::arg("color_left"), py::arg("color_right"))
.def("gradient2d_vertical", Primitives::gradient2DVertical, "2D square with a vertical gradient", py::arg("color_bottom"), py::arg("color_top"))
.def("gradient3d", Primitives::gradient3D, "3D plane with a gradient", py::arg("a"), py::arg("color_a"), py::arg("b"), py::arg("color_b"))
.def("gradient3d_horizontal", Primitives::gradient3DHorizontal, "3D plane with a horizontal gradient", py::arg("color_left"), py::arg("color_right"))
.def("gradient3d_vertical", Primitives::gradient3DVertical, "3D plane with a vertical gradient", py::arg("color_bottom"), py::arg("color_top"))

.def("grid3d_solid", [](const Vector2i& subdivisions, Primitives::GridFlag flags) {
return Primitives::grid3DSolid(subdivisions, flags);
}, "Solid 3D grid", py::arg("subdivisions"), py::arg("flags") = Primitives::GridFlag::GenerateNormals)
.def("grid3d_wireframe", Primitives::grid3DWireframe, "Wireframe 3D grid")

.def("icosphere_solid", Primitives::icosphereSolid, py::arg("subdivisions"))

.def("line2d", static_cast<Trade::MeshData2D(*)(const Vector2&, const Vector2&)>(Primitives::line2D), "2D line", py::arg("a"), py::arg("b"))
.def("line2d", static_cast<Trade::MeshData2D(*)()>(Primitives::line2D), "2D line in an identity transformation")
.def("line3d", static_cast<Trade::MeshData3D(*)(const Vector3&, const Vector3&)>(Primitives::line3D), "3D line", py::arg("a"), py::arg("b"))
.def("line3d", static_cast<Trade::MeshData3D(*)()>(Primitives::line3D), "3D line in an identity transformation")

.def("plane_solid", Primitives::planeSolid, "Solid 3D plane", py::arg("texture_coords") = Primitives::PlaneTextureCoords::DontGenerate)
.def("plane_wireframe", Primitives::planeWireframe, "Wireframe 3D plane")

.def("square_solid", Primitives::squareSolid, "Solid 2D square", py::arg("texture_coords") = Primitives::SquareTextureCoords::DontGenerate)
.def("square_wireframe", Primitives::squareWireframe, "Wireframe 2D square");
.def("square_wireframe", Primitives::squareWireframe, "Wireframe 2D square")

.def("uv_sphere_solid", Primitives::uvSphereSolid, "Solid 3D UV sphere", py::arg("rings"), py::arg("segments"), py::arg("texture_coords") = Primitives::UVSphereTextureCoords::DontGenerate)
.def("uv_sphere_wireframe", Primitives::uvSphereWireframe, "Wireframe 3D UV sphere", py::arg("rings"), py::arg("segments"));
}

}
Expand Down
222 changes: 222 additions & 0 deletions src/python/magnum/test/test_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,102 @@
from magnum import *
from magnum import primitives

class Axis(unittest.TestCase):
def test_2d(self):
a = primitives.axis2d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_colors())

def test_3d(self):
a = primitives.axis3d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_colors())

class Capsule(unittest.TestCase):
def test_2d_wireframe(self):
a = primitives.capsule2d_wireframe(3, 3, 2.0)
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

def test_3d_solid(self):
a = primitives.capsule3d_solid(3, 3, 10, 2.0, primitives.CapsuleTextureCoords.GENERATE)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.capsule3d_solid(3, 3, 10, 2.0)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_3d_wireframe(self):
a = primitives.capsule3d_wireframe(5, 3, 12, 0.3)
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

class Circle(unittest.TestCase):
def test_2d_solid(self):
a = primitives.circle2d_solid(5, primitives.CircleTextureCoords.GENERATE)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_FAN)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.circle2d_solid(5)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLE_FAN)
self.assertFalse(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_2d_wireframe(self):
a = primitives.circle2d_wireframe(5)
self.assertEqual(a.primitive, MeshPrimitive.LINE_LOOP)
self.assertFalse(a.is_indexed())

def test_3d_solid(self):
a = primitives.circle3d_solid(5, primitives.CircleTextureCoords.GENERATE)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_FAN)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.circle3d_solid(5)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLE_FAN)
self.assertFalse(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_3d_wireframe(self):
a = primitives.circle3d_wireframe(5)
self.assertEqual(a.primitive, MeshPrimitive.LINE_LOOP)
self.assertFalse(a.is_indexed())

class Cone(unittest.TestCase):
def test_solid(self):
a = primitives.cone_solid(5, 7, 7.1, primitives.ConeFlags.GENERATE_TEXTURE_COORDS|primitives.ConeFlags.CAP_END)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.cone_solid(5, 7, 7.1)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_wireframe(self):
a = primitives.cone_wireframe(16, 7.1)
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

class Crosshair(unittest.TestCase):
def test_2d(self):
a = primitives.crosshair2d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

def test_3d(self):
a = primitives.crosshair3d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

class Cube(unittest.TestCase):
def test_solid(self):
a = primitives.cube_solid()
Expand All @@ -44,6 +140,115 @@ def test_wireframe(self):
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

class Cylinder(unittest.TestCase):
def test_solid(self):
a = primitives.cylinder_solid(7, 12, 0.2, primitives.CylinderFlags.GENERATE_TEXTURE_COORDS|primitives.CylinderFlags.CAP_ENDS)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.cylinder_solid(7, 12, 0.2)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_wireframe(self):
a = primitives.cylinder_wireframe(8, 16, 1.1)
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

class Gradient(unittest.TestCase):
def test_gradient2d(self):
a = primitives.gradient2d((3.1, 2.0), Color3(), (0.2, 1.1), Color4())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

def test_gradient2d_horizontal(self):
a = primitives.gradient2d_horizontal(Color4(), Color3())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

def test_gradient2d_vertical(self):
a = primitives.gradient2d_vertical(Color4(), Color3())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

def test_gradient3d(self):
a = primitives.gradient3d((3.1, 2.0, 0.1), Color3(), (0.2, 1.1, 1.2), Color4())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

def test_gradient3d_horizontal(self):
a = primitives.gradient3d_horizontal(Color4(), Color3())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

def test_gradient3d_vertical(self):
a = primitives.gradient3d_vertical(Color4(), Color3())
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_colors())

class Grid(unittest.TestCase):
def test_solid(self):
a = primitives.grid3d_solid((4, 5))
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())

def test_wireframe(self):
a = primitives.grid3d_wireframe((2, 7))
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

class Icosphere(unittest.TestCase):
def test(self):
a = primitives.icosphere_solid(2)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())

class Line(unittest.TestCase):
def test_2d(self):
a = primitives.line2d((1.0, 2.0), (7.0, 3.2))
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

def test_2d_identity(self):
a = primitives.line2d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

def test_3d(self):
a = primitives.line3d((1.0, 2.0, 1.1), (7.0, 3.2, 1.1))
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

def test_3d_identity(self):
a = primitives.line3d()
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertFalse(a.is_indexed())

class Plane(unittest.TestCase):
def test_solid(self):
a = primitives.plane_solid(primitives.PlaneTextureCoords.GENERATE)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.plane_solid()
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLE_STRIP)
self.assertFalse(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_wireframe(self):
a = primitives.plane_wireframe()
self.assertEqual(a.primitive, MeshPrimitive.LINE_LOOP)
self.assertFalse(a.is_indexed())

class Square(unittest.TestCase):
def test_solid(self):
a = primitives.square_solid(primitives.SquareTextureCoords.GENERATE)
Expand All @@ -60,3 +265,20 @@ def test_wireframe(self):
a = primitives.square_wireframe()
self.assertEqual(a.primitive, MeshPrimitive.LINE_LOOP)
self.assertFalse(a.is_indexed())

class UVSphere(unittest.TestCase):
def test_solid(self):
a = primitives.uv_sphere_solid(3, 7, primitives.UVSphereTextureCoords.GENERATE)
self.assertEqual(a.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(a.is_indexed())
self.assertTrue(a.has_texture_coords2d())

b = primitives.uv_sphere_solid(3, 7)
self.assertEqual(b.primitive, MeshPrimitive.TRIANGLES)
self.assertTrue(b.is_indexed())
self.assertFalse(b.has_texture_coords2d())

def test_wireframe(self):
a = primitives.uv_sphere_wireframe(6, 8)
self.assertEqual(a.primitive, MeshPrimitive.LINES)
self.assertTrue(a.is_indexed())

0 comments on commit e334cc1

Please sign in to comment.