engine/examples/free_space/src/celestial_object.rs

193 lines
5.1 KiB
Rust
Raw Normal View History

2025-03-13 21:09:11 +00:00
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<Option<Entity>>,
) -> Result<EntityObject> {
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<AssetMesh> {
let context = world.resources.get::<Context>();
let scene = world.resources.get::<Scene>();
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::<Vec<_>>(),
)
.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<f32>, Vector3<f32>)> {
let sphere = IcoSphere::new(subdivisions, |_| ());
let points = sphere
.raw_points()
.into_iter()
.map(|v| Vector3::from(v.to_array()))
.collect::<Vec<Vector3<f32>>>();
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<f32>,
pub radius: f32,
pub density: f32,
pub velocity: f32,
last_update: Duration,
}
impl CelestialObjectSettings {
fn model_matrix(&self) -> Matrix4<f32> {
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"
}
}