Blender V4.3
blenkernel/intern/mesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <optional>
10
11#include "MEM_guardedalloc.h"
12
13/* Allow using deprecated functionality for .blend file I/O. */
14#define DNA_DEPRECATED_ALLOW
15
16#include "DNA_defaults.h"
17#include "DNA_key_types.h"
18#include "DNA_material_types.h"
19#include "DNA_mesh_types.h"
20#include "DNA_meshdata_types.h"
21#include "DNA_object_types.h"
22
23#include "BLI_bounds.hh"
24#include "BLI_endian_switch.h"
25#include "BLI_ghash.h"
26#include "BLI_hash.h"
28#include "BLI_index_range.hh"
29#include "BLI_linklist.h"
30#include "BLI_listbase.h"
31#include "BLI_math_matrix.h"
32#include "BLI_math_vector.hh"
33#include "BLI_memarena.h"
34#include "BLI_memory_counter.hh"
35#include "BLI_ordered_edge.hh"
36#include "BLI_resource_scope.hh"
37#include "BLI_set.hh"
38#include "BLI_span.hh"
39#include "BLI_string.h"
40#include "BLI_task.hh"
41#include "BLI_time.h"
42#include "BLI_utildefines.h"
43#include "BLI_vector.hh"
44#include "BLI_virtual_array.hh"
45
46#include "BLT_translation.hh"
47
48#include "BKE_anim_data.hh"
49#include "BKE_attribute.hh"
51#include "BKE_bpath.hh"
52#include "BKE_deform.hh"
53#include "BKE_editmesh.hh"
54#include "BKE_editmesh_cache.hh"
55#include "BKE_global.hh"
56#include "BKE_idtype.hh"
57#include "BKE_key.hh"
58#include "BKE_lib_id.hh"
59#include "BKE_lib_query.hh"
60#include "BKE_main.hh"
61#include "BKE_material.h"
62#include "BKE_mesh.hh"
64#include "BKE_mesh_runtime.hh"
65#include "BKE_mesh_wrapper.hh"
66#include "BKE_modifier.hh"
67#include "BKE_multires.hh"
68#include "BKE_object.hh"
69
70#include "DEG_depsgraph.hh"
72
73#include "BLO_read_write.hh"
74
75using blender::float3;
76using blender::int2;
79using blender::Span;
81using blender::VArray;
82using blender::Vector;
83
84static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
85
86static void mesh_init_data(ID *id)
87{
88 Mesh *mesh = reinterpret_cast<Mesh *>(id);
89
91
93
94 CustomData_reset(&mesh->vert_data);
95 CustomData_reset(&mesh->edge_data);
96 CustomData_reset(&mesh->fdata_legacy);
97 CustomData_reset(&mesh->face_data);
98 CustomData_reset(&mesh->corner_data);
99
100 mesh->runtime = new blender::bke::MeshRuntime();
101
102 mesh->face_sets_color_seed = BLI_hash_int(BLI_time_now_seconds_i() & UINT_MAX);
103}
104
105static void mesh_copy_data(Main *bmain,
106 std::optional<Library *> owner_library,
107 ID *id_dst,
108 const ID *id_src,
109 const int flag)
110{
111 Mesh *mesh_dst = reinterpret_cast<Mesh *>(id_dst);
112 const Mesh *mesh_src = reinterpret_cast<const Mesh *>(id_src);
113
114 mesh_dst->runtime = new blender::bke::MeshRuntime();
115 mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
116 mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type;
117 mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
118 mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
119 /* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or
120 * node, but we still need to be able to draw face center vertices and "optimal edges"
121 * differently. The tags may be cleared explicitly when the topology is changed. */
122 mesh_dst->runtime->subsurf_face_dot_tags = mesh_src->runtime->subsurf_face_dot_tags;
123 mesh_dst->runtime->subsurf_optimal_display_edges =
124 mesh_src->runtime->subsurf_optimal_display_edges;
125 if ((mesh_src->id.tag & ID_TAG_NO_MAIN) == 0) {
126 /* This is a direct copy of a main mesh, so for now it has the same topology. */
127 mesh_dst->runtime->deformed_only = true;
128 }
129 /* This option is set for run-time meshes that have been copied from the current object's mode.
130 * Currently this is used for edit-mesh although it could be used for sculpt or other
131 * kinds of data specific to an object's mode.
132 *
133 * The flag signals that the mesh hasn't been modified from the data that generated it,
134 * allowing us to use the object-mode data for drawing.
135 *
136 * While this could be the caller's responsibility, keep here since it's
137 * highly unlikely we want to create a duplicate and not use it for drawing. */
138 mesh_dst->runtime->is_original_bmesh = false;
139
140 /* Share various derived caches between the source and destination mesh for improved performance
141 * when the source is persistent and edits to the destination mesh don't affect the caches.
142 * Caches will be "un-shared" as necessary later on. */
143 mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache;
144 mesh_dst->runtime->vert_normals_cache = mesh_src->runtime->vert_normals_cache;
145 mesh_dst->runtime->face_normals_cache = mesh_src->runtime->face_normals_cache;
146 mesh_dst->runtime->corner_normals_cache = mesh_src->runtime->corner_normals_cache;
147 mesh_dst->runtime->loose_verts_cache = mesh_src->runtime->loose_verts_cache;
148 mesh_dst->runtime->verts_no_face_cache = mesh_src->runtime->verts_no_face_cache;
149 mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
150 mesh_dst->runtime->corner_tris_cache = mesh_src->runtime->corner_tris_cache;
151 mesh_dst->runtime->corner_tri_faces_cache = mesh_src->runtime->corner_tri_faces_cache;
152 mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache;
153 mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache;
154 mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache;
155 mesh_dst->runtime->corner_to_face_map_cache = mesh_src->runtime->corner_to_face_map_cache;
156 if (mesh_src->runtime->bake_materials) {
157 mesh_dst->runtime->bake_materials = std::make_unique<blender::bke::bake::BakeMaterialsList>(
158 *mesh_src->runtime->bake_materials);
159 }
160
161 /* Only do tessface if we have no faces. */
162 const bool do_tessface = ((mesh_src->totface_legacy != 0) && (mesh_src->faces_num == 0));
163
165
166 if (mesh_src->id.tag & ID_TAG_NO_MAIN) {
167 /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */
169 }
170
171 mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat);
172
174 mesh_dst->active_color_attribute = static_cast<char *>(
176 mesh_dst->default_color_attribute = static_cast<char *>(
178
180 &mesh_src->vert_data, &mesh_dst->vert_data, mask.vmask, mesh_dst->verts_num);
182 &mesh_src->edge_data, &mesh_dst->edge_data, mask.emask, mesh_dst->edges_num);
184 &mesh_src->corner_data, &mesh_dst->corner_data, mask.lmask, mesh_dst->corners_num);
186 &mesh_src->face_data, &mesh_dst->face_data, mask.pmask, mesh_dst->faces_num);
188 mesh_src->runtime->face_offsets_sharing_info,
189 &mesh_dst->face_offset_indices,
190 &mesh_dst->runtime->face_offsets_sharing_info);
191 if (do_tessface) {
193 &mesh_src->fdata_legacy, &mesh_dst->fdata_legacy, mask.fmask, mesh_dst->totface_legacy);
194 }
195 else {
196 mesh_tessface_clear_intern(mesh_dst, false);
197 }
198
199 mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
200
201 if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
202 BKE_id_copy_in_lib(bmain,
203 owner_library,
204 &mesh_src->key->id,
205 &mesh_dst->id,
206 reinterpret_cast<ID **>(&mesh_dst->key),
207 flag);
208 }
209}
210
212{
213 mesh->runtime->edit_mesh.reset();
214}
215
216static void mesh_free_data(ID *id)
217{
218 Mesh *mesh = reinterpret_cast<Mesh *>(id);
219
221
223 MEM_SAFE_FREE(mesh->mat);
224
225 delete mesh->runtime;
226}
227
229{
230 Mesh *mesh = reinterpret_cast<Mesh *>(id);
232
235 for (int i = 0; i < mesh->totcol; i++) {
237 }
238
241 }
242}
243
244static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
245{
246 Mesh *mesh = reinterpret_cast<Mesh *>(id);
247 if (mesh->corner_data.external) {
249 mesh->corner_data.external->filepath,
250 sizeof(mesh->corner_data.external->filepath));
251 }
252}
253
254static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
255{
256 using namespace blender;
257 using namespace blender::bke;
258 Mesh *mesh = reinterpret_cast<Mesh *>(id);
259 const bool is_undo = BLO_write_is_undo(writer);
260
261 Vector<CustomDataLayer, 16> vert_layers;
262 Vector<CustomDataLayer, 16> edge_layers;
263 Vector<CustomDataLayer, 16> loop_layers;
264 Vector<CustomDataLayer, 16> face_layers;
265
266 /* Cache only - don't write. */
267 mesh->mface = nullptr;
268 mesh->totface_legacy = 0;
269 memset(&mesh->fdata_legacy, 0, sizeof(mesh->fdata_legacy));
270
271 /* Do not store actual geometry data in case this is a library override ID. */
272 if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
273 mesh->verts_num = 0;
274 memset(&mesh->vert_data, 0, sizeof(mesh->vert_data));
275
276 mesh->edges_num = 0;
277 memset(&mesh->edge_data, 0, sizeof(mesh->edge_data));
278
279 mesh->corners_num = 0;
280 memset(&mesh->corner_data, 0, sizeof(mesh->corner_data));
281
282 mesh->faces_num = 0;
283 memset(&mesh->face_data, 0, sizeof(mesh->face_data));
284 mesh->face_offset_indices = nullptr;
285 }
286 else {
287 CustomData_blend_write_prepare(mesh->vert_data, vert_layers, {});
288 CustomData_blend_write_prepare(mesh->edge_data, edge_layers, {});
289 CustomData_blend_write_prepare(mesh->corner_data, loop_layers, {});
290 CustomData_blend_write_prepare(mesh->face_data, face_layers, {});
291 if (!is_undo) {
292 mesh_sculpt_mask_to_legacy(vert_layers);
293 }
294 }
295
296 const blender::bke::MeshRuntime *mesh_runtime = mesh->runtime;
297 mesh->runtime = nullptr;
298
299 BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
300 BKE_id_blend_write(writer, &mesh->id);
301
302 BKE_defbase_blend_write(writer, &mesh->vertex_group_names);
303 BLO_write_string(writer, mesh->active_color_attribute);
304 BLO_write_string(writer, mesh->default_color_attribute);
305
306 BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
307 BLO_write_struct_array(writer, MSelect, mesh->totselect, mesh->mselect);
308
310 writer, &mesh->vert_data, vert_layers, mesh->verts_num, CD_MASK_MESH.vmask, &mesh->id);
312 writer, &mesh->edge_data, edge_layers, mesh->edges_num, CD_MASK_MESH.emask, &mesh->id);
313 /* `fdata` is cleared above but written so slots align. */
315 writer, &mesh->fdata_legacy, {}, mesh->totface_legacy, CD_MASK_MESH.fmask, &mesh->id);
317 writer, &mesh->corner_data, loop_layers, mesh->corners_num, CD_MASK_MESH.lmask, &mesh->id);
319 writer, &mesh->face_data, face_layers, mesh->faces_num, CD_MASK_MESH.pmask, &mesh->id);
320
321 if (mesh->face_offset_indices) {
323 writer,
324 mesh->face_offset_indices,
325 sizeof(int) * mesh->faces_num,
326 mesh_runtime->face_offsets_sharing_info,
327 [&]() { BLO_write_int32_array(writer, mesh->faces_num + 1, mesh->face_offset_indices); });
328 }
329}
330
331static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
332{
333 Mesh *mesh = reinterpret_cast<Mesh *>(id);
334 BLO_read_pointer_array(reader, mesh->totcol, (void **)&mesh->mat);
335 /* This check added for python created meshes. */
336 if (!mesh->mat) {
337 mesh->totcol = 0;
338 }
339
340 /* Deprecated pointers to custom data layers are read here for backward compatibility
341 * with files where these were owning pointers rather than a view into custom data. */
342 BLO_read_struct_array(reader, MVert, mesh->verts_num, &mesh->mvert);
343 BLO_read_struct_array(reader, MEdge, mesh->edges_num, &mesh->medge);
344 BLO_read_struct_array(reader, MFace, mesh->totface_legacy, &mesh->mface);
345 BLO_read_struct_array(reader, MTFace, mesh->totface_legacy, &mesh->mtface);
346 BLO_read_struct_array(reader, MDeformVert, mesh->verts_num, &mesh->dvert);
347 BLO_read_struct_array(reader, TFace, mesh->totface_legacy, &mesh->tface);
348 BLO_read_struct_array(reader, MCol, mesh->totface_legacy, &mesh->mcol);
349
350 BLO_read_struct_array(reader, MSelect, mesh->totselect, &mesh->mselect);
351
352 BLO_read_struct_list(reader, bDeformGroup, &mesh->vertex_group_names);
353
354 CustomData_blend_read(reader, &mesh->vert_data, mesh->verts_num);
355 CustomData_blend_read(reader, &mesh->edge_data, mesh->edges_num);
356 CustomData_blend_read(reader, &mesh->fdata_legacy, mesh->totface_legacy);
357 CustomData_blend_read(reader, &mesh->corner_data, mesh->corners_num);
358 CustomData_blend_read(reader, &mesh->face_data, mesh->faces_num);
359 if (mesh->deform_verts().is_empty()) {
360 /* Vertex group data was also an owning pointer in old Blender versions.
361 * Don't read them again if they were read as part of #CustomData. */
362 BKE_defvert_blend_read(reader, mesh->verts_num, mesh->dvert);
363 }
364 BLO_read_string(reader, &mesh->active_color_attribute);
365 BLO_read_string(reader, &mesh->default_color_attribute);
366
367 mesh->texspace_flag &= ~ME_TEXSPACE_FLAG_AUTO_EVALUATED;
368
369 mesh->runtime = new blender::bke::MeshRuntime();
370
371 if (mesh->face_offset_indices) {
372 mesh->runtime->face_offsets_sharing_info = BLO_read_shared(
373 reader, &mesh->face_offset_indices, [&]() {
374 BLO_read_int32_array(reader, mesh->faces_num + 1, &mesh->face_offset_indices);
375 return blender::implicit_sharing::info_for_mem_free(mesh->face_offset_indices);
376 });
377 }
378
379 if (mesh->mselect == nullptr) {
380 mesh->totselect = 0;
381 }
382
383 if (BLO_read_requires_endian_switch(reader) && mesh->tface) {
384 TFace *tf = mesh->tface;
385 for (int i = 0; i < mesh->totface_legacy; i++, tf++) {
387 }
388 }
389}
390
392 /*id_code*/ ID_ME,
393 /*id_filter*/ FILTER_ID_ME,
394 /*dependencies_id_types*/ FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE,
395 /*main_listbase_index*/ INDEX_ID_ME,
396 /*struct_size*/ sizeof(Mesh),
397 /*name*/ "Mesh",
398 /*name_plural*/ N_("meshes"),
399 /*translation_context*/ BLT_I18NCONTEXT_ID_MESH,
401 /*asset_type_info*/ nullptr,
402
403 /*init_data*/ mesh_init_data,
404 /*copy_data*/ mesh_copy_data,
405 /*free_data*/ mesh_free_data,
406 /*make_local*/ nullptr,
407 /*foreach_id*/ mesh_foreach_id,
408 /*foreach_cache*/ nullptr,
409 /*foreach_path*/ mesh_foreach_path,
410 /*owner_pointer_get*/ nullptr,
411
412 /*blend_write*/ mesh_blend_write,
413 /*blend_read_data*/ mesh_blend_read_data,
414 /*blend_read_after_liblink*/ nullptr,
415
416 /*blend_read_undo_preserve*/ nullptr,
417
418 /*lib_override_apply_post*/ nullptr,
419};
420
421bool BKE_mesh_attribute_required(const char *name)
422{
423 return ELEM(StringRef(name), "position", ".corner_vert", ".corner_edge", ".edge_verts");
424}
425
427{
428 BMesh *bm = mesh->runtime->edit_mesh ? mesh->runtime->edit_mesh->bm : nullptr;
429 MVertSkin *vs;
430
431 if (bm) {
433 BMVert *v;
434 BMIter iter;
435
437
438 /* Mark an arbitrary vertex as root */
439 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
441 vs->flag |= MVERT_SKIN_ROOT;
442 break;
443 }
444 }
445 }
446 else {
447 if (!CustomData_has_layer(&mesh->vert_data, CD_MVERT_SKIN)) {
449 &mesh->vert_data, CD_MVERT_SKIN, CD_SET_DEFAULT, mesh->verts_num);
450
451 /* Mark an arbitrary vertex as root */
452 if (vs) {
453 vs->flag |= MVERT_SKIN_ROOT;
454 }
455 }
456 }
457}
458
460{
461 if (mesh->runtime->edit_mesh) {
462 return CustomData_has_layer(&mesh->runtime->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL);
463 }
464
465 return CustomData_has_layer(&mesh->corner_data, CD_CUSTOMLOOPNORMAL);
466}
467
468namespace blender::bke {
469
471 const StringRef id,
472 AttrDomain domain,
473 eCustomDataType data_type)
474{
476 return;
477 }
478 if (!(CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) ||
480 {
481 return;
482 }
483 if (mesh.default_color_attribute) {
484 return;
485 }
486 mesh.default_color_attribute = BLI_strdupn(id.data(), id.size());
487}
488
490{
491 MutableAttributeAccessor attributes = mesh.attributes_for_write();
492 AttributeInitConstruct attribute_init;
493
494 /* Try to create attributes if they do not exist. */
495 attributes.add("position", AttrDomain::Point, CD_PROP_FLOAT3, attribute_init);
496 attributes.add(".edge_verts", AttrDomain::Edge, CD_PROP_INT32_2D, attribute_init);
497 attributes.add(".corner_vert", AttrDomain::Corner, CD_PROP_INT32, attribute_init);
498 attributes.add(".corner_edge", AttrDomain::Corner, CD_PROP_INT32, attribute_init);
499}
500
501} // namespace blender::bke
502
504{
505 mesh_free_data(&mesh->id);
506}
507
520static void mesh_clear_geometry(Mesh &mesh)
521{
522 CustomData_free(&mesh.vert_data, mesh.verts_num);
523 CustomData_free(&mesh.edge_data, mesh.edges_num);
524 CustomData_free(&mesh.fdata_legacy, mesh.totface_legacy);
525 CustomData_free(&mesh.corner_data, mesh.corners_num);
526 CustomData_free(&mesh.face_data, mesh.faces_num);
527 if (mesh.face_offset_indices) {
528 blender::implicit_sharing::free_shared_data(&mesh.face_offset_indices,
529 &mesh.runtime->face_offsets_sharing_info);
530 }
531 MEM_SAFE_FREE(mesh.mselect);
532
533 mesh.verts_num = 0;
534 mesh.edges_num = 0;
535 mesh.totface_legacy = 0;
536 mesh.corners_num = 0;
537 mesh.faces_num = 0;
538 mesh.act_face = -1;
539 mesh.totselect = 0;
540}
541
542static void clear_attribute_names(Mesh &mesh)
543{
544 BLI_freelistN(&mesh.vertex_group_names);
545 MEM_SAFE_FREE(mesh.active_color_attribute);
546 MEM_SAFE_FREE(mesh.default_color_attribute);
547}
548
554
561
562static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
563{
564 if (free_customdata) {
565 CustomData_free(&mesh->fdata_legacy, mesh->totface_legacy);
566 }
567 else {
568 CustomData_reset(&mesh->fdata_legacy);
569 }
570
571 mesh->totface_legacy = 0;
572}
573
574Mesh *BKE_mesh_add(Main *bmain, const char *name)
575{
576 return static_cast<Mesh *>(BKE_id_new(bmain, ID_ME, name));
577}
578
580{
581 BLI_assert(mesh->face_offset_indices == nullptr);
582 BLI_assert(mesh->runtime->face_offsets_sharing_info == nullptr);
583 if (mesh->faces_num == 0) {
584 return;
585 }
586 mesh->face_offset_indices = static_cast<int *>(
587 MEM_malloc_arrayN(mesh->faces_num + 1, sizeof(int), __func__));
588 mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
589 mesh->face_offset_indices);
590
591#ifndef NDEBUG
592 /* Fill offsets with obviously bad values to simplify finding missing initialization. */
593 mesh->face_offsets_for_write().fill(-1);
594#endif
595 /* Set common values for convenience. */
596 mesh->face_offset_indices[0] = 0;
597 mesh->face_offset_indices[mesh->faces_num] = mesh->corners_num;
598}
599
600Span<float3> Mesh::vert_positions() const
601{
602 return {static_cast<const float3 *>(
604 this->verts_num};
605}
606MutableSpan<float3> Mesh::vert_positions_for_write()
607{
608 return {static_cast<float3 *>(CustomData_get_layer_named_for_write(
609 &this->vert_data, CD_PROP_FLOAT3, "position", this->verts_num)),
610 this->verts_num};
611}
612
613Span<int2> Mesh::edges() const
614{
615 return {static_cast<const int2 *>(
617 this->edges_num};
618}
619MutableSpan<int2> Mesh::edges_for_write()
620{
621 return {static_cast<int2 *>(CustomData_get_layer_named_for_write(
622 &this->edge_data, CD_PROP_INT32_2D, ".edge_verts", this->edges_num)),
623 this->edges_num};
624}
625
626OffsetIndices<int> Mesh::faces() const
627{
628 return Span(this->face_offset_indices, this->faces_num + 1);
629}
630Span<int> Mesh::face_offsets() const
631{
632 if (this->faces_num == 0) {
633 return {};
634 }
635 return {this->face_offset_indices, this->faces_num + 1};
636}
637MutableSpan<int> Mesh::face_offsets_for_write()
638{
639 if (this->faces_num == 0) {
640 return {};
641 }
643 &this->face_offset_indices, &this->runtime->face_offsets_sharing_info, this->faces_num + 1);
644 return {this->face_offset_indices, this->faces_num + 1};
645}
646
647Span<int> Mesh::corner_verts() const
648{
649 return {static_cast<const int *>(
650 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_vert")),
651 this->corners_num};
652}
653MutableSpan<int> Mesh::corner_verts_for_write()
654{
655 return {static_cast<int *>(CustomData_get_layer_named_for_write(
656 &this->corner_data, CD_PROP_INT32, ".corner_vert", this->corners_num)),
657 this->corners_num};
658}
659
660Span<int> Mesh::corner_edges() const
661{
662 return {static_cast<const int *>(
663 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_edge")),
664 this->corners_num};
665}
666MutableSpan<int> Mesh::corner_edges_for_write()
667{
668 return {static_cast<int *>(CustomData_get_layer_named_for_write(
669 &this->corner_data, CD_PROP_INT32, ".corner_edge", this->corners_num)),
670 this->corners_num};
671}
672
673Span<MDeformVert> Mesh::deform_verts() const
674{
675 const MDeformVert *dverts = static_cast<const MDeformVert *>(
677 if (!dverts) {
678 return {};
679 }
680 return {dverts, this->verts_num};
681}
682MutableSpan<MDeformVert> Mesh::deform_verts_for_write()
683{
684 MDeformVert *dvert = static_cast<MDeformVert *>(
686 if (dvert) {
687 return {dvert, this->verts_num};
688 }
689 return {static_cast<MDeformVert *>(CustomData_add_layer(
691 this->verts_num};
692}
693
694void Mesh::count_memory(blender::MemoryCounter &memory) const
695{
696 memory.add_shared(this->runtime->face_offsets_sharing_info,
697 this->face_offsets().size_in_bytes());
698 CustomData_count_memory(this->vert_data, this->verts_num, memory);
699 CustomData_count_memory(this->edge_data, this->edges_num, memory);
700 CustomData_count_memory(this->face_data, this->faces_num, memory);
701 CustomData_count_memory(this->corner_data, this->corners_num, memory);
702}
703
704Mesh *BKE_mesh_new_nomain(const int verts_num,
705 const int edges_num,
706 const int faces_num,
707 const int corners_num)
708{
709 Mesh *mesh = static_cast<Mesh *>(BKE_libblock_alloc(
711 BKE_libblock_init_empty(&mesh->id);
712
713 mesh->verts_num = verts_num;
714 mesh->edges_num = edges_num;
715 mesh->faces_num = faces_num;
716 mesh->corners_num = corners_num;
717
720
721 return mesh;
722}
723
724namespace blender::bke {
725
726Mesh *mesh_new_no_attributes(const int verts_num,
727 const int edges_num,
728 const int faces_num,
729 const int corners_num)
730{
731 Mesh *mesh = BKE_mesh_new_nomain(0, 0, faces_num, 0);
732 mesh->verts_num = verts_num;
733 mesh->edges_num = edges_num;
734 mesh->corners_num = corners_num;
735 CustomData_free_layer_named(&mesh->vert_data, "position", 0);
736 CustomData_free_layer_named(&mesh->edge_data, ".edge_verts", 0);
737 CustomData_free_layer_named(&mesh->corner_data, ".corner_vert", 0);
738 CustomData_free_layer_named(&mesh->corner_data, ".corner_edge", 0);
739 return mesh;
740}
741
742} // namespace blender::bke
743
744static void copy_attribute_names(const Mesh &mesh_src, Mesh &mesh_dst)
745{
746 if (mesh_src.active_color_attribute) {
749 }
750 if (mesh_src.default_color_attribute) {
753 }
754}
755
756void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
757{
758 /* Copy general settings. */
759 me_dst->editflag = me_src->editflag;
760 me_dst->flag = me_src->flag;
761 me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
763 me_dst->remesh_mode = me_src->remesh_mode;
764 me_dst->symmetry = me_src->symmetry;
765
768
769 /* Copy texture space. */
770 me_dst->texspace_flag = me_src->texspace_flag;
772 copy_v3_v3(me_dst->texspace_size, me_src->texspace_size);
773
776}
777
778void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
779{
780 /* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
782
783 BKE_mesh_copy_parameters(me_dst, me_src);
784 copy_attribute_names(*me_src, *me_dst);
785
786 /* Copy vertex group names. */
789
790 /* Copy materials. */
791 if (me_dst->mat != nullptr) {
792 MEM_freeN(me_dst->mat);
793 }
794 me_dst->mat = (Material **)MEM_dupallocN(me_src->mat);
795 me_dst->totcol = me_src->totcol;
796}
797
799 const int verts_num,
800 const int edges_num,
801 const int tessface_num,
802 const int faces_num,
803 const int corners_num,
804 const CustomData_MeshMasks mask)
805{
806 /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
807 const bool do_tessface = (tessface_num ||
808 ((me_src->totface_legacy != 0) && (me_src->faces_num == 0)));
809
810 Mesh *me_dst = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
811
812 me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect);
813
814 me_dst->verts_num = verts_num;
815 me_dst->edges_num = edges_num;
816 me_dst->faces_num = faces_num;
817 me_dst->corners_num = corners_num;
818 me_dst->totface_legacy = tessface_num;
819
820 BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
821
823 &me_src->vert_data, &me_dst->vert_data, mask.vmask, CD_SET_DEFAULT, verts_num);
825 &me_src->edge_data, &me_dst->edge_data, mask.emask, CD_SET_DEFAULT, edges_num);
827 &me_src->face_data, &me_dst->face_data, mask.pmask, CD_SET_DEFAULT, faces_num);
829 &me_src->corner_data, &me_dst->corner_data, mask.lmask, CD_SET_DEFAULT, corners_num);
830 if (do_tessface) {
832 &me_src->fdata_legacy, &me_dst->fdata_legacy, mask.fmask, CD_SET_DEFAULT, tessface_num);
833 }
834 else {
835 mesh_tessface_clear_intern(me_dst, false);
836 }
837
838 /* The destination mesh should at least have valid primary CD layers,
839 * even in cases where the source mesh does not. */
842 if (do_tessface && !CustomData_get_layer(&me_dst->fdata_legacy, CD_MFACE)) {
844 }
845
846 return me_dst;
847}
848
850 const int verts_num,
851 const int edges_num,
852 const int faces_num,
853 const int corners_num)
854{
856 me_src, verts_num, edges_num, 0, faces_num, corners_num, CD_MASK_EVERYTHING);
857}
858
860{
861 return reinterpret_cast<Mesh *>(
862 BKE_id_copy_ex(nullptr, &source.id, nullptr, LIB_ID_COPY_LOCALIZE));
863}
864
866 const BMeshCreateParams *create_params,
867 const BMeshFromMeshParams *convert_params)
868{
869 const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
870
871 BMesh *bm = BM_mesh_create(&allocsize, create_params);
872 BM_mesh_bm_from_me(bm, mesh, convert_params);
873
874 return bm;
875}
876
878 Object *ob,
879 const bool add_key_index,
881{
882 BMeshFromMeshParams bmesh_from_mesh_params{};
883 bmesh_from_mesh_params.calc_face_normal = false;
884 bmesh_from_mesh_params.calc_vert_normal = false;
885 bmesh_from_mesh_params.add_key_index = add_key_index;
886 bmesh_from_mesh_params.use_shapekey = true;
887 bmesh_from_mesh_params.active_shapekey = ob->shapenr;
888 return BKE_mesh_to_bmesh_ex(mesh, params, &bmesh_from_mesh_params);
889}
890
893 const Mesh *me_settings)
894{
895 BLI_assert(params->calc_object_remap == false);
896 Mesh *mesh = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
897 BM_mesh_bm_to_me(nullptr, bm, mesh, params);
898 BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
899 return mesh;
900}
901
903 const CustomData_MeshMasks *cd_mask_extra,
904 const Mesh *me_settings)
905{
906 Mesh *mesh = static_cast<Mesh *>(BKE_id_new_nomain(ID_ME, nullptr));
907 BM_mesh_bm_to_me_for_eval(*bm, *mesh, cd_mask_extra);
908 BKE_mesh_copy_parameters_for_eval(mesh, me_settings);
909 return mesh;
910}
911
912static void ensure_orig_index_layer(CustomData &data, const int size)
913{
915 return;
916 }
917 int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, size);
918 range_vn_i(indices, size, 0);
919}
920
926
928{
929 ensure_orig_index_layer(mesh->vert_data, mesh->verts_num);
930 ensure_orig_index_layer(mesh->edge_data, mesh->edges_num);
931 ensure_orig_index_layer(mesh->face_data, mesh->faces_num);
932}
933
935{
936 using namespace blender;
937 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) {
938 const Bounds<float3> bounds = mesh->bounds_min_max().value_or(
939 Bounds(float3(-1.0f), float3(1.0f)));
940
941 float texspace_location[3], texspace_size[3];
942 mid_v3_v3v3(texspace_location, bounds.min, bounds.max);
943
944 texspace_size[0] = (bounds.max[0] - bounds.min[0]) / 2.0f;
945 texspace_size[1] = (bounds.max[1] - bounds.min[1]) / 2.0f;
946 texspace_size[2] = (bounds.max[2] - bounds.min[2]) / 2.0f;
947
948 for (int a = 0; a < 3; a++) {
949 if (texspace_size[a] == 0.0f) {
950 texspace_size[a] = 1.0f;
951 }
952 else if (texspace_size[a] > 0.0f && texspace_size[a] < 0.00001f) {
953 texspace_size[a] = 0.00001f;
954 }
955 else if (texspace_size[a] < 0.0f && texspace_size[a] > -0.00001f) {
956 texspace_size[a] = -0.00001f;
957 }
958 }
959
960 copy_v3_v3(mesh->texspace_location, texspace_location);
961 copy_v3_v3(mesh->texspace_size, texspace_size);
962
963 mesh->texspace_flag |= ME_TEXSPACE_FLAG_AUTO_EVALUATED;
964 }
965}
966
968{
969 if ((mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) &&
970 !(mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED))
971 {
973 }
974}
975
976void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
977{
979
980 if (r_texspace_location) {
981 copy_v3_v3(r_texspace_location, mesh->texspace_location);
982 }
983 if (r_texspace_size) {
984 copy_v3_v3(r_texspace_size, mesh->texspace_size);
985 }
986}
987
989 char **r_texspace_flag,
990 float **r_texspace_location,
991 float **r_texspace_size)
992{
994
995 if (r_texspace_flag != nullptr) {
996 *r_texspace_flag = &mesh->texspace_flag;
997 }
998 if (r_texspace_location != nullptr) {
999 *r_texspace_location = mesh->texspace_location;
1000 }
1001 if (r_texspace_size != nullptr) {
1002 *r_texspace_size = mesh->texspace_size;
1003 }
1004}
1005
1007{
1008 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
1009 const Mesh *tme = mesh->texcomesh ? mesh->texcomesh : mesh;
1010
1011 blender::Array<float3> result(mesh->verts_num);
1012 const Span<float3> positions = tme->vert_positions();
1013 result.as_mutable_span().take_front(positions.size()).copy_from(positions);
1014 result.as_mutable_span().drop_front(positions.size()).fill(float3(0));
1015
1016 return result;
1017}
1018
1020{
1021 float texspace_location[3], texspace_size[3];
1022
1024 mesh->texcomesh ? mesh->texcomesh : mesh, texspace_location, texspace_size);
1025
1026 if (invert) {
1027 for (const int a : orco.index_range()) {
1028 float3 &co = orco[a];
1029 madd_v3_v3v3v3(co, texspace_location, co, texspace_size);
1030 }
1031 }
1032 else {
1033 for (const int a : orco.index_range()) {
1034 float3 &co = orco[a];
1035 co[0] = (co[0] - texspace_location[0]) / texspace_size[0];
1036 co[1] = (co[1] - texspace_location[1]) / texspace_size[1];
1037 co[2] = (co[2] - texspace_location[2]) / texspace_size[2];
1038 }
1039 }
1040}
1041
1042void BKE_mesh_orco_verts_transform(Mesh *mesh, float (*orco)[3], int totvert, bool invert)
1043{
1044 BKE_mesh_orco_verts_transform(mesh, {reinterpret_cast<float3 *>(orco), totvert}, invert);
1045}
1046
1048{
1049 if (CustomData_has_layer(&mesh->vert_data, CD_ORCO)) {
1050 return;
1051 }
1052
1053 /* Orcos are stored in normalized 0..1 range by convention. */
1055 BKE_mesh_orco_verts_transform(mesh, orcodata, false);
1056 float3 *data = static_cast<float3 *>(
1057 CustomData_add_layer(&mesh->vert_data, CD_ORCO, CD_CONSTRUCT, mesh->verts_num));
1058 MutableSpan(data, mesh->verts_num).copy_from(orcodata);
1059}
1060
1062{
1063 if (ob == nullptr) {
1064 return nullptr;
1065 }
1066 if (ob->type == OB_MESH) {
1067 return static_cast<Mesh *>(ob->data);
1068 }
1069
1070 return nullptr;
1071}
1072
1073void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *mesh)
1074{
1075 Mesh *old = nullptr;
1076
1077 if (ob == nullptr) {
1078 return;
1079 }
1080
1082
1083 if (ob->type == OB_MESH) {
1084 old = static_cast<Mesh *>(ob->data);
1085 if (old) {
1086 id_us_min(&old->id);
1087 }
1088 ob->data = mesh;
1089 id_us_plus((ID *)mesh);
1090 }
1091
1092 BKE_object_materials_test(bmain, ob, (ID *)mesh);
1093
1095}
1096
1097void BKE_mesh_material_index_remove(Mesh *mesh, short index)
1098{
1099 using namespace blender;
1100 using namespace blender::bke;
1101 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1102 AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
1103 if (!material_indices) {
1104 return;
1105 }
1106 if (material_indices.domain != AttrDomain::Face) {
1108 return;
1109 }
1110 MutableVArraySpan<int> indices_span(material_indices.varray);
1111 for (const int i : indices_span.index_range()) {
1112 if (indices_span[i] > 0 && indices_span[i] >= index) {
1113 indices_span[i]--;
1114 }
1115 }
1116 indices_span.save();
1117 material_indices.finish();
1118
1120}
1121
1122bool BKE_mesh_material_index_used(Mesh *mesh, short index)
1123{
1124 using namespace blender;
1125 using namespace blender::bke;
1126 const AttributeAccessor attributes = mesh->attributes();
1127 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
1128 "material_index", AttrDomain::Face, 0);
1129 if (material_indices.is_single()) {
1130 return material_indices.get_internal_single() == index;
1131 }
1132 const VArraySpan<int> indices_span(material_indices);
1133 return indices_span.contains(index);
1134}
1135
1137{
1138 using namespace blender;
1139 using namespace blender::bke;
1140 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1141 attributes.remove("material_index");
1142
1144}
1145
1146void BKE_mesh_material_remap(Mesh *mesh, const uint *remap, uint remap_len)
1147{
1148 using namespace blender;
1149 using namespace blender::bke;
1150 const short remap_len_short = short(remap_len);
1151
1152#define MAT_NR_REMAP(n) \
1153 if (n < remap_len_short) { \
1154 BLI_assert(n >= 0 && remap[n] < remap_len_short); \
1155 n = remap[n]; \
1156 } \
1157 ((void)0)
1158
1159 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1160 BMIter iter;
1161 BMFace *efa;
1162
1163 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1164 MAT_NR_REMAP(efa->mat_nr);
1165 }
1166 }
1167 else {
1168 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1169 SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
1170 "material_index", AttrDomain::Face);
1171 if (!material_indices) {
1172 return;
1173 }
1174 for (const int i : material_indices.span.index_range()) {
1175 MAT_NR_REMAP(material_indices.span[i]);
1176 }
1177 material_indices.span.save();
1178 material_indices.finish();
1179 }
1180
1181#undef MAT_NR_REMAP
1182}
1183
1184namespace blender::bke {
1185
1186void mesh_smooth_set(Mesh &mesh, const bool use_smooth, const bool keep_sharp_edges)
1187{
1188 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1189 if (!keep_sharp_edges) {
1190 attributes.remove("sharp_edge");
1191 }
1192 attributes.remove("sharp_face");
1193 if (!use_smooth) {
1194 attributes.add<bool>("sharp_face",
1196 AttributeInitVArray(VArray<bool>::ForSingle(true, mesh.faces_num)));
1197 }
1198}
1199
1200void mesh_sharp_edges_set_from_angle(Mesh &mesh, const float angle, const bool keep_sharp_edges)
1201{
1202 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1203 if (angle >= M_PI) {
1204 mesh_smooth_set(mesh, true, keep_sharp_edges);
1205 return;
1206 }
1207 if (angle == 0.0f) {
1208 mesh_smooth_set(mesh, false, keep_sharp_edges);
1209 return;
1210 }
1211 if (!keep_sharp_edges) {
1212 attributes.remove("sharp_edge");
1213 }
1214 SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
1215 "sharp_edge", AttrDomain::Edge);
1216 const VArraySpan<bool> sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
1218 mesh.corner_verts(),
1219 mesh.corner_edges(),
1220 mesh.face_normals(),
1221 mesh.corner_to_face_map(),
1222 sharp_faces,
1223 angle,
1224 sharp_edges.span);
1225 sharp_edges.finish();
1226}
1227
1228} // namespace blender::bke
1229
1230std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
1231{
1232 using namespace blender;
1233 const int verts_num = BKE_mesh_wrapper_vert_len(this);
1234 if (verts_num == 0) {
1235 return std::nullopt;
1236 }
1237 this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
1238 switch (this->runtime->wrapper_type) {
1239 case ME_WRAPPER_TYPE_BMESH:
1240 r_bounds = *BKE_editmesh_cache_calc_minmax(*this->runtime->edit_mesh,
1241 *this->runtime->edit_data);
1242 break;
1243 case ME_WRAPPER_TYPE_MDATA:
1244 case ME_WRAPPER_TYPE_SUBD:
1245 r_bounds = *bounds::min_max(this->vert_positions());
1246 break;
1247 }
1248 });
1249 return this->runtime->bounds_cache.data();
1250}
1251
1252void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)
1253{
1254 this->runtime->bounds_cache.ensure([&](blender::Bounds<float3> &r_data) { r_data = bounds; });
1255}
1256
1257void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys)
1258{
1259 MutableSpan<float3> positions = mesh->vert_positions_for_write();
1260
1261 for (float3 &position : positions) {
1262 mul_m4_v3(mat, position);
1263 }
1264
1265 if (do_keys && mesh->key) {
1266 LISTBASE_FOREACH (KeyBlock *, kb, &mesh->key->block) {
1267 float *fp = (float *)kb->data;
1268 for (int i = kb->totelem; i--; fp += 3) {
1269 mul_m4_v3(mat, fp);
1270 }
1271 }
1272 }
1273
1274 mesh->tag_positions_changed();
1275}
1276
1277static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
1278{
1279 using namespace blender;
1280 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
1281 for (float3 &position : positions.slice(range)) {
1282 position += translation;
1283 }
1284 });
1285}
1286
1287void BKE_mesh_translate(Mesh *mesh, const float offset[3], const bool do_keys)
1288{
1289 using namespace blender;
1290 if (math::is_zero(float3(offset))) {
1291 return;
1292 }
1293
1294 std::optional<Bounds<float3>> bounds;
1295 if (mesh->runtime->bounds_cache.is_cached()) {
1296 bounds = mesh->runtime->bounds_cache.data();
1297 }
1298
1299 translate_positions(mesh->vert_positions_for_write(), offset);
1300 if (do_keys && mesh->key) {
1301 LISTBASE_FOREACH (KeyBlock *, kb, &mesh->key->block) {
1302 translate_positions({static_cast<float3 *>(kb->data), kb->totelem}, offset);
1303 }
1304 }
1305
1306 mesh->tag_positions_changed_uniformly();
1307
1308 if (bounds) {
1309 bounds->min += offset;
1310 bounds->max += offset;
1311 mesh->bounds_set_eager(*bounds);
1312 }
1313}
1314
1316{
1317 mesh_tessface_clear_intern(mesh, true);
1318}
1319
1320/* -------------------------------------------------------------------- */
1321/* MSelect functions (currently used in weight paint mode) */
1322
1324{
1325 MEM_SAFE_FREE(mesh->mselect);
1326 mesh->totselect = 0;
1327}
1328
1330{
1331 using namespace blender;
1332 using namespace blender::bke;
1333 MSelect *mselect_src, *mselect_dst;
1334 int i_src, i_dst;
1335
1336 if (mesh->totselect == 0) {
1337 return;
1338 }
1339
1340 mselect_src = mesh->mselect;
1341 mselect_dst = (MSelect *)MEM_malloc_arrayN(
1342 (mesh->totselect), sizeof(MSelect), "Mesh selection history");
1343
1344 const AttributeAccessor attributes = mesh->attributes();
1345 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1346 ".select_vert", AttrDomain::Point, false);
1347 const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
1348 ".select_edge", AttrDomain::Edge, false);
1349 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
1350 ".select_poly", AttrDomain::Face, false);
1351
1352 for (i_src = 0, i_dst = 0; i_src < mesh->totselect; i_src++) {
1353 int index = mselect_src[i_src].index;
1354 switch (mselect_src[i_src].type) {
1355 case ME_VSEL: {
1356 if (select_vert[index]) {
1357 mselect_dst[i_dst] = mselect_src[i_src];
1358 i_dst++;
1359 }
1360 break;
1361 }
1362 case ME_ESEL: {
1363 if (select_edge[index]) {
1364 mselect_dst[i_dst] = mselect_src[i_src];
1365 i_dst++;
1366 }
1367 break;
1368 }
1369 case ME_FSEL: {
1370 if (select_poly[index]) {
1371 mselect_dst[i_dst] = mselect_src[i_src];
1372 i_dst++;
1373 }
1374 break;
1375 }
1376 default: {
1378 break;
1379 }
1380 }
1381 }
1382
1383 MEM_freeN(mselect_src);
1384
1385 if (i_dst == 0) {
1386 MEM_freeN(mselect_dst);
1387 mselect_dst = nullptr;
1388 }
1389 else if (i_dst != mesh->totselect) {
1390 mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
1391 }
1392
1393 mesh->totselect = i_dst;
1394 mesh->mselect = mselect_dst;
1395}
1396
1397int BKE_mesh_mselect_find(const Mesh *mesh, int index, int type)
1398{
1400
1401 for (int i = 0; i < mesh->totselect; i++) {
1402 if ((mesh->mselect[i].index == index) && (mesh->mselect[i].type == type)) {
1403 return i;
1404 }
1405 }
1406
1407 return -1;
1408}
1409
1410int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
1411{
1413
1414 if (mesh->totselect) {
1415 if (mesh->mselect[mesh->totselect - 1].type == type) {
1416 return mesh->mselect[mesh->totselect - 1].index;
1417 }
1418 }
1419 return -1;
1420}
1421
1422void BKE_mesh_mselect_active_set(Mesh *mesh, int index, int type)
1423{
1424 const int msel_index = BKE_mesh_mselect_find(mesh, index, type);
1425
1426 if (msel_index == -1) {
1427 /* add to the end */
1428 mesh->mselect = (MSelect *)MEM_reallocN(mesh->mselect,
1429 sizeof(MSelect) * (mesh->totselect + 1));
1430 mesh->mselect[mesh->totselect].index = index;
1431 mesh->mselect[mesh->totselect].type = type;
1432 mesh->totselect++;
1433 }
1434 else if (msel_index != mesh->totselect - 1) {
1435 /* move to the end */
1436 std::swap(mesh->mselect[msel_index], mesh->mselect[mesh->totselect - 1]);
1437 }
1438
1439 BLI_assert((mesh->mselect[mesh->totselect - 1].index == index) &&
1440 (mesh->mselect[mesh->totselect - 1].type == type));
1441}
1442
1443void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
1444{
1445 r_count[0] = r_count[1] = r_count[2] = 0;
1446 if (mesh->runtime->edit_mesh) {
1447 BMesh *bm = mesh->runtime->edit_mesh->bm;
1448 r_count[0] = bm->totvertsel;
1449 r_count[1] = bm->totedgesel;
1450 r_count[2] = bm->totfacesel;
1451 }
1452 /* We could support faces in paint modes. */
1453}
1454
1455/* **** Depsgraph evaluation **** */
1456
1458{
1459 DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
1461 /* We are here because something did change in the mesh. This means we can not trust the existing
1462 * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
1463 * evaluated mesh and let objects to re-create it with updated settings. */
1464 if (mesh->runtime->mesh_eval != nullptr) {
1465 BKE_id_free(nullptr, mesh->runtime->mesh_eval);
1466 mesh->runtime->mesh_eval = nullptr;
1467 }
1468 if (DEG_is_active(depsgraph)) {
1469 Mesh *mesh_orig = reinterpret_cast<Mesh *>(DEG_get_original_id(&mesh->id));
1470 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED) {
1472 copy_v3_v3(mesh_orig->texspace_location, mesh->texspace_location);
1473 copy_v3_v3(mesh_orig->texspace_size, mesh->texspace_size);
1474 }
1475 }
1476}
#define ATTR_DOMAIN_MASK_COLOR
#define ATTR_DOMAIN_AS_MASK(domain)
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:123
void CustomData_blend_write_prepare(CustomData &data, blender::Vector< CustomDataLayer, 16 > &layers_to_write, const blender::Set< std::string > &skip_names={})
void CustomData_count_memory(const CustomData &data, int totelem, blender::MemoryCounter &memory)
const CustomData_MeshMasks CD_MASK_EVERYTHING
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name, const int totelem)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
const void * CustomData_get_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
void CustomData_MeshMasks_update(CustomData_MeshMasks *mask_dst, const CustomData_MeshMasks *mask_src)
Definition customdata.cc:91
void CustomData_reset(CustomData *data)
void * CustomData_bmesh_get(const CustomData *data, void *block, eCustomDataType type)
void CustomData_blend_write(BlendWriter *writer, CustomData *data, blender::Span< CustomDataLayer > layers_to_write, int count, eCustomDataMask cddata_mask, ID *id)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
void CustomData_free(CustomData *data, int totelem)
void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
void CustomData_init_layout_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
const CustomData_MeshMasks CD_MASK_DERIVEDMESH
#define CD_TYPE_AS_MASK(_type)
const CustomData_MeshMasks CD_MASK_MESH
support for deformation groups and hooks.
void BKE_defbase_blend_write(BlendWriter *writer, const ListBase *defbase)
Definition deform.cc:1635
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:76
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1659
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1415
@ LIB_ID_CREATE_LOCALIZE
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_SHAPEKEY
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1420
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, const ID *new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:656
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1482
void id_us_min(ID *id)
Definition lib_id.cc:359
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER
int BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:120
@ IDWALK_DO_DEPRECATED_POINTERS
#define BKE_LIB_FOREACHID_PROCESS_ID_NOCHECK(data_, id_, cb_flag_)
General operations, lookup, etc. for materials.
void BKE_object_materials_test(struct Main *bmain, struct Object *ob, struct ID *id)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_mesh_runtime_clear_cache(Mesh *mesh)
@ ME_WRAPPER_TYPE_MDATA
int BKE_mesh_wrapper_vert_len(const Mesh *mesh)
void BKE_modifiers_test_object(Object *ob)
void multires_force_sculpt_rebuild(Object *object)
Definition multires.cc:451
General operations, lookup, etc. for blender objects.
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_endian_switch_uint32_array(unsigned int *val, int size) ATTR_NONNULL(1)
BLI_INLINE unsigned int BLI_hash_int(unsigned int k)
Definition BLI_hash.h:91
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
#define M_PI
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE void madd_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void range_vn_i(int *array_tar, int size, int start)
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.c:29
unsigned int uint
Platform independent time functions.
long int BLI_time_now_seconds_i(void)
Definition time.c:75
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:4992
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
bool BLO_read_requires_endian_switch(BlendDataReader *reader)
Definition readfile.cc:4903
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
void BLO_read_pointer_array(BlendDataReader *reader, int array_size, void **ptr_p)
Definition readfile.cc:5052
bool BLO_write_is_undo(BlendWriter *writer)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr)
#define BLT_I18NCONTEXT_ID_MESH
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:318
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
ID * DEG_get_original_id(ID *id)
#define FILTER_ID_MA
Definition DNA_ID.h:1175
#define FILTER_ID_ME
Definition DNA_ID.h:1178
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:964
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:945
@ INDEX_ID_ME
Definition DNA_ID.h:1293
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
#define FILTER_ID_KE
Definition DNA_ID.h:1199
#define FILTER_ID_IM
Definition DNA_ID.h:1171
@ ID_ME
#define CD_MASK_COLOR_ALL
@ CD_MVERT_SKIN
@ CD_CUSTOMLOOPNORMAL
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_MDEFORMVERT
@ CD_PROP_INT32
#define DNA_struct_default_get(struct_name)
struct Mesh Mesh
@ ME_TEXSPACE_FLAG_AUTO
@ ME_TEXSPACE_FLAG_AUTO_EVALUATED
@ ME_VSEL
@ ME_FSEL
@ ME_ESEL
@ MVERT_SKIN_ROOT
struct MSelect MSelect
Object is a sort of wrapper for general info.
@ OB_MESH
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
bool BKE_mesh_attribute_required(const char *name)
void BKE_mesh_mselect_clear(Mesh *mesh)
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
void BKE_mesh_orco_verts_transform(Mesh *mesh, MutableSpan< float3 > orco, const bool invert)
void BKE_mesh_tessface_clear(Mesh *mesh)
void BKE_mesh_ensure_skin_customdata(Mesh *mesh)
Mesh * BKE_mesh_new_nomain(const int verts_num, const int edges_num, const int faces_num, const int corners_num)
Mesh * BKE_mesh_from_bmesh_nomain(BMesh *bm, const BMeshToMeshParams *params, const Mesh *me_settings)
void BKE_mesh_clear_geometry_and_metadata(Mesh *mesh)
void BKE_mesh_translate(Mesh *mesh, const float offset[3], const bool do_keys)
int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh)
static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
#define MAT_NR_REMAP(n)
void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, const int verts_num, const int edges_num, const int faces_num, const int corners_num)
bool BKE_mesh_has_custom_loop_normals(Mesh *mesh)
void BKE_mesh_texspace_ensure(Mesh *mesh)
void BKE_mesh_mselect_active_set(Mesh *mesh, int index, int type)
Mesh * BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *mesh)
bool BKE_mesh_material_index_used(Mesh *mesh, short index)
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
static void copy_attribute_names(const Mesh &mesh_src, Mesh &mesh_dst)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
static void mesh_clear_geometry(Mesh &mesh)
void BKE_mesh_mselect_validate(Mesh *mesh)
static void mesh_free_data(ID *id)
void BKE_mesh_free_editmesh(Mesh *mesh)
BMesh * BKE_mesh_to_bmesh(Mesh *mesh, Object *ob, const bool add_key_index, const BMeshCreateParams *params)
static void clear_attribute_names(Mesh &mesh)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
static void ensure_orig_index_layer(CustomData &data, const int size)
static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
static void translate_positions(MutableSpan< float3 > positions, const float3 &translation)
Mesh * BKE_mesh_from_object(Object *ob)
int BKE_mesh_mselect_find(const Mesh *mesh, int index, int type)
static void mesh_init_data(ID *id)
static void mesh_foreach_id(ID *id, LibraryForeachIDData *data)
void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
blender::Array< float3 > BKE_mesh_orco_verts_get(const Object *ob)
static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
void BKE_mesh_material_index_clear(Mesh *mesh)
void BKE_mesh_free_data_for_undo(Mesh *mesh)
void BKE_mesh_material_index_remove(Mesh *mesh, short index)
void BKE_mesh_texspace_get_reference(Mesh *mesh, char **r_texspace_flag, float **r_texspace_location, float **r_texspace_size)
void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh)
static void mesh_copy_data(Main *bmain, std::optional< Library * > owner_library, ID *id_dst, const ID *id_src, const int flag)
void BKE_mesh_clear_geometry(Mesh *mesh)
void BKE_mesh_face_offsets_ensure_alloc(Mesh *mesh)
BMesh * BKE_mesh_to_bmesh_ex(const Mesh *mesh, const BMeshCreateParams *create_params, const BMeshFromMeshParams *convert_params)
void BKE_mesh_material_remap(Mesh *mesh, const uint *remap, uint remap_len)
IDTypeInfo IDType_ID_ME
Mesh * BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, const int verts_num, const int edges_num, const int tessface_num, const int faces_num, const int corners_num, const CustomData_MeshMasks mask)
void BKE_mesh_ensure_default_orig_index_customdata(Mesh *mesh)
void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
void BKE_mesh_texspace_calc(Mesh *mesh)
void BKE_mesh_transform(Mesh *mesh, const float mat[4][4], bool do_keys)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const BMeshCreateParams *params)
BMesh Make Mesh.
#define BMALLOC_TEMPLATE_FROM_ME(...)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me_for_eval(BMesh &bm, Mesh &mesh, const CustomData_MeshMasks *cd_mask_extra)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
ATTR_WARN_UNUSED_RESULT const BMVert * v
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
BoundBox bounds
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
bool remove(const StringRef attribute_id)
void add_shared(const ImplicitSharingInfo *sharing_info, const FunctionRef< void(MemoryCounter &shared_memory)> count_fn)
const Depsgraph * depsgraph
#define UINT_MAX
Definition hash_md5.cc:44
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition invert.h:9
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
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void edges_sharp_from_angle_set(OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< float3 > face_normals, Span< int > corner_to_face, Span< bool > sharp_faces, const float split_angle, MutableSpan< bool > sharp_edges)
bool attribute_name_is_anonymous(const StringRef name)
void mesh_sharp_edges_set_from_angle(Mesh &mesh, float angle, bool keep_sharp_edges=false)
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
void mesh_ensure_default_color_attribute_on_add(Mesh &mesh, StringRef id, AttrDomain domain, eCustomDataType data_type)
Mesh * mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num)
void mesh_ensure_required_data_layers(Mesh &mesh)
void copy_shared_pointer(T *src_ptr, const ImplicitSharingInfo *src_sharing_info, T **r_dst_ptr, const ImplicitSharingInfo **r_dst_sharing_info)
const ImplicitSharingInfo * info_for_mem_free(void *data)
void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
void make_trivial_data_mutable(T **data, const ImplicitSharingInfo **sharing_info, const int64_t size)
bool is_zero(const T &a)
short mat_nr
void * data
BMHeader head
int totfacesel
CustomData vdata
int totvertsel
int totedgesel
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
float texspace_size[3]
float remesh_voxel_adaptivity
struct Mesh * texcomesh
int corners_num
CustomData edge_data
char symmetry
char texspace_flag
int edges_num
MeshRuntimeHandle * runtime
uint16_t flag
struct Material ** mat
CustomData corner_data
float remesh_voxel_size
CustomData face_data
char * default_color_attribute
ListBase vertex_group_names
int * face_offset_indices
char editflag
CustomData vert_data
short totcol
int face_sets_color_seed
int attributes_active_index
int vertex_group_active_index
int face_sets_color_default
struct Key * key
CustomData fdata_legacy
char remesh_mode
int totface_legacy
float texspace_location[3]
int faces_num
struct MSelect * mselect
int verts_num
char * active_color_attribute
const ImplicitSharingInfo * face_offsets_sharing_info
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:138