From 1e6cdb74cbaa22e43eb683fa746029d066a49710 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sun, 5 Nov 2023 01:29:04 +0100 Subject: [PATCH 01/22] update for Bevy 0.12 --- Cargo.toml | 4 ++-- examples/gltf.rs | 27 +++++++++++------------- examples/lines.rs | 2 +- examples/many.rs | 24 +++++++++++---------- src/asset_loaders.rs | 50 ++++++++++++++++++++++++++++++++++++-------- src/lib.rs | 8 +++---- 6 files changed, 72 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3504c5a..a705712 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ itertools = "0.11" version = "0.4" [dependencies.bevy] -version = "0.11" +version = "0.12" features = ["bevy_render", "bevy_asset"] default-features = false @@ -27,7 +27,7 @@ default-features = false rand = "0.8" [dev-dependencies.bevy] -version = "0.11" +version = "0.12" features = [ "bevy_ui", "bevy_text", diff --git a/examples/gltf.rs b/examples/gltf.rs index e643e2f..9ae38f3 100644 --- a/examples/gltf.rs +++ b/examples/gltf.rs @@ -4,15 +4,13 @@ use bevy::{ math::Vec3Swizzles, pbr::NotShadowCaster, prelude::*, - reflect::TypeUuid, window::PrimaryWindow, }; use bevy_pathmesh::{PathMesh, PathMeshPlugin}; use rand::Rng; use std::f32::consts::FRAC_PI_2; -const HANDLE_TRIMESH_OPTIMIZED: HandleUntyped = - HandleUntyped::weak_from_u64(PathMesh::TYPE_UUID, 0); +const HANDLE_TRIMESH_OPTIMIZED: Handle = Handle::weak_from_u128(0); fn main() { App::new() @@ -127,7 +125,7 @@ fn setup(mut commands: Commands, asset_server: Res) { ..Default::default() }); - commands.insert_resource(CurrentMesh(HANDLE_TRIMESH_OPTIMIZED.typed())); + commands.insert_resource(CurrentMesh(HANDLE_TRIMESH_OPTIMIZED)); } fn check_textures( @@ -135,7 +133,7 @@ fn check_textures( gltf: ResMut, asset_server: Res, ) { - if let LoadState::Loaded = asset_server.get_load_state(gltf.id()) { + if let Some(LoadState::Loaded) = asset_server.get_load_state(gltf.id()) { next_state.set(AppState::Playing); } } @@ -170,7 +168,7 @@ fn setup_scene( let mut material: StandardMaterial = Color::ALICE_BLUE.into(); material.perceptual_roughness = 1.0; let ground_material = materials.add(material); - if let Some(gltf) = gltfs.get(&gltf) { + if let Some(gltf) = gltfs.get(gltf.id()) { let mesh = gltf_meshes.get(&gltf.named_meshes["obstacles"]).unwrap(); let mut material: StandardMaterial = Color::GRAY.into(); material.perceptual_roughness = 1.0; @@ -223,7 +221,7 @@ fn setup_scene( } } - if let Some(gltf) = gltfs.get(&gltf) { + if let Some(gltf) = gltfs.get(gltf.id()) { { let navmesh = bevy_pathmesh::PathMesh::from_bevy_mesh( meshes @@ -248,9 +246,9 @@ fn setup_scene( visibility: Visibility::Hidden, ..Default::default() }, - NavMeshDisp(HANDLE_TRIMESH_OPTIMIZED.typed()), + NavMeshDisp(HANDLE_TRIMESH_OPTIMIZED), )); - pathmeshes.set_untracked(HANDLE_TRIMESH_OPTIMIZED, navmesh); + pathmeshes.insert(HANDLE_TRIMESH_OPTIMIZED, navmesh); } commands @@ -303,7 +301,7 @@ fn give_target_auto( let Some(path) = navmesh.transformed_path(transform.translation, Vec3::new(x, 0.0, z)) else { - break + break; }; if let Some((first, remaining)) = path.path.split_first() { let mut remaining = remaining.to_vec(); @@ -363,17 +361,16 @@ fn give_target_on_click( let (camera, transform) = camera.get_single().ok()?; let ray = camera.viewport_to_world(transform, position)?; let denom = Vec3::Y.dot(ray.direction); - let t = (Vec3::ZERO - ray.origin).dot(Vec3::Y) / denom; + let t = (Vec3::ZERO - ray.origin).dot(Vec3::Y) / denom; let target = ray.origin + ray.direction * t; navmesh.transformed_is_in_mesh(target).then_some(target) })() else { - return + return; }; for (entity, transform, mut object) in object_query.iter_mut() { - let Some(path) = navmesh.transformed_path(transform.translation, target) - else { - break + let Some(path) = navmesh.transformed_path(transform.translation, target) else { + break; }; if let Some((first, remaining)) = path.path.split_first() { let mut remaining = remaining.to_vec(); diff --git a/examples/lines.rs b/examples/lines.rs index ca27033..da14ff1 100644 --- a/examples/lines.rs +++ b/examples/lines.rs @@ -283,7 +283,7 @@ fn compute_paths( meshes: Res, pathmeshes: Res>, ) { - for ev in event_new_step_path.iter() { + for ev in event_new_step_path.read() { if path_to_display.steps.is_empty() { path_to_display.steps.push(ev.0); return; diff --git a/examples/many.rs b/examples/many.rs index f641af9..a273ee6 100644 --- a/examples/many.rs +++ b/examples/many.rs @@ -64,7 +64,7 @@ fn main() { ), ) .add_systems(FixedUpdate, (spawn, update_ui)) - .insert_resource(FixedTime::new_from_secs(0.1)) + .insert_resource(Time::::from_seconds(0.1)) .run(); } @@ -289,17 +289,19 @@ fn spawn( .unwrap(); let position = (in_mesh - MESH_SIZE / 2.0) * factor; let color = Color::hsl(rng.gen_range(0.0..360.0), 1.0, 0.5).as_rgba(); + commands.spawn(( - SpriteBundle { - sprite: Sprite { - color, - custom_size: Some(Vec2::ONE), - ..default() - }, - transform: Transform::from_translation(position.extend(1.0)) - .with_scale(Vec3::splat(5.0)), - ..default() - }, + // SpriteBundle { + // sprite: Sprite { + // color, + // custom_size: Some(Vec2::ONE), + // ..default() + // }, + // transform: Transform::from_translation(position.extend(1.0)) + // .with_scale(Vec3::splat(5.0)), + // ..default() + // }, + Transform::from_translation(position.extend(1.0)).with_scale(Vec3::splat(5.0)), Navigator { speed: rng.gen_range(50.0..100.0), color, diff --git a/src/asset_loaders.rs b/src/asset_loaders.rs index 6cd5ae0..8ec03fa 100644 --- a/src/asset_loaders.rs +++ b/src/asset_loaders.rs @@ -1,9 +1,9 @@ //! Asset loaders that can load a [`PathMesh`] from a file -use std::sync::Arc; +use std::{error::Error, fmt::Display, sync::Arc}; use bevy::{ - asset::{AssetLoader, LoadContext, LoadedAsset}, + asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}, prelude::{Transform, Vec3}, utils::BoxedFuture, }; @@ -11,6 +11,28 @@ use polyanya::PolyanyaFile; use crate::PathMesh; +/// Error that can happen while reading a `PathMesh` from a file +#[derive(Debug)] +pub enum PathMeshLoaderError { + /// Error when reading file + Io(std::io::Error), +} + +impl Display for PathMeshLoaderError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PathMeshLoaderError::Io(io_error) => write!(f, "IO error: {}", io_error), + } + } +} + +impl Error for PathMeshLoaderError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + PathMeshLoaderError::Io(io_error) => Some(io_error), + } + } +} /// Asset loader for a mesh in the `mesh 2` format with a `.polyanya.mesh` extension. /// /// See for format description. @@ -18,17 +40,27 @@ use crate::PathMesh; pub struct PathMeshPolyanyaLoader; impl AssetLoader for PathMeshPolyanyaLoader { + type Asset = PathMesh; + type Settings = (); + type Error = PathMeshLoaderError; + fn load<'a>( &'a self, - bytes: &'a [u8], - load_context: &'a mut LoadContext, - ) -> BoxedFuture<'a, Result<(), bevy::asset::Error>> { + reader: &'a mut Reader, + _settings: &'a Self::Settings, + _load_context: &'a mut LoadContext, + ) -> BoxedFuture<'a, Result> { Box::pin(async move { - load_context.set_default_asset(LoadedAsset::new(PathMesh { - mesh: Arc::new(PolyanyaFile::from_bytes(bytes).into()), + let mut bytes = Vec::new(); + reader + .read_to_end(&mut bytes) + .await + .map_err(|e| PathMeshLoaderError::Io(e))?; + let pathmesh = PathMesh { + mesh: Arc::new(PolyanyaFile::from_bytes(bytes.as_slice()).into()), transform: Transform::from_scale(Vec3::splat(1.)), - })); - Ok(()) + }; + Ok(pathmesh) }) } diff --git a/src/lib.rs b/src/lib.rs index a6f068f..51b63d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ use bevy::reflect::TypePath; use bevy::render::mesh::{MeshVertexAttributeId, VertexAttributeValues}; use bevy::{ prelude::*, - reflect::TypeUuid, render::{mesh::Indices, render_resource::PrimitiveTopology}, }; use itertools::Itertools; @@ -31,8 +30,8 @@ pub struct PathMeshPlugin; impl Plugin for PathMeshPlugin { fn build(&self, app: &mut App) { - app.add_asset::() - .init_asset_loader::(); + app.register_asset_loader(asset_loaders::PathMeshPolyanyaLoader) + .init_asset::(); } } @@ -49,8 +48,7 @@ pub use polyanya::Path; use polyanya::Trimesh; /// A navigation mesh -#[derive(Debug, TypePath, TypeUuid, Clone)] -#[uuid = "807C7A31-EA06-4A3B-821B-6E91ADB95734"] +#[derive(Debug, TypePath, Clone, Asset)] pub struct PathMesh { mesh: Arc, transform: Transform, From 5992e48ab76e8628a97b2f5fff2d7be4b2960db2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sun, 5 Nov 2023 01:55:33 +0100 Subject: [PATCH 02/22] multi threads! --- Cargo.toml | 1 + examples/many.rs | 62 ++++++++++++++++++++++++++++-------------------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a705712..ae6dce6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ features = [ "tonemapping_luts", "ktx2", "zstd", + "multi-threaded", ] default-features = false diff --git a/examples/many.rs b/examples/many.rs index a273ee6..5198529 100644 --- a/examples/many.rs +++ b/examples/many.rs @@ -274,7 +274,13 @@ fn spawn( let screen = Vec2::new(window.width(), window.height()); let factor = (screen.x / MESH_SIZE.x).min(screen.y / MESH_SIZE.y); - for _ in 0..100 { + #[cfg(target_arch = "wasm32")] + let per_update = 20; + #[cfg(not(target_arch = "wasm32"))] + let per_update = 100; + + let mut to_spawn = Vec::with_capacity(per_update); + for _ in 0..per_update { let in_mesh = *[ Vec2::new(575.0, 410.0), Vec2::new(387.0, 524.0), @@ -290,24 +296,24 @@ fn spawn( let position = (in_mesh - MESH_SIZE / 2.0) * factor; let color = Color::hsl(rng.gen_range(0.0..360.0), 1.0, 0.5).as_rgba(); - commands.spawn(( - // SpriteBundle { - // sprite: Sprite { - // color, - // custom_size: Some(Vec2::ONE), - // ..default() - // }, - // transform: Transform::from_translation(position.extend(1.0)) - // .with_scale(Vec3::splat(5.0)), - // ..default() - // }, - Transform::from_translation(position.extend(1.0)).with_scale(Vec3::splat(5.0)), + to_spawn.push(( + SpriteBundle { + sprite: Sprite { + color, + custom_size: Some(Vec2::ONE), + ..default() + }, + transform: Transform::from_translation(position.extend(1.0)) + .with_scale(Vec3::splat(5.0)), + ..default() + }, Navigator { speed: rng.gen_range(50.0..100.0), color, }, )); } + commands.spawn_batch(to_spawn); } } @@ -419,23 +425,27 @@ fn move_navigator( mut query: Query<(Entity, &mut Transform, &mut Path, &Navigator)>, primary_window: Query<&Window, With>, time: Res