use super::StencilTableRef;
use crate::{Error, Index};
use opensubdiv_petite_sys as sys;
use std::marker::PhantomData;
use std::pin::Pin;
pub struct PatchTableOptions {
inner: Pin<Box<sys::far::PatchTableFactoryOptions>>,
}
impl Default for PatchTableOptions {
fn default() -> Self {
Self::new()
}
}
impl PatchTableOptions {
pub fn new() -> Self {
unsafe {
let ptr = sys::far::PatchTableFactory_Options_new();
assert!(!ptr.is_null());
Self {
inner: Pin::new(Box::from_raw(ptr)),
}
}
}
pub fn end_cap_type(mut self, end_cap_type: EndCapType) -> Self {
unsafe {
sys::far::PatchTableFactory_Options_SetEndCapType(
self.inner.as_mut().get_unchecked_mut(),
end_cap_type as i32,
);
}
self
}
pub fn get_end_cap_type(&self) -> EndCapType {
unsafe {
let end_cap = sys::far::PatchTableFactory_Options_GetEndCapType(
self.inner.as_ref().get_ref() as *const _,
);
match end_cap {
0 => EndCapType::None,
1 => EndCapType::BSplineBasis,
2 => EndCapType::GregoryBasis,
3 => EndCapType::LegacyGregory,
_ => EndCapType::None,
}
}
}
pub fn triangle_subdivision(mut self, triangle_subdivision: TriangleSubdivision) -> Self {
unsafe {
sys::far::PatchTableFactory_Options_SetTriangleSubdivision(
self.inner.as_mut().get_unchecked_mut(),
triangle_subdivision as i32,
);
}
self
}
pub fn use_inf_sharp_patch(mut self, use_inf_sharp_patch: bool) -> Self {
unsafe {
sys::far::PatchTableFactory_Options_SetUseInfSharpPatch(
self.inner.as_mut().get_unchecked_mut(),
use_inf_sharp_patch,
);
}
self
}
pub fn num_legacy_gregory_patches(mut self, num_patches: i32) -> Self {
unsafe {
sys::far::PatchTableFactory_Options_SetNumLegacyGregoryPatches(
self.inner.as_mut().get_unchecked_mut(),
num_patches,
);
}
self
}
pub(crate) fn as_ptr(&self) -> *const sys::far::PatchTableFactoryOptions {
self.inner.as_ref().get_ref() as *const _
}
}
impl Drop for PatchTableOptions {
fn drop(&mut self) {
unsafe {
sys::far::PatchTableFactory_Options_delete(self.inner.as_mut().get_unchecked_mut());
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EndCapType {
None,
BSplineBasis,
GregoryBasis,
LegacyGregory,
}
pub use crate::far::topology_refiner::TriangleSubdivision;
pub struct PatchTable {
ptr: *mut sys::far::PatchTable,
_phantom: PhantomData<sys::far::PatchTable>,
}
impl PatchTable {
pub fn new(
refiner: &crate::far::TopologyRefiner,
options: Option<PatchTableOptions>,
) -> Result<Self, Error> {
unsafe {
let options_ptr = options
.as_ref()
.map(|o| o.as_ptr())
.unwrap_or(std::ptr::null());
let ptr = sys::far::PatchTableFactory_Create(refiner.as_ptr(), options_ptr);
if ptr.is_null() {
Err(Error::PatchTableCreation)
} else {
Ok(Self {
ptr,
_phantom: PhantomData,
})
}
}
}
pub fn patch_array_count(&self) -> usize {
unsafe { sys::far::PatchTable_GetNumPatchArrays(self.ptr) as usize }
}
#[deprecated(since = "0.3.0", note = "Use `patch_array_count` instead")]
#[inline]
pub fn patch_arrays_len(&self) -> usize {
self.patch_array_count()
}
pub fn patch_count(&self) -> usize {
unsafe { sys::far::PatchTable_GetNumPatches(self.ptr) as usize }
}
#[deprecated(since = "0.3.0", note = "Use `patch_count` instead")]
#[inline]
pub fn patches_len(&self) -> usize {
self.patch_count()
}
pub fn control_vertex_count(&self) -> usize {
unsafe { sys::far::PatchTable_GetNumControlVertices(self.ptr) as usize }
}
#[deprecated(since = "0.3.0", note = "Use `control_vertex_count` instead")]
#[inline]
pub fn control_vertices_len(&self) -> usize {
self.control_vertex_count()
}
pub fn max_valence(&self) -> usize {
unsafe { sys::far::PatchTable_GetMaxValence(self.ptr) as usize }
}
pub fn local_point_count(&self) -> usize {
unsafe { sys::far::PatchTable_GetNumLocalPoints(self.ptr) as usize }
}
pub fn local_point_stencil_table(&self) -> Option<StencilTableRef<'_>> {
unsafe {
let stencil_ptr = sys::far::PatchTable_GetLocalPointStencilTable(self.ptr);
if stencil_ptr.is_null() {
None
} else {
Some(StencilTableRef {
ptr: stencil_ptr as *mut _,
_marker: std::marker::PhantomData,
})
}
}
}
pub fn patch_array_patch_count(&self, array_index: usize) -> usize {
unsafe {
sys::far::PatchTable_GetNumPatches_PatchArray(self.ptr, array_index as i32) as usize
}
}
#[deprecated(since = "0.3.0", note = "Use `patch_array_patch_count` instead")]
#[inline]
pub fn patch_array_patches_len(&self, array_index: usize) -> usize {
self.patch_array_patch_count(array_index)
}
pub fn patch_array_descriptor(&self, array_index: usize) -> Option<PatchDescriptor> {
if array_index >= self.patch_array_count() {
return None;
}
unsafe {
let mut desc = std::mem::zeroed::<sys::far::PatchDescriptor>();
sys::far::PatchTable_GetPatchArrayDescriptor(self.ptr, array_index as i32, &mut desc);
Some(PatchDescriptor { inner: desc })
}
}
pub fn patch_array_vertices(&self, array_index: usize) -> Option<&[Index]> {
if array_index >= self.patch_array_count() {
return None;
}
unsafe {
let ptr = sys::far::PatchTable_GetPatchArrayVertices(self.ptr, array_index as i32);
if ptr.is_null() {
None
} else {
let len = self.patch_array_patch_count(array_index);
let desc = self.patch_array_descriptor(array_index)?;
let num_cvs = desc.control_vertex_count();
let total_len = len * num_cvs;
Some(std::slice::from_raw_parts(ptr as *const Index, total_len))
}
}
}
pub fn patch_param(&self, array_index: usize, patch_index: usize) -> Option<PatchParam> {
if array_index >= self.patch_array_count() {
return None;
}
if patch_index >= self.patch_array_patch_count(array_index) {
return None;
}
unsafe {
let mut param = std::mem::zeroed::<sys::far::PatchParam>();
sys::far::PatchTable_GetPatchParam(
self.ptr,
array_index as i32,
patch_index as i32,
&mut param,
);
Some(PatchParam { inner: param })
}
}
pub fn control_vertices_table(&self) -> Option<&[Index]> {
unsafe {
let ptr = sys::far::PatchTable_GetPatchControlVerticesTable(self.ptr);
if ptr.is_null() {
None
} else {
let len = self.control_vertex_count();
Some(std::slice::from_raw_parts(ptr as *const Index, len))
}
}
}
pub(crate) fn as_ptr(&self) -> *const sys::far::PatchTable {
self.ptr
}
}
impl Drop for PatchTable {
fn drop(&mut self) {
unsafe {
sys::far::PatchTable_delete(self.ptr);
}
}
}
unsafe impl Send for PatchTable {}
unsafe impl Sync for PatchTable {}
#[derive(Clone, Copy)]
pub struct PatchDescriptor {
inner: sys::far::PatchDescriptor,
}
impl PatchDescriptor {
pub fn patch_type(&self) -> PatchType {
unsafe {
let patch_type = sys::far::PatchDescriptor_GetType(&self.inner);
match patch_type {
0 => PatchType::NonPatch,
1 => PatchType::Points,
2 => PatchType::Lines,
3 => PatchType::Quads,
4 => PatchType::Triangles,
5 => PatchType::Loop,
6 => PatchType::Regular,
7 => PatchType::BoundaryPattern0,
8 => PatchType::BoundaryPattern1,
9 => PatchType::BoundaryPattern2,
10 => PatchType::BoundaryPattern3,
11 => PatchType::BoundaryPattern4,
12 => PatchType::CornerPattern0,
13 => PatchType::CornerPattern1,
14 => PatchType::CornerPattern2,
15 => PatchType::CornerPattern3,
16 => PatchType::CornerPattern4,
17 => PatchType::Gregory,
18 => PatchType::GregoryBoundary,
19 => PatchType::GregoryCorner,
20 => PatchType::GregoryBasis,
21 => PatchType::GregoryTriangle,
_ => PatchType::NonPatch,
}
}
}
pub fn control_vertex_count(&self) -> usize {
unsafe { sys::far::PatchDescriptor_GetNumControlVertices(&self.inner) as usize }
}
#[deprecated(since = "0.3.0", note = "Use `control_vertex_count` instead")]
#[inline]
pub fn control_vertices_len(&self) -> usize {
self.control_vertex_count()
}
pub fn is_regular(&self) -> bool {
unsafe { sys::far::PatchDescriptor_IsRegular(&self.inner) }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PatchType {
NonPatch,
Points,
Lines,
Quads,
Triangles,
Loop,
Regular,
BoundaryPattern0,
BoundaryPattern1,
BoundaryPattern2,
BoundaryPattern3,
BoundaryPattern4,
CornerPattern0,
CornerPattern1,
CornerPattern2,
CornerPattern3,
CornerPattern4,
Gregory,
GregoryBoundary,
GregoryCorner,
GregoryBasis,
GregoryTriangle,
}
#[derive(Clone, Copy)]
pub struct PatchParam {
inner: sys::far::PatchParam,
}
impl PatchParam {
pub fn uv(&self) -> (f32, f32) {
unsafe {
let mut u = 0.0;
let mut v = 0.0;
sys::far::PatchParam_GetUV(&self.inner, &mut u, &mut v);
(u, v)
}
}
pub fn depth(&self) -> usize {
unsafe { sys::far::PatchParam_GetDepth(&self.inner) as usize }
}
pub fn is_regular(&self) -> bool {
unsafe { sys::far::PatchParam_IsRegular(&self.inner) }
}
pub fn boundary(&self) -> i32 {
unsafe { sys::far::PatchParam_GetBoundary(&self.inner) }
}
pub fn transition(&self) -> i32 {
unsafe { sys::far::PatchParam_GetTransition(&self.inner) }
}
}
#[derive(Clone, Copy)]
pub struct PatchEvalResult {
pub point: [f32; 3],
pub du: [f32; 3],
pub dv: [f32; 3],
pub duu: [f32; 3],
pub duv: [f32; 3],
pub dvv: [f32; 3],
}
impl From<sys::far::PatchEvalResult> for PatchEvalResult {
fn from(result: sys::far::PatchEvalResult) -> Self {
Self {
point: result.point,
du: result.du,
dv: result.dv,
duu: result.duu,
duv: result.duv,
dvv: result.dvv,
}
}
}
pub type BasisWeights = (Vec<f32>, Vec<f32>, Vec<f32>, Vec<f32>, Vec<f32>, Vec<f32>);
impl PatchTable {
pub fn evaluate_basis(&self, patch_index: usize, u: f32, v: f32) -> Option<BasisWeights> {
if patch_index >= self.patch_count() {
return None;
}
let mut array_index = 0;
let mut local_patch_index = patch_index;
for i in 0..self.patch_array_count() {
let num_patches = self.patch_array_patch_count(i);
if local_patch_index < num_patches {
array_index = i;
break;
}
local_patch_index -= num_patches;
}
let desc = self.patch_array_descriptor(array_index)?;
let num_cvs = desc.control_vertex_count();
let mut w_p = vec![0.0f32; num_cvs];
let mut w_du = vec![0.0f32; num_cvs];
let mut w_dv = vec![0.0f32; num_cvs];
let mut w_duu = vec![0.0f32; num_cvs];
let mut w_duv = vec![0.0f32; num_cvs];
let mut w_dvv = vec![0.0f32; num_cvs];
unsafe {
let success = sys::far::PatchTable_EvaluateBasis(
self.ptr,
patch_index as i32,
u,
v,
w_p.as_mut_ptr(),
w_du.as_mut_ptr(),
w_dv.as_mut_ptr(),
w_duu.as_mut_ptr(),
w_duv.as_mut_ptr(),
w_dvv.as_mut_ptr(),
);
if success {
Some((w_p, w_du, w_dv, w_duu, w_duv, w_dvv))
} else {
None
}
}
}
pub fn evaluate_point(
&self,
patch_index: usize,
u: f32,
v: f32,
control_points: &[[f32; 3]],
) -> Option<PatchEvalResult> {
if patch_index >= self.patch_count() {
return None;
}
unsafe {
let mut result = std::mem::zeroed::<sys::far::PatchEvalResult>();
let success = sys::far::PatchTable_EvaluatePoint(
self.ptr,
patch_index as i32,
u,
v,
control_points.as_ptr() as *const f32,
control_points.len() as i32,
&mut result,
);
if success {
Some(result.into())
} else {
None
}
}
}
}
pub struct PatchMap {
ptr: *mut sys::far::PatchMap,
_phantom: PhantomData<sys::far::PatchMap>,
}
impl PatchMap {
pub fn new(patch_table: &PatchTable) -> Option<Self> {
unsafe {
let ptr = sys::far::PatchMap_Create(patch_table.as_ptr());
if ptr.is_null() {
None
} else {
Some(Self {
ptr,
_phantom: PhantomData,
})
}
}
}
pub fn find_patch(&self, face_index: usize, u: f32, v: f32) -> Option<(usize, f32, f32)> {
unsafe {
let mut patch_index = 0i32;
let mut patch_u = 0.0f32;
let mut patch_v = 0.0f32;
let found = sys::far::PatchMap_FindPatch(
self.ptr,
face_index as i32,
u,
v,
&mut patch_index,
&mut patch_u,
&mut patch_v,
);
if found {
Some((patch_index as usize, patch_u, patch_v))
} else {
None
}
}
}
}
impl Drop for PatchMap {
fn drop(&mut self) {
unsafe {
sys::far::PatchMap_delete(self.ptr);
}
}
}
unsafe impl Send for PatchMap {}
unsafe impl Sync for PatchMap {}