2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2015-05-19 18:22:37 +00:00
|
|
|
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
|
|
|
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
#include "../version.h"
|
|
|
|
|
|
|
|
#include "../far/topologyRefiner.h"
|
2014-12-04 01:19:07 +00:00
|
|
|
#include "../far/error.h"
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
namespace OpenSubdiv {
|
|
|
|
namespace OPENSUBDIV_VERSION {
|
|
|
|
|
|
|
|
namespace Far {
|
|
|
|
|
|
|
|
//
|
|
|
|
// TopologyRefinerFactoryBase:
|
|
|
|
// This is an abstract base class for subclasses that are intended to construct
|
2015-01-08 05:33:48 +00:00
|
|
|
// TopologyRefiner from external mesh representations. These subclasses are
|
2015-05-29 05:39:45 +00:00
|
|
|
// parameterized by the mesh type <class MESH>.
|
|
|
|
// This base class provides all implementation details related to assembly and
|
|
|
|
// validation that are independent of the subclass' mesh type. It also includes a
|
|
|
|
// suite of methods for modifying/assembling a newly created TopologyRefiner.
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
class TopologyRefinerFactoryBase {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2015-01-06 03:34:47 +00:00
|
|
|
/// \brief Descriptor for raw topology data, provided as a convenience for one
|
|
|
|
/// particular factory, but not used by others.
|
2014-09-05 22:07:46 +00:00
|
|
|
///
|
|
|
|
struct TopologyDescriptor {
|
|
|
|
|
|
|
|
int numVertices,
|
|
|
|
numFaces;
|
|
|
|
|
2014-12-12 19:19:24 +00:00
|
|
|
int const * numVertsPerFace;
|
|
|
|
Index const * vertIndicesPerFace;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
int numCreases;
|
2014-10-09 21:48:50 +00:00
|
|
|
Index const * creaseVertexIndexPairs;
|
2014-09-05 22:07:46 +00:00
|
|
|
float const * creaseWeights;
|
|
|
|
|
|
|
|
int numCorners;
|
2014-10-09 21:48:50 +00:00
|
|
|
Index const * cornerVertexIndices;
|
2014-09-05 22:07:46 +00:00
|
|
|
float const * cornerWeights;
|
2014-10-24 20:52:40 +00:00
|
|
|
|
|
|
|
int numHoles;
|
|
|
|
Index const * holeIndices;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-04-15 21:32:48 +00:00
|
|
|
bool isLeftHanded;
|
2015-04-14 17:03:02 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
// Face-varying data channel -- value indices correspond to vertex indices,
|
|
|
|
// i.e. one for every vertex of every face:
|
|
|
|
//
|
|
|
|
struct FVarChannel {
|
|
|
|
|
2015-06-01 23:25:44 +00:00
|
|
|
int numValues;
|
|
|
|
Index const * valueIndices;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
FVarChannel() : numValues(0), valueIndices(0) { }
|
|
|
|
};
|
|
|
|
|
|
|
|
int numFVarChannels;
|
|
|
|
FVarChannel const * fvarChannels;
|
|
|
|
|
|
|
|
TopologyDescriptor();
|
|
|
|
};
|
|
|
|
|
2015-05-29 05:39:45 +00:00
|
|
|
protected:
|
|
|
|
|
|
|
|
//
|
|
|
|
// For use by subclasses to construct the base level:
|
|
|
|
//
|
|
|
|
// Topology sizing methods required before allocation:
|
|
|
|
static void setNumBaseFaces(TopologyRefiner & newRefiner, int count);
|
|
|
|
static void setNumBaseEdges(TopologyRefiner & newRefiner, int count);
|
|
|
|
static void setNumBaseVertices(TopologyRefiner & newRefiner, int count);
|
|
|
|
|
|
|
|
static int getNumBaseFaces(TopologyRefiner const & newRefiner);
|
|
|
|
static int getNumBaseEdges(TopologyRefiner const & newRefiner);
|
|
|
|
static int getNumBaseVertices(TopologyRefiner const & newRefiner);
|
|
|
|
|
|
|
|
static void setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count);
|
|
|
|
static void setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count);
|
|
|
|
static void setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count);
|
|
|
|
static void setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count);
|
|
|
|
|
|
|
|
// Topology assignment methods to populate base level after allocation:
|
|
|
|
static IndexArray getBaseFaceVertices(TopologyRefiner & newRefiner, Index f);
|
|
|
|
static IndexArray getBaseFaceEdges(TopologyRefiner & newRefiner, Index f);
|
|
|
|
static IndexArray getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e);
|
|
|
|
static IndexArray getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e);
|
|
|
|
static IndexArray getBaseVertexFaces(TopologyRefiner & newRefiner, Index v);
|
|
|
|
static IndexArray getBaseVertexEdges(TopologyRefiner & newRefiner, Index v);
|
|
|
|
|
|
|
|
static LocalIndexArray getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e);
|
|
|
|
static LocalIndexArray getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v);
|
|
|
|
static LocalIndexArray getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v);
|
|
|
|
|
|
|
|
static Index findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1);
|
|
|
|
|
|
|
|
static void populateBaseLocalIndices(TopologyRefiner & newRefiner);
|
|
|
|
|
|
|
|
static void setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b);
|
|
|
|
static void setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b);
|
|
|
|
|
|
|
|
// Optional feature tagging methods for setting sharpness, holes, etc.:
|
|
|
|
static void setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float s);
|
|
|
|
static void setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float s);
|
|
|
|
static void setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool b);
|
|
|
|
|
|
|
|
// Optional methods for creating and assigning face-varying data channels:
|
|
|
|
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues);
|
|
|
|
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions);
|
2015-06-01 23:25:44 +00:00
|
|
|
static IndexArray getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel = 0);
|
2015-05-29 05:39:45 +00:00
|
|
|
|
|
|
|
static void setBaseMaxValence(TopologyRefiner & newRefiner, int valence);
|
|
|
|
static void initializeBaseInventory(TopologyRefiner & newRefiner);
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
protected:
|
|
|
|
|
2015-01-06 03:34:47 +00:00
|
|
|
//
|
|
|
|
// Protected methods invoked by the subclass template to verify and process each
|
|
|
|
// stage of construction implemented by the subclass:
|
|
|
|
//
|
2015-05-26 03:34:50 +00:00
|
|
|
typedef Vtr::internal::Level::ValidationCallback TopologyCallback;
|
2015-01-08 05:33:48 +00:00
|
|
|
|
2015-01-06 03:34:47 +00:00
|
|
|
static bool prepareComponentTopologySizing(TopologyRefiner& refiner);
|
2015-01-08 05:33:48 +00:00
|
|
|
static bool prepareComponentTopologyAssignment(TopologyRefiner& refiner, bool fullValidation,
|
|
|
|
TopologyCallback callback, void const * callbackData);
|
2015-01-06 03:34:47 +00:00
|
|
|
static bool prepareComponentTagsAndSharpness(TopologyRefiner& refiner);
|
|
|
|
static bool prepareFaceVaryingChannels(TopologyRefiner& refiner);
|
2014-09-05 22:07:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2015-05-29 05:39:45 +00:00
|
|
|
//
|
|
|
|
// Inline methods:
|
|
|
|
//
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseFaces(TopologyRefiner & newRefiner, int count) {
|
|
|
|
newRefiner._levels[0]->resizeFaces(count);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseEdges(TopologyRefiner & newRefiner, int count) {
|
|
|
|
newRefiner._levels[0]->resizeEdges(count);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseVertices(TopologyRefiner & newRefiner, int count) {
|
|
|
|
newRefiner._levels[0]->resizeVertices(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int
|
|
|
|
TopologyRefinerFactoryBase::getNumBaseFaces(TopologyRefiner const & newRefiner) {
|
|
|
|
return newRefiner._levels[0]->getNumFaces();
|
|
|
|
}
|
|
|
|
inline int
|
|
|
|
TopologyRefinerFactoryBase::getNumBaseEdges(TopologyRefiner const & newRefiner) {
|
|
|
|
return newRefiner._levels[0]->getNumEdges();
|
|
|
|
}
|
|
|
|
inline int
|
|
|
|
TopologyRefinerFactoryBase::getNumBaseVertices(TopologyRefiner const & newRefiner) {
|
|
|
|
return newRefiner._levels[0]->getNumVertices();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count) {
|
|
|
|
newRefiner._levels[0]->resizeFaceVertices(f, count);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count) {
|
|
|
|
newRefiner._levels[0]->resizeEdgeFaces(e, count);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count) {
|
|
|
|
newRefiner._levels[0]->resizeVertexFaces(v, count);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count) {
|
|
|
|
newRefiner._levels[0]->resizeVertexEdges(v, count);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseFaceVertices(TopologyRefiner & newRefiner, Index f) {
|
|
|
|
return newRefiner._levels[0]->getFaceVertices(f);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseFaceEdges(TopologyRefiner & newRefiner, Index f) {
|
|
|
|
return newRefiner._levels[0]->getFaceEdges(f);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e) {
|
|
|
|
return newRefiner._levels[0]->getEdgeVertices(e);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e) {
|
|
|
|
return newRefiner._levels[0]->getEdgeFaces(e);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseVertexFaces(TopologyRefiner & newRefiner, Index v) {
|
|
|
|
return newRefiner._levels[0]->getVertexFaces(v);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseVertexEdges(TopologyRefiner & newRefiner, Index v) {
|
|
|
|
return newRefiner._levels[0]->getVertexEdges(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline LocalIndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e) {
|
|
|
|
return newRefiner._levels[0]->getEdgeFaceLocalIndices(e);
|
|
|
|
}
|
|
|
|
inline LocalIndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
|
|
|
return newRefiner._levels[0]->getVertexFaceLocalIndices(v);
|
|
|
|
}
|
|
|
|
inline LocalIndexArray
|
|
|
|
TopologyRefinerFactoryBase::getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
|
|
|
return newRefiner._levels[0]->getVertexEdgeLocalIndices(v);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline Index
|
|
|
|
TopologyRefinerFactoryBase::findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1) {
|
|
|
|
return newRefiner._levels[0]->findEdge(v0, v1);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::populateBaseLocalIndices(TopologyRefiner & newRefiner) {
|
|
|
|
newRefiner._levels[0]->populateLocalIndices();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b) {
|
|
|
|
newRefiner._levels[0]->setEdgeNonManifold(e, b);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b) {
|
|
|
|
newRefiner._levels[0]->setVertexNonManifold(v, b);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float s) {
|
|
|
|
newRefiner._levels[0]->getEdgeSharpness(e) = s;
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float s) {
|
|
|
|
newRefiner._levels[0]->getVertexSharpness(v) = s;
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool b) {
|
|
|
|
newRefiner._levels[0]->setFaceHole(f, b);
|
|
|
|
newRefiner._hasHoles |= b;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline int
|
|
|
|
TopologyRefinerFactoryBase::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues) {
|
|
|
|
return newRefiner._levels[0]->createFVarChannel(numValues, newRefiner._subdivOptions);
|
|
|
|
}
|
|
|
|
inline int
|
|
|
|
TopologyRefinerFactoryBase::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);
|
|
|
|
}
|
|
|
|
inline IndexArray
|
2015-06-01 23:25:44 +00:00
|
|
|
TopologyRefinerFactoryBase::getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel) {
|
2015-06-02 03:31:27 +00:00
|
|
|
return newRefiner._levels[0]->getFaceFVarValues(face, channel);
|
2015-05-29 05:39:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::setBaseMaxValence(TopologyRefiner & newRefiner, int valence) {
|
|
|
|
newRefiner._levels[0]->setMaxValence(valence);
|
|
|
|
}
|
|
|
|
inline void
|
|
|
|
TopologyRefinerFactoryBase::initializeBaseInventory(TopologyRefiner & newRefiner) {
|
|
|
|
newRefiner.initializeInventory();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// TopologyRefinerFactory<MESH>:
|
|
|
|
// The factory class template to convert and refine 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.
|
|
|
|
// 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,
|
|
|
|
// using methods independent of MESH from the base class and those specialized for
|
|
|
|
// class MESH appropriately.
|
|
|
|
//
|
|
|
|
template <class MESH>
|
|
|
|
class TopologyRefinerFactory : public TopologyRefinerFactoryBase {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2015-01-08 05:33:48 +00:00
|
|
|
/// \brief Options related to the construction of each TopologyRefiner.
|
|
|
|
///
|
2015-01-06 08:03:21 +00:00
|
|
|
struct Options {
|
|
|
|
|
2015-01-07 01:40:11 +00:00
|
|
|
Options(Sdc::SchemeType sdcType = Sdc::SCHEME_CATMARK, Sdc::Options sdcOptions = Sdc::Options()) :
|
2015-01-06 08:03:21 +00:00
|
|
|
schemeType(sdcType),
|
|
|
|
schemeOptions(sdcOptions),
|
|
|
|
validateFullTopology(false) { }
|
|
|
|
|
2015-01-07 01:40:11 +00:00
|
|
|
Sdc::SchemeType schemeType; ///< The subdivision scheme type identifier
|
|
|
|
Sdc::Options schemeOptions; ///< The full set of options for the scheme,
|
2015-01-06 08:03:21 +00:00
|
|
|
///< e.g. boundary interpolation rules...
|
|
|
|
unsigned int validateFullTopology : 1; ///< Apply more extensive validation of
|
|
|
|
///< the constructed topology -- intended
|
|
|
|
///< for debugging.
|
|
|
|
};
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
/// \brief Instantiates 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.
|
|
|
|
///
|
2015-01-06 08:03:21 +00:00
|
|
|
/// @param mesh Client's topological representation (or a converter)
|
|
|
|
//
|
|
|
|
/// @param options Options controlling the creation of the TopologyRefiner
|
2014-09-05 22:07:46 +00:00
|
|
|
///
|
2015-01-06 08:03:21 +00:00
|
|
|
/// return A new instance of TopologyRefiner or NULL for failure
|
2014-09-05 22:07:46 +00:00
|
|
|
///
|
2015-01-06 08:03:21 +00:00
|
|
|
static TopologyRefiner* Create(MESH const& mesh, Options options = Options());
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
protected:
|
2015-01-08 05:33:48 +00:00
|
|
|
static bool populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options);
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// Methods to be specialized that implement all details specific to class MESH required
|
|
|
|
// to convert MESH data to TopologyRefiner. Note that some of these *must* be specialized
|
2015-01-08 05:33:48 +00:00
|
|
|
// in order to complete construction while some are optional.
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-06 03:34:47 +00:00
|
|
|
// There are two minimal construction requirements (to specify the size and content of
|
|
|
|
// all topology relations) and two optional (to specify feature tags and face-varying
|
|
|
|
// channels).
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
// See comments in the generic stubs or the tutorials for more details on writing these.
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// Required:
|
2015-01-08 05:33:48 +00:00
|
|
|
static bool resizeComponentTopology(TopologyRefiner& refiner, MESH const& mesh);
|
|
|
|
static bool assignComponentTopology(TopologyRefiner& refiner, MESH const& mesh);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
|
|
|
// Optional:
|
2015-01-08 05:33:48 +00:00
|
|
|
static bool assignComponentTags(TopologyRefiner& refiner, MESH const& mesh);
|
|
|
|
static bool assignFaceVaryingTopology(TopologyRefiner& refiner, MESH const& mesh);
|
2014-12-09 01:24:54 +00:00
|
|
|
|
2015-01-08 05:33:48 +00:00
|
|
|
// Optional miscellaneous specializations -- error reporting, etc.:
|
2015-05-26 03:34:50 +00:00
|
|
|
typedef Vtr::internal::Level::TopologyError TopologyError;
|
2014-12-09 01:24:54 +00:00
|
|
|
|
|
|
|
static void reportInvalidTopology(TopologyError errCode, char const * msg, MESH const& mesh);
|
2014-09-05 22:07:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Generic implementations:
|
|
|
|
//
|
|
|
|
template <class MESH>
|
|
|
|
TopologyRefiner*
|
2015-01-06 08:03:21 +00:00
|
|
|
TopologyRefinerFactory<MESH>::Create(MESH const& mesh, Options options) {
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-01-06 08:03:21 +00:00
|
|
|
TopologyRefiner * refiner = new TopologyRefiner(options.schemeType, options.schemeOptions);
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-01-08 05:33:48 +00:00
|
|
|
if (not populateBaseLevel(*refiner, mesh, options)) {
|
|
|
|
delete refiner;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXXX -- any state in the TopologyRefiner to update after the base level is complete?
|
|
|
|
|
|
|
|
return refiner;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class MESH>
|
|
|
|
bool
|
|
|
|
TopologyRefinerFactory<MESH>::populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options) {
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// Construction of a specialized topology refiner involves four steps, each of which
|
2015-01-06 03:34:47 +00:00
|
|
|
// involves a method specialized for MESH followed by one that takes an action in
|
2015-01-08 05:33:48 +00:00
|
|
|
// 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:
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
|
2015-01-03 20:26:02 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
if (not resizeComponentTopology(refiner, mesh)) return false;
|
|
|
|
if (not prepareComponentTopologySizing(refiner)) return false;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2014-12-09 01:24:54 +00:00
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// 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:
|
2014-12-09 01:24:54 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
bool validate = options.validateFullTopology;
|
|
|
|
TopologyCallback callback = reinterpret_cast<TopologyCallback>(reportInvalidTopology);
|
|
|
|
void const * userData = &mesh;
|
|
|
|
|
|
|
|
if (not assignComponentTopology(refiner, mesh)) return false;
|
|
|
|
if (not prepareComponentTopologyAssignment(refiner, validate, callback, userData)) return false;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-01-03 20:26:02 +00:00
|
|
|
//
|
2015-01-06 03:34:47 +00:00
|
|
|
// User assigned and internal tagging of components -- an optional specialization for
|
|
|
|
// MESH. Allows the specification of sharpness values, holes, etc.
|
2015-01-03 20:26:02 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
if (not assignComponentTags(refiner, mesh)) return false;
|
|
|
|
if (not prepareComponentTagsAndSharpness(refiner)) return false;
|
2014-09-05 22:07:46 +00:00
|
|
|
|
2015-01-03 20:26:02 +00:00
|
|
|
//
|
2015-01-06 03:34:47 +00:00
|
|
|
// Defining channels of face-varying primvar data -- an optional specialization for MESH.
|
2015-01-03 20:26:02 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
if (not assignFaceVaryingTopology(refiner, mesh)) return false;
|
|
|
|
if (not prepareFaceVaryingChannels(refiner)) return false;
|
2015-01-03 20:26:02 +00:00
|
|
|
|
2015-01-08 05:33:48 +00:00
|
|
|
return true;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// XXXX manuelk MSVC specializes these templated functions which creates duplicated symbols
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
|
|
|
|
template <class MESH>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-05 22:07:46 +00:00
|
|
|
TopologyRefinerFactory<MESH>::resizeComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
|
|
|
|
assert("Missing specialization for TopologyRefinerFactory<MESH>::resizeComponentTopology()" == 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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 TopologyRefiner::setBaseFaceCount(int count)
|
|
|
|
// void TopologyRefiner::setBaseEdgeCount(int count)
|
|
|
|
// void TopologyRefiner::setBaseVertexCount(int count)
|
|
|
|
//
|
|
|
|
// and then for each face, edge and vertex, the number of its incident components:
|
|
|
|
//
|
|
|
|
// void TopologyRefiner::setBaseFaceVertexCount(Index face, int count)
|
|
|
|
// void TopologyRefiner::setBaseEdgeFaceCount( Index edge, int count)
|
|
|
|
// void TopologyRefiner::setBaseVertexFaceCount(Index vertex, int count)
|
|
|
|
// void TopologyRefiner::setBaseVertexEdgeCount(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.
|
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
return false;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class MESH>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-05 22:07:46 +00:00
|
|
|
TopologyRefinerFactory<MESH>::assignComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
|
|
|
|
assert("Missing specialization for TopologyRefinerFactory<MESH>::assignComponentTopology()" == 0);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Assigning the topology tables:
|
|
|
|
// Once the topology tables have been allocated, the six required topological
|
|
|
|
// relations can be directly populated using the following methods:
|
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// IndexArray TopologyRefiner::setBaseFaceVertices(Index face)
|
|
|
|
// IndexArray TopologyRefiner::setBaseFaceEdges(Index face)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// IndexArray TopologyRefiner::setBaseEdgeVertices(Index edge)
|
|
|
|
// IndexArray TopologyRefiner::setBaseEdgeFaces(Index edge)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// IndexArray TopologyRefiner::setBaseVertexEdges(Index vertex)
|
|
|
|
// IndexArray TopologyRefiner::setBaseVertexFaces(Index vertex)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// 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:
|
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// LocalIndexArray TopologyRefiner::setBaseVertexFaceLocalIndices(Index vertex)
|
|
|
|
// LocalIndexArray TopologyRefiner::setBaseVertexEdgeLocalIndices(Index vertex)
|
|
|
|
//
|
2015-01-05 00:33:18 +00:00
|
|
|
// or, if the mesh is manifold, explicit assignment of these can be deferred and
|
|
|
|
// all will be determined via:
|
|
|
|
//
|
|
|
|
// void TopologyRefiner::populateBaseLocalIndices()
|
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// 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
|
2015-01-05 00:33:18 +00:00
|
|
|
// assumed or required, but be sure to explicitly tag such components (vertices and
|
2015-01-03 20:26:02 +00:00
|
|
|
// edges) as non-manifold:
|
|
|
|
//
|
|
|
|
// void TopologyRefiner::setBaseEdgeNonManifold(Index edge, bool b);
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-03 20:26:02 +00:00
|
|
|
// void TopologyRefiner::setBaseVertexNonManifold(Index vertex, bool b);
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-05-22 04:26:41 +00:00
|
|
|
// Also consider using TopologyLevel::ValidateTopology() when debugging to ensure
|
2015-01-03 20:26:02 +00:00
|
|
|
// that topolology has been completely and correctly specified.
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
return false;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class MESH>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-05 22:07:46 +00:00
|
|
|
TopologyRefinerFactory<MESH>::assignFaceVaryingTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
|
|
|
|
//
|
|
|
|
// Optional assigning face-varying topology tables:
|
|
|
|
//
|
|
|
|
// Create independent face-varying primitive variable channels:
|
2015-01-05 00:33:18 +00:00
|
|
|
// int TopologyRefiner::createBaseFVarChannel(int numValues)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
|
|
|
// For each channel, populate the face-vertex values:
|
2015-06-01 23:25:44 +00:00
|
|
|
// IndexArray TopologyRefiner::setBaseFaceFVarValues(Index face, int channel = 0)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
return true;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <class MESH>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-05 22:07:46 +00:00
|
|
|
TopologyRefinerFactory<MESH>::assignComponentTags(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
|
|
|
|
|
|
|
//
|
|
|
|
// Optional tagging:
|
|
|
|
// This is where any additional feature tags -- sharpness, holes, etc. -- can be
|
2015-01-05 00:33:18 +00:00
|
|
|
// specified using:
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-05 00:33:18 +00:00
|
|
|
// void TopologyRefiner::setBaseEdgeSharpness(Index edge, float sharpness)
|
|
|
|
// void TopologyRefiner::setBaseVertexSharpness(Index vertex, float sharpness)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-05 00:33:18 +00:00
|
|
|
// void TopologyRefiner::setBaseFaceHole(Index face, bool hole)
|
2014-09-05 22:07:46 +00:00
|
|
|
//
|
2015-01-08 05:33:48 +00:00
|
|
|
return true;
|
2014-09-05 22:07:46 +00:00
|
|
|
}
|
|
|
|
|
2014-12-04 01:19:07 +00:00
|
|
|
template <class MESH>
|
|
|
|
void
|
2014-12-09 01:24:54 +00:00
|
|
|
TopologyRefinerFactory<MESH>::reportInvalidTopology(
|
|
|
|
TopologyError /* errCode */, char const * /* msg */, MESH const& /* mesh */) {
|
2014-12-04 01:19:07 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Optional topology validation error reporting:
|
|
|
|
// This method is called whenever the factory encounters topology validation
|
2014-12-09 01:24:54 +00:00
|
|
|
// errors. By default, nothing is reported
|
2014-12-04 01:19:07 +00:00
|
|
|
//
|
|
|
|
}
|
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
#endif
|
|
|
|
|
2014-09-11 23:20:46 +00:00
|
|
|
//
|
|
|
|
// Specialization for raw topology data
|
|
|
|
//
|
|
|
|
template <>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-11 23:20:46 +00:00
|
|
|
TopologyRefinerFactory<TopologyRefinerFactoryBase::TopologyDescriptor>::resizeComponentTopology(
|
|
|
|
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
|
|
|
|
|
|
|
template <>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
2014-09-11 23:20:46 +00:00
|
|
|
TopologyRefinerFactory<TopologyRefinerFactoryBase::TopologyDescriptor>::assignComponentTopology(
|
|
|
|
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
|
|
|
|
|
|
|
template <>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
|
|
|
TopologyRefinerFactory<TopologyRefinerFactoryBase::TopologyDescriptor>::assignComponentTags(
|
2014-09-11 23:20:46 +00:00
|
|
|
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
|
|
|
|
|
|
|
template <>
|
2015-01-08 05:33:48 +00:00
|
|
|
bool
|
|
|
|
TopologyRefinerFactory<TopologyRefinerFactoryBase::TopologyDescriptor>::assignFaceVaryingTopology(
|
2014-09-11 23:20:46 +00:00
|
|
|
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
|
|
|
|
2014-12-04 01:19:07 +00:00
|
|
|
template <>
|
|
|
|
void
|
|
|
|
TopologyRefinerFactory<TopologyRefinerFactoryBase::TopologyDescriptor>::reportInvalidTopology(
|
2014-12-09 01:24:54 +00:00
|
|
|
TopologyError errCode, char const * msg, TopologyDescriptor const& /* mesh */);
|
2014-12-04 01:19:07 +00:00
|
|
|
|
2014-09-05 22:07:46 +00:00
|
|
|
} // end namespace Far
|
|
|
|
|
|
|
|
} // end namespace OPENSUBDIV_VERSION
|
|
|
|
using namespace OPENSUBDIV_VERSION;
|
|
|
|
} // end namespace OpenSubdiv
|
|
|
|
|
2015-05-19 18:22:37 +00:00
|
|
|
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H */
|