use egui::{Color32, Response, Ui};
use egui_wgpu::RenderState;
use crate::core::scene3d::mat4::Vec3;
use crate::core::scene3d::pick::picking_segment;
use crate::render::gpu_scene3d::{Scene3dGeometry, Scene3dId};
use crate::render::scene3d_items::ScalarField3D;
use crate::widget::scene_widget::SceneWidget;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct FieldPick {
pub position: Vec3,
pub value: Option<f32>,
}
pub struct ScalarFieldView {
scene: SceneWidget,
field: ScalarField3D,
had_data: bool,
}
impl ScalarFieldView {
pub fn new(render_state: &RenderState, id: Scene3dId) -> Self {
ScalarFieldView {
scene: SceneWidget::new(render_state, id),
field: ScalarField3D::new(),
had_data: false,
}
}
pub fn set_data(
&mut self,
render_state: &RenderState,
data: &[f32],
depth: usize,
height: usize,
width: usize,
) -> bool {
let first = !self.had_data;
if !self.field.set_data(data, depth, height, width) {
return false;
}
self.had_data = true;
if let Some(bounds) = self.field.bounds() {
if first {
self.scene.set_bounds(render_state, bounds);
} else {
self.scene.set_bounds_keep_view(render_state, bounds);
}
}
self.rebuild(render_state);
true
}
pub fn field(&self) -> &ScalarField3D {
&self.field
}
pub fn field_mut(&mut self) -> &mut ScalarField3D {
&mut self.field
}
pub fn scene(&self) -> &SceneWidget {
&self.scene
}
pub fn scene_mut(&mut self) -> &mut SceneWidget {
&mut self.scene
}
pub fn add_isosurface(
&mut self,
render_state: &RenderState,
level: f32,
color: Color32,
) -> usize {
let index = self.field.add_isosurface(level, color);
self.rebuild(render_state);
index
}
pub fn add_auto_isosurface(
&mut self,
render_state: &RenderState,
auto: fn(&[f32]) -> f32,
color: Color32,
) -> usize {
let index = self.field.add_auto_isosurface(auto, color);
self.rebuild(render_state);
index
}
pub fn remove_isosurface(&mut self, render_state: &RenderState, index: usize) -> bool {
if self.field.remove_isosurface(index) {
self.rebuild(render_state);
true
} else {
false
}
}
pub fn clear_isosurfaces(&mut self, render_state: &RenderState) {
self.field.clear_isosurfaces();
self.rebuild(render_state);
}
pub fn rebuild(&mut self, render_state: &RenderState) {
let mut geometry = Scene3dGeometry::new();
self.field.append_to(&mut geometry);
self.scene.set_geometry(render_state, geometry);
}
pub fn pick(&self, ndc: (f32, f32)) -> Option<FieldPick> {
let camera = self.scene.camera();
let mvp = camera.matrix();
let mut best: Option<(f32, Vec3)> = None;
if let Some(hit) = self.scene.pick(ndc) {
best = Some((hit.ndc_depth, hit.position));
}
if let Some(segment) = picking_segment(camera, ndc)
&& let Some(pos) = self.field.pick_cut_plane(segment)
{
let depth = mvp.transform_point(pos, true).z;
if best.is_none_or(|(d, _)| depth < d) {
best = Some((depth, pos));
}
}
let (_, position) = best?;
Some(FieldPick {
position,
value: self.field.value_at(position),
})
}
pub fn show(&mut self, ui: &mut Ui) -> Response {
self.scene.show(ui)
}
}