diff --git a/src/atlas.cpp b/src/atlas.cpp index 7c4d23c..ed32f7d 100644 --- a/src/atlas.cpp +++ b/src/atlas.cpp @@ -176,6 +176,66 @@ MeshResult Atlas::getMesh(std::uint32_t index) const return std::make_tuple(mapping, indices, uvs); } +VertexAssignment Atlas::getMeshVertexAssignment(std::uint32_t meshIndex) const +{ + if (meshIndex >= m_atlas->meshCount) + { + throw std::out_of_range("Mesh index " + std::to_string(meshIndex) + " out of bounds for atlas with " + std::to_string(m_atlas->meshCount) + " meshes."); + } + + auto const& mesh = m_atlas->meshes[meshIndex]; + + py::array_t atlasIndex(py::array::ShapeContainer{mesh.vertexCount}); + py::array_t chartIndex(py::array::ShapeContainer{mesh.vertexCount}); + auto atlasIndex_ = atlasIndex.mutable_unchecked<1>(); + auto chartIndex_ = chartIndex.mutable_unchecked<1>(); + for (size_t v = 0; v < static_cast(mesh.vertexCount); ++v) + { + auto const& vertex = mesh.vertexArray[v]; + atlasIndex_(v) = vertex.atlasIndex; + chartIndex_(v) = vertex.chartIndex; + } + + return std::make_tuple(atlasIndex, chartIndex); +} + +uint32_t Atlas::getMeshChartCount(std::uint32_t meshIndex) const +{ + if (meshIndex >= m_atlas->meshCount) + throw std::out_of_range("Mesh index " + std::to_string(meshIndex) + " out of bounds for atlas with " + std::to_string(m_atlas->meshCount) + " meshes."); + + auto const& mesh = m_atlas->meshes[meshIndex]; + + return mesh.chartCount; +} + +Chart Atlas::getMeshChart(std::uint32_t meshIndex, std::uint32_t chartIndex) const +{ + if (meshIndex >= m_atlas->meshCount) + throw std::out_of_range("Mesh index " + std::to_string(meshIndex) + " out of bounds for atlas with " + std::to_string(m_atlas->meshCount) + " meshes."); + + auto const& mesh = m_atlas->meshes[meshIndex]; + + if (chartIndex >= mesh.chartCount) + throw std::out_of_range("Chart index " + std::to_string(chartIndex) + " out of bounds for mesh with " + std::to_string(mesh.chartCount) + " charts."); + + xatlas::Chart& chart = mesh.chartArray[chartIndex]; + py::array_t faces(py::array::ShapeContainer{chart.faceCount}); + auto faces_ = faces.mutable_unchecked<1>(); + for (size_t i = 0; i < static_cast(chart.faceCount); ++i) + { + faces_(i) = chart.faceArray[i]; + } + + Chart chart_; + chart_.faces = faces; + chart_.atlasIndex = chart.atlasIndex; + chart_.type = chart.type; + chart_.material = chart.material; + + return chart_; +} + float Atlas::getUtilization(std::uint32_t index) const { if (index >= m_atlas->atlasCount) @@ -259,12 +319,21 @@ py::array_t Atlas::getChartImage(std::uint32_t index) const void Atlas::bind(py::module& m) { + py::class_(m, "Chart") + .def_property_readonly("faces", [](Chart const& self) { return self.faces; }) + .def_property_readonly("atlas_index", [](Chart const& self) { return self.atlasIndex; }) + .def_property_readonly("type", [](Chart const& self) { return self.type; }) + .def_property_readonly("material", [](Chart const& self) { return self.material; }); + py::class_(m, "Atlas") .def(py::init<>()) .def("add_mesh", &Atlas::addMesh, py::arg("positions"), py::arg("indices"), py::arg("normals") = std::nullopt, py::arg("uvs") = std::nullopt) .def("add_uv_mesh", &Atlas::addUvMesh, py::arg("uvs"), py::arg("indices"), py::arg("face_materials") = std::nullopt) .def("generate", &Atlas::generate, py::arg("chart_options") = xatlas::ChartOptions(), py::arg("pack_options") = xatlas::PackOptions(), py::arg("verbose") = false) .def("get_mesh", &Atlas::getMesh, py::arg("mesh_index")) + .def("get_mesh_vertex_assignment", &Atlas::getMeshVertexAssignment, py::arg("mesh_index")) + .def("get_mesh_chart_count", &Atlas::getMeshChartCount, py::arg("mesh_index")) + .def("get_mesh_chart", &Atlas::getMeshChart, py::arg("mesh_index"), py::arg("chart_index")) .def("get_utilization", &Atlas::getUtilization, py::arg("atlas_index")) .def("get_chart_image", &Atlas::getChartImage, py::arg("atlas_index")) .def_property_readonly("atlas_count", [](Atlas const& self) { return self.m_atlas->atlasCount; }) diff --git a/src/atlas.hpp b/src/atlas.hpp index 9a2d823..8c33fc0 100644 --- a/src/atlas.hpp +++ b/src/atlas.hpp @@ -34,7 +34,24 @@ #include #include -using MeshResult = std::tuple, pybind11::array_t, pybind11::array_t>; +using MeshResult = std::tuple< + pybind11::array_t, + pybind11::array_t, + pybind11::array_t +>; + +using VertexAssignment = std::tuple< + pybind11::array_t, // Atlas index + pybind11::array_t // Chart index +>; + +struct Chart +{ + pybind11::array_t faces; + uint32_t atlasIndex; // Sub-atlas index. + xatlas::ChartType type; + uint32_t material; +}; class Atlas { @@ -56,6 +73,12 @@ class Atlas MeshResult getMesh(std::uint32_t index) const; + VertexAssignment getMeshVertexAssignment(std::uint32_t meshIndex) const; + + uint32_t getMeshChartCount(std::uint32_t meshIndex) const; + + Chart getMeshChart(std::uint32_t meshIndex, std::uint32_t chartIndex) const; + float getUtilization(std::uint32_t index) const; pybind11::array_t getChartImage(std::uint32_t index) const; diff --git a/src/module.cpp b/src/module.cpp index 9a59636..d5ef22a 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -139,7 +139,13 @@ void exportObj(std::string const& path, PYBIND11_MODULE(xatlas, m) { - // Bindings + py::enum_(m, "ChartType") + .value("Planar", xatlas::ChartType::Planar) + .value("Ortho", xatlas::ChartType::Ortho) + .value("LSCM", xatlas::ChartType::LSCM) + .value("Piecewise", xatlas::ChartType::Piecewise) + .value("Invalid", xatlas::ChartType::Invalid); + ChartOptions::bind(m); PackOptions::bind(m); Atlas::bind(m);