Subdiv: Move most blenkernel subdiv code to C++ namespace
Move most code to `blender::bke::subdiv`. That helps organization and makes using C++ in subdiv code easier, which will be useful for removing the unnecessary opensubdiv C-API wrapper.
This commit is contained in:
@@ -20,8 +20,10 @@ struct MultiresModifierData;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct SubdivCCG;
|
||||
struct SubdivSettings;
|
||||
struct SubdivToMeshSettings;
|
||||
namespace blender::bke::subdiv {
|
||||
struct Settings;
|
||||
struct ToMeshSettings;
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
/**
|
||||
* Delete mesh mdisps and grid paint masks.
|
||||
@@ -180,10 +182,11 @@ void multiresModifier_subdivide_to_level(Object *object,
|
||||
|
||||
/* Subdivision integration, defined in multires_subdiv.cc */
|
||||
|
||||
void BKE_multires_subdiv_settings_init(SubdivSettings *settings, const MultiresModifierData *mmd);
|
||||
void BKE_multires_subdiv_settings_init(blender::bke::subdiv::Settings *settings,
|
||||
const MultiresModifierData *mmd);
|
||||
|
||||
/* TODO(sergey): Replace this set of boolean flags with bitmask. */
|
||||
void BKE_multires_subdiv_mesh_settings_init(SubdivToMeshSettings *mesh_settings,
|
||||
void BKE_multires_subdiv_mesh_settings_init(blender::bke::subdiv::ToMeshSettings *mesh_settings,
|
||||
const Scene *scene,
|
||||
const Object *object,
|
||||
const MultiresModifierData *mmd,
|
||||
|
||||
@@ -16,9 +16,10 @@ struct MultiresModifierData;
|
||||
struct OpenSubdiv_Converter;
|
||||
struct OpenSubdiv_Evaluator;
|
||||
struct OpenSubdiv_TopologyRefiner;
|
||||
struct Subdiv;
|
||||
|
||||
enum eSubdivVtxBoundaryInterpolation {
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
enum VtxBoundaryInterpolation {
|
||||
/* Do not interpolate boundaries. */
|
||||
SUBDIV_VTX_BOUNDARY_NONE,
|
||||
/* Sharpen edges. */
|
||||
@@ -27,7 +28,7 @@ enum eSubdivVtxBoundaryInterpolation {
|
||||
SUBDIV_VTX_BOUNDARY_EDGE_AND_CORNER,
|
||||
};
|
||||
|
||||
enum eSubdivFVarLinearInterpolation {
|
||||
enum FVarLinearInterpolation {
|
||||
SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE,
|
||||
SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
|
||||
SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS,
|
||||
@@ -36,7 +37,7 @@ enum eSubdivFVarLinearInterpolation {
|
||||
SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL,
|
||||
};
|
||||
|
||||
struct SubdivSettings {
|
||||
struct Settings {
|
||||
/* Simple subdivision corresponds to "Simple" option in the interface. When it's enabled, the
|
||||
* subdivided mesh is not "smoothed": new vertices are added uniformly on the existing surface.
|
||||
*
|
||||
@@ -64,12 +65,12 @@ struct SubdivSettings {
|
||||
|
||||
bool use_creases;
|
||||
|
||||
eSubdivVtxBoundaryInterpolation vtx_boundary_interpolation;
|
||||
eSubdivFVarLinearInterpolation fvar_linear_interpolation;
|
||||
VtxBoundaryInterpolation vtx_boundary_interpolation;
|
||||
FVarLinearInterpolation fvar_linear_interpolation;
|
||||
};
|
||||
|
||||
/* NOTE: Order of enumerators MUST match order of values in SubdivStats. */
|
||||
enum eSubdivStatsValue {
|
||||
enum StatsValue {
|
||||
SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME = 0,
|
||||
SUBDIV_STATS_SUBDIV_TO_MESH,
|
||||
SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY,
|
||||
@@ -89,7 +90,7 @@ struct SubdivStats {
|
||||
* spend on conversion from Blender data to OpenSubdiv data, and
|
||||
* time spent on topology orientation on OpenSubdiv C-API side. */
|
||||
double topology_refiner_creation_time;
|
||||
/* Total time spent in BKE_subdiv_to_mesh(). */
|
||||
/* Total time spent in blender::bke::subdiv::subdiv_to_mesh(). */
|
||||
double subdiv_to_mesh_time;
|
||||
/* Geometry (mesh vertices) creation time during SUBDIV_TYO_MESH. */
|
||||
double subdiv_to_mesh_geometry_time;
|
||||
@@ -107,19 +108,19 @@ struct SubdivStats {
|
||||
double values_[NUM_SUBDIV_STATS_VALUES];
|
||||
};
|
||||
|
||||
/* Per-value timestamp on when corresponding BKE_subdiv_stats_begin() was
|
||||
/* Per-value timestamp on when corresponding stats_begin() was
|
||||
* called. */
|
||||
double begin_timestamp_[NUM_SUBDIV_STATS_VALUES];
|
||||
};
|
||||
|
||||
/* Functor which evaluates displacement at a given (u, v) of given ptex face. */
|
||||
struct SubdivDisplacement {
|
||||
struct Displacement {
|
||||
/* Initialize displacement evaluator.
|
||||
*
|
||||
* Is called right before evaluation is actually needed. This allows to do
|
||||
* some lazy initialization, like allocate evaluator from a main thread but
|
||||
* then do actual evaluation from background job. */
|
||||
void (*initialize)(SubdivDisplacement *displacement);
|
||||
void (*initialize)(Displacement *displacement);
|
||||
|
||||
/* Return displacement which is to be added to the original coordinate.
|
||||
*
|
||||
@@ -131,7 +132,7 @@ struct SubdivDisplacement {
|
||||
*
|
||||
* Averaging of displacement for vertices created for over coarse vertices
|
||||
* and edges is done by subdiv code. */
|
||||
void (*eval_displacement)(SubdivDisplacement *displacement,
|
||||
void (*eval_displacement)(Displacement *displacement,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
@@ -140,7 +141,7 @@ struct SubdivDisplacement {
|
||||
float r_D[3]);
|
||||
|
||||
/* Free the data, not the evaluator itself. */
|
||||
void (*free)(SubdivDisplacement *displacement);
|
||||
void (*free)(Displacement *displacement);
|
||||
|
||||
void *user_data;
|
||||
};
|
||||
@@ -154,7 +155,7 @@ struct Subdiv {
|
||||
/* Settings this subdivision surface is created for.
|
||||
*
|
||||
* It is read-only after assignment in BKE_subdiv_new_from_FOO(). */
|
||||
SubdivSettings settings;
|
||||
Settings settings;
|
||||
/* 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. */
|
||||
@@ -162,7 +163,7 @@ struct Subdiv {
|
||||
/* CPU side evaluator. */
|
||||
OpenSubdiv_Evaluator *evaluator;
|
||||
/* Optional displacement evaluator. */
|
||||
SubdivDisplacement *displacement_evaluator;
|
||||
Displacement *displacement_evaluator;
|
||||
/* Statistics for debugging. */
|
||||
SubdivStats stats;
|
||||
|
||||
@@ -188,37 +189,36 @@ struct Subdiv {
|
||||
*/
|
||||
|
||||
/* (De)initialize the entire subdivision surface module. */
|
||||
void BKE_subdiv_init();
|
||||
void BKE_subdiv_exit();
|
||||
void init();
|
||||
void exit();
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Conversion helpers.
|
||||
*/
|
||||
|
||||
/* NOTE: uv_smooth is eSubsurfUVSmooth. */
|
||||
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth);
|
||||
FVarLinearInterpolation fvar_interpolation_from_uv_smooth(int uv_smooth);
|
||||
|
||||
eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
int boundary_smooth);
|
||||
VtxBoundaryInterpolation vtx_boundary_interpolation_from_subsurf(int boundary_smooth);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Statistics.
|
||||
*/
|
||||
|
||||
void BKE_subdiv_stats_init(SubdivStats *stats);
|
||||
void stats_init(SubdivStats *stats);
|
||||
|
||||
void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value);
|
||||
void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value);
|
||||
void stats_begin(SubdivStats *stats, StatsValue value);
|
||||
void stats_end(SubdivStats *stats, StatsValue value);
|
||||
|
||||
void BKE_subdiv_stats_reset(SubdivStats *stats, eSubdivStatsValue value);
|
||||
void stats_reset(SubdivStats *stats, StatsValue value);
|
||||
|
||||
void BKE_subdiv_stats_print(const SubdivStats *stats);
|
||||
void stats_print(const SubdivStats *stats);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Settings.
|
||||
*/
|
||||
|
||||
bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSettings *settings_b);
|
||||
bool settings_equal(const Settings *settings_a, const Settings *settings_b);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Construction.
|
||||
@@ -226,9 +226,8 @@ bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSet
|
||||
|
||||
/* Construct new subdivision surface descriptor, from scratch, using given
|
||||
* settings and topology. */
|
||||
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
|
||||
OpenSubdiv_Converter *converter);
|
||||
Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, const Mesh *mesh);
|
||||
Subdiv *new_from_converter(const Settings *settings, OpenSubdiv_Converter *converter);
|
||||
Subdiv *new_from_mesh(const Settings *settings, const Mesh *mesh);
|
||||
|
||||
/* Similar to above, but will not re-create descriptor if it was created for the
|
||||
* same settings and topology.
|
||||
@@ -238,24 +237,22 @@ Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, const Mesh *mes
|
||||
* NOTE: It is allowed to pass NULL as an existing subdivision surface
|
||||
* descriptor. This will create a new descriptor without any extra checks.
|
||||
*/
|
||||
Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
|
||||
const SubdivSettings *settings,
|
||||
OpenSubdiv_Converter *converter);
|
||||
Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
|
||||
const SubdivSettings *settings,
|
||||
const Mesh *mesh);
|
||||
Subdiv *update_from_converter(Subdiv *subdiv,
|
||||
const Settings *settings,
|
||||
OpenSubdiv_Converter *converter);
|
||||
Subdiv *update_from_mesh(Subdiv *subdiv, const Settings *settings, const Mesh *mesh);
|
||||
|
||||
void BKE_subdiv_free(Subdiv *subdiv);
|
||||
void free(Subdiv *subdiv);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Displacement API.
|
||||
*/
|
||||
|
||||
void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
|
||||
Mesh *mesh,
|
||||
const MultiresModifierData *mmd);
|
||||
void displacement_attach_from_multires(Subdiv *subdiv,
|
||||
Mesh *mesh,
|
||||
const MultiresModifierData *mmd);
|
||||
|
||||
void BKE_subdiv_displacement_detach(Subdiv *subdiv);
|
||||
void displacement_detach(Subdiv *subdiv);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Topology helpers.
|
||||
@@ -264,7 +261,7 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv);
|
||||
/* For each element in the array, this stores the total number of ptex faces up to that element,
|
||||
* with the total number of ptex faces being the last element in the array. The array is of length
|
||||
* `base face count + 1`. */
|
||||
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
|
||||
int *face_ptex_offset_get(Subdiv *subdiv);
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* PTex faces and grids.
|
||||
@@ -272,37 +269,39 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv);
|
||||
|
||||
/* For a given (ptex_u, ptex_v) within a ptex face get corresponding
|
||||
* (grid_u, grid_v) within a grid. */
|
||||
BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(float ptex_u,
|
||||
float ptex_v,
|
||||
float *r_grid_u,
|
||||
float *r_grid_v);
|
||||
BLI_INLINE void ptex_face_uv_to_grid_uv(float ptex_u,
|
||||
float ptex_v,
|
||||
float *r_grid_u,
|
||||
float *r_grid_v);
|
||||
|
||||
/* Inverse of above. */
|
||||
BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(float grid_u,
|
||||
float grid_v,
|
||||
float *r_ptex_u,
|
||||
float *r_ptex_v);
|
||||
BLI_INLINE void grid_uv_to_ptex_face_uv(float grid_u,
|
||||
float grid_v,
|
||||
float *r_ptex_u,
|
||||
float *r_ptex_v);
|
||||
|
||||
/* For a given subdivision level (which is NOT refinement level) get size of
|
||||
* CCG grid (number of grid points on a side).
|
||||
*/
|
||||
BLI_INLINE int BKE_subdiv_grid_size_from_level(int level);
|
||||
BLI_INLINE int grid_size_from_level(int level);
|
||||
|
||||
/* Simplified version of mdisp_rot_face_to_crn, only handles quad and
|
||||
* works in normalized coordinates.
|
||||
*
|
||||
* NOTE: Output coordinates are in ptex coordinates. */
|
||||
BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(float quad_u,
|
||||
float quad_v,
|
||||
float *r_corner_u,
|
||||
float *r_corner_v);
|
||||
BLI_INLINE int rotate_quad_to_corner(float quad_u,
|
||||
float quad_v,
|
||||
float *r_corner_u,
|
||||
float *r_corner_v);
|
||||
|
||||
/* Converts (u, v) coordinate from within a grid to a quad coordinate in
|
||||
* normalized ptex coordinates. */
|
||||
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
|
||||
BLI_INLINE void rotate_grid_to_quad(
|
||||
int corner, float grid_u, float grid_v, float *r_quad_u, float *r_quad_v);
|
||||
|
||||
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
|
||||
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
|
||||
BLI_INLINE float crease_to_sharpness(float edge_crease);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
#include "intern/subdiv_inline.hh"
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
struct CCGElem;
|
||||
struct CCGKey;
|
||||
struct Mesh;
|
||||
namespace blender::bke::subdiv {
|
||||
struct Subdiv;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Masks.
|
||||
@@ -88,7 +90,7 @@ struct SubdivCCG {
|
||||
*
|
||||
* TODO(sergey): Make sure the whole descriptor is valid, including all the
|
||||
* displacement attached to the surface. */
|
||||
Subdiv *subdiv = nullptr;
|
||||
blender::bke::subdiv::Subdiv *subdiv = nullptr;
|
||||
/* A level at which geometry was subdivided. This is what defines grid
|
||||
* resolution. It is NOT the topology refinement level. */
|
||||
int level = -1;
|
||||
@@ -183,7 +185,7 @@ struct SubdivCCG {
|
||||
* TODO(sergey): Allow some user-counter or more explicit control over who owns
|
||||
* the Subdiv. The goal should be to allow viewport GL Mesh and CCG to share
|
||||
* same Subsurf without conflicts. */
|
||||
std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
|
||||
std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(blender::bke::subdiv::Subdiv &subdiv,
|
||||
const SubdivToCCGSettings &settings,
|
||||
const Mesh &coarse_mesh,
|
||||
SubdivCCGMaskEvaluator *mask_evaluator);
|
||||
@@ -191,7 +193,7 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
|
||||
/* Helper function, creates Mesh structure which is properly setup to use
|
||||
* grids.
|
||||
*/
|
||||
Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
|
||||
Mesh *BKE_subdiv_to_ccg_mesh(blender::bke::subdiv::Subdiv &subdiv,
|
||||
const SubdivToCCGSettings &settings,
|
||||
const Mesh &coarse_mesh);
|
||||
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct Subdiv;
|
||||
|
||||
/* Special version of subdivision surface which calculates final positions for coarse vertices.
|
||||
@@ -20,7 +23,9 @@ struct Subdiv;
|
||||
* paint on a deformed mesh with sub-surf on it.
|
||||
*
|
||||
* vertex_cos are supposed to hold coordinates of the coarse mesh. */
|
||||
void BKE_subdiv_deform_coarse_vertices(Subdiv *subdiv,
|
||||
const Mesh *coarse_mesh,
|
||||
float (*vertex_cos)[3],
|
||||
int num_verts);
|
||||
void deform_coarse_vertices(Subdiv *subdiv,
|
||||
const Mesh *coarse_mesh,
|
||||
float (*vertex_cos)[3],
|
||||
int num_verts);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
struct Mesh;
|
||||
struct OpenSubdiv_EvaluatorCache;
|
||||
struct OpenSubdiv_EvaluatorSettings;
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct Subdiv;
|
||||
|
||||
enum eSubdivEvaluatorType {
|
||||
@@ -21,73 +24,71 @@ enum eSubdivEvaluatorType {
|
||||
};
|
||||
|
||||
/* Returns true if evaluator is ready for use. */
|
||||
bool BKE_subdiv_eval_begin(Subdiv *subdiv,
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache,
|
||||
const OpenSubdiv_EvaluatorSettings *settings);
|
||||
bool eval_begin(Subdiv *subdiv,
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache,
|
||||
const OpenSubdiv_EvaluatorSettings *settings);
|
||||
|
||||
/* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse
|
||||
* mesh. */
|
||||
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
|
||||
const Mesh *mesh,
|
||||
const float (*coarse_vertex_cos)[3],
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache);
|
||||
bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
|
||||
const Mesh *mesh,
|
||||
const float (*coarse_vertex_cos)[3]);
|
||||
bool eval_begin_from_mesh(Subdiv *subdiv,
|
||||
const Mesh *mesh,
|
||||
const float (*coarse_vertex_cos)[3],
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache);
|
||||
bool eval_refine_from_mesh(Subdiv *subdiv, const Mesh *mesh, const float (*coarse_vertex_cos)[3]);
|
||||
|
||||
/* Makes sure displacement evaluator is initialized.
|
||||
*
|
||||
* NOTE: This function must be called once before evaluating displacement or
|
||||
* final surface position. */
|
||||
void BKE_subdiv_eval_init_displacement(Subdiv *subdiv);
|
||||
void eval_init_displacement(Subdiv *subdiv);
|
||||
|
||||
/* Single point queries. */
|
||||
|
||||
/* Evaluate point at a limit surface, with optional derivatives and normal. */
|
||||
|
||||
void BKE_subdiv_eval_limit_point(
|
||||
Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
|
||||
void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
float r_P[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3]);
|
||||
void BKE_subdiv_eval_limit_point_and_normal(
|
||||
void eval_limit_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
|
||||
void eval_limit_point_and_derivatives(Subdiv *subdiv,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
float r_P[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3]);
|
||||
void eval_limit_point_and_normal(
|
||||
Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3], float r_N[3]);
|
||||
|
||||
/* Evaluate smoothly interpolated vertex data (such as ORCO). */
|
||||
void BKE_subdiv_eval_vertex_data(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_vertex_data[]);
|
||||
void eval_vertex_data(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_vertex_data[]);
|
||||
|
||||
/* Evaluate face-varying layer (such as UV). */
|
||||
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
|
||||
int face_varying_channel,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
float r_face_varying[2]);
|
||||
void eval_face_varying(Subdiv *subdiv,
|
||||
int face_varying_channel,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
float r_face_varying[2]);
|
||||
|
||||
/* NOTE: Expects derivatives to be correct.
|
||||
*
|
||||
* TODO(sergey): This is currently used together with
|
||||
* BKE_subdiv_eval_final_point() which can easily evaluate derivatives.
|
||||
* eval_final_point() which can easily evaluate derivatives.
|
||||
* Would be nice to have displacement evaluation function which does not require
|
||||
* knowing derivatives ahead of a time. */
|
||||
void BKE_subdiv_eval_displacement(Subdiv *subdiv,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
const float dPdu[3],
|
||||
const float dPdv[3],
|
||||
float r_D[3]);
|
||||
void eval_displacement(Subdiv *subdiv,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
const float dPdu[3],
|
||||
const float dPdv[3],
|
||||
float r_D[3]);
|
||||
|
||||
/* Evaluate point on a limit surface with displacement applied to it. */
|
||||
void BKE_subdiv_eval_final_point(
|
||||
Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
|
||||
void eval_final_point(Subdiv *subdiv, int ptex_face_index, float u, float v, float r_P[3]);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -11,120 +11,123 @@
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct ToMeshSettings;
|
||||
struct ForeachContext;
|
||||
struct Subdiv;
|
||||
struct SubdivForeachContext;
|
||||
struct SubdivToMeshSettings;
|
||||
|
||||
using SubdivForeachTopologyInformationCb = bool (*)(const SubdivForeachContext *context,
|
||||
int num_vertices,
|
||||
int num_edges,
|
||||
int num_loops,
|
||||
int num_faces,
|
||||
const int *subdiv_face_offset);
|
||||
using ForeachTopologyInformationCb = bool (*)(const ForeachContext *context,
|
||||
int num_vertices,
|
||||
int num_edges,
|
||||
int num_loops,
|
||||
int num_faces,
|
||||
const int *subdiv_face_offset);
|
||||
|
||||
using SubdivForeachVertexFromCornerCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_vertex_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
using ForeachVertexFromCornerCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_vertex_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
using SubdivForeachVertexFromEdgeCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_edge_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
using ForeachVertexFromEdgeCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_edge_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
using SubdivForeachVertexInnerCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
using SubdivForeachEdgeCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_edge_index,
|
||||
int subdiv_edge_index,
|
||||
bool is_loose,
|
||||
int subdiv_v1,
|
||||
int subdiv_v2);
|
||||
|
||||
using SubdivForeachLoopCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_loop_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_loop_index,
|
||||
int subdiv_vertex_index,
|
||||
int subdiv_edge_index);
|
||||
|
||||
using SubdivForeachPolygonCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_face_index,
|
||||
int subdiv_face_index,
|
||||
int start_loop_index,
|
||||
int num_loops);
|
||||
|
||||
using SubdivForeachLooseCb = void (*)(const SubdivForeachContext *context,
|
||||
using ForeachVertexInnerCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_vertex_index,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
using SubdivForeachVertexOfLooseEdgeCb = void (*)(const SubdivForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_edge_index,
|
||||
float u,
|
||||
int subdiv_vertex_index);
|
||||
using ForeachEdgeCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_edge_index,
|
||||
int subdiv_edge_index,
|
||||
bool is_loose,
|
||||
int subdiv_v1,
|
||||
int subdiv_v2);
|
||||
|
||||
struct SubdivForeachContext {
|
||||
using ForeachLoopCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int ptex_face_index,
|
||||
float u,
|
||||
float v,
|
||||
int coarse_loop_index,
|
||||
int coarse_face_index,
|
||||
int coarse_corner,
|
||||
int subdiv_loop_index,
|
||||
int subdiv_vertex_index,
|
||||
int subdiv_edge_index);
|
||||
|
||||
using ForeachPolygonCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_face_index,
|
||||
int subdiv_face_index,
|
||||
int start_loop_index,
|
||||
int num_loops);
|
||||
|
||||
using ForeachLooseCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_vertex_index,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
using ForeachVertexOfLooseEdgeCb = void (*)(const ForeachContext *context,
|
||||
void *tls,
|
||||
int coarse_edge_index,
|
||||
float u,
|
||||
int subdiv_vertex_index);
|
||||
|
||||
struct ForeachContext {
|
||||
/* Is called when topology information becomes available.
|
||||
* Is only called once.
|
||||
*
|
||||
* NOTE: If this callback returns false, the foreach loop is aborted.
|
||||
*/
|
||||
SubdivForeachTopologyInformationCb topology_info;
|
||||
ForeachTopologyInformationCb topology_info;
|
||||
/* These callbacks are called from every ptex which shares "emitting"
|
||||
* vertex or edge.
|
||||
*/
|
||||
SubdivForeachVertexFromCornerCb vertex_every_corner;
|
||||
SubdivForeachVertexFromEdgeCb vertex_every_edge;
|
||||
ForeachVertexFromCornerCb vertex_every_corner;
|
||||
ForeachVertexFromEdgeCb vertex_every_edge;
|
||||
/* Those callbacks are run once per subdivision vertex, ptex is undefined
|
||||
* as in it will be whatever first ptex face happened to be traversed in
|
||||
* the multi-threaded environment and which shares "emitting" vertex or
|
||||
* edge.
|
||||
*/
|
||||
SubdivForeachVertexFromCornerCb vertex_corner;
|
||||
SubdivForeachVertexFromEdgeCb vertex_edge;
|
||||
ForeachVertexFromCornerCb vertex_corner;
|
||||
ForeachVertexFromEdgeCb vertex_edge;
|
||||
/* Called exactly once, always corresponds to a single ptex face. */
|
||||
SubdivForeachVertexInnerCb vertex_inner;
|
||||
ForeachVertexInnerCb vertex_inner;
|
||||
/* Called once for each loose vertex. One loose coarse vertex corresponds
|
||||
* to a single subdivision vertex.
|
||||
*/
|
||||
SubdivForeachLooseCb vertex_loose;
|
||||
ForeachLooseCb vertex_loose;
|
||||
/* Called once per vertex created for loose edge. */
|
||||
SubdivForeachVertexOfLooseEdgeCb vertex_of_loose_edge;
|
||||
ForeachVertexOfLooseEdgeCb vertex_of_loose_edge;
|
||||
/* NOTE: If subdivided edge does not come from coarse edge, ORIGINDEX_NONE
|
||||
* will be passed as coarse_edge_index.
|
||||
*/
|
||||
SubdivForeachEdgeCb edge;
|
||||
ForeachEdgeCb edge;
|
||||
/* NOTE: If subdivided loop does not come from coarse loop, ORIGINDEX_NONE
|
||||
* will be passed as coarse_loop_index.
|
||||
*/
|
||||
SubdivForeachLoopCb loop;
|
||||
SubdivForeachPolygonCb poly;
|
||||
ForeachLoopCb loop;
|
||||
ForeachPolygonCb poly;
|
||||
|
||||
/* User-defined pointer, to allow callbacks know something about context the
|
||||
* traversal is happening for.
|
||||
@@ -152,7 +155,9 @@ struct SubdivForeachContext {
|
||||
* The main point here is to be able to get base level topology, which can be
|
||||
* done with either of those. Having both of them is kind of redundant.
|
||||
*/
|
||||
bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
|
||||
const SubdivForeachContext *context,
|
||||
const SubdivToMeshSettings *mesh_settings,
|
||||
const Mesh *coarse_mesh);
|
||||
bool foreach_subdiv_geometry(Subdiv *subdiv,
|
||||
const ForeachContext *context,
|
||||
const ToMeshSettings *mesh_settings,
|
||||
const Mesh *coarse_mesh);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -13,9 +13,12 @@
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
struct Mesh;
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct Subdiv;
|
||||
|
||||
struct SubdivToMeshSettings {
|
||||
struct ToMeshSettings {
|
||||
/**
|
||||
* Resolution at which regular PTEX (created for quad face) are being
|
||||
* evaluated. This defines how many vertices final mesh will have: every
|
||||
@@ -29,19 +32,19 @@ struct SubdivToMeshSettings {
|
||||
};
|
||||
|
||||
/** Create real hi-res mesh from subdivision, all geometry is "real". */
|
||||
Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
|
||||
const SubdivToMeshSettings *settings,
|
||||
const Mesh *coarse_mesh);
|
||||
Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh);
|
||||
|
||||
/**
|
||||
* Interpolate a position along the `coarse_edge` at the relative `u` coordinate.
|
||||
* If `is_simple` is false, this will perform a B-Spline interpolation using the edge neighbors,
|
||||
* otherwise a linear interpolation will be done base on the edge vertices.
|
||||
*/
|
||||
void BKE_subdiv_mesh_interpolate_position_on_edge(const float (*coarse_positions)[3],
|
||||
const blender::int2 *coarse_edges,
|
||||
blender::GroupedSpan<int> vert_to_edge_map,
|
||||
int coarse_edge_index,
|
||||
bool is_simple,
|
||||
float u,
|
||||
float pos_r[3]);
|
||||
void mesh_interpolate_position_on_edge(const float (*coarse_positions)[3],
|
||||
const blender::int2 *coarse_edges,
|
||||
blender::GroupedSpan<int> vert_to_edge_map,
|
||||
int coarse_edge_index,
|
||||
bool is_simple,
|
||||
float u,
|
||||
float pos_r[3]);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -19,18 +19,21 @@
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
struct Scene;
|
||||
struct Subdiv;
|
||||
struct SubdivSettings;
|
||||
struct SubsurfModifierData;
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
struct Subdiv;
|
||||
struct Settings;
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
/* Runtime subsurf modifier data, cached in modifier on evaluated meshes. */
|
||||
struct SubsurfRuntimeData {
|
||||
/* Subdivision settings, exists before descriptor or mesh wrapper is created. */
|
||||
SubdivSettings settings;
|
||||
blender::bke::subdiv::Settings settings;
|
||||
|
||||
/* Cached subdivision surface descriptor, with topology and settings. */
|
||||
Subdiv *subdiv_cpu;
|
||||
Subdiv *subdiv_gpu;
|
||||
blender::bke::subdiv::Subdiv *subdiv_cpu;
|
||||
blender::bke::subdiv::Subdiv *subdiv_gpu;
|
||||
|
||||
/* Recent usage markers for UI diagnostics. To avoid UI flicker due to races
|
||||
* between evaluation and UI redraw, they are set to 2 when an evaluator is used,
|
||||
@@ -50,8 +53,8 @@ struct SubsurfRuntimeData {
|
||||
int stats_totloop;
|
||||
};
|
||||
|
||||
SubdivSettings BKE_subsurf_modifier_settings_init(const SubsurfModifierData *smd,
|
||||
bool use_render_params);
|
||||
blender::bke::subdiv::Settings BKE_subsurf_modifier_settings_init(const SubsurfModifierData *smd,
|
||||
bool use_render_params);
|
||||
|
||||
bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, bool use_render_params);
|
||||
|
||||
@@ -78,15 +81,14 @@ bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene,
|
||||
|
||||
bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh);
|
||||
|
||||
extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv);
|
||||
extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(blender::bke::subdiv::Subdiv *subdiv);
|
||||
|
||||
/**
|
||||
* Main goal of this function is to give usable subdivision surface descriptor
|
||||
* which matches settings and topology.
|
||||
*/
|
||||
Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
|
||||
const Mesh *mesh,
|
||||
bool for_draw_code);
|
||||
blender::bke::subdiv::Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(
|
||||
SubsurfRuntimeData *runtime_data, const Mesh *mesh, bool for_draw_code);
|
||||
|
||||
/**
|
||||
* Return the #ModifierMode required for the evaluation of the subsurf modifier,
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct Subdiv;
|
||||
|
||||
int BKE_subdiv_topology_num_fvar_layers_get(const Subdiv *subdiv);
|
||||
int topology_num_fvar_layers_get(const Subdiv *subdiv);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -319,6 +319,7 @@ int BKE_mesh_wrapper_face_len(const Mesh *mesh)
|
||||
|
||||
static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)mesh->runtime->subsurf_runtime_data;
|
||||
if (runtime_data == nullptr || runtime_data->settings.level == 0) {
|
||||
return mesh;
|
||||
@@ -327,7 +328,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh)
|
||||
/* Initialize the settings before ensuring the descriptor as this is checked to decide whether
|
||||
* subdivision is needed at all, and checking the descriptor status might involve checking if the
|
||||
* data is out-of-date, which is a very expensive operation. */
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = runtime_data->resolution;
|
||||
mesh_settings.use_optimal_display = runtime_data->use_optimal_display;
|
||||
|
||||
@@ -335,7 +336,8 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh)
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
|
||||
subdiv::Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
|
||||
runtime_data, mesh, false);
|
||||
if (subdiv == nullptr) {
|
||||
/* Happens on bad topology, but also on empty input mesh. */
|
||||
return mesh;
|
||||
@@ -349,7 +351,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh)
|
||||
memcpy(data, mesh->corner_normals().data(), mesh->corner_normals().size_in_bytes());
|
||||
}
|
||||
|
||||
Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
Mesh *subdiv_mesh = subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
|
||||
if (use_clnors) {
|
||||
BKE_mesh_set_custom_normals(subdiv_mesh,
|
||||
@@ -359,7 +361,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh)
|
||||
}
|
||||
|
||||
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
subdiv::free(subdiv);
|
||||
}
|
||||
|
||||
if (subdiv_mesh != mesh) {
|
||||
|
||||
@@ -22,7 +22,9 @@ struct MDisps;
|
||||
struct Mesh;
|
||||
struct MultiresModifierData;
|
||||
struct Object;
|
||||
namespace blender::bke::subdiv {
|
||||
struct Subdiv;
|
||||
}
|
||||
struct SubdivCCG;
|
||||
|
||||
struct MultiresReshapeContext {
|
||||
@@ -45,7 +47,7 @@ struct MultiresReshapeContext {
|
||||
*
|
||||
* The coarse mesh of this subdivision surface is a base mesh with all deformation modifiers
|
||||
* leading multires applied on it. */
|
||||
Subdiv *subdiv;
|
||||
blender::bke::subdiv::Subdiv *subdiv;
|
||||
bool need_free_subdiv;
|
||||
|
||||
struct {
|
||||
@@ -146,9 +148,9 @@ struct ReshapeConstGridElement {
|
||||
* Create subdivision surface descriptor which is configured for surface evaluation at a given
|
||||
* multi-res modifier.
|
||||
*/
|
||||
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
|
||||
Object *object,
|
||||
const MultiresModifierData *mmd);
|
||||
blender::bke::subdiv::Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
|
||||
Object *object,
|
||||
const MultiresModifierData *mmd);
|
||||
|
||||
/**
|
||||
* \note Initialized base mesh to object's mesh, the Subdivision is created from the deformed
|
||||
@@ -178,7 +180,7 @@ bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *resha
|
||||
bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape_context,
|
||||
Object *object,
|
||||
MultiresModifierData *mmd,
|
||||
Subdiv *subdiv,
|
||||
blender::bke::subdiv::Subdiv *subdiv,
|
||||
int top_level);
|
||||
|
||||
void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_context);
|
||||
|
||||
@@ -135,7 +135,8 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape
|
||||
|
||||
void multires_reshape_apply_base_refine_from_base(MultiresReshapeContext *reshape_context)
|
||||
{
|
||||
BKE_subdiv_eval_refine_from_mesh(reshape_context->subdiv, reshape_context->base_mesh, nullptr);
|
||||
blender::bke::subdiv::eval_refine_from_mesh(
|
||||
reshape_context->subdiv, reshape_context->base_mesh, nullptr);
|
||||
}
|
||||
|
||||
void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *reshape_context)
|
||||
@@ -150,7 +151,8 @@ void multires_reshape_apply_base_refine_from_deform(MultiresReshapeContext *resh
|
||||
blender::Array<blender::float3> deformed_verts =
|
||||
BKE_multires_create_deformed_base_mesh_vert_coords(depsgraph, object, mmd);
|
||||
|
||||
BKE_subdiv_eval_refine_from_mesh(reshape_context->subdiv,
|
||||
reshape_context->base_mesh,
|
||||
reinterpret_cast<float(*)[3]>(deformed_verts.data()));
|
||||
blender::bke::subdiv::eval_refine_from_mesh(
|
||||
reshape_context->subdiv,
|
||||
reshape_context->base_mesh,
|
||||
reinterpret_cast<float(*)[3]>(deformed_verts.data()));
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ struct MultiresReshapeSmoothContext {
|
||||
blender::BitSpan loose_base_edges;
|
||||
|
||||
/* Subdivision surface created for geometry at a reshape level. */
|
||||
Subdiv *reshape_subdiv;
|
||||
blender::bke::subdiv::Subdiv *reshape_subdiv;
|
||||
|
||||
/* Limit surface of the base mesh with original sculpt level details on it, subdivided up to the
|
||||
* top level.
|
||||
@@ -176,7 +176,7 @@ static void linear_grids_init(LinearGrids *linear_grids)
|
||||
|
||||
static void linear_grids_allocate(LinearGrids *linear_grids, int num_grids, int level)
|
||||
{
|
||||
const size_t grid_size = BKE_subdiv_grid_size_from_level(level);
|
||||
const size_t grid_size = blender::bke::subdiv::grid_size_from_level(level);
|
||||
const size_t grid_area = grid_size * grid_size;
|
||||
const size_t num_grid_elements = num_grids * grid_area;
|
||||
|
||||
@@ -552,7 +552,7 @@ static void context_free_subdiv(MultiresReshapeSmoothContext *reshape_smooth_con
|
||||
if (reshape_smooth_context->reshape_subdiv == nullptr) {
|
||||
return;
|
||||
}
|
||||
BKE_subdiv_free(reshape_smooth_context->reshape_subdiv);
|
||||
blender::bke::subdiv::free(reshape_smooth_context->reshape_subdiv);
|
||||
}
|
||||
|
||||
static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
|
||||
@@ -562,7 +562,7 @@ static void context_free(MultiresReshapeSmoothContext *reshape_smooth_context)
|
||||
base_surface_grids_free(reshape_smooth_context);
|
||||
}
|
||||
|
||||
static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
|
||||
static bool foreach_topology_info(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const int num_vertices,
|
||||
const int num_edges,
|
||||
const int num_loops,
|
||||
@@ -595,7 +595,7 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_single_vertex(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const GridCoord *grid_coord,
|
||||
const int coarse_vertex_index,
|
||||
const int subdiv_vertex_index)
|
||||
@@ -627,11 +627,11 @@ static void foreach_single_vertex(const SubdivForeachContext *foreach_context,
|
||||
}
|
||||
|
||||
crease = get_effective_crease_float(reshape_smooth_context, crease);
|
||||
vertex->sharpness = BKE_subdiv_crease_to_sharpness_f(crease);
|
||||
vertex->sharpness = blender::bke::subdiv::crease_to_sharpness(crease);
|
||||
}
|
||||
|
||||
/* TODO(sergey): De-duplicate with similar function in multires_reshape_vertcos.cc */
|
||||
static void foreach_vertex(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_vertex(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const PTexCoord *ptex_coord,
|
||||
const int coarse_vertex_index,
|
||||
const int subdiv_vertex_index)
|
||||
@@ -681,7 +681,7 @@ static void foreach_vertex(const SubdivForeachContext *foreach_context,
|
||||
}
|
||||
}
|
||||
|
||||
static void foreach_vertex_inner(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_vertex_inner(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
@@ -697,15 +697,16 @@ static void foreach_vertex_inner(const SubdivForeachContext *foreach_context,
|
||||
foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void foreach_vertex_every_corner(const SubdivForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
const float ptex_face_v,
|
||||
const int coarse_vertex_index,
|
||||
const int /*coarse_face_index*/,
|
||||
const int /*coarse_face_corner*/,
|
||||
const int subdiv_vertex_index)
|
||||
static void foreach_vertex_every_corner(
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
const float ptex_face_v,
|
||||
const int coarse_vertex_index,
|
||||
const int /*coarse_face_index*/,
|
||||
const int /*coarse_face_corner*/,
|
||||
const int subdiv_vertex_index)
|
||||
{
|
||||
PTexCoord ptex_coord{};
|
||||
ptex_coord.ptex_face_index = ptex_face_index;
|
||||
@@ -714,7 +715,7 @@ static void foreach_vertex_every_corner(const SubdivForeachContext *foreach_cont
|
||||
foreach_vertex(foreach_context, &ptex_coord, coarse_vertex_index, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void foreach_vertex_every_edge(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_vertex_every_edge(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
@@ -731,7 +732,7 @@ static void foreach_vertex_every_edge(const SubdivForeachContext *foreach_contex
|
||||
foreach_vertex(foreach_context, &ptex_coord, -1, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void foreach_loop(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_loop(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int /*ptex_face_index*/,
|
||||
const float /*ptex_face_u*/,
|
||||
@@ -756,7 +757,7 @@ static void foreach_loop(const SubdivForeachContext *foreach_context,
|
||||
corner->grid_index = first_grid_index + coarse_corner;
|
||||
}
|
||||
|
||||
static void foreach_poly(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_poly(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int /*coarse_face_index*/,
|
||||
const int subdiv_face_index,
|
||||
@@ -773,11 +774,12 @@ static void foreach_poly(const SubdivForeachContext *foreach_context,
|
||||
face->num_corners = num_loops;
|
||||
}
|
||||
|
||||
static void foreach_vertex_of_loose_edge(const SubdivForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int /*coarse_edge_index*/,
|
||||
const float /*u*/,
|
||||
const int vertex_index)
|
||||
static void foreach_vertex_of_loose_edge(
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int /*coarse_edge_index*/,
|
||||
const float /*u*/,
|
||||
const int vertex_index)
|
||||
{
|
||||
const MultiresReshapeSmoothContext *reshape_smooth_context =
|
||||
static_cast<const MultiresReshapeSmoothContext *>(foreach_context->user_data);
|
||||
@@ -801,10 +803,10 @@ static void store_edge(MultiresReshapeSmoothContext *reshape_smooth_context,
|
||||
Edge *edge = &reshape_smooth_context->geometry.edges[edge_index];
|
||||
edge->v1 = subdiv_v1;
|
||||
edge->v2 = subdiv_v2;
|
||||
edge->sharpness = BKE_subdiv_crease_to_sharpness_f(crease);
|
||||
edge->sharpness = blender::bke::subdiv::crease_to_sharpness(crease);
|
||||
}
|
||||
|
||||
static void foreach_edge(const SubdivForeachContext *foreach_context,
|
||||
static void foreach_edge(const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_edge_index,
|
||||
const int /*subdiv_edge_index*/,
|
||||
@@ -870,7 +872,7 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context
|
||||
{
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
|
||||
SubdivForeachContext foreach_context{};
|
||||
blender::bke::subdiv::ForeachContext foreach_context{};
|
||||
foreach_context.topology_info = foreach_topology_info;
|
||||
foreach_context.vertex_inner = foreach_vertex_inner;
|
||||
foreach_context.vertex_every_corner = foreach_vertex_every_corner;
|
||||
@@ -883,12 +885,12 @@ static void geometry_create(MultiresReshapeSmoothContext *reshape_smooth_context
|
||||
|
||||
geometry_init_loose_information(reshape_smooth_context);
|
||||
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
blender::bke::subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = get_reshape_level_resolution(reshape_context);
|
||||
mesh_settings.use_optimal_display = false;
|
||||
|
||||
/* TODO(sergey): Tell the foreach() to ignore loose vertices. */
|
||||
BKE_subdiv_foreach_subdiv_geometry(
|
||||
blender::bke::subdiv::foreach_subdiv_geometry(
|
||||
reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
|
||||
}
|
||||
|
||||
@@ -909,10 +911,10 @@ static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
|
||||
const MultiresReshapeSmoothContext *reshape_smooth_context =
|
||||
static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
const SubdivSettings *settings = &reshape_context->subdiv->settings;
|
||||
const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
|
||||
|
||||
return OpenSubdiv_VtxBoundaryInterpolation(
|
||||
BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(settings));
|
||||
blender::bke::subdiv::converter_vtx_boundary_interpolation_from_settings(settings));
|
||||
}
|
||||
|
||||
static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
|
||||
@@ -921,10 +923,10 @@ static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
|
||||
const MultiresReshapeSmoothContext *reshape_smooth_context =
|
||||
static_cast<const MultiresReshapeSmoothContext *>(converter->user_data);
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
const SubdivSettings *settings = &reshape_context->subdiv->settings;
|
||||
const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
|
||||
|
||||
return OpenSubdiv_FVarLinearInterpolation(
|
||||
BKE_subdiv_converter_fvar_linear_from_settings(settings));
|
||||
blender::bke::subdiv::converter_fvar_linear_from_settings(settings));
|
||||
}
|
||||
|
||||
static bool specifies_full_topology(const OpenSubdiv_Converter * /*converter*/)
|
||||
@@ -1069,19 +1071,23 @@ static void converter_init(const MultiresReshapeSmoothContext *reshape_smooth_co
|
||||
static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_context)
|
||||
{
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
const SubdivSettings *settings = &reshape_context->subdiv->settings;
|
||||
const blender::bke::subdiv::Settings *settings = &reshape_context->subdiv->settings;
|
||||
|
||||
OpenSubdiv_Converter converter;
|
||||
converter_init(reshape_smooth_context, &converter);
|
||||
|
||||
Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter);
|
||||
blender::bke::subdiv::Subdiv *reshape_subdiv = blender::bke::subdiv::new_from_converter(
|
||||
settings, &converter);
|
||||
|
||||
OpenSubdiv_EvaluatorSettings evaluator_settings = {0};
|
||||
BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, nullptr, &evaluator_settings);
|
||||
blender::bke::subdiv::eval_begin(reshape_subdiv,
|
||||
blender::bke::subdiv::SUBDIV_EVALUATOR_TYPE_CPU,
|
||||
nullptr,
|
||||
&evaluator_settings);
|
||||
|
||||
reshape_smooth_context->reshape_subdiv = reshape_subdiv;
|
||||
|
||||
BKE_subdiv_converter_free(&converter);
|
||||
blender::bke::subdiv::converter_free(&converter);
|
||||
}
|
||||
|
||||
/* Callback to provide coarse position for subdivision surface topology at a reshape level. */
|
||||
@@ -1094,7 +1100,7 @@ using ReshapeSubdivCoarsePositionCb =
|
||||
static void reshape_subdiv_refine(const MultiresReshapeSmoothContext *reshape_smooth_context,
|
||||
ReshapeSubdivCoarsePositionCb coarse_position_cb)
|
||||
{
|
||||
Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
|
||||
blender::bke::subdiv::Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
|
||||
|
||||
/* TODO(sergey): For non-trivial coarse_position_cb we should multi-thread this loop. */
|
||||
|
||||
@@ -1186,13 +1192,13 @@ static void reshape_subdiv_evaluate_limit_at_grid(
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
|
||||
float dPdu[3], dPdv[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(reshape_smooth_context->reshape_subdiv,
|
||||
ptex_coord->ptex_face_index,
|
||||
ptex_coord->u,
|
||||
ptex_coord->v,
|
||||
limit_P,
|
||||
dPdu,
|
||||
dPdv);
|
||||
blender::bke::subdiv::eval_limit_point_and_derivatives(reshape_smooth_context->reshape_subdiv,
|
||||
ptex_coord->ptex_face_index,
|
||||
ptex_coord->u,
|
||||
ptex_coord->v,
|
||||
limit_P,
|
||||
dPdu,
|
||||
dPdv);
|
||||
|
||||
const int face_index = multires_reshape_grid_to_face_index(reshape_context,
|
||||
grid_coord->grid_index);
|
||||
@@ -1252,7 +1258,7 @@ static void linear_grid_element_delta_interpolate(
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
|
||||
const int reshape_level = reshape_context->reshape.level;
|
||||
const int reshape_level_grid_size = BKE_subdiv_grid_size_from_level(reshape_level);
|
||||
const int reshape_level_grid_size = blender::bke::subdiv::grid_size_from_level(reshape_level);
|
||||
const int reshape_level_grid_size_1 = reshape_level_grid_size - 1;
|
||||
const float reshape_level_grid_size_1_inv = 1.0f / float(reshape_level_grid_size_1);
|
||||
|
||||
@@ -1452,14 +1458,14 @@ static void evaluate_higher_grid_positions_callback(
|
||||
void * /*userdata_v*/)
|
||||
{
|
||||
const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
|
||||
Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
|
||||
blender::bke::subdiv::Subdiv *reshape_subdiv = reshape_smooth_context->reshape_subdiv;
|
||||
|
||||
ReshapeGridElement grid_element = multires_reshape_grid_element_for_grid_coord(reshape_context,
|
||||
grid_coord);
|
||||
|
||||
/* Surface. */
|
||||
float P[3];
|
||||
BKE_subdiv_eval_limit_point(
|
||||
blender::bke::subdiv::eval_limit_point(
|
||||
reshape_subdiv, ptex_coord->ptex_face_index, ptex_coord->u, ptex_coord->v, P);
|
||||
|
||||
copy_v3_v3(grid_element.displacement, P);
|
||||
|
||||
@@ -32,10 +32,11 @@
|
||||
/** \name Construct/destruct reshape context
|
||||
* \{ */
|
||||
|
||||
Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
|
||||
/*const*/ Object *object,
|
||||
const MultiresModifierData *mmd)
|
||||
blender::bke::subdiv::Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
|
||||
/*const*/ Object *object,
|
||||
const MultiresModifierData *mmd)
|
||||
{
|
||||
using namespace blender::bke;
|
||||
Mesh *base_mesh;
|
||||
|
||||
if (depsgraph != nullptr) {
|
||||
@@ -47,13 +48,13 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph,
|
||||
base_mesh = (Mesh *)object->data;
|
||||
}
|
||||
|
||||
SubdivSettings subdiv_settings;
|
||||
subdiv::Settings subdiv_settings;
|
||||
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh);
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
subdiv, base_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
subdiv::Subdiv *subdiv = subdiv::new_from_mesh(&subdiv_settings, base_mesh);
|
||||
if (!subdiv::eval_begin_from_mesh(
|
||||
subdiv, base_mesh, nullptr, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
BKE_subdiv_free(subdiv);
|
||||
subdiv::free(subdiv);
|
||||
return nullptr;
|
||||
}
|
||||
return subdiv;
|
||||
@@ -115,7 +116,8 @@ static void context_init_commoon(MultiresReshapeContext *reshape_context)
|
||||
BLI_assert(reshape_context->subdiv != nullptr);
|
||||
BLI_assert(reshape_context->base_mesh != nullptr);
|
||||
|
||||
reshape_context->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(reshape_context->subdiv);
|
||||
reshape_context->face_ptex_offset = blender::bke::subdiv::face_ptex_offset_get(
|
||||
reshape_context->subdiv);
|
||||
|
||||
context_init_lookup(reshape_context);
|
||||
context_init_grid_pointers(reshape_context);
|
||||
@@ -166,11 +168,12 @@ bool multires_reshape_context_create_from_base_mesh(MultiresReshapeContext *resh
|
||||
|
||||
reshape_context->reshape.level = multires_get_level(
|
||||
scene_eval, object, mmd, use_render_params, true);
|
||||
reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
|
||||
reshape_context->reshape.grid_size = blender::bke::subdiv::grid_size_from_level(
|
||||
reshape_context->reshape.level);
|
||||
|
||||
reshape_context->top.level = mmd->totlvl;
|
||||
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
|
||||
reshape_context->top.grid_size = blender::bke::subdiv::grid_size_from_level(
|
||||
reshape_context->top.level);
|
||||
|
||||
context_init_commoon(reshape_context);
|
||||
|
||||
@@ -206,11 +209,11 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
|
||||
|
||||
reshape_context->reshape.level = multires_get_level(
|
||||
scene_eval, object, mmd, use_render_params, true);
|
||||
reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
|
||||
reshape_context->reshape.grid_size = subdiv::grid_size_from_level(
|
||||
reshape_context->reshape.level);
|
||||
|
||||
reshape_context->top.level = mmd->totlvl;
|
||||
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
|
||||
reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
|
||||
|
||||
const bke::AttributeAccessor attributes = base_mesh->attributes();
|
||||
reshape_context->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
|
||||
@@ -239,11 +242,12 @@ bool multires_reshape_context_create_from_ccg(MultiresReshapeContext *reshape_co
|
||||
reshape_context->need_free_subdiv = false;
|
||||
|
||||
reshape_context->reshape.level = subdiv_ccg->level;
|
||||
reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
|
||||
reshape_context->reshape.grid_size = blender::bke::subdiv::grid_size_from_level(
|
||||
reshape_context->reshape.level);
|
||||
|
||||
reshape_context->top.level = top_level;
|
||||
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
|
||||
reshape_context->top.grid_size = blender::bke::subdiv::grid_size_from_level(
|
||||
reshape_context->top.level);
|
||||
|
||||
context_init_commoon(reshape_context);
|
||||
|
||||
@@ -255,7 +259,7 @@ bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *resha
|
||||
MultiresModifierData *mmd,
|
||||
int top_level)
|
||||
{
|
||||
Subdiv *subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
|
||||
blender::bke::subdiv::Subdiv *subdiv = multires_reshape_create_subdiv(nullptr, object, mmd);
|
||||
|
||||
const bool result = multires_reshape_context_create_from_subdiv(
|
||||
reshape_context, object, mmd, subdiv, top_level);
|
||||
@@ -268,7 +272,7 @@ bool multires_reshape_context_create_from_modifier(MultiresReshapeContext *resha
|
||||
bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape_context,
|
||||
Object *object,
|
||||
MultiresModifierData *mmd,
|
||||
Subdiv *subdiv,
|
||||
blender::bke::subdiv::Subdiv *subdiv,
|
||||
int top_level)
|
||||
{
|
||||
using namespace blender;
|
||||
@@ -292,11 +296,11 @@ bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape
|
||||
reshape_context->need_free_subdiv = false;
|
||||
|
||||
reshape_context->reshape.level = mmd->totlvl;
|
||||
reshape_context->reshape.grid_size = BKE_subdiv_grid_size_from_level(
|
||||
reshape_context->reshape.grid_size = subdiv::grid_size_from_level(
|
||||
reshape_context->reshape.level);
|
||||
|
||||
reshape_context->top.level = top_level;
|
||||
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
|
||||
reshape_context->top.grid_size = subdiv::grid_size_from_level(reshape_context->top.level);
|
||||
|
||||
context_init_commoon(reshape_context);
|
||||
|
||||
@@ -334,7 +338,7 @@ void multires_reshape_free_original_grids(MultiresReshapeContext *reshape_contex
|
||||
void multires_reshape_context_free(MultiresReshapeContext *reshape_context)
|
||||
{
|
||||
if (reshape_context->need_free_subdiv) {
|
||||
BKE_subdiv_free(reshape_context->subdiv);
|
||||
blender::bke::subdiv::free(reshape_context->subdiv);
|
||||
}
|
||||
|
||||
multires_reshape_free_original_grids(reshape_context);
|
||||
@@ -397,15 +401,17 @@ PTexCoord multires_reshape_grid_coord_to_ptex(const MultiresReshapeContext *resh
|
||||
grid_coord->grid_index);
|
||||
|
||||
float corner_u, corner_v;
|
||||
BKE_subdiv_grid_uv_to_ptex_face_uv(grid_coord->u, grid_coord->v, &corner_u, &corner_v);
|
||||
blender::bke::subdiv::grid_uv_to_ptex_face_uv(
|
||||
grid_coord->u, grid_coord->v, &corner_u, &corner_v);
|
||||
|
||||
const int face_index = multires_reshape_grid_to_face_index(reshape_context,
|
||||
grid_coord->grid_index);
|
||||
const int corner = multires_reshape_grid_to_corner(reshape_context, grid_coord->grid_index);
|
||||
if (multires_reshape_is_quad_face(reshape_context, face_index)) {
|
||||
float grid_u, grid_v;
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
|
||||
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v);
|
||||
blender::bke::subdiv::ptex_face_uv_to_grid_uv(corner_u, corner_v, &grid_u, &grid_v);
|
||||
blender::bke::subdiv::rotate_grid_to_quad(
|
||||
corner, grid_u, grid_v, &ptex_coord.u, &ptex_coord.v);
|
||||
}
|
||||
else {
|
||||
ptex_coord.u = corner_u;
|
||||
@@ -425,7 +431,7 @@ GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *resh
|
||||
|
||||
int corner_delta;
|
||||
if (multires_reshape_is_quad_face(reshape_context, face_index)) {
|
||||
corner_delta = BKE_subdiv_rotate_quad_to_corner(
|
||||
corner_delta = blender::bke::subdiv::rotate_quad_to_corner(
|
||||
ptex_coord->u, ptex_coord->v, &grid_coord.u, &grid_coord.v);
|
||||
}
|
||||
else {
|
||||
@@ -435,7 +441,8 @@ GridCoord multires_reshape_ptex_coord_to_grid(const MultiresReshapeContext *resh
|
||||
}
|
||||
grid_coord.grid_index = start_grid_index + corner_delta;
|
||||
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v);
|
||||
blender::bke::subdiv::ptex_face_uv_to_grid_uv(
|
||||
grid_coord.u, grid_coord.v, &grid_coord.u, &grid_coord.v);
|
||||
|
||||
return grid_coord;
|
||||
}
|
||||
@@ -493,7 +500,7 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
|
||||
if (mdisps != nullptr) {
|
||||
const MDisps *displacement_grid = &mdisps[grid_coord->grid_index];
|
||||
if (displacement_grid->disps != nullptr) {
|
||||
const int grid_size = BKE_subdiv_grid_size_from_level(displacement_grid->level);
|
||||
const int grid_size = blender::bke::subdiv::grid_size_from_level(displacement_grid->level);
|
||||
const int grid_x = lround(grid_coord->u * (grid_size - 1));
|
||||
const int grid_y = lround(grid_coord->v * (grid_size - 1));
|
||||
const int grid_element_index = grid_y * grid_size + grid_x;
|
||||
@@ -505,7 +512,7 @@ ReshapeConstGridElement multires_reshape_orig_grid_element_for_grid_coord(
|
||||
if (grid_paint_masks != nullptr) {
|
||||
const GridPaintMask *paint_mask_grid = &grid_paint_masks[grid_coord->grid_index];
|
||||
if (paint_mask_grid->data != nullptr) {
|
||||
const int grid_size = BKE_subdiv_grid_size_from_level(paint_mask_grid->level);
|
||||
const int grid_size = blender::bke::subdiv::grid_size_from_level(paint_mask_grid->level);
|
||||
const int grid_x = lround(grid_coord->u * (grid_size - 1));
|
||||
const int grid_y = lround(grid_coord->v * (grid_size - 1));
|
||||
const int grid_element_index = grid_y * grid_size + grid_x;
|
||||
@@ -529,8 +536,8 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
|
||||
{
|
||||
float dPdu[3], dPdv[3];
|
||||
const PTexCoord ptex_coord = multires_reshape_grid_coord_to_ptex(reshape_context, grid_coord);
|
||||
Subdiv *subdiv = reshape_context->subdiv;
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(
|
||||
blender::bke::subdiv::Subdiv *subdiv = reshape_context->subdiv;
|
||||
blender::bke::subdiv::eval_limit_point_and_derivatives(
|
||||
subdiv, ptex_coord.ptex_face_index, ptex_coord.u, ptex_coord.v, r_P, dPdu, dPdv);
|
||||
|
||||
const int face_index = multires_reshape_grid_to_face_index(reshape_context,
|
||||
@@ -548,7 +555,7 @@ void multires_reshape_evaluate_limit_at_grid(const MultiresReshapeContext *resha
|
||||
|
||||
static void allocate_displacement_grid(MDisps *displacement_grid, const int level)
|
||||
{
|
||||
const int grid_size = BKE_subdiv_grid_size_from_level(level);
|
||||
const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
|
||||
const int grid_area = grid_size * grid_size;
|
||||
float(*disps)[3] = static_cast<float(*)[3]>(
|
||||
MEM_calloc_arrayN(grid_area, sizeof(float[3]), "multires disps"));
|
||||
@@ -587,7 +594,7 @@ static void ensure_mask_grids(Mesh *mesh, const int level)
|
||||
return;
|
||||
}
|
||||
const int num_grids = mesh->corners_num;
|
||||
const int grid_size = BKE_subdiv_grid_size_from_level(level);
|
||||
const int grid_size = blender::bke::subdiv::grid_size_from_level(level);
|
||||
const int grid_area = grid_size * grid_size;
|
||||
for (int grid_index = 0; grid_index < num_grids; grid_index++) {
|
||||
GridPaintMask *grid_paint_mask = &grid_paint_masks[grid_index];
|
||||
@@ -703,7 +710,7 @@ static void foreach_grid_coordinate(const MultiresReshapeContext *reshape_contex
|
||||
{
|
||||
ForeachGridCoordinateTaskData data;
|
||||
data.reshape_context = reshape_context;
|
||||
data.grid_size = BKE_subdiv_grid_size_from_level(level);
|
||||
data.grid_size = blender::bke::subdiv::grid_size_from_level(level);
|
||||
data.grid_size_1_inv = 1.0f / (float(data.grid_size) - 1.0f);
|
||||
data.callback = callback;
|
||||
data.callback_userdata_v = userdata_v;
|
||||
|
||||
@@ -25,7 +25,7 @@ struct MultiresReshapeAssignVertcosContext {
|
||||
* This function will be called for every side of a boundary grid points for inner coordinates.
|
||||
*/
|
||||
static void multires_reshape_vertcos_foreach_single_vertex(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const GridCoord *grid_coord,
|
||||
const int subdiv_vertex_index)
|
||||
{
|
||||
@@ -40,9 +40,10 @@ static void multires_reshape_vertcos_foreach_single_vertex(
|
||||
}
|
||||
|
||||
/* TODO(sergey): De-duplicate with similar function in multires_reshape_smooth.cc */
|
||||
static void multires_reshape_vertcos_foreach_vertex(const SubdivForeachContext *foreach_context,
|
||||
const PTexCoord *ptex_coord,
|
||||
const int subdiv_vertex_index)
|
||||
static void multires_reshape_vertcos_foreach_vertex(
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const PTexCoord *ptex_coord,
|
||||
const int subdiv_vertex_index)
|
||||
{
|
||||
const MultiresReshapeAssignVertcosContext *reshape_vertcos_context =
|
||||
static_cast<MultiresReshapeAssignVertcosContext *>(foreach_context->user_data);
|
||||
@@ -90,9 +91,9 @@ static void multires_reshape_vertcos_foreach_vertex(const SubdivForeachContext *
|
||||
}
|
||||
}
|
||||
|
||||
/* SubdivForeachContext::topology_info() */
|
||||
/* blender::bke::subdiv::ForeachContext::topology_info() */
|
||||
static bool multires_reshape_vertcos_foreach_topology_info(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
const int num_vertices,
|
||||
const int /*num_edges*/,
|
||||
const int /*num_loops*/,
|
||||
@@ -107,9 +108,9 @@ static bool multires_reshape_vertcos_foreach_topology_info(
|
||||
return true;
|
||||
}
|
||||
|
||||
/* SubdivForeachContext::vertex_inner() */
|
||||
/* blender::bke::subdiv::ForeachContext::vertex_inner() */
|
||||
static void multires_reshape_vertcos_foreach_vertex_inner(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
@@ -125,9 +126,9 @@ static void multires_reshape_vertcos_foreach_vertex_inner(
|
||||
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
/* SubdivForeachContext::vertex_every_corner() */
|
||||
/* blender::bke::subdiv::ForeachContext::vertex_every_corner() */
|
||||
static void multires_reshape_vertcos_foreach_vertex_every_corner(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
@@ -144,9 +145,9 @@ static void multires_reshape_vertcos_foreach_vertex_every_corner(
|
||||
multires_reshape_vertcos_foreach_vertex(foreach_context, &ptex_coord, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
/* SubdivForeachContext::vertex_every_edge() */
|
||||
/* blender::bke::subdiv::ForeachContext::vertex_every_edge() */
|
||||
static void multires_reshape_vertcos_foreach_vertex_every_edge(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const blender::bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float ptex_face_u,
|
||||
@@ -173,17 +174,17 @@ bool multires_reshape_assign_final_coords_from_vertcos(
|
||||
reshape_vertcos_context.vert_coords = vert_coords;
|
||||
reshape_vertcos_context.num_vert_coords = num_vert_coords;
|
||||
|
||||
SubdivForeachContext foreach_context{};
|
||||
blender::bke::subdiv::ForeachContext foreach_context{};
|
||||
foreach_context.topology_info = multires_reshape_vertcos_foreach_topology_info;
|
||||
foreach_context.vertex_inner = multires_reshape_vertcos_foreach_vertex_inner;
|
||||
foreach_context.vertex_every_edge = multires_reshape_vertcos_foreach_vertex_every_edge;
|
||||
foreach_context.vertex_every_corner = multires_reshape_vertcos_foreach_vertex_every_corner;
|
||||
foreach_context.user_data = &reshape_vertcos_context;
|
||||
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
blender::bke::subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = (1 << reshape_context->reshape.level) + 1;
|
||||
mesh_settings.use_optimal_display = false;
|
||||
|
||||
return BKE_subdiv_foreach_subdiv_geometry(
|
||||
return blender::bke::subdiv::foreach_subdiv_geometry(
|
||||
reshape_context->subdiv, &foreach_context, &mesh_settings, reshape_context->base_mesh);
|
||||
}
|
||||
|
||||
@@ -15,19 +15,20 @@
|
||||
#include "BKE_subdiv.hh"
|
||||
#include "BKE_subdiv_mesh.hh"
|
||||
|
||||
void BKE_multires_subdiv_settings_init(SubdivSettings *settings, const MultiresModifierData *mmd)
|
||||
void BKE_multires_subdiv_settings_init(blender::bke::subdiv::Settings *settings,
|
||||
const MultiresModifierData *mmd)
|
||||
{
|
||||
settings->is_simple = false;
|
||||
settings->is_adaptive = true;
|
||||
settings->level = settings->is_simple ? 1 : mmd->quality;
|
||||
settings->use_creases = (mmd->flags & eMultiresModifierFlag_UseCrease);
|
||||
settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
mmd->boundary_smooth);
|
||||
settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
|
||||
settings->vtx_boundary_interpolation =
|
||||
blender::bke::subdiv::vtx_boundary_interpolation_from_subsurf(mmd->boundary_smooth);
|
||||
settings->fvar_linear_interpolation = blender::bke::subdiv::fvar_interpolation_from_uv_smooth(
|
||||
mmd->uv_smooth);
|
||||
}
|
||||
|
||||
void BKE_multires_subdiv_mesh_settings_init(SubdivToMeshSettings *mesh_settings,
|
||||
void BKE_multires_subdiv_mesh_settings_init(blender::bke::subdiv::ToMeshSettings *mesh_settings,
|
||||
const Scene *scene,
|
||||
const Object *object,
|
||||
const MultiresModifierData *mmd,
|
||||
|
||||
@@ -31,25 +31,27 @@ static bool simple_to_catmull_clark_is_infinite_sharp_vertex(
|
||||
return true;
|
||||
}
|
||||
|
||||
static Subdiv *subdiv_for_simple_to_catmull_clark(Object *object, MultiresModifierData *mmd)
|
||||
static blender::bke::subdiv::Subdiv *subdiv_for_simple_to_catmull_clark(Object *object,
|
||||
MultiresModifierData *mmd)
|
||||
{
|
||||
SubdivSettings subdiv_settings;
|
||||
using namespace blender::bke;
|
||||
subdiv::Settings subdiv_settings;
|
||||
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
|
||||
|
||||
const Mesh *base_mesh = static_cast<const Mesh *>(object->data);
|
||||
|
||||
OpenSubdiv_Converter converter;
|
||||
BKE_subdiv_converter_init_for_mesh(&converter, &subdiv_settings, base_mesh);
|
||||
subdiv::converter_init_for_mesh(&converter, &subdiv_settings, base_mesh);
|
||||
converter.getEdgeSharpness = simple_to_catmull_clark_get_edge_sharpness;
|
||||
converter.isInfiniteSharpVertex = simple_to_catmull_clark_is_infinite_sharp_vertex;
|
||||
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_converter(&subdiv_settings, &converter);
|
||||
BKE_subdiv_converter_free(&converter);
|
||||
subdiv::Subdiv *subdiv = subdiv::new_from_converter(&subdiv_settings, &converter);
|
||||
subdiv::converter_free(&converter);
|
||||
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
subdiv, base_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
if (!subdiv::eval_begin_from_mesh(
|
||||
subdiv, base_mesh, nullptr, subdiv::SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
BKE_subdiv_free(subdiv);
|
||||
subdiv::free(subdiv);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -65,12 +67,12 @@ void multires_do_versions_simple_to_catmull_clark(Object *object, MultiresModifi
|
||||
|
||||
/* Store the grids displacement in object space against the simple limit surface. */
|
||||
{
|
||||
Subdiv *subdiv = subdiv_for_simple_to_catmull_clark(object, mmd);
|
||||
blender::bke::subdiv::Subdiv *subdiv = subdiv_for_simple_to_catmull_clark(object, mmd);
|
||||
MultiresReshapeContext reshape_context;
|
||||
if (!multires_reshape_context_create_from_subdiv(
|
||||
&reshape_context, object, mmd, subdiv, mmd->totlvl))
|
||||
{
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,7 +80,7 @@ void multires_do_versions_simple_to_catmull_clark(Object *object, MultiresModifi
|
||||
multires_reshape_assign_final_coords_from_mdisps(&reshape_context);
|
||||
multires_reshape_context_free(&reshape_context);
|
||||
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
}
|
||||
|
||||
/* Calculate the new tangent displacement against the new Catmull-Clark limit surface. */
|
||||
|
||||
@@ -24,16 +24,18 @@
|
||||
#include "opensubdiv_evaluator_capi.hh"
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Module.
|
||||
*/
|
||||
|
||||
void BKE_subdiv_init()
|
||||
void init()
|
||||
{
|
||||
openSubdiv_init();
|
||||
}
|
||||
|
||||
void BKE_subdiv_exit()
|
||||
void exit()
|
||||
{
|
||||
openSubdiv_cleanup();
|
||||
}
|
||||
@@ -42,7 +44,7 @@ void BKE_subdiv_exit()
|
||||
* Conversion helpers.
|
||||
*/
|
||||
|
||||
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
|
||||
FVarLinearInterpolation fvar_interpolation_from_uv_smooth(int uv_smooth)
|
||||
{
|
||||
switch (uv_smooth) {
|
||||
case SUBSURF_UV_SMOOTH_NONE:
|
||||
@@ -62,8 +64,7 @@ eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int
|
||||
return SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
|
||||
}
|
||||
|
||||
eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
int boundary_smooth)
|
||||
VtxBoundaryInterpolation vtx_boundary_interpolation_from_subsurf(int boundary_smooth)
|
||||
{
|
||||
switch (boundary_smooth) {
|
||||
case SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS:
|
||||
@@ -79,7 +80,7 @@ eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsu
|
||||
* Settings.
|
||||
*/
|
||||
|
||||
bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSettings *settings_b)
|
||||
bool settings_equal(const Settings *settings_a, const Settings *settings_b)
|
||||
{
|
||||
return (settings_a->is_simple == settings_b->is_simple &&
|
||||
settings_a->is_adaptive == settings_b->is_adaptive &&
|
||||
@@ -94,12 +95,11 @@ bool BKE_subdiv_settings_equal(const SubdivSettings *settings_a, const SubdivSet
|
||||
|
||||
/* Creation from scratch. */
|
||||
|
||||
Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
|
||||
OpenSubdiv_Converter *converter)
|
||||
Subdiv *new_from_converter(const Settings *settings, OpenSubdiv_Converter *converter)
|
||||
{
|
||||
SubdivStats stats;
|
||||
BKE_subdiv_stats_init(&stats);
|
||||
BKE_subdiv_stats_begin(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
|
||||
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;
|
||||
@@ -118,40 +118,40 @@ Subdiv *BKE_subdiv_new_from_converter(const SubdivSettings *settings,
|
||||
subdiv->topology_refiner = osd_topology_refiner;
|
||||
subdiv->evaluator = nullptr;
|
||||
subdiv->displacement_evaluator = nullptr;
|
||||
BKE_subdiv_stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
|
||||
stats_end(&stats, SUBDIV_STATS_TOPOLOGY_REFINER_CREATION_TIME);
|
||||
subdiv->stats = stats;
|
||||
return subdiv;
|
||||
}
|
||||
|
||||
Subdiv *BKE_subdiv_new_from_mesh(const SubdivSettings *settings, const Mesh *mesh)
|
||||
Subdiv *new_from_mesh(const Settings *settings, const Mesh *mesh)
|
||||
{
|
||||
if (mesh->verts_num == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
OpenSubdiv_Converter converter;
|
||||
BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_converter(settings, &converter);
|
||||
BKE_subdiv_converter_free(&converter);
|
||||
converter_init_for_mesh(&converter, settings, mesh);
|
||||
Subdiv *subdiv = new_from_converter(settings, &converter);
|
||||
converter_free(&converter);
|
||||
return subdiv;
|
||||
}
|
||||
|
||||
/* Creation with cached-aware semantic. */
|
||||
|
||||
Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
|
||||
const SubdivSettings *settings,
|
||||
OpenSubdiv_Converter *converter)
|
||||
Subdiv *update_from_converter(Subdiv *subdiv,
|
||||
const Settings *settings,
|
||||
OpenSubdiv_Converter *converter)
|
||||
{
|
||||
/* Check if the existing descriptor can be re-used. */
|
||||
bool can_reuse_subdiv = true;
|
||||
if (subdiv != nullptr && subdiv->topology_refiner != nullptr) {
|
||||
if (!BKE_subdiv_settings_equal(&subdiv->settings, settings)) {
|
||||
if (!settings_equal(&subdiv->settings, settings)) {
|
||||
can_reuse_subdiv = false;
|
||||
}
|
||||
else {
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
can_reuse_subdiv = openSubdiv_topologyRefinerCompareWithConverter(subdiv->topology_refiner,
|
||||
converter);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_TOPOLOGY_COMPARE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -162,25 +162,23 @@ Subdiv *BKE_subdiv_update_from_converter(Subdiv *subdiv,
|
||||
}
|
||||
/* Create new subdiv. */
|
||||
if (subdiv != nullptr) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
free(subdiv);
|
||||
}
|
||||
return BKE_subdiv_new_from_converter(settings, converter);
|
||||
return new_from_converter(settings, converter);
|
||||
}
|
||||
|
||||
Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv,
|
||||
const SubdivSettings *settings,
|
||||
const Mesh *mesh)
|
||||
Subdiv *update_from_mesh(Subdiv *subdiv, const Settings *settings, const Mesh *mesh)
|
||||
{
|
||||
OpenSubdiv_Converter converter;
|
||||
BKE_subdiv_converter_init_for_mesh(&converter, settings, mesh);
|
||||
subdiv = BKE_subdiv_update_from_converter(subdiv, settings, &converter);
|
||||
BKE_subdiv_converter_free(&converter);
|
||||
converter_init_for_mesh(&converter, settings, mesh);
|
||||
subdiv = update_from_converter(subdiv, settings, &converter);
|
||||
converter_free(&converter);
|
||||
return subdiv;
|
||||
}
|
||||
|
||||
/* Memory release. */
|
||||
|
||||
void BKE_subdiv_free(Subdiv *subdiv)
|
||||
void free(Subdiv *subdiv)
|
||||
{
|
||||
if (subdiv->evaluator != nullptr) {
|
||||
const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type;
|
||||
@@ -194,7 +192,7 @@ void BKE_subdiv_free(Subdiv *subdiv)
|
||||
if (subdiv->topology_refiner != nullptr) {
|
||||
openSubdiv_deleteTopologyRefiner(subdiv->topology_refiner);
|
||||
}
|
||||
BKE_subdiv_displacement_detach(subdiv);
|
||||
displacement_detach(subdiv);
|
||||
if (subdiv->cache_.face_ptex_offset != nullptr) {
|
||||
MEM_freeN(subdiv->cache_.face_ptex_offset);
|
||||
}
|
||||
@@ -205,7 +203,7 @@ void BKE_subdiv_free(Subdiv *subdiv)
|
||||
* Topology helpers.
|
||||
*/
|
||||
|
||||
int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
|
||||
int *face_ptex_offset_get(Subdiv *subdiv)
|
||||
{
|
||||
if (subdiv->cache_.face_ptex_offset != nullptr) {
|
||||
return subdiv->cache_.face_ptex_offset;
|
||||
@@ -226,3 +224,5 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv)
|
||||
subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset;
|
||||
return subdiv->cache_.face_ptex_offset;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -38,6 +38,7 @@ using blender::OffsetIndices;
|
||||
using blender::Span;
|
||||
using blender::Vector;
|
||||
using blender::VectorSet;
|
||||
using namespace blender::bke::subdiv;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Various forward declarations
|
||||
@@ -131,7 +132,7 @@ static void subdiv_ccg_alloc_elements(SubdivCCG &subdiv_ccg, Subdiv &subdiv)
|
||||
const int64_t element_size = element_size_bytes_get(subdiv_ccg);
|
||||
/* Allocate memory for surface grids. */
|
||||
const int64_t num_grids = topology_refiner_count_face_corners(topology_refiner);
|
||||
const int64_t grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg.level);
|
||||
const int64_t grid_size = grid_size_from_level(subdiv_ccg.level);
|
||||
const int64_t grid_area = grid_size * grid_size;
|
||||
subdiv_ccg.grid_element_size = element_size;
|
||||
subdiv_ccg.grids.reinitialize(num_grids);
|
||||
@@ -158,18 +159,18 @@ static void subdiv_ccg_eval_grid_element_limit(Subdiv &subdiv,
|
||||
uchar *element)
|
||||
{
|
||||
if (subdiv.displacement_evaluator != nullptr) {
|
||||
BKE_subdiv_eval_final_point(&subdiv, ptex_face_index, u, v, (float *)element);
|
||||
eval_final_point(&subdiv, ptex_face_index, u, v, (float *)element);
|
||||
}
|
||||
else if (subdiv_ccg.has_normal) {
|
||||
BKE_subdiv_eval_limit_point_and_normal(&subdiv,
|
||||
ptex_face_index,
|
||||
u,
|
||||
v,
|
||||
(float *)element,
|
||||
(float *)(element + subdiv_ccg.normal_offset));
|
||||
eval_limit_point_and_normal(&subdiv,
|
||||
ptex_face_index,
|
||||
u,
|
||||
v,
|
||||
(float *)element,
|
||||
(float *)(element + subdiv_ccg.normal_offset));
|
||||
}
|
||||
else {
|
||||
BKE_subdiv_eval_limit_point(&subdiv, ptex_face_index, u, v, (float *)element);
|
||||
eval_limit_point(&subdiv, ptex_face_index, u, v, (float *)element);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +224,7 @@ static void subdiv_ccg_eval_regular_grid(Subdiv &subdiv,
|
||||
for (int x = 0; x < grid_size; x++) {
|
||||
const float grid_u = x * grid_size_1_inv;
|
||||
float u, v;
|
||||
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
|
||||
rotate_grid_to_quad(corner, grid_u, grid_v, &u, &v);
|
||||
const size_t grid_element_index = size_t(y) * grid_size + x;
|
||||
const size_t grid_element_offset = grid_element_index * element_size;
|
||||
subdiv_ccg_eval_grid_element(
|
||||
@@ -267,8 +268,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 Span<int> face_ptex_offset(BKE_subdiv_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) {
|
||||
for (const int face_index : range) {
|
||||
if (subdiv_ccg.faces[face_index].size() == 4) {
|
||||
@@ -460,21 +460,21 @@ std::unique_ptr<SubdivCCG> BKE_subdiv_to_ccg(Subdiv &subdiv,
|
||||
const Mesh &coarse_mesh,
|
||||
SubdivCCGMaskEvaluator *mask_evaluator)
|
||||
{
|
||||
BKE_subdiv_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>();
|
||||
subdiv_ccg->subdiv = &subdiv;
|
||||
subdiv_ccg->level = bitscan_forward_i(settings.resolution - 1);
|
||||
subdiv_ccg->grid_size = BKE_subdiv_grid_size_from_level(subdiv_ccg->level);
|
||||
subdiv_ccg->grid_size = grid_size_from_level(subdiv_ccg->level);
|
||||
subdiv_ccg_init_layers(*subdiv_ccg, settings);
|
||||
subdiv_ccg->faces = coarse_mesh.faces();
|
||||
subdiv_ccg->grid_to_face_map = coarse_mesh.corner_to_face_map();
|
||||
subdiv_ccg_alloc_elements(*subdiv_ccg, subdiv);
|
||||
subdiv_ccg_init_faces_neighborhood(*subdiv_ccg);
|
||||
if (!subdiv_ccg_evaluate_grids(*subdiv_ccg, subdiv, mask_evaluator)) {
|
||||
BKE_subdiv_stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
return nullptr;
|
||||
}
|
||||
BKE_subdiv_stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
return subdiv_ccg;
|
||||
}
|
||||
|
||||
@@ -483,15 +483,13 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
|
||||
const Mesh &coarse_mesh)
|
||||
{
|
||||
/* Make sure evaluator is ready. */
|
||||
BKE_subdiv_stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
&subdiv, &coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
stats_begin(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
if (!eval_begin_from_mesh(&subdiv, &coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
|
||||
if (coarse_mesh.faces_num) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
BKE_subdiv_stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
stats_end(&subdiv.stats, SUBDIV_STATS_SUBDIV_TO_CCG);
|
||||
SubdivCCGMaskEvaluator mask_evaluator;
|
||||
bool has_mask = BKE_subdiv_ccg_mask_init_from_paint(&mask_evaluator, &coarse_mesh);
|
||||
std::unique_ptr<SubdivCCG> subdiv_ccg = BKE_subdiv_to_ccg(
|
||||
@@ -510,7 +508,7 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv &subdiv,
|
||||
SubdivCCG::~SubdivCCG()
|
||||
{
|
||||
if (this->subdiv != nullptr) {
|
||||
BKE_subdiv_free(this->subdiv);
|
||||
free(this->subdiv);
|
||||
}
|
||||
|
||||
for (const int i : this->adjacent_edges.index_range()) {
|
||||
@@ -532,7 +530,7 @@ CCGKey BKE_subdiv_ccg_key(const SubdivCCG &subdiv_ccg, int level)
|
||||
CCGKey key;
|
||||
key.level = level;
|
||||
key.elem_size = element_size_bytes_get(subdiv_ccg);
|
||||
key.grid_size = BKE_subdiv_grid_size_from_level(level);
|
||||
key.grid_size = grid_size_from_level(level);
|
||||
key.grid_area = key.grid_size * key.grid_size;
|
||||
key.grid_bytes = key.elem_size * key.grid_area;
|
||||
|
||||
@@ -1639,13 +1637,13 @@ static void subdiv_ccg_coord_to_ptex_coord(const SubdivCCG &subdiv_ccg,
|
||||
const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord.grid_index);
|
||||
const OffsetIndices<int> faces = subdiv_ccg.faces;
|
||||
const IndexRange face = faces[face_index];
|
||||
const int *face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
|
||||
const int *face_ptex_offset = face_ptex_offset_get(subdiv);
|
||||
*r_ptex_face_index = face_ptex_offset[face_index];
|
||||
|
||||
const float corner = coord.grid_index - face.start();
|
||||
|
||||
if (face.size() == 4) {
|
||||
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_u, r_v);
|
||||
rotate_grid_to_quad(corner, grid_u, grid_v, r_u, r_v);
|
||||
}
|
||||
else {
|
||||
*r_ptex_face_index += corner;
|
||||
@@ -1662,7 +1660,7 @@ void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG &subdiv_ccg,
|
||||
int ptex_face_index;
|
||||
float u, v;
|
||||
subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, &ptex_face_index, &u, &v);
|
||||
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_point);
|
||||
eval_limit_point(subdiv, ptex_face_index, u, v, r_point);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using namespace blender::bke::subdiv;
|
||||
|
||||
struct PolyCornerIndex {
|
||||
int face_index;
|
||||
int corner;
|
||||
@@ -53,13 +55,13 @@ static int mask_get_grid_and_coord(SubdivCCGMaskEvaluator *mask_evaluator,
|
||||
int corner = 0;
|
||||
if (face.size() == 4) {
|
||||
float corner_u, corner_v;
|
||||
corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
|
||||
corner = rotate_quad_to_corner(u, v, &corner_u, &corner_v);
|
||||
*r_mask_grid = &data->grid_paint_mask[start_grid_index + corner];
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
|
||||
ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
|
||||
}
|
||||
else {
|
||||
*r_mask_grid = &data->grid_paint_mask[start_grid_index];
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
|
||||
ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
|
||||
}
|
||||
return corner;
|
||||
}
|
||||
@@ -71,7 +73,7 @@ BLI_INLINE float read_mask_grid(const GridPaintMask *mask_grid,
|
||||
if (mask_grid->data == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
const int grid_size = BKE_subdiv_grid_size_from_level(mask_grid->level);
|
||||
const int grid_size = grid_size_from_level(mask_grid->level);
|
||||
const int x = roundf(grid_u * (grid_size - 1));
|
||||
const int y = roundf(grid_v * (grid_size - 1));
|
||||
return mask_grid->data[y * grid_size + x];
|
||||
|
||||
@@ -10,14 +10,16 @@
|
||||
|
||||
#include "opensubdiv_converter_capi.hh"
|
||||
|
||||
void BKE_subdiv_converter_free(OpenSubdiv_Converter *converter)
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
void converter_free(OpenSubdiv_Converter *converter)
|
||||
{
|
||||
if (converter->freeUserData) {
|
||||
converter->freeUserData(converter);
|
||||
}
|
||||
}
|
||||
|
||||
int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSettings *settings)
|
||||
int converter_vtx_boundary_interpolation_from_settings(const Settings *settings)
|
||||
{
|
||||
switch (settings->vtx_boundary_interpolation) {
|
||||
case SUBDIV_VTX_BOUNDARY_NONE:
|
||||
@@ -31,8 +33,8 @@ int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSe
|
||||
return OSD_VTX_BOUNDARY_EDGE_ONLY;
|
||||
}
|
||||
|
||||
/*OpenSubdiv_FVarLinearInterpolation*/ int BKE_subdiv_converter_fvar_linear_from_settings(
|
||||
const SubdivSettings *settings)
|
||||
/*OpenSubdiv_FVarLinearInterpolation*/ int converter_fvar_linear_from_settings(
|
||||
const Settings *settings)
|
||||
{
|
||||
switch (settings->fvar_linear_interpolation) {
|
||||
case SUBDIV_FVAR_LINEAR_INTERPOLATION_NONE:
|
||||
@@ -51,3 +53,5 @@ int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSe
|
||||
BLI_assert_msg(0, "Unknown fvar linear interpolation");
|
||||
return OSD_FVAR_LINEAR_INTERPOLATION_NONE;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -16,22 +16,27 @@
|
||||
|
||||
struct Mesh;
|
||||
struct OpenSubdiv_Converter;
|
||||
struct SubdivSettings;
|
||||
|
||||
void BKE_subdiv_converter_init_for_mesh(OpenSubdiv_Converter *converter,
|
||||
const SubdivSettings *settings,
|
||||
const Mesh *mesh);
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct Settings;
|
||||
|
||||
void converter_init_for_mesh(OpenSubdiv_Converter *converter,
|
||||
const Settings *settings,
|
||||
const Mesh *mesh);
|
||||
|
||||
/* NOTE: Frees converter data, but not converter itself. This means, that if
|
||||
* converter was allocated on heap, it is up to the user to free that memory. */
|
||||
void BKE_subdiv_converter_free(OpenSubdiv_Converter *converter);
|
||||
void converter_free(OpenSubdiv_Converter *converter);
|
||||
|
||||
/* ============================ INTERNAL HELPERS ============================ */
|
||||
|
||||
/* TODO(sergey): Find a way to make it OpenSubdiv_VtxBoundaryInterpolation,
|
||||
* without breaking compilation without OpenSubdiv. */
|
||||
int BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(const SubdivSettings *settings);
|
||||
int converter_vtx_boundary_interpolation_from_settings(const Settings *settings);
|
||||
|
||||
/* TODO(sergey): Find a way to make it OpenSubdiv_FVarLinearInterpolation,
|
||||
* without breaking compilation without OpenSubdiv. */
|
||||
int BKE_subdiv_converter_fvar_linear_from_settings(const SubdivSettings *settings);
|
||||
int converter_fvar_linear_from_settings(const Settings *settings);
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -22,23 +22,25 @@
|
||||
|
||||
#include "opensubdiv_converter_capi.hh"
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
/* Enable work-around for non-working CPU evaluator when using bilinear scheme.
|
||||
* This forces Catmark scheme with all edges marked as infinitely sharp. */
|
||||
#define BUGGY_SIMPLE_SCHEME_WORKAROUND 1
|
||||
|
||||
struct ConverterStorage {
|
||||
SubdivSettings settings;
|
||||
Settings settings;
|
||||
const Mesh *mesh;
|
||||
blender::Span<blender::float3> vert_positions;
|
||||
blender::Span<blender::int2> edges;
|
||||
blender::OffsetIndices<int> faces;
|
||||
blender::Span<int> corner_verts;
|
||||
blender::Span<int> corner_edges;
|
||||
Span<float3> vert_positions;
|
||||
Span<int2> edges;
|
||||
OffsetIndices<int> faces;
|
||||
Span<int> corner_verts;
|
||||
Span<int> corner_edges;
|
||||
|
||||
/* CustomData layer for vertex sharpnesses. */
|
||||
blender::VArraySpan<float> cd_vertex_crease;
|
||||
VArraySpan<float> cd_vertex_crease;
|
||||
/* CustomData layer for edge sharpness. */
|
||||
blender::VArraySpan<float> cd_edge_crease;
|
||||
VArraySpan<float> cd_edge_crease;
|
||||
/* Indexed by loop index, value denotes index of face-varying vertex
|
||||
* which corresponds to the UV coordinate.
|
||||
*/
|
||||
@@ -55,7 +57,7 @@ struct ConverterStorage {
|
||||
/* Indexed by vertex index from mesh, corresponds to whether this vertex has
|
||||
* infinite sharpness due to non-manifold topology.
|
||||
*/
|
||||
blender::BitVector<> infinite_sharp_vertices_map;
|
||||
BitVector<> infinite_sharp_vertices_map;
|
||||
/* Reverse mapping to above. */
|
||||
int *manifold_vertex_index_reverse;
|
||||
int *manifold_edge_index_reverse;
|
||||
@@ -85,7 +87,7 @@ static OpenSubdiv_VtxBoundaryInterpolation get_vtx_boundary_interpolation(
|
||||
{
|
||||
ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
|
||||
return OpenSubdiv_VtxBoundaryInterpolation(
|
||||
BKE_subdiv_converter_vtx_boundary_interpolation_from_settings(&storage->settings));
|
||||
converter_vtx_boundary_interpolation_from_settings(&storage->settings));
|
||||
}
|
||||
|
||||
static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
|
||||
@@ -93,7 +95,7 @@ static OpenSubdiv_FVarLinearInterpolation get_fvar_linear_interpolation(
|
||||
{
|
||||
ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
|
||||
return OpenSubdiv_FVarLinearInterpolation(
|
||||
BKE_subdiv_converter_fvar_linear_from_settings(&storage->settings));
|
||||
converter_fvar_linear_from_settings(&storage->settings));
|
||||
}
|
||||
|
||||
static bool specifies_full_topology(const OpenSubdiv_Converter * /*converter*/)
|
||||
@@ -130,7 +132,7 @@ static void get_face_vertices(const OpenSubdiv_Converter *converter,
|
||||
int *manifold_face_vertices)
|
||||
{
|
||||
ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
|
||||
const blender::IndexRange face = storage->faces[manifold_face_index];
|
||||
const IndexRange face = storage->faces[manifold_face_index];
|
||||
for (int i = 0; i < face.size(); i++) {
|
||||
const int vert = storage->corner_verts[face[i]];
|
||||
manifold_face_vertices[i] = storage->manifold_vertex_index[vert];
|
||||
@@ -143,7 +145,7 @@ static void get_edge_vertices(const OpenSubdiv_Converter *converter,
|
||||
{
|
||||
ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
|
||||
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
|
||||
const blender::int2 &edge = storage->edges[edge_index];
|
||||
const int2 &edge = storage->edges[edge_index];
|
||||
manifold_edge_vertices[0] = storage->manifold_vertex_index[edge[0]];
|
||||
manifold_edge_vertices[1] = storage->manifold_vertex_index[edge[1]];
|
||||
}
|
||||
@@ -160,7 +162,7 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
|
||||
return 0.0f;
|
||||
}
|
||||
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
|
||||
return BKE_subdiv_crease_to_sharpness_f(storage->cd_edge_crease[edge_index]);
|
||||
return crease_to_sharpness(storage->cd_edge_crease[edge_index]);
|
||||
}
|
||||
|
||||
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
|
||||
@@ -186,7 +188,7 @@ static float get_vertex_sharpness(const OpenSubdiv_Converter *converter, int man
|
||||
return 0.0f;
|
||||
}
|
||||
const int vertex_index = storage->manifold_vertex_index_reverse[manifold_vertex_index];
|
||||
return BKE_subdiv_crease_to_sharpness_f(storage->cd_vertex_crease[vertex_index]);
|
||||
return crease_to_sharpness(storage->cd_vertex_crease[vertex_index]);
|
||||
}
|
||||
|
||||
static int get_num_uv_layers(const OpenSubdiv_Converter *converter)
|
||||
@@ -226,7 +228,7 @@ static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int la
|
||||
if (uv_vert->separate) {
|
||||
storage->num_uv_coordinates++;
|
||||
}
|
||||
const blender::IndexRange face = storage->faces[uv_vert->face_index];
|
||||
const IndexRange face = storage->faces[uv_vert->face_index];
|
||||
const int global_loop_index = face.start() + uv_vert->loop_of_face_index;
|
||||
storage->loop_uv_indices[global_loop_index] = storage->num_uv_coordinates;
|
||||
uv_vert = uv_vert->next;
|
||||
@@ -252,7 +254,7 @@ static int get_face_corner_uv_index(const OpenSubdiv_Converter *converter,
|
||||
const int corner)
|
||||
{
|
||||
ConverterStorage *storage = static_cast<ConverterStorage *>(converter->user_data);
|
||||
const blender::IndexRange face = storage->faces[face_index];
|
||||
const IndexRange face = storage->faces[face_index];
|
||||
return storage->loop_uv_indices[face.start() + corner];
|
||||
}
|
||||
|
||||
@@ -302,7 +304,7 @@ static void init_functions(OpenSubdiv_Converter *converter)
|
||||
converter->freeUserData = free_user_data;
|
||||
}
|
||||
|
||||
static void initialize_manifold_index_array(const blender::BitSpan not_used_map,
|
||||
static void initialize_manifold_index_array(const BitSpan not_used_map,
|
||||
const int num_elements,
|
||||
int **r_indices,
|
||||
int **r_indices_reverse,
|
||||
@@ -345,7 +347,6 @@ static void initialize_manifold_index_array(const blender::BitSpan not_used_map,
|
||||
|
||||
static void initialize_manifold_indices(ConverterStorage *storage)
|
||||
{
|
||||
using namespace blender;
|
||||
const Mesh *mesh = storage->mesh;
|
||||
const bke::LooseVertCache &loose_verts = mesh->verts_no_face();
|
||||
const bke::LooseEdgeCache &loose_edges = mesh->loose_edges();
|
||||
@@ -374,11 +375,9 @@ static void initialize_manifold_indices(ConverterStorage *storage)
|
||||
}
|
||||
|
||||
static void init_user_data(OpenSubdiv_Converter *converter,
|
||||
const SubdivSettings *settings,
|
||||
const Settings *settings,
|
||||
const Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
ConverterStorage *user_data = MEM_new<ConverterStorage>(__func__);
|
||||
user_data->settings = *settings;
|
||||
user_data->mesh = mesh;
|
||||
@@ -388,7 +387,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
|
||||
user_data->corner_verts = mesh->corner_verts();
|
||||
user_data->corner_edges = mesh->corner_edges();
|
||||
if (settings->use_creases) {
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const AttributeAccessor attributes = mesh->attributes();
|
||||
user_data->cd_vertex_crease = *attributes.lookup<float>("crease_vert", AttrDomain::Point);
|
||||
user_data->cd_edge_crease = *attributes.lookup<float>("crease_edge", AttrDomain::Edge);
|
||||
}
|
||||
@@ -397,10 +396,12 @@ static void init_user_data(OpenSubdiv_Converter *converter,
|
||||
converter->user_data = user_data;
|
||||
}
|
||||
|
||||
void BKE_subdiv_converter_init_for_mesh(OpenSubdiv_Converter *converter,
|
||||
const SubdivSettings *settings,
|
||||
const Mesh *mesh)
|
||||
void converter_init_for_mesh(OpenSubdiv_Converter *converter,
|
||||
const Settings *settings,
|
||||
const Mesh *mesh)
|
||||
{
|
||||
init_functions(converter);
|
||||
init_user_data(converter, settings, mesh);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Subdivision context
|
||||
* \{ */
|
||||
@@ -75,10 +77,10 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
|
||||
{
|
||||
Subdiv *subdiv = ctx->subdiv;
|
||||
float dummy_P[3], dPdu[3], dPdv[3], D[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
/* Accumulate displacement if needed. */
|
||||
if (ctx->have_displacement) {
|
||||
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
/* NOTE: The storage for vertex coordinates is coming from an external world, not necessarily
|
||||
* initialized to zeroes. */
|
||||
if (ctx->accumulated_counters[vertex_index] == 0) {
|
||||
@@ -97,7 +99,7 @@ static void subdiv_accumulate_vertex_displacement(SubdivDeformContext *ctx,
|
||||
/** \name Subdivision callbacks
|
||||
* \{ */
|
||||
|
||||
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
|
||||
static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
|
||||
const int /*num_vertices*/,
|
||||
const int /*num_edges*/,
|
||||
const int /*num_loops*/,
|
||||
@@ -110,7 +112,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
|
||||
return true;
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_every_corner(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -124,7 +126,7 @@ static void subdiv_mesh_vertex_every_corner(const SubdivForeachContext *foreach_
|
||||
subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, coarse_vertex_index);
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -150,7 +152,7 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex
|
||||
mul_v3_fl(D, inv_num_accumulated);
|
||||
}
|
||||
/* Copy custom data and evaluate position. */
|
||||
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
|
||||
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, vertex_co);
|
||||
/* Apply displacement. */
|
||||
add_v3_v3(vertex_co, D);
|
||||
}
|
||||
@@ -162,7 +164,7 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex
|
||||
* \{ */
|
||||
|
||||
static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
|
||||
SubdivForeachContext *foreach_context)
|
||||
ForeachContext *foreach_context)
|
||||
{
|
||||
memset(foreach_context, 0, sizeof(*foreach_context));
|
||||
/* General information. */
|
||||
@@ -180,24 +182,22 @@ static void setup_foreach_callbacks(const SubdivDeformContext *subdiv_context,
|
||||
/** \name Public entry point
|
||||
* \{ */
|
||||
|
||||
void BKE_subdiv_deform_coarse_vertices(Subdiv *subdiv,
|
||||
const Mesh *coarse_mesh,
|
||||
float (*vertex_cos)[3],
|
||||
int num_verts)
|
||||
void deform_coarse_vertices(Subdiv *subdiv,
|
||||
const Mesh *coarse_mesh,
|
||||
float (*vertex_cos)[3],
|
||||
int num_verts)
|
||||
{
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
/* Make sure evaluator is up to date with possible new topology, and that
|
||||
* is refined for the new positions of coarse vertices. */
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
if (!eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
|
||||
/* This could happen in two situations:
|
||||
* - OpenSubdiv is disabled.
|
||||
* - Something totally bad happened, and OpenSubdiv rejected our
|
||||
* topology.
|
||||
* In either way, we can't safely continue. */
|
||||
if (coarse_mesh->faces_num) {
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -210,25 +210,27 @@ void BKE_subdiv_deform_coarse_vertices(Subdiv *subdiv,
|
||||
subdiv_context.num_verts = num_verts;
|
||||
subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
|
||||
|
||||
SubdivForeachContext foreach_context;
|
||||
ForeachContext foreach_context;
|
||||
setup_foreach_callbacks(&subdiv_context, &foreach_context);
|
||||
foreach_context.user_data = &subdiv_context;
|
||||
|
||||
/* Dummy mesh rasterization settings. */
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = 1;
|
||||
mesh_settings.use_optimal_display = false;
|
||||
|
||||
/* Multi-threaded traversal/evaluation. */
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
foreach_subdiv_geometry(subdiv, &foreach_context, &mesh_settings, coarse_mesh);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
|
||||
// BKE_mesh_validate(result, true, true);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
|
||||
/* Free used memory. */
|
||||
subdiv_mesh_context_free(&subdiv_context);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
void BKE_subdiv_displacement_detach(Subdiv *subdiv)
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
void displacement_detach(Subdiv *subdiv)
|
||||
{
|
||||
if (subdiv->displacement_evaluator == nullptr) {
|
||||
return;
|
||||
@@ -21,3 +23,5 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv)
|
||||
MEM_freeN(subdiv->displacement_evaluator);
|
||||
subdiv->displacement_evaluator = nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
struct PolyCornerIndex {
|
||||
int face_index;
|
||||
int corner;
|
||||
@@ -36,7 +38,7 @@ struct MultiresDisplacementData {
|
||||
/* Mesh is used to read external displacement. */
|
||||
Mesh *mesh;
|
||||
const MultiresModifierData *mmd;
|
||||
blender::OffsetIndices<int> faces;
|
||||
OffsetIndices<int> faces;
|
||||
const MDisps *mdisps;
|
||||
/* Indexed by PTEX face index, contains face/corner which corresponds
|
||||
* to it.
|
||||
@@ -61,7 +63,7 @@ enum eAverageWith {
|
||||
AVERAGE_WITH_NEXT,
|
||||
};
|
||||
|
||||
static int displacement_get_grid_and_coord(SubdivDisplacement *displacement,
|
||||
static int displacement_get_grid_and_coord(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
@@ -72,23 +74,23 @@ static int displacement_get_grid_and_coord(SubdivDisplacement *displacement,
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
const PolyCornerIndex *face_corner = &data->ptex_face_corner[ptex_face_index];
|
||||
const blender::IndexRange face = data->faces[face_corner->face_index];
|
||||
const IndexRange face = data->faces[face_corner->face_index];
|
||||
const int start_grid_index = face.start() + face_corner->corner;
|
||||
int corner = 0;
|
||||
if (face.size() == 4) {
|
||||
float corner_u, corner_v;
|
||||
corner = BKE_subdiv_rotate_quad_to_corner(u, v, &corner_u, &corner_v);
|
||||
corner = rotate_quad_to_corner(u, v, &corner_u, &corner_v);
|
||||
*r_displacement_grid = &data->mdisps[start_grid_index + corner];
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
|
||||
ptex_face_uv_to_grid_uv(corner_u, corner_v, grid_u, grid_v);
|
||||
}
|
||||
else {
|
||||
*r_displacement_grid = &data->mdisps[start_grid_index];
|
||||
BKE_subdiv_ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
|
||||
ptex_face_uv_to_grid_uv(u, v, grid_u, grid_v);
|
||||
}
|
||||
return corner;
|
||||
}
|
||||
|
||||
static const MDisps *displacement_get_other_grid(SubdivDisplacement *displacement,
|
||||
static const MDisps *displacement_get_other_grid(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
const int corner_delta)
|
||||
@@ -96,7 +98,7 @@ static const MDisps *displacement_get_other_grid(SubdivDisplacement *displacemen
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
const PolyCornerIndex *face_corner = &data->ptex_face_corner[ptex_face_index];
|
||||
const blender::IndexRange face = data->faces[face_corner->face_index];
|
||||
const IndexRange face = data->faces[face_corner->face_index];
|
||||
const int effective_corner = (face.size() == 4) ? corner : face_corner->corner;
|
||||
const int next_corner = (effective_corner + corner_delta + face.size()) % face.size();
|
||||
return &data->mdisps[face[next_corner]];
|
||||
@@ -135,10 +137,10 @@ static void average_convert_grid_coord_to_ptex(const int num_corners,
|
||||
float *r_ptex_face_v)
|
||||
{
|
||||
if (num_corners == 4) {
|
||||
BKE_subdiv_rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
|
||||
rotate_grid_to_quad(corner, grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
|
||||
}
|
||||
else {
|
||||
BKE_subdiv_grid_uv_to_ptex_face_uv(grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
|
||||
grid_uv_to_ptex_face_uv(grid_u, grid_v, r_ptex_face_u, r_ptex_face_v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ static void average_construct_tangent_matrix(Subdiv *subdiv,
|
||||
const bool is_quad = num_corners == 4;
|
||||
const int quad_corner = is_quad ? corner : 0;
|
||||
float dummy_P[3], dPdu[3], dPdv[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
BKE_multires_construct_tangent_matrix(r_tangent_matrix, dPdu, dPdv, quad_corner);
|
||||
}
|
||||
|
||||
@@ -210,7 +212,7 @@ static void average_get_other_ptex_and_corner(MultiresDisplacementData *data,
|
||||
}
|
||||
|
||||
/* NOTE: Grid coordinates are relative to the other grid already. */
|
||||
static void average_with_other(SubdivDisplacement *displacement,
|
||||
static void average_with_other(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
const float grid_u,
|
||||
@@ -239,7 +241,7 @@ static void average_with_other(SubdivDisplacement *displacement,
|
||||
mul_v3_fl(r_D, 0.5f);
|
||||
}
|
||||
|
||||
static void average_with_all(SubdivDisplacement *displacement,
|
||||
static void average_with_all(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
const float /*grid_u*/,
|
||||
@@ -255,7 +257,7 @@ static void average_with_all(SubdivDisplacement *displacement,
|
||||
}
|
||||
}
|
||||
|
||||
static void average_with_next(SubdivDisplacement *displacement,
|
||||
static void average_with_next(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
const float grid_u,
|
||||
@@ -265,7 +267,7 @@ static void average_with_next(SubdivDisplacement *displacement,
|
||||
average_with_other(displacement, ptex_face_index, corner, 0.0f, grid_u, 1, r_D);
|
||||
}
|
||||
|
||||
static void average_with_prev(SubdivDisplacement *displacement,
|
||||
static void average_with_prev(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
const float /*grid_u*/,
|
||||
@@ -275,7 +277,7 @@ static void average_with_prev(SubdivDisplacement *displacement,
|
||||
average_with_other(displacement, ptex_face_index, corner, grid_v, 0.0f, -1, r_D);
|
||||
}
|
||||
|
||||
static void average_displacement(SubdivDisplacement *displacement,
|
||||
static void average_displacement(Displacement *displacement,
|
||||
eAverageWith average_with,
|
||||
const int ptex_face_index,
|
||||
const int corner,
|
||||
@@ -308,13 +310,13 @@ static int displacement_get_face_corner(MultiresDisplacementData *data,
|
||||
const bool is_quad = (num_corners == 4);
|
||||
if (is_quad) {
|
||||
float dummy_corner_u, dummy_corner_v;
|
||||
return BKE_subdiv_rotate_quad_to_corner(u, v, &dummy_corner_u, &dummy_corner_v);
|
||||
return rotate_quad_to_corner(u, v, &dummy_corner_u, &dummy_corner_v);
|
||||
}
|
||||
|
||||
return face_corner->corner;
|
||||
}
|
||||
|
||||
static void initialize(SubdivDisplacement *displacement)
|
||||
static void initialize(Displacement *displacement)
|
||||
{
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
@@ -322,7 +324,7 @@ static void initialize(SubdivDisplacement *displacement)
|
||||
data->is_initialized = true;
|
||||
}
|
||||
|
||||
static void eval_displacement(SubdivDisplacement *displacement,
|
||||
static void eval_displacement(Displacement *displacement,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
@@ -353,7 +355,7 @@ static void eval_displacement(SubdivDisplacement *displacement,
|
||||
average_displacement(displacement, average_with, ptex_face_index, corner, grid_u, grid_v, r_D);
|
||||
}
|
||||
|
||||
static void free_displacement(SubdivDisplacement *displacement)
|
||||
static void free_displacement(Displacement *displacement)
|
||||
{
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
@@ -366,18 +368,18 @@ static void free_displacement(SubdivDisplacement *displacement)
|
||||
static int count_num_ptex_faces(const Mesh *mesh)
|
||||
{
|
||||
int num_ptex_faces = 0;
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
for (int face_index = 0; face_index < mesh->faces_num; face_index++) {
|
||||
num_ptex_faces += (faces[face_index].size() == 4) ? 1 : faces[face_index].size();
|
||||
}
|
||||
return num_ptex_faces;
|
||||
}
|
||||
|
||||
static void displacement_data_init_mapping(SubdivDisplacement *displacement, const Mesh *mesh)
|
||||
static void displacement_data_init_mapping(Displacement *displacement, const Mesh *mesh)
|
||||
{
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
const blender::OffsetIndices faces = mesh->faces();
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
const int num_ptex_faces = count_num_ptex_faces(mesh);
|
||||
/* Allocate memory. */
|
||||
data->ptex_face_corner = static_cast<PolyCornerIndex *>(
|
||||
@@ -386,7 +388,7 @@ static void displacement_data_init_mapping(SubdivDisplacement *displacement, con
|
||||
int ptex_face_index = 0;
|
||||
PolyCornerIndex *ptex_face_corner = data->ptex_face_corner;
|
||||
for (int face_index = 0; face_index < mesh->faces_num; face_index++) {
|
||||
const blender::IndexRange face = faces[face_index];
|
||||
const IndexRange face = faces[face_index];
|
||||
if (face.size() == 4) {
|
||||
ptex_face_corner[ptex_face_index].face_index = face_index;
|
||||
ptex_face_corner[ptex_face_index].corner = 0;
|
||||
@@ -402,7 +404,7 @@ static void displacement_data_init_mapping(SubdivDisplacement *displacement, con
|
||||
}
|
||||
}
|
||||
|
||||
static void displacement_init_data(SubdivDisplacement *displacement,
|
||||
static void displacement_init_data(Displacement *displacement,
|
||||
Subdiv *subdiv,
|
||||
Mesh *mesh,
|
||||
const MultiresModifierData *mmd)
|
||||
@@ -410,36 +412,34 @@ static void displacement_init_data(SubdivDisplacement *displacement,
|
||||
MultiresDisplacementData *data = static_cast<MultiresDisplacementData *>(
|
||||
displacement->user_data);
|
||||
data->subdiv = subdiv;
|
||||
data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl);
|
||||
data->grid_size = grid_size_from_level(mmd->totlvl);
|
||||
data->mesh = mesh;
|
||||
data->mmd = mmd;
|
||||
data->faces = mesh->faces();
|
||||
data->mdisps = static_cast<const MDisps *>(CustomData_get_layer(&mesh->corner_data, CD_MDISPS));
|
||||
data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
|
||||
data->face_ptex_offset = face_ptex_offset_get(subdiv);
|
||||
data->is_initialized = false;
|
||||
displacement_data_init_mapping(displacement, mesh);
|
||||
}
|
||||
|
||||
static void displacement_init_functions(SubdivDisplacement *displacement)
|
||||
static void displacement_init_functions(Displacement *displacement)
|
||||
{
|
||||
displacement->initialize = initialize;
|
||||
displacement->eval_displacement = eval_displacement;
|
||||
displacement->free = free_displacement;
|
||||
}
|
||||
|
||||
void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
|
||||
Mesh *mesh,
|
||||
const MultiresModifierData *mmd)
|
||||
void displacement_attach_from_multires(Subdiv *subdiv, Mesh *mesh, const MultiresModifierData *mmd)
|
||||
{
|
||||
/* Make sure we don't have previously assigned displacement. */
|
||||
BKE_subdiv_displacement_detach(subdiv);
|
||||
displacement_detach(subdiv);
|
||||
/* It is possible to have mesh without CD_MDISPS layer. Happens when using
|
||||
* dynamic topology. */
|
||||
if (!CustomData_has_layer(&mesh->corner_data, CD_MDISPS)) {
|
||||
return;
|
||||
}
|
||||
/* Allocate all required memory. */
|
||||
SubdivDisplacement *displacement = MEM_cnew<SubdivDisplacement>("multires displacement");
|
||||
Displacement *displacement = MEM_cnew<Displacement>("multires displacement");
|
||||
displacement->user_data = MEM_callocN(sizeof(MultiresDisplacementData),
|
||||
"multires displacement data");
|
||||
displacement_init_data(displacement, subdiv, mesh, mmd);
|
||||
@@ -447,3 +447,5 @@ void BKE_subdiv_displacement_attach_from_multires(Subdiv *subdiv,
|
||||
/* Finish. */
|
||||
subdiv->displacement_evaluator = displacement;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
* Helper functions.
|
||||
*/
|
||||
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
|
||||
eSubdivEvaluatorType evaluator_type)
|
||||
{
|
||||
@@ -44,12 +46,12 @@ static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type(
|
||||
* Main subdivision evaluation.
|
||||
*/
|
||||
|
||||
bool BKE_subdiv_eval_begin(Subdiv *subdiv,
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache,
|
||||
const OpenSubdiv_EvaluatorSettings *settings)
|
||||
bool eval_begin(Subdiv *subdiv,
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache,
|
||||
const OpenSubdiv_EvaluatorSettings *settings)
|
||||
{
|
||||
BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
if (subdiv->topology_refiner == nullptr) {
|
||||
/* Happens on input mesh with just loose geometry,
|
||||
* or when OpenSubdiv is disabled */
|
||||
@@ -58,10 +60,10 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
|
||||
if (subdiv->evaluator == nullptr) {
|
||||
eOpenSubdivEvaluator opensubdiv_evaluator_type =
|
||||
opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type);
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(
|
||||
subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE);
|
||||
if (subdiv->evaluator == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -70,15 +72,14 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv,
|
||||
/* TODO(sergey): Check for topology change. */
|
||||
}
|
||||
subdiv->evaluator->setSettings(subdiv->evaluator, settings);
|
||||
BKE_subdiv_eval_init_displacement(subdiv);
|
||||
eval_init_displacement(subdiv);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_coarse_positions(Subdiv *subdiv,
|
||||
const blender::Span<blender::float3> positions,
|
||||
const blender::bke::LooseVertCache &verts_no_face)
|
||||
const Span<float3> positions,
|
||||
const bke::LooseVertCache &verts_no_face)
|
||||
{
|
||||
using namespace blender;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
if (verts_no_face.count == 0) {
|
||||
evaluator->setCoarsePositions(
|
||||
@@ -105,7 +106,7 @@ static void set_coarse_positions(Subdiv *subdiv,
|
||||
struct FaceVaryingDataFromUVContext {
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner;
|
||||
const Mesh *mesh;
|
||||
blender::OffsetIndices<int> faces;
|
||||
OffsetIndices<int> faces;
|
||||
const float (*mloopuv)[2];
|
||||
float (*buffer)[2];
|
||||
int layer_index;
|
||||
@@ -205,25 +206,22 @@ static void get_mesh_evaluator_settings(OpenSubdiv_EvaluatorSettings *settings,
|
||||
(CustomData_has_layer(&mesh->vert_data, CD_CLOTH_ORCO) ? 3 : 0);
|
||||
}
|
||||
|
||||
bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv,
|
||||
const Mesh *mesh,
|
||||
const float (*coarse_vertex_cos)[3],
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache)
|
||||
bool eval_begin_from_mesh(Subdiv *subdiv,
|
||||
const Mesh *mesh,
|
||||
const float (*coarse_vertex_cos)[3],
|
||||
eSubdivEvaluatorType evaluator_type,
|
||||
OpenSubdiv_EvaluatorCache *evaluator_cache)
|
||||
{
|
||||
OpenSubdiv_EvaluatorSettings settings = {0};
|
||||
get_mesh_evaluator_settings(&settings, mesh);
|
||||
if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) {
|
||||
if (!eval_begin(subdiv, evaluator_type, evaluator_cache, &settings)) {
|
||||
return false;
|
||||
}
|
||||
return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
|
||||
return eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos);
|
||||
}
|
||||
|
||||
bool BKE_subdiv_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])
|
||||
{
|
||||
using namespace blender;
|
||||
if (subdiv->evaluator == nullptr) {
|
||||
/* NOTE: This situation is supposed to be handled by begin(). */
|
||||
BLI_assert_msg(0, "Is not supposed to happen");
|
||||
@@ -247,13 +245,13 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv,
|
||||
/* Set vertex data to orco. */
|
||||
set_vertex_data_from_orco(subdiv, mesh);
|
||||
/* Update evaluator to the new coarse geometry. */
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
|
||||
subdiv->evaluator->refine(subdiv->evaluator);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE);
|
||||
return true;
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_init_displacement(Subdiv *subdiv)
|
||||
void eval_init_displacement(Subdiv *subdiv)
|
||||
{
|
||||
if (subdiv->displacement_evaluator == nullptr) {
|
||||
return;
|
||||
@@ -268,20 +266,19 @@ void BKE_subdiv_eval_init_displacement(Subdiv *subdiv)
|
||||
* Single point queries.
|
||||
*/
|
||||
|
||||
void BKE_subdiv_eval_limit_point(
|
||||
void eval_limit_point(
|
||||
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3])
|
||||
{
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(
|
||||
subdiv, ptex_face_index, u, v, r_P, nullptr, nullptr);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, nullptr, nullptr);
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_P[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3])
|
||||
void eval_limit_point_and_derivatives(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_P[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3])
|
||||
{
|
||||
subdiv->evaluator->evaluateLimit(subdiv->evaluator, ptex_face_index, u, v, r_P, r_dPdu, r_dPdv);
|
||||
|
||||
@@ -309,43 +306,43 @@ void BKE_subdiv_eval_limit_point_and_derivatives(Subdiv *subdiv,
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_limit_point_and_normal(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_P[3],
|
||||
float r_N[3])
|
||||
void eval_limit_point_and_normal(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_P[3],
|
||||
float r_N[3])
|
||||
{
|
||||
float dPdu[3], dPdv[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
|
||||
cross_v3_v3v3(r_N, dPdu, dPdv);
|
||||
normalize_v3(r_N);
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_vertex_data(
|
||||
void eval_vertex_data(
|
||||
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_vertex_data[])
|
||||
{
|
||||
subdiv->evaluator->evaluateVertexData(subdiv->evaluator, ptex_face_index, u, v, r_vertex_data);
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_face_varying(Subdiv *subdiv,
|
||||
const int face_varying_channel,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_face_varying[2])
|
||||
void eval_face_varying(Subdiv *subdiv,
|
||||
const int face_varying_channel,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
float r_face_varying[2])
|
||||
{
|
||||
subdiv->evaluator->evaluateFaceVarying(
|
||||
subdiv->evaluator, face_varying_channel, ptex_face_index, u, v, r_face_varying);
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_displacement(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
const float dPdu[3],
|
||||
const float dPdv[3],
|
||||
float r_D[3])
|
||||
void eval_displacement(Subdiv *subdiv,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
const float dPdu[3],
|
||||
const float dPdv[3],
|
||||
float r_D[3])
|
||||
{
|
||||
if (subdiv->displacement_evaluator == nullptr) {
|
||||
zero_v3(r_D);
|
||||
@@ -355,16 +352,18 @@ void BKE_subdiv_eval_displacement(Subdiv *subdiv,
|
||||
subdiv->displacement_evaluator, ptex_face_index, u, v, dPdu, dPdv, r_D);
|
||||
}
|
||||
|
||||
void BKE_subdiv_eval_final_point(
|
||||
void eval_final_point(
|
||||
Subdiv *subdiv, const int ptex_face_index, const float u, const float v, float r_P[3])
|
||||
{
|
||||
if (subdiv->displacement_evaluator) {
|
||||
float dPdu[3], dPdv[3], D[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
|
||||
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, r_P, dPdu, dPdv);
|
||||
eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
add_v3_v3(r_P, D);
|
||||
}
|
||||
else {
|
||||
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
|
||||
eval_limit_point(subdiv, ptex_face_index, u, v, r_P);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::IndexRange;
|
||||
using blender::int2;
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name General helpers
|
||||
@@ -66,13 +65,13 @@ BLI_INLINE int ptex_face_resolution_get(const IndexRange face, int resolution)
|
||||
|
||||
struct SubdivForeachTaskContext {
|
||||
const Mesh *coarse_mesh;
|
||||
blender::Span<int2> coarse_edges;
|
||||
blender::OffsetIndices<int> coarse_faces;
|
||||
blender::Span<int> coarse_corner_verts;
|
||||
blender::Span<int> coarse_corner_edges;
|
||||
const SubdivToMeshSettings *settings;
|
||||
Span<int2> coarse_edges;
|
||||
OffsetIndices<int> coarse_faces;
|
||||
Span<int> coarse_corner_verts;
|
||||
Span<int> coarse_corner_edges;
|
||||
const ToMeshSettings *settings;
|
||||
/* Callbacks. */
|
||||
const SubdivForeachContext *foreach_context;
|
||||
const ForeachContext *foreach_context;
|
||||
/* Counters of geometry in subdivided mesh, initialized as a part of
|
||||
* offsets calculation.
|
||||
*/
|
||||
@@ -119,7 +118,7 @@ struct SubdivForeachTaskContext {
|
||||
|
||||
static void *subdiv_foreach_tls_alloc(SubdivForeachTaskContext *ctx)
|
||||
{
|
||||
const SubdivForeachContext *foreach_context = ctx->foreach_context;
|
||||
const ForeachContext *foreach_context = ctx->foreach_context;
|
||||
void *tls = nullptr;
|
||||
if (foreach_context->user_data_tls_size != 0) {
|
||||
tls = MEM_mallocN(foreach_context->user_data_tls_size, "tls");
|
||||
@@ -259,7 +258,7 @@ static void subdiv_foreach_ctx_init(Subdiv *subdiv, SubdivForeachTaskContext *ct
|
||||
subdiv_foreach_ctx_init_offsets(ctx);
|
||||
/* Calculate number of geometry in the result subdivision mesh. */
|
||||
subdiv_foreach_ctx_count(ctx);
|
||||
ctx->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
|
||||
ctx->face_ptex_offset = face_ptex_offset_get(subdiv);
|
||||
}
|
||||
|
||||
static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
|
||||
@@ -279,12 +278,11 @@ static void subdiv_foreach_ctx_free(SubdivForeachTaskContext *ctx)
|
||||
|
||||
/* Traversal of corner vertices. They are coming from coarse vertices. */
|
||||
|
||||
static void subdiv_foreach_corner_vertices_regular_do(
|
||||
SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
SubdivForeachVertexFromCornerCb vertex_corner,
|
||||
bool check_usage)
|
||||
static void subdiv_foreach_corner_vertices_regular_do(SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
ForeachVertexFromCornerCb vertex_corner,
|
||||
bool check_usage)
|
||||
{
|
||||
const float weights[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
|
||||
const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
|
||||
@@ -319,12 +317,11 @@ static void subdiv_foreach_corner_vertices_regular(SubdivForeachTaskContext *ctx
|
||||
ctx, tls, coarse_face_index, ctx->foreach_context->vertex_corner, true);
|
||||
}
|
||||
|
||||
static void subdiv_foreach_corner_vertices_special_do(
|
||||
SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
SubdivForeachVertexFromCornerCb vertex_corner,
|
||||
bool check_usage)
|
||||
static void subdiv_foreach_corner_vertices_special_do(SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
ForeachVertexFromCornerCb vertex_corner,
|
||||
bool check_usage)
|
||||
{
|
||||
const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
|
||||
int ptex_face_index = ctx->face_ptex_offset[coarse_face_index];
|
||||
@@ -405,7 +402,7 @@ static void subdiv_foreach_every_corner_vertices(SubdivForeachTaskContext *ctx,
|
||||
static void subdiv_foreach_edge_vertices_regular_do(SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
SubdivForeachVertexFromEdgeCb vertex_edge,
|
||||
ForeachVertexFromEdgeCb vertex_edge,
|
||||
bool check_usage)
|
||||
{
|
||||
const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
|
||||
@@ -469,7 +466,7 @@ static void subdiv_foreach_edge_vertices_regular(SubdivForeachTaskContext *ctx,
|
||||
static void subdiv_foreach_edge_vertices_special_do(SubdivForeachTaskContext *ctx,
|
||||
void *tls,
|
||||
const int coarse_face_index,
|
||||
SubdivForeachVertexFromEdgeCb vertex_edge,
|
||||
ForeachVertexFromEdgeCb vertex_edge,
|
||||
bool check_usage)
|
||||
{
|
||||
const IndexRange coarse_face = ctx->coarse_faces[coarse_face_index];
|
||||
@@ -1752,7 +1749,7 @@ static void subdiv_foreach_single_thread_tasks(SubdivForeachTaskContext *ctx)
|
||||
subdiv_foreach_single_geometry_vertices(ctx, tls);
|
||||
subdiv_foreach_tls_free(ctx, tls);
|
||||
|
||||
const SubdivForeachContext *foreach_context = ctx->foreach_context;
|
||||
const ForeachContext *foreach_context = ctx->foreach_context;
|
||||
const bool is_loose_geometry_tagged = (foreach_context->vertex_every_edge != nullptr &&
|
||||
foreach_context->vertex_every_corner != nullptr);
|
||||
const bool is_loose_geometry_tags_needed = (foreach_context->vertex_loose != nullptr ||
|
||||
@@ -1795,10 +1792,10 @@ static void subdiv_foreach_free(const void *__restrict userdata, void *__restric
|
||||
ctx->foreach_context->user_data_tls_free(userdata_chunk);
|
||||
}
|
||||
|
||||
bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
|
||||
const SubdivForeachContext *context,
|
||||
const SubdivToMeshSettings *mesh_settings,
|
||||
const Mesh *coarse_mesh)
|
||||
bool foreach_subdiv_geometry(Subdiv *subdiv,
|
||||
const ForeachContext *context,
|
||||
const ToMeshSettings *mesh_settings,
|
||||
const Mesh *coarse_mesh)
|
||||
{
|
||||
SubdivForeachTaskContext ctx = {nullptr};
|
||||
ctx.coarse_mesh = coarse_mesh;
|
||||
@@ -1867,3 +1864,5 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv,
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -13,33 +13,35 @@
|
||||
|
||||
#include "BKE_subdiv.hh"
|
||||
|
||||
BLI_INLINE void BKE_subdiv_ptex_face_uv_to_grid_uv(const float ptex_u,
|
||||
const float ptex_v,
|
||||
float *r_grid_u,
|
||||
float *r_grid_v)
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
BLI_INLINE void ptex_face_uv_to_grid_uv(const float ptex_u,
|
||||
const float ptex_v,
|
||||
float *r_grid_u,
|
||||
float *r_grid_v)
|
||||
{
|
||||
*r_grid_u = 1.0f - ptex_v;
|
||||
*r_grid_v = 1.0f - ptex_u;
|
||||
}
|
||||
|
||||
BLI_INLINE void BKE_subdiv_grid_uv_to_ptex_face_uv(const float grid_u,
|
||||
const float grid_v,
|
||||
float *r_ptex_u,
|
||||
float *r_ptex_v)
|
||||
BLI_INLINE void grid_uv_to_ptex_face_uv(const float grid_u,
|
||||
const float grid_v,
|
||||
float *r_ptex_u,
|
||||
float *r_ptex_v)
|
||||
{
|
||||
*r_ptex_u = 1.0f - grid_v;
|
||||
*r_ptex_v = 1.0f - grid_u;
|
||||
}
|
||||
|
||||
BLI_INLINE int BKE_subdiv_grid_size_from_level(const int level)
|
||||
BLI_INLINE int grid_size_from_level(const int level)
|
||||
{
|
||||
return (1 << (level - 1)) + 1;
|
||||
}
|
||||
|
||||
BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(const float quad_u,
|
||||
const float quad_v,
|
||||
float *r_corner_u,
|
||||
float *r_corner_v)
|
||||
BLI_INLINE int rotate_quad_to_corner(const float quad_u,
|
||||
const float quad_v,
|
||||
float *r_corner_u,
|
||||
float *r_corner_v)
|
||||
{
|
||||
int corner;
|
||||
if (quad_u <= 0.5f && quad_v <= 0.5f) {
|
||||
@@ -66,7 +68,7 @@ BLI_INLINE int BKE_subdiv_rotate_quad_to_corner(const float quad_u,
|
||||
return corner;
|
||||
}
|
||||
|
||||
BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
|
||||
BLI_INLINE void rotate_grid_to_quad(
|
||||
const int corner, const float grid_u, const float grid_v, float *r_quad_u, float *r_quad_v)
|
||||
{
|
||||
if (corner == 0) {
|
||||
@@ -88,7 +90,9 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease)
|
||||
BLI_INLINE float crease_to_sharpness(float edge_crease)
|
||||
{
|
||||
return edge_crease * edge_crease * 10.0f;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -27,32 +27,27 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
using blender::float2;
|
||||
using blender::float3;
|
||||
using blender::IndexRange;
|
||||
using blender::int2;
|
||||
using blender::MutableSpan;
|
||||
using blender::Span;
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Subdivision Context
|
||||
* \{ */
|
||||
|
||||
struct SubdivMeshContext {
|
||||
const SubdivToMeshSettings *settings;
|
||||
const ToMeshSettings *settings;
|
||||
const Mesh *coarse_mesh;
|
||||
blender::Span<float3> coarse_positions;
|
||||
blender::Span<int2> coarse_edges;
|
||||
blender::OffsetIndices<int> coarse_faces;
|
||||
blender::Span<int> coarse_corner_verts;
|
||||
Span<float3> coarse_positions;
|
||||
Span<int2> coarse_edges;
|
||||
OffsetIndices<int> coarse_faces;
|
||||
Span<int> coarse_corner_verts;
|
||||
|
||||
Subdiv *subdiv;
|
||||
Mesh *subdiv_mesh;
|
||||
blender::MutableSpan<float3> subdiv_positions;
|
||||
blender::MutableSpan<int2> subdiv_edges;
|
||||
blender::MutableSpan<int> subdiv_face_offsets;
|
||||
blender::MutableSpan<int> subdiv_corner_verts;
|
||||
blender::MutableSpan<int> subdiv_corner_edges;
|
||||
MutableSpan<float3> subdiv_positions;
|
||||
MutableSpan<int2> subdiv_edges;
|
||||
MutableSpan<int> subdiv_face_offsets;
|
||||
MutableSpan<int> subdiv_corner_verts;
|
||||
MutableSpan<int> subdiv_corner_edges;
|
||||
|
||||
/* Cached custom data arrays for faster access. */
|
||||
int *vert_origindex;
|
||||
@@ -72,12 +67,12 @@ struct SubdivMeshContext {
|
||||
|
||||
/* Write optimal display edge tags into a boolean array rather than the final bit vector
|
||||
* to avoid race conditions when setting bits. */
|
||||
blender::Array<bool> subdiv_display_edges;
|
||||
Array<bool> subdiv_display_edges;
|
||||
|
||||
/* Lazily initialize a map from vertices to connected edges. */
|
||||
blender::Array<int> vert_to_edge_offsets;
|
||||
blender::Array<int> vert_to_edge_indices;
|
||||
blender::GroupedSpan<int> vert_to_edge_map;
|
||||
Array<int> vert_to_edge_offsets;
|
||||
Array<int> vert_to_edge_indices;
|
||||
GroupedSpan<int> vert_to_edge_map;
|
||||
};
|
||||
|
||||
static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx)
|
||||
@@ -231,8 +226,8 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx,
|
||||
/* Interpolate center of face right away, it stays unchanged for all
|
||||
* ptex faces. */
|
||||
const float weight = 1.0f / float(coarse_face.size());
|
||||
blender::Array<float, 32> weights(coarse_face.size());
|
||||
blender::Array<int, 32> indices(coarse_face.size());
|
||||
Array<float, 32> weights(coarse_face.size());
|
||||
Array<int, 32> indices(coarse_face.size());
|
||||
for (int i = 0; i < coarse_face.size(); i++) {
|
||||
weights[i] = weight;
|
||||
indices[i] = ctx->coarse_corner_verts[coarse_face.start() + i];
|
||||
@@ -361,8 +356,8 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx,
|
||||
/* Interpolate center of face right away, it stays unchanged for all
|
||||
* ptex faces. */
|
||||
const float weight = 1.0f / float(coarse_face.size());
|
||||
blender::Array<float, 32> weights(coarse_face.size());
|
||||
blender::Array<int, 32> indices(coarse_face.size());
|
||||
Array<float, 32> weights(coarse_face.size());
|
||||
Array<int, 32> indices(coarse_face.size());
|
||||
for (int i = 0; i < coarse_face.size(); i++) {
|
||||
weights[i] = weight;
|
||||
indices[i] = coarse_face.start() + i;
|
||||
@@ -472,7 +467,7 @@ static void subdiv_vertex_orco_evaluate(const SubdivMeshContext *ctx,
|
||||
{
|
||||
if (ctx->orco || ctx->cloth_orco) {
|
||||
float vertex_data[6];
|
||||
BKE_subdiv_eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data);
|
||||
eval_vertex_data(ctx->subdiv, ptex_face_index, u, v, vertex_data);
|
||||
|
||||
if (ctx->orco) {
|
||||
copy_v3_v3(ctx->orco[subdiv_vertex_index], vertex_data);
|
||||
@@ -501,11 +496,11 @@ static void subdiv_accumulate_vertex_displacement(SubdivMeshContext *ctx,
|
||||
/* Accumulate displacement. */
|
||||
Subdiv *subdiv = ctx->subdiv;
|
||||
float dummy_P[3], dPdu[3], dPdv[3], D[3];
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
eval_limit_point_and_derivatives(subdiv, ptex_face_index, u, v, dummy_P, dPdu, dPdv);
|
||||
|
||||
/* NOTE: The subdivided mesh is allocated in this module, and its vertices are kept at zero
|
||||
* locations as a default calloc(). */
|
||||
BKE_subdiv_eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
eval_displacement(subdiv, ptex_face_index, u, v, dPdu, dPdv, D);
|
||||
ctx->subdiv_positions[subdiv_vertex_index] += D;
|
||||
|
||||
if (ctx->accumulated_counters) {
|
||||
@@ -519,7 +514,7 @@ static void subdiv_accumulate_vertex_displacement(SubdivMeshContext *ctx,
|
||||
/** \name Callbacks
|
||||
* \{ */
|
||||
|
||||
static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_context,
|
||||
static bool subdiv_mesh_topology_info(const ForeachContext *foreach_context,
|
||||
const int num_vertices,
|
||||
const int num_edges,
|
||||
const int num_loops,
|
||||
@@ -539,7 +534,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
|
||||
subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags.clear();
|
||||
subdiv_context->subdiv_mesh->runtime->subsurf_face_dot_tags.resize(num_vertices);
|
||||
if (subdiv_context->settings->use_optimal_display) {
|
||||
subdiv_context->subdiv_display_edges = blender::Array<bool>(num_edges, false);
|
||||
subdiv_context->subdiv_display_edges = Array<bool>(num_edges, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -599,7 +594,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext
|
||||
}
|
||||
/* Copy custom data and evaluate position. */
|
||||
subdiv_vertex_data_copy(ctx, coarse_vertex_index, subdiv_vertex_index);
|
||||
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
/* Apply displacement. */
|
||||
subdiv_position += D;
|
||||
/* Evaluate undeformed texture coordinate. */
|
||||
@@ -627,7 +622,7 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
|
||||
}
|
||||
/* Interpolate custom data and evaluate position. */
|
||||
subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, vertex_interpolation, u, v);
|
||||
BKE_subdiv_eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
eval_limit_point(ctx->subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
/* Apply displacement. */
|
||||
add_v3_v3(subdiv_position, D);
|
||||
/* Evaluate undeformed texture coordinate. */
|
||||
@@ -635,7 +630,7 @@ static void evaluate_vertex_and_apply_displacement_interpolate(
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_displacement_every_corner_or_edge(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -646,22 +641,21 @@ static void subdiv_mesh_vertex_displacement_every_corner_or_edge(
|
||||
subdiv_accumulate_vertex_displacement(ctx, ptex_face_index, u, v, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_displacement_every_corner(
|
||||
const SubdivForeachContext *foreach_context,
|
||||
void *tls,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
const int /*coarse_vertex_index*/,
|
||||
const int /*coarse_face_index*/,
|
||||
const int /*coarse_corner*/,
|
||||
const int subdiv_vertex_index)
|
||||
static void subdiv_mesh_vertex_displacement_every_corner(const ForeachContext *foreach_context,
|
||||
void *tls,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
const float v,
|
||||
const int /*coarse_vertex_index*/,
|
||||
const int /*coarse_face_index*/,
|
||||
const int /*coarse_corner*/,
|
||||
const int subdiv_vertex_index)
|
||||
{
|
||||
subdiv_mesh_vertex_displacement_every_corner_or_edge(
|
||||
foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_displacement_every_edge(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_displacement_every_edge(const ForeachContext *foreach_context,
|
||||
void *tls,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -675,7 +669,7 @@ static void subdiv_mesh_vertex_displacement_every_edge(const SubdivForeachContex
|
||||
foreach_context, tls, ptex_face_index, u, v, subdiv_vertex_index);
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_corner(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -722,7 +716,7 @@ static void subdiv_mesh_ensure_vertex_interpolation(SubdivMeshContext *ctx,
|
||||
tls->vertex_interpolation_coarse_corner = coarse_corner;
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_edge(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_edge(const ForeachContext *foreach_context,
|
||||
void *tls_v,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -767,7 +761,7 @@ static void subdiv_mesh_tag_center_vertex(const IndexRange coarse_face,
|
||||
}
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_inner(const ForeachContext *foreach_context,
|
||||
void *tls_v,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -784,7 +778,7 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context
|
||||
float3 &subdiv_position = ctx->subdiv_positions[subdiv_vertex_index];
|
||||
subdiv_mesh_ensure_vertex_interpolation(ctx, tls, coarse_face_index, coarse_corner);
|
||||
subdiv_vertex_data_interpolate(ctx, subdiv_vertex_index, &tls->vertex_interpolation, u, v);
|
||||
BKE_subdiv_eval_final_point(subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
eval_final_point(subdiv, ptex_face_index, u, v, subdiv_position);
|
||||
subdiv_mesh_tag_center_vertex(coarse_face, subdiv_vertex_index, u, v, subdiv_mesh);
|
||||
subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index);
|
||||
}
|
||||
@@ -815,7 +809,7 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_edge(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_edge_index,
|
||||
const int subdiv_edge_index,
|
||||
@@ -863,7 +857,7 @@ static void subdiv_eval_uv_layer(SubdivMeshContext *ctx,
|
||||
}
|
||||
Subdiv *subdiv = ctx->subdiv;
|
||||
for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) {
|
||||
BKE_subdiv_eval_face_varying(
|
||||
eval_face_varying(
|
||||
subdiv, layer_index, ptex_face_index, u, v, ctx->uv_layers[layer_index][corner_index]);
|
||||
}
|
||||
}
|
||||
@@ -899,7 +893,7 @@ static void subdiv_mesh_ensure_loop_interpolation(SubdivMeshContext *ctx,
|
||||
tls->loop_interpolation_coarse_corner = coarse_corner;
|
||||
}
|
||||
|
||||
static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_loop(const ForeachContext *foreach_context,
|
||||
void *tls_v,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -926,7 +920,7 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context,
|
||||
/** \name Polygons subdivision process
|
||||
* \{ */
|
||||
|
||||
static void subdiv_mesh_face(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_face(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_face_index,
|
||||
const int subdiv_face_index,
|
||||
@@ -949,7 +943,7 @@ static void subdiv_mesh_face(const SubdivForeachContext *foreach_context,
|
||||
/** \name Loose elements subdivision process
|
||||
* \{ */
|
||||
|
||||
static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_loose(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_vertex_index,
|
||||
const int subdiv_vertex_index)
|
||||
@@ -962,7 +956,7 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context
|
||||
* - neighbors[0] is an edge adjacent to edge->v1.
|
||||
* - neighbors[1] is an edge adjacent to edge->v2. */
|
||||
static void find_edge_neighbors(const int2 *coarse_edges,
|
||||
const blender::GroupedSpan<int> vert_to_edge_map,
|
||||
const GroupedSpan<int> vert_to_edge_map,
|
||||
const int edge_index,
|
||||
const int2 *neighbors[2])
|
||||
{
|
||||
@@ -1035,13 +1029,13 @@ static void points_for_loose_edges_interpolation_get(const float (*coarse_positi
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_subdiv_mesh_interpolate_position_on_edge(const float (*coarse_positions)[3],
|
||||
const blender::int2 *coarse_edges,
|
||||
const blender::GroupedSpan<int> vert_to_edge_map,
|
||||
const int coarse_edge_index,
|
||||
const bool is_simple,
|
||||
const float u,
|
||||
float pos_r[3])
|
||||
void mesh_interpolate_position_on_edge(const float (*coarse_positions)[3],
|
||||
const int2 *coarse_edges,
|
||||
const GroupedSpan<int> vert_to_edge_map,
|
||||
const int coarse_edge_index,
|
||||
const bool is_simple,
|
||||
const float u,
|
||||
float pos_r[3])
|
||||
{
|
||||
const int2 &coarse_edge = coarse_edges[coarse_edge_index];
|
||||
if (is_simple) {
|
||||
@@ -1083,7 +1077,7 @@ static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach_context,
|
||||
static void subdiv_mesh_vertex_of_loose_edge(const ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_edge_index,
|
||||
const float u,
|
||||
@@ -1099,7 +1093,7 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
|
||||
subdiv_mesh_vertex_of_loose_edge_interpolate(ctx, coarse_edge, u, subdiv_vertex_index);
|
||||
}
|
||||
/* Interpolate coordinate. */
|
||||
BKE_subdiv_mesh_interpolate_position_on_edge(
|
||||
mesh_interpolate_position_on_edge(
|
||||
reinterpret_cast<const float(*)[3]>(ctx->coarse_positions.data()),
|
||||
ctx->coarse_edges.data(),
|
||||
ctx->vert_to_edge_map,
|
||||
@@ -1116,7 +1110,7 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
|
||||
* \{ */
|
||||
|
||||
static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
|
||||
SubdivForeachContext *foreach_context)
|
||||
ForeachContext *foreach_context)
|
||||
{
|
||||
memset(foreach_context, 0, sizeof(*foreach_context));
|
||||
/* General information. */
|
||||
@@ -1143,24 +1137,20 @@ static void setup_foreach_callbacks(const SubdivMeshContext *subdiv_context,
|
||||
/** \name Public entry point
|
||||
* \{ */
|
||||
|
||||
Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
|
||||
const SubdivToMeshSettings *settings,
|
||||
const Mesh *coarse_mesh)
|
||||
Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh *coarse_mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
/* Make sure evaluator is up to date with possible new topology, and that
|
||||
* it is refined for the new positions of coarse vertices. */
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
subdiv, coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr))
|
||||
{
|
||||
if (!eval_begin_from_mesh(subdiv, coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) {
|
||||
/* This could happen in two situations:
|
||||
* - OpenSubdiv is disabled.
|
||||
* - Something totally bad happened, and OpenSubdiv rejected our
|
||||
* topology.
|
||||
* In either way, we can't safely continue. */
|
||||
if (coarse_mesh->faces_num) {
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1164,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
|
||||
subdiv_context.coarse_faces = coarse_mesh->faces();
|
||||
subdiv_context.coarse_corner_verts = coarse_mesh->corner_verts();
|
||||
if (coarse_mesh->loose_edges().count > 0) {
|
||||
subdiv_context.vert_to_edge_map = bke::mesh::build_vert_to_edge_map(
|
||||
subdiv_context.vert_to_edge_map = mesh::build_vert_to_edge_map(
|
||||
subdiv_context.coarse_edges,
|
||||
coarse_mesh->verts_num,
|
||||
subdiv_context.vert_to_edge_offsets,
|
||||
@@ -1184,15 +1174,15 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
|
||||
subdiv_context.subdiv = subdiv;
|
||||
subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr);
|
||||
/* Multi-threaded traversal/evaluation. */
|
||||
BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
SubdivForeachContext foreach_context;
|
||||
stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
ForeachContext foreach_context;
|
||||
setup_foreach_callbacks(&subdiv_context, &foreach_context);
|
||||
SubdivMeshTLS tls{};
|
||||
foreach_context.user_data = &subdiv_context;
|
||||
foreach_context.user_data_tls_size = sizeof(SubdivMeshTLS);
|
||||
foreach_context.user_data_tls = &tls;
|
||||
BKE_subdiv_foreach_subdiv_geometry(subdiv, &foreach_context, settings, coarse_mesh);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
foreach_subdiv_geometry(subdiv, &foreach_context, settings, coarse_mesh);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY);
|
||||
Mesh *result = subdiv_context.subdiv_mesh;
|
||||
|
||||
/* NOTE: Using normals from the limit surface gives different results than Blender's vertex
|
||||
@@ -1228,9 +1218,11 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv,
|
||||
}
|
||||
|
||||
// BKE_mesh_validate(result, true, true);
|
||||
BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH);
|
||||
subdiv_mesh_context_free(&subdiv_context);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -19,28 +19,29 @@
|
||||
#include "GPU_capabilities.hh"
|
||||
#include "GPU_context.hh"
|
||||
|
||||
SubdivSettings BKE_subsurf_modifier_settings_init(const SubsurfModifierData *smd,
|
||||
const bool use_render_params)
|
||||
using namespace blender::bke;
|
||||
|
||||
subdiv::Settings BKE_subsurf_modifier_settings_init(const SubsurfModifierData *smd,
|
||||
const bool use_render_params)
|
||||
{
|
||||
const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels;
|
||||
|
||||
SubdivSettings settings{};
|
||||
subdiv::Settings settings{};
|
||||
settings.is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
|
||||
settings.is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision);
|
||||
settings.level = settings.is_simple ? 1 :
|
||||
(settings.is_adaptive ? smd->quality : requested_levels);
|
||||
settings.use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease);
|
||||
settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
settings.vtx_boundary_interpolation = subdiv::vtx_boundary_interpolation_from_subsurf(
|
||||
smd->boundary_smooth);
|
||||
settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
|
||||
smd->uv_smooth);
|
||||
settings.fvar_linear_interpolation = subdiv::fvar_interpolation_from_uv_smooth(smd->uv_smooth);
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
bool BKE_subsurf_modifier_runtime_init(SubsurfModifierData *smd, const bool use_render_params)
|
||||
{
|
||||
SubdivSettings settings = BKE_subsurf_modifier_settings_init(smd, use_render_params);
|
||||
subdiv::Settings settings = BKE_subsurf_modifier_settings_init(smd, use_render_params);
|
||||
|
||||
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
|
||||
if (settings.level == 0) {
|
||||
@@ -90,7 +91,7 @@ bool BKE_subsurf_modifier_use_custom_loop_normals(const SubsurfModifierData *smd
|
||||
bool BKE_subsurf_modifier_has_split_normals(const SubsurfModifierData *smd, const Mesh *mesh)
|
||||
{
|
||||
return BKE_subsurf_modifier_use_custom_loop_normals(smd, mesh) ||
|
||||
mesh->normals_domain() == blender::bke::MeshNormalDomain::Corner;
|
||||
mesh->normals_domain() == MeshNormalDomain::Corner;
|
||||
}
|
||||
|
||||
static bool is_subdivision_evaluation_possible_on_gpu()
|
||||
@@ -157,20 +158,20 @@ bool BKE_subsurf_modifier_has_gpu_subdiv(const Mesh *mesh)
|
||||
return runtime_data && runtime_data->has_gpu_subdiv;
|
||||
}
|
||||
|
||||
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = nullptr;
|
||||
void (*BKE_subsurf_modifier_free_gpu_cache_cb)(subdiv::Subdiv *subdiv) = nullptr;
|
||||
|
||||
Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
|
||||
const Mesh *mesh,
|
||||
const bool for_draw_code)
|
||||
subdiv::Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(SubsurfRuntimeData *runtime_data,
|
||||
const Mesh *mesh,
|
||||
const bool for_draw_code)
|
||||
{
|
||||
if (for_draw_code) {
|
||||
runtime_data->used_gpu = 2; /* countdown in frames */
|
||||
|
||||
return runtime_data->subdiv_gpu = BKE_subdiv_update_from_mesh(
|
||||
return runtime_data->subdiv_gpu = subdiv::update_from_mesh(
|
||||
runtime_data->subdiv_gpu, &runtime_data->settings, mesh);
|
||||
}
|
||||
runtime_data->used_cpu = 2;
|
||||
return runtime_data->subdiv_cpu = BKE_subdiv_update_from_mesh(
|
||||
return runtime_data->subdiv_cpu = subdiv::update_from_mesh(
|
||||
runtime_data->subdiv_cpu, &runtime_data->settings, mesh);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
|
||||
#include "BLI_time.h"
|
||||
|
||||
void BKE_subdiv_stats_init(SubdivStats *stats)
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
void stats_init(SubdivStats *stats)
|
||||
{
|
||||
stats->topology_refiner_creation_time = 0.0;
|
||||
stats->subdiv_to_mesh_time = 0.0;
|
||||
@@ -24,22 +26,22 @@ void BKE_subdiv_stats_init(SubdivStats *stats)
|
||||
stats->topology_compare_time = 0.0;
|
||||
}
|
||||
|
||||
void BKE_subdiv_stats_begin(SubdivStats *stats, eSubdivStatsValue value)
|
||||
void stats_begin(SubdivStats *stats, StatsValue value)
|
||||
{
|
||||
stats->begin_timestamp_[value] = BLI_time_now_seconds();
|
||||
}
|
||||
|
||||
void BKE_subdiv_stats_end(SubdivStats *stats, eSubdivStatsValue value)
|
||||
void stats_end(SubdivStats *stats, StatsValue value)
|
||||
{
|
||||
stats->values_[value] = BLI_time_now_seconds() - stats->begin_timestamp_[value];
|
||||
}
|
||||
|
||||
void BKE_subdiv_stats_reset(SubdivStats *stats, eSubdivStatsValue value)
|
||||
void stats_reset(SubdivStats *stats, StatsValue value)
|
||||
{
|
||||
stats->values_[value] = 0.0;
|
||||
}
|
||||
|
||||
void BKE_subdiv_stats_print(const SubdivStats *stats)
|
||||
void stats_print(const SubdivStats *stats)
|
||||
{
|
||||
#define STATS_PRINT_TIME(stats, value, description) \
|
||||
do { \
|
||||
@@ -61,3 +63,5 @@ void BKE_subdiv_stats_print(const SubdivStats *stats)
|
||||
|
||||
#undef STATS_PRINT_TIME
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -12,8 +12,12 @@
|
||||
|
||||
#include "opensubdiv_topology_refiner_capi.hh"
|
||||
|
||||
int BKE_subdiv_topology_num_fvar_layers_get(const Subdiv *subdiv)
|
||||
namespace blender::bke::subdiv {
|
||||
|
||||
int topology_num_fvar_layers_get(const Subdiv *subdiv)
|
||||
{
|
||||
OpenSubdiv_TopologyRefiner *topology_refiner = subdiv->topology_refiner;
|
||||
return topology_refiner->getNumFVarChannels(topology_refiner);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::subdiv
|
||||
|
||||
@@ -585,7 +585,7 @@ gpu::VertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_l
|
||||
/** \name Utilities for DRWPatchMap.
|
||||
* \{ */
|
||||
|
||||
static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, Subdiv *subdiv)
|
||||
static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
gpu::VertBuf *patch_map_handles = GPU_vertbuf_calloc();
|
||||
GPU_vertbuf_init_with_format_ex(patch_map_handles, get_patch_handle_format(), GPU_USAGE_STATIC);
|
||||
@@ -839,7 +839,8 @@ static DRWSubdivCache &mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache &mbc)
|
||||
return *subdiv_cache;
|
||||
}
|
||||
|
||||
static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, const Mesh *mesh)
|
||||
static void draw_subdiv_invalidate_evaluator_for_orco(bke::subdiv::Subdiv *subdiv,
|
||||
const Mesh *mesh)
|
||||
{
|
||||
if (!(subdiv && subdiv->evaluator)) {
|
||||
return;
|
||||
@@ -875,8 +876,8 @@ static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, const Mesh
|
||||
|
||||
struct DRWCacheBuildingContext {
|
||||
const Mesh *coarse_mesh;
|
||||
const Subdiv *subdiv;
|
||||
const SubdivToMeshSettings *settings;
|
||||
const bke::subdiv::Subdiv *subdiv;
|
||||
const bke::subdiv::ToMeshSettings *settings;
|
||||
|
||||
DRWSubdivCache *cache;
|
||||
|
||||
@@ -901,7 +902,7 @@ struct DRWCacheBuildingContext {
|
||||
const int *e_origindex;
|
||||
};
|
||||
|
||||
static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context,
|
||||
static bool draw_subdiv_topology_info_cb(const bke::subdiv::ForeachContext *foreach_context,
|
||||
const int num_verts,
|
||||
const int num_edges,
|
||||
const int num_loops,
|
||||
@@ -1001,7 +1002,7 @@ static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_con
|
||||
return true;
|
||||
}
|
||||
|
||||
static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context,
|
||||
static void draw_subdiv_vertex_corner_cb(const bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int /*ptex_face_index*/,
|
||||
const float /*u*/,
|
||||
@@ -1016,7 +1017,7 @@ static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_con
|
||||
ctx->vert_origindex_map[subdiv_vertex_index] = coarse_vertex_index;
|
||||
}
|
||||
|
||||
static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext * /*foreach_context*/,
|
||||
static void draw_subdiv_vertex_edge_cb(const bke::subdiv::ForeachContext * /*foreach_context*/,
|
||||
void * /*tls_v*/,
|
||||
const int /*ptex_face_index*/,
|
||||
const float /*u*/,
|
||||
@@ -1026,10 +1027,10 @@ static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext * /*foreach_co
|
||||
const int /*coarse_corner*/,
|
||||
const int /*subdiv_vertex_index*/)
|
||||
{
|
||||
/* Required if SubdivForeachContext.vertex_corner is also set. */
|
||||
/* Required if bke::subdiv::ForeachContext.vertex_corner is also set. */
|
||||
}
|
||||
|
||||
static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
|
||||
static void draw_subdiv_edge_cb(const bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls*/,
|
||||
const int coarse_edge_index,
|
||||
const int subdiv_edge_index,
|
||||
@@ -1066,7 +1067,7 @@ static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context,
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
|
||||
static void draw_subdiv_loop_cb(const bke::subdiv::ForeachContext *foreach_context,
|
||||
void * /*tls_v*/,
|
||||
const int ptex_face_index,
|
||||
const float u,
|
||||
@@ -1089,7 +1090,7 @@ static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context,
|
||||
ctx->subdiv_loop_vert_index[subdiv_loop_index] = coarse_vertex_index;
|
||||
}
|
||||
|
||||
static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context)
|
||||
static void draw_subdiv_foreach_callbacks(bke::subdiv::ForeachContext *foreach_context)
|
||||
{
|
||||
memset(foreach_context, 0, sizeof(*foreach_context));
|
||||
foreach_context->topology_info = draw_subdiv_topology_info_cb;
|
||||
@@ -1099,16 +1100,17 @@ static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context)
|
||||
foreach_context->vertex_edge = draw_subdiv_vertex_edge_cb;
|
||||
}
|
||||
|
||||
static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context, Subdiv *subdiv)
|
||||
static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context,
|
||||
bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
SubdivForeachContext foreach_context;
|
||||
bke::subdiv::ForeachContext foreach_context;
|
||||
draw_subdiv_foreach_callbacks(&foreach_context);
|
||||
foreach_context.user_data = cache_building_context;
|
||||
|
||||
BKE_subdiv_foreach_subdiv_geometry(subdiv,
|
||||
&foreach_context,
|
||||
cache_building_context->settings,
|
||||
cache_building_context->coarse_mesh);
|
||||
bke::subdiv::foreach_subdiv_geometry(subdiv,
|
||||
&foreach_context,
|
||||
cache_building_context->settings,
|
||||
cache_building_context->coarse_mesh);
|
||||
|
||||
/* Now that traversal is done, we can set up the right original indices for the
|
||||
* subdiv-loop-to-coarse-edge map.
|
||||
@@ -1166,11 +1168,11 @@ static void build_vertex_face_adjacency_maps(DRWSubdivCache &cache)
|
||||
}
|
||||
|
||||
static bool draw_subdiv_build_cache(DRWSubdivCache &cache,
|
||||
Subdiv *subdiv,
|
||||
bke::subdiv::Subdiv *subdiv,
|
||||
const Mesh *mesh_eval,
|
||||
const SubsurfRuntimeData *runtime_data)
|
||||
{
|
||||
SubdivToMeshSettings to_mesh_settings;
|
||||
bke::subdiv::ToMeshSettings to_mesh_settings;
|
||||
to_mesh_settings.resolution = runtime_data->resolution;
|
||||
to_mesh_settings.use_optimal_display = false;
|
||||
|
||||
@@ -1209,7 +1211,7 @@ static bool draw_subdiv_build_cache(DRWSubdivCache &cache,
|
||||
/* Build buffers for the PatchMap. */
|
||||
draw_patch_map_build(&cache.gpu_patch_map, subdiv);
|
||||
|
||||
cache.face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv);
|
||||
cache.face_ptex_offset = bke::subdiv::face_ptex_offset_get(subdiv);
|
||||
|
||||
/* Build patch coordinates for all the face dots. */
|
||||
cache.fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(),
|
||||
@@ -1437,7 +1439,7 @@ void draw_subdiv_extract_pos_nor(const DRWSubdivCache &cache,
|
||||
return;
|
||||
}
|
||||
|
||||
Subdiv *subdiv = cache.subdiv;
|
||||
bke::subdiv::Subdiv *subdiv = cache.subdiv;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
|
||||
OpenSubdiv_Buffer src_buffer_interface;
|
||||
@@ -1519,7 +1521,7 @@ void draw_subdiv_extract_uvs(const DRWSubdivCache &cache,
|
||||
return;
|
||||
}
|
||||
|
||||
Subdiv *subdiv = cache.subdiv;
|
||||
bke::subdiv::Subdiv *subdiv = cache.subdiv;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
|
||||
OpenSubdiv_Buffer src_buffer_interface;
|
||||
@@ -1769,7 +1771,7 @@ void draw_subdiv_build_fdots_buffers(const DRWSubdivCache &cache,
|
||||
return;
|
||||
}
|
||||
|
||||
Subdiv *subdiv = cache.subdiv;
|
||||
bke::subdiv::Subdiv *subdiv = cache.subdiv;
|
||||
OpenSubdiv_Evaluator *evaluator = subdiv->evaluator;
|
||||
|
||||
OpenSubdiv_Buffer src_buffer_interface;
|
||||
@@ -2117,13 +2119,14 @@ static bool draw_subdiv_create_requested_buffers(Object *ob,
|
||||
|
||||
draw_subdiv_invalidate_evaluator_for_orco(runtime_data->subdiv_gpu, mesh_eval);
|
||||
|
||||
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true);
|
||||
bke::subdiv::Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
|
||||
runtime_data, mesh_eval, true);
|
||||
if (!subdiv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!BKE_subdiv_eval_begin_from_mesh(
|
||||
subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GPU, evaluator_cache))
|
||||
if (!bke::subdiv::eval_begin_from_mesh(
|
||||
subdiv, mesh_eval, nullptr, bke::subdiv::SUBDIV_EVALUATOR_TYPE_GPU, evaluator_cache))
|
||||
{
|
||||
/* This could happen in two situations:
|
||||
* - OpenSubdiv is disabled.
|
||||
@@ -2253,7 +2256,7 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
|
||||
DRWSubdivLooseVertex &subd_v1 = loose_subd_verts[subd_vert_offset];
|
||||
subd_v1.coarse_vertex_index = (i == 0) ? coarse_edge[0] : -1u;
|
||||
const float u1 = i * inv_resolution_1;
|
||||
BKE_subdiv_mesh_interpolate_position_on_edge(
|
||||
bke::subdiv::mesh_interpolate_position_on_edge(
|
||||
reinterpret_cast<const float(*)[3]>(coarse_positions.data()),
|
||||
coarse_edges.data(),
|
||||
vert_to_edge_map,
|
||||
@@ -2268,7 +2271,7 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
|
||||
DRWSubdivLooseVertex &subd_v2 = loose_subd_verts[subd_vert_offset];
|
||||
subd_v2.coarse_vertex_index = ((i + 1) == resolution - 1) ? coarse_edge[1] : -1u;
|
||||
const float u2 = (i + 1) * inv_resolution_1;
|
||||
BKE_subdiv_mesh_interpolate_position_on_edge(
|
||||
bke::subdiv::mesh_interpolate_position_on_edge(
|
||||
reinterpret_cast<const float(*)[3]>(coarse_positions.data()),
|
||||
coarse_edges.data(),
|
||||
vert_to_edge_map,
|
||||
@@ -2376,7 +2379,7 @@ void DRW_subdiv_free()
|
||||
static LinkNode *gpu_subdiv_free_queue = nullptr;
|
||||
static ThreadMutex gpu_subdiv_queue_mutex = BLI_MUTEX_INITIALIZER;
|
||||
|
||||
void DRW_subdiv_cache_free(Subdiv *subdiv)
|
||||
void DRW_subdiv_cache_free(bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
BLI_mutex_lock(&gpu_subdiv_queue_mutex);
|
||||
BLI_linklist_prepend(&gpu_subdiv_free_queue, subdiv);
|
||||
@@ -2392,10 +2395,11 @@ void DRW_cache_free_old_subdiv()
|
||||
BLI_mutex_lock(&gpu_subdiv_queue_mutex);
|
||||
|
||||
while (gpu_subdiv_free_queue != nullptr) {
|
||||
Subdiv *subdiv = static_cast<Subdiv *>(BLI_linklist_pop(&gpu_subdiv_free_queue));
|
||||
bke::subdiv::Subdiv *subdiv = static_cast<bke::subdiv::Subdiv *>(
|
||||
BLI_linklist_pop(&gpu_subdiv_free_queue));
|
||||
/* Set the type to CPU so that we do actually free the cache. */
|
||||
subdiv->evaluator->type = OPENSUBDIV_EVALUATOR_CPU;
|
||||
BKE_subdiv_free(subdiv);
|
||||
bke::subdiv::free(subdiv);
|
||||
}
|
||||
|
||||
BLI_mutex_unlock(&gpu_subdiv_queue_mutex);
|
||||
|
||||
@@ -17,7 +17,9 @@ class VertBuf;
|
||||
struct GPUVertFormat;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
namespace blender::bke::subdiv {
|
||||
struct Subdiv;
|
||||
}
|
||||
struct ToolSettings;
|
||||
|
||||
namespace blender::draw {
|
||||
@@ -103,7 +105,7 @@ struct DRWSubdivLooseGeom {
|
||||
struct DRWSubdivCache {
|
||||
const Mesh *mesh;
|
||||
BMesh *bm;
|
||||
Subdiv *subdiv;
|
||||
bke::subdiv::Subdiv *subdiv;
|
||||
bool optimal_display;
|
||||
bool hide_unmapped_edges;
|
||||
bool use_custom_loop_normals;
|
||||
@@ -211,7 +213,7 @@ void DRW_create_subdivision(Object *ob,
|
||||
|
||||
void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache);
|
||||
|
||||
void DRW_subdiv_cache_free(Subdiv *subdiv);
|
||||
void DRW_subdiv_cache_free(bke::subdiv::Subdiv *subdiv);
|
||||
|
||||
void draw_subdiv_init_origindex_buffer(gpu::VertBuf *buffer,
|
||||
int32_t *vert_origindex,
|
||||
|
||||
@@ -863,14 +863,17 @@ static int bmesh_restore(bContext *C, Node &unode, Object *ob, SculptSession *ss
|
||||
*
|
||||
* Note that the dependency graph is ensured to be evaluated prior to the undo step is decoded,
|
||||
* so if the object's modifier stack references other object it is all fine. */
|
||||
static void refine_subdiv(Depsgraph *depsgraph, SculptSession *ss, Object *object, Subdiv *subdiv)
|
||||
static void refine_subdiv(Depsgraph *depsgraph,
|
||||
SculptSession *ss,
|
||||
Object *object,
|
||||
bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Array<float3> deformed_verts = BKE_multires_create_deformed_base_mesh_vert_coords(
|
||||
depsgraph, object, ss->multires.modifier);
|
||||
|
||||
BKE_subdiv_eval_refine_from_mesh(subdiv,
|
||||
static_cast<const Mesh *>(object->data),
|
||||
reinterpret_cast<float(*)[3]>(deformed_verts.data()));
|
||||
bke::subdiv::eval_refine_from_mesh(subdiv,
|
||||
static_cast<const Mesh *>(object->data),
|
||||
reinterpret_cast<float(*)[3]>(deformed_verts.data()));
|
||||
}
|
||||
|
||||
static void restore_list(bContext *C, Depsgraph *depsgraph, UndoSculpt &usculpt)
|
||||
|
||||
@@ -564,23 +564,24 @@ static Mesh *subdivide_edit_mesh(const Object *object,
|
||||
const BMEditMesh *em,
|
||||
const SubsurfModifierData *smd)
|
||||
{
|
||||
using namespace blender;
|
||||
Mesh *me_from_em = BKE_mesh_from_bmesh_for_eval_nomain(
|
||||
em->bm, nullptr, static_cast<const Mesh *>(object->data));
|
||||
BKE_mesh_ensure_default_orig_index_customdata(me_from_em);
|
||||
|
||||
SubdivSettings settings = BKE_subsurf_modifier_settings_init(smd, false);
|
||||
bke::subdiv::Settings settings = BKE_subsurf_modifier_settings_init(smd, false);
|
||||
if (settings.level == 1) {
|
||||
return me_from_em;
|
||||
}
|
||||
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
bke::subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = (1 << smd->levels) + 1;
|
||||
mesh_settings.use_optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges);
|
||||
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&settings, me_from_em);
|
||||
Mesh *result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me_from_em);
|
||||
bke::subdiv::Subdiv *subdiv = bke::subdiv::new_from_mesh(&settings, me_from_em);
|
||||
Mesh *result = bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, me_from_em);
|
||||
BKE_id_free(nullptr, me_from_em);
|
||||
BKE_subdiv_free(subdiv);
|
||||
bke::subdiv::free(subdiv);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
struct MultiresRuntimeData {
|
||||
/* Cached subdivision surface descriptor, with topology and settings. */
|
||||
Subdiv *subdiv;
|
||||
blender::bke::subdiv::Subdiv *subdiv;
|
||||
};
|
||||
|
||||
static void init_data(ModifierData *md)
|
||||
@@ -80,7 +80,7 @@ static void free_runtime_data(void *runtime_data_v)
|
||||
}
|
||||
MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)runtime_data_v;
|
||||
if (runtime_data->subdiv != nullptr) {
|
||||
BKE_subdiv_free(runtime_data->subdiv);
|
||||
blender::bke::subdiv::free(runtime_data->subdiv);
|
||||
}
|
||||
MEM_freeN(runtime_data);
|
||||
}
|
||||
@@ -104,12 +104,14 @@ static MultiresRuntimeData *multires_ensure_runtime(MultiresModifierData *mmd)
|
||||
|
||||
/* Main goal of this function is to give usable subdivision surface descriptor
|
||||
* which matches settings and topology. */
|
||||
static Subdiv *subdiv_descriptor_ensure(MultiresModifierData *mmd,
|
||||
const SubdivSettings *subdiv_settings,
|
||||
const Mesh *mesh)
|
||||
static blender::bke::subdiv::Subdiv *subdiv_descriptor_ensure(
|
||||
MultiresModifierData *mmd,
|
||||
const blender::bke::subdiv::Settings *subdiv_settings,
|
||||
const Mesh *mesh)
|
||||
{
|
||||
MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)mmd->modifier.runtime;
|
||||
Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh);
|
||||
blender::bke::subdiv::Subdiv *subdiv = blender::bke::subdiv::update_from_mesh(
|
||||
runtime_data->subdiv, subdiv_settings, mesh);
|
||||
runtime_data->subdiv = subdiv;
|
||||
return subdiv;
|
||||
}
|
||||
@@ -119,7 +121,7 @@ static Subdiv *subdiv_descriptor_ensure(MultiresModifierData *mmd,
|
||||
static Mesh *multires_as_mesh(MultiresModifierData *mmd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh,
|
||||
Subdiv *subdiv)
|
||||
blender::bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Mesh *result = mesh;
|
||||
const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
|
||||
@@ -127,7 +129,7 @@ static Mesh *multires_as_mesh(MultiresModifierData *mmd,
|
||||
const bool ignore_control_edges = (ctx->flag & MOD_APPLY_TO_BASE_MESH);
|
||||
const Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
Object *object = ctx->object;
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
blender::bke::subdiv::ToMeshSettings mesh_settings;
|
||||
BKE_multires_subdiv_mesh_settings_init(&mesh_settings,
|
||||
scene,
|
||||
object,
|
||||
@@ -138,8 +140,8 @@ static Mesh *multires_as_mesh(MultiresModifierData *mmd,
|
||||
if (mesh_settings.resolution < 3) {
|
||||
return result;
|
||||
}
|
||||
BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
blender::bke::subdiv::displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
result = blender::bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -164,7 +166,7 @@ static void multires_ccg_settings_init(SubdivToCCGSettings *settings,
|
||||
static Mesh *multires_as_ccg(MultiresModifierData *mmd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh,
|
||||
Subdiv *subdiv)
|
||||
blender::bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Mesh *result = mesh;
|
||||
SubdivToCCGSettings ccg_settings;
|
||||
@@ -172,7 +174,7 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd,
|
||||
if (ccg_settings.resolution < 3) {
|
||||
return result;
|
||||
}
|
||||
BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
blender::bke::subdiv::displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
result = BKE_subdiv_to_ccg_mesh(*subdiv, ccg_settings, *mesh);
|
||||
|
||||
/* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share
|
||||
@@ -192,13 +194,13 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||
return result;
|
||||
#endif
|
||||
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
||||
SubdivSettings subdiv_settings;
|
||||
blender::bke::subdiv::Settings subdiv_settings;
|
||||
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
|
||||
if (subdiv_settings.level == 0) {
|
||||
return result;
|
||||
}
|
||||
MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
|
||||
Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
|
||||
blender::bke::subdiv::Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
|
||||
if (subdiv == nullptr) {
|
||||
/* Happens on bad topology, also on empty input mesh. */
|
||||
return result;
|
||||
@@ -235,7 +237,7 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||
sculpt_session->faces = {};
|
||||
sculpt_session->corner_verts = {};
|
||||
}
|
||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||
// blender::bke::subdiv::stats_print(&subdiv->stats);
|
||||
}
|
||||
else {
|
||||
if (use_clnors) {
|
||||
@@ -252,9 +254,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||
BKE_mesh_set_custom_normals(result, corner_normals);
|
||||
CustomData_free_layers(&result->corner_data, CD_NORMAL, result->corners_num);
|
||||
}
|
||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||
// blender::bke::subdiv::stats_print(&subdiv->stats);
|
||||
if (subdiv != runtime_data->subdiv) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -274,7 +276,7 @@ static void deform_matrices(ModifierData *md,
|
||||
|
||||
MultiresModifierData *mmd = (MultiresModifierData *)md;
|
||||
|
||||
SubdivSettings subdiv_settings;
|
||||
blender::bke::subdiv::Settings subdiv_settings;
|
||||
BKE_multires_subdiv_settings_init(&subdiv_settings, mmd);
|
||||
if (subdiv_settings.level == 0) {
|
||||
return;
|
||||
@@ -287,16 +289,16 @@ static void deform_matrices(ModifierData *md,
|
||||
}
|
||||
|
||||
MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
|
||||
Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
|
||||
blender::bke::subdiv::Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
|
||||
if (subdiv == nullptr) {
|
||||
/* Happens on bad topology, also on empty input mesh. */
|
||||
return;
|
||||
}
|
||||
BKE_subdiv_displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
BKE_subdiv_deform_coarse_vertices(
|
||||
blender::bke::subdiv::displacement_attach_from_multires(subdiv, mesh, mmd);
|
||||
blender::bke::subdiv::deform_coarse_vertices(
|
||||
subdiv, mesh, reinterpret_cast<float(*)[3]>(positions.data()), positions.size());
|
||||
if (subdiv != runtime_data->subdiv) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,10 +86,10 @@ static void free_runtime_data(void *runtime_data_v)
|
||||
}
|
||||
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)runtime_data_v;
|
||||
if (runtime_data->subdiv_cpu != nullptr) {
|
||||
BKE_subdiv_free(runtime_data->subdiv_cpu);
|
||||
blender::bke::subdiv::free(runtime_data->subdiv_cpu);
|
||||
}
|
||||
if (runtime_data->subdiv_gpu != nullptr) {
|
||||
BKE_subdiv_free(runtime_data->subdiv_gpu);
|
||||
blender::bke::subdiv::free(runtime_data->subdiv_gpu);
|
||||
}
|
||||
MEM_freeN(runtime_data);
|
||||
}
|
||||
@@ -128,7 +128,7 @@ static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
|
||||
|
||||
/* Subdivide into fully qualified mesh. */
|
||||
|
||||
static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
|
||||
static void subdiv_mesh_settings_init(blender::bke::subdiv::ToMeshSettings *settings,
|
||||
const SubsurfModifierData *smd,
|
||||
const ModifierEvalContext *ctx)
|
||||
{
|
||||
@@ -141,15 +141,15 @@ static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
|
||||
static Mesh *subdiv_as_mesh(SubsurfModifierData *smd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh,
|
||||
Subdiv *subdiv)
|
||||
blender::bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Mesh *result = mesh;
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
blender::bke::subdiv::ToMeshSettings mesh_settings;
|
||||
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
|
||||
if (mesh_settings.resolution < 3) {
|
||||
return result;
|
||||
}
|
||||
result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
result = blender::bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ static void subdiv_ccg_settings_init(SubdivToCCGSettings *settings,
|
||||
static Mesh *subdiv_as_ccg(SubsurfModifierData *smd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh,
|
||||
Subdiv *subdiv)
|
||||
blender::bke::subdiv::Subdiv *subdiv)
|
||||
{
|
||||
Mesh *result = mesh;
|
||||
SubdivToCCGSettings ccg_settings;
|
||||
@@ -187,7 +187,7 @@ static void subdiv_cache_mesh_wrapper_settings(const ModifierEvalContext *ctx,
|
||||
SubsurfModifierData *smd,
|
||||
SubsurfRuntimeData *runtime_data)
|
||||
{
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
blender::bke::subdiv::ToMeshSettings mesh_settings;
|
||||
subdiv_mesh_settings_init(&mesh_settings, smd, ctx);
|
||||
|
||||
runtime_data->has_gpu_subdiv = true;
|
||||
@@ -239,7 +239,8 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||
}
|
||||
}
|
||||
|
||||
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
|
||||
blender::bke::subdiv::Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
|
||||
runtime_data, mesh, false);
|
||||
if (subdiv == nullptr) {
|
||||
/* Happens on bad topology, but also on empty input mesh. */
|
||||
return result;
|
||||
@@ -265,9 +266,9 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh
|
||||
&result->corner_data, CD_NORMAL, result->corners_num)));
|
||||
CustomData_free_layers(&result->corner_data, CD_NORMAL, result->corners_num);
|
||||
}
|
||||
// BKE_subdiv_stats_print(&subdiv->stats);
|
||||
// blender::bke::subdiv::stats_print(&subdiv->stats);
|
||||
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -290,15 +291,16 @@ static void deform_matrices(ModifierData *md,
|
||||
return;
|
||||
}
|
||||
SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime;
|
||||
Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh, false);
|
||||
blender::bke::subdiv::Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(
|
||||
runtime_data, mesh, false);
|
||||
if (subdiv == nullptr) {
|
||||
/* Happens on bad topology, but also on empty input mesh. */
|
||||
return;
|
||||
}
|
||||
BKE_subdiv_deform_coarse_vertices(
|
||||
blender::bke::subdiv::deform_coarse_vertices(
|
||||
subdiv, mesh, reinterpret_cast<float(*)[3]>(positions.data()), positions.size());
|
||||
if (!ELEM(subdiv, runtime_data->subdiv_cpu, runtime_data->subdiv_gpu)) {
|
||||
BKE_subdiv_free(subdiv);
|
||||
blender::bke::subdiv::free(subdiv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,29 +24,29 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
static Mesh *simple_subdivide_mesh(const Mesh &mesh, const int level)
|
||||
{
|
||||
/* Initialize mesh settings. */
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
bke::subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = (1 << level) + 1;
|
||||
mesh_settings.use_optimal_display = false;
|
||||
|
||||
/* Initialize subdivision settings. */
|
||||
SubdivSettings subdiv_settings;
|
||||
bke::subdiv::Settings subdiv_settings;
|
||||
subdiv_settings.is_simple = true;
|
||||
subdiv_settings.is_adaptive = false;
|
||||
subdiv_settings.use_creases = false;
|
||||
subdiv_settings.level = 1;
|
||||
subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
0);
|
||||
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(0);
|
||||
subdiv_settings.vtx_boundary_interpolation =
|
||||
bke::subdiv::vtx_boundary_interpolation_from_subsurf(0);
|
||||
subdiv_settings.fvar_linear_interpolation = bke::subdiv::fvar_interpolation_from_uv_smooth(0);
|
||||
|
||||
/* Apply subdivision from mesh. */
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, &mesh);
|
||||
bke::subdiv::Subdiv *subdiv = bke::subdiv::new_from_mesh(&subdiv_settings, &mesh);
|
||||
if (!subdiv) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mesh *result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh);
|
||||
Mesh *result = bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, &mesh);
|
||||
|
||||
BKE_subdiv_free(subdiv);
|
||||
bke::subdiv::free(subdiv);
|
||||
|
||||
geometry::debug_randomize_mesh_order(result);
|
||||
return result;
|
||||
|
||||
@@ -126,27 +126,27 @@ static Mesh *mesh_subsurf_calc(const Mesh *mesh,
|
||||
mesh = mesh_copy;
|
||||
}
|
||||
|
||||
SubdivToMeshSettings mesh_settings;
|
||||
bke::subdiv::ToMeshSettings mesh_settings;
|
||||
mesh_settings.resolution = (1 << level) + 1;
|
||||
mesh_settings.use_optimal_display = false;
|
||||
|
||||
SubdivSettings subdiv_settings;
|
||||
bke::subdiv::Settings subdiv_settings;
|
||||
subdiv_settings.is_simple = false;
|
||||
subdiv_settings.is_adaptive = false;
|
||||
subdiv_settings.use_creases = use_creases;
|
||||
subdiv_settings.level = level;
|
||||
subdiv_settings.vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf(
|
||||
boundary_smooth);
|
||||
subdiv_settings.fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth(
|
||||
subdiv_settings.vtx_boundary_interpolation =
|
||||
bke::subdiv::vtx_boundary_interpolation_from_subsurf(boundary_smooth);
|
||||
subdiv_settings.fvar_linear_interpolation = bke::subdiv::fvar_interpolation_from_uv_smooth(
|
||||
uv_smooth);
|
||||
|
||||
Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
|
||||
bke::subdiv::Subdiv *subdiv = bke::subdiv::new_from_mesh(&subdiv_settings, mesh);
|
||||
if (!subdiv) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mesh *result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
BKE_subdiv_free(subdiv);
|
||||
Mesh *result = bke::subdiv::subdiv_to_mesh(subdiv, &mesh_settings, mesh);
|
||||
bke::subdiv::free(subdiv);
|
||||
|
||||
if (use_creases) {
|
||||
/* Remove the layer in case it was created by the node from the field input. The fact
|
||||
|
||||
@@ -308,7 +308,7 @@ void WM_init(bContext *C, int argc, const char **argv)
|
||||
GPU_render_end();
|
||||
}
|
||||
|
||||
BKE_subdiv_init();
|
||||
blender::bke::subdiv::init();
|
||||
|
||||
ED_spacemacros_init();
|
||||
|
||||
@@ -588,7 +588,7 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_
|
||||
COM_deinitialize();
|
||||
#endif
|
||||
|
||||
BKE_subdiv_exit();
|
||||
bke::subdiv::exit();
|
||||
|
||||
if (gpu_is_init) {
|
||||
BKE_image_free_unused_gpu_textures();
|
||||
|
||||
Reference in New Issue
Block a user