mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-11 11:50:04 +00:00
688 lines
29 KiB
C++
688 lines
29 KiB
C++
//
|
|
// 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 OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
|
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
|
|
|
#include "../version.h"
|
|
|
|
#include "../far/topologyRefiner.h"
|
|
#include "../far/error.h"
|
|
|
|
#include <cassert>
|
|
|
|
namespace OpenSubdiv {
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
namespace Far {
|
|
|
|
///\brief Private base class of Factories for constructing TopologyRefiners
|
|
///
|
|
/// TopologyRefinerFactoryBase is the base class for subclasses that are intended to
|
|
/// construct TopologyRefiners directly from meshes in their native representations.
|
|
/// The subclasses are parameterized by the mesh type \<class MESH\> and are expected
|
|
/// to inherit the details related to assembly and validation provided here that are
|
|
/// independent of the subclass' mesh type.
|
|
//
|
|
class TopologyRefinerFactoryBase {
|
|
protected:
|
|
|
|
//
|
|
// Protected methods invoked by the subclass template to verify and process each
|
|
// stage of construction implemented by the subclass:
|
|
//
|
|
typedef Vtr::internal::Level::ValidationCallback TopologyCallback;
|
|
|
|
static bool prepareComponentTopologySizing(TopologyRefiner& refiner);
|
|
static bool prepareComponentTopologyAssignment(TopologyRefiner& refiner, bool fullValidation,
|
|
TopologyCallback callback, void const * callbackData);
|
|
static bool prepareComponentTagsAndSharpness(TopologyRefiner& refiner);
|
|
static bool prepareFaceVaryingChannels(TopologyRefiner& refiner);
|
|
};
|
|
|
|
|
|
///\brief Factory for constructing TopologyRefiners from specific mesh classes.
|
|
///
|
|
/// TopologyRefinerFactory<MESH> is the factory class template to convert an instance of
|
|
/// TopologyRefiner from an arbitrary mesh class. While a class template, the implementation
|
|
/// is not (cannot) be complete, so specialization of a few methods is required (it is a
|
|
/// stateless factory, so no instance and only static methods).
|
|
///
|
|
/// This template provides both the interface and high level assembly for the construction
|
|
/// of the TopologyRefiner instance. The high level construction executes a specific set
|
|
/// of operations to convert the client's MESH into TopologyRefiner. This set of operations
|
|
/// combines methods independent of MESH from the base class with those specialized here for
|
|
/// class MESH.
|
|
///
|
|
template <class MESH>
|
|
class TopologyRefinerFactory : public TopologyRefinerFactoryBase {
|
|
|
|
public:
|
|
|
|
/// \brief Options related to the construction of each TopologyRefiner.
|
|
///
|
|
struct Options {
|
|
|
|
Options(Sdc::SchemeType sdcType = Sdc::SCHEME_CATMARK, Sdc::Options sdcOptions = Sdc::Options()) :
|
|
schemeType(sdcType),
|
|
schemeOptions(sdcOptions),
|
|
validateFullTopology(false) { }
|
|
|
|
Sdc::SchemeType schemeType; ///< The subdivision scheme type identifier
|
|
Sdc::Options schemeOptions; ///< The full set of options for the scheme,
|
|
///< e.g. boundary interpolation rules...
|
|
unsigned int validateFullTopology : 1; ///< Apply more extensive validation of
|
|
///< the constructed topology -- intended
|
|
///< for debugging.
|
|
};
|
|
|
|
/// \brief Instantiates a TopologyRefiner from client-provided topological
|
|
/// representation.
|
|
///
|
|
/// If only the face-vertices topological relationships are specified
|
|
/// with this factory, edge relationships have to be inferred, which
|
|
/// requires additional processing. If the client topological rep can
|
|
/// provide this information, it is highly recommended to do so.
|
|
///
|
|
/// @param mesh Client's topological representation (or a converter)
|
|
//
|
|
/// @param options Options controlling the creation of the TopologyRefiner
|
|
///
|
|
/// @return A new instance of TopologyRefiner or 0 for failure
|
|
///
|
|
static TopologyRefiner* Create(MESH const& mesh, Options options = Options());
|
|
|
|
protected:
|
|
typedef Vtr::internal::Level::TopologyError TopologyError;
|
|
|
|
//@{
|
|
/// @name Methods to be provided to complete assembly of the TopologyRefiner
|
|
///
|
|
///
|
|
/// These methods are to be specialized to implement all details specific to
|
|
/// class MESH required to convert MESH data to TopologyRefiner. Note that
|
|
/// some of these *must* be specialized in order to complete construction while
|
|
/// some are optional.
|
|
///
|
|
/// There are two minimal construction requirements (to specify the size and
|
|
/// content of all topology relations) and three optional (to specify feature
|
|
/// tags, face-varying data, and runtime validation and error reporting).
|
|
///
|
|
/// See comments in the generic stubs, the factory for Far::TopologyDescriptor
|
|
/// or the tutorials for more details on writing these.
|
|
///
|
|
|
|
/// \brief Specify the number of vertices, faces, face-vertices, etc.
|
|
static bool resizeComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
|
|
|
/// \brief Specify the relationships between vertices, faces, etc. ie the
|
|
/// face-vertices, vertex-faces, edge-vertices, etc.
|
|
static bool assignComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
|
|
|
/// \brief (Optional) Specify edge or vertex sharpness or face holes
|
|
static bool assignComponentTags(TopologyRefiner& newRefiner, MESH const& mesh);
|
|
|
|
/// \brief (Optional) Specify face-varying data per face
|
|
static bool assignFaceVaryingTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
|
|
|
/// \brief (Optional) Control run-time topology validation and error reporting
|
|
static void reportInvalidTopology(TopologyError errCode, char const * msg, MESH const& mesh);
|
|
|
|
//@}
|
|
|
|
protected:
|
|
//@{
|
|
/// @name Base level assembly methods to be used within resizeComponentTopology()
|
|
///
|
|
/// \brief These methods specify sizes of various quantities, e.g. the number of
|
|
/// vertices, faces, face-vertices, etc. The number of the primary components
|
|
/// (vertices, faces and edges) should be specified prior to anything else that
|
|
/// references them (e.g. we need to know the number of faces before specifying
|
|
/// the vertices for that face.
|
|
///
|
|
/// If a full boundary representation with all neighborhood information is not
|
|
/// available, e.g. faces and vertices are avaible but not edges, only the
|
|
/// face-vertices should be specified. The remaining topological relationships
|
|
/// will be constructed later in the assembly (though at greater cost than if
|
|
/// specified directly).
|
|
///
|
|
/// The sizes for topological relationships between individual components should be
|
|
/// specified in order, i.e. the number of face-vertices for each successive face.
|
|
///
|
|
|
|
/// \brief Specify the number of vertices to be accomodated
|
|
static void setNumBaseVertices(TopologyRefiner & newRefiner, int count);
|
|
|
|
/// \brief Specify the number of faces to be accomodated
|
|
static void setNumBaseFaces(TopologyRefiner & newRefiner, int count);
|
|
|
|
/// \brief Specify the number of edges to be accomodated
|
|
static void setNumBaseEdges(TopologyRefiner & newRefiner, int count);
|
|
|
|
/// \brief Specify the number of vertices incident each face
|
|
static void setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count);
|
|
|
|
/// \brief Specify the number of faces incident each edge
|
|
static void setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count);
|
|
|
|
/// \brief Specify the number of faces incident each vertex
|
|
static void setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count);
|
|
|
|
/// \brief Specify the number of edges incident each vertex
|
|
static void setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count);
|
|
|
|
static int getNumBaseVertices(TopologyRefiner const & newRefiner);
|
|
static int getNumBaseFaces(TopologyRefiner const & newRefiner);
|
|
static int getNumBaseEdges(TopologyRefiner const & newRefiner);
|
|
//@}
|
|
|
|
//@{
|
|
/// @name Base level assembly methods to be used within assignComponentTopology()
|
|
///
|
|
/// \brief These methods populate relationships between components -- in much the
|
|
/// same manner as they are inspected once the TopologyRefiner is completed.
|
|
///
|
|
/// An array of fixed size is returned from these methods and its entries are to be
|
|
/// populated with the appropriate indices for its neighbors. At minimum, the
|
|
/// vertices for each face must be specified. As noted previously, the remaining
|
|
/// relationships will be constructed as needed.
|
|
///
|
|
/// The ordering of entries in these arrays is important -- they are expected to
|
|
/// be ordered counter-clockwise for a right-hand orientation.
|
|
///
|
|
/// Non-manifold components must be explicitly tagged as such and they do not
|
|
/// require the ordering expected of manifold components. Special consideration
|
|
/// must also be given to certain non-manifold situations, e.g. the same edge
|
|
/// cannot appear twice in a face, and a degenerate edge (same vertex at both
|
|
/// ends) can only have one incident face. Such considerations are typically
|
|
/// achievable by creating multiple instances of an edge. So while there will
|
|
/// always be a one-to-one correspondence between vertices and faces, the same
|
|
/// is not guaranteed of edges in certain non-manifold circumstances.
|
|
///
|
|
|
|
/// \brief Assign the vertices incident each face
|
|
static IndexArray getBaseFaceVertices(TopologyRefiner & newRefiner, Index f);
|
|
|
|
/// \brief Assign the edges incident each face
|
|
static IndexArray getBaseFaceEdges(TopologyRefiner & newRefiner, Index f);
|
|
|
|
/// \brief Assign the vertices incident each edge
|
|
static IndexArray getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e);
|
|
|
|
/// \brief Assign the faces incident each edge
|
|
static IndexArray getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e);
|
|
|
|
/// \brief Assign the faces incident each vertex
|
|
static IndexArray getBaseVertexFaces(TopologyRefiner & newRefiner, Index v);
|
|
|
|
/// \brief Assign the edges incident each vertex
|
|
static IndexArray getBaseVertexEdges(TopologyRefiner & newRefiner, Index v);
|
|
|
|
/// \brief Assign the local indices of a vertex within each of its incident faces
|
|
static LocalIndexArray getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v);
|
|
/// \brief Assign the local indices of a vertex within each of its incident edges
|
|
static LocalIndexArray getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v);
|
|
/// \brief Assign the local indices of an edge within each of its incident faces
|
|
static LocalIndexArray getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e);
|
|
|
|
/// \brief Determine all local indices by inspection (only for pure manifold meshes)
|
|
static void populateBaseLocalIndices(TopologyRefiner & newRefiner);
|
|
|
|
/// \brief Tag an edge as non-manifold
|
|
static void setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b);
|
|
|
|
/// \brief Tag a vertex as non-manifold
|
|
static void setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b);
|
|
//@}
|
|
|
|
//@{
|
|
/// @name Base level assembly methods to be used within assignComponentTags()
|
|
///
|
|
/// These methods are used to assign edge or vertex sharpness, for tagging faces
|
|
/// as holes, etc. Unlike topological assignment, only those components that
|
|
/// posses a feature of interest need be explicitly assigned.
|
|
///
|
|
/// Since topological construction is largely complete by this point, a method is
|
|
/// availble to identify an edge for sharpness assignment given a pair of vertices.
|
|
///
|
|
|
|
/// \brief Identify an edge to be assigned a sharpness value given a vertex pair
|
|
static Index findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1);
|
|
|
|
/// \brief Assign a sharpness value to a given edge
|
|
static void setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float sharpness);
|
|
|
|
/// \brief Assign a sharpness value to a given vertex
|
|
static void setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float sharpness);
|
|
|
|
/// \brief Tag a face as a hole
|
|
static void setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool isHole);
|
|
//@}
|
|
|
|
//@{
|
|
/// @name Base level assembly methods to be used within assignFaceVaryingTopology()
|
|
///
|
|
/// Face-varying data is assigned to faces in much the same way as face-vertex
|
|
/// topology is assigned -- indices for face-varying values are assigned to the
|
|
/// corners of each face just as indices for vertices were assigned.
|
|
///
|
|
/// Independent sets of face-varying data is stored in channels. The identifier
|
|
/// of each channel (an integer) is expected whenever referring to face-varying
|
|
/// data in any form.
|
|
///
|
|
|
|
/// \brief Create a new face-varying channel with the given number of values
|
|
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues);
|
|
|
|
/// \brief Create a new face-varying channel with the given number of values and independent interpolation options
|
|
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions);
|
|
|
|
/// \brief Assign the face-varying values for the corners of each face
|
|
static IndexArray getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel = 0);
|
|
|
|
//@}
|
|
|
|
protected:
|
|
//
|
|
// Not to be specialized:
|
|
//
|
|
static bool populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options);
|
|
};
|
|
|
|
|
|
//
|
|
// Generic implementations:
|
|
//
|
|
template <class MESH>
|
|
TopologyRefiner*
|
|
TopologyRefinerFactory<MESH>::Create(MESH const& mesh, Options options) {
|
|
|
|
TopologyRefiner * refiner = new TopologyRefiner(options.schemeType, options.schemeOptions);
|
|
|
|
if (! populateBaseLevel(*refiner, mesh, options)) {
|
|
delete refiner;
|
|
return 0;
|
|
}
|
|
|
|
// Eventually want to move the Refiner's inventory initialization here. Currently it
|
|
// is handled after topology assignment, but if the inventory is to include additional
|
|
// features (e.g. holes, etc.) it is better off deferred to here.
|
|
|
|
return refiner;
|
|
}
|
|
|
|
template <class MESH>
|
|
bool
|
|
TopologyRefinerFactory<MESH>::populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options) {
|
|
|
|
//
|
|
// Construction of a specialized topology refiner involves four steps, each of which
|
|
// involves a method specialized for MESH followed by one that takes an action in
|
|
// response to it or in preparation for the next step.
|
|
//
|
|
// Both the specialized methods and those that follow them may find fault in the
|
|
// construction and trigger failure at any time:
|
|
//
|
|
|
|
//
|
|
// Sizing of the topology -- this is a required specialization for MESH. This defines
|
|
// an inventory of all components and their relations that is used to allocate buffers
|
|
// to be efficiently populated in the subsequent topology assignment step.
|
|
//
|
|
if (! resizeComponentTopology(refiner, mesh)) return false;
|
|
if (! prepareComponentTopologySizing(refiner)) return false;
|
|
|
|
//
|
|
// Assignment of the topology -- this is a required specialization for MESH. If edges
|
|
// are specified, all other topological relations are expected to be defined for them.
|
|
// Otherwise edges and remaining topology will be completed from the face-vertices:
|
|
//
|
|
bool validate = options.validateFullTopology;
|
|
TopologyCallback callback = reinterpret_cast<TopologyCallback>(reportInvalidTopology);
|
|
void const * userData = &mesh;
|
|
|
|
if (! assignComponentTopology(refiner, mesh)) return false;
|
|
if (! prepareComponentTopologyAssignment(refiner, validate, callback, userData)) return false;
|
|
|
|
//
|
|
// User assigned and internal tagging of components -- an optional specialization for
|
|
// MESH. Allows the specification of sharpness values, holes, etc.
|
|
//
|
|
if (! assignComponentTags(refiner, mesh)) return false;
|
|
if (! prepareComponentTagsAndSharpness(refiner)) return false;
|
|
|
|
//
|
|
// Defining channels of face-varying primvar data -- an optional specialization for MESH.
|
|
//
|
|
if (! assignFaceVaryingTopology(refiner, mesh)) return false;
|
|
if (! prepareFaceVaryingChannels(refiner)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseFaces(TopologyRefiner & newRefiner, int count) {
|
|
newRefiner._levels[0]->resizeFaces(count);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseEdges(TopologyRefiner & newRefiner, int count) {
|
|
newRefiner._levels[0]->resizeEdges(count);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseVertices(TopologyRefiner & newRefiner, int count) {
|
|
newRefiner._levels[0]->resizeVertices(count);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline int
|
|
TopologyRefinerFactory<MESH>::getNumBaseFaces(TopologyRefiner const & newRefiner) {
|
|
return newRefiner._levels[0]->getNumFaces();
|
|
}
|
|
template <class MESH>
|
|
inline int
|
|
TopologyRefinerFactory<MESH>::getNumBaseEdges(TopologyRefiner const & newRefiner) {
|
|
return newRefiner._levels[0]->getNumEdges();
|
|
}
|
|
template <class MESH>
|
|
inline int
|
|
TopologyRefinerFactory<MESH>::getNumBaseVertices(TopologyRefiner const & newRefiner) {
|
|
return newRefiner._levels[0]->getNumVertices();
|
|
}
|
|
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count) {
|
|
newRefiner._levels[0]->resizeFaceVertices(f, count);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count) {
|
|
newRefiner._levels[0]->resizeEdgeFaces(e, count);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count) {
|
|
newRefiner._levels[0]->resizeVertexFaces(v, count);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count) {
|
|
newRefiner._levels[0]->resizeVertexEdges(v, count);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseFaceVertices(TopologyRefiner & newRefiner, Index f) {
|
|
return newRefiner._levels[0]->getFaceVertices(f);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseFaceEdges(TopologyRefiner & newRefiner, Index f) {
|
|
return newRefiner._levels[0]->getFaceEdges(f);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e) {
|
|
return newRefiner._levels[0]->getEdgeVertices(e);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e) {
|
|
return newRefiner._levels[0]->getEdgeFaces(e);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseVertexFaces(TopologyRefiner & newRefiner, Index v) {
|
|
return newRefiner._levels[0]->getVertexFaces(v);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseVertexEdges(TopologyRefiner & newRefiner, Index v) {
|
|
return newRefiner._levels[0]->getVertexEdges(v);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline LocalIndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e) {
|
|
return newRefiner._levels[0]->getEdgeFaceLocalIndices(e);
|
|
}
|
|
template <class MESH>
|
|
inline LocalIndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
|
return newRefiner._levels[0]->getVertexFaceLocalIndices(v);
|
|
}
|
|
template <class MESH>
|
|
inline LocalIndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
|
return newRefiner._levels[0]->getVertexEdgeLocalIndices(v);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline Index
|
|
TopologyRefinerFactory<MESH>::findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1) {
|
|
return newRefiner._levels[0]->findEdge(v0, v1);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::populateBaseLocalIndices(TopologyRefiner & newRefiner) {
|
|
newRefiner._levels[0]->populateLocalIndices();
|
|
}
|
|
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b) {
|
|
newRefiner._levels[0]->setEdgeNonManifold(e, b);
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b) {
|
|
newRefiner._levels[0]->setVertexNonManifold(v, b);
|
|
}
|
|
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float s) {
|
|
newRefiner._levels[0]->getEdgeSharpness(e) = s;
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float s) {
|
|
newRefiner._levels[0]->getVertexSharpness(v) = s;
|
|
}
|
|
template <class MESH>
|
|
inline void
|
|
TopologyRefinerFactory<MESH>::setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool b) {
|
|
newRefiner._levels[0]->setFaceHole(f, b);
|
|
newRefiner._hasHoles |= b;
|
|
}
|
|
|
|
template <class MESH>
|
|
inline int
|
|
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues) {
|
|
return newRefiner._levels[0]->createFVarChannel(numValues, newRefiner._subdivOptions);
|
|
}
|
|
template <class MESH>
|
|
inline int
|
|
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions) {
|
|
Sdc::Options newOptions = newRefiner._subdivOptions;
|
|
newOptions.SetFVarLinearInterpolation(fvarOptions.GetFVarLinearInterpolation());
|
|
return newRefiner._levels[0]->createFVarChannel(numValues, newOptions);
|
|
}
|
|
template <class MESH>
|
|
inline IndexArray
|
|
TopologyRefinerFactory<MESH>::getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel) {
|
|
return newRefiner._levels[0]->getFaceFVarValues(face, channel);
|
|
}
|
|
|
|
|
|
template <class MESH>
|
|
bool
|
|
TopologyRefinerFactory<MESH>::resizeComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
Error(FAR_RUNTIME_ERROR,
|
|
"Failure in TopologyRefinerFactory<>::resizeComponentTopology() -- no specialization provided.");
|
|
|
|
//
|
|
// Sizing the topology tables:
|
|
// This method is for determining the sizes of the various topology tables (and other
|
|
// data) associated with the mesh. Once completed, appropriate memory will be allocated
|
|
// and an additional method invoked to populate it accordingly.
|
|
//
|
|
// The following methods should be called -- first those to specify the number of faces,
|
|
// edges and vertices in the mesh:
|
|
//
|
|
// void setBaseFaceCount( TopologyRefiner& newRefiner, int count)
|
|
// void setBaseEdgeCount( TopologyRefiner& newRefiner, int count)
|
|
// void setBaseVertexCount(TopologyRefiner& newRefiner, int count)
|
|
//
|
|
// and then for each face, edge and vertex, the number of its incident components:
|
|
//
|
|
// void setBaseFaceVertexCount(TopologyRefiner& newRefiner, Index face, int count)
|
|
// void setBaseEdgeFaceCount( TopologyRefiner& newRefiner, Index edge, int count)
|
|
// void setBaseVertexFaceCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
|
// void setBaseVertexEdgeCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
|
//
|
|
// The count/size for a component type must be set before indices associated with that
|
|
// component type can be used.
|
|
//
|
|
// Note that it is only necessary to size 4 of the 6 supported topological relations --
|
|
// the number of edge-vertices is fixed at two per edge, and the number of face-edges is
|
|
// the same as the number of face-vertices.
|
|
//
|
|
// So a single pass through your mesh to gather up all of this sizing information will
|
|
// allow the Tables to be allocated appropriately once and avoid any dynamic resizing as
|
|
// it grows.
|
|
//
|
|
return false;
|
|
}
|
|
|
|
template <class MESH>
|
|
bool
|
|
TopologyRefinerFactory<MESH>::assignComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
Error(FAR_RUNTIME_ERROR,
|
|
"Failure in TopologyRefinerFactory<>::assignComponentTopology() -- no specialization provided.");
|
|
|
|
//
|
|
// Assigning the topology tables:
|
|
// Once the topology tables have been allocated, the six required topological
|
|
// relations can be directly populated using the following methods:
|
|
//
|
|
// IndexArray setBaseFaceVertices(TopologyRefiner& newRefiner, Index face)
|
|
// IndexArray setBaseFaceEdges(TopologyRefiner& newRefiner, Index face)
|
|
//
|
|
// IndexArray setBaseEdgeVertices(TopologyRefiner& newRefiner, Index edge)
|
|
// IndexArray setBaseEdgeFaces(TopologyRefiner& newRefiner, Index edge)
|
|
//
|
|
// IndexArray setBaseVertexEdges(TopologyRefiner& newRefiner, Index vertex)
|
|
// IndexArray setBaseVertexFaces(TopologyRefiner& newRefiner, Index vertex)
|
|
//
|
|
// For the last two relations -- the faces and edges incident a vertex -- there are
|
|
// also "local indices" that must be specified (considering doing this internally),
|
|
// where the "local index" of each incident face or edge is the index of the vertex
|
|
// within that face or edge, and so ranging from 0-3 for incident quads and 0-1 for
|
|
// incident edges. These are assigned through similarly retrieved arrays:
|
|
//
|
|
// LocalIndexArray setBaseVertexFaceLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
|
// LocalIndexArray setBaseVertexEdgeLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
|
// LocalIndexArray setBaseEdgeFaceLocalIndices( TopologyRefiner& newRefiner, Index edge)
|
|
//
|
|
// or, if the mesh is manifold, explicit assignment of these can be deferred and
|
|
// all can be determined by calling:
|
|
//
|
|
// void populateBaseLocalIndices(TopologyRefiner& newRefiner, )
|
|
//
|
|
// All components are assumed to be locally manifold and ordering of components in
|
|
// the above relations is expected to be counter-clockwise.
|
|
//
|
|
// For non-manifold components, no ordering/orientation of incident components is
|
|
// assumed or required, but be sure to explicitly tag such components (vertices and
|
|
// edges) as non-manifold:
|
|
//
|
|
// void setBaseEdgeNonManifold(TopologyRefiner& newRefiner, Index edge, bool b);
|
|
//
|
|
// void setBaseVertexNonManifold(TopologyRefiner& newRefiner, Index vertex, bool b);
|
|
//
|
|
// Also consider using TopologyLevel::ValidateTopology() when debugging to ensure
|
|
// that topolology has been completely and correctly specified.
|
|
//
|
|
return false;
|
|
}
|
|
|
|
template <class MESH>
|
|
bool
|
|
TopologyRefinerFactory<MESH>::assignFaceVaryingTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
//
|
|
// Optional assigning face-varying topology tables:
|
|
//
|
|
// Create independent face-varying primitive variable channels:
|
|
// int createBaseFVarChannel(TopologyRefiner& newRefiner, int numValues)
|
|
//
|
|
// For each channel, populate the face-vertex values:
|
|
// IndexArray setBaseFaceFVarValues(TopologyRefiner& newRefiner, Index face, int channel = 0)
|
|
//
|
|
return true;
|
|
}
|
|
|
|
template <class MESH>
|
|
bool
|
|
TopologyRefinerFactory<MESH>::assignComponentTags(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
//
|
|
// Optional tagging:
|
|
// This is where any additional feature tags -- sharpness, holes, etc. -- can be
|
|
// specified using:
|
|
//
|
|
// void setBaseEdgeSharpness(TopologyRefiner& newRefiner, Index edge, float sharpness)
|
|
// void setBaseVertexSharpness(TopologyRefiner& newRefiner, Index vertex, float sharpness)
|
|
//
|
|
// void setBaseFaceHole(TopologyRefiner& newRefiner, Index face, bool hole)
|
|
//
|
|
return true;
|
|
}
|
|
|
|
template <class MESH>
|
|
void
|
|
TopologyRefinerFactory<MESH>::reportInvalidTopology(
|
|
TopologyError /* errCode */, char const * /* msg */, MESH const& /* mesh */) {
|
|
|
|
//
|
|
// Optional topology validation error reporting:
|
|
// This method is called whenever the factory encounters topology validation
|
|
// errors. By default, nothing is reported
|
|
//
|
|
}
|
|
|
|
} // end namespace Far
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
using namespace OPENSUBDIV_VERSION;
|
|
} // end namespace OpenSubdiv
|
|
|
|
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H */
|