use std::time::Duration; use anyhow::Result; use ecs::*; use engine::prelude::{ cgmath::{Matrix4, Vector3}, *, }; use hexasphere::shapes::IcoSphere; pub struct CelestialObject; impl CelestialObject { pub fn new( world: &mut World, subdivisions: usize, celestial_reference: impl Into>, ) -> Result { let mut entity_object = AssetHandler::create(world).empty_entity(); let celestial_settings = CelestialObjectSettings::default(); let draw = Draw::new(vec![Self::create_asset(world, subdivisions)?]); draw.set_transform(celestial_settings.model_matrix())?; entity_object.insert_component(draw); entity_object.insert_component(celestial_settings); if let Some(e) = celestial_reference.into() { entity_object.insert_component(CelestialReference { entity: e }); } Ok(entity_object) } fn create_asset(world: &World, subdivisions: usize) -> Result { let context = world.resources.get::(); let scene = world.resources.get::(); let command_buffer = CommandBuffer::new_primary() .build(context.device().clone(), context.queue().clone())?; let buffer = { let mut recorder = command_buffer.begin(VkCommandBufferBeginInfo::new( VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, ))?; Buffer::builder() .set_memory_usage(MemoryUsage::CpuToGpu) .set_usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT) .set_data( &Self::create_sphere(subdivisions) .into_iter() .map(|(v, n)| PositionNormal::new(v, n)) .collect::>(), ) .build(context.device().clone())? .into_device_local( &mut recorder, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, )? }; // submit let submit = SubmitInfo::default().add_command_buffer(&command_buffer); let fence = Fence::builder().build(context.device().clone())?; context .queue() .lock() .unwrap() .submit(Some(&fence), &[submit])?; context .device() .wait_for_fences(&[&fence], true, Duration::from_secs(1))?; let mut asset_mesh = AssetMesh::new(context.device(), scene.render_type())?; asset_mesh.add_primitive( buffer, None, None, PrimitiveMaterial { emissive_factor: [0.65, 0.65, 0.65], metallic_factor: 0.5, roughness_factor: 0.7, ..PrimitiveMaterial::default() }, false, )?; Ok(asset_mesh) } fn create_sphere(subdivisions: usize) -> Vec<(Vector3, Vector3)> { let sphere = IcoSphere::new(subdivisions, |_| ()); let points = sphere .raw_points() .into_iter() .map(|v| Vector3::from(v.to_array())) .collect::>>(); sphere .get_all_indices() .chunks(3) .map(|triangle| { let p1 = points[triangle[0] as usize]; let p2 = points[triangle[1] as usize]; let p3 = points[triangle[2] as usize]; let v1 = p1 - p2; let v2 = p1 - p3; let n = v2.cross(v1); [(p1, n), (p2, n), (p3, n)] }) .flatten() .collect() } } #[derive(Debug)] pub struct CelestialObjectSettings { pub location: Vector3, pub radius: f32, pub density: f32, pub velocity: f32, last_update: Duration, } impl CelestialObjectSettings { fn model_matrix(&self) -> Matrix4 { Matrix4::from_translation(self.location) * Matrix4::from_scale(self.radius) } pub fn update( &mut self, now: Duration, draw: &Draw, celestial_object_settings_reference: &CelestialObjectSettings, ) -> Result<()> { Ok(()) } } impl Default for CelestialObjectSettings { fn default() -> Self { Self { location: Vector3::zero(), radius: 1.0, density: 1.0, velocity: 0.0, last_update: Duration::default(), } } } impl EntityComponent for CelestialObjectSettings { fn name(&self) -> &str { Self::debug_name() } } impl ComponentDebug for CelestialObjectSettings { fn debug_name() -> &'static str { "CelestialObjectSettings" } } #[derive(Debug)] pub struct CelestialReference { pub entity: Entity, } impl EntityComponent for CelestialReference { fn name(&self) -> &str { Self::debug_name() } } impl ComponentDebug for CelestialReference { fn debug_name() -> &'static str { "CelestialReference" } }