use super::topology_refiner::TopologyRefiner;
use opensubdiv_petite_sys as sys;
use crate::Index;
use sys::vtr::types::LocalIndex;
const INVALID_INDEX: u32 = u32::MAX;
pub struct TopologyLevel<'a> {
pub(crate) ptr: sys::far::TopologyLevelPtr,
pub(crate) refiner: std::marker::PhantomData<&'a TopologyRefiner>,
}
unsafe impl<'a> Send for TopologyLevel<'a> {}
unsafe impl<'a> Sync for TopologyLevel<'a> {}
impl<'a> TopologyLevel<'a> {
pub fn vertex_count(&self) -> usize {
unsafe { sys::far::TopologyLevel_GetNumVertices(self.ptr) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `vertex_count` instead")]
#[inline]
pub fn vertices_len(&self) -> usize {
self.vertex_count()
}
pub fn face_count(&self) -> usize {
unsafe { sys::far::TopologyLevel_GetNumFaces(self.ptr) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `face_count` instead")]
#[inline]
pub fn faces_len(&self) -> usize {
self.face_count()
}
pub fn edge_count(&self) -> usize {
unsafe { sys::far::TopologyLevel_GetNumEdges(self.ptr) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `edge_count` instead")]
#[inline]
pub fn edges_len(&self) -> usize {
self.edge_count()
}
pub fn face_vertex_count(&self) -> usize {
unsafe { sys::far::TopologyLevel_GetNumFaceVertices(self.ptr) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `face_vertex_count` instead")]
#[inline]
pub fn face_vertices_len(&self) -> usize {
self.face_vertex_count()
}
pub fn face_vertices_iter(&self) -> FaceVerticesIter<'_> {
FaceVerticesIter {
level: self,
current: 0,
num: self.face_count() as _,
}
}
#[cfg(feature = "rayon")]
pub fn face_vertices_par_iter(&self) -> FaceVerticesParIter<'_> {
FaceVerticesParIter::new(self)
}
}
impl<'a> TopologyLevel<'a> {
pub fn face_vertices(&self, face: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetFaceVertices(self.ptr, face.into());
if 0 == arr.size() || arr.begin().is_null() || self.face_count() <= face.into() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn face_edges(&self, face: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetFaceEdges(self.ptr, face.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn edge_vertices(&self, edge: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetEdgeVertices(self.ptr, edge.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn edge_faces(&self, f: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetEdgeFaces(self.ptr, f.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn vertex_faces(&self, vertex: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetVertexFaces(self.ptr, vertex.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn vertex_edges(&self, vertex: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetVertexEdges(self.ptr, vertex.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as _,
))
}
}
}
pub fn vertex_face_local_indices(&self, vertex: Index) -> Option<&[LocalIndex]> {
unsafe {
let arr = sys::far::TopologyLevel_GetVertexFaceLocalIndices(self.ptr, vertex.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(arr.begin(), arr.size() as _))
}
}
}
pub fn vertex_edge_local_indices(&self, vertex: Index) -> Option<&[LocalIndex]> {
unsafe {
let arr = sys::far::TopologyLevel_GetVertexEdgeLocalIndices(self.ptr, vertex.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(arr.begin(), arr.size() as _))
}
}
}
pub fn edge_face_local_indices(&self, face: Index) -> Option<&[LocalIndex]> {
unsafe {
let arr = sys::far::TopologyLevel_GetEdgeFaceLocalIndices(self.ptr, face.into());
if arr.size() == 0 || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(arr.begin(), arr.size() as _))
}
}
}
#[inline]
pub fn find_edge(&self, vertex0: Index, vertex1: Index) -> Option<Index> {
let i =
unsafe { sys::far::TopologyLevel_FindEdge(self.ptr, vertex0.into(), vertex1.into()) };
if INVALID_INDEX == i {
None
} else {
Some(i.into())
}
}
}
#[derive(Copy, Clone)]
pub struct FaceVerticesIter<'a> {
level: &'a TopologyLevel<'a>,
num: u32,
current: u32,
}
impl<'a> Iterator for FaceVerticesIter<'a> {
type Item = &'a [Index];
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.current == self.num {
None
} else {
self.current += 1;
self.level.face_vertices((self.current - 1).into())
}
}
}
#[cfg(feature = "rayon")]
use rayon::prelude::*;
#[cfg(feature = "rayon")]
#[derive(Copy, Clone)]
pub struct FaceVerticesParIter<'a> {
level: &'a TopologyLevel<'a>,
num: u32,
}
#[cfg(feature = "rayon")]
impl<'a> FaceVerticesParIter<'a> {
fn new(level: &'a TopologyLevel<'a>) -> Self {
Self {
level,
num: level.face_count() as u32,
}
}
}
#[cfg(feature = "rayon")]
impl<'a> ParallelIterator for FaceVerticesParIter<'a> {
type Item = &'a [Index];
fn drive_unindexed<C>(self, consumer: C) -> C::Result
where
C: rayon::iter::plumbing::UnindexedConsumer<Self::Item>,
{
(0..self.num)
.into_par_iter()
.map(|i| self.level.face_vertices(i.into()).unwrap())
.drive_unindexed(consumer)
}
}
#[cfg(feature = "rayon")]
impl<'a> IndexedParallelIterator for FaceVerticesParIter<'a> {
fn len(&self) -> usize {
self.num as usize
}
fn drive<C>(self, consumer: C) -> C::Result
where
C: rayon::iter::plumbing::Consumer<Self::Item>,
{
(0..self.num)
.into_par_iter()
.map(|i| self.level.face_vertices(i.into()).unwrap())
.drive(consumer)
}
fn with_producer<CB>(self, callback: CB) -> CB::Output
where
CB: rayon::iter::plumbing::ProducerCallback<Self::Item>,
{
(0..self.num)
.into_par_iter()
.map(|i| self.level.face_vertices(i.into()).unwrap())
.with_producer(callback)
}
}
impl<'a> TopologyLevel<'a> {
#[inline]
pub fn is_edge_non_manifold(&self, edge: Index) -> bool {
unsafe { sys::far::TopologyLevel_IsEdgeNonManifold(self.ptr, edge.into()) }
}
#[inline]
pub fn is_vertex_non_manifold(&self, vertex: Index) -> bool {
unsafe { sys::far::TopologyLevel_IsVertexNonManifold(self.ptr, vertex.into()) }
}
#[inline]
pub fn is_edge_boundary(&self, edge: Index) -> bool {
unsafe { sys::far::TopologyLevel_IsEdgeBoundary(self.ptr, edge.into()) }
}
#[inline]
pub fn is_vertex_boundary(&self, vertex: Index) -> bool {
unsafe { sys::far::TopologyLevel_IsVertexBoundary(self.ptr, vertex.into()) }
}
#[inline]
pub fn edge_sharpness(&self, edge: Index) -> f32 {
unsafe { sys::far::TopologyLevel_GetEdgeSharpness(self.ptr, edge.into()) }
}
#[inline]
pub fn vertex_sharpness(&self, vertex: Index) -> f32 {
unsafe { sys::far::TopologyLevel_GetVertexSharpness(self.ptr, vertex.into()) }
}
}
impl<'a> TopologyLevel<'a> {
#[inline]
pub fn face_varying_channel_count(&self) -> usize {
unsafe { sys::far::TopologyLevel_GetNumFVarChannels(self.ptr) as _ }
}
#[deprecated(since = "0.3.0", note = "Use `face_varying_channel_count` instead")]
#[inline]
pub fn face_varying_channels_len(&self) -> usize {
self.face_varying_channel_count()
}
#[inline]
pub fn face_varying_value_count(&self, channel: usize) -> usize {
unsafe {
let channel_i32 = channel.min(i32::MAX as usize) as i32;
sys::far::TopologyLevel_GetNumFVarValues(self.ptr, channel_i32) as _
}
}
#[deprecated(since = "0.3.0", note = "Use `face_varying_value_count` instead")]
#[inline]
pub fn face_varying_values_len(&self, channel: usize) -> usize {
self.face_varying_value_count(channel)
}
#[inline]
pub fn face_varying_values_on_face(&self, face: Index, channel: usize) -> Option<&[Index]> {
unsafe {
let arr =
sys::far::TopologyLevel_GetFaceFVarValues(self.ptr, face.into(), channel as _);
if 0 == arr.size() || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as usize,
))
}
}
}
#[inline]
pub fn vertex_face_varying_topology_matches(&self, vertex: Index, channel: usize) -> bool {
unsafe {
let channel_i32 = channel.min(i32::MAX as usize) as i32;
sys::far::TopologyLevel_DoesVertexFVarTopologyMatch(
self.ptr,
vertex.into(),
channel_i32,
)
}
}
#[inline]
pub fn edge_face_varying_topology_matches(&self, edge: Index, channel: usize) -> bool {
unsafe {
let channel_i32 = channel.min(i32::MAX as usize) as i32;
sys::far::TopologyLevel_DoesEdgeFVarTopologyMatch(self.ptr, edge.into(), channel_i32)
}
}
#[inline]
pub fn face_varying_topology_on_face_matches(&self, face: Index, channel: usize) -> bool {
unsafe {
let channel_i32 = channel.min(i32::MAX as usize) as i32;
sys::far::TopologyLevel_DoesFaceFVarTopologyMatch(self.ptr, face.into(), channel_i32)
}
}
}
impl<'a> TopologyLevel<'a> {
#[inline]
pub fn face_child_faces(&self, face: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetFaceChildFaces(self.ptr, face.into());
if 0 == arr.size() || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as usize,
))
}
}
}
#[inline]
pub fn face_child_edges(&self, face: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetFaceChildEdges(self.ptr, face.into());
if 0 == arr.size() || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as usize,
))
}
}
}
#[inline]
pub fn edge_child_edges(&self, edge: Index) -> Option<&[Index]> {
unsafe {
let arr = sys::far::TopologyLevel_GetEdgeChildEdges(self.ptr, edge.into());
if 0 == arr.size() || arr.begin().is_null() {
None
} else {
Some(std::slice::from_raw_parts(
arr.begin() as *const Index,
arr.size() as usize,
))
}
}
}
#[inline]
pub fn face_child_vertex(&self, face: Index) -> Index {
unsafe { sys::far::TopologyLevel_GetFaceChildVertex(self.ptr, face.into()).into() }
}
#[inline]
pub fn edge_child_vertex(&self, edge: Index) -> Index {
unsafe { sys::far::TopologyLevel_GetEdgeChildVertex(self.ptr, edge.into()).into() }
}
#[inline]
pub fn vertex_child_vertex(&self, vertex: Index) -> Index {
unsafe { sys::far::TopologyLevel_GetVertexChildVertex(self.ptr, vertex.into()).into() }
}
#[inline]
pub fn face_parent_face(&self, face: Index) -> Index {
unsafe { sys::far::TopologyLevel_GetFaceParentFace(self.ptr, face.into()).into() }
}
}