Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/modifiers')
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_array.c5
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c279
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c2
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c72
-rw-r--r--source/blender/modifiers/intern/MOD_util.c1
-rw-r--r--source/blender/modifiers/intern/MOD_weighted_normal.c671
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c12
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c13
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c21
11 files changed, 1041 insertions, 37 deletions
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 45a4070d29f..43dc8507ffb 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -101,6 +101,7 @@ set(SRC
intern/MOD_uvproject.c
intern/MOD_warp.c
intern/MOD_wave.c
+ intern/MOD_weighted_normal.c
intern/MOD_weightvg_util.c
intern/MOD_weightvgedit.c
intern/MOD_weightvgmix.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index cf3794dfaa5..d6e4e1868b2 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -86,6 +86,7 @@ extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
+extern ModifierTypeInfo modifierType_WeightedNormal;
extern ModifierTypeInfo modifierType_Hair;
/* MOD_util.c */
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 5ae0013aab0..085f21fe138 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -456,9 +456,10 @@ static Mesh *arrayModifier_doArray(
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
Curve *cu = amd->curve_ob->data;
if (cu) {
- if (amd->curve_ob->curve_cache && amd->curve_ob->curve_cache->path) {
+ CurveCache *curve_cache = amd->curve_ob->runtime.curve_cache;
+ if (curve_cache != NULL && curve_cache->path != NULL) {
float scale_fac = mat4_to_scale(amd->curve_ob->obmat);
- length = scale_fac * amd->curve_ob->curve_cache->path->totdist;
+ length = scale_fac * curve_cache->path->totdist;
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 64d1a6c310b..ba07a3a56cc 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -32,11 +32,15 @@
* \ingroup modifiers
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "BLI_utildefines.h"
+#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_string.h"
@@ -49,6 +53,8 @@
#include "bmesh.h"
#include "bmesh_tools.h"
+#include "DEG_depsgraph_query.h"
+
static void initData(ModifierData *md)
{
BevelModifierData *bmd = (BevelModifierData *) md;
@@ -59,10 +65,14 @@ static void initData(ModifierData *md)
bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
bmd->lim_flags = 0;
bmd->e_flags = 0;
+ bmd->edge_flags = 0;
bmd->mat = -1;
bmd->profile = 0.5f;
bmd->bevel_angle = DEG2RADF(30.0f);
bmd->defgrp_name[0] = '\0';
+ bmd->hnmode = MOD_BEVEL_HN_NONE;
+ bmd->hn_strength = 0.5f;
+ bmd->clnordata.faceHash = NULL;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -76,6 +86,254 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
return dataMask;
}
+static void bevel_set_weighted_normal_face_strength(BMesh *bm, Scene *scene)
+{
+ BMFace *f;
+ BMIter fiter;
+ const char *wn_layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+
+ if (cd_prop_int_idx == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, wn_layer_id);
+ cd_prop_int_idx = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, wn_layer_id);
+ }
+ cd_prop_int_idx -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(&bm->pdata, CD_PROP_INT, cd_prop_int_idx);
+
+ const int face_strength = scene->toolsettings->face_strength;
+
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_TAG)) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength = face_strength;
+ }
+ }
+}
+
+static void bevel_mod_harden_normals(
+ BevelModifierData *bmd, BMesh *bm, const float hn_strength,
+ const int hnmode, MDeformVert *dvert, int vgroup)
+{
+ if (bmd->res > 20 || bmd->value == 0)
+ return;
+
+ BM_mesh_normals_update(bm);
+ BM_lnorspace_update(bm);
+ BM_normals_loops_edges_tag(bm, true);
+
+ const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ const bool do_normal_to_recon = (hn_strength == 1.0f);
+
+ BMFace *f;
+ BMLoop *l, *l_cur, *l_first;
+ BMIter fiter;
+ GHash *faceHash = bmd->clnordata.faceHash;
+
+ /* Iterate throught all loops of a face */
+ BM_ITER_MESH(f, &fiter, bm, BM_FACES_OF_MESH) {
+
+ l_cur = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if ((!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG)) ||
+ (!BM_elem_flag_test(l_cur, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_cur)))
+ {
+
+ /* previous and next edge is sharp, accumulate face normals into loop */
+ if (!BM_elem_flag_test(l_cur->e, BM_ELEM_TAG) && !BM_elem_flag_test(l_cur->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_cur);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_cur, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_cur->v;
+ BMEdge *e_next;
+ const BMEdge *e_org = l_cur->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+ UNUSED_VARS_NDEBUG(v_pivot);
+
+ lfan_pivot = l_cur;
+ e_next = lfan_pivot->e;
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float cn_wght[3] = { 0.0f, 0.0f, 0.0f };
+ int recon_face_count = 0; /* Counts number of reconstructed faces current vert is connected to */
+ BMFace *recon_face = NULL; /* Reconstructed face */
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
+
+ BLI_SMALLSTACK_PUSH(loops, lfan_pivot);
+
+ if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
+ int weight = BM_elem_float_data_get(&bm->edata, lfan_pivot->f, CD_BWEIGHT);
+ if (weight) {
+ if (hnmode == MOD_BEVEL_HN_FACE) {
+ float cur[3]; //Add area weighted face normals
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no); //Else simply add face normals
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no);
+
+ }
+ else if (bmd->lim_flags & MOD_BEVEL_VGROUP) {
+ const bool has_vgroup = dvert != NULL;
+ const bool vert_of_group = (
+ has_vgroup &&
+ (defvert_find_index(&dvert[BM_elem_index_get(l->v)], vgroup) != NULL));
+
+ if (vert_of_group && hnmode == MOD_BEVEL_HN_FACE) {
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ else
+ add_v3_v3(cn_wght, lfan_pivot->f->no);
+ }
+ else {
+ float cur[3];
+ mul_v3_v3fl(cur, lfan_pivot->f->no, BM_face_calc_area(lfan_pivot->f));
+ add_v3_v3(cn_wght, cur);
+ }
+ if (!BLI_ghash_haskey(faceHash, lfan_pivot->f)) {
+ recon_face = f;
+ recon_face_count++;
+ }
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
+ }
+
+ normalize_v3(cn_wght);
+ mul_v3_fl(cn_wght, hn_strength);
+ float n_final[3];
+
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+
+ /* If vertex is edge vert with 1 reconnected face */
+ if (recon_face_count == 1 || do_normal_to_recon) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], recon_face->no, clnors);
+ }
+ else if (vertex_only == false || recon_face_count == 0) {
+ copy_v3_v3(n_final, l->f->no);
+ mul_v3_fl(n_final, 1.0f - hn_strength);
+ add_v3_v3(n_final, cn_wght);
+ normalize_v3(n_final);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ else if (BLI_ghash_haskey(faceHash, l->f)) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], l->v->no, clnors);
+ }
+ }
+ }
+ }
+ } while ((l_cur = l_cur->next) != l_first);
+ }
+}
+
+static void bevel_fix_normal_shading_continuity(BevelModifierData *bmd, BMesh *bm)
+{
+ const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
+ if (bmd->value == 0 || (bmd->clnordata.faceHash == NULL && vertex_only))
+ return;
+
+ BM_mesh_normals_update(bm);
+ BM_lnorspace_update(bm);
+
+ GHash *faceHash = bmd->clnordata.faceHash;
+ BMEdge *e;
+ BMLoop *l;
+ BMIter liter, eiter;
+
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+ const float hn_strength = bmd->hn_strength;
+ float ref = 10.0f;
+
+ BM_ITER_MESH(e, &eiter, bm, BM_EDGES_OF_MESH) {
+ BMFace *f_a, *f_b;
+ BM_edge_face_pair(e, &f_a, &f_b);
+
+ bool has_f_a = false, has_f_b = false;
+ if (f_a)
+ has_f_a = BLI_ghash_haskey(faceHash, f_a);
+ if (f_b)
+ has_f_b = BLI_ghash_haskey(faceHash, f_b);
+ if (has_f_a ^ has_f_b) {
+ /* If one of both faces is present in faceHash then we are at a border
+ * between new vmesh created and reconstructed face */
+
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = (i == 0) ? e->v1 : e->v2;
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+
+ if (l->f == f_a || l->f == f_b) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ float n_final[3], pow_a[3], pow_b[3];
+
+ zero_v3(n_final);
+ copy_v3_v3(pow_a, f_a->no);
+ copy_v3_v3(pow_b, f_b->no);
+ if (has_f_a) {
+ mul_v3_fl(pow_a, bmd->res / ref);
+ mul_v3_fl(pow_b, ref / bmd->res);
+ }
+ else {
+ mul_v3_fl(pow_b, bmd->res / ref);
+ mul_v3_fl(pow_a, ref / bmd->res);
+ }
+ add_v3_v3(n_final, pow_a);
+ add_v3_v3(n_final, pow_b);
+ normalize_v3(n_final);
+
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ }
+ }
+ }
+ else if (has_f_a == true && has_f_b == true) {
+ /* Else if both faces are present we assign clnor corresponding
+ * to vert normal and face normal */
+ for (int i = 0; i < 2; i++) {
+ BMVert *v = (i == 0) ? e->v1 : e->v2;
+ BM_ITER_ELEM(l, &liter, v, BM_LOOPS_OF_VERT) {
+
+ if (l->f == f_a || l->f == f_b) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ float n_final[3], cn_wght[3];
+
+ copy_v3_v3(n_final, v->no);
+ mul_v3_fl(n_final, hn_strength);
+
+ copy_v3_v3(cn_wght, l->f->no);
+ mul_v3_fl(cn_wght, 1.0f - hn_strength);
+
+ add_v3_v3(n_final, cn_wght);
+ normalize_v3(n_final);
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[l_index], n_final, clnors);
+ }
+ }
+ }
+ }
+ }
+}
+
/*
* This calls the new bevel code (added since 2.64)
*/
@@ -96,6 +354,11 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
const int offset_type = bmd->val_flags;
const int mat = CLAMPIS(bmd->mat, -1, ctx->object->totcol - 1);
const bool loop_slide = (bmd->flags & MOD_BEVEL_EVEN_WIDTHS) == 0;
+ const bool mark_seam = (bmd->edge_flags & MOD_BEVEL_MARK_SEAM);
+ const bool mark_sharp = (bmd->edge_flags & MOD_BEVEL_MARK_SHARP);
+ const bool set_wn_strength = (bmd->flags & MOD_BEVEL_SET_WN_STR);
+
+ struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
bm = BKE_mesh_to_bmesh_ex(
mesh,
@@ -166,7 +429,15 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile,
vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
- dvert, vgroup, mat, loop_slide);
+ dvert, vgroup, mat, loop_slide, mark_seam, mark_sharp, bmd->hnmode, &bmd->clnordata);
+
+ if (bmd->hnmode != BEVEL_HN_FIX_SHA && bmd->hnmode != MOD_BEVEL_HN_NONE) {
+ bevel_mod_harden_normals(bmd, bm, bmd->hn_strength, bmd->hnmode, dvert, vgroup);
+ }
+ if (bmd->hnmode == BEVEL_HN_FIX_SHA)
+ bevel_fix_normal_shading_continuity(bmd, bm);
+ if (set_wn_strength)
+ bevel_set_weighted_normal_face_strength(bm, scene);
result = BKE_bmesh_to_mesh_nomain(bm, &(struct BMeshToMeshParams){0});
@@ -175,6 +446,9 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
bm->ftoolflagpool == NULL); /* make sure we never alloc'd these */
BM_mesh_free(bm);
+ if (bmd->clnordata.faceHash)
+ BLI_ghash_free(bmd->clnordata.faceHash, NULL, NULL);
+
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
return result;
@@ -192,7 +466,8 @@ ModifierTypeInfo modifierType_Bevel = {
/* type */ eModifierTypeType_Constructive,
/* flags */ eModifierTypeFlag_AcceptsMesh |
eModifierTypeFlag_SupportsEditmode |
- eModifierTypeFlag_EnableInEditmode,
+ eModifierTypeFlag_EnableInEditmode |
+ eModifierTypeFlag_AcceptsCVs,
/* copyData */ modifier_copyData_generic,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 3a1fe1513af..1fac637a9ef 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -774,7 +774,7 @@ static Mesh *applyModifier(
/* add faces & edges */
origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
- BLI_assert(origindex_edge != NULL);
+ BLI_assert((numEdges == 0) || (origindex_edge != NULL));
ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
orig_ed = &origindex_edge[(numEdges * stride) + newEdges];
for (i = 0; i < rimVerts; i++, ed++, orig_ed++) {
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index f532c168b04..1b25b4f62dc 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -35,8 +35,9 @@
#include <stddef.h>
-#include "DNA_scene_types.h"
#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_mesh_types.h"
#ifdef WITH_OPENSUBDIV
# include "DNA_userdef_types.h"
@@ -44,9 +45,9 @@
#include "BLI_utildefines.h"
-
#include "BKE_cdderivedmesh.h"
#include "BKE_scene.h"
+#include "BKE_subdiv.h"
#include "BKE_subsurf.h"
#include "DEG_depsgraph.h"
@@ -56,6 +57,8 @@
#include "intern/CCGSubSurf.h"
+// #define USE_OPENSUBDIV
+
static void initData(ModifierData *md)
{
SubsurfModifierData *smd = (SubsurfModifierData *) md;
@@ -181,9 +184,70 @@ static DerivedMesh *applyModifierEM(
#endif
result = subsurf_make_derived_from_derived(derivedData, smd, scene, NULL, ss_flags);
+ return result;
+}
+
+#ifdef USE_OPENSUBDIV
+static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx)
+{
+ Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
+ const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER);
+ const int requested_levels = (use_render_params) ? smd->renderLevels
+ : smd->levels;
+ return get_render_subsurf_level(&scene->r,
+ requested_levels,
+ use_render_params);
+}
+
+static void subdiv_settings_init(SubdivSettings *settings,
+ const SubsurfModifierData *smd,
+ const ModifierEvalContext *ctx)
+{
+ settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE);
+ settings->is_adaptive = !settings->is_simple;
+ settings->level = subdiv_levels_for_modifier_get(smd, ctx);
+ settings->fvar_linear_interpolation =
+ (smd->flags & eSubsurfModifierFlag_SubsurfUv)
+ ? SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY
+ : SUBDIV_FVAR_LINEAR_INTERPOLATION_ALL;
+}
+
+static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings,
+ const SubdivSettings *subdiv_settings)
+{
+ settings->resolution = (1 << subdiv_settings->level) + 1;
+}
+static Mesh *applyModifier_subdiv(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
+{
+ Mesh *result = mesh;
+ SubsurfModifierData *smd = (SubsurfModifierData *) md;
+ SubdivSettings subdiv_settings;
+ subdiv_settings_init(&subdiv_settings, smd, ctx);
+ if (subdiv_settings.level == 0) {
+ /* NOTE: Shouldn't really happen, is supposed to be catched by
+ * isDisabled() callback.
+ */
+ return result;
+ }
+ /* TODO(sergey): Try to re-use subdiv when possible. */
+ Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
+ if (subdiv == NULL) {
+ /* Happens on bad topology, ut also on empty input mesh. */
+ return result;
+ }
+ SubdivToMeshSettings mesh_settings;
+ subdiv_mesh_settings_init(&mesh_settings, &subdiv_settings);
+ result = BKE_subdiv_to_mesh(subdiv, &mesh_settings, mesh);
+ /* TODO(sergey): Cache subdiv somehow. */
+ // BKE_subdiv_stats_print(&subdiv->stats);
+ BKE_subdiv_free(subdiv);
return result;
}
+#endif
static bool dependsOnNormals(ModifierData *md)
{
@@ -222,7 +286,11 @@ ModifierTypeInfo modifierType_Subsurf = {
/* deformMatrices */ NULL,
/* deformVertsEM */ NULL,
/* deformMatricesEM */ NULL,
+#ifdef USE_OPENSUBDIV
+ /* applyModifier */ applyModifier_subdiv,
+#else
/* applyModifier */ NULL,
+#endif
/* applyModifierEM */ NULL,
/* initData */ initData,
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 42fd37c19f2..b240dd18119 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -290,6 +290,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(CorrectiveSmooth);
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
+ INIT_TYPE(WeightedNormal);
INIT_TYPE(Hair);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c
new file mode 100644
index 00000000000..69c71d34dbc
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_weighted_normal.c
@@ -0,0 +1,671 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/modifiers/intern/MOD_weighted_normal.c
+ * \ingroup modifiers
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_deform.h"
+#include "BKE_library.h"
+#include "BKE_library_query.h"
+#include "BKE_mesh.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+
+#define CLNORS_VALID_VEC_LEN (1e-6f)
+
+typedef struct ModePair {
+ float val; /* Contains mode based value (face area / corner angle). */
+ int index; /* Index value per poly or per loop. */
+} ModePair;
+
+/* Sorting function used in modifier, sorts in decreasing order. */
+static int modepair_cmp_by_val_inverse(const void *p1, const void *p2)
+{
+ ModePair *r1 = (ModePair *)p1;
+ ModePair *r2 = (ModePair *)p2;
+
+ return (r1->val < r2->val) ? 1 : ((r1->val > r2->val) ? -1 : 0);
+}
+
+/* There will be one of those per vertex (simple case, computing one normal per vertex), or per smooth fan. */
+typedef struct WeightedNormalDataAggregateItem {
+ float normal[3];
+
+ int num_loops; /* Count number of loops using this item so far. */
+ float curr_val; /* Current max val for this item. */
+ int curr_strength; /* Current max strength encountered for this item. */
+} WeightedNormalDataAggregateItem;
+
+#define NUM_CACHED_INVERSE_POWERS_OF_WEIGHT 128
+
+typedef struct WeightedNormalData {
+ const int numVerts;
+ const int numEdges;
+ const int numLoops;
+ const int numPolys;
+
+ MVert *mvert;
+ MEdge *medge;
+
+ MLoop *mloop;
+ short (*clnors)[2];
+ const bool has_clnors; /* True if clnors already existed, false if we had to create them. */
+ const float split_angle;
+
+ MPoly *mpoly;
+ float (*polynors)[3];
+ int *poly_strength;
+
+ MDeformVert *dvert;
+ const int defgrp_index;
+ const bool use_invert_vgroup;
+
+ const float weight;
+ const short mode;
+
+ /* Lower-level, internal processing data. */
+ float cached_inverse_powers_of_weight[NUM_CACHED_INVERSE_POWERS_OF_WEIGHT];
+
+ WeightedNormalDataAggregateItem *items_data;
+
+ ModePair *mode_pair;
+
+ int *loop_to_poly;
+} WeightedNormalData;
+
+/* Check strength of given poly compared to those found so far for that given item (vertex or smooth fan),
+ * and reset matching item_data in case we get a stronger new strength. */
+static bool check_item_poly_strength(
+ WeightedNormalData *wn_data, WeightedNormalDataAggregateItem *item_data, const int mp_index)
+{
+ BLI_assert (wn_data->poly_strength != NULL);
+
+ const int mp_strength = wn_data->poly_strength[mp_index];
+
+ if (mp_strength > item_data->curr_strength) {
+ item_data->curr_strength = mp_strength;
+ item_data->curr_val = 0.0f;
+ item_data->num_loops = 0;
+ zero_v3(item_data->normal);
+ }
+
+ return mp_strength == item_data->curr_strength;
+}
+
+static void aggregate_item_normal(
+ WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data,
+ WeightedNormalDataAggregateItem *item_data,
+ const int mv_index, const int mp_index,
+ const float curr_val, const bool use_face_influence)
+{
+ float (*polynors)[3] = wn_data->polynors;
+
+ MDeformVert *dvert = wn_data->dvert;
+ const int defgrp_index = wn_data->defgrp_index;
+ const bool use_invert_vgroup = wn_data->use_invert_vgroup;
+
+ const float weight = wn_data->weight;
+
+ float *cached_inverse_powers_of_weight = wn_data->cached_inverse_powers_of_weight;
+
+ const bool has_vgroup = dvert != NULL;
+ const bool vert_of_group = has_vgroup && defvert_find_index(&dvert[mv_index], defgrp_index) != NULL;
+
+ if (has_vgroup && ((vert_of_group && use_invert_vgroup) || (!vert_of_group && !use_invert_vgroup))) {
+ return;
+ }
+
+ if (use_face_influence && !check_item_poly_strength(wn_data, item_data, mp_index)) {
+ return;
+ }
+
+ /* If item's curr_val is 0 init it to present value. */
+ if (item_data->curr_val == 0.0f) {
+ item_data->curr_val = curr_val;
+ }
+ if (!compare_ff(item_data->curr_val, curr_val, wnmd->thresh)) {
+ /* item's curr_val and present value differ more than threshold, update. */
+ item_data->num_loops++;
+ item_data->curr_val = curr_val;
+ }
+
+ /* Exponentially divided weight for each normal (since a few values will be used by most cases, we cache those). */
+ const int num_loops = item_data->num_loops;
+ if (num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT && cached_inverse_powers_of_weight[num_loops] == 0.0f) {
+ cached_inverse_powers_of_weight[num_loops] = 1.0f / powf(weight, num_loops);
+ }
+ const float inverted_n_weight = num_loops < NUM_CACHED_INVERSE_POWERS_OF_WEIGHT ?
+ cached_inverse_powers_of_weight[num_loops] : 1.0f / powf(weight, num_loops);
+
+ madd_v3_v3fl(item_data->normal, polynors[mp_index], curr_val * inverted_n_weight);
+}
+
+static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numVerts = wn_data->numVerts;
+ const int numEdges = wn_data->numEdges;
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MEdge *medge = wn_data->medge;
+
+ MLoop *mloop = wn_data->mloop;
+ short (*clnors)[2] = wn_data->clnors;
+ int *loop_to_poly = wn_data->loop_to_poly;
+
+ MPoly *mpoly = wn_data->mpoly;
+ float (*polynors)[3] = wn_data->polynors;
+ int *poly_strength = wn_data->poly_strength;
+
+ MDeformVert *dvert = wn_data->dvert;
+
+ const short mode = wn_data->mode;
+ ModePair *mode_pair = wn_data->mode_pair;
+
+ const bool has_clnors = wn_data->has_clnors;
+ const float split_angle = wn_data->split_angle;
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+
+ const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0;
+ const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && poly_strength != NULL;
+ const bool has_vgroup = dvert != NULL;
+
+ float (*loop_normals)[3] = NULL;
+
+ WeightedNormalDataAggregateItem *items_data = NULL;
+ int num_items = 0;
+ if (keep_sharp) {
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW(numLoops, __func__);
+
+ /* This will give us loop normal spaces, we do not actually care about computed loop_normals for now... */
+ loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
+ BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
+ true, split_angle, &lnors_spacearr, has_clnors ? clnors : NULL, loop_to_poly);
+
+ num_items = lnors_spacearr.num_spaces;
+ items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
+
+ /* In this first loop, we assign each WeightedNormalDataAggregateItem
+ * to its smooth fan of loops (aka lnor space). */
+ MPoly *mp;
+ int mp_index;
+ int item_index;
+ for (mp = mpoly, mp_index = 0, item_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ int ml_index = mp->loopstart;
+ const int ml_end_index = ml_index + mp->totloop;
+
+ for (; ml_index < ml_end_index; ml_index++) {
+ if (BLI_BITMAP_TEST(done_loops, ml_index)) {
+ /* Smooth fan of this loop has already been processed, skip it. */
+ continue;
+ }
+ BLI_assert(item_index < num_items);
+
+ WeightedNormalDataAggregateItem *itdt = &items_data[item_index];
+ itdt->curr_strength = FACE_STRENGTH_WEAK;
+
+ MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index];
+ lnor_space->user_data = itdt;
+
+ if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) {
+ for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) {
+ const int ml_fan_index = GET_INT_FROM_POINTER(lnode->link);
+ BLI_BITMAP_ENABLE(done_loops, ml_fan_index);
+ }
+ }
+ else {
+ BLI_BITMAP_ENABLE(done_loops, ml_index);
+ }
+
+ item_index++;
+ }
+ }
+
+ MEM_freeN(done_loops);
+ }
+ else {
+ num_items = numVerts;
+ items_data = MEM_calloc_arrayN((size_t)num_items, sizeof(*items_data), __func__);
+ if (use_face_influence) {
+ for (int item_index = 0; item_index < num_items; item_index++) {
+ items_data[item_index].curr_strength = FACE_STRENGTH_WEAK;
+ }
+ }
+ }
+ wn_data->items_data = items_data;
+
+ switch (mode) {
+ case MOD_WEIGHTEDNORMAL_MODE_FACE:
+ for (int i = 0; i < numPolys; i++) {
+ const int mp_index = mode_pair[i].index;
+ const float mp_val = mode_pair[i].val;
+
+ int ml_index = mpoly[mp_index].loopstart;
+ const int ml_index_end = ml_index + mpoly[mp_index].totloop;
+ for (; ml_index < ml_index_end; ml_index++) {
+ const int mv_index = mloop[ml_index].v;
+ WeightedNormalDataAggregateItem *item_data = keep_sharp ?
+ lnors_spacearr.lspacearr[ml_index]->user_data:
+ &items_data[mv_index];
+
+ aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, mp_val, use_face_influence);
+ }
+ }
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
+ case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
+ BLI_assert(loop_to_poly != NULL);
+
+ for (int i = 0; i < numLoops; i++) {
+ const int ml_index = mode_pair[i].index;
+ const float ml_val = mode_pair[i].val;
+
+ const int mp_index = loop_to_poly[ml_index];
+ const int mv_index = mloop[ml_index].v;
+ WeightedNormalDataAggregateItem *item_data = keep_sharp ?
+ lnors_spacearr.lspacearr[ml_index]->user_data:
+ &items_data[mv_index];
+
+ aggregate_item_normal(wnmd, wn_data, item_data, mv_index, mp_index, ml_val, use_face_influence);
+ }
+ break;
+ default:
+ BLI_assert(0);
+ }
+
+ /* Validate computed weighted normals. */
+ for (int item_index = 0; item_index < num_items; item_index++) {
+ if (normalize_v3(items_data[item_index].normal) < CLNORS_VALID_VEC_LEN) {
+ zero_v3(items_data[item_index].normal);
+ }
+ }
+
+ if (keep_sharp) {
+ /* Set loop normals for normal computed for each lnor space (smooth fan).
+ * Note that loop_normals is already populated with clnors (before this modifier is applied, at start of
+ * this function), so no need to recompute them here. */
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ WeightedNormalDataAggregateItem *item_data = lnors_spacearr.lspacearr[ml_index]->user_data;
+ if (!is_zero_v3(item_data->normal)) {
+ copy_v3_v3(loop_normals[ml_index], item_data->normal);
+ }
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
+ }
+ else {
+ /* TODO: Ideally, we could add an option to BKE_mesh_normals_loop_custom_[from_vertices_]set() to keep current
+ * clnors instead of resetting them to default autocomputed ones, when given new custom normal is zero-vec.
+ * But this is not exactly trivial change, better to keep this optimization for later...
+ */
+ if (!has_vgroup) {
+ /* Note: in theory, we could avoid this extra allocation & copying... But think we can live with it for now,
+ * and it makes code simpler & cleaner. */
+ float (*vert_normals)[3] = MEM_calloc_arrayN((size_t)numVerts, sizeof(*loop_normals), __func__);
+
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ const int mv_index = mloop[ml_index].v;
+ copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal);
+ }
+
+ BKE_mesh_normals_loop_custom_from_vertices_set(mvert, vert_normals, numVerts, medge, numEdges,
+ mloop, numLoops, mpoly, polynors, numPolys, clnors);
+
+ MEM_freeN(vert_normals);
+ }
+ else {
+ loop_normals = MEM_calloc_arrayN((size_t)numLoops, sizeof(*loop_normals), __func__);
+
+ BKE_mesh_normals_loop_split(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys,
+ true, split_angle, NULL, has_clnors ? clnors : NULL, loop_to_poly);
+
+ for (int ml_index = 0; ml_index < numLoops; ml_index++) {
+ const int item_index = mloop[ml_index].v;
+ if (!is_zero_v3(items_data[item_index].normal)) {
+ copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal);
+ }
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, numVerts, medge, numEdges,
+ mloop, loop_normals, numLoops, mpoly, polynors, numPolys, clnors);
+ }
+ }
+
+ if (keep_sharp) {
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+ }
+ MEM_SAFE_FREE(loop_normals);
+}
+
+static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ ModePair *face_area = MEM_malloc_arrayN((size_t)numPolys, sizeof(*face_area), __func__);
+
+ ModePair *f_area = face_area;
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++, f_area++) {
+ f_area->val = BKE_mesh_calc_poly_area(mp, &mloop[mp->loopstart], mvert);
+ f_area->index = mp_index;
+ }
+
+ qsort(face_area, numPolys, sizeof(*face_area), modepair_cmp_by_val_inverse);
+
+ wn_data->mode_pair = face_area;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ ModePair *corner_angle = MEM_malloc_arrayN((size_t)numLoops, sizeof(*corner_angle), __func__);
+
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
+ BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
+
+ ModePair *c_angl = &corner_angle[mp->loopstart];
+ float *angl = index_angle;
+ for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, c_angl++, angl++) {
+ c_angl->val = (float)M_PI - *angl;
+ c_angl->index = ml_index;
+
+ loop_to_poly[ml_index] = mp_index;
+ }
+ MEM_freeN(index_angle);
+ }
+
+ qsort(corner_angle, numLoops, sizeof(*corner_angle), modepair_cmp_by_val_inverse);
+
+ wn_data->loop_to_poly = loop_to_poly;
+ wn_data->mode_pair = corner_angle;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data)
+{
+ const int numLoops = wn_data->numLoops;
+ const int numPolys = wn_data->numPolys;
+
+ MVert *mvert = wn_data->mvert;
+ MLoop *mloop = wn_data->mloop;
+ MPoly *mpoly = wn_data->mpoly;
+
+ MPoly *mp;
+ int mp_index;
+
+ int *loop_to_poly = MEM_malloc_arrayN((size_t)numLoops, sizeof(*loop_to_poly), __func__);
+
+ ModePair *combined = MEM_malloc_arrayN((size_t)numLoops, sizeof(*combined), __func__);
+
+ for (mp_index = 0, mp = mpoly; mp_index < numPolys; mp_index++, mp++) {
+ MLoop *ml_start = &mloop[mp->loopstart];
+
+ float face_area = BKE_mesh_calc_poly_area(mp, ml_start, mvert);
+ float *index_angle = MEM_malloc_arrayN((size_t)mp->totloop, sizeof(*index_angle), __func__);
+ BKE_mesh_calc_poly_angles(mp, ml_start, mvert, index_angle);
+
+ ModePair *cmbnd = &combined[mp->loopstart];
+ float *angl = index_angle;
+ for (int ml_index = mp->loopstart; ml_index < mp->loopstart + mp->totloop; ml_index++, cmbnd++, angl++) {
+ /* In this case val is product of corner angle and face area. */
+ cmbnd->val = ((float)M_PI - *angl) * face_area;
+ cmbnd->index = ml_index;
+
+ loop_to_poly[ml_index] = mp_index;
+ }
+ MEM_freeN(index_angle);
+ }
+
+ qsort(combined, numLoops, sizeof(*combined), modepair_cmp_by_val_inverse);
+
+ wn_data->loop_to_poly = loop_to_poly;
+ wn_data->mode_pair = combined;
+ apply_weights_vertex_normal(wnmd, wn_data);
+}
+
+static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ Object *ob = ctx->object;
+
+ /* XXX TODO ARG GRRR XYQWNMPRXTYY
+ * Once we fully switch to Mesh evaluation of modifiers, we can expect to get that flag from the COW copy.
+ * But for now, it is lost in the DM intermediate step, so we need to directly check orig object's data. */
+#if 0
+ if (!(mesh->flag & ME_AUTOSMOOTH)) {
+#else
+ if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) {
+#endif
+ modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings");
+ return mesh;
+ }
+
+ Mesh *result;
+ BKE_id_copy_ex(
+ NULL, &mesh->id, (ID **)&result,
+ LIB_ID_CREATE_NO_MAIN |
+ LIB_ID_CREATE_NO_USER_REFCOUNT |
+ LIB_ID_CREATE_NO_DEG_TAG |
+ LIB_ID_COPY_NO_PREVIEW,
+ false);
+
+ const int numVerts = result->totvert;
+ const int numEdges = result->totedge;
+ const int numLoops = result->totloop;
+ const int numPolys = result->totpoly;
+
+ MEdge *medge = result->medge;
+ MPoly *mpoly = result->mpoly;
+ MVert *mvert = result->mvert;
+ MLoop *mloop = result->mloop;
+
+ /* Right now:
+ * If weight = 50 then all faces are given equal weight.
+ * If weight > 50 then more weight given to faces with larger vals (face area / corner angle).
+ * If weight < 50 then more weight given to faces with lesser vals. However current calculation
+ * does not converge to min/max.
+ */
+ float weight = ((float)wnmd->weight) / 50.0f;
+ if (wnmd->weight == 100) {
+ weight = (float)SHRT_MAX;
+ }
+ else if (wnmd->weight == 1) {
+ weight = 1 / (float)SHRT_MAX;
+ }
+ else if ((weight - 1) * 25 > 1) {
+ weight = (weight - 1) * 25;
+ }
+
+ CustomData *pdata = &result->pdata;
+ float (*polynors)[3] = CustomData_get_layer(pdata, CD_NORMAL);
+ if (!polynors) {
+ polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
+ }
+ BKE_mesh_calc_normals_poly(mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
+
+
+ const float split_angle = mesh->smoothresh;
+ short (*clnors)[2];
+ CustomData *ldata = &result->ldata;
+ clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+
+ /* Keep info whether we had clnors, it helps when generating clnor spaces and default normals. */
+ const bool has_clnors = clnors != NULL;
+ if (!clnors) {
+ clnors = CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, numLoops);
+ clnors = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+ }
+
+ MDeformVert *dvert;
+ int defgrp_index;
+ MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index);
+
+ WeightedNormalData wn_data = {
+ .numVerts = numVerts,
+ .numEdges = numEdges,
+ .numLoops = numLoops,
+ .numPolys = numPolys,
+
+ .mvert = mvert,
+ .medge = medge,
+
+ .mloop = mloop,
+ .clnors = clnors,
+ .has_clnors = has_clnors,
+ .split_angle = split_angle,
+
+ .mpoly = mpoly,
+ .polynors = polynors,
+ .poly_strength = CustomData_get_layer_named(
+ &result->pdata, CD_PROP_INT,
+ MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID),
+
+ .dvert = dvert,
+ .defgrp_index = defgrp_index,
+ .use_invert_vgroup = (wnmd->flag & MOD_WEIGHTEDNORMAL_INVERT_VGROUP) != 0,
+
+ .weight = weight,
+ .mode = wnmd->mode,
+ };
+
+ switch (wnmd->mode) {
+ case MOD_WEIGHTEDNORMAL_MODE_FACE:
+ wn_face_area(wnmd, &wn_data);
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_ANGLE:
+ wn_corner_angle(wnmd, &wn_data);
+ break;
+ case MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE:
+ wn_face_with_angle(wnmd, &wn_data);
+ break;
+ }
+
+ MEM_SAFE_FREE(wn_data.loop_to_poly);
+ MEM_SAFE_FREE(wn_data.mode_pair);
+ MEM_SAFE_FREE(wn_data.items_data);
+
+ return result;
+}
+
+static void initData(ModifierData *md)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ wnmd->mode = MOD_WEIGHTEDNORMAL_MODE_FACE;
+ wnmd->weight = 50;
+ wnmd->thresh = 1e-2f;
+ wnmd->flag = 0;
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ WeightedNormalModifierData *wnmd = (WeightedNormalModifierData *)md;
+ CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
+
+ if (wnmd->defgrp_name[0]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ }
+
+ if (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) {
+ dataMask |= CD_MASK_PROP_INT;
+ }
+
+ return dataMask;
+}
+
+static bool dependsOnNormals(ModifierData *UNUSED(md))
+{
+ return true;
+}
+
+ModifierTypeInfo modifierType_WeightedNormal = {
+ /* name */ "Weighted Normal",
+ /* structName */ "WeightedNormalModifierData",
+ /* structSize */ sizeof(WeightedNormalModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_EnableInEditmode,
+
+ /* copyData */ modifier_copyData_generic,
+
+ /* deformVerts_DM */ NULL,
+ /* deformMatrices_DM */ NULL,
+ /* deformVertsEM_DM */ NULL,
+ /* deformMatricesEM_DM*/NULL,
+ /* applyModifier_DM */ NULL,
+ /* applyModifierEM_DM */NULL,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ NULL,
+
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ NULL,
+ /* isDisabled */ NULL,
+ /* updateDepsgraph */ NULL,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
+ /* foreachObjectLink */ NULL,
+ /* foreachIDLink */ NULL,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index a34ed1baaff..47379dec99a 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -203,20 +203,18 @@ static Mesh *applyModifier(
}
}
- Mesh *result = mesh;
-
if (has_mdef) {
- dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, numVerts);
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
}
else {
/* Add a valid data layer! */
- dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
+ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
}
/* Ultimate security check. */
if (!dvert) {
- BKE_id_free(NULL, result);
return mesh;
}
+ mesh->dvert = dvert;
/* Get org weights, assuming 0.0 for vertices not in given vgroup. */
org_w = MEM_malloc_arrayN(numVerts, sizeof(float), "WeightVGEdit Modifier, org_w");
@@ -249,7 +247,7 @@ static Mesh *applyModifier(
/* Do masking. */
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- weightvg_do_mask(ctx, numVerts, NULL, org_w, new_w, ctx->object, result, wmd->mask_constant,
+ weightvg_do_mask(ctx, numVerts, NULL, org_w, new_w, ctx->object, mesh, wmd->mask_constant,
wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -270,7 +268,7 @@ static Mesh *applyModifier(
MEM_freeN(dw);
/* Return the vgroup-modified mesh. */
- return result;
+ return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index b6a7228b171..ea401d01f66 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -243,20 +243,18 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
}
}
- Mesh *result = mesh;
-
if (has_mdef) {
- dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, numVerts);
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
}
else {
/* Add a valid data layer! */
- dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
+ dvert = CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
}
/* Ultimate security check. */
if (!dvert) {
- BKE_id_free(NULL, result);
return mesh;
}
+ mesh->dvert = dvert;
/* Find out which vertices to work on. */
tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGMix Modifier, tidx");
@@ -324,7 +322,6 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(tdw1);
MEM_freeN(tdw2);
MEM_freeN(tidx);
- BKE_id_free(NULL, result);
return mesh;
}
if (numIdx != -1) {
@@ -360,7 +357,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Do masking. */
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ctx->object, result, wmd->mask_constant,
+ weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ctx->object, mesh, wmd->mask_constant,
wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -384,7 +381,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_SAFE_FREE(indices);
/* Return the vgroup-modified mesh. */
- return result;
+ return mesh;
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 05b1ec19253..4a5a54642ef 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -422,20 +422,12 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
return mesh;
}
- Mesh *result = mesh;
-
- if (has_mdef) {
- dvert = CustomData_duplicate_referenced_layer(&result->vdata, CD_MDEFORMVERT, numVerts);
- }
- else {
- /* Add a valid data layer! */
- dvert = CustomData_add_layer(&result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, numVerts);
- }
+ dvert = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MDEFORMVERT, numVerts);
/* Ultimate security check. */
if (!dvert) {
- BKE_id_free(NULL, result);
return mesh;
}
+ mesh->dvert = dvert;
/* Find out which vertices to work on (all vertices in vgroup), and get their relevant weight. */
tidx = MEM_malloc_arrayN(numVerts, sizeof(int), "WeightVGProximity Modifier, tidx");
@@ -454,7 +446,6 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(tidx);
MEM_freeN(tw);
MEM_freeN(tdw);
- BKE_id_free(NULL, result);
return mesh;
}
if (numIdx != numVerts) {
@@ -476,7 +467,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Get our vertex coordinates. */
if (numIdx != numVerts) {
- float (*tv_cos)[3] = BKE_mesh_vertexCos_get(result, NULL);
+ float (*tv_cos)[3] = BKE_mesh_vertexCos_get(mesh, NULL);
v_cos = MEM_malloc_arrayN(numIdx, sizeof(float[3]), "WeightVGProximity Modifier, v_cos");
for (i = 0; i < numIdx; i++) {
copy_v3_v3(v_cos[i], tv_cos[indices[i]]);
@@ -484,7 +475,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
MEM_freeN(tv_cos);
}
else {
- v_cos = BKE_mesh_vertexCos_get(result, NULL);
+ v_cos = BKE_mesh_vertexCos_get(mesh, NULL);
}
/* Compute wanted distances. */
@@ -544,7 +535,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
/* Do masking. */
struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
- weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ob, result, wmd->mask_constant,
+ weightvg_do_mask(ctx, numIdx, indices, org_w, new_w, ob, mesh, wmd->mask_constant,
wmd->mask_defgrp_name, scene, wmd->mask_texture,
wmd->mask_tex_use_channel, wmd->mask_tex_mapping,
wmd->mask_tex_map_obj, wmd->mask_tex_uvlayer_name);
@@ -570,7 +561,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes
#endif
/* Return the vgroup-modified mesh. */
- return result;
+ return mesh;
}