MAJOR rendering overhaul. Snow deformation, persistent light, flowmap out. Also ECS architexture overhaul

This commit is contained in:
Jonas H
2026-03-03 19:30:41 +01:00
parent f615810509
commit 08ddaa2c5d
56 changed files with 2737 additions and 3463 deletions

150
src/bundles/terrain.rs Normal file
View File

@@ -0,0 +1,150 @@
use std::rc::Rc;
use glam::Vec2;
use nalgebra::vector;
use rapier3d::prelude::{ColliderBuilder, RigidBodyBuilder};
use crate::components::{MeshComponent, PhysicsComponent};
use crate::entity::EntityHandle;
use crate::loaders::mesh::{InstanceData, InstanceRaw, Mesh};
use crate::loaders::terrain::load_heightfield_from_exr;
use crate::physics::PhysicsManager;
use crate::render;
use crate::world::{Transform, World};
pub struct TerrainConfig
{
pub gltf_path: String,
pub heightmap_path: String,
pub size: Vec2,
}
impl TerrainConfig
{
pub fn new(gltf_path: &str, heightmap_path: &str, size: Vec2) -> Self
{
Self {
gltf_path: gltf_path.to_string(),
heightmap_path: heightmap_path.to_string(),
size,
}
}
pub fn default() -> Self
{
Self {
gltf_path: "meshes/terrain.gltf".to_string(),
heightmap_path: "textures/terrain_heightmap.exr".to_string(),
size: Vec2::new(1000.0, 1000.0),
}
}
}
pub struct TerrainBundle;
impl TerrainBundle
{
pub fn spawn(
world: &mut World,
mesh_data: Vec<(Mesh, Vec<InstanceData>)>,
config: &TerrainConfig,
) -> anyhow::Result<EntityHandle>
{
let transform = Transform::IDENTITY;
let mut first_entity = None;
let mut physics_added = false;
for (mesh, instances) in mesh_data
{
let entity = world.spawn();
if first_entity.is_none()
{
first_entity = Some(entity);
}
if instances.is_empty()
{
world.transforms.insert(entity, transform);
world.meshes.insert(
entity,
MeshComponent {
mesh: Rc::new(mesh),
pipeline: render::Pipeline::Standard,
instance_buffer: None,
num_instances: 1,
tile_scale: 2.0,
enable_dissolve: false,
enable_snow_light: true,
},
);
if !physics_added
{
let heights = load_heightfield_from_exr(&config.heightmap_path)?;
let height_scale = 1.0;
let scale = vector![config.size.x, height_scale, config.size.y];
let body = RigidBodyBuilder::fixed()
.translation(transform.get_position().into())
.build();
let rigidbody_handle = PhysicsManager::add_rigidbody(body);
let collider = ColliderBuilder::heightfield(heights.clone(), scale).build();
let collider_handle =
PhysicsManager::add_collider(collider, Some(rigidbody_handle));
PhysicsManager::set_heightfield_data(
heights,
scale,
transform.get_position().into(),
);
world.physics.insert(
entity,
PhysicsComponent {
rigidbody: rigidbody_handle,
collider: Some(collider_handle),
},
);
physics_added = true;
}
}
else
{
let num_instances = instances.len();
let instance_raw: Vec<InstanceRaw> = instances.iter().map(|i| i.to_raw()).collect();
let instance_buffer = render::with_device(|device| {
use wgpu::util::DeviceExt;
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Tree Instance Buffer"),
contents: bytemuck::cast_slice(&instance_raw),
usage: wgpu::BufferUsages::VERTEX,
})
});
world.transforms.insert(entity, Transform::IDENTITY);
world.meshes.insert(
entity,
MeshComponent {
mesh: Rc::new(mesh),
pipeline: render::Pipeline::Standard,
instance_buffer: Some(instance_buffer),
num_instances: num_instances as u32,
tile_scale: 4.0,
enable_dissolve: true,
enable_snow_light: false,
},
);
}
}
first_entity.ok_or_else(|| anyhow::anyhow!("No meshes found in glTF file"))
}
}