use crate::{actor, camera}; 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::core_pipeline::bloom::{BloomCompositeMode, BloomSettings}; use std::f32::consts::PI; 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)); } } #[derive(Resource)] pub struct Cubemap { is_loaded: bool, image_handle: Handle, } const CUBEMAP_PATH: &str = "textures/stars_cubemap.png"; pub fn setup( mut commands: Commands, mut meshes: ResMut>, mut materials: ResMut>, mut ambient_light: ResMut, asset_server: Res, ) { // Add player commands.spawn(( actor::Player, actor::Actor::default(), actor::LifeForm::default(), actor::Suit { oxygen: actor::OXY_M, ..default() } )); // Add skybox let skybox_handle = asset_server.load(CUBEMAP_PATH); commands.spawn(( Camera3dBundle { camera: Camera { hdr: true, // HDR is required for bloom ..default() }, transform: Transform::from_xyz(0.0, 0.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, camera::CameraController::default(), Skybox { image: skybox_handle.clone(), brightness: 200.0, }, BloomSettings { composite_mode: BloomCompositeMode::EnergyConserving, ..default() }, )); commands.insert_resource(Cubemap { is_loaded: false, image_handle: skybox_handle, }); // Add spheres let sphere_radius = 50.0; let sphere_handle = meshes.add(Sphere::new(sphere_radius)); let gray_handle = materials.add(StandardMaterial { base_color: Color::GRAY, perceptual_roughness: 1.0, ..default() }); let brown_handle = materials.add(StandardMaterial { base_color: Color::Rgba { alpha: 1.0, red: 0.8, green: 0.5, blue: 0.1 }, perceptual_roughness: 1.0, ..default() }); commands.spawn(PbrBundle { mesh: sphere_handle.clone(), material: gray_handle.clone(), transform: Transform::from_xyz( 0.0, 0.0, -500.0, ), ..default() }); let sphere_radius = 10.0; let sphere_handle = meshes.add(Sphere::new(sphere_radius)); commands.spawn(PbrBundle { mesh: sphere_handle.clone(), material: brown_handle.clone(), transform: Transform::from_xyz( 300.0, 40.0, 250.0, ), ..default() }); // Add a bunch of asteriods let sphere_radius = 10.0; let sphere_handle = meshes.add(Sphere::new(sphere_radius)); let asteroid_color_handle = materials.add(StandardMaterial { base_color: Color::rgb(0.4, 0.3, 0.1), perceptual_roughness: 1.0, ..default() }); for i in -20..20 { for j in -20..20 { for k in -20..20 { commands.spawn(( actor::Actor::default(), PbrBundle { mesh: sphere_handle.clone(), material: asteroid_color_handle.clone(), transform: Transform::from_xyz( 200.0 * i as f32, 400.0 * j as f32, 250.0 * k as f32, ), ..default() } )); } } } // Add THE SUN let hydrogenfusion_handle = materials.add(StandardMaterial { emissive: Color::rgb_linear(1e6, 0.9e6, 1e6), ..default() }); let sphere_radius = 5000.0; let sphere_handle = meshes.add(Sphere::new(sphere_radius)); commands.spawn(PbrBundle { mesh: sphere_handle.clone(), material: hydrogenfusion_handle.clone(), transform: Transform::from_xyz( 0.0, 30000.0, -500000.0, ), ..default() }); // Add alien commands.spawn(SceneBundle { transform: Transform { translation: Vec3::new( 0.0, 0.0, 100.0, ), rotation: Quat::from_rotation_y(-PI / 3.), scale: Vec3::splat(5.0), }, scene: asset_server.load("tmp/alien.glb#Scene0"), ..default() }); // Space is DARK ambient_light.brightness = 0.0; // Add Light commands.spawn(DirectionalLightBundle { directional_light: DirectionalLight { illuminance: 1000.0, shadows_enabled: false, ..default() }, transform: Transform::from_rotation(Quat::from_euler( EulerRot::ZYX, 0.0, PI / 1.0, -PI / 7.0, )), cascade_shadow_config: CascadeShadowConfigBuilder { first_cascade_far_bound: 7.0, maximum_distance: 25.0, ..default() } .into(), ..default() }); } pub fn load_cubemap_asset( mut cubemap: ResMut, asset_server: Res, ) { cubemap.image_handle = asset_server.load(CUBEMAP_PATH); cubemap.is_loaded = false; } pub fn asset_loaded( asset_server: Res, mut images: ResMut>, mut cubemap: ResMut, mut skyboxes: Query<&mut Skybox>, ) { if !cubemap.is_loaded && asset_server.load_state(&cubemap.image_handle) == LoadState::Loaded { let image = images.get_mut(&cubemap.image_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.image_handle.clone(); } cubemap.is_loaded = true; } }