Blender V4.3
MOD_normal_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstring>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_utildefines.h"
14
15#include "BLI_bitmap.h"
16#include "BLI_math_matrix.h"
17#include "BLI_math_vector.h"
18
19#include "BLT_translation.hh"
20
21#include "DNA_defaults.h"
22#include "DNA_mesh_types.h"
23#include "DNA_object_types.h"
24#include "DNA_screen_types.h"
25
26#include "BKE_attribute.hh"
27#include "BKE_customdata.hh"
28#include "BKE_deform.hh"
29#include "BKE_lib_id.hh"
30#include "BKE_lib_query.hh"
31#include "BKE_mesh.hh"
32
33#include "UI_interface.hh"
34#include "UI_resources.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
39#include "MOD_ui_common.hh"
40#include "MOD_util.hh"
41
43 Object *ob,
44 Object *ob_center,
45 const float offset[3],
46 const int verts_num,
47 float (*r_cos)[3],
48 float r_size[3])
49{
50 using namespace blender;
51 float min_co[3], max_co[3];
52 float diff[3];
53 bool do_diff = false;
54
55 INIT_MINMAX(min_co, max_co);
56
57 const Span<float3> positions = mesh->vert_positions();
58 for (int i = 0; i < mesh->verts_num; i++) {
59 copy_v3_v3(r_cos[i], positions[i]);
60 if (r_size != nullptr && ob_center == nullptr) {
61 minmax_v3v3_v3(min_co, max_co, r_cos[i]);
62 }
63 }
64
65 /* Get size (i.e. deformation of the spheroid generating normals),
66 * either from target object, or geometry. */
67 if (r_size != nullptr) {
68 if (ob_center != nullptr) {
69 /* Using 'scale' as 'size' here. The input object is typically an empty
70 * who's scale is used to define an ellipsoid instead of a simple sphere. */
71
72 /* Not we are not interested in signs here - they are even troublesome actually,
73 * due to security clamping! */
74 abs_v3_v3(r_size, ob_center->scale);
75 }
76 else {
77 /* Set size. */
78 sub_v3_v3v3(r_size, max_co, min_co);
79 }
80
81 /* Error checks - we do not want one or more of our sizes to be null! */
82 if (is_zero_v3(r_size)) {
83 r_size[0] = r_size[1] = r_size[2] = 1.0f;
84 }
85 else {
86 CLAMP_MIN(r_size[0], FLT_EPSILON);
87 CLAMP_MIN(r_size[1], FLT_EPSILON);
88 CLAMP_MIN(r_size[2], FLT_EPSILON);
89 }
90 }
91
92 if (ob_center != nullptr) {
93 float inv_obmat[4][4];
94
95 /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
96 /* Get ob_center (world) coordinates in ob local coordinates.
97 * No need to take into account ob_center's space here, see #44027. */
98 invert_m4_m4(inv_obmat, ob->object_to_world().ptr());
99 mul_v3_m4v3(diff, inv_obmat, ob_center->object_to_world().location());
101
102 do_diff = true;
103 }
104 else if (offset != nullptr && !is_zero_v3(offset)) {
105 negate_v3_v3(diff, offset);
106
107 do_diff = true;
108 }
109 /* Else, no need to change coordinates! */
110
111 if (do_diff) {
112 int i = verts_num;
113 while (i--) {
114 add_v3_v3(r_cos[i], diff);
115 }
116 }
117}
118
119/* Note this modifies nos_new in-place. */
120static void mix_normals(const float mix_factor,
121 const MDeformVert *dvert,
122 const int defgrp_index,
123 const bool use_invert_vgroup,
124 const float mix_limit,
125 const short mix_mode,
126 const int verts_num,
127 const blender::Span<int> corner_verts,
128 blender::float3 *nos_old,
129 blender::float3 *nos_new)
130{
131 /* Mix with org normals... */
132 float *facs = nullptr, *wfac;
133 blender::float3 *no_new, *no_old;
134 int i;
135
136 if (dvert) {
137 facs = static_cast<float *>(
138 MEM_malloc_arrayN(size_t(corner_verts.size()), sizeof(*facs), __func__));
140 defgrp_index,
141 verts_num,
142 corner_verts.data(),
143 corner_verts.size(),
144 use_invert_vgroup,
145 facs);
146 }
147
148 for (i = corner_verts.size(), no_new = nos_new, no_old = nos_old, wfac = facs; i--;
149 no_new++, no_old++, wfac++)
150 {
151 const float fac = facs ? *wfac * mix_factor : mix_factor;
152
153 switch (mix_mode) {
155 add_v3_v3(*no_new, *no_old);
156 normalize_v3(*no_new);
157 break;
159 sub_v3_v3(*no_new, *no_old);
160 normalize_v3(*no_new);
161 break;
163 mul_v3_v3(*no_new, *no_old);
164 normalize_v3(*no_new);
165 break;
167 break;
168 }
169
171 *no_new,
172 *no_old,
173 *no_new,
174 (mix_limit < float(M_PI)) ? min_ff(fac, mix_limit / angle_v3v3(*no_new, *no_old)) : fac);
175 }
176
177 MEM_SAFE_FREE(facs);
178}
179
180/* Check face normals and new loop normals are compatible, otherwise flip faces
181 * (and invert matching face normals). */
182static void faces_check_flip(Mesh &mesh,
184 const blender::Span<blender::float3> face_normals)
185{
186 using namespace blender;
187 const OffsetIndices faces = mesh.faces();
188 IndexMaskMemory memory;
189 const IndexMask faces_to_flip = IndexMask::from_predicate(
190 faces.index_range(), GrainSize(1024), memory, [&](const int i) {
191 const blender::IndexRange face = faces[i];
192 float norsum[3] = {0.0f};
193
194 for (const int64_t j : face) {
195 add_v3_v3(norsum, nos[j]);
196 }
197 if (!normalize_v3(norsum)) {
198 return false;
199 }
200
201 /* If average of new loop normals is opposed to face normal, flip face. */
202 if (dot_v3v3(face_normals[i], norsum) < 0.0f) {
203 nos.slice(faces[i].drop_front(1)).reverse();
204 return true;
205 }
206 return false;
207 });
208
209 bke::mesh_flip_faces(mesh, faces_to_flip);
210}
211
213 const ModifierEvalContext * /*ctx*/,
214 Object *ob,
215 Mesh *mesh,
218 const short mix_mode,
219 const float mix_factor,
220 const float mix_limit,
221 const MDeformVert *dvert,
222 const int defgrp_index,
223 const bool use_invert_vgroup,
224 blender::Span<blender::float3> vert_positions,
226 blender::MutableSpan<bool> sharp_edges,
227 blender::MutableSpan<int> corner_verts,
228 blender::MutableSpan<int> corner_edges,
229 const blender::OffsetIndices<int> faces)
230{
231 using namespace blender;
232 Object *ob_target = enmd->target;
233
234 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
235
236 float(*cos)[3] = static_cast<float(*)[3]>(
237 MEM_malloc_arrayN(size_t(vert_positions.size()), sizeof(*cos), __func__));
238 blender::Array<blender::float3> nos(corner_verts.size());
239 float size[3];
240
241 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(vert_positions.size()), __func__);
242
243 generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, vert_positions.size(), cos, size);
244
276 {
277 const float a = size[0], b = size[1], c = size[2];
278 const float m2 = (b * b) / (a * a);
279 const float n2 = (c * c) / (a * a);
280
281 /* We reuse cos to now store the ellipsoid-normal of the verts! */
282 for (const int64_t i : corner_verts.index_range()) {
283 const int vidx = corner_verts[i];
284 float *co = cos[vidx];
285
286 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
287 const float x2 = co[0] * co[0];
288 const float y2 = co[1] * co[1];
289 const float z2 = co[2] * co[2];
290 const float a2 = x2 + (y2 / m2) + (z2 / n2);
291 const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2);
292 const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2;
293
294 co[0] /= a2;
295 co[1] /= b2;
296 co[2] /= c2;
297 normalize_v3(co);
298
299 BLI_BITMAP_ENABLE(done_verts, vidx);
300 }
301 nos[i] = co;
302 }
303 }
304
305 if (!corner_normals.is_empty()) {
306 mix_normals(mix_factor,
307 dvert,
308 defgrp_index,
309 use_invert_vgroup,
310 mix_limit,
311 mix_mode,
312 vert_positions.size(),
313 corner_verts,
314 corner_normals.data(),
315 nos.data());
316 }
317
318 if (do_facenors_fix) {
319 faces_check_flip(*mesh, nos, mesh->face_normals());
320 }
321 const bke::AttributeAccessor attributes = mesh->attributes();
322 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
323 bke::mesh::normals_corner_custom_set(vert_positions,
324 edges,
325 faces,
326 corner_verts,
327 corner_edges,
328 mesh->vert_normals(),
329 mesh->face_normals(),
330 sharp_faces,
331 sharp_edges,
332 nos,
333 clnors);
334
335 MEM_freeN(cos);
336 MEM_freeN(done_verts);
337}
338
340 const ModifierEvalContext * /*ctx*/,
341 Object *ob,
342 Mesh *mesh,
345 const short mix_mode,
346 const float mix_factor,
347 const float mix_limit,
348 const MDeformVert *dvert,
349 const int defgrp_index,
350 const bool use_invert_vgroup,
351 const blender::Span<blender::float3> positions,
353 blender::MutableSpan<bool> sharp_edges,
354 blender::MutableSpan<int> corner_verts,
355 blender::MutableSpan<int> corner_edges,
356 const blender::OffsetIndices<int> faces)
357{
358 using namespace blender;
359 Object *ob_target = enmd->target;
360
361 const bool do_facenors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0;
362 const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
363
364 blender::Array<blender::float3> nos(corner_verts.size());
365
366 float target_co[3];
367 int i;
368
369 /* Get target's center coordinates in ob local coordinates. */
370 float mat[4][4];
371
372 invert_m4_m4(mat, ob->object_to_world().ptr());
373 mul_m4_m4m4(mat, mat, ob_target->object_to_world().ptr());
374 copy_v3_v3(target_co, mat[3]);
375
376 if (use_parallel_normals) {
377 float no[3];
378
379 sub_v3_v3v3(no, target_co, enmd->offset);
380 normalize_v3(no);
381
382 for (i = corner_verts.size(); i--;) {
383 copy_v3_v3(nos[i], no);
384 }
385 }
386 else {
387 float(*cos)[3] = static_cast<float(*)[3]>(
388 MEM_malloc_arrayN(size_t(positions.size()), sizeof(*cos), __func__));
389 generate_vert_coordinates(mesh, ob, ob_target, nullptr, positions.size(), cos, nullptr);
390
391 BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(positions.size()), __func__);
392
393 /* We reuse cos to now store the 'to target' normal of the verts! */
394 for (const int64_t i : corner_verts.index_range()) {
395 const int vidx = corner_verts[i];
396 float *co = cos[vidx];
397
398 if (!BLI_BITMAP_TEST(done_verts, vidx)) {
399 sub_v3_v3v3(co, target_co, co);
400 normalize_v3(co);
401
402 BLI_BITMAP_ENABLE(done_verts, vidx);
403 }
404 nos[i] = co;
405 }
406
407 MEM_freeN(done_verts);
408 MEM_freeN(cos);
409 }
410
411 if (!corner_normals.is_empty()) {
412 mix_normals(mix_factor,
413 dvert,
414 defgrp_index,
415 use_invert_vgroup,
416 mix_limit,
417 mix_mode,
418 positions.size(),
419 corner_verts,
420 corner_normals.data(),
421 nos.data());
422 }
423
424 if (do_facenors_fix) {
425 faces_check_flip(*mesh, nos, mesh->face_normals());
426 }
427 const bke::AttributeAccessor attributes = mesh->attributes();
428 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
429 bke::mesh::normals_corner_custom_set(positions,
430 edges,
431 faces,
432 corner_verts,
433 corner_edges,
434 mesh->vert_normals(),
435 mesh->face_normals(),
436 sharp_faces,
437 sharp_edges,
438 nos,
439 clnors);
440}
441
443{
444 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
445 return true;
446 }
447 if ((enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && enmd->target) {
448 return true;
449 }
450 return false;
451}
452
454{
455 if (is_valid_target(enmd)) {
456 return true;
457 }
458 BKE_modifier_set_error(ob, (ModifierData *)enmd, "Invalid target settings");
459 return false;
460}
461
463 const ModifierEvalContext *ctx,
464 Object *ob,
465 Mesh *mesh)
466{
467 using namespace blender;
468 const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
469 const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
470 (enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') &&
471 (enmd->mix_limit == float(M_PI)));
472
473 /* Do not run that modifier at all if auto-smooth is disabled! */
474 if (!is_valid_target_with_error(ctx->object, enmd) || mesh->corners_num == 0) {
475 return mesh;
476 }
477
478 Mesh *result;
479 if (mesh->edges().data() == ((Mesh *)ob->data)->edges().data()) {
480 /* We need to duplicate data here, otherwise setting custom normals
481 * (which may also affect sharp edges) could
482 * modify original mesh, see #43671. */
483 result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE);
484 }
485 else {
486 result = mesh;
487 }
488
489 const blender::Span<blender::float3> positions = result->vert_positions();
490 const blender::Span<int2> edges = result->edges();
491 const OffsetIndices faces = result->faces();
492 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
493 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
494
495 int defgrp_index;
496 const MDeformVert *dvert;
497
498 blender::Array<blender::float3> corner_normals;
499
500 CustomData *ldata = &result->corner_data;
501
502 bke::MutableAttributeAccessor attributes = result->attributes_for_write();
503 bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
504 "sharp_edge", bke::AttrDomain::Edge);
505
506 blender::short2 *clnors = static_cast<blender::short2 *>(
508 if (use_current_clnors) {
509 clnors = static_cast<blender::short2 *>(
511 corner_normals.reinitialize(corner_verts.size());
512 const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
514 edges,
515 faces,
516 corner_verts,
517 corner_edges,
518 result->corner_to_face_map(),
519 result->vert_normals(),
520 result->face_normals(),
521 sharp_edges.span,
522 sharp_faces,
523 clnors,
524 nullptr,
525 corner_normals);
526 }
527
528 if (clnors == nullptr) {
529 clnors = static_cast<blender::short2 *>(
531 }
532
533 MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index);
534
535 if (enmd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
537 ctx,
538 ob,
539 result,
540 {clnors, result->corners_num},
541 corner_normals,
542 enmd->mix_mode,
543 enmd->mix_factor,
544 enmd->mix_limit,
545 dvert,
546 defgrp_index,
547 use_invert_vgroup,
548 positions,
549 edges,
550 sharp_edges.span,
551 corner_verts,
552 corner_edges,
553 faces);
554 }
555 else if (enmd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
557 ctx,
558 ob,
559 result,
560 {clnors, result->corners_num},
561 corner_normals,
562 enmd->mix_mode,
563 enmd->mix_factor,
564 enmd->mix_limit,
565 dvert,
566 defgrp_index,
567 use_invert_vgroup,
568 positions,
569 edges,
570 sharp_edges.span,
571 corner_verts,
572 corner_edges,
573 faces);
574 }
575
576 result->runtime->is_original_bmesh = false;
577
578 sharp_edges.finish();
579
580 return result;
581}
582
591
592static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
593{
595
596 r_cddata_masks->lmask |= CD_MASK_CUSTOMLOOPNORMAL;
597
598 /* Ask for vertex-groups if we need them. */
599 if (enmd->defgrp_name[0] != '\0') {
600 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
601 }
602}
603
604static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
605{
607
608 walk(user_data, ob, (ID **)&enmd->target, IDWALK_CB_NOP);
609}
610
611static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
612{
614
615 return !is_valid_target(enmd);
616}
617
619{
621 if (enmd->target) {
622 DEG_add_object_relation(ctx->node, enmd->target, DEG_OB_COMP_TRANSFORM, "NormalEdit Modifier");
623 DEG_add_depends_on_transform_relation(ctx->node, "NormalEdit Modifier");
624 }
625}
626
627static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
628{
629 return normalEditModifier_do((NormalEditModifierData *)md, ctx, ctx->object, mesh);
630}
631
632static void panel_draw(const bContext * /*C*/, Panel *panel)
633{
634 uiLayout *col;
635 uiLayout *layout = panel->layout;
636
637 PointerRNA ob_ptr;
639
640 int mode = RNA_enum_get(ptr, "mode");
641
642 uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
643
644 uiLayoutSetPropSep(layout, true);
645
646 uiItemR(layout, ptr, "target", UI_ITEM_NONE, nullptr, ICON_NONE);
647
648 col = uiLayoutColumn(layout, false);
650 uiItemR(col, ptr, "use_direction_parallel", UI_ITEM_NONE, nullptr, ICON_NONE);
651
652 modifier_panel_end(layout, ptr);
653}
654
655/* This panel could be open by default, but it isn't currently. */
656static void mix_mode_panel_draw(const bContext * /*C*/, Panel *panel)
657{
658 uiLayout *row;
659 uiLayout *layout = panel->layout;
660
661 PointerRNA ob_ptr;
663
664 uiLayoutSetPropSep(layout, true);
665
666 uiItemR(layout, ptr, "mix_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
667 uiItemR(layout, ptr, "mix_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
668
669 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
670
671 row = uiLayoutRow(layout, true);
672 uiItemR(row, ptr, "mix_limit", UI_ITEM_NONE, nullptr, ICON_NONE);
673 uiItemR(row,
674 ptr,
675 "no_polynors_fix",
677 "",
678 (RNA_boolean_get(ptr, "no_polynors_fix") ? ICON_LOCKED : ICON_UNLOCKED));
679}
680
681static void offset_panel_draw(const bContext * /*C*/, Panel *panel)
682{
683 uiLayout *layout = panel->layout;
684
686
687 int mode = RNA_enum_get(ptr, "mode");
688 PointerRNA target_ptr = RNA_pointer_get(ptr, "target");
689 bool needs_object_offset = (mode == MOD_NORMALEDIT_MODE_RADIAL &&
690 RNA_pointer_is_null(&target_ptr)) ||
692 RNA_boolean_get(ptr, "use_direction_parallel"));
693
694 uiLayoutSetPropSep(layout, true);
695
696 uiLayoutSetActive(layout, needs_object_offset);
697 uiItemR(layout, ptr, "offset", UI_ITEM_NONE, nullptr, ICON_NONE);
698}
699
700static void panel_register(ARegionType *region_type)
701{
704 modifier_subpanel_register(region_type, "mix", "Mix", nullptr, mix_mode_panel_draw, panel_type);
706 region_type, "offset", "Offset", nullptr, offset_panel_draw, panel_type);
707}
708
710 /*idname*/ "NormalEdit",
711 /*name*/ N_("NormalEdit"),
712 /*struct_name*/ "NormalEditModifierData",
713 /*struct_size*/ sizeof(NormalEditModifierData),
714 /*srna*/ &RNA_NormalEditModifier,
718 /*icon*/ ICON_MOD_NORMALEDIT,
719
720 /*copy_data*/ BKE_modifier_copydata_generic,
721
722 /*deform_verts*/ nullptr,
723 /*deform_matrices*/ nullptr,
724 /*deform_verts_EM*/ nullptr,
725 /*deform_matrices_EM*/ nullptr,
726 /*modify_mesh*/ modify_mesh,
727 /*modify_geometry_set*/ nullptr,
728
729 /*init_data*/ init_data,
730 /*required_data_mask*/ required_data_mask,
731 /*free_data*/ nullptr,
732 /*is_disabled*/ is_disabled,
733 /*update_depsgraph*/ update_depsgraph,
734 /*depends_on_time*/ nullptr,
735 /*depends_on_normals*/ nullptr,
736 /*foreach_ID_link*/ foreach_ID_link,
737 /*foreach_tex_link*/ nullptr,
738 /*free_runtime_data*/ nullptr,
739 /*panel_register*/ panel_register,
740 /*blend_write*/ nullptr,
741 /*blend_read*/ nullptr,
742 /*foreach_cache*/ nullptr,
743};
CustomData interface, see also DNA_customdata_types.h.
@ CD_SET_DEFAULT
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
support for deformation groups and hooks.
void BKE_defvert_extract_vgroup_to_loopweights(const MDeformVert *dvert, int defgroup, int verts_num, const int *corner_verts, int loops_num, bool invert_vgroup, float *r_weights)
Definition deform.cc:1129
@ LIB_ID_COPY_LOCALIZE
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
@ IDWALK_CB_NOP
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition BLI_bitmap.h:41
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition BLI_bitmap.h:65
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition BLI_bitmap.h:82
unsigned int BLI_bitmap
Definition BLI_bitmap.h:17
MINLINE float min_ff(float a, float b)
#define M_PI
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_v3_m4v3(float r[3], const float mat[4][4], const float vec[3])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
MINLINE void mul_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], float t)
Definition math_vector.c:99
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v3(float r[3])
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void abs_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
#define INIT_MINMAX(min, max)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define CLAMP_MIN(a, b)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
#define CD_MASK_MDEFORMVERT
@ CD_CUSTOMLOOPNORMAL
#define CD_MASK_CUSTOMLOOPNORMAL
#define DNA_struct_default_get(struct_name)
struct NormalEditModifierData NormalEditModifierData
@ eModifierType_NormalEdit
@ MOD_NORMALEDIT_NO_POLYNORS_FIX
@ MOD_NORMALEDIT_INVERT_VGROUP
@ MOD_NORMALEDIT_USE_DIRECTION_PARALLEL
@ MOD_NORMALEDIT_MODE_RADIAL
@ MOD_NORMALEDIT_MODE_DIRECTIONAL
@ MOD_NORMALEDIT_MIX_COPY
@ MOD_NORMALEDIT_MIX_ADD
@ MOD_NORMALEDIT_MIX_SUB
@ MOD_NORMALEDIT_MIX_MUL
Object is a sort of wrapper for general info.
static bool is_disabled
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static void init_data(ModifierData *md)
static void mix_mode_panel_draw(const bContext *, Panel *panel)
static bool is_valid_target(NormalEditModifierData *enmd)
static void panel_register(ARegionType *region_type)
static bool is_valid_target_with_error(const Object *ob, NormalEditModifierData *enmd)
static void normalEditModifier_do_radial(NormalEditModifierData *enmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, blender::MutableSpan< blender::short2 > clnors, blender::MutableSpan< blender::float3 > corner_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, blender::Span< blender::float3 > vert_positions, const blender::Span< blender::int2 > edges, blender::MutableSpan< bool > sharp_edges, blender::MutableSpan< int > corner_verts, blender::MutableSpan< int > corner_edges, const blender::OffsetIndices< int > faces)
ModifierTypeInfo modifierType_NormalEdit
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
static void generate_vert_coordinates(Mesh *mesh, Object *ob, Object *ob_center, const float offset[3], const int verts_num, float(*r_cos)[3], float r_size[3])
static void normalEditModifier_do_directional(NormalEditModifierData *enmd, const ModifierEvalContext *, Object *ob, Mesh *mesh, blender::MutableSpan< blender::short2 > clnors, blender::MutableSpan< blender::float3 > corner_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, const blender::Span< blender::float3 > positions, const blender::Span< blender::int2 > edges, blender::MutableSpan< bool > sharp_edges, blender::MutableSpan< int > corner_verts, blender::MutableSpan< int > corner_edges, const blender::OffsetIndices< int > faces)
static Mesh * normalEditModifier_do(NormalEditModifierData *enmd, const ModifierEvalContext *ctx, Object *ob, Mesh *mesh)
static void faces_check_flip(Mesh &mesh, blender::MutableSpan< blender::float3 > nos, const blender::Span< blender::float3 > face_normals)
static void panel_draw(const bContext *, Panel *panel)
static void offset_panel_draw(const bContext *, Panel *panel)
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void mix_normals(const float mix_factor, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, const float mix_limit, const short mix_mode, const int verts_num, const blender::Span< int > corner_verts, blender::float3 *nos_old, blender::float3 *nos_new)
PanelType * modifier_subpanel_register(ARegionType *region_type, const char *name, const char *label, PanelDrawFn draw_header, PanelDrawFn draw, PanelType *parent)
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
void uiLayoutSetActive(uiLayout *layout, bool active)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
const T * data() const
Definition BLI_array.hh:301
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr bool is_empty() const
Definition BLI_span.hh:510
constexpr T * data() const
Definition BLI_span.hh:540
constexpr void reverse() const
Definition BLI_span.hh:651
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr const T * data() const
Definition BLI_span.hh:216
constexpr int64_t size() const
Definition BLI_span.hh:253
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
uint col
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float3 cos(float3 v)
static char faces[256]
void normals_calc_corners(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< int > corner_to_face_map, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_edges, Span< bool > sharp_faces, const short2 *clnors_data, CornerNormalSpaceArray *r_lnors_spacearr, MutableSpan< float3 > r_corner_normals)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
__int64 int64_t
Definition stdint.h:89
Definition DNA_ID.h:413
float scale[3]
struct uiLayout * layout
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126