From 363ab111bcaa3d19dc6e7ff88546611d924376a7 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Thu, 13 Mar 2025 22:09:11 +0100 Subject: [PATCH] Add celestial body --- examples/free_space/Cargo.toml | 1 + examples/free_space/src/celestial_object.rs | 192 ++++++++++++++++++++ examples/free_space/src/game.rs | 19 +- examples/free_space/src/main.rs | 3 +- 4 files changed, 206 insertions(+), 9 deletions(-) create mode 100644 examples/free_space/src/celestial_object.rs diff --git a/examples/free_space/Cargo.toml b/examples/free_space/Cargo.toml index 247cce8..f3c43c9 100644 --- a/examples/free_space/Cargo.toml +++ b/examples/free_space/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] anyhow.workspace = true ecs.workspace = true +hexasphere = "15.1.0" engine = { path = "../../engine" } skybox = { path = "../../skybox" } diff --git a/examples/free_space/src/celestial_object.rs b/examples/free_space/src/celestial_object.rs new file mode 100644 index 0000000..0dc3c45 --- /dev/null +++ b/examples/free_space/src/celestial_object.rs @@ -0,0 +1,192 @@ +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" + } +} diff --git a/examples/free_space/src/game.rs b/examples/free_space/src/game.rs index a3f2621..633d7e0 100644 --- a/examples/free_space/src/game.rs +++ b/examples/free_space/src/game.rs @@ -8,7 +8,7 @@ use engine::prelude::{ *, }; -use crate::FREE_CAMERA_CONTROL; +use crate::{FREE_CAMERA_CONTROL, celestial_object::CelestialObject}; #[derive(Clone, Copy, Debug)] struct PlayerEntity(Entity); @@ -268,16 +268,19 @@ impl Game { } pub fn setup_scene(world: &mut World) -> Result<()> { - let mut fighter = AssetHandler::create(world).create_entity("fighter_edited")?; - fighter.insert_component(FreeSpaceControl::new( - 0.02, - FreeSpaceControlSettings::default(), - )); + // let mut fighter = AssetHandler::create(world).create_entity("fighter_edited")?; + // fighter.insert_component(FreeSpaceControl::new( + // 0.02, + // FreeSpaceControlSettings::default(), + // )); - let player = PlayerEntity(world.add_entity(fighter)?); - world.resources.insert(player); + // let player = PlayerEntity(world.add_entity(fighter)?); + // world.resources.insert(player); world.resources.insert(InputSettings::default()); + let example_planet = CelestialObject::new(world, 5, None)?; + world.add_entity(example_planet)?; + let context = world.resources.get::(); let mut light = Light::point_light(context.device())?; light.set_position(vec3(10_000.0, 10_000.0, 10_000.0))?; diff --git a/examples/free_space/src/main.rs b/examples/free_space/src/main.rs index e601ae2..494e8e0 100644 --- a/examples/free_space/src/main.rs +++ b/examples/free_space/src/main.rs @@ -1,3 +1,4 @@ +mod celestial_object; mod game; mod game_state; @@ -11,7 +12,7 @@ use game::Game; use game_state::GameState; use skybox::SkyBox; -const FREE_CAMERA_CONTROL: bool = false; +const FREE_CAMERA_CONTROL: bool = true; fn main() -> Result<()> { let mut world_builder = World::builder();