mod camera;
mod compute_mesh;
mod error;
mod mesh;
mod pipeline;
#[cfg(feature = "window")]
mod viewer;
pub use camera::Camera;
pub use compute_mesh::{
CylinderDescriptor, DEFAULT_TARGET_PX, TessFactor, extract_cylinder_descriptor,
render_cylinder_compute_offscreen, render_cylinder_compute_screen_lod,
screen_space_tess_factor,
};
pub use error::RenderError;
pub use pipeline::probe_adapter;
#[cfg(feature = "window")]
pub use viewer::{ViewOpts, view_solid};
use brepkit_topology::Topology;
use brepkit_topology::solid::SolidId;
pub const DEFAULT_DEFLECTION: f64 = 0.05;
#[derive(Debug, Clone, Copy)]
pub struct RenderOpts {
pub width: u32,
pub height: u32,
pub edges: bool,
pub background: [f32; 4],
pub ambient: f32,
pub deflection: f64,
}
impl RenderOpts {
#[must_use]
pub fn new(width: u32, height: u32) -> Self {
Self {
width,
height,
edges: true,
background: [0.11, 0.12, 0.14, 1.0],
ambient: 0.25,
deflection: DEFAULT_DEFLECTION,
}
}
}
pub struct RenderOutput {
pub color: image::RgbaImage,
pub id_buffer: Vec<u32>,
pub width: u32,
pub height: u32,
}
impl RenderOutput {
#[must_use]
pub fn face_id_at(&self, x: u32, y: u32) -> Option<u32> {
if x >= self.width || y >= self.height {
return None;
}
let idx = (y * self.width + x) as usize;
match self.id_buffer.get(idx).copied() {
Some(0) | None => None,
Some(v) => Some(v),
}
}
}
pub fn render_solid_offscreen(
topo: &Topology,
solid: SolidId,
cam: &Camera,
opts: &RenderOpts,
) -> Result<RenderOutput, RenderError> {
if opts.width == 0 || opts.height == 0 {
return Err(RenderError::InvalidSize {
width: opts.width,
height: opts.height,
});
}
let render_mesh = mesh::RenderMesh::build(topo, solid, opts.deflection)?;
pipeline::render(&render_mesh, cam, opts)
}