Add Chromium-only Blender WebEngine parity work
This commit is contained in:
73
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/CMakeLists.txt
vendored
Normal file
73
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# source & headers
|
||||
set(SOURCE_FILES
|
||||
fvarLevel.cpp
|
||||
fvarRefinement.cpp
|
||||
level.cpp
|
||||
quadRefinement.cpp
|
||||
refinement.cpp
|
||||
sparseSelector.cpp
|
||||
triRefinement.cpp
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADER_FILES
|
||||
quadRefinement.h
|
||||
triRefinement.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_FILES
|
||||
array.h
|
||||
componentInterfaces.h
|
||||
fvarLevel.h
|
||||
fvarRefinement.h
|
||||
level.h
|
||||
refinement.h
|
||||
sparseSelector.h
|
||||
stackBuffer.h
|
||||
types.h
|
||||
)
|
||||
|
||||
set(DOXY_HEADER_FILES ${PUBLIC_HEADER_FILES})
|
||||
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
if (NOT NO_LIB)
|
||||
|
||||
# Compile objs first for both the CPU and GPU libs -----
|
||||
add_library(vtr_obj
|
||||
OBJECT
|
||||
${SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(vtr_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
osd_add_doxy_headers( "${DOXY_HEADER_FILES}" )
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/vtr"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
131
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/array.h
vendored
Normal file
131
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/array.h
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_ARRAY_INTERFACE_H
|
||||
#define OPENSUBDIV3_VTR_ARRAY_INTERFACE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
|
||||
//
|
||||
// This class provides a simple array-like interface -- a subset std::vector's interface -- for
|
||||
// a sequence of elements stored in contiguous memory. It provides a unified representation for
|
||||
// referencing data on the stack, all or a subset of std::vector<>, or anywhere else in memory.
|
||||
//
|
||||
// Note that its members are head/size rather than begin/end as in std::vector -- we frequently
|
||||
// need only the size for many queries, and that is most often what is stored elsewhere in other
|
||||
// classes, so we hope to reduce unnecessary address arithmetic constructing the interface and
|
||||
// accessing the size. The size type is also specifically 32-bit (rather than size_t) to match
|
||||
// internal usage and avoid unnecessary conversion to/from 64-bit.
|
||||
//
|
||||
// Question:
|
||||
// Naming is at issue here... formerly called ArrayInterface until that was shot down it has
|
||||
// been simplified to Array but needs to be distanced from std::array as it DOES NOT store its
|
||||
// own memory and is simply an interface to memory stored elsewhere.
|
||||
//
|
||||
template <typename TYPE>
|
||||
class ConstArray {
|
||||
|
||||
public:
|
||||
typedef TYPE value_type;
|
||||
typedef int size_type;
|
||||
|
||||
typedef TYPE const& const_reference;
|
||||
typedef TYPE const* const_iterator;
|
||||
|
||||
typedef TYPE& reference;
|
||||
typedef TYPE* iterator;
|
||||
|
||||
public:
|
||||
|
||||
ConstArray() : _begin(0), _size(0) { }
|
||||
|
||||
ConstArray(value_type const * ptr, size_type sizeArg) :
|
||||
_begin(ptr), _size(sizeArg) { }
|
||||
|
||||
size_type size() const { return _size; }
|
||||
|
||||
bool empty() const { return _size==0; }
|
||||
|
||||
const_reference operator[](int index) const { return _begin[index]; }
|
||||
const_iterator begin() const { return _begin; }
|
||||
const_iterator end() const { return _begin + _size; }
|
||||
|
||||
size_type FindIndexIn4Tuple(value_type value) const {
|
||||
assert(_size>=4);
|
||||
if (value == _begin[0]) return 0;
|
||||
if (value == _begin[1]) return 1;
|
||||
if (value == _begin[2]) return 2;
|
||||
if (value == _begin[3]) return 3;
|
||||
assert("FindIndexIn4Tuple() did not find expected value!" == 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_type FindIndex(value_type value) const {
|
||||
for (size_type i=0; i<size(); ++i) {
|
||||
if (value==_begin[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected:
|
||||
value_type const * _begin;
|
||||
size_type _size;
|
||||
};
|
||||
|
||||
template <typename TYPE>
|
||||
class Array : public ConstArray<TYPE> {
|
||||
|
||||
public:
|
||||
typedef TYPE value_type;
|
||||
typedef int size_type;
|
||||
|
||||
typedef TYPE const& const_reference;
|
||||
|
||||
typedef TYPE& reference;
|
||||
typedef TYPE* iterator;
|
||||
|
||||
public:
|
||||
|
||||
Array() : ConstArray<TYPE>() { }
|
||||
|
||||
Array(value_type * ptr, size_type sizeArg) : ConstArray<TYPE>(ptr, sizeArg) { }
|
||||
|
||||
public:
|
||||
|
||||
const_reference operator[](int index) const {
|
||||
return ConstArray<TYPE>::_begin[index];
|
||||
}
|
||||
|
||||
reference operator[](int index) {
|
||||
return const_cast<reference>(ConstArray<TYPE>::_begin[index]);
|
||||
}
|
||||
|
||||
iterator begin() {
|
||||
return const_cast<iterator>(ConstArray<TYPE>::_begin);
|
||||
}
|
||||
|
||||
iterator end() {
|
||||
return const_cast<iterator>(ConstArray<TYPE>::_begin +
|
||||
ConstArray<TYPE>::_size);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_ARRAY_INTERFACE_H */
|
||||
141
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/componentInterfaces.h
vendored
Normal file
141
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/componentInterfaces.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_COMPONENT_INTERFACES_H
|
||||
#define OPENSUBDIV3_VTR_COMPONENT_INTERFACES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/crease.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/stackBuffer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// Simple classes supporting the interfaces required of generic topological
|
||||
// types in the Scheme mask queries, e.g. <typename FACE, VERTEX, etc.>
|
||||
//
|
||||
// These are not used with Vtr but arguably belong with it as the details to
|
||||
// write these efficiently depends very much on intimate details of Vtr's
|
||||
// implementation, e.g. the use of tag bits, subdivision Rules, etc.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// For <typename FACE>, which provides information in the neighborhood of a face:
|
||||
//
|
||||
class FaceInterface {
|
||||
public:
|
||||
FaceInterface() { }
|
||||
FaceInterface(int vertCount) : _vertCount(vertCount) { }
|
||||
~FaceInterface() { }
|
||||
|
||||
public: // Generic interface expected of <typename FACE>:
|
||||
int GetNumVertices() const { return _vertCount; }
|
||||
|
||||
private:
|
||||
int _vertCount;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// For <typename EDGE>, which provides information in the neighborhood of an edge:
|
||||
//
|
||||
class EdgeInterface {
|
||||
public:
|
||||
EdgeInterface() { }
|
||||
EdgeInterface(Level const& level) : _level(&level) { }
|
||||
~EdgeInterface() { }
|
||||
|
||||
void SetIndex(int edgeIndex) { _eIndex = edgeIndex; }
|
||||
|
||||
public: // Generic interface expected of <typename EDGE>:
|
||||
int GetNumFaces() const { return _level->getEdgeFaces(_eIndex).size(); }
|
||||
float GetSharpness() const { return _level->getEdgeSharpness(_eIndex); }
|
||||
|
||||
void GetChildSharpnesses(Sdc::Crease const&, float s[2]) const {
|
||||
// Need to use the Refinement here to identify the two child edges:
|
||||
s[0] = s[1] = GetSharpness() - 1.0f;
|
||||
}
|
||||
|
||||
void GetNumVerticesPerFace(int vertsPerFace[]) const {
|
||||
ConstIndexArray eFaces = _level->getEdgeFaces(_eIndex);
|
||||
for (int i = 0; i < eFaces.size(); ++i) {
|
||||
vertsPerFace[i] = _level->getFaceVertices(eFaces[i]).size();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Level* _level;
|
||||
|
||||
int _eIndex;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// For <typename VERTEX>, which provides information in the neighborhood of a vertex:
|
||||
//
|
||||
class VertexInterface {
|
||||
public:
|
||||
VertexInterface() { }
|
||||
VertexInterface(Level const& parent, Level const& child) : _parent(&parent), _child(&child) { }
|
||||
~VertexInterface() { }
|
||||
|
||||
void SetIndex(int parentIndex, int childIndex) {
|
||||
_pIndex = parentIndex;
|
||||
_cIndex = childIndex;
|
||||
_eCount = _parent->getVertexEdges(_pIndex).size();
|
||||
_fCount = _parent->getVertexFaces(_pIndex).size();
|
||||
}
|
||||
|
||||
public: // Generic interface expected of <typename VERT>:
|
||||
int GetNumEdges() const { return _eCount; }
|
||||
int GetNumFaces() const { return _fCount; }
|
||||
|
||||
float GetSharpness() const { return _parent->getVertexSharpness(_pIndex); }
|
||||
float* GetSharpnessPerEdge(float pSharpness[]) const {
|
||||
ConstIndexArray pEdges = _parent->getVertexEdges(_pIndex);
|
||||
for (int i = 0; i < _eCount; ++i) {
|
||||
pSharpness[i] = _parent->getEdgeSharpness(pEdges[i]);
|
||||
}
|
||||
return pSharpness;
|
||||
}
|
||||
|
||||
float GetChildSharpness(Sdc::Crease const&) const { return _child->getVertexSharpness(_cIndex); }
|
||||
float* GetChildSharpnessPerEdge(Sdc::Crease const& crease, float cSharpness[]) const {
|
||||
internal::StackBuffer<float,16> pSharpness(_eCount);
|
||||
GetSharpnessPerEdge(pSharpness);
|
||||
crease.SubdivideEdgeSharpnessesAroundVertex(_eCount, pSharpness, cSharpness);
|
||||
return cSharpness;
|
||||
}
|
||||
|
||||
private:
|
||||
const Level* _parent;
|
||||
const Level* _child;
|
||||
|
||||
int _pIndex;
|
||||
int _cIndex;
|
||||
int _eCount;
|
||||
int _fCount;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_COMPONENT_INTERFACES_H */
|
||||
1053
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarLevel.cpp
vendored
Normal file
1053
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarLevel.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
422
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarLevel.h
vendored
Normal file
422
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarLevel.h
vendored
Normal file
@@ -0,0 +1,422 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_FVAR_LEVEL_H
|
||||
#define OPENSUBDIV3_VTR_FVAR_LEVEL_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/crease.h"
|
||||
#include "../sdc/options.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// FVarLevel:
|
||||
// A "face-varying channel" includes the topology for a set of face-varying
|
||||
// data, relative to the topology of the Level with which it is associated.
|
||||
//
|
||||
// Analogous to a set of vertices and face-vertices that define the topology for
|
||||
// the geometry, a channel requires a set of "values" and "face-values". The
|
||||
// "values" are indices of entries in a set of face-varying data, just as vertices
|
||||
// are indices into a set of vertex data. The face-values identify a value for
|
||||
// each vertex of the face, and so define topology for the values that may be
|
||||
// unique to each channel.
|
||||
//
|
||||
// In addition to the value size and the vector of face-values (which matches the
|
||||
// size of the geometry's face-vertices), tags are associated with each component
|
||||
// to identify deviations of the face-varying topology from the vertex topology.
|
||||
// And since there may be a one-to-many mapping between vertices and face-varying
|
||||
// values, that mapping is also allocated.
|
||||
//
|
||||
// It turns out that the mapping used is able to completely encode the set of
|
||||
// face-values and is more amenable to refinement. Currently the face-values
|
||||
// take up almost half the memory of this representation, so if memory does
|
||||
// become a concern, we do not need to store them. The only reason we do so now
|
||||
// is that the face-value interface for specifying base topology and inspecting
|
||||
// subsequent levels is very familiar to that of face-vertices for clients. So
|
||||
// having them available for such access is convenient.
|
||||
//
|
||||
// Regarding scope and access...
|
||||
// Unclear at this early state, but leaning towards nesting this class within
|
||||
// Level, given the intimate dependency between the two.
|
||||
// Everything is being declared public for now to facilitate access until it's
|
||||
// clearer how this functionality will be provided.
|
||||
//
|
||||
class FVarLevel {
|
||||
public:
|
||||
//
|
||||
// Component tags -- trying to minimize the types needed here:
|
||||
//
|
||||
// Tag per Edge:
|
||||
// - facilitates topological analysis around each vertex
|
||||
// - required during refinement to spawn one or more edge-values
|
||||
//
|
||||
struct ETag {
|
||||
ETag() { }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(ETag)); }
|
||||
|
||||
typedef unsigned char ETagSize;
|
||||
|
||||
ETagSize _mismatch : 1; // local FVar topology does not match
|
||||
ETagSize _disctsV0 : 1; // discontinuous at vertex 0
|
||||
ETagSize _disctsV1 : 1; // discontinuous at vertex 1
|
||||
ETagSize _linear : 1; // linear boundary constraints
|
||||
|
||||
Level::ETag combineWithLevelETag(Level::ETag) const;
|
||||
};
|
||||
|
||||
//
|
||||
// Tag per Value:
|
||||
// - informs both refinement and interpolation
|
||||
// - every value spawns a child value in refinement
|
||||
// - includes a subset of Level::VTag to be later combined with a VTag
|
||||
//
|
||||
struct ValueTag {
|
||||
ValueTag() { }
|
||||
|
||||
void clear() { std::memset(this, 0, sizeof(ValueTag)); }
|
||||
|
||||
bool isMismatch() const { return _mismatch; }
|
||||
bool isCrease() const { return _crease; }
|
||||
bool isCorner() const { return !_crease; }
|
||||
bool isSemiSharp() const { return _semiSharp; }
|
||||
bool isInfSharp() const { return !_semiSharp && !_crease; }
|
||||
bool isDepSharp() const { return _depSharp; }
|
||||
bool hasCreaseEnds() const { return _crease || _semiSharp; }
|
||||
|
||||
bool hasInfSharpEdges() const { return _infSharpEdges; }
|
||||
bool hasInfIrregularity() const { return _infIrregular; }
|
||||
|
||||
typedef unsigned char ValueTagSize;
|
||||
|
||||
// If there is no mismatch, no other members should be inspected
|
||||
ValueTagSize _mismatch : 1; // local FVar topology does not match
|
||||
ValueTagSize _xordinary : 1; // local FVar topology is extra-ordinary
|
||||
ValueTagSize _nonManifold : 1; // local FVar topology is non-manifold
|
||||
ValueTagSize _crease : 1; // value is a crease, otherwise a corner
|
||||
ValueTagSize _semiSharp : 1; // value is a corner decaying to crease
|
||||
ValueTagSize _depSharp : 1; // value is a corner by dependency on another
|
||||
|
||||
ValueTagSize _infSharpEdges : 1; // value is a corner by inf-sharp features
|
||||
ValueTagSize _infIrregular : 1; // value span includes inf-sharp irregularity
|
||||
|
||||
Level::VTag combineWithLevelVTag(Level::VTag) const;
|
||||
|
||||
// Alternate constructor and accessor for dealing with integer bits directly:
|
||||
explicit ValueTag(ValueTagSize bits) {
|
||||
std::memcpy(this, &bits, sizeof(bits));
|
||||
}
|
||||
ValueTagSize getBits() const {
|
||||
ValueTagSize bits;
|
||||
std::memcpy(&bits, this, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vtr::ConstArray<ValueTag> ConstValueTagArray;
|
||||
typedef Vtr::Array<ValueTag> ValueTagArray;
|
||||
|
||||
//
|
||||
// Simple struct containing the "end faces" of a crease, i.e. the faces which
|
||||
// contain the FVar values to be used when interpolating the crease. (Prefer
|
||||
// the struct over std::pair for its member names)
|
||||
//
|
||||
struct CreaseEndPair {
|
||||
LocalIndex _startFace;
|
||||
LocalIndex _endFace;
|
||||
};
|
||||
|
||||
typedef Vtr::ConstArray<CreaseEndPair> ConstCreaseEndPairArray;
|
||||
typedef Vtr::Array<CreaseEndPair> CreaseEndPairArray;
|
||||
|
||||
typedef LocalIndex Sibling;
|
||||
|
||||
typedef ConstLocalIndexArray ConstSiblingArray;
|
||||
typedef LocalIndexArray SiblingArray;
|
||||
|
||||
public:
|
||||
FVarLevel(Level const& level);
|
||||
~FVarLevel();
|
||||
|
||||
// Queries for the entire channel:
|
||||
Level const& getLevel() const { return _level; }
|
||||
|
||||
int getNumValues() const { return _valueCount; }
|
||||
int getNumFaceValuesTotal() const { return (int) _faceVertValues.size(); }
|
||||
|
||||
bool isLinear() const { return _isLinear; }
|
||||
bool hasLinearBoundaries() const { return _hasLinearBoundaries; }
|
||||
bool hasSmoothBoundaries() const { return ! _hasLinearBoundaries; }
|
||||
bool hasCreaseEnds() const { return hasSmoothBoundaries(); }
|
||||
|
||||
Sdc::Options getOptions() const { return _options; }
|
||||
|
||||
// Queries per face:
|
||||
ConstIndexArray getFaceValues(Index fIndex) const;
|
||||
IndexArray getFaceValues(Index fIndex);
|
||||
|
||||
// Queries per edge:
|
||||
ETag getEdgeTag(Index eIndex) const { return _edgeTags[eIndex]; }
|
||||
bool edgeTopologyMatches(Index eIndex) const { return !getEdgeTag(eIndex)._mismatch; }
|
||||
|
||||
// Queries per vertex (and its potential sibling values):
|
||||
int getNumVertexValues(Index v) const { return _vertSiblingCounts[v]; }
|
||||
Index getVertexValueOffset(Index v, Sibling i = 0) const { return _vertSiblingOffsets[v] + i; }
|
||||
|
||||
Index getVertexValue(Index v, Sibling i = 0) const { return _vertValueIndices[getVertexValueOffset(v,i)]; }
|
||||
|
||||
Index findVertexValueIndex(Index vertexIndex, Index valueIndex) const;
|
||||
|
||||
// Methods to access/modify array properties per vertex:
|
||||
ConstIndexArray getVertexValues(Index vIndex) const;
|
||||
IndexArray getVertexValues(Index vIndex);
|
||||
|
||||
ConstValueTagArray getVertexValueTags(Index vIndex) const;
|
||||
ValueTagArray getVertexValueTags(Index vIndex);
|
||||
|
||||
ConstCreaseEndPairArray getVertexValueCreaseEnds(Index vIndex) const;
|
||||
CreaseEndPairArray getVertexValueCreaseEnds(Index vIndex);
|
||||
|
||||
ConstSiblingArray getVertexFaceSiblings(Index vIndex) const;
|
||||
SiblingArray getVertexFaceSiblings(Index vIndex);
|
||||
|
||||
// Queries per value:
|
||||
ValueTag getValueTag(Index valueIndex) const { return _vertValueTags[valueIndex]; }
|
||||
bool valueTopologyMatches(Index valueIndex) const { return !getValueTag(valueIndex)._mismatch; }
|
||||
|
||||
CreaseEndPair getValueCreaseEndPair(Index valueIndex) const { return _vertValueCreaseEnds[valueIndex]; }
|
||||
|
||||
// Tag queries related to faces (use Level methods for those returning Level::VTag/ETag)
|
||||
void getFaceValueTags(Index faceIndex, ValueTag valueTags[]) const;
|
||||
|
||||
ValueTag getFaceCompositeValueTag(Index faceIndex) const;
|
||||
|
||||
// Higher-level topological queries, i.e. values in a neighborhood:
|
||||
void getEdgeFaceValues(Index eIndex, int fIncToEdge, Index valuesPerVert[2]) const;
|
||||
void getVertexEdgeValues(Index vIndex, Index valuesPerEdge[]) const;
|
||||
void getVertexCreaseEndValues(Index vIndex, Sibling sibling, Index endValues[2]) const;
|
||||
|
||||
// Initialization and allocation helpers:
|
||||
void setOptions(Sdc::Options const& options);
|
||||
void resizeVertexValues(int numVertexValues);
|
||||
void resizeValues(int numValues);
|
||||
void resizeComponents();
|
||||
|
||||
// Topological analysis methods -- tagging and face-value population:
|
||||
void completeTopologyFromFaceValues(int regBoundaryValence);
|
||||
void initializeFaceValuesFromFaceVertices();
|
||||
void initializeFaceValuesFromVertexFaceSiblings();
|
||||
|
||||
struct ValueSpan;
|
||||
void gatherValueSpans(Index vIndex, ValueSpan * vValueSpans) const;
|
||||
|
||||
// Debugging methods:
|
||||
bool validate() const;
|
||||
void print() const;
|
||||
void buildFaceVertexSiblingsFromVertexFaceSiblings(std::vector<Sibling>& fvSiblings) const;
|
||||
|
||||
private:
|
||||
// Just as Refinements build Levels, FVarRefinements build FVarLevels...
|
||||
friend class FVarRefinement;
|
||||
|
||||
Level const & _level;
|
||||
|
||||
// Linear interpolation options vary between channels:
|
||||
Sdc::Options _options;
|
||||
|
||||
bool _isLinear;
|
||||
bool _hasLinearBoundaries;
|
||||
bool _hasDependentSharpness;
|
||||
int _valueCount;
|
||||
|
||||
//
|
||||
// Vectors recording face-varying topology including tags that help propagate
|
||||
// data through the refinement hierarchy. Vectors are not sparse but most use
|
||||
// 8-bit values relative to the local topology.
|
||||
//
|
||||
// The vector of face-values is actually redundant here, but is constructed as
|
||||
// it is most convenient for clients. It represents almost half the memory of
|
||||
// the topology (4 32-bit integers per face) and not surprisingly, populating
|
||||
// it takes a considerable amount of the refinement time (1/3). We can reduce
|
||||
// both if we are willing to compute these on demand for clients.
|
||||
//
|
||||
// Per-face (matches face-verts of corresponding level):
|
||||
std::vector<Index> _faceVertValues;
|
||||
|
||||
// Per-edge:
|
||||
std::vector<ETag> _edgeTags;
|
||||
|
||||
// Per-vertex:
|
||||
std::vector<Sibling> _vertSiblingCounts;
|
||||
std::vector<int> _vertSiblingOffsets;
|
||||
std::vector<Sibling> _vertFaceSiblings;
|
||||
|
||||
// Per-value:
|
||||
std::vector<Index> _vertValueIndices;
|
||||
std::vector<ValueTag> _vertValueTags;
|
||||
std::vector<CreaseEndPair> _vertValueCreaseEnds;
|
||||
};
|
||||
|
||||
//
|
||||
// Access/modify the values associated with each face:
|
||||
//
|
||||
inline ConstIndexArray
|
||||
FVarLevel::getFaceValues(Index fIndex) const {
|
||||
|
||||
int vCount = _level.getNumFaceVertices(fIndex);
|
||||
int vOffset = _level.getOffsetOfFaceVertices(fIndex);
|
||||
return ConstIndexArray(&_faceVertValues[vOffset], vCount);
|
||||
}
|
||||
inline IndexArray
|
||||
FVarLevel::getFaceValues(Index fIndex) {
|
||||
|
||||
int vCount = _level.getNumFaceVertices(fIndex);
|
||||
int vOffset = _level.getOffsetOfFaceVertices(fIndex);
|
||||
return IndexArray(&_faceVertValues[vOffset], vCount);
|
||||
}
|
||||
|
||||
inline FVarLevel::ConstSiblingArray
|
||||
FVarLevel::getVertexFaceSiblings(Index vIndex) const {
|
||||
|
||||
int vCount = _level.getNumVertexFaces(vIndex);
|
||||
int vOffset = _level.getOffsetOfVertexFaces(vIndex);
|
||||
return ConstSiblingArray(&_vertFaceSiblings[vOffset], vCount);
|
||||
}
|
||||
inline FVarLevel::SiblingArray
|
||||
FVarLevel::getVertexFaceSiblings(Index vIndex) {
|
||||
|
||||
int vCount = _level.getNumVertexFaces(vIndex);
|
||||
int vOffset = _level.getOffsetOfVertexFaces(vIndex);
|
||||
return SiblingArray(&_vertFaceSiblings[vOffset], vCount);
|
||||
}
|
||||
|
||||
inline ConstIndexArray
|
||||
FVarLevel::getVertexValues(Index vIndex) const
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return ConstIndexArray(&_vertValueIndices[vOffset], vCount);
|
||||
}
|
||||
inline IndexArray
|
||||
FVarLevel::getVertexValues(Index vIndex)
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return IndexArray(&_vertValueIndices[vOffset], vCount);
|
||||
}
|
||||
|
||||
inline FVarLevel::ConstValueTagArray
|
||||
FVarLevel::getVertexValueTags(Index vIndex) const
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return ConstValueTagArray(&_vertValueTags[vOffset], vCount);
|
||||
}
|
||||
inline FVarLevel::ValueTagArray
|
||||
FVarLevel::getVertexValueTags(Index vIndex)
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return ValueTagArray(&_vertValueTags[vOffset], vCount);
|
||||
}
|
||||
|
||||
inline FVarLevel::ConstCreaseEndPairArray
|
||||
FVarLevel::getVertexValueCreaseEnds(Index vIndex) const
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return ConstCreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
|
||||
}
|
||||
inline FVarLevel::CreaseEndPairArray
|
||||
FVarLevel::getVertexValueCreaseEnds(Index vIndex)
|
||||
{
|
||||
int vCount = getNumVertexValues(vIndex);
|
||||
int vOffset = getVertexValueOffset(vIndex);
|
||||
return CreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
|
||||
}
|
||||
|
||||
inline Index
|
||||
FVarLevel::findVertexValueIndex(Index vertexIndex, Index valueIndex) const {
|
||||
|
||||
if (_level.getDepth() > 0) return valueIndex;
|
||||
|
||||
Index vvIndex = getVertexValueOffset(vertexIndex);
|
||||
while (_vertValueIndices[vvIndex] != valueIndex) {
|
||||
++ vvIndex;
|
||||
}
|
||||
return vvIndex;
|
||||
}
|
||||
|
||||
//
|
||||
// Methods related to tagging:
|
||||
//
|
||||
inline Level::ETag
|
||||
FVarLevel::ETag::combineWithLevelETag(Level::ETag levelTag) const
|
||||
{
|
||||
if (this->_mismatch) {
|
||||
levelTag._boundary = true;
|
||||
levelTag._infSharp = true;
|
||||
}
|
||||
return levelTag;
|
||||
}
|
||||
inline Level::VTag
|
||||
FVarLevel::ValueTag::combineWithLevelVTag(Level::VTag levelTag) const
|
||||
{
|
||||
if (this->_mismatch) {
|
||||
//
|
||||
// Semi-sharp FVar values are always tagged and treated as corners
|
||||
// (at least three sharp edges (two boundary edges and one interior
|
||||
// semi-sharp) and/or vertex is semi-sharp) until the sharpness has
|
||||
// decayed, but they ultimately lie on the inf-sharp crease of the
|
||||
// FVar boundary. Consider this when tagging inf-sharp features.
|
||||
//
|
||||
if (this->isCorner()) {
|
||||
levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CORNER;
|
||||
} else {
|
||||
levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CREASE;
|
||||
}
|
||||
if (this->isCrease() || this->isSemiSharp()) {
|
||||
levelTag._infSharp = false;
|
||||
levelTag._infSharpCrease = true;
|
||||
levelTag._corner = false;
|
||||
} else {
|
||||
levelTag._infSharp = true;
|
||||
levelTag._infSharpCrease = false;
|
||||
levelTag._corner = !this->_infIrregular && !this->_infSharpEdges;
|
||||
}
|
||||
levelTag._infSharpEdges = true;
|
||||
levelTag._infIrregular = this->_infIrregular;
|
||||
|
||||
levelTag._boundary = true;
|
||||
levelTag._xordinary = this->_xordinary;
|
||||
|
||||
levelTag._nonManifold |= this->_nonManifold;
|
||||
}
|
||||
return levelTag;
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_FVAR_LEVEL_H */
|
||||
675
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarRefinement.cpp
vendored
Normal file
675
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarRefinement.cpp
vendored
Normal file
@@ -0,0 +1,675 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/crease.h"
|
||||
#include "../vtr/array.h"
|
||||
#include "../vtr/stackBuffer.h"
|
||||
#include "../vtr/refinement.h"
|
||||
#include "../vtr/fvarLevel.h"
|
||||
|
||||
#include "../vtr/fvarRefinement.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
//
|
||||
// FVarRefinement:
|
||||
// Analogous to Refinement -- retains data to facilitate refinement and
|
||||
// population of refined face-varying data channels.
|
||||
//
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// Simple (for now) constructor and destructor:
|
||||
//
|
||||
FVarRefinement::FVarRefinement(Refinement const& refinement,
|
||||
FVarLevel& parentFVarLevel,
|
||||
FVarLevel& childFVarLevel) :
|
||||
_refinement(refinement),
|
||||
_parentLevel(refinement.parent()),
|
||||
_parentFVar(parentFVarLevel),
|
||||
_childLevel(refinement.child()),
|
||||
_childFVar(childFVarLevel) {
|
||||
}
|
||||
|
||||
FVarRefinement::~FVarRefinement() {
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods supporting the refinement of face-varying data that has previously
|
||||
// been applied to the Refinement member. So these methods already have access
|
||||
// to fully refined child components.
|
||||
//
|
||||
|
||||
void
|
||||
FVarRefinement::applyRefinement() {
|
||||
|
||||
//
|
||||
// Transfer basic properties from the parent to child level:
|
||||
//
|
||||
_childFVar._options = _parentFVar._options;
|
||||
|
||||
_childFVar._isLinear = _parentFVar._isLinear;
|
||||
_childFVar._hasLinearBoundaries = _parentFVar._hasLinearBoundaries;
|
||||
_childFVar._hasDependentSharpness = _parentFVar._hasDependentSharpness;
|
||||
|
||||
//
|
||||
// It's difficult to know immediately how many child values arise from the
|
||||
// refinement -- particularly when sparse, so we get a close upper bound,
|
||||
// resize for that number and trim when finished:
|
||||
//
|
||||
estimateAndAllocateChildValues();
|
||||
populateChildValues();
|
||||
trimAndFinalizeChildValues();
|
||||
|
||||
propagateEdgeTags();
|
||||
propagateValueTags();
|
||||
if (_childFVar.hasSmoothBoundaries()) {
|
||||
propagateValueCreases();
|
||||
reclassifySemisharpValues();
|
||||
}
|
||||
|
||||
//
|
||||
// The refined face-values are technically redundant as they can be constructed
|
||||
// from the face-vertex siblings -- do so here as a post-process
|
||||
//
|
||||
if (_childFVar.getNumValues() > _childLevel.getNumVertices()) {
|
||||
_childFVar.initializeFaceValuesFromVertexFaceSiblings();
|
||||
} else {
|
||||
_childFVar.initializeFaceValuesFromFaceVertices();
|
||||
}
|
||||
|
||||
//printf("FVar refinement to level %d:\n", _childLevel.getDepth());
|
||||
//_childFVar.print();
|
||||
|
||||
//printf("Validating refinement to level %d:\n", _childLevel.getDepth());
|
||||
//_childFVar.validate();
|
||||
//assert(_childFVar.validate());
|
||||
}
|
||||
|
||||
//
|
||||
// Quickly estimate the memory required for face-varying vertex-values in the child
|
||||
// and allocate them. For uniform refinement this estimate should exactly match the
|
||||
// desired result. For sparse refinement the excess should generally be low as the
|
||||
// sparse boundary components generally occur where face-varying data is continuous.
|
||||
//
|
||||
void
|
||||
FVarRefinement::estimateAndAllocateChildValues() {
|
||||
|
||||
int maxVertexValueCount = _refinement.getNumChildVerticesFromFaces();
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromEdges();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromEdges();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
Index pEdge = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
maxVertexValueCount += _parentFVar.edgeTopologyMatches(pEdge)
|
||||
? 1 : _parentLevel.getEdgeFaces(pEdge).size();
|
||||
}
|
||||
|
||||
cVert = _refinement.getFirstChildVertexFromVertices();
|
||||
cVertEnd = cVert + _refinement.getNumChildVerticesFromVertices();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
assert(_refinement.isChildVertexComplete(cVert));
|
||||
Index pVert = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
maxVertexValueCount += _parentFVar.getNumVertexValues(pVert);
|
||||
}
|
||||
|
||||
//
|
||||
// Now allocate/initialize for the maximum -- use resize() and trim the size later
|
||||
// to avoid the constant growing with reserve() and incremental sizing. We know
|
||||
// the estimate should be close and memory wasted should be small, so initialize
|
||||
// all to zero as well to avoid writing in all but affected areas:
|
||||
//
|
||||
// Resize vectors that mirror the component counts:
|
||||
_childFVar.resizeComponents();
|
||||
|
||||
// Resize the vertex-value tags in the child level:
|
||||
_childFVar._vertValueTags.resize(maxVertexValueCount);
|
||||
|
||||
// Resize the vertex-value "parent source" mapping in the refinement:
|
||||
_childValueParentSource.resize(maxVertexValueCount, 0);
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::trimAndFinalizeChildValues() {
|
||||
|
||||
_childFVar._vertValueTags.resize(_childFVar._valueCount);
|
||||
if (_childFVar.hasSmoothBoundaries()) {
|
||||
_childFVar._vertValueCreaseEnds.resize(_childFVar._valueCount);
|
||||
}
|
||||
|
||||
_childValueParentSource.resize(_childFVar._valueCount);
|
||||
|
||||
// Allocate and initialize the vector of indices (redundant after level 0):
|
||||
_childFVar._vertValueIndices.resize(_childFVar._valueCount);
|
||||
for (int i = 0; i < _childFVar._valueCount; ++i) {
|
||||
_childFVar._vertValueIndices[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
inline int
|
||||
FVarRefinement::populateChildValuesForEdgeVertex(Index cVert, Index pEdge) {
|
||||
|
||||
//
|
||||
// Determine the number of sibling values for the child vertex of this discts
|
||||
// edge and populate their related topological data (e.g. source face).
|
||||
//
|
||||
// This turns out to be very simple. For FVar refinement to handle all cases
|
||||
// of non-manifold edges, when an edge is discts we generate a FVar value for
|
||||
// each face incident the edge. So in the uniform refinement case we will
|
||||
// have as many child values as parent faces incident the edge. But even when
|
||||
// refinement is sparse, if this edge-vertex is not complete, we will still be
|
||||
// guaranteed that a child face exists for each parent face since one of the
|
||||
// edge's end vertices must be complete and therefore include all child faces.
|
||||
//
|
||||
ConstIndexArray pEdgeFaces = _parentLevel.getEdgeFaces(pEdge);
|
||||
if (pEdgeFaces.size() == 1) {
|
||||
// No sibling so the first face (0) guaranteed to be a source and all
|
||||
// sibling indices per incident face will also be 0 -- all of which was
|
||||
// done on initialization, so nothing further to do.
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the parent-source of all child values:
|
||||
//
|
||||
int cValueCount = pEdgeFaces.size();
|
||||
Index cValueOffset = _childFVar.getVertexValueOffset(cVert);
|
||||
|
||||
for (int i = 0; i < cValueCount; ++i) {
|
||||
_childValueParentSource[cValueOffset + i] = (LocalIndex) i;
|
||||
}
|
||||
|
||||
//
|
||||
// Update the vertex-face siblings for the faces incident the child vertex:
|
||||
//
|
||||
ConstIndexArray cVertFaces = _childLevel.getVertexFaces(cVert);
|
||||
FVarLevel::SiblingArray cVertFaceSiblings = _childFVar.getVertexFaceSiblings(cVert);
|
||||
|
||||
assert(cVertFaces.size() == cVertFaceSiblings.size());
|
||||
assert(cVertFaces.size() >= cValueCount);
|
||||
|
||||
for (int i = 0; i < cVertFaceSiblings.size(); ++i) {
|
||||
Index pFaceI = _refinement.getChildFaceParentFace(cVertFaces[i]);
|
||||
if (pEdgeFaces.size() == 2) {
|
||||
// Only two parent faces and all siblings previously initialized to 0:
|
||||
if (pFaceI == pEdgeFaces[1]) {
|
||||
cVertFaceSiblings[i] = (LocalIndex) 1;
|
||||
}
|
||||
} else {
|
||||
// Non-manifold case with > 2 parent faces -- match child faces to parent:
|
||||
for (int j = 0; j < pEdgeFaces.size(); ++j) {
|
||||
if (pFaceI == pEdgeFaces[j]) {
|
||||
cVertFaceSiblings[i] = (LocalIndex) j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cValueCount;
|
||||
}
|
||||
|
||||
inline int
|
||||
FVarRefinement::populateChildValuesForVertexVertex(Index cVert, Index pVert) {
|
||||
|
||||
//
|
||||
// We should not be getting incomplete vertex-vertices from feature-adaptive
|
||||
// refinement (as neighboring vertices will be face-vertices or edge-vertices).
|
||||
// This will get messy when we do (i.e. sparse refinement of Bilinear or more
|
||||
// flexible and specific sparse refinement of Catmark) but for now assume 1-to-1.
|
||||
//
|
||||
assert(_refinement.isChildVertexComplete(cVert));
|
||||
|
||||
// Number of child values is same as number of parent values since complete:
|
||||
int cValueCount = _parentFVar.getNumVertexValues(pVert);
|
||||
|
||||
if (cValueCount > 1) {
|
||||
Index cValueIndex = _childFVar.getVertexValueOffset(cVert);
|
||||
|
||||
// Update the parent source for all child values:
|
||||
for (int j = 1; j < cValueCount; ++j) {
|
||||
_childValueParentSource[cValueIndex + j] = (LocalIndex) j;
|
||||
}
|
||||
|
||||
// Update the vertex-face siblings:
|
||||
FVarLevel::ConstSiblingArray pVertFaceSiblings = _parentFVar.getVertexFaceSiblings(pVert);
|
||||
FVarLevel::SiblingArray cVertFaceSiblings = _childFVar.getVertexFaceSiblings(cVert);
|
||||
for (int j = 0; j < cVertFaceSiblings.size(); ++j) {
|
||||
cVertFaceSiblings[j] = pVertFaceSiblings[j];
|
||||
}
|
||||
}
|
||||
return cValueCount;
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::populateChildValues() {
|
||||
|
||||
//
|
||||
// Be sure to match the same vertex ordering as Refinement, i.e. face-vertices
|
||||
// first vs vertex-vertices first, etc. A few optimizations within the use of
|
||||
// face-varying data take advantage of this assumption, and it just makes sense
|
||||
// to be consistent (e.g. if there is a 1-to-1 correspondence between vertices
|
||||
// and their FVar-values, their children will correspond).
|
||||
//
|
||||
_childFVar._valueCount = 0;
|
||||
|
||||
if (_refinement.hasFaceVerticesFirst()) {
|
||||
populateChildValuesFromFaceVertices();
|
||||
populateChildValuesFromEdgeVertices();
|
||||
populateChildValuesFromVertexVertices();
|
||||
} else {
|
||||
populateChildValuesFromVertexVertices();
|
||||
populateChildValuesFromFaceVertices();
|
||||
populateChildValuesFromEdgeVertices();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::populateChildValuesFromFaceVertices() {
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromFaces();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromFaces();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
_childFVar._vertSiblingOffsets[cVert] = _childFVar._valueCount;
|
||||
_childFVar._vertSiblingCounts[cVert] = 1;
|
||||
_childFVar._valueCount ++;
|
||||
}
|
||||
}
|
||||
void
|
||||
FVarRefinement::populateChildValuesFromEdgeVertices() {
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromEdges();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromEdges();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
Index pEdge = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
_childFVar._vertSiblingOffsets[cVert] = _childFVar._valueCount;
|
||||
if (_parentFVar.edgeTopologyMatches(pEdge)) {
|
||||
_childFVar._vertSiblingCounts[cVert] = 1;
|
||||
_childFVar._valueCount ++;
|
||||
} else {
|
||||
int cValueCount = populateChildValuesForEdgeVertex(cVert, pEdge);
|
||||
_childFVar._vertSiblingCounts[cVert] = (LocalIndex)cValueCount;
|
||||
_childFVar._valueCount += cValueCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
FVarRefinement::populateChildValuesFromVertexVertices() {
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromVertices();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromVertices();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
Index pVert = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
_childFVar._vertSiblingOffsets[cVert] = _childFVar._valueCount;
|
||||
if (_parentFVar.valueTopologyMatches(_parentFVar.getVertexValueOffset(pVert))) {
|
||||
_childFVar._vertSiblingCounts[cVert] = 1;
|
||||
_childFVar._valueCount ++;
|
||||
} else {
|
||||
int cValueCount = populateChildValuesForVertexVertex(cVert, pVert);
|
||||
_childFVar._vertSiblingCounts[cVert] = (LocalIndex)cValueCount;
|
||||
_childFVar._valueCount += cValueCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::propagateEdgeTags() {
|
||||
|
||||
//
|
||||
// Edge tags correspond to child edges and originate from faces or edges:
|
||||
// Face-edges:
|
||||
// - tag can be initialized as cts (*)
|
||||
// * what was this comment: "discts based on parent face-edges at ends"
|
||||
// Edge-edges:
|
||||
// - tag propagated from parent edge
|
||||
// - need to modify if parent edge was discts at one end
|
||||
// - child edge for the matching end inherits tag
|
||||
// - child edge at the other end is doubly discts
|
||||
//
|
||||
FVarLevel::ETag eTagMatch;
|
||||
eTagMatch.clear();
|
||||
eTagMatch._mismatch = false;
|
||||
|
||||
for (int eIndex = 0; eIndex < _refinement.getNumChildEdgesFromFaces(); ++eIndex) {
|
||||
_childFVar._edgeTags[eIndex] = eTagMatch;
|
||||
}
|
||||
for (int eIndex = _refinement.getNumChildEdgesFromFaces(); eIndex < _childLevel.getNumEdges(); ++eIndex) {
|
||||
Index pEdge = _refinement.getChildEdgeParentIndex(eIndex);
|
||||
|
||||
_childFVar._edgeTags[eIndex] = _parentFVar._edgeTags[pEdge];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::propagateValueTags() {
|
||||
|
||||
//
|
||||
// Value tags correspond to vertex-values and originate from all three sources:
|
||||
// Face-values:
|
||||
// - trivially initialized as matching
|
||||
// Edge-values:
|
||||
// - conditionally initialized based on parent edge continuity
|
||||
// - should be trivial though (unlike edge-tags for the child edges)
|
||||
// Vertex-values:
|
||||
// - if complete, trivially propagated/inherited
|
||||
// - if incomplete, need to map to child subset
|
||||
//
|
||||
|
||||
//
|
||||
// Values from face-vertices -- all match and are sequential:
|
||||
//
|
||||
FVarLevel::ValueTag valTagMatch;
|
||||
valTagMatch.clear();
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromFaces();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromFaces();
|
||||
Index cVertValue = _childFVar.getVertexValueOffset(cVert);
|
||||
for ( ; cVert < cVertEnd; ++cVert, ++cVertValue) {
|
||||
_childFVar._vertValueTags[cVertValue] = valTagMatch;
|
||||
}
|
||||
|
||||
//
|
||||
// Values from edge-vertices -- for edges that are split, tag as mismatched and tag
|
||||
// as corner or crease depending on the presence of creases in the parent:
|
||||
//
|
||||
FVarLevel::ValueTag valTagMismatch = valTagMatch;
|
||||
valTagMismatch._mismatch = true;
|
||||
|
||||
FVarLevel::ValueTag valTagCrease = valTagMismatch;
|
||||
valTagCrease._crease = true;
|
||||
|
||||
FVarLevel::ValueTag& valTagSplitEdge = _parentFVar.hasSmoothBoundaries() ? valTagCrease : valTagMismatch;
|
||||
|
||||
cVert = _refinement.getFirstChildVertexFromEdges();
|
||||
cVertEnd = cVert + _refinement.getNumChildVerticesFromEdges();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
Index pEdge = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
FVarLevel::ValueTagArray cValueTags = _childFVar.getVertexValueTags(cVert);
|
||||
|
||||
FVarLevel::ETag pEdgeTag = _parentFVar._edgeTags[pEdge];
|
||||
if (pEdgeTag._mismatch || pEdgeTag._linear) {
|
||||
std::fill(cValueTags.begin(), cValueTags.end(), valTagSplitEdge);
|
||||
} else {
|
||||
std::fill(cValueTags.begin(), cValueTags.end(), valTagMatch);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Values from vertex-vertices -- inherit tags from parent values when complete
|
||||
// otherwise (not yet supported) need to identify the parent value for each child:
|
||||
//
|
||||
cVert = _refinement.getFirstChildVertexFromVertices();
|
||||
cVertEnd = cVert + _refinement.getNumChildVerticesFromVertices();
|
||||
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
Index pVert = _refinement.getChildVertexParentIndex(cVert);
|
||||
assert(_refinement.isChildVertexComplete(cVert));
|
||||
|
||||
FVarLevel::ConstValueTagArray pValueTags = _parentFVar.getVertexValueTags(pVert);
|
||||
FVarLevel::ValueTagArray cValueTags = _childFVar.getVertexValueTags(cVert);
|
||||
|
||||
memcpy(cValueTags.begin(), pValueTags.begin(),
|
||||
pValueTags.size()*sizeof(FVarLevel::ValueTag));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::propagateValueCreases() {
|
||||
|
||||
assert(_childFVar.hasSmoothBoundaries());
|
||||
|
||||
// Skip child vertices from faces:
|
||||
|
||||
//
|
||||
// For each child vertex from an edge that has FVar values and is complete, initialize
|
||||
// the crease-ends for those values tagged as smooth boundaries
|
||||
//
|
||||
// Note that this does depend on the nature of the topological split, i.e. how many
|
||||
// child faces are incident the new child vertex for each face that becomes a crease,
|
||||
// so identify constants to be used in each iteration first:
|
||||
//
|
||||
int incChildFacesPerEdge = (_refinement.getRegularFaceSize() == 4) ? 2 : 3;
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromEdges();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromEdges();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
FVarLevel::ValueTagArray cValueTags = _childFVar.getVertexValueTags(cVert);
|
||||
|
||||
if (!cValueTags[0].isMismatch()) continue;
|
||||
if (!_refinement.isChildVertexComplete(cVert)) continue;
|
||||
|
||||
FVarLevel::CreaseEndPairArray cValueCreaseEnds = _childFVar.getVertexValueCreaseEnds(cVert);
|
||||
|
||||
int creaseStartFace = 0;
|
||||
int creaseEndFace = creaseStartFace + incChildFacesPerEdge - 1;
|
||||
|
||||
for (int i = 0; i < cValueTags.size(); ++i) {
|
||||
if (!cValueTags[i].isInfSharp()) {
|
||||
cValueCreaseEnds[i]._startFace = (LocalIndex) creaseStartFace;
|
||||
cValueCreaseEnds[i]._endFace = (LocalIndex) creaseEndFace;
|
||||
}
|
||||
creaseStartFace += incChildFacesPerEdge;
|
||||
creaseEndFace += incChildFacesPerEdge;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// For each child vertex from a vertex that has FVar values and is complete, initialize
|
||||
// the crease-ends for those values tagged as smooth or semi-sharp (to become smooth
|
||||
// eventually):
|
||||
//
|
||||
cVert = _refinement.getFirstChildVertexFromVertices();
|
||||
cVertEnd = cVert + _refinement.getNumChildVerticesFromVertices();
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
FVarLevel::ValueTagArray cValueTags = _childFVar.getVertexValueTags(cVert);
|
||||
|
||||
if (!cValueTags[0].isMismatch()) continue;
|
||||
if (!_refinement.isChildVertexComplete(cVert)) continue;
|
||||
|
||||
Index pVert = _refinement.getChildVertexParentIndex(cVert);
|
||||
|
||||
FVarLevel::ConstCreaseEndPairArray pCreaseEnds = _parentFVar.getVertexValueCreaseEnds(pVert);
|
||||
FVarLevel::CreaseEndPairArray cCreaseEnds = _childFVar.getVertexValueCreaseEnds(cVert);
|
||||
|
||||
for (int j = 0; j < cValueTags.size(); ++j) {
|
||||
if (!cValueTags[j].isInfSharp()) {
|
||||
cCreaseEnds[j] = pCreaseEnds[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FVarRefinement::reclassifySemisharpValues() {
|
||||
|
||||
//
|
||||
// Reclassify the tags of semi-sharp vertex values to smooth creases according to
|
||||
// changes in sharpness:
|
||||
//
|
||||
// Vertex values introduced on edge-verts can never be semi-sharp as they will be
|
||||
// introduced on discts edges, which are implicitly infinitely sharp, so we can
|
||||
// skip them entirely.
|
||||
//
|
||||
// So we just need to deal with those values descended from parent vertices that
|
||||
// were semi-sharp. The child values will have inherited the semi-sharp tag from
|
||||
// their parent values -- we will be able to clear it in many simple cases but
|
||||
// ultimately will need to inspect each value:
|
||||
//
|
||||
bool hasDependentSharpness = _parentFVar._hasDependentSharpness;
|
||||
|
||||
internal::StackBuffer<Index,16> cVertEdgeBuffer(_childLevel.getMaxValence());
|
||||
|
||||
Index cVert = _refinement.getFirstChildVertexFromVertices();
|
||||
Index cVertEnd = cVert + _refinement.getNumChildVerticesFromVertices();
|
||||
|
||||
for ( ; cVert < cVertEnd; ++cVert) {
|
||||
FVarLevel::ValueTagArray cValueTags = _childFVar.getVertexValueTags(cVert);
|
||||
|
||||
if (!cValueTags[0].isMismatch()) continue;
|
||||
if (!_refinement.isChildVertexComplete(cVert)) continue;
|
||||
|
||||
// If the parent vertex wasn't semi-sharp, the child vertex and values can't be:
|
||||
Index pVert = _refinement.getChildVertexParentIndex(cVert);
|
||||
Level::VTag pVertTags = _parentLevel.getVertexTag(pVert);
|
||||
|
||||
if (!pVertTags._semiSharp && !pVertTags._semiSharpEdges) continue;
|
||||
|
||||
// If the child vertex is still sharp, all values remain unaffected:
|
||||
Level::VTag cVertTags = _childLevel.getVertexTag(cVert);
|
||||
|
||||
if (cVertTags._semiSharp || cVertTags._infSharp) continue;
|
||||
|
||||
// If the child is no longer semi-sharp, we can just clear those values marked
|
||||
// (i.e. make them creases, others may remain corners) and continue:
|
||||
//
|
||||
if (!cVertTags._semiSharp && !cVertTags._semiSharpEdges) {
|
||||
for (int j = 0; j < cValueTags.size(); ++j) {
|
||||
if (cValueTags[j]._semiSharp) {
|
||||
cValueTags[j]._semiSharp = false;
|
||||
cValueTags[j]._depSharp = false;
|
||||
cValueTags[j]._crease = true;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// There are some semi-sharp edges left -- for those values tagged as semi-sharp,
|
||||
// see if they are still semi-sharp and clear those that are not:
|
||||
//
|
||||
FVarLevel::CreaseEndPairArray const cValueCreaseEnds = _childFVar.getVertexValueCreaseEnds(cVert);
|
||||
|
||||
// Beware accessing the child's vert-edges -- full topology may not be enabled:
|
||||
ConstIndexArray cVertEdges;
|
||||
if (_childLevel.getNumVertexEdgesTotal()) {
|
||||
cVertEdges = _childLevel.getVertexEdges(cVert);
|
||||
} else {
|
||||
ConstIndexArray pVertEdges = _parentLevel.getVertexEdges(pVert);
|
||||
ConstLocalIndexArray pVertInEdge = _parentLevel.getVertexEdgeLocalIndices(pVert);
|
||||
for (int i = 0; i < pVertEdges.size(); ++i) {
|
||||
cVertEdgeBuffer[i] = _refinement.getEdgeChildEdges(pVertEdges[i])[pVertInEdge[i]];
|
||||
}
|
||||
cVertEdges = IndexArray(cVertEdgeBuffer, pVertEdges.size());
|
||||
}
|
||||
|
||||
for (int j = 0; j < cValueTags.size(); ++j) {
|
||||
if (cValueTags[j]._semiSharp && !cValueTags[j]._depSharp) {
|
||||
LocalIndex vStartFace = cValueCreaseEnds[j]._startFace;
|
||||
LocalIndex vEndFace = cValueCreaseEnds[j]._endFace;
|
||||
|
||||
bool isStillSemiSharp = false;
|
||||
if (vEndFace > vStartFace) {
|
||||
for (int k = vStartFace + 1; !isStillSemiSharp && (k <= vEndFace); ++k) {
|
||||
isStillSemiSharp = _childLevel.getEdgeTag(cVertEdges[k])._semiSharp;
|
||||
}
|
||||
} else if (vStartFace > vEndFace) {
|
||||
for (int k = vStartFace + 1; !isStillSemiSharp && (k < cVertEdges.size()); ++k) {
|
||||
isStillSemiSharp = _childLevel.getEdgeTag(cVertEdges[k])._semiSharp;
|
||||
}
|
||||
for (int k = 0; !isStillSemiSharp && (k <= vEndFace); ++k) {
|
||||
isStillSemiSharp = _childLevel.getEdgeTag(cVertEdges[k])._semiSharp;
|
||||
}
|
||||
}
|
||||
if (!isStillSemiSharp) {
|
||||
cValueTags[j]._semiSharp = false;
|
||||
cValueTags[j]._depSharp = false;
|
||||
cValueTags[j]._crease = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now account for "dependent sharpness" (only matters when we have two values) --
|
||||
// if one value was dependent/sharpened based on the other, clear the dependency
|
||||
// tag if it is no longer sharp:
|
||||
//
|
||||
if ((cValueTags.size() == 2) && hasDependentSharpness) {
|
||||
if (cValueTags[0]._depSharp && !cValueTags[1]._semiSharp) {
|
||||
cValueTags[0]._depSharp = false;
|
||||
} else if (cValueTags[1]._depSharp && !cValueTags[0]._semiSharp) {
|
||||
cValueTags[1]._depSharp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
FVarRefinement::getFractionalWeight(Index pVert, LocalIndex pSibling,
|
||||
Index cVert, LocalIndex /* cSibling */) const {
|
||||
|
||||
//
|
||||
// Need to identify sharpness values for edges within the spans for both the
|
||||
// parent and child...
|
||||
//
|
||||
// Consider gathering the complete parent and child sharpness vectors outside
|
||||
// this method and re-using them for each sibling, i.e. passing them to this
|
||||
// method somehow. We may also need them there for mask-related purposes...
|
||||
//
|
||||
internal::StackBuffer<Index,16> cVertEdgeBuffer;
|
||||
|
||||
ConstIndexArray pVertEdges = _parentLevel.getVertexEdges(pVert);
|
||||
ConstIndexArray cVertEdges;
|
||||
|
||||
// Beware accessing the child's vert-edges -- full topology may not be enabled:
|
||||
if (_childLevel.getNumVertexEdgesTotal()) {
|
||||
cVertEdges = _childLevel.getVertexEdges(cVert);
|
||||
} else {
|
||||
cVertEdgeBuffer.SetSize(pVertEdges.size());
|
||||
|
||||
ConstLocalIndexArray pVertInEdge = _parentLevel.getVertexEdgeLocalIndices(pVert);
|
||||
for (int i = 0; i < pVertEdges.size(); ++i) {
|
||||
cVertEdgeBuffer[i] = _refinement.getEdgeChildEdges(pVertEdges[i])[pVertInEdge[i]];
|
||||
}
|
||||
cVertEdges = IndexArray(cVertEdgeBuffer, pVertEdges.size());
|
||||
}
|
||||
|
||||
internal::StackBuffer<float,32> sharpnessBuffer(2 * pVertEdges.size());
|
||||
float * pEdgeSharpness = sharpnessBuffer;
|
||||
float * cEdgeSharpness = sharpnessBuffer + pVertEdges.size();
|
||||
|
||||
FVarLevel::CreaseEndPair pValueCreaseEnds = _parentFVar.getVertexValueCreaseEnds(pVert)[pSibling];
|
||||
|
||||
LocalIndex pStartFace = pValueCreaseEnds._startFace;
|
||||
LocalIndex pEndFace = pValueCreaseEnds._endFace;
|
||||
|
||||
int interiorEdgeCount = 0;
|
||||
if (pEndFace > pStartFace) {
|
||||
for (int i = pStartFace + 1; i <= pEndFace; ++i, ++interiorEdgeCount) {
|
||||
pEdgeSharpness[interiorEdgeCount] = _parentLevel.getEdgeSharpness(pVertEdges[i]);
|
||||
cEdgeSharpness[interiorEdgeCount] = _childLevel.getEdgeSharpness(cVertEdges[i]);
|
||||
}
|
||||
} else if (pStartFace > pEndFace) {
|
||||
for (int i = pStartFace + 1; i < pVertEdges.size(); ++i, ++interiorEdgeCount) {
|
||||
pEdgeSharpness[interiorEdgeCount] = _parentLevel.getEdgeSharpness(pVertEdges[i]);
|
||||
cEdgeSharpness[interiorEdgeCount] = _childLevel.getEdgeSharpness(cVertEdges[i]);
|
||||
}
|
||||
for (int i = 0; i <= pEndFace; ++i, ++interiorEdgeCount) {
|
||||
pEdgeSharpness[interiorEdgeCount] = _parentLevel.getEdgeSharpness(pVertEdges[i]);
|
||||
cEdgeSharpness[interiorEdgeCount] = _childLevel.getEdgeSharpness(cVertEdges[i]);
|
||||
}
|
||||
}
|
||||
return Sdc::Crease(_refinement.getOptions()).ComputeFractionalWeightAtVertex(
|
||||
_parentLevel.getVertexSharpness(pVert), _childLevel.getVertexSharpness(cVert),
|
||||
interiorEdgeCount, pEdgeSharpness, cEdgeSharpness);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
100
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarRefinement.h
vendored
Normal file
100
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/fvarRefinement.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_FVAR_REFINEMENT_H
|
||||
#define OPENSUBDIV3_VTR_FVAR_REFINEMENT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/crease.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/refinement.h"
|
||||
#include "../vtr/fvarLevel.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// FVarRefinement:
|
||||
// A face-varying refinement contains data to support the refinement of a
|
||||
// particular face-varying "channel". Just as Refinement maintains a mapping
|
||||
// between the components of a parent Level and its child, the face-varying
|
||||
// analog maintains a mapping between the face-varying values of a parent
|
||||
// FVarLevel and its child.
|
||||
//
|
||||
// It turns out there is little data necessary here, so the class consists
|
||||
// mainly of methods that populate the child FVarLevel. The mapping data in
|
||||
// the refinement between Levels serves most purposes and all that is required
|
||||
// in addition is a mapping from values in the child FVarLevel to the parent.
|
||||
//
|
||||
class FVarRefinement {
|
||||
public:
|
||||
FVarRefinement(Refinement const& refinement, FVarLevel& parent, FVarLevel& child);
|
||||
~FVarRefinement();
|
||||
|
||||
int getChildValueParentSource(Index vIndex, int sibling) const {
|
||||
return _childValueParentSource[_childFVar.getVertexValueOffset(vIndex, (LocalIndex)sibling)];
|
||||
}
|
||||
|
||||
float getFractionalWeight(Index pVert, LocalIndex pSibling,
|
||||
Index cVert, LocalIndex cSibling) const;
|
||||
|
||||
|
||||
// Modifiers supporting application of the refinement:
|
||||
void applyRefinement();
|
||||
|
||||
void estimateAndAllocateChildValues();
|
||||
void populateChildValues();
|
||||
void populateChildValuesFromFaceVertices();
|
||||
void populateChildValuesFromEdgeVertices();
|
||||
int populateChildValuesForEdgeVertex(Index cVert, Index pEdge);
|
||||
void populateChildValuesFromVertexVertices();
|
||||
int populateChildValuesForVertexVertex(Index cVert, Index pVert);
|
||||
void trimAndFinalizeChildValues();
|
||||
|
||||
void propagateEdgeTags();
|
||||
void propagateValueTags();
|
||||
void propagateValueCreases();
|
||||
void reclassifySemisharpValues();
|
||||
|
||||
private:
|
||||
//
|
||||
// Identify the Refinement, its Levels and assigned FVarLevels for more
|
||||
// immediate access -- child FVarLevel is non-const as it is to be assigned:
|
||||
//
|
||||
Refinement const & _refinement;
|
||||
|
||||
Level const & _parentLevel;
|
||||
FVarLevel const & _parentFVar;
|
||||
|
||||
Level const & _childLevel;
|
||||
FVarLevel & _childFVar;
|
||||
|
||||
// When refinement is sparse, we need a mapping between siblings of a vertex
|
||||
// value in the parent and child -- and for some child values, there will not
|
||||
// be a parent value, in which case the source of the parent component will
|
||||
// be stored. So we refer to the parent "source" rather than "sibling":
|
||||
//
|
||||
std::vector<LocalIndex> _childValueParentSource;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_FVAR_REFINEMENT_H */
|
||||
2142
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/level.cpp
vendored
Normal file
2142
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/level.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
863
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/level.h
vendored
Normal file
863
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/level.h
vendored
Normal file
@@ -0,0 +1,863 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_LEVEL_H
|
||||
#define OPENSUBDIV3_VTR_LEVEL_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.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 {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
class Refinement;
|
||||
class TriRefinement;
|
||||
class QuadRefinement;
|
||||
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).
|
||||
//
|
||||
// This class is intended for private use within the library. There are still
|
||||
// opportunities to specialize levels -- e.g. those supporting N-sided faces vs
|
||||
// those that are purely quads or tris -- so we prefer to insulate it from public
|
||||
// access.
|
||||
//
|
||||
// The representation 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
|
||||
// representation, 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.
|
||||
//
|
||||
|
||||
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 sharpness values are reduced at each
|
||||
// level.
|
||||
//
|
||||
struct VTag {
|
||||
VTag() { }
|
||||
|
||||
// When cleared, the VTag ALMOST represents a smooth, regular, interior
|
||||
// vertex -- the Type enum requires a bit be explicitly set for Smooth,
|
||||
// so that must be done explicitly if desired on initialization.
|
||||
void clear() { std::memset((void*) this, 0, sizeof(VTag)); }
|
||||
|
||||
typedef unsigned short VTagSize;
|
||||
|
||||
VTagSize _nonManifold : 1; // fixed
|
||||
VTagSize _xordinary : 1; // fixed
|
||||
VTagSize _boundary : 1; // fixed
|
||||
VTagSize _corner : 1; // fixed
|
||||
VTagSize _infSharp : 1; // fixed
|
||||
VTagSize _semiSharp : 1; // variable
|
||||
VTagSize _semiSharpEdges : 1; // variable
|
||||
VTagSize _rule : 4; // variable when _semiSharp
|
||||
|
||||
// These next to tags are complementary -- the "incomplete" tag is only
|
||||
// relevant for refined levels while the "incident an irregular face" tag
|
||||
// is only relevant for the base level. They could be combined as both
|
||||
// indicate "no full regular ring" around a vertex
|
||||
VTagSize _incomplete : 1; // variable only set in refined levels
|
||||
VTagSize _incidIrregFace : 1; // variable only set in base level
|
||||
|
||||
// Tags indicating incident infinitely-sharp (permanent) features
|
||||
VTagSize _infSharpEdges : 1; // fixed
|
||||
VTagSize _infSharpCrease : 1; // fixed
|
||||
VTagSize _infIrregular : 1; // fixed
|
||||
|
||||
// Alternate constructor and accessor for dealing with integer bits directly:
|
||||
explicit VTag(VTagSize bits) {
|
||||
std::memcpy(this, &bits, sizeof(bits));
|
||||
}
|
||||
VTagSize getBits() const {
|
||||
VTagSize bits;
|
||||
std::memcpy(&bits, this, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
|
||||
static VTag BitwiseOr(VTag const vTags[], int size = 4);
|
||||
};
|
||||
struct ETag {
|
||||
ETag() { }
|
||||
|
||||
// When cleared, the ETag represents a smooth, manifold, interior edge
|
||||
void clear() { std::memset((void*) this, 0, sizeof(ETag)); }
|
||||
|
||||
typedef unsigned char ETagSize;
|
||||
|
||||
ETagSize _nonManifold : 1; // fixed
|
||||
ETagSize _boundary : 1; // fixed
|
||||
ETagSize _infSharp : 1; // fixed
|
||||
ETagSize _semiSharp : 1; // variable
|
||||
|
||||
// Alternate constructor and accessor for dealing with integer bits directly:
|
||||
explicit ETag(ETagSize bits) {
|
||||
std::memcpy(this, &bits, sizeof(bits));
|
||||
}
|
||||
ETagSize getBits() const {
|
||||
ETagSize bits;
|
||||
std::memcpy(&bits, this, sizeof(bits));
|
||||
return bits;
|
||||
}
|
||||
|
||||
static ETag BitwiseOr(ETag const eTags[], int size = 4);
|
||||
};
|
||||
struct FTag {
|
||||
FTag() { }
|
||||
|
||||
void clear() { std::memset((void*) this, 0, sizeof(FTag)); }
|
||||
|
||||
typedef unsigned char FTagSize;
|
||||
|
||||
FTagSize _hole : 1; // fixed
|
||||
|
||||
// On deck -- coming soon...
|
||||
//FTagSize _hasEdits : 1; // variable
|
||||
};
|
||||
|
||||
// Additional simple struct to identify a "span" around a vertex, i.e. a
|
||||
// subset of the faces around a vertex delimited by some property (e.g. a
|
||||
// face-varying discontinuity, an inf-sharp edge, etc.)
|
||||
//
|
||||
// The span requires an "origin" and a "size" to fully define its extent.
|
||||
// Use of the size is required over a leading/trailing pair as the valence
|
||||
// around a non-manifold vertex cannot be trivially determined from two
|
||||
// extremeties. Similarly a start face is chosen over an edge as starting
|
||||
// with a manifold edge is ambiguous. Additional tags also support
|
||||
// non-manifold cases, e.g. periodic spans at the apex of a double cone.
|
||||
//
|
||||
// Currently setting the size to 0 or leaving the span "unassigned" is an
|
||||
// indication to use the full neighborhood rather than a subset -- prefer
|
||||
// use of the const method here to direct inspection of the member.
|
||||
//
|
||||
struct VSpan {
|
||||
VSpan() { std::memset((void*) this, 0, sizeof(VSpan)); }
|
||||
|
||||
void clear() { std::memset((void*) this, 0, sizeof(VSpan)); }
|
||||
bool isAssigned() const { return _numFaces > 0; }
|
||||
|
||||
LocalIndex _numFaces;
|
||||
LocalIndex _startFace;
|
||||
LocalIndex _cornerInSpan;
|
||||
|
||||
unsigned short _periodic : 1;
|
||||
unsigned short _sharp : 1;
|
||||
};
|
||||
|
||||
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
|
||||
// (i.e. those where a component is "contained by" a neighbor, or more generally
|
||||
// when the neighbor is a simplex of higher dimension) 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
|
||||
// use 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 getEdgeFaceLocalIndices(Index edgeIndex) 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 setFaceHole(Index faceIndex, bool b);
|
||||
bool isFaceHole(Index faceIndex) const;
|
||||
|
||||
// Face-varying
|
||||
Sdc::Options getFVarOptions(int channel) const;
|
||||
int getNumFVarChannels() const { return (int) _fvarChannels.size(); }
|
||||
int getNumFVarValues(int channel) const;
|
||||
ConstIndexArray getFaceFVarValues(Index faceIndex, int channel) const;
|
||||
|
||||
FVarLevel & getFVarLevel(int channel) { return *_fvarChannels[channel]; }
|
||||
FVarLevel const & getFVarLevel(int channel) const { return *_fvarChannels[channel]; }
|
||||
|
||||
// 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;
|
||||
|
||||
// General access to all component tags:
|
||||
VTag const & getVertexTag(Index vertIndex) const { return _vertTags[vertIndex]; }
|
||||
ETag const & getEdgeTag(Index edgeIndex) const { return _edgeTags[edgeIndex]; }
|
||||
FTag const & getFaceTag(Index faceIndex) const { return _faceTags[faceIndex]; }
|
||||
|
||||
VTag & getVertexTag(Index vertIndex) { return _vertTags[vertIndex]; }
|
||||
ETag & getEdgeTag(Index edgeIndex) { return _edgeTags[edgeIndex]; }
|
||||
FTag & getFaceTag(Index faceIndex) { return _faceTags[faceIndex]; }
|
||||
|
||||
public:
|
||||
|
||||
// Debugging aides:
|
||||
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 may be moved elsewhere:
|
||||
|
||||
bool isSingleCreasePatch(Index face, float* sharpnessOut=NULL, int* rotationOut=NULL) const;
|
||||
|
||||
//
|
||||
// When inspecting topology, the component tags -- particularly VTag and ETag -- are most
|
||||
// often inspected in groups for the face to which they belong. They are designed to be
|
||||
// bitwise OR'd (the result then referred to as a "composite" tag) to make quick decisions
|
||||
// about the face as a whole to avoid tedious topological inspection.
|
||||
//
|
||||
// The same logic can be applied to topology in a FVar channel when tags specific to that
|
||||
// channel are used. Note that the VTags apply to the FVar values assigned to the corners
|
||||
// of the face and not the vertex as a whole. The "composite" face-varying VTag for a
|
||||
// vertex is the union of VTags of all distinct FVar values for that vertex.
|
||||
//
|
||||
bool doesVertexFVarTopologyMatch(Index vIndex, int fvarChannel) const;
|
||||
bool doesFaceFVarTopologyMatch( Index fIndex, int fvarChannel) const;
|
||||
bool doesEdgeFVarTopologyMatch( Index eIndex, int fvarChannel) const;
|
||||
|
||||
void getFaceVTags(Index fIndex, VTag vTags[], int fvarChannel = -1) const;
|
||||
void getFaceETags(Index fIndex, ETag eTags[], int fvarChannel = -1) const;
|
||||
|
||||
VTag getFaceCompositeVTag(Index fIndex, int fvarChannel = -1) const;
|
||||
VTag getFaceCompositeVTag(ConstIndexArray & fVerts) const;
|
||||
|
||||
VTag getVertexCompositeFVarVTag(Index vIndex, int fvarChannel) const;
|
||||
|
||||
//
|
||||
// When gathering "patch points" we may want the indices of the vertices or the corresponding
|
||||
// FVar values for a particular channel. Both are represented and equally accessible within
|
||||
// the faces, so we allow all to be returned through these methods. Setting the optional FVar
|
||||
// channel to -1 will retrieve indices of vertices instead of FVar values:
|
||||
//
|
||||
int gatherQuadLinearPatchPoints(Index fIndex, Index patchPoints[], int rotation = 0,
|
||||
int fvarChannel = -1) const;
|
||||
|
||||
int gatherQuadRegularInteriorPatchPoints(Index fIndex, Index patchPoints[], int rotation = 0,
|
||||
int fvarChannel = -1) const;
|
||||
int gatherQuadRegularBoundaryPatchPoints(Index fIndex, Index patchPoints[], int boundaryEdgeInFace,
|
||||
int fvarChannel = -1) const;
|
||||
int gatherQuadRegularCornerPatchPoints( Index fIndex, Index patchPoints[], int cornerVertInFace,
|
||||
int fvarChannel = -1) const;
|
||||
|
||||
int gatherQuadRegularRingAroundVertex(Index vIndex, Index ringPoints[],
|
||||
int fvarChannel = -1) const;
|
||||
int gatherQuadRegularPartialRingAroundVertex(Index vIndex, VSpan const & span, Index ringPoints[],
|
||||
int fvarChannel = -1) const;
|
||||
|
||||
// WIP -- for future use, need to extend for face-varying...
|
||||
int gatherTriRegularInteriorPatchPoints( Index fIndex, Index patchVerts[], int rotation = 0) const;
|
||||
int gatherTriRegularBoundaryVertexPatchPoints(Index fIndex, Index patchVerts[], int boundaryVertInFace) const;
|
||||
int gatherTriRegularBoundaryEdgePatchPoints( Index fIndex, Index patchVerts[], int boundaryEdgeInFace) const;
|
||||
int gatherTriRegularCornerVertexPatchPoints( Index fIndex, Index patchVerts[], int cornerVertInFace) const;
|
||||
int gatherTriRegularCornerEdgePatchPoints( Index fIndex, Index patchVerts[], int cornerEdgeInFace) const;
|
||||
|
||||
public:
|
||||
// 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);
|
||||
|
||||
void setMaxValence(int maxValence);
|
||||
|
||||
// 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);
|
||||
IndexArray getVertexEdges(Index vertIndex);
|
||||
|
||||
LocalIndexArray getEdgeFaceLocalIndices(Index edgeIndex);
|
||||
LocalIndexArray getVertexFaceLocalIndices(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);
|
||||
|
||||
IndexArray getFaceFVarValues(Index faceIndex, int channel);
|
||||
|
||||
void completeFVarChannelTopology(int channel, int regBoundaryValence);
|
||||
|
||||
// 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]; }
|
||||
|
||||
ConstIndexArray getFaceVertices() const;
|
||||
|
||||
//
|
||||
// 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);
|
||||
|
||||
public:
|
||||
//
|
||||
// Initial plans were to have a few specific classes properly construct the
|
||||
// topology from scratch, e.g. the Refinement class and a Factory class for
|
||||
// the base level, by populating all topological relations. The need to have
|
||||
// a class construct full topology given only a simple face-vertex list, made
|
||||
// it necessary to write code to define and orient all relations -- and most
|
||||
// of that seemed best placed here.
|
||||
//
|
||||
bool 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);
|
||||
bool testVertexNonManifoldCrease(Index vIndex) const;
|
||||
void populateLocalIndices();
|
||||
|
||||
IndexArray shareFaceVertCountsAndOffsets() const;
|
||||
|
||||
private:
|
||||
// Refinement classes (including all subclasses) build a Level:
|
||||
friend class Refinement;
|
||||
friend class TriRefinement;
|
||||
friend class QuadRefinement;
|
||||
|
||||
//
|
||||
// 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;
|
||||
|
||||
// The "depth" member is clearly useful in both the topological splitting and the
|
||||
// stencil queries, but arguably it ties the Level to a hierarchy which counters
|
||||
// the idea of it being independent.
|
||||
int _depth;
|
||||
|
||||
// Maxima to help clients manage sizing of data buffers. Given "max valence",
|
||||
// the "max edge faces" is strictly redundant as it will always be less, but
|
||||
// since it will typically be so much less (i.e. 2) it is kept for now.
|
||||
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<LocalIndex> _edgeFaceLocalIndices; // 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 incident 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) {
|
||||
|
||||
int* countOffsetPair = &_faceVertCountsAndOffsets[faceIndex*2];
|
||||
|
||||
countOffsetPair[0] = count;
|
||||
countOffsetPair[1] = (faceIndex == 0) ? 0 : (countOffsetPair[-2] + countOffsetPair[-1]);
|
||||
|
||||
_maxValence = std::max(_maxValence, count);
|
||||
}
|
||||
|
||||
inline ConstIndexArray
|
||||
Level::getFaceVertices() const {
|
||||
return ConstIndexArray(&_faceVertIndices[0], (int)_faceVertIndices.size());
|
||||
}
|
||||
|
||||
//
|
||||
// Access/modify the edges incident 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 incident a given vertex:
|
||||
//
|
||||
inline ConstIndexArray
|
||||
Level::getVertexFaces(Index vertIndex) const {
|
||||
return ConstIndexArray( (&_vertFaceIndices[0]) + _vertFaceCountsAndOffsets[vertIndex*2+1],
|
||||
_vertFaceCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
inline IndexArray
|
||||
Level::getVertexFaces(Index vertIndex) {
|
||||
return IndexArray( (&_vertFaceIndices[0]) + _vertFaceCountsAndOffsets[vertIndex*2+1],
|
||||
_vertFaceCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
|
||||
inline ConstLocalIndexArray
|
||||
Level::getVertexFaceLocalIndices(Index vertIndex) const {
|
||||
return ConstLocalIndexArray( (&_vertFaceLocalIndices[0]) + _vertFaceCountsAndOffsets[vertIndex*2+1],
|
||||
_vertFaceCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
inline LocalIndexArray
|
||||
Level::getVertexFaceLocalIndices(Index vertIndex) {
|
||||
return LocalIndexArray( (&_vertFaceLocalIndices[0]) + _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 incident a given vertex:
|
||||
//
|
||||
inline ConstIndexArray
|
||||
Level::getVertexEdges(Index vertIndex) const {
|
||||
return ConstIndexArray( (&_vertEdgeIndices[0]) +_vertEdgeCountsAndOffsets[vertIndex*2+1],
|
||||
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
inline IndexArray
|
||||
Level::getVertexEdges(Index vertIndex) {
|
||||
return IndexArray( (&_vertEdgeIndices[0]) +_vertEdgeCountsAndOffsets[vertIndex*2+1],
|
||||
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
|
||||
inline ConstLocalIndexArray
|
||||
Level::getVertexEdgeLocalIndices(Index vertIndex) const {
|
||||
return ConstLocalIndexArray( (&_vertEdgeLocalIndices[0]) + _vertEdgeCountsAndOffsets[vertIndex*2+1],
|
||||
_vertEdgeCountsAndOffsets[vertIndex*2]);
|
||||
}
|
||||
inline LocalIndexArray
|
||||
Level::getVertexEdgeLocalIndices(Index vertIndex) {
|
||||
return LocalIndexArray( (&_vertEdgeLocalIndices[0]) + _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;
|
||||
}
|
||||
|
||||
inline void
|
||||
Level::setMaxValence(int valence) {
|
||||
_maxValence = valence;
|
||||
}
|
||||
|
||||
//
|
||||
// Access/modify the vertices incident 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 incident a given edge:
|
||||
//
|
||||
inline ConstIndexArray
|
||||
Level::getEdgeFaces(Index edgeIndex) const {
|
||||
return ConstIndexArray(&_edgeFaceIndices[0] +
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2+1],
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2]);
|
||||
}
|
||||
inline IndexArray
|
||||
Level::getEdgeFaces(Index edgeIndex) {
|
||||
return IndexArray(&_edgeFaceIndices[0] +
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2+1],
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2]);
|
||||
}
|
||||
|
||||
inline ConstLocalIndexArray
|
||||
Level::getEdgeFaceLocalIndices(Index edgeIndex) const {
|
||||
return ConstLocalIndexArray(&_edgeFaceLocalIndices[0] +
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2+1],
|
||||
_edgeFaceCountsAndOffsets[edgeIndex*2]);
|
||||
}
|
||||
inline LocalIndexArray
|
||||
Level::getEdgeFaceLocalIndices(Index edgeIndex) {
|
||||
return LocalIndexArray(&_edgeFaceLocalIndices[0] +
|
||||
_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::setFaceHole(Index faceIndex, bool b) {
|
||||
_faceTags[faceIndex]._hole = b;
|
||||
}
|
||||
inline bool
|
||||
Level::isFaceHole(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((void*) &_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((void*) &_edgeTags[0], 0, _edgeCount * sizeof(ETag));
|
||||
}
|
||||
}
|
||||
inline void
|
||||
Level::resizeEdgeVertices() {
|
||||
|
||||
_edgeVertIndices.resize(2 * _edgeCount);
|
||||
}
|
||||
inline void
|
||||
Level::resizeEdgeFaces(int totalEdgeFaceCount) {
|
||||
|
||||
_edgeFaceIndices.resize(totalEdgeFaceCount);
|
||||
_edgeFaceLocalIndices.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((void*) &_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 internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_LEVEL_H */
|
||||
993
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/quadRefinement.cpp
vendored
Normal file
993
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/quadRefinement.cpp
vendored
Normal file
@@ -0,0 +1,993 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../sdc/crease.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/level.h"
|
||||
#include "../vtr/quadRefinement.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// Simple constructor, destructor and basic initializers:
|
||||
//
|
||||
QuadRefinement::QuadRefinement(Level const & parentArg, Level & childArg, Sdc::Options const & optionsArg) :
|
||||
Refinement(parentArg, childArg, optionsArg) {
|
||||
|
||||
_splitType = Sdc::SPLIT_TO_QUADS;
|
||||
_regFaceSize = 4;
|
||||
}
|
||||
|
||||
QuadRefinement::~QuadRefinement() {
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to construct the parent-to-child mapping
|
||||
//
|
||||
void
|
||||
QuadRefinement::allocateParentChildIndices() {
|
||||
|
||||
//
|
||||
// Initialize the vectors of indices mapping parent components to those child components
|
||||
// that will originate from each.
|
||||
//
|
||||
int faceChildFaceCount = (int) _parent->_faceVertIndices.size();
|
||||
int faceChildEdgeCount = (int) _parent->_faceEdgeIndices.size();
|
||||
int edgeChildEdgeCount = (int) _parent->_edgeVertIndices.size();
|
||||
|
||||
int faceChildVertCount = _parent->getNumFaces();
|
||||
int edgeChildVertCount = _parent->getNumEdges();
|
||||
int vertChildVertCount = _parent->getNumVertices();
|
||||
|
||||
//
|
||||
// First reference the parent Level's face-vertex counts/offsets -- they can be used
|
||||
// here for both the face-child-faces and face-child-edges as they both have one per
|
||||
// face-vertex.
|
||||
//
|
||||
// Given we will be ignoring initial values with uniform refinement and assigning all
|
||||
// directly, initializing here is a waste...
|
||||
//
|
||||
Index initValue = 0;
|
||||
|
||||
_faceChildFaceCountsAndOffsets = _parent->shareFaceVertCountsAndOffsets();
|
||||
_faceChildEdgeCountsAndOffsets = _parent->shareFaceVertCountsAndOffsets();
|
||||
|
||||
_faceChildFaceIndices.resize(faceChildFaceCount, initValue);
|
||||
_faceChildEdgeIndices.resize(faceChildEdgeCount, initValue);
|
||||
_edgeChildEdgeIndices.resize(edgeChildEdgeCount, initValue);
|
||||
|
||||
_faceChildVertIndex.resize(faceChildVertCount, initValue);
|
||||
_edgeChildVertIndex.resize(edgeChildVertCount, initValue);
|
||||
_vertChildVertIndex.resize(vertChildVertCount, initValue);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the face-vertex relation of the child Level:
|
||||
// - child faces only originate from parent faces
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateFaceVertexRelation() {
|
||||
|
||||
// Both face-vertex and face-edge share the face-vertex counts/offsets within a
|
||||
// Level, so be sure not to re-initialize it if already done:
|
||||
//
|
||||
if (_child->_faceVertCountsAndOffsets.size() == 0) {
|
||||
populateFaceVertexCountsAndOffsets();
|
||||
}
|
||||
_child->_faceVertIndices.resize(_child->getNumFaces() * 4);
|
||||
|
||||
populateFaceVerticesFromParentFaces();
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateFaceVertexCountsAndOffsets() {
|
||||
|
||||
_child->_faceVertCountsAndOffsets.resize(_child->getNumFaces() * 2);
|
||||
|
||||
for (int i = 0; i < _child->getNumFaces(); ++i) {
|
||||
_child->_faceVertCountsAndOffsets[i*2 + 0] = 4;
|
||||
_child->_faceVertCountsAndOffsets[i*2 + 1] = i << 2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateFaceVerticesFromParentFaces() {
|
||||
|
||||
//
|
||||
// This is pretty straightforward, but is a good example for the case of
|
||||
// iterating through the parent faces rather than the child faces, as the
|
||||
// same topology information for the parent faces is required for each of
|
||||
// the child faces.
|
||||
//
|
||||
// For each of the child faces of a parent face, identify the child vertices
|
||||
// for its face-verts from the child vertices of the parent face, its edges
|
||||
// and its vertices.
|
||||
//
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildren = getFaceChildFaces(pFace);
|
||||
|
||||
int pFaceSize = pFaceVerts.size();
|
||||
for (int j = 0; j < pFaceSize; ++j) {
|
||||
Index cFace = pFaceChildren[j];
|
||||
if (IndexIsValid(cFace)) {
|
||||
int jPrev = j ? (j - 1) : (pFaceSize - 1);
|
||||
|
||||
Index cVertOfFace = _faceChildVertIndex[pFace];
|
||||
Index cVertOfEPrev = _edgeChildVertIndex[pFaceEdges[jPrev]];
|
||||
Index cVertOfVert = _vertChildVertIndex[pFaceVerts[j]];
|
||||
Index cVertOfENext = _edgeChildVertIndex[pFaceEdges[j]];
|
||||
|
||||
IndexArray cFaceVerts = _child->getFaceVertices(cFace);
|
||||
|
||||
// Note orientation wrt parent face -- quad vs non-quad...
|
||||
if (pFaceSize == 4) {
|
||||
int jOpp = jPrev ? (jPrev - 1) : 3;
|
||||
int jNext = jOpp ? (jOpp - 1) : 3;
|
||||
|
||||
cFaceVerts[j] = cVertOfVert;
|
||||
cFaceVerts[jNext] = cVertOfENext;
|
||||
cFaceVerts[jOpp] = cVertOfFace;
|
||||
cFaceVerts[jPrev] = cVertOfEPrev;
|
||||
} else {
|
||||
cFaceVerts[0] = cVertOfVert;
|
||||
cFaceVerts[1] = cVertOfENext;
|
||||
cFaceVerts[2] = cVertOfFace;
|
||||
cFaceVerts[3] = cVertOfEPrev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the face-vertex relation of the child Level:
|
||||
// - child faces only originate from parent faces
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateFaceEdgeRelation() {
|
||||
|
||||
// Both face-vertex and face-edge share the face-vertex counts/offsets, so be sure
|
||||
// not to re-initialize it if already done:
|
||||
//
|
||||
if (_child->_faceVertCountsAndOffsets.size() == 0) {
|
||||
populateFaceVertexCountsAndOffsets();
|
||||
}
|
||||
_child->_faceEdgeIndices.resize(_child->getNumFaces() * 4);
|
||||
|
||||
populateFaceEdgesFromParentFaces();
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateFaceEdgesFromParentFaces() {
|
||||
|
||||
//
|
||||
// This is fairly straightforward, but since we are dealing with edges here, we
|
||||
// occasionally have to deal with the limitation of them being undirected. Since
|
||||
// child faces from the same parent face share much in common, we iterate through
|
||||
// the parent faces.
|
||||
//
|
||||
// Each child face of the parent is based on a corner vertex from which we denote
|
||||
// a "previous" and "next" edge, which are child edges of the parent face's edges.
|
||||
// The two remaining edges per child faces are perpendicular to these prev/next
|
||||
// edges and share the child vertex of the parent face.
|
||||
//
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildFaces = getFaceChildFaces(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
int pFaceSize = pFaceVerts.size();
|
||||
|
||||
for (int j = 0; j < pFaceSize; ++j) {
|
||||
Index cFace = pFaceChildFaces[j];
|
||||
if (IndexIsValid(cFace)) {
|
||||
//
|
||||
// Identify the vertex pairs for the prev/next parent edges -- from
|
||||
// which we will determine the prev/next child edges:
|
||||
//
|
||||
int jPrev = j ? (j - 1) : (pFaceSize - 1);
|
||||
|
||||
Index pPrevEdge = pFaceEdges[jPrev];
|
||||
ConstIndexArray pPrevEdgeVerts = _parent->getEdgeVertices(pPrevEdge);
|
||||
|
||||
Index pNextEdge = pFaceEdges[j];
|
||||
ConstIndexArray pNextEdgeVerts = _parent->getEdgeVertices(pNextEdge);
|
||||
|
||||
//
|
||||
// Now identify the two prev/next child edges (beware of degenerate
|
||||
// edges here) and the two remaining perpendicular child edges:
|
||||
//
|
||||
Index pCornerVert = pFaceVerts[j];
|
||||
|
||||
int cornerInPrevEdge = (pPrevEdgeVerts[0] != pPrevEdgeVerts[1])
|
||||
? (pPrevEdgeVerts[0] != pCornerVert) : 1;
|
||||
|
||||
int cornerInNextEdge = (pNextEdgeVerts[0] != pNextEdgeVerts[1])
|
||||
? (pNextEdgeVerts[0] != pCornerVert) : 0;
|
||||
|
||||
Index cEdgeOfEdgePrev = getEdgeChildEdges(pPrevEdge)[cornerInPrevEdge];
|
||||
Index cEdgeOfEdgeNext = getEdgeChildEdges(pNextEdge)[cornerInNextEdge];
|
||||
|
||||
Index cEdgePerpEdgePrev = pFaceChildEdges[jPrev];
|
||||
Index cEdgePerpEdgeNext = pFaceChildEdges[j];
|
||||
|
||||
//
|
||||
// Assign the identified child edges to the child face's face-edges:
|
||||
//
|
||||
IndexArray cFaceEdges = _child->getFaceEdges(cFace);
|
||||
|
||||
// Note orientation wrt parent face -- quad vs non-quad...
|
||||
if (pFaceSize == 4) {
|
||||
int jOpp = jPrev ? (jPrev - 1) : 3;
|
||||
int jNext = jOpp ? (jOpp - 1) : 3;
|
||||
|
||||
cFaceEdges[j] = cEdgeOfEdgeNext;
|
||||
cFaceEdges[jNext] = cEdgePerpEdgeNext;
|
||||
cFaceEdges[jOpp] = cEdgePerpEdgePrev;
|
||||
cFaceEdges[jPrev] = cEdgeOfEdgePrev;
|
||||
} else {
|
||||
cFaceEdges[0] = cEdgeOfEdgeNext;
|
||||
cFaceEdges[1] = cEdgePerpEdgeNext;
|
||||
cFaceEdges[2] = cEdgePerpEdgePrev;
|
||||
cFaceEdges[3] = cEdgeOfEdgePrev;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods to populate the edge-vertex relation of the child Level:
|
||||
// - child edges originate from parent faces and edges
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateEdgeVertexRelation() {
|
||||
|
||||
_child->_edgeVertIndices.resize(_child->getNumEdges() * 2);
|
||||
|
||||
populateEdgeVerticesFromParentFaces();
|
||||
populateEdgeVerticesFromParentEdges();
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateEdgeVerticesFromParentFaces() {
|
||||
|
||||
//
|
||||
// This is straightforward. All child edges of parent faces are assigned
|
||||
// their first vertex from the child vertex of the face -- so it is common
|
||||
// to all. The second vertex is the child vertex of the parent edge to
|
||||
// which the new child edge is perpendicular.
|
||||
//
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
for (int j = 0; j < pFaceEdges.size(); ++j) {
|
||||
Index cEdge = pFaceChildEdges[j];
|
||||
if (IndexIsValid(cEdge)) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(cEdge);
|
||||
|
||||
cEdgeVerts[0] = _faceChildVertIndex[pFace];
|
||||
cEdgeVerts[1] = _edgeChildVertIndex[pFaceEdges[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateEdgeVerticesFromParentEdges() {
|
||||
|
||||
//
|
||||
// This is straightforward. All child edges of parent edges are assigned
|
||||
// their first vertex from the child vertex of the edge -- so it is common
|
||||
// to both. The second vertex is the child vertex of the vertex at the
|
||||
// end of the parent edge.
|
||||
//
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge),
|
||||
pEdgeChildren = getEdgeChildEdges(pEdge);
|
||||
|
||||
// May want to unroll this trivial loop of 2...
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
Index cEdge = pEdgeChildren[j];
|
||||
if (IndexIsValid(cEdge)) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(cEdge);
|
||||
|
||||
cEdgeVerts[0] = _edgeChildVertIndex[pEdge];
|
||||
cEdgeVerts[1] = _vertChildVertIndex[pEdgeVerts[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods to populate the edge-face relation of the child Level:
|
||||
// - child edges originate from parent faces and edges
|
||||
// - sparse refinement poses challenges with allocation here
|
||||
// - we need to update the counts/offsets as we populate
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateEdgeFaceRelation() {
|
||||
|
||||
//
|
||||
// Notes on allocating/initializing the edge-face counts/offsets vector:
|
||||
//
|
||||
// Be aware of scheme-specific decisions here, e.g.:
|
||||
// - inspection of sparse child faces for edges from faces
|
||||
// - no guaranteed "neighborhood" around Bilinear verts from verts
|
||||
//
|
||||
// If uniform subdivision, face count of a child edge will be:
|
||||
// - 2 for new interior edges from parent faces
|
||||
// == 2 * number of parent face verts for both quad- and tri-split
|
||||
// - same as parent edge for edges from parent edges
|
||||
// If sparse subdivision, face count of a child edge will be:
|
||||
// - 1 or 2 for new interior edge depending on child faces in parent face
|
||||
// - requires inspection if not all child faces present
|
||||
// ? same as parent edge for edges from parent edges
|
||||
// - given end vertex must have its full set of child faces
|
||||
// - not for Bilinear -- only if neighborhood is non-zero
|
||||
// - could at least make a quick traversal of components and use the above
|
||||
// two points to get much closer estimate than what is used for uniform
|
||||
//
|
||||
int childEdgeFaceIndexSizeEstimate = (int)_parent->_faceVertIndices.size() * 2 +
|
||||
(int)_parent->_edgeFaceIndices.size() * 2;
|
||||
|
||||
_child->_edgeFaceCountsAndOffsets.resize(_child->getNumEdges() * 2);
|
||||
_child->_edgeFaceIndices.resize( childEdgeFaceIndexSizeEstimate);
|
||||
_child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
|
||||
// Update _maxEdgeFaces from the parent level before calling the
|
||||
// populateEdgeFacesFromParent methods below, as these may further
|
||||
// update _maxEdgeFaces.
|
||||
_child->_maxEdgeFaces = _parent->_maxEdgeFaces;
|
||||
|
||||
populateEdgeFacesFromParentFaces();
|
||||
populateEdgeFacesFromParentEdges();
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vector accordingly:
|
||||
childEdgeFaceIndexSizeEstimate = _child->getNumEdgeFaces(_child->getNumEdges()-1) +
|
||||
_child->getOffsetOfEdgeFaces(_child->getNumEdges()-1);
|
||||
_child->_edgeFaceIndices.resize( childEdgeFaceIndexSizeEstimate);
|
||||
_child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateEdgeFacesFromParentFaces() {
|
||||
|
||||
//
|
||||
// This is straightforward topologically, but when refinement is sparse the
|
||||
// contents of the counts/offsets vector is not certain and is populated
|
||||
// incrementally. So there will be some resizing/trimming here.
|
||||
//
|
||||
// Topologically, the child edges from within a parent face will typically
|
||||
// have two incident child faces (only one or none if sparse). These child
|
||||
// edges and faces are interleaved within the parent and easily identified.
|
||||
// Note that the edge-face "local indices" are also needed here and that
|
||||
// orientation of child faces within their parent depends on it being a quad
|
||||
// or not.
|
||||
//
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceChildFaces = getFaceChildFaces(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
int pFaceSize = pFaceChildFaces.size();
|
||||
|
||||
for (int j = 0; j < pFaceSize; ++j) {
|
||||
Index cEdge = pFaceChildEdges[j];
|
||||
if (IndexIsValid(cEdge)) {
|
||||
//
|
||||
// Reserve enough edge-faces, populate and trim as needed:
|
||||
//
|
||||
_child->resizeEdgeFaces(cEdge, 2);
|
||||
|
||||
IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge);
|
||||
LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge);
|
||||
|
||||
// One or two child faces may be assigned:
|
||||
int jNext = ((j + 1) < pFaceSize) ? (j + 1) : 0;
|
||||
|
||||
int cEdgeFaceCount = 0;
|
||||
if (IndexIsValid(pFaceChildFaces[j])) {
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cEdgeFaces[cEdgeFaceCount] = pFaceChildFaces[j];
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex)((pFaceSize == 4) ? jNext : 1);
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
if (IndexIsValid(pFaceChildFaces[jNext])) {
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cEdgeFaces[cEdgeFaceCount] = pFaceChildFaces[jNext];
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex)((pFaceSize == 4) ? ((jNext + 2) & 3) : 2);
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
_child->trimEdgeFaces(cEdge, cEdgeFaceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateEdgeFacesFromParentEdges() {
|
||||
|
||||
//
|
||||
// Note -- the edge-face counts/offsets vector is not known
|
||||
// ahead of time and is populated incrementally, so we cannot
|
||||
// thread this yet...
|
||||
//
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
ConstIndexArray pEdgeChildEdges = getEdgeChildEdges(pEdge);
|
||||
if (!IndexIsValid(pEdgeChildEdges[0]) && !IndexIsValid(pEdgeChildEdges[1])) continue;
|
||||
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge);
|
||||
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
Index cEdge = pEdgeChildEdges[j];
|
||||
if (!IndexIsValid(cEdge)) continue;
|
||||
|
||||
// Reserve enough edge-faces, populate and trim as needed:
|
||||
_child->resizeEdgeFaces(cEdge, pEdgeFaces.size());
|
||||
|
||||
IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge);
|
||||
LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge);
|
||||
|
||||
//
|
||||
// Each parent face may contribute an incident child face:
|
||||
//
|
||||
int cEdgeFaceCount = 0;
|
||||
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceChildren = getFaceChildFaces(pFace);
|
||||
|
||||
//
|
||||
// We need to first identify the potentially incident child-face and see
|
||||
// if it exists before we can assign it. Beware a degenerate edge here
|
||||
// when inspecting the undirected edge.
|
||||
//
|
||||
int childOfEdge = (pEdgeVerts[0] == pEdgeVerts[1]) ? j : (pFaceVerts[edgeInFace] != pEdgeVerts[j]);
|
||||
|
||||
int childInFace = edgeInFace + childOfEdge;
|
||||
if (childInFace == pFaceChildren.size()) childInFace = 0;
|
||||
|
||||
if (IndexIsValid(pFaceChildren[childInFace])) {
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cEdgeFaces[cEdgeFaceCount] = pFaceChildren[childInFace];
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex)
|
||||
((pFaceVerts.size() == 4) ? edgeInFace : (childOfEdge ? 3 : 0));
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimEdgeFaces(cEdge, cEdgeFaceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the vertex-face relation of the child Level:
|
||||
// - child vertices originate from parent faces, edges and vertices
|
||||
// - sparse refinement poses challenges with allocation here:
|
||||
// - we need to update the counts/offsets as we populate
|
||||
// - note this imposes ordering constraints and inhibits concurrency
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateVertexFaceRelation() {
|
||||
|
||||
//
|
||||
// Notes on allocating/initializing the vertex-face counts/offsets vector:
|
||||
//
|
||||
// Be aware of scheme-specific decisions here, e.g.:
|
||||
// - no verts from parent faces for Loop (unless N-gons supported)
|
||||
// - more interior edges and faces for verts from parent edges for Loop
|
||||
// - no guaranteed "neighborhood" around Bilinear verts from verts
|
||||
//
|
||||
// If uniform subdivision, vert-face count will be (catmark or loop):
|
||||
// - 4 or 0 for verts from parent faces (for catmark)
|
||||
// - 2x or 3x number in parent edge for verts from parent edges
|
||||
// - same as parent vert for verts from parent verts
|
||||
// If sparse subdivision, vert-face count will be:
|
||||
// - the number of child faces in parent face
|
||||
// - 1 or 2x number in parent edge for verts from parent edges
|
||||
// - where the 1 or 2 is number of child edges of parent edge
|
||||
// - same as parent vert for verts from parent verts (catmark)
|
||||
//
|
||||
int childVertFaceIndexSizeEstimate = (int)_parent->_faceVertIndices.size()
|
||||
+ (int)_parent->_edgeFaceIndices.size() * 2
|
||||
+ (int)_parent->_vertFaceIndices.size();
|
||||
|
||||
_child->_vertFaceCountsAndOffsets.resize(_child->getNumVertices() * 2);
|
||||
_child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
_child->_vertFaceLocalIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
|
||||
if (getFirstChildVertexFromVertices() == 0) {
|
||||
populateVertexFacesFromParentVertices();
|
||||
populateVertexFacesFromParentFaces();
|
||||
populateVertexFacesFromParentEdges();
|
||||
} else {
|
||||
populateVertexFacesFromParentFaces();
|
||||
populateVertexFacesFromParentEdges();
|
||||
populateVertexFacesFromParentVertices();
|
||||
}
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vectors accordingly:
|
||||
childVertFaceIndexSizeEstimate = _child->getNumVertexFaces(_child->getNumVertices()-1) +
|
||||
_child->getOffsetOfVertexFaces(_child->getNumVertices()-1);
|
||||
_child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
_child->_vertFaceLocalIndices.resize(childVertFaceIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateVertexFacesFromParentFaces() {
|
||||
|
||||
for (int pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
int cVert = _faceChildVertIndex[pFace];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pFaceChildren = getFaceChildFaces(pFace);
|
||||
int pFaceSize = pFaceChildren.size();
|
||||
|
||||
//
|
||||
// Reserve enough vert-faces, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexFaces(cVert, pFaceSize);
|
||||
|
||||
IndexArray cVertFaces = _child->getVertexFaces(cVert);
|
||||
LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// Inspect each of the child faces of this parent face and add those that
|
||||
// exist as incident the child vertex of this face:
|
||||
//
|
||||
int cVertFaceCount = 0;
|
||||
for (int j = 0; j < pFaceSize; ++j) {
|
||||
if (IndexIsValid(pFaceChildren[j])) {
|
||||
// Note orientation wrt parent face -- quad vs non-quad...
|
||||
cVertFaces[cVertFaceCount] = pFaceChildren[j];
|
||||
cVertInFace[cVertFaceCount] = (LocalIndex)((pFaceSize == 4) ? ((j+2) & 3) : 2);
|
||||
cVertFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexFaces(cVert, cVertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateVertexFacesFromParentEdges() {
|
||||
|
||||
for (int pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
int cVert = _edgeChildVertIndex[pEdge];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
|
||||
//
|
||||
// Reserve enough vert-faces, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexFaces(cVert, 2 * pEdgeFaces.size());
|
||||
|
||||
IndexArray cVertFaces = _child->getVertexFaces(cVert);
|
||||
LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// For each face incident the parent edge, identify its corresponding two child faces
|
||||
// and assign those of the two that exist. The second face is considered and added
|
||||
// first to preserve CC-wise ordering of faces wrt the vertex.
|
||||
//
|
||||
int cVertFaceCount = 0;
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
ConstIndexArray pFaceChildren = getFaceChildFaces(pFace);
|
||||
int pFaceSize = pFaceChildren.size();
|
||||
|
||||
int faceChild0 = edgeInFace;
|
||||
int faceChild1 = edgeInFace + 1;
|
||||
if (faceChild1 == pFaceChildren.size()) faceChild1 = 0;
|
||||
|
||||
if (IndexIsValid(pFaceChildren[faceChild1])) {
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cVertFaces[cVertFaceCount] = pFaceChildren[faceChild1];
|
||||
cVertInFace[cVertFaceCount] = (LocalIndex)((pFaceSize == 4) ? faceChild0 : 3);
|
||||
cVertFaceCount++;
|
||||
}
|
||||
if (IndexIsValid(pFaceChildren[faceChild0])) {
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cVertFaces[cVertFaceCount] = pFaceChildren[faceChild0];
|
||||
cVertInFace[cVertFaceCount] = (LocalIndex)((pFaceSize == 4) ? faceChild1 : 1);
|
||||
cVertFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexFaces(cVert, cVertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateVertexFacesFromParentVertices() {
|
||||
|
||||
for (int pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
|
||||
int cVert = _vertChildVertIndex[pVert];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pVertFaces = _parent->getVertexFaces(pVert);
|
||||
ConstLocalIndexArray pVertInFace = _parent->getVertexFaceLocalIndices(pVert);
|
||||
|
||||
//
|
||||
// Reserve enough vert-faces, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexFaces(cVert, pVertFaces.size());
|
||||
|
||||
IndexArray cVertFaces = _child->getVertexFaces(cVert);
|
||||
LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// Inspect each of the faces incident the parent vertex and add those that
|
||||
// spawned a child face corresponding to (and so incident) this child vertex:
|
||||
//
|
||||
int cVertFaceCount = 0;
|
||||
for (int i = 0; i < pVertFaces.size(); ++i) {
|
||||
Index pFace = pVertFaces[i];
|
||||
LocalIndex vertInFace = pVertInFace[i];
|
||||
|
||||
ConstIndexArray pFaceChildren = getFaceChildFaces(pFace);
|
||||
|
||||
if (IndexIsValid(pFaceChildren[vertInFace])) {
|
||||
int pFaceSize = pFaceChildren.size();
|
||||
|
||||
// Note orientation wrt incident parent faces -- quad vs non-quad...
|
||||
cVertFaces[cVertFaceCount] = pFaceChildren[vertInFace];
|
||||
cVertInFace[cVertFaceCount] = (LocalIndex)((pFaceSize == 4) ? vertInFace : 0);
|
||||
cVertFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexFaces(cVert, cVertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods to populate the vertex-edge relation of the child Level:
|
||||
// - child vertices originate from parent faces, edges and vertices
|
||||
// - sparse refinement poses challenges with allocation here:
|
||||
// - we need to update the counts/offsets as we populate
|
||||
// - note this imposes ordering constraints and inhibits concurrency
|
||||
//
|
||||
void
|
||||
QuadRefinement::populateVertexEdgeRelation() {
|
||||
|
||||
//
|
||||
// Notes on allocating/initializing the vertex-edge counts/offsets vector:
|
||||
//
|
||||
// Be aware of scheme-specific decisions here, e.g.:
|
||||
// - no verts from parent faces for Loop
|
||||
// - more interior edges and faces for verts from parent edges for Loop
|
||||
// - no guaranteed "neighborhood" around Bilinear verts from verts
|
||||
//
|
||||
// If uniform subdivision, vert-edge count will be:
|
||||
// - 4 or 0 for verts from parent faces (for catmark)
|
||||
// - 2 + N or 2 + 2*N faces incident parent edge for verts from parent edges
|
||||
// - same as parent vert for verts from parent verts
|
||||
// If sparse subdivision, vert-edge count will be:
|
||||
// - non-trivial function of child faces in parent face
|
||||
// - 1 child face will always result in 2 child edges
|
||||
// * 2 child faces can mean 3 or 4 child edges
|
||||
// - 3 child faces will always result in 4 child edges
|
||||
// - 1 or 2 + N faces incident parent edge for verts from parent edges
|
||||
// - where the 1 or 2 is number of child edges of parent edge
|
||||
// - any end vertex will require all N child faces (catmark)
|
||||
// - same as parent vert for verts from parent verts (catmark)
|
||||
//
|
||||
int childVertEdgeIndexSizeEstimate = (int)_parent->_faceVertIndices.size()
|
||||
+ (int)_parent->_edgeFaceIndices.size() + _parent->getNumEdges() * 2
|
||||
+ (int)_parent->_vertEdgeIndices.size();
|
||||
|
||||
_child->_vertEdgeCountsAndOffsets.resize(_child->getNumVertices() * 2);
|
||||
_child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
_child->_vertEdgeLocalIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
|
||||
if (getFirstChildVertexFromVertices() == 0) {
|
||||
populateVertexEdgesFromParentVertices();
|
||||
populateVertexEdgesFromParentFaces();
|
||||
populateVertexEdgesFromParentEdges();
|
||||
} else {
|
||||
populateVertexEdgesFromParentFaces();
|
||||
populateVertexEdgesFromParentEdges();
|
||||
populateVertexEdgesFromParentVertices();
|
||||
}
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vectors accordingly:
|
||||
childVertEdgeIndexSizeEstimate = _child->getNumVertexEdges(_child->getNumVertices()-1) +
|
||||
_child->getOffsetOfVertexEdges(_child->getNumVertices()-1);
|
||||
_child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
_child->_vertEdgeLocalIndices.resize(childVertEdgeIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::populateVertexEdgesFromParentFaces() {
|
||||
|
||||
for (int pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
int cVert = _faceChildVertIndex[pFace];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
//
|
||||
// Reserve enough vert-edges, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexEdges(cVert, pFaceVerts.size());
|
||||
|
||||
IndexArray cVertEdges = _child->getVertexEdges(cVert);
|
||||
LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// Need to ensure correct ordering here when complete -- we want the "leading"
|
||||
// edge of each child face first. The child vert is in the center of a new
|
||||
// face so new "boundaries" will only occur when the vertex is incomplete.
|
||||
//
|
||||
int cVertEdgeCount = 0;
|
||||
for (int j = 0; j < pFaceVerts.size(); ++j) {
|
||||
int jLeadingEdge = j ? (j - 1) : (pFaceVerts.size() - 1);
|
||||
if (IndexIsValid(pFaceChildEdges[jLeadingEdge])) {
|
||||
cVertEdges[cVertEdgeCount] = pFaceChildEdges[jLeadingEdge];
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexEdges(cVert, cVertEdgeCount);
|
||||
}
|
||||
}
|
||||
void
|
||||
QuadRefinement::populateVertexEdgesFromParentEdges() {
|
||||
|
||||
//
|
||||
// This relation turns out to be awkward to populate given the mixed parentage
|
||||
// of the incident edges of the child vertex of an edge -- two child edges
|
||||
// originate from the parent edge while one or more will originate from the
|
||||
// faces incident the parent edge. The need to interleave these for proper
|
||||
// CC-wise orientation is what really complicates this.
|
||||
//
|
||||
// Unlike other relations, we generate the results and then re-order them as
|
||||
// needed. In this case we assign the first two incident edges as the child
|
||||
// edges of the parent edge, followed then by those originating from a parent
|
||||
// face. We then swap the second and third (and possibly the first two) so
|
||||
// that we have the desired origin sequence beginning [edge, face, edge, ...]
|
||||
//
|
||||
for (int pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
int cVert = _edgeChildVertIndex[pEdge];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge),
|
||||
pEdgeChildEdges = getEdgeChildEdges(pEdge);
|
||||
|
||||
//
|
||||
// Reserve enough vert-edges, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexEdges(cVert, pEdgeFaces.size() + 2);
|
||||
|
||||
IndexArray cVertEdges = _child->getVertexEdges(cVert);
|
||||
LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// Identify and assign the first two child edges of the parent edge -- until
|
||||
// we look more closely at the orientation of the parent edge in the first
|
||||
// face we don't know what order these two should be in, so just assign them
|
||||
// for now and swap them later if necessary:
|
||||
//
|
||||
int cVertEdgeCount = 0;
|
||||
|
||||
if (IndexIsValid(pEdgeChildEdges[0])) {
|
||||
cVertEdges[cVertEdgeCount] = pEdgeChildEdges[0];
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
if (IndexIsValid(pEdgeChildEdges[1])) {
|
||||
cVertEdges[cVertEdgeCount] = pEdgeChildEdges[1];
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
|
||||
//
|
||||
// Append the interior edge of each incident parent face -- swapping the
|
||||
// first face-edge with the second edge-edge just added to get the desired
|
||||
// sequence of child edges originating from (edge, face0, edge, ...)
|
||||
//
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
Index cEdgeOfFace = getFaceChildEdges(pFace)[edgeInFace];
|
||||
|
||||
if (IndexIsValid(cEdgeOfFace)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdgeOfFace;
|
||||
cVertInEdge[cVertEdgeCount] = 1;
|
||||
cVertEdgeCount++;
|
||||
|
||||
// Check if swapping this first face-edge with the last edge-edge
|
||||
// is necessary:
|
||||
if ((i == 0) && (cVertEdgeCount == 3)) {
|
||||
// Remember to order the first of the two child edges according
|
||||
// to the parent edge's orientation in this first face:
|
||||
if ((pEdgeVerts[0] != pEdgeVerts[1]) &&
|
||||
(_parent->getFaceVertices(pFace)[edgeInFace] == pEdgeVerts[0])) {
|
||||
std::swap(cVertEdges[0], cVertEdges[1]);
|
||||
std::swap(cVertInEdge[0], cVertInEdge[1]);
|
||||
}
|
||||
std::swap(cVertEdges[1], cVertEdges[2]);
|
||||
std::swap(cVertInEdge[1], cVertInEdge[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
_child->trimVertexEdges(cVert, cVertEdgeCount);
|
||||
}
|
||||
}
|
||||
void
|
||||
QuadRefinement::populateVertexEdgesFromParentVertices() {
|
||||
|
||||
for (int pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
|
||||
int cVert = _vertChildVertIndex[pVert];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pVertEdges = _parent->getVertexEdges(pVert);
|
||||
ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert);
|
||||
|
||||
//
|
||||
// Reserve enough vert-edges, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexEdges(cVert, pVertEdges.size());
|
||||
|
||||
IndexArray cVertEdges = _child->getVertexEdges(cVert);
|
||||
LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert);
|
||||
|
||||
int cVertEdgeCount = 0;
|
||||
for (int i = 0; i < pVertEdges.size(); ++i) {
|
||||
Index pEdgeIndex = pVertEdges[i];
|
||||
LocalIndex pEdgeVert = pVertInEdge[i];
|
||||
|
||||
Index pEdgeChildIndex = getEdgeChildEdges(pEdgeIndex)[pEdgeVert];
|
||||
if (IndexIsValid(pEdgeChildIndex)) {
|
||||
cVertEdges[cVertEdgeCount] = pEdgeChildIndex;
|
||||
cVertInEdge[cVertEdgeCount] = 1;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexEdges(cVert, cVertEdgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods to populate child-component indices for sparse selection:
|
||||
//
|
||||
// Need to find a better place for these anon helper methods now that they are required
|
||||
// both in the base class and the two subclasses for quad- and tri-splitting...
|
||||
//
|
||||
namespace {
|
||||
Index const IndexSparseMaskNeighboring = (1 << 0);
|
||||
Index const IndexSparseMaskSelected = (1 << 1);
|
||||
|
||||
inline void markSparseIndexNeighbor(Index& index) { index = IndexSparseMaskNeighboring; }
|
||||
inline void markSparseIndexSelected(Index& index) { index = IndexSparseMaskSelected; }
|
||||
}
|
||||
|
||||
void
|
||||
QuadRefinement::markSparseFaceChildren() {
|
||||
|
||||
assert(_parentFaceTag.size() > 0);
|
||||
|
||||
//
|
||||
// For each parent face:
|
||||
// All boundary edges will be adequately marked as a result of the pass over the
|
||||
// edges above and boundary vertices marked by selection. So all that remains is to
|
||||
// identify the child faces and interior child edges for a face requiring neighboring
|
||||
// child faces.
|
||||
// For each corner vertex selected, we need to mark the corresponding child face,
|
||||
// the two interior child edges and shared child vertex in the middle.
|
||||
//
|
||||
assert(_splitType == Sdc::SPLIT_TO_QUADS);
|
||||
|
||||
for (Index pFace = 0; pFace < parent().getNumFaces(); ++pFace) {
|
||||
//
|
||||
// Mark all descending child components of a selected face. Otherwise inspect
|
||||
// its incident vertices to see if anything neighboring has been selected --
|
||||
// requiring partial refinement of this face.
|
||||
//
|
||||
// Remember that a selected face cannot be transitional, and that only a
|
||||
// transitional face will be partially refined.
|
||||
//
|
||||
IndexArray fChildFaces = getFaceChildFaces(pFace);
|
||||
IndexArray fChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
ConstIndexArray fVerts = parent().getFaceVertices(pFace);
|
||||
|
||||
SparseTag& pFaceTag = _parentFaceTag[pFace];
|
||||
|
||||
if (pFaceTag._selected) {
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
markSparseIndexSelected(fChildFaces[i]);
|
||||
markSparseIndexSelected(fChildEdges[i]);
|
||||
}
|
||||
markSparseIndexSelected(_faceChildVertIndex[pFace]);
|
||||
|
||||
pFaceTag._transitional = 0;
|
||||
} else {
|
||||
int marked = false;
|
||||
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
if (_parentVertexTag[fVerts[i]]._selected) {
|
||||
int iPrev = i ? (i - 1) : (fVerts.size() - 1);
|
||||
|
||||
markSparseIndexNeighbor(fChildFaces[i]);
|
||||
|
||||
markSparseIndexNeighbor(fChildEdges[i]);
|
||||
markSparseIndexNeighbor(fChildEdges[iPrev]);
|
||||
|
||||
marked = true;
|
||||
}
|
||||
}
|
||||
if (marked) {
|
||||
markSparseIndexNeighbor(_faceChildVertIndex[pFace]);
|
||||
|
||||
//
|
||||
// Assign selection and transitional tags to faces when required:
|
||||
//
|
||||
// Only non-selected faces may be "transitional", and we need to inspect
|
||||
// all tags on its boundary edges to be sure. Since we're inspecting each
|
||||
// now (and may need to later) retain the transitional state of each in a
|
||||
// 4-bit mask that reflects the full transitional topology for later.
|
||||
//
|
||||
ConstIndexArray fEdges = parent().getFaceEdges(pFace);
|
||||
if (fEdges.size() == 4) {
|
||||
pFaceTag._transitional = (unsigned char)
|
||||
((_parentEdgeTag[fEdges[0]]._transitional << 0) |
|
||||
(_parentEdgeTag[fEdges[1]]._transitional << 1) |
|
||||
(_parentEdgeTag[fEdges[2]]._transitional << 2) |
|
||||
(_parentEdgeTag[fEdges[3]]._transitional << 3));
|
||||
} else if (fEdges.size() == 3) {
|
||||
pFaceTag._transitional = (unsigned char)
|
||||
((_parentEdgeTag[fEdges[0]]._transitional << 0) |
|
||||
(_parentEdgeTag[fEdges[1]]._transitional << 1) |
|
||||
(_parentEdgeTag[fEdges[2]]._transitional << 2));
|
||||
} else {
|
||||
pFaceTag._transitional = 0;
|
||||
for (int i = 0; i < fEdges.size(); ++i) {
|
||||
pFaceTag._transitional |= _parentEdgeTag[fEdges[i]]._transitional;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
86
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/quadRefinement.h
vendored
Normal file
86
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/quadRefinement.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_QUAD_REFINEMENT_H
|
||||
#define OPENSUBDIV3_VTR_QUAD_REFINEMENT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/refinement.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// QuadRefinement:
|
||||
// A QuadRefinement is a subclass of Refinement that splits all faces into quads.
|
||||
// It provides the configuration of parent-to-child components and the population of
|
||||
// all required topological relations in order to complete a valid Refinement.
|
||||
//
|
||||
class QuadRefinement : public Refinement {
|
||||
|
||||
public:
|
||||
QuadRefinement(Level const & parent, Level & child, Sdc::Options const & options);
|
||||
~QuadRefinement();
|
||||
|
||||
protected:
|
||||
//
|
||||
// Virtual methods to complete the configuration of the parent-to-child mapping:
|
||||
//
|
||||
virtual void allocateParentChildIndices();
|
||||
|
||||
virtual void markSparseFaceChildren();
|
||||
|
||||
//
|
||||
// Virtual methods to populate the six topological relations:
|
||||
//
|
||||
virtual void populateFaceVertexRelation();
|
||||
virtual void populateFaceEdgeRelation();
|
||||
virtual void populateEdgeVertexRelation();
|
||||
virtual void populateEdgeFaceRelation();
|
||||
virtual void populateVertexFaceRelation();
|
||||
virtual void populateVertexEdgeRelation();
|
||||
|
||||
//
|
||||
// Internal helper methods for populating the topology:
|
||||
//
|
||||
void populateFaceVertexCountsAndOffsets();
|
||||
void populateFaceVerticesFromParentFaces();
|
||||
|
||||
void populateFaceEdgesFromParentFaces();
|
||||
|
||||
void populateEdgeVerticesFromParentFaces();
|
||||
void populateEdgeVerticesFromParentEdges();
|
||||
|
||||
void populateEdgeFacesFromParentFaces();
|
||||
void populateEdgeFacesFromParentEdges();
|
||||
|
||||
void populateVertexFacesFromParentFaces();
|
||||
void populateVertexFacesFromParentEdges();
|
||||
void populateVertexFacesFromParentVertices();
|
||||
|
||||
void populateVertexEdgesFromParentFaces();
|
||||
void populateVertexEdgesFromParentEdges();
|
||||
void populateVertexEdgesFromParentVertices();
|
||||
|
||||
private:
|
||||
//
|
||||
// Data members -- currently none
|
||||
//
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_REFINEMENT_H */
|
||||
1234
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/refinement.cpp
vendored
Normal file
1234
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/refinement.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
439
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/refinement.h
vendored
Normal file
439
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/refinement.h
vendored
Normal file
@@ -0,0 +1,439 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_REFINEMENT_H
|
||||
#define OPENSUBDIV3_VTR_REFINEMENT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/options.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
//
|
||||
// Declaration for the main refinement class (Refinement) and its pre-requisites:
|
||||
//
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
class FVarRefinement;
|
||||
|
||||
//
|
||||
// Refinement:
|
||||
// A refinement is a mapping between two levels -- relating the components in the original
|
||||
// (parent) level to the one refined (child). The refinement may be complete (uniform) or sparse
|
||||
// (adaptive or otherwise selective), so not all components in the parent level will spawn
|
||||
// components in the child level.
|
||||
//
|
||||
// Refinement is an abstract class and expects subclasses corresponding to the different types
|
||||
// of topological splits that the supported subdivision schemes collectively require, i.e. those
|
||||
// listed in Sdc::SplitType. Note the virtual requirements expected of the subclasses in the list
|
||||
// of protected methods -- they differ mainly in the topology that is created in the child Level
|
||||
// and not the propagation of tags through refinement, subdivision of sharpness values or the
|
||||
// treatment of face-varying data. The primary subclasses are QuadRefinement and TriRefinement.
|
||||
//
|
||||
// At a high level, all that is necessary in terms of interface is to construct, initialize
|
||||
// (linking the two levels), optionally select components for sparse refinement (via use of the
|
||||
// SparseSelector) and call the refine() method. This usage is expected of Far::TopologyRefiner.
|
||||
//
|
||||
// Since we really want this class to be restricted from public access eventually, all methods
|
||||
// begin with lower case (as is the convention for protected methods) and the list of friends
|
||||
// will be maintained more strictly.
|
||||
//
|
||||
class Refinement {
|
||||
|
||||
public:
|
||||
Refinement(Level const & parent, Level & child, Sdc::Options const& schemeOptions);
|
||||
virtual ~Refinement();
|
||||
|
||||
Level const& parent() const { return *_parent; }
|
||||
Level const& child() const { return *_child; }
|
||||
Level& child() { return *_child; }
|
||||
|
||||
Sdc::Split getSplitType() const { return _splitType; }
|
||||
int getRegularFaceSize() const { return _regFaceSize; }
|
||||
Sdc::Options getOptions() const { return _options; }
|
||||
|
||||
// Face-varying:
|
||||
int getNumFVarChannels() const { return (int) _fvarChannels.size(); }
|
||||
|
||||
FVarRefinement const & getFVarRefinement(int c) const { return *_fvarChannels[c]; }
|
||||
|
||||
//
|
||||
// Options associated with the actual refinement operation, which may end up
|
||||
// quite involved if we want to allow for the refinement of data that is not
|
||||
// of interest to be suppressed. For now we have:
|
||||
//
|
||||
// "sparse": the alternative to uniform refinement, which requires that
|
||||
// components be previously selected/marked to be included.
|
||||
//
|
||||
// "minimal topology": this is one that may get broken down into a finer
|
||||
// set of options. It suppresses "full topology" in the child level
|
||||
// and only generates what is minimally necessary for interpolation --
|
||||
// which requires at least the face-vertices for faces, but also the
|
||||
// vertex-faces for any face-varying channels present. So it will
|
||||
// generate one or two of the six possible topological relations.
|
||||
//
|
||||
// These are strictly controlled right now, e.g. for sparse refinement, we
|
||||
// currently enforce full topology at the finest level to allow for subsequent
|
||||
// patch construction.
|
||||
//
|
||||
struct Options {
|
||||
Options() : _sparse(false),
|
||||
_faceVertsFirst(false),
|
||||
_minimalTopology(false)
|
||||
{ }
|
||||
|
||||
unsigned int _sparse : 1;
|
||||
unsigned int _faceVertsFirst : 1;
|
||||
unsigned int _minimalTopology : 1;
|
||||
|
||||
// Still under consideration:
|
||||
//unsigned int _childToParentMap : 1;
|
||||
};
|
||||
|
||||
void refine(Options options = Options());
|
||||
|
||||
bool hasFaceVerticesFirst() const { return _faceVertsFirst; }
|
||||
|
||||
public:
|
||||
//
|
||||
// Access to members -- some testing classes (involving vertex interpolation)
|
||||
// currently make use of these:
|
||||
//
|
||||
int getNumChildFacesFromFaces() const { return _childFaceFromFaceCount; }
|
||||
int getNumChildEdgesFromFaces() const { return _childEdgeFromFaceCount; }
|
||||
int getNumChildEdgesFromEdges() const { return _childEdgeFromEdgeCount; }
|
||||
int getNumChildVerticesFromFaces() const { return _childVertFromFaceCount; }
|
||||
int getNumChildVerticesFromEdges() const { return _childVertFromEdgeCount; }
|
||||
int getNumChildVerticesFromVertices() const { return _childVertFromVertCount; }
|
||||
|
||||
Index getFirstChildFaceFromFaces() const { return _firstChildFaceFromFace; }
|
||||
Index getFirstChildEdgeFromFaces() const { return _firstChildEdgeFromFace; }
|
||||
Index getFirstChildEdgeFromEdges() const { return _firstChildEdgeFromEdge; }
|
||||
Index getFirstChildVertexFromFaces() const { return _firstChildVertFromFace; }
|
||||
Index getFirstChildVertexFromEdges() const { return _firstChildVertFromEdge; }
|
||||
Index getFirstChildVertexFromVertices() const { return _firstChildVertFromVert; }
|
||||
|
||||
Index getFaceChildVertex(Index f) const { return _faceChildVertIndex[f]; }
|
||||
Index getEdgeChildVertex(Index e) const { return _edgeChildVertIndex[e]; }
|
||||
Index getVertexChildVertex(Index v) const { return _vertChildVertIndex[v]; }
|
||||
|
||||
ConstIndexArray getFaceChildFaces(Index parentFace) const;
|
||||
ConstIndexArray getFaceChildEdges(Index parentFace) const;
|
||||
ConstIndexArray getEdgeChildEdges(Index parentEdge) const;
|
||||
|
||||
// Child-to-parent relationships
|
||||
bool isChildVertexComplete(Index v) const { return ! _childVertexTag[v]._incomplete; }
|
||||
|
||||
Index getChildFaceParentFace(Index f) const { return _childFaceParentIndex[f]; }
|
||||
int getChildFaceInParentFace(Index f) const { return _childFaceTag[f]._indexInParent; }
|
||||
|
||||
Index getChildEdgeParentIndex(Index e) const { return _childEdgeParentIndex[e]; }
|
||||
|
||||
Index getChildVertexParentIndex(Index v) const { return _childVertexParentIndex[v]; }
|
||||
|
||||
//
|
||||
// Modifiers intended for internal/protected use:
|
||||
//
|
||||
public:
|
||||
|
||||
IndexArray getFaceChildFaces(Index parentFace);
|
||||
IndexArray getFaceChildEdges(Index parentFace);
|
||||
IndexArray getEdgeChildEdges(Index parentEdge);
|
||||
|
||||
public:
|
||||
//
|
||||
// Tags have now been added per-component in Level, but there is additional need to tag
|
||||
// components within Refinement -- we can't tag the parent level components for any
|
||||
// refinement (in order to keep it const) and tags associated with children that are
|
||||
// specific to the child-to-parent mapping may not be warranted in the child level.
|
||||
//
|
||||
// Parent tags are only required for sparse refinement. The main property to tag is
|
||||
// whether a component was selected, and so a single SparseTag is used for all three
|
||||
// component types. Tagging if a component is "transitional" is also useful. This may
|
||||
// only be necessary for edges but is currently packed into a mask per-edge for faces,
|
||||
// which could be deferred, in which case "transitional" could be a single bit.
|
||||
//
|
||||
// Child tags are part of the child-to-parent mapping, which consists of the parent
|
||||
// component index for each child component, plus a tag for the child indicating more
|
||||
// about its relationship to its parent, e.g. is it completely defined, what the parent
|
||||
// component type is, what is the index of the child within its parent, etc.
|
||||
//
|
||||
struct SparseTag {
|
||||
SparseTag() : _selected(0), _transitional(0) { }
|
||||
|
||||
unsigned char _selected : 1; // component specifically selected for refinement
|
||||
unsigned char _transitional : 4; // adjacent to a refined component (4-bits for face)
|
||||
};
|
||||
|
||||
struct ChildTag {
|
||||
ChildTag() { }
|
||||
|
||||
unsigned char _incomplete : 1; // incomplete neighborhood to represent limit of parent
|
||||
unsigned char _parentType : 2; // type of parent component: vertex, edge or face
|
||||
unsigned char _indexInParent : 2; // index of child wrt parent: 0-3, or iterative if N > 4
|
||||
};
|
||||
|
||||
// Methods to access and modify tags:
|
||||
SparseTag const & getParentFaceSparseTag( Index f) const { return _parentFaceTag[f]; }
|
||||
SparseTag const & getParentEdgeSparseTag( Index e) const { return _parentEdgeTag[e]; }
|
||||
SparseTag const & getParentVertexSparseTag(Index v) const { return _parentVertexTag[v]; }
|
||||
|
||||
SparseTag & getParentFaceSparseTag( Index f) { return _parentFaceTag[f]; }
|
||||
SparseTag & getParentEdgeSparseTag( Index e) { return _parentEdgeTag[e]; }
|
||||
SparseTag & getParentVertexSparseTag(Index v) { return _parentVertexTag[v]; }
|
||||
|
||||
ChildTag const & getChildFaceTag( Index f) const { return _childFaceTag[f]; }
|
||||
ChildTag const & getChildEdgeTag( Index e) const { return _childEdgeTag[e]; }
|
||||
ChildTag const & getChildVertexTag(Index v) const { return _childVertexTag[v]; }
|
||||
|
||||
ChildTag & getChildFaceTag( Index f) { return _childFaceTag[f]; }
|
||||
ChildTag & getChildEdgeTag( Index e) { return _childEdgeTag[e]; }
|
||||
ChildTag & getChildVertexTag(Index v) { return _childVertexTag[v]; }
|
||||
|
||||
// Remaining methods should really be protected -- for use by subclasses...
|
||||
public:
|
||||
//
|
||||
// Methods involved in constructing the parent-to-child mapping -- when the
|
||||
// refinement is sparse, additional methods are needed to identify the selection:
|
||||
//
|
||||
void populateParentToChildMapping();
|
||||
void populateParentChildIndices();
|
||||
void printParentToChildMapping() const;
|
||||
|
||||
virtual void allocateParentChildIndices() = 0;
|
||||
|
||||
// Supporting method for sparse refinement:
|
||||
void initializeSparseSelectionTags();
|
||||
void markSparseChildComponentIndices();
|
||||
void markSparseVertexChildren();
|
||||
void markSparseEdgeChildren();
|
||||
|
||||
virtual void markSparseFaceChildren() = 0;
|
||||
|
||||
void initializeChildComponentCounts();
|
||||
|
||||
//
|
||||
// Methods involved in constructing the child-to-parent mapping:
|
||||
//
|
||||
void populateChildToParentMapping();
|
||||
|
||||
void populateFaceParentVectors(ChildTag const initialChildTags[2][4]);
|
||||
void populateFaceParentFromParentFaces(ChildTag const initialChildTags[2][4]);
|
||||
|
||||
void populateEdgeParentVectors(ChildTag const initialChildTags[2][4]);
|
||||
void populateEdgeParentFromParentFaces(ChildTag const initialChildTags[2][4]);
|
||||
void populateEdgeParentFromParentEdges(ChildTag const initialChildTags[2][4]);
|
||||
|
||||
void populateVertexParentVectors(ChildTag const initialChildTags[2][4]);
|
||||
void populateVertexParentFromParentFaces(ChildTag const initialChildTags[2][4]);
|
||||
void populateVertexParentFromParentEdges(ChildTag const initialChildTags[2][4]);
|
||||
void populateVertexParentFromParentVertices(ChildTag const initialChildTags[2][4]);
|
||||
|
||||
//
|
||||
// Methods involved in propagating component tags from parent to child:
|
||||
//
|
||||
void propagateComponentTags();
|
||||
|
||||
void populateFaceTagVectors();
|
||||
void populateFaceTagsFromParentFaces();
|
||||
|
||||
void populateEdgeTagVectors();
|
||||
void populateEdgeTagsFromParentFaces();
|
||||
void populateEdgeTagsFromParentEdges();
|
||||
|
||||
void populateVertexTagVectors();
|
||||
void populateVertexTagsFromParentFaces();
|
||||
void populateVertexTagsFromParentEdges();
|
||||
void populateVertexTagsFromParentVertices();
|
||||
|
||||
//
|
||||
// Methods (and types) involved in subdividing the topology -- though not
|
||||
// fully exploited, any subset of the 6 relations can be generated:
|
||||
//
|
||||
struct Relations {
|
||||
unsigned int _faceVertices : 1;
|
||||
unsigned int _faceEdges : 1;
|
||||
unsigned int _edgeVertices : 1;
|
||||
unsigned int _edgeFaces : 1;
|
||||
unsigned int _vertexFaces : 1;
|
||||
unsigned int _vertexEdges : 1;
|
||||
|
||||
void setAll(bool enable) {
|
||||
_faceVertices = enable;
|
||||
_faceEdges = enable;
|
||||
_edgeVertices = enable;
|
||||
_edgeFaces = enable;
|
||||
_vertexFaces = enable;
|
||||
_vertexEdges = enable;
|
||||
}
|
||||
};
|
||||
|
||||
void subdivideTopology(Relations const& relationsToSubdivide);
|
||||
|
||||
virtual void populateFaceVertexRelation() = 0;
|
||||
virtual void populateFaceEdgeRelation() = 0;
|
||||
virtual void populateEdgeVertexRelation() = 0;
|
||||
virtual void populateEdgeFaceRelation() = 0;
|
||||
virtual void populateVertexFaceRelation() = 0;
|
||||
virtual void populateVertexEdgeRelation() = 0;
|
||||
|
||||
//
|
||||
// Methods involved in subdividing and inspecting sharpness values:
|
||||
//
|
||||
void subdivideSharpnessValues();
|
||||
|
||||
void subdivideVertexSharpness();
|
||||
void subdivideEdgeSharpness();
|
||||
void reclassifySemisharpVertices();
|
||||
|
||||
//
|
||||
// Methods involved in subdividing face-varying topology:
|
||||
//
|
||||
void subdivideFVarChannels();
|
||||
|
||||
protected:
|
||||
// A debug method of Level prints a Refinement (should really change this)
|
||||
friend void Level::print(const Refinement *) const;
|
||||
|
||||
//
|
||||
// Data members -- the logical grouping of some of these (and methods that make use
|
||||
// of them) may lead to grouping them into a few utility classes or structs...
|
||||
//
|
||||
|
||||
// Defined on construction:
|
||||
Level const * _parent;
|
||||
Level * _child;
|
||||
Sdc::Options _options;
|
||||
|
||||
// Defined by the subclass:
|
||||
Sdc::Split _splitType;
|
||||
int _regFaceSize;
|
||||
|
||||
// Determined by the refinement options:
|
||||
bool _uniform;
|
||||
bool _faceVertsFirst;
|
||||
|
||||
//
|
||||
// Inventory and ordering of the types of child components:
|
||||
//
|
||||
int _childFaceFromFaceCount; // arguably redundant (all faces originate from faces)
|
||||
int _childEdgeFromFaceCount;
|
||||
int _childEdgeFromEdgeCount;
|
||||
int _childVertFromFaceCount;
|
||||
int _childVertFromEdgeCount;
|
||||
int _childVertFromVertCount;
|
||||
|
||||
int _firstChildFaceFromFace; // arguably redundant (all faces originate from faces)
|
||||
int _firstChildEdgeFromFace;
|
||||
int _firstChildEdgeFromEdge;
|
||||
int _firstChildVertFromFace;
|
||||
int _firstChildVertFromEdge;
|
||||
int _firstChildVertFromVert;
|
||||
|
||||
//
|
||||
// The parent-to-child mapping:
|
||||
// These are vectors sized according to the number of parent components (and
|
||||
// their topology) that contain references/indices to the child components that
|
||||
// result from them by refinement. When refinement is sparse, parent components
|
||||
// that have not spawned all child components will have their missing children
|
||||
// marked as invalid.
|
||||
//
|
||||
// NOTE the "Array" members here. Often vectors within the Level can be shared
|
||||
// with the Refinement, and an Array instance is used to do so. If not shared
|
||||
// the subclass just initializes the Array members after allocating its own local
|
||||
// vector members.
|
||||
//
|
||||
IndexArray _faceChildFaceCountsAndOffsets;
|
||||
IndexArray _faceChildEdgeCountsAndOffsets;
|
||||
|
||||
IndexVector _faceChildFaceIndices; // *cannot* always use face-vert counts/offsets
|
||||
IndexVector _faceChildEdgeIndices; // can use face-vert counts/offsets
|
||||
IndexVector _faceChildVertIndex;
|
||||
|
||||
IndexVector _edgeChildEdgeIndices; // trivial/corresponding pair for each
|
||||
IndexVector _edgeChildVertIndex;
|
||||
|
||||
IndexVector _vertChildVertIndex;
|
||||
|
||||
//
|
||||
// The child-to-parent mapping:
|
||||
//
|
||||
IndexVector _childFaceParentIndex;
|
||||
IndexVector _childEdgeParentIndex;
|
||||
IndexVector _childVertexParentIndex;
|
||||
|
||||
std::vector<ChildTag> _childFaceTag;
|
||||
std::vector<ChildTag> _childEdgeTag;
|
||||
std::vector<ChildTag> _childVertexTag;
|
||||
|
||||
//
|
||||
// Tags for sparse selection of components:
|
||||
//
|
||||
std::vector<SparseTag> _parentFaceTag;
|
||||
std::vector<SparseTag> _parentEdgeTag;
|
||||
std::vector<SparseTag> _parentVertexTag;
|
||||
|
||||
//
|
||||
// Refinement data for face-varying channels present in the Levels being refined:
|
||||
//
|
||||
std::vector<FVarRefinement*> _fvarChannels;
|
||||
};
|
||||
|
||||
inline ConstIndexArray
|
||||
Refinement::getFaceChildFaces(Index parentFace) const {
|
||||
|
||||
return ConstIndexArray(&_faceChildFaceIndices[_faceChildFaceCountsAndOffsets[2*parentFace+1]],
|
||||
_faceChildFaceCountsAndOffsets[2*parentFace]);
|
||||
}
|
||||
|
||||
inline IndexArray
|
||||
Refinement::getFaceChildFaces(Index parentFace) {
|
||||
|
||||
return IndexArray(&_faceChildFaceIndices[_faceChildFaceCountsAndOffsets[2*parentFace+1]],
|
||||
_faceChildFaceCountsAndOffsets[2*parentFace]);
|
||||
}
|
||||
|
||||
inline ConstIndexArray
|
||||
Refinement::getFaceChildEdges(Index parentFace) const {
|
||||
|
||||
return ConstIndexArray(&_faceChildEdgeIndices[_faceChildEdgeCountsAndOffsets[2*parentFace+1]],
|
||||
_faceChildEdgeCountsAndOffsets[2*parentFace]);
|
||||
}
|
||||
inline IndexArray
|
||||
Refinement::getFaceChildEdges(Index parentFace) {
|
||||
|
||||
return IndexArray(&_faceChildEdgeIndices[_faceChildEdgeCountsAndOffsets[2*parentFace+1]],
|
||||
_faceChildEdgeCountsAndOffsets[2*parentFace]);
|
||||
}
|
||||
|
||||
inline ConstIndexArray
|
||||
Refinement::getEdgeChildEdges(Index parentEdge) const {
|
||||
|
||||
return ConstIndexArray(&_edgeChildEdgeIndices[parentEdge*2], 2);
|
||||
}
|
||||
|
||||
inline IndexArray
|
||||
Refinement::getEdgeChildEdges(Index parentEdge) {
|
||||
|
||||
return IndexArray(&_edgeChildEdgeIndices[parentEdge*2], 2);
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_REFINEMENT_H */
|
||||
84
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/sparseSelector.cpp
vendored
Normal file
84
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/sparseSelector.cpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../vtr/sparseSelector.h"
|
||||
#include "../vtr/level.h"
|
||||
#include "../vtr/refinement.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// Component selection methods:
|
||||
// Marking of selection is retained in the SparseTags of the Refinement. The
|
||||
// selection simply marks the parent components -- not any child components that may
|
||||
// be derived from them. That is done later when we need to additionally identify
|
||||
// all of the "neighboring" child components that must exist at the next subdivision
|
||||
// level in order to fully define supported further refinement of selected components.
|
||||
//
|
||||
inline void
|
||||
SparseSelector::initializeSelection() {
|
||||
|
||||
if (!_selected) {
|
||||
_refine->initializeSparseSelectionTags();
|
||||
_selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SparseSelector::selectVertex(Index parentVertex) {
|
||||
|
||||
initializeSelection();
|
||||
|
||||
// Don't bother to test-and-set here, just set
|
||||
markVertexSelected(parentVertex);
|
||||
}
|
||||
|
||||
void
|
||||
SparseSelector::selectEdge(Index parentEdge) {
|
||||
|
||||
initializeSelection();
|
||||
|
||||
if (!wasEdgeSelected(parentEdge)) {
|
||||
markEdgeSelected(parentEdge);
|
||||
|
||||
// Mark the two end vertices:
|
||||
ConstIndexArray eVerts = _refine->parent().getEdgeVertices(parentEdge);
|
||||
markVertexSelected(eVerts[0]);
|
||||
markVertexSelected(eVerts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SparseSelector::selectFace(Index parentFace) {
|
||||
|
||||
initializeSelection();
|
||||
|
||||
if (!wasFaceSelected(parentFace)) {
|
||||
markFaceSelected(parentFace);
|
||||
|
||||
// Mark the face's incident verts and edges as selected:
|
||||
ConstIndexArray fEdges = _refine->parent().getFaceEdges(parentFace),
|
||||
fVerts = _refine->parent().getFaceVertices(parentFace);
|
||||
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
markEdgeSelected(fEdges[i]);
|
||||
markVertexSelected(fVerts[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
84
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/sparseSelector.h
vendored
Normal file
84
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/sparseSelector.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_SPARSE_SELECTOR_H
|
||||
#define OPENSUBDIV3_VTR_SPARSE_SELECTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/refinement.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// SparseSelector:
|
||||
// Class supporting "selection" of components in a Level for sparse Refinement.
|
||||
// The term "selection" here implies interest in the limit for that component, i.e.
|
||||
// the limit point for a selected vertex, the limit patch for a face, etc. So this
|
||||
// class is responsible for ensuring that all neighboring components required to
|
||||
// support the limit of those selected are included in the refinement.
|
||||
//
|
||||
// This class is associated with (and constructed given) a Refinement and its role
|
||||
// is to initialize that Refinement instance for eventual sparse refinement. So it
|
||||
// is a friend of and expected to modify the Refinement as part of the selection.
|
||||
// Given its simplicity and scope it may be worth nesting it in Vtr::Refinement.
|
||||
//
|
||||
// While all three component types -- vertices, edges and faces -- can be selected,
|
||||
// only selection of faces is currently used and actively supported as part of the
|
||||
// feature-adaptive refinement.
|
||||
//
|
||||
class SparseSelector {
|
||||
|
||||
public:
|
||||
SparseSelector(Refinement& refine) : _refine(&refine), _selected(false) { }
|
||||
~SparseSelector() { }
|
||||
|
||||
void setRefinement(Refinement& refine) { _refine = &refine; }
|
||||
Refinement& getRefinement() const { return *_refine; }
|
||||
|
||||
bool isSelectionEmpty() const { return !_selected; }
|
||||
|
||||
//
|
||||
// Methods for selecting (and marking) components for refinement. All component indices
|
||||
// refer to components in the parent:
|
||||
//
|
||||
void selectVertex(Index pVertex);
|
||||
void selectEdge( Index pEdge);
|
||||
void selectFace( Index pFace);
|
||||
|
||||
private:
|
||||
SparseSelector() : _refine(0), _selected(false) { }
|
||||
|
||||
bool wasVertexSelected(Index pVertex) const { return _refine->getParentVertexSparseTag(pVertex)._selected; }
|
||||
bool wasEdgeSelected( Index pEdge) const { return _refine->getParentEdgeSparseTag(pEdge)._selected; }
|
||||
bool wasFaceSelected( Index pFace) const { return _refine->getParentFaceSparseTag(pFace)._selected; }
|
||||
|
||||
void markVertexSelected(Index pVertex) const { _refine->getParentVertexSparseTag(pVertex)._selected = true; }
|
||||
void markEdgeSelected( Index pEdge) const { _refine->getParentEdgeSparseTag(pEdge)._selected = true; }
|
||||
void markFaceSelected( Index pFace) const { _refine->getParentFaceSparseTag(pFace)._selected = true; }
|
||||
|
||||
void initializeSelection();
|
||||
|
||||
private:
|
||||
Refinement* _refine;
|
||||
bool _selected;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_SPARSE_SELECTOR_H */
|
||||
210
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/stackBuffer.h
vendored
Normal file
210
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/stackBuffer.h
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
//
|
||||
// Copyright 2015 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_STACK_BUFFER_H
|
||||
#define OPENSUBDIV3_VTR_STACK_BUFFER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// The StackBuffer class is intended solely to take the place of VLAs (Variable
|
||||
// Length Arrays) which most compilers support, but are not strictly standard C++.
|
||||
// Portability concerns forces us to make use of either alloca() or some other
|
||||
// mechanism to create small arrays on the stack that are typically based on the
|
||||
// valence of a vertex -- small in general, but occasionally large.
|
||||
//
|
||||
// Note also that since the intent of this is to replace VLAs -- not general
|
||||
// std::vectors -- support for std::vector functionality is intentionally limited
|
||||
// and STL-like naming is avoided. Like a VLA there is no incremental growth.
|
||||
// Support for resizing is available to reuse an instance at the beginning of a
|
||||
// loop with a new size, but resizing in this case reinitializes all elements.
|
||||
//
|
||||
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE = false>
|
||||
class StackBuffer
|
||||
{
|
||||
public:
|
||||
typedef unsigned int size_type;
|
||||
|
||||
public:
|
||||
// Constructors and destructor -- declared inline below:
|
||||
StackBuffer();
|
||||
StackBuffer(size_type size);
|
||||
~StackBuffer();
|
||||
|
||||
public:
|
||||
// Note the reliance on implicit casting so that it can be used similar to
|
||||
// a VLA. This removes the need for operator[] as the resulting TYPE* will
|
||||
// natively support []. (The presence of both TYPE* and operator[] also
|
||||
// causes an ambiguous overloading error with 32-bit MSVC builds.)
|
||||
|
||||
operator TYPE const * () const { return _data; }
|
||||
operator TYPE * () { return _data; }
|
||||
|
||||
size_type GetSize() const { return _size; }
|
||||
|
||||
void SetSize(size_type size);
|
||||
void Reserve(size_type capacity);
|
||||
|
||||
private:
|
||||
// Non-copyable:
|
||||
StackBuffer(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { }
|
||||
StackBuffer& operator=(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { return *this; }
|
||||
|
||||
void allocate(size_type capacity);
|
||||
void deallocate();
|
||||
void construct();
|
||||
void destruct();
|
||||
|
||||
private:
|
||||
TYPE * _data;
|
||||
size_type _size;
|
||||
size_type _capacity;
|
||||
|
||||
// Is alignment an issue here? The staticData arena will at least be double-word
|
||||
// aligned within this struct, which meets current and most anticipated needs.
|
||||
char _staticData[SIZE * sizeof(TYPE)];
|
||||
char * _dynamicData;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Core allocation/deallocation methods:
|
||||
//
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::allocate(size_type capacity) {
|
||||
|
||||
// Again, is alignment an issue here? C++ spec says new will return pointer
|
||||
// "suitably aligned" for conversion to pointers of other types, which implies
|
||||
// at least an alignment of 16.
|
||||
_dynamicData = static_cast<char*>(::operator new(capacity * sizeof(TYPE)));
|
||||
|
||||
_data = reinterpret_cast<TYPE*>(_dynamicData);
|
||||
_capacity = capacity;
|
||||
}
|
||||
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::deallocate() {
|
||||
|
||||
::operator delete(_dynamicData);
|
||||
|
||||
_data = reinterpret_cast<TYPE*>(_staticData);
|
||||
_capacity = SIZE;
|
||||
}
|
||||
|
||||
//
|
||||
// Explicit element-wise construction and destruction within allocated memory.
|
||||
// Compilers do not always optimize out the iteration here even when there is
|
||||
// no construction or destruction, so the POD_TYPE arguement can be used to
|
||||
// force this when/if it becomes an issue (and it has been in some cases).
|
||||
//
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
|
||||
|
||||
for (size_type i = 0; i < _size; ++i) {
|
||||
(void) new (&_data[i]) TYPE;
|
||||
}
|
||||
}
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::destruct() {
|
||||
|
||||
for (size_type i = 0; i < _size; ++i) {
|
||||
_data[i].~TYPE();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Inline constructors and destructor:
|
||||
//
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer() :
|
||||
_data(reinterpret_cast<TYPE*>(_staticData)),
|
||||
_size(0),
|
||||
_capacity(SIZE),
|
||||
_dynamicData(0) {
|
||||
|
||||
}
|
||||
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer(size_type size) :
|
||||
_data(reinterpret_cast<TYPE*>(_staticData)),
|
||||
_size(size),
|
||||
_capacity(SIZE),
|
||||
_dynamicData(0) {
|
||||
|
||||
if (size > SIZE) {
|
||||
allocate(size);
|
||||
}
|
||||
if (!POD_TYPE) {
|
||||
construct();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::~StackBuffer() {
|
||||
|
||||
if (!POD_TYPE) {
|
||||
destruct();
|
||||
}
|
||||
deallocate();
|
||||
}
|
||||
|
||||
//
|
||||
// Inline sizing methods:
|
||||
//
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::Reserve(size_type capacity) {
|
||||
|
||||
if (capacity > _capacity) {
|
||||
if (!POD_TYPE) {
|
||||
destruct();
|
||||
}
|
||||
deallocate();
|
||||
allocate(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
|
||||
inline void
|
||||
StackBuffer<TYPE,SIZE,POD_TYPE>::SetSize(size_type size)
|
||||
{
|
||||
if (!POD_TYPE) {
|
||||
destruct();
|
||||
}
|
||||
if (size == 0) {
|
||||
deallocate();
|
||||
} else if (size > _capacity) {
|
||||
deallocate();
|
||||
allocate(size);
|
||||
}
|
||||
_size = size;
|
||||
if (!POD_TYPE) {
|
||||
construct();
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_STACK_BUFFER_H */
|
||||
913
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/triRefinement.cpp
vendored
Normal file
913
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/triRefinement.cpp
vendored
Normal file
@@ -0,0 +1,913 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../sdc/crease.h"
|
||||
#include "../vtr/types.h"
|
||||
#include "../vtr/level.h"
|
||||
#include "../vtr/triRefinement.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// Simple constructor, destructor and basic initializers:
|
||||
//
|
||||
TriRefinement::TriRefinement(Level const & parentArg, Level & childArg, Sdc::Options const & optionsArg) :
|
||||
Refinement(parentArg, childArg, optionsArg) {
|
||||
|
||||
_splitType = Sdc::SPLIT_TO_TRIS;
|
||||
_regFaceSize = 3;
|
||||
}
|
||||
|
||||
TriRefinement::~TriRefinement() {
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to construct the parent-to-child mapping
|
||||
//
|
||||
void
|
||||
TriRefinement::allocateParentChildIndices() {
|
||||
|
||||
//
|
||||
// Initialize the vectors of indices mapping parent components to those child components
|
||||
// that will originate from each.
|
||||
//
|
||||
//
|
||||
// Beware these child-counts when Loop subdivision supports N-sided faces in the cage
|
||||
// - there will 2*(N-2) additional face-child-faces for each N-sided face
|
||||
// - there will 2*(N-2)+1 additional face-child-edges for each N-sided face
|
||||
// - there will 1 face-child-vertex for each N-sided face
|
||||
// Can consider these reasonable estimates and grow as needed later -- but be clear
|
||||
// about it if so.
|
||||
//
|
||||
int faceChildFaceCount = _parent->getNumFaces() * 4;
|
||||
int faceChildEdgeCount = (int) _parent->_faceEdgeIndices.size();
|
||||
int edgeChildEdgeCount = (int) _parent->_edgeVertIndices.size();
|
||||
|
||||
int faceChildVertCount = 0;
|
||||
int edgeChildVertCount = _parent->getNumEdges();
|
||||
int vertChildVertCount = _parent->getNumVertices();
|
||||
|
||||
//
|
||||
// First initialize the count/offset vectors for the child-faces and child-edges of
|
||||
// parent faces. For now we can use the parent's face-vert counts for the child-edges
|
||||
// of faces, but we must use a local vector for the child-faces.
|
||||
//
|
||||
// This will be more necessary (and need adjustment) when N-sided faces are supported.
|
||||
//
|
||||
_localFaceChildFaceCountsAndOffsets.resize(_parent->getNumFaces() * 2, 4);
|
||||
for (int i = 0; i < _parent->getNumFaces(); ++i) {
|
||||
_localFaceChildFaceCountsAndOffsets[i*2 + 1] = 4 * i;
|
||||
}
|
||||
|
||||
_faceChildFaceCountsAndOffsets = IndexArray(&_localFaceChildFaceCountsAndOffsets[0],
|
||||
(int)_localFaceChildFaceCountsAndOffsets.size());
|
||||
_faceChildEdgeCountsAndOffsets = _parent->shareFaceVertCountsAndOffsets();
|
||||
|
||||
//
|
||||
// Given we will be ignoring initial values with uniform refinement and assigning all
|
||||
// directly, initializing here is a waste...
|
||||
//
|
||||
Index initValue = 0;
|
||||
|
||||
_faceChildFaceIndices.resize(faceChildFaceCount, initValue);
|
||||
_faceChildEdgeIndices.resize(faceChildEdgeCount, initValue);
|
||||
_edgeChildEdgeIndices.resize(edgeChildEdgeCount, initValue);
|
||||
|
||||
_faceChildVertIndex.resize(faceChildVertCount, initValue);
|
||||
_edgeChildVertIndex.resize(edgeChildVertCount, initValue);
|
||||
_vertChildVertIndex.resize(vertChildVertCount, initValue);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the face-vertex relation of the child Level:
|
||||
// - child faces only originate from parent faces
|
||||
//
|
||||
void
|
||||
TriRefinement::populateFaceVertexRelation() {
|
||||
|
||||
// Both face-vertex and face-edge share the face-vertex counts/offsets within a
|
||||
// Level, so be sure not to re-initialize it if already done:
|
||||
//
|
||||
if (_child->_faceVertCountsAndOffsets.size() == 0) {
|
||||
populateFaceVertexCountsAndOffsets();
|
||||
}
|
||||
_child->_faceVertIndices.resize(_child->getNumFaces() * 3);
|
||||
|
||||
populateFaceVerticesFromParentFaces();
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateFaceVertexCountsAndOffsets() {
|
||||
|
||||
_child->_faceVertCountsAndOffsets.resize(_child->getNumFaces() * 2, 3);
|
||||
|
||||
for (int i = 0; i < _child->getNumFaces(); ++i) {
|
||||
_child->_faceVertCountsAndOffsets[i*2 + 1] = i * 3;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateFaceVerticesFromParentFaces() {
|
||||
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildren = getFaceChildFaces(pFace);
|
||||
|
||||
assert(pFaceVerts.size() == 3);
|
||||
assert(pFaceChildren.size() == 4);
|
||||
|
||||
Index cVertsOfPEdges[3];
|
||||
cVertsOfPEdges[0] = _edgeChildVertIndex[pFaceEdges[0]];
|
||||
cVertsOfPEdges[1] = _edgeChildVertIndex[pFaceEdges[1]];
|
||||
cVertsOfPEdges[2] = _edgeChildVertIndex[pFaceEdges[2]];
|
||||
|
||||
//
|
||||
// For the child face at vertex I (where I is 0..2), the child vertex
|
||||
// of vertex I becomes the I'th vertex of its child face. This matches
|
||||
// the pattern for quads of irregular faces for Catmark.
|
||||
//
|
||||
// The orientation for the 4th "interior" face is unclear -- it begins
|
||||
// with the child vertex of the 2nd edge of the triangle. According
|
||||
// to the notes with the Hbr implementation "the ordering of vertices
|
||||
// here is done to preserve parametric space as best we can."
|
||||
//
|
||||
if (IndexIsValid(pFaceChildren[0])) {
|
||||
IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[0]);
|
||||
|
||||
cFaceVerts[0] = _vertChildVertIndex[pFaceVerts[0]];
|
||||
cFaceVerts[1] = cVertsOfPEdges[0];
|
||||
cFaceVerts[2] = cVertsOfPEdges[2];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildren[1])) {
|
||||
IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[1]);
|
||||
|
||||
cFaceVerts[0] = cVertsOfPEdges[0];
|
||||
cFaceVerts[1] = _vertChildVertIndex[pFaceVerts[1]];
|
||||
cFaceVerts[2] = cVertsOfPEdges[1];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildren[2])) {
|
||||
IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[2]);
|
||||
|
||||
cFaceVerts[0] = cVertsOfPEdges[2];
|
||||
cFaceVerts[1] = cVertsOfPEdges[1];
|
||||
cFaceVerts[2] = _vertChildVertIndex[pFaceVerts[2]];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildren[3])) {
|
||||
IndexArray cFaceVerts = _child->getFaceVertices(pFaceChildren[3]);
|
||||
|
||||
cFaceVerts[0] = cVertsOfPEdges[1];
|
||||
cFaceVerts[1] = cVertsOfPEdges[2];
|
||||
cFaceVerts[2] = cVertsOfPEdges[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the face-vertex relation of the child Level:
|
||||
// - child faces only originate from parent faces
|
||||
//
|
||||
void
|
||||
TriRefinement::populateFaceEdgeRelation() {
|
||||
|
||||
// Both face-vertex and face-edge share the face-vertex counts/offsets, so be sure
|
||||
// not to re-initialize it if already done:
|
||||
//
|
||||
if (_child->_faceVertCountsAndOffsets.size() == 0) {
|
||||
populateFaceVertexCountsAndOffsets();
|
||||
}
|
||||
_child->_faceEdgeIndices.resize(_child->getNumFaces() * 3);
|
||||
|
||||
populateFaceEdgesFromParentFaces();
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateFaceEdgesFromParentFaces() {
|
||||
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildFaces = getFaceChildFaces(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
assert(pFaceChildFaces.size() == 4);
|
||||
assert(pFaceChildEdges.size() == 3);
|
||||
|
||||
Index pEdgeChildEdges[3][2];
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
Index pEdge = pFaceEdges[i];
|
||||
ConstIndexArray cEdges = getEdgeChildEdges(pEdge);
|
||||
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge);
|
||||
|
||||
// Be careful to consider degenerate edge when orienting here:
|
||||
bool edgeReversedWrtFace = (pEdgeVerts[0] != pEdgeVerts[1]) &&
|
||||
(pFaceVerts[i] != pEdgeVerts[0]);
|
||||
|
||||
pEdgeChildEdges[i][0] = cEdges[edgeReversedWrtFace];
|
||||
pEdgeChildEdges[i][1] = cEdges[!edgeReversedWrtFace];
|
||||
}
|
||||
|
||||
if (IndexIsValid(pFaceChildFaces[0])) {
|
||||
IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[0]);
|
||||
|
||||
cFaceEdges[0] = pEdgeChildEdges[0][0];
|
||||
cFaceEdges[1] = pFaceChildEdges[0];
|
||||
cFaceEdges[2] = pEdgeChildEdges[2][1];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildFaces[1])) {
|
||||
IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[1]);
|
||||
|
||||
cFaceEdges[0] = pEdgeChildEdges[0][1];
|
||||
cFaceEdges[1] = pEdgeChildEdges[1][0];
|
||||
cFaceEdges[2] = pFaceChildEdges[1];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildFaces[2])) {
|
||||
IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[2]);
|
||||
|
||||
cFaceEdges[0] = pFaceChildEdges[2];
|
||||
cFaceEdges[1] = pEdgeChildEdges[1][1];
|
||||
cFaceEdges[2] = pEdgeChildEdges[2][0];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildFaces[3])) {
|
||||
IndexArray cFaceEdges = _child->getFaceEdges(pFaceChildFaces[3]);
|
||||
|
||||
cFaceEdges[0] = pFaceChildEdges[2];
|
||||
cFaceEdges[1] = pFaceChildEdges[0];
|
||||
cFaceEdges[2] = pFaceChildEdges[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the edge-vertex relation of the child Level:
|
||||
// - child edges originate from parent faces and edges
|
||||
//
|
||||
void
|
||||
TriRefinement::populateEdgeVertexRelation() {
|
||||
|
||||
_child->_edgeVertIndices.resize(_child->getNumEdges() * 2);
|
||||
|
||||
populateEdgeVerticesFromParentFaces();
|
||||
populateEdgeVerticesFromParentEdges();
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateEdgeVerticesFromParentFaces() {
|
||||
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceEdges = _parent->getFaceEdges(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
assert(pFaceEdges.size() == 3);
|
||||
assert(pFaceChildEdges.size() == 3);
|
||||
|
||||
Index pEdgeChildVerts[3];
|
||||
pEdgeChildVerts[0] = _edgeChildVertIndex[pFaceEdges[0]];
|
||||
pEdgeChildVerts[1] = _edgeChildVertIndex[pFaceEdges[1]];
|
||||
pEdgeChildVerts[2] = _edgeChildVertIndex[pFaceEdges[2]];
|
||||
|
||||
if (IndexIsValid(pFaceChildEdges[0])) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[0]);
|
||||
|
||||
cEdgeVerts[0] = pEdgeChildVerts[0];
|
||||
cEdgeVerts[1] = pEdgeChildVerts[2];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildEdges[1])) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[1]);
|
||||
|
||||
cEdgeVerts[0] = pEdgeChildVerts[1];
|
||||
cEdgeVerts[1] = pEdgeChildVerts[0];
|
||||
}
|
||||
if (IndexIsValid(pFaceChildEdges[2])) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(pFaceChildEdges[2]);
|
||||
|
||||
cEdgeVerts[0] = pEdgeChildVerts[2];
|
||||
cEdgeVerts[1] = pEdgeChildVerts[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateEdgeVerticesFromParentEdges() {
|
||||
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge),
|
||||
pEdgeChildEdges = getEdgeChildEdges(pEdge);
|
||||
|
||||
if (IndexIsValid(pEdgeChildEdges[0])) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(pEdgeChildEdges[0]);
|
||||
|
||||
cEdgeVerts[0] = _edgeChildVertIndex[pEdge];
|
||||
cEdgeVerts[1] = _vertChildVertIndex[pEdgeVerts[0]];
|
||||
}
|
||||
if (IndexIsValid(pEdgeChildEdges[1])) {
|
||||
IndexArray cEdgeVerts = _child->getEdgeVertices(pEdgeChildEdges[1]);
|
||||
|
||||
cEdgeVerts[0] = _edgeChildVertIndex[pEdge];
|
||||
cEdgeVerts[1] = _vertChildVertIndex[pEdgeVerts[1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the edge-face relation of the child Level:
|
||||
// - child edges originate from parent faces and edges
|
||||
// - sparse refinement poses challenges with allocation here
|
||||
// - we need to update the counts/offsets as we populate
|
||||
//
|
||||
void
|
||||
TriRefinement::populateEdgeFaceRelation() {
|
||||
|
||||
//
|
||||
// This is essentially the same as the quad-split version except for the
|
||||
// sizing estimates:
|
||||
// - every child-edge within a face will have 2 incident faces
|
||||
// - every child-edge from a edge may have N incident faces
|
||||
// - use the parents edge-face count for this
|
||||
//
|
||||
int childEdgeFaceIndexSizeEstimate = (int)_faceChildEdgeIndices.size() * 2 +
|
||||
(int)_parent->_edgeFaceIndices.size() * 2;
|
||||
|
||||
_child->_edgeFaceCountsAndOffsets.resize(_child->getNumEdges() * 2);
|
||||
_child->_edgeFaceIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
_child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
|
||||
// Update _maxEdgeFaces from the parent level before calling the
|
||||
// populateEdgeFacesFromParent methods below, as these may further
|
||||
// update _maxEdgeFaces.
|
||||
_child->_maxEdgeFaces = _parent->_maxEdgeFaces;
|
||||
|
||||
populateEdgeFacesFromParentFaces();
|
||||
populateEdgeFacesFromParentEdges();
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vector accordingly:
|
||||
childEdgeFaceIndexSizeEstimate = _child->getNumEdgeFaces(_child->getNumEdges()-1) +
|
||||
_child->getOffsetOfEdgeFaces(_child->getNumEdges()-1);
|
||||
_child->_edgeFaceIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
_child->_edgeFaceLocalIndices.resize(childEdgeFaceIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateEdgeFacesFromParentFaces() {
|
||||
|
||||
for (Index pFace = 0; pFace < _parent->getNumFaces(); ++pFace) {
|
||||
ConstIndexArray pFaceChildFaces = getFaceChildFaces(pFace),
|
||||
pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
assert(pFaceChildFaces.size() == 4);
|
||||
assert(pFaceChildEdges.size() == 3);
|
||||
|
||||
// Every child-edge of a face potentially shares the middle child face:
|
||||
Index cFaceMiddle = pFaceChildFaces[3];
|
||||
bool isFaceMiddleValid = IndexIsValid(cFaceMiddle);
|
||||
|
||||
for (int j = 0; j < pFaceChildEdges.size(); ++j) {
|
||||
Index cEdge = pFaceChildEdges[j];
|
||||
if (IndexIsValid(cEdge)) {
|
||||
// Reserve enough edge-faces, populate and trim as needed:
|
||||
_child->resizeEdgeFaces(cEdge, 2);
|
||||
|
||||
IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge);
|
||||
LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge);
|
||||
|
||||
int cEdgeFaceCount = 0;
|
||||
if (IndexIsValid(pFaceChildFaces[j])) {
|
||||
cEdgeFaces[cEdgeFaceCount] = pFaceChildFaces[j];
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex) ((j + 1) % 3);
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
if (isFaceMiddleValid) {
|
||||
cEdgeFaces[cEdgeFaceCount] = cFaceMiddle;
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex) ((j + 1) % 3);
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
_child->trimEdgeFaces(cEdge, cEdgeFaceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateEdgeFacesFromParentEdges() {
|
||||
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
ConstIndexArray pEdgeChildEdges = getEdgeChildEdges(pEdge);
|
||||
if (!IndexIsValid(pEdgeChildEdges[0]) && !IndexIsValid(pEdgeChildEdges[1])) continue;
|
||||
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge);
|
||||
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
Index cEdge = pEdgeChildEdges[j];
|
||||
if (!IndexIsValid(cEdge)) continue;
|
||||
|
||||
//
|
||||
// Reserve enough edge-faces, populate and trim as needed:
|
||||
//
|
||||
_child->resizeEdgeFaces(cEdge, pEdgeFaces.size());
|
||||
|
||||
IndexArray cEdgeFaces = _child->getEdgeFaces(cEdge);
|
||||
LocalIndexArray cEdgeInFace = _child->getEdgeFaceLocalIndices(cEdge);
|
||||
|
||||
//
|
||||
// Each parent face may contribute an incident child face:
|
||||
//
|
||||
// For each incident face and local-index, we immediately know
|
||||
// the two child faces that are associated with the two child edges.
|
||||
// We just need to identify how to pair them based on edge direction.
|
||||
//
|
||||
// Note also here, that we could identify the pairs of child faces
|
||||
// once for the parent before dealing with each child edge (we do the
|
||||
// "find edge in face search" twice here as a result). We will
|
||||
// generally have 2 or 1 incident face to the parent edge so we
|
||||
// can put the child-pairs on the stack.
|
||||
//
|
||||
// Here's a more promising alternative -- instead of iterating
|
||||
// through the child edges to "pull" data from the parent, iterate
|
||||
// through the parent edges' faces and apply valid child faces to
|
||||
// the appropriate child edge. We should be able to use end-verts
|
||||
// of the parent edge to get the corresponding child face for each,
|
||||
// but we can't avoid a vert-in-face search and a subsequent parity
|
||||
// test of the end-vert.
|
||||
//
|
||||
int cEdgeFaceCount = 0;
|
||||
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
ConstIndexArray pFaceVerts = _parent->getFaceVertices(pFace),
|
||||
pFaceChildren = getFaceChildFaces(pFace);
|
||||
|
||||
// Inspect either this child of the face or the next -- be careful
|
||||
// to consider degenerate edge when orienting here:
|
||||
int childOfEdge = (pEdgeVerts[0] == pEdgeVerts[1]) ? j :
|
||||
(pFaceVerts[edgeInFace] != pEdgeVerts[j]);
|
||||
|
||||
int childInFace = edgeInFace + childOfEdge;
|
||||
if (childInFace == pFaceVerts.size()) childInFace = 0;
|
||||
|
||||
if (IndexIsValid(pFaceChildren[childInFace])) {
|
||||
cEdgeFaces[cEdgeFaceCount] = pFaceChildren[childInFace];
|
||||
cEdgeInFace[cEdgeFaceCount] = (LocalIndex) edgeInFace;
|
||||
cEdgeFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimEdgeFaces(cEdge, cEdgeFaceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the vertex-face relation of the child Level:
|
||||
// - child vertices originate from parent faces, edges and vertices
|
||||
// - sparse refinement poses challenges with allocation here:
|
||||
// - we need to update the counts/offsets as we populate
|
||||
// - note this imposes ordering constraints and inhibits concurrency
|
||||
//
|
||||
void
|
||||
TriRefinement::populateVertexFaceRelation() {
|
||||
|
||||
//
|
||||
// Unlike quad-splitting, we don't have to consider vertices originating from
|
||||
// faces. We also have to consider 3 faces for every incident face for vertices
|
||||
// originating from edges.
|
||||
//
|
||||
int childVertFaceIndexSizeEstimate = (int)_parent->_edgeFaceIndices.size() * 3
|
||||
+ (int)_parent->_vertFaceIndices.size();
|
||||
|
||||
_child->_vertFaceCountsAndOffsets.resize(_child->getNumVertices() * 2);
|
||||
_child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
_child->_vertFaceLocalIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
|
||||
// Remember -- no vertices-from-faces to consider here (until N-gon support)
|
||||
if (getFirstChildVertexFromVertices() == 0) {
|
||||
populateVertexFacesFromParentVertices();
|
||||
populateVertexFacesFromParentEdges();
|
||||
} else {
|
||||
populateVertexFacesFromParentEdges();
|
||||
populateVertexFacesFromParentVertices();
|
||||
}
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vectors accordingly:
|
||||
childVertFaceIndexSizeEstimate = _child->getNumVertexFaces(_child->getNumVertices()-1) +
|
||||
_child->getOffsetOfVertexFaces(_child->getNumVertices()-1);
|
||||
_child->_vertFaceIndices.resize( childVertFaceIndexSizeEstimate);
|
||||
_child->_vertFaceLocalIndices.resize(childVertFaceIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateVertexFacesFromParentEdges() {
|
||||
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
Index cVert = _edgeChildVertIndex[pEdge];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
|
||||
//
|
||||
// Reserve enough vert-faces, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexFaces(cVert, 2 * pEdgeFaces.size());
|
||||
|
||||
IndexArray cVertFaces = _child->getVertexFaces(cVert);
|
||||
LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert);
|
||||
|
||||
int cVertFaceCount = 0;
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
//
|
||||
// Identify the corresponding three child faces for this parent face and
|
||||
// their orientation wrt the child vertex to which they are incident --
|
||||
// since we have the desired ordering of child faces from the parent face,
|
||||
// we don't care about the orientation of the parent edge.
|
||||
//
|
||||
LocalIndex leadingFace = (LocalIndex) ((edgeInFace + 1) % 3);
|
||||
LocalIndex middleFace = (LocalIndex) 3;
|
||||
LocalIndex trailingFace = (LocalIndex) edgeInFace;
|
||||
|
||||
LocalIndex leadingLocalIndex = (LocalIndex) edgeInFace;
|
||||
LocalIndex middleLocalIndex = (LocalIndex) ((edgeInFace + 2) % 3);
|
||||
LocalIndex trailingLocalIndex = (LocalIndex) ((edgeInFace + 1) % 3);
|
||||
|
||||
//
|
||||
// Now simply assign those of the three child faces that are valid:
|
||||
//
|
||||
ConstIndexArray pFaceChildFaces = getFaceChildFaces(pFace);
|
||||
assert(pFaceChildFaces.size() == 4);
|
||||
|
||||
Index cFace = pFaceChildFaces[leadingFace];
|
||||
if (IndexIsValid(cFace)) {
|
||||
cVertFaces[cVertFaceCount] = cFace;
|
||||
cVertInFace[cVertFaceCount] = leadingLocalIndex;
|
||||
cVertFaceCount++;
|
||||
}
|
||||
|
||||
cFace = pFaceChildFaces[middleFace];
|
||||
if (IndexIsValid(cFace)) {
|
||||
cVertFaces[cVertFaceCount] = cFace;
|
||||
cVertInFace[cVertFaceCount] = middleLocalIndex;
|
||||
cVertFaceCount++;
|
||||
}
|
||||
|
||||
cFace = pFaceChildFaces[trailingFace];
|
||||
if (IndexIsValid(cFace)) {
|
||||
cVertFaces[cVertFaceCount] = cFace;
|
||||
cVertInFace[cVertFaceCount] = trailingLocalIndex;
|
||||
cVertFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexFaces(cVert, cVertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateVertexFacesFromParentVertices() {
|
||||
|
||||
for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
|
||||
Index cVert = _vertChildVertIndex[pVert];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
//
|
||||
// Inspect the parent vert's faces:
|
||||
//
|
||||
ConstIndexArray pVertFaces = _parent->getVertexFaces(pVert);
|
||||
ConstLocalIndexArray pVertInFace = _parent->getVertexFaceLocalIndices(pVert);
|
||||
|
||||
//
|
||||
// Reserve enough vert-faces, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexFaces(cVert, pVertFaces.size());
|
||||
|
||||
IndexArray cVertFaces = _child->getVertexFaces(cVert);
|
||||
LocalIndexArray cVertInFace = _child->getVertexFaceLocalIndices(cVert);
|
||||
|
||||
int cVertFaceCount = 0;
|
||||
for (int i = 0; i < pVertFaces.size(); ++i) {
|
||||
Index pFace = pVertFaces[i];
|
||||
LocalIndex pFaceChild = pVertInFace[i];
|
||||
|
||||
Index cFace = getFaceChildFaces(pFace)[pFaceChild];
|
||||
if (IndexIsValid(cFace)) {
|
||||
cVertFaces[cVertFaceCount] = cFace;
|
||||
cVertInFace[cVertFaceCount] = pFaceChild;
|
||||
cVertFaceCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexFaces(cVert, cVertFaceCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Methods to populate the vertex-edge relation of the child Level:
|
||||
// - child vertices originate from parent faces, edges and vertices
|
||||
// - sparse refinement poses challenges with allocation here:
|
||||
// - we need to update the counts/offsets as we populate
|
||||
// - note this imposes ordering constraints and inhibits concurrency
|
||||
//
|
||||
void
|
||||
TriRefinement::populateVertexEdgeRelation() {
|
||||
|
||||
//
|
||||
// Notes on allocating/initializing the vertex-edge counts/offsets vector:
|
||||
//
|
||||
// Be aware of scheme-specific decisions here, e.g.:
|
||||
// - no verts from parent faces for Loop
|
||||
// - more interior edges and faces for verts from parent edges for Loop
|
||||
// - no guaranteed "neighborhood" around Bilinear verts from verts
|
||||
//
|
||||
// If uniform subdivision, vert-edge count will be:
|
||||
// - 2 + 2*N faces incident parent edge for verts from parent edges
|
||||
// - same as parent vert for verts from parent verts
|
||||
// If sparse subdivision, vert-edge count will be:
|
||||
// - non-trivial function of child faces in parent face
|
||||
// - 1 child face will always result in 2 child edges
|
||||
// * 2 child faces can mean 3 or 4 child edges
|
||||
// - 3 child faces will always result in 4 child edges
|
||||
// - 1 or 2 + N faces incident parent edge for verts from parent edges
|
||||
// - where the 1 or 2 is number of child edges of parent edge
|
||||
// - any end vertex will require all N child faces (catmark)
|
||||
// - same as parent vert for verts from parent verts (catmark)
|
||||
//
|
||||
int childVertEdgeIndexSizeEstimate = (int)_parent->_edgeFaceIndices.size() * 2 + _parent->getNumEdges() * 2
|
||||
+ (int)_parent->_vertEdgeIndices.size();
|
||||
|
||||
_child->_vertEdgeCountsAndOffsets.resize(_child->getNumVertices() * 2);
|
||||
_child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
_child->_vertEdgeLocalIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
|
||||
if (getFirstChildVertexFromVertices() == 0) {
|
||||
populateVertexEdgesFromParentVertices();
|
||||
populateVertexEdgesFromParentEdges();
|
||||
} else {
|
||||
populateVertexEdgesFromParentEdges();
|
||||
populateVertexEdgesFromParentVertices();
|
||||
}
|
||||
|
||||
// Revise the over-allocated estimate based on what is used (as indicated in the
|
||||
// count/offset for the last vertex) and trim the index vectors accordingly:
|
||||
childVertEdgeIndexSizeEstimate = _child->getNumVertexEdges(_child->getNumVertices()-1) +
|
||||
_child->getOffsetOfVertexEdges(_child->getNumVertices()-1);
|
||||
_child->_vertEdgeIndices.resize( childVertEdgeIndexSizeEstimate);
|
||||
_child->_vertEdgeLocalIndices.resize(childVertEdgeIndexSizeEstimate);
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::populateVertexEdgesFromParentEdges() {
|
||||
|
||||
for (Index pEdge = 0; pEdge < _parent->getNumEdges(); ++pEdge) {
|
||||
Index cVert = _edgeChildVertIndex[pEdge];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
//
|
||||
// First inspect the parent edge -- its parent faces then its child edges:
|
||||
//
|
||||
ConstIndexArray pEdgeFaces = _parent->getEdgeFaces(pEdge);
|
||||
ConstLocalIndexArray pEdgeInFace = _parent->getEdgeFaceLocalIndices(pEdge);
|
||||
|
||||
ConstIndexArray pEdgeVerts = _parent->getEdgeVertices(pEdge),
|
||||
pEdgeChildEdges = getEdgeChildEdges(pEdge);
|
||||
|
||||
//
|
||||
// Reserve enough vert-edges, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexEdges(cVert, pEdgeFaces.size() + 2);
|
||||
|
||||
IndexArray cVertEdges = _child->getVertexEdges(cVert);
|
||||
LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert);
|
||||
|
||||
//
|
||||
// We need to order the incident edges around the vertex appropriately:
|
||||
// - one child edge of the parent edge ("leading" in face 0)
|
||||
// - two child edges interior to face 0
|
||||
// - one other child edge of the parent edge ("trailing" in face 0)
|
||||
// - child edges of all remaining faces
|
||||
// Be careful to place the leading/trailing child edges of the parent edge
|
||||
// correctly -- edges are not directed their orientation may vary. The
|
||||
// interior child edges are appropriately oriented wrt their parent face.
|
||||
//
|
||||
// Also need to consider no faces at all, in which case we just want the
|
||||
// child edges of the parent edge.
|
||||
//
|
||||
int cVertEdgeCount = 0;
|
||||
|
||||
// We only care about edge reversal in the first iteration -- in which
|
||||
// the child edges of the parent edges are assigned. Other iterations
|
||||
// only assign the child edges from the incident parent face:
|
||||
bool pEdgeReversed = false;
|
||||
Index cEdgeOfEdge0 = INDEX_INVALID,
|
||||
cEdgeOfEdge1 = INDEX_INVALID;
|
||||
|
||||
for (int i = 0; i < pEdgeFaces.size(); ++i) {
|
||||
Index pFace = pEdgeFaces[i];
|
||||
int edgeInFace = pEdgeInFace[i];
|
||||
|
||||
ConstIndexArray pFaceChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
// Test the orientation of a non-degenerate edge in the first face:
|
||||
if (i == 0) {
|
||||
if (pEdgeVerts[0] != pEdgeVerts[1]) {
|
||||
pEdgeReversed = (_parent->getFaceVertices(pFace)[edgeInFace] != pEdgeVerts[0]);
|
||||
}
|
||||
cEdgeOfEdge0 = pEdgeChildEdges[!pEdgeReversed];
|
||||
cEdgeOfEdge1 = pEdgeChildEdges[pEdgeReversed];
|
||||
}
|
||||
|
||||
//
|
||||
// Identify the two interior and incident child edges within the face --
|
||||
// bracketed by the child edges of the parent edge when dealing with the
|
||||
// first face:
|
||||
//
|
||||
Index cEdgeOfFace0 = pFaceChildEdges[(edgeInFace + 1) % 3];
|
||||
Index cEdgeOfFace1 = pFaceChildEdges[edgeInFace];
|
||||
|
||||
if ((i == 0) && IndexIsValid(cEdgeOfEdge0)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdgeOfEdge0;
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
if (IndexIsValid(cEdgeOfFace0)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdgeOfFace0;
|
||||
cVertInEdge[cVertEdgeCount] = 1;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
if (IndexIsValid(cEdgeOfFace1)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdgeOfFace1;
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
if ((i == 0) && IndexIsValid(cEdgeOfEdge1)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdgeOfEdge1;
|
||||
cVertInEdge[cVertEdgeCount] = 0;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexEdges(cVert, cVertEdgeCount);
|
||||
}
|
||||
}
|
||||
void
|
||||
TriRefinement::populateVertexEdgesFromParentVertices() {
|
||||
|
||||
for (Index pVert = 0; pVert < _parent->getNumVertices(); ++pVert) {
|
||||
Index cVert = _vertChildVertIndex[pVert];
|
||||
if (!IndexIsValid(cVert)) continue;
|
||||
|
||||
//
|
||||
// Inspect the parent vert's edges first:
|
||||
//
|
||||
ConstIndexArray pVertEdges = _parent->getVertexEdges(pVert);
|
||||
ConstLocalIndexArray pVertInEdge = _parent->getVertexEdgeLocalIndices(pVert);
|
||||
|
||||
//
|
||||
// Reserve enough vert-edges, populate and trim to the actual size:
|
||||
//
|
||||
_child->resizeVertexEdges(cVert, pVertEdges.size());
|
||||
|
||||
IndexArray cVertEdges = _child->getVertexEdges(cVert);
|
||||
LocalIndexArray cVertInEdge = _child->getVertexEdgeLocalIndices(cVert);
|
||||
|
||||
int cVertEdgeCount = 0;
|
||||
for (int i = 0; i < pVertEdges.size(); ++i) {
|
||||
Index cEdge = getEdgeChildEdges(pVertEdges[i])[pVertInEdge[i]];
|
||||
if (IndexIsValid(cEdge)) {
|
||||
cVertEdges[cVertEdgeCount] = cEdge;
|
||||
cVertInEdge[cVertEdgeCount] = 1;
|
||||
cVertEdgeCount++;
|
||||
}
|
||||
}
|
||||
_child->trimVertexEdges(cVert, cVertEdgeCount);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Methods to populate child-component indices for sparse selection:
|
||||
//
|
||||
// Need to find a better place for these anon helper methods now that they are required
|
||||
// both in the base class and the two subclasses for quad- and tri-splitting...
|
||||
//
|
||||
namespace {
|
||||
Index const IndexSparseMaskNeighboring = (1 << 0);
|
||||
Index const IndexSparseMaskSelected = (1 << 1);
|
||||
|
||||
inline void markSparseIndexNeighbor(Index& index) { index = IndexSparseMaskNeighboring; }
|
||||
inline void markSparseIndexSelected(Index& index) { index = IndexSparseMaskSelected; }
|
||||
}
|
||||
|
||||
void
|
||||
TriRefinement::markSparseFaceChildren() {
|
||||
|
||||
assert(_parentFaceTag.size() > 0);
|
||||
|
||||
//
|
||||
// For each parent face:
|
||||
// All boundary edges will be adequately marked as a result of the pass over the
|
||||
// edges above and boundary vertices marked by selection. So all that remains is to
|
||||
// identify the child faces and interior child edges for a face requiring neighboring
|
||||
// child faces.
|
||||
// For each corner vertex selected, we need to mark the corresponding child face,
|
||||
// the two interior child edges and shared child vertex in the middle.
|
||||
//
|
||||
for (Index pFace = 0; pFace < parent().getNumFaces(); ++pFace) {
|
||||
//
|
||||
// Mark all descending child components of a selected face. Otherwise inspect
|
||||
// its incident vertices to see if anything neighboring has been selected --
|
||||
// requiring partial refinement of this face.
|
||||
//
|
||||
// Remember that a selected face cannot be transitional, and that only a
|
||||
// transitional face will be partially refined.
|
||||
//
|
||||
IndexArray fChildFaces = getFaceChildFaces(pFace);
|
||||
IndexArray fChildEdges = getFaceChildEdges(pFace);
|
||||
|
||||
assert(fChildFaces.size() == 4);
|
||||
assert(fChildEdges.size() == 3);
|
||||
|
||||
ConstIndexArray fVerts = parent().getFaceVertices(pFace);
|
||||
|
||||
SparseTag& pFaceTag = _parentFaceTag[pFace];
|
||||
|
||||
if (pFaceTag._selected) {
|
||||
markSparseIndexSelected(fChildFaces[0]);
|
||||
markSparseIndexSelected(fChildFaces[1]);
|
||||
markSparseIndexSelected(fChildFaces[2]);
|
||||
markSparseIndexSelected(fChildFaces[3]);
|
||||
|
||||
markSparseIndexSelected(fChildEdges[0]);
|
||||
markSparseIndexSelected(fChildEdges[1]);
|
||||
markSparseIndexSelected(fChildEdges[2]);
|
||||
|
||||
pFaceTag._transitional = 0;
|
||||
} else {
|
||||
int marked = _parentVertexTag[fVerts[0]]._selected
|
||||
+ _parentVertexTag[fVerts[1]]._selected
|
||||
+ _parentVertexTag[fVerts[2]]._selected;
|
||||
|
||||
if (marked) {
|
||||
//
|
||||
// If marked, see if we have any transitional edges, in which case we
|
||||
// need to include the middle face:
|
||||
//
|
||||
ConstIndexArray fEdges = parent().getFaceEdges(pFace);
|
||||
|
||||
pFaceTag._transitional = (unsigned char)
|
||||
((_parentEdgeTag[fEdges[0]]._transitional << 0) |
|
||||
(_parentEdgeTag[fEdges[1]]._transitional << 1) |
|
||||
(_parentEdgeTag[fEdges[2]]._transitional << 2));
|
||||
|
||||
// Now mark the child faces and their associated edges:
|
||||
//
|
||||
if (pFaceTag._transitional) {
|
||||
markSparseIndexNeighbor(fChildFaces[3]);
|
||||
|
||||
markSparseIndexNeighbor(fChildEdges[0]);
|
||||
markSparseIndexNeighbor(fChildEdges[1]);
|
||||
markSparseIndexNeighbor(fChildEdges[2]);
|
||||
}
|
||||
if (_parentVertexTag[fVerts[0]]._selected) {
|
||||
markSparseIndexNeighbor(fChildFaces[0]);
|
||||
markSparseIndexNeighbor(fChildEdges[0]);
|
||||
}
|
||||
if (_parentVertexTag[fVerts[1]]._selected) {
|
||||
markSparseIndexNeighbor(fChildFaces[1]);
|
||||
markSparseIndexNeighbor(fChildEdges[1]);
|
||||
}
|
||||
if (_parentVertexTag[fVerts[2]]._selected) {
|
||||
markSparseIndexNeighbor(fChildFaces[2]);
|
||||
markSparseIndexNeighbor(fChildEdges[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/triRefinement.h
vendored
Normal file
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/triRefinement.h
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_TRI_REFINEMENT_H
|
||||
#define OPENSUBDIV3_VTR_TRI_REFINEMENT_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/refinement.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// TriRefinement:
|
||||
// A TriRefinement is a subclass of Refinement that splits all faces into tris.
|
||||
// It provides the configuration of parent-to-child components and the population of
|
||||
// all required topological relations in order to complete a valid Refinement.
|
||||
//
|
||||
class TriRefinement : public Refinement {
|
||||
|
||||
public:
|
||||
TriRefinement(Level const & parent, Level & child, Sdc::Options const & options);
|
||||
~TriRefinement();
|
||||
|
||||
protected:
|
||||
//
|
||||
// Virtual methods to complete the configuration of the parent-to-child mapping:
|
||||
//
|
||||
virtual void allocateParentChildIndices();
|
||||
|
||||
virtual void markSparseFaceChildren();
|
||||
|
||||
//
|
||||
// Virtual methods to populate the six topological relations:
|
||||
//
|
||||
virtual void populateFaceVertexRelation();
|
||||
virtual void populateFaceEdgeRelation();
|
||||
virtual void populateEdgeVertexRelation();
|
||||
virtual void populateEdgeFaceRelation();
|
||||
virtual void populateVertexFaceRelation();
|
||||
virtual void populateVertexEdgeRelation();
|
||||
|
||||
//
|
||||
// Internal helper methods for populating the topology -- a few of these are
|
||||
// identical to what is used for quad-splitting, so we may move them to the
|
||||
// base class...
|
||||
//
|
||||
void populateFaceVertexCountsAndOffsets();
|
||||
void populateFaceVerticesFromParentFaces();
|
||||
|
||||
void populateFaceEdgesFromParentFaces();
|
||||
|
||||
void populateEdgeVerticesFromParentFaces();
|
||||
void populateEdgeVerticesFromParentEdges();
|
||||
|
||||
void populateEdgeFacesFromParentFaces();
|
||||
void populateEdgeFacesFromParentEdges();
|
||||
|
||||
void populateVertexFacesFromParentEdges();
|
||||
void populateVertexFacesFromParentVertices();
|
||||
|
||||
void populateVertexEdgesFromParentEdges();
|
||||
void populateVertexEdgesFromParentVertices();
|
||||
|
||||
private:
|
||||
//
|
||||
// Unlike the quad-split, which can share some vectors with the parent Level since
|
||||
// child components correspond to face-vertices, the tri-split must define its
|
||||
// own local vectors to identify the children for each parent component -- to
|
||||
// be referenced within the base class for more immediate/inline access:
|
||||
//
|
||||
IndexVector _localFaceChildFaceCountsAndOffsets;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_REFINEMENT_H */
|
||||
75
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/types.h
vendored
Normal file
75
blender-5.2.0/extern/opensubdiv-source/opensubdiv/vtr/types.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_VTR_TYPES_H
|
||||
#define OPENSUBDIV3_VTR_TYPES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/array.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr {
|
||||
|
||||
//
|
||||
// A few types (and constants) for use within Vtr and potentially by its
|
||||
// clients (appropriately exported and retyped)
|
||||
//
|
||||
|
||||
//
|
||||
// Integer type and constants to index the vectors of components. Note that we
|
||||
// can't use specific width integer types like uint32_t, etc. as use of stdint
|
||||
// is not portable.
|
||||
//
|
||||
// The convention throughout the OpenSubdiv code is to use "int" in most places,
|
||||
// with "unsigned int" being limited to a few cases (why?). So we continue that
|
||||
// trend here and use "int" for topological indices (with -1 indicating "invalid")
|
||||
// despite the fact that we lose half the range compared to using "uint" (with ~0
|
||||
// as invalid).
|
||||
//
|
||||
typedef int Index;
|
||||
|
||||
static const Index INDEX_INVALID = -1;
|
||||
|
||||
inline bool IndexIsValid(Index index) { return (index != INDEX_INVALID); }
|
||||
|
||||
//
|
||||
// Integer type and constants used to index one component within another. Ideally
|
||||
// this is just 2 bits once refinement reduces faces to tris or quads -- and so
|
||||
// could potentially be combined with an Index -- but we need something larger for
|
||||
// the N-sided face.
|
||||
//
|
||||
typedef unsigned short LocalIndex;
|
||||
|
||||
// Declared as "int" since it's intended for more general use
|
||||
static const int VALENCE_LIMIT = ((1 << 16) - 1); // std::numeric_limits<LocalIndex>::max()
|
||||
|
||||
//
|
||||
// Collections of integer types in variable or fixed sized arrays. Note that the use
|
||||
// of "vector" in the name indicates a class that wraps an std::vector (typically a
|
||||
// member variable) which is fully resizable and owns its own storage, whereas "array"
|
||||
// wraps a vtr::Array which uses a fixed block of pre-allocated memory.
|
||||
//
|
||||
typedef std::vector<Index> IndexVector;
|
||||
|
||||
typedef Array<Index> IndexArray;
|
||||
typedef ConstArray<Index> ConstIndexArray;
|
||||
|
||||
typedef Array<LocalIndex> LocalIndexArray;
|
||||
typedef ConstArray<LocalIndex> ConstLocalIndexArray;
|
||||
|
||||
|
||||
} // end namespace Vtr
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_VTR_TYPES_H */
|
||||
Reference in New Issue
Block a user