|
|
|
@ -0,0 +1,768 @@
|
|
|
|
|
//
|
|
|
|
|
// Copyright 2014 DreamWorks Animation LLC.
|
|
|
|
|
//
|
|
|
|
|
// 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 VTR_LEVEL_H
|
|
|
|
|
#define VTR_LEVEL_H
|
|
|
|
|
|
|
|
|
|
#include "../version.h"
|
|
|
|
|
|
|
|
|
|
#include "../sdc/type.h"
|
|
|
|
|
#include "../sdc/crease.h"
|
|
|
|
|
#include "../sdc/options.h"
|
|
|
|
|
#include "../vtr/types.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace OpenSubdiv {
|
|
|
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
|
|
|
|
|
|
// Forward declarations for friends:
|
|
|
|
|
namespace Far {
|
|
|
|
|
template <class MESH> class TopologyRefinerFactory;
|
|
|
|
|
class TopologyRefinerFactoryBase;
|
|
|
|
|
class TopologyRefiner;
|
|
|
|
|
class PatchTablesFactory;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace Vtr {
|
|
|
|
|
|
|
|
|
|
class Refinement;
|
|
|
|
|
class QuadRefinement;
|
|
|
|
|
class TriRefinement;
|
|
|
|
|
class FVarRefinement;
|
|
|
|
|
class FVarLevel;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Level:
|
|
|
|
|
// A refinement level includes a vectorized representation of the topology
|
|
|
|
|
// for a particular subdivision level. The topology is "complete" in that any
|
|
|
|
|
// level can be used as the base level of another subdivision hierarchy and can
|
|
|
|
|
// be considered a complete mesh independent of its ancestors. It currently
|
|
|
|
|
// does contain a "depth" member -- as some inferences can then be made about
|
|
|
|
|
// the topology (i.e. all quads or all tris if not level 0) but that is still
|
|
|
|
|
// under consideration (e.g. a "regular" flag would serve the same purpose, and
|
|
|
|
|
// level 0 may even be regular).
|
|
|
|
|
//
|
|
|
|
|
// This class is intended for private use within the library. So really its
|
|
|
|
|
// interface should be fully protected and only those library classes that need
|
|
|
|
|
// it will be declared as friends, e.g. Refinement.
|
|
|
|
|
//
|
|
|
|
|
// The represenation of topology here is to store six topological relationships
|
|
|
|
|
// in tables of integers. Each is stored in its own array(s) so the result is
|
|
|
|
|
// a SOA representation of the topology. The six relations are:
|
|
|
|
|
//
|
|
|
|
|
// - face-verts: vertices incident/comprising a face
|
|
|
|
|
// - face-edges: edges incident a face
|
|
|
|
|
// - edge-verts: vertices incident/comprising an edge
|
|
|
|
|
// - edge-faces: faces incident an edge
|
|
|
|
|
// - vert-faces: faces incident a vertex
|
|
|
|
|
// - vert-edges: edges incident a vertex
|
|
|
|
|
//
|
|
|
|
|
// There is some redundancy here but the intent is not that this be a minimal
|
|
|
|
|
// represenation, the intent is that it be amenable to refinement. Classes in
|
|
|
|
|
// the Far layer essentially store 5 of these 6 in a permuted form -- we add
|
|
|
|
|
// the face-edges here to simplify refinement.
|
|
|
|
|
//
|
|
|
|
|
// Notes/limitations/stuff to do -- much of this code still reflects the early days
|
|
|
|
|
// when it was being prototyped and so it does not conform to OSD standards in many
|
|
|
|
|
// ways:
|
|
|
|
|
// - superficial stylistic issues:
|
|
|
|
|
// . replacing "m" prefix with "_" on member variables
|
|
|
|
|
// - done
|
|
|
|
|
// . replace "access" and "modify" prefixes on Array methods with "get"
|
|
|
|
|
// - done
|
|
|
|
|
// - replace use of "...Count" with "GetNum..."
|
|
|
|
|
// - use of Vertex vs Vert in non-local (or any?) methods
|
|
|
|
|
// - review public/protected/friend accessibility
|
|
|
|
|
//
|
|
|
|
|
// Most are more relevant to the refinement, which used to be part of this class:
|
|
|
|
|
// - short cuts that need revisiting:
|
|
|
|
|
// - support for face-vert counts > 4
|
|
|
|
|
// - support for edge-face counts > 2
|
|
|
|
|
// - some neighborhood searches avoidable with more "local indexing"
|
|
|
|
|
// - identify (informally) where scheme-specific code will be needed, so far:
|
|
|
|
|
// - topological splitting and associated marking
|
|
|
|
|
// - really the only variable here is whether to generate tris or
|
|
|
|
|
// quads from non-quads
|
|
|
|
|
// - interpolation
|
|
|
|
|
// - potentially not part of the pre-processing required for FarMesh
|
|
|
|
|
// and where it appears *not* to be needed:
|
|
|
|
|
// - subdivision of sharpness values
|
|
|
|
|
// - classification of vertex type/mask
|
|
|
|
|
// - apply classification of vertices (computing Rules or masks)
|
|
|
|
|
// - apply to base/course level on conversion
|
|
|
|
|
// - apply to child level after subdivision of sharpness
|
|
|
|
|
// - keep in mind desired similarity with FarMesh tables for ease of transfer
|
|
|
|
|
// (contradicts previous point to some degree)
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
class Level {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
//
|
|
|
|
|
// Simple nested types to hold the tags for each component type -- some of
|
|
|
|
|
// which are user-specified features (e.g. whether a face is a hole or not)
|
|
|
|
|
// while others indicate the topological nature of the component, how it
|
|
|
|
|
// is affected by creasing in its neighborhood, etc.
|
|
|
|
|
//
|
|
|
|
|
// Most of these properties are passed down to child components during
|
|
|
|
|
// refinement, but some -- notably the designation of a component as semi-
|
|
|
|
|
// sharp -- require re-determination as sharpnes values are reduced at each
|
|
|
|
|
// level.
|
|
|
|
|
//
|
|
|
|
|
struct VTag {
|
|
|
|
|
typedef unsigned short VTagSize;
|
|
|
|
|
|
|
|
|
|
VTag() { }
|
|
|
|
|
|
|
|
|
|
VTagSize _nonManifold : 1; // fixed
|
|
|
|
|
VTagSize _xordinary : 1; // fixed
|
|
|
|
|
VTagSize _boundary : 1; // fixed
|
|
|
|
|
VTagSize _infSharp : 1; // fixed
|
|
|
|
|
VTagSize _semiSharp : 1; // variable
|
|
|
|
|
VTagSize _rule : 4; // variable when _semiSharp
|
|
|
|
|
VTagSize _incomplete : 1; // variable for sparse refinement
|
|
|
|
|
|
|
|
|
|
// On deck -- coming soon...
|
|
|
|
|
//VTagSize _constSharp : 1; // variable when _semiSharp
|
|
|
|
|
//VTagSize _hasEdits : 1; // variable
|
|
|
|
|
//VTagSize _editsApplied : 1; // variable
|
|
|
|
|
};
|
|
|
|
|
struct ETag {
|
|
|
|
|
typedef unsigned char ETagSize;
|
|
|
|
|
|
|
|
|
|
ETag() { }
|
|
|
|
|
|
|
|
|
|
ETagSize _nonManifold : 1; // fixed
|
|
|
|
|
ETagSize _boundary : 1; // fixed
|
|
|
|
|
ETagSize _infSharp : 1; // fixed
|
|
|
|
|
ETagSize _semiSharp : 1; // variable
|
|
|
|
|
};
|
|
|
|
|
struct FTag {
|
|
|
|
|
typedef unsigned char FTagSize;
|
|
|
|
|
|
|
|
|
|
FTag() { }
|
|
|
|
|
|
|
|
|
|
FTagSize _hole : 1; // fixed
|
|
|
|
|
|
|
|
|
|
// On deck -- coming soon...
|
|
|
|
|
//FTagSize _hasEdits : 1; // variable
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
VTag getFaceCompositeVTag(ConstIndexArray & faceVerts) const;
|
|
|
|
|
|
|
|
|
|
ETag getFaceCompositeETag(ConstIndexArray & faceEdges) const;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Level();
|
|
|
|
|
~Level();
|
|
|
|
|
|
|
|
|
|
// Simple accessors:
|
|
|
|
|
int getDepth() const { return _depth; }
|
|
|
|
|
|
|
|
|
|
int getNumVertices() const { return _vertCount; }
|
|
|
|
|
int getNumFaces() const { return _faceCount; }
|
|
|
|
|
int getNumEdges() const { return _edgeCount; }
|
|
|
|
|
|
|
|
|
|
// More global sizes may prove useful...
|
|
|
|
|
int getNumFaceVerticesTotal() const { return (int) _faceVertIndices.size(); }
|
|
|
|
|
int getNumFaceEdgesTotal() const { return (int) _faceEdgeIndices.size(); }
|
|
|
|
|
int getNumEdgeVerticesTotal() const { return (int) _edgeVertIndices.size(); }
|
|
|
|
|
int getNumEdgeFacesTotal() const { return (int) _edgeFaceIndices.size(); }
|
|
|
|
|
int getNumVertexFacesTotal() const { return (int) _vertFaceIndices.size(); }
|
|
|
|
|
int getNumVertexEdgesTotal() const { return (int) _vertEdgeIndices.size(); }
|
|
|
|
|
|
|
|
|
|
int getMaxValence() const { return _maxValence; }
|
|
|
|
|
int getMaxEdgeFaces() const { return _maxEdgeFaces; }
|
|
|
|
|
|
|
|
|
|
// Methods to access the relation tables/indices -- note that for some relations
|
|
|
|
|
// we store an additional "local index", e.g. for the case of vert-faces if one
|
|
|
|
|
// of the faces F[i] is incident a vertex V, then L[i] is the "local index" in
|
|
|
|
|
// F[i] of vertex V. Once have only quads (or tris), this local index need only
|
|
|
|
|
// occupy two bits and could conceivably be packed into the same integer as the
|
|
|
|
|
// face index, but for now, given the need to support faces of potentially high
|
|
|
|
|
// valence we'll us an 8- or 16-bit integer.
|
|
|
|
|
//
|
|
|
|
|
// Methods to access the six topological relations:
|
|
|
|
|
ConstIndexArray getFaceVertices(Index faceIndex) const;
|
|
|
|
|
ConstIndexArray getFaceEdges(Index faceIndex) const;
|
|
|
|
|
ConstIndexArray getEdgeVertices(Index edgeIndex) const;
|
|
|
|
|
ConstIndexArray getEdgeFaces(Index edgeIndex) const;
|
|
|
|
|
ConstIndexArray getVertexFaces(Index vertIndex) const;
|
|
|
|
|
ConstIndexArray getVertexEdges(Index vertIndex) const;
|
|
|
|
|
|
|
|
|
|
ConstLocalIndexArray getVertexFaceLocalIndices(Index vertIndex) const;
|
|
|
|
|
ConstLocalIndexArray getVertexEdgeLocalIndices(Index vertIndex) const;
|
|
|
|
|
|
|
|
|
|
// Replace these with access to sharpness buffers/arrays rather than elements:
|
|
|
|
|
float getEdgeSharpness(Index edgeIndex) const;
|
|
|
|
|
float getVertexSharpness(Index vertIndex) const;
|
|
|
|
|
Sdc::Crease::Rule getVertexRule(Index vertIndex) const;
|
|
|
|
|
|
|
|
|
|
Index findEdge(Index v0Index, Index v1Index) const;
|
|
|
|
|
|
|
|
|
|
// Holes
|
|
|
|
|
void setHole(Index faceIndex, bool b);
|
|
|
|
|
bool isHole(Index faceIndex) const;
|
|
|
|
|
|
|
|
|
|
// Manifold/non-manifold tags:
|
|
|
|
|
void setEdgeNonManifold(Index edgeIndex, bool b);
|
|
|
|
|
bool isEdgeNonManifold(Index edgeIndex) const;
|
|
|
|
|
|
|
|
|
|
void setVertexNonManifold(Index vertIndex, bool b);
|
|
|
|
|
bool isVertexNonManifold(Index vertIndex) const;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
// Debugging aides -- unclear what will persist...
|
|
|
|
|
enum TopologyError {
|
|
|
|
|
TOPOLOGY_MISSING_EDGE_FACES=0,
|
|
|
|
|
TOPOLOGY_MISSING_EDGE_VERTS,
|
|
|
|
|
TOPOLOGY_MISSING_FACE_EDGES,
|
|
|
|
|
TOPOLOGY_MISSING_FACE_VERTS,
|
|
|
|
|
TOPOLOGY_MISSING_VERT_FACES,
|
|
|
|
|
TOPOLOGY_MISSING_VERT_EDGES,
|
|
|
|
|
|
|
|
|
|
TOPOLOGY_FAILED_CORRELATION_EDGE_FACE,
|
|
|
|
|
TOPOLOGY_FAILED_CORRELATION_FACE_VERT,
|
|
|
|
|
TOPOLOGY_FAILED_CORRELATION_FACE_EDGE,
|
|
|
|
|
|
|
|
|
|
TOPOLOGY_FAILED_ORIENTATION_INCIDENT_EDGE,
|
|
|
|
|
TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACE,
|
|
|
|
|
TOPOLOGY_FAILED_ORIENTATION_INCIDENT_FACES_EDGES,
|
|
|
|
|
|
|
|
|
|
TOPOLOGY_DEGENERATE_EDGE,
|
|
|
|
|
TOPOLOGY_NON_MANIFOLD_EDGE,
|
|
|
|
|
|
|
|
|
|
TOPOLOGY_INVALID_CREASE_EDGE,
|
|
|
|
|
TOPOLOGY_INVALID_CREASE_VERT
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static char const * getTopologyErrorString(TopologyError errCode);
|
|
|
|
|
|
|
|
|
|
typedef void (* ValidationCallback)(TopologyError errCode, char const * msg, void const * clientData);
|
|
|
|
|
|
|
|
|
|
bool validateTopology(ValidationCallback callback=0, void const * clientData=0) const;
|
|
|
|
|
|
|
|
|
|
void print(const Refinement* parentRefinement = 0) const;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// High-level topology queries -- these are likely to be moved elsewhere, but here
|
|
|
|
|
// is the best place for them for now...
|
|
|
|
|
|
|
|
|
|
int gatherManifoldVertexRingFromIncidentQuads(Index vIndex, int vOffset, int ringVerts[]) const;
|
|
|
|
|
|
|
|
|
|
int gatherQuadRegularInteriorPatchVertices(Index fIndex, Index patchVerts[], int rotation = 0) const;
|
|
|
|
|
int gatherQuadRegularBoundaryPatchVertices(Index fIndex, Index patchVerts[], int boundaryEdgeInFace) const;
|
|
|
|
|
int gatherQuadRegularCornerPatchVertices( Index fIndex, Index patchVerts[], int cornerVertInFace) const;
|
|
|
|
|
|
|
|
|
|
int gatherTriRegularInteriorPatchVertices( Index fIndex, Index patchVerts[], int rotation = 0) const;
|
|
|
|
|
int gatherTriRegularBoundaryVertexPatchVertices(Index fIndex, Index patchVerts[], int boundaryVertInFace) const;
|
|
|
|
|
int gatherTriRegularBoundaryEdgePatchVertices( Index fIndex, Index patchVerts[], int boundaryEdgeInFace) const;
|
|
|
|
|
int gatherTriRegularCornerVertexPatchVertices( Index fIndex, Index patchVerts[], int cornerVertInFace) const;
|
|
|
|
|
int gatherTriRegularCornerEdgePatchVertices( Index fIndex, Index patchVerts[], int cornerEdgeInFace) const;
|
|
|
|
|
|
|
|
|
|
bool isSingleCreasePatch(Index face, float* sharpnessOut=NULL, int* rotationOut=NULL) const;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
|
|
friend class Refinement;
|
|
|
|
|
friend class QuadRefinement;
|
|
|
|
|
friend class TriRefinement;
|
|
|
|
|
friend class FVarRefinement;
|
|
|
|
|
friend class FVarLevel;
|
|
|
|
|
|
|
|
|
|
template <class MESH> friend class Far::TopologyRefinerFactory;
|
|
|
|
|
friend class Far::TopologyRefinerFactoryBase;
|
|
|
|
|
friend class Far::TopologyRefiner;
|
|
|
|
|
friend class Far::PatchTablesFactory;
|
|
|
|
|
|
|
|
|
|
// Sizing methods used to construct a level to populate:
|
|
|
|
|
void resizeFaces( int numFaces);
|
|
|
|
|
void resizeFaceVertices(int numFaceVertsTotal);
|
|
|
|
|
void resizeFaceEdges( int numFaceEdgesTotal);
|
|
|
|
|
|
|
|
|
|
void resizeEdges( int numEdges);
|
|
|
|
|
void resizeEdgeVertices(); // always 2*edgeCount
|
|
|
|
|
void resizeEdgeFaces(int numEdgeFacesTotal);
|
|
|
|
|
|
|
|
|
|
void resizeVertices( int numVertices);
|
|
|
|
|
void resizeVertexFaces(int numVertexFacesTotal);
|
|
|
|
|
void resizeVertexEdges(int numVertexEdgesTotal);
|
|
|
|
|
|
|
|
|
|
// Modifiers to populate the relations for each component:
|
|
|
|
|
IndexArray getFaceVertices(Index faceIndex);
|
|
|
|
|
IndexArray getFaceEdges(Index faceIndex);
|
|
|
|
|
IndexArray getEdgeVertices(Index edgeIndex);
|
|
|
|
|
IndexArray getEdgeFaces(Index edgeIndex);
|
|
|
|
|
IndexArray getVertexFaces( Index vertIndex);
|
|
|
|
|
LocalIndexArray getVertexFaceLocalIndices(Index vertIndex);
|
|
|
|
|
IndexArray getVertexEdges( Index vertIndex);
|
|
|
|
|
LocalIndexArray getVertexEdgeLocalIndices(Index vertIndex);
|
|
|
|
|
|
|
|
|
|
// Replace these with access to sharpness buffers/arrays rather than elements:
|
|
|
|
|
float& getEdgeSharpness(Index edgeIndex);
|
|
|
|
|
float& getVertexSharpness(Index vertIndex);
|
|
|
|
|
|
|
|
|
|
// Create, destroy and populate face-varying channels:
|
|
|
|
|
int createFVarChannel(int fvarValueCount, Sdc::Options const& options);
|
|
|
|
|
void destroyFVarChannel(int channel = 0);
|
|
|
|
|
|
|
|
|
|
int getNumFVarChannels() const { return (int) _fvarChannels.size(); }
|
|
|
|
|
int getNumFVarValues(int channel = 0) const;
|
|
|
|
|
|
|
|
|
|
ConstIndexArray getFVarFaceValues(Index faceIndex, int channel = 0) const;
|
|
|
|
|
IndexArray getFVarFaceValues(Index faceIndex, int channel = 0);
|
|
|
|
|
|
|
|
|
|
void completeFVarChannelTopology(int channel = 0);
|
|
|
|
|
|
|
|
|
|
// Counts and offsets for all relation types:
|
|
|
|
|
// - these may be unwarranted if we let Refinement access members directly...
|
|
|
|
|
int getNumFaceVertices( Index faceIndex) const { return _faceVertCountsAndOffsets[2*faceIndex]; }
|
|
|
|
|
int getOffsetOfFaceVertices(Index faceIndex) const { return _faceVertCountsAndOffsets[2*faceIndex + 1]; }
|
|
|
|
|
|
|
|
|
|
int getNumFaceEdges( Index faceIndex) const { return getNumFaceVertices(faceIndex); }
|
|
|
|
|
int getOffsetOfFaceEdges(Index faceIndex) const { return getOffsetOfFaceVertices(faceIndex); }
|
|
|
|
|
|
|
|
|
|
int getNumEdgeVertices( Index ) const { return 2; }
|
|
|
|
|
int getOffsetOfEdgeVertices(Index edgeIndex) const { return 2 * edgeIndex; }
|
|
|
|
|
|
|
|
|
|
int getNumEdgeFaces( Index edgeIndex) const { return _edgeFaceCountsAndOffsets[2*edgeIndex]; }
|
|
|
|
|
int getOffsetOfEdgeFaces(Index edgeIndex) const { return _edgeFaceCountsAndOffsets[2*edgeIndex + 1]; }
|
|
|
|
|
|
|
|
|
|
int getNumVertexFaces( Index vertIndex) const { return _vertFaceCountsAndOffsets[2*vertIndex]; }
|
|
|
|
|
int getOffsetOfVertexFaces(Index vertIndex) const { return _vertFaceCountsAndOffsets[2*vertIndex + 1]; }
|
|
|
|
|
|
|
|
|
|
int getNumVertexEdges( Index vertIndex) const { return _vertEdgeCountsAndOffsets[2*vertIndex]; }
|
|
|
|
|
int getOffsetOfVertexEdges(Index vertIndex) const { return _vertEdgeCountsAndOffsets[2*vertIndex + 1]; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Note that for some relations, the size of the relations for a child component
|
|
|
|
|
// can vary radically from its parent due to the sparsity of the refinement. So
|
|
|
|
|
// in these cases a few additional utilities are provided to help define the set
|
|
|
|
|
// of incident components. Assuming adequate memory has been allocated, the
|
|
|
|
|
// "resize" methods here initialize the set of incident components by setting
|
|
|
|
|
// both the size and the appropriate offset, while "trim" is use to quickly lower
|
|
|
|
|
// the size from an upper bound and nothing else.
|
|
|
|
|
//
|
|
|
|
|
void resizeFaceVertices(Index FaceIndex, int count);
|
|
|
|
|
|
|
|
|
|
void resizeEdgeFaces(Index edgeIndex, int count);
|
|
|
|
|
void trimEdgeFaces( Index edgeIndex, int count);
|
|
|
|
|
|
|
|
|
|
void resizeVertexFaces(Index vertIndex, int count);
|
|
|
|
|
void trimVertexFaces( Index vertIndex, int count);
|
|
|
|
|
|
|
|
|
|
void resizeVertexEdges(Index vertIndex, int count);
|
|
|
|
|
void trimVertexEdges( Index vertIndex, int count);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
//
|
|
|
|
|
// Plans where to have a few specific friend classes properly construct the topology,
|
|
|
|
|
// e.g. the Refinement class. There is now clearly a need to have some class
|
|
|
|
|
// construct full topology given only a simple face-vertex list. That can be done
|
|
|
|
|
// externally (either a Factory outside Vtr or another Vtr construction helper), but
|
|
|
|
|
// until we decide where, the required implementation is defined here.
|
|
|
|
|
//
|
|
|
|
|
void completeTopologyFromFaceVertices();
|
|
|
|
|
Index findEdge(Index v0, Index v1, ConstIndexArray v0Edges) const;
|
|
|
|
|
|
|
|
|
|
// Methods supporting the above:
|
|
|
|
|
void orientIncidentComponents();
|
|
|
|
|
bool orderVertexFacesAndEdges(Index vIndex, Index* vFaces, Index* vEdges) const;
|
|
|
|
|
bool orderVertexFacesAndEdges(Index vIndex);
|
|
|
|
|
void populateLocalIndices();
|
|
|
|
|
|
|
|
|
|
IndexArray shareFaceVertCountsAndOffsets() const;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
//
|
|
|
|
|
// A Level is independent of subdivision scheme or options. While it may have been
|
|
|
|
|
// affected by them in its construction, they are not associated with it -- a Level
|
|
|
|
|
// is pure topology and any subdivision parameters are external.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Simple members for inventory, etc.
|
|
|
|
|
int _faceCount;
|
|
|
|
|
int _edgeCount;
|
|
|
|
|
int _vertCount;
|
|
|
|
|
|
|
|
|
|
// TBD - "depth" is clearly useful in both the topological splitting and the
|
|
|
|
|
// stencil queries so could be valuable in both. As face-vert valence becomes
|
|
|
|
|
// constant there is no need to store face-vert and face-edge counts so it has
|
|
|
|
|
// value in Level, though perhaps specified as something other than "depth"
|
|
|
|
|
int _depth;
|
|
|
|
|
int _maxEdgeFaces;
|
|
|
|
|
int _maxValence;
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Topology vectors:
|
|
|
|
|
// Note that of all of these, only data for the face-edge relation is not
|
|
|
|
|
// stored in the osd::FarTables in any form. The FarTable vectors combine
|
|
|
|
|
// the edge-vert and edge-face relations. The eventual goal is that this
|
|
|
|
|
// data be part of the osd::Far classes and be a superset of the FarTable
|
|
|
|
|
// vectors, i.e. no data duplication or conversion. The fact that FarTable
|
|
|
|
|
// already stores 5 of the 6 possible relations should make the topology
|
|
|
|
|
// storage as a whole a non-issue.
|
|
|
|
|
//
|
|
|
|
|
// The vert-face-child and vert-edge-child indices are also arguably not
|
|
|
|
|
// a topology relation but more one for parent/child relations. But it is
|
|
|
|
|
// a topological relationship, and if named differently would not likely
|
|
|
|
|
// raise this. It has been named with "child" in the name as it does play
|
|
|
|
|
// a more significant role during subdivision in mapping between parent
|
|
|
|
|
// and child components, and so has been named to reflect that more clearly.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// Per-face:
|
|
|
|
|
std::vector<Index> _faceVertCountsAndOffsets; // 2 per face, redundant after level 0
|
|
|
|
|
std::vector<Index> _faceVertIndices; // 3 or 4 per face, variable at level 0
|
|
|
|
|
std::vector<Index> _faceEdgeIndices; // matches face-vert indices
|
|
|
|
|
std::vector<FTag> _faceTags; // 1 per face: includes "hole" tag
|
|
|
|
|
|
|
|
|
|
// Per-edge:
|
|
|
|
|
std::vector<Index> _edgeVertIndices; // 2 per edge
|
|
|
|
|
std::vector<Index> _edgeFaceCountsAndOffsets; // 2 per edge
|
|
|
|
|
std::vector<Index> _edgeFaceIndices; // varies with faces per edge
|
|
|
|
|
|
|
|
|
|
std::vector<float> _edgeSharpness; // 1 per edge
|
|
|
|
|
std::vector<ETag> _edgeTags; // 1 per edge: manifold, boundary, etc.
|
|
|
|
|
|
|
|
|
|
// Per-vertex:
|
|
|
|
|
std::vector<Index> _vertFaceCountsAndOffsets; // 2 per vertex
|
|
|
|
|
std::vector<Index> _vertFaceIndices; // varies with valence
|
|
|
|
|
std::vector<LocalIndex> _vertFaceLocalIndices; // varies with valence, 8-bit for now
|
|
|
|
|
|
|
|
|
|
std::vector<Index> _vertEdgeCountsAndOffsets; // 2 per vertex
|
|
|
|
|
std::vector<Index> _vertEdgeIndices; // varies with valence
|
|
|
|
|
std::vector<LocalIndex> _vertEdgeLocalIndices; // varies with valence, 8-bit for now
|
|
|
|
|
|
|
|
|
|
std::vector<float> _vertSharpness; // 1 per vertex
|
|
|
|
|
std::vector<VTag> _vertTags; // 1 per vertex: manifold, Sdc::Rule, etc.
|
|
|
|
|
|
|
|
|
|
// Face-varying channels:
|
|
|
|
|
std::vector<FVarLevel*> _fvarChannels;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the vertices indicent a given face:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getFaceVertices(Index faceIndex) const {
|
|
|
|
|
return ConstIndexArray(&_faceVertIndices[_faceVertCountsAndOffsets[faceIndex*2+1]],
|
|
|
|
|
_faceVertCountsAndOffsets[faceIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getFaceVertices(Index faceIndex) {
|
|
|
|
|
return IndexArray(&_faceVertIndices[_faceVertCountsAndOffsets[faceIndex*2+1]],
|
|
|
|
|
_faceVertCountsAndOffsets[faceIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeFaceVertices(Index faceIndex, int count) {
|
|
|
|
|
assert(count < 256);
|
|
|
|
|
|
|
|
|
|
int* countOffsetPair = &_faceVertCountsAndOffsets[faceIndex*2];
|
|
|
|
|
|
|
|
|
|
countOffsetPair[0] = count;
|
|
|
|
|
countOffsetPair[1] = (faceIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]);
|
|
|
|
|
|
|
|
|
|
_maxValence = std::max(_maxValence, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the edges indicent a given face:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getFaceEdges(Index faceIndex) const {
|
|
|
|
|
return ConstIndexArray(&_faceEdgeIndices[_faceVertCountsAndOffsets[faceIndex*2+1]],
|
|
|
|
|
_faceVertCountsAndOffsets[faceIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getFaceEdges(Index faceIndex) {
|
|
|
|
|
return IndexArray(&_faceEdgeIndices[_faceVertCountsAndOffsets[faceIndex*2+1]],
|
|
|
|
|
_faceVertCountsAndOffsets[faceIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the faces indicent a given vertex:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getVertexFaces(Index vertIndex) const {
|
|
|
|
|
return ConstIndexArray(&_vertFaceIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertFaceCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getVertexFaces(Index vertIndex) {
|
|
|
|
|
return IndexArray(&_vertFaceIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertFaceCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline ConstLocalIndexArray
|
|
|
|
|
Level::getVertexFaceLocalIndices(Index vertIndex) const {
|
|
|
|
|
return ConstLocalIndexArray(&_vertFaceLocalIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertFaceCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline LocalIndexArray
|
|
|
|
|
Level::getVertexFaceLocalIndices(Index vertIndex) {
|
|
|
|
|
return LocalIndexArray(&_vertFaceLocalIndices[_vertFaceCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertFaceCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeVertexFaces(Index vertIndex, int count) {
|
|
|
|
|
int* countOffsetPair = &_vertFaceCountsAndOffsets[vertIndex*2];
|
|
|
|
|
|
|
|
|
|
countOffsetPair[0] = count;
|
|
|
|
|
countOffsetPair[1] = (vertIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::trimVertexFaces(Index vertIndex, int count) {
|
|
|
|
|
_vertFaceCountsAndOffsets[vertIndex*2] = count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the edges indicent a given vertex:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getVertexEdges(Index vertIndex) const {
|
|
|
|
|
return ConstIndexArray(&_vertEdgeIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getVertexEdges(Index vertIndex) {
|
|
|
|
|
return IndexArray(&_vertEdgeIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline ConstLocalIndexArray
|
|
|
|
|
Level::getVertexEdgeLocalIndices(Index vertIndex) const {
|
|
|
|
|
return ConstLocalIndexArray(&_vertEdgeLocalIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline LocalIndexArray
|
|
|
|
|
Level::getVertexEdgeLocalIndices(Index vertIndex) {
|
|
|
|
|
return LocalIndexArray(&_vertEdgeLocalIndices[_vertEdgeCountsAndOffsets[vertIndex*2+1]],
|
|
|
|
|
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeVertexEdges(Index vertIndex, int count) {
|
|
|
|
|
int* countOffsetPair = &_vertEdgeCountsAndOffsets[vertIndex*2];
|
|
|
|
|
|
|
|
|
|
countOffsetPair[0] = count;
|
|
|
|
|
countOffsetPair[1] = (vertIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]);
|
|
|
|
|
|
|
|
|
|
_maxValence = std::max(_maxValence, count);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::trimVertexEdges(Index vertIndex, int count) {
|
|
|
|
|
_vertEdgeCountsAndOffsets[vertIndex*2] = count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the vertices indicent a given edge:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getEdgeVertices(Index edgeIndex) const {
|
|
|
|
|
return ConstIndexArray(&_edgeVertIndices[edgeIndex*2], 2);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getEdgeVertices(Index edgeIndex) {
|
|
|
|
|
return IndexArray(&_edgeVertIndices[edgeIndex*2], 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify the faces indicent a given edge:
|
|
|
|
|
//
|
|
|
|
|
inline ConstIndexArray
|
|
|
|
|
Level::getEdgeFaces(Index edgeIndex) const {
|
|
|
|
|
return ConstIndexArray(&_edgeFaceIndices[_edgeFaceCountsAndOffsets[edgeIndex*2+1]],
|
|
|
|
|
_edgeFaceCountsAndOffsets[edgeIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::getEdgeFaces(Index edgeIndex) {
|
|
|
|
|
return IndexArray(&_edgeFaceIndices[_edgeFaceCountsAndOffsets[edgeIndex*2+1]],
|
|
|
|
|
_edgeFaceCountsAndOffsets[edgeIndex*2]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeEdgeFaces(Index edgeIndex, int count) {
|
|
|
|
|
int* countOffsetPair = &_edgeFaceCountsAndOffsets[edgeIndex*2];
|
|
|
|
|
|
|
|
|
|
countOffsetPair[0] = count;
|
|
|
|
|
countOffsetPair[1] = (edgeIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]);
|
|
|
|
|
|
|
|
|
|
_maxEdgeFaces = std::max(_maxEdgeFaces, count);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::trimEdgeFaces(Index edgeIndex, int count) {
|
|
|
|
|
_edgeFaceCountsAndOffsets[edgeIndex*2] = count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify sharpness values:
|
|
|
|
|
//
|
|
|
|
|
inline float
|
|
|
|
|
Level::getEdgeSharpness(Index edgeIndex) const {
|
|
|
|
|
return _edgeSharpness[edgeIndex];
|
|
|
|
|
}
|
|
|
|
|
inline float&
|
|
|
|
|
Level::getEdgeSharpness(Index edgeIndex) {
|
|
|
|
|
return _edgeSharpness[edgeIndex];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline float
|
|
|
|
|
Level::getVertexSharpness(Index vertIndex) const {
|
|
|
|
|
return _vertSharpness[vertIndex];
|
|
|
|
|
}
|
|
|
|
|
inline float&
|
|
|
|
|
Level::getVertexSharpness(Index vertIndex) {
|
|
|
|
|
return _vertSharpness[vertIndex];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline Sdc::Crease::Rule
|
|
|
|
|
Level::getVertexRule(Index vertIndex) const {
|
|
|
|
|
return (Sdc::Crease::Rule) _vertTags[vertIndex]._rule;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify hole tag:
|
|
|
|
|
//
|
|
|
|
|
inline void
|
|
|
|
|
Level::setHole(Index faceIndex, bool b) {
|
|
|
|
|
_faceTags[faceIndex]._hole = b;
|
|
|
|
|
}
|
|
|
|
|
inline bool
|
|
|
|
|
Level::isHole(Index faceIndex) const {
|
|
|
|
|
return _faceTags[faceIndex]._hole;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Access/modify non-manifold tags:
|
|
|
|
|
//
|
|
|
|
|
inline void
|
|
|
|
|
Level::setEdgeNonManifold(Index edgeIndex, bool b) {
|
|
|
|
|
_edgeTags[edgeIndex]._nonManifold = b;
|
|
|
|
|
}
|
|
|
|
|
inline bool
|
|
|
|
|
Level::isEdgeNonManifold(Index edgeIndex) const {
|
|
|
|
|
return _edgeTags[edgeIndex]._nonManifold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::setVertexNonManifold(Index vertIndex, bool b) {
|
|
|
|
|
_vertTags[vertIndex]._nonManifold = b;
|
|
|
|
|
}
|
|
|
|
|
inline bool
|
|
|
|
|
Level::isVertexNonManifold(Index vertIndex) const {
|
|
|
|
|
return _vertTags[vertIndex]._nonManifold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Sizing methods to allocate space:
|
|
|
|
|
//
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeFaces(int faceCount) {
|
|
|
|
|
_faceCount = faceCount;
|
|
|
|
|
_faceVertCountsAndOffsets.resize(2 * faceCount);
|
|
|
|
|
|
|
|
|
|
_faceTags.resize(faceCount);
|
|
|
|
|
std::memset(&_faceTags[0], 0, _faceCount * sizeof(FTag));
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeFaceVertices(int totalFaceVertCount) {
|
|
|
|
|
_faceVertIndices.resize(totalFaceVertCount);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeFaceEdges(int totalFaceEdgeCount) {
|
|
|
|
|
_faceEdgeIndices.resize(totalFaceEdgeCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeEdges(int edgeCount) {
|
|
|
|
|
|
|
|
|
|
_edgeCount = edgeCount;
|
|
|
|
|
_edgeFaceCountsAndOffsets.resize(2 * edgeCount);
|
|
|
|
|
|
|
|
|
|
_edgeSharpness.resize(edgeCount);
|
|
|
|
|
_edgeTags.resize(edgeCount);
|
|
|
|
|
|
|
|
|
|
if (edgeCount>0) {
|
|
|
|
|
std::memset(&_edgeTags[0], 0, _edgeCount * sizeof(ETag));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeEdgeVertices() {
|
|
|
|
|
|
|
|
|
|
_edgeVertIndices.resize(2 * _edgeCount);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeEdgeFaces(int totalEdgeFaceCount) {
|
|
|
|
|
|
|
|
|
|
_edgeFaceIndices.resize(totalEdgeFaceCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeVertices(int vertCount) {
|
|
|
|
|
|
|
|
|
|
_vertCount = vertCount;
|
|
|
|
|
_vertFaceCountsAndOffsets.resize(2 * vertCount);
|
|
|
|
|
_vertEdgeCountsAndOffsets.resize(2 * vertCount);
|
|
|
|
|
|
|
|
|
|
_vertSharpness.resize(vertCount);
|
|
|
|
|
_vertTags.resize(vertCount);
|
|
|
|
|
std::memset(&_vertTags[0], 0, _vertCount * sizeof(VTag));
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeVertexFaces(int totalVertFaceCount) {
|
|
|
|
|
|
|
|
|
|
_vertFaceIndices.resize(totalVertFaceCount);
|
|
|
|
|
_vertFaceLocalIndices.resize(totalVertFaceCount);
|
|
|
|
|
}
|
|
|
|
|
inline void
|
|
|
|
|
Level::resizeVertexEdges(int totalVertEdgeCount) {
|
|
|
|
|
|
|
|
|
|
_vertEdgeIndices.resize(totalVertEdgeCount);
|
|
|
|
|
_vertEdgeLocalIndices.resize(totalVertEdgeCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline IndexArray
|
|
|
|
|
Level::shareFaceVertCountsAndOffsets() const {
|
|
|
|
|
// XXXX manuelk we have to force const casting here (classes don't 'share'
|
|
|
|
|
// members usually...)
|
|
|
|
|
return IndexArray(const_cast<Index *>(&_faceVertCountsAndOffsets[0]),
|
|
|
|
|
(int)_faceVertCountsAndOffsets.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // end namespace Vtr
|
|
|
|
|
|
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
|
|
|
using namespace OPENSUBDIV_VERSION;
|
|
|
|
|
} // end namespace OpenSubdiv
|
|
|
|
|
|
|
|
|
|
#endif /* VTR_LEVEL_H */
|