use opensubdiv_petite_sys as sys;
use crate::Index;
use crate::far::TopologyRefiner;
pub struct Stencil<'a> {
indices: &'a [Index],
weights: &'a [f32],
}
impl<'a> Stencil<'a> {
pub fn indices(&self) -> &'a [Index] {
self.indices
}
pub fn weights(&self) -> &'a [f32] {
self.weights
}
}
pub struct StencilTable(pub(crate) sys::far::StencilTablePtr);
pub struct StencilTableRef<'a> {
pub(crate) ptr: sys::far::StencilTablePtr,
pub(crate) _marker: std::marker::PhantomData<&'a ()>,
}
impl Drop for StencilTable {
#[inline]
fn drop(&mut self) {
unsafe { sys::far::stencil_table::StencilTable_destroy(self.0) }
}
}
impl StencilTable {
pub fn new(
refiner: &TopologyRefiner,
options: StencilTableOptions,
) -> crate::Result<StencilTable> {
let mut sys_options = sys::far::stencil_table::StencilTableOptions::new();
sys_options.set_interpolation_mode(options.interpolation_mode as u32);
sys_options.set_generate_offsets(options.generate_offsets);
sys_options.set_generate_control_vertices(options.generate_control_vertices);
sys_options.set_generate_intermediate_levels(options.generate_intermediate_levels);
sys_options.set_factorize_intermediate_levels(options.factorize_intermediate_levels);
sys_options.set_max_level(options.max_level.min(u32::MAX as usize) as u32);
sys_options.fvar_channel = options.face_varying_channel.min(u32::MAX as usize) as u32;
let ptr =
unsafe { sys::far::stencil_table::StencilTableFactory_Create(refiner.0, sys_options) };
if ptr.is_null() {
return Err(crate::Error::StencilTableCreation);
}
Ok(StencilTable(ptr))
}
#[inline]
pub fn len(&self) -> usize {
unsafe { sys::far::stencil_table::StencilTable_GetNumStencils(self.0) as _ }
}
#[inline]
pub fn is_empty(&self) -> bool {
0 == self.len()
}
#[inline]
pub fn control_vertex_count(&self) -> usize {
unsafe { sys::far::stencil_table::StencilTable_GetNumControlVertices(self.0) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `control_vertex_count` instead")]
#[inline]
pub fn control_vertices_len(&self) -> usize {
self.control_vertex_count()
}
#[inline]
pub fn stencil(&self, i: Index) -> Option<Stencil<'_>> {
if self.len() <= i.into() {
None
} else {
unsafe {
let stencil = sys::far::stencil_table::StencilTable_GetStencil(self.0, i.into());
Some(Stencil {
indices: std::slice::from_raw_parts(
stencil._base._indices as _,
*stencil._base._size as _,
),
weights: std::slice::from_raw_parts(
stencil._base._weights,
*stencil._base._size as _,
),
})
}
}
}
#[inline]
pub fn sizes(&self) -> &[i32] {
unsafe {
let vr = sys::far::stencil_table::StencilTable_GetSizes(self.0);
std::slice::from_raw_parts(vr.data() as _, vr.size())
}
}
#[inline]
pub fn offsets(&self) -> &[Index] {
unsafe {
let vr = sys::far::stencil_table::StencilTable_GetOffsets(self.0);
std::slice::from_raw_parts(vr.data() as *const Index, vr.size())
}
}
#[inline]
pub fn control_indices(&self) -> &[Index] {
unsafe {
let vr = sys::far::stencil_table::StencilTable_GetControlIndices(self.0);
std::slice::from_raw_parts(vr.data() as *const Index, vr.size())
}
}
#[inline]
pub fn weights(&self) -> &[f32] {
unsafe {
let vr = sys::far::stencil_table::StencilTable_GetWeights(self.0);
std::slice::from_raw_parts(vr.data(), vr.size())
}
}
pub fn update_values(&self, src: &[f32], start: Option<usize>, end: Option<usize>) -> Vec<f32> {
self.update_values_impl(self.0, src, start, end)
}
fn update_values_impl(
&self,
ptr: sys::far::StencilTablePtr,
src: &[f32],
start: Option<usize>,
end: Option<usize>,
) -> Vec<f32> {
let num_stencils =
unsafe { sys::far::stencil_table::StencilTable_GetNumStencils(ptr) as usize };
let actual_start = start.unwrap_or(0);
let actual_end = end.unwrap_or(num_stencils);
let output_size = actual_end - actual_start;
let mut dst = Vec::with_capacity(output_size);
unsafe {
sys::far::stencil_table::StencilTable_UpdateValues(
ptr,
src.as_ptr(),
dst.as_mut_ptr(),
start.map(|s| s as i32).unwrap_or(-1),
end.map(|e| e as i32).unwrap_or(-1),
);
dst.set_len(output_size);
}
dst
}
}
#[repr(u32)]
#[derive(Clone, Copy, Debug)]
pub enum InterpolationMode {
Vertex = 0,
Varying,
FaceVarying,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct StencilTableOptions {
pub interpolation_mode: InterpolationMode,
pub generate_offsets: bool,
pub generate_control_vertices: bool,
pub generate_intermediate_levels: bool,
pub factorize_intermediate_levels: bool,
pub max_level: usize,
pub face_varying_channel: usize,
}
impl<'a> StencilTableRef<'a> {
#[inline]
pub fn len(&self) -> usize {
unsafe { sys::far::stencil_table::StencilTable_GetNumStencils(self.ptr) as _ }
}
#[inline]
pub fn is_empty(&self) -> bool {
0 == self.len()
}
#[inline]
pub fn control_vertex_count(&self) -> usize {
unsafe { sys::far::stencil_table::StencilTable_GetNumControlVertices(self.ptr) as _ }
}
pub fn update_values(&self, src: &[f32], start: Option<usize>, end: Option<usize>) -> Vec<f32> {
StencilTable(std::ptr::null_mut()).update_values_impl(self.ptr, src, start, end)
}
}
impl Default for StencilTableOptions {
fn default() -> Self {
Self {
interpolation_mode: InterpolationMode::Vertex,
generate_offsets: false,
generate_control_vertices: false,
generate_intermediate_levels: true,
factorize_intermediate_levels: true,
max_level: 10,
face_varying_channel: 0,
}
}
}