mesh/io/mesh_io.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /// @file | ||
| 2 | /// @brief Reading and writing triangle meshes and instanced scenes as OBJ with MTL, glTF and STL. | ||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "terraingen/mesh/mesh.h" | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <cstddef> | ||
| 9 | #include <filesystem> | ||
| 10 | #include <string> | ||
| 11 | #include <vector> | ||
| 12 | |||
| 13 | namespace terraingen { | ||
| 14 | |||
| 15 | /// A mesh's material: a name and a diffuse colour. | ||
| 16 | struct MeshMaterial { | ||
| 17 | 90 | std::string name = "default"; ///< Name in OBJ/MTL and glTF. | |
| 18 | 14 | std::array<double, 3> colour{0.5, 0.5, 0.5}; ///< Linear RGB, each in [0, 1]. | |
| 19 | |||
| 20 | 90 | bool operator==(const MeshMaterial&) const = default; | |
| 21 | }; | ||
| 22 | |||
| 23 | /// A mesh with optional normals and its material. | ||
| 24 | struct SceneMesh { | ||
| 25 | TriangleMesh mesh; ///< The mesh, in metres. | ||
| 26 | std::vector<Vec3d> normals; ///< Empty, or one unit normal per vertex. | ||
| 27 | MeshMaterial material{}; ///< Written as an MTL material or a glTF base colour. | ||
| 28 | }; | ||
| 29 | |||
| 30 | /// An instance of a scene mesh: its vertices scaled per axis by `scale`, then moved by | ||
| 31 | /// `pose`, as glTF composes a node's scale, rotation and translation. | ||
| 32 | struct SceneNode { | ||
| 33 | std::size_t mesh = 0; ///< Index into the scene's meshes. | ||
| 34 | Vec3d scale{1.0, 1.0, 1.0}; ///< Per-axis scale, nonzero and finite. | ||
| 35 | RigidTransform pose{}; ///< Rotation and translation applied after the scale. | ||
| 36 | }; | ||
| 37 | |||
| 38 | /// Whether `path` names a mesh format by its extension: .obj, .gltf, .glb or .stl. | ||
| 39 | bool IsMeshPath(const std::filesystem::path& path); | ||
| 40 | |||
| 41 | /// Writes meshes drawn once per node, in the format the extension names. glTF (.glb, or .gltf | ||
| 42 | /// with a .bin beside it) stores each mesh once and instances it; OBJ (with an .mtl beside it) | ||
| 43 | /// writes one object per node; both are y-up, TerrainGen's z-up (x, y, z) written as (x, z, -y). | ||
| 44 | /// STL (binary) gets every node's mesh merged, z-up, without materials. | ||
| 45 | /// @throws std::invalid_argument for another extension, no meshes or nodes, an empty or invalid | ||
| 46 | /// mesh, mismatched normals, a node naming no mesh, a scale that is zero or not finite, or a pose | ||
| 47 | /// whose rotation is not a rotation. | ||
| 48 | /// @throws std::runtime_error if a file cannot be written. | ||
| 49 | void WriteScene(const std::filesystem::path& path, const std::vector<SceneMesh>& meshes, | ||
| 50 | const std::vector<SceneNode>& nodes); | ||
| 51 | |||
| 52 | /// Writes one mesh, as `WriteScene` with a single node. | ||
| 53 | /// @throws std::invalid_argument and std::runtime_error as `WriteScene`. | ||
| 54 | void WriteMesh(const std::filesystem::path& path, const SceneMesh& mesh); | ||
| 55 | |||
| 56 | /// Reads every triangle of an .obj (polygons triangulated), a .gltf or .glb (every triangle | ||
| 57 | /// primitive of the default scene, with its nodes' transforms), a binary or ASCII .stl, or an ICQ | ||
| 58 | /// shape model in kilometres (.icq, as `ReadIcq` and `IcqToMesh`), in metres and z-up, with the | ||
| 59 | /// first material's diffuse colour where the format has one. Normals are not read. | ||
| 60 | /// @throws std::invalid_argument for another extension. | ||
| 61 | /// @throws std::runtime_error if the file cannot be read or holds no triangles. | ||
| 62 | SceneMesh ReadMesh(const std::filesystem::path& path); | ||
| 63 | |||
| 64 | } // namespace terraingen | ||
| 65 |