Subdiv: Remove topology refiner C-API wrapper
Remove the indirection previously used for the topology refiner to separate C and C++ code. Instead retrieve the base level in calling code and call opensubdiv API functions directly. This avoids copying arrays of mesh indices and should reduce function call overhead since index retrieval can now be inlined. It also lets us remove a lot of boilerplate shim code. The downside is increased need for WITH_OPENSUBDIV defines in various parts of blenkernel, but I think that is required to avoid the previous indirection and have the kernel deal with OpenSubdiv more directly. Pull Request: https://projects.blender.org/blender/blender/pulls/120825
This commit is contained in:
@@ -64,7 +64,6 @@ if(WITH_OPENSUBDIV)
|
||||
internal/topology/mesh_topology.cc
|
||||
internal/topology/mesh_topology_compare.cc
|
||||
internal/topology/mesh_topology.h
|
||||
internal/topology/topology_refiner_capi.cc
|
||||
internal/topology/topology_refiner_factory.cc
|
||||
internal/topology/topology_refiner_impl.cc
|
||||
internal/topology/topology_refiner_impl_compare.cc
|
||||
@@ -95,7 +94,6 @@ else()
|
||||
list(APPEND SRC
|
||||
stub/opensubdiv_stub.cc
|
||||
stub/opensubdiv_evaluator_stub.cc
|
||||
stub/opensubdiv_topology_refiner_stub.cc
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ static void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator)
|
||||
}
|
||||
|
||||
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner,
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner,
|
||||
eOpenSubdivEvaluator evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache)
|
||||
{
|
||||
|
||||
@@ -420,11 +420,11 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl()
|
||||
}
|
||||
|
||||
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner,
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner,
|
||||
eOpenSubdivEvaluator evaluator_type,
|
||||
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr)
|
||||
{
|
||||
TopologyRefiner *refiner = topology_refiner->impl->topology_refiner;
|
||||
TopologyRefiner *refiner = topology_refiner->topology_refiner;
|
||||
if (refiner == NULL) {
|
||||
// Happens on bad topology.
|
||||
return NULL;
|
||||
@@ -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();
|
||||
const bool is_adaptive = topology_refiner->getIsAdaptive();
|
||||
const int level = topology_refiner->settings.level;
|
||||
const bool is_adaptive = topology_refiner->settings.is_adaptive;
|
||||
// Common settings for stencils and patches.
|
||||
const bool stencil_generate_intermediate_levels = is_adaptive;
|
||||
const bool stencil_generate_offsets = true;
|
||||
|
||||
@@ -22,10 +22,10 @@ struct OpenSubdiv_Buffer;
|
||||
struct OpenSubdiv_EvaluatorCacheImpl;
|
||||
struct OpenSubdiv_EvaluatorSettings;
|
||||
struct OpenSubdiv_PatchCoord;
|
||||
class OpenSubdiv_TopologyRefiner;
|
||||
|
||||
namespace blender::opensubdiv {
|
||||
|
||||
class TopologyRefinerImpl;
|
||||
class PatchMap;
|
||||
|
||||
// Wrapper around implementation, which defines API which we are capable to
|
||||
@@ -197,7 +197,7 @@ struct OpenSubdiv_EvaluatorImpl {
|
||||
};
|
||||
|
||||
OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal(
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner,
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner,
|
||||
eOpenSubdivEvaluator evaluator_type,
|
||||
OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr);
|
||||
|
||||
|
||||
@@ -106,8 +106,12 @@ class MeshTopology {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Comparison.
|
||||
|
||||
// Check whether this topology refiner defines same topology as the given
|
||||
// converter.
|
||||
// Compare given topology with converter. Returns truth if topology
|
||||
// matches given converter, false otherwise.
|
||||
//
|
||||
// This allows users to construct converter (which is supposed to be cheap)
|
||||
// and compare with existing topology before going into more computationally
|
||||
// complicated parts of subdivision process.
|
||||
bool isEqualToConverter(const OpenSubdiv_Converter *converter) const;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2018 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* Author: Sergey Sharybin. */
|
||||
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "internal/base/type_convert.h"
|
||||
#include "internal/topology/topology_refiner_impl.h"
|
||||
|
||||
static const OpenSubdiv::Far::TopologyRefiner *getOSDTopologyRefiner(
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
{
|
||||
return topology_refiner->impl->topology_refiner;
|
||||
}
|
||||
|
||||
static const OpenSubdiv::Far::TopologyLevel &getOSDTopologyBaseLevel(
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
{
|
||||
return getOSDTopologyRefiner(topology_refiner)->GetLevel(0);
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getSubdivisionLevel() const
|
||||
{
|
||||
return this->impl->settings.level;
|
||||
}
|
||||
|
||||
bool OpenSubdiv_TopologyRefiner::getIsAdaptive() const
|
||||
{
|
||||
return this->impl->settings.is_adaptive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Query basic topology information from base level.
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumVertices() const
|
||||
{
|
||||
return getOSDTopologyBaseLevel(this).GetNumVertices();
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumEdges() const
|
||||
{
|
||||
return getOSDTopologyBaseLevel(this).GetNumEdges();
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFaces() const
|
||||
{
|
||||
return getOSDTopologyBaseLevel(this).GetNumFaces();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PTex face geometry queries.
|
||||
|
||||
static void convertArrayToRaw(const OpenSubdiv::Far::ConstIndexArray &array, int *raw_array)
|
||||
{
|
||||
for (int i = 0; i < array.size(); ++i) {
|
||||
raw_array[i] = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFaceVertices(const int face_index) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return base_level.GetFaceVertices(face_index).size();
|
||||
}
|
||||
|
||||
void OpenSubdiv_TopologyRefiner::getFaceVertices(const int face_index,
|
||||
int *face_vertices_indices) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceVertices(face_index);
|
||||
convertArrayToRaw(array, face_vertices_indices);
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFaceEdges(const int face_index) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return base_level.GetFaceEdges(face_index).size();
|
||||
}
|
||||
|
||||
void OpenSubdiv_TopologyRefiner::getFaceEdges(const int face_index, int *face_edges_indices) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
OpenSubdiv::Far::ConstIndexArray array = base_level.GetFaceEdges(face_index);
|
||||
convertArrayToRaw(array, face_edges_indices);
|
||||
}
|
||||
|
||||
void OpenSubdiv_TopologyRefiner::getEdgeVertices(const int edge_index,
|
||||
int edge_vertices_indices[2]) const
|
||||
{
|
||||
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];
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumVertexEdges(const int vertex_index) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return base_level.GetVertexEdges(vertex_index).size();
|
||||
}
|
||||
|
||||
void OpenSubdiv_TopologyRefiner::getVertexEdges(const int vertex_index,
|
||||
int *vertex_edges_indices) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
OpenSubdiv::Far::ConstIndexArray array = base_level.GetVertexEdges(vertex_index);
|
||||
convertArrayToRaw(array, vertex_edges_indices);
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFacePtexFaces(const int face_index) const
|
||||
{
|
||||
const int num_face_vertices = this->getNumFaceVertices(face_index);
|
||||
if (num_face_vertices == 4) {
|
||||
return 1;
|
||||
}
|
||||
return num_face_vertices;
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumPtexFaces() const
|
||||
{
|
||||
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 += this->getNumFacePtexFaces(face_index);
|
||||
}
|
||||
return num_ptex_faces;
|
||||
}
|
||||
|
||||
void OpenSubdiv_TopologyRefiner::fillFacePtexIndexOffset(int *face_ptex_index_offset) const
|
||||
{
|
||||
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 += this->getNumFacePtexFaces(face_index);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Face-varying data.
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFVarChannels() const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return base_level.GetNumFVarChannels();
|
||||
}
|
||||
|
||||
OpenSubdiv_FVarLinearInterpolation OpenSubdiv_TopologyRefiner::getFVarLinearInterpolation() const
|
||||
{
|
||||
return blender::opensubdiv::getCAPIFVarLinearInterpolationFromOSD(
|
||||
getOSDTopologyRefiner(this)->GetFVarLinearInterpolation());
|
||||
}
|
||||
|
||||
int OpenSubdiv_TopologyRefiner::getNumFVarValues(const int channel) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return base_level.GetNumFVarValues(channel);
|
||||
}
|
||||
|
||||
const int *OpenSubdiv_TopologyRefiner::getFaceFVarValueIndices(const int face_index,
|
||||
const int channel) const
|
||||
{
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = getOSDTopologyBaseLevel(this);
|
||||
return &base_level.GetFaceFVarValues(face_index, channel)[0];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal helpers.
|
||||
|
||||
OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
|
||||
OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings)
|
||||
{
|
||||
using blender::opensubdiv::TopologyRefinerImpl;
|
||||
|
||||
TopologyRefinerImpl *topology_refiner_impl = TopologyRefinerImpl::createFromConverter(converter,
|
||||
*settings);
|
||||
if (topology_refiner_impl == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__);
|
||||
topology_refiner->impl = static_cast<OpenSubdiv_TopologyRefinerImpl *>(topology_refiner_impl);
|
||||
|
||||
return topology_refiner;
|
||||
}
|
||||
|
||||
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
{
|
||||
delete topology_refiner->impl;
|
||||
MEM_delete(topology_refiner);
|
||||
}
|
||||
|
||||
bool openSubdiv_topologyRefinerCompareWithConverter(
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner, const OpenSubdiv_Converter *converter)
|
||||
{
|
||||
return topology_refiner->impl->isEqualToConverter(converter);
|
||||
}
|
||||
@@ -17,6 +17,16 @@
|
||||
#include "internal/topology/mesh_topology.h"
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
|
||||
// Those settings don't really belong to OpenSubdiv's topology refiner, but
|
||||
// we are keeping track of them on our side of topology refiner. This is to
|
||||
// make it possible to ensure we are not trying to abuse same OpenSubdiv's
|
||||
// topology refiner with different subdivision levels or with different
|
||||
// adaptive settings.
|
||||
struct OpenSubdiv_TopologyRefinerSettings {
|
||||
bool is_adaptive;
|
||||
int level;
|
||||
};
|
||||
|
||||
struct OpenSubdiv_Converter;
|
||||
|
||||
namespace blender::opensubdiv {
|
||||
@@ -31,6 +41,11 @@ class TopologyRefinerImpl {
|
||||
TopologyRefinerImpl();
|
||||
~TopologyRefinerImpl();
|
||||
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level() const
|
||||
{
|
||||
return topology_refiner->GetLevel(0);
|
||||
}
|
||||
|
||||
// Check whether this topology refiner defines same topology as the given
|
||||
// converter.
|
||||
// Covers options, geometry, and geometry tags.
|
||||
@@ -62,6 +77,4 @@ class TopologyRefinerImpl {
|
||||
|
||||
} // namespace blender::opensubdiv
|
||||
|
||||
struct OpenSubdiv_TopologyRefinerImpl : public blender::opensubdiv::TopologyRefinerImpl {};
|
||||
|
||||
#endif // OPENSUBDIV_TOPOLOGY_REFINER_IMPL_H_
|
||||
|
||||
@@ -12,7 +12,9 @@ struct OpenSubdiv_EvaluatorCacheImpl;
|
||||
struct OpenSubdiv_EvaluatorImpl;
|
||||
struct OpenSubdiv_EvaluatorInternal;
|
||||
struct OpenSubdiv_PatchCoord;
|
||||
class OpenSubdiv_TopologyRefiner;
|
||||
namespace blender::opensubdiv {
|
||||
class TopologyRefinerImpl;
|
||||
}
|
||||
|
||||
struct OpenSubdiv_EvaluatorSettings {
|
||||
// Number of smoothly interpolated vertex data channels.
|
||||
@@ -225,7 +227,7 @@ struct OpenSubdiv_EvaluatorCache {
|
||||
};
|
||||
|
||||
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner,
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner,
|
||||
eOpenSubdivEvaluator evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache);
|
||||
|
||||
|
||||
@@ -4,112 +4,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // for bool
|
||||
|
||||
#include "opensubdiv_capi_type.hh"
|
||||
|
||||
struct OpenSubdiv_Converter;
|
||||
struct OpenSubdiv_TopologyRefinerImpl;
|
||||
|
||||
// Those settings don't really belong to OpenSubdiv's topology refiner, but
|
||||
// we are keeping track of them on our side of topology refiner. This is to
|
||||
// make it possible to ensure we are not trying to abuse same OpenSubdiv's
|
||||
// topology refiner with different subdivision levels or with different
|
||||
// adaptive settings.
|
||||
struct OpenSubdiv_TopologyRefinerSettings {
|
||||
bool is_adaptive;
|
||||
int level;
|
||||
};
|
||||
|
||||
// C-style wrapper around actual topology refiner.
|
||||
//
|
||||
// The only purpose is to allow C-only code to access C++ implementation of the
|
||||
// topology refiner.
|
||||
class OpenSubdiv_TopologyRefiner {
|
||||
public:
|
||||
// Query subdivision level the refiner is created for.
|
||||
int getSubdivisionLevel() const;
|
||||
bool getIsAdaptive() const;
|
||||
|
||||
// NOTE: All queries are querying base level.
|
||||
//
|
||||
// TODO(sergey): Consider making it more obvious in function naming,
|
||||
// but since it's unlikely (or at least, will be uncommon use) for API
|
||||
// which queries final geometry, we should be fine with this name for
|
||||
// now.
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Query basic topology information from base level.
|
||||
|
||||
int getNumVertices() const;
|
||||
int getNumEdges() const;
|
||||
int getNumFaces() const;
|
||||
|
||||
int getNumFaceVertices(int face_index) const;
|
||||
void getFaceVertices(int face_index, int *face_vertices_indices) const;
|
||||
|
||||
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(int vertex_index) const;
|
||||
void getVertexEdges(int vertex_index, int *vertex_edges_indices) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// PTex face geometry queries.
|
||||
|
||||
// Ptex face corresponds to OpenSubdiv's internal "patch" and to Blender's
|
||||
// subdivision grid. The rule commes as:
|
||||
// - Triangle face consist of 3 ptex faces, ordered in the order of
|
||||
// face-vertices.
|
||||
// - 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(int face_index) const;
|
||||
int getNumPtexFaces() const;
|
||||
|
||||
// Initialize a per-base-face offset measured in ptex face indices.
|
||||
//
|
||||
// Basically, face_ptex_offset[base_face_index] is a total number of ptex
|
||||
// faces created for bases faces [0 .. base_face_index - 1].
|
||||
//
|
||||
// The array must contain at least total number of ptex faces elements.
|
||||
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;
|
||||
// Get face-varying interpolation type.
|
||||
OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation() const;
|
||||
// Get total number of face-varying values in a particular 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(int face_index, int channel) const;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Internal use.
|
||||
|
||||
// Implementation of the topology refiner.
|
||||
OpenSubdiv_TopologyRefinerImpl *impl;
|
||||
};
|
||||
|
||||
// NOTE: Will return NULL in cases of bad topology.
|
||||
// NOTE: Mesh without faces is considered a bad topology.
|
||||
OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
|
||||
OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings);
|
||||
|
||||
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner);
|
||||
|
||||
// Compare given topology refiner with converter. Returns truth if topology
|
||||
// refiner matches given converter, false otherwise.
|
||||
//
|
||||
// This allows users to construct converter (which is supposed to be cheap)
|
||||
// and compare with existing refiner before going into more computationally
|
||||
// complicated parts of subdivision process.
|
||||
bool openSubdiv_topologyRefinerCompareWithConverter(
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner, const OpenSubdiv_Converter *converter);
|
||||
#include "internal/topology/topology_refiner_impl.h"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <cstddef>
|
||||
|
||||
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
|
||||
OpenSubdiv_TopologyRefiner * /*topology_refiner*/,
|
||||
blender::opensubdiv::TopologyRefinerImpl * /*topology_refiner*/,
|
||||
eOpenSubdivEvaluator /*evaluator_type*/,
|
||||
OpenSubdiv_EvaluatorCache * /*evaluator_cache*/)
|
||||
{
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2018 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* Author: Sergey Sharybin. */
|
||||
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
|
||||
OpenSubdiv_Converter * /*converter*/, const OpenSubdiv_TopologyRefinerSettings * /*settings*/)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner * /*topology_refiner*/) {}
|
||||
|
||||
bool openSubdiv_topologyRefinerCompareWithConverter(
|
||||
const OpenSubdiv_TopologyRefiner * /*topology_refiner*/,
|
||||
const OpenSubdiv_Converter * /*converter*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -15,7 +15,9 @@ struct Mesh;
|
||||
struct MultiresModifierData;
|
||||
struct OpenSubdiv_Converter;
|
||||
struct OpenSubdiv_Evaluator;
|
||||
class OpenSubdiv_TopologyRefiner;
|
||||
namespace blender::opensubdiv {
|
||||
class TopologyRefinerImpl;
|
||||
}
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
@@ -159,7 +161,7 @@ struct Subdiv {
|
||||
/* Topology refiner includes all the glue logic to feed Blender side
|
||||
* topology to OpenSubdiv. It can be shared by both evaluator and GL mesh
|
||||
* drawer. */
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner;
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner;
|
||||
/* CPU side evaluator. */
|
||||
OpenSubdiv_Evaluator *evaluator;
|
||||
/* Optional displacement evaluator. */
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include "atomic_ops.h"
|
||||
#include "subdiv_converter.hh"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Local Structs
|
||||
* \{ */
|
||||
@@ -317,13 +319,13 @@ static int get_face_grid_index(const MultiresReshapeSmoothContext *reshape_smoot
|
||||
const Corner *first_corner = &reshape_smooth_context->geometry.corners[face->start_corner_index];
|
||||
const int grid_index = first_corner->grid_index;
|
||||
|
||||
#ifndef NDEBUG
|
||||
# ifndef NDEBUG
|
||||
for (int face_corner = 0; face_corner < face->num_corners; ++face_corner) {
|
||||
const int corner_index = face->start_corner_index + face_corner;
|
||||
const Corner *corner = &reshape_smooth_context->geometry.corners[corner_index];
|
||||
BLI_assert(corner->grid_index == grid_index);
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
|
||||
return grid_index;
|
||||
}
|
||||
@@ -1422,6 +1424,8 @@ static void evaluate_higher_grid_positions(
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -1431,6 +1435,7 @@ static void evaluate_higher_grid_positions(
|
||||
void multires_reshape_smooth_object_grids_with_details(
|
||||
const MultiresReshapeContext *reshape_context)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
|
||||
if (level_difference == 0) {
|
||||
/* Early output. */
|
||||
@@ -1458,11 +1463,15 @@ void multires_reshape_smooth_object_grids_with_details(
|
||||
evaluate_higher_grid_positions_with_details(&reshape_smooth_context);
|
||||
|
||||
context_free(&reshape_smooth_context);
|
||||
#else
|
||||
UNUSED_VARS(reshape_context);
|
||||
#endif
|
||||
}
|
||||
|
||||
void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_context,
|
||||
const eMultiresSubdivideModeType mode)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
const int level_difference = (reshape_context->top.level - reshape_context->reshape.level);
|
||||
if (level_difference == 0) {
|
||||
/* Early output. */
|
||||
@@ -1481,6 +1490,9 @@ void multires_reshape_smooth_object_grids(const MultiresReshapeContext *reshape_
|
||||
evaluate_higher_grid_positions(&reshape_smooth_context);
|
||||
|
||||
context_free(&reshape_smooth_context);
|
||||
#else
|
||||
UNUSED_VARS(reshape_context, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -51,6 +51,9 @@ blender::bke::subdiv::Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgrap
|
||||
subdiv::Settings subdiv_settings;
|
||||
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
|
||||
subdiv::Subdiv *subdiv = subdiv::new_from_mesh(&subdiv_settings, base_mesh);
|
||||
if (!subdiv) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!subdiv::eval_begin_from_mesh(
|
||||
subdiv, base_mesh, {}, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
@@ -164,6 +167,9 @@ bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *resh
|
||||
reshape_context->base_corner_edges = base_mesh->corner_edges();
|
||||
|
||||
reshape_context->subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
|
||||
if (!reshape_context->subdiv) {
|
||||
return false;
|
||||
}
|
||||
reshape_context->need_free_subdiv = true;
|
||||
|
||||
reshape_context->reshape.level = multires_get_level(
|
||||
@@ -205,6 +211,9 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
|
||||
reshape_context->base_corner_edges = base_mesh->corner_edges();
|
||||
|
||||
reshape_context->subdiv = multires_reshape_create_subdiv(depsgraph, object, mmd);
|
||||
if (!reshape_context->subdiv) {
|
||||
return false;
|
||||
}
|
||||
reshape_context->need_free_subdiv = true;
|
||||
|
||||
reshape_context->reshape.level = multires_get_level(
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "opensubdiv_converter_capi.hh"
|
||||
#include "subdiv_converter.hh"
|
||||
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
|
||||
static float simple_to_catmull_clark_get_edge_sharpness(const OpenSubdiv_Converter * /*converter*/,
|
||||
int /*manifold_edge_index*/)
|
||||
{
|
||||
@@ -58,8 +60,11 @@ static blender::bke::subdiv::Subdiv *subdiv_for_simple_to_catmull_clark(Object *
|
||||
return subdiv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void multires_do_versions_simple_to_catmull_clark(Object *object, MultiresModifierData *mmd)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
const Mesh *base_mesh = static_cast<const Mesh *>(object->data);
|
||||
if (base_mesh->corners_num == 0) {
|
||||
return;
|
||||
@@ -93,4 +98,7 @@ void multires_do_versions_simple_to_catmull_clark(Object *object, MultiresModifi
|
||||
multires_reshape_object_grids_to_tangent_displacement(&reshape_context);
|
||||
multires_reshape_context_free(&reshape_context);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(object, mmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
#include "opensubdiv_capi.hh"
|
||||
#include "opensubdiv_converter_capi.hh"
|
||||
#include "opensubdiv_evaluator_capi.hh"
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
#ifdef WITH_OPENVDB
|
||||
# include "opensubdiv_topology_refiner_capi.hh"
|
||||
#endif
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
@@ -97,16 +99,17 @@ bool settings_equal(const Settings *settings_a, const Settings *settings_b)
|
||||
|
||||
Subdiv *new_from_converter(const Settings *settings, OpenSubdiv_Converter *converter)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
SubdivStats stats;
|
||||
stats_init(&stats);
|
||||
stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
|
||||
OpenSubdiv_TopologyRefinerSettings topology_refiner_settings;
|
||||
topology_refiner_settings.level = settings->level;
|
||||
topology_refiner_settings.is_adaptive = settings->is_adaptive;
|
||||
OpenSubdiv_TopologyRefiner *osd_topology_refiner = nullptr;
|
||||
blender::opensubdiv::TopologyRefinerImpl *osd_topology_refiner = nullptr;
|
||||
if (converter->getNumVertices(converter) != 0) {
|
||||
osd_topology_refiner = openSubdiv_createTopologyRefinerFromConverter(
|
||||
converter, &topology_refiner_settings);
|
||||
osd_topology_refiner = blender::opensubdiv::TopologyRefinerImpl::createFromConverter(
|
||||
converter, topology_refiner_settings);
|
||||
}
|
||||
else {
|
||||
/* TODO(sergey): Check whether original geometry had any vertices.
|
||||
@@ -121,6 +124,10 @@ Subdiv *new_from_converter(const Settings *settings, OpenSubdiv_Converter *conve
|
||||
stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
|
||||
subdiv->stats = stats;
|
||||
return subdiv;
|
||||
#else
|
||||
UNUSED_VARS(settings, converter);
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
Subdiv *new_from_mesh(const Settings *settings, const Mesh *mesh)
|
||||
@@ -141,6 +148,7 @@ Subdiv *update_from_converter(Subdiv *subdiv,
|
||||
const Settings *settings,
|
||||
OpenSubdiv_Converter *converter)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
/* Check if the existing descriptor can be re-used. */
|
||||
bool can_reuse_subdiv = true;
|
||||
if (subdiv != nullptr && subdiv->topology_refiner != nullptr) {
|
||||
@@ -149,8 +157,7 @@ Subdiv *update_from_converter(Subdiv *subdiv,
|
||||
}
|
||||
else {
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(subdiv->topology_refiner,
|
||||
converter);
|
||||
can_reuse_subdiv = subdiv->topology_refiner->isEqualToConverter(converter);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
}
|
||||
}
|
||||
@@ -165,6 +172,10 @@ Subdiv *update_from_converter(Subdiv *subdiv,
|
||||
free(subdiv);
|
||||
}
|
||||
return new_from_converter(settings, converter);
|
||||
#else
|
||||
UNUSED_VARS(subdiv, settings, converter);
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
Subdiv *update_from_mesh(Subdiv *subdiv, const Settings *settings, const Mesh *mesh)
|
||||
@@ -180,6 +191,7 @@ Subdiv *update_from_mesh(Subdiv *subdiv, const Settings *settings, const Mesh *m
|
||||
|
||||
void free(Subdiv *subdiv)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
if (subdiv->evaluator != nullptr) {
|
||||
const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type;
|
||||
if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU) {
|
||||
@@ -189,14 +201,15 @@ void free(Subdiv *subdiv)
|
||||
}
|
||||
openSubdiv_deleteEvaluator(subdiv->evaluator);
|
||||
}
|
||||
if (subdiv->topology_refiner != nullptr) {
|
||||
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
|
||||
}
|
||||
delete subdiv->topology_refiner;
|
||||
displacement_detach(subdiv);
|
||||
if (subdiv->cache_.face_ptex_offset != nullptr) {
|
||||
MEM_freeN(subdiv->cache_.face_ptex_offset);
|
||||
}
|
||||
MEM_freeN(subdiv);
|
||||
#else
|
||||
UNUSED_VARS(subdiv);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
@@ -209,16 +222,17 @@ int *face_ptex_offset_get(Subdiv *subdiv)
|
||||
if (subdiv->cache_.face_ptex_offset != nullptr) {
|
||||
return subdiv->cache_.face_ptex_offset;
|
||||
}
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
if (topology_refiner == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
const int num_coarse_faces = topology_refiner->getNumFaces();
|
||||
const int num_coarse_faces = topology_refiner->base_level().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(face_index);
|
||||
const int face_size = topology_refiner->base_level().GetFaceVertices(face_index).size();
|
||||
const int num_ptex_faces = face_size == 4 ? 1 : face_size;
|
||||
subdiv->cache_.face_ptex_offset[face_index] = ptex_offset;
|
||||
ptex_offset += num_ptex_faces;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
#include "BKE_subdiv.hh"
|
||||
#include "BKE_subdiv_eval.hh"
|
||||
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "opensubdiv_topology_refiner_capi.hh"
|
||||
#endif
|
||||
|
||||
using blender::Array;
|
||||
using blender::float3;
|
||||
@@ -61,12 +63,13 @@ void subdiv_ccg_average_faces_boundaries_and_corners(SubdivCCG &subdiv_ccg,
|
||||
* \{ */
|
||||
|
||||
/* TODO(sergey): Make it more accessible function. */
|
||||
static int topology_refiner_count_face_corners(const OpenSubdiv_TopologyRefiner *topology_refiner)
|
||||
static int topology_refiner_count_face_corners(
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner)
|
||||
{
|
||||
const int num_faces = topology_refiner->getNumFaces();
|
||||
const int num_faces = topology_refiner->base_level().GetNumFaces();
|
||||
int num_corners = 0;
|
||||
for (int face_index = 0; face_index < num_faces; face_index++) {
|
||||
num_corners += topology_refiner->getNumFaceVertices(face_index);
|
||||
num_corners += topology_refiner->base_level().GetFaceVertices(face_index).size();
|
||||
}
|
||||
return num_corners;
|
||||
}
|
||||
@@ -77,7 +80,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg,
|
||||
Subdiv &subdiv,
|
||||
const SubdivToCCGSettings &settings)
|
||||
{
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv.topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv.topology_refiner;
|
||||
/* Allocate memory for surface grids. */
|
||||
const int64_t num_grids = topology_refiner_count_face_corners(topology_refiner);
|
||||
const int64_t grid_size = grid_size_from_level(subdiv_ccg.level);
|
||||
@@ -210,8 +213,8 @@ static bool subdiv_ccg_evaluate_grids(SubdivCCG &subdiv_ccg,
|
||||
SubdivCCGMaskEvaluator *mask_evaluator)
|
||||
{
|
||||
using namespace blender;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv.topology_refiner;
|
||||
const int num_faces = topology_refiner->getNumFaces();
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv.topology_refiner;
|
||||
const int num_faces = topology_refiner->base_level().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) {
|
||||
@@ -267,8 +270,8 @@ 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();
|
||||
const OpenSubdiv::Far::TopologyLevel &base_level = subdiv->topology_refiner->base_level();
|
||||
const int num_edges = base_level.GetNumEdges();
|
||||
const int grid_size = subdiv_ccg.grid_size;
|
||||
if (num_edges == 0) {
|
||||
/* Early output, nothing to do in this case. */
|
||||
@@ -276,24 +279,20 @@ static void subdiv_ccg_init_faces_edge_neighborhood(SubdivCCG &subdiv_ccg)
|
||||
}
|
||||
subdiv_ccg_allocate_adjacent_edges(subdiv_ccg, num_edges);
|
||||
|
||||
Vector<int, 64> face_vertices;
|
||||
Vector<int, 64> face_edges;
|
||||
/* Store adjacency for all faces. */
|
||||
for (const int face_index : faces.index_range()) {
|
||||
const IndexRange face = faces[face_index];
|
||||
const int num_face_grids = face.size();
|
||||
face_vertices.reinitialize(num_face_grids);
|
||||
topology_refiner->getFaceVertices(face_index, face_vertices.data());
|
||||
const OpenSubdiv::Far::ConstIndexArray face_vertices = base_level.GetFaceVertices(face_index);
|
||||
/* 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(face_index, face_edges.data());
|
||||
const OpenSubdiv::Far::ConstIndexArray face_edges = base_level.GetFaceEdges(face_index);
|
||||
/* 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(edge_index, edge_vertices);
|
||||
const OpenSubdiv::Far::ConstIndexArray edge_vertices = base_level.GetEdgeVertices(
|
||||
edge_index);
|
||||
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;
|
||||
@@ -353,21 +352,20 @@ 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();
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
const int num_vertices = topology_refiner->base_level().GetNumVertices();
|
||||
const int grid_size = subdiv_ccg.grid_size;
|
||||
if (num_vertices == 0) {
|
||||
/* Early output, nothing to do in this case. */
|
||||
return;
|
||||
}
|
||||
subdiv_ccg_allocate_adjacent_vertices(subdiv_ccg, num_vertices);
|
||||
Vector<int, 64> face_vertices;
|
||||
/* Store adjacency for all faces. */
|
||||
for (const int face_index : faces.index_range()) {
|
||||
const IndexRange face = faces[face_index];
|
||||
const int num_face_grids = face.size();
|
||||
face_vertices.reinitialize(num_face_grids);
|
||||
topology_refiner->getFaceVertices(face_index, face_vertices.data());
|
||||
const OpenSubdiv::Far::ConstIndexArray face_vertices =
|
||||
topology_refiner->base_level().GetFaceVertices(face_index);
|
||||
for (int corner = 0; corner < num_face_grids; corner++) {
|
||||
const int vertex_index = face_vertices[corner];
|
||||
/* Grid which is adjacent to the current corner. */
|
||||
@@ -858,20 +856,16 @@ static void subdiv_ccg_affected_face_adjacency(SubdivCCG &subdiv_ccg,
|
||||
blender::Set<int> &adjacent_edges)
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg.subdiv;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
|
||||
Vector<int, 64> face_vertices;
|
||||
Vector<int, 64> face_edges;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
|
||||
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(face_index, face_vertices.data());
|
||||
adjacent_verts.add_multiple(face_vertices);
|
||||
const OpenSubdiv::Far::ConstIndexArray face_vertices =
|
||||
topology_refiner->base_level().GetFaceVertices(face_index);
|
||||
adjacent_verts.add_multiple({face_vertices.begin(), face_vertices.size()});
|
||||
|
||||
face_edges.reinitialize(num_face_grids);
|
||||
topology_refiner->getFaceEdges(face_index, face_edges.data());
|
||||
adjacent_edges.add_multiple(face_edges);
|
||||
const OpenSubdiv::Far::ConstIndexArray face_edges =
|
||||
topology_refiner->base_level().GetFaceEdges(face_index);
|
||||
adjacent_edges.add_multiple({face_edges.begin(), face_edges.size()});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1115,15 +1109,14 @@ static int adjacent_vertex_index_from_coord(const SubdivCCG &subdiv_ccg,
|
||||
const SubdivCCGCoord &coord)
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg.subdiv;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
|
||||
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_grids = face.size();
|
||||
|
||||
Array<int, 64> face_vertices(num_face_grids);
|
||||
topology_refiner->getFaceVertices(face_index, face_vertices.data());
|
||||
const OpenSubdiv::Far::ConstIndexArray face_vertices =
|
||||
topology_refiner->base_level().GetFaceVertices(face_index);
|
||||
|
||||
const int adjacent_vertex_index = face_vertices[face_grid_index];
|
||||
return adjacent_vertex_index;
|
||||
@@ -1136,29 +1129,27 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
|
||||
SubdivCCGNeighbors &r_neighbors)
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg.subdiv;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *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(adjacent_vertex_index);
|
||||
const OpenSubdiv::Far::ConstIndexArray vertex_edges =
|
||||
topology_refiner->base_level().GetVertexEdges(adjacent_vertex_index);
|
||||
|
||||
const SubdivCCGAdjacentVertex &adjacent_vert = subdiv_ccg.adjacent_verts[adjacent_vertex_index];
|
||||
const int num_adjacent_faces = adjacent_vert.num_adjacent_faces;
|
||||
|
||||
subdiv_ccg_neighbors_init(
|
||||
r_neighbors, num_vertex_edges, (include_duplicates) ? num_adjacent_faces - 1 : 0);
|
||||
r_neighbors, vertex_edges.size(), (include_duplicates) ? num_adjacent_faces - 1 : 0);
|
||||
|
||||
Array<int, 64> vertex_edges(num_vertex_edges);
|
||||
topology_refiner->getVertexEdges(adjacent_vertex_index, vertex_edges.data());
|
||||
|
||||
for (int i = 0; i < num_vertex_edges; ++i) {
|
||||
for (int i = 0; i < vertex_edges.size(); ++i) {
|
||||
const int edge_index = vertex_edges[i];
|
||||
|
||||
/* Use very first grid of every edge. */
|
||||
const int edge_face_index = 0;
|
||||
|
||||
/* Depending edge orientation we use first (zero-based) or previous-to-last point. */
|
||||
int edge_vertices_indices[2];
|
||||
topology_refiner->getEdgeVertices(edge_index, edge_vertices_indices);
|
||||
const OpenSubdiv::Far::ConstIndexArray edge_vertices_indices =
|
||||
topology_refiner->base_level().GetEdgeVertices(edge_index);
|
||||
int edge_point_index, duplicate_edge_point_index;
|
||||
if (edge_vertices_indices[0] == adjacent_vertex_index) {
|
||||
duplicate_edge_point_index = 0;
|
||||
@@ -1178,7 +1169,7 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
|
||||
|
||||
if (include_duplicates) {
|
||||
/* Add duplicates of the current grid vertex in adjacent faces if requested. */
|
||||
for (int i = 0, duplicate_i = num_vertex_edges; i < num_adjacent_faces; i++) {
|
||||
for (int i = 0, duplicate_i = vertex_edges.size(); i < num_adjacent_faces; i++) {
|
||||
SubdivCCGCoord neighbor_coord = adjacent_vert.corner_coords[i];
|
||||
if (neighbor_coord.grid_index != coord.grid_index) {
|
||||
r_neighbors.coords[duplicate_i++] = neighbor_coord;
|
||||
@@ -1190,15 +1181,14 @@ static void neighbor_coords_corner_vertex_get(const SubdivCCG &subdiv_ccg,
|
||||
static int adjacent_edge_index_from_coord(const SubdivCCG &subdiv_ccg, const SubdivCCGCoord &coord)
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg.subdiv;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
|
||||
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(face_index);
|
||||
|
||||
Array<int, 64> face_edges(num_face_edges);
|
||||
topology_refiner->getFaceEdges(face_index, face_edges.data());
|
||||
const OpenSubdiv::Far::ConstIndexArray face_edges = topology_refiner->base_level().GetFaceEdges(
|
||||
face_index);
|
||||
|
||||
const int grid_size_1 = subdiv_ccg.grid_size - 1;
|
||||
int adjacent_edge_index = -1;
|
||||
@@ -1218,11 +1208,11 @@ static int adjacent_edge_point_index_from_coord(const SubdivCCG &subdiv_ccg,
|
||||
const int adjacent_edge_index)
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg.subdiv;
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
|
||||
const int adjacent_vertex_index = adjacent_vertex_index_from_coord(subdiv_ccg, coord);
|
||||
int edge_vertices_indices[2];
|
||||
topology_refiner->getEdgeVertices(adjacent_edge_index, edge_vertices_indices);
|
||||
const OpenSubdiv::Far::ConstIndexArray edge_vertices_indices =
|
||||
topology_refiner->base_level().GetEdgeVertices(adjacent_edge_index);
|
||||
|
||||
/* 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
|
||||
@@ -1490,18 +1480,18 @@ 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;
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
if (topology_refiner == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int num_coarse_faces = topology_refiner->getNumFaces();
|
||||
const int num_coarse_faces = topology_refiner->base_level().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(face_index);
|
||||
const int num_face_grids = topology_refiner->base_level().GetFaceVertices(face_index).size();
|
||||
subdiv_ccg.cache_.start_face_grid_index[face_index] = start_grid_index;
|
||||
start_grid_index += num_face_grids;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "opensubdiv_evaluator_capi.hh"
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "opensubdiv_topology_refiner_capi.hh"
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Helper functions.
|
||||
@@ -106,7 +108,7 @@ static void set_coarse_positions(Subdiv *subdiv,
|
||||
|
||||
/* Context which is used to fill face varying data in parallel. */
|
||||
struct FaceVaryingDataFromUVContext {
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner;
|
||||
opensubdiv::TopologyRefinerImpl *topology_refiner;
|
||||
const Mesh *mesh;
|
||||
OffsetIndices<int> faces;
|
||||
const float (*mloopuv)[2];
|
||||
@@ -119,16 +121,16 @@ static void set_face_varying_data_from_uv_task(void *__restrict userdata,
|
||||
const TaskParallelTLS *__restrict /*tls*/)
|
||||
{
|
||||
FaceVaryingDataFromUVContext *ctx = static_cast<FaceVaryingDataFromUVContext *>(userdata);
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner;
|
||||
opensubdiv::TopologyRefinerImpl *topology_refiner = ctx->topology_refiner;
|
||||
const int layer_index = ctx->layer_index;
|
||||
const float(*mluv)[2] = &ctx->mloopuv[ctx->faces[face_index].start()];
|
||||
|
||||
/* 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(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++) {
|
||||
const OpenSubdiv::Vtr::ConstIndexArray uv_indices =
|
||||
topology_refiner->base_level().GetFaceFVarValues(face_index, layer_index);
|
||||
for (int vertex_index = 0; vertex_index < uv_indices.size(); vertex_index++, mluv++) {
|
||||
copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], *mluv);
|
||||
}
|
||||
}
|
||||
@@ -138,12 +140,12 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv,
|
||||
const float (*mloopuv)[2],
|
||||
const int layer_index)
|
||||
{
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
const int num_faces = topology_refiner->getNumFaces();
|
||||
const int num_faces = topology_refiner->base_level().GetNumFaces();
|
||||
const float(*mluv)[2] = mloopuv;
|
||||
|
||||
const int num_fvar_values = topology_refiner->getNumFVarValues(layer_index);
|
||||
const int num_fvar_values = topology_refiner->base_level().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__));
|
||||
@@ -176,9 +178,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) {
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
const int num_verts = topology_refiner->getNumVertices();
|
||||
const int num_verts = topology_refiner->base_level().GetNumVertices();
|
||||
|
||||
if (orco && cloth_orco) {
|
||||
/* Set one by one if have both. */
|
||||
|
||||
@@ -12,15 +12,17 @@
|
||||
|
||||
#include "BKE_subdiv.hh"
|
||||
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "opensubdiv_topology_refiner_capi.hh"
|
||||
#endif
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
int topology_num_fvar_layers_get(const Subdiv *subdiv)
|
||||
{
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
const OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
return topology_refiner->getNumFVarChannels();
|
||||
const blender::opensubdiv::TopologyRefinerImpl *topology_refiner = subdiv->topology_refiner;
|
||||
return topology_refiner->base_level().GetNumFVarChannels();
|
||||
#else
|
||||
UNUSED_VARS(subdiv);
|
||||
return 0;
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
#include "opensubdiv_capi_type.hh"
|
||||
#include "opensubdiv_converter_capi.hh"
|
||||
#include "opensubdiv_evaluator_capi.hh"
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
# include "opensubdiv_topology_refiner_capi.hh"
|
||||
#endif
|
||||
|
||||
#include "draw_cache_extract.hh"
|
||||
#include "draw_cache_impl.hh"
|
||||
@@ -848,10 +850,10 @@ static void draw_subdiv_invalidate_evaluator_for_orco(bke::subdiv::Subdiv *subdi
|
||||
openSubdiv_deleteEvaluator(subdiv->evaluator);
|
||||
subdiv->evaluator = nullptr;
|
||||
|
||||
if (subdiv->topology_refiner != nullptr) {
|
||||
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
|
||||
subdiv->topology_refiner = nullptr;
|
||||
}
|
||||
#ifdef WITH_OPENSUBDIV
|
||||
delete subdiv->topology_refiner;
|
||||
subdiv->topology_refiner = nullptr;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -811,6 +811,9 @@ static Mesh *subdivide_edit_mesh(const Object *object,
|
||||
mesh_settings.use_optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges);
|
||||
|
||||
bke::subdiv::Subdiv *subdiv = bke::subdiv::new_from_mesh(&settings, me_from_em);
|
||||
if (!subdiv) {
|
||||
return nullptr;
|
||||
}
|
||||
Mesh *result = bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, me_from_em);
|
||||
BKE_id_free(nullptr, me_from_em);
|
||||
bke::subdiv::free(subdiv);
|
||||
|
||||
Reference in New Issue
Block a user