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 int num_face_varying_channels = refiner->GetNumFVarChannels();
const bool has_face_varying_data = (num_face_varying_channels != 0);
const int level = topology_refiner->getSubdivisionLevel(topology_refiner);
const bool is_adaptive = topology_refiner->getIsAdaptive(topology_refiner);
const int level = topology_refiner->getSubdivisionLevel();
const bool is_adaptive = topology_refiner->getIsAdaptive();
// Common settings for stencils and patches.
const bool stencil_generate_intermediate_levels = is_adaptive;
const bool stencil_generate_offsets = true;

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

@ -22,32 +22,32 @@ static const OpenSubdiv::Far::TopologyLevel &getOSDTopologyBaseLevel(
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.
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,
const int face_index)
int OpenSubdiv_TopologyRefiner::getNumFaceVertices(const int face_index) const
{
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner);
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetFaceVertices(face_index).size();
}
static void getFaceVertices(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_vertices_indices)
void OpenSubdiv_TopologyRefiner::getFaceVertices(const int face_index,
int *face_vertices_indices) const
{
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);
convertArrayToRaw(array, face_vertices_indices);
}
static int getNumFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index)
int OpenSubdiv_TopologyRefiner::getNumFaceEdges(const int face_index) const
{
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner);
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetFaceEdges(face_index).size();
}
static void getFaceEdges(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_edges_indices)
void OpenSubdiv_TopologyRefiner::getFaceEdges(const int face_index, int *face_edges_indices) const
{
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);
convertArrayToRaw(array, face_edges_indices);
}
static void getEdgeVertices(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int edge_index,
int edge_vertices_indices[2])
void OpenSubdiv_TopologyRefiner::getEdgeVertices(const int edge_index,
int edge_vertices_indices[2]) const
{
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);
assert(array.size() == 2);
edge_vertices_indices[0] = array[0];
edge_vertices_indices[1] = array[1];
}
static int getNumVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index)
int OpenSubdiv_TopologyRefiner::getNumVertexEdges(const int vertex_index) const
{
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner);
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetVertexEdges(vertex_index).size();
}
static void getVertexEdges(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index,
int *vertex_edges_indices)
void OpenSubdiv_TopologyRefiner::getVertexEdges(const int vertex_index,
int *vertex_edges_indices) const
{
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);
convertArrayToRaw(array, vertex_edges_indices);
}
static int getNumFacePtexFaces(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index)
int OpenSubdiv_TopologyRefiner::getNumFacePtexFaces(const int face_index) const
{
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) {
return 1;
}
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;
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;
}
static void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner *topology_refiner,
int *face_ptex_index_offset)
void OpenSubdiv_TopologyRefiner::fillFacePtexIndexOffset(int *face_ptex_index_offset) const
{
const int num_faces = topology_refiner->getNumFaces(topology_refiner);
const int num_faces = this->getNumFaces();
int num_ptex_faces = 0;
for (int face_index = 0; face_index < num_faces; ++face_index) {
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.
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();
}
static OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation(
const struct OpenSubdiv_TopologyRefiner *topology_refiner)
OpenSubdiv_FVarLinearInterpolation OpenSubdiv_TopologyRefiner::getFVarLinearInterpolation() const
{
return blender::opensubdiv::getCAPIFVarLinearInterpolationFromOSD(
getOSDTopologyRefiner(topology_refiner)->GetFVarLinearInterpolation());
getOSDTopologyRefiner(this)->GetFVarLinearInterpolation());
}
static int getNumFVarValues(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int channel)
int OpenSubdiv_TopologyRefiner::getNumFVarValues(const int channel) const
{
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(topology_refiner);
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
return base_level.GetNumFVarValues(channel);
}
static const int *getFaceFVarValueIndices(
const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
const int channel)
const int *OpenSubdiv_TopologyRefiner::getFaceFVarValueIndices(const int face_index,
const int channel) const
{
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];
}
////////////////////////////////////////////////////////////////////////////////
// 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_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings)
{
@ -229,7 +182,7 @@ OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
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);
return topology_refiner;

@ -12,7 +12,7 @@ struct OpenSubdiv_EvaluatorCacheImpl;
struct OpenSubdiv_EvaluatorImpl;
struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
class OpenSubdiv_TopologyRefiner;
struct OpenSubdiv_EvaluatorSettings {
// 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
// topology refiner.
struct OpenSubdiv_TopologyRefiner {
class OpenSubdiv_TopologyRefiner {
public:
// Query subdivision level the refiner is created for.
int (*getSubdivisionLevel)(const OpenSubdiv_TopologyRefiner *topology_refiner);
bool (*getIsAdaptive)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int getSubdivisionLevel() const;
bool getIsAdaptive() const;
// NOTE: All queries are querying base level.
//
@ -40,29 +41,19 @@ struct OpenSubdiv_TopologyRefiner {
//////////////////////////////////////////////////////////////////////////////
// Query basic topology information from base level.
int (*getNumVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int getNumVertices() const;
int getNumEdges() const;
int getNumFaces() const;
int (*getNumFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
void (*getFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_vertices_indices);
int getNumFaceVertices(int face_index) const;
void getFaceVertices(int face_index, int *face_vertices_indices) const;
int (*getNumFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index);
void (*getFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_edges_indices);
void (*getEdgeVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int edge_index,
int edge_vertices_indices[2]);
int getNumFaceEdges(int face_index) const;
void getFaceEdges(int face_index, int *face_edges_indices) const;
void getEdgeVertices(int edge_index, int edge_vertices_indices[2]) const;
int (*getNumVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index);
void (*getVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index,
int *vertex_edges_indices);
int getNumVertexEdges(int vertex_index) const;
void getVertexEdges(int vertex_index, int *vertex_edges_indices) const;
//////////////////////////////////////////////////////////////////////////////
// PTex face geometry queries.
@ -74,9 +65,8 @@ struct OpenSubdiv_TopologyRefiner {
// - Quad face consists of a single ptex face.
// - N-gons (similar to triangle) consists of N ptex faces, ordered same
// way as for triangle.
int (*getNumFacePtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
int (*getNumPtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int getNumFacePtexFaces(int face_index) const;
int getNumPtexFaces() const;
// 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].
//
// The array must contain at least total number of ptex faces elements.
void (*fillFacePtexIndexOffset)(const OpenSubdiv_TopologyRefiner *topology_refiner,
int *face_ptex_index_offset);
void fillFacePtexIndexOffset(int *face_ptex_index_offset) const;
//////////////////////////////////////////////////////////////////////////////
// Face-varying data.
// 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.
OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)(
const OpenSubdiv_TopologyRefiner *topology_refiner);
OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation() const;
// 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.
//
// This is an array of indices inside of face-varying array, array elements
// are aligned with face corners (or loops in Blender terminology).
const int *(*getFaceFVarValueIndices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
const int channel);
const int *getFaceFVarValueIndices(int face_index, int channel) const;
//////////////////////////////////////////////////////////////////////////////
// Internal use.

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

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

@ -205,24 +205,29 @@ void free(Subdiv *subdiv)
int *face_ptex_offset_get(Subdiv *subdiv)
{
#ifdef WITH_OPENSUBDIV
if (subdiv->cache_.face_ptex_offset != nullptr) {
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) {
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 *>(
MEM_malloc_arrayN(num_coarse_faces + 1, sizeof(int), __func__));
int ptex_offset = 0;
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;
ptex_offset += num_ptex_faces;
}
subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
return subdiv->cache_.face_ptex_offset;
#else
UNUSED_VARS(subdiv);
return nullptr;
#endif
}
} // namespace blender::bke::subdiv

@ -44,6 +44,8 @@ using namespace blender::bke::subdiv;
/** \name Various forward declarations
* \{ */
#ifdef WITH_OPENSUBDIV
static void subdiv_ccg_average_inner_face_grids(SubdivCCG &subdiv_ccg,
const CCGKey &key,
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. */
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;
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;
}
@ -267,7 +269,7 @@ static bool subdiv_ccg_evaluate_grids(SubdivCCG &subdiv_ccg,
{
using namespace blender;
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());
threading::parallel_for(IndexRange(num_faces), 1024, [&](const IndexRange 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;
const OffsetIndices<int> faces = subdiv_ccg.faces;
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;
if (num_edges == 0) {
/* 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 int num_face_grids = face.size();
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
* means it's the same as order of 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. */
for (int corner = 0; corner < num_face_grids; corner++) {
const int vertex_index = face_vertices[corner];
const int edge_index = face_edges[corner];
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);
/* Grid which is adjacent to the current 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;
const OffsetIndices<int> faces = subdiv_ccg.faces;
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;
if (num_vertices == 0) {
/* 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 int num_face_grids = face.size();
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++) {
const int vertex_index = face_vertices[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);
}
#endif
/** \} */
/* -------------------------------------------------------------------- */
@ -460,6 +464,7 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
const Mesh &coarse_mesh,
SubdivCCGMaskEvaluator *mask_evaluator)
{
#ifdef WITH_OPENSUBDIV
stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
std::unique_ptr<SubdivCCG> subdiv_ccg = std::make_unique<SubdivCCG>();
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);
return subdiv_ccg;
#else
UNUSED_VARS(subdiv, settings, coarse_mesh, mask_evaluator);
return {};
#endif
}
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)
{
#ifdef WITH_OPENSUBDIV
CCGKey key;
key.level = level;
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_mask = subdiv_ccg.has_mask;
return key;
#else
UNUSED_VARS(subdiv_ccg, level);
return {};
#endif
}
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
* \{ */
#ifdef WITH_OPENSUBDIV
/* Evaluate high-res face normals, for faces which corresponds to grid elements
*
* {(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)
{
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) {
/* Grids don't have normals, can do early output. */
return;
}
subdiv_ccg_recalc_inner_grid_normals(subdiv_ccg, subdiv_ccg.faces.index_range());
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)
{
#ifdef WITH_OPENSUBDIV
if (!subdiv_ccg.has_normal) {
/* Grids don't have normals, can do early output. */
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);
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
* \{ */
#ifdef WITH_OPENSUBDIV
static void average_grid_element_value_v3(float a[3], float b[3])
{
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)
{
#ifdef WITH_OPENSUBDIV
using namespace blender;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
/* 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());
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());
#else
UNUSED_VARS(subdiv_ccg);
#endif
}
#ifdef WITH_OPENSUBDIV
static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg,
const IndexMask &face_mask,
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) {
const int num_face_grids = subdiv_ccg.faces[face_index].size();
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);
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);
});
}
@ -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));
}
#endif
void BKE_subdiv_ccg_average_stitch_faces(SubdivCCG &subdiv_ccg, const IndexMask &face_mask)
{
#ifdef WITH_OPENSUBDIV
using namespace blender;
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
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. */
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());
#else
UNUSED_VARS(subdiv_ccg, face_mask);
#endif
}
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;
}
#ifdef WITH_OPENSUBDIV
/* 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,
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();
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];
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;
const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
const int num_vertex_edges = topology_refiner->getNumVertexEdges(topology_refiner,
adjacent_vertex_index);
const int num_vertex_edges = topology_refiner->getNumVertexEdges(adjacent_vertex_index);
const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[adjacent_vertex_index];
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);
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) {
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. */
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;
if (edge_vertices_indices[0] == adjacent_vertex_index) {
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 IndexRange face = subdiv_ccg.faces[face_index];
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);
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;
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);
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.
* 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);
}
#endif
void BKE_subdiv_ccg_neighbor_coords_get(const SubdivCCG &subdiv_ccg,
const SubdivCCGCoord &coord,
const bool include_duplicates,
SubdivCCGNeighbors &r_neighbors)
{
#ifdef WITH_OPENSUBDIV
BLI_assert(coord.grid_index >= 0);
BLI_assert(coord.grid_index < subdiv_ccg.grids.size());
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);
}
#ifndef NDEBUG
# ifndef NDEBUG
for (const int i : r_neighbors.coords.index_range()) {
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
}
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()) {
const Subdiv *subdiv = subdiv_ccg.subdiv;
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;
}
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);
int start_grid_index = 0;
for (int face_index = 0; face_index < num_coarse_faces; face_index++) {
const int num_face_grids = topology_refiner->getNumFaceVertices(topology_refiner,
face_index);
const int num_face_grids = topology_refiner->getNumFaceVertices(face_index);
subdiv_ccg.cache_.start_face_grid_index[face_index] = start_grid_index;
start_grid_index += num_face_grids;
}
}
#endif
return subdiv_ccg.cache_.start_face_grid_index.data();
}

@ -76,6 +76,8 @@ bool eval_begin(Subdiv *subdiv,
return true;
}
#ifdef WITH_OPENSUBDIV
static void set_coarse_positions(Subdiv *subdiv,
const Span<float3> positions,
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
* 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 *uv_indices = topology_refiner->getFaceFVarValueIndices(
topology_refiner, face_index, layer_index);
const int num_face_vertices = topology_refiner->getNumFaceVertices(face_index);
const int *uv_indices = topology_refiner->getFaceFVarValueIndices(face_index, layer_index);
for (int vertex_index = 0; vertex_index < num_face_vertices; 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_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 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. */
float(*buffer)[2] = static_cast<float(*)[2]>(
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));
if (orco || cloth_orco) {
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
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) {
/* 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);
}
#endif
bool eval_begin_from_mesh(Subdiv *subdiv,
const Mesh *mesh,
const float (*coarse_vertex_cos)[3],
eSubdivEvaluatorType evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache)
{
#ifdef WITH_OPENSUBDIV
OpenSubdiv_EvaluatorSettings settings = {0};
get_mesh_evaluator_settings(&settings, mesh);
if (!eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) {
return false;
}
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])
{
#ifdef WITH_OPENSUBDIV
if (subdiv->evaluator == nullptr) {
/* NOTE: This situation is supposed to be handled by begin(). */
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);
stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
return true;
#else
UNUSED_VARS(subdiv, mesh, coarse_vertex_cos);
return false;
#endif
}
void eval_init_displacement(Subdiv *subdiv)

@ -16,8 +16,12 @@ namespace blender::bke::subdiv {
int topology_num_fvar_layers_get(const Subdiv *subdiv)
{
#ifdef WITH_OPENSUBDIV
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