use crate::error::RenderError;
use crate::scene_gpu::{
FAMILY_BOX, FAMILY_ELLIPSOID, FAMILY_PARTICLE, FAMILY_POLYGON, PrimitiveDrawGroup,
};
use molgfx_gpu::{
ColorTarget, DepthState, Device, PrimitiveTopology, RenderPipelineDesc, ShaderModuleDesc,
};
pub(crate) const PRIMITIVE_QUAD_VERTICES: u32 = 6;
const PARTICLE_SHAPE_CONSTANT: &str = "PARTICLE_SHAPE_KIND";
const PARTICLE_SHAPE_VARIANTS: [u32; 7] = [0, 2, 3, 4, 5, 6, 7];
const PARTICLE_SHAPE_MAX: u32 = 8;
pub(crate) struct PrimitiveEntries {
pub(crate) ellipsoid: &'static str,
pub(crate) oriented_box: &'static str,
pub(crate) polygon: &'static str,
pub(crate) particle: &'static str,
}
pub(crate) const OPAQUE_ENTRIES: PrimitiveEntries = PrimitiveEntries {
ellipsoid: "fs_primitive_ellipsoid",
oriented_box: "fs_primitive_box",
polygon: "fs_primitive_polygon",
particle: "fs_primitive_particle",
};
pub(crate) const TRANSPARENT_ENTRIES: PrimitiveEntries = PrimitiveEntries {
ellipsoid: "fs_primitive_ellipsoid_transparent",
oriented_box: "fs_primitive_box_transparent",
polygon: "fs_primitive_polygon_transparent",
particle: "fs_primitive_particle_transparent",
};
#[derive(Debug)]
pub(crate) struct PrimitivePipelineSet<D: Device> {
ellipsoid: D::Pipeline,
oriented_box: D::Pipeline,
polygon: D::Pipeline,
particle: Vec<Option<D::Pipeline>>,
}
impl<D: Device> PrimitivePipelineSet<D> {
pub(crate) fn build(
device: &D,
group0: &D::BindGroupLayout,
group1: Option<&D::BindGroupLayout>,
primitive: &D::BindGroupLayout,
entries: &PrimitiveEntries,
color_targets: &[ColorTarget],
depth: Option<DepthState>,
) -> Result<Self, RenderError> {
let shader = device.create_shader_module(&ShaderModuleDesc {
label: "geometry_primitive",
wgsl: molgfx_shaders::GEOMETRY_PRIMITIVE,
})?;
let build = |label, fs_entry, constants: &[(&'static str, f64)]| {
device.create_render_pipeline(&RenderPipelineDesc {
label,
layouts: &[Some(group0), group1, Some(primitive)],
shader: &shader,
vs_entry: "vs_primitive",
fs_entry: Some(fs_entry),
color_targets,
depth,
constants,
topology: PrimitiveTopology::TriangleList,
})
};
let mut particle = Vec::with_capacity(PARTICLE_SHAPE_MAX as usize);
for shape in 0..PARTICLE_SHAPE_MAX {
let variant = PARTICLE_SHAPE_VARIANTS.contains(&shape).then(|| {
build(
"analytic particles",
entries.particle,
&[(PARTICLE_SHAPE_CONSTANT, f64::from(shape))],
)
});
particle.push(variant.transpose()?);
}
Ok(Self {
ellipsoid: build("analytic ellipsoids", entries.ellipsoid, &[])?,
oriented_box: build("analytic boxes", entries.oriented_box, &[])?,
polygon: build("analytic polygons", entries.polygon, &[])?,
particle,
})
}
pub(crate) fn pipeline(&self, group: &PrimitiveDrawGroup) -> Option<&D::Pipeline> {
match group.family {
FAMILY_ELLIPSOID => Some(&self.ellipsoid),
FAMILY_BOX => Some(&self.oriented_box),
FAMILY_POLYGON => Some(&self.polygon),
FAMILY_PARTICLE => self
.particle
.get(group.shape as usize)
.and_then(Option::as_ref),
_ => None,
}
}
}