use glam::Vec3;
use polyscope_core::{MaterialLoadRequest, slice_plane::SlicePlaneUniforms};
use polyscope_render::RenderEngine;
use polyscope_structures::{
CameraView, CurveNetwork, PointCloud, SurfaceMesh, VolumeGrid, VolumeMesh,
};
pub fn auto_fit_camera(engine: &mut RenderEngine, camera_fitted: bool) -> bool {
if !camera_fitted {
let (has_structures, bbox) = crate::with_context(|ctx| {
let has_structures = !ctx.registry.is_empty();
(has_structures, ctx.bounding_box)
});
if has_structures {
let (min, max) = bbox;
if min.x.is_finite() && max.x.is_finite() && (max - min).length() > 0.0 {
engine.camera.look_at_box(min, max);
return true;
}
}
}
camera_fitted
}
pub fn drain_material_queue(engine: &mut RenderEngine) {
let pending_materials: Vec<MaterialLoadRequest> =
crate::with_context_mut(|ctx| std::mem::take(&mut ctx.material_load_queue));
for req in pending_materials {
match req {
MaterialLoadRequest::Static { name, path } => {
if let Err(e) = engine.load_static_material(&name, &path) {
eprintln!("Failed to load static material '{name}': {e}");
}
}
MaterialLoadRequest::Blendable { name, filenames } => {
let refs: [&str; 4] = [&filenames[0], &filenames[1], &filenames[2], &filenames[3]];
if let Err(e) = engine.load_blendable_material(&name, refs) {
eprintln!("Failed to load blendable material '{name}': {e}");
}
}
}
}
}
pub fn update_uniforms(engine: &mut RenderEngine) {
engine.update_camera_uniforms();
crate::with_context(|ctx| {
engine.update_slice_plane_uniforms(ctx.slice_planes().map(SlicePlaneUniforms::from));
});
}
pub fn init_structure_gpu_resources(engine: &mut RenderEngine) {
crate::with_context_mut(|ctx| {
let slice_planes: Vec<_> = ctx.slice_planes().cloned().collect();
for structure in ctx.registry.iter_mut() {
if structure.type_name() == "PointCloud" {
if let Some(pc) = structure.as_any_mut().downcast_mut::<PointCloud>() {
if pc.render_data().is_none() {
pc.init_gpu_resources(
&engine.device,
engine.point_bind_group_layout(),
engine.camera_buffer(),
);
}
let points = pc.points().to_vec();
if let Some(vq) = pc.active_vector_quantity_mut() {
if vq.render_data().is_none() {
vq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
&points,
);
}
}
}
}
if structure.type_name() == "SurfaceMesh" {
if let Some(mesh) = structure.as_any_mut().downcast_mut::<SurfaceMesh>() {
if mesh.render_data().is_none() {
mesh.init_gpu_resources(
&engine.device,
engine.mesh_bind_group_layout(),
engine.camera_buffer(),
);
}
if mesh.render_data().is_some() && !mesh.has_shadow_resources() {
if let (Some(shadow_layout), Some(shadow_pass)) =
(engine.shadow_bind_group_layout(), engine.shadow_map_pass())
{
mesh.init_shadow_resources(
&engine.device,
shadow_layout,
shadow_pass.light_buffer(),
);
}
}
let vertices = mesh.vertices().to_vec();
if let Some(vq) = mesh.active_vertex_vector_quantity_mut() {
if vq.render_data().is_none() {
vq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
&vertices,
);
}
}
let centroids = mesh.face_centroids();
if let Some(vq) = mesh.active_face_vector_quantity_mut() {
if vq.render_data().is_none() {
vq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
¢roids,
);
}
}
let vertices = mesh.vertices().to_vec();
if let Some(iq) = mesh.active_vertex_intrinsic_vector_quantity_mut() {
if iq.render_data().is_none() {
iq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
&vertices,
);
}
}
let centroids = mesh.face_centroids();
if let Some(iq) = mesh.active_face_intrinsic_vector_quantity_mut() {
if iq.render_data().is_none() {
iq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
¢roids,
);
}
}
let vertices = mesh.vertices().to_vec();
let edges = mesh.edges().to_vec();
if let Some(oq) = mesh.active_one_form_quantity_mut() {
if oq.render_data().is_none() {
oq.init_gpu_resources(
&engine.device,
engine.vector_bind_group_layout(),
engine.camera_buffer(),
&vertices,
&edges,
);
}
}
}
}
if structure.type_name() == "CurveNetwork" {
if let Some(cn) = structure.as_any_mut().downcast_mut::<CurveNetwork>() {
if cn.render_data().is_none() {
cn.init_gpu_resources(
&engine.device,
engine.curve_network_edge_bind_group_layout(),
engine.camera_buffer(),
);
}
let needs_tube = cn.render_data().is_some_and(|rd| !rd.has_tube_resources());
let needs_node = cn
.render_data()
.is_some_and(|rd| !rd.has_node_render_resources());
if needs_tube {
cn.init_tube_resources(
&engine.device,
engine.curve_network_tube_compute_bind_group_layout(),
engine.curve_network_tube_bind_group_layout(),
engine.camera_buffer(),
);
}
if needs_node {
cn.init_node_render_resources(
&engine.device,
engine.point_bind_group_layout(),
engine.camera_buffer(),
);
}
}
}
if structure.type_name() == "CameraView" {
if let Some(cv) = structure.as_any_mut().downcast_mut::<CameraView>() {
if cv.needs_reinit(ctx.length_scale) {
cv.init_render_data(
&engine.device,
engine.curve_network_edge_bind_group_layout(),
engine.camera_buffer(),
&engine.queue,
ctx.length_scale,
);
}
}
}
if structure.type_name() == "VolumeGrid" {
if let Some(vg) = structure.as_any_mut().downcast_mut::<VolumeGrid>() {
if vg.render_data().is_none() {
vg.init_render_data(
&engine.device,
engine.curve_network_edge_bind_group_layout(),
engine.camera_buffer(),
&engine.queue,
);
}
}
}
if structure.type_name() == "VolumeMesh" {
if let Some(vm) = structure.as_any_mut().downcast_mut::<VolumeMesh>() {
let mut enabled_planes: Vec<(String, Vec3, Vec3)> = slice_planes
.iter()
.filter(|p| p.is_enabled())
.map(|p| (p.name().to_string(), p.origin(), p.normal()))
.collect();
enabled_planes.sort_by(|a, b| a.0.cmp(&b.0));
let plane_params: Vec<(Vec3, Vec3)> = enabled_planes
.iter()
.map(|(_, origin, normal)| (*origin, *normal))
.collect();
if !plane_params.is_empty() {
vm.update_render_data_with_culling(
&engine.device,
engine.mesh_bind_group_layout(),
engine.camera_buffer(),
&plane_params,
);
} else if vm.is_culled() {
vm.reset_render_data(
&engine.device,
engine.mesh_bind_group_layout(),
engine.camera_buffer(),
);
} else if vm.render_data().is_none() {
vm.init_render_data(
&engine.device,
engine.mesh_bind_group_layout(),
engine.camera_buffer(),
);
}
}
}
}
});
}
pub fn update_gpu_buffers(engine: &RenderEngine, update_pick_uniforms: bool) {
crate::with_context(|ctx| {
for structure in ctx.registry.iter() {
if structure.type_name() == "PointCloud" {
if let Some(pc) = structure.as_any().downcast_ref::<PointCloud>() {
pc.update_gpu_buffers(&engine.queue, &engine.color_maps);
if update_pick_uniforms {
pc.update_pick_uniforms(&engine.queue);
}
let model = structure.transform();
if let Some(vq) = pc.active_vector_quantity() {
vq.update_uniforms(&engine.queue, &model);
}
}
}
if structure.type_name() == "SurfaceMesh" {
if let Some(mesh) = structure.as_any().downcast_ref::<SurfaceMesh>() {
mesh.update_gpu_buffers(&engine.queue, &engine.color_maps);
if update_pick_uniforms {
mesh.update_pick_uniforms(&engine.queue);
}
let model = structure.transform();
if let Some(vq) = mesh.active_vertex_vector_quantity() {
vq.update_uniforms(&engine.queue, &model);
}
if let Some(vq) = mesh.active_face_vector_quantity() {
vq.update_uniforms(&engine.queue, &model);
}
if let Some(iq) = mesh.active_vertex_intrinsic_vector_quantity() {
iq.update_uniforms(&engine.queue, &model);
}
if let Some(iq) = mesh.active_face_intrinsic_vector_quantity() {
iq.update_uniforms(&engine.queue, &model);
}
if let Some(oq) = mesh.active_one_form_quantity() {
oq.update_uniforms(&engine.queue, &model);
}
}
}
if structure.type_name() == "CurveNetwork" {
if let Some(cn) = structure.as_any().downcast_ref::<CurveNetwork>() {
cn.update_gpu_buffers(&engine.queue, &engine.color_maps);
}
}
if structure.type_name() == "VolumeGrid" {
if let Some(vg) = structure.as_any().downcast_ref::<VolumeGrid>() {
vg.update_gpu_buffers(&engine.queue);
}
}
if structure.type_name() == "VolumeMesh" {
if let Some(vm) = structure.as_any().downcast_ref::<VolumeMesh>() {
vm.update_gpu_buffers(&engine.queue);
if update_pick_uniforms {
vm.update_pick_uniforms(&engine.queue);
}
}
}
}
});
}