TerrainGen coverage


terraingen/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
25 / 25
100.0%
Branches:
22 / 44
50.0%
Functions:
3 / 3, 1 excl
100.0%

layers/boulders/boulder_shape.h
Line Branch Exec Source
1 /// @file
2 /// @brief Procedural boulder meshes: styles, shape options and seeded shape generation.
3 #pragma once
4
5 #include "terraingen/mesh/io/mesh_io.h"
6 #include "terraingen/mesh/mesh.h"
7 #include "terraingen/mesh/polyhedra.h"
8
9 #include <cstddef>
10 #include <cstdint>
11 #include <memory>
12 #include <string>
13 #include <vector>
14
15 namespace terraingen {
16
17 /// An interval to draw a value uniformly from.
18 struct ValueRange {
19 460 double min = 0.0; ///< Lower end.
20 460 double max = 0.0; ///< Upper end, >= `min`.
21
22
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 460 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 460 times.
460 bool operator==(const ValueRange&) const = default;
23 };
24
25 /// One kind of boulder: the solid it starts from and the ranges its shape is drawn from.
26 ///
27 /// The solid is subdivided, stretched, rounded, roughened and cut by fracture planes, every vertex
28 /// moving only along its ray from the origin, so the mesh never folds over itself. Ratios and
29 /// lengths are in long-axis lengths.
30 struct BoulderStyle {
31 92 std::string name; ///< Label, e.g. "block".
32 92 double weight = 1.0; ///< Relative share of boulders of this style.
33 /// The solid the shape starts from.
34 92 BaseSolid solid = BaseSolid::Icosahedron;
35 92 ValueRange intermediate{0.6, 0.85}; ///< b / a, the intermediate axis over the long one.
36 92 ValueRange shortAxis{0.4, 0.6}; ///< c / a, the short (vertical) axis over the long one.
37 92 ValueRange rounding{0.0, 0.0}; ///< Share toward the ellipsoid: 0 keeps corners, 1 is it.
38 92 int minFractures = 0; ///< Fewest fracture planes.
39 92 int maxFractures = 0; ///< Most fracture planes.
40 92 ValueRange fractureDepth{0.6, 0.9}; ///< Plane offset as a share of the shape's reach.
41 92 double maxFractureTilt = 1.0; ///< Largest |z| of a fracture normal, in [0, 1].
42 92 double noiseAmplitude = 0.05; ///< Largest relative change of the radius by noise.
43 92 double noiseWavelength = 0.6; ///< Wavelength of the first noise octave.
44 92 int noiseOctaves = 3; ///< Noise octaves, each half the wavelength.
45 /// How far edges and corners are worn back where faces meet, as weathering rounds them, in
46 /// long-axis lengths; 0 keeps them sharp.
47 92 ValueRange edgeSoftness{0.0, 0.0};
48 /// How far fracture faces undulate, as a share of each plane's offset; 0 keeps them flat.
49 92 double faceRoughness = 0.0;
50
51
15/30
✗ Branch 1 not taken.
✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 92 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 92 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 92 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 92 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 92 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 92 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 92 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 92 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 92 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 92 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 92 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 92 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 92 times.
92 bool operator==(const BoulderStyle&) const = default;
52 };
53
54 /// The default mix of boulder styles, every one cut irregularly, weathered at its edges and rough
55 /// on its faces: polyhedra from a sphere (angular, platy, subrounded) most of all, then blocks from
56 /// a cube, wedges, pyramids, rounded boulders, shards from a tetrahedron and near-spheres.
57 std::vector<BoulderStyle> DefaultBoulderStyles();
58
59 /// Settings for `GenerateBoulderShape`.
60 struct BoulderShapeOptions {
61 12 std::vector<BoulderStyle> styles = DefaultBoulderStyles(); ///< Styles to pick from by weight.
62 12 int subdivisions = 3; ///< Times the solid's triangles are split in four.
63 12 std::uint32_t seed = 0; ///< Seed shared by every shape.
64 /// Scales every style's edge softness: 0 gives sharp edges, 1 the styles' own, more is more
65 /// worn.
66 12 double weathering = 1.0;
67 /// Rock meshes, such as `ReadMesh` reads, that replace the styles when not empty: each seed
68 /// picks one, normalised to the unit form of `BoulderShape` with its z axis kept vertical.
69 12 std::vector<std::shared_ptr<const SceneMesh>> library{};
70
71
5/10
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
12 bool operator==(const BoulderShapeOptions&) const = default;
72 };
73
74 /// Checks boulder shape options.
75 /// @throws std::invalid_argument for no styles, a style with a negative weight, all weights zero,
76 /// an empty or inverted range, axis ratios outside (0, 1], rounding or depths outside [0, 1],
77 /// fracture counts not in 0 <= min <= max <= 64, a tilt outside [0, 1], noise amplitude outside
78 /// [0, 1), a non-positive wavelength, octaves outside 1 to 12, an edge softness outside [0, 0.5],
79 /// a face roughness outside [0, 0.5], a negative weathering, or subdivisions outside 0 to 6,
80 /// or a library mesh that is null, invalid or flat along an axis.
81 void ValidateBoulderShapeOptions(const BoulderShapeOptions& options);
82
83 /// A boulder's shape in unit form, with the origin inside it.
84 struct BoulderShape {
85 TriangleMesh mesh; ///< Long axis along x, extent exactly 1.
86 std::size_t style = 0; ///< Index into the options' styles, or its library when it has one.
87 double intermediate = 1.0; ///< Extent along y, in long-axis lengths.
88 double shortAxis = 1.0; ///< Extent along z, in long-axis lengths.
89 MeshMaterial material{"rock", {0.5, 0.5, 0.5}}; ///< The library mesh's, or plain grey.
90 };
91
92 /// `mesh` in the unit form of `BoulderShape`: centred on its box, turned about z so its longer
93 /// horizontal side lies along x, and scaled so that side is 1 long.
94 /// @throws std::invalid_argument for a mesh that is invalid or flat along an axis.
95 BoulderShape NormalizedBoulderShape(const SceneMesh& mesh);
96
97 /// The shape a seed gives, a pure function of the seed and options; every subdivision level
98 /// gives the same shape in finer detail.
99 /// @param shapeSeed E.g. from `BoulderShapeSeed`.
100 /// @throws std::invalid_argument as `ValidateBoulderShapeOptions`.
101 BoulderShape GenerateBoulderShape(std::uint64_t shapeSeed, const BoulderShapeOptions& options);
102
103 /// The shape seed of the boulder with ID `id`: `id` itself for 0 `prototypes`, otherwise `id`
104 /// hashed into [0, `prototypes`), so a field can be drawn with a small library of instanced meshes.
105 std::uint64_t BoulderShapeSeed(std::uint64_t id, std::uint32_t prototypes = 0);
106
107 } // namespace terraingen
108