Add Chromium-only Blender WebEngine parity work
This commit is contained in:
91
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/CMakeLists.txt
vendored
Normal file
91
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
#
|
||||
# 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
|
||||
bilinearPatchBuilder.cpp
|
||||
catmarkPatchBuilder.cpp
|
||||
error.cpp
|
||||
loopPatchBuilder.cpp
|
||||
patchBasis.cpp
|
||||
patchBuilder.cpp
|
||||
patchDescriptor.cpp
|
||||
patchMap.cpp
|
||||
patchTable.cpp
|
||||
patchTableFactory.cpp
|
||||
ptexIndices.cpp
|
||||
stencilTable.cpp
|
||||
stencilTableFactory.cpp
|
||||
stencilBuilder.cpp
|
||||
topologyDescriptor.cpp
|
||||
topologyRefiner.cpp
|
||||
topologyRefinerFactory.cpp
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADER_FILES
|
||||
bilinearPatchBuilder.h
|
||||
catmarkPatchBuilder.h
|
||||
loopPatchBuilder.h
|
||||
patchBasis.h
|
||||
patchBuilder.h
|
||||
sparseMatrix.h
|
||||
stencilBuilder.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADER_FILES
|
||||
error.h
|
||||
patchDescriptor.h
|
||||
patchParam.h
|
||||
patchMap.h
|
||||
patchTable.h
|
||||
patchTableFactory.h
|
||||
primvarRefiner.h
|
||||
ptexIndices.h
|
||||
stencilTable.h
|
||||
stencilTableFactory.h
|
||||
topologyDescriptor.h
|
||||
topologyLevel.h
|
||||
topologyRefiner.h
|
||||
topologyRefinerFactory.h
|
||||
types.h
|
||||
)
|
||||
|
||||
set(DOXY_HEADER_FILES ${PUBLIC_HEADER_FILES})
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
if (NOT NO_LIB)
|
||||
|
||||
# Compile objs first for both the CPU and GPU libs -----
|
||||
add_library(far_obj
|
||||
OBJECT
|
||||
${SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(far_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
osd_add_doxy_headers( "${DOXY_HEADER_FILES}" )
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/far"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/bilinearPatchBuilder.cpp
vendored
Normal file
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/bilinearPatchBuilder.cpp
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright 2018 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/bilinearPatchBuilder.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
using Vtr::internal::FVarLevel;
|
||||
using Vtr::internal::Refinement;
|
||||
|
||||
namespace Far {
|
||||
|
||||
namespace {
|
||||
|
||||
//
|
||||
// The patch type associated with each basis for Bilinear -- quickly indexed
|
||||
// from an array. The patch type here is essentially the quad form of each
|
||||
// basis.
|
||||
//
|
||||
PatchDescriptor::Type patchTypeFromBasisArray[] = {
|
||||
PatchDescriptor::NON_PATCH, // undefined
|
||||
PatchDescriptor::QUADS, // regular
|
||||
PatchDescriptor::GREGORY_BASIS, // Gregory
|
||||
PatchDescriptor::QUADS, // linear
|
||||
PatchDescriptor::NON_PATCH }; // Bezier -- for future use
|
||||
};
|
||||
|
||||
BilinearPatchBuilder::BilinearPatchBuilder(
|
||||
TopologyRefiner const& refiner, Options const& options) :
|
||||
PatchBuilder(refiner, options) {
|
||||
|
||||
_regPatchType = patchTypeFromBasisArray[_options.regBasisType];
|
||||
_irregPatchType = (_options.irregBasisType == BASIS_UNSPECIFIED)
|
||||
? _regPatchType
|
||||
: patchTypeFromBasisArray[_options.irregBasisType];
|
||||
|
||||
_nativePatchType = PatchDescriptor::QUADS;
|
||||
_linearPatchType = PatchDescriptor::QUADS;
|
||||
}
|
||||
|
||||
BilinearPatchBuilder::~BilinearPatchBuilder() {
|
||||
}
|
||||
|
||||
PatchDescriptor::Type
|
||||
BilinearPatchBuilder::patchTypeFromBasis(BasisType basis) const {
|
||||
|
||||
return patchTypeFromBasisArray[(int)basis];
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
int
|
||||
BilinearPatchBuilder::convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const {
|
||||
|
||||
assert("Conversion from Bilinear patches to other bases not yet supported" == 0);
|
||||
|
||||
// For suppressing warnings until implemented...
|
||||
if (sourcePatch.GetNumSourcePoints() == 0) return -1;
|
||||
if (patchType == PatchDescriptor::NON_PATCH) return -1;
|
||||
if (matrix.GetNumRows() <= 0) return -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
BilinearPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const {
|
||||
return convertSourcePatch(sourcePatch, patchType, matrix);
|
||||
}
|
||||
int
|
||||
BilinearPatchBuilder::convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const {
|
||||
return convertSourcePatch(sourcePatch, patchType, matrix);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
56
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/bilinearPatchBuilder.h
vendored
Normal file
56
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/bilinearPatchBuilder.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// BilinearPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_BILINEAR.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class BilinearPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
BilinearPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~BilinearPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
private:
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_BILINEAR_PATCH_BUILDER_H */
|
||||
1989
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/catmarkPatchBuilder.cpp
vendored
Normal file
1989
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/catmarkPatchBuilder.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/catmarkPatchBuilder.h
vendored
Normal file
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/catmarkPatchBuilder.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// CatmarkPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_CATMARK.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class CatmarkPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
CatmarkPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~CatmarkPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
|
||||
private:
|
||||
typedef SparseMatrix<float> ConversionMatrix;
|
||||
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_CATMARK_PATCH_BUILDER_H */
|
||||
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/error.cpp
vendored
Normal file
90
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/error.cpp
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Statics for the publicly assignable callbacks and the methods to
|
||||
// assign them (disable static assignment warnings when doing so):
|
||||
//
|
||||
static ErrorCallbackFunc errorFunc = 0;
|
||||
static WarningCallbackFunc warningFunc = 0;
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning disable 1711
|
||||
#endif
|
||||
|
||||
void SetErrorCallback(ErrorCallbackFunc func) {
|
||||
errorFunc = func;
|
||||
}
|
||||
|
||||
void SetWarningCallback(WarningCallbackFunc func) {
|
||||
warningFunc = func;
|
||||
}
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning enable 1711
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// The default error and warning callbacks eventually belong in the
|
||||
// internal namespace:
|
||||
//
|
||||
void Error(ErrorType err, const char *format, ...) {
|
||||
|
||||
static char const * errorTypeLabel[] = {
|
||||
"No Error",
|
||||
"Fatal Error",
|
||||
"Coding Error (internal)",
|
||||
"Coding Error",
|
||||
"Error"
|
||||
};
|
||||
|
||||
assert(err!=FAR_NO_ERROR);
|
||||
|
||||
char message[10240];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsnprintf(message, 10240, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (errorFunc) {
|
||||
errorFunc(err, message);
|
||||
} else {
|
||||
printf("%s: %s\n", errorTypeLabel[err], message);
|
||||
}
|
||||
}
|
||||
|
||||
void Warning(const char *format, ...) {
|
||||
|
||||
char message[10240];
|
||||
va_list argptr;
|
||||
va_start(argptr, format);
|
||||
vsnprintf(message, 10240, format, argptr);
|
||||
va_end(argptr);
|
||||
|
||||
if (warningFunc) {
|
||||
warningFunc(message);
|
||||
} else {
|
||||
fprintf(stdout, "Warning: %s\n", message);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
78
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/error.h
vendored
Normal file
78
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/error.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_ERROR_H
|
||||
#define OPENSUBDIV3_FAR_ERROR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
typedef enum {
|
||||
FAR_NO_ERROR, ///< No error. Move along.
|
||||
FAR_FATAL_ERROR, ///< Issue a fatal error and end the program.
|
||||
FAR_INTERNAL_CODING_ERROR, ///< Issue an internal programming error, but continue execution.
|
||||
FAR_CODING_ERROR, ///< Issue a generic programming error, but continue execution.
|
||||
FAR_RUNTIME_ERROR ///< Issue a generic runtime error, but continue execution.
|
||||
} ErrorType;
|
||||
|
||||
|
||||
/// \brief The error callback function type (default is "printf")
|
||||
typedef void (*ErrorCallbackFunc)(ErrorType err, const char *message);
|
||||
|
||||
/// \brief Sets the error callback function (default is "printf")
|
||||
///
|
||||
/// \note This function is not thread-safe !
|
||||
///
|
||||
/// @param func function pointer to the callback function
|
||||
///
|
||||
void SetErrorCallback(ErrorCallbackFunc func);
|
||||
|
||||
|
||||
/// \brief The warning callback function type (default is "printf")
|
||||
typedef void (*WarningCallbackFunc)(const char *message);
|
||||
|
||||
/// \brief Sets the warning callback function (default is "printf")
|
||||
///
|
||||
/// \note This function is not thread-safe !
|
||||
///
|
||||
/// @param func function pointer to the callback function
|
||||
///
|
||||
void SetWarningCallback(WarningCallbackFunc func);
|
||||
|
||||
|
||||
//
|
||||
// The following are intended for internal use only (and will eventually
|
||||
// be moved within namespace internal)
|
||||
//
|
||||
|
||||
/// \brief Sends an OSD error with a message (internal use only)
|
||||
///
|
||||
/// @param err the error type
|
||||
///
|
||||
/// @param format the format of the message (followed by arguments)
|
||||
///
|
||||
void Error(ErrorType err, const char *format, ...);
|
||||
|
||||
/// \brief Sends an OSD warning message (internal use only)
|
||||
///
|
||||
/// @param format the format of the message (followed by arguments)
|
||||
///
|
||||
void Warning(const char *format, ...);
|
||||
|
||||
|
||||
} // end namespace
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_ERROR_H
|
||||
1873
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/loopPatchBuilder.cpp
vendored
Normal file
1873
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/loopPatchBuilder.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
56
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/loopPatchBuilder.h
vendored
Normal file
56
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/loopPatchBuilder.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchBuilder.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// LoopPatchBuilder
|
||||
//
|
||||
// Declaration of PatchBuilder subclass supporting Sdc::SCHEME_LOOP.
|
||||
// Required virtual methods are included, along with any customizations
|
||||
// local to their implementation.
|
||||
//
|
||||
class LoopPatchBuilder : public PatchBuilder {
|
||||
public:
|
||||
LoopPatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
virtual ~LoopPatchBuilder();
|
||||
|
||||
protected:
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const;
|
||||
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const;
|
||||
private:
|
||||
template <typename REAL>
|
||||
int convertSourcePatch(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_LOOP_PATCH_BUILDER_H */
|
||||
1388
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBasis.cpp
vendored
Normal file
1388
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBasis.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
93
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBasis.h
vendored
Normal file
93
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBasis.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_BASIS_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_BASIS_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchParam.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
//
|
||||
// XXXX barfowl: These functions are being kept internal while more complete
|
||||
// underlying support for all patch types is being worked out. The set of
|
||||
// bases supported here is actually larger than PatchDescriptor::Type -- with
|
||||
// Bezier available for internal use. A new and more complete set of types
|
||||
// is warranted (without the non-patch types associated with PatchDescriptor)
|
||||
// along with an interface to query properties associated with them.
|
||||
//
|
||||
// Note that with the high-level functions here that operate on all patch
|
||||
// types, it is not strictly necessary to expose the low-level methods in
|
||||
// currant usage.
|
||||
//
|
||||
|
||||
//
|
||||
// Low-level basis evaluation (normalized, unscaled) for quad patch types:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvalBasisLinear(REAL s, REAL t,
|
||||
REAL wP[4], REAL wDs[4] = 0, REAL wDt[4] = 0, REAL wDss[4] = 0, REAL wDst[4] = 0, REAL wDtt[4] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBezier(REAL s, REAL t,
|
||||
REAL wP[16], REAL wDs[16] = 0, REAL wDt[16] = 0, REAL wDss[16] = 0, REAL wDst[16] = 0, REAL wDtt[16] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBSpline(REAL s, REAL t,
|
||||
REAL wP[16], REAL wDs[16] = 0, REAL wDt[16] = 0, REAL wDss[16] = 0, REAL wDst[16] = 0, REAL wDtt[16] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisGregory(REAL s, REAL t,
|
||||
REAL wP[20], REAL wDs[20] = 0, REAL wDt[20] = 0, REAL wDss[20] = 0, REAL wDst[20] = 0, REAL wDtt[20] = 0);
|
||||
|
||||
//
|
||||
// Low-level basis evaluation (normalized, unscaled) for triangular patch types:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvalBasisLinearTri(REAL s, REAL t,
|
||||
REAL wP[3], REAL wDs[3] = 0, REAL wDt[3] = 0, REAL wDss[3] = 0, REAL wDst[3] = 0, REAL wDtt[3] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBezierTri(REAL s, REAL t,
|
||||
REAL wP[15], REAL wDs[15] = 0, REAL wDt[15] = 0, REAL wDss[15] = 0, REAL wDst[15] = 0, REAL wDtt[15] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisBoxSplineTri(REAL s, REAL t,
|
||||
REAL wP[12], REAL wDs[12] = 0, REAL wDt[12] = 0, REAL wDss[12] = 0, REAL wDst[12] = 0, REAL wDtt[12] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvalBasisGregoryTri(REAL s, REAL t,
|
||||
REAL wP[18], REAL wDs[18] = 0, REAL wDt[18] = 0, REAL wDss[18] = 0, REAL wDst[18] = 0, REAL wDtt[18] = 0);
|
||||
|
||||
|
||||
//
|
||||
// High-level basis evaluation for all types using PatchParam:
|
||||
//
|
||||
template <typename REAL>
|
||||
int EvaluatePatchBasisNormalized(int patchType, PatchParam const & param, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[] = 0, REAL wDt[] = 0, REAL wDss[] = 0, REAL wDst[] = 0, REAL wDtt[] = 0);
|
||||
|
||||
template <typename REAL>
|
||||
int EvaluatePatchBasis(int patchType, PatchParam const & param, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[] = 0, REAL wDt[] = 0, REAL wDss[] = 0, REAL wDst[] = 0, REAL wDtt[] = 0);
|
||||
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_BASIS_H */
|
||||
1607
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBuilder.cpp
vendored
Normal file
1607
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBuilder.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
315
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBuilder.h
vendored
Normal file
315
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchBuilder.h
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_BUILDER_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_BUILDER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../far/types.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/patchDescriptor.h"
|
||||
#include "../far/patchParam.h"
|
||||
#include "../far/ptexIndices.h"
|
||||
#include "../far/sparseMatrix.h"
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// SourcePatch
|
||||
//
|
||||
// This is a local utility class that captures the full local topology of an
|
||||
// arbitrarily irregular patch, i.e. a patch which may have one or all corners
|
||||
// irregular. Given the topology at each corner the entire collection of
|
||||
// points involved is identified and oriented consistently.
|
||||
//
|
||||
// Note (barfowl):
|
||||
// This was originally a class internal to PatchBuilder, but there is some
|
||||
// redundancy between it and the Level::VSpan used more publicly to identify
|
||||
// irregular corner topology. Replacing VSpan with SourcePatch is now under
|
||||
// consideration, and doing so will impact its public/private interface (which
|
||||
// was left public to give PatchBuilder access).
|
||||
// A simpler constructor to initialize an instance given a set of Corners
|
||||
// would also be preferable if made more public (i.e. public for use within
|
||||
// the library, not exported to clients) -- eliminating the need for the
|
||||
// explicit initialization and required call to the Finalize() method that
|
||||
// the PatchBuilder currently performs internally.
|
||||
//
|
||||
class SourcePatch {
|
||||
public:
|
||||
struct Corner {
|
||||
Corner() { std::memset((void*) this, 0, sizeof(Corner)); }
|
||||
|
||||
LocalIndex _numFaces; // valence of corner vertex
|
||||
LocalIndex _patchFace; // location of patch within incident faces
|
||||
|
||||
unsigned short _boundary : 1;
|
||||
unsigned short _sharp : 1;
|
||||
unsigned short _dart : 1;
|
||||
|
||||
// For internal bookkeeping -- consider hiding or moving elsewhere
|
||||
unsigned short _sharesWithPrev : 1;
|
||||
unsigned short _sharesWithNext : 1;
|
||||
unsigned short _val2Interior : 1;
|
||||
unsigned short _val2Adjacent : 1;
|
||||
};
|
||||
|
||||
public:
|
||||
SourcePatch() { std::memset((void*) this, 0, sizeof(SourcePatch)); }
|
||||
~SourcePatch() { }
|
||||
|
||||
// To be called after all Corners have been initialized (hope to
|
||||
// replace this with alternative constructor at some point)
|
||||
void Finalize(int size3or4);
|
||||
|
||||
int GetNumSourcePoints() const { return _numSourcePoints; }
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
int GetMaxRingSize() const { return _maxRingSize; }
|
||||
|
||||
int GetCornerRingSize(int corner) const { return _ringSizes[corner]; }
|
||||
int GetCornerRingPoints(int corner, int points[]) const;
|
||||
|
||||
// public/private access needs to be reviewed when/if used more publicly
|
||||
//private:
|
||||
public:
|
||||
// The SourcePatch is fully defined by its Corner members
|
||||
Corner _corners[4];
|
||||
int _numCorners;
|
||||
|
||||
// Additional members (derived from Corners) to help assemble corner rings:
|
||||
int _numSourcePoints;
|
||||
int _maxValence;
|
||||
int _maxRingSize;
|
||||
|
||||
int _ringSizes[4];
|
||||
int _localRingSizes[4];
|
||||
int _localRingOffsets[4];
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// PatchBuilder
|
||||
//
|
||||
// This is the main class to assist the identification of limit surface
|
||||
// patches from faces in a TopologyRefiner for assembly into other, larger
|
||||
// datatypes.
|
||||
//
|
||||
// The PatchBuilder takes a const reference to a refiner and supports
|
||||
// arbitrarily refined hierarchies, i.e. it is not restricted to uniform or
|
||||
// adaptive refinement strategies and does not include any logic relating
|
||||
// to the origin of the hierarchy. It can associate a patch with any face
|
||||
// in the hierarchy (subject to a few minimum requirements) -- leaving the
|
||||
// decision as to which faces/patches are appropriate to its client.
|
||||
//
|
||||
// PatchBuilder is an abstract base class with a subclass derived to support
|
||||
// each subdivision scheme -- as such, construction relies on a factory
|
||||
// method to create an instance of the appropriate subclass. Only two pure
|
||||
// virtual methods are required (other than the required destructor):
|
||||
//
|
||||
// - determine the patch type for a subdivision scheme given a more
|
||||
// general basis specification (e.g. Bezier, Gregory, Linear, etc)
|
||||
//
|
||||
// - convert the vertices in the subdivision hierarchy into points of a
|
||||
// specified patch type, using computations specific to that scheme
|
||||
//
|
||||
// The base class handles the more general topological analysis that
|
||||
// determines the nature of a patch associated with each face -- providing
|
||||
// both queries to the client, along with more involved methods to extract
|
||||
// or convert data associated with the patches. There is no concrete "Patch"
|
||||
// class to which all clients would be required to conform. The queries and
|
||||
// data returned are provided for clients to assemble into patches or other
|
||||
// aggregates as they see fit.
|
||||
//
|
||||
// This is intended as an internal/private class for use within the library
|
||||
// for now -- possibly to be exported for use by clients when/if its
|
||||
// interface is appropriate and stable.
|
||||
//
|
||||
class PatchBuilder {
|
||||
public:
|
||||
//
|
||||
// A PatchBuilder is constructed given a patch "basis" rather than a
|
||||
// "type" to use with the subdivision scheme involved. The relevant
|
||||
// explicit patch types will be determined from the basis and scheme:
|
||||
//
|
||||
enum BasisType {
|
||||
BASIS_UNSPECIFIED,
|
||||
BASIS_REGULAR,
|
||||
BASIS_GREGORY,
|
||||
BASIS_LINEAR,
|
||||
BASIS_BEZIER // to be supported in future
|
||||
};
|
||||
|
||||
//
|
||||
// Required Options specify a patch basis to use for both regular and
|
||||
// irregular patches -- sparing the client the need to repeatedly
|
||||
// specify these for each face considered. Other options are included
|
||||
// to support legacy approximations:
|
||||
//
|
||||
struct Options {
|
||||
Options() : regBasisType(BASIS_UNSPECIFIED),
|
||||
irregBasisType(BASIS_UNSPECIFIED),
|
||||
fillMissingBoundaryPoints(false),
|
||||
approxInfSharpWithSmooth(false),
|
||||
approxSmoothCornerWithSharp(false) { }
|
||||
|
||||
BasisType regBasisType;
|
||||
BasisType irregBasisType;
|
||||
bool fillMissingBoundaryPoints;
|
||||
bool approxInfSharpWithSmooth;
|
||||
bool approxSmoothCornerWithSharp;
|
||||
};
|
||||
|
||||
public:
|
||||
//
|
||||
// Public construction (via factory method) and destruction:
|
||||
//
|
||||
static PatchBuilder* Create(TopologyRefiner const& refiner,
|
||||
Options const& options);
|
||||
virtual ~PatchBuilder();
|
||||
|
||||
//
|
||||
// High-level queries related to the subdivision scheme of the refiner, the
|
||||
// patch types associated with it and those chosen to represent its faces:
|
||||
//
|
||||
int GetRegularFaceSize() const { return _schemeRegFaceSize; }
|
||||
|
||||
BasisType GetRegularBasisType() const { return _options.regBasisType; }
|
||||
BasisType GetIrregularBasisType() const { return _options.irregBasisType; }
|
||||
|
||||
PatchDescriptor::Type GetRegularPatchType() const { return _regPatchType; }
|
||||
PatchDescriptor::Type GetIrregularPatchType() const { return _irregPatchType; }
|
||||
|
||||
PatchDescriptor::Type GetNativePatchType() const { return _nativePatchType; }
|
||||
PatchDescriptor::Type GetLinearPatchType() const { return _linearPatchType; }
|
||||
|
||||
//
|
||||
// Face-level queries to determine presence of patches:
|
||||
//
|
||||
bool IsFaceAPatch(int level, Index face) const;
|
||||
bool IsFaceALeaf(int level, Index face) const;
|
||||
|
||||
//
|
||||
// Patch-level topological queries:
|
||||
//
|
||||
bool IsPatchRegular(int level, Index face, int fvc = -1) const;
|
||||
|
||||
int GetRegularPatchBoundaryMask(int level, Index face, int fvc = -1) const;
|
||||
|
||||
void GetIrregularPatchCornerSpans(int level, Index face,
|
||||
Vtr::internal::Level::VSpan cornerSpans[4], int fvc = -1) const;
|
||||
|
||||
bool DoesFaceVaryingPatchMatch(int level, Index face, int fvc) const {
|
||||
return _refiner.getLevel(level).doesFaceFVarTopologyMatch(face, fvc);
|
||||
}
|
||||
|
||||
//
|
||||
// Patch-level control point retrieval and methods for converting source
|
||||
// points to a set of local points in a different basis
|
||||
//
|
||||
int GetRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, // compute internally when < 0
|
||||
Index patchPoints[],
|
||||
int fvc = -1) const;
|
||||
|
||||
template <typename REAL>
|
||||
int GetIrregularPatchConversionMatrix(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SparseMatrix<REAL> & matrix) const;
|
||||
|
||||
int GetIrregularPatchSourcePoints(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
Index sourcePoints[],
|
||||
int fvc = -1) const;
|
||||
//
|
||||
// Queries related to "single-crease" patches -- currently a subset of
|
||||
// regular interior patches:
|
||||
//
|
||||
struct SingleCreaseInfo {
|
||||
int creaseEdgeInFace;
|
||||
float creaseSharpness;
|
||||
};
|
||||
bool IsRegularSingleCreasePatch(int level, Index face,
|
||||
SingleCreaseInfo & info) const;
|
||||
|
||||
//
|
||||
// Computing the PatchParam -- note the regrettable dependency on
|
||||
// PtexIndices but PatchParam is essentially tied to it indefinitely.
|
||||
// Better to pass it in than have the PatchBuilder build its own
|
||||
// PtexIndices.
|
||||
//
|
||||
// Consider creating a PatchParamFactory which can manage the PtexIndices
|
||||
// along with this method. It will then be able to generate additional
|
||||
// data to accelerate these computations.
|
||||
//
|
||||
PatchParam ComputePatchParam(int level, Index face,
|
||||
PtexIndices const& ptexIndices, bool isRegular = true,
|
||||
int boundaryMask = 0, bool computeTransitionMask = false) const;
|
||||
|
||||
protected:
|
||||
PatchBuilder(TopologyRefiner const& refiner, Options const& options);
|
||||
|
||||
// Internal methods supporting topology queries:
|
||||
int getRegularFacePoints(int level, Index face,
|
||||
Index patchPoints[], int fvc) const;
|
||||
|
||||
int getQuadRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, Index patchPoints[], int fvc) const;
|
||||
|
||||
int getTriRegularPatchPoints(int level, Index face,
|
||||
int regBoundaryMask, Index patchPoints[], int fvc) const;
|
||||
|
||||
// Internal methods using the SourcePatch:
|
||||
int assembleIrregularSourcePatch(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SourcePatch & sourcePatch) const;
|
||||
|
||||
int gatherIrregularSourcePoints(int level, Index face,
|
||||
Vtr::internal::Level::VSpan const cornerSpans[],
|
||||
SourcePatch & sourcePatch,
|
||||
Index patchPoints[], int fvc) const;
|
||||
|
||||
protected:
|
||||
//
|
||||
// Virtual methods to be provided by subclass for each scheme:
|
||||
//
|
||||
virtual PatchDescriptor::Type patchTypeFromBasis(BasisType basis) const = 0;
|
||||
|
||||
// Note overloading of the conversion for SparseMatrix<REAL>:
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<float> & matrix) const = 0;
|
||||
virtual int convertToPatchType(SourcePatch const & sourcePatch,
|
||||
PatchDescriptor::Type patchType,
|
||||
SparseMatrix<double> & matrix) const = 0;
|
||||
|
||||
protected:
|
||||
TopologyRefiner const& _refiner;
|
||||
Options const _options;
|
||||
|
||||
Sdc::SchemeType _schemeType;
|
||||
int _schemeRegFaceSize;
|
||||
bool _schemeIsLinear;
|
||||
|
||||
PatchDescriptor::Type _regPatchType;
|
||||
PatchDescriptor::Type _irregPatchType;
|
||||
PatchDescriptor::Type _nativePatchType;
|
||||
PatchDescriptor::Type _linearPatchType;
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_BUILDER_H */
|
||||
75
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchDescriptor.cpp
vendored
Normal file
75
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchDescriptor.cpp
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.
|
||||
//
|
||||
|
||||
#include "../far/patchDescriptor.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Lists of valid patch Descriptors for each subdivision scheme
|
||||
//
|
||||
// Historically this has only included the non-linear patch types, though
|
||||
// it is possible for linear patches to represent irregularities for both
|
||||
// Catmark and Loop, and the Bilinear scheme is adaptively refined into
|
||||
// linear quads (e.g. a pentagon becoming five quads).
|
||||
//
|
||||
|
||||
ConstPatchDescriptorArray
|
||||
PatchDescriptor::GetAdaptivePatchDescriptors(Sdc::SchemeType type) {
|
||||
|
||||
static PatchDescriptor _loopDescriptors[] = {
|
||||
PatchDescriptor(LOOP),
|
||||
PatchDescriptor(GREGORY_TRIANGLE),
|
||||
};
|
||||
|
||||
static PatchDescriptor _catmarkDescriptors[] = {
|
||||
PatchDescriptor(REGULAR),
|
||||
PatchDescriptor(GREGORY),
|
||||
PatchDescriptor(GREGORY_BOUNDARY),
|
||||
PatchDescriptor(GREGORY_BASIS),
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case Sdc::SCHEME_BILINEAR :
|
||||
return ConstPatchDescriptorArray(0, 0);
|
||||
case Sdc::SCHEME_CATMARK :
|
||||
return ConstPatchDescriptorArray(_catmarkDescriptors,
|
||||
(int)(sizeof(_catmarkDescriptors)/sizeof(PatchDescriptor)));
|
||||
case Sdc::SCHEME_LOOP :
|
||||
return ConstPatchDescriptorArray(_loopDescriptors,
|
||||
(int)(sizeof(_loopDescriptors)/sizeof(PatchDescriptor)));
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return ConstPatchDescriptorArray(0, 0);;
|
||||
}
|
||||
|
||||
void
|
||||
PatchDescriptor::print() const {
|
||||
static char const * types[13] = {
|
||||
"NON_PATCH", "POINTS", "LINES", "QUADS", "TRIANGLES", "LOOP",
|
||||
"REGULAR", "GREGORY", "GREGORY_BOUNDARY", "GREGORY_BASIS",
|
||||
"GREGORY_TRIANGLE"};
|
||||
|
||||
printf(" type %s\n",
|
||||
types[_type]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
176
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchDescriptor.h
vendored
Normal file
176
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchDescriptor.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
#include "../sdc/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Describes the type of a patch
|
||||
///
|
||||
/// Uniquely identifies all the different types of patches
|
||||
///
|
||||
class PatchDescriptor {
|
||||
|
||||
public:
|
||||
|
||||
enum Type {
|
||||
NON_PATCH = 0, ///< undefined
|
||||
|
||||
POINTS, ///< points (useful for cage drawing)
|
||||
LINES, ///< lines (useful for cage drawing)
|
||||
|
||||
QUADS, ///< 4-sided quadrilateral (bilinear)
|
||||
TRIANGLES, ///< 3-sided triangle
|
||||
|
||||
LOOP, ///< regular triangular patch for the Loop scheme
|
||||
|
||||
REGULAR, ///< regular B-Spline patch for the Catmark scheme
|
||||
GREGORY,
|
||||
GREGORY_BOUNDARY,
|
||||
GREGORY_BASIS,
|
||||
GREGORY_TRIANGLE
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Default constructor.
|
||||
PatchDescriptor() :
|
||||
_type(NON_PATCH) { }
|
||||
|
||||
/// \brief Constructor
|
||||
PatchDescriptor(int type) :
|
||||
_type(type) { }
|
||||
|
||||
/// \brief Copy Constructor
|
||||
PatchDescriptor( PatchDescriptor const & d ) :
|
||||
_type(d.GetType()) { }
|
||||
|
||||
/// \brief Assignment operator
|
||||
PatchDescriptor & operator=( PatchDescriptor const & d ) {
|
||||
_type = d.GetType();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// \brief Returns the type of the patch
|
||||
Type GetType() const {
|
||||
return (Type)_type;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the type is an adaptive (non-linear) patch
|
||||
static inline bool IsAdaptive(Type type) {
|
||||
return type > TRIANGLES;
|
||||
}
|
||||
|
||||
/// \brief Returns true if the type is an adaptive patch
|
||||
bool IsAdaptive() const {
|
||||
return IsAdaptive( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Returns the number of control vertices expected for a patch of the
|
||||
/// type described
|
||||
static inline short GetNumControlVertices( Type t );
|
||||
|
||||
/// \brief Deprecated @see PatchDescriptor#GetNumControlVertices
|
||||
static inline short GetNumFVarControlVertices( Type t );
|
||||
|
||||
/// \brief Returns the number of control vertices expected for a patch of the
|
||||
/// type described
|
||||
short GetNumControlVertices() const {
|
||||
return GetNumControlVertices( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Deprecated @see PatchDescriptor#GetNumControlVertices
|
||||
short GetNumFVarControlVertices() const {
|
||||
return GetNumFVarControlVertices( this->GetType() );
|
||||
}
|
||||
|
||||
/// \brief Number of control vertices of Regular Patches in table.
|
||||
static short GetRegularPatchSize() { return 16; }
|
||||
|
||||
/// \brief Number of control vertices of Gregory (and Gregory Boundary) Patches in table.
|
||||
static short GetGregoryPatchSize() { return 4; }
|
||||
|
||||
/// \brief Number of control vertices of Gregory patch basis (20)
|
||||
static short GetGregoryBasisPatchSize() { return 20; }
|
||||
|
||||
|
||||
/// \brief Returns a vector of all the legal patch descriptors for the
|
||||
/// given adaptive subdivision scheme
|
||||
static Vtr::ConstArray<PatchDescriptor> GetAdaptivePatchDescriptors(Sdc::SchemeType type);
|
||||
|
||||
/// \brief Allows ordering of patches by type
|
||||
inline bool operator < ( PatchDescriptor const other ) const;
|
||||
|
||||
/// \brief True if the descriptors are identical
|
||||
inline bool operator == ( PatchDescriptor const other ) const;
|
||||
|
||||
// debug helper
|
||||
void print() const;
|
||||
|
||||
private:
|
||||
unsigned int _type;
|
||||
};
|
||||
|
||||
typedef Vtr::ConstArray<PatchDescriptor> ConstPatchDescriptorArray;
|
||||
|
||||
// Returns the number of control vertices expected for a patch of this type
|
||||
inline short
|
||||
PatchDescriptor::GetNumControlVertices( Type type ) {
|
||||
switch (type) {
|
||||
case REGULAR : return GetRegularPatchSize();
|
||||
case LOOP : return 12;
|
||||
case QUADS : return 4;
|
||||
case GREGORY :
|
||||
case GREGORY_BOUNDARY : return GetGregoryPatchSize();
|
||||
case GREGORY_BASIS : return GetGregoryBasisPatchSize();
|
||||
case GREGORY_TRIANGLE : return 18;
|
||||
case TRIANGLES : return 3;
|
||||
case LINES : return 2;
|
||||
case POINTS : return 1;
|
||||
default : return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of face-varying control vertices expected for a patch of this type
|
||||
inline short
|
||||
PatchDescriptor::GetNumFVarControlVertices( Type type ) {
|
||||
return PatchDescriptor::GetNumControlVertices(type);
|
||||
}
|
||||
|
||||
// Allows ordering of patches by type
|
||||
inline bool
|
||||
PatchDescriptor::operator < ( PatchDescriptor const other ) const {
|
||||
return (_type < other._type);
|
||||
}
|
||||
|
||||
// True if the descriptors are identical
|
||||
inline bool
|
||||
PatchDescriptor::operator == ( PatchDescriptor const other ) const {
|
||||
return _type == other._type;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_DESCRIPTOR_H */
|
||||
190
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchMap.cpp
vendored
Normal file
190
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchMap.cpp
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/patchMap.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Inline quadtree assembly methods used by the constructor:
|
||||
//
|
||||
|
||||
// sets all the children to point to the patch of given index
|
||||
inline void
|
||||
PatchMap::QuadNode::SetChildren(int index) {
|
||||
|
||||
for (int i=0; i<4; ++i) {
|
||||
children[i].isSet = true;
|
||||
children[i].isLeaf = true;
|
||||
children[i].index = index;
|
||||
}
|
||||
}
|
||||
|
||||
// sets the child in "quadrant" to point to the node or patch of the given index
|
||||
inline void
|
||||
PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf) {
|
||||
|
||||
assert(!children[quadrant].isSet);
|
||||
children[quadrant].isSet = true;
|
||||
children[quadrant].isLeaf = isLeaf;
|
||||
children[quadrant].index = index;
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchMap::assignRootNode(QuadNode * node, int index) {
|
||||
|
||||
// Assign the given index to all children of the node (all leaves)
|
||||
node->SetChildren(index);
|
||||
}
|
||||
|
||||
inline PatchMap::QuadNode *
|
||||
PatchMap::assignLeafOrChildNode(QuadNode * node, bool isLeaf, int quadrant, int index) {
|
||||
|
||||
// Assign the node given if it is a leaf node, otherwise traverse
|
||||
// the node -- creating/assigning a new child node if needed
|
||||
|
||||
if (isLeaf) {
|
||||
node->SetChild(quadrant, index, true);
|
||||
return node;
|
||||
}
|
||||
if (node->children[quadrant].isSet) {
|
||||
return &_quadtree[node->children[quadrant].index];
|
||||
} else {
|
||||
int newChildNodeIndex = (int)_quadtree.size();
|
||||
_quadtree.push_back(QuadNode());
|
||||
node->SetChild(quadrant, newChildNodeIndex, false);
|
||||
return &_quadtree[newChildNodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Constructor and initialization methods for the handles and quadtree:
|
||||
//
|
||||
PatchMap::PatchMap(PatchTable const & patchTable) :
|
||||
_minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0) {
|
||||
|
||||
_patchesAreTriangular =
|
||||
patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3;
|
||||
|
||||
if (patchTable.GetNumPatchesTotal() > 0) {
|
||||
initializeHandles(patchTable);
|
||||
initializeQuadtree(patchTable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PatchMap::initializeHandles(PatchTable const & patchTable) {
|
||||
|
||||
//
|
||||
// Populate the vector of patch Handles. Keep track of the min and max
|
||||
// face indices to allocate resources accordingly and limit queries:
|
||||
//
|
||||
_minPatchFace = (int) patchTable.GetPatchParamTable()[0].GetFaceId();
|
||||
_maxPatchFace = _minPatchFace;
|
||||
|
||||
int numArrays = (int) patchTable.GetNumPatchArrays();
|
||||
int numPatches = (int) patchTable.GetNumPatchesTotal();
|
||||
|
||||
_handles.resize(numPatches);
|
||||
|
||||
for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) {
|
||||
|
||||
ConstPatchParamArray params = patchTable.GetPatchParams(pArray);
|
||||
|
||||
int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices();
|
||||
|
||||
for (Index j=0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) {
|
||||
|
||||
Handle & h = _handles[handleIndex];
|
||||
|
||||
h.arrayIndex = pArray;
|
||||
h.patchIndex = handleIndex;
|
||||
h.vertIndex = j * patchSize;
|
||||
|
||||
int patchFaceId = params[j].GetFaceId();
|
||||
_minPatchFace = std::min(_minPatchFace, patchFaceId);
|
||||
_maxPatchFace = std::max(_maxPatchFace, patchFaceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PatchMap::initializeQuadtree(PatchTable const & patchTable) {
|
||||
|
||||
//
|
||||
// Reserve quadtree nodes for the worst case and prune later. Set the
|
||||
// initial size to accomodate the root node of each patch face:
|
||||
//
|
||||
int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1;
|
||||
|
||||
int nHandles = (int)_handles.size();
|
||||
|
||||
_quadtree.reserve(nPatchFaces + nHandles);
|
||||
_quadtree.resize(nPatchFaces);
|
||||
|
||||
PatchParamTable const & params = patchTable.GetPatchParamTable();
|
||||
|
||||
for (int handle = 0; handle < nHandles; ++handle) {
|
||||
|
||||
PatchParam const & param = params[handle];
|
||||
|
||||
int depth = param.GetDepth();
|
||||
int rootDepth = param.NonQuadRoot();
|
||||
|
||||
_maxDepth = std::max(_maxDepth, depth);
|
||||
|
||||
QuadNode * node = &_quadtree[param.GetFaceId() - _minPatchFace];
|
||||
|
||||
if (depth == rootDepth) {
|
||||
assignRootNode(node, handle);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_patchesAreTriangular) {
|
||||
// Use the UV bits of the PatchParam directly for quad patches:
|
||||
int u = param.GetU();
|
||||
int v = param.GetV();
|
||||
|
||||
for (int j = rootDepth + 1; j <= depth; ++j) {
|
||||
int uBit = (u >> (depth - j)) & 1;
|
||||
int vBit = (v >> (depth - j)) & 1;
|
||||
|
||||
int quadrant = (vBit << 1) | uBit;
|
||||
|
||||
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
|
||||
}
|
||||
} else {
|
||||
// Use an interior UV point of triangles to identify quadrants:
|
||||
double u = 0.25;
|
||||
double v = 0.25;
|
||||
param.UnnormalizeTriangle(u, v);
|
||||
|
||||
double median = 0.5;
|
||||
bool triRotated = false;
|
||||
|
||||
for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) {
|
||||
int quadrant = transformUVToTriQuadrant(median, u, v, triRotated);
|
||||
|
||||
node = assignLeafOrChildNode(node, (j == depth), quadrant, handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the Node vector with a copy to reduce worst case memory allocation:
|
||||
QuadTree tmpTree = _quadtree;
|
||||
_quadtree.swap(tmpTree);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
223
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchMap.h
vendored
Normal file
223
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchMap.h
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_MAP_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_MAP_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief An quadtree-based map connecting coarse faces to their sub-patches
|
||||
///
|
||||
/// PatchTable::PatchArrays contain lists of patches that represent the limit
|
||||
/// surface of a mesh, sorted by their topological type. These arrays break the
|
||||
/// connection between coarse faces and their sub-patches.
|
||||
///
|
||||
/// The PatchMap provides a quad-tree based lookup structure that, given a singular
|
||||
/// parametric location, can efficiently return a handle to the sub-patch that
|
||||
/// contains this location.
|
||||
///
|
||||
class PatchMap {
|
||||
public:
|
||||
|
||||
typedef PatchTable::PatchHandle Handle;
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param patchTable A valid PatchTable
|
||||
///
|
||||
PatchMap( PatchTable const & patchTable );
|
||||
|
||||
/// \brief Returns a handle to the sub-patch of the face at the given (u,v).
|
||||
/// Note that the patch face ID corresponds to potentially quadrangulated
|
||||
/// face indices and not the base face indices (see Far::PtexIndices for more
|
||||
/// details).
|
||||
///
|
||||
/// @param patchFaceId The index of the patch (Ptex) face
|
||||
///
|
||||
/// @param u Local u parameter
|
||||
///
|
||||
/// @param v Local v parameter
|
||||
///
|
||||
/// @return A patch handle or 0 if the face is not supported (index
|
||||
/// out of bounds) or is tagged as a hole
|
||||
///
|
||||
Handle const * FindPatch( int patchFaceId, double u, double v ) const;
|
||||
|
||||
private:
|
||||
void initializeHandles(PatchTable const & patchTable);
|
||||
void initializeQuadtree(PatchTable const & patchTable);
|
||||
|
||||
private:
|
||||
// Quadtree node with 4 children, tree is just a vector of nodes
|
||||
struct QuadNode {
|
||||
QuadNode() { std::memset(this, 0, sizeof(QuadNode)); }
|
||||
|
||||
struct Child {
|
||||
unsigned int isSet : 1; // true if the child has been set
|
||||
unsigned int isLeaf : 1; // true if the child is a QuadNode
|
||||
unsigned int index : 30; // child index (either QuadNode or Handle)
|
||||
};
|
||||
|
||||
// sets all the children to point to the patch of given index
|
||||
void SetChildren(int index);
|
||||
|
||||
// sets the child in "quadrant" to point to the node or patch of the given index
|
||||
void SetChild(int quadrant, int index, bool isLeaf);
|
||||
|
||||
Child children[4];
|
||||
};
|
||||
typedef std::vector<QuadNode> QuadTree;
|
||||
|
||||
// Internal methods supporting quadtree construction and queries
|
||||
void assignRootNode(QuadNode * node, int index);
|
||||
QuadNode * assignLeafOrChildNode(QuadNode * node, bool isLeaf, int quad, int index);
|
||||
|
||||
template <class T>
|
||||
static int transformUVToQuadQuadrant(T const & median, T & u, T & v);
|
||||
template <class T>
|
||||
static int transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated);
|
||||
|
||||
private:
|
||||
bool _patchesAreTriangular; // tri and quad assembly and search requirements differ
|
||||
|
||||
int _minPatchFace; // minimum patch face index supported by the map
|
||||
int _maxPatchFace; // maximum patch face index supported by the map
|
||||
int _maxDepth; // maximum depth of a patch in the tree
|
||||
|
||||
std::vector<Handle> _handles; // all the patches in the PatchTable
|
||||
std::vector<QuadNode> _quadtree; // quadtree nodes
|
||||
};
|
||||
|
||||
//
|
||||
// Given a median value for both U and V, these methods transform a (u,v) pair
|
||||
// into the quadrant that contains them and returns the quadrant index.
|
||||
//
|
||||
// Quadrant indexing for tri and quad patches -- consistent with PatchParam's
|
||||
// usage of UV bits:
|
||||
//
|
||||
// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0)
|
||||
// | | | |\ \ 1 |\ 0 |
|
||||
// | 2 | 3 | | \ \ | \ |
|
||||
// | | | | 2 \ \| 3 \|
|
||||
// o-----o-----o o-----o o-----o
|
||||
// | | | |\ 3 |\ \ 2 |
|
||||
// | 0 | 1 | | \ | \ \ |
|
||||
// | | | | 0 \| 1 \ \|
|
||||
// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1)
|
||||
//
|
||||
// The triangular case also takes and returns/affects the rotation of the
|
||||
// quadrant being searched and identified (quadrant 3 imparts a rotation).
|
||||
//
|
||||
template <class T>
|
||||
inline int
|
||||
PatchMap::transformUVToQuadQuadrant(T const & median, T & u, T & v) {
|
||||
|
||||
int uHalf = (u >= median);
|
||||
if (uHalf) u -= median;
|
||||
|
||||
int vHalf = (v >= median);
|
||||
if (vHalf) v -= median;
|
||||
|
||||
return (vHalf << 1) | uHalf;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
int inline
|
||||
PatchMap::transformUVToTriQuadrant(T const & median, T & u, T & v, bool & rotated) {
|
||||
|
||||
if (!rotated) {
|
||||
if (u >= median) {
|
||||
u -= median;
|
||||
return 1;
|
||||
}
|
||||
if (v >= median) {
|
||||
v -= median;
|
||||
return 2;
|
||||
}
|
||||
if ((u + v) >= median) {
|
||||
rotated = true;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (u < median) {
|
||||
v -= median;
|
||||
return 1;
|
||||
}
|
||||
if (v < median) {
|
||||
u -= median;
|
||||
return 2;
|
||||
}
|
||||
u -= median;
|
||||
v -= median;
|
||||
if ((u + v) < median) {
|
||||
rotated = false;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a handle to the sub-patch of the face at the given (u,v).
|
||||
inline PatchMap::Handle const *
|
||||
PatchMap::FindPatch( int faceid, double u, double v ) const {
|
||||
|
||||
//
|
||||
// Reject patch faces not supported by this map, or those corresponding
|
||||
// to holes or otherwise unassigned (the root node for a patch will
|
||||
// have all or no quadrants set):
|
||||
//
|
||||
if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) return 0;
|
||||
|
||||
QuadNode const * node = &_quadtree[faceid - _minPatchFace];
|
||||
|
||||
if (!node->children[0].isSet) return 0;
|
||||
|
||||
//
|
||||
// Search the tree for the sub-patch containing the given (u,v)
|
||||
//
|
||||
assert( (u>=0.0) && (u<=1.0) && (v>=0.0) && (v<=1.0) );
|
||||
|
||||
double median = 0.5;
|
||||
bool triRotated = false;
|
||||
|
||||
for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) {
|
||||
|
||||
int quadrant = _patchesAreTriangular
|
||||
? transformUVToTriQuadrant(median, u, v, triRotated)
|
||||
: transformUVToQuadQuadrant(median, u, v);
|
||||
|
||||
// holes should have been rejected at the root node of the face
|
||||
assert(node->children[quadrant].isSet);
|
||||
|
||||
if (node->children[quadrant].isLeaf) {
|
||||
return &_handles[node->children[quadrant].index];
|
||||
} else {
|
||||
node = &_quadtree[node->children[quadrant].index];
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_PARAM */
|
||||
315
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchParam.h
vendored
Normal file
315
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchParam.h
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_PARAM_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_PARAM_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Patch parameterization
|
||||
///
|
||||
/// Topological refinement splits coarse mesh faces into refined faces.
|
||||
///
|
||||
/// This patch parameterzation describes the relationship between one
|
||||
/// of these refined faces and its corresponding coarse face. It is used
|
||||
/// both for refined faces that are represented as full limit surface
|
||||
/// parametric patches as well as for refined faces represented as simple
|
||||
/// triangles or quads. This parameterization is needed to interpolate
|
||||
/// primvar data across a refined face.
|
||||
///
|
||||
/// The U,V and refinement level parameters describe the scale and offset
|
||||
/// needed to map a location on the patch between levels of refinement.
|
||||
/// The encoding of these values exploits the quad-tree organization of
|
||||
/// the faces produced by subdivision. We encode the U,V origin of the
|
||||
/// patch using two 10-bit integer values and the refinement level as
|
||||
/// a 4-bit integer. This is sufficient to represent up through 10 levels
|
||||
/// of refinement.
|
||||
///
|
||||
/// Special consideration must be given to the refined faces resulting from
|
||||
/// irregular coarse faces. We adopt a convention similar to Ptex texture
|
||||
/// mapping and define the parameterization for these faces in terms of the
|
||||
/// regular faces resulting from the first topological splitting of the
|
||||
/// irregular coarse face.
|
||||
///
|
||||
/// When computing the basis functions needed to evaluate the limit surface
|
||||
/// parametric patch representing a refined face, we also need to know which
|
||||
/// edges of the patch are interpolated boundaries. These edges are encoded
|
||||
/// as a boundary bitmask identifying the boundary edges of the patch in
|
||||
/// sequential order starting from the first vertex of the refined face.
|
||||
///
|
||||
/// A sparse topological refinement (like feature adaptive refinement) can
|
||||
/// produce refined faces that are adjacent to faces at the next level of
|
||||
/// subdivision. We identify these transitional edges with a transition
|
||||
/// bitmask using the same encoding as the boundary bitmask.
|
||||
///
|
||||
/// For triangular subdivision schemes we specify the parameterization using
|
||||
/// a similar method. Alternate triangles at a given level of refinement
|
||||
/// are parameterized from their opposite corners and encoded as occupying
|
||||
/// the opposite diagonal of the quad-tree hierarchy. The third barycentric
|
||||
/// coordinate is dependent on and can be derived from the other two
|
||||
/// coordinates. This encoding also takes inspiration from the Ptex
|
||||
/// texture mapping specification.
|
||||
///
|
||||
/// Bitfield layout :
|
||||
///
|
||||
/// Field0 | Bits | Content
|
||||
/// -----------|:----:|------------------------------------------------------
|
||||
/// faceId | 28 | the faceId of the patch
|
||||
/// transition | 4 | transition edge mask encoding
|
||||
///
|
||||
/// Field1 | Bits | Content
|
||||
/// -----------|:----:|------------------------------------------------------
|
||||
/// level | 4 | the subdivision level of the patch
|
||||
/// nonquad | 1 | whether patch is refined from a non-quad face
|
||||
/// regular | 1 | whether patch is regular
|
||||
/// unused | 1 | unused
|
||||
/// boundary | 5 | boundary edge mask encoding
|
||||
/// v | 10 | log2 value of u parameter at first patch corner
|
||||
/// u | 10 | log2 value of v parameter at first patch corner
|
||||
///
|
||||
/// Note : the bitfield is not expanded in the struct due to differences in how
|
||||
/// GPU & CPU compilers pack bit-fields and endian-ness.
|
||||
///
|
||||
/*!
|
||||
\verbatim
|
||||
Quad Patch Parameterization
|
||||
|
||||
(0,1) (1,1)
|
||||
+-------+-------+---------------+
|
||||
| | | |
|
||||
| L2 | L2 | |
|
||||
|0,3 |1,3 | |
|
||||
+-------+-------+ L1 |
|
||||
| | | |
|
||||
| L2 | L2 | |
|
||||
|0,2 |1,2 |1,1 |
|
||||
+-------+-------+---------------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| L1 | L1 |
|
||||
| | |
|
||||
| | |
|
||||
|0,0 |1,0 |
|
||||
+---------------+---------------+
|
||||
(0,0) (1,0)
|
||||
\endverbatim
|
||||
*/
|
||||
/*!
|
||||
\verbatim
|
||||
Triangle Patch Parameterization
|
||||
|
||||
(0,1) (1,1) (0,1,0)
|
||||
+-------+-------+---------------+ +
|
||||
| \ | \ | \ | | \
|
||||
|L2 \ |L2 \ | \ | | \
|
||||
|0,3 \ |1,3 \ | \ | | L2 \
|
||||
+-------+-------+ \ | +-------+
|
||||
| \ | \ | L1 \ | | \ L2 | \
|
||||
|L2 \ |L2 \ | \ | | \ | \
|
||||
|0,2 \ |1,2 \ |1,1 \ | | L2 \ | L2 \
|
||||
+-------+-------+---------------+ +-------+-------+
|
||||
| \ | \ | | \ | \
|
||||
| \ | \ | | \ | \
|
||||
| \ | \ | | \ L1 | \
|
||||
| \ | \ | | \ | \
|
||||
| L1 \ | L1 \ | | L1 \ | L1 \
|
||||
| \ | \ | | \ | \
|
||||
|0,0 \ |1,0 \ | | \ | \
|
||||
+---------------+---------------+ +---------------+---------------+
|
||||
(0,0) (1,0) (0,0,1) (1,0,0)
|
||||
\endverbatim
|
||||
*/
|
||||
|
||||
struct PatchParam {
|
||||
/// \brief Sets the values of the bit fields
|
||||
///
|
||||
/// @param faceid face index
|
||||
///
|
||||
/// @param u value of the u parameter for the first corner of the face
|
||||
/// @param v value of the v parameter for the first corner of the face
|
||||
///
|
||||
/// @param depth subdivision level of the patch
|
||||
/// @param nonquad true if the root face is not a quad
|
||||
///
|
||||
/// @param boundary 5-bits identifying boundary edges (and verts for tris)
|
||||
/// @param transition 4-bits identifying transition edges
|
||||
///
|
||||
/// @param regular whether the patch is regular
|
||||
///
|
||||
void Set(Index faceid, short u, short v,
|
||||
unsigned short depth, bool nonquad,
|
||||
unsigned short boundary, unsigned short transition,
|
||||
bool regular = false);
|
||||
|
||||
/// \brief Resets everything to 0
|
||||
void Clear() { field0 = field1 = 0; }
|
||||
|
||||
/// \brief Returns the faceid
|
||||
Index GetFaceId() const { return Index(unpack(field0,28,0)); }
|
||||
|
||||
/// \brief Returns the log2 value of the u parameter at
|
||||
/// the first corner of the patch
|
||||
unsigned short GetU() const { return (unsigned short)unpack(field1,10,22); }
|
||||
|
||||
/// \brief Returns the log2 value of the v parameter at
|
||||
/// the first corner of the patch
|
||||
unsigned short GetV() const { return (unsigned short)unpack(field1,10,12); }
|
||||
|
||||
/// \brief Returns the transition edge encoding for the patch.
|
||||
unsigned short GetTransition() const { return (unsigned short)unpack(field0,4,28); }
|
||||
|
||||
/// \brief Returns the boundary edge encoding for the patch.
|
||||
unsigned short GetBoundary() const { return (unsigned short)unpack(field1,5,7); }
|
||||
|
||||
/// \brief True if the parent base face is a non-quad
|
||||
bool NonQuadRoot() const { return (unpack(field1,1,4) != 0); }
|
||||
|
||||
/// \brief Returns the level of subdivision of the patch
|
||||
unsigned short GetDepth() const { return (unsigned short)unpack(field1,4,0); }
|
||||
|
||||
/// \brief Returns the fraction of unit parametric space covered by this face.
|
||||
float GetParamFraction() const;
|
||||
|
||||
/// \brief A (u,v) pair in the fraction of parametric space covered by this
|
||||
/// face is mapped into a normalized parametric space.
|
||||
///
|
||||
/// @param u u parameter
|
||||
/// @param v v parameter
|
||||
///
|
||||
template <typename REAL>
|
||||
void Normalize( REAL & u, REAL & v ) const;
|
||||
template <typename REAL>
|
||||
void NormalizeTriangle( REAL & u, REAL & v ) const;
|
||||
|
||||
/// \brief A (u,v) pair in a normalized parametric space is mapped back into the
|
||||
/// fraction of parametric space covered by this face.
|
||||
///
|
||||
/// @param u u parameter
|
||||
/// @param v v parameter
|
||||
///
|
||||
template <typename REAL>
|
||||
void Unnormalize( REAL & u, REAL & v ) const;
|
||||
template <typename REAL>
|
||||
void UnnormalizeTriangle( REAL & u, REAL & v ) const;
|
||||
|
||||
/// \brief Returns if a triangular patch is parametrically rotated 180 degrees
|
||||
bool IsTriangleRotated() const;
|
||||
|
||||
/// \brief Returns whether the patch is regular
|
||||
bool IsRegular() const { return (unpack(field1,1,5) != 0); }
|
||||
|
||||
unsigned int field0:32;
|
||||
unsigned int field1:32;
|
||||
|
||||
private:
|
||||
unsigned int pack(unsigned int value, int width, int offset) const {
|
||||
return (unsigned int)((value & ((1<<width)-1)) << offset);
|
||||
}
|
||||
|
||||
unsigned int unpack(unsigned int value, int width, int offset) const {
|
||||
return (unsigned int)((value >> offset) & ((1<<width)-1));
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<PatchParam> PatchParamTable;
|
||||
|
||||
typedef Vtr::Array<PatchParam> PatchParamArray;
|
||||
typedef Vtr::ConstArray<PatchParam> ConstPatchParamArray;
|
||||
|
||||
inline void
|
||||
PatchParam::Set(Index faceid, short u, short v,
|
||||
unsigned short depth, bool nonquad,
|
||||
unsigned short boundary, unsigned short transition,
|
||||
bool regular) {
|
||||
field0 = pack(faceid, 28, 0) |
|
||||
pack(transition, 4, 28);
|
||||
|
||||
field1 = pack(u, 10, 22) |
|
||||
pack(v, 10, 12) |
|
||||
pack(boundary, 5, 7) |
|
||||
pack(regular, 1, 5) |
|
||||
pack(nonquad, 1, 4) |
|
||||
pack(depth, 4, 0);
|
||||
}
|
||||
|
||||
inline float
|
||||
PatchParam::GetParamFraction( ) const {
|
||||
return 1.0f / (float)(1 << (GetDepth() - NonQuadRoot()));
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::Normalize( REAL & u, REAL & v ) const {
|
||||
|
||||
REAL fracInv = (REAL)(1.0f / GetParamFraction());
|
||||
|
||||
u = u * fracInv - (REAL)GetU();
|
||||
v = v * fracInv - (REAL)GetV();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::Unnormalize( REAL & u, REAL & v ) const {
|
||||
|
||||
REAL frac = (REAL)GetParamFraction();
|
||||
|
||||
u = (u + (REAL)GetU()) * frac;
|
||||
v = (v + (REAL)GetV()) * frac;
|
||||
}
|
||||
|
||||
inline bool
|
||||
PatchParam::IsTriangleRotated() const {
|
||||
|
||||
return (GetU() + GetV()) >= (1 << GetDepth());
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::NormalizeTriangle( REAL & u, REAL & v ) const {
|
||||
|
||||
if (IsTriangleRotated()) {
|
||||
REAL fracInv = (REAL)(1.0f / GetParamFraction());
|
||||
|
||||
int depthFactor = 1 << GetDepth();
|
||||
u = (REAL)(depthFactor - GetU()) - (u * fracInv);
|
||||
v = (REAL)(depthFactor - GetV()) - (v * fracInv);
|
||||
} else {
|
||||
Normalize(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
PatchParam::UnnormalizeTriangle( REAL & u, REAL & v ) const {
|
||||
|
||||
if (IsTriangleRotated()) {
|
||||
REAL frac = GetParamFraction();
|
||||
|
||||
int depthFactor = 1 << GetDepth();
|
||||
u = ((REAL)(depthFactor - GetU()) - u) * frac;
|
||||
v = ((REAL)(depthFactor - GetV()) - v) * frac;
|
||||
} else {
|
||||
Unnormalize(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_PARAM */
|
||||
637
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTable.cpp
vendored
Normal file
637
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTable.cpp
vendored
Normal file
@@ -0,0 +1,637 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
#include "../far/patchBasis.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
PatchTable::PatchTable(int maxvalence) :
|
||||
_maxValence(maxvalence),
|
||||
_localPointStencils(),
|
||||
_localPointVaryingStencils(),
|
||||
_varyingDesc(Far::PatchDescriptor::QUADS),
|
||||
_isUniformLinear(false),
|
||||
_vertexPrecisionIsDouble(false),
|
||||
_varyingPrecisionIsDouble(false),
|
||||
_faceVaryingPrecisionIsDouble(false) {
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
// XXXX manuelk we need to eliminate this constructor (C++11 smart pointers)
|
||||
PatchTable::PatchTable(PatchTable const & src) :
|
||||
_maxValence(src._maxValence),
|
||||
_numPtexFaces(src._numPtexFaces),
|
||||
_patchArrays(src._patchArrays),
|
||||
_patchVerts(src._patchVerts),
|
||||
_paramTable(src._paramTable),
|
||||
_quadOffsetsTable(src._quadOffsetsTable),
|
||||
_vertexValenceTable(src._vertexValenceTable),
|
||||
_localPointStencils(src._localPointStencils),
|
||||
_localPointVaryingStencils(src._localPointVaryingStencils),
|
||||
_varyingDesc(src._varyingDesc),
|
||||
_fvarChannels(src._fvarChannels),
|
||||
_sharpnessIndices(src._sharpnessIndices),
|
||||
_sharpnessValues(src._sharpnessValues),
|
||||
_isUniformLinear(src._isUniformLinear),
|
||||
_vertexPrecisionIsDouble(src._vertexPrecisionIsDouble),
|
||||
_varyingPrecisionIsDouble(src._varyingPrecisionIsDouble),
|
||||
_faceVaryingPrecisionIsDouble(src._faceVaryingPrecisionIsDouble) {
|
||||
|
||||
if (src._localPointStencils) {
|
||||
if (src._vertexPrecisionIsDouble) {
|
||||
_localPointStencils.Set(
|
||||
new StencilTableReal<double>(*src._localPointStencils.Get<double>()));
|
||||
} else {
|
||||
_localPointStencils.Set(
|
||||
new StencilTableReal<float>(*src._localPointStencils.Get<float>()));
|
||||
}
|
||||
}
|
||||
if (src._localPointVaryingStencils) {
|
||||
if (src._varyingPrecisionIsDouble) {
|
||||
_localPointVaryingStencils.Set(
|
||||
new StencilTableReal<double>(*src._localPointVaryingStencils.Get<double>()));
|
||||
} else {
|
||||
_localPointVaryingStencils.Set(
|
||||
new StencilTableReal<float>(*src._localPointVaryingStencils.Get<float>()));
|
||||
}
|
||||
}
|
||||
if (! src._localPointFaceVaryingStencils.empty()) {
|
||||
_localPointFaceVaryingStencils.resize(src._localPointFaceVaryingStencils.size());
|
||||
for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) {
|
||||
if (src._localPointFaceVaryingStencils[fvc]) {
|
||||
if (src._faceVaryingPrecisionIsDouble) {
|
||||
_localPointFaceVaryingStencils[fvc].Set(new StencilTableReal<double>(
|
||||
*src._localPointFaceVaryingStencils[fvc].Get<double>()));
|
||||
} else {
|
||||
_localPointFaceVaryingStencils[fvc].Set(new StencilTableReal<float>(
|
||||
*src._localPointFaceVaryingStencils[fvc].Get<float>()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PatchTable::~PatchTable() {
|
||||
if (_vertexPrecisionIsDouble) {
|
||||
delete _localPointStencils.Get<double>();
|
||||
} else {
|
||||
delete _localPointStencils.Get<float>();
|
||||
}
|
||||
|
||||
if (_varyingPrecisionIsDouble) {
|
||||
delete _localPointVaryingStencils.Get<double>();
|
||||
} else {
|
||||
delete _localPointVaryingStencils.Get<float>();
|
||||
}
|
||||
|
||||
for (int fvc=0; fvc<(int)_localPointFaceVaryingStencils.size(); ++fvc) {
|
||||
if (_faceVaryingPrecisionIsDouble) {
|
||||
delete _localPointFaceVaryingStencils[fvc].Get<double>();
|
||||
} else {
|
||||
delete _localPointFaceVaryingStencils[fvc].Get<float>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PatchArrays
|
||||
//
|
||||
|
||||
// debug helper
|
||||
void
|
||||
PatchTable::PatchArray::print() const {
|
||||
desc.print();
|
||||
printf(" numPatches=%d vertIndex=%d patchIndex=%d "
|
||||
"quadOffsetIndex=%d\n", numPatches, vertIndex, patchIndex,
|
||||
quadOffsetIndex);
|
||||
}
|
||||
inline PatchTable::PatchArray &
|
||||
PatchTable::getPatchArray(Index arrayIndex) {
|
||||
assert(arrayIndex<(Index)GetNumPatchArrays());
|
||||
return _patchArrays[arrayIndex];
|
||||
}
|
||||
inline PatchTable::PatchArray const &
|
||||
PatchTable::getPatchArray(Index arrayIndex) const {
|
||||
assert(arrayIndex<(Index)GetNumPatchArrays());
|
||||
return _patchArrays[arrayIndex];
|
||||
}
|
||||
void
|
||||
PatchTable::reservePatchArrays(int numPatchArrays) {
|
||||
_patchArrays.reserve(numPatchArrays);
|
||||
}
|
||||
|
||||
void
|
||||
PatchTable::allocateVaryingVertices(
|
||||
PatchDescriptor desc, int numPatches) {
|
||||
_varyingDesc = desc;
|
||||
_varyingVerts.resize(numPatches*desc.GetNumControlVertices());
|
||||
}
|
||||
|
||||
inline PatchTable::FVarPatchChannel &
|
||||
PatchTable::getFVarPatchChannel(int channel) {
|
||||
assert(channel>=0 && channel<(int)_fvarChannels.size());
|
||||
return _fvarChannels[channel];
|
||||
}
|
||||
inline PatchTable::FVarPatchChannel const &
|
||||
PatchTable::getFVarPatchChannel(int channel) const {
|
||||
assert(channel>=0 && channel<(int)_fvarChannels.size());
|
||||
return _fvarChannels[channel];
|
||||
}
|
||||
void
|
||||
PatchTable::allocateFVarPatchChannels(int numChannels) {
|
||||
_fvarChannels.resize(numChannels);
|
||||
}
|
||||
void
|
||||
PatchTable::allocateFVarPatchChannelValues(
|
||||
PatchDescriptor regDesc, PatchDescriptor irregDesc,
|
||||
int numPatches, int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
c.regDesc = regDesc;
|
||||
c.irregDesc = irregDesc;
|
||||
|
||||
c.stride = std::max(regDesc.GetNumControlVertices(),
|
||||
irregDesc.GetNumControlVertices());
|
||||
|
||||
c.patchValues.resize(numPatches * c.stride);
|
||||
c.patchParam.resize(numPatches);
|
||||
}
|
||||
void
|
||||
PatchTable::setFVarPatchChannelLinearInterpolation(
|
||||
Sdc::Options::FVarLinearInterpolation interpolation, int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
c.interpolation = interpolation;
|
||||
}
|
||||
|
||||
//
|
||||
// PatchTable
|
||||
//
|
||||
|
||||
inline int
|
||||
getPatchSize(PatchDescriptor desc) {
|
||||
return desc.GetNumControlVertices();
|
||||
}
|
||||
|
||||
void
|
||||
PatchTable::pushPatchArray(PatchDescriptor desc, int npatches,
|
||||
Index * vidx, Index * pidx, Index * qoidx) {
|
||||
|
||||
if (npatches>0) {
|
||||
_patchArrays.push_back(PatchArray(
|
||||
desc, npatches, *vidx, *pidx, qoidx ? *qoidx : 0));
|
||||
int nverts = getPatchSize(desc);
|
||||
*vidx += npatches * nverts;
|
||||
*pidx += npatches;
|
||||
if (qoidx) {
|
||||
*qoidx += (desc.GetType() == PatchDescriptor::GREGORY) ?
|
||||
npatches*nverts : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::getPatchIndex(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert(patchIndex<pa.numPatches);
|
||||
return pa.patchIndex + patchIndex;
|
||||
}
|
||||
Index *
|
||||
PatchTable::getSharpnessIndices(int arrayIndex) {
|
||||
return &_sharpnessIndices[getPatchArray(arrayIndex).patchIndex];
|
||||
}
|
||||
|
||||
float *
|
||||
PatchTable::getSharpnessValues(int arrayIndex) {
|
||||
return &_sharpnessValues[getPatchArray(arrayIndex).patchIndex];
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetPatchDescriptor(PatchHandle const & handle) const {
|
||||
return getPatchArray(handle.arrayIndex).desc;
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetPatchArrayDescriptor(int arrayIndex) const {
|
||||
return getPatchArray(arrayIndex).desc;
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumPatchArrays() const {
|
||||
return (int)_patchArrays.size();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumPatches(int arrayIndex) const {
|
||||
return getPatchArray(arrayIndex).numPatches;
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumPatchesTotal() const {
|
||||
// there is one PatchParam record for each patch in the mesh
|
||||
return (int)_paramTable.size();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumControlVertices(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return pa.numPatches * getPatchSize(pa.desc);
|
||||
}
|
||||
|
||||
Index
|
||||
PatchTable::findPatchArray(PatchDescriptor desc) {
|
||||
for (int i=0; i<(int)_patchArrays.size(); ++i) {
|
||||
if (_patchArrays[i].desc==desc)
|
||||
return i;
|
||||
}
|
||||
return Vtr::INDEX_INVALID;
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getPatchArrayVertices(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert(pa.vertIndex<(Index)_patchVerts.size());
|
||||
return IndexArray(&_patchVerts[pa.vertIndex], pa.numPatches * size);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayVertices(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert(pa.vertIndex<(Index)_patchVerts.size());
|
||||
return ConstIndexArray(&_patchVerts[pa.vertIndex], pa.numPatches * size);
|
||||
}
|
||||
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVertices(PatchHandle const & handle) const {
|
||||
PatchArray const & pa = getPatchArray(handle.arrayIndex);
|
||||
Index vert = pa.vertIndex + handle.vertIndex;
|
||||
return ConstIndexArray(&_patchVerts[vert], getPatchSize(pa.desc));
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVertices(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int size = getPatchSize(pa.desc);
|
||||
assert((pa.vertIndex + patchIndex*size)<(Index)_patchVerts.size());
|
||||
return ConstIndexArray(&_patchVerts[pa.vertIndex + patchIndex*size], size);
|
||||
}
|
||||
|
||||
PatchParam
|
||||
PatchTable::GetPatchParam(PatchHandle const & handle) const {
|
||||
assert(handle.patchIndex < (Index)_paramTable.size());
|
||||
return _paramTable[handle.patchIndex];
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchParam(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert((pa.patchIndex + patchIndex) < (int)_paramTable.size());
|
||||
return _paramTable[pa.patchIndex + patchIndex];
|
||||
}
|
||||
PatchParamArray
|
||||
PatchTable::getPatchParams(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return PatchParamArray(&_paramTable[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
ConstPatchParamArray const
|
||||
PatchTable::GetPatchParams(int arrayIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
return ConstPatchParamArray(&_paramTable[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
|
||||
float
|
||||
PatchTable::GetSingleCreasePatchSharpnessValue(PatchHandle const & handle) const {
|
||||
assert((handle.patchIndex) < (int)_sharpnessIndices.size());
|
||||
Index index = _sharpnessIndices[handle.patchIndex];
|
||||
if (index == Vtr::INDEX_INVALID) {
|
||||
return 0.0f;
|
||||
}
|
||||
assert(index < (Index)_sharpnessValues.size());
|
||||
return _sharpnessValues[index];
|
||||
}
|
||||
float
|
||||
PatchTable::GetSingleCreasePatchSharpnessValue(int arrayIndex, int patchIndex) const {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
assert((pa.patchIndex + patchIndex) < (int)_sharpnessIndices.size());
|
||||
Index index = _sharpnessIndices[pa.patchIndex + patchIndex];
|
||||
if (index == Vtr::INDEX_INVALID) {
|
||||
return 0.0f;
|
||||
}
|
||||
assert(index < (Index)_sharpnessValues.size());
|
||||
return _sharpnessValues[index];
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumLocalPoints() const {
|
||||
if (!_localPointStencils) return 0;
|
||||
return _vertexPrecisionIsDouble
|
||||
? _localPointStencils.Get<double>()->GetNumStencils()
|
||||
: _localPointStencils.Get<float>()->GetNumStencils();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumLocalPointsVarying() const {
|
||||
if (!_localPointVaryingStencils) return 0;
|
||||
return _varyingPrecisionIsDouble
|
||||
? _localPointVaryingStencils.Get<double>()->GetNumStencils()
|
||||
: _localPointVaryingStencils.Get<float>()->GetNumStencils();
|
||||
}
|
||||
int
|
||||
PatchTable::GetNumLocalPointsFaceVarying(int channel) const {
|
||||
if (channel>=0 && channel<(int)_localPointFaceVaryingStencils.size()) {
|
||||
if (!_localPointFaceVaryingStencils[channel]) return 0;
|
||||
return _faceVaryingPrecisionIsDouble
|
||||
? _localPointFaceVaryingStencils[channel].Get<double>()->GetNumStencils()
|
||||
: _localPointFaceVaryingStencils[channel].Get<float>()->GetNumStencils();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PatchTable::ConstQuadOffsetsArray
|
||||
PatchTable::GetPatchQuadOffsets(PatchHandle const & handle) const {
|
||||
PatchArray const & pa = getPatchArray(handle.arrayIndex);
|
||||
return Vtr::ConstArray<unsigned int>(&_quadOffsetsTable[pa.quadOffsetIndex + handle.vertIndex], 4);
|
||||
}
|
||||
bool
|
||||
PatchTable::IsFeatureAdaptive() const {
|
||||
|
||||
return !_isUniformLinear;
|
||||
}
|
||||
|
||||
PatchDescriptor
|
||||
PatchTable::GetVaryingPatchDescriptor() const {
|
||||
return _varyingDesc;
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVaryingVertices(PatchHandle const & handle) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = handle.patchIndex * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], numVaryingCVs);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchVaryingVertices(int array, int patch) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = (pa.patchIndex + patch) * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], numVaryingCVs);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayVaryingVertices(int array) const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = pa.patchIndex * numVaryingCVs;
|
||||
Index count = pa.numPatches * numVaryingCVs;
|
||||
return ConstIndexArray(&_varyingVerts[start], count);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetVaryingVertices() const {
|
||||
if (_varyingVerts.empty()) {
|
||||
return ConstIndexArray();
|
||||
}
|
||||
return ConstIndexArray(&_varyingVerts[0], (int)_varyingVerts.size());
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getPatchArrayVaryingVertices(int arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
Index start = pa.patchIndex * numVaryingCVs;
|
||||
return IndexArray(&_varyingVerts[start], pa.numPatches * numVaryingCVs);
|
||||
}
|
||||
void
|
||||
PatchTable::populateVaryingVertices() {
|
||||
// In order to support evaluation of varying data we need to access
|
||||
// the varying values indexed by the zero ring vertices of the vertex
|
||||
// patch. This indexing is redundant for triangles and quads and
|
||||
// could be made redunant for other patch types if we reorganized
|
||||
// the vertex patch indices so that the zero ring indices always occured
|
||||
// first. This will also need to be updated when we add support for
|
||||
// triangle patches.
|
||||
int numVaryingCVs = _varyingDesc.GetNumControlVertices();
|
||||
for (int arrayIndex=0; arrayIndex<(int)_patchArrays.size(); ++arrayIndex) {
|
||||
PatchArray const & pa = getPatchArray(arrayIndex);
|
||||
PatchDescriptor::Type patchType = pa.desc.GetType();
|
||||
for (int patch=0; patch<pa.numPatches; ++patch) {
|
||||
ConstIndexArray vertexCVs = GetPatchVertices(arrayIndex, patch);
|
||||
int start = (pa.patchIndex + patch) * numVaryingCVs;
|
||||
if (patchType == PatchDescriptor::REGULAR) {
|
||||
_varyingVerts[start+0] = vertexCVs[5];
|
||||
_varyingVerts[start+1] = vertexCVs[6];
|
||||
_varyingVerts[start+2] = vertexCVs[10];
|
||||
_varyingVerts[start+3] = vertexCVs[9];
|
||||
} else if (patchType == PatchDescriptor::GREGORY_BASIS) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[5];
|
||||
_varyingVerts[start+2] = vertexCVs[10];
|
||||
_varyingVerts[start+3] = vertexCVs[15];
|
||||
} else if (patchType == PatchDescriptor::QUADS) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[1];
|
||||
_varyingVerts[start+2] = vertexCVs[2];
|
||||
_varyingVerts[start+3] = vertexCVs[3];
|
||||
} else if (patchType == PatchDescriptor::TRIANGLES) {
|
||||
_varyingVerts[start+0] = vertexCVs[0];
|
||||
_varyingVerts[start+1] = vertexCVs[1];
|
||||
_varyingVerts[start+2] = vertexCVs[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
PatchTable::GetNumFVarChannels() const {
|
||||
return (int)_fvarChannels.size();
|
||||
}
|
||||
Sdc::Options::FVarLinearInterpolation
|
||||
PatchTable::GetFVarChannelLinearInterpolation(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.interpolation;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptorRegular(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.regDesc;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptorIrregular(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.irregDesc;
|
||||
}
|
||||
PatchDescriptor
|
||||
PatchTable::GetFVarPatchDescriptor(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.irregDesc;
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetFVarValues(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstIndexArray(&c.patchValues[0], (int)c.patchValues.size());
|
||||
}
|
||||
int
|
||||
PatchTable::GetFVarValueStride(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.stride;
|
||||
}
|
||||
IndexArray
|
||||
PatchTable::getFVarValues(int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
return IndexArray(&c.patchValues[0], (int)c.patchValues.size());
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::getPatchFVarValues(int patch, int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
int ncvsThisPatch = c.patchParam[patch].IsRegular()
|
||||
? c.regDesc.GetNumControlVertices()
|
||||
: c.irregDesc.GetNumControlVertices();
|
||||
return ConstIndexArray(&c.patchValues[patch * c.stride], ncvsThisPatch);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchFVarValues(PatchHandle const & handle, int channel) const {
|
||||
return getPatchFVarValues(handle.patchIndex, channel);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchFVarValues(int arrayIndex, int patchIndex, int channel) const {
|
||||
return getPatchFVarValues(getPatchIndex(arrayIndex, patchIndex), channel);
|
||||
}
|
||||
ConstIndexArray
|
||||
PatchTable::GetPatchArrayFVarValues(int array, int channel) const {
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
int ncvs = c.stride;
|
||||
int start = pa.patchIndex * ncvs;
|
||||
int count = pa.numPatches * ncvs;
|
||||
return ConstIndexArray(&c.patchValues[start], count);
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::getPatchFVarPatchParam(int patch, int channel) const {
|
||||
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return c.patchParam[patch];
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchFVarPatchParam(PatchHandle const & handle, int channel) const {
|
||||
return getPatchFVarPatchParam(handle.patchIndex, channel);
|
||||
}
|
||||
PatchParam
|
||||
PatchTable::GetPatchFVarPatchParam(int arrayIndex, int patchIndex, int channel) const {
|
||||
return getPatchFVarPatchParam(getPatchIndex(arrayIndex, patchIndex), channel);
|
||||
}
|
||||
ConstPatchParamArray
|
||||
PatchTable::GetPatchArrayFVarPatchParams(int array, int channel) const {
|
||||
PatchArray const & pa = getPatchArray(array);
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstPatchParamArray(&c.patchParam[pa.patchIndex], pa.numPatches);
|
||||
}
|
||||
ConstPatchParamArray
|
||||
PatchTable::GetFVarPatchParams(int channel) const {
|
||||
FVarPatchChannel const & c = getFVarPatchChannel(channel);
|
||||
return ConstPatchParamArray(&c.patchParam[0], (int)c.patchParam.size());
|
||||
}
|
||||
PatchParamArray
|
||||
PatchTable::getFVarPatchParams(int channel) {
|
||||
FVarPatchChannel & c = getFVarPatchChannel(channel);
|
||||
return PatchParamArray(&c.patchParam[0], (int)c.patchParam.size());
|
||||
}
|
||||
|
||||
void
|
||||
PatchTable::print() const {
|
||||
printf("patchTable (0x%p)\n", this);
|
||||
printf(" numPatches = %d\n", GetNumPatchesTotal());
|
||||
for (int i=0; i<GetNumPatchArrays(); ++i) {
|
||||
printf(" patchArray %d:\n", i);
|
||||
PatchArray const & pa = getPatchArray(i);
|
||||
pa.print();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for vertex and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasis(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[]) const {
|
||||
|
||||
PatchParam const & param = _paramTable[handle.patchIndex];
|
||||
PatchDescriptor::Type patchType = GetPatchArrayDescriptor(handle.arrayIndex).GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for varying and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasisVarying(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[]) const {
|
||||
|
||||
PatchParam const & param = _paramTable[handle.patchIndex];
|
||||
PatchDescriptor::Type patchType = GetVaryingPatchDescriptor().GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
//
|
||||
// Evaluate basis functions for face-varying and derivatives at (s,t):
|
||||
//
|
||||
template <typename REAL>
|
||||
void
|
||||
PatchTable::EvaluateBasisFaceVarying(
|
||||
PatchHandle const & handle, REAL s, REAL t,
|
||||
REAL wP[], REAL wDs[], REAL wDt[],
|
||||
REAL wDss[], REAL wDst[], REAL wDtt[],
|
||||
int channel) const {
|
||||
|
||||
PatchParam param = getPatchFVarPatchParam(handle.patchIndex, channel);
|
||||
PatchDescriptor::Type patchType = param.IsRegular()
|
||||
? GetFVarPatchDescriptorRegular(channel).GetType()
|
||||
: GetFVarPatchDescriptorIrregular(channel).GetType();
|
||||
|
||||
internal::EvaluatePatchBasis(patchType, param, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Explicit instantiation of EvaluateBasis...() methods for float and double:
|
||||
//
|
||||
template void PatchTable::EvaluateBasis<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisVarying<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisFaceVarying<float>(PatchHandle const & handle,
|
||||
float s, float t, float wP[], float wDs[], float wDt[],
|
||||
float wDss[], float wDst[], float wDtt[], int channel) const;
|
||||
|
||||
template void PatchTable::EvaluateBasis<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisVarying<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[]) const;
|
||||
template void PatchTable::EvaluateBasisFaceVarying<double>(PatchHandle const & handle,
|
||||
double s, double t, double wP[], double wDs[], double wDt[],
|
||||
double wDss[], double wDst[], double wDtt[], int channel) const;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
892
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTable.h
vendored
Normal file
892
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTable.h
vendored
Normal file
@@ -0,0 +1,892 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_TABLE_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_TABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchDescriptor.h"
|
||||
#include "../far/patchParam.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
#include "../sdc/options.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Container for arrays of parametric patches
|
||||
///
|
||||
/// PatchTable contains topology and parametric information about the patches
|
||||
/// generated by the Refinement process. Patches in the table are sorted into
|
||||
/// arrays based on their PatchDescriptor Type.
|
||||
///
|
||||
/// Note : PatchTable can be accessed either using a PatchHandle or a
|
||||
/// combination of array and patch indices.
|
||||
///
|
||||
/// XXXX manuelk we should add a PatchIterator that can dereference into
|
||||
/// a PatchHandle for fast linear traversal of the table
|
||||
///
|
||||
class PatchTable {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Handle that can be used as unique patch identifier within PatchTable
|
||||
class PatchHandle {
|
||||
// XXXX manuelk members will eventually be made private
|
||||
public:
|
||||
|
||||
friend class PatchTable;
|
||||
friend class PatchMap;
|
||||
|
||||
Index arrayIndex, // Array index of the patch
|
||||
patchIndex, // Absolute Index of the patch
|
||||
vertIndex; // Relative offset to the first CV of the patch in array
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Copy constructor
|
||||
PatchTable(PatchTable const & src);
|
||||
|
||||
/// \brief Destructor
|
||||
~PatchTable();
|
||||
|
||||
/// \brief True if the patches are of feature adaptive types
|
||||
bool IsFeatureAdaptive() const;
|
||||
|
||||
/// \brief Returns the total number of control vertex indices in the table
|
||||
int GetNumControlVerticesTotal() const {
|
||||
return (int)_patchVerts.size();
|
||||
}
|
||||
|
||||
/// \brief Returns the total number of patches stored in the table
|
||||
int GetNumPatchesTotal() const;
|
||||
|
||||
/// \brief Returns max vertex valence
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
|
||||
/// \brief Returns the total number of ptex faces in the mesh
|
||||
int GetNumPtexFaces() const { return _numPtexFaces; }
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Individual patches
|
||||
///
|
||||
/// \anchor individual_patches
|
||||
///
|
||||
/// \brief Accessors for individual patches
|
||||
///
|
||||
|
||||
/// \brief Returns the PatchDescriptor for the patch identified by \p handle
|
||||
PatchDescriptor GetPatchDescriptor(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for the patch identified by \p handle
|
||||
ConstIndexArray GetPatchVertices(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns a PatchParam for the patch identified by \p handle
|
||||
PatchParam GetPatchParam(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for \p patch in \p array
|
||||
ConstIndexArray GetPatchVertices(int array, int patch) const;
|
||||
|
||||
/// \brief Returns the PatchParam for \p patch in \p array
|
||||
PatchParam GetPatchParam(int array, int patch) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Arrays of patches
|
||||
///
|
||||
/// \anchor arrays_of_patches
|
||||
///
|
||||
/// \brief Accessors for arrays of patches of the same type
|
||||
///
|
||||
|
||||
/// \brief Returns the number of patch arrays in the table
|
||||
int GetNumPatchArrays() const;
|
||||
|
||||
/// \brief Returns the number of patches in \p array
|
||||
int GetNumPatches(int array) const;
|
||||
|
||||
/// \brief Returns the number of control vertices in \p array
|
||||
int GetNumControlVertices(int array) const;
|
||||
|
||||
/// \brief Returns the PatchDescriptor for the patches in \p array
|
||||
PatchDescriptor GetPatchArrayDescriptor(int array) const;
|
||||
|
||||
/// \brief Returns the control vertex indices for the patches in \p array
|
||||
ConstIndexArray GetPatchArrayVertices(int array) const;
|
||||
|
||||
/// \brief Returns the PatchParams for the patches in \p array
|
||||
ConstPatchParamArray const GetPatchParams(int array) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Change of basis patches
|
||||
///
|
||||
/// \anchor change_of_basis_patches
|
||||
///
|
||||
/// \brief Accessors for change of basis patches
|
||||
///
|
||||
///
|
||||
|
||||
/// \brief Returns the number of local vertex points.
|
||||
int GetNumLocalPoints() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point vertex values
|
||||
StencilTable const *GetLocalPointStencilTable() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point vertex values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *GetLocalPointStencilTable() const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// vertex values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point vertex values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// vertex values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// vertex values
|
||||
///
|
||||
/// For more flexibility computing local vertex points, retrieval of
|
||||
/// the local point stencil table and use of its public methods is
|
||||
/// recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValues(T const *src, T *dst) const;
|
||||
|
||||
|
||||
/// \brief Returns the number of local varying points.
|
||||
int GetNumLocalPointsVarying() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point varying values
|
||||
StencilTable const *GetLocalPointVaryingStencilTable() const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point varying values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *GetLocalPointVaryingStencilTable() const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// varying values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointVaryingStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point varying values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// varying values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// varying values
|
||||
///
|
||||
/// For more flexibility computing local varying points, retrieval of
|
||||
/// the local point varying stencil table and use of its public methods
|
||||
/// is recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesVarying(T const *src, T *dst) const;
|
||||
|
||||
|
||||
/// \brief Returns the number of local face-varying points for \p channel
|
||||
int GetNumLocalPointsFaceVarying(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point face-varying values
|
||||
StencilTable const *GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stencil table to compute local point face-varying values
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const * GetLocalPointFaceVaryingStencilTable(int channel = 0) const;
|
||||
|
||||
/// \brief Tests if the precision of the stencil table to compute local point
|
||||
/// face-varying values matches the given floating point type \<REAL\>.
|
||||
template <typename REAL> bool LocalPointFaceVaryingStencilPrecisionMatchesType() const;
|
||||
|
||||
/// \brief Updates local point face-varying values.
|
||||
///
|
||||
/// @param src Buffer with primvar data for the base and refined
|
||||
/// face-varying values
|
||||
///
|
||||
/// @param dst Destination buffer for the computed local point
|
||||
/// face-varying values
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
/// For more flexibility computing local face-varying points, retrieval
|
||||
/// of the local point face-varying stencil table and use of its public
|
||||
/// methods is recommended or often required.
|
||||
///
|
||||
template <class T> void
|
||||
ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel = 0) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Legacy gregory patch evaluation buffers
|
||||
|
||||
/// \brief Accessors for the gregory patch evaluation buffers.
|
||||
/// These methods will be deprecated.
|
||||
///
|
||||
typedef Vtr::ConstArray<unsigned int> ConstQuadOffsetsArray;
|
||||
|
||||
/// \brief Returns the 'QuadOffsets' for the Gregory patch identified by \p handle
|
||||
ConstQuadOffsetsArray GetPatchQuadOffsets(PatchHandle const & handle) const;
|
||||
|
||||
typedef std::vector<Index> VertexValenceTable;
|
||||
|
||||
/// \brief Returns the 'VertexValences' table (vertex neighborhoods table)
|
||||
VertexValenceTable const & GetVertexValenceTable() const {
|
||||
return _vertexValenceTable;
|
||||
}
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Single-crease patches
|
||||
///
|
||||
/// \anchor single_crease_patches
|
||||
///
|
||||
/// \brief Accessors for single-crease patch edge sharpness
|
||||
///
|
||||
|
||||
/// \brief Returns the crease sharpness for the patch identified by \p handle
|
||||
/// if it is a single-crease patch, or 0.0f
|
||||
float GetSingleCreasePatchSharpnessValue(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the crease sharpness for the \p patch in \p array
|
||||
/// if it is a single-crease patch, or 0.0f
|
||||
float GetSingleCreasePatchSharpnessValue(int array, int patch) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Varying data
|
||||
///
|
||||
/// \anchor varying_data
|
||||
///
|
||||
/// \brief Accessors for varying data
|
||||
///
|
||||
|
||||
/// \brief Returns the varying patch descriptor
|
||||
PatchDescriptor GetVaryingPatchDescriptor() const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for a given patch
|
||||
ConstIndexArray GetPatchVaryingVertices(PatchHandle const & handle) const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for a given patch
|
||||
ConstIndexArray GetPatchVaryingVertices(int array, int patch) const;
|
||||
|
||||
/// \brief Returns the varying vertex indices for the patches in \p array
|
||||
ConstIndexArray GetPatchArrayVaryingVertices(int array) const;
|
||||
|
||||
/// \brief Returns an array of varying vertex indices for the patches.
|
||||
ConstIndexArray GetVaryingVertices() const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Face-varying channels
|
||||
///
|
||||
/// \anchor face_varying_channels
|
||||
///
|
||||
/// \brief Accessors for face-varying channels
|
||||
///
|
||||
|
||||
/// \brief Returns the number of face-varying channels
|
||||
int GetNumFVarChannels() const;
|
||||
|
||||
/// \brief Returns the regular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptorRegular(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the irregular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptorIrregular(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the default/irregular patch descriptor for \p channel
|
||||
PatchDescriptor GetFVarPatchDescriptor(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
ConstIndexArray GetPatchFVarValues(PatchHandle const & handle, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
ConstIndexArray GetPatchFVarValues(int array, int patch, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for the patches in \p array in \p channel
|
||||
ConstIndexArray GetPatchArrayFVarValues(int array, int channel = 0) const;
|
||||
|
||||
/// \brief Returns an array of value indices for the patches in \p channel
|
||||
ConstIndexArray GetFVarValues(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the stride between patches in the value index array of \p channel
|
||||
int GetFVarValueStride(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the value indices for a given patch in \p channel
|
||||
PatchParam GetPatchFVarPatchParam(PatchHandle const & handle, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the face-varying params for a given patch \p channel
|
||||
PatchParam GetPatchFVarPatchParam(int array, int patch, int channel = 0) const;
|
||||
|
||||
/// \brief Returns the face-varying for a given patch in \p array in \p channel
|
||||
ConstPatchParamArray GetPatchArrayFVarPatchParams(int array, int channel = 0) const;
|
||||
|
||||
/// \brief Returns an array of face-varying patch param for \p channel
|
||||
ConstPatchParamArray GetFVarPatchParams(int channel = 0) const;
|
||||
|
||||
/// \brief Deprecated @see PatchTable#GetFVarPatchDescriptor
|
||||
Sdc::Options::FVarLinearInterpolation GetFVarChannelLinearInterpolation(int channel = 0) const;
|
||||
//@}
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Direct accessors
|
||||
///
|
||||
/// \warning These direct accessors are left for convenience, but they are
|
||||
/// likely going to be deprecated in future releases
|
||||
///
|
||||
|
||||
typedef std::vector<Index> PatchVertsTable;
|
||||
|
||||
/// \brief Get the table of patch control vertices
|
||||
PatchVertsTable const & GetPatchControlVerticesTable() const { return _patchVerts; }
|
||||
|
||||
/// \brief Returns the PatchParamTable (PatchParams order matches patch array sorting)
|
||||
PatchParamTable const & GetPatchParamTable() const { return _paramTable; }
|
||||
|
||||
/// \brief Returns a sharpness index table for each patch (if exists)
|
||||
std::vector<Index> const &GetSharpnessIndexTable() const { return _sharpnessIndices; }
|
||||
|
||||
/// \brief Returns sharpness values table
|
||||
std::vector<float> const &GetSharpnessValues() const { return _sharpnessValues; }
|
||||
|
||||
typedef std::vector<unsigned int> QuadOffsetsTable;
|
||||
|
||||
/// \brief Returns the quad-offsets table
|
||||
QuadOffsetsTable const & GetQuadOffsetsTable() const {
|
||||
return _quadOffsetsTable;
|
||||
}
|
||||
//@}
|
||||
|
||||
/// debug helper
|
||||
void print() const;
|
||||
|
||||
public:
|
||||
|
||||
//@{
|
||||
/// @name Evaluation methods
|
||||
///
|
||||
|
||||
/// \brief Evaluate basis functions for position and derivatives at a
|
||||
/// given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasis(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasis(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasis(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0) const;
|
||||
|
||||
/// \brief Evaluate basis functions for a varying value and
|
||||
/// derivatives at a given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0) const;
|
||||
|
||||
/// \brief Evaluate basis functions for a face-varying value and
|
||||
/// derivatives at a given (u,v) parametric location of a patch.
|
||||
///
|
||||
/// @param handle A patch handle identifying the sub-patch containing the
|
||||
/// (u,v) location
|
||||
///
|
||||
/// @param u Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param v Patch coordinate (in base face normalized space)
|
||||
///
|
||||
/// @param wP Weights (evaluated basis functions) for the position
|
||||
///
|
||||
/// @param wDu Weights (evaluated basis functions) for derivative wrt u
|
||||
///
|
||||
/// @param wDv Weights (evaluated basis functions) for derivative wrt v
|
||||
///
|
||||
/// @param wDuu Weights (evaluated basis functions) for 2nd derivative wrt u
|
||||
///
|
||||
/// @param wDuv Weights (evaluated basis functions) for 2nd derivative wrt u and v
|
||||
///
|
||||
/// @param wDvv Weights (evaluated basis functions) for 2nd derivative wrt v
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
template <typename REAL>
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, REAL u, REAL v,
|
||||
REAL wP[], REAL wDu[] = 0, REAL wDv[] = 0,
|
||||
REAL wDuu[] = 0, REAL wDuv[] = 0, REAL wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[] = 0, float wDv[] = 0,
|
||||
float wDuu[] = 0, float wDuv[] = 0, float wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
|
||||
/// \brief An overloaded version to assist template parameter resolution
|
||||
/// when explicitly declaring unused array arguments as 0.
|
||||
void EvaluateBasisFaceVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[] = 0, double wDv[] = 0,
|
||||
double wDuu[] = 0, double wDuv[] = 0, double wDvv[] = 0,
|
||||
int channel = 0) const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
friend class PatchTableBuilder;
|
||||
|
||||
// Factory constructor
|
||||
PatchTable(int maxvalence);
|
||||
|
||||
Index getPatchIndex(int array, int patch) const;
|
||||
|
||||
PatchParamArray getPatchParams(int arrayIndex);
|
||||
|
||||
Index * getSharpnessIndices(Index arrayIndex);
|
||||
float * getSharpnessValues(Index arrayIndex);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Patch arrays
|
||||
//
|
||||
struct PatchArray {
|
||||
PatchArray(PatchDescriptor d, int np, Index v, Index p, Index qo) :
|
||||
desc(d), numPatches(np), vertIndex(v),
|
||||
patchIndex(p), quadOffsetIndex (qo) { }
|
||||
|
||||
void print() const;
|
||||
|
||||
PatchDescriptor desc; // type of patches in the array
|
||||
|
||||
int numPatches; // number of patches in the array
|
||||
|
||||
Index vertIndex, // index to the first control vertex
|
||||
patchIndex, // absolute index of the first patch in the array
|
||||
quadOffsetIndex; // index of the first quad offset entry
|
||||
};
|
||||
|
||||
typedef std::vector<PatchArray> PatchArrayVector;
|
||||
|
||||
PatchArray & getPatchArray(Index arrayIndex);
|
||||
PatchArray const & getPatchArray(Index arrayIndex) const;
|
||||
|
||||
void reservePatchArrays(int numPatchArrays);
|
||||
void pushPatchArray(PatchDescriptor desc, int npatches,
|
||||
Index * vidx, Index * pidx, Index * qoidx=0);
|
||||
|
||||
IndexArray getPatchArrayVertices(int arrayIndex);
|
||||
|
||||
Index findPatchArray(PatchDescriptor desc);
|
||||
|
||||
|
||||
//
|
||||
// Varying patch arrays
|
||||
//
|
||||
IndexArray getPatchArrayVaryingVertices(int arrayIndex);
|
||||
|
||||
void allocateVaryingVertices(
|
||||
PatchDescriptor desc, int numPatches);
|
||||
void populateVaryingVertices();
|
||||
|
||||
//
|
||||
// Face-varying patch channels
|
||||
//
|
||||
|
||||
//
|
||||
// FVarPatchChannel
|
||||
//
|
||||
// Stores a record for each patch in the primitive :
|
||||
//
|
||||
// - Each patch in the PatchTable has a corresponding patch in each
|
||||
// face-varying patch channel. Patch vertex indices are sorted in the same
|
||||
// patch-type order as PatchTable::PTables. Face-varying data for a patch
|
||||
// can therefore be quickly accessed by using the patch primitive ID as
|
||||
// index into patchValueOffsets to locate the face-varying control vertex
|
||||
// indices.
|
||||
//
|
||||
// - Face-varying channels can have a different interpolation modes
|
||||
//
|
||||
// - Unlike "vertex" patches, there are no transition masks required
|
||||
// for face-varying patches.
|
||||
//
|
||||
// - Face-varying patches still require boundary edge masks.
|
||||
//
|
||||
// - currently most patches with sharp boundaries but smooth interiors have
|
||||
// to be isolated to level 10 : we need a special type of bicubic patch
|
||||
// similar to single-crease to resolve this condition without requiring
|
||||
// isolation if possible
|
||||
//
|
||||
struct FVarPatchChannel {
|
||||
Sdc::Options::FVarLinearInterpolation interpolation;
|
||||
|
||||
PatchDescriptor regDesc;
|
||||
PatchDescriptor irregDesc;
|
||||
|
||||
int stride;
|
||||
|
||||
std::vector<Index> patchValues;
|
||||
std::vector<PatchParam> patchParam;
|
||||
};
|
||||
typedef std::vector<FVarPatchChannel> FVarPatchChannelVector;
|
||||
|
||||
FVarPatchChannel & getFVarPatchChannel(int channel);
|
||||
FVarPatchChannel const & getFVarPatchChannel(int channel) const;
|
||||
|
||||
void allocateFVarPatchChannels(int numChannels);
|
||||
void allocateFVarPatchChannelValues(
|
||||
PatchDescriptor regDesc, PatchDescriptor irregDesc,
|
||||
int numPatches, int channel);
|
||||
|
||||
// deprecated
|
||||
void setFVarPatchChannelLinearInterpolation(
|
||||
Sdc::Options::FVarLinearInterpolation interpolation, int channel);
|
||||
|
||||
IndexArray getFVarValues(int channel);
|
||||
ConstIndexArray getPatchFVarValues(int patch, int channel) const;
|
||||
|
||||
PatchParamArray getFVarPatchParams(int channel);
|
||||
PatchParam getPatchFVarPatchParam(int patch, int channel) const;
|
||||
|
||||
private:
|
||||
//
|
||||
// Simple private class to hold stencil table pointers of varying precision,
|
||||
// where the discriminant of the precision is external.
|
||||
//
|
||||
// NOTE that this is a simple pointer container and NOT a smart pointer that
|
||||
// manages the ownership of the object referred to by it.
|
||||
//
|
||||
class StencilTablePtr {
|
||||
private:
|
||||
typedef StencilTableReal<float> float_type;
|
||||
typedef StencilTableReal<double> double_type;
|
||||
|
||||
union {
|
||||
float_type * _fPtr;
|
||||
double_type * _dPtr;
|
||||
};
|
||||
|
||||
public:
|
||||
StencilTablePtr() { _fPtr = 0; }
|
||||
StencilTablePtr(float_type * ptr) { _fPtr = ptr; }
|
||||
StencilTablePtr(double_type * ptr) { _dPtr = ptr; }
|
||||
|
||||
operator bool() const { return _fPtr != 0; }
|
||||
|
||||
void Set() { _fPtr = 0; }
|
||||
void Set(float_type * ptr) { _fPtr = ptr; }
|
||||
void Set(double_type * ptr) { _dPtr = ptr; }
|
||||
|
||||
template <typename REAL> StencilTableReal<REAL> * Get() const;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Topology
|
||||
//
|
||||
|
||||
int _maxValence, // highest vertex valence found in the mesh
|
||||
_numPtexFaces; // total number of ptex faces
|
||||
|
||||
PatchArrayVector _patchArrays; // Vector of descriptors for arrays of patches
|
||||
|
||||
std::vector<Index> _patchVerts; // Indices of the control vertices of the patches
|
||||
|
||||
PatchParamTable _paramTable; // PatchParam bitfields (one per patch)
|
||||
|
||||
//
|
||||
// Extraordinary vertex closed-form evaluation / endcap basis conversion
|
||||
//
|
||||
// XXXtakahito: these data will probably be replaced with mask coefficient or something
|
||||
// SchemeWorker populates.
|
||||
//
|
||||
QuadOffsetsTable _quadOffsetsTable; // Quad offsets (for Gregory patches)
|
||||
VertexValenceTable _vertexValenceTable; // Vertex valence table (for Gregory patches)
|
||||
|
||||
StencilTablePtr _localPointStencils; // local point conversion stencils
|
||||
StencilTablePtr _localPointVaryingStencils; // local point varying stencils
|
||||
|
||||
//
|
||||
// Varying data
|
||||
//
|
||||
PatchDescriptor _varyingDesc;
|
||||
|
||||
std::vector<Index> _varyingVerts;
|
||||
|
||||
//
|
||||
// Face-varying data
|
||||
//
|
||||
FVarPatchChannelVector _fvarChannels;
|
||||
|
||||
std::vector<StencilTablePtr> _localPointFaceVaryingStencils;
|
||||
|
||||
//
|
||||
// 'single-crease' patch sharpness tables
|
||||
//
|
||||
std::vector<Index> _sharpnessIndices; // Indices of single-crease sharpness (one per patch)
|
||||
std::vector<float> _sharpnessValues; // Sharpness values.
|
||||
|
||||
//
|
||||
// Construction history -- relevant to at least one public query:
|
||||
//
|
||||
unsigned int _isUniformLinear : 1;
|
||||
|
||||
//
|
||||
// Precision -- only applies to local-point stencil tables
|
||||
//
|
||||
unsigned int _vertexPrecisionIsDouble : 1;
|
||||
unsigned int _varyingPrecisionIsDouble : 1;
|
||||
unsigned int _faceVaryingPrecisionIsDouble : 1;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Template specializations for float/double -- to be defined before used:
|
||||
//
|
||||
template <> inline StencilTableReal<float> *
|
||||
PatchTable::StencilTablePtr::Get<float>() const { return _fPtr; }
|
||||
|
||||
template <> inline StencilTableReal<double> *
|
||||
PatchTable::StencilTablePtr::Get<double>() const { return _dPtr; }
|
||||
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointStencilPrecisionMatchesType<float>() const {
|
||||
return !_vertexPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointVaryingStencilPrecisionMatchesType<float>() const {
|
||||
return !_varyingPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointFaceVaryingStencilPrecisionMatchesType<float>() const {
|
||||
return !_faceVaryingPrecisionIsDouble;
|
||||
}
|
||||
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointStencilPrecisionMatchesType<double>() const {
|
||||
return _vertexPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointVaryingStencilPrecisionMatchesType<double>() const {
|
||||
return _varyingPrecisionIsDouble;
|
||||
}
|
||||
template <> inline bool
|
||||
PatchTable::LocalPointFaceVaryingStencilPrecisionMatchesType<double>() const {
|
||||
return _faceVaryingPrecisionIsDouble;
|
||||
}
|
||||
|
||||
//
|
||||
// StencilTable access -- backward compatible and generic:
|
||||
//
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointStencilTable() const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<float>());
|
||||
return reinterpret_cast<StencilTable const *>(_localPointStencils.Get<float>());
|
||||
}
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointVaryingStencilTable() const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<float>());
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
_localPointVaryingStencils.Get<float>());
|
||||
}
|
||||
inline StencilTable const *
|
||||
PatchTable::GetLocalPointFaceVaryingStencilTable(int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<float>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
_localPointFaceVaryingStencils[channel].Get<float>());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointStencilTable() const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<REAL>());
|
||||
return _localPointStencils.Get<REAL>();
|
||||
}
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointVaryingStencilTable() const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<REAL>());
|
||||
return _localPointVaryingStencils.Get<REAL>();
|
||||
}
|
||||
template <typename REAL>
|
||||
inline StencilTableReal<REAL> const *
|
||||
PatchTable::GetLocalPointFaceVaryingStencilTable(int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<REAL>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
return _localPointFaceVaryingStencils[channel].Get<REAL>();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Computation of local point values:
|
||||
//
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValues(T const *src, T *dst) const {
|
||||
assert(LocalPointStencilPrecisionMatchesType<float>());
|
||||
if (_localPointStencils) {
|
||||
_localPointStencils.Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesVarying(T const *src, T *dst) const {
|
||||
assert(LocalPointVaryingStencilPrecisionMatchesType<float>());
|
||||
if (_localPointVaryingStencils) {
|
||||
_localPointVaryingStencils.Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void
|
||||
PatchTable::ComputeLocalPointValuesFaceVarying(T const *src, T *dst, int channel) const {
|
||||
assert(LocalPointFaceVaryingStencilPrecisionMatchesType<float>());
|
||||
if (channel >= 0 && channel < (int)_localPointFaceVaryingStencils.size()) {
|
||||
if (_localPointFaceVaryingStencils[channel]) {
|
||||
_localPointFaceVaryingStencils[channel].Get<float>()->UpdateValues(src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Basis evaluation overloads
|
||||
//
|
||||
inline void
|
||||
PatchTable::EvaluateBasis(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[]) const {
|
||||
|
||||
EvaluateBasis<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasis(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[]) const {
|
||||
|
||||
EvaluateBasis<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchTable::EvaluateBasisVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[]) const {
|
||||
|
||||
EvaluateBasisVarying<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasisVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[]) const {
|
||||
|
||||
EvaluateBasisVarying<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv);
|
||||
}
|
||||
|
||||
inline void
|
||||
PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, float u, float v,
|
||||
float wP[], float wDu[], float wDv[],
|
||||
float wDuu[], float wDuv[], float wDvv[], int channel) const {
|
||||
|
||||
EvaluateBasisFaceVarying<float>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv, channel);
|
||||
}
|
||||
inline void
|
||||
PatchTable::EvaluateBasisFaceVarying(PatchHandle const & handle, double u, double v,
|
||||
double wP[], double wDu[], double wDv[],
|
||||
double wDuu[], double wDuv[], double wDvv[], int channel) const {
|
||||
|
||||
EvaluateBasisFaceVarying<double>(handle, u, v, wP, wDu, wDv, wDuu, wDuv, wDvv, channel);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_TABLE */
|
||||
2033
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTableFactory.cpp
vendored
Normal file
2033
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTableFactory.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
218
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTableFactory.h
vendored
Normal file
218
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/patchTableFactory.h
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
/// \brief Factory for constructing a PatchTable from a TopologyRefiner
|
||||
///
|
||||
class PatchTableFactory {
|
||||
public:
|
||||
|
||||
/// \brief Public options for the PatchTable factory
|
||||
///
|
||||
struct Options {
|
||||
|
||||
/// \brief Choice for approximating irregular patches (end-caps)
|
||||
///
|
||||
/// This enum specifies how irregular patches (end-caps) are approximated.
|
||||
/// A basis is chosen, rather than a specific patch type, and has a
|
||||
/// corresponding patch type for each subdivision scheme, i.e. a quad and
|
||||
/// triangular patch type exists for each basis. These choices provide a
|
||||
/// trade-off between surface quality and performance.
|
||||
///
|
||||
enum EndCapType {
|
||||
ENDCAP_NONE = 0, ///< unspecified
|
||||
ENDCAP_BILINEAR_BASIS, ///< use linear patches (simple quads or tris)
|
||||
ENDCAP_BSPLINE_BASIS, ///< use BSpline-like patches (same patch type as regular)
|
||||
ENDCAP_GREGORY_BASIS, ///< use Gregory patches (highest quality, recommended default)
|
||||
ENDCAP_LEGACY_GREGORY ///< legacy option for 2.x style Gregory patches (Catmark only)
|
||||
};
|
||||
|
||||
Options(unsigned int maxIsolation=10) :
|
||||
generateAllLevels(false),
|
||||
includeBaseLevelIndices(true),
|
||||
includeFVarBaseLevelIndices(false),
|
||||
triangulateQuads(false),
|
||||
useSingleCreasePatch(false),
|
||||
useInfSharpPatch(false),
|
||||
maxIsolationLevel(maxIsolation & 0xf),
|
||||
endCapType(ENDCAP_GREGORY_BASIS),
|
||||
shareEndCapPatchPoints(true),
|
||||
generateVaryingTables(true),
|
||||
generateVaryingLocalPoints(true),
|
||||
generateFVarTables(false),
|
||||
patchPrecisionDouble(false),
|
||||
fvarPatchPrecisionDouble(false),
|
||||
generateFVarLegacyLinearPatches(true),
|
||||
generateLegacySharpCornerPatches(true),
|
||||
numFVarChannels(-1),
|
||||
fvarChannelIndices(0)
|
||||
{ }
|
||||
|
||||
/// \brief Get endcap basis type
|
||||
EndCapType GetEndCapType() const { return (EndCapType)endCapType; }
|
||||
|
||||
/// \brief Set endcap basis type
|
||||
void SetEndCapType(EndCapType e) { endCapType = e & 0x7; }
|
||||
|
||||
/// \brief Set maximum isolation level
|
||||
void SetMaxIsolationLevel(unsigned int level) { maxIsolationLevel = level & 0xf; }
|
||||
|
||||
/// \brief Set precision of vertex patches
|
||||
template <typename REAL> void SetPatchPrecision();
|
||||
|
||||
/// \brief Set precision of face-varying patches
|
||||
template <typename REAL> void SetFVarPatchPrecision();
|
||||
|
||||
/// \brief Determine adaptive refinement options to match assigned patch options
|
||||
TopologyRefiner::AdaptiveOptions GetRefineAdaptiveOptions() const {
|
||||
TopologyRefiner::AdaptiveOptions adaptiveOptions(maxIsolationLevel);
|
||||
|
||||
adaptiveOptions.useInfSharpPatch = useInfSharpPatch;
|
||||
adaptiveOptions.useSingleCreasePatch = useSingleCreasePatch;
|
||||
adaptiveOptions.considerFVarChannels = generateFVarTables &&
|
||||
!generateFVarLegacyLinearPatches;
|
||||
return adaptiveOptions;
|
||||
}
|
||||
|
||||
unsigned int generateAllLevels : 1, ///< Generate levels from 'firstLevel' to 'maxLevel' (Uniform mode only)
|
||||
includeBaseLevelIndices : 1, ///< Include base level in patch point indices (Uniform mode only)
|
||||
includeFVarBaseLevelIndices : 1, ///< Include base level in face-varying patch point indices (Uniform mode only)
|
||||
triangulateQuads : 1, ///< Triangulate 'QUADS' primitives (Uniform mode only)
|
||||
|
||||
useSingleCreasePatch : 1, ///< Use single crease patch
|
||||
useInfSharpPatch : 1, ///< Use infinitely-sharp patch
|
||||
maxIsolationLevel : 4, ///< Cap adaptive feature isolation to the given level (max. 10)
|
||||
|
||||
// end-capping
|
||||
endCapType : 3, ///< EndCapType
|
||||
shareEndCapPatchPoints : 1, ///< Share endcap patch points among adjacent endcap patches.
|
||||
///< currently only work with GregoryBasis.
|
||||
|
||||
// varying
|
||||
generateVaryingTables : 1, ///< Generate varying patch tables
|
||||
generateVaryingLocalPoints : 1, ///< Generate local points with varying patches
|
||||
|
||||
// face-varying
|
||||
generateFVarTables : 1, ///< Generate face-varying patch tables
|
||||
|
||||
// precision
|
||||
patchPrecisionDouble : 1, ///< Generate double-precision stencils for vertex patches
|
||||
fvarPatchPrecisionDouble : 1, ///< Generate double-precision stencils for face-varying patches
|
||||
|
||||
// legacy behaviors (default to true)
|
||||
generateFVarLegacyLinearPatches : 1, ///< Generate all linear face-varying patches (legacy)
|
||||
generateLegacySharpCornerPatches : 1; ///< Generate sharp regular patches at smooth corners (legacy)
|
||||
|
||||
int numFVarChannels; ///< Number of channel indices and interpolation modes passed
|
||||
int const * fvarChannelIndices; ///< List containing the indices of the channels selected for the factory
|
||||
};
|
||||
|
||||
/// \brief Instantiates a PatchTable from a client-provided TopologyRefiner.
|
||||
///
|
||||
/// A PatchTable can be constructed from a TopologyRefiner that has been
|
||||
/// either adaptively or uniformly refined. In both cases, the resulting
|
||||
/// patches reference vertices in the various refined levels by index,
|
||||
/// and those indices accumulate with the levels in different ways.
|
||||
///
|
||||
/// For adaptively refined patches, patches are defined at different levels,
|
||||
/// including the base level, so the indices of patch vertices include
|
||||
/// vertices from all levels. A sparse set of patches can be created by
|
||||
/// restricting the patches generated to those descending from a given set
|
||||
/// of faces at the base level. This sparse set of base faces is expected
|
||||
/// to be a subset of the faces that were adaptively refined in the given
|
||||
/// TopologyRefiner, otherwise results are undefined.
|
||||
///
|
||||
/// For uniformly refined patches, all patches are completely defined within
|
||||
/// the last level. There is often no use for intermediate levels and they
|
||||
/// can usually be ignored. Indices of patch vertices might therefore be
|
||||
/// expected to be defined solely within the last level. While this is true
|
||||
/// for face-varying patches, for historical reasons it is not the case for
|
||||
/// vertex and varying patches. Indices for vertex and varying patches include
|
||||
/// the base level in addition to the last level while indices for face-varying
|
||||
/// patches include only the last level.
|
||||
///
|
||||
/// @param refiner TopologyRefiner from which to generate patches
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
/// @param selectedFaces Only create patches for the given set of base faces.
|
||||
///
|
||||
/// @return A new instance of PatchTable
|
||||
///
|
||||
static PatchTable * Create(TopologyRefiner const & refiner,
|
||||
Options options = Options(),
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
public:
|
||||
// PatchFaceTag
|
||||
//
|
||||
// This simple struct was previously used within the factory to take inventory of
|
||||
// various kinds of patches to fully allocate buffers prior to populating them. It
|
||||
// was not intended to be exposed as part of the public interface.
|
||||
//
|
||||
// It is no longer used internally and is being kept here to respect preservation
|
||||
// of the public interface, but it will be deprecated at the earliest opportunity.
|
||||
//
|
||||
/// \brief Obsolete internal struct not intended for public use -- due to
|
||||
/// be deprecated.
|
||||
//
|
||||
struct PatchFaceTag {
|
||||
public:
|
||||
unsigned int _hasPatch : 1;
|
||||
unsigned int _isRegular : 1;
|
||||
unsigned int _transitionMask : 4;
|
||||
unsigned int _boundaryMask : 4;
|
||||
unsigned int _boundaryIndex : 2;
|
||||
unsigned int _boundaryCount : 3;
|
||||
unsigned int _hasBoundaryEdge : 3;
|
||||
unsigned int _isSingleCrease : 1;
|
||||
|
||||
void clear();
|
||||
void assignBoundaryPropertiesFromEdgeMask(int boundaryEdgeMask);
|
||||
void assignBoundaryPropertiesFromVertexMask(int boundaryVertexMask);
|
||||
void assignTransitionPropertiesFromEdgeMask(int boundaryVertexMask);
|
||||
};
|
||||
typedef std::vector<PatchFaceTag> PatchTagVector;
|
||||
};
|
||||
|
||||
|
||||
template <> inline void PatchTableFactory::Options::SetPatchPrecision<float>() {
|
||||
patchPrecisionDouble = false;
|
||||
}
|
||||
template <> inline void PatchTableFactory::Options::SetFVarPatchPrecision<float>() {
|
||||
fvarPatchPrecisionDouble = false;
|
||||
}
|
||||
|
||||
template <> inline void PatchTableFactory::Options::SetPatchPrecision<double>() {
|
||||
patchPrecisionDouble = true;
|
||||
}
|
||||
template <> inline void PatchTableFactory::Options::SetFVarPatchPrecision<double>() {
|
||||
fvarPatchPrecisionDouble = true;
|
||||
}
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PATCH_TABLE_FACTORY_H */
|
||||
1260
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/primvarRefiner.h
vendored
Normal file
1260
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/primvarRefiner.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
196
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/ptexIndices.cpp
vendored
Normal file
196
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/ptexIndices.cpp
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../far/ptexIndices.h"
|
||||
|
||||
#include "../far/error.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
PtexIndices::PtexIndices(TopologyRefiner const &refiner) {
|
||||
initializePtexIndices(refiner);
|
||||
}
|
||||
|
||||
PtexIndices::~PtexIndices() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PtexIndices::initializePtexIndices(TopologyRefiner const &refiner) {
|
||||
|
||||
int regFaceSize = Sdc::SchemeTypeTraits::GetRegularFaceSize(
|
||||
refiner.GetSchemeType());
|
||||
|
||||
Vtr::internal::Level const & coarseLevel = refiner.getLevel(0);
|
||||
|
||||
int nfaces = coarseLevel.getNumFaces();
|
||||
_ptexIndices.resize(nfaces+1);
|
||||
int ptexID=0;
|
||||
for (int i = 0; i < nfaces; ++i) {
|
||||
_ptexIndices[i] = ptexID;
|
||||
Vtr::ConstIndexArray fverts = coarseLevel.getFaceVertices(i);
|
||||
ptexID += fverts.size()==regFaceSize ? 1 : fverts.size();
|
||||
}
|
||||
// last entry contains the number of ptex texture faces
|
||||
_ptexIndices[nfaces]=ptexID;
|
||||
}
|
||||
|
||||
int
|
||||
PtexIndices::GetNumFaces() const {
|
||||
return _ptexIndices.back();
|
||||
}
|
||||
|
||||
int
|
||||
PtexIndices::GetFaceId(Index f) const {
|
||||
assert(f<(int)_ptexIndices.size());
|
||||
return _ptexIndices[f];
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Returns the face adjacent to 'face' along edge 'edge'
|
||||
inline Index
|
||||
getAdjacentFace(Vtr::internal::Level const & level, Index edge, Index face) {
|
||||
Far::ConstIndexArray adjFaces = level.getEdgeFaces(edge);
|
||||
if (adjFaces.size()!=2) {
|
||||
return -1;
|
||||
}
|
||||
return (adjFaces[0]==face) ? adjFaces[1] : adjFaces[0];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PtexIndices::GetAdjacency(
|
||||
TopologyRefiner const &refiner,
|
||||
int face, int quadrant,
|
||||
int adjFaces[4], int adjEdges[4]) const {
|
||||
|
||||
int regFaceSize =
|
||||
Sdc::SchemeTypeTraits::GetRegularFaceSize(refiner.GetSchemeType());
|
||||
|
||||
Vtr::internal::Level const & level = refiner.getLevel(0);
|
||||
|
||||
ConstIndexArray fedges = level.getFaceEdges(face);
|
||||
|
||||
if (fedges.size() == regFaceSize) {
|
||||
|
||||
// Regular ptex quad face
|
||||
for (int i=0; i<regFaceSize; ++i) {
|
||||
int edge = fedges[i];
|
||||
Index adjface = getAdjacentFace(level, edge, face);
|
||||
if (adjface==-1) {
|
||||
adjFaces[i] = -1; // boundary or non-manifold
|
||||
adjEdges[i] = 0;
|
||||
} else {
|
||||
|
||||
ConstIndexArray aedges = level.getFaceEdges(adjface);
|
||||
if (aedges.size()==regFaceSize) {
|
||||
adjFaces[i] = _ptexIndices[adjface];
|
||||
adjEdges[i] = aedges.FindIndex(edge);
|
||||
assert(adjEdges[i]!=-1);
|
||||
} else {
|
||||
// neighbor is a sub-face
|
||||
adjFaces[i] = _ptexIndices[adjface] +
|
||||
(aedges.FindIndex(edge)+1)%aedges.size();
|
||||
adjEdges[i] = 3;
|
||||
}
|
||||
assert(adjFaces[i]!=-1);
|
||||
}
|
||||
}
|
||||
if (regFaceSize == 3) {
|
||||
adjFaces[3] = -1;
|
||||
adjEdges[3] = 0;
|
||||
}
|
||||
} else if (regFaceSize == 4) {
|
||||
|
||||
// Ptex sub-face 'quadrant' (non-quad)
|
||||
//
|
||||
// Ptex adjacency pattern for non-quads:
|
||||
//
|
||||
// v2
|
||||
/* o
|
||||
// / \
|
||||
// / \
|
||||
// /0 3\
|
||||
// / \
|
||||
// o_ 1 2 _o
|
||||
// / -_ _- \
|
||||
// / 2 -o- 1 \
|
||||
// /3 | 0\
|
||||
// / 1|2 \
|
||||
// / 0 | 3 \
|
||||
// o----------o----------o
|
||||
// v0 v1
|
||||
*/
|
||||
assert(quadrant>=0 && quadrant<fedges.size());
|
||||
|
||||
int nextQuadrant = (quadrant+1) % fedges.size(),
|
||||
prevQuadrant = (quadrant+fedges.size()-1) % fedges.size();
|
||||
|
||||
{ // resolve neighbors within the sub-face (edges 1 & 2)
|
||||
adjFaces[1] = _ptexIndices[face] + nextQuadrant;
|
||||
adjEdges[1] = 2;
|
||||
|
||||
adjFaces[2] = _ptexIndices[face] + prevQuadrant;
|
||||
adjEdges[2] = 1;
|
||||
}
|
||||
|
||||
{ // resolve neighbor outside the sub-face (edge 0)
|
||||
int edge0 = fedges[quadrant];
|
||||
Index adjface0 = getAdjacentFace(level, edge0, face);
|
||||
if (adjface0==-1) {
|
||||
adjFaces[0] = -1; // boundary or non-manifold
|
||||
adjEdges[0] = 0;
|
||||
} else {
|
||||
ConstIndexArray afedges = level.getFaceEdges(adjface0);
|
||||
if (afedges.size()==4) {
|
||||
adjFaces[0] = _ptexIndices[adjface0];
|
||||
adjEdges[0] = afedges.FindIndexIn4Tuple(edge0);
|
||||
} else {
|
||||
int subedge = (afedges.FindIndex(edge0)+1)%afedges.size();
|
||||
adjFaces[0] = _ptexIndices[adjface0] + subedge;
|
||||
adjEdges[0] = 3;
|
||||
}
|
||||
assert(adjFaces[0]!=-1);
|
||||
}
|
||||
|
||||
// resolve neighbor outside the sub-face (edge 3)
|
||||
int edge3 = fedges[prevQuadrant];
|
||||
Index adjface3 = getAdjacentFace(level, edge3, face);
|
||||
if (adjface3==-1) {
|
||||
adjFaces[3]=-1; // boundary or non-manifold
|
||||
adjEdges[3]=0;
|
||||
} else {
|
||||
ConstIndexArray afedges = level.getFaceEdges(adjface3);
|
||||
if (afedges.size()==4) {
|
||||
adjFaces[3] = _ptexIndices[adjface3];
|
||||
adjEdges[3] = afedges.FindIndexIn4Tuple(edge3);
|
||||
} else {
|
||||
int subedge = afedges.FindIndex(edge3);
|
||||
adjFaces[3] = _ptexIndices[adjface3] + subedge;
|
||||
adjEdges[3] = 0;
|
||||
}
|
||||
assert(adjFaces[3]!=-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Far::Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in PtexIndices::GetAdjacency() -- "
|
||||
"irregular faces only supported for quad schemes.");
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
89
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/ptexIndices.h
vendored
Normal file
89
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/ptexIndices.h
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_PTEX_INDICES_H
|
||||
#define OPENSUBDIV3_FAR_PTEX_INDICES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief Object used to compute and query ptex face indices.
|
||||
///
|
||||
/// Given a refiner, constructing a PtexIndices object builds the mapping
|
||||
/// from coarse faces to ptex ids. Once built, the object can be used to
|
||||
/// query the mapping.
|
||||
///
|
||||
class PtexIndices {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
PtexIndices(TopologyRefiner const &refiner);
|
||||
|
||||
/// \brief Destructor
|
||||
~PtexIndices();
|
||||
|
||||
//@{
|
||||
///
|
||||
/// Ptex
|
||||
///
|
||||
|
||||
/// \brief Returns the number of ptex faces in the mesh
|
||||
///
|
||||
int GetNumFaces() const;
|
||||
|
||||
/// \brief Returns the ptex face index given a coarse face 'f' or -1
|
||||
///
|
||||
int GetFaceId(Index f) const;
|
||||
|
||||
/// \brief Returns ptex face adjacency information for a given coarse face
|
||||
///
|
||||
/// @param refiner refiner used to build this PtexIndices object.
|
||||
///
|
||||
/// @param face coarse face index
|
||||
///
|
||||
/// @param quadrant quadrant index if 'face' is not a quad (the local ptex
|
||||
/// sub-face index). Must be less than the number of face
|
||||
/// vertices.
|
||||
///
|
||||
/// @param adjFaces ptex face indices of adjacent faces
|
||||
///
|
||||
/// @param adjEdges ptex edge indices of adjacent faces
|
||||
///
|
||||
void GetAdjacency(
|
||||
TopologyRefiner const &refiner,
|
||||
int face, int quadrant,
|
||||
int adjFaces[4], int adjEdges[4]) const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
||||
void initializePtexIndices(TopologyRefiner const &refiner);
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Index> _ptexIndices;
|
||||
};
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_PTEX_INDICES_H */
|
||||
182
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/sparseMatrix.h
vendored
Normal file
182
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/sparseMatrix.h
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright 2017 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_SPARSE_MATRIX_H
|
||||
#define OPENSUBDIV3_FAR_SPARSE_MATRIX_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/array.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// SparseMatrix
|
||||
//
|
||||
// The SparseMatrix class is used by the PatchBuilder to store coefficients
|
||||
// for a set of patch points derived from some other set of points -- usually
|
||||
// the refined points in a subdivision level. The compressed sparse row
|
||||
// format (CSR) is used as it provides us with stencils for points that
|
||||
// correspond to rows and so can be more directly and efficiently copied.
|
||||
//
|
||||
// It has potential for other uses and so may eventually warrant a seperate
|
||||
// header file of its own. For now, in keeping with the trend of exposing
|
||||
// classes only where used, it is defined with the PatchBuilder.
|
||||
//
|
||||
// We may also want to explore the possibility of being able to assign
|
||||
// static buffers as members here -- allowing common matrices to be set
|
||||
// directly rather than repeatedly replicated.
|
||||
//
|
||||
template <typename REAL>
|
||||
class SparseMatrix {
|
||||
public:
|
||||
typedef int column_type;
|
||||
typedef REAL element_type;
|
||||
|
||||
public:
|
||||
// Declaration and access methods:
|
||||
SparseMatrix() : _numRows(0), _numColumns(0), _numElements(0) { }
|
||||
|
||||
int GetNumRows() const { return _numRows; }
|
||||
int GetNumColumns() const { return _numColumns; }
|
||||
int GetNumElements() const { return _numElements; }
|
||||
int GetCapacity() const;
|
||||
|
||||
int GetRowSize(int rowIndex) const {
|
||||
return _rowOffsets[rowIndex + 1] - _rowOffsets[rowIndex];
|
||||
}
|
||||
|
||||
Vtr::ConstArray<column_type> GetRowColumns( int rowIndex) const {
|
||||
return Vtr::ConstArray<column_type>(&_columns[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
Vtr::ConstArray<element_type> GetRowElements(int rowIndex) const {
|
||||
return Vtr::ConstArray<element_type>(&_elements[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
|
||||
Vtr::ConstArray<column_type> GetColumns() const {
|
||||
return Vtr::ConstArray<column_type>(&_columns[0], GetNumElements());
|
||||
}
|
||||
Vtr::ConstArray<element_type> GetElements() const {
|
||||
return Vtr::ConstArray<element_type>(&_elements[0], GetNumElements());
|
||||
}
|
||||
|
||||
public:
|
||||
// Modification methods
|
||||
void Resize(int numRows, int numColumns, int numNonZeroEntriesToReserve);
|
||||
void Copy(SparseMatrix const & srcMatrix);
|
||||
void Swap(SparseMatrix & otherMatrix);
|
||||
|
||||
void SetRowSize(int rowIndex, int size);
|
||||
|
||||
Vtr::Array<column_type> SetRowColumns( int rowIndex) {
|
||||
return Vtr::Array<column_type>(&_columns[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
Vtr::Array<element_type> SetRowElements(int rowIndex) {
|
||||
return Vtr::Array<element_type>(&_elements[_rowOffsets[rowIndex]],
|
||||
GetRowSize(rowIndex));
|
||||
}
|
||||
|
||||
private:
|
||||
// Simple dimensions:
|
||||
int _numRows;
|
||||
int _numColumns;
|
||||
int _numElements;
|
||||
|
||||
std::vector<int> _rowOffsets; // remember one more entry here than rows
|
||||
|
||||
// XXXX (barfowl) - Note that the use of std::vector for the columns and
|
||||
// element arrays was causing performance issues in the incremental
|
||||
// resizing of consecutive rows, so we've been exploring alternatives...
|
||||
std::vector<column_type> _columns;
|
||||
std::vector<element_type> _elements;
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
inline int
|
||||
SparseMatrix<REAL>::GetCapacity() const {
|
||||
|
||||
return (int) _elements.size();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Resize(int numRows, int numCols, int numElementsToReserve) {
|
||||
|
||||
_numRows = numRows;
|
||||
_numColumns = numCols;
|
||||
_numElements = 0;
|
||||
|
||||
_rowOffsets.resize(0);
|
||||
_rowOffsets.resize(_numRows + 1, -1);
|
||||
_rowOffsets[0] = 0;
|
||||
|
||||
if (numElementsToReserve > GetCapacity()) {
|
||||
_columns.resize(numElementsToReserve);
|
||||
_elements.resize(numElementsToReserve);
|
||||
}
|
||||
}
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::SetRowSize(int rowIndex, int rowSize) {
|
||||
|
||||
assert(_rowOffsets[rowIndex] == _numElements);
|
||||
|
||||
int & newVectorSize = _rowOffsets[rowIndex + 1];
|
||||
newVectorSize = _rowOffsets[rowIndex] + rowSize;
|
||||
|
||||
_numElements = newVectorSize;
|
||||
if (newVectorSize > GetCapacity()) {
|
||||
_columns.resize(newVectorSize);
|
||||
_elements.resize(newVectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Copy(SparseMatrix const & src) {
|
||||
|
||||
_numRows = src._numRows;
|
||||
_numColumns = src._numColumns;
|
||||
|
||||
_rowOffsets = src._rowOffsets;
|
||||
|
||||
_numElements = src._numElements;
|
||||
|
||||
_columns = src._columns;
|
||||
_elements = src._elements;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
SparseMatrix<REAL>::Swap(SparseMatrix & other) {
|
||||
|
||||
std::swap(_numRows, other._numRows);
|
||||
std::swap(_numColumns, other._numColumns);
|
||||
std::swap(_numElements, other._numElements);
|
||||
|
||||
_rowOffsets.swap(other._rowOffsets);
|
||||
_columns.swap(other._columns);
|
||||
_elements.swap(other._elements);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_SPARSE_MATRIX_H */
|
||||
589
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilBuilder.cpp
vendored
Normal file
589
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilBuilder.cpp
vendored
Normal file
@@ -0,0 +1,589 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/stencilBuilder.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (push)
|
||||
#pragma warning disable 1572
|
||||
#endif
|
||||
|
||||
template <typename REAL>
|
||||
inline bool isWeightZero(REAL w) { return (w == (REAL)0.0); }
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
struct Point1stDerivWeight {
|
||||
REAL p;
|
||||
REAL du;
|
||||
REAL dv;
|
||||
|
||||
Point1stDerivWeight()
|
||||
: p(0.0f), du(0.0f), dv(0.0f)
|
||||
{ }
|
||||
Point1stDerivWeight(REAL w)
|
||||
: p(w), du(w), dv(w)
|
||||
{ }
|
||||
Point1stDerivWeight(REAL w, REAL wDu, REAL wDv)
|
||||
: p(w), du(wDu), dv(wDv)
|
||||
{ }
|
||||
|
||||
friend Point1stDerivWeight operator*(Point1stDerivWeight lhs,
|
||||
Point1stDerivWeight const& rhs) {
|
||||
lhs.p *= rhs.p;
|
||||
lhs.du *= rhs.du;
|
||||
lhs.dv *= rhs.dv;
|
||||
return lhs;
|
||||
}
|
||||
Point1stDerivWeight& operator+=(Point1stDerivWeight const& rhs) {
|
||||
p += rhs.p;
|
||||
du += rhs.du;
|
||||
dv += rhs.dv;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
struct Point2ndDerivWeight {
|
||||
REAL p;
|
||||
REAL du;
|
||||
REAL dv;
|
||||
REAL duu;
|
||||
REAL duv;
|
||||
REAL dvv;
|
||||
|
||||
Point2ndDerivWeight()
|
||||
: p(0.0f), du(0.0f), dv(0.0f), duu(0.0f), duv(0.0f), dvv(0.0f)
|
||||
{ }
|
||||
Point2ndDerivWeight(REAL w)
|
||||
: p(w), du(w), dv(w), duu(w), duv(w), dvv(w)
|
||||
{ }
|
||||
Point2ndDerivWeight(REAL w, REAL wDu, REAL wDv,
|
||||
REAL wDuu, REAL wDuv, REAL wDvv)
|
||||
: p(w), du(wDu), dv(wDv), duu(wDuu), duv(wDuv), dvv(wDvv)
|
||||
{ }
|
||||
|
||||
friend Point2ndDerivWeight operator*(Point2ndDerivWeight lhs,
|
||||
Point2ndDerivWeight const& rhs) {
|
||||
lhs.p *= rhs.p;
|
||||
lhs.du *= rhs.du;
|
||||
lhs.dv *= rhs.dv;
|
||||
lhs.duu *= rhs.duu;
|
||||
lhs.duv *= rhs.duv;
|
||||
lhs.dvv *= rhs.dvv;
|
||||
return lhs;
|
||||
}
|
||||
Point2ndDerivWeight& operator+=(Point2ndDerivWeight const& rhs) {
|
||||
p += rhs.p;
|
||||
du += rhs.du;
|
||||
dv += rhs.dv;
|
||||
duu += rhs.duu;
|
||||
duv += rhs.duv;
|
||||
dvv += rhs.dvv;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// Stencil table constructor set.
|
||||
///
|
||||
template <typename REAL>
|
||||
class WeightTable {
|
||||
public:
|
||||
WeightTable(int coarseVerts,
|
||||
bool genCtrlVertStencils,
|
||||
bool compactWeights)
|
||||
: _size(0)
|
||||
, _lastOffset(0)
|
||||
, _coarseVertCount(coarseVerts)
|
||||
, _compactWeights(compactWeights)
|
||||
{
|
||||
// These numbers were chosen by profiling production assets at uniform
|
||||
// level 3.
|
||||
size_t n = std::max(coarseVerts,
|
||||
std::min(int(5*1024*1024),
|
||||
coarseVerts*2));
|
||||
_dests.reserve(n);
|
||||
_sources.reserve(n);
|
||||
_weights.reserve(n);
|
||||
|
||||
if (!genCtrlVertStencils)
|
||||
return;
|
||||
|
||||
// Generate trivial control vert stencils
|
||||
_sources.resize(coarseVerts);
|
||||
_weights.resize(coarseVerts);
|
||||
_dests.resize(coarseVerts);
|
||||
_indices.resize(coarseVerts);
|
||||
_sizes.resize(coarseVerts);
|
||||
|
||||
for (int i = 0; i < coarseVerts; i++) {
|
||||
_indices[i] = i;
|
||||
_sizes[i] = 1;
|
||||
_dests[i] = i;
|
||||
_sources[i] = i;
|
||||
_weights[i] = 1.0;
|
||||
}
|
||||
|
||||
_size = static_cast<int>(_sources.size());
|
||||
_lastOffset = _size - 1;
|
||||
}
|
||||
|
||||
template <class W, class WACCUM>
|
||||
void AddWithWeight(int src, int dest, W weight, WACCUM weights)
|
||||
{
|
||||
// Factorized stencils are expressed purely in terms of the control
|
||||
// mesh verts. Without this flattening, level_i's weights would point
|
||||
// to level_i-1, which would point to level_i-2, until the final level
|
||||
// points to the control verts.
|
||||
//
|
||||
// So here, we check if the incoming vert (src) is in the control mesh,
|
||||
// if it is, we can simply merge it without attempting to resolve it
|
||||
// first.
|
||||
if (src < _coarseVertCount) {
|
||||
merge(src, dest, weight, W(1.0), _lastOffset, _size, weights);
|
||||
return;
|
||||
}
|
||||
|
||||
// src is not in the control mesh, so resolve all contributing coarse
|
||||
// verts (src itself is made up of many control vert weights).
|
||||
//
|
||||
// Find the src stencil and number of contributing CVs.
|
||||
int len = _sizes[src];
|
||||
int start = _indices[src];
|
||||
|
||||
for (int i = start; i < start+len; i++) {
|
||||
// Invariant: by processing each level in order and each vertex in
|
||||
// dependent order, any src stencil vertex reference is guaranteed
|
||||
// to consist only of coarse verts: therefore resolving src verts
|
||||
// must yield verts in the coarse mesh.
|
||||
assert(_sources[i] < _coarseVertCount);
|
||||
|
||||
// Merge each of src's contributing verts into this stencil.
|
||||
merge(_sources[i], dest, weights.Get(i), weight,
|
||||
_lastOffset, _size, weights);
|
||||
}
|
||||
}
|
||||
|
||||
class Point1stDerivAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
Point1stDerivAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(Point1stDerivWeight<REAL> weight) {
|
||||
_tbl->_weights.push_back(weight.p);
|
||||
_tbl->_duWeights.push_back(weight.du);
|
||||
_tbl->_dvWeights.push_back(weight.dv);
|
||||
}
|
||||
void Add(size_t i, Point1stDerivWeight<REAL> weight) {
|
||||
_tbl->_weights[i] += weight.p;
|
||||
_tbl->_duWeights[i] += weight.du;
|
||||
_tbl->_dvWeights[i] += weight.dv;
|
||||
}
|
||||
Point1stDerivWeight<REAL> Get(size_t index) {
|
||||
return Point1stDerivWeight<REAL>(_tbl->_weights[index],
|
||||
_tbl->_duWeights[index],
|
||||
_tbl->_dvWeights[index]);
|
||||
}
|
||||
};
|
||||
Point1stDerivAccumulator GetPoint1stDerivAccumulator() {
|
||||
return Point1stDerivAccumulator(this);
|
||||
};
|
||||
|
||||
class Point2ndDerivAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
Point2ndDerivAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(Point2ndDerivWeight<REAL> weight) {
|
||||
_tbl->_weights.push_back(weight.p);
|
||||
_tbl->_duWeights.push_back(weight.du);
|
||||
_tbl->_dvWeights.push_back(weight.dv);
|
||||
_tbl->_duuWeights.push_back(weight.duu);
|
||||
_tbl->_duvWeights.push_back(weight.duv);
|
||||
_tbl->_dvvWeights.push_back(weight.dvv);
|
||||
}
|
||||
void Add(size_t i, Point2ndDerivWeight<REAL> weight) {
|
||||
_tbl->_weights[i] += weight.p;
|
||||
_tbl->_duWeights[i] += weight.du;
|
||||
_tbl->_dvWeights[i] += weight.dv;
|
||||
_tbl->_duuWeights[i] += weight.duu;
|
||||
_tbl->_duvWeights[i] += weight.duv;
|
||||
_tbl->_dvvWeights[i] += weight.dvv;
|
||||
}
|
||||
Point2ndDerivWeight<REAL> Get(size_t index) {
|
||||
return Point2ndDerivWeight<REAL>(_tbl->_weights[index],
|
||||
_tbl->_duWeights[index],
|
||||
_tbl->_dvWeights[index],
|
||||
_tbl->_duuWeights[index],
|
||||
_tbl->_duvWeights[index],
|
||||
_tbl->_dvvWeights[index]);
|
||||
}
|
||||
};
|
||||
Point2ndDerivAccumulator GetPoint2ndDerivAccumulator() {
|
||||
return Point2ndDerivAccumulator(this);
|
||||
};
|
||||
|
||||
class ScalarAccumulator {
|
||||
WeightTable* _tbl;
|
||||
public:
|
||||
ScalarAccumulator(WeightTable* tbl) : _tbl(tbl)
|
||||
{ }
|
||||
void PushBack(REAL weight) {
|
||||
_tbl->_weights.push_back(weight);
|
||||
}
|
||||
void Add(size_t i, REAL w) {
|
||||
_tbl->_weights[i] += w;
|
||||
}
|
||||
REAL Get(size_t index) {
|
||||
return _tbl->_weights[index];
|
||||
}
|
||||
};
|
||||
ScalarAccumulator GetScalarAccumulator() {
|
||||
return ScalarAccumulator(this);
|
||||
};
|
||||
|
||||
std::vector<int> const&
|
||||
GetOffsets() const { return _indices; }
|
||||
|
||||
std::vector<int> const&
|
||||
GetSizes() const { return _sizes; }
|
||||
|
||||
std::vector<int> const&
|
||||
GetSources() const { return _sources; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetWeights() const { return _weights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuWeights() const { return _duWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDvWeights() const { return _dvWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuuWeights() const { return _duuWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDuvWeights() const { return _duvWeights; }
|
||||
|
||||
std::vector<REAL> const&
|
||||
GetDvvWeights() const { return _dvvWeights; }
|
||||
|
||||
void SetCoarseVertCount(int numVerts) {
|
||||
_coarseVertCount = numVerts;
|
||||
}
|
||||
private:
|
||||
|
||||
// Merge a vertex weight into the stencil table, if there is an existing
|
||||
// weight for a given source vertex it will be combined.
|
||||
//
|
||||
// PERFORMANCE: caution, this function is super hot.
|
||||
template <class W, class WACCUM>
|
||||
void merge(int src, int dst, W weight,
|
||||
// Delaying weight*factor multiplication hides memory latency of
|
||||
// accessing weight[i], yielding more stable performance.
|
||||
W weightFactor,
|
||||
// Similarly, passing offset & tableSize as params yields higher
|
||||
// performance than accessing the class members directly.
|
||||
int lastOffset, int tableSize, WACCUM weights)
|
||||
{
|
||||
// The lastOffset is the vertex we're currently processing, by
|
||||
// leveraging this we need not lookup the dest stencil size or offset.
|
||||
//
|
||||
// Additionally, if the client does not want the resulting verts
|
||||
// compacted, do not attempt to combine weights.
|
||||
if (_compactWeights && !_dests.empty() && _dests[lastOffset] == dst) {
|
||||
|
||||
// tableSize is exactly _sources.size(), but using tableSize is
|
||||
// significantly faster.
|
||||
for (int i = lastOffset; i < tableSize; i++) {
|
||||
|
||||
// If we find an existing vertex that matches src, we need to
|
||||
// combine the weights to avoid duplicate entries for src.
|
||||
if (_sources[i] == src) {
|
||||
weights.Add(i, weight*weightFactor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We haven't seen src yet, insert it as a new vertex weight.
|
||||
add(src, dst, weight*weightFactor, weights);
|
||||
}
|
||||
|
||||
// Add a new vertex weight to the stencil table.
|
||||
template <class W, class WACCUM>
|
||||
void add(int src, int dst, W weight, WACCUM weights)
|
||||
{
|
||||
// The _dests array has num(weights) elements mapping each individual
|
||||
// element back to a specific stencil. The array is constructed in such
|
||||
// a way that the current stencil being built is always at the end of
|
||||
// the array, so if the dests array is empty or back() doesn't match
|
||||
// dst, then we just started building a new stencil.
|
||||
if (_dests.empty() || dst != _dests.back()) {
|
||||
// _indices and _sizes always have num(stencils) elements so that
|
||||
// stencils can be directly looked up by their index in these
|
||||
// arrays. So here, ensure that they are large enough to hold the
|
||||
// new stencil about to be built.
|
||||
if (dst+1 > (int)_indices.size()) {
|
||||
_indices.resize(dst+1);
|
||||
_sizes.resize(dst+1);
|
||||
}
|
||||
// Initialize the new stencil's meta-data (offset, size).
|
||||
_indices[dst] = static_cast<int>(_sources.size());
|
||||
_sizes[dst] = 0;
|
||||
// Keep track of where the current stencil begins, which lets us
|
||||
// avoid having to look it up later.
|
||||
_lastOffset = static_cast<int>(_sources.size());
|
||||
}
|
||||
// Cache the number of elements as an optimization, it's faster than
|
||||
// calling size() on any of the vectors.
|
||||
_size++;
|
||||
|
||||
// Increment the current stencil element size.
|
||||
_sizes[dst]++;
|
||||
// Track this element as belonging to the stencil "dst".
|
||||
_dests.push_back(dst);
|
||||
|
||||
// Store the actual stencil data.
|
||||
_sources.push_back(src);
|
||||
weights.PushBack(weight);
|
||||
}
|
||||
|
||||
// The following vectors are explicitly stored as non-interleaved elements
|
||||
// to reduce cache misses.
|
||||
|
||||
// Stencil to destination vertex map.
|
||||
std::vector<int> _dests;
|
||||
|
||||
// The actual stencil data.
|
||||
std::vector<int> _sources;
|
||||
std::vector<REAL> _weights;
|
||||
std::vector<REAL> _duWeights;
|
||||
std::vector<REAL> _dvWeights;
|
||||
std::vector<REAL> _duuWeights;
|
||||
std::vector<REAL> _duvWeights;
|
||||
std::vector<REAL> _dvvWeights;
|
||||
|
||||
// Index data used to recover stencil-to-vertex mapping.
|
||||
std::vector<int> _indices;
|
||||
std::vector<int> _sizes;
|
||||
|
||||
// Acceleration members to avoid pointer chasing and reverse loops.
|
||||
int _size;
|
||||
int _lastOffset;
|
||||
int _coarseVertCount;
|
||||
bool _compactWeights;
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
StencilBuilder<REAL>::StencilBuilder(int coarseVertCount,
|
||||
bool genCtrlVertStencils,
|
||||
bool compactWeights)
|
||||
: _weightTable(new WeightTable<REAL>(coarseVertCount,
|
||||
genCtrlVertStencils,
|
||||
compactWeights))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilBuilder<REAL>::~StencilBuilder()
|
||||
{
|
||||
delete _weightTable;
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
size_t
|
||||
StencilBuilder<REAL>::GetNumVerticesTotal() const
|
||||
{
|
||||
return _weightTable->GetWeights().size();
|
||||
}
|
||||
|
||||
|
||||
template <typename REAL>
|
||||
int
|
||||
StencilBuilder<REAL>::GetNumVertsInStencil(size_t stencilIndex) const
|
||||
{
|
||||
if (stencilIndex > _weightTable->GetSizes().size() - 1)
|
||||
return 0;
|
||||
|
||||
return (int)_weightTable->GetSizes()[stencilIndex];
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::SetCoarseVertCount(int numVerts)
|
||||
{
|
||||
_weightTable->SetCoarseVertCount(numVerts);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilOffsets() const {
|
||||
return _weightTable->GetOffsets();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilSizes() const {
|
||||
return _weightTable->GetSizes();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<int> const&
|
||||
StencilBuilder<REAL>::GetStencilSources() const {
|
||||
return _weightTable->GetSources();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilWeights() const {
|
||||
return _weightTable->GetWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuWeights() const {
|
||||
return _weightTable->GetDuWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDvWeights() const {
|
||||
return _weightTable->GetDvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuuWeights() const {
|
||||
return _weightTable->GetDuuWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDuvWeights() const {
|
||||
return _weightTable->GetDuvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
std::vector<REAL> const&
|
||||
StencilBuilder<REAL>::GetStencilDvvWeights() const {
|
||||
return _weightTable->GetDvvWeights();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(Index const & src, REAL weight)
|
||||
{
|
||||
// Ignore no-op weights.
|
||||
if (isWeightZero(weight)) {
|
||||
return;
|
||||
}
|
||||
_owner->_weightTable->AddWithWeight(src._index, _index, weight,
|
||||
_owner->_weightTable->GetScalarAccumulator());
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src, REAL weight)
|
||||
{
|
||||
if (isWeightZero(weight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
REAL wgt = weight * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetScalarAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv)
|
||||
{
|
||||
if (isWeightZero(weight) && isWeightZero(du) && isWeightZero(dv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
Point1stDerivWeight<REAL> wgt = Point1stDerivWeight<REAL>(weight, du, dv) * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetPoint1stDerivAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilBuilder<REAL>::Index::AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv, REAL duu, REAL duv, REAL dvv)
|
||||
{
|
||||
if (isWeightZero(weight) && isWeightZero(du) && isWeightZero(dv) &&
|
||||
isWeightZero(duu) && isWeightZero(duv) && isWeightZero(dvv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int srcSize = *src.GetSizePtr();
|
||||
Vtr::Index const * srcIndices = src.GetVertexIndices();
|
||||
REAL const * srcWeights = src.GetWeights();
|
||||
|
||||
for (int i = 0; i < srcSize; ++i) {
|
||||
REAL w = srcWeights[i];
|
||||
if (isWeightZero(w)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vtr::Index srcIndex = srcIndices[i];
|
||||
|
||||
Point2ndDerivWeight<REAL> wgt = Point2ndDerivWeight<REAL>(weight, du, dv, duu, duv, dvv) * w;
|
||||
_owner->_weightTable->AddWithWeight(srcIndex, _index, wgt,
|
||||
_owner->_weightTable->GetPoint2ndDerivAccumulator());
|
||||
}
|
||||
}
|
||||
|
||||
template class StencilBuilder<float>;
|
||||
template class StencilBuilder<double>;
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
98
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilBuilder.h
vendored
Normal file
98
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilBuilder.h
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILBUILDER_H
|
||||
#define OPENSUBDIV3_FAR_STENCILBUILDER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "../version.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
namespace internal {
|
||||
|
||||
template <typename REAL> class WeightTable;
|
||||
|
||||
template <typename REAL>
|
||||
class StencilBuilder {
|
||||
public:
|
||||
StencilBuilder(int coarseVertCount,
|
||||
bool genCtrlVertStencils=true,
|
||||
bool compactWeights=true);
|
||||
~StencilBuilder();
|
||||
|
||||
// TODO: noncopyable.
|
||||
|
||||
size_t GetNumVerticesTotal() const;
|
||||
|
||||
int GetNumVertsInStencil(size_t stencilIndex) const;
|
||||
|
||||
void SetCoarseVertCount(int numVerts);
|
||||
|
||||
// Mapping from stencil[i] to its starting offset in the sources[] and weights[] arrays;
|
||||
std::vector<int> const& GetStencilOffsets() const;
|
||||
|
||||
// The number of contributing sources and weights in stencil[i]
|
||||
std::vector<int> const& GetStencilSizes() const;
|
||||
|
||||
// The absolute source vertex offsets.
|
||||
std::vector<int> const& GetStencilSources() const;
|
||||
|
||||
// The individual vertex weights, each weight is paired with one source.
|
||||
std::vector<REAL> const& GetStencilWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuWeights() const;
|
||||
std::vector<REAL> const& GetStencilDvWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuuWeights() const;
|
||||
std::vector<REAL> const& GetStencilDuvWeights() const;
|
||||
std::vector<REAL> const& GetStencilDvvWeights() const;
|
||||
|
||||
// Vertex Facade.
|
||||
class Index {
|
||||
public:
|
||||
Index(StencilBuilder* owner, int index)
|
||||
: _owner(owner)
|
||||
, _index(index)
|
||||
{}
|
||||
|
||||
// Add with point/vertex weight only.
|
||||
void AddWithWeight(Index const & src, REAL weight);
|
||||
void AddWithWeight(StencilReal<REAL> const& src, REAL weight);
|
||||
|
||||
// Add with first derivative.
|
||||
void AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv);
|
||||
|
||||
// Add with first and second derivatives.
|
||||
void AddWithWeight(StencilReal<REAL> const& src,
|
||||
REAL weight, REAL du, REAL dv, REAL duu, REAL duv, REAL dvv);
|
||||
|
||||
Index operator[](int index) const {
|
||||
return Index(_owner, index+_index);
|
||||
}
|
||||
|
||||
int GetOffset() const { return _index; }
|
||||
|
||||
void Clear() {/*nothing to do here*/}
|
||||
private:
|
||||
StencilBuilder* _owner;
|
||||
int _index;
|
||||
};
|
||||
|
||||
private:
|
||||
WeightTable<REAL>* _weightTable;
|
||||
};
|
||||
|
||||
} // end namespace internal
|
||||
} // end namespace Far
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // FAR_STENCILBUILDER_H
|
||||
217
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTable.cpp
vendored
Normal file
217
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTable.cpp
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
//
|
||||
// Copyright 2015 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../version.h"
|
||||
#include "../far/stencilTable.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
|
||||
namespace {
|
||||
template <typename REAL>
|
||||
void
|
||||
copyStencilData(int numControlVerts,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset,
|
||||
std::vector<int> const* offsets,
|
||||
std::vector<int> * _offsets,
|
||||
std::vector<int> const* sizes,
|
||||
std::vector<int> * _sizes,
|
||||
std::vector<int> const* sources,
|
||||
std::vector<int> * _sources,
|
||||
std::vector<REAL> const* weights,
|
||||
std::vector<REAL> * _weights,
|
||||
std::vector<REAL> const* duWeights=NULL,
|
||||
std::vector<REAL> * _duWeights=NULL,
|
||||
std::vector<REAL> const* dvWeights=NULL,
|
||||
std::vector<REAL> * _dvWeights=NULL,
|
||||
std::vector<REAL> const* duuWeights=NULL,
|
||||
std::vector<REAL> * _duuWeights=NULL,
|
||||
std::vector<REAL> const* duvWeights=NULL,
|
||||
std::vector<REAL> * _duvWeights=NULL,
|
||||
std::vector<REAL> const* dvvWeights=NULL,
|
||||
std::vector<REAL> * _dvvWeights=NULL) {
|
||||
size_t start = includeCoarseVerts ? 0 : firstOffset;
|
||||
|
||||
_offsets->resize(offsets->size());
|
||||
_sizes->resize(sizes->size());
|
||||
_sources->resize(sources->size());
|
||||
_weights->resize(weights->size());
|
||||
if (_duWeights)
|
||||
_duWeights->resize(duWeights->size());
|
||||
if (_dvWeights)
|
||||
_dvWeights->resize(dvWeights->size());
|
||||
if (_duuWeights)
|
||||
_duuWeights->resize(duuWeights->size());
|
||||
if (_duvWeights)
|
||||
_duvWeights->resize(duvWeights->size());
|
||||
if (_dvvWeights)
|
||||
_dvvWeights->resize(dvvWeights->size());
|
||||
|
||||
// The stencils are probably not in order, so we must copy/sort them.
|
||||
// Note here that loop index 'i' represents stencil_i for vertex_i.
|
||||
int curOffset = 0;
|
||||
|
||||
size_t stencilCount = 0,
|
||||
weightCount = 0;
|
||||
|
||||
for ( size_t i=start; i<offsets->size(); i++ ) {
|
||||
// Once we've copied out all the control verts, jump to the offset
|
||||
// where the actual stencils begin.
|
||||
if (includeCoarseVerts && (int)i == numControlVerts)
|
||||
i = firstOffset;
|
||||
|
||||
// Copy the stencil.
|
||||
int sz = (*sizes)[i];
|
||||
int off = (*offsets)[i];
|
||||
|
||||
(*_offsets)[stencilCount] = curOffset;
|
||||
(*_sizes)[stencilCount] = sz;
|
||||
|
||||
std::memcpy(&(*_sources)[curOffset],
|
||||
&(*sources)[off], sz*sizeof(int));
|
||||
std::memcpy(&(*_weights)[curOffset],
|
||||
&(*weights)[off], sz*sizeof(REAL));
|
||||
|
||||
if (_duWeights && !_duWeights->empty()) {
|
||||
std::memcpy(&(*_duWeights)[curOffset],
|
||||
&(*duWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_dvWeights && !_dvWeights->empty()) {
|
||||
std::memcpy(&(*_dvWeights)[curOffset],
|
||||
&(*dvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
|
||||
if (_duuWeights && !_duuWeights->empty()) {
|
||||
std::memcpy(&(*_duuWeights)[curOffset],
|
||||
&(*duuWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_duvWeights && !_duvWeights->empty()) {
|
||||
std::memcpy(&(*_duvWeights)[curOffset],
|
||||
&(*duvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
if (_dvvWeights && !_dvvWeights->empty()) {
|
||||
std::memcpy(&(*_dvvWeights)[curOffset],
|
||||
&(*dvvWeights)[off], sz*sizeof(REAL));
|
||||
}
|
||||
|
||||
curOffset += sz;
|
||||
stencilCount++;
|
||||
weightCount += sz;
|
||||
}
|
||||
|
||||
_offsets->resize(stencilCount);
|
||||
_sizes->resize(stencilCount);
|
||||
_sources->resize(weightCount);
|
||||
|
||||
if (_duWeights && !_duWeights->empty())
|
||||
_duWeights->resize(weightCount);
|
||||
if (_dvWeights && !_dvWeights->empty())
|
||||
_dvWeights->resize(weightCount);
|
||||
|
||||
if (_duuWeights && !_duuWeights->empty())
|
||||
_duuWeights->resize(weightCount);
|
||||
if (_duvWeights && !_duvWeights->empty())
|
||||
_duvWeights->resize(weightCount);
|
||||
if (_dvvWeights && !_dvvWeights->empty())
|
||||
_dvvWeights->resize(weightCount);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL>::StencilTableReal(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: _numControlVertices(numControlVerts) {
|
||||
copyStencilData(numControlVerts,
|
||||
includeCoarseVerts,
|
||||
firstOffset,
|
||||
&offsets, &_offsets,
|
||||
&sizes, &_sizes,
|
||||
&sources, &_indices,
|
||||
&weights, &_weights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilTableReal<REAL>::Clear() {
|
||||
_numControlVertices=0;
|
||||
_sizes.clear();
|
||||
_offsets.clear();
|
||||
_indices.clear();
|
||||
_weights.clear();
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
LimitStencilTableReal<REAL>::LimitStencilTableReal(
|
||||
int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
std::vector<REAL> const& duWeights,
|
||||
std::vector<REAL> const& dvWeights,
|
||||
std::vector<REAL> const& duuWeights,
|
||||
std::vector<REAL> const& duvWeights,
|
||||
std::vector<REAL> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: StencilTableReal<REAL>(numControlVerts) {
|
||||
copyStencilData(numControlVerts,
|
||||
includeCoarseVerts,
|
||||
firstOffset,
|
||||
&offsets, &this->_offsets,
|
||||
&sizes, &this->_sizes,
|
||||
&sources, &this->_indices,
|
||||
&weights, &this->_weights,
|
||||
&duWeights, &_duWeights,
|
||||
&dvWeights, &_dvWeights,
|
||||
&duuWeights, &_duuWeights,
|
||||
&duvWeights, &_duvWeights,
|
||||
&dvvWeights, &_dvvWeights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
LimitStencilTableReal<REAL>::Clear() {
|
||||
StencilTableReal<REAL>::Clear();
|
||||
_duWeights.clear();
|
||||
_dvWeights.clear();
|
||||
_duuWeights.clear();
|
||||
_duvWeights.clear();
|
||||
_dvvWeights.clear();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Explicit instantiation for float and double:
|
||||
//
|
||||
template class StencilReal<float>;
|
||||
template class StencilReal<double>;
|
||||
|
||||
template class LimitStencilReal<float>;
|
||||
template class LimitStencilReal<double>;
|
||||
|
||||
template class StencilTableReal<float>;
|
||||
template class StencilTableReal<double>;
|
||||
|
||||
template class LimitStencilTableReal<float>;
|
||||
template class LimitStencilTableReal<double>;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
776
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTable.h
vendored
Normal file
776
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTable.h
vendored
Normal file
@@ -0,0 +1,776 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
#define OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
// Forward declarations for friends:
|
||||
class PatchTableBuilder;
|
||||
|
||||
template <typename REAL> class StencilTableFactoryReal;
|
||||
template <typename REAL> class LimitStencilTableFactoryReal;
|
||||
|
||||
/// \brief Vertex stencil descriptor
|
||||
///
|
||||
/// Allows access and manipulation of a single stencil in a StencilTable.
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilReal {
|
||||
public:
|
||||
|
||||
/// \brief Default constructor
|
||||
StencilReal() {}
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param size Table pointer to the size of the stencil
|
||||
///
|
||||
/// @param indices Table pointer to the vertex indices of the stencil
|
||||
///
|
||||
/// @param weights Table pointer to the vertex weights of the stencil
|
||||
///
|
||||
StencilReal(int * size, Index * indices, REAL * weights)
|
||||
: _size(size), _indices(indices), _weights(weights) { }
|
||||
|
||||
/// \brief Copy constructor
|
||||
StencilReal(StencilReal const & other) {
|
||||
_size = other._size;
|
||||
_indices = other._indices;
|
||||
_weights = other._weights;
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the stencil
|
||||
int GetSize() const {
|
||||
return *_size;
|
||||
}
|
||||
|
||||
/// \brief Returns the size of the stencil as a pointer
|
||||
int * GetSizePtr() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
/// \brief Returns the control vertices' indices
|
||||
Index const * GetVertexIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// \brief Returns the interpolation weights
|
||||
REAL const * GetWeights() const {
|
||||
return _weights;
|
||||
}
|
||||
|
||||
/// \brief Advance to the next stencil in the table
|
||||
void Next() {
|
||||
int stride = *_size;
|
||||
++_size;
|
||||
_indices += stride;
|
||||
_weights += stride;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
int * _size;
|
||||
Index * _indices;
|
||||
REAL * _weights;
|
||||
};
|
||||
|
||||
/// \brief Vertex stencil class wrapping the template for compatibility.
|
||||
///
|
||||
class Stencil : public StencilReal<float> {
|
||||
protected:
|
||||
typedef StencilReal<float> BaseStencil;
|
||||
|
||||
public:
|
||||
Stencil() : BaseStencil() { }
|
||||
Stencil(BaseStencil const & other) : BaseStencil(other) { }
|
||||
Stencil(int * size, Index * indices, float * weights)
|
||||
: BaseStencil(size, indices, weights) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Table of subdivision stencils.
|
||||
///
|
||||
/// Stencils are the most direct method of evaluation of locations on the limit
|
||||
/// of a surface. Every point of a limit surface can be computed by linearly
|
||||
/// blending a collection of coarse control vertices.
|
||||
///
|
||||
/// A stencil assigns a series of control vertex indices with a blending weight
|
||||
/// that corresponds to a unique parametric location of the limit surface. When
|
||||
/// the control vertices move in space, the limit location can be very efficiently
|
||||
/// recomputed simply by applying the blending weights to the series of coarse
|
||||
/// control vertices.
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilTableReal {
|
||||
protected:
|
||||
StencilTableReal(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset);
|
||||
|
||||
public:
|
||||
|
||||
virtual ~StencilTableReal() {};
|
||||
|
||||
/// \brief Returns the number of stencils in the table
|
||||
int GetNumStencils() const {
|
||||
return (int)_sizes.size();
|
||||
}
|
||||
|
||||
/// \brief Returns the number of control vertices indexed in the table
|
||||
int GetNumControlVertices() const {
|
||||
return _numControlVertices;
|
||||
}
|
||||
|
||||
/// \brief Returns a Stencil at index i in the table
|
||||
StencilReal<REAL> GetStencil(Index i) const;
|
||||
|
||||
/// \brief Returns the number of control vertices of each stencil in the table
|
||||
std::vector<int> const & GetSizes() const {
|
||||
return _sizes;
|
||||
}
|
||||
|
||||
/// \brief Returns the offset to a given stencil (factory may leave empty)
|
||||
std::vector<Index> const & GetOffsets() const {
|
||||
return _offsets;
|
||||
}
|
||||
|
||||
/// \brief Returns the indices of the control vertices
|
||||
std::vector<Index> const & GetControlIndices() const {
|
||||
return _indices;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencil interpolation weights
|
||||
std::vector<REAL> const & GetWeights() const {
|
||||
return _weights;
|
||||
}
|
||||
|
||||
/// \brief Returns the stencil at index i in the table
|
||||
StencilReal<REAL> operator[] (Index index) const;
|
||||
|
||||
/// \brief Updates point values based on the control values
|
||||
///
|
||||
/// \note The destination buffers are assumed to have allocated at least
|
||||
/// \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param dstValues Destination buffer for the interpolated primvar data
|
||||
///
|
||||
/// @param start Index of first destination value to update
|
||||
///
|
||||
/// @param end Index of last destination value to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void UpdateValues(T const &srcValues, U &dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcValues, dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateValues(T1 const &srcBase, int numBase, T2 const &srcRef,
|
||||
U &dstValues, Index start=-1, Index end=-1) const {
|
||||
this->update(srcBase, numBase, srcRef, dstValues, _weights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void UpdateValues(T const *src, U *dst, Index start=-1, Index end=-1) const {
|
||||
this->update(src, dst, _weights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateValues(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *dst, Index start=-1, Index end=-1) const {
|
||||
this->update(srcBase, numBase, srcRef, dst, _weights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <class T, class U>
|
||||
void update( T const &srcValues, U &dstValues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
template <class T1, class T2, class U>
|
||||
void update( T1 const &srcBase, int numBase, T2 const &srcRef, U &dstValues,
|
||||
std::vector<REAL> const & valueWeights, Index start, Index end) const;
|
||||
|
||||
// Populate the offsets table from the stencil sizes in _sizes (factory helper)
|
||||
void generateOffsets();
|
||||
|
||||
// Resize the table arrays (factory helper)
|
||||
void resize(int nstencils, int nelems);
|
||||
|
||||
// Reserves the table arrays (factory helper)
|
||||
void reserve(int nstencils, int nelems);
|
||||
|
||||
// Reallocates the table arrays to remove excess capacity (factory helper)
|
||||
void shrinkToFit();
|
||||
|
||||
// Performs any final operations on internal tables (factory helper)
|
||||
void finalize();
|
||||
|
||||
protected:
|
||||
StencilTableReal() : _numControlVertices(0) {}
|
||||
StencilTableReal(int numControlVerts)
|
||||
: _numControlVertices(numControlVerts)
|
||||
{ }
|
||||
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class Far::PatchTableBuilder;
|
||||
|
||||
int _numControlVertices; // number of control vertices
|
||||
|
||||
std::vector<int> _sizes; // number of coefficients for each stencil
|
||||
std::vector<Index> _offsets, // offset to the start of each stencil
|
||||
_indices; // indices of contributing coarse vertices
|
||||
std::vector<REAL> _weights; // stencil weight coefficients
|
||||
};
|
||||
|
||||
/// \brief Stencil table class wrapping the template for compatibility.
|
||||
///
|
||||
class StencilTable : public StencilTableReal<float> {
|
||||
protected:
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
Stencil GetStencil(Index index) const {
|
||||
return Stencil(BaseTable::GetStencil(index));
|
||||
}
|
||||
Stencil operator[] (Index index) const {
|
||||
return Stencil(BaseTable::GetStencil(index));
|
||||
}
|
||||
|
||||
protected:
|
||||
StencilTable() : BaseTable() { }
|
||||
StencilTable(int numControlVerts) : BaseTable(numControlVerts) { }
|
||||
StencilTable(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<float> const& weights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: BaseTable(numControlVerts, offsets,
|
||||
sizes, sources, weights, includeCoarseVerts, firstOffset) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Limit point stencil descriptor
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilReal : public StencilReal<REAL> {
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
///
|
||||
/// @param size Table pointer to the size of the stencil
|
||||
///
|
||||
/// @param indices Table pointer to the vertex indices of the stencil
|
||||
///
|
||||
/// @param weights Table pointer to the vertex weights of the stencil
|
||||
///
|
||||
/// @param duWeights Table pointer to the 'u' derivative weights
|
||||
///
|
||||
/// @param dvWeights Table pointer to the 'v' derivative weights
|
||||
///
|
||||
/// @param duuWeights Table pointer to the 'uu' derivative weights
|
||||
///
|
||||
/// @param duvWeights Table pointer to the 'uv' derivative weights
|
||||
///
|
||||
/// @param dvvWeights Table pointer to the 'vv' derivative weights
|
||||
///
|
||||
LimitStencilReal( int* size,
|
||||
Index * indices,
|
||||
REAL * weights,
|
||||
REAL * duWeights=0,
|
||||
REAL * dvWeights=0,
|
||||
REAL * duuWeights=0,
|
||||
REAL * duvWeights=0,
|
||||
REAL * dvvWeights=0)
|
||||
: StencilReal<REAL>(size, indices, weights),
|
||||
_duWeights(duWeights),
|
||||
_dvWeights(dvWeights),
|
||||
_duuWeights(duuWeights),
|
||||
_duvWeights(duvWeights),
|
||||
_dvvWeights(dvvWeights) {
|
||||
}
|
||||
|
||||
/// \brief Returns the u derivative weights
|
||||
REAL const * GetDuWeights() const {
|
||||
return _duWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the v derivative weights
|
||||
REAL const * GetDvWeights() const {
|
||||
return _dvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the uu derivative weights
|
||||
REAL const * GetDuuWeights() const {
|
||||
return _duuWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the uv derivative weights
|
||||
REAL const * GetDuvWeights() const {
|
||||
return _duvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the vv derivative weights
|
||||
REAL const * GetDvvWeights() const {
|
||||
return _dvvWeights;
|
||||
}
|
||||
|
||||
/// \brief Advance to the next stencil in the table
|
||||
void Next() {
|
||||
int stride = *this->_size;
|
||||
++this->_size;
|
||||
this->_indices += stride;
|
||||
this->_weights += stride;
|
||||
if (_duWeights) _duWeights += stride;
|
||||
if (_dvWeights) _dvWeights += stride;
|
||||
if (_duuWeights) _duuWeights += stride;
|
||||
if (_duvWeights) _duvWeights += stride;
|
||||
if (_dvvWeights) _dvvWeights += stride;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class StencilTableFactoryReal<REAL>;
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
REAL * _duWeights, // pointer to stencil u derivative limit weights
|
||||
* _dvWeights, // pointer to stencil v derivative limit weights
|
||||
* _duuWeights, // pointer to stencil uu derivative limit weights
|
||||
* _duvWeights, // pointer to stencil uv derivative limit weights
|
||||
* _dvvWeights; // pointer to stencil vv derivative limit weights
|
||||
};
|
||||
|
||||
/// \brief Limit point stencil class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencil : public LimitStencilReal<float> {
|
||||
protected:
|
||||
typedef LimitStencilReal<float> BaseStencil;
|
||||
|
||||
public:
|
||||
LimitStencil(BaseStencil const & other) : BaseStencil(other) { }
|
||||
LimitStencil(int* size, Index * indices, float * weights,
|
||||
float * duWeights=0, float * dvWeights=0,
|
||||
float * duuWeights=0, float * duvWeights=0, float * dvvWeights=0)
|
||||
: BaseStencil(size, indices, weights,
|
||||
duWeights, dvWeights, duuWeights, duvWeights, dvvWeights) { }
|
||||
};
|
||||
|
||||
|
||||
/// \brief Table of limit subdivision stencils.
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilTableReal : public StencilTableReal<REAL> {
|
||||
protected:
|
||||
LimitStencilTableReal(
|
||||
int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<REAL> const& weights,
|
||||
std::vector<REAL> const& duWeights,
|
||||
std::vector<REAL> const& dvWeights,
|
||||
std::vector<REAL> const& duuWeights,
|
||||
std::vector<REAL> const& duvWeights,
|
||||
std::vector<REAL> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset);
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Returns a LimitStencil at index i in the table
|
||||
LimitStencilReal<REAL> GetLimitStencil(Index i) const;
|
||||
|
||||
/// \brief Returns the limit stencil at index i in the table
|
||||
LimitStencilReal<REAL> operator[] (Index index) const;
|
||||
|
||||
/// \brief Returns the 'u' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuWeights() const {
|
||||
return _duWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'v' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDvWeights() const {
|
||||
return _dvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'uu' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuuWeights() const {
|
||||
return _duuWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'uv' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDuvWeights() const {
|
||||
return _duvWeights;
|
||||
}
|
||||
|
||||
/// \brief Returns the 'vv' derivative stencil interpolation weights
|
||||
std::vector<REAL> const & GetDvvWeights() const {
|
||||
return _dvvWeights;
|
||||
}
|
||||
|
||||
/// \brief Updates derivative values based on the control values
|
||||
///
|
||||
/// \note The destination buffers ('uderivs' & 'vderivs') are assumed to
|
||||
/// have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uderivs Destination buffer for the interpolated 'u'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param vderivs Destination buffer for the interpolated 'v'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void UpdateDerivs(T const & srcValues, U & uderivs, U & vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcValues, uderivs, _duWeights, start, end);
|
||||
this->update(srcValues, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateDerivs(T1 const & srcBase, int numBase, T2 const & srcRef,
|
||||
U & uderivs, U & vderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uderivs, _duWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void UpdateDerivs(T const *src, U *uderivs, U *vderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(src, uderivs, _duWeights, start, end);
|
||||
this->update(src, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void UpdateDerivs(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *uderivs, U *vderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uderivs, _duWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vderivs, _dvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Updates 2nd derivative values based on the control values
|
||||
///
|
||||
/// \note The destination buffers ('uuderivs', 'uvderivs', & 'vderivs') are
|
||||
/// assumed to have allocated at least \c GetNumStencils() elements.
|
||||
///
|
||||
/// @param srcValues Buffer with primvar data for the control vertices
|
||||
///
|
||||
/// @param uuderivs Destination buffer for the interpolated 'uu'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param uvderivs Destination buffer for the interpolated 'uv'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param vvderivs Destination buffer for the interpolated 'vv'
|
||||
/// derivative primvar data
|
||||
///
|
||||
/// @param start Index of first destination derivative to update
|
||||
///
|
||||
/// @param end Index of last destination derivative to update
|
||||
///
|
||||
template <class T, class U>
|
||||
void Update2ndDerivs(T const & srcValues,
|
||||
U & uuderivs, U & uvderivs, U & vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcValues, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcValues, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcValues, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class U>
|
||||
void Update2ndDerivs(T1 const & srcBase, int numBase, T2 const & srcRef,
|
||||
U & uuderivs, U & uvderivs, U & vvderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
// Pointer interface for backward compatibility
|
||||
template <class T, class U>
|
||||
void Update2ndDerivs(T const *src, T *uuderivs, U *uvderivs, U *vvderivs,
|
||||
int start=-1, int end=-1) const {
|
||||
|
||||
this->update(src, uuderivs, _duuWeights, start, end);
|
||||
this->update(src, uvderivs, _duvWeights, start, end);
|
||||
this->update(src, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
template <class T1, class T2, class U>
|
||||
void Update2ndDerivs(T1 const *srcBase, int numBase, T2 const *srcRef,
|
||||
U *uuderivs, U *uvderivs, U *vvderivs, int start=-1, int end=-1) const {
|
||||
|
||||
this->update(srcBase, numBase, srcRef, uuderivs, _duuWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, uvderivs, _duvWeights, start, end);
|
||||
this->update(srcBase, numBase, srcRef, vvderivs, _dvvWeights, start, end);
|
||||
}
|
||||
|
||||
/// \brief Clears the stencils from the table
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
friend class LimitStencilTableFactoryReal<REAL>;
|
||||
|
||||
// Resize the table arrays (factory helper)
|
||||
void resize(int nstencils, int nelems);
|
||||
|
||||
private:
|
||||
std::vector<REAL> _duWeights, // u derivative limit stencil weights
|
||||
_dvWeights, // v derivative limit stencil weights
|
||||
_duuWeights, // uu derivative limit stencil weights
|
||||
_duvWeights, // uv derivative limit stencil weights
|
||||
_dvvWeights; // vv derivative limit stencil weights
|
||||
};
|
||||
|
||||
/// \brief Limit stencil table class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencilTable : public LimitStencilTableReal<float> {
|
||||
protected:
|
||||
typedef LimitStencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
LimitStencil GetLimitStencil(Index index) const {
|
||||
return LimitStencil(BaseTable::GetLimitStencil(index));
|
||||
}
|
||||
LimitStencil operator[] (Index index) const {
|
||||
return LimitStencil(BaseTable::GetLimitStencil(index));
|
||||
}
|
||||
|
||||
protected:
|
||||
LimitStencilTable(int numControlVerts,
|
||||
std::vector<int> const& offsets,
|
||||
std::vector<int> const& sizes,
|
||||
std::vector<int> const& sources,
|
||||
std::vector<float> const& weights,
|
||||
std::vector<float> const& duWeights,
|
||||
std::vector<float> const& dvWeights,
|
||||
std::vector<float> const& duuWeights,
|
||||
std::vector<float> const& duvWeights,
|
||||
std::vector<float> const& dvvWeights,
|
||||
bool includeCoarseVerts,
|
||||
size_t firstOffset)
|
||||
: BaseTable(numControlVerts,
|
||||
offsets, sizes, sources, weights,
|
||||
duWeights, dvWeights, duuWeights, duvWeights, dvvWeights,
|
||||
includeCoarseVerts, firstOffset) { }
|
||||
};
|
||||
|
||||
|
||||
// Update values by applying cached stencil weights to new control values
|
||||
template <typename REAL>
|
||||
template <class T1, class T2, class U> void
|
||||
StencilTableReal<REAL>::update(T1 const &srcBase, int numBase,
|
||||
T2 const &srcRef, U &dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
int const * sizes = &_sizes.at(0);
|
||||
Index const * indices = &_indices.at(0);
|
||||
REAL const * weights = &valueWeights.at(0);
|
||||
|
||||
if (start > 0) {
|
||||
assert(start < (Index)_offsets.size());
|
||||
sizes += start;
|
||||
indices += _offsets[start];
|
||||
weights += _offsets[start];
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
int nstencils = ((end < start) ? GetNumStencils() : end) - start;
|
||||
|
||||
for (int i = 0; i < nstencils; ++i, ++sizes) {
|
||||
dstValues[start + i].Clear();
|
||||
for (int j = 0; j < *sizes; ++j, ++indices, ++weights) {
|
||||
if (*indices < numBase) {
|
||||
dstValues[start + i].AddWithWeight(srcBase[*indices], *weights);
|
||||
} else {
|
||||
dstValues[start + i].AddWithWeight(srcRef[*indices - numBase], *weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename REAL>
|
||||
template <class T, class U> void
|
||||
StencilTableReal<REAL>::update(T const &srcValues, U &dstValues,
|
||||
std::vector<REAL> const &valueWeights, Index start, Index end) const {
|
||||
|
||||
int const * sizes = &_sizes.at(0);
|
||||
Index const * indices = &_indices.at(0);
|
||||
REAL const * weights = &valueWeights.at(0);
|
||||
|
||||
if (start > 0) {
|
||||
assert(start < (Index)_offsets.size());
|
||||
sizes += start;
|
||||
indices += _offsets[start];
|
||||
weights += _offsets[start];
|
||||
} else {
|
||||
start = 0;
|
||||
}
|
||||
|
||||
int nstencils = ((end < start) ? GetNumStencils() : end) - start;
|
||||
|
||||
for (int i = 0; i < nstencils; ++i, ++sizes) {
|
||||
dstValues[start + i].Clear();
|
||||
for (int j = 0; j < *sizes; ++j, ++indices, ++weights) {
|
||||
dstValues[start + i].AddWithWeight(srcValues[*indices], *weights);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::generateOffsets() {
|
||||
Index offset=0;
|
||||
int noffsets = (int)_sizes.size();
|
||||
_offsets.resize(noffsets);
|
||||
for (int i=0; i<(int)_sizes.size(); ++i ) {
|
||||
_offsets[i]=offset;
|
||||
offset+=_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::resize(int nstencils, int nelems) {
|
||||
_sizes.resize(nstencils);
|
||||
_indices.resize(nelems);
|
||||
_weights.resize(nelems);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::reserve(int nstencils, int nelems) {
|
||||
_sizes.reserve(nstencils);
|
||||
_indices.reserve(nelems);
|
||||
_weights.reserve(nelems);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::shrinkToFit() {
|
||||
std::vector<int>(_sizes).swap(_sizes);
|
||||
std::vector<Index>(_indices).swap(_indices);
|
||||
std::vector<REAL>(_weights).swap(_weights);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
StencilTableReal<REAL>::finalize() {
|
||||
shrinkToFit();
|
||||
generateOffsets();
|
||||
}
|
||||
|
||||
// Returns a Stencil at index i in the table
|
||||
template <typename REAL>
|
||||
inline StencilReal<REAL>
|
||||
StencilTableReal<REAL>::GetStencil(Index i) const {
|
||||
assert((! _offsets.empty()) && i<(int)_offsets.size());
|
||||
|
||||
Index ofs = _offsets[i];
|
||||
|
||||
return StencilReal<REAL>(const_cast<int*>(&_sizes[i]),
|
||||
const_cast<Index*>(&_indices[ofs]),
|
||||
const_cast<REAL*>(&_weights[ofs]));
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline StencilReal<REAL>
|
||||
StencilTableReal<REAL>::operator[] (Index index) const {
|
||||
return GetStencil(index);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline void
|
||||
LimitStencilTableReal<REAL>::resize(int nstencils, int nelems) {
|
||||
StencilTableReal<REAL>::resize(nstencils, nelems);
|
||||
_duWeights.resize(nelems);
|
||||
_dvWeights.resize(nelems);
|
||||
}
|
||||
|
||||
// Returns a LimitStencil at index i in the table
|
||||
template <typename REAL>
|
||||
inline LimitStencilReal<REAL>
|
||||
LimitStencilTableReal<REAL>::GetLimitStencil(Index i) const {
|
||||
assert((! this->GetOffsets().empty()) && i<(int)this->GetOffsets().size());
|
||||
|
||||
Index ofs = this->GetOffsets()[i];
|
||||
|
||||
if (!_duWeights.empty() && !_dvWeights.empty() &&
|
||||
!_duuWeights.empty() && !_duvWeights.empty() && !_dvvWeights.empty()) {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuvWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvvWeights()[ofs]) );
|
||||
} else if (!_duWeights.empty() && !_dvWeights.empty()) {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDuWeights()[ofs]),
|
||||
const_cast<REAL *>(&GetDvWeights()[ofs]) );
|
||||
} else {
|
||||
return LimitStencilReal<REAL>(
|
||||
const_cast<int *>(&this->GetSizes()[i]),
|
||||
const_cast<Index *>(&this->GetControlIndices()[ofs]),
|
||||
const_cast<REAL *>(&this->GetWeights()[ofs]) );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
inline LimitStencilReal<REAL>
|
||||
LimitStencilTableReal<REAL>::operator[] (Index index) const {
|
||||
return GetLimitStencil(index);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_STENCILTABLE_H
|
||||
660
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTableFactory.cpp
vendored
Normal file
660
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTableFactory.cpp
vendored
Normal file
@@ -0,0 +1,660 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#include "../far/stencilTableFactory.h"
|
||||
#include "../far/stencilBuilder.h"
|
||||
#include "../far/patchTable.h"
|
||||
#include "../far/patchTableFactory.h"
|
||||
#include "../far/patchMap.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/primvarRefiner.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
using internal::StencilBuilder;
|
||||
|
||||
namespace {
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (push)
|
||||
#pragma warning disable 1572
|
||||
#endif
|
||||
|
||||
template <typename REAL>
|
||||
inline bool isWeightZero(REAL w) { return (w == (REAL) 0.0); }
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
void
|
||||
StencilTableFactoryReal<REAL>::generateControlVertStencils(
|
||||
int numControlVerts,
|
||||
StencilReal<REAL> & dst) {
|
||||
|
||||
// Control vertices contribute a single index with a weight of 1.0
|
||||
for (int i=0; i<numControlVerts; ++i) {
|
||||
*dst._size = 1;
|
||||
*dst._indices = i;
|
||||
*dst._weights = (REAL) 1.0;
|
||||
dst.Next();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// StencilTable factory
|
||||
//
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::Create(TopologyRefiner const & refiner,
|
||||
Options options) {
|
||||
|
||||
bool interpolateVertex = options.interpolationMode==INTERPOLATE_VERTEX;
|
||||
bool interpolateVarying = options.interpolationMode==INTERPOLATE_VARYING;
|
||||
bool interpolateFaceVarying = options.interpolationMode==INTERPOLATE_FACE_VARYING;
|
||||
|
||||
int numControlVertices = !interpolateFaceVarying
|
||||
? refiner.GetLevel(0).GetNumVertices()
|
||||
: refiner.GetLevel(0).GetNumFVarValues(options.fvarChannel);
|
||||
|
||||
int maxlevel = std::min(int(options.maxLevel), refiner.GetMaxLevel());
|
||||
if (maxlevel==0 && (! options.generateControlVerts)) {
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->_numControlVertices = numControlVertices;
|
||||
return result;
|
||||
}
|
||||
|
||||
StencilBuilder<REAL> builder(numControlVertices,
|
||||
/*genControlVerts*/ true,
|
||||
/*compactWeights*/ true);
|
||||
|
||||
//
|
||||
// Interpolate stencils for each refinement level
|
||||
//
|
||||
PrimvarRefinerReal<REAL> primvarRefiner(refiner);
|
||||
|
||||
typename StencilBuilder<REAL>::Index srcIndex(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dstIndex(&builder, numControlVertices);
|
||||
|
||||
for (int level=1; level<=maxlevel; ++level) {
|
||||
if (interpolateVertex) {
|
||||
primvarRefiner.Interpolate(level, srcIndex, dstIndex);
|
||||
} else if (interpolateVarying) {
|
||||
primvarRefiner.InterpolateVarying(level, srcIndex, dstIndex);
|
||||
} else {
|
||||
primvarRefiner.InterpolateFaceVarying(level, srcIndex, dstIndex, options.fvarChannel);
|
||||
}
|
||||
|
||||
if (options.factorizeIntermediateLevels) {
|
||||
srcIndex = dstIndex;
|
||||
}
|
||||
|
||||
int dstVertex = !interpolateFaceVarying
|
||||
? refiner.GetLevel(level).GetNumVertices()
|
||||
: refiner.GetLevel(level).GetNumFVarValues(options.fvarChannel);
|
||||
dstIndex = dstIndex[dstVertex];
|
||||
|
||||
if (! options.factorizeIntermediateLevels) {
|
||||
// All previous verts are considered as coarse verts, as a
|
||||
// result, we don't update the srcIndex and update the coarse
|
||||
// vertex count.
|
||||
builder.SetCoarseVertCount(dstIndex.GetOffset());
|
||||
}
|
||||
}
|
||||
|
||||
size_t firstOffset = numControlVertices;
|
||||
if (! options.generateIntermediateLevels)
|
||||
firstOffset = srcIndex.GetOffset();
|
||||
|
||||
// Copy stencils from the StencilBuilder into the StencilTable.
|
||||
// Always initialize numControlVertices (useful for torus case)
|
||||
StencilTableReal<REAL> * result =
|
||||
new StencilTableReal<REAL>(numControlVertices,
|
||||
builder.GetStencilOffsets(),
|
||||
builder.GetStencilSizes(),
|
||||
builder.GetStencilSources(),
|
||||
builder.GetStencilWeights(),
|
||||
options.generateControlVerts,
|
||||
firstOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::Create(int numTables,
|
||||
StencilTableReal<REAL> const ** tables) {
|
||||
|
||||
// XXXtakahito:
|
||||
// This function returns NULL for empty inputs or erroneous condition.
|
||||
// It's convenient for skipping varying stencils etc, however,
|
||||
// other Create() API returns an empty stencil instead of NULL.
|
||||
// They need to be consistent.
|
||||
|
||||
if ( (numTables<=0) || (! tables)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ncvs = -1,
|
||||
nstencils = 0,
|
||||
nelems = 0;
|
||||
|
||||
for (int i=0; i<numTables; ++i) {
|
||||
|
||||
StencilTableReal<REAL> const * st = tables[i];
|
||||
// allow the tables could have a null entry.
|
||||
if (!st) continue;
|
||||
|
||||
if (ncvs >= 0 && st->GetNumControlVertices() != ncvs) {
|
||||
return NULL;
|
||||
}
|
||||
ncvs = st->GetNumControlVertices();
|
||||
nstencils += st->GetNumStencils();
|
||||
nelems += (int)st->GetControlIndices().size();
|
||||
}
|
||||
|
||||
if (ncvs == -1) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->resize(nstencils, nelems);
|
||||
|
||||
int * sizes = &result->_sizes[0];
|
||||
Index * indices = &result->_indices[0];
|
||||
REAL * weights = &result->_weights[0];
|
||||
for (int i=0; i<numTables; ++i) {
|
||||
StencilTableReal<REAL> const * st = tables[i];
|
||||
if (!st) continue;
|
||||
|
||||
int st_nstencils = st->GetNumStencils(),
|
||||
st_nelems = (int)st->_indices.size();
|
||||
memcpy(sizes, &st->_sizes[0], st_nstencils*sizeof(int));
|
||||
memcpy(indices, &st->_indices[0], st_nelems*sizeof(Index));
|
||||
memcpy(weights, &st->_weights[0], st_nelems*sizeof(REAL));
|
||||
|
||||
sizes += st_nstencils;
|
||||
indices += st_nelems;
|
||||
weights += st_nelems;
|
||||
}
|
||||
|
||||
result->_numControlVertices = ncvs;
|
||||
|
||||
// have to re-generate offsets from scratch
|
||||
result->generateOffsets();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
bool factorize) {
|
||||
|
||||
return appendLocalPointStencilTable(
|
||||
refiner,
|
||||
baseStencilTable,
|
||||
localPointStencilTable,
|
||||
/*channel*/-1,
|
||||
factorize);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize) {
|
||||
|
||||
return appendLocalPointStencilTable(
|
||||
refiner,
|
||||
baseStencilTable,
|
||||
localPointStencilTable,
|
||||
channel,
|
||||
factorize);
|
||||
}
|
||||
|
||||
template <typename REAL>
|
||||
StencilTableReal<REAL> const *
|
||||
StencilTableFactoryReal<REAL>::appendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize) {
|
||||
|
||||
// require the local point stencils exist and be non-empty
|
||||
if ((localPointStencilTable == NULL) ||
|
||||
(localPointStencilTable->GetNumStencils() == 0)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nControlVerts = channel < 0
|
||||
? refiner.GetLevel(0).GetNumVertices()
|
||||
: refiner.GetLevel(0).GetNumFVarValues(channel);
|
||||
|
||||
// if no base stencils or empty, return copy of local point stencils
|
||||
if ((baseStencilTable == NULL) ||
|
||||
(baseStencilTable->GetNumStencils() == 0)) {
|
||||
StencilTableReal<REAL> * result =
|
||||
new StencilTableReal<REAL>(*localPointStencilTable);
|
||||
result->_numControlVertices = nControlVerts;
|
||||
return result;
|
||||
}
|
||||
|
||||
// baseStencilTable can be built with or without singular stencils
|
||||
// (single weight of 1.0f) as place-holders for coarse mesh vertices.
|
||||
|
||||
int controlVertsIndexOffset = 0;
|
||||
int nBaseStencils = baseStencilTable->GetNumStencils();
|
||||
int nBaseStencilsElements = (int)baseStencilTable->_indices.size();
|
||||
{
|
||||
int nverts = channel < 0
|
||||
? refiner.GetNumVerticesTotal()
|
||||
: refiner.GetNumFVarValuesTotal(channel);
|
||||
if (nBaseStencils == nverts) {
|
||||
|
||||
// the table contains stencils for the control vertices
|
||||
//
|
||||
// <----------------- nverts ------------------>
|
||||
//
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | control verts | refined verts : (max lv) | local points |
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | base stencil table | LP stencils |
|
||||
// +--------------------------------------------+-----------------+
|
||||
// ^ /
|
||||
// \_________________________/
|
||||
//
|
||||
//
|
||||
controlVertsIndexOffset = 0;
|
||||
|
||||
} else if (nBaseStencils == (nverts - nControlVerts)) {
|
||||
|
||||
// the table does not contain stencils for the control vertices
|
||||
//
|
||||
// <----------------- nverts ------------------>
|
||||
// <------ nBaseStencils ------->
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | control verts | refined verts : (max lv) | local points |
|
||||
// +---------------+----------------------------+-----------------+
|
||||
// | base stencil table | LP stencils |
|
||||
// +----------------------------+-----------------+
|
||||
// ^ /
|
||||
// \_________________/
|
||||
// <-------------->
|
||||
// controlVertsIndexOffset
|
||||
//
|
||||
controlVertsIndexOffset = nControlVerts;
|
||||
|
||||
} else {
|
||||
// these are not the stencils you are looking for.
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// copy all local point stencils to proto stencils, and factorize if needed.
|
||||
int nLocalPointStencils = localPointStencilTable->GetNumStencils();
|
||||
int nLocalPointStencilsElements = 0;
|
||||
|
||||
StencilBuilder<REAL> builder(nControlVerts,
|
||||
/*genControlVerts*/ false,
|
||||
/*compactWeights*/ factorize);
|
||||
typename StencilBuilder<REAL>::Index origin(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dst = origin;
|
||||
typename StencilBuilder<REAL>::Index srcIdx = origin;
|
||||
|
||||
for (int i = 0 ; i < nLocalPointStencils; ++i) {
|
||||
StencilReal<REAL> src = localPointStencilTable->GetStencil(i);
|
||||
dst = origin[i];
|
||||
for (int j = 0; j < src.GetSize(); ++j) {
|
||||
Index index = src.GetVertexIndices()[j];
|
||||
REAL weight = src.GetWeights()[j];
|
||||
if (isWeightZero<REAL>(weight)) continue;
|
||||
|
||||
if (factorize) {
|
||||
dst.AddWithWeight(
|
||||
// subtracting controlVertsIndex if the baseStencil doesn't
|
||||
// include control vertices (see above diagram)
|
||||
// since currently local point stencils are created with
|
||||
// absolute indices including control (level=0) vertices.
|
||||
baseStencilTable->GetStencil(index - controlVertsIndexOffset),
|
||||
weight);
|
||||
} else {
|
||||
srcIdx = origin[index + controlVertsIndexOffset];
|
||||
dst.AddWithWeight(srcIdx, weight);
|
||||
}
|
||||
}
|
||||
nLocalPointStencilsElements += builder.GetNumVertsInStencil(i);
|
||||
}
|
||||
|
||||
// create new stencil table
|
||||
StencilTableReal<REAL> * result = new StencilTableReal<REAL>;
|
||||
result->_numControlVertices = nControlVerts;
|
||||
result->resize(nBaseStencils + nLocalPointStencils,
|
||||
nBaseStencilsElements + nLocalPointStencilsElements);
|
||||
|
||||
int* sizes = &result->_sizes[0];
|
||||
Index * indices = &result->_indices[0];
|
||||
REAL * weights = &result->_weights[0];
|
||||
|
||||
// put base stencils first
|
||||
memcpy(sizes, &baseStencilTable->_sizes[0],
|
||||
nBaseStencils*sizeof(int));
|
||||
memcpy(indices, &baseStencilTable->_indices[0],
|
||||
nBaseStencilsElements*sizeof(Index));
|
||||
memcpy(weights, &baseStencilTable->_weights[0],
|
||||
nBaseStencilsElements*sizeof(REAL));
|
||||
|
||||
sizes += nBaseStencils;
|
||||
indices += nBaseStencilsElements;
|
||||
weights += nBaseStencilsElements;
|
||||
|
||||
// endcap stencils second
|
||||
for (int i = 0 ; i < nLocalPointStencils; ++i) {
|
||||
int size = builder.GetNumVertsInStencil(i);
|
||||
int idx = builder.GetStencilOffsets()[i];
|
||||
for (int j = 0; j < size; ++j) {
|
||||
*indices++ = builder.GetStencilSources()[idx+j];
|
||||
*weights++ = builder.GetStencilWeights()[idx+j];
|
||||
}
|
||||
*sizes++ = size;
|
||||
}
|
||||
|
||||
// have to re-generate offsets from scratch
|
||||
result->generateOffsets();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <typename REAL>
|
||||
LimitStencilTableReal<REAL> const *
|
||||
LimitStencilTableFactoryReal<REAL>::Create(TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTableReal<REAL> const * cvStencilsIn,
|
||||
PatchTable const * patchTableIn,
|
||||
Options options) {
|
||||
|
||||
// Compute the total number of stencils to generate
|
||||
int numStencils=0, numLimitStencils=0;
|
||||
for (int i=0; i<(int)locationArrays.size(); ++i) {
|
||||
assert(locationArrays[i].numLocations>=0);
|
||||
numStencils += locationArrays[i].numLocations;
|
||||
}
|
||||
if (numStencils<=0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uniform = refiner.IsUniform();
|
||||
int maxlevel = refiner.GetMaxLevel();
|
||||
|
||||
bool interpolateVertex = (options.interpolationMode == INTERPOLATE_VERTEX);
|
||||
bool interpolateVarying = (options.interpolationMode == INTERPOLATE_VARYING);
|
||||
bool interpolateFaceVarying = (options.interpolationMode == INTERPOLATE_FACE_VARYING);
|
||||
int fvarChannel = options.fvarChannel;
|
||||
|
||||
//
|
||||
// Quick sanity checks for given PatchTable and/or StencilTables:
|
||||
//
|
||||
int nRefinedStencils = 0;
|
||||
if (uniform) {
|
||||
// Uniform stencils must include at least the last level points:
|
||||
nRefinedStencils = interpolateFaceVarying
|
||||
? refiner.GetLevel(maxlevel).GetNumFVarValues(fvarChannel)
|
||||
: refiner.GetLevel(maxlevel).GetNumVertices();
|
||||
} else {
|
||||
// Adaptive stencils must include at least all refined points:
|
||||
nRefinedStencils = interpolateFaceVarying
|
||||
? refiner.GetNumFVarValuesTotal(fvarChannel)
|
||||
: refiner.GetNumVerticesTotal();
|
||||
}
|
||||
if (cvStencilsIn && (cvStencilsIn->GetNumStencils() < nRefinedStencils)) {
|
||||
// Too few stencils in given StencilTable
|
||||
return 0;
|
||||
}
|
||||
if (patchTableIn && (patchTableIn->IsFeatureAdaptive() == uniform)) {
|
||||
// Adaptive/uniform mismatch with given PatchTable and refiner
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If an appropriate StencilTable was given, use it, otherwise, create a new one
|
||||
StencilTableReal<REAL> const * cvstencils = cvStencilsIn;
|
||||
if (! cvstencils) {
|
||||
//
|
||||
// Generate stencils for the control vertices - this is necessary to
|
||||
// properly factorize patches with control vertices at level 0 (natural
|
||||
// regular patches, such as in a torus)
|
||||
// note: the control vertices of the mesh are added as single-index
|
||||
// stencils of weight 1.0f
|
||||
//
|
||||
typename StencilTableFactoryReal<REAL>::Options stencilTableOptions;
|
||||
stencilTableOptions.generateIntermediateLevels = uniform ? false :true;
|
||||
stencilTableOptions.generateControlVerts = true;
|
||||
stencilTableOptions.generateOffsets = true;
|
||||
stencilTableOptions.interpolationMode = options.interpolationMode;
|
||||
stencilTableOptions.fvarChannel = options.fvarChannel;
|
||||
|
||||
cvstencils = StencilTableFactoryReal<REAL>::Create(refiner, stencilTableOptions);
|
||||
}
|
||||
|
||||
// If an appropriate PatchTable was given, use it, otherwise, create a new one
|
||||
PatchTable const * patchtable = patchTableIn;
|
||||
if (! patchtable) {
|
||||
//
|
||||
// Ideally we could create a sparse PatchTable here for the given
|
||||
// Locations, but that requires inverting the ptex/base-face relation.
|
||||
// so the caller must deal with that and provide such a PatchTable
|
||||
//
|
||||
PatchTableFactory::Options patchTableOptions;
|
||||
patchTableOptions.SetPatchPrecision<REAL>();
|
||||
patchTableOptions.includeBaseLevelIndices = true;
|
||||
patchTableOptions.generateVaryingTables = interpolateVarying;
|
||||
patchTableOptions.generateFVarTables = interpolateFaceVarying;
|
||||
if (interpolateFaceVarying) {
|
||||
patchTableOptions.includeFVarBaseLevelIndices = true;
|
||||
patchTableOptions.numFVarChannels = 1;
|
||||
patchTableOptions.fvarChannelIndices = &fvarChannel;
|
||||
patchTableOptions.generateFVarLegacyLinearPatches = uniform ||
|
||||
!refiner.GetAdaptiveOptions().considerFVarChannels;
|
||||
}
|
||||
patchTableOptions.SetEndCapType(
|
||||
Far::PatchTableFactory::Options::ENDCAP_GREGORY_BASIS);
|
||||
patchTableOptions.useInfSharpPatch = !uniform &&
|
||||
refiner.GetAdaptiveOptions().useInfSharpPatch;
|
||||
|
||||
patchtable = PatchTableFactory::Create(refiner, patchTableOptions);
|
||||
}
|
||||
|
||||
// Append local point stencils and further verfiy size of given StencilTable:
|
||||
StencilTableReal<REAL> const * localstencils = 0;
|
||||
if (interpolateVertex) {
|
||||
localstencils = patchtable->GetLocalPointStencilTable<REAL>();
|
||||
} else if (interpolateFaceVarying) {
|
||||
localstencils = patchtable->GetLocalPointFaceVaryingStencilTable<REAL>(fvarChannel);
|
||||
} else {
|
||||
localstencils = patchtable->GetLocalPointVaryingStencilTable<REAL>();
|
||||
}
|
||||
|
||||
if (localstencils && (cvstencils->GetNumStencils() == nRefinedStencils)) {
|
||||
StencilTableReal<REAL> const *refinedstencils = cvstencils;
|
||||
if (interpolateFaceVarying) {
|
||||
cvstencils = StencilTableFactoryReal<REAL>::AppendLocalPointStencilTableFaceVarying(
|
||||
refiner, refinedstencils, localstencils, fvarChannel);
|
||||
} else {
|
||||
cvstencils = StencilTableFactoryReal<REAL>::AppendLocalPointStencilTable(
|
||||
refiner, refinedstencils, localstencils);
|
||||
}
|
||||
if (!cvStencilsIn) delete refinedstencils;
|
||||
}
|
||||
|
||||
assert(patchtable && cvstencils);
|
||||
|
||||
// Create a patch-map to locate sub-patches faster
|
||||
PatchMap patchmap( *patchtable );
|
||||
|
||||
//
|
||||
// Generate limit stencils for locations
|
||||
//
|
||||
int nControlVertices = interpolateFaceVarying
|
||||
? refiner.GetLevel(0).GetNumFVarValues(fvarChannel)
|
||||
: refiner.GetLevel(0).GetNumVertices();
|
||||
|
||||
StencilBuilder<REAL> builder(nControlVertices,
|
||||
/*genControlVerts*/ false,
|
||||
/*compactWeights*/ true);
|
||||
typename StencilBuilder<REAL>::Index origin(&builder, 0);
|
||||
typename StencilBuilder<REAL>::Index dst = origin;
|
||||
|
||||
//
|
||||
// Generally use the patches corresponding to the interpolation mode, but Uniform
|
||||
// PatchTables do not have varying patches -- use the equivalent linear vertex
|
||||
// patches in this case:
|
||||
//
|
||||
bool useVertexPatches = interpolateVertex || (interpolateVarying && uniform);
|
||||
bool useFVarPatches = interpolateFaceVarying;
|
||||
|
||||
REAL wP[20], wDs[20], wDt[20], wDss[20], wDst[20], wDtt[20];
|
||||
|
||||
for (size_t i=0; i<locationArrays.size(); ++i) {
|
||||
LocationArray const & array = locationArrays[i];
|
||||
assert(array.ptexIdx>=0);
|
||||
|
||||
for (int j=0; j<array.numLocations; ++j) { // for each face we're working on
|
||||
REAL s = array.s[j],
|
||||
t = array.t[j]; // for each target (s,t) point on that face
|
||||
|
||||
PatchMap::Handle const * handle =
|
||||
patchmap.FindPatch(array.ptexIdx, s, t);
|
||||
if (handle) {
|
||||
ConstIndexArray cvs;
|
||||
if (useVertexPatches) {
|
||||
cvs = patchtable->GetPatchVertices(*handle);
|
||||
} else if (useFVarPatches) {
|
||||
cvs = patchtable->GetPatchFVarValues(*handle, fvarChannel);
|
||||
} else {
|
||||
cvs = patchtable->GetPatchVaryingVertices(*handle);
|
||||
}
|
||||
|
||||
StencilTableReal<REAL> const & src = *cvstencils;
|
||||
dst = origin[numLimitStencils];
|
||||
|
||||
if (options.generate2ndDerivatives) {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, wDss, wDst, wDtt);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k], wDss[k], wDst[k], wDtt[k]);
|
||||
}
|
||||
} else if (options.generate1stDerivatives) {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt, 0, 0, 0, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP, wDs, wDt);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k], wDs[k], wDt[k]);
|
||||
}
|
||||
} else {
|
||||
if (useVertexPatches) {
|
||||
patchtable->EvaluateBasis<REAL>(
|
||||
*handle, s, t, wP);
|
||||
} else if (useFVarPatches) {
|
||||
patchtable->EvaluateBasisFaceVarying<REAL>(
|
||||
*handle, s, t, wP, 0, 0, 0, 0, 0, fvarChannel);
|
||||
} else {
|
||||
patchtable->EvaluateBasisVarying<REAL>(
|
||||
*handle, s, t, wP);
|
||||
}
|
||||
|
||||
dst.Clear();
|
||||
for (int k = 0; k < cvs.size(); ++k) {
|
||||
dst.AddWithWeight(src[cvs[k]], wP[k]);
|
||||
}
|
||||
}
|
||||
|
||||
++numLimitStencils;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! cvStencilsIn) {
|
||||
delete cvstencils;
|
||||
}
|
||||
|
||||
if (! patchTableIn) {
|
||||
delete patchtable;
|
||||
}
|
||||
|
||||
//
|
||||
// Copy the proto-stencils into the limit stencil table
|
||||
//
|
||||
LimitStencilTableReal<REAL> * result = new LimitStencilTableReal<REAL>(
|
||||
nControlVertices,
|
||||
builder.GetStencilOffsets(),
|
||||
builder.GetStencilSizes(),
|
||||
builder.GetStencilSources(),
|
||||
builder.GetStencilWeights(),
|
||||
builder.GetStencilDuWeights(),
|
||||
builder.GetStencilDvWeights(),
|
||||
builder.GetStencilDuuWeights(),
|
||||
builder.GetStencilDuvWeights(),
|
||||
builder.GetStencilDvvWeights(),
|
||||
/*ctrlVerts*/false,
|
||||
/*fristOffset*/0);
|
||||
return result;
|
||||
}
|
||||
|
||||
//
|
||||
// Explicit instantiation for float and double:
|
||||
//
|
||||
template class StencilTableFactoryReal<float>;
|
||||
template class StencilTableFactoryReal<double>;
|
||||
|
||||
template class LimitStencilTableFactoryReal<float>;
|
||||
template class LimitStencilTableFactoryReal<double>;
|
||||
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
367
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTableFactory.h
vendored
Normal file
367
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/stencilTableFactory.h
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
//
|
||||
// Copyright 2013 Pixar
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/patchTable.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
class TopologyRefiner;
|
||||
|
||||
template <typename REAL> class StencilReal;
|
||||
template <typename REAL> class StencilTableReal;
|
||||
|
||||
template <typename REAL> class LimitStencilReal;
|
||||
template <typename REAL> class LimitStencilTableReal;
|
||||
|
||||
|
||||
/// \brief A specialized factory for StencilTable
|
||||
///
|
||||
template <typename REAL>
|
||||
class StencilTableFactoryReal {
|
||||
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
INTERPOLATE_VERTEX=0, ///< vertex primvar stencils
|
||||
INTERPOLATE_VARYING, ///< varying primvar stencils
|
||||
INTERPOLATE_FACE_VARYING ///< face-varying primvar stencils
|
||||
};
|
||||
|
||||
struct Options {
|
||||
|
||||
Options() : interpolationMode(INTERPOLATE_VERTEX),
|
||||
generateOffsets(false),
|
||||
generateControlVerts(false),
|
||||
generateIntermediateLevels(true),
|
||||
factorizeIntermediateLevels(true),
|
||||
maxLevel(10),
|
||||
fvarChannel(0) { }
|
||||
|
||||
unsigned int interpolationMode : 2, ///< interpolation mode
|
||||
generateOffsets : 1, ///< populate optional "_offsets" field
|
||||
generateControlVerts : 1, ///< generate stencils for control-vertices
|
||||
generateIntermediateLevels : 1, ///< vertices at all levels or highest only
|
||||
factorizeIntermediateLevels : 1, ///< accumulate stencil weights from control
|
||||
/// vertices or from the stencils of the
|
||||
/// previous level
|
||||
maxLevel : 4; ///< generate stencils up to 'maxLevel'
|
||||
unsigned int fvarChannel; ///< face-varying channel to use
|
||||
/// when generating face-varying stencils
|
||||
};
|
||||
|
||||
/// \brief Instantiates StencilTable from TopologyRefiner that have been
|
||||
/// refined uniformly or adaptively.
|
||||
///
|
||||
/// \note The factory only creates stencils for vertices that have already
|
||||
/// been refined in the TopologyRefiner. Use RefineUniform() or
|
||||
/// RefineAdaptive() before constructing the stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
static StencilTableReal<REAL> const * Create(
|
||||
TopologyRefiner const & refiner, Options options = Options());
|
||||
|
||||
|
||||
/// \brief Instantiates StencilTable by concatenating an array of existing
|
||||
/// stencil tables.
|
||||
///
|
||||
/// \note This factory checks that the stencil tables point to the same set
|
||||
/// of supporting control vertices - no re-indexing is done.
|
||||
/// GetNumControlVertices() *must* return the same value for all input
|
||||
/// tables.
|
||||
///
|
||||
/// @param numTables Number of input StencilTables
|
||||
///
|
||||
/// @param tables Array of input StencilTables
|
||||
///
|
||||
static StencilTableReal<REAL> const * Create(
|
||||
int numTables, StencilTableReal<REAL> const ** tables);
|
||||
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
bool factorize = true);
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point varying stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTableVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
return AppendLocalPointStencilTable(
|
||||
refiner, baseStencilTable, localPointStencilTable, factorize);
|
||||
}
|
||||
|
||||
/// \brief Utility function for stencil splicing for local point
|
||||
/// face-varying stencils.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param baseStencilTable Input StencilTable for refined vertices
|
||||
///
|
||||
/// @param localPointStencilTable
|
||||
/// StencilTable for the change of basis patch points.
|
||||
///
|
||||
/// @param channel face-varying channel
|
||||
///
|
||||
/// @param factorize If factorize is set to true, endcap stencils will be
|
||||
/// factorized with supporting vertices from baseStencil
|
||||
/// table so that the endcap points can be computed
|
||||
/// directly from control vertices.
|
||||
///
|
||||
static StencilTableReal<REAL> const * AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const *baseStencilTable,
|
||||
StencilTableReal<REAL> const *localPointStencilTable,
|
||||
int channel = 0,
|
||||
bool factorize = true);
|
||||
|
||||
private:
|
||||
|
||||
// Generate stencils for the coarse control-vertices (single weight = 1.0f)
|
||||
static void generateControlVertStencils(
|
||||
int numControlVerts,
|
||||
StencilReal<REAL> & dst);
|
||||
|
||||
// Internal method to splice local point stencils
|
||||
static StencilTableReal<REAL> const * appendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTableReal<REAL> const * baseStencilTable,
|
||||
StencilTableReal<REAL> const * localPointStencilTable,
|
||||
int channel,
|
||||
bool factorize);
|
||||
};
|
||||
|
||||
/// \brief A specialized factory for LimitStencilTable
|
||||
///
|
||||
/// The LimitStencilTableFactory creates a table of limit stencils. Limit
|
||||
/// stencils can interpolate any arbitrary location on the limit surface.
|
||||
/// The stencils will be bilinear if the surface is refined uniformly, and
|
||||
/// bicubic if feature adaptive isolation is used instead.
|
||||
///
|
||||
/// Surface locations are expressed as a combination of ptex face index and
|
||||
/// normalized (s,t) patch coordinates. The factory exposes the LocationArray
|
||||
/// struct as a container for these location descriptors.
|
||||
///
|
||||
template <typename REAL>
|
||||
class LimitStencilTableFactoryReal {
|
||||
|
||||
public:
|
||||
|
||||
enum Mode {
|
||||
INTERPOLATE_VERTEX=0, ///< vertex primvar stencils
|
||||
INTERPOLATE_VARYING, ///< varying primvar stencils
|
||||
INTERPOLATE_FACE_VARYING ///< face-varying primvar stencils
|
||||
};
|
||||
|
||||
struct Options {
|
||||
|
||||
Options() : interpolationMode(INTERPOLATE_VERTEX),
|
||||
generate1stDerivatives(true),
|
||||
generate2ndDerivatives(false),
|
||||
fvarChannel(0) { }
|
||||
|
||||
unsigned int interpolationMode : 2, ///< interpolation mode
|
||||
generate1stDerivatives : 1, ///< Generate weights for 1st derivatives
|
||||
generate2ndDerivatives : 1; ///< Generate weights for 2nd derivatives
|
||||
unsigned int fvarChannel; ///< face-varying channel to use
|
||||
};
|
||||
|
||||
/// \brief Descriptor for limit surface locations
|
||||
struct LocationArray {
|
||||
|
||||
LocationArray() : ptexIdx(-1), numLocations(0), s(0), t(0) { }
|
||||
|
||||
int ptexIdx, ///< ptex face index
|
||||
numLocations; ///< number of (u,v) coordinates in the array
|
||||
|
||||
REAL const * s, ///< array of u coordinates
|
||||
* t; ///< array of v coordinates
|
||||
};
|
||||
|
||||
typedef std::vector<LocationArray> LocationArrayVec;
|
||||
|
||||
/// \brief Instantiates LimitStencilTable from a TopologyRefiner that has
|
||||
/// been refined either uniformly or adaptively.
|
||||
///
|
||||
/// @param refiner The TopologyRefiner containing the topology
|
||||
///
|
||||
/// @param locationArrays An array of surface location descriptors
|
||||
/// (see LocationArray)
|
||||
///
|
||||
/// @param cvStencils A StencilTable generated from the TopologyRefiner
|
||||
/// (Optional: prevents redundant instantiation of the
|
||||
/// table if available. The given table must at least
|
||||
/// contain stencils for all control points and all
|
||||
/// refined points -- any stencils for local points of
|
||||
/// a PatchTable must match the PatchTable provided or
|
||||
/// internally generated)
|
||||
///
|
||||
/// @param patchTable A PatchTable generated from the TopologyRefiner
|
||||
/// (Optional: prevents redundant instantiation of the
|
||||
/// table if available. The given table must match
|
||||
/// the optional StencilTable if also provided)
|
||||
///
|
||||
/// @param options Options controlling the creation of the table
|
||||
///
|
||||
static LimitStencilTableReal<REAL> const * Create(
|
||||
TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTableReal<REAL> const * cvStencils = 0,
|
||||
PatchTable const * patchTable = 0,
|
||||
Options options = Options());
|
||||
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Public wrapper classes for the templates
|
||||
//
|
||||
class Stencil;
|
||||
class StencilTable;
|
||||
|
||||
/// \brief Stencil table factory class wrapping the template for compatibility.
|
||||
///
|
||||
class StencilTableFactory : public StencilTableFactoryReal<float> {
|
||||
private:
|
||||
typedef StencilTableFactoryReal<float> BaseFactory;
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
static StencilTable const * Create(
|
||||
TopologyRefiner const & refiner, Options options = Options()) {
|
||||
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
BaseFactory::Create(refiner, options));
|
||||
}
|
||||
|
||||
static StencilTable const * Create(
|
||||
int numTables, StencilTable const ** tables) {
|
||||
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
BaseFactory::Create(numTables,
|
||||
reinterpret_cast<BaseTable const **>(tables)));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTable(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTable(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
factorize));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTableVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
bool factorize = true) {
|
||||
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTableVarying(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
factorize));
|
||||
}
|
||||
|
||||
static StencilTable const * AppendLocalPointStencilTableFaceVarying(
|
||||
TopologyRefiner const &refiner,
|
||||
StencilTable const *baseStencilTable,
|
||||
StencilTable const *localPointStencilTable,
|
||||
int channel = 0,
|
||||
bool factorize = true) {
|
||||
|
||||
return reinterpret_cast<StencilTable const *>(
|
||||
BaseFactory::AppendLocalPointStencilTableFaceVarying(refiner,
|
||||
static_cast<BaseTable const *>(baseStencilTable),
|
||||
static_cast<BaseTable const *>(localPointStencilTable),
|
||||
channel, factorize));
|
||||
}
|
||||
};
|
||||
|
||||
class LimitStencil;
|
||||
class LimitStencilTable;
|
||||
|
||||
/// \brief Stencil table factory class wrapping the template for compatibility.
|
||||
///
|
||||
class LimitStencilTableFactory : public LimitStencilTableFactoryReal<float> {
|
||||
private:
|
||||
typedef LimitStencilTableFactoryReal<float> BaseFactory;
|
||||
typedef StencilTableReal<float> BaseTable;
|
||||
|
||||
public:
|
||||
static LimitStencilTable const * Create(
|
||||
TopologyRefiner const & refiner,
|
||||
LocationArrayVec const & locationArrays,
|
||||
StencilTable const * cvStencils = 0,
|
||||
PatchTable const * patchTable = 0,
|
||||
Options options = Options()) {
|
||||
|
||||
return reinterpret_cast<LimitStencilTable const *>(
|
||||
BaseFactory::Create(
|
||||
refiner,
|
||||
locationArrays,
|
||||
static_cast<BaseTable const *>(cvStencils),
|
||||
patchTable,
|
||||
options));
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif // OPENSUBDIV3_FAR_STENCILTABLE_FACTORY_H
|
||||
168
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyDescriptor.cpp
vendored
Normal file
168
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyDescriptor.cpp
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../far/topologyDescriptor.h"
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
|
||||
// Unfortunately necessary for error codes that should be more accessible...
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Definitions for TopologyDescriptor:
|
||||
//
|
||||
TopologyDescriptor::TopologyDescriptor() {
|
||||
memset(this, 0, sizeof(TopologyDescriptor));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Definitions/specializations for its RefinerFactory<TopologyDescriptor>:
|
||||
//
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::resizeComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
setNumBaseVertices(refiner, desc.numVertices);
|
||||
setNumBaseFaces(refiner, desc.numFaces);
|
||||
|
||||
for (int face=0; face<desc.numFaces; ++face) {
|
||||
|
||||
setNumBaseFaceVertices(refiner, face, desc.numVertsPerFace[face]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
for (int face=0, idx=0; face<desc.numFaces; ++face) {
|
||||
|
||||
IndexArray dstFaceVerts = getBaseFaceVertices(refiner, face);
|
||||
|
||||
if (desc.isLeftHanded) {
|
||||
dstFaceVerts[0] = desc.vertIndicesPerFace[idx++];
|
||||
for (int vert=dstFaceVerts.size()-1; vert > 0; --vert) {
|
||||
|
||||
dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++];
|
||||
}
|
||||
} else {
|
||||
for (int vert=0; vert<dstFaceVerts.size(); ++vert) {
|
||||
|
||||
dstFaceVerts[vert] = desc.vertIndicesPerFace[idx++];
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTags(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
if ((desc.numCreases>0) && desc.creaseVertexIndexPairs && desc.creaseWeights) {
|
||||
|
||||
int const * vertIndexPairs = desc.creaseVertexIndexPairs;
|
||||
for (int edge=0; edge<desc.numCreases; ++edge, vertIndexPairs+=2) {
|
||||
|
||||
Index idx = findBaseEdge(refiner, vertIndexPairs[0], vertIndexPairs[1]);
|
||||
|
||||
if (idx!=INDEX_INVALID) {
|
||||
setBaseEdgeSharpness(refiner, idx, desc.creaseWeights[edge]);
|
||||
} else {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024, "Edge %d specified to be sharp does not exist (%d, %d)",
|
||||
edge, vertIndexPairs[0], vertIndexPairs[1]);
|
||||
reportInvalidTopology(Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_EDGE, msg, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((desc.numCorners>0) && desc.cornerVertexIndices && desc.cornerWeights) {
|
||||
|
||||
for (int vert=0; vert<desc.numCorners; ++vert) {
|
||||
|
||||
int idx = desc.cornerVertexIndices[vert];
|
||||
|
||||
if (idx >= 0 && idx < getNumBaseVertices(refiner)) {
|
||||
setBaseVertexSharpness(refiner, idx, desc.cornerWeights[vert]);
|
||||
} else {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024, "Vertex %d specified to be sharp does not exist", idx);
|
||||
reportInvalidTopology(Vtr::internal::Level::TOPOLOGY_INVALID_CREASE_VERT, msg, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (desc.numHoles>0) {
|
||||
for (int i=0; i<desc.numHoles; ++i) {
|
||||
setBaseFaceHole(refiner, desc.holeIndices[i], true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignFaceVaryingTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc) {
|
||||
|
||||
if (desc.numFVarChannels>0) {
|
||||
|
||||
for (int channel=0; channel<desc.numFVarChannels; ++channel) {
|
||||
|
||||
int numFVarValues = desc.fvarChannels[channel].numValues;
|
||||
int const* srcFVarValues = desc.fvarChannels[channel].valueIndices;
|
||||
|
||||
createBaseFVarChannel(refiner, numFVarValues);
|
||||
|
||||
for (int face = 0, srcNext = 0; face < desc.numFaces; ++face) {
|
||||
|
||||
IndexArray dstFaceFVarValues = getBaseFaceFVarValues(refiner, face, channel);
|
||||
|
||||
if (desc.isLeftHanded) {
|
||||
dstFaceFVarValues[0] = srcFVarValues[srcNext++];
|
||||
for (int vert = dstFaceFVarValues.size() - 1; vert > 0; --vert) {
|
||||
|
||||
dstFaceFVarValues[vert] = srcFVarValues[srcNext++];
|
||||
}
|
||||
} else {
|
||||
for (int vert = 0; vert < dstFaceFVarValues.size(); ++vert) {
|
||||
|
||||
dstFaceFVarValues[vert] = srcFVarValues[srcNext++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
TopologyRefinerFactory<TopologyDescriptor>::reportInvalidTopology(
|
||||
TopologyError /* errCode */, char const * msg, TopologyDescriptor const& /* mesh */) {
|
||||
Warning(msg);
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
110
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyDescriptor.h
vendored
Normal file
110
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyDescriptor.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief A simple reference to raw topology data for use with TopologyRefinerFactory
|
||||
///
|
||||
/// TopologyDescriptor is a simple struct containing references to raw topology data used
|
||||
/// to construct a TopologyRefiner. It is not a requirement but a convenience for use
|
||||
/// with TopologyRefinerFactory when mesh topology is not available in an existing mesh
|
||||
/// data structure. It should be functionally complete and simple to use, but for more
|
||||
/// demanding situations, writing a custom Factory is usually warranted.
|
||||
///
|
||||
struct TopologyDescriptor {
|
||||
|
||||
int numVertices,
|
||||
numFaces;
|
||||
|
||||
int const * numVertsPerFace;
|
||||
Index const * vertIndicesPerFace;
|
||||
|
||||
int numCreases;
|
||||
Index const * creaseVertexIndexPairs;
|
||||
float const * creaseWeights;
|
||||
|
||||
int numCorners;
|
||||
Index const * cornerVertexIndices;
|
||||
float const * cornerWeights;
|
||||
|
||||
int numHoles;
|
||||
Index const * holeIndices;
|
||||
|
||||
bool isLeftHanded;
|
||||
|
||||
// Face-varying data channel -- value indices correspond to vertex indices,
|
||||
// i.e. one for every vertex of every face:
|
||||
//
|
||||
struct FVarChannel {
|
||||
|
||||
int numValues;
|
||||
Index const * valueIndices;
|
||||
|
||||
FVarChannel() : numValues(0), valueIndices(0) { }
|
||||
};
|
||||
|
||||
int numFVarChannels;
|
||||
FVarChannel const * fvarChannels;
|
||||
|
||||
TopologyDescriptor();
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Forward declarations of required TopologyRefinerFactory<TopologyDescriptor>
|
||||
// specializations (defined internally):
|
||||
//
|
||||
// @cond EXCLUDE_DOXYGEN
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::resizeComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignComponentTags(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
bool
|
||||
TopologyRefinerFactory<TopologyDescriptor>::assignFaceVaryingTopology(
|
||||
TopologyRefiner & refiner, TopologyDescriptor const & desc);
|
||||
|
||||
template <>
|
||||
void
|
||||
TopologyRefinerFactory<TopologyDescriptor>::reportInvalidTopology(
|
||||
TopologyError errCode, char const * msg, TopologyDescriptor const & desc);
|
||||
|
||||
// @endcond
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_DESCRIPTOR_H */
|
||||
293
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyLevel.h
vendored
Normal file
293
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyLevel.h
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Copyright 2015 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/level.h"
|
||||
#include "../vtr/refinement.h"
|
||||
#include "../far/types.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///
|
||||
/// \brief An interface for accessing data in a specific level of a refined topology hierarchy.
|
||||
///
|
||||
/// TopologyLevel provides an interface to data in a specific level of a topology hierarchy.
|
||||
/// Instances of TopologyLevel are created and owned by a TopologyRefiner,
|
||||
/// which will return const-references to them. Such references are only valid during the
|
||||
/// lifetime of the TopologyRefiner that created and returned them, and only for a given refinement,
|
||||
/// i.e. if the TopologyRefiner is re-refined, any references to TopoologyLevels are invalidated.
|
||||
///
|
||||
class TopologyLevel {
|
||||
|
||||
public:
|
||||
//@{
|
||||
/// @name Methods to inspect the overall inventory of components:
|
||||
///
|
||||
/// All three main component types are indexed locally within each level. For
|
||||
/// some topological relationships -- notably face-vertices, which is often
|
||||
/// the only relationship of interest -- the total number of entries is also
|
||||
/// made available.
|
||||
///
|
||||
|
||||
/// \brief Return the number of vertices in this level
|
||||
int GetNumVertices() const { return _level->getNumVertices(); }
|
||||
|
||||
/// \brief Return the number of faces in this level
|
||||
int GetNumFaces() const { return _level->getNumFaces(); }
|
||||
|
||||
/// \brief Return the number of edges in this level
|
||||
int GetNumEdges() const { return _level->getNumEdges(); }
|
||||
|
||||
/// \brief Return the total number of face-vertices, i.e. the sum of all vertices for all faces
|
||||
int GetNumFaceVertices() const { return _level->getNumFaceVerticesTotal(); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect topological relationships for individual components:
|
||||
///
|
||||
/// With three main component types (vertices, faces and edges), for each of the
|
||||
/// three components the TopologyLevel stores the incident/adjacent components of
|
||||
/// the other two types. So there are six relationships available for immediate
|
||||
/// inspection. All are accessed by methods that return an array of fixed size
|
||||
/// containing the indices of the incident components.
|
||||
///
|
||||
/// For some of the relations, i.e. those for which the incident components are
|
||||
/// of higher order or 'contain' the component itself (e.g. a vertex has incident
|
||||
/// faces that contain it), an additional 'local index' is available that identifies
|
||||
/// the component within each of its neighbors. For example, if vertex V is the k'th
|
||||
/// vertex in some face F, then when F occurs in the set of incident vertices of V,
|
||||
/// the local index corresponding to F will be k. The ordering of local indices
|
||||
/// matches the ordering of the incident component to which it corresponds.
|
||||
//
|
||||
|
||||
/// \brief Access the vertices incident a given face
|
||||
ConstIndexArray GetFaceVertices(Index f) const { return _level->getFaceVertices(f); }
|
||||
|
||||
/// \brief Access the edges incident a given face
|
||||
ConstIndexArray GetFaceEdges(Index f) const { return _level->getFaceEdges(f); }
|
||||
|
||||
/// \brief Access the vertices incident a given edge
|
||||
ConstIndexArray GetEdgeVertices(Index e) const { return _level->getEdgeVertices(e); }
|
||||
|
||||
/// \brief Access the faces incident a given edge
|
||||
ConstIndexArray GetEdgeFaces(Index e) const { return _level->getEdgeFaces(e); }
|
||||
|
||||
/// \brief Access the faces incident a given vertex
|
||||
ConstIndexArray GetVertexFaces(Index v) const { return _level->getVertexFaces(v); }
|
||||
|
||||
/// \brief Access the edges incident a given vertex
|
||||
ConstIndexArray GetVertexEdges(Index v) const { return _level->getVertexEdges(v); }
|
||||
|
||||
/// \brief Access the local indices of a vertex with respect to its incident faces
|
||||
ConstLocalIndexArray GetVertexFaceLocalIndices(Index v) const { return _level->getVertexFaceLocalIndices(v); }
|
||||
|
||||
/// \brief Access the local indices of a vertex with respect to its incident edges
|
||||
ConstLocalIndexArray GetVertexEdgeLocalIndices(Index v) const { return _level->getVertexEdgeLocalIndices(v); }
|
||||
|
||||
/// \brief Access the local indices of an edge with respect to its incident faces
|
||||
ConstLocalIndexArray GetEdgeFaceLocalIndices(Index e) const { return _level->getEdgeFaceLocalIndices(e); }
|
||||
|
||||
/// \brief Identify the edge matching the given vertex pair
|
||||
Index FindEdge(Index v0, Index v1) const { return _level->findEdge(v0, v1); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect other topological properties of individual components:
|
||||
///
|
||||
|
||||
/// \brief Return if the edge is non-manifold
|
||||
bool IsEdgeNonManifold(Index e) const { return _level->isEdgeNonManifold(e); }
|
||||
|
||||
/// \brief Return if the vertex is non-manifold
|
||||
bool IsVertexNonManifold(Index v) const { return _level->isVertexNonManifold(v); }
|
||||
|
||||
/// \brief Return if the edge is a boundary (only one incident face)
|
||||
bool IsEdgeBoundary(Index e) const { return _level->getEdgeTag(e)._boundary; }
|
||||
|
||||
/// \brief Return if the vertex is on a boundary (at least one incident boundary edge)
|
||||
bool IsVertexBoundary(Index v) const { return _level->getVertexTag(v)._boundary; }
|
||||
|
||||
/// \brief Return if the vertex is a corner (only one incident face)
|
||||
bool IsVertexCorner(Index v) const { return (_level->getNumVertexFaces(v) == 1); }
|
||||
|
||||
/// \brief Return if the valence of the vertex is regular (must be manifold)
|
||||
///
|
||||
/// Note that this test only determines if the valence of the vertex is regular
|
||||
/// with respect to the assigned subdivision scheme -- not if the neighborhood
|
||||
/// around the vertex is regular. The latter depends on a number of factors
|
||||
/// including the incident faces of the vertex (they must all be regular) and
|
||||
/// the presence of sharpness at the vertex itself or its incident edges.
|
||||
///
|
||||
/// The regularity of the valence is a necessary but not a sufficient condition
|
||||
/// in determining the regularity of the neighborhood. For example, while the
|
||||
/// valence of an interior vertex may be regular, its neighborhood is not if the
|
||||
/// vertex was made infinitely sharp. Conversely, a corner vertex is considered
|
||||
/// regular by its valence but its neighborhood is not if the vertex was not made
|
||||
/// infinitely sharp.
|
||||
///
|
||||
/// Whether the valence of the vertex is regular is also a property that remains
|
||||
/// the same for the vertex in all subdivision levels. In contrast, the regularity
|
||||
/// of the region around the vertex may change as the presence of irregular faces
|
||||
/// or semi-sharp features is reduced by subdivision.
|
||||
///
|
||||
bool IsVertexValenceRegular(Index v) const { return !_level->getVertexTag(v)._xordinary || IsVertexCorner(v); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect feature tags for individual components:
|
||||
///
|
||||
/// While only a subset of components may have been tagged with features such
|
||||
/// as sharpness, all such features have a default value and so all components
|
||||
/// can be inspected.
|
||||
|
||||
/// \brief Return the sharpness assigned a given edge
|
||||
float GetEdgeSharpness(Index e) const { return _level->getEdgeSharpness(e); }
|
||||
|
||||
/// \brief Return the sharpness assigned a given vertex
|
||||
float GetVertexSharpness(Index v) const { return _level->getVertexSharpness(v); }
|
||||
|
||||
/// \brief Return if the edge is infinitely-sharp
|
||||
bool IsEdgeInfSharp(Index e) const { return _level->getEdgeTag(e)._infSharp; }
|
||||
|
||||
/// \brief Return if the vertex is infinitely-sharp
|
||||
bool IsVertexInfSharp(Index v) const { return _level->getVertexTag(v)._infSharp; }
|
||||
|
||||
/// \brief Return if the edge is semi-sharp
|
||||
bool IsEdgeSemiSharp(Index e) const { return _level->getEdgeTag(e)._semiSharp; }
|
||||
|
||||
/// \brief Return if the vertex is semi-sharp
|
||||
bool IsVertexSemiSharp(Index v) const { return _level->getVertexTag(v)._semiSharp; }
|
||||
|
||||
/// \brief Return if a given face has been tagged as a hole
|
||||
bool IsFaceHole(Index f) const { return _level->isFaceHole(f); }
|
||||
|
||||
/// \brief Return the subdivision rule assigned a given vertex specific to this level
|
||||
Sdc::Crease::Rule GetVertexRule(Index v) const { return _level->getVertexRule(v); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to inspect face-varying data:
|
||||
///
|
||||
/// Face-varying data is organized into topologically independent channels,
|
||||
/// each with an integer identifier. Access to face-varying data generally
|
||||
/// requires the specification of a channel, though with a single channel
|
||||
/// being a common situation the first/only channel will be assumed if
|
||||
/// unspecified.
|
||||
///
|
||||
/// A face-varying channel is composed of a set of values that may be shared
|
||||
/// by faces meeting at a common vertex. Just as there are sets of vertices
|
||||
/// that are associated with faces by index (ranging from 0 to
|
||||
/// num-vertices - 1), face-varying values are also referenced by index
|
||||
/// (ranging from 0 to num-values -1).
|
||||
///
|
||||
/// The face-varying values associated with a face are accessed similarly to
|
||||
/// the way in which vertices associated with the face are accessed -- an
|
||||
/// array of fixed size containing the indices for each corner is provided
|
||||
/// for inspection, iteration, etc.
|
||||
///
|
||||
/// When the face-varying topology around a vertex "matches", it has the
|
||||
/// same limit properties and so results in the same limit surface when
|
||||
/// collections of adjacent vertices match. Like other references to
|
||||
/// "topology", this includes consideration of sharpness. So it may be
|
||||
/// that face-varying values are assigned around a vertex on a boundary in
|
||||
/// a way that appears to match, but the face-varying interpolation option
|
||||
/// requires sharpening of that vertex in face-varying space -- the
|
||||
/// difference in the topology of the resulting limit surfaces leading to
|
||||
/// the query returning false for the match. The edge case is simpler in
|
||||
/// that it only considers continuity across the edge, not the entire
|
||||
/// neighborhood around each end vertex.
|
||||
|
||||
/// \brief Return the number of face-varying channels (should be same for all levels)
|
||||
int GetNumFVarChannels() const { return _level->getNumFVarChannels(); }
|
||||
|
||||
/// \brief Return the total number of face-varying values in a particular channel
|
||||
/// (the upper bound of a face-varying value index)
|
||||
int GetNumFVarValues(int channel = 0) const { return _level->getNumFVarValues(channel); }
|
||||
|
||||
/// \brief Access the face-varying values associated with a particular face
|
||||
ConstIndexArray GetFaceFVarValues(Index f, int channel = 0) const {
|
||||
return _level->getFaceFVarValues(f, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology around a vertex matches
|
||||
bool DoesVertexFVarTopologyMatch(Index v, int channel = 0) const {
|
||||
return _level->doesVertexFVarTopologyMatch(v, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology across the edge only matches
|
||||
bool DoesEdgeFVarTopologyMatch(Index e, int channel = 0) const {
|
||||
return _level->doesEdgeFVarTopologyMatch(e, channel);
|
||||
}
|
||||
|
||||
/// \brief Return if face-varying topology around a face matches
|
||||
bool DoesFaceFVarTopologyMatch(Index f, int channel = 0) const {
|
||||
return _level->doesFaceFVarTopologyMatch(f, channel);
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Methods to identify parent or child components in adjoining levels of refinement:
|
||||
|
||||
/// \brief Access the child faces (in the next level) of a given face
|
||||
ConstIndexArray GetFaceChildFaces(Index f) const { return _refToChild->getFaceChildFaces(f); }
|
||||
|
||||
/// \brief Access the child edges (in the next level) of a given face
|
||||
ConstIndexArray GetFaceChildEdges(Index f) const { return _refToChild->getFaceChildEdges(f); }
|
||||
|
||||
/// \brief Access the child edges (in the next level) of a given edge
|
||||
ConstIndexArray GetEdgeChildEdges(Index e) const { return _refToChild->getEdgeChildEdges(e); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given face
|
||||
Index GetFaceChildVertex( Index f) const { return _refToChild->getFaceChildVertex(f); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given edge
|
||||
Index GetEdgeChildVertex( Index e) const { return _refToChild->getEdgeChildVertex(e); }
|
||||
|
||||
/// \brief Return the child vertex (in the next level) of a given vertex
|
||||
Index GetVertexChildVertex(Index v) const { return _refToChild->getVertexChildVertex(v); }
|
||||
|
||||
/// \brief Return the parent face (in the previous level) of a given face
|
||||
Index GetFaceParentFace(Index f) const { return _refToParent->getChildFaceParentFace(f); }
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Debugging aides:
|
||||
|
||||
bool ValidateTopology() const { return _level->validateTopology(); }
|
||||
void PrintTopology(bool children = true) const { _level->print((children && _refToChild) ? _refToChild : 0); }
|
||||
//@}
|
||||
|
||||
|
||||
private:
|
||||
friend class TopologyRefiner;
|
||||
|
||||
Vtr::internal::Level const * _level;
|
||||
Vtr::internal::Refinement const * _refToParent;
|
||||
Vtr::internal::Refinement const * _refToChild;
|
||||
|
||||
public:
|
||||
// Not intended for public use, but required by std::vector, etc...
|
||||
TopologyLevel() { }
|
||||
~TopologyLevel() { }
|
||||
};
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_LEVEL_H */
|
||||
815
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefiner.cpp
vendored
Normal file
815
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefiner.cpp
vendored
Normal file
@@ -0,0 +1,815 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/error.h"
|
||||
#include "../vtr/fvarLevel.h"
|
||||
#include "../vtr/sparseSelector.h"
|
||||
#include "../vtr/quadRefinement.h"
|
||||
#include "../vtr/triRefinement.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Relatively trivial construction/destruction -- the base level (level[0]) needs
|
||||
// to be explicitly initialized after construction and refinement then applied
|
||||
//
|
||||
TopologyRefiner::TopologyRefiner(Sdc::SchemeType schemeType, Sdc::Options schemeOptions) :
|
||||
_subdivType(schemeType),
|
||||
_subdivOptions(schemeOptions),
|
||||
_isUniform(true),
|
||||
_hasHoles(false),
|
||||
_hasIrregFaces(false),
|
||||
_regFaceSize(Sdc::SchemeTypeTraits::GetRegularFaceSize(schemeType)),
|
||||
_maxLevel(0),
|
||||
_uniformOptions(0),
|
||||
_adaptiveOptions(0),
|
||||
_totalVertices(0),
|
||||
_totalEdges(0),
|
||||
_totalFaces(0),
|
||||
_totalFaceVertices(0),
|
||||
_maxValence(0),
|
||||
_baseLevelOwned(true) {
|
||||
|
||||
// Need to revisit allocation scheme here -- want to use smart-ptrs for these
|
||||
// but will probably have to settle for explicit new/delete...
|
||||
_levels.reserve(10);
|
||||
_levels.push_back(new Vtr::internal::Level);
|
||||
_farLevels.reserve(10);
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// The copy constructor is protected and used by the factory to create a new instance
|
||||
// from only the base level of the given instance -- it does not create a full copy.
|
||||
// So members reflecting any refinement are default-initialized while those dependent
|
||||
// on the base level are copied or explicitly initialized after its assignment.
|
||||
//
|
||||
TopologyRefiner::TopologyRefiner(TopologyRefiner const & source) :
|
||||
_subdivType(source._subdivType),
|
||||
_subdivOptions(source._subdivOptions),
|
||||
_isUniform(true),
|
||||
_hasHoles(source._hasHoles),
|
||||
_hasIrregFaces(source._hasIrregFaces),
|
||||
_regFaceSize(source._regFaceSize),
|
||||
_maxLevel(0),
|
||||
_uniformOptions(0),
|
||||
_adaptiveOptions(0),
|
||||
_baseLevelOwned(false) {
|
||||
|
||||
_levels.reserve(10);
|
||||
_levels.push_back(source._levels[0]);
|
||||
initializeInventory();
|
||||
|
||||
_farLevels.reserve(10);
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
|
||||
TopologyRefiner::~TopologyRefiner() {
|
||||
|
||||
for (int i=0; i<(int)_levels.size(); ++i) {
|
||||
if ((i > 0) || _baseLevelOwned) delete _levels[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<(int)_refinements.size(); ++i) {
|
||||
delete _refinements[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::Unrefine() {
|
||||
|
||||
if (_levels.size()) {
|
||||
for (int i=1; i<(int)_levels.size(); ++i) {
|
||||
delete _levels[i];
|
||||
}
|
||||
_levels.resize(1);
|
||||
initializeInventory();
|
||||
}
|
||||
for (int i=0; i<(int)_refinements.size(); ++i) {
|
||||
delete _refinements[i];
|
||||
}
|
||||
_refinements.clear();
|
||||
_maxLevel = 0;
|
||||
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Initializing and updating the component inventory:
|
||||
//
|
||||
void
|
||||
TopologyRefiner::initializeInventory() {
|
||||
|
||||
if (_levels.size()) {
|
||||
assert(_levels.size() == 1);
|
||||
|
||||
Vtr::internal::Level const & baseLevel = *_levels[0];
|
||||
|
||||
_totalVertices = baseLevel.getNumVertices();
|
||||
_totalEdges = baseLevel.getNumEdges();
|
||||
_totalFaces = baseLevel.getNumFaces();
|
||||
_totalFaceVertices = baseLevel.getNumFaceVerticesTotal();
|
||||
|
||||
_maxValence = baseLevel.getMaxValence();
|
||||
} else {
|
||||
_totalVertices = 0;
|
||||
_totalEdges = 0;
|
||||
_totalFaces = 0;
|
||||
_totalFaceVertices = 0;
|
||||
|
||||
_maxValence = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::updateInventory(Vtr::internal::Level const & newLevel) {
|
||||
|
||||
_totalVertices += newLevel.getNumVertices();
|
||||
_totalEdges += newLevel.getNumEdges();
|
||||
_totalFaces += newLevel.getNumFaces();
|
||||
_totalFaceVertices += newLevel.getNumFaceVerticesTotal();
|
||||
|
||||
_maxValence = std::max(_maxValence, newLevel.getMaxValence());
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::appendLevel(Vtr::internal::Level & newLevel) {
|
||||
|
||||
_levels.push_back(&newLevel);
|
||||
|
||||
updateInventory(newLevel);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::appendRefinement(Vtr::internal::Refinement & newRefinement) {
|
||||
|
||||
_refinements.push_back(&newRefinement);
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::assembleFarLevels() {
|
||||
|
||||
_farLevels.resize(_levels.size());
|
||||
|
||||
_farLevels[0]._refToParent = 0;
|
||||
_farLevels[0]._level = _levels[0];
|
||||
_farLevels[0]._refToChild = 0;
|
||||
|
||||
int nRefinements = (int)_refinements.size();
|
||||
if (nRefinements) {
|
||||
_farLevels[0]._refToChild = _refinements[0];
|
||||
|
||||
for (int i = 1; i < nRefinements; ++i) {
|
||||
_farLevels[i]._refToParent = _refinements[i - 1];
|
||||
_farLevels[i]._level = _levels[i];
|
||||
_farLevels[i]._refToChild = _refinements[i];;
|
||||
}
|
||||
|
||||
_farLevels[nRefinements]._refToParent = _refinements[nRefinements - 1];
|
||||
_farLevels[nRefinements]._level = _levels[nRefinements];
|
||||
_farLevels[nRefinements]._refToChild = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Accessors to the topology information:
|
||||
//
|
||||
int
|
||||
TopologyRefiner::GetNumFVarValuesTotal(int channel) const {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < (int)_levels.size(); ++i) {
|
||||
sum += _levels[i]->getNumFVarValues(channel);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Main refinement method -- allocating and initializing levels and refinements:
|
||||
//
|
||||
void
|
||||
TopologyRefiner::RefineUniform(UniformOptions options) {
|
||||
|
||||
if (_levels[0]->getNumVertices() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineUniform() -- base level is uninitialized.");
|
||||
return;
|
||||
}
|
||||
if (_refinements.size()) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineUniform() -- previous refinements already applied.");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Allocate the stack of levels and the refinements between them:
|
||||
//
|
||||
_uniformOptions = options;
|
||||
|
||||
_isUniform = true;
|
||||
_maxLevel = options.refinementLevel;
|
||||
|
||||
Sdc::Split splitType = Sdc::SchemeTypeTraits::GetTopologicalSplitType(_subdivType);
|
||||
|
||||
//
|
||||
// Initialize refinement options for Vtr -- adjusting full-topology for the last level:
|
||||
//
|
||||
Vtr::internal::Refinement::Options refineOptions;
|
||||
refineOptions._sparse = false;
|
||||
refineOptions._faceVertsFirst = options.orderVerticesFromFacesFirst;
|
||||
|
||||
for (int i = 1; i <= (int)options.refinementLevel; ++i) {
|
||||
refineOptions._minimalTopology =
|
||||
options.fullTopologyInLastLevel ? false : (i == (int)options.refinementLevel);
|
||||
|
||||
Vtr::internal::Level& parentLevel = getLevel(i-1);
|
||||
Vtr::internal::Level& childLevel = *(new Vtr::internal::Level);
|
||||
|
||||
Vtr::internal::Refinement* refinement = 0;
|
||||
if (splitType == Sdc::SPLIT_TO_QUADS) {
|
||||
refinement = new Vtr::internal::QuadRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
} else {
|
||||
refinement = new Vtr::internal::TriRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
}
|
||||
refinement->refine(refineOptions);
|
||||
|
||||
appendLevel(childLevel);
|
||||
appendRefinement(*refinement);
|
||||
}
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// Internal utility class and function supporting feature adaptive selection of faces...
|
||||
//
|
||||
namespace internal {
|
||||
//
|
||||
// FeatureMask is a simple set of bits identifying features to be selected during a level of
|
||||
// adaptive refinement. Adaptive refinement options passed the Refiner are interpreted as a
|
||||
// specific set of features defined here. Given options to reduce faces generated at deeper
|
||||
// levels, a method to "reduce" the set of features is also provided here.
|
||||
//
|
||||
// This class was specifically not nested in TopologyRefiner to allow simple non-class methods
|
||||
// to make use of it in the core selection methods. Those selection methods were similarly
|
||||
// made non-class methods to ensure they conform to the feature set defined by the FeatureMask
|
||||
// and not some internal class state.
|
||||
//
|
||||
class FeatureMask {
|
||||
public:
|
||||
typedef TopologyRefiner::AdaptiveOptions Options;
|
||||
typedef unsigned int int_type;
|
||||
|
||||
void Clear() { *((int_type*)this) = 0; }
|
||||
bool IsEmpty() const { return *((int_type*)this) == 0; }
|
||||
|
||||
FeatureMask() { Clear(); }
|
||||
FeatureMask(Options const & options, int regFaceSize) {
|
||||
Clear();
|
||||
InitializeFeatures(options, regFaceSize);
|
||||
}
|
||||
|
||||
// These are the two primary methods intended for use -- intialization via a set of Options
|
||||
// and reduction of the subsequent feature set (which presumes prior initialization with the
|
||||
// same set as give)
|
||||
//
|
||||
void InitializeFeatures(Options const & options, int regFaceSize);
|
||||
void ReduceFeatures( Options const & options);
|
||||
|
||||
public:
|
||||
int_type selectXOrdinaryInterior : 1;
|
||||
int_type selectXOrdinaryBoundary : 1;
|
||||
|
||||
int_type selectSemiSharpSingle : 1;
|
||||
int_type selectSemiSharpNonSingle : 1;
|
||||
|
||||
int_type selectInfSharpRegularCrease : 1;
|
||||
int_type selectInfSharpRegularCorner : 1;
|
||||
int_type selectInfSharpIrregularDart : 1;
|
||||
int_type selectInfSharpIrregularCrease : 1;
|
||||
int_type selectInfSharpIrregularCorner : 1;
|
||||
|
||||
int_type selectUnisolatedInteriorEdge : 1;
|
||||
|
||||
int_type selectNonManifold : 1;
|
||||
int_type selectFVarFeatures : 1;
|
||||
};
|
||||
|
||||
void
|
||||
FeatureMask::InitializeFeatures(Options const & options, int regFaceSize) {
|
||||
|
||||
//
|
||||
// Support for the "single-crease patch" case is limited to the subdivision scheme
|
||||
// (currently only Catmull-Clark). It has historically been applied to both semi-
|
||||
// sharp and inf-sharp creases -- the semi-sharp application is still relevant,
|
||||
// but the inf-sharp has been superceded.
|
||||
//
|
||||
// The inf-sharp single-crease case now corresponds to an inf-sharp regular crease
|
||||
// in the interior -- and since such regular creases on the boundary are never
|
||||
// considered for selection (just as interior smoot regular faces are not), this
|
||||
// feature is only relevant for the interior case. So aside from it being used
|
||||
// when regular inf-sharp features are all selected, it can also be used for the
|
||||
// single-crease case.
|
||||
//
|
||||
bool useSingleCreasePatch = options.useSingleCreasePatch && (regFaceSize == 4);
|
||||
|
||||
// Extra-ordinary features (independent of the inf-sharp options):
|
||||
selectXOrdinaryInterior = true;
|
||||
selectXOrdinaryBoundary = true;
|
||||
|
||||
// Semi-sharp features -- the regular single crease case and all others:
|
||||
selectSemiSharpSingle = !useSingleCreasePatch;
|
||||
selectSemiSharpNonSingle = true;
|
||||
|
||||
// Inf-sharp features -- boundary extra-ordinary vertices are irreg creases:
|
||||
selectInfSharpRegularCrease = !(options.useInfSharpPatch || useSingleCreasePatch);
|
||||
selectInfSharpRegularCorner = !options.useInfSharpPatch;
|
||||
selectInfSharpIrregularDart = true;
|
||||
selectInfSharpIrregularCrease = true;
|
||||
selectInfSharpIrregularCorner = true;
|
||||
|
||||
selectUnisolatedInteriorEdge = useSingleCreasePatch && !options.useInfSharpPatch;
|
||||
|
||||
selectNonManifold = true;
|
||||
selectFVarFeatures = options.considerFVarChannels;
|
||||
}
|
||||
|
||||
void
|
||||
FeatureMask::ReduceFeatures(Options const & options) {
|
||||
|
||||
// Disable typical xordinary vertices:
|
||||
selectXOrdinaryInterior = false;
|
||||
selectXOrdinaryBoundary = false;
|
||||
|
||||
// If minimizing inf-sharp patches, disable all but sharp/corner irregularities
|
||||
if (options.useInfSharpPatch) {
|
||||
selectInfSharpRegularCrease = false;
|
||||
selectInfSharpRegularCorner = false;
|
||||
selectInfSharpIrregularDart = false;
|
||||
selectInfSharpIrregularCrease = false;
|
||||
}
|
||||
}
|
||||
} // end namespace internal
|
||||
|
||||
void
|
||||
TopologyRefiner::RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray baseFacesToRefine) {
|
||||
|
||||
if (_levels[0]->getNumVertices() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineAdaptive() -- base level is uninitialized.");
|
||||
return;
|
||||
}
|
||||
if (_refinements.size()) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefiner::RefineAdaptive() -- previous refinements already applied.");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize member and local variables from the adaptive options:
|
||||
//
|
||||
_isUniform = false;
|
||||
_adaptiveOptions = options;
|
||||
|
||||
//
|
||||
// Initialize the feature-selection options based on given options -- with two sets
|
||||
// of levels isolating different sets of features, initialize the two feature sets
|
||||
// up front and use the appropriate one for each level:
|
||||
//
|
||||
int nonLinearScheme = Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(_subdivType);
|
||||
|
||||
int shallowLevel = std::min<int>(options.secondaryLevel, options.isolationLevel);
|
||||
int deeperLevel = options.isolationLevel;
|
||||
|
||||
int potentialMaxLevel = nonLinearScheme ? deeperLevel : _hasIrregFaces;
|
||||
|
||||
internal::FeatureMask moreFeaturesMask(options, _regFaceSize);
|
||||
internal::FeatureMask lessFeaturesMask = moreFeaturesMask;
|
||||
|
||||
if (shallowLevel < potentialMaxLevel) {
|
||||
lessFeaturesMask.ReduceFeatures(options);
|
||||
}
|
||||
|
||||
//
|
||||
// If face-varying channels are considered, make sure non-linear channels are present
|
||||
// and turn off consideration if none present:
|
||||
//
|
||||
if (moreFeaturesMask.selectFVarFeatures && nonLinearScheme) {
|
||||
bool nonLinearChannelsPresent = false;
|
||||
for (int channel = 0; channel < _levels[0]->getNumFVarChannels(); ++channel) {
|
||||
nonLinearChannelsPresent |= !_levels[0]->getFVarLevel(channel).isLinear();
|
||||
}
|
||||
if (!nonLinearChannelsPresent) {
|
||||
moreFeaturesMask.selectFVarFeatures = false;
|
||||
lessFeaturesMask.selectFVarFeatures = false;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize refinement options for Vtr -- full topology is always generated in
|
||||
// the last level as expected usage is for patch retrieval:
|
||||
//
|
||||
Vtr::internal::Refinement::Options refineOptions;
|
||||
|
||||
refineOptions._sparse = true;
|
||||
refineOptions._minimalTopology = false;
|
||||
refineOptions._faceVertsFirst = options.orderVerticesFromFacesFirst;
|
||||
|
||||
Sdc::Split splitType = Sdc::SchemeTypeTraits::GetTopologicalSplitType(_subdivType);
|
||||
|
||||
for (int i = 1; i <= potentialMaxLevel; ++i) {
|
||||
|
||||
Vtr::internal::Level& parentLevel = getLevel(i-1);
|
||||
Vtr::internal::Level& childLevel = *(new Vtr::internal::Level);
|
||||
|
||||
Vtr::internal::Refinement* refinement = 0;
|
||||
if (splitType == Sdc::SPLIT_TO_QUADS) {
|
||||
refinement = new Vtr::internal::QuadRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
} else {
|
||||
refinement = new Vtr::internal::TriRefinement(parentLevel, childLevel, _subdivOptions);
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize a Selector to mark a sparse set of components for refinement -- choose
|
||||
// the feature selection mask appropriate to the level:
|
||||
//
|
||||
Vtr::internal::SparseSelector selector(*refinement);
|
||||
|
||||
internal::FeatureMask const & levelFeatures = (i <= shallowLevel) ? moreFeaturesMask
|
||||
: lessFeaturesMask;
|
||||
|
||||
if (i > 1) {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, ConstIndexArray());
|
||||
} else if (nonLinearScheme) {
|
||||
selectFeatureAdaptiveComponents(selector, levelFeatures, baseFacesToRefine);
|
||||
} else {
|
||||
selectLinearIrregularFaces(selector, baseFacesToRefine);
|
||||
}
|
||||
|
||||
if (selector.isSelectionEmpty()) {
|
||||
delete refinement;
|
||||
delete &childLevel;
|
||||
break;
|
||||
} else {
|
||||
refinement->refine(refineOptions);
|
||||
|
||||
appendLevel(childLevel);
|
||||
appendRefinement(*refinement);
|
||||
}
|
||||
}
|
||||
_maxLevel = (unsigned int) _refinements.size();
|
||||
|
||||
assembleFarLevels();
|
||||
}
|
||||
|
||||
//
|
||||
// Local utility functions for selecting features in faces for adaptive refinement:
|
||||
//
|
||||
namespace {
|
||||
//
|
||||
// First are a couple of low-level utility methods to perform the same analysis
|
||||
// at a corner or the entire face for specific detection of inf-sharp or boundary
|
||||
// features. These are shared between the analysis of the main face and those in
|
||||
// face-varying channels (which only differ from the main face in the presence of
|
||||
// face-varying boundaries).
|
||||
//
|
||||
// The first can be applied equally to an individual corner or to the entire face
|
||||
// (using its composite tag). The second applies to the entire face, making use
|
||||
// of the first, and is the main entry point for dealng with inf-sharp features.
|
||||
//
|
||||
// Note we can use the composite tag here even though it arises from all corners
|
||||
// of the face and so does not represent a specific corner. When at least one
|
||||
// smooth interior vertex exists, it limits the combinations that can exist on the
|
||||
// remaining corners (though quads and tris cannot be treated equally here).
|
||||
//
|
||||
// If any inf-sharp features are to be selected, identify them first as irregular
|
||||
// or not, then qualify them more specifically. (Remember that a regular vertex
|
||||
// may have its neighboring faces partitioned into irregular regions in the
|
||||
// presence of inf-sharp edges. Similarly an irregular vertex may have its
|
||||
// neighborhood partitioned into regular regions.)
|
||||
//
|
||||
inline bool
|
||||
doesInfSharpVTagHaveFeatures(Vtr::internal::Level::VTag compVTag,
|
||||
internal::FeatureMask const & featureMask) {
|
||||
|
||||
// Note that even though the given VTag may represent an individual corner, we
|
||||
// use more general bitwise tests here (particularly the Rule) so that we can
|
||||
// pass in a composite tag for the entire face and have the same tests applied:
|
||||
//
|
||||
if (compVTag._infIrregular) {
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return featureMask.selectInfSharpIrregularCorner;
|
||||
} else if (compVTag._rule & Sdc::Crease::RULE_CREASE) {
|
||||
return compVTag._boundary ? featureMask.selectXOrdinaryBoundary :
|
||||
featureMask.selectInfSharpIrregularCrease;
|
||||
} else if (compVTag._rule & Sdc::Crease::RULE_DART) {
|
||||
return featureMask.selectInfSharpIrregularDart;
|
||||
}
|
||||
} else if (compVTag._boundary) {
|
||||
// Remember that regular boundary features should never be selected, except
|
||||
// for a boundary crease sharpened (and so a Corner) by an interior edge:
|
||||
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return compVTag._corner ? false : featureMask.selectInfSharpRegularCorner;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (compVTag._rule & Sdc::Crease::RULE_CORNER) {
|
||||
return featureMask.selectInfSharpRegularCorner;
|
||||
} else {
|
||||
return featureMask.selectInfSharpRegularCrease;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
doesInfSharpFaceHaveFeatures(Vtr::internal::Level::VTag compVTag,
|
||||
Vtr::internal::Level::VTag vTags[], int numVerts,
|
||||
internal::FeatureMask const & featureMask) {
|
||||
//
|
||||
// For quads, if at least one smooth corner of a regular face, features
|
||||
// are isolated enough to make use of the composite tag alone (unless
|
||||
// boundary isolation is enabled, in which case trivially return).
|
||||
//
|
||||
// For tris, the presence of boundaries creates more ambiguity, so we
|
||||
// need to exclude that case and inspect corner features individually.
|
||||
//
|
||||
bool isolateQuadBoundaries = false;
|
||||
|
||||
bool atLeastOneSmoothCorner = (compVTag._rule & Sdc::Crease::RULE_SMOOTH);
|
||||
if (numVerts == 4) {
|
||||
if (atLeastOneSmoothCorner) {
|
||||
return doesInfSharpVTagHaveFeatures(compVTag, featureMask);
|
||||
} else if (isolateQuadBoundaries) {
|
||||
return true;
|
||||
} else if (featureMask.selectUnisolatedInteriorEdge) {
|
||||
// Needed for single-crease approximation to inf-sharp interior edge:
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (vTags[i]._infSharpEdges && !vTags[i]._boundary) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (atLeastOneSmoothCorner && !compVTag._boundary) {
|
||||
return doesInfSharpVTagHaveFeatures(compVTag, featureMask);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numVerts; ++i) {
|
||||
if (!(vTags[i]._rule & Sdc::Crease::RULE_SMOOTH)) {
|
||||
if (doesInfSharpVTagHaveFeatures(vTags[i], featureMask)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// This is the core method/function for analyzing a face and deciding whether or not
|
||||
// to included it during feature-adaptive refinement.
|
||||
//
|
||||
// Topological analysis of the face exploits tags that are applied to corner vertices
|
||||
// and carried through the refinement hierarchy. The tags were designed with this
|
||||
// in mind and also to be combined via bitwise-OR to make collective decisions about
|
||||
// the neighborhood of the entire face.
|
||||
//
|
||||
// After a few trivial acceptances/rejections, feature detection is divided up into
|
||||
// semi-sharp and inf-sharp cases -- note that both may be present, but semi-sharp
|
||||
// features have an implicit precedence until they decay and so are handled first.
|
||||
// They are also fairly trivial to deal with (most often requiring selection) while
|
||||
// the presence of boundaries and additional options complicates the inf-sharp case.
|
||||
// Since the inf-sharp logic needs to be applied in face-varying cases, it exists in
|
||||
// a separate method.
|
||||
//
|
||||
// This was originally written specific to the quad-centric Catmark scheme and was
|
||||
// since generalized to support Loop given the enhanced tagging of components based
|
||||
// on the scheme. Any enhancements here should be aware of the intended generality.
|
||||
// Ultimately it may not be worth trying to keep this general and we will be better
|
||||
// off specializing it for each scheme. The fact that this method is intimately tied
|
||||
// to patch generation also begs for it to become part of a class that encompasses
|
||||
// both the feature adaptive tagging and the identification of the intended patches
|
||||
// that result from it.
|
||||
//
|
||||
bool
|
||||
doesFaceHaveFeatures(Vtr::internal::Level const& level, Index face,
|
||||
internal::FeatureMask const & featureMask, int regFaceSize) {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
|
||||
ConstIndexArray fVerts = level.getFaceVertices(face);
|
||||
|
||||
// Irregular faces (base level) are unconditionally included:
|
||||
if (fVerts.size() != regFaceSize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gather and combine the VTags:
|
||||
Level::VTag vTags[4];
|
||||
level.getFaceVTags(face, vTags);
|
||||
|
||||
Level::VTag compFaceVTag = Level::VTag::BitwiseOr(vTags, fVerts.size());
|
||||
|
||||
// Faces incident irregular faces (base level) are unconditionally included:
|
||||
if (compFaceVTag._incidIrregFace) {
|
||||
return true;
|
||||
}
|
||||
// Incomplete faces (incomplete neighborhood) are unconditionally excluded:
|
||||
if (compFaceVTag._incomplete) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select non-manifold features if specified, otherwise treat as inf-sharp:
|
||||
if (compFaceVTag._nonManifold && featureMask.selectNonManifold) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Select (smooth) xord vertices if specified, boundaries handled with inf-sharp:
|
||||
if (compFaceVTag._xordinary && featureMask.selectXOrdinaryInterior) {
|
||||
if (compFaceVTag._rule == Sdc::Crease::RULE_SMOOTH) {
|
||||
return true;
|
||||
} else if (level.getDepth() < 2) {
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
if (vTags[i]._xordinary && (vTags[i]._rule == Sdc::Crease::RULE_SMOOTH)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If all smooth corners, no remaining features to select (x-ordinary dealt with):
|
||||
if (compFaceVTag._rule == Sdc::Crease::RULE_SMOOTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Semi-sharp features -- select all immediately or test the single-crease case:
|
||||
if (compFaceVTag._semiSharp || compFaceVTag._semiSharpEdges) {
|
||||
if (featureMask.selectSemiSharpSingle && featureMask.selectSemiSharpNonSingle) {
|
||||
return true;
|
||||
} else if (level.isSingleCreasePatch(face)) {
|
||||
return featureMask.selectSemiSharpSingle;
|
||||
} else {
|
||||
return featureMask.selectSemiSharpNonSingle;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf-sharp features (including boundaries) -- delegate to shared method:
|
||||
if (compFaceVTag._infSharp || compFaceVTag._infSharpEdges) {
|
||||
return doesInfSharpFaceHaveFeatures(compFaceVTag, vTags, fVerts.size(), featureMask);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Analyzing the face-varying topology for selection is considerably simpler that
|
||||
// for the face and its vertices -- in part due to the fact that these faces lie on
|
||||
// face-varying boundaries, and also due to assumptions about prior inspection:
|
||||
//
|
||||
// - it is assumed the face topologgy does not match, so the face must lie on
|
||||
// a FVar boundary, i.e. inf-sharp
|
||||
//
|
||||
// - it is assumed the face vertices were already inspected, so cases such as
|
||||
// semi-sharp or smooth interior x-ordinary features have already triggered
|
||||
// selection
|
||||
//
|
||||
// That leaves the inspection of inf-sharp features, for the tags from the face
|
||||
// varying channel -- code that is shared with the main face.
|
||||
//
|
||||
bool
|
||||
doesFaceHaveDistinctFaceVaryingFeatures(Vtr::internal::Level const& level, Index face,
|
||||
internal::FeatureMask const & featureMask, int fvarChannel) {
|
||||
|
||||
using Vtr::internal::Level;
|
||||
|
||||
ConstIndexArray fVerts = level.getFaceVertices(face);
|
||||
|
||||
assert(!level.doesFaceFVarTopologyMatch(face, fvarChannel));
|
||||
|
||||
// We can't use the composite VTag for the face here as it only includes the FVar
|
||||
// values specific to this face. We need to account for all FVar values around
|
||||
// each corner of the face -- including those in potentially completely disjoint
|
||||
// sets -- to ensure that adjacent faces remain compatibly refined (i.e. differ
|
||||
// by only one level), so we use the composite tags for the corner vertices:
|
||||
//
|
||||
Level::VTag vTags[4];
|
||||
|
||||
for (int i = 0; i < fVerts.size(); ++i) {
|
||||
vTags[i] = level.getVertexCompositeFVarVTag(fVerts[i], fvarChannel);
|
||||
}
|
||||
Level::VTag compVTag = Level::VTag::BitwiseOr(vTags, fVerts.size());
|
||||
|
||||
// Incomplete faces (incomplete neighborhood) are unconditionally excluded:
|
||||
if (compVTag._incomplete) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select non-manifold features if specified, otherwise treat as inf-sharp:
|
||||
if (compVTag._nonManifold && featureMask.selectNonManifold) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Any remaining locally extra-ordinary face-varying boundaries warrant selection:
|
||||
if (compVTag._xordinary && featureMask.selectXOrdinaryInterior) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given faces with differing FVar topology are on boundaries, defer to inf-sharp:
|
||||
return doesInfSharpFaceHaveFeatures(compVTag, vTags, fVerts.size(), featureMask);
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
//
|
||||
// Method for selecting components for sparse refinement based on the feature-adaptive needs
|
||||
// of patch generation.
|
||||
//
|
||||
// It assumes we have a freshly initialized SparseSelector (i.e. nothing already selected)
|
||||
// and will select all relevant topological features for inclusion in the subsequent sparse
|
||||
// refinement.
|
||||
//
|
||||
void
|
||||
TopologyRefiner::selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & featureMask,
|
||||
ConstIndexArray facesToRefine) {
|
||||
|
||||
//
|
||||
// Inspect each face and the properties tagged at all of its corners:
|
||||
//
|
||||
Vtr::internal::Level const& level = selector.getRefinement().parent();
|
||||
|
||||
int numFacesToRefine = facesToRefine.size() ? facesToRefine.size() : level.getNumFaces();
|
||||
|
||||
int numFVarChannels = featureMask.selectFVarFeatures ? level.getNumFVarChannels() : 0;
|
||||
|
||||
for (int fIndex = 0; fIndex < numFacesToRefine; ++fIndex) {
|
||||
|
||||
Vtr::Index face = facesToRefine.size() ? facesToRefine[fIndex] : (Index) fIndex;
|
||||
|
||||
if (HasHoles() && level.isFaceHole(face)) continue;
|
||||
|
||||
//
|
||||
// Test if the face has any of the specified features present. If not, and FVar
|
||||
// channels are to be considered, look for features in the FVar channels:
|
||||
//
|
||||
bool selectFace = doesFaceHaveFeatures(level, face, featureMask, _regFaceSize);
|
||||
|
||||
if (!selectFace && featureMask.selectFVarFeatures) {
|
||||
for (int channel = 0; !selectFace && (channel < numFVarChannels); ++channel) {
|
||||
|
||||
// Only test the face for this channel if the topology does not match:
|
||||
if (!level.doesFaceFVarTopologyMatch(face, channel)) {
|
||||
selectFace = doesFaceHaveDistinctFaceVaryingFeatures(
|
||||
level, face, featureMask, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectFace) {
|
||||
selector.selectFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TopologyRefiner::selectLinearIrregularFaces(Vtr::internal::SparseSelector& selector,
|
||||
ConstIndexArray facesToRefine) {
|
||||
|
||||
//
|
||||
// Inspect each face and select only irregular faces:
|
||||
//
|
||||
Vtr::internal::Level const& level = selector.getRefinement().parent();
|
||||
|
||||
int numFacesToRefine = facesToRefine.size() ? facesToRefine.size() : level.getNumFaces();
|
||||
|
||||
for (int fIndex = 0; fIndex < numFacesToRefine; ++fIndex) {
|
||||
|
||||
Vtr::Index face = facesToRefine.size() ? facesToRefine[fIndex] : (Index) fIndex;
|
||||
|
||||
if (HasHoles() && level.isFaceHole(face)) continue;
|
||||
|
||||
if (level.getFaceVertices(face).size() != _regFaceSize) {
|
||||
selector.selectFace(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
292
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefiner.h
vendored
Normal file
292
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefiner.h
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/options.h"
|
||||
#include "../far/types.h"
|
||||
#include "../far/topologyLevel.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Vtr { namespace internal { class SparseSelector; } }
|
||||
namespace Far { namespace internal { class FeatureMask; } }
|
||||
|
||||
namespace Far {
|
||||
|
||||
template <typename REAL> class PrimvarRefinerReal;
|
||||
template <class MESH> class TopologyRefinerFactory;
|
||||
|
||||
///
|
||||
/// \brief Stores topology data for a specified set of refinement options.
|
||||
///
|
||||
class TopologyRefiner {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Constructor
|
||||
TopologyRefiner(Sdc::SchemeType type, Sdc::Options options = Sdc::Options());
|
||||
|
||||
/// \brief Destructor
|
||||
~TopologyRefiner();
|
||||
|
||||
/// \brief Returns the subdivision scheme
|
||||
Sdc::SchemeType GetSchemeType() const { return _subdivType; }
|
||||
|
||||
/// \brief Returns the subdivision options
|
||||
Sdc::Options GetSchemeOptions() const { return _subdivOptions; }
|
||||
|
||||
/// \brief Returns true if uniform refinement has been applied
|
||||
bool IsUniform() const { return _isUniform; }
|
||||
|
||||
/// \brief Returns the number of refinement levels
|
||||
int GetNumLevels() const { return (int)_farLevels.size(); }
|
||||
|
||||
/// \brief Returns the highest level of refinement
|
||||
int GetMaxLevel() const { return _maxLevel; }
|
||||
|
||||
/// \brief Returns the maximum vertex valence in all levels
|
||||
int GetMaxValence() const { return _maxValence; }
|
||||
|
||||
/// \brief Returns true if faces have been tagged as holes
|
||||
bool HasHoles() const { return _hasHoles; }
|
||||
|
||||
/// \brief Returns the total number of vertices in all levels
|
||||
int GetNumVerticesTotal() const { return _totalVertices; }
|
||||
|
||||
/// \brief Returns the total number of edges in all levels
|
||||
int GetNumEdgesTotal() const { return _totalEdges; }
|
||||
|
||||
/// \brief Returns the total number of edges in all levels
|
||||
int GetNumFacesTotal() const { return _totalFaces; }
|
||||
|
||||
/// \brief Returns the total number of face vertices in all levels
|
||||
int GetNumFaceVerticesTotal() const { return _totalFaceVertices; }
|
||||
|
||||
/// \brief Returns a handle to access data specific to a particular level
|
||||
TopologyLevel const & GetLevel(int level) const { return _farLevels[level]; }
|
||||
|
||||
//@{
|
||||
/// @name High-level refinement and related methods
|
||||
///
|
||||
|
||||
//
|
||||
// Uniform refinement
|
||||
//
|
||||
|
||||
/// \brief Uniform refinement options
|
||||
///
|
||||
/// Options for uniform refinement, including the number of levels, vertex
|
||||
/// ordering and generation of topology information.
|
||||
///
|
||||
/// Note the impact of the option to generate fullTopologyInLastLevel. Given
|
||||
/// subsequent levels of uniform refinement typically reguire 4x the data
|
||||
/// of the previous level, only the minimum amount of data is generated in the
|
||||
/// last level by default, i.e. a vertex and face-vertex list. If requiring
|
||||
/// topology traversal of the last level, e.g. inspecting edges or incident
|
||||
/// faces of vertices, the option to generate full topology in the last
|
||||
/// level should be enabled.
|
||||
///
|
||||
struct UniformOptions {
|
||||
|
||||
UniformOptions(int level) :
|
||||
refinementLevel(level & 0xf),
|
||||
orderVerticesFromFacesFirst(false),
|
||||
fullTopologyInLastLevel(false) { }
|
||||
|
||||
/// \brief Set uniform refinement level
|
||||
void SetRefinementLevel(int level) { refinementLevel = level & 0xf; }
|
||||
|
||||
unsigned int refinementLevel:4, ///< Number of refinement iterations
|
||||
orderVerticesFromFacesFirst:1, ///< Order child vertices from faces first
|
||||
///< instead of child vertices of vertices
|
||||
fullTopologyInLastLevel:1; ///< Skip topological relationships in the last
|
||||
///< level of refinement that are not needed for
|
||||
///< interpolation (keep false if using limit).
|
||||
};
|
||||
|
||||
/// \brief Refine the topology uniformly
|
||||
///
|
||||
/// This method applies uniform refinement to the level specified in the
|
||||
/// given UniformOptions.
|
||||
///
|
||||
/// Note the impact of the UniformOption to generate fullTopologyInLastLevel
|
||||
/// and be sure it is assigned to satisfy the needs of the resulting refinement.
|
||||
///
|
||||
/// @param options Options controlling uniform refinement
|
||||
///
|
||||
void RefineUniform(UniformOptions options);
|
||||
|
||||
/// \brief Returns the options specified on refinement
|
||||
UniformOptions GetUniformOptions() const { return _uniformOptions; }
|
||||
|
||||
//
|
||||
// Adaptive refinement
|
||||
//
|
||||
|
||||
/// \brief Adaptive refinement options
|
||||
struct AdaptiveOptions {
|
||||
|
||||
AdaptiveOptions(int level) :
|
||||
isolationLevel(level & 0xf),
|
||||
secondaryLevel(0xf),
|
||||
useSingleCreasePatch(false),
|
||||
useInfSharpPatch(false),
|
||||
considerFVarChannels(false),
|
||||
orderVerticesFromFacesFirst(false) { }
|
||||
|
||||
/// \brief Set isolation level
|
||||
void SetIsolationLevel(int level) { isolationLevel = level & 0xf; }
|
||||
|
||||
/// \brief Set secondary isolation level
|
||||
void SetSecondaryLevel(int level) { secondaryLevel = level & 0xf; }
|
||||
|
||||
unsigned int isolationLevel:4; ///< Number of iterations applied to isolate
|
||||
///< extraordinary vertices and creases
|
||||
unsigned int secondaryLevel:4; ///< Shallower level to stop isolation of
|
||||
///< smooth irregular features
|
||||
unsigned int useSingleCreasePatch:1; ///< Use 'single-crease' patch and stop
|
||||
///< isolation where applicable
|
||||
unsigned int useInfSharpPatch:1; ///< Use infinitely sharp patches and stop
|
||||
///< isolation where applicable
|
||||
unsigned int considerFVarChannels:1; ///< Inspect face-varying channels and
|
||||
///< isolate when irregular features present
|
||||
unsigned int orderVerticesFromFacesFirst:1; ///< Order child vertices from faces first
|
||||
///< instead of child vertices of vertices
|
||||
};
|
||||
|
||||
/// \brief Feature Adaptive topology refinement
|
||||
///
|
||||
/// @param options Options controlling adaptive refinement
|
||||
///
|
||||
/// @param selectedFaces Limit adaptive refinement to the specified faces
|
||||
///
|
||||
void RefineAdaptive(AdaptiveOptions options,
|
||||
ConstIndexArray selectedFaces = ConstIndexArray());
|
||||
|
||||
/// \brief Returns the options specified on refinement
|
||||
AdaptiveOptions GetAdaptiveOptions() const { return _adaptiveOptions; }
|
||||
|
||||
/// \brief Unrefine the topology, keeping only the base level.
|
||||
void Unrefine();
|
||||
|
||||
|
||||
//@{
|
||||
/// @name Number and properties of face-varying channels:
|
||||
///
|
||||
|
||||
/// \brief Returns the number of face-varying channels in the tables
|
||||
int GetNumFVarChannels() const;
|
||||
|
||||
/// \brief Returns the face-varying interpolation rule set for a given channel
|
||||
Sdc::Options::FVarLinearInterpolation GetFVarLinearInterpolation(int channel = 0) const;
|
||||
|
||||
/// \brief Returns the total number of face-varying values in all levels
|
||||
int GetNumFVarValuesTotal(int channel = 0) const;
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Lower level protected methods intended strictly for internal use:
|
||||
//
|
||||
template <class MESH>
|
||||
friend class TopologyRefinerFactory;
|
||||
friend class TopologyRefinerFactoryBase;
|
||||
friend class PatchTableBuilder;
|
||||
friend class PatchBuilder;
|
||||
friend class PtexIndices;
|
||||
template <typename REAL>
|
||||
friend class PrimvarRefinerReal;
|
||||
|
||||
// Copy constructor exposed via the factory class:
|
||||
TopologyRefiner(TopologyRefiner const & source);
|
||||
|
||||
public:
|
||||
// Levels and Refinements available internally (avoids need for more friends)
|
||||
Vtr::internal::Level & getLevel(int l) { return *_levels[l]; }
|
||||
Vtr::internal::Level const & getLevel(int l) const { return *_levels[l]; }
|
||||
|
||||
Vtr::internal::Refinement & getRefinement(int l) { return *_refinements[l]; }
|
||||
Vtr::internal::Refinement const & getRefinement(int l) const { return *_refinements[l]; }
|
||||
|
||||
private:
|
||||
// Not default constructible or copyable:
|
||||
TopologyRefiner() : _uniformOptions(0), _adaptiveOptions(0) { }
|
||||
TopologyRefiner & operator=(TopologyRefiner const &) { return *this; }
|
||||
|
||||
void selectFeatureAdaptiveComponents(Vtr::internal::SparseSelector& selector,
|
||||
internal::FeatureMask const & mask,
|
||||
ConstIndexArray selectedFaces);
|
||||
void selectLinearIrregularFaces(Vtr::internal::SparseSelector& selector,
|
||||
ConstIndexArray selectedFaces);
|
||||
|
||||
void initializeInventory();
|
||||
void updateInventory(Vtr::internal::Level const & newLevel);
|
||||
|
||||
void appendLevel(Vtr::internal::Level & newLevel);
|
||||
void appendRefinement(Vtr::internal::Refinement & newRefinement);
|
||||
void assembleFarLevels();
|
||||
|
||||
private:
|
||||
|
||||
Sdc::SchemeType _subdivType;
|
||||
Sdc::Options _subdivOptions;
|
||||
|
||||
unsigned int _isUniform : 1;
|
||||
unsigned int _hasHoles : 1;
|
||||
unsigned int _hasIrregFaces : 1;
|
||||
unsigned int _regFaceSize : 3;
|
||||
unsigned int _maxLevel : 4;
|
||||
|
||||
// Options assigned on refinement:
|
||||
UniformOptions _uniformOptions;
|
||||
AdaptiveOptions _adaptiveOptions;
|
||||
|
||||
// Cumulative properties of all levels:
|
||||
int _totalVertices;
|
||||
int _totalEdges;
|
||||
int _totalFaces;
|
||||
int _totalFaceVertices;
|
||||
int _maxValence;
|
||||
|
||||
// Note the base level may be shared with another instance
|
||||
bool _baseLevelOwned;
|
||||
|
||||
std::vector<Vtr::internal::Level *> _levels;
|
||||
std::vector<Vtr::internal::Refinement *> _refinements;
|
||||
|
||||
std::vector<TopologyLevel> _farLevels;
|
||||
};
|
||||
|
||||
|
||||
inline int
|
||||
TopologyRefiner::GetNumFVarChannels() const {
|
||||
|
||||
return _levels[0]->getNumFVarChannels();
|
||||
}
|
||||
inline Sdc::Options::FVarLinearInterpolation
|
||||
TopologyRefiner::GetFVarLinearInterpolation(int channel) const {
|
||||
|
||||
return _levels[0]->getFVarOptions(channel).GetFVarLinearInterpolation();
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_H */
|
||||
434
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefinerFactory.cpp
vendored
Normal file
434
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefinerFactory.cpp
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../far/topologyRefinerFactory.h"
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../sdc/types.h"
|
||||
#include "../vtr/level.h"
|
||||
|
||||
#include <cstdio>
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Methods for the Factory base class -- general enough to warrant including
|
||||
// in the base class rather than the subclass template (and so replicated for
|
||||
// each usage)
|
||||
//
|
||||
//
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTopologySizing(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
//
|
||||
// At minimum we require face-vertices (the total count of which can be
|
||||
// determined from the offsets accumulated during sizing pass) and we
|
||||
// need to resize members related to them to be populated during
|
||||
// assignment:
|
||||
//
|
||||
int vCount = baseLevel.getNumVertices();
|
||||
int fCount = baseLevel.getNumFaces();
|
||||
|
||||
if (vCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"mesh contains no vertices.");
|
||||
return false;
|
||||
}
|
||||
if (fCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"meshes without faces not yet supported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure no face was defined that would lead to a valence overflow --
|
||||
// the max valence has been initialized with the maximum number of
|
||||
// face-vertices:
|
||||
if (baseLevel.getMaxValence() > Vtr::VALENCE_LIMIT) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"face with %d vertices > %d max.",
|
||||
baseLevel.getMaxValence(), Vtr::VALENCE_LIMIT);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
int fVertCount = baseLevel.getNumFaceVertices(fCount - 1) +
|
||||
baseLevel.getOffsetOfFaceVertices(fCount - 1);
|
||||
|
||||
if (fVertCount == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"mesh contains no face-vertices.");
|
||||
return false;
|
||||
}
|
||||
if ((refiner.GetSchemeType() == Sdc::SCHEME_LOOP) &&
|
||||
(fVertCount != (3 * fCount))) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"non-triangular faces not supported by Loop scheme.");
|
||||
return false;
|
||||
}
|
||||
baseLevel.resizeFaceVertices(fVertCount);
|
||||
|
||||
//
|
||||
// If edges were sized, all other topological relations must be sized
|
||||
// with it, in which case we allocate those members to be populated.
|
||||
// Otherwise, sizing of the other topology members is deferred until
|
||||
// the face-vertices are assigned and the resulting relationships
|
||||
// determined:
|
||||
//
|
||||
int eCount = baseLevel.getNumEdges();
|
||||
|
||||
if (eCount > 0) {
|
||||
baseLevel.resizeFaceEdges(baseLevel.getNumFaceVerticesTotal());
|
||||
baseLevel.resizeEdgeVertices();
|
||||
baseLevel.resizeEdgeFaces( baseLevel.getNumEdgeFaces(eCount-1) +
|
||||
baseLevel.getOffsetOfEdgeFaces(eCount-1));
|
||||
baseLevel.resizeVertexFaces(baseLevel.getNumVertexFaces(vCount-1) +
|
||||
baseLevel.getOffsetOfVertexFaces(vCount-1));
|
||||
baseLevel.resizeVertexEdges(baseLevel.getNumVertexEdges(vCount-1) +
|
||||
baseLevel.getOffsetOfVertexEdges(vCount-1));
|
||||
|
||||
assert(baseLevel.getNumFaceEdgesTotal() > 0);
|
||||
assert(baseLevel.getNumEdgeVerticesTotal() > 0);
|
||||
assert(baseLevel.getNumEdgeFacesTotal() > 0);
|
||||
assert(baseLevel.getNumVertexFacesTotal() > 0);
|
||||
assert(baseLevel.getNumVertexEdgesTotal() > 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTopologyAssignment(
|
||||
TopologyRefiner& refiner, bool fullValidation,
|
||||
TopologyCallback callback, void const * callbackData) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
bool completeMissingTopology = (baseLevel.getNumEdges() == 0);
|
||||
if (completeMissingTopology) {
|
||||
if (! baseLevel.completeTopologyFromFaceVertices()) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"vertex with valence %d > %d max.",
|
||||
baseLevel.getMaxValence(), Vtr::VALENCE_LIMIT);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (baseLevel.getMaxValence() == 0) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"maximum valence not assigned.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fullValidation) {
|
||||
if (! baseLevel.validateTopology(callback, callbackData)) {
|
||||
if (completeMissingTopology) {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"invalid topology detected from partial specification.");
|
||||
} else {
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"invalid topology detected as fully specified.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we have a valid base level, initialize the Refiner's
|
||||
// component inventory:
|
||||
refiner.initializeInventory();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareComponentTagsAndSharpness(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
//
|
||||
// This method combines the initialization of internal component tags
|
||||
// with the sharpening of edges and vertices according to the given
|
||||
// boundary interpolation rule in the Options.
|
||||
// Since both involve traversing the edge and vertex lists and noting
|
||||
// the presence of boundaries -- best to do both at once...
|
||||
//
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
Sdc::Options options = refiner.GetSchemeOptions();
|
||||
Sdc::Crease creasing(options);
|
||||
|
||||
bool makeBoundaryFacesHoles =
|
||||
(options.GetVtxBoundaryInterpolation() ==
|
||||
Sdc::Options::VTX_BOUNDARY_NONE) &&
|
||||
(Sdc::SchemeTypeTraits::GetLocalNeighborhoodSize(
|
||||
refiner.GetSchemeType()) > 0);
|
||||
|
||||
bool sharpenCornerVerts =
|
||||
(options.GetVtxBoundaryInterpolation() ==
|
||||
Sdc::Options::VTX_BOUNDARY_EDGE_AND_CORNER);
|
||||
|
||||
bool sharpenNonManFeatures = true;
|
||||
|
||||
//
|
||||
// Before initializing edge and vertex tags, tag any qualifying boundary
|
||||
// faces as holes before the sharpness of incident vertices and edges is
|
||||
// affected by boundary interpolation rules.
|
||||
//
|
||||
// Faces will be excluded (tagged as holes) if they contain a vertex on a
|
||||
// boundary that did not have all of its incident boundary edges sharpened
|
||||
// (not just the boundary edges within the face), so inspect the vertices
|
||||
// and tag their incident faces when necessary:
|
||||
//
|
||||
if (makeBoundaryFacesHoles) {
|
||||
for (Vtr::Index vIndex = 0; vIndex < baseLevel.getNumVertices();
|
||||
++vIndex) {
|
||||
Vtr::ConstIndexArray vEdges = baseLevel.getVertexEdges(vIndex);
|
||||
Vtr::ConstIndexArray vFaces = baseLevel.getVertexFaces(vIndex);
|
||||
|
||||
// Ignore manifold interior vertices:
|
||||
if ((vEdges.size() == vFaces.size()) &&
|
||||
!baseLevel.getVertexTag(vIndex)._nonManifold) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool excludeFaces = false;
|
||||
for (int i = 0; !excludeFaces && (i < vEdges.size()); ++i) {
|
||||
excludeFaces = (baseLevel.getNumEdgeFaces(vEdges[i]) == 1) &&
|
||||
!Sdc::Crease::IsInfinite(
|
||||
baseLevel.getEdgeSharpness(vEdges[i]));
|
||||
}
|
||||
if (excludeFaces) {
|
||||
for (int i = 0; i < vFaces.size(); ++i) {
|
||||
baseLevel.getFaceTag(vFaces[i])._hole = true;
|
||||
}
|
||||
// Need to tag Refiner (the Level does not keep track of this)
|
||||
refiner._hasHoles = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Process the Edge tags first, as Vertex tags (notably the Rule) are
|
||||
// dependent on properties of their incident edges.
|
||||
//
|
||||
for (Vtr::Index eIndex = 0; eIndex < baseLevel.getNumEdges(); ++eIndex) {
|
||||
Vtr::internal::Level::ETag& eTag = baseLevel.getEdgeTag(eIndex);
|
||||
|
||||
float& eSharpness = baseLevel.getEdgeSharpness(eIndex);
|
||||
|
||||
eTag._boundary = (baseLevel.getNumEdgeFaces(eIndex) < 2);
|
||||
if (eTag._boundary || (eTag._nonManifold && sharpenNonManFeatures)) {
|
||||
eSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
}
|
||||
eTag._infSharp = Sdc::Crease::IsInfinite(eSharpness);
|
||||
eTag._semiSharp = Sdc::Crease::IsSharp(eSharpness) && !eTag._infSharp;
|
||||
}
|
||||
|
||||
//
|
||||
// Process the Vertex tags now -- for some tags (semi-sharp and its rule)
|
||||
// we need to inspect all incident edges:
|
||||
//
|
||||
int schemeRegularInteriorValence =
|
||||
Sdc::SchemeTypeTraits::GetRegularVertexValence(refiner.GetSchemeType());
|
||||
int schemeRegularBoundaryValence = schemeRegularInteriorValence / 2;
|
||||
|
||||
for (Vtr::Index vIndex = 0; vIndex < baseLevel.getNumVertices(); ++vIndex) {
|
||||
Vtr::internal::Level::VTag& vTag = baseLevel.getVertexTag(vIndex);
|
||||
|
||||
float& vSharpness = baseLevel.getVertexSharpness(vIndex);
|
||||
|
||||
Vtr::ConstIndexArray vEdges = baseLevel.getVertexEdges(vIndex);
|
||||
Vtr::ConstIndexArray vFaces = baseLevel.getVertexFaces(vIndex);
|
||||
|
||||
//
|
||||
// Take inventory of properties of incident edges that affect this
|
||||
// vertex:
|
||||
//
|
||||
int boundaryEdgeCount = 0;
|
||||
int infSharpEdgeCount = 0;
|
||||
int semiSharpEdgeCount = 0;
|
||||
int nonManifoldEdgeCount = 0;
|
||||
for (int i = 0; i < vEdges.size(); ++i) {
|
||||
Vtr::internal::Level::ETag const& eTag =
|
||||
baseLevel.getEdgeTag(vEdges[i]);
|
||||
|
||||
boundaryEdgeCount += eTag._boundary;
|
||||
infSharpEdgeCount += eTag._infSharp;
|
||||
semiSharpEdgeCount += eTag._semiSharp;
|
||||
nonManifoldEdgeCount += eTag._nonManifold;
|
||||
}
|
||||
int sharpEdgeCount = infSharpEdgeCount + semiSharpEdgeCount;
|
||||
|
||||
//
|
||||
// Sharpen the vertex before using it in conjunction with incident edge
|
||||
// properties to determine the semi-sharp tag and rule:
|
||||
//
|
||||
bool isTopologicalCorner = (vFaces.size() == 1) && (vEdges.size() == 2);
|
||||
bool isSharpenedCorner = isTopologicalCorner && sharpenCornerVerts;
|
||||
if (isSharpenedCorner) {
|
||||
vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
} else if (vTag._nonManifold && sharpenNonManFeatures &&
|
||||
!Sdc::Crease::IsInfinite(vSharpness)) {
|
||||
//
|
||||
// We avoid sharpening non-manifold vertices when they occur on
|
||||
// interior non-manifold creases, i.e. a pair of opposing non-
|
||||
// manifold edges with more than two incident faces. In these
|
||||
// cases there are more incident faces than edges (1 more for
|
||||
// each additional "fin") and no boundaries. Closer inspection
|
||||
// of manifold subsets around the vertex is required to truly
|
||||
// determine the crease case, so avoid it using pre-conditions
|
||||
// that are available here:
|
||||
//
|
||||
bool isNonManCrease = (nonManifoldEdgeCount == 2) &&
|
||||
(boundaryEdgeCount == 0) &&
|
||||
(vFaces.size() > vEdges.size()) &&
|
||||
baseLevel.testVertexNonManifoldCrease(vIndex);
|
||||
if (!isNonManCrease) {
|
||||
vSharpness = Sdc::Crease::SHARPNESS_INFINITE;
|
||||
}
|
||||
}
|
||||
|
||||
vTag._infSharp = Sdc::Crease::IsInfinite(vSharpness);
|
||||
vTag._semiSharp = Sdc::Crease::IsSemiSharp(vSharpness);
|
||||
vTag._semiSharpEdges = (semiSharpEdgeCount > 0);
|
||||
|
||||
vTag._rule = (Vtr::internal::Level::VTag::VTagSize)
|
||||
creasing.DetermineVertexVertexRule(vSharpness, sharpEdgeCount);
|
||||
|
||||
//
|
||||
// Assign topological tags -- note that the "xordinary" tag is not
|
||||
// assigned if non-manifold:
|
||||
//
|
||||
vTag._boundary = (boundaryEdgeCount > 0);
|
||||
vTag._corner = isTopologicalCorner && vTag._infSharp;
|
||||
if (vTag._nonManifold) {
|
||||
vTag._xordinary = false;
|
||||
} else if (vTag._corner) {
|
||||
vTag._xordinary = false;
|
||||
} else if (vTag._boundary) {
|
||||
vTag._xordinary = (vFaces.size() != schemeRegularBoundaryValence);
|
||||
} else {
|
||||
vTag._xordinary = (vFaces.size() != schemeRegularInteriorValence);
|
||||
}
|
||||
vTag._incomplete = 0;
|
||||
|
||||
//
|
||||
// Assign tags specific to inf-sharp features to identify regular
|
||||
// topologies partitioned by inf-sharp creases -- must be no semi-
|
||||
// harp features here (and manifold for now):
|
||||
//
|
||||
vTag._infSharpEdges = (infSharpEdgeCount > 0);
|
||||
vTag._infSharpCrease = false;
|
||||
vTag._infIrregular = vTag._infSharp || vTag._infSharpEdges;
|
||||
|
||||
if (vTag._infSharpEdges) {
|
||||
// Ignore semi-sharp vertex sharpness when computing the
|
||||
// inf-sharp Rule:
|
||||
Sdc::Crease::Rule infRule = creasing.DetermineVertexVertexRule(
|
||||
(vTag._infSharp ? vSharpness : 0.0f), infSharpEdgeCount);
|
||||
|
||||
if (infRule == Sdc::Crease::RULE_CREASE) {
|
||||
vTag._infSharpCrease = true;
|
||||
|
||||
// A "regular" inf-crease can only occur along a manifold
|
||||
// regular boundary or by bisecting a manifold interior
|
||||
// region (it is also possible along non-manifold vertices
|
||||
// in some cases, but that requires much more effort to
|
||||
// detect -- perhaps later...)
|
||||
//
|
||||
if (!vTag._xordinary && !vTag._nonManifold) {
|
||||
if (vTag._boundary) {
|
||||
vTag._infIrregular = false;
|
||||
} else {
|
||||
assert((schemeRegularInteriorValence == 4) ||
|
||||
(schemeRegularInteriorValence == 6));
|
||||
|
||||
if (schemeRegularInteriorValence == 4) {
|
||||
vTag._infIrregular =
|
||||
(baseLevel.getEdgeTag(vEdges[0])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[2])._infSharp);
|
||||
} else if (schemeRegularInteriorValence == 6) {
|
||||
vTag._infIrregular =
|
||||
(baseLevel.getEdgeTag(vEdges[0])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[3])._infSharp) ||
|
||||
(baseLevel.getEdgeTag(vEdges[1])._infSharp !=
|
||||
baseLevel.getEdgeTag(vEdges[4])._infSharp);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (infRule == Sdc::Crease::RULE_CORNER) {
|
||||
// A regular set of inf-corners occurs when all edges are
|
||||
// sharp and not a smooth corner:
|
||||
//
|
||||
if ((infSharpEdgeCount == vEdges.size() &&
|
||||
((vEdges.size() > 2) || vTag._infSharp))) {
|
||||
vTag._infIrregular = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If any irregular faces are present, mark whether or not a vertex
|
||||
// is incident any irregular face:
|
||||
//
|
||||
if (refiner._hasIrregFaces) {
|
||||
int regSize = refiner._regFaceSize;
|
||||
for (int i = 0; i < vFaces.size(); ++i) {
|
||||
if (baseLevel.getFaceVertices(vFaces[i]).size() != regSize) {
|
||||
vTag._incidIrregFace = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TopologyRefinerFactoryBase::prepareFaceVaryingChannels(
|
||||
TopologyRefiner& refiner) {
|
||||
|
||||
Vtr::internal::Level& baseLevel = refiner.getLevel(0);
|
||||
|
||||
int regVertexValence =
|
||||
Sdc::SchemeTypeTraits::GetRegularVertexValence(refiner.GetSchemeType());
|
||||
int regBoundaryValence = regVertexValence / 2;
|
||||
|
||||
for (int channel=0; channel<refiner.GetNumFVarChannels(); ++channel) {
|
||||
if (baseLevel.getNumFVarValues(channel) == 0) {
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024,
|
||||
"Failure in TopologyRefinerFactory<>::Create() -- "
|
||||
"face-varying channel %d has no values.", channel);
|
||||
Error(FAR_RUNTIME_ERROR, msg);
|
||||
return false;
|
||||
}
|
||||
baseLevel.completeFVarChannelTopology(channel, regBoundaryValence);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
706
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefinerFactory.h
vendored
Normal file
706
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/topologyRefinerFactory.h
vendored
Normal file
@@ -0,0 +1,706 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
||||
#define OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../far/topologyRefiner.h"
|
||||
#include "../far/error.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
///\brief Private base class of Factories for constructing TopologyRefiners
|
||||
///
|
||||
/// TopologyRefinerFactoryBase is the base class for subclasses that are intended to
|
||||
/// construct TopologyRefiners directly from meshes in their native representations.
|
||||
/// The subclasses are parameterized by the mesh type \<class MESH\> and are expected
|
||||
/// to inherit the details related to assembly and validation provided here that are
|
||||
/// independent of the subclass' mesh type.
|
||||
//
|
||||
class TopologyRefinerFactoryBase {
|
||||
protected:
|
||||
|
||||
//
|
||||
// Protected methods invoked by the subclass template to verify and process each
|
||||
// stage of construction implemented by the subclass:
|
||||
//
|
||||
typedef Vtr::internal::Level::ValidationCallback TopologyCallback;
|
||||
|
||||
static bool prepareComponentTopologySizing(TopologyRefiner& refiner);
|
||||
static bool prepareComponentTopologyAssignment(TopologyRefiner& refiner, bool fullValidation,
|
||||
TopologyCallback callback, void const * callbackData);
|
||||
static bool prepareComponentTagsAndSharpness(TopologyRefiner& refiner);
|
||||
static bool prepareFaceVaryingChannels(TopologyRefiner& refiner);
|
||||
};
|
||||
|
||||
|
||||
///\brief Factory for constructing TopologyRefiners from specific mesh classes.
|
||||
///
|
||||
/// TopologyRefinerFactory<MESH> is the factory class template to convert an instance of
|
||||
/// TopologyRefiner from an arbitrary mesh class. While a class template, the implementation
|
||||
/// is not (cannot) be complete, so specialization of a few methods is required (it is a
|
||||
/// stateless factory, so no instance and only static methods).
|
||||
///
|
||||
/// This template provides both the interface and high level assembly for the construction
|
||||
/// of the TopologyRefiner instance. The high level construction executes a specific set
|
||||
/// of operations to convert the client's MESH into TopologyRefiner. This set of operations
|
||||
/// combines methods independent of MESH from the base class with those specialized here for
|
||||
/// class MESH.
|
||||
///
|
||||
template <class MESH>
|
||||
class TopologyRefinerFactory : public TopologyRefinerFactoryBase {
|
||||
|
||||
public:
|
||||
|
||||
/// \brief Options related to the construction of each TopologyRefiner.
|
||||
///
|
||||
struct Options {
|
||||
|
||||
Options(Sdc::SchemeType sdcType = Sdc::SCHEME_CATMARK, Sdc::Options sdcOptions = Sdc::Options()) :
|
||||
schemeType(sdcType),
|
||||
schemeOptions(sdcOptions),
|
||||
validateFullTopology(false) { }
|
||||
|
||||
Sdc::SchemeType schemeType; ///< The subdivision scheme type identifier
|
||||
Sdc::Options schemeOptions; ///< The full set of options for the scheme,
|
||||
///< e.g. boundary interpolation rules...
|
||||
unsigned int validateFullTopology : 1; ///< Apply more extensive validation of
|
||||
///< the constructed topology -- intended
|
||||
///< for debugging.
|
||||
};
|
||||
|
||||
/// \brief Instantiates a TopologyRefiner from client-provided topological
|
||||
/// representation.
|
||||
///
|
||||
/// If only the face-vertices topological relationships are specified
|
||||
/// with this factory, edge relationships have to be inferred, which
|
||||
/// requires additional processing. If the client topological rep can
|
||||
/// provide this information, it is highly recommended to do so.
|
||||
///
|
||||
/// @param mesh Client's topological representation (or a converter)
|
||||
//
|
||||
/// @param options Options controlling the creation of the TopologyRefiner
|
||||
///
|
||||
/// @return A new instance of TopologyRefiner or 0 for failure
|
||||
///
|
||||
static TopologyRefiner* Create(MESH const& mesh, Options options = Options());
|
||||
|
||||
/// \brief Instantiates a TopologyRefiner from the base level of an
|
||||
/// existing instance.
|
||||
///
|
||||
/// This allows lightweight copies of the same topology to be refined
|
||||
/// differently for each new instance. As with other classes that refer
|
||||
/// to an existing TopologyRefiner, it must generally exist for the entire
|
||||
/// lifetime of the new instance. In this case, the base level of the
|
||||
/// original instance must be preserved.
|
||||
///
|
||||
/// @param baseLevel An existing TopologyRefiner to share base level.
|
||||
///
|
||||
/// @return A new instance of TopologyRefiner or 0 for failure
|
||||
///
|
||||
static TopologyRefiner* Create(TopologyRefiner const & baseLevel);
|
||||
|
||||
protected:
|
||||
typedef Vtr::internal::Level::TopologyError TopologyError;
|
||||
|
||||
//@{
|
||||
/// @name Methods to be provided to complete assembly of the TopologyRefiner
|
||||
///
|
||||
///
|
||||
/// These methods are to be specialized to implement all details specific to
|
||||
/// class MESH required to convert MESH data to TopologyRefiner. Note that
|
||||
/// some of these *must* be specialized in order to complete construction while
|
||||
/// some are optional.
|
||||
///
|
||||
/// There are two minimal construction requirements (to specify the size and
|
||||
/// content of all topology relations) and three optional (to specify feature
|
||||
/// tags, face-varying data, and runtime validation and error reporting).
|
||||
///
|
||||
/// See comments in the generic stubs, the factory for Far::TopologyDescriptor
|
||||
/// or the tutorials for more details on writing these.
|
||||
///
|
||||
|
||||
/// \brief Specify the number of vertices, faces, face-vertices, etc.
|
||||
static bool resizeComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief Specify the relationships between vertices, faces, etc. ie the
|
||||
/// face-vertices, vertex-faces, edge-vertices, etc.
|
||||
static bool assignComponentTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Specify edge or vertex sharpness or face holes
|
||||
static bool assignComponentTags(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Specify face-varying data per face
|
||||
static bool assignFaceVaryingTopology(TopologyRefiner& newRefiner, MESH const& mesh);
|
||||
|
||||
/// \brief (Optional) Control run-time topology validation and error reporting
|
||||
static void reportInvalidTopology(TopologyError errCode, char const * msg, MESH const& mesh);
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within resizeComponentTopology()
|
||||
///
|
||||
/// \brief These methods specify sizes of various quantities, e.g. the number of
|
||||
/// vertices, faces, face-vertices, etc. The number of the primary components
|
||||
/// (vertices, faces and edges) should be specified prior to anything else that
|
||||
/// references them (e.g. we need to know the number of faces before specifying
|
||||
/// the vertices for that face.
|
||||
///
|
||||
/// If a full boundary representation with all neighborhood information is not
|
||||
/// available, e.g. faces and vertices are available but not edges, only the
|
||||
/// face-vertices should be specified. The remaining topological relationships
|
||||
/// will be constructed later in the assembly (though at greater cost than if
|
||||
/// specified directly).
|
||||
///
|
||||
/// The sizes for topological relationships between individual components should be
|
||||
/// specified in order, i.e. the number of face-vertices for each successive face.
|
||||
///
|
||||
|
||||
/// \brief Specify the number of vertices to be accommodated
|
||||
static void setNumBaseVertices(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of faces to be accommodated
|
||||
static void setNumBaseFaces(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of edges to be accommodated
|
||||
static void setNumBaseEdges(TopologyRefiner & newRefiner, int count);
|
||||
|
||||
/// \brief Specify the number of vertices incident each face
|
||||
static void setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count);
|
||||
|
||||
/// \brief Specify the number of faces incident each edge
|
||||
static void setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count);
|
||||
|
||||
/// \brief Specify the number of faces incident each vertex
|
||||
static void setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count);
|
||||
|
||||
/// \brief Specify the number of edges incident each vertex
|
||||
static void setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count);
|
||||
|
||||
static int getNumBaseVertices(TopologyRefiner const & newRefiner);
|
||||
static int getNumBaseFaces(TopologyRefiner const & newRefiner);
|
||||
static int getNumBaseEdges(TopologyRefiner const & newRefiner);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignComponentTopology()
|
||||
///
|
||||
/// \brief These methods populate relationships between components -- in much the
|
||||
/// same manner as they are inspected once the TopologyRefiner is completed.
|
||||
///
|
||||
/// An array of fixed size is returned from these methods and its entries are to be
|
||||
/// populated with the appropriate indices for its neighbors. At minimum, the
|
||||
/// vertices for each face must be specified. As noted previously, the remaining
|
||||
/// relationships will be constructed as needed.
|
||||
///
|
||||
/// The ordering of entries in these arrays is important -- they are expected to
|
||||
/// be ordered counter-clockwise for a right-hand orientation.
|
||||
///
|
||||
/// Non-manifold components must be explicitly tagged as such and they do not
|
||||
/// require the ordering expected of manifold components. Special consideration
|
||||
/// must also be given to certain non-manifold situations, e.g. the same edge
|
||||
/// cannot appear twice in a face, and a degenerate edge (same vertex at both
|
||||
/// ends) can only have one incident face. Such considerations are typically
|
||||
/// achievable by creating multiple instances of an edge. So while there will
|
||||
/// always be a one-to-one correspondence between vertices and faces, the same
|
||||
/// is not guaranteed of edges in certain non-manifold circumstances.
|
||||
///
|
||||
|
||||
/// \brief Assign the vertices incident each face
|
||||
static IndexArray getBaseFaceVertices(TopologyRefiner & newRefiner, Index f);
|
||||
|
||||
/// \brief Assign the edges incident each face
|
||||
static IndexArray getBaseFaceEdges(TopologyRefiner & newRefiner, Index f);
|
||||
|
||||
/// \brief Assign the vertices incident each edge
|
||||
static IndexArray getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Assign the faces incident each edge
|
||||
static IndexArray getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Assign the faces incident each vertex
|
||||
static IndexArray getBaseVertexFaces(TopologyRefiner & newRefiner, Index v);
|
||||
|
||||
/// \brief Assign the edges incident each vertex
|
||||
static IndexArray getBaseVertexEdges(TopologyRefiner & newRefiner, Index v);
|
||||
|
||||
/// \brief Assign the local indices of a vertex within each of its incident faces
|
||||
static LocalIndexArray getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v);
|
||||
/// \brief Assign the local indices of a vertex within each of its incident edges
|
||||
static LocalIndexArray getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v);
|
||||
/// \brief Assign the local indices of an edge within each of its incident faces
|
||||
static LocalIndexArray getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e);
|
||||
|
||||
/// \brief Determine all local indices by inspection (only for pure manifold meshes)
|
||||
static void populateBaseLocalIndices(TopologyRefiner & newRefiner);
|
||||
|
||||
/// \brief Tag an edge as non-manifold
|
||||
static void setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b);
|
||||
|
||||
/// \brief Tag a vertex as non-manifold
|
||||
static void setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignComponentTags()
|
||||
///
|
||||
/// These methods are used to assign edge or vertex sharpness, for tagging faces
|
||||
/// as holes, etc. Unlike topological assignment, only those components that
|
||||
/// possess a feature of interest need be explicitly assigned.
|
||||
///
|
||||
/// Since topological construction is largely complete by this point, a method is
|
||||
/// available to identify an edge for sharpness assignment given a pair of vertices.
|
||||
///
|
||||
|
||||
/// \brief Identify an edge to be assigned a sharpness value given a vertex pair
|
||||
static Index findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1);
|
||||
|
||||
/// \brief Assign a sharpness value to a given edge
|
||||
static void setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float sharpness);
|
||||
|
||||
/// \brief Assign a sharpness value to a given vertex
|
||||
static void setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float sharpness);
|
||||
|
||||
/// \brief Tag a face as a hole
|
||||
static void setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool isHole);
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// @name Base level assembly methods to be used within assignFaceVaryingTopology()
|
||||
///
|
||||
/// Face-varying data is assigned to faces in much the same way as face-vertex
|
||||
/// topology is assigned -- indices for face-varying values are assigned to the
|
||||
/// corners of each face just as indices for vertices were assigned.
|
||||
///
|
||||
/// Independent sets of face-varying data are stored in channels. The identifier
|
||||
/// of each channel (an integer) is expected whenever referring to face-varying
|
||||
/// data in any form.
|
||||
///
|
||||
|
||||
/// \brief Create a new face-varying channel with the given number of values
|
||||
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues);
|
||||
|
||||
/// \brief Create a new face-varying channel with the given number of values and independent interpolation options
|
||||
static int createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions);
|
||||
|
||||
/// \brief Assign the face-varying values for the corners of each face
|
||||
static IndexArray getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel = 0);
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//
|
||||
// Not to be specialized:
|
||||
//
|
||||
static bool populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options);
|
||||
|
||||
private:
|
||||
//
|
||||
// An oversight in the interfaces of the error reporting function between the factory
|
||||
// class and the Vtr::Level requires this adapter function to avoid warnings.
|
||||
//
|
||||
// The static class method requires a reference as the MESH argument, but the interface
|
||||
// for Vtr::Level requires a pointer (void*). So this adapter with a MESH* argument is
|
||||
// used to effectively cast the function pointer required by Vtr::Level error reporting:
|
||||
//
|
||||
static void reportInvalidTopologyAdapter(TopologyError errCode, char const * msg, MESH const * mesh) {
|
||||
reportInvalidTopology(errCode, msg, *mesh);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Generic implementations:
|
||||
//
|
||||
template <class MESH>
|
||||
TopologyRefiner*
|
||||
TopologyRefinerFactory<MESH>::Create(MESH const& mesh, Options options) {
|
||||
|
||||
TopologyRefiner * refiner = new TopologyRefiner(options.schemeType, options.schemeOptions);
|
||||
|
||||
if (! populateBaseLevel(*refiner, mesh, options)) {
|
||||
delete refiner;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Eventually want to move the Refiner's inventory initialization here. Currently it
|
||||
// is handled after topology assignment, but if the inventory is to include additional
|
||||
// features (e.g. holes, etc.) it is better off deferred to here.
|
||||
|
||||
return refiner;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
TopologyRefiner*
|
||||
TopologyRefinerFactory<MESH>::Create(TopologyRefiner const & source) {
|
||||
|
||||
return new TopologyRefiner(source);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::populateBaseLevel(TopologyRefiner& refiner, MESH const& mesh, Options options) {
|
||||
|
||||
//
|
||||
// Construction of a specialized topology refiner involves four steps, each of which
|
||||
// involves a method specialized for MESH followed by one that takes an action in
|
||||
// response to it or in preparation for the next step.
|
||||
//
|
||||
// Both the specialized methods and those that follow them may find fault in the
|
||||
// construction and trigger failure at any time:
|
||||
//
|
||||
|
||||
//
|
||||
// Sizing of the topology -- this is a required specialization for MESH. This defines
|
||||
// an inventory of all components and their relations that is used to allocate buffers
|
||||
// to be efficiently populated in the subsequent topology assignment step.
|
||||
//
|
||||
if (! resizeComponentTopology(refiner, mesh)) return false;
|
||||
if (! prepareComponentTopologySizing(refiner)) return false;
|
||||
|
||||
//
|
||||
// Assignment of the topology -- this is a required specialization for MESH. If edges
|
||||
// are specified, all other topological relations are expected to be defined for them.
|
||||
// Otherwise edges and remaining topology will be completed from the face-vertices:
|
||||
//
|
||||
bool validate = options.validateFullTopology;
|
||||
TopologyCallback callback = reinterpret_cast<TopologyCallback>(reportInvalidTopologyAdapter);
|
||||
void const * userData = &mesh;
|
||||
|
||||
if (! assignComponentTopology(refiner, mesh)) return false;
|
||||
if (! prepareComponentTopologyAssignment(refiner, validate, callback, userData)) return false;
|
||||
|
||||
//
|
||||
// User assigned and internal tagging of components -- an optional specialization for
|
||||
// MESH. Allows the specification of sharpness values, holes, etc.
|
||||
//
|
||||
if (! assignComponentTags(refiner, mesh)) return false;
|
||||
if (! prepareComponentTagsAndSharpness(refiner)) return false;
|
||||
|
||||
//
|
||||
// Defining channels of face-varying primvar data -- an optional specialization for MESH.
|
||||
//
|
||||
if (! assignFaceVaryingTopology(refiner, mesh)) return false;
|
||||
if (! prepareFaceVaryingChannels(refiner)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseFaces(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeFaces(count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseEdges(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeEdges(count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertices(TopologyRefiner & newRefiner, int count) {
|
||||
newRefiner._levels[0]->resizeVertices(count);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseFaces(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumFaces();
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseEdges(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumEdges();
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::getNumBaseVertices(TopologyRefiner const & newRefiner) {
|
||||
return newRefiner._levels[0]->getNumVertices();
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseFaceVertices(TopologyRefiner & newRefiner, Index f, int count) {
|
||||
newRefiner._levels[0]->resizeFaceVertices(f, count);
|
||||
newRefiner._hasIrregFaces = newRefiner._hasIrregFaces || (count != newRefiner._regFaceSize);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseEdgeFaces(TopologyRefiner & newRefiner, Index e, int count) {
|
||||
newRefiner._levels[0]->resizeEdgeFaces(e, count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertexFaces(TopologyRefiner & newRefiner, Index v, int count) {
|
||||
newRefiner._levels[0]->resizeVertexFaces(v, count);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setNumBaseVertexEdges(TopologyRefiner & newRefiner, Index v, int count) {
|
||||
newRefiner._levels[0]->resizeVertexEdges(v, count);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceVertices(TopologyRefiner & newRefiner, Index f) {
|
||||
return newRefiner._levels[0]->getFaceVertices(f);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceEdges(TopologyRefiner & newRefiner, Index f) {
|
||||
return newRefiner._levels[0]->getFaceEdges(f);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeVertices(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeVertices(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeFaces(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeFaces(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexFaces(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexFaces(v);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexEdges(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexEdges(v);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseEdgeFaceLocalIndices(TopologyRefiner & newRefiner, Index e) {
|
||||
return newRefiner._levels[0]->getEdgeFaceLocalIndices(e);
|
||||
}
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexFaceLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexFaceLocalIndices(v);
|
||||
}
|
||||
template <class MESH>
|
||||
inline LocalIndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseVertexEdgeLocalIndices(TopologyRefiner & newRefiner, Index v) {
|
||||
return newRefiner._levels[0]->getVertexEdgeLocalIndices(v);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline Index
|
||||
TopologyRefinerFactory<MESH>::findBaseEdge(TopologyRefiner const & newRefiner, Index v0, Index v1) {
|
||||
return newRefiner._levels[0]->findEdge(v0, v1);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::populateBaseLocalIndices(TopologyRefiner & newRefiner) {
|
||||
newRefiner._levels[0]->populateLocalIndices();
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseEdgeNonManifold(TopologyRefiner & newRefiner, Index e, bool b) {
|
||||
newRefiner._levels[0]->setEdgeNonManifold(e, b);
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseVertexNonManifold(TopologyRefiner & newRefiner, Index v, bool b) {
|
||||
newRefiner._levels[0]->setVertexNonManifold(v, b);
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseEdgeSharpness(TopologyRefiner & newRefiner, Index e, float s) {
|
||||
newRefiner._levels[0]->getEdgeSharpness(e) = s;
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseVertexSharpness(TopologyRefiner & newRefiner, Index v, float s) {
|
||||
newRefiner._levels[0]->getVertexSharpness(v) = s;
|
||||
}
|
||||
template <class MESH>
|
||||
inline void
|
||||
TopologyRefinerFactory<MESH>::setBaseFaceHole(TopologyRefiner & newRefiner, Index f, bool b) {
|
||||
newRefiner._levels[0]->setFaceHole(f, b);
|
||||
newRefiner._hasHoles = newRefiner._hasHoles || b;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues) {
|
||||
return newRefiner._levels[0]->createFVarChannel(numValues, newRefiner._subdivOptions);
|
||||
}
|
||||
template <class MESH>
|
||||
inline int
|
||||
TopologyRefinerFactory<MESH>::createBaseFVarChannel(TopologyRefiner & newRefiner, int numValues, Sdc::Options const& fvarOptions) {
|
||||
Sdc::Options newOptions = newRefiner._subdivOptions;
|
||||
newOptions.SetFVarLinearInterpolation(fvarOptions.GetFVarLinearInterpolation());
|
||||
return newRefiner._levels[0]->createFVarChannel(numValues, newOptions);
|
||||
}
|
||||
template <class MESH>
|
||||
inline IndexArray
|
||||
TopologyRefinerFactory<MESH>::getBaseFaceFVarValues(TopologyRefiner & newRefiner, Index face, int channel) {
|
||||
return newRefiner._levels[0]->getFaceFVarValues(face, channel);
|
||||
}
|
||||
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::resizeComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::resizeComponentTopology() -- no specialization provided.");
|
||||
|
||||
//
|
||||
// Sizing the topology tables:
|
||||
// This method is for determining the sizes of the various topology tables (and other
|
||||
// data) associated with the mesh. Once completed, appropriate memory will be allocated
|
||||
// and an additional method invoked to populate it accordingly.
|
||||
//
|
||||
// The following methods should be called -- first those to specify the number of faces,
|
||||
// edges and vertices in the mesh:
|
||||
//
|
||||
// void setBaseFaceCount( TopologyRefiner& newRefiner, int count)
|
||||
// void setBaseEdgeCount( TopologyRefiner& newRefiner, int count)
|
||||
// void setBaseVertexCount(TopologyRefiner& newRefiner, int count)
|
||||
//
|
||||
// and then for each face, edge and vertex, the number of its incident components:
|
||||
//
|
||||
// void setBaseFaceVertexCount(TopologyRefiner& newRefiner, Index face, int count)
|
||||
// void setBaseEdgeFaceCount( TopologyRefiner& newRefiner, Index edge, int count)
|
||||
// void setBaseVertexFaceCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
||||
// void setBaseVertexEdgeCount(TopologyRefiner& newRefiner, Index vertex, int count)
|
||||
//
|
||||
// The count/size for a component type must be set before indices associated with that
|
||||
// component type can be used.
|
||||
//
|
||||
// Note that it is only necessary to size 4 of the 6 supported topological relations --
|
||||
// the number of edge-vertices is fixed at two per edge, and the number of face-edges is
|
||||
// the same as the number of face-vertices.
|
||||
//
|
||||
// So a single pass through your mesh to gather up all of this sizing information will
|
||||
// allow the Tables to be allocated appropriately once and avoid any dynamic resizing as
|
||||
// it grows.
|
||||
//
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignComponentTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
Error(FAR_RUNTIME_ERROR,
|
||||
"Failure in TopologyRefinerFactory<>::assignComponentTopology() -- no specialization provided.");
|
||||
|
||||
//
|
||||
// Assigning the topology tables:
|
||||
// Once the topology tables have been allocated, the six required topological
|
||||
// relations can be directly populated using the following methods:
|
||||
//
|
||||
// IndexArray setBaseFaceVertices(TopologyRefiner& newRefiner, Index face)
|
||||
// IndexArray setBaseFaceEdges(TopologyRefiner& newRefiner, Index face)
|
||||
//
|
||||
// IndexArray setBaseEdgeVertices(TopologyRefiner& newRefiner, Index edge)
|
||||
// IndexArray setBaseEdgeFaces(TopologyRefiner& newRefiner, Index edge)
|
||||
//
|
||||
// IndexArray setBaseVertexEdges(TopologyRefiner& newRefiner, Index vertex)
|
||||
// IndexArray setBaseVertexFaces(TopologyRefiner& newRefiner, Index vertex)
|
||||
//
|
||||
// For the last two relations -- the faces and edges incident a vertex -- there are
|
||||
// also "local indices" that must be specified (considering doing this internally),
|
||||
// where the "local index" of each incident face or edge is the index of the vertex
|
||||
// within that face or edge, and so ranging from 0-3 for incident quads and 0-1 for
|
||||
// incident edges. These are assigned through similarly retrieved arrays:
|
||||
//
|
||||
// LocalIndexArray setBaseVertexFaceLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
||||
// LocalIndexArray setBaseVertexEdgeLocalIndices(TopologyRefiner& newRefiner, Index vertex)
|
||||
// LocalIndexArray setBaseEdgeFaceLocalIndices( TopologyRefiner& newRefiner, Index edge)
|
||||
//
|
||||
// or, if the mesh is manifold, explicit assignment of these can be deferred and
|
||||
// all can be determined by calling:
|
||||
//
|
||||
// void populateBaseLocalIndices(TopologyRefiner& newRefiner)
|
||||
//
|
||||
// All components are assumed to be locally manifold and ordering of components in
|
||||
// the above relations is expected to be counter-clockwise.
|
||||
//
|
||||
// For non-manifold components, no ordering/orientation of incident components is
|
||||
// assumed or required, but be sure to explicitly tag such components (vertices and
|
||||
// edges) as non-manifold:
|
||||
//
|
||||
// void setBaseEdgeNonManifold(TopologyRefiner& newRefiner, Index edge, bool b);
|
||||
//
|
||||
// void setBaseVertexNonManifold(TopologyRefiner& newRefiner, Index vertex, bool b);
|
||||
//
|
||||
// Also consider using TopologyLevel::ValidateTopology() when debugging to ensure
|
||||
// that topology has been completely and correctly specified.
|
||||
//
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignFaceVaryingTopology(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional assigning face-varying topology tables:
|
||||
//
|
||||
// Create independent face-varying primitive variable channels:
|
||||
// int createBaseFVarChannel(TopologyRefiner& newRefiner, int numValues)
|
||||
//
|
||||
// For each channel, populate the face-vertex values:
|
||||
// IndexArray setBaseFaceFVarValues(TopologyRefiner& newRefiner, Index face, int channel = 0)
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
bool
|
||||
TopologyRefinerFactory<MESH>::assignComponentTags(TopologyRefiner& /* refiner */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional tagging:
|
||||
// This is where any additional feature tags -- sharpness, holes, etc. -- can be
|
||||
// specified using:
|
||||
//
|
||||
// void setBaseEdgeSharpness(TopologyRefiner& newRefiner, Index edge, float sharpness)
|
||||
// void setBaseVertexSharpness(TopologyRefiner& newRefiner, Index vertex, float sharpness)
|
||||
//
|
||||
// void setBaseFaceHole(TopologyRefiner& newRefiner, Index face, bool hole)
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class MESH>
|
||||
void
|
||||
TopologyRefinerFactory<MESH>::reportInvalidTopology(
|
||||
TopologyError /* errCode */, char const * /* msg */, MESH const& /* mesh */) {
|
||||
|
||||
//
|
||||
// Optional topology validation error reporting:
|
||||
// This method is called whenever the factory encounters topology validation
|
||||
// errors. By default, nothing is reported
|
||||
//
|
||||
}
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TOPOLOGY_REFINER_FACTORY_H */
|
||||
44
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/types.h
vendored
Normal file
44
blender-5.2.0/extern/opensubdiv-source/opensubdiv/far/types.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
|
||||
#ifndef OPENSUBDIV3_FAR_TYPES_H
|
||||
#define OPENSUBDIV3_FAR_TYPES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../vtr/types.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Far {
|
||||
|
||||
//
|
||||
// Typedefs for indices that are inherited from the Vtr level -- eventually
|
||||
// these primitive Vtr types may be declared at a lower, more public level.
|
||||
//
|
||||
typedef Vtr::Index Index;
|
||||
typedef Vtr::LocalIndex LocalIndex;
|
||||
|
||||
typedef Vtr::IndexArray IndexArray;
|
||||
typedef Vtr::LocalIndexArray LocalIndexArray;
|
||||
|
||||
typedef Vtr::ConstIndexArray ConstIndexArray;
|
||||
typedef Vtr::ConstLocalIndexArray ConstLocalIndexArray;
|
||||
|
||||
inline bool IndexIsValid(Index index) { return Vtr::IndexIsValid(index); }
|
||||
|
||||
static const Index INDEX_INVALID = Vtr::INDEX_INVALID;
|
||||
static const int VALENCE_LIMIT = Vtr::VALENCE_LIMIT;
|
||||
|
||||
} // end namespace Far
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_FAR_TYPES_H */
|
||||
Reference in New Issue
Block a user