all_is_cubes_mesh/lib.rs
1//! Data structures and algorithms for converting [`all_is_cubes`] voxel data to triangle
2//! meshes for rendering or export.
3//!
4//! All of the algorithms here are independent of graphics API, but they require providing
5//! vertex and texture data types suitable for the API or data format you wish to use.
6//!
7//! Restrictions and caveats:
8//! * The algorithms always generate triangles with counterclockwise winding order.
9//! * The generated meshes are designed for rendering and not for purposes which require
10//! “watertight” meshes such as 3D printing systems.
11//! * The generated meshes are in the “blocky” style (have the appearance of being made of
12//! axis-aligned cubes) rather than attempting to present a smooth surface (as would be
13//! produced by, for example, the marching cubes algorithm); this is consistent with the
14//! approach used by [`all_is_cubes`] as a whole.
15//!
16//! # Getting started
17//!
18//! [`BlockMesh`] and [`SpaceMesh`] are the key types; everything else supports their
19//! creation and usage. For real-time dynamically modified meshes, use
20//! [`dynamic::ChunkedSpaceMesh`].
21//!
22//! To support a new API/format, you will need to create suitable implementations of the
23//! [`Vertex`] and [`texture::Allocator`] traits, then implement [`MeshTypes`] to bundle them
24//! together.
25//!
26//! ## Package features
27//!
28//! This package defines the following feature flags:
29//!
30//! * `"auto-threads"`:
31//! Enables implicit use of threads for parallel and background processing, including via
32//! [`rayon`]’s global thread pool.
33//! * `"dynamic"`:
34//! Enable the `dynamic` module.
35//! Incompatible with `no_std` platforms.
36
37#![no_std]
38// Crate-specific lint settings. (General settings can be found in the workspace manifest.)
39#![cfg_attr(test, allow(clippy::large_stack_arrays))]
40
41extern crate alloc;
42
43#[cfg(any(
44 test,
45 feature = "arbitrary", // derive uses std paths
46 feature = "dynamic", // uses std::sync
47))]
48#[cfg_attr(test, macro_use)]
49extern crate std;
50
51use core::fmt;
52
53use all_is_cubes_render::camera::{GraphicsOptions, TransparencyOption};
54
55// -------------------------------------------------------------------------------------------------
56
57mod aabb;
58use aabb::Aabb;
59pub use aabb::Aabbs;
60mod block_mesh;
61pub use block_mesh::*;
62#[cfg(feature = "dynamic")]
63mod cache;
64mod depth_sorting;
65pub use depth_sorting::{DepthOrdering, DepthSortInfo, DepthSortResult};
66#[cfg(feature = "dynamic")]
67pub mod dynamic;
68mod index_vec;
69pub use index_vec::*;
70mod space_mesh;
71pub use space_mesh::*;
72#[doc(hidden)]
73pub mod testing;
74pub mod texture;
75mod vertex;
76pub use vertex::*;
77
78#[cfg(test)]
79mod tests;
80
81// -------------------------------------------------------------------------------------------------
82
83/// Parameters for creating meshes that aren't the block/space data itself
84/// (or the texture allocator, since that may need to be mutable).
85///
86/// Creating this and comparing it against a previous instance is appropriate for
87/// determining when to invalidate previously computed meshes. This type is also intended
88/// to make the API future-proof against additional configuration being needed.
89///
90/// See also [`MeshTypes`] for statically chosen properties of meshes.
91#[derive(Clone, Debug, Eq, PartialEq)]
92#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
93pub struct MeshOptions {
94 /// Input to [`TransparencyOption::limit_alpha()`] applied to all vertex colors and voxels.
95 transparency: TransparencyOption,
96
97 /// Ignore blocks' [`voxels`] data and use only the overall color.
98 ///
99 /// [`voxels`]: all_is_cubes::block::EvaluatedBlock::voxels
100 ignore_voxels: bool,
101}
102
103impl MeshOptions {
104 /// Take the options relevant to mesh generation from the given [`GraphicsOptions`].
105 pub fn new(graphics_options: &GraphicsOptions) -> Self {
106 Self {
107 transparency: graphics_options.transparency.clone(),
108 ignore_voxels: false,
109 }
110 }
111
112 /// Placeholder for use in tests which do not care about any of the
113 /// characteristics that are affected by options (yet).
114 #[doc(hidden)]
115 pub fn dont_care_for_test() -> Self {
116 Self {
117 transparency: TransparencyOption::Volumetric,
118 ignore_voxels: false,
119 }
120 }
121
122 /// Determines what geometry should be produced when a mesh contains transparent voxels,
123 /// after filtering by [`TransparencyOption::limit_alpha()`].
124 pub(crate) fn transparency_format(&self) -> TransparencyFormat {
125 match self.transparency {
126 TransparencyOption::Surface => TransparencyFormat::Surfaces,
127 // TODO: Do this only if the textures support it (but we don't have MeshTypes here)
128 TransparencyOption::Volumetric => TransparencyFormat::BoundingBox,
129 TransparencyOption::Threshold(_) => TransparencyFormat::Surfaces,
130 ref o => {
131 if cfg!(debug_assertions) {
132 unreachable!("missing support for transparency option {o:?}");
133 } else {
134 TransparencyFormat::Surfaces
135 }
136 }
137 }
138 }
139}
140
141/// Bundle of types chosen to support a specific graphics API or other mesh format.
142///
143/// Implement this trait (using a placeholder type which need not store any data) to choose the
144/// vertex format, texture format, and texture coordinates to be used.
145///
146/// The rationale of this trait existing is to be able to avoid numerous type parameters passed
147/// around separately.
148pub trait MeshTypes: 'static {
149 /// Mesh vertex type.
150 type Vertex: Vertex<
151 TexPoint = <Self::Alloc as texture::Allocator>::Point,
152 SecondaryData: fmt::Debug + PartialEq + Send + Sync + 'static,
153 > + fmt::Debug
154 + PartialEq
155 + Send
156 + Sync
157 + 'static;
158
159 /// Texture, or texture atlas, allocator.
160 ///
161 /// If texture support is not desired or possible, use [`texture::NoTextures`] here.
162 type Alloc: texture::Allocator<Tile = Self::Tile> + fmt::Debug + 'static;
163
164 /// Texture handle type.
165 //--
166 // Design note: This `Point` constraint is theoretically redundant with the above `TexPoint`
167 // and `Tile` constraints, but the compiler won't infer it for us.
168 type Tile: texture::Tile<Point = <Self::Alloc as texture::Allocator>::Point>
169 + fmt::Debug
170 + 'static;
171}
172
173/// Determines what geometry should be produced when a mesh contains transparent voxels.
174///
175/// Currently, this is always derived from [`GraphicsOptions::transparency`].
176/// If necessary, it may be made a public option.
177#[derive(Clone, Copy, Debug, Eq, PartialEq)]
178#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
179#[non_exhaustive]
180pub(crate) enum TransparencyFormat {
181 /// Generate triangles for transparent surfaces just like opaque ones.
182 Surfaces,
183
184 /// Generate a single bounding box for all transparent voxels.
185 /// Assume that shading will take care of rendering all details within that box.
186 BoundingBox,
187}