Blender V4.3
MOD_solidify_extrude.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 "BLI_math_vector.h"
10#include "BLI_utildefines.h"
11
12#include "BLI_bitmap.h"
13#include "BLI_math_geom.h"
15
16#include "DNA_mesh_types.h"
17#include "DNA_meshdata_types.h"
18#include "DNA_object_types.h"
19
20#include "MEM_guardedalloc.h"
21
22#include "BKE_attribute.hh"
23#include "BKE_customdata.hh"
24#include "BKE_deform.hh"
25#include "BKE_mesh.hh"
26
27#include "MOD_modifiertypes.hh"
28#include "MOD_solidify_util.hh" /* own include */
29#include "MOD_util.hh"
30
31/* -------------------------------------------------------------------- */
38/* skip shell thickness for non-manifold edges, see #35710. */
39#define USE_NONMANIFOLD_WORKAROUND
40
42 int p1; /* init as -1 */
43 int p2;
44};
45
47{
48 return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0));
49}
50
56static void mesh_calc_hq_normal(Mesh *mesh,
57 const blender::Span<blender::float3> face_normals,
58 float (*r_vert_nors)[3],
60 BLI_bitmap *edge_tmp_tag
61#endif
62)
63{
64 const int verts_num = mesh->verts_num;
65 const blender::Span<blender::int2> edges = mesh->edges();
66 const blender::OffsetIndices faces = mesh->faces();
67 const blender::Span<int> corner_edges = mesh->corner_edges();
68
69 {
70 EdgeFaceRef *edge_ref_array = MEM_cnew_array<EdgeFaceRef>(size_t(edges.size()), __func__);
71 EdgeFaceRef *edge_ref;
72 float edge_normal[3];
73
74 /* Add an edge reference if it's not there, pointing back to the face index. */
75 for (const int i : faces.index_range()) {
76 for (const int edge_i : corner_edges.slice(faces[i])) {
77 /* --- add edge ref to face --- */
78 edge_ref = &edge_ref_array[edge_i];
79 if (!edgeref_is_init(edge_ref)) {
80 edge_ref->p1 = i;
81 edge_ref->p2 = -1;
82 }
83 else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) {
84 edge_ref->p2 = i;
85 }
86 else {
87 /* 3+ faces using an edge, we can't handle this usefully */
88 edge_ref->p1 = edge_ref->p2 = -1;
89#ifdef USE_NONMANIFOLD_WORKAROUND
90 BLI_BITMAP_ENABLE(edge_tmp_tag, edge_i);
91#endif
92 }
93 /* --- done --- */
94 }
95 }
96
97 int i;
98 const blender::int2 *edge;
99 for (i = 0, edge = edges.data(), edge_ref = edge_ref_array; i < edges.size();
100 i++, edge++, edge_ref++)
101 {
102 /* Get the edge vert indices, and edge value (the face indices that use it) */
103
104 if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) {
105 if (edge_ref->p2 != -1) {
106 /* We have 2 faces using this edge, calculate the edges normal
107 * using the angle between the 2 faces as a weighting */
108#if 0
109 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
111 edge_normal,
112 angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
113#else
115 edge_normal, face_normals[edge_ref->p1], face_normals[edge_ref->p2]);
116#endif
117 }
118 else {
119 /* only one face attached to that edge */
120 /* an edge without another attached- the weight on this is undefined */
121 copy_v3_v3(edge_normal, face_normals[edge_ref->p1]);
122 }
123 add_v3_v3(r_vert_nors[(*edge)[0]], edge_normal);
124 add_v3_v3(r_vert_nors[(*edge)[1]], edge_normal);
125 }
126 }
127 MEM_freeN(edge_ref_array);
128 }
129
130 /* normalize vertex normals and assign */
131 const blender::Span<blender::float3> vert_normals = mesh->vert_normals();
132 for (int i = 0; i < verts_num; i++) {
133 if (normalize_v3(r_vert_nors[i]) == 0.0f) {
134 copy_v3_v3(r_vert_nors[i], vert_normals[i]);
135 }
136 }
137}
138
141/* -------------------------------------------------------------------- */
145/* NOLINTNEXTLINE: readability-function-size */
147{
148 using namespace blender;
149 Mesh *result;
151
152 const uint verts_num = uint(mesh->verts_num);
153 const uint edges_num = uint(mesh->edges_num);
154 const uint faces_num = uint(mesh->faces_num);
155 const uint loops_num = uint(mesh->corners_num);
156 uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
157
158 /* Only use material offsets if we have 2 or more materials. */
159 const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
160 const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
161 const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
162
163 /* use for edges */
164 /* Over-allocate new_vert_arr, old_vert_arr. */
165 uint *new_vert_arr = nullptr;
166 STACK_DECLARE(new_vert_arr);
167
168 uint *new_edge_arr = nullptr;
169 STACK_DECLARE(new_edge_arr);
170
171 uint *old_vert_arr = MEM_cnew_array<uint>(verts_num, "old_vert_arr in solidify");
172
173 uint *edge_users = nullptr;
174 int *edge_order = nullptr;
175
176 float(*vert_nors)[3] = nullptr;
178
179 const bool need_face_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
180 (smd->flag & MOD_SOLIDIFY_EVEN) ||
182 (smd->bevel_convex != 0);
183
184 const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
185 const float ofs_new = smd->offset + ofs_orig;
186 const float offset_fac_vg = smd->offset_fac_vg;
187 const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
188 const float bevel_convex = smd->bevel_convex;
189 const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
190 const bool do_clamp = (smd->offset_clamp != 0.0f);
191 const bool do_angle_clamp = do_clamp && (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) != 0;
192 const bool do_bevel_convex = bevel_convex != 0.0f;
193 const bool do_rim = (smd->flag & MOD_SOLIDIFY_RIM) != 0;
194 const bool do_shell = !(do_rim && (smd->flag & MOD_SOLIDIFY_NOSHELL) != 0);
195
196 /* weights */
197 const MDeformVert *dvert;
198 const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
199 int defgrp_index;
200 const int shell_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->shell_defgrp_name);
201 const int rim_defgrp_index = BKE_id_defgroup_name_index(&mesh->id, smd->rim_defgrp_name);
202
203 /* array size is doubled in case of using a shell */
204 const uint stride = do_shell ? 2 : 1;
205
206 const blender::Span<blender::float3> vert_normals = mesh->vert_normals();
207
208 MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
209
210 const blender::Span<blender::float3> orig_vert_positions = mesh->vert_positions();
211 const blender::Span<blender::int2> orig_edges = mesh->edges();
212 const blender::OffsetIndices orig_faces = mesh->faces();
213 const blender::Span<int> orig_corner_verts = mesh->corner_verts();
214 const blender::Span<int> orig_corner_edges = mesh->corner_edges();
215
216 if (need_face_normals) {
217 /* calculate only face normals */
218 face_normals = mesh->face_normals();
219 }
220
221 STACK_INIT(new_vert_arr, verts_num * 2);
222 STACK_INIT(new_edge_arr, edges_num * 2);
223
224 if (do_rim) {
225 BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(verts_num, __func__);
226 uint eidx;
227 uint i;
228
229#define INVALID_UNUSED uint(-1)
230#define INVALID_PAIR uint(-2)
231
232 new_vert_arr = static_cast<uint *>(
233 MEM_malloc_arrayN(verts_num, 2 * sizeof(*new_vert_arr), __func__));
234 new_edge_arr = static_cast<uint *>(
235 MEM_malloc_arrayN(((edges_num * 2) + verts_num), sizeof(*new_edge_arr), __func__));
236
237 edge_users = static_cast<uint *>(MEM_malloc_arrayN(edges_num, sizeof(*edge_users), __func__));
238 edge_order = static_cast<int *>(MEM_malloc_arrayN(edges_num, sizeof(*edge_order), __func__));
239
240 /* save doing 2 loops here... */
241#if 0
242 copy_vn_i(edge_users, edges_num, INVALID_UNUSED);
243#endif
244
245 for (eidx = 0; eidx < edges_num; eidx++) {
246 edge_users[eidx] = INVALID_UNUSED;
247 }
248
249 for (const int64_t i : orig_faces.index_range()) {
250 const blender::IndexRange face = orig_faces[i];
251 int j;
252
253 int corner_i_prev = face.last();
254
255 for (j = 0; j < face.size(); j++) {
256 const int corner_i = face[j];
257 const int vert_i = orig_corner_verts[corner_i];
258 const int prev_vert_i = orig_corner_verts[corner_i_prev];
259 /* add edge user */
260 eidx = int(orig_corner_edges[corner_i_prev]);
261 if (edge_users[eidx] == INVALID_UNUSED) {
262 const blender::int2 &edge = orig_edges[eidx];
263 BLI_assert(ELEM(prev_vert_i, edge[0], edge[1]) && ELEM(vert_i, edge[0], edge[1]));
264 edge_users[eidx] = (prev_vert_i > vert_i) == (edge[0] < edge[1]) ? uint(i) :
265 (uint(i) + faces_num);
266 edge_order[eidx] = j;
267 }
268 else {
269 edge_users[eidx] = INVALID_PAIR;
270 }
271 corner_i_prev = corner_i;
272 }
273 }
274
275 for (eidx = 0; eidx < edges_num; eidx++) {
276 if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
277 BLI_BITMAP_ENABLE(orig_mvert_tag, orig_edges[eidx][0]);
278 BLI_BITMAP_ENABLE(orig_mvert_tag, orig_edges[eidx][1]);
279 STACK_PUSH(new_edge_arr, eidx);
280 newPolys++;
281 newLoops += 4;
282 }
283 }
284
285 for (i = 0; i < verts_num; i++) {
286 if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
287 old_vert_arr[i] = STACK_SIZE(new_vert_arr);
288 STACK_PUSH(new_vert_arr, i);
289 rimVerts++;
290 }
291 else {
292 old_vert_arr[i] = INVALID_UNUSED;
293 }
294 }
295
296 MEM_freeN(orig_mvert_tag);
297 }
298
299 if (do_shell == false) {
300 /* only add rim vertices */
301 newVerts = rimVerts;
302 /* each extruded face needs an opposite edge */
303 newEdges = newPolys;
304 }
305 else {
306 /* (stride == 2) in this case, so no need to add newVerts/newEdges */
307 BLI_assert(newVerts == 0);
308 BLI_assert(newEdges == 0);
309 }
310
311#ifdef USE_NONMANIFOLD_WORKAROUND
312 BLI_bitmap *edge_tmp_tag = BLI_BITMAP_NEW(mesh->edges_num, __func__);
313#endif
314
315 if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
316 vert_nors = static_cast<float(*)[3]>(MEM_calloc_arrayN(verts_num, sizeof(float[3]), __func__));
318 face_normals,
319 vert_nors
321 ,
322 edge_tmp_tag
323#endif
324 );
325 }
326
328 int((verts_num * stride) + newVerts),
329 int((edges_num * stride) + newEdges + rimVerts),
330 int((faces_num * stride) + newPolys),
331 int((loops_num * stride) + newLoops));
332
333 blender::MutableSpan<blender::float3> vert_positions = result->vert_positions_for_write();
334 blender::MutableSpan<blender::int2> edges = result->edges_for_write();
335 blender::MutableSpan<int> face_offsets = result->face_offsets_for_write();
336 blender::MutableSpan<int> corner_verts = result->corner_verts_for_write();
337 blender::MutableSpan<int> corner_edges = result->corner_edges_for_write();
338
339 if (do_shell) {
340 CustomData_copy_data(&mesh->vert_data, &result->vert_data, 0, 0, int(verts_num));
341 CustomData_copy_data(&mesh->vert_data, &result->vert_data, 0, int(verts_num), int(verts_num));
342
343 CustomData_copy_data(&mesh->edge_data, &result->edge_data, 0, 0, int(edges_num));
344 CustomData_copy_data(&mesh->edge_data, &result->edge_data, 0, int(edges_num), int(edges_num));
345
346 CustomData_copy_data(&mesh->corner_data, &result->corner_data, 0, 0, int(loops_num));
347 /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops
348 * (so that winding of copied face get reversed, so that normals get reversed
349 * and point in expected direction...).
350 * If we also copy data here, then this data get overwritten
351 * (and allocated memory becomes a memory leak). */
352
353 CustomData_copy_data(&mesh->face_data, &result->face_data, 0, 0, int(faces_num));
354 CustomData_copy_data(&mesh->face_data, &result->face_data, 0, int(faces_num), int(faces_num));
355 face_offsets.take_front(faces_num).copy_from(mesh->face_offsets().drop_back(1));
356 for (const int i : orig_faces.index_range()) {
357 face_offsets[faces_num + i] = orig_faces[i].start() + mesh->corners_num;
358 }
359 }
360 else {
361 int i, j;
362 CustomData_copy_data(&mesh->vert_data, &result->vert_data, 0, 0, int(verts_num));
363 for (i = 0, j = int(verts_num); i < verts_num; i++) {
364 if (old_vert_arr[i] != INVALID_UNUSED) {
365 CustomData_copy_data(&mesh->vert_data, &result->vert_data, i, j, 1);
366 j++;
367 }
368 }
369
370 CustomData_copy_data(&mesh->edge_data, &result->edge_data, 0, 0, int(edges_num));
371
372 for (i = 0, j = int(edges_num); i < edges_num; i++) {
373 if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
374 blender::int2 *ed_src, *ed_dst;
375 CustomData_copy_data(&mesh->edge_data, &result->edge_data, i, j, 1);
376
377 ed_src = &edges[i];
378 ed_dst = &edges[j];
379 (*ed_dst)[0] = old_vert_arr[(*ed_src)[0]] + verts_num;
380 (*ed_dst)[1] = old_vert_arr[(*ed_src)[1]] + verts_num;
381 j++;
382 }
383 }
384
385 /* will be created later */
386 CustomData_copy_data(&mesh->corner_data, &result->corner_data, 0, 0, int(loops_num));
387 CustomData_copy_data(&mesh->face_data, &result->face_data, 0, 0, int(faces_num));
388 face_offsets.take_front(faces_num).copy_from(mesh->face_offsets().drop_back(1));
389 }
390
391 const float *orig_vert_bweight = static_cast<const float *>(
392 CustomData_get_layer_named(&mesh->vert_data, CD_PROP_FLOAT, "bevel_weight_vert"));
393 float *result_edge_bweight = static_cast<float *>(CustomData_get_layer_named_for_write(
394 &result->edge_data, CD_PROP_FLOAT, "bevel_weight_edge", result->edges_num));
395 if (!result_edge_bweight && (do_bevel_convex || orig_vert_bweight)) {
396 result_edge_bweight = static_cast<float *>(CustomData_add_layer_named(&result->edge_data,
399 result->edges_num,
400 "bevel_weight_edge"));
401 }
402
403 /* Initializes: (`i_end`, `do_shell_align`, `vert_index`). */
404#define INIT_VERT_ARRAY_OFFSETS(test) \
405 if (((ofs_new >= ofs_orig) == do_flip) == test) { \
406 i_end = verts_num; \
407 do_shell_align = true; \
408 vert_index = 0; \
409 } \
410 else { \
411 if (do_shell) { \
412 i_end = verts_num; \
413 do_shell_align = true; \
414 } \
415 else { \
416 i_end = newVerts; \
417 do_shell_align = false; \
418 } \
419 vert_index = verts_num; \
420 } \
421 (void)0
422
423 bke::MutableAttributeAccessor dst_attributes = result->attributes_for_write();
424 bke::SpanAttributeWriter dst_material_index = dst_attributes.lookup_or_add_for_write_span<int>(
425 "material_index", bke::AttrDomain::Face);
426
427 /* flip normals */
428
429 if (do_shell) {
430 for (const int64_t i : blender::IndexRange(mesh->faces_num)) {
431 const blender::IndexRange face = orig_faces[i];
432 const int loop_end = face.size() - 1;
433 int e;
434 int j;
435
436 /* reverses the loop direction (corner verts as well as custom-data)
437 * Corner edges also need to be corrected too, done in a separate loop below. */
438 const int corner_2 = face.start() + mesh->corners_num;
439#if 0
440 for (j = 0; j < face.size(); j++) {
441 CustomData_copy_data(&mesh->ldata,
442 &result->ldata,
443 face.start() + j,
444 face.start() + (loop_end - j) + mesh->corners_num,
445 1);
446 }
447#else
448 /* slightly more involved, keep the first vertex the same for the copy,
449 * ensures the diagonals in the new face match the original. */
450 j = 0;
451 for (int j_prev = loop_end; j < face.size(); j_prev = j++) {
452 CustomData_copy_data(&mesh->corner_data,
453 &result->corner_data,
454 face.start() + j,
455 face.start() + (loop_end - j_prev) + mesh->corners_num,
456 1);
457 }
458#endif
459
460 if (mat_ofs) {
461 dst_material_index.span[faces_num + i] += mat_ofs;
462 CLAMP(dst_material_index.span[faces_num + i], 0, mat_nr_max);
463 }
464
465 e = corner_edges[corner_2 + 0];
466 for (j = 0; j < loop_end; j++) {
467 corner_edges[corner_2 + j] = corner_edges[corner_2 + j + 1];
468 }
469 corner_edges[corner_2 + loop_end] = e;
470
471 for (j = 0; j < face.size(); j++) {
472 corner_verts[corner_2 + j] += verts_num;
473 corner_edges[corner_2 + j] += edges_num;
474 }
475 }
476
477 for (blender::int2 &edge : edges.slice(edges_num, edges_num)) {
478 edge += verts_num;
479 }
480 }
481
482 /* NOTE: copied vertex layers don't have flipped normals yet. do this after applying offset. */
483 if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
484 /* no even thickness, very simple */
485 float ofs_new_vgroup;
486
487 /* for clamping */
488 float *vert_lens = nullptr;
489 float *vert_angs = nullptr;
490 const float offset = fabsf(smd->offset) * smd->offset_clamp;
491 const float offset_sq = offset * offset;
492
493 /* for bevel weight */
494 float *edge_angs = nullptr;
495
496 if (do_clamp) {
497 vert_lens = static_cast<float *>(MEM_malloc_arrayN(verts_num, sizeof(float), "vert_lens"));
498 copy_vn_fl(vert_lens, int(verts_num), FLT_MAX);
499 for (uint i = 0; i < edges_num; i++) {
500 const float ed_len_sq = len_squared_v3v3(vert_positions[edges[i][0]],
501 vert_positions[edges[i][1]]);
502 vert_lens[edges[i][0]] = min_ff(vert_lens[edges[i][0]], ed_len_sq);
503 vert_lens[edges[i][1]] = min_ff(vert_lens[edges[i][1]], ed_len_sq);
504 }
505 }
506
507 if (do_angle_clamp || do_bevel_convex) {
508 uint eidx;
509 if (do_angle_clamp) {
510 vert_angs = static_cast<float *>(MEM_malloc_arrayN(verts_num, sizeof(float), "vert_angs"));
511 copy_vn_fl(vert_angs, int(verts_num), 0.5f * M_PI);
512 }
513 if (do_bevel_convex) {
514 edge_angs = static_cast<float *>(MEM_malloc_arrayN(edges_num, sizeof(float), "edge_angs"));
515 if (!do_rim) {
516 edge_users = static_cast<uint *>(
517 MEM_malloc_arrayN(edges_num, sizeof(*edge_users), "solid_mod edges"));
518 }
519 }
520 uint(*edge_user_pairs)[2] = static_cast<uint(*)[2]>(
521 MEM_malloc_arrayN(edges_num, sizeof(*edge_user_pairs), "edge_user_pairs"));
522 for (eidx = 0; eidx < edges_num; eidx++) {
523 edge_user_pairs[eidx][0] = INVALID_UNUSED;
524 edge_user_pairs[eidx][1] = INVALID_UNUSED;
525 }
526 for (const int64_t i : orig_faces.index_range()) {
527 const blender::IndexRange face = orig_faces[i];
528 int prev_corner_i = face.last();
529 for (const int corner_i : face) {
530 const int vert_i = orig_corner_verts[corner_i];
531 const int prev_vert_i = orig_corner_verts[prev_corner_i];
532 /* add edge user */
533 eidx = orig_corner_edges[prev_corner_i];
534 const blender::int2 &ed = orig_edges[eidx];
535 BLI_assert(ELEM(prev_vert_i, ed[0], ed[1]) && ELEM(vert_i, ed[0], ed[1]));
536 char flip = char((prev_vert_i > vert_i) == (ed[0] < ed[1]));
537 if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
538 edge_user_pairs[eidx][flip] = uint(i);
539 }
540 else {
541 edge_user_pairs[eidx][0] = INVALID_PAIR;
542 edge_user_pairs[eidx][1] = INVALID_PAIR;
543 }
544 prev_corner_i = corner_i;
545 }
546 }
547 float e[3];
548 for (uint i = 0; i < edges_num; i++) {
549 const blender::int2 &edge = orig_edges[i];
550 if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
551 !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR))
552 {
553 const float *n0 = face_normals[edge_user_pairs[i][0]];
554 const float *n1 = face_normals[edge_user_pairs[i][1]];
555 sub_v3_v3v3(e, orig_vert_positions[edge[0]], orig_vert_positions[edge[1]]);
557 const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e);
558 if (do_angle_clamp) {
559 vert_angs[edge[0]] = max_ff(vert_angs[edge[0]], angle);
560 vert_angs[edge[1]] = max_ff(vert_angs[edge[1]], angle);
561 }
562 if (do_bevel_convex) {
563 edge_angs[i] = angle;
564 if (!do_rim) {
565 edge_users[i] = INVALID_PAIR;
566 }
567 }
568 }
569 }
570 MEM_freeN(edge_user_pairs);
571 }
572
573 if (ofs_new != 0.0f) {
574 uint i_orig, i_end;
575 bool do_shell_align;
576
577 ofs_new_vgroup = ofs_new;
578
579 uint vert_index;
581
582 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
583 const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
584 if (dvert) {
585 const MDeformVert *dv = &dvert[i];
586 if (defgrp_invert) {
587 ofs_new_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
588 }
589 else {
590 ofs_new_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
591 }
592 ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_new;
593 }
594 if (do_clamp && offset > FLT_EPSILON) {
595 /* always reset because we may have set before */
596 if (dvert == nullptr) {
597 ofs_new_vgroup = ofs_new;
598 }
599 if (do_angle_clamp) {
600 float cos_ang = cosf(((2 * M_PI) - vert_angs[i]) * 0.5f);
601 if (cos_ang > 0) {
602 float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
603 if (max_off < offset * 0.5f) {
604 ofs_new_vgroup *= max_off / offset * 2;
605 }
606 }
607 }
608 else {
609 if (vert_lens[i] < offset_sq) {
610 float scalar = sqrtf(vert_lens[i]) / offset;
611 ofs_new_vgroup *= scalar;
612 }
613 }
614 }
615 if (vert_nors) {
616 madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup);
617 }
618 else {
619 madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup);
620 }
621 }
622 }
623
624 if (ofs_orig != 0.0f) {
625 uint i_orig, i_end;
626 bool do_shell_align;
627
628 ofs_new_vgroup = ofs_orig;
629
630 /* as above but swapped */
631 uint vert_index;
633
634 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
635 const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
636 if (dvert) {
637 const MDeformVert *dv = &dvert[i];
638 if (defgrp_invert) {
639 ofs_new_vgroup = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
640 }
641 else {
642 ofs_new_vgroup = BKE_defvert_find_weight(dv, defgrp_index);
643 }
644 ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_orig;
645 }
646 if (do_clamp && offset > FLT_EPSILON) {
647 /* always reset because we may have set before */
648 if (dvert == nullptr) {
649 ofs_new_vgroup = ofs_orig;
650 }
651 if (do_angle_clamp) {
652 float cos_ang = cosf(vert_angs[i_orig] * 0.5f);
653 if (cos_ang > 0) {
654 float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
655 if (max_off < offset * 0.5f) {
656 ofs_new_vgroup *= max_off / offset * 2;
657 }
658 }
659 }
660 else {
661 if (vert_lens[i] < offset_sq) {
662 float scalar = sqrtf(vert_lens[i]) / offset;
663 ofs_new_vgroup *= scalar;
664 }
665 }
666 }
667 if (vert_nors) {
668 madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup);
669 }
670 else {
671 madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup);
672 }
673 }
674 }
675
676 if (do_bevel_convex) {
677 for (uint i = 0; i < edges_num; i++) {
678 if (edge_users[i] == INVALID_PAIR) {
679 float angle = edge_angs[i];
680 result_edge_bweight[i] = clamp_f(result_edge_bweight[i] +
681 (angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
682 clamp_f(bevel_convex, -1.0f, 0.0f)),
683 0.0f,
684 1.0f);
685 if (do_shell) {
686 result_edge_bweight[i + edges_num] = clamp_f(
687 result_edge_bweight[i + edges_num] + (angle > M_PI ?
688 clamp_f(bevel_convex, 0.0f, 1.0f) :
689 clamp_f(bevel_convex, -1.0f, 0.0f)),
690 0,
691 1.0f);
692 }
693 }
694 }
695 if (!do_rim) {
696 MEM_freeN(edge_users);
697 }
698 MEM_freeN(edge_angs);
699 }
700
701 if (do_clamp) {
702 MEM_freeN(vert_lens);
703 if (do_angle_clamp) {
704 MEM_freeN(vert_angs);
705 }
706 }
707 }
708 else {
709#ifdef USE_NONMANIFOLD_WORKAROUND
710 const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
711#endif
712 /* same as EM_solidify() in editmesh_lib.c */
713 float *vert_angles = static_cast<float *>(
714 MEM_calloc_arrayN(verts_num, sizeof(float[2]), "mod_solid_pair")); /* 2 in 1 */
715 float *vert_accum = vert_angles + verts_num;
716 uint vidx;
717 uint i;
718
719 if (vert_nors == nullptr) {
720 vert_nors = static_cast<float(*)[3]>(
721 MEM_malloc_arrayN(verts_num, sizeof(float[3]), "mod_solid_vno"));
722 for (i = 0; i < verts_num; i++) {
723 copy_v3_v3(vert_nors[i], vert_normals[i]);
724 }
725 }
726
727 for (const int64_t i : blender::IndexRange(faces_num)) {
728 const blender::IndexRange face = orig_faces[i];
729 /* #bke::mesh::face_angles_calc logic is inlined here */
730 float nor_prev[3];
731 float nor_next[3];
732
733 int i_curr = face.size() - 1;
734 int i_next = 0;
735
736 const int *face_verts = &corner_verts[face.start()];
737 const int *face_edges = &corner_edges[face.start()];
738
740 nor_prev, vert_positions[face_verts[i_curr - 1]], vert_positions[face_verts[i_curr]]);
741 normalize_v3(nor_prev);
742
743 while (i_next < face.size()) {
744 float angle;
746 nor_next, vert_positions[face_verts[i_curr]], vert_positions[face_verts[i_next]]);
747 normalize_v3(nor_next);
748 angle = angle_normalized_v3v3(nor_prev, nor_next);
749
750 /* --- not related to angle calc --- */
751 if (angle < FLT_EPSILON) {
752 angle = FLT_EPSILON;
753 }
754
755 vidx = face_verts[i_curr];
756 vert_accum[vidx] += angle;
757
758#ifdef USE_NONMANIFOLD_WORKAROUND
759 /* skip 3+ face user edges */
760 if ((check_non_manifold == false) ||
761 LIKELY(!BLI_BITMAP_TEST(edge_tmp_tag, face_edges[i_curr]) &&
762 !BLI_BITMAP_TEST(edge_tmp_tag, face_edges[i_next])))
763 {
764 vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_normals[i]) *
765 angle;
766 }
767 else {
768 vert_angles[vidx] += angle;
769 }
770#else
771 vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], face_normals[i]) *
772 angle;
773#endif
774 /* --- end non-angle-calc section --- */
775
776 /* step */
777 copy_v3_v3(nor_prev, nor_next);
778 i_curr = i_next;
779 i_next++;
780 }
781 }
782
783 /* vertex group support */
784 if (dvert) {
785 const MDeformVert *dv = dvert;
786 float scalar;
787
788 if (defgrp_invert) {
789 for (i = 0; i < verts_num; i++, dv++) {
790 scalar = 1.0f - BKE_defvert_find_weight(dv, defgrp_index);
791 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
792 vert_angles[i] *= scalar;
793 }
794 }
795 else {
796 for (i = 0; i < verts_num; i++, dv++) {
797 scalar = BKE_defvert_find_weight(dv, defgrp_index);
798 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
799 vert_angles[i] *= scalar;
800 }
801 }
802 }
803
804 /* for angle clamp */
805 float *vert_angs = nullptr;
806 /* for bevel convex */
807 float *edge_angs = nullptr;
808
809 if (do_angle_clamp || do_bevel_convex) {
810 uint eidx;
811 if (do_angle_clamp) {
812 vert_angs = static_cast<float *>(
813 MEM_malloc_arrayN(verts_num, sizeof(float), "vert_angs even"));
814 copy_vn_fl(vert_angs, int(verts_num), 0.5f * M_PI);
815 }
816 if (do_bevel_convex) {
817 edge_angs = static_cast<float *>(
818 MEM_malloc_arrayN(edges_num, sizeof(float), "edge_angs even"));
819 if (!do_rim) {
820 edge_users = static_cast<uint *>(
821 MEM_malloc_arrayN(edges_num, sizeof(*edge_users), "solid_mod edges"));
822 }
823 }
824 uint(*edge_user_pairs)[2] = static_cast<uint(*)[2]>(
825 MEM_malloc_arrayN(edges_num, sizeof(*edge_user_pairs), "edge_user_pairs"));
826 for (eidx = 0; eidx < edges_num; eidx++) {
827 edge_user_pairs[eidx][0] = INVALID_UNUSED;
828 edge_user_pairs[eidx][1] = INVALID_UNUSED;
829 }
830 for (const int i : orig_faces.index_range()) {
831 const blender::IndexRange face = orig_faces[i];
832 int prev_corner_i = face.start() + face.size() - 1;
833 for (int j = 0; j < face.size(); j++) {
834 const int corner_i = face.start() + j;
835 const int vert_i = orig_corner_verts[corner_i];
836 const int prev_vert_i = orig_corner_verts[prev_corner_i];
837
838 /* add edge user */
839 eidx = orig_corner_edges[prev_corner_i];
840 const blender::int2 &edge = orig_edges[eidx];
841 BLI_assert(ELEM(prev_vert_i, edge[0], edge[1]) && ELEM(vert_i, edge[0], edge[1]));
842 char flip = char((prev_vert_i > vert_i) == (edge[0] < edge[1]));
843 if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
844 edge_user_pairs[eidx][flip] = uint(i);
845 }
846 else {
847 edge_user_pairs[eidx][0] = INVALID_PAIR;
848 edge_user_pairs[eidx][1] = INVALID_PAIR;
849 }
850 prev_corner_i = corner_i;
851 }
852 }
853 float e[3];
854 for (i = 0; i < edges_num; i++) {
855 const blender::int2 &edge = orig_edges[i];
856 if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
857 !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR))
858 {
859 const float *n0 = face_normals[edge_user_pairs[i][0]];
860 const float *n1 = face_normals[edge_user_pairs[i][1]];
861 if (do_angle_clamp) {
862 const float angle = M_PI - angle_normalized_v3v3(n0, n1);
863 vert_angs[edge[0]] = max_ff(vert_angs[edge[0]], angle);
864 vert_angs[edge[1]] = max_ff(vert_angs[edge[1]], angle);
865 }
866 if (do_bevel_convex) {
867 sub_v3_v3v3(e, orig_vert_positions[edge[0]], orig_vert_positions[edge[1]]);
869 edge_angs[i] = angle_signed_on_axis_v3v3_v3(n0, n1, e);
870 if (!do_rim) {
871 edge_users[i] = INVALID_PAIR;
872 }
873 }
874 }
875 }
876 MEM_freeN(edge_user_pairs);
877 }
878
879 if (do_clamp) {
880 const float clamp_fac = 1 + (do_angle_clamp ? fabsf(smd->offset_fac) : 0);
881 const float offset = fabsf(smd->offset) * smd->offset_clamp * clamp_fac;
882 if (offset > FLT_EPSILON) {
883 float *vert_lens_sq = static_cast<float *>(
884 MEM_malloc_arrayN(verts_num, sizeof(float), "vert_lens_sq"));
885 const float offset_sq = offset * offset;
886 copy_vn_fl(vert_lens_sq, int(verts_num), FLT_MAX);
887 for (i = 0; i < edges_num; i++) {
888 const float ed_len = len_squared_v3v3(vert_positions[edges[i][0]],
889 vert_positions[edges[i][1]]);
890 vert_lens_sq[edges[i][0]] = min_ff(vert_lens_sq[edges[i][0]], ed_len);
891 vert_lens_sq[edges[i][1]] = min_ff(vert_lens_sq[edges[i][1]], ed_len);
892 }
893 if (do_angle_clamp) {
894 for (i = 0; i < verts_num; i++) {
895 float cos_ang = cosf(vert_angs[i] * 0.5f);
896 if (cos_ang > 0) {
897 float max_off = sqrtf(vert_lens_sq[i]) * 0.5f / cos_ang;
898 if (max_off < offset * 0.5f) {
899 vert_angles[i] *= max_off / offset * 2;
900 }
901 }
902 }
903 MEM_freeN(vert_angs);
904 }
905 else {
906 for (i = 0; i < verts_num; i++) {
907 if (vert_lens_sq[i] < offset_sq) {
908 float scalar = sqrtf(vert_lens_sq[i]) / offset;
909 vert_angles[i] *= scalar;
910 }
911 }
912 }
913 MEM_freeN(vert_lens_sq);
914 }
915 }
916
917 if (do_bevel_convex) {
918 for (i = 0; i < edges_num; i++) {
919 if (edge_users[i] == INVALID_PAIR) {
920 float angle = edge_angs[i];
921 result_edge_bweight[i] = clamp_f(result_edge_bweight[i] +
922 (angle < M_PI ? clamp_f(bevel_convex, 0.0f, 1.0f) :
923 clamp_f(bevel_convex, -1.0f, 0.0f)),
924 0.0f,
925 1.0f);
926 if (do_shell) {
927 result_edge_bweight[i + edges_num] = clamp_f(
928 result_edge_bweight[i + edges_num] +
929 (angle > M_PI ? clamp_f(bevel_convex, 0, 1) : clamp_f(bevel_convex, -1, 0)),
930 0.0f,
931 1.0f);
932 }
933 }
934 }
935 if (!do_rim) {
936 MEM_freeN(edge_users);
937 }
938 MEM_freeN(edge_angs);
939 }
940
941#undef INVALID_UNUSED
942#undef INVALID_PAIR
943
944 if (ofs_new != 0.0f) {
945 uint i_orig, i_end;
946 bool do_shell_align;
947
948 uint vert_index;
950
951 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
952 const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
953 if (vert_accum[i_other]) { /* zero if unselected */
954 madd_v3_v3fl(vert_positions[vert_index],
955 vert_nors[i_other],
956 ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
957 }
958 }
959 }
960
961 if (ofs_orig != 0.0f) {
962 uint i_orig, i_end;
963 bool do_shell_align;
964
965 /* same as above but swapped, intentional use of 'ofs_new' */
966 uint vert_index;
968
969 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
970 const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
971 if (vert_accum[i_other]) { /* zero if unselected */
972 madd_v3_v3fl(vert_positions[vert_index],
973 vert_nors[i_other],
974 ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
975 }
976 }
977 }
978
979 MEM_freeN(vert_angles);
980 }
981
982#ifdef USE_NONMANIFOLD_WORKAROUND
983 MEM_SAFE_FREE(edge_tmp_tag);
984#endif
985
986 if (vert_nors) {
987 MEM_freeN(vert_nors);
988 }
989
990 /* Add vertex weights for rim and shell vgroups. */
991 if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
992 MDeformVert *dst_dvert = result->deform_verts_for_write().data();
993
994 /* Ultimate security check. */
995 if (dst_dvert != nullptr) {
996
997 if (rim_defgrp_index != -1) {
998 for (uint i = 0; i < rimVerts; i++) {
999 BKE_defvert_ensure_index(&dst_dvert[new_vert_arr[i]], rim_defgrp_index)->weight = 1.0f;
1000 BKE_defvert_ensure_index(&dst_dvert[(do_shell ? new_vert_arr[i] : i) + verts_num],
1001 rim_defgrp_index)
1002 ->weight = 1.0f;
1003 }
1004 }
1005
1006 if (shell_defgrp_index != -1) {
1007 for (uint i = verts_num; i < result->verts_num; i++) {
1008 BKE_defvert_ensure_index(&dst_dvert[i], shell_defgrp_index)->weight = 1.0f;
1009 }
1010 }
1011 }
1012 }
1013 if (do_rim) {
1014 uint i;
1015
1016 const float crease_rim = smd->crease_rim;
1017 const float crease_outer = smd->crease_outer;
1018 const float crease_inner = smd->crease_inner;
1019
1020 int *origindex_edge;
1021 int *orig_ed;
1022 uint j;
1023
1024 float *result_edge_crease = nullptr;
1025 if (crease_rim || crease_outer || crease_inner) {
1026 result_edge_crease = static_cast<float *>(CustomData_get_layer_named_for_write(
1027 &result->edge_data, CD_PROP_FLOAT, "crease_edge", result->edges_num));
1028 if (!result_edge_crease) {
1029 result_edge_crease = static_cast<float *>(CustomData_add_layer_named(
1030 &result->edge_data, CD_PROP_FLOAT, CD_SET_DEFAULT, result->edges_num, "crease_edge"));
1031 }
1032 }
1033
1034 /* add faces & edges */
1035 origindex_edge = static_cast<int *>(
1036 CustomData_get_layer_for_write(&result->edge_data, CD_ORIGINDEX, result->edges_num));
1037 orig_ed = (origindex_edge) ? &origindex_edge[(edges_num * stride) + newEdges] : nullptr;
1038 /* Start after copied edges. */
1039 int new_edge_index = int(edges_num * stride + newEdges);
1040 for (i = 0; i < rimVerts; i++) {
1041 edges[new_edge_index][0] = new_vert_arr[i];
1042 edges[new_edge_index][1] = (do_shell ? new_vert_arr[i] : i) + verts_num;
1043
1044 if (orig_vert_bweight) {
1045 result_edge_bweight[new_edge_index] = orig_vert_bweight[new_vert_arr[i]];
1046 }
1047
1048 if (orig_ed) {
1049 *orig_ed = ORIGINDEX_NONE;
1050 orig_ed++;
1051 }
1052
1053 if (crease_rim) {
1054 result_edge_crease[new_edge_index] = crease_rim;
1055 }
1056 new_edge_index++;
1057 }
1058
1059 /* faces */
1060 int new_face_index = int(faces_num * stride);
1061 blender::MutableSpan<int> new_corner_verts = corner_verts.drop_front(loops_num * stride);
1062 blender::MutableSpan<int> new_corner_edges = corner_edges.drop_front(loops_num * stride);
1063 j = 0;
1064 for (i = 0; i < newPolys; i++) {
1065 uint eidx = new_edge_arr[i];
1066 uint pidx = edge_users[eidx];
1067 int k1, k2;
1068 bool flip;
1069
1070 if (pidx >= faces_num) {
1071 pidx -= faces_num;
1072 flip = true;
1073 }
1074 else {
1075 flip = false;
1076 }
1077
1078 const blender::int2 &edge = edges[eidx];
1079
1080 /* copy most of the face settings */
1082 &mesh->face_data, &result->face_data, int(pidx), int((faces_num * stride) + i), 1);
1083
1084 const int old_face_size = orig_faces[pidx].size();
1085 face_offsets[new_face_index] = int(j + (loops_num * stride));
1086
1087 /* prev loop */
1088 k1 = face_offsets[pidx] + (((edge_order[eidx] - 1) + old_face_size) % old_face_size);
1089
1090 k2 = face_offsets[pidx] + (edge_order[eidx]);
1091
1093 &mesh->corner_data, &result->corner_data, k2, int((loops_num * stride) + j + 0), 1);
1095 &mesh->corner_data, &result->corner_data, k1, int((loops_num * stride) + j + 1), 1);
1097 &mesh->corner_data, &result->corner_data, k1, int((loops_num * stride) + j + 2), 1);
1099 &mesh->corner_data, &result->corner_data, k2, int((loops_num * stride) + j + 3), 1);
1100
1101 if (flip == false) {
1102 new_corner_verts[j] = edge[0];
1103 new_corner_edges[j++] = eidx;
1104
1105 new_corner_verts[j] = edge[1];
1106 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[1]] + newEdges;
1107
1108 new_corner_verts[j] = (do_shell ? edge[1] : old_vert_arr[edge[1]]) + verts_num;
1109 new_corner_edges[j++] = (do_shell ? eidx : i) + edges_num;
1110
1111 new_corner_verts[j] = (do_shell ? edge[0] : old_vert_arr[edge[0]]) + verts_num;
1112 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[0]] + newEdges;
1113 }
1114 else {
1115 new_corner_verts[j] = edge[1];
1116 new_corner_edges[j++] = eidx;
1117
1118 new_corner_verts[j] = edge[0];
1119 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[0]] + newEdges;
1120
1121 new_corner_verts[j] = (do_shell ? edge[0] : old_vert_arr[edge[0]]) + verts_num;
1122 new_corner_edges[j++] = (do_shell ? eidx : i) + edges_num;
1123
1124 new_corner_verts[j] = (do_shell ? edge[1] : old_vert_arr[edge[1]]) + verts_num;
1125 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[1]] + newEdges;
1126 }
1127
1128 if (origindex_edge) {
1129 origindex_edge[new_corner_edges[j - 3]] = ORIGINDEX_NONE;
1130 origindex_edge[new_corner_edges[j - 1]] = ORIGINDEX_NONE;
1131 }
1132
1133 /* use the next material index if option enabled */
1134 if (mat_ofs_rim) {
1135 dst_material_index.span[new_face_index] += mat_ofs_rim;
1136 CLAMP(dst_material_index.span[new_face_index], 0, mat_nr_max);
1137 }
1138 if (crease_outer) {
1139 /* crease += crease_outer; without wrapping */
1140 float *cr = &(result_edge_crease[eidx]);
1141 float tcr = *cr + crease_outer;
1142 *cr = tcr > 1.0f ? 1.0f : tcr;
1143 }
1144
1145 if (crease_inner) {
1146 /* crease += crease_inner; without wrapping */
1147 float *cr = &(result_edge_crease[edges_num + (do_shell ? eidx : i)]);
1148 float tcr = *cr + crease_inner;
1149 *cr = tcr > 1.0f ? 1.0f : tcr;
1150 }
1151
1152 new_face_index++;
1153 }
1154
1155 MEM_freeN(new_vert_arr);
1156 MEM_freeN(new_edge_arr);
1157
1158 MEM_freeN(edge_users);
1159 MEM_freeN(edge_order);
1160 }
1161
1162 if (old_vert_arr) {
1163 MEM_freeN(old_vert_arr);
1164 }
1165
1166 dst_material_index.finish();
1167
1168 return result;
1169}
1170
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
@ CD_SET_DEFAULT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
#define ORIGINDEX_NONE
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
MDeformWeight * BKE_defvert_ensure_index(MDeformVert *dv, int defgroup)
Definition deform.cc:814
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:543
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
#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
#define BLI_INLINE
MINLINE float max_ff(float a, float b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
#define M_PI
MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
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])
void copy_vn_fl(float *array_tar, int size, float val)
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3])
float angle_signed_on_axis_v3v3_v3(const float v1[3], const float v2[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT
void copy_vn_i(int *array_tar, int size, int val)
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_length(float n[3], float unit_length)
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define CLAMP(a, b, c)
#define ELEM(...)
#define LIKELY(x)
#define STACK_PUSH(stack, val)
#define STACK_DECLARE(stack)
#define STACK_SIZE(stack)
#define STACK_INIT(stack, stack_num)
@ CD_PROP_FLOAT
@ MOD_SOLIDIFY_RIM
@ MOD_SOLIDIFY_FLIP
@ MOD_SOLIDIFY_NORMAL_CALC
@ MOD_SOLIDIFY_EVEN
@ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP
@ MOD_SOLIDIFY_VGROUP_INV
@ MOD_SOLIDIFY_NOSHELL
Object is a sort of wrapper for general info.
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:125
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
Mesh * MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
#define INVALID_UNUSED
#define USE_NONMANIFOLD_WORKAROUND
#define INVALID_PAIR
#define INIT_VERT_ARRAY_OFFSETS(test)
static void mesh_calc_hq_normal(Mesh *mesh, const blender::Span< blender::float3 > face_normals, float(*r_vert_nors)[3], BLI_bitmap *edge_tmp_tag)
void MOD_get_vgroup(const Object *ob, const Mesh *mesh, const char *name, const MDeformVert **dvert, int *defgrp_index)
Definition MOD_util.cc:159
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:608
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:630
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
#define cosf(x)
#define fabsf(x)
#define sqrtf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define FLT_MAX
Definition stdcycles.h:14
__int64 int64_t
Definition stdint.h:89