Subdiv: Make OpenSubdiv_TopologyRefiner into a C++ class

Replace the C-class pattern function pointers with actual class methods.
Other than the obvious benefit of not requiring the "this" pointer to be
explicitly passed into every function call, this will make it much simpler
to remove the entire C-API class and replace it with its "impl" next.

For that next step we need to expose code to the implementation
of the topology refiner, so instead of defining stubs locally in the
opensubdiv intern class, we spread some WITH_OPENSUBDIV checks
in the blenkernel. As far as I know this is the only way to remove the
intermediate C-API and call opensubdiv functions directly from there.
This commit is contained in:
Hans Goudey 2024-04-18 22:27:35 -04:00
parent 52c0f4078a
commit 7f5dd29abd
11 changed files with 179 additions and 168 deletions

@ -433,8 +433,8 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
const bool has_varying_data = false; const bool has_varying_data = false;
const int num_face_varying_channels = refiner->GetNumFVarChannels(); const int num_face_varying_channels = refiner->GetNumFVarChannels();
const bool has_face_varying_data = (num_face_varying_channels != 0); const bool has_face_varying_data = (num_face_varying_channels != 0);
const int level = topology_refiner->getSubdivisionLevel(topology_refiner); const int level = topology_refiner->getSubdivisionLevel();
const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner); const bool is_adaptive = topology_refiner->getIsAdaptive();
// Common settings for stencils and patches. // Common settings for stencils and patches.
const bool stencil_generate_intermediate_levels = is_adaptive; const bool stencil_generate_intermediate_levels = is_adaptive;
const bool stencil_generate_offsets = true; const bool stencil_generate_offsets = true;

@ -22,7 +22,7 @@ struct OpenSubdiv_Buffer;
struct OpenSubdiv_EvaluatorCacheImpl; struct OpenSubdiv_EvaluatorCacheImpl;
struct OpenSubdiv_EvaluatorSettings; struct OpenSubdiv_EvaluatorSettings;
struct OpenSubdiv_PatchCoord; struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner; class OpenSubdiv_TopologyRefiner;
namespace blender::opensubdiv { namespace blender::opensubdiv {
@ -197,7 +197,7 @@ struct OpenSubdiv_EvaluatorImpl {
}; };
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
struct OpenSubdiv_TopologyRefiner *topology_refiner, OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type, eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr); OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr);

@ -22,32 +22,32 @@ static const OpenSubdiv::Far::TopologyLevel &getOSDTopologyBaseLevel(
return getOSDTopologyRefiner(topology_refiner)->GetLevel(0); return getOSDTopologyRefiner(topology_refiner)->GetLevel(0);
} }
static int getSubdivisionLevel(const OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getSubdivisionLevel() const
{ {
return topology_refiner->impl->settings.level; return this->impl->settings.level;
} }
static bool getIsAdaptive(const OpenSubdiv_TopologyRefiner *topology_refiner) bool OpenSubdiv_TopologyRefiner::getIsAdaptive() const
{ {
return topology_refiner->impl->settings.is_adaptive; return this->impl->settings.is_adaptive;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Query basic topology information from base level. // Query basic topology information from base level.
static int getNumVertices(const OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getNumVertices() const
{ {
return getOSDTopologyBaseLevel(topology_refiner).GetNumVertices(); return getOSDTopologyBaseLevel(this).GetNumVertices();
} }
static int getNumEdges(const OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getNumEdges() const
{ {
return getOSDTopologyBaseLevel(topology_refiner).GetNumEdges(); return getOSDTopologyBaseLevel(this).GetNumEdges();
} }
static int getNumFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getNumFaces() const
{ {
return getOSDTopologyBaseLevel(topology_refiner).GetNumFaces(); return getOSDTopologyBaseLevel(this).GetNumFaces();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -60,164 +60,117 @@ static void convertArrayToRaw(const OpenSubdiv::Far::ConstIndexArray &array, int
} }
} }
static int getNumFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, int OpenSubdiv_TopologyRefiner::getNumFaceVertices(const int face_index) const
const int face_index)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetFaceVertices(face_index).size(); return base_level.GetFaceVertices(face_index).size();
} }
static void getFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, void OpenSubdiv_TopologyRefiner::getFaceVertices(const int face_index,
const int face_index, int *face_vertices_indices) const
int *face_vertices_indices)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceVertices(face_index); OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceVertices(face_index);
convertArrayToRaw(array, face_vertices_indices); convertArrayToRaw(array, face_vertices_indices);
} }
static int getNumFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, int OpenSubdiv_TopologyRefiner::getNumFaceEdges(const int face_index) const
const int face_index)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetFaceEdges(face_index).size(); return base_level.GetFaceEdges(face_index).size();
} }
static void getFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, void OpenSubdiv_TopologyRefiner::getFaceEdges(const int face_index, int *face_edges_indices) const
const int face_index,
int *face_edges_indices)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceEdges(face_index); OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceEdges(face_index);
convertArrayToRaw(array, face_edges_indices); convertArrayToRaw(array, face_edges_indices);
} }
static void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner, void OpenSubdiv_TopologyRefiner::getEdgeVertices(const int edge_index,
const int edge_index, int edge_vertices_indices[2]) const
int edge_vertices_indices[2])
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
OpenSubdiv::Far::ConstIndexArray array = base_level.GetEdgeVertices(edge_index); OpenSubdiv::Far::ConstIndexArray array = base_level.GetEdgeVertices(edge_index);
assert(array.size() == 2); assert(array.size() == 2);
edge_vertices_indices[0] = array[0]; edge_vertices_indices[0] = array[0];
edge_vertices_indices[1] = array[1]; edge_vertices_indices[1] = array[1];
} }
static int getNumVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, int OpenSubdiv_TopologyRefiner::getNumVertexEdges(const int vertex_index) const
const int vertex_index)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetVertexEdges(vertex_index).size(); return base_level.GetVertexEdges(vertex_index).size();
} }
static void getVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner, void OpenSubdiv_TopologyRefiner::getVertexEdges(const int vertex_index,
const int vertex_index, int *vertex_edges_indices) const
int *vertex_edges_indices)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
OpenSubdiv::Far::ConstIndexArray array = base_level.GetVertexEdges(vertex_index); OpenSubdiv::Far::ConstIndexArray array = base_level.GetVertexEdges(vertex_index);
convertArrayToRaw(array, vertex_edges_indices); convertArrayToRaw(array, vertex_edges_indices);
} }
static int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner, int OpenSubdiv_TopologyRefiner::getNumFacePtexFaces(const int face_index) const
const int face_index)
{ {
const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); const int num_face_vertices = this->getNumFaceVertices(face_index);
if (num_face_vertices == 4) { if (num_face_vertices == 4) {
return 1; return 1;
} }
return num_face_vertices; return num_face_vertices;
} }
static int getNumPtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getNumPtexFaces() const
{ {
const int num_faces = topology_refiner->getNumFaces(topology_refiner); const int num_faces = this->getNumFaces();
int num_ptex_faces = 0; int num_ptex_faces = 0;
for (int face_index = 0; face_index < num_faces; ++face_index) { for (int face_index = 0; face_index < num_faces; ++face_index) {
num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); num_ptex_faces += this->getNumFacePtexFaces(face_index);
} }
return num_ptex_faces; return num_ptex_faces;
} }
static void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner *topology_refiner, void OpenSubdiv_TopologyRefiner::fillFacePtexIndexOffset(int *face_ptex_index_offset) const
int *face_ptex_index_offset)
{ {
const int num_faces = topology_refiner->getNumFaces(topology_refiner); const int num_faces = this->getNumFaces();
int num_ptex_faces = 0; int num_ptex_faces = 0;
for (int face_index = 0; face_index < num_faces; ++face_index) { for (int face_index = 0; face_index < num_faces; ++face_index) {
face_ptex_index_offset[face_index] = num_ptex_faces; face_ptex_index_offset[face_index] = num_ptex_faces;
num_ptex_faces += topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); num_ptex_faces += this->getNumFacePtexFaces(face_index);
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Face-varying data. // Face-varying data.
static int getNumFVarChannels(const struct OpenSubdiv_TopologyRefiner *topology_refiner) int OpenSubdiv_TopologyRefiner::getNumFVarChannels() const
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetNumFVarChannels(); return base_level.GetNumFVarChannels();
} }
static OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation( OpenSubdiv_FVarLinearInterpolation OpenSubdiv_TopologyRefiner::getFVarLinearInterpolation() const
const struct OpenSubdiv_TopologyRefiner *topology_refiner)
{ {
return blender::opensubdiv::getCAPIFVarLinearInterpolationFromOSD( return blender::opensubdiv::getCAPIFVarLinearInterpolationFromOSD(
getOSDTopologyRefiner(topology_refiner)->GetFVarLinearInterpolation()); getOSDTopologyRefiner(this)->GetFVarLinearInterpolation());
} }
static int getNumFVarValues(const struct OpenSubdiv_TopologyRefiner *topology_refiner, int OpenSubdiv_TopologyRefiner::getNumFVarValues(const int channel) const
const int channel)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetNumFVarValues(channel); return base_level.GetNumFVarValues(channel);
} }
static const int *getFaceFVarValueIndices( const int *OpenSubdiv_TopologyRefiner::getFaceFVarValueIndices(const int face_index,
const struct OpenSubdiv_TopologyRefiner *topology_refiner, const int channel) const
const int face_index,
const int channel)
{ {
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner); const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return &base_level.GetFaceFVarValues(face_index, channel)[0]; return &base_level.GetFaceFVarValues(face_index, channel)[0];
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Internal helpers. // Internal helpers.
static void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner)
{
topology_refiner->getSubdivisionLevel = getSubdivisionLevel;
topology_refiner->getIsAdaptive = getIsAdaptive;
// Basic topology information.
topology_refiner->getNumVertices = getNumVertices;
topology_refiner->getNumEdges = getNumEdges;
topology_refiner->getNumFaces = getNumFaces;
topology_refiner->getNumFaceVertices = getNumFaceVertices;
topology_refiner->getFaceVertices = getFaceVertices;
topology_refiner->getNumFaceEdges = getNumFaceEdges;
topology_refiner->getFaceEdges = getFaceEdges;
topology_refiner->getEdgeVertices = getEdgeVertices;
topology_refiner->getNumVertexEdges = getNumVertexEdges;
topology_refiner->getVertexEdges = getVertexEdges;
// PTex face geometry.
topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces;
topology_refiner->getNumPtexFaces = getNumPtexFaces;
topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset;
// Face-varying data.
topology_refiner->getNumFVarChannels = getNumFVarChannels;
topology_refiner->getFVarLinearInterpolation = getFVarLinearInterpolation;
topology_refiner->getNumFVarValues = getNumFVarValues;
topology_refiner->getFaceFVarValueIndices = getFaceFVarValueIndices;
}
static OpenSubdiv_TopologyRefiner *allocateTopologyRefiner()
{
OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__);
assignFunctionPointers(topology_refiner);
return topology_refiner;
}
OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter( OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings) OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings)
{ {
@ -229,7 +182,7 @@ OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
return nullptr; return nullptr;
} }
OpenSubdiv_TopologyRefiner *topology_refiner = allocateTopologyRefiner(); OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__);
topology_refiner->impl = static_cast<OpenSubdiv_TopologyRefinerImpl *>(topology_refiner_impl); topology_refiner->impl = static_cast<OpenSubdiv_TopologyRefinerImpl *>(topology_refiner_impl);
return topology_refiner; return topology_refiner;

@ -12,7 +12,7 @@ struct OpenSubdiv_EvaluatorCacheImpl;
struct OpenSubdiv_EvaluatorImpl; struct OpenSubdiv_EvaluatorImpl;
struct OpenSubdiv_EvaluatorInternal; struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord; struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner; class OpenSubdiv_TopologyRefiner;
struct OpenSubdiv_EvaluatorSettings { struct OpenSubdiv_EvaluatorSettings {
// Number of smoothly interpolated vertex data channels. // Number of smoothly interpolated vertex data channels.

@ -25,10 +25,11 @@ struct OpenSubdiv_TopologyRefinerSettings {
// //
// The only purpose is to allow C-only code to access C++ implementation of the // The only purpose is to allow C-only code to access C++ implementation of the
// topology refiner. // topology refiner.
struct OpenSubdiv_TopologyRefiner { class OpenSubdiv_TopologyRefiner {
public:
// Query subdivision level the refiner is created for. // Query subdivision level the refiner is created for.
int (*getSubdivisionLevel)(const OpenSubdiv_TopologyRefiner *topology_refiner); int getSubdivisionLevel() const;
bool (*getIsAdaptive)(const OpenSubdiv_TopologyRefiner *topology_refiner); bool getIsAdaptive() const;
// NOTE: All queries are querying base level. // NOTE: All queries are querying base level.
// //
@ -40,29 +41,19 @@ struct OpenSubdiv_TopologyRefiner {
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Query basic topology information from base level. // Query basic topology information from base level.
int (*getNumVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner); int getNumVertices() const;
int (*getNumEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner); int getNumEdges() const;
int (*getNumFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner); int getNumFaces() const;
int (*getNumFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner, int getNumFaceVertices(int face_index) const;
const int face_index); void getFaceVertices(int face_index, int *face_vertices_indices) const;
void (*getFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_vertices_indices);
int (*getNumFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index); int getNumFaceEdges(int face_index) const;
void (*getFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner, void getFaceEdges(int face_index, int *face_edges_indices) const;
const int face_index, void getEdgeVertices(int edge_index, int edge_vertices_indices[2]) const;
int *face_edges_indices);
void (*getEdgeVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int edge_index,
int edge_vertices_indices[2]);
int (*getNumVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner, int getNumVertexEdges(int vertex_index) const;
const int vertex_index); void getVertexEdges(int vertex_index, int *vertex_edges_indices) const;
void (*getVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index,
int *vertex_edges_indices);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// PTex face geometry queries. // PTex face geometry queries.
@ -74,9 +65,8 @@ struct OpenSubdiv_TopologyRefiner {
// - Quad face consists of a single ptex face. // - Quad face consists of a single ptex face.
// - N-gons (similar to triangle) consists of N ptex faces, ordered same // - N-gons (similar to triangle) consists of N ptex faces, ordered same
// way as for triangle. // way as for triangle.
int (*getNumFacePtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner, int getNumFacePtexFaces(int face_index) const;
const int face_index); int getNumPtexFaces() const;
int (*getNumPtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner);
// Initialize a per-base-face offset measured in ptex face indices. // Initialize a per-base-face offset measured in ptex face indices.
// //
@ -84,26 +74,22 @@ struct OpenSubdiv_TopologyRefiner {
// faces created for bases faces [0 .. base_face_index - 1]. // faces created for bases faces [0 .. base_face_index - 1].
// //
// The array must contain at least total number of ptex faces elements. // The array must contain at least total number of ptex faces elements.
void (*fillFacePtexIndexOffset)(const OpenSubdiv_TopologyRefiner *topology_refiner, void fillFacePtexIndexOffset(int *face_ptex_index_offset) const;
int *face_ptex_index_offset);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Face-varying data. // Face-varying data.
// Number of face-varying channels (or how they are called in Blender layers). // Number of face-varying channels (or how they are called in Blender layers).
int (*getNumFVarChannels)(const OpenSubdiv_TopologyRefiner *topology_refiner); int getNumFVarChannels() const;
// Get face-varying interpolation type. // Get face-varying interpolation type.
OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)( OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation() const;
const OpenSubdiv_TopologyRefiner *topology_refiner);
// Get total number of face-varying values in a particular channel. // Get total number of face-varying values in a particular channel.
int (*getNumFVarValues)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int channel); int getNumFVarValues(int channel) const;
// Get face-varying value indices associated with a particular face. // Get face-varying value indices associated with a particular face.
// //
// This is an array of indices inside of face-varying array, array elements // This is an array of indices inside of face-varying array, array elements
// are aligned with face corners (or loops in Blender terminology). // are aligned with face corners (or loops in Blender terminology).
const int *(*getFaceFVarValueIndices)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int *getFaceFVarValueIndices(int face_index, int channel) const;
const int face_index,
const int channel);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Internal use. // Internal use.

@ -9,7 +9,7 @@
#include <cstddef> #include <cstddef>
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/, OpenSubdiv_TopologyRefiner * /*topology_refiner*/,
eOpenSubdivEvaluator /*evaluator_type*/, eOpenSubdivEvaluator /*evaluator_type*/,
OpenSubdiv_EvaluatorCache * /*evaluator_cache*/) OpenSubdiv_EvaluatorCache * /*evaluator_cache*/)
{ {

@ -15,7 +15,7 @@ struct Mesh;
struct MultiresModifierData; struct MultiresModifierData;
struct OpenSubdiv_Converter; struct OpenSubdiv_Converter;
struct OpenSubdiv_Evaluator; struct OpenSubdiv_Evaluator;
struct OpenSubdiv_TopologyRefiner; class OpenSubdiv_TopologyRefiner;
namespace blender::bke::subdiv { namespace blender::bke::subdiv {

@ -205,24 +205,29 @@ void free(Subdiv *subdiv)
int *face_ptex_offset_get(Subdiv *subdiv) int *face_ptex_offset_get(Subdiv *subdiv)
{ {
#ifdef WITH_OPENSUBDIV
if (subdiv->cache_.face_ptex_offset != nullptr) { if (subdiv->cache_.face_ptex_offset != nullptr) {
return subdiv->cache_.face_ptex_offset; return subdiv->cache_.face_ptex_offset;
} }
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
if (topology_refiner == nullptr) { if (topology_refiner == nullptr) {
return nullptr; return nullptr;
} }
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner); const int num_coarse_faces = topology_refiner->getNumFaces();
subdiv->cache_.face_ptex_offset = static_cast<int *>( subdiv->cache_.face_ptex_offset = static_cast<int *>(
MEM_malloc_arrayN(num_coarse_faces + 1, sizeof(int), __func__)); MEM_malloc_arrayN(num_coarse_faces + 1, sizeof(int), __func__));
int ptex_offset = 0; int ptex_offset = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) { for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(face_index);
subdiv->cache_.face_ptex_offset[face_index] = ptex_offset; subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
ptex_offset += num_ptex_faces; ptex_offset += num_ptex_faces;
} }
subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset; subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
return subdiv->cache_.face_ptex_offset; return subdiv->cache_.face_ptex_offset;
#else
UNUSED_VARS(subdiv);
return nullptr;
#endif
} }
} // namespace blender::bke::subdiv } // namespace blender::bke::subdiv

@ -44,6 +44,8 @@ using namespace blender::bke::subdiv;
/** \name Various forward declarations /** \name Various forward declarations
* \{ */ * \{ */
#ifdef WITH_OPENSUBDIV
static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg, static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
const CCGKey &key, const CCGKey &key,
const IndexRange face); const IndexRange face);
@ -116,10 +118,10 @@ static void subdiv_ccg_init_layers(SubdivCCG &subdiv_ccg, const SubdivToCCGSetti
/* TODO(sergey): Make it more accessible function. */ /* TODO(sergey): Make it more accessible function. */
static int topology_refiner_count_face_corners(OpenSubdiv_TopologyRefiner *topology_refiner) static int topology_refiner_count_face_corners(OpenSubdiv_TopologyRefiner *topology_refiner)
{ {
const int num_faces = topology_refiner->getNumFaces(topology_refiner); const int num_faces = topology_refiner->getNumFaces();
int num_corners = 0; int num_corners = 0;
for (int face_index = 0; face_index < num_faces; face_index++) { for (int face_index = 0; face_index < num_faces; face_index++) {
num_corners += topology_refiner->getNumFaceVertices(topology_refiner, face_index); num_corners += topology_refiner->getNumFaceVertices(face_index);
} }
return num_corners; return num_corners;
} }
@ -267,7 +269,7 @@ static bool subdiv_ccg_evaluate_grids(SubdivCCG &subdiv_ccg,
{ {
using namespace blender; using namespace blender;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv.topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv.topology_refiner;
const int num_faces = topology_refiner->getNumFaces(topology_refiner); const int num_faces = topology_refiner->getNumFaces();
const Span<int> face_ptex_offset(face_ptex_offset_get(&subdiv), subdiv_ccg.faces.size()); const Span<int> face_ptex_offset(face_ptex_offset_get(&subdiv), subdiv_ccg.faces.size());
threading::parallel_for(IndexRange(num_faces), 1024, [&](const IndexRange range) { threading::parallel_for(IndexRange(num_faces), 1024, [&](const IndexRange range) {
for (const int face_index : range) { for (const int face_index : range) {
@ -331,7 +333,7 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG &subdiv_ccg)
Subdiv *subdiv = subdiv_ccg.subdiv; Subdiv *subdiv = subdiv_ccg.subdiv;
const OffsetIndices<int> faces = subdiv_ccg.faces; const OffsetIndices<int> faces = subdiv_ccg.faces;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
const int num_edges = topology_refiner->getNumEdges(topology_refiner); const int num_edges = topology_refiner->getNumEdges();
const int grid_size = subdiv_ccg.grid_size; const int grid_size = subdiv_ccg.grid_size;
if (num_edges == 0) { if (num_edges == 0) {
/* Early output, nothing to do in this case. */ /* Early output, nothing to do in this case. */
@ -346,17 +348,17 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG &subdiv_ccg)
const IndexRange face = faces[face_index]; const IndexRange face = faces[face_index];
const int num_face_grids = face.size(); const int num_face_grids = face.size();
face_vertices.reinitialize(num_face_grids); face_vertices.reinitialize(num_face_grids);
topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices.data()); topology_refiner->getFaceVertices(face_index, face_vertices.data());
/* Note that order of edges is same as order of MLoops, which also /* Note that order of edges is same as order of MLoops, which also
* means it's the same as order of grids. */ * means it's the same as order of grids. */
face_edges.reinitialize(num_face_grids); face_edges.reinitialize(num_face_grids);
topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges.data()); topology_refiner->getFaceEdges(face_index, face_edges.data());
/* Store grids adjacency for this edge. */ /* Store grids adjacency for this edge. */
for (int corner = 0; corner < num_face_grids; corner++) { for (int corner = 0; corner < num_face_grids; corner++) {
const int vertex_index = face_vertices[corner]; const int vertex_index = face_vertices[corner];
const int edge_index = face_edges[corner]; const int edge_index = face_edges[corner];
int edge_vertices[2]; int edge_vertices[2];
topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices); topology_refiner->getEdgeVertices(edge_index, edge_vertices);
const bool is_edge_flipped = (edge_vertices[0] != vertex_index); const bool is_edge_flipped = (edge_vertices[0] != vertex_index);
/* Grid which is adjacent to the current corner. */ /* Grid which is adjacent to the current corner. */
const int current_grid_index = face.start() + corner; const int current_grid_index = face.start() + corner;
@ -417,7 +419,7 @@ static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG &subdiv_ccg)
Subdiv *subdiv = subdiv_ccg.subdiv; Subdiv *subdiv = subdiv_ccg.subdiv;
const OffsetIndices<int> faces = subdiv_ccg.faces; const OffsetIndices<int> faces = subdiv_ccg.faces;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
const int num_vertices = topology_refiner->getNumVertices(topology_refiner); const int num_vertices = topology_refiner->getNumVertices();
const int grid_size = subdiv_ccg.grid_size; const int grid_size = subdiv_ccg.grid_size;
if (num_vertices == 0) { if (num_vertices == 0) {
/* Early output, nothing to do in this case. */ /* Early output, nothing to do in this case. */
@ -430,7 +432,7 @@ static void subdiv_ccg_init_faces_vertex_neighborhood(SubdivCCG &subdiv_ccg)
const IndexRange face = faces[face_index]; const IndexRange face = faces[face_index];
const int num_face_grids = face.size(); const int num_face_grids = face.size();
face_vertices.reinitialize(num_face_grids); face_vertices.reinitialize(num_face_grids);
topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices.data()); topology_refiner->getFaceVertices(face_index, face_vertices.data());
for (int corner = 0; corner < num_face_grids; corner++) { for (int corner = 0; corner < num_face_grids; corner++) {
const int vertex_index = face_vertices[corner]; const int vertex_index = face_vertices[corner];
/* Grid which is adjacent to the current corner. */ /* Grid which is adjacent to the current corner. */
@ -449,6 +451,8 @@ static void subdiv_ccg_init_faces_neighborhood(SubdivCCG &subdiv_ccg)
subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg); subdiv_ccg_init_faces_vertex_neighborhood(subdiv_ccg);
} }
#endif
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -460,6 +464,7 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
const Mesh &coarse_mesh, const Mesh &coarse_mesh,
SubdivCCGMaskEvaluator *mask_evaluator) SubdivCCGMaskEvaluator *mask_evaluator)
{ {
#ifdef WITH_OPENSUBDIV
stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG); stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
std::unique_ptr<SubdivCCG> subdiv_ccg = std::make_unique<SubdivCCG>(); std::unique_ptr<SubdivCCG> subdiv_ccg = std::make_unique<SubdivCCG>();
subdiv_ccg->subdiv = &subdiv; subdiv_ccg->subdiv = &subdiv;
@ -476,6 +481,10 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
} }
stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG); stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
return subdiv_ccg; return subdiv_ccg;
#else
UNUSED_VARS(subdiv, settings, coarse_mesh, mask_evaluator);
return {};
#endif
} }
Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv, Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
@ -527,6 +536,7 @@ SubdivCCG::~SubdivCCG()
CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level) CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level)
{ {
#ifdef WITH_OPENSUBDIV
CCGKey key; CCGKey key;
key.level = level; key.level = level;
key.elem_size = element_size_bytes_get(subdiv_ccg); key.elem_size = element_size_bytes_get(subdiv_ccg);
@ -540,6 +550,10 @@ CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level)
key.has_normals = subdiv_ccg.has_normal; key.has_normals = subdiv_ccg.has_normal;
key.has_mask = subdiv_ccg.has_mask; key.has_mask = subdiv_ccg.has_mask;
return key; return key;
#else
UNUSED_VARS(subdiv_ccg, level);
return {};
#endif
} }
CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg) CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
@ -553,6 +567,8 @@ CCGKey BKE_subdiv_ccg_key_top_level(const SubdivCCG &subdiv_ccg)
/** \name Normals /** \name Normals
* \{ */ * \{ */
#ifdef WITH_OPENSUBDIV
/* Evaluate high-res face normals, for faces which corresponds to grid elements /* Evaluate high-res face normals, for faces which corresponds to grid elements
* *
* {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}} * {(x, y), {x + 1, y}, {x + 1, y + 1}, {x, y + 1}}
@ -649,18 +665,25 @@ static void subdiv_ccg_recalc_inner_grid_normals(SubdivCCG &subdiv_ccg, const In
}); });
} }
#endif
void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg) void BKE_subdiv_ccg_recalc_normals(SubdivCCG &subdiv_ccg)
{ {
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) { if (!subdiv_ccg.has_normal) {
/* Grids don't have normals, can do early output. */ /* Grids don't have normals, can do early output. */
return; return;
} }
subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg, subdiv_ccg.faces.index_range()); subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg, subdiv_ccg.faces.index_range());
BKE_subdiv_ccg_average_grids(subdiv_ccg); BKE_subdiv_ccg_average_grids(subdiv_ccg);
#else
UNUSED_VARS(subdiv_ccg);
#endif
} }
void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask) void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
{ {
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) { if (!subdiv_ccg.has_normal) {
/* Grids don't have normals, can do early output. */ /* Grids don't have normals, can do early output. */
return; return;
@ -673,6 +696,9 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg); const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
subdiv_ccg_average_faces_boundaries_and_corners(subdiv_ccg, key, face_mask); subdiv_ccg_average_faces_boundaries_and_corners(subdiv_ccg, key, face_mask);
#else
UNUSED_VARS(subdiv_ccg, face_mask);
#endif
} }
/** \} */ /** \} */
@ -681,6 +707,8 @@ void BKE_subdiv_ccg_update_normals(SubdivCCG &subdiv_ccg, const IndexMask &face_
/** \name Boundary averaging/stitching /** \name Boundary averaging/stitching
* \{ */ * \{ */
#ifdef WITH_OPENSUBDIV
static void average_grid_element_value_v3(float a[3], float b[3]) static void average_grid_element_value_v3(float a[3], float b[3])
{ {
add_v3_v3(a, b); add_v3_v3(a, b);
@ -886,8 +914,11 @@ static void subdiv_ccg_average_corners(SubdivCCG &subdiv_ccg,
}); });
} }
#endif
void BKE_subdiv_ccg_average_grids(SubdivCCG &subdiv_ccg) void BKE_subdiv_ccg_average_grids(SubdivCCG &subdiv_ccg)
{ {
#ifdef WITH_OPENSUBDIV
using namespace blender; using namespace blender;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg); const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
/* Average inner boundaries of grids (within one face), across faces /* Average inner boundaries of grids (within one face), across faces
@ -895,8 +926,13 @@ void BKE_subdiv_ccg_average_grids(SubdivCCG &subdiv_ccg)
BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, subdiv_ccg.faces.index_range()); BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, subdiv_ccg.faces.index_range());
subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range()); subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range());
subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range()); subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range());
#else
UNUSED_VARS(subdiv_ccg);
#endif
} }
#ifdef WITH_OPENSUBDIV
static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg, static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg,
const IndexMask &face_mask, const IndexMask &face_mask,
blender::Set<int> &adjacent_verts, blender::Set<int> &adjacent_verts,
@ -911,11 +947,11 @@ static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg,
face_mask.foreach_index([&](const int face_index) { face_mask.foreach_index([&](const int face_index) {
const int num_face_grids = subdiv_ccg.faces[face_index].size(); const int num_face_grids = subdiv_ccg.faces[face_index].size();
face_vertices.reinitialize(num_face_grids); face_vertices.reinitialize(num_face_grids);
topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices.data()); topology_refiner->getFaceVertices(face_index, face_vertices.data());
adjacent_verts.add_multiple(face_vertices); adjacent_verts.add_multiple(face_vertices);
face_edges.reinitialize(num_face_grids); face_edges.reinitialize(num_face_grids);
topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges.data()); topology_refiner->getFaceEdges(face_index, face_edges.data());
adjacent_edges.add_multiple(face_edges); adjacent_edges.add_multiple(face_edges);
}); });
} }
@ -942,8 +978,11 @@ void subdiv_ccg_average_faces_boundaries_and_corners(SubdivCCG &subdiv_ccg,
subdiv_ccg, key, IndexMask::from_indices(adjacent_verts.as_span(), memory)); subdiv_ccg, key, IndexMask::from_indices(adjacent_verts.as_span(), memory));
} }
#endif
void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask &face_mask) void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
{ {
#ifdef WITH_OPENSUBDIV
using namespace blender; using namespace blender;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg); const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
face_mask.foreach_index(GrainSize(512), [&](const int face_index) { face_mask.foreach_index(GrainSize(512), [&](const int face_index) {
@ -953,6 +992,9 @@ void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask
* faces. */ * faces. */
subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range()); subdiv_ccg_average_boundaries(subdiv_ccg, key, subdiv_ccg.adjacent_edges.index_range());
subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range()); subdiv_ccg_average_corners(subdiv_ccg, key, subdiv_ccg.adjacent_verts.index_range());
#else
UNUSED_VARS(subdiv_ccg, face_mask);
#endif
} }
void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg, void BKE_subdiv_ccg_topology_counters(const SubdivCCG &subdiv_ccg,
@ -1072,6 +1114,8 @@ BLI_INLINE SubdivCCGCoord coord_at_next_col(const SubdivCCG &subdiv_ccg,
return result; return result;
} }
#ifdef WITH_OPENSUBDIV
/* For the input coordinate which is at the boundary of the grid do one step inside. */ /* For the input coordinate which is at the boundary of the grid do one step inside. */
static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG &subdiv_ccg, static SubdivCCGCoord coord_step_inside_from_boundary(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord) const SubdivCCGCoord &coord)
@ -1160,7 +1204,7 @@ static int adjacent_vertex_index_from_coord(const SubdivCCG &subdiv_ccg,
const int num_face_grids = face.size(); const int num_face_grids = face.size();
Array<int, 64> face_vertices(num_face_grids); Array<int, 64> face_vertices(num_face_grids);
topology_refiner->getFaceVertices(topology_refiner, face_index, face_vertices.data()); topology_refiner->getFaceVertices(face_index, face_vertices.data());
const int adjacent_vertex_index = face_vertices[face_grid_index]; const int adjacent_vertex_index = face_vertices[face_grid_index];
return adjacent_vertex_index; return adjacent_vertex_index;
@ -1176,8 +1220,7 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner, const int num_vertex_edges = topology_refiner->getNumVertexEdges(adjacent_vertex_index);
adjacent_vertex_index);
const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[adjacent_vertex_index]; const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[adjacent_vertex_index];
const int num_adjacent_faces = adjacent_vert.num_adjacent_faces; const int num_adjacent_faces = adjacent_vert.num_adjacent_faces;
@ -1186,7 +1229,7 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0); r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0);
Array<int, 64> vertex_edges(num_vertex_edges); Array<int, 64> vertex_edges(num_vertex_edges);
topology_refiner->getVertexEdges(topology_refiner, adjacent_vertex_index, vertex_edges.data()); topology_refiner->getVertexEdges(adjacent_vertex_index, vertex_edges.data());
for (int i = 0; i < num_vertex_edges; ++i) { for (int i = 0; i < num_vertex_edges; ++i) {
const int edge_index = vertex_edges[i]; const int edge_index = vertex_edges[i];
@ -1196,7 +1239,7 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
/* Depending edge orientation we use first (zero-based) or previous-to-last point. */ /* Depending edge orientation we use first (zero-based) or previous-to-last point. */
int edge_vertices_indices[2]; int edge_vertices_indices[2];
topology_refiner->getEdgeVertices(topology_refiner, edge_index, edge_vertices_indices); topology_refiner->getEdgeVertices(edge_index, edge_vertices_indices);
int edge_point_index, duplicate_edge_point_index; int edge_point_index, duplicate_edge_point_index;
if (edge_vertices_indices[0] == adjacent_vertex_index) { if (edge_vertices_indices[0] == adjacent_vertex_index) {
duplicate_edge_point_index = 0; duplicate_edge_point_index = 0;
@ -1233,10 +1276,10 @@ static int adjacent_edge_index_from_coord(const SubdivCCG &subdiv_ccg, const Sub
const int face_index = subdiv_ccg.grid_to_face_map[coord.grid_index]; const int face_index = subdiv_ccg.grid_to_face_map[coord.grid_index];
const IndexRange face = subdiv_ccg.faces[face_index]; const IndexRange face = subdiv_ccg.faces[face_index];
const int face_grid_index = coord.grid_index - face.start(); const int face_grid_index = coord.grid_index - face.start();
const int num_face_edges = topology_refiner->getNumFaceEdges(topology_refiner, face_index); const int num_face_edges = topology_refiner->getNumFaceEdges(face_index);
Array<int, 64> face_edges(num_face_edges); Array<int, 64> face_edges(num_face_edges);
topology_refiner->getFaceEdges(topology_refiner, face_index, face_edges.data()); topology_refiner->getFaceEdges(face_index, face_edges.data());
const int grid_size_1 = subdiv_ccg.grid_size - 1; const int grid_size_1 = subdiv_ccg.grid_size - 1;
int adjacent_edge_index = -1; int adjacent_edge_index = -1;
@ -1260,7 +1303,7 @@ static int adjacent_edge_point_index_from_coord(const SubdivCCG &subdiv_ccg,
const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord); const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
int edge_vertices_indices[2]; int edge_vertices_indices[2];
topology_refiner->getEdgeVertices(topology_refiner, adjacent_edge_index, edge_vertices_indices); topology_refiner->getEdgeVertices(adjacent_edge_index, edge_vertices_indices);
/* Vertex index of an edge which is used to see whether edge points in the right direction. /* Vertex index of an edge which is used to see whether edge points in the right direction.
* Tricky part here is that depending whether input coordinate is are maximum X or Y coordinate * Tricky part here is that depending whether input coordinate is are maximum X or Y coordinate
@ -1488,11 +1531,14 @@ static void neighbor_coords_inner_get(const SubdivCCG &subdiv_ccg,
r_neighbors.coords[3] = coord_at_next_col(subdiv_ccg, coord); r_neighbors.coords[3] = coord_at_next_col(subdiv_ccg, coord);
} }
#endif
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg, void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord, const SubdivCCGCoord &coord,
const bool include_duplicates, const bool include_duplicates,
SubdivCCGNeighbors &r_neighbors) SubdivCCGNeighbors &r_neighbors)
{ {
#ifdef WITH_OPENSUBDIV
BLI_assert(coord.grid_index >= 0); BLI_assert(coord.grid_index >= 0);
BLI_assert(coord.grid_index < subdiv_ccg.grids.size()); BLI_assert(coord.grid_index < subdiv_ccg.grids.size());
BLI_assert(coord.x >= 0); BLI_assert(coord.x >= 0);
@ -1510,15 +1556,19 @@ void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors); neighbor_coords_inner_get(subdiv_ccg, coord, r_neighbors);
} }
#ifndef NDEBUG # ifndef NDEBUG
for (const int i : r_neighbors.coords.index_range()) { for (const int i : r_neighbors.coords.index_range()) {
BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, r_neighbors.coords[i])); BLI_assert(BKE_subdiv_ccg_check_coord_valid(subdiv_ccg, r_neighbors.coords[i]));
} }
# endif
#else
UNUSED_VARS(subdiv_ccg, coord, include_duplicates, r_neighbors);
#endif #endif
} }
const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg) const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg)
{ {
#ifdef WITH_OPENSUBDIV
if (subdiv_ccg.cache_.start_face_grid_index.is_empty()) { if (subdiv_ccg.cache_.start_face_grid_index.is_empty()) {
const Subdiv *subdiv = subdiv_ccg.subdiv; const Subdiv *subdiv = subdiv_ccg.subdiv;
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
@ -1526,18 +1576,18 @@ const int *BKE_subdiv_ccg_start_face_grid_index_ensure(SubdivCCG &subdiv_ccg)
return nullptr; return nullptr;
} }
const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner); const int num_coarse_faces = topology_refiner->getNumFaces();
subdiv_ccg.cache_.start_face_grid_index.reinitialize(num_coarse_faces); subdiv_ccg.cache_.start_face_grid_index.reinitialize(num_coarse_faces);
int start_grid_index = 0; int start_grid_index = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) { for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_face_grids = topology_refiner->getNumFaceVertices(topology_refiner, const int num_face_grids = topology_refiner->getNumFaceVertices(face_index);
face_index);
subdiv_ccg.cache_.start_face_grid_index[face_index] = start_grid_index; subdiv_ccg.cache_.start_face_grid_index[face_index] = start_grid_index;
start_grid_index += num_face_grids; start_grid_index += num_face_grids;
} }
} }
#endif
return subdiv_ccg.cache_.start_face_grid_index.data(); return subdiv_ccg.cache_.start_face_grid_index.data();
} }

@ -76,6 +76,8 @@ bool eval_begin(Subdiv *subdiv,
return true; return true;
} }
#ifdef WITH_OPENSUBDIV
static void set_coarse_positions(Subdiv *subdiv, static void set_coarse_positions(Subdiv *subdiv,
const Span<float3> positions, const Span<float3> positions,
const bke::LooseVertCache &verts_no_face) const bke::LooseVertCache &verts_no_face)
@ -124,9 +126,8 @@ static void set_face_varying_data_from_uv_task(void *__restrict userdata,
/* TODO(sergey): OpenSubdiv's C-API converter can change winding of /* TODO(sergey): OpenSubdiv's C-API converter can change winding of
* loops of a face, need to watch for that, to prevent wrong UVs assigned. * loops of a face, need to watch for that, to prevent wrong UVs assigned.
*/ */
const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); const int num_face_vertices = topology_refiner->getNumFaceVertices(face_index);
const int *uv_indices = topology_refiner->getFaceFVarValueIndices( const int *uv_indices = topology_refiner->getFaceFVarValueIndices(face_index, layer_index);
topology_refiner, face_index, layer_index);
for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) { for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) {
copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], *mluv); copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], *mluv);
} }
@ -139,10 +140,10 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
{ {
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
const int num_faces = topology_refiner->getNumFaces(topology_refiner); const int num_faces = topology_refiner->getNumFaces();
const float(*mluv)[2] = mloopuv; const float(*mluv)[2] = mloopuv;
const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index); const int num_fvar_values = topology_refiner->getNumFVarValues(layer_index);
/* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */ /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */
float(*buffer)[2] = static_cast<float(*)[2]>( float(*buffer)[2] = static_cast<float(*)[2]>(
MEM_mallocN(sizeof(float[2]) * num_fvar_values, __func__)); MEM_mallocN(sizeof(float[2]) * num_fvar_values, __func__));
@ -175,9 +176,9 @@ static void set_vertex_data_from_orco(Subdiv *subdiv, const Mesh *mesh)
CustomData_get_layer(&mesh->vert_data, CD_CLOTH_ORCO)); CustomData_get_layer(&mesh->vert_data, CD_CLOTH_ORCO));
if (orco || cloth_orco) { if (orco || cloth_orco) {
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
const int num_verts = topology_refiner->getNumVertices(topology_refiner); const int num_verts = topology_refiner->getNumVertices();
if (orco && cloth_orco) { if (orco && cloth_orco) {
/* Set one by one if have both. */ /* Set one by one if have both. */
@ -206,22 +207,30 @@ static void get_mesh_evaluator_settings(OpenSubdiv_EvaluatorSettings *settings,
(CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO) ? 3 : 0); (CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO) ? 3 : 0);
} }
#endif
bool eval_begin_from_mesh(Subdiv *subdiv, bool eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh, const Mesh *mesh,
const float (*coarse_vertex_cos)[3], const float (*coarse_vertex_cos)[3],
eSubdivEvaluatorType evaluator_type, eSubdivEvaluatorType evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache) OpenSubdiv_EvaluatorCache *evaluator_cache)
{ {
#ifdef WITH_OPENSUBDIV
OpenSubdiv_EvaluatorSettings settings = {0}; OpenSubdiv_EvaluatorSettings settings = {0};
get_mesh_evaluator_settings(&settings, mesh); get_mesh_evaluator_settings(&settings, mesh);
if (!eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) { if (!eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) {
return false; return false;
} }
return eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos); return eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
#else
UNUSED_VARS(subdiv, mesh, coarse_vertex_cos, evaluator_type, evaluator_cache);
return false;
#endif
} }
bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, const float (*coarse_vertex_cos)[3]) bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, const float (*coarse_vertex_cos)[3])
{ {
#ifdef WITH_OPENSUBDIV
if (subdiv->evaluator == nullptr) { if (subdiv->evaluator == nullptr) {
/* NOTE: This situation is supposed to be handled by begin(). */ /* NOTE: This situation is supposed to be handled by begin(). */
BLI_assert_msg(0, "Is not supposed to happen"); BLI_assert_msg(0, "Is not supposed to happen");
@ -249,6 +258,10 @@ bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, const float (*coars
subdiv->evaluator->refine(subdiv->evaluator); subdiv->evaluator->refine(subdiv->evaluator);
stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
return true; return true;
#else
UNUSED_VARS(subdiv, mesh, coarse_vertex_cos);
return false;
#endif
} }
void eval_init_displacement(Subdiv *subdiv) void eval_init_displacement(Subdiv *subdiv)

@ -16,8 +16,12 @@ namespace blender::bke::subdiv {
int topology_num_fvar_layers_get(const Subdiv *subdiv) int topology_num_fvar_layers_get(const Subdiv *subdiv)
{ {
#ifdef WITH_OPENSUBDIV
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner; OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
return topology_refiner->getNumFVarChannels(topology_refiner); return topology_refiner->getNumFVarChannels();
#else
return 0;
#endif
} }
} // namespace blender::bke::subdiv } // namespace blender::bke::subdiv