diff --git a/src/python/magnum/primitives.cpp b/src/python/magnum/primitives.cpp index 2c8a69b..e91e5b9 100644 --- a/src/python/magnum/primitives.cpp +++ b/src/python/magnum/primitives.cpp @@ -24,11 +24,25 @@ */ #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include #include +#include #include #include +#include "corrade/EnumOperators.h" #include "magnum/bootstrap.h" namespace magnum { @@ -42,17 +56,101 @@ void primitives(py::module& m) { py::module::import("magnum.trade"); #endif + py::enum_{m, "CapsuleTextureCoords", "Whether to generate capsule texture coordinates"} + .value("DONT_GENERATE", Primitives::CapsuleTextureCoords::DontGenerate) + .value("GENERATE", Primitives::CapsuleTextureCoords::Generate); + + py::enum_{m, "CircleTextureCoords", "Whether to generate circle texture coordinates"} + .value("DONT_GENERATE", Primitives::CircleTextureCoords::DontGenerate) + .value("GENERATE", Primitives::CircleTextureCoords::Generate); + + py::enum_ 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_ 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_ 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_{m, "PlaneTextureCoords", "Whether to generate plane texture coordinates"} + .value("DONT_GENERATE", Primitives::PlaneTextureCoords::DontGenerate) + .value("GENERATE", Primitives::PlaneTextureCoords::Generate); + py::enum_{m, "SquareTextureCoords", "Whether to generate square texture coordinates"} .value("DONT_GENERATE", Primitives::SquareTextureCoords::DontGenerate) .value("GENERATE", Primitives::SquareTextureCoords::Generate); + py::enum_{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(Primitives::line2D), "2D line", py::arg("a"), py::arg("b")) + .def("line2d", static_cast(Primitives::line2D), "2D line in an identity transformation") + .def("line3d", static_cast(Primitives::line3D), "3D line", py::arg("a"), py::arg("b")) + .def("line3d", static_cast(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")); } } diff --git a/src/python/magnum/test/test_primitives.py b/src/python/magnum/test/test_primitives.py index 28ec4c7..c7b5401 100644 --- a/src/python/magnum/test/test_primitives.py +++ b/src/python/magnum/test/test_primitives.py @@ -28,6 +28,102 @@ import unittest 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() @@ -44,6 +140,115 @@ class Cube(unittest.TestCase): 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) @@ -60,3 +265,20 @@ class Square(unittest.TestCase): 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())