diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a42e3783..b1c216d3a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -467,13 +467,13 @@ jobs: - name: no_std lint run: | - cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render + cargo clippy --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh - name: no_std build # This is `cargo build`, not `cargo check`, because `cargo check` won't detect problems like # use of undefined linker symbols. Not sure if that matters. run: | - cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render + cargo build --target=thumbv7em-none-eabihf --no-default-features -p all-is-cubes -p all-is-cubes-render -p all-is-cubes-mesh fuzz: # Don't spend time on fuzzing if the build failed indicating the code is bad other ways diff --git a/all-is-cubes-desktop/Cargo.toml b/all-is-cubes-desktop/Cargo.toml index 15540a7b5..89de6edb1 100644 --- a/all-is-cubes-desktop/Cargo.toml +++ b/all-is-cubes-desktop/Cargo.toml @@ -38,7 +38,12 @@ required-features = ["record"] # builds. default = ["audio", "import", "record", "terminal"] # Producing image or video recording, or any exported/saved data. -record = ["dep:png", "all-is-cubes-port/export", "all-is-cubes-port/all-formats"] +record = [ + "dep:png", + "all-is-cubes-mesh", # used in glTF recording + "all-is-cubes-port/export", + "all-is-cubes-port/all-formats", +] # Importing non-native data formats. import = ["all-is-cubes-port/import", "all-is-cubes-port/all-formats"] # Required for `--graphics=terminal` and `--graphics=print`; @@ -47,7 +52,12 @@ terminal = ["dep:ratatui", "dep:unicode-width"] # Game audio output support. audio = ["dep:kira"] # Adds rerun logging support. Intended mainly for development of All is Cubes itself. -rerun = ["dep:re_sdk", "all-is-cubes/rerun", "all-is-cubes-gpu/rerun"] +rerun = [ + "dep:re_sdk", + "all-is-cubes/rerun", + "all-is-cubes-gpu/rerun", + "all-is-cubes-mesh", +] # TODO: Define a feature with which to turn off windowing & GPU support. [dependencies] @@ -55,7 +65,7 @@ all-is-cubes = { workspace = true, features = ["auto-threads", "save"] } # TODO: make template support an optional feature, and this dependency with it all-is-cubes-content = { workspace = true } all-is-cubes-gpu = { workspace = true, features = ["auto-threads", "wgpu"] } -all-is-cubes-mesh = { workspace = true } +all-is-cubes-mesh = { workspace = true, optional = true, features = ["dynamic"] } # TODO: make this optional # TODO: make all file access an optional feature all-is-cubes-port = { workspace = true, features = ["import", "native"] } # TODO: make raytracer optional diff --git a/all-is-cubes-gpu/Cargo.toml b/all-is-cubes-gpu/Cargo.toml index 34adb0ca1..36d5db1c7 100644 --- a/all-is-cubes-gpu/Cargo.toml +++ b/all-is-cubes-gpu/Cargo.toml @@ -50,7 +50,7 @@ auto-threads = [ [dependencies] all-is-cubes = { workspace = true, features = ["std"] } -all-is-cubes-mesh = { workspace = true } +all-is-cubes-mesh = { workspace = true, features = ["dynamic"] } all-is-cubes-render = { workspace = true, features = ["raytracer"] } bytemuck = { workspace = true, features = ["derive"] } cfg-if = { workspace = true } diff --git a/all-is-cubes-mesh/Cargo.toml b/all-is-cubes-mesh/Cargo.toml index 8d70a1bde..f4b012383 100644 --- a/all-is-cubes-mesh/Cargo.toml +++ b/all-is-cubes-mesh/Cargo.toml @@ -12,7 +12,7 @@ categories = ["games", "graphics", "rendering"] keywords = ["all-is-cubes", "voxel", "mesh"] [package.metadata.docs.rs] -features = ["_full-documentation"] +features = ["_full-documentation", "arbitrary", "dynamic"] [lib] # Disable running as benchmark so that the default doesn't interfere with Criterion usage. @@ -31,6 +31,14 @@ required-features = ["rerun"] [features] default = [] +# Updating meshes as their data sources change. Requires std. +dynamic = [ + "dep:flume", + "dep:futures-channel", + "dep:futures-util", + "dep:hashbrown", + "dep:log", +] # Adds support for mesh generation performance logging to Rerun. rerun = ["all-is-cubes/rerun"] # Adds `impl arbitrary::Arbitrary for ...` @@ -52,13 +60,13 @@ bitvec = { workspace = true } bytemuck = { workspace = true } cfg-if = { workspace = true } either = { workspace = true } -flume = { workspace = true } -futures-channel = { workspace = true } -futures-util = { workspace = true } -hashbrown = { workspace = true } +flume = { workspace = true, optional = true } +futures-channel = { workspace = true, optional = true } +futures-util = { workspace = true, optional = true } +hashbrown = { workspace = true, optional = true } indoc = { workspace = true } itertools = { workspace = true } -log = { workspace = true } +log = { workspace = true, optional = true } mutants = { workspace = true } num-traits = { workspace = true } ordered-float = { workspace = true } diff --git a/all-is-cubes-mesh/benches/mesh.rs b/all-is-cubes-mesh/benches/mesh.rs index 3e8b79927..5e812f1fd 100644 --- a/all-is-cubes-mesh/benches/mesh.rs +++ b/all-is-cubes-mesh/benches/mesh.rs @@ -1,31 +1,27 @@ #![allow(missing_docs)] -use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; +use criterion::{criterion_main, BatchSize, Criterion}; use all_is_cubes::block::{Block, Resolution::R16, AIR}; use all_is_cubes::color_block; use all_is_cubes::content::make_some_voxel_blocks; use all_is_cubes::math::{GridAab, Rgba}; use all_is_cubes::space::Space; -use all_is_cubes::time; -use all_is_cubes::universe::{Handle, Name, Universe}; -use all_is_cubes_render::camera::{Camera, GraphicsOptions, Viewport}; -use all_is_cubes_render::Flaws; - -use all_is_cubes_mesh::testing::Allocator; -use all_is_cubes_mesh::testing::TextureMt as Mt; -use all_is_cubes_mesh::{ - block_meshes_for_space, dynamic, BlockMesh, BlockMeshes, MeshOptions, SpaceMesh, -}; - -criterion_group!( - benches, - block_mesh_benches, - space_mesh_benches, - slow_mesh_benches, - dynamic_benches, -); +use all_is_cubes::universe::Universe; +use all_is_cubes_render::camera::GraphicsOptions; + +use all_is_cubes_mesh::testing::{Allocator, TextureMt as Mt}; +use all_is_cubes_mesh::{block_meshes_for_space, BlockMesh, BlockMeshes, MeshOptions, SpaceMesh}; + criterion_main!(benches); +fn benches() { + let mut c = Criterion::default().configure_from_args(); + block_mesh_benches(&mut c); + space_mesh_benches(&mut c); + slow_mesh_benches(&mut c); + #[cfg(feature = "dynamic")] + dynamic_benches(&mut c); +} fn block_mesh_benches(c: &mut Criterion) { let mut g = c.benchmark_group("block"); @@ -172,7 +168,14 @@ fn slow_mesh_benches(c: &mut Criterion) { }); } +#[cfg(feature = "dynamic")] fn dynamic_benches(c: &mut Criterion) { + use all_is_cubes::time; + use all_is_cubes::universe::{Handle, Name}; + use all_is_cubes_mesh::dynamic; + use all_is_cubes_render::camera::{Camera, Viewport}; + use all_is_cubes_render::Flaws; + let mut g = c.benchmark_group("dynamic"); let graphics_options = GraphicsOptions::default(); let camera = Camera::new(graphics_options, Viewport::with_scale(1.0, [100, 100])); diff --git a/all-is-cubes-mesh/src/block_mesh.rs b/all-is-cubes-mesh/src/block_mesh.rs index e0a65044e..57bd23e7d 100644 --- a/all-is-cubes-mesh/src/block_mesh.rs +++ b/all-is-cubes-mesh/src/block_mesh.rs @@ -151,6 +151,7 @@ impl BlockMesh { // chunk meshes. That's implemented but not fully settled yet. Think about whether this should // be public and whether it should count indices or whole triangles. // Whatever is decided, also update `MeshMeta::count_indices()`. + #[cfg_attr(not(feature = "dynamic"), allow(dead_code))] pub(crate) fn count_indices(&self) -> usize { self.all_face_meshes() .map(|(_, fm)| fm.indices_opaque.len() + fm.indices_transparent.len()) @@ -160,6 +161,7 @@ impl BlockMesh { /// Update this mesh's textures in-place to the given new block data, if this is /// possible without changing the vertices. // TODO: non-public while we decide whether it's a good interface + #[cfg_attr(not(feature = "dynamic"), allow(dead_code))] #[must_use] #[mutants::skip] // optimization, doesn't change things if it fails pub(crate) fn try_update_texture_only(&mut self, block: &EvaluatedBlock) -> bool { diff --git a/all-is-cubes-mesh/src/block_mesh/viz.rs b/all-is-cubes-mesh/src/block_mesh/viz.rs index f56ef5d80..ea02d75bc 100644 --- a/all-is-cubes-mesh/src/block_mesh/viz.rs +++ b/all-is-cubes-mesh/src/block_mesh/viz.rs @@ -15,6 +15,7 @@ use { all_is_cubes::math::{Cube, GridAab, GridVector}, all_is_cubes::rerun_glue as rg, alloc::vec::Vec, + core::iter, itertools::Itertools as _, }; @@ -213,11 +214,10 @@ impl Viz { .mesh_vertex_positions .extend(vertex_positions.iter().copied()); state.mesh_vertex_colors.extend( - std::iter::repeat(rg::components::Color(color_fn().into())) - .take(vertex_positions.len()), + iter::repeat(rg::components::Color(color_fn().into())).take(vertex_positions.len()), ); state.mesh_vertex_normals.extend( - std::iter::repeat(rg::components::Vector3D(rg::convert_vec( + iter::repeat(rg::components::Vector3D(rg::convert_vec( normal.normal_vector::(), ))) .take(vertex_positions.len()), diff --git a/all-is-cubes-mesh/src/lib.rs b/all-is-cubes-mesh/src/lib.rs index 404f26a61..9d3c28e3b 100644 --- a/all-is-cubes-mesh/src/lib.rs +++ b/all-is-cubes-mesh/src/lib.rs @@ -23,20 +23,14 @@ //! [`GfxVertex`] and [`texture::Allocator`] traits, then implement [`MeshTypes`] to bundle them //! together. -// This crate is *almost* `no_std` compatible; the tricky parts are synchronization stuff: -// * the `Mutex` that `chunked_mesh::CsmTodo` uses. -// * the `flume` channels used for background mesh calculation. -// We could address that by exporting `all_is_cubes::util::maybe_sync::Mutex` and using some -// non-Sync channel implementation, but I don't want to do that (and switch hash maps to -// `hashbrown`) until I have some imaginable use case for mesh building on a `no_std` target. -// So for now, the code is just in a state of “reveal how close it is”, hence using `core` and -// `alloc` imports. #![no_std] // Crate-specific lint settings. (General settings can be found in the workspace manifest.) #![forbid(unsafe_code)] #![cfg_attr(test, allow(clippy::large_stack_arrays))] extern crate alloc; + +#[cfg(any(test, feature = "dynamic"))] #[macro_use] extern crate std; @@ -48,7 +42,9 @@ mod block_vertex; pub use block_vertex::*; mod block_mesh; pub use block_mesh::*; +#[cfg(feature = "dynamic")] mod cache; +#[cfg(feature = "dynamic")] pub mod dynamic; mod index_vec; pub use index_vec::*; diff --git a/all-is-cubes-mesh/src/testing.rs b/all-is-cubes-mesh/src/testing.rs index 3f9a4ad3b..f92438d5c 100644 --- a/all-is-cubes-mesh/src/testing.rs +++ b/all-is-cubes-mesh/src/testing.rs @@ -13,7 +13,6 @@ use all_is_cubes::space::Space; use all_is_cubes::util::{ConciseDebug, Fmt}; use all_is_cubes_render::camera::GraphicsOptions; -use crate::dynamic::DynamicMeshTypes; use crate::{block_meshes_for_space, texture, BlockMeshes, BlockVertex, MeshTypes, SpaceMesh}; /// Generic [`MeshTypes`] implementor for tests to use. @@ -30,8 +29,9 @@ where type Alloc = Alloc; type Tile = Alloc::Tile; } -impl DynamicMeshTypes - for Mt +#[cfg(feature = "dynamic")] +impl + crate::dynamic::DynamicMeshTypes for Mt where Alloc::Point: Fmt, // TODO: clunky bound {