diff --git a/Cargo.toml b/Cargo.toml index 3dabe60..52e5c62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,22 +14,22 @@ documentation = "https://docs.rs/bevy_generative" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bevy = { version = "0.14.0", default-features = false, features = [ +bevy = { version = "0.16.1", default-features = false, features = [ "bevy_core_pipeline", "bevy_pbr", "bevy_ui", ] } -colorgrad = "0.6.2" +colorgrad = "0.7.2" gltf = "1.3.0" image = "0.25" noise = { version = "0.9.0", git = "https://github.com/Razaekel/noise-rs.git" } -rfd = "0.12.1" +rfd = "0.15.4" serde = "1.0.195" serde_json = "1.0.111" wasm-bindgen = "0.2.89" [dev-dependencies] -bevy = "0.14.0" +bevy = "0.16.1" # Enable max optimizations for dependencies, but not for our code: [profile.dev.package."*"] diff --git a/examples/export.rs b/examples/export.rs index aacc6da..2a82d99 100644 --- a/examples/export.rs +++ b/examples/export.rs @@ -11,39 +11,47 @@ fn main() { } fn setup(mut commands: Commands) { - commands.spawn(PointLightBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); + let light_bundle = ( + PointLight::default(), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + + commands.spawn(light_bundle); + + let camera_bundle = ( + Camera3d::default(), + Projection::Perspective(PerspectiveProjection::default()), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + commands.spawn(camera_bundle); + commands.spawn(TerrainBundle::default()); - commands - .spawn(ButtonBundle { - style: Style { - padding: UiRect::all(Val::Px(12.)), - justify_content: JustifyContent::Center, - align_items: AlignItems::Center, - margin: UiRect::all(Val::Px(12.)), - ..default() - }, - border_radius: BorderRadius::all(Val::Px(5.)), - background_color: NORMAL_BUTTON.into(), + let button_bundle = ( + Button, + Node { + padding: UiRect::all(Val::Px(12.)), + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + margin: UiRect::all(Val::Px(12.)), ..default() - }) - .with_children(|parent| { - parent.spawn(TextBundle::from_section( - "Export", - TextStyle { - font_size: 30.0, - color: BUTTON_TEXT.into(), - ..default() - }, - )); - }); + }, + BorderRadius::all(Val::Px(5.)), + BackgroundColor(NORMAL_BUTTON.into()), + ); + + commands.spawn(button_bundle).with_children(|parent| { + let text_bundle = ( + Text::from("Export"), + TextFont { + font_size: 30.0, + ..Default::default() + }, + TextColor(BUTTON_TEXT.into()), + ); + + parent.spawn(text_bundle); + }); } fn export_button( diff --git a/examples/map.rs b/examples/map.rs index 913204c..b1875d4 100644 --- a/examples/map.rs +++ b/examples/map.rs @@ -10,6 +10,7 @@ fn main() { } fn setup(mut commands: Commands) { - commands.spawn(Camera2dBundle::default()); + let camera_bundle = (Camera2d::default(),); + commands.spawn(camera_bundle); commands.spawn(MapBundle::default()); } diff --git a/examples/planet.rs b/examples/planet.rs index fd594c6..2d2f888 100644 --- a/examples/planet.rs +++ b/examples/planet.rs @@ -10,13 +10,18 @@ fn main() { } fn setup(mut commands: Commands) { - commands.spawn(PointLightBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); + let light_bundle = ( + PointLight::default(), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + + commands.spawn(light_bundle); + + let camera_bundle = ( + Camera3d::default(), + Projection::Perspective(PerspectiveProjection::default()), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + commands.spawn(camera_bundle); commands.spawn(PlanetBundle::default()); } diff --git a/examples/terrain.rs b/examples/terrain.rs index 9f00512..e8f56fe 100644 --- a/examples/terrain.rs +++ b/examples/terrain.rs @@ -10,14 +10,19 @@ fn main() { } fn setup(mut commands: Commands) { - commands.spawn(PointLightBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); - commands.spawn(Camera3dBundle { - transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), - ..default() - }); + let light_bundle = ( + PointLight::default(), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + + commands.spawn(light_bundle); + + let camera_bundle = ( + Camera3d::default(), + Projection::Perspective(PerspectiveProjection::default()), + Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), + ); + commands.spawn(camera_bundle); commands.spawn(TerrainBundle { terrain: bevy_generative::terrain::Terrain { resolution: 4, diff --git a/src/map.rs b/src/map.rs index 34ea79e..a1d122a 100644 --- a/src/map.rs +++ b/src/map.rs @@ -14,14 +14,18 @@ //! } //! //! fn setup(mut commands: Commands) { -//! commands.spawn(Camera2dBundle::default()); -//! commands.spawn(MapBundle::default()); +//! let camera_bundle = ( +//! Camera2d::default(), +//! ); +//! commands.spawn(camera_bundle); +//! commands.spawn(MapBundle::default()); //! } //! ``` use bevy::{ prelude::*, render::{render_asset::RenderAssetUsages, render_resource::TextureFormat}, }; +use colorgrad::{Gradient, LinearGradient}; use image::{imageops::FilterType, DynamicImage, Pixel}; use serde::{Deserialize, Serialize}; @@ -64,7 +68,7 @@ pub struct MapBundle { /// See [`Map`](./struct.Map.html) pub map: Map, /// See [`ImageBundle`](../../bevy/prelude/struct.ImageBundle.html) - pub image_bundle: ImageBundle, + pub image_bundle: ImageNode, } impl Default for Map { @@ -79,38 +83,34 @@ impl Default for Map { } } } -fn generate_map(mut images: ResMut>, mut query: Query<(&mut Map, &mut UiImage)>) { +fn generate_map(mut images: ResMut>, mut query: Query<(&mut Map, &mut ImageNode)>) { for (mut map, mut ui_image) in &mut query { map.noise.size = map.size; let noise_values = generate_noise_map(&map.noise); let noise = &mut map.noise; let mut colors: Vec = Vec::with_capacity(noise.regions.len()); - let mut domain: Vec = Vec::with_capacity(noise.regions.len()); + let mut domain: Vec = Vec::with_capacity(noise.regions.len()); for region in &noise.regions { colors.push(colorgrad::Color { - r: f64::from(region.color[0]) / 255.0, - g: f64::from(region.color[1]) / 255.0, - b: f64::from(region.color[2]) / 255.0, - a: f64::from(region.color[3]) / 255.0, + r: f32::from(region.color[0]) / 255.0, + g: f32::from(region.color[1]) / 255.0, + b: f32::from(region.color[2]) / 255.0, + a: f32::from(region.color[3]) / 255.0, }); domain.push(region.position); } - let mut grad = colorgrad::CustomGradient::new() + let grad = colorgrad::GradientBuilder::new() .colors(&colors) .domain(&domain) - .build() + .build::() .unwrap_or_else(|_| { - colorgrad::CustomGradient::new() + colorgrad::GradientBuilder::new() .colors(&colors) - .build() + .build::() .expect("Gradient generation failed") }); - if noise.gradient.segments != 0 { - grad = grad.sharp(noise.gradient.segments, noise.gradient.smoothness); - } - let mut gradient_buffer = image::ImageBuffer::from_pixel( noise.gradient.size[0], noise.gradient.size[1], @@ -119,7 +119,7 @@ fn generate_map(mut images: ResMut>, mut query: Query<(&mut Map, & for (x, _, pixel) in gradient_buffer.enumerate_pixels_mut() { let rgba = grad - .at(f64::from(x) * 100.0 / f64::from(noise.gradient.size[0])) + .at((f64::from(x) * 100.0 / f64::from(noise.gradient.size[0])) as f32) .to_rgba8(); pixel.blend(&image::Rgba(rgba)); } @@ -142,7 +142,7 @@ fn generate_map(mut images: ResMut>, mut query: Query<(&mut Map, & for (x, y, pixel) in image_buffer.enumerate_pixels_mut() { let height = noise_values[x as usize][y as usize]; - let target_color = grad.at(height).to_rgba8(); + let target_color = grad.at(height as f32).to_rgba8(); pixel.blend(&image::Rgba(target_color)); } if !map.same_size { @@ -167,6 +167,6 @@ fn generate_map(mut images: ResMut>, mut query: Query<(&mut Map, & .convert(TextureFormat::Rgba8UnormSrgb) .expect("Could not convert to Rgba8UnormSrgb"); - ui_image.texture = images.add(map_texture); + ui_image.image = images.add(map_texture); } } diff --git a/src/noise.rs b/src/noise.rs index 6dd1739..4a42f32 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -103,7 +103,7 @@ pub struct Region { /// Label of the region pub label: String, /// Percentage below which the region should render - pub position: f64, + pub position: f32, /// Color representing the region pub color: [u8; 4], } diff --git a/src/planet.rs b/src/planet.rs index 954d5f1..3ef63c6 100644 --- a/src/planet.rs +++ b/src/planet.rs @@ -14,27 +14,37 @@ //! } //! //! fn setup(mut commands: Commands) { -//! commands.spawn(PointLightBundle { -//! transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), -//! ..default() -//! }); -//! commands.spawn(Camera3dBundle { -//! transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), -//! ..default() -//! }); -//! commands.spawn(PlanetBundle::default()); +//! let light_bundle = ( +//! PointLight::default(), +//! Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), +//! ); +//! +//! +//! commands.spawn(light_bundle); +//! +//! let camera_bundle = ( +//! Camera3d::default(), +//! Projection::Perspective(PerspectiveProjection::default()), +//! Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), +//! +//! ); +//! commands.spawn(camera_bundle); +//! commands.spawn(PlanetBundle::default()); //! } //! ``` use bevy::{ + pbr::MeshMaterial3d, prelude::{ - App, Assets, Bundle, Component, Handle, Image, Mesh, PbrBundle, Plugin, Query, ResMut, - StandardMaterial, Update, Vec3, + App, Assets, Bundle, Component, Image, Mesh, Plugin, Query, ResMut, StandardMaterial, + Update, Vec3, }, render::{ + mesh::Mesh3d, render_asset::RenderAssetUsages, render_resource::{PrimitiveTopology, TextureFormat}, }, }; +use colorgrad::LinearGradient; use image::Pixel; use serde::{Deserialize, Serialize}; @@ -118,7 +128,7 @@ pub struct PlanetBundle { /// Planet configuration pub planet: Planet, /// Generated mesh data is written to `PbrBundle` - pub pbr_bundle: PbrBundle, + pub pbr_bundle: (Mesh3d, MeshMaterial3d), } /// Plugin to generate planet @@ -142,7 +152,7 @@ fn generate_planet( mut images: ResMut>, mut materials: ResMut>, mut meshes: ResMut>, - mut query: Query<(&mut Planet, &mut Handle, &Handle)>, + mut query: Query<(&mut Planet, &mut Mesh3d, &MeshMaterial3d)>, ) { for (mut planet, mut mesh_handle, material) in &mut query { if let Some(material) = materials.get_mut(material) { @@ -204,7 +214,7 @@ fn generate_planet( mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone()); mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - *mesh_handle = meshes.add(mesh); + *mesh_handle = Mesh3d(meshes.add(mesh)); if planet.export { export_model(&positions, indices, &colors); @@ -216,33 +226,29 @@ fn generate_planet( fn generate_gradient( images: &mut ResMut>, planet: &mut Planet, -) -> colorgrad::Gradient { +) -> colorgrad::LinearGradient { let mut colors: Vec = Vec::with_capacity(planet.regions.len()); - let mut domain: Vec = Vec::with_capacity(planet.regions.len()); + let mut domain: Vec = Vec::with_capacity(planet.regions.len()); for region in &planet.regions { colors.push(colorgrad::Color { - r: f64::from(region.color[0]) / 255.0, - g: f64::from(region.color[1]) / 255.0, - b: f64::from(region.color[2]) / 255.0, - a: f64::from(region.color[3]) / 255.0, + r: f32::from(region.color[0]) / 255.0, + g: f32::from(region.color[1]) / 255.0, + b: f32::from(region.color[2]) / 255.0, + a: f32::from(region.color[3]) / 255.0, }); domain.push(region.position); } - let mut grad = colorgrad::CustomGradient::new() + let grad = colorgrad::GradientBuilder::new() .colors(&colors) .domain(&domain) - .build() + .build::() .unwrap_or_else(|_| { - colorgrad::CustomGradient::new() + colorgrad::GradientBuilder::new() .colors(&colors) - .build() + .build::() .expect("Gradient generation failed") }); - if planet.gradient.segments != 0 { - grad = grad.sharp(planet.gradient.segments, planet.gradient.smoothness); - } - let mut gradient_buffer = image::ImageBuffer::from_pixel( planet.gradient.size[0], planet.gradient.size[1], @@ -250,9 +256,11 @@ fn generate_gradient( ); for (x, _, pixel) in gradient_buffer.enumerate_pixels_mut() { - let rgba = grad - .at(f64::from(x) * 100.0 / f64::from(planet.gradient.size[0])) - .to_rgba8(); + let rgba = colorgrad::Gradient::at( + &grad, + (f64::from(x) * 100.0 / f64::from(planet.gradient.size[0])) as f32, + ) + .to_rgba8(); pixel.blend(&image::Rgba(rgba)); } @@ -268,7 +276,7 @@ fn generate_gradient( grad } -fn generate_face(planet: &Planet, local_up: Vec3, grad: &colorgrad::Gradient) -> MeshData { +fn generate_face(planet: &Planet, local_up: Vec3, grad: &colorgrad::LinearGradient) -> MeshData { let axis_a = Vec3::new(local_up.y, local_up.z, local_up.x); let axis_b = local_up.cross(axis_a); let vertices_count = (planet.resolution * planet.resolution) as usize; @@ -306,7 +314,7 @@ fn generate_face(planet: &Planet, local_up: Vec3, grad: &colorgrad::Gradient) -> let i = x + y * resolution; positions.push([vertex.x, vertex.y, vertex.z]); normals.push([vertex.x, vertex.y, vertex.z]); - let color = grad.at(f64::from(noise_value) * 100.0); + let color = colorgrad::Gradient::at(grad, (f64::from(noise_value) * 100.0) as f32); let color = [ color.r as f32, color.g as f32, diff --git a/src/terrain.rs b/src/terrain.rs index 36f69c0..9ac4d23 100644 --- a/src/terrain.rs +++ b/src/terrain.rs @@ -14,15 +14,28 @@ //! } //! //! fn setup(mut commands: Commands) { -//! commands.spawn(PointLightBundle { -//! transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), -//! ..default() -//! }); -//! commands.spawn(Camera3dBundle { -//! transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), -//! ..default() -//! }); -//! commands.spawn(TerrainBundle::default()); +//! let light_bundle = ( +//! PointLight::default(), +//! Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), +//! ); +//! +//! +//! commands.spawn(light_bundle); +//! +//! let camera_bundle = ( +//! Camera3d::default(), +//! Projection::Perspective(PerspectiveProjection::default()), +//! Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y), +//! +//! ); +//! commands.spawn(camera_bundle); +//! commands.spawn(TerrainBundle { +//! terrain: bevy_generative::terrain::Terrain { +//! resolution: 4, +//! ..default() +//! }, +//! ..default() +//! }); //! } //! ``` use bevy::{ @@ -32,6 +45,7 @@ use bevy::{ render_resource::{PrimitiveTopology, TextureFormat}, }, }; +use colorgrad::LinearGradient; use image::Pixel; use serde::{Deserialize, Serialize}; @@ -80,7 +94,7 @@ pub struct TerrainBundle { /// Terrain configuration pub terrain: Terrain, /// Generated mesh data is written to `PbrBundle` - pub pbr_bundle: PbrBundle, + pub pbr_bundle: (Mesh3d, MeshMaterial3d), } /// Plugin to generate terrain @@ -96,7 +110,7 @@ fn generate_terrain( mut images: ResMut>, mut materials: ResMut>, mut meshes: ResMut>, - mut query: Query<(&mut Terrain, &mut Handle, &Handle)>, + mut query: Query<(&mut Terrain, &mut Mesh3d, &MeshMaterial3d)>, ) { for (mut terrain, mut mesh_handle, material) in &mut query { if let Some(material) = materials.get_mut(material) { @@ -109,34 +123,27 @@ fn generate_terrain( let noise_values = generate_noise_map(&terrain.noise); let mut colors: Vec = Vec::with_capacity(terrain.noise.regions.len()); - let mut domain: Vec = Vec::with_capacity(terrain.noise.regions.len()); + let mut domain: Vec = Vec::with_capacity(terrain.noise.regions.len()); for region in &terrain.noise.regions { colors.push(colorgrad::Color { - r: f64::from(region.color[0]) / 255.0, - g: f64::from(region.color[1]) / 255.0, - b: f64::from(region.color[2]) / 255.0, - a: f64::from(region.color[3]) / 255.0, + r: f32::from(region.color[0]) / 255.0, + g: f32::from(region.color[1]) / 255.0, + b: f32::from(region.color[2]) / 255.0, + a: f32::from(region.color[3]) / 255.0, }); domain.push(region.position); } - let mut grad = colorgrad::CustomGradient::new() + let grad = colorgrad::GradientBuilder::new() .colors(&colors) .domain(&domain) - .build() + .build::() .unwrap_or_else(|_| { - colorgrad::CustomGradient::new() + colorgrad::GradientBuilder::new() .colors(&colors) - .build() + .build::() .expect("Gradient generation failed") }); - if terrain.noise.gradient.segments != 0 { - grad = grad.sharp( - terrain.noise.gradient.segments, - terrain.noise.gradient.smoothness, - ); - } - let mut gradient_buffer = image::ImageBuffer::from_pixel( terrain.noise.gradient.size[0], terrain.noise.gradient.size[1], @@ -144,9 +151,11 @@ fn generate_terrain( ); for (x, _, pixel) in gradient_buffer.enumerate_pixels_mut() { - let rgba = grad - .at(f64::from(x) * 100.0 / f64::from(terrain.noise.gradient.size[0])) - .to_rgba8(); + let rgba = colorgrad::Gradient::at( + &grad, + (f64::from(x) * 100.0 / f64::from(terrain.noise.gradient.size[0])) as f32, + ) + .to_rgba8(); pixel.blend(&image::Rgba(rgba)); } @@ -185,7 +194,10 @@ fn generate_terrain( let y = ((height_value * 1.2).powf(terrain.height_exponent) - 0.5) * 2.0; let z = (col / terrain.resolution as f32 - depth / 2.0) + 0.5; - let color = grad.at(noise_values[row as usize][col as usize]); + let color = colorgrad::Gradient::at( + &grad, + (noise_values[row as usize][col as usize]) as f32, + ); let color = [ color.r as f32, color.g as f32, @@ -241,7 +253,7 @@ fn generate_terrain( mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals); mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone()); mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs); - *mesh_handle = meshes.add(mesh); + *mesh_handle = Mesh3d(meshes.add(mesh)); if terrain.export { export_model(&positions, indices, &colors);