use crate::{actor, nature}; use bevy::prelude::*; //use bevy::core_pipeline::Skybox; //use bevy::asset::LoadState; //use bevy::render::render_resource::{TextureViewDescriptor, TextureViewDimension}; use bevy::pbr::CascadeShadowConfigBuilder; use bevy::render::render_resource::{AsBindGroup, ShaderRef}; use bevy_xpbd_3d::prelude::*; use std::f32::consts::PI; const ASTEROID_SIZE: f32 = 100.0; const STARS_MAX_MAGNITUDE: f32 = 5.5; //const SKYBOX_BRIGHTNESS: f32 = 300.0; //const SKYBOX_BRIGHTNESS_AR: f32 = 100.0; //const ASSET_CUBEMAP: &str = "textures/cubemap-fs8.png"; //const ASSET_CUBEMAP_AR: &str = "textures/out.png"; const ASSET_ASTEROID1: &str = "models/asteroid.glb#Scene0"; const ASSET_ASTEROID2: &str = "models/asteroid2.glb#Scene0"; pub fn asset_name_to_path(name: &str) -> &'static str { match name { "suit" => "models/suit.glb#Scene0", "asteroid1" => ASSET_ASTEROID1, "asteroid2" => ASSET_ASTEROID2, "moonlet" => "models/moonlet.glb#Scene0", "monolith" => "models/monolith_neon.glb#Scene0", "lightorb" => "models/lightorb.glb#Scene0", "MeteorAceGT" => "models/MeteorAceGT.glb#Scene0", "pizzeria" => "models/pizzeria2.glb#Scene0", "pizzasign" => "models/pizzasign.glb#Scene0", _ => "models/error.glb#Scene0", } } pub struct WorldPlugin; impl Plugin for WorldPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup); //app.add_systems(Update, asset_loaded.after(load_cubemap_asset)); //app.add_systems(Update, swap_world_on_ar_toggle); app.add_plugins(PhysicsPlugins::default()); app.add_plugins(MaterialPlugin::::default()); //app.add_plugins(PhysicsDebugPlugin::default()); app.insert_resource(Gravity(Vec3::splat(0.0))); } } #[derive(Asset, TypePath, AsBindGroup, Debug, Clone)] pub struct RingMaterial { alpha_mode: AlphaMode, #[uniform(0)] ring_radius: f32, #[uniform(1)] jupiter_radius: f32, } impl Material for RingMaterial { fn fragment_shader() -> ShaderRef { "shaders/jupiters_rings.wgsl".into() } fn alpha_mode(&self) -> AlphaMode { self.alpha_mode } } #[derive(Component)] pub struct Star; //#[derive(Resource)] //pub struct WorldState { // is_loaded: bool, // entities_viewn_through_ar: bool, // cubemap_handle: Handle, // cubemap_ar_handle: Handle, //} //impl WorldState { // pub fn get_cubemap_handle(&self) -> Handle { // if self.entities_viewn_through_ar { // self.cubemap_ar_handle.clone() // } else { // self.cubemap_handle.clone() // } // } //} pub fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, mut materials_custom: ResMut>, asset_server: Res, ) { // let cubemap_handle = asset_server.load(ASSET_CUBEMAP); // commands.insert_resource(WorldState { // is_loaded: false, // entities_viewn_through_ar: settings.hud_active, // cubemap_handle: asset_server.load(ASSET_CUBEMAP), // cubemap_ar_handle: asset_server.load(ASSET_CUBEMAP_AR), // }); // Generate a bunch of asteriods let maxdist = 4; for i in -maxdist..maxdist { for j in -maxdist..maxdist { for k in -maxdist..maxdist { let offset = 500.0; let dist = 8e3; let wobble = dist/2.0; let (i, j, k) = (i as f32, j as f32, k as f32); let asset = match ((i+j+k) as i32) % 2 { 0 => ASSET_ASTEROID1, _ => ASSET_ASTEROID2, }; commands.spawn(( actor::Actor::default(), RigidBody::Dynamic, AngularVelocity(Vec3::new(0.1, 0.1, 0.03)), LinearVelocity(Vec3::new(0.0, 0.0, 0.35)), Collider::sphere(1.0), SceneBundle { transform: Transform { translation: Vec3::new( offset + dist * i + wobble * (j+k/PI).sin() * (k+j/PI).cos(), offset + dist * j + wobble * (k+i/PI).sin() * (i+k/PI).cos(), offset + dist * k + wobble * (i+j/PI).sin() * (j+i/PI).cos(), ), rotation: Quat::from_rotation_y(-PI / 3.), scale: Vec3::splat(ASTEROID_SIZE), }, scene: asset_server.load(asset), ..default() }, )); } } } // Generate starmap let sphere_handle = meshes.add(Sphere::new(1.0)); let mut starcount = 0; for star in nature::STARS { let mag = star[3]; if mag > STARS_MAX_MAGNITUDE { continue; } let scale_color = {|color: f32| if mag < -20.0 { color * 13.0f32 // Sun } else { color * (0.0659663 * mag * mag - 1.09862 * mag + 4.3) } }; let scale_size = {|mag: f32| if mag < -20.0 { 40000.0f32 // Sun } else { 1000.0 * (0.230299 * mag * mag - 3.09013 * mag + 15.1782) } }; let (r, g, b) = nature::star_color_index_to_rgb(star[4]); let star_color_handle = materials.add(StandardMaterial { base_color: Color::rgb(scale_color(r), scale_color(g), scale_color(b)), unlit: true, ..default() }); let dist = 1e7; commands.spawn(( Star, PbrBundle { mesh: sphere_handle.clone(), material: star_color_handle.clone(), transform: Transform::from_xyz( dist * star[0], dist * star[1], dist * star[2], ) .with_scale(Vec3::splat(scale_size(mag))), ..default() } )); starcount += 1; } info!("Generated {starcount} stars"); // Add shaded ring let ring_radius = 640000.0; let jupiter_radius = 200000.0; commands.spawn(MaterialMeshBundle { mesh: meshes.add(Mesh::from(Cylinder::new(ring_radius, 1.0))), transform: Transform::from_xyz(300000.0, -1000.0, 500000.0) .with_rotation(Quat::from_rotation_z(1f32.to_radians())) , //transform: Transform::from_xyz(300000.0, 0.0, 500000.0)), material: materials_custom.add(RingMaterial { alpha_mode: AlphaMode::Blend, ring_radius: ring_radius, jupiter_radius: jupiter_radius, }), ..default() }); //let max = 20; //for i in 0..max { // let f = i as f32; // let maxf = max as f32; // let ringmesh = Mesh::from(Cylinder::new(400000.0 + f * 10000.0, 5000.0 - 150.0 * f)); // let clr = 0.4 + (f/maxf).clamp(0.0,0.6); // commands.spawn(MaterialMeshBundle { // mesh: meshes.add(ringmesh), // transform: Transform::from_xyz(300000.0, 0.0, 500000.0), // material: materials_custom.add(RingMaterial { // alpha_mode: AlphaMode::Blend, // }), // material: materials.add(StandardMaterial { // base_color: Color::rgba(clr, clr, clr, 0.0001), // unlit: true, // cull_mode: None, // alpha_mode: AlphaMode::Blend, // ..default() // }), // ..default() // }); //} // Add Light from the Sun commands.spawn(DirectionalLightBundle { directional_light: DirectionalLight { illuminance: 1000.0, shadows_enabled: false, ..default() }, transform: Transform::from_rotation(Quat::from_rotation_y(PI/2.0)), cascade_shadow_config: CascadeShadowConfigBuilder { first_cascade_far_bound: 7.0, maximum_distance: 25.0, ..default() } .into(), ..default() }); } //pub fn swap_world_on_ar_toggle( // asset_server: Res, // mut images: ResMut>, // mut worldstate: ResMut, // mut skyboxes: Query<&mut Skybox>, // settings: Res, //) { // if settings.hud_active != worldstate.entities_viewn_through_ar { // worldstate.is_loaded = false; // worldstate.entities_viewn_through_ar = settings.hud_active; // } // if !worldstate.is_loaded && asset_server.load_state(&worldstate.get_cubemap_handle()) == LoadState::Loaded { // let cubemap_handle = &worldstate.get_cubemap_handle(); // let image = images.get_mut(cubemap_handle).unwrap(); // if image.texture_descriptor.array_layer_count() == 1 { // image.reinterpret_stacked_2d_as_array(image.height() / image.width()); // image.texture_view_descriptor = Some(TextureViewDescriptor { // dimension: Some(TextureViewDimension::Cube), // ..default() // }); // } // // for mut skybox in &mut skyboxes { // skybox.image = cubemap_handle.clone(); // skybox.brightness = if settings.hud_active { // SKYBOX_BRIGHTNESS_AR // } else { // SKYBOX_BRIGHTNESS // } // } // // worldstate.is_loaded = true; // } //}