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}