Add support for displaying faces

This commit is contained in:
Hanno Braun 2025-05-16 12:39:21 +02:00
parent f910ebf6a5
commit d56459da92
7 changed files with 99 additions and 7 deletions

View File

@ -9,6 +9,9 @@ use super::{
#[derive(Debug)]
pub enum Pipelines {
ForFace {
lines: Pipeline,
},
ForModel {
model: Pipeline,
mesh: Option<Pipeline>,
@ -16,6 +19,24 @@ pub enum Pipelines {
}
impl Pipelines {
pub fn for_face(
device: &wgpu::Device,
shaders: &Shaders,
pipeline_layout: &wgpu::PipelineLayout,
color_format: wgpu::TextureFormat,
) -> Self {
let lines = Pipeline::new(
device,
pipeline_layout,
shaders.face(),
wgpu::PrimitiveTopology::TriangleList,
wgpu::PolygonMode::Line,
color_format,
);
Self::ForFace { lines }
}
pub fn for_model(
device: &wgpu::Device,
shaders: &Shaders,
@ -58,6 +79,9 @@ impl Pipelines {
render_pass: &mut wgpu::RenderPass,
) {
match self {
Self::ForFace { lines } => {
lines.draw(geometry, render_pass);
}
Self::ForModel { model, mesh } => {
if config.draw_model {
model.draw(geometry, render_pass);

View File

@ -188,6 +188,12 @@ impl Renderer {
let shaders = Shaders::new(&device.device);
let pipelines = match mode {
RenderMode::Face => Pipelines::for_face(
&device.device,
&shaders,
&pipeline_layout,
color_format,
),
RenderMode::Model => Pipelines::for_model(
&device.device,
&shaders,
@ -381,6 +387,7 @@ impl Renderer {
}
pub enum RenderMode {
Face,
Model,
}

View File

@ -35,6 +35,13 @@ fn vertex(in: VertexInput) -> VertexOutput {
const pi: f32 = 3.14159265359;
@fragment
fn frag_face(in: VertexOutput) -> FragmentOutput {
var out: FragmentOutput;
out.color = vec4<f32>(0.0, 0.0, 0.0, 1.0);
return out;
}
@fragment
fn frag_model(in: VertexOutput) -> FragmentOutput {
let light = vec3<f32>(0.0, 0.0, -1.0);

View File

@ -17,6 +17,13 @@ impl Shaders {
Self { module }
}
pub fn face(&self) -> Shader {
Shader {
module: &self.module,
frag_entry: "frag_face",
}
}
pub fn model(&self) -> Shader {
Shader {
module: &self.module,

View File

@ -1,5 +1,6 @@
use bytemuck::{Pod, Zeroable};
use fj_interop::{Index, TriMesh, vertices_to_indexed_vertices};
use fj_math::{Point, Scalar};
#[derive(Debug)]
pub struct Vertices {
@ -8,6 +9,24 @@ pub struct Vertices {
}
impl Vertices {
pub fn for_face(points: &[Point<2>]) -> Self {
let vertices = points
.iter()
.map(|point| {
let [x, y] = point.coords.components.map(Scalar::into_f32);
Vertex {
position: [x, y, 0.],
normal: [0., 0., 1.],
color: [0., 0., 0., 1.],
}
})
.collect();
let indices = (0..).take(points.len()).collect();
Self { vertices, indices }
}
pub fn for_model(tri_mesh: &TriMesh) -> Self {
let (vertices, indices) = vertices_to_indexed_vertices(
tri_mesh.triangles.iter().flat_map(|triangle| {

View File

@ -1,6 +1,7 @@
use std::{collections::BTreeMap, panic, thread};
use fj_interop::TriMesh;
use fj_math::Point;
use futures::executor::block_on;
use winit::{
application::ApplicationHandler,
@ -63,6 +64,14 @@ pub struct Viewer {
}
impl Viewer {
/// # Display a 2D face in a new window
pub fn display_face(&self, points: Vec<Point<2>>) {
// If there's an error, that means the display thread has closed down
// and we're on our way to shutting down as well. I don't think there's
// much we can do about that.
let _ = self.event_loop.send_event(ToDisplay::face(points));
}
/// # Display a 3D model in a new window
pub fn display_model(&self, tri_mesh: TriMesh) {
// If there's an error, that means the display thread has closed down

View File

@ -1,7 +1,7 @@
use std::sync::Arc;
use fj_interop::TriMesh;
use fj_math::Aabb;
use fj_math::{Aabb, Point};
use tracing::warn;
use winit::{dpi::PhysicalSize, event_loop::ActiveEventLoop};
@ -30,6 +30,11 @@ impl Window {
event_loop: &ActiveEventLoop,
) -> Result<Self, WindowError> {
let (vertices, render_mode, aabb) = match &to_display {
ToDisplay::Face { points, aabb } => {
let vertices = Vertices::for_face(points);
let render_mode = RenderMode::Face;
(vertices, render_mode, aabb)
}
ToDisplay::Model { tri_mesh, aabb } => {
let vertices = Vertices::for_model(tri_mesh);
let render_mode = RenderMode::Model;
@ -78,13 +83,13 @@ impl Window {
/// # Compute and store a focus point, unless one is already stored
pub fn add_focus_point(&mut self) {
let ToDisplay::Model { tri_mesh, aabb } = &self.to_display;
if let ToDisplay::Model { tri_mesh, aabb } = &self.to_display {
if self.focus_point.is_none() {
self.focus_point =
Some(self.camera.focus_point(self.cursor, tri_mesh, aabb));
}
}
}
/// # Handle the screen being resized
pub fn on_screen_resize(&mut self, new_size: PhysicalSize<u32>) {
@ -175,6 +180,7 @@ impl Window {
}
let aabb = match &self.to_display {
ToDisplay::Face { points: _, aabb } => aabb,
ToDisplay::Model { tri_mesh: _, aabb } => aabb,
};
self.camera.update_planes(aabb);
@ -186,10 +192,23 @@ impl Window {
}
pub enum ToDisplay {
Model { tri_mesh: TriMesh, aabb: Aabb<3> },
Face {
points: Vec<Point<2>>,
aabb: Aabb<3>,
},
Model {
tri_mesh: TriMesh,
aabb: Aabb<3>,
},
}
impl ToDisplay {
pub fn face(points: Vec<Point<2>>) -> Self {
let aabb =
Aabb::<3>::from_points(points.iter().map(|point| point.to_xyz()));
Self::Face { points, aabb }
}
pub fn model(tri_mesh: TriMesh) -> Self {
let aabb = tri_mesh.aabb();
Self::Model { tri_mesh, aabb }