OpenSubdiv/opensubdiv/bfr/faceVertex.h
Barry Fowler a1c7be7c8e Addition of Bfr interface (1 of 4): opensubdiv/bfr
This set of commits includes the addition of a new evaluation interface
that treats a subdivision mesh more like a piecewise parametric surface
primitive.  The new interface was placed in namespace "Bfr" for "Base
Face Representation" as all concepts and classes relate to a single face
of the base mesh.
2022-08-02 20:38:17 -07:00

396 lines
13 KiB
C++

//
// Copyright 2021 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#ifndef OPENSUBDIV3_BFR_FACE_VERTEX_H
#define OPENSUBDIV3_BFR_FACE_VERTEX_H
#include "../version.h"
#include "../bfr/vertexTag.h"
#include "../bfr/vertexDescriptor.h"
#include "../bfr/faceVertexSubset.h"
#include "../bfr/surfaceData.h"
#include "../sdc/crease.h"
#include <cassert>
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Bfr {
//
// The FaceVertex class is the primary internal class for gathering all
// topological information around the corner of a face. As such, it
// wraps an instance of the public VertexDescriptor class populated by the
// Factory subclasses. It extends an instance of VertexDescriptor with
// additional topological information and methods to make it more widely
// available and useful to internal classes.
//
// One fundamental extension of FaceVertex is that it includes the
// location of the face in the ring of incident faces around the vertex.
// VertexDescriptor alone simply specifies the neighborhood of the
// vertex, but the FaceVertex provides context relative to the face for
// which all of this information is being gathered.
//
// Several instances of FaceVertex (one for each corner of a face)
// are necessary to fully define the limit surface for a face, but in
// many cases, only a subset of the FaceVertex's incident faces will
// actually contribute to the surface. A companion class for defining
// that subset is defined elsewhere.
//
class FaceVertex {
public:
typedef internal::SurfaceData::Index Index;
public:
FaceVertex() { }
~FaceVertex() { }
// Methods supporting construction/initialization (subclass required
// to populate VertexDescriptor between Initialize and Finalize):
void Initialize(int faceSize, int regFaceSize);
void Finalize(int faceInVertex);
VertexDescriptor & GetVertexDescriptor() { return _vDesc; }
void ConnectUnOrderedFaces(Index const faceVertexIndices[]);
public:
// Methods to initialize and find subsets:
typedef FaceVertexSubset Subset;
int GetVertexSubset(Subset * subset) const;
int FindFaceVaryingSubset(Subset * fvarSubset,
Index const fvarIndices[],
Subset const & vtxSubset) const;
// Methods to control sharpness of the corner in a subset:
void SharpenSubset(Subset * subset) const;
void SharpenSubset(Subset * subset, float sharpness) const;
void UnSharpenSubset(Subset * subset) const;
public:
//
// Public methods to query simple properties:
//
VertexTag GetTag() const { return _tag; }
int GetFace() const { return _faceInRing; }
int GetNumFaces() const { return _vDesc._numFaces; }
int GetNumFaceVertices() const { return _numFaceVerts; }
bool HasCommonFaceSize() const { return (_commonFaceSize > 0); }
int GetCommonFaceSize() const { return _commonFaceSize; }
public:
//
// Public methods to inspect incident faces and connected neighbors:
//
int GetFaceSize(int face) const;
// Get neighbors of a specific face (return -1 if unconnected):
int GetFaceNext( int face) const;
int GetFacePrevious(int face) const;
// Find faces relative to this face (require a known safe step size):
int GetFaceAfter (int stepForwardFromCornerFace) const;
int GetFaceBefore(int stepBackwardFromCornerFace) const;
// Get first and last faces of a subset:
int GetFaceFirst(Subset const & subset) const;
int GetFaceLast( Subset const & subset) const;
public:
//
// Public methods to access indices assigned to incident faces:
//
int GetFaceIndexOffset(int face) const;
Index GetFaceIndexAtCorner(Index const indices[]) const;
Index GetFaceIndexAtCorner(int face, Index const indices[]) const;
Index GetFaceIndexTrailing(int face, Index const indices[]) const;
Index GetFaceIndexLeading( int face, Index const indices[]) const;
bool FaceIndicesMatchAtCorner( int f1, int f2, Index const indices[])const;
bool FaceIndicesMatchAtEdgeEnd( int f1, int f2, Index const indices[])const;
bool FaceIndicesMatchAcrossEdge(int f1, int f2, Index const indices[])const;
public:
//
// Public methods for sharpness of the vertex or its incident edges:
//
float GetVertexSharpness() const;
float GetFaceEdgeSharpness(int faceEdge) const;
float GetFaceEdgeSharpness(int face, bool trailingEdge) const;
bool IsFaceEdgeSharp( int face, bool trailingEdge) const;
bool IsFaceEdgeInfSharp( int face, bool trailingEdge) const;
bool IsFaceEdgeSemiSharp(int face, bool trailingEdge) const;
bool HasImplicitVertexSharpness() const;
float GetImplicitVertexSharpness() const;
private:
// Internal convenience methods:
bool isOrdered() const { return _tag.IsOrdered(); }
bool isUnOrdered() const { return _tag.IsUnOrdered(); }
bool isBoundary() const { return _tag.IsBoundary(); }
bool isInterior() const { return _tag.IsInterior(); }
bool isManifold() const { return _tag.IsManifold(); }
int getConnectedFaceNext(int face) const;
int getConnectedFacePrev(int face) const;
private:
// Internal methods for assembling and managing subsets:
int initCompleteSubset(Subset * subset) const;
int findConnectedSubsetExtent(Subset * subset) const;
int findFVarSubsetExtent(Subset const & vtxSubset,
Subset * fvarSubset,
Index const fvarIndices[]) const;
void adjustSubsetTags(Subset * subset,
Subset const * superset = 0) const;
bool subsetHasInfSharpEdges( Subset const & subset) const;
bool subsetHasSemiSharpEdges(Subset const & subset) const;
bool subsetHasIrregularFaces(Subset const & subset) const;
private:
// Internal methods to connect a set of unordered faces (given their
// associated face-vertex indices) and assess the resulting topology:
struct Edge;
int createUnOrderedEdges(Edge edges[],
short faceEdgeIndices[],
Index const faceVertIndices[]) const;
void markDuplicateEdges(Edge edges[],
short const faceEdgeIndices[],
Index const faceVertIndices[]) const;
void assignUnOrderedFaceNeighbors(Edge const edges[],
short const faceEdgeIndices[]);
void finalizeUnOrderedTags(Edge const edges[], int numEdges);
// Ordered counterpart to the above method for finalizing tags
void finalizeOrderedTags();
private:
typedef Vtr::internal::StackBuffer<short,16,true> ShortBuffer;
// Private members:
VertexDescriptor _vDesc;
VertexTag _tag;
short _faceInRing;
short _commonFaceSize;
unsigned char _regFaceSize;
unsigned char _isExpInfSharp : 1;
unsigned char _isExpSemiSharp : 1;
unsigned char _isImpInfSharp : 1;
unsigned char _isImpSemiSharp : 1;
int _numFaceVerts;
ShortBuffer _faceEdgeNeighbors;
};
//
// Inline methods for inspecting/traversing incident faces of the vertex:
//
inline int
FaceVertex::GetFaceSize(int face) const {
return _commonFaceSize ? _commonFaceSize :
(_vDesc._faceSizeOffsets[face+1] - _vDesc._faceSizeOffsets[face]);
}
inline int
FaceVertex::getConnectedFaceNext(int face) const {
return _faceEdgeNeighbors[2*face + 1];
}
inline int
FaceVertex::getConnectedFacePrev(int face) const {
return _faceEdgeNeighbors[2*face];
}
inline int
FaceVertex::GetFaceNext(int face) const {
if (isUnOrdered()) {
return getConnectedFaceNext(face);
} else if (face < (_vDesc._numFaces - 1)) {
return face + 1;
} else {
return isBoundary() ? -1 : 0;
}
}
inline int
FaceVertex::GetFacePrevious(int face) const {
if (isUnOrdered()) {
return getConnectedFacePrev(face);
} else if (face) {
return face - 1;
} else {
return isBoundary() ? -1 : (_vDesc._numFaces - 1);
}
}
inline int
FaceVertex::GetFaceAfter(int step) const {
assert(step >= 0);
if (isOrdered()) {
return (_faceInRing + step) % _vDesc._numFaces;
} else if (step == 1) {
return getConnectedFaceNext(_faceInRing);
} else if (step == 2) {
return getConnectedFaceNext(getConnectedFaceNext(_faceInRing));
} else {
int face = _faceInRing;
for ( ; step > 0; --step) {
face = getConnectedFaceNext(face);
}
return face;
}
}
inline int
FaceVertex::GetFaceBefore(int step) const {
assert(step >= 0);
if (isOrdered()) {
return (_faceInRing - step + _vDesc._numFaces) % _vDesc._numFaces;
} else if (step == 1) {
return getConnectedFacePrev(_faceInRing);
} else if (step == 2) {
return getConnectedFacePrev(getConnectedFacePrev(_faceInRing));
} else {
int face = _faceInRing;
for ( ; step > 0; --step) {
face = getConnectedFacePrev(face);
}
return face;
}
}
inline int
FaceVertex::GetFaceFirst(Subset const & subset) const {
return GetFaceBefore(subset._numFacesBefore);
}
inline int
FaceVertex::GetFaceLast(Subset const & subset) const {
return GetFaceAfter(subset._numFacesAfter);
}
//
// Inline methods for accessing indices associated with incident faces:
//
inline int
FaceVertex::GetFaceIndexOffset(int face) const {
return _commonFaceSize ? (face * _commonFaceSize) :
_vDesc._faceSizeOffsets[face];
}
inline FaceVertex::Index
FaceVertex::GetFaceIndexAtCorner(Index const indices[]) const {
return indices[GetFaceIndexOffset(_faceInRing)];
}
inline FaceVertex::Index
FaceVertex::GetFaceIndexAtCorner(int face, Index const indices[]) const {
return indices[GetFaceIndexOffset(face)];
}
inline FaceVertex::Index
FaceVertex::GetFaceIndexLeading(int face, Index const indices[]) const {
return indices[GetFaceIndexOffset(face) + 1];
}
inline FaceVertex::Index
FaceVertex::GetFaceIndexTrailing(int face, Index const indices[]) const {
// It is safe to use "face+1" here for the last face:
return indices[GetFaceIndexOffset(face+1) - 1];
}
inline bool
FaceVertex::FaceIndicesMatchAtCorner(int facePrev, int faceNext,
Index const indices[]) const {
return GetFaceIndexAtCorner(facePrev, indices) ==
GetFaceIndexAtCorner(faceNext, indices);
}
inline bool
FaceVertex::FaceIndicesMatchAtEdgeEnd(int facePrev, int faceNext,
Index const indices[]) const {
return GetFaceIndexTrailing(facePrev, indices) ==
GetFaceIndexLeading(faceNext, indices);
}
inline bool
FaceVertex::FaceIndicesMatchAcrossEdge(int facePrev, int faceNext,
Index const indices[]) const {
return FaceIndicesMatchAtCorner (facePrev, faceNext, indices) &&
FaceIndicesMatchAtEdgeEnd(facePrev, faceNext, indices);
}
//
// Inline methods for accessing vertex and edge sharpness:
//
inline float
FaceVertex::GetVertexSharpness() const {
return _vDesc._vertSharpness;
}
inline float
FaceVertex::GetFaceEdgeSharpness(int faceEdge) const {
return _vDesc._faceEdgeSharpness[faceEdge];
}
inline float
FaceVertex::GetFaceEdgeSharpness(int face, bool trailing) const {
return _vDesc._faceEdgeSharpness[face*2 + trailing];
}
inline bool
FaceVertex::IsFaceEdgeSharp(int face, bool trailing) const {
return Sdc::Crease::IsSharp(_vDesc._faceEdgeSharpness[face*2+trailing]);
}
inline bool
FaceVertex::IsFaceEdgeInfSharp(int face, bool trailing) const {
return Sdc::Crease::IsInfinite(_vDesc._faceEdgeSharpness[face*2+trailing]);
}
inline bool
FaceVertex::IsFaceEdgeSemiSharp(int face, bool trailing) const {
return Sdc::Crease::IsSemiSharp(_vDesc._faceEdgeSharpness[face*2+trailing]);
}
} // end namespace Bfr
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_BFR_FACE_VERTEX_H */