Blender V4.5
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
8
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_hash.h"
27#include "BLI_index_range.hh"
28#include "BLI_listbase.h"
29#include "BLI_math_matrix.hh"
30#include "BLI_math_vector.hh"
31#include "BLI_memory_counter.hh"
32#include "BLI_resource_scope.hh"
33#include "BLI_set.hh"
34#include "BLI_span.hh"
35#include "BLI_string.h"
36#include "BLI_task.hh"
37#include "BLI_time.h"
38#include "BLI_utildefines.h"
39#include "BLI_vector.hh"
40#include "BLI_virtual_array.hh"
41
42#include "BLT_translation.hh"
43
44#include "BKE_anim_data.hh"
46#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.hh"
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
99
102
104}
105
106static void mesh_copy_data(Main *bmain,
107 std::optional<Library *> owner_library,
108 ID *id_dst,
109 const ID *id_src,
110 const int flag)
111{
112 Mesh *mesh_dst = reinterpret_cast<Mesh *>(id_dst);
113 const Mesh *mesh_src = reinterpret_cast<const Mesh *>(id_src);
114
115 mesh_dst->runtime = new blender::bke::MeshRuntime();
116 mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
117 /* Subd runtime.mesh_eval is not copied, will need to be reevaluated. */
118 mesh_dst->runtime->wrapper_type = (mesh_src->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) ?
120 mesh_src->runtime->wrapper_type;
121 mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
122 mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
123 /* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or
124 * node, but we still need to be able to draw face center vertices and "optimal edges"
125 * differently. The tags may be cleared explicitly when the topology is changed. */
126 mesh_dst->runtime->subsurf_face_dot_tags = mesh_src->runtime->subsurf_face_dot_tags;
127 mesh_dst->runtime->subsurf_optimal_display_edges =
128 mesh_src->runtime->subsurf_optimal_display_edges;
129 if ((mesh_src->id.tag & ID_TAG_NO_MAIN) == 0) {
130 /* This is a direct copy of a main mesh, so for now it has the same topology. */
131 mesh_dst->runtime->deformed_only = true;
132 }
133 /* This option is set for run-time meshes that have been copied from the current object's mode.
134 * Currently this is used for edit-mesh although it could be used for sculpt or other
135 * kinds of data specific to an object's mode.
136 *
137 * The flag signals that the mesh hasn't been modified from the data that generated it,
138 * allowing us to use the object-mode data for drawing.
139 *
140 * While this could be the caller's responsibility, keep here since it's
141 * highly unlikely we want to create a duplicate and not use it for drawing. */
142 mesh_dst->runtime->is_original_bmesh = false;
143
144 /* Share various derived caches between the source and destination mesh for improved performance
145 * when the source is persistent and edits to the destination mesh don't affect the caches.
146 * Caches will be "un-shared" as necessary later on. */
147 mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache;
148 mesh_dst->runtime->vert_normals_cache = mesh_src->runtime->vert_normals_cache;
149 mesh_dst->runtime->vert_normals_true_cache = mesh_src->runtime->vert_normals_true_cache;
150 mesh_dst->runtime->face_normals_cache = mesh_src->runtime->face_normals_cache;
151 mesh_dst->runtime->face_normals_true_cache = mesh_src->runtime->face_normals_true_cache;
152 mesh_dst->runtime->corner_normals_cache = mesh_src->runtime->corner_normals_cache;
153 mesh_dst->runtime->loose_verts_cache = mesh_src->runtime->loose_verts_cache;
154 mesh_dst->runtime->verts_no_face_cache = mesh_src->runtime->verts_no_face_cache;
155 mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
156 mesh_dst->runtime->corner_tris_cache = mesh_src->runtime->corner_tris_cache;
157 mesh_dst->runtime->corner_tri_faces_cache = mesh_src->runtime->corner_tri_faces_cache;
158 mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache;
159 mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache;
160 mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache;
161 mesh_dst->runtime->corner_to_face_map_cache = mesh_src->runtime->corner_to_face_map_cache;
162 mesh_dst->runtime->bvh_cache_verts = mesh_src->runtime->bvh_cache_verts;
163 mesh_dst->runtime->bvh_cache_edges = mesh_src->runtime->bvh_cache_edges;
164 mesh_dst->runtime->bvh_cache_faces = mesh_src->runtime->bvh_cache_faces;
165 mesh_dst->runtime->bvh_cache_corner_tris = mesh_src->runtime->bvh_cache_corner_tris;
166 mesh_dst->runtime->bvh_cache_corner_tris_no_hidden =
167 mesh_src->runtime->bvh_cache_corner_tris_no_hidden;
168 mesh_dst->runtime->bvh_cache_loose_verts = mesh_src->runtime->bvh_cache_loose_verts;
169 mesh_dst->runtime->bvh_cache_loose_verts_no_hidden =
170 mesh_src->runtime->bvh_cache_loose_verts_no_hidden;
171 mesh_dst->runtime->bvh_cache_loose_edges = mesh_src->runtime->bvh_cache_loose_edges;
172 mesh_dst->runtime->bvh_cache_loose_edges_no_hidden =
173 mesh_src->runtime->bvh_cache_loose_edges_no_hidden;
174 mesh_dst->runtime->max_material_index = mesh_src->runtime->max_material_index;
175 if (mesh_src->runtime->bake_materials) {
176 mesh_dst->runtime->bake_materials = std::make_unique<blender::bke::bake::BakeMaterialsList>(
177 *mesh_src->runtime->bake_materials);
178 }
179
180 /* Only do tessface if we have no faces. */
181 const bool do_tessface = ((mesh_src->totface_legacy != 0) && (mesh_src->faces_num == 0));
182
184
185 if (mesh_src->id.tag & ID_TAG_NO_MAIN) {
186 /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */
188
189 /* Meshes copied during evaluation pass the edit mesh pointer to determine whether a mapping
190 * from the evaluated to the original state is possible. */
191 mesh_dst->runtime->edit_mesh = mesh_src->runtime->edit_mesh;
192 if (const blender::bke::EditMeshData *edit_data = mesh_src->runtime->edit_data.get()) {
193 mesh_dst->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>(*edit_data);
194 }
195 }
196
197 mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat);
198
200 mesh_dst->active_color_attribute = static_cast<char *>(
202 mesh_dst->default_color_attribute = static_cast<char *>(
204 mesh_dst->active_uv_map_attribute = static_cast<char *>(
206 mesh_dst->default_uv_map_attribute = static_cast<char *>(
208
210 &mesh_src->vert_data, &mesh_dst->vert_data, mask.vmask, mesh_dst->verts_num);
212 &mesh_src->edge_data, &mesh_dst->edge_data, mask.emask, mesh_dst->edges_num);
214 &mesh_src->corner_data, &mesh_dst->corner_data, mask.lmask, mesh_dst->corners_num);
216 &mesh_src->face_data, &mesh_dst->face_data, mask.pmask, mesh_dst->faces_num);
217 new (&mesh_dst->attribute_storage.wrap())
220 mesh_src->runtime->face_offsets_sharing_info,
221 &mesh_dst->face_offset_indices,
222 &mesh_dst->runtime->face_offsets_sharing_info);
223 if (do_tessface) {
225 &mesh_src->fdata_legacy, &mesh_dst->fdata_legacy, mask.fmask, mesh_dst->totface_legacy);
226 }
227 else {
228 mesh_tessface_clear_intern(mesh_dst, false);
229 }
230
231 mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
232
233 if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
234 BKE_id_copy_in_lib(bmain,
235 owner_library,
236 &mesh_src->key->id,
237 &mesh_dst->id,
238 reinterpret_cast<ID **>(&mesh_dst->key),
239 flag);
240 }
241}
242
243static void mesh_free_data(ID *id)
244{
245 Mesh *mesh = reinterpret_cast<Mesh *>(id);
246
257 mesh->attribute_storage.wrap().~AttributeStorage();
258 if (mesh->face_offset_indices) {
260 &mesh->runtime->face_offsets_sharing_info);
261 }
262 MEM_SAFE_FREE(mesh->mselect);
263 MEM_SAFE_FREE(mesh->mat);
264 delete mesh->runtime;
265}
266
282
283static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
284{
285 Mesh *mesh = reinterpret_cast<Mesh *>(id);
286 if (mesh->corner_data.external) {
289 sizeof(mesh->corner_data.external->filepath));
290 }
291}
292
293static void rename_seam_layer_to_old_name(const ListBase vertex_groups,
294 const Span<CustomDataLayer> vert_layers,
296 const Span<CustomDataLayer> face_layers,
297 const Span<CustomDataLayer> corner_layers)
298{
299 CustomDataLayer *seam_layer = nullptr;
300 for (CustomDataLayer &layer : edge_layers) {
301 if (STREQ(layer.name, ".uv_seam")) {
302 return;
303 }
304 if (layer.type == CD_PROP_BOOL && STREQ(layer.name, "uv_seam")) {
305 seam_layer = &layer;
306 }
307 }
308
309 if (!seam_layer) {
310 return;
311 }
312
313 /* Current files are not expected to have a ".uv_seam" attribute (the old name) except in the
314 * rare case users created it themselves. If that happens, avoid renaming the current UV seam
315 * attribute so that at least it's not hidden in the old version. */
316 for (const CustomDataLayer &layer : vert_layers) {
317 if (STREQ(layer.name, ".uv_seam")) {
318 return;
319 }
320 }
321 for (const CustomDataLayer &layer : face_layers) {
322 if (STREQ(layer.name, ".uv_seam")) {
323 return;
324 }
325 }
326 for (const CustomDataLayer &layer : corner_layers) {
327 if (STREQ(layer.name, ".uv_seam")) {
328 return;
329 }
330 }
331 LISTBASE_FOREACH (const bDeformGroup *, vertex_group, &vertex_groups) {
332 if (STREQ(vertex_group->name, ".uv_seam")) {
333 return;
334 }
335 }
336
337 STRNCPY(seam_layer->name, ".uv_seam");
338}
339
340static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
341{
342 using namespace blender;
343 using namespace blender::bke;
344 Mesh *mesh = reinterpret_cast<Mesh *>(id);
345 const bool is_undo = BLO_write_is_undo(writer);
346
347 ResourceScope scope;
348 Vector<CustomDataLayer, 16> vert_layers;
349 Vector<CustomDataLayer, 16> edge_layers;
350 Vector<CustomDataLayer, 16> loop_layers;
351 Vector<CustomDataLayer, 16> face_layers;
352 bke::AttributeStorage::BlendWriteData attribute_data{scope};
353
354 /* Cache only - don't write. */
355 mesh->mface = nullptr;
356 mesh->totface_legacy = 0;
357 mesh->fdata_legacy = CustomData{};
358
359 /* Do not store actual geometry data in case this is a library override ID. */
360 if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
361 mesh->verts_num = 0;
362 mesh->vert_data = CustomData{};
363
364 mesh->edges_num = 0;
365 mesh->edge_data = CustomData{};
366
367 mesh->corners_num = 0;
368 mesh->corner_data = CustomData{};
369
370 mesh->faces_num = 0;
371 mesh->face_data = CustomData{};
372 mesh->face_offset_indices = nullptr;
373 }
374 else {
375 attribute_storage_blend_write_prepare(mesh->attribute_storage.wrap(),
376 {{AttrDomain::Point, &vert_layers},
377 {AttrDomain::Edge, &edge_layers},
378 {AttrDomain::Face, &face_layers},
379 {AttrDomain::Corner, &loop_layers}},
380 attribute_data);
382 mesh->vert_data, AttrDomain::Point, mesh->verts_num, vert_layers, attribute_data);
384 mesh->edge_data, AttrDomain::Edge, mesh->edges_num, edge_layers, attribute_data);
386 mesh->face_data, AttrDomain::Face, mesh->faces_num, face_layers, attribute_data);
388 mesh->corner_data, AttrDomain::Corner, mesh->corners_num, loop_layers, attribute_data);
389 if (attribute_data.attributes.is_empty()) {
390 mesh->attribute_storage.dna_attributes = nullptr;
391 mesh->attribute_storage.dna_attributes_num = 0;
392 }
393 else {
394 mesh->attribute_storage.dna_attributes = attribute_data.attributes.data();
395 mesh->attribute_storage.dna_attributes_num = attribute_data.attributes.size();
396 }
397 if (!is_undo) {
398 /* Write forward compatible format. To be removed in 5.0. */
400 mesh->vertex_group_names, vert_layers, edge_layers, face_layers, loop_layers);
401 mesh_sculpt_mask_to_legacy(vert_layers);
403 }
404 }
405
406 const blender::bke::MeshRuntime *mesh_runtime = mesh->runtime;
407 mesh->runtime = nullptr;
408
409 BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
410 BKE_id_blend_write(writer, &mesh->id);
411
412 BKE_defbase_blend_write(writer, &mesh->vertex_group_names);
413 BLO_write_string(writer, mesh->active_color_attribute);
414 BLO_write_string(writer, mesh->default_color_attribute);
415
416 BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
417 BLO_write_struct_array(writer, MSelect, mesh->totselect, mesh->mselect);
418
420 writer, &mesh->vert_data, vert_layers, mesh->verts_num, CD_MASK_MESH.vmask, &mesh->id);
422 writer, &mesh->edge_data, edge_layers, mesh->edges_num, CD_MASK_MESH.emask, &mesh->id);
423 /* `fdata` is cleared above but written so slots align. */
425 writer, &mesh->fdata_legacy, {}, mesh->totface_legacy, CD_MASK_MESH.fmask, &mesh->id);
427 writer, &mesh->corner_data, loop_layers, mesh->corners_num, CD_MASK_MESH.lmask, &mesh->id);
429 writer, &mesh->face_data, face_layers, mesh->faces_num, CD_MASK_MESH.pmask, &mesh->id);
430
431 mesh->attribute_storage.wrap().blend_write(*writer, attribute_data);
432
433 if (mesh->face_offset_indices) {
435 writer,
436 mesh->face_offset_indices,
437 sizeof(int) * mesh->faces_num,
438 mesh_runtime->face_offsets_sharing_info,
439 [&]() { BLO_write_int32_array(writer, mesh->faces_num + 1, mesh->face_offset_indices); });
440 }
441}
442
443static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
444{
445 Mesh *mesh = reinterpret_cast<Mesh *>(id);
446 BLO_read_pointer_array(reader, mesh->totcol, (void **)&mesh->mat);
447 /* This check added for python created meshes. */
448 if (!mesh->mat) {
449 mesh->totcol = 0;
450 }
451
452 /* Deprecated pointers to custom data layers are read here for backward compatibility
453 * with files where these were owning pointers rather than a view into custom data. */
454 BLO_read_struct_array(reader, MVert, mesh->verts_num, &mesh->mvert);
455 BLO_read_struct_array(reader, MEdge, mesh->edges_num, &mesh->medge);
456 BLO_read_struct_array(reader, MFace, mesh->totface_legacy, &mesh->mface);
457 BLO_read_struct_array(reader, MTFace, mesh->totface_legacy, &mesh->mtface);
458 BLO_read_struct_array(reader, MDeformVert, mesh->verts_num, &mesh->dvert);
459 BLO_read_struct_array(reader, TFace, mesh->totface_legacy, &mesh->tface);
460 BLO_read_struct_array(reader, MCol, mesh->totface_legacy, &mesh->mcol);
461
462 BLO_read_struct_array(reader, MSelect, mesh->totselect, &mesh->mselect);
463
464 BLO_read_struct_list(reader, bDeformGroup, &mesh->vertex_group_names);
465
466 CustomData_blend_read(reader, &mesh->vert_data, mesh->verts_num);
467 CustomData_blend_read(reader, &mesh->edge_data, mesh->edges_num);
468 CustomData_blend_read(reader, &mesh->fdata_legacy, mesh->totface_legacy);
469 CustomData_blend_read(reader, &mesh->corner_data, mesh->corners_num);
470 CustomData_blend_read(reader, &mesh->face_data, mesh->faces_num);
471 mesh->attribute_storage.wrap().blend_read(*reader);
472 if (mesh->deform_verts().is_empty()) {
473 /* Vertex group data was also an owning pointer in old Blender versions.
474 * Don't read them again if they were read as part of #CustomData. */
475 BKE_defvert_blend_read(reader, mesh->verts_num, mesh->dvert);
476 }
477 BLO_read_string(reader, &mesh->active_color_attribute);
478 BLO_read_string(reader, &mesh->default_color_attribute);
479 BLO_read_string(reader, &mesh->active_uv_map_attribute);
480 BLO_read_string(reader, &mesh->default_uv_map_attribute);
481
482 /* Forward compatibility. To be removed when runtime format changes. */
484
485 mesh->texspace_flag &= ~ME_TEXSPACE_FLAG_AUTO_EVALUATED;
486
487 mesh->runtime = new blender::bke::MeshRuntime();
488
489 if (mesh->face_offset_indices) {
490 mesh->runtime->face_offsets_sharing_info = BLO_read_shared(
491 reader, &mesh->face_offset_indices, [&]() {
492 BLO_read_int32_array(reader, mesh->faces_num + 1, &mesh->face_offset_indices);
493 return blender::implicit_sharing::info_for_mem_free(mesh->face_offset_indices);
494 });
495 }
496
497 if (mesh->mselect == nullptr) {
498 mesh->totselect = 0;
499 }
500
501 if (BLO_read_requires_endian_switch(reader) && mesh->tface) {
502 TFace *tf = mesh->tface;
503 for (int i = 0; i < mesh->totface_legacy; i++, tf++) {
505 }
506 }
507}
508
510 /*id_code*/ Mesh::id_type,
511 /*id_filter*/ FILTER_ID_ME,
512 /*dependencies_id_types*/ FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE,
513 /*main_listbase_index*/ INDEX_ID_ME,
514 /*struct_size*/ sizeof(Mesh),
515 /*name*/ "Mesh",
516 /*name_plural*/ N_("meshes"),
517 /*translation_context*/ BLT_I18NCONTEXT_ID_MESH,
519 /*asset_type_info*/ nullptr,
520
521 /*init_data*/ mesh_init_data,
522 /*copy_data*/ mesh_copy_data,
523 /*free_data*/ mesh_free_data,
524 /*make_local*/ nullptr,
525 /*foreach_id*/ mesh_foreach_id,
526 /*foreach_cache*/ nullptr,
527 /*foreach_path*/ mesh_foreach_path,
528 /*owner_pointer_get*/ nullptr,
529
530 /*blend_write*/ mesh_blend_write,
531 /*blend_read_data*/ mesh_blend_read_data,
532 /*blend_read_after_liblink*/ nullptr,
533
534 /*blend_read_undo_preserve*/ nullptr,
535
536 /*lib_override_apply_post*/ nullptr,
537};
538
540{
541 return ELEM(name, "position", ".corner_vert", ".corner_edge", ".edge_verts");
542}
543
545{
546 BMesh *bm = mesh->runtime->edit_mesh ? mesh->runtime->edit_mesh->bm : nullptr;
547 MVertSkin *vs;
548
549 if (bm) {
550 if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
551 BMVert *v;
552 BMIter iter;
553
555
556 /* Mark an arbitrary vertex as root */
557 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
558 vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
559 vs->flag |= MVERT_SKIN_ROOT;
560 break;
561 }
562 }
563 }
564 else {
565 if (!CustomData_has_layer(&mesh->vert_data, CD_MVERT_SKIN)) {
567 &mesh->vert_data, CD_MVERT_SKIN, CD_SET_DEFAULT, mesh->verts_num);
568
569 /* Mark an arbitrary vertex as root */
570 if (vs) {
571 vs->flag |= MVERT_SKIN_ROOT;
572 }
573 }
574 }
575}
576
578{
579 if (mesh->runtime->edit_mesh) {
581 &mesh->runtime->edit_mesh->bm->ldata, CD_PROP_INT16_2D, "custom_normal");
582 }
583
584 return mesh->attributes().contains("custom_normal");
585}
586
587namespace blender::bke {
588
590 const StringRef id,
591 AttrDomain domain,
592 eCustomDataType data_type)
593{
595 return;
596 }
597 if (!(CD_TYPE_AS_MASK(data_type) & CD_MASK_COLOR_ALL) ||
599 {
600 return;
601 }
602 if (mesh.default_color_attribute) {
603 return;
604 }
605 mesh.default_color_attribute = BLI_strdupn(id.data(), id.size());
606}
607
609{
610 MutableAttributeAccessor attributes = mesh.attributes_for_write();
611 AttributeInitConstruct attribute_init;
612
613 /* Try to create attributes if they do not exist. */
614 attributes.add("position", AttrDomain::Point, CD_PROP_FLOAT3, attribute_init);
615 attributes.add(".edge_verts", AttrDomain::Edge, CD_PROP_INT32_2D, attribute_init);
616 attributes.add(".corner_vert", AttrDomain::Corner, CD_PROP_INT32, attribute_init);
617 attributes.add(".corner_edge", AttrDomain::Corner, CD_PROP_INT32, attribute_init);
618}
619
620static bool meta_data_matches(const std::optional<bke::AttributeMetaData> meta_data,
621 const AttrDomainMask domains,
622 const eCustomDataMask types)
623{
624 if (!meta_data) {
625 return false;
626 }
627 if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & domains)) {
628 return false;
629 }
630 if (!(CD_TYPE_AS_MASK(meta_data->data_type) & types)) {
631 return false;
632 }
633 return true;
634}
635
637{
638 bke::AttributeAccessor attributes = mesh.attributes();
639 if (!meta_data_matches(attributes.lookup_meta_data(mesh.active_color_attribute),
642 {
643 MEM_SAFE_FREE(mesh.active_color_attribute);
644 }
645 if (!meta_data_matches(attributes.lookup_meta_data(mesh.default_color_attribute),
648 {
649 MEM_SAFE_FREE(mesh.default_color_attribute);
650 }
651}
652
653} // namespace blender::bke
654
668{
669 CustomData_free(&mesh.vert_data);
670 CustomData_free(&mesh.edge_data);
671 CustomData_free(&mesh.fdata_legacy);
672 CustomData_free(&mesh.corner_data);
673 CustomData_free(&mesh.face_data);
674 mesh.attribute_storage.wrap() = blender::bke::AttributeStorage();
675 if (mesh.face_offset_indices) {
677 &mesh.runtime->face_offsets_sharing_info);
678 }
679 MEM_SAFE_FREE(mesh.mselect);
680
681 mesh.verts_num = 0;
682 mesh.edges_num = 0;
683 mesh.totface_legacy = 0;
684 mesh.corners_num = 0;
685 mesh.faces_num = 0;
686 mesh.act_face = -1;
687 mesh.totselect = 0;
688}
689
691{
692 BLI_freelistN(&mesh.vertex_group_names);
693 MEM_SAFE_FREE(mesh.active_color_attribute);
694 MEM_SAFE_FREE(mesh.default_color_attribute);
695}
696
702
709
710static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
711{
712 if (free_customdata) {
713 CustomData_free(&mesh->fdata_legacy);
714 }
715 else {
716 CustomData_reset(&mesh->fdata_legacy);
717 }
718
719 mesh->totface_legacy = 0;
720}
721
722Mesh *BKE_mesh_add(Main *bmain, const char *name)
723{
724 return BKE_id_new<Mesh>(bmain, name);
725}
726
728{
729 BLI_assert(mesh->face_offset_indices == nullptr);
730 BLI_assert(mesh->runtime->face_offsets_sharing_info == nullptr);
731 if (mesh->faces_num == 0) {
732 return;
733 }
734 mesh->face_offset_indices = MEM_malloc_arrayN<int>(size_t(mesh->faces_num) + 1, __func__);
735 mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
736 mesh->face_offset_indices);
737
738#ifndef NDEBUG
739 /* Fill offsets with obviously bad values to simplify finding missing initialization. */
740 mesh->face_offsets_for_write().fill(-1);
741#endif
742 /* Set common values for convenience. */
743 mesh->face_offset_indices[0] = 0;
744 mesh->face_offset_indices[mesh->faces_num] = mesh->corners_num;
745}
746
747Span<float3> Mesh::vert_positions() const
748{
749 return {static_cast<const float3 *>(
751 this->verts_num};
752}
753MutableSpan<float3> Mesh::vert_positions_for_write()
754{
755 return {static_cast<float3 *>(CustomData_get_layer_named_for_write(
756 &this->vert_data, CD_PROP_FLOAT3, "position", this->verts_num)),
757 this->verts_num};
758}
759
760Span<int2> Mesh::edges() const
761{
762 return {static_cast<const int2 *>(
764 this->edges_num};
765}
766MutableSpan<int2> Mesh::edges_for_write()
767{
768 return {static_cast<int2 *>(CustomData_get_layer_named_for_write(
769 &this->edge_data, CD_PROP_INT32_2D, ".edge_verts", this->edges_num)),
770 this->edges_num};
771}
772
773OffsetIndices<int> Mesh::faces() const
774{
775 return Span(this->face_offset_indices, this->faces_num + 1);
776}
777Span<int> Mesh::face_offsets() const
778{
779 if (this->faces_num == 0) {
780 return {};
781 }
782 return {this->face_offset_indices, this->faces_num + 1};
783}
784MutableSpan<int> Mesh::face_offsets_for_write()
785{
786 if (this->faces_num == 0) {
787 return {};
788 }
790 &this->face_offset_indices, &this->runtime->face_offsets_sharing_info, this->faces_num + 1);
791 return {this->face_offset_indices, this->faces_num + 1};
792}
793
794Span<int> Mesh::corner_verts() const
795{
796 return {static_cast<const int *>(
797 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_vert")),
798 this->corners_num};
799}
800MutableSpan<int> Mesh::corner_verts_for_write()
801{
802 return {static_cast<int *>(CustomData_get_layer_named_for_write(
803 &this->corner_data, CD_PROP_INT32, ".corner_vert", this->corners_num)),
804 this->corners_num};
805}
806
807Span<int> Mesh::corner_edges() const
808{
809 return {static_cast<const int *>(
810 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_edge")),
811 this->corners_num};
812}
813MutableSpan<int> Mesh::corner_edges_for_write()
814{
815 return {static_cast<int *>(CustomData_get_layer_named_for_write(
816 &this->corner_data, CD_PROP_INT32, ".corner_edge", this->corners_num)),
817 this->corners_num};
818}
819
820Span<MDeformVert> Mesh::deform_verts() const
821{
822 const MDeformVert *dverts = static_cast<const MDeformVert *>(
824 if (!dverts) {
825 return {};
826 }
827 return {dverts, this->verts_num};
828}
829MutableSpan<MDeformVert> Mesh::deform_verts_for_write()
830{
831 MDeformVert *dvert = static_cast<MDeformVert *>(
833 if (dvert) {
834 return {dvert, this->verts_num};
835 }
836 return {static_cast<MDeformVert *>(CustomData_add_layer(
838 this->verts_num};
839}
840
841void Mesh::count_memory(blender::MemoryCounter &memory) const
842{
843 memory.add_shared(this->runtime->face_offsets_sharing_info,
844 this->face_offsets().size_in_bytes());
845 CustomData_count_memory(this->vert_data, this->verts_num, memory);
846 CustomData_count_memory(this->edge_data, this->edges_num, memory);
847 CustomData_count_memory(this->face_data, this->faces_num, memory);
848 CustomData_count_memory(this->corner_data, this->corners_num, memory);
849}
850
852{
853 return blender::bke::AttributeAccessor(this, blender::bke::mesh_attribute_accessor_functions());
854}
855
856blender::bke::MutableAttributeAccessor Mesh::attributes_for_write()
857{
858 return blender::bke::MutableAttributeAccessor(this,
860}
861
862Mesh *BKE_mesh_new_nomain(const int verts_num,
863 const int edges_num,
864 const int faces_num,
865 const int corners_num)
866{
867 Mesh *mesh = static_cast<Mesh *>(BKE_libblock_alloc(
870
871 mesh->verts_num = verts_num;
872 mesh->edges_num = edges_num;
873 mesh->faces_num = faces_num;
874 mesh->corners_num = corners_num;
875
878
879 return mesh;
880}
881
882namespace blender::bke {
883
884Mesh *mesh_new_no_attributes(const int verts_num,
885 const int edges_num,
886 const int faces_num,
887 const int corners_num)
888{
889 Mesh *mesh = BKE_mesh_new_nomain(0, 0, faces_num, 0);
890 mesh->verts_num = verts_num;
891 mesh->edges_num = edges_num;
892 mesh->corners_num = corners_num;
893 CustomData_free_layer_named(&mesh->vert_data, "position");
894 CustomData_free_layer_named(&mesh->edge_data, ".edge_verts");
895 CustomData_free_layer_named(&mesh->corner_data, ".corner_vert");
896 CustomData_free_layer_named(&mesh->corner_data, ".corner_edge");
897 return mesh;
898}
899
900} // namespace blender::bke
901
902static void copy_attribute_names(const Mesh &mesh_src, Mesh &mesh_dst)
903{
904 if (mesh_src.active_color_attribute) {
907 }
908 if (mesh_src.default_color_attribute) {
911 }
912}
913
914void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
915{
916 /* Copy general settings. */
917 me_dst->editflag = me_src->editflag;
918 me_dst->flag = me_src->flag;
919 me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
921 me_dst->remesh_mode = me_src->remesh_mode;
922 me_dst->symmetry = me_src->symmetry;
923
926
927 /* Copy texture space. */
928 me_dst->texspace_flag = me_src->texspace_flag;
930 copy_v3_v3(me_dst->texspace_size, me_src->texspace_size);
931
934}
935
936void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
937{
938 /* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
940
941 BKE_mesh_copy_parameters(me_dst, me_src);
942 copy_attribute_names(*me_src, *me_dst);
943
944 /* Copy vertex group names. */
947
948 /* Copy materials. */
949 if (me_dst->mat != nullptr) {
950 MEM_freeN(me_dst->mat);
951 }
952 me_dst->mat = (Material **)MEM_dupallocN(me_src->mat);
953 me_dst->totcol = me_src->totcol;
954
955 me_dst->runtime->edit_mesh = me_src->runtime->edit_mesh;
956}
957
959 const int verts_num,
960 const int edges_num,
961 const int tessface_num,
962 const int faces_num,
963 const int corners_num,
965{
966 /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
967 const bool do_tessface = (tessface_num ||
968 ((me_src->totface_legacy != 0) && (me_src->faces_num == 0)));
969
970 Mesh *me_dst = BKE_id_new_nomain<Mesh>(nullptr);
971
972 me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect);
973
974 me_dst->verts_num = verts_num;
975 me_dst->edges_num = edges_num;
976 me_dst->faces_num = faces_num;
977 me_dst->corners_num = corners_num;
978 me_dst->totface_legacy = tessface_num;
979
980 BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
981
983 &me_src->vert_data, &me_dst->vert_data, mask.vmask, CD_SET_DEFAULT, verts_num);
985 &me_src->edge_data, &me_dst->edge_data, mask.emask, CD_SET_DEFAULT, edges_num);
987 &me_src->face_data, &me_dst->face_data, mask.pmask, CD_SET_DEFAULT, faces_num);
989 &me_src->corner_data, &me_dst->corner_data, mask.lmask, CD_SET_DEFAULT, corners_num);
990 if (do_tessface) {
992 &me_src->fdata_legacy, &me_dst->fdata_legacy, mask.fmask, CD_SET_DEFAULT, tessface_num);
993 }
994 else {
995 mesh_tessface_clear_intern(me_dst, false);
996 }
997
998 /* The destination mesh should at least have valid primary CD layers,
999 * even in cases where the source mesh does not. */
1002 if (do_tessface && !CustomData_get_layer(&me_dst->fdata_legacy, CD_MFACE)) {
1004 }
1005
1006 return me_dst;
1007}
1008
1010 const int verts_num,
1011 const int edges_num,
1012 const int faces_num,
1013 const int corners_num)
1014{
1016 me_src, verts_num, edges_num, 0, faces_num, corners_num, CD_MASK_EVERYTHING);
1017}
1018
1020{
1021 return reinterpret_cast<Mesh *>(
1022 BKE_id_copy_ex(nullptr, &source.id, nullptr, LIB_ID_COPY_LOCALIZE));
1023}
1024
1026 const BMeshCreateParams *create_params,
1027 const BMeshFromMeshParams *convert_params)
1028{
1030
1031 BMesh *bm = BM_mesh_create(&allocsize, create_params);
1032 BM_mesh_bm_from_me(bm, mesh, convert_params);
1033
1034 return bm;
1035}
1036
1038 const int active_shapekey,
1039 const bool add_key_index,
1041{
1042 BMeshFromMeshParams bmesh_from_mesh_params{};
1043 bmesh_from_mesh_params.calc_face_normal = false;
1044 bmesh_from_mesh_params.calc_vert_normal = false;
1045 bmesh_from_mesh_params.add_key_index = add_key_index;
1046 bmesh_from_mesh_params.use_shapekey = true;
1047 bmesh_from_mesh_params.active_shapekey = active_shapekey;
1048 return BKE_mesh_to_bmesh_ex(mesh, params, &bmesh_from_mesh_params);
1049}
1050
1053 const Mesh *me_settings)
1054{
1055 BLI_assert(params->calc_object_remap == false);
1056 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
1057 BM_mesh_bm_to_me(nullptr, bm, mesh, params);
1059 return mesh;
1060}
1061
1063 const CustomData_MeshMasks *cd_mask_extra,
1064 const Mesh *me_settings)
1065{
1066 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
1067 BM_mesh_bm_to_me_for_eval(*bm, *mesh, cd_mask_extra);
1069 return mesh;
1070}
1071
1073{
1075 return;
1076 }
1078 range_vn_i(indices, size, 0);
1079}
1080
1086
1088{
1089 ensure_orig_index_layer(mesh->vert_data, mesh->verts_num);
1090 ensure_orig_index_layer(mesh->edge_data, mesh->edges_num);
1091 ensure_orig_index_layer(mesh->face_data, mesh->faces_num);
1092}
1093
1095{
1096 using namespace blender;
1097 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) {
1098 const Bounds<float3> bounds = mesh->bounds_min_max().value_or(
1099 Bounds(float3(-1.0f), float3(1.0f)));
1100
1101 float texspace_location[3], texspace_size[3];
1102 mid_v3_v3v3(texspace_location, bounds.min, bounds.max);
1103
1104 texspace_size[0] = (bounds.max[0] - bounds.min[0]) / 2.0f;
1105 texspace_size[1] = (bounds.max[1] - bounds.min[1]) / 2.0f;
1106 texspace_size[2] = (bounds.max[2] - bounds.min[2]) / 2.0f;
1107
1108 for (int a = 0; a < 3; a++) {
1109 if (texspace_size[a] == 0.0f) {
1110 texspace_size[a] = 1.0f;
1111 }
1112 else if (texspace_size[a] > 0.0f && texspace_size[a] < 0.00001f) {
1113 texspace_size[a] = 0.00001f;
1114 }
1115 else if (texspace_size[a] < 0.0f && texspace_size[a] > -0.00001f) {
1116 texspace_size[a] = -0.00001f;
1117 }
1118 }
1119
1120 copy_v3_v3(mesh->texspace_location, texspace_location);
1121 copy_v3_v3(mesh->texspace_size, texspace_size);
1122
1123 mesh->texspace_flag |= ME_TEXSPACE_FLAG_AUTO_EVALUATED;
1124 }
1125}
1126
1128{
1129 if ((mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) &&
1130 !(mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED))
1131 {
1133 }
1134}
1135
1136void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
1137{
1139
1140 if (r_texspace_location) {
1141 copy_v3_v3(r_texspace_location, mesh->texspace_location);
1142 }
1143 if (r_texspace_size) {
1144 copy_v3_v3(r_texspace_size, mesh->texspace_size);
1145 }
1146}
1147
1149 char **r_texspace_flag,
1150 float **r_texspace_location,
1151 float **r_texspace_size)
1152{
1154
1155 if (r_texspace_flag != nullptr) {
1156 *r_texspace_flag = &mesh->texspace_flag;
1157 }
1158 if (r_texspace_location != nullptr) {
1159 *r_texspace_location = mesh->texspace_location;
1160 }
1161 if (r_texspace_size != nullptr) {
1162 *r_texspace_size = mesh->texspace_size;
1163 }
1164}
1165
1167{
1168 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
1169 const Mesh *tme = mesh->texcomesh ? mesh->texcomesh : mesh;
1170
1172 const Span<float3> positions = tme->vert_positions();
1173 result.as_mutable_span().take_front(positions.size()).copy_from(positions);
1174 result.as_mutable_span().drop_front(positions.size()).fill(float3(0));
1175
1176 return result;
1177}
1178
1180{
1181 float texspace_location[3], texspace_size[3];
1182
1184 mesh->texcomesh ? mesh->texcomesh : mesh, texspace_location, texspace_size);
1185
1186 if (invert) {
1187 for (const int a : orco.index_range()) {
1188 float3 &co = orco[a];
1189 madd_v3_v3v3v3(co, texspace_location, co, texspace_size);
1190 }
1191 }
1192 else {
1193 for (const int a : orco.index_range()) {
1194 float3 &co = orco[a];
1195 co[0] = (co[0] - texspace_location[0]) / texspace_size[0];
1196 co[1] = (co[1] - texspace_location[1]) / texspace_size[1];
1197 co[2] = (co[2] - texspace_location[2]) / texspace_size[2];
1198 }
1199 }
1200}
1201
1202void BKE_mesh_orco_verts_transform(Mesh *mesh, float (*orco)[3], int totvert, bool invert)
1203{
1204 BKE_mesh_orco_verts_transform(mesh, {reinterpret_cast<float3 *>(orco), totvert}, invert);
1205}
1206
1208{
1209 if (CustomData_has_layer(&mesh->vert_data, CD_ORCO)) {
1210 return;
1211 }
1212
1213 /* Orcos are stored in normalized 0..1 range by convention. */
1215 BKE_mesh_orco_verts_transform(mesh, orcodata, false);
1216 float3 *data = static_cast<float3 *>(
1217 CustomData_add_layer(&mesh->vert_data, CD_ORCO, CD_CONSTRUCT, mesh->verts_num));
1218 MutableSpan(data, mesh->verts_num).copy_from(orcodata);
1219}
1220
1222{
1223 if (ob == nullptr) {
1224 return nullptr;
1225 }
1226 if (ob->type == OB_MESH) {
1227 return static_cast<Mesh *>(ob->data);
1228 }
1229
1230 return nullptr;
1231}
1232
1234{
1235 Mesh *old = nullptr;
1236
1237 if (ob == nullptr) {
1238 return;
1239 }
1240
1242
1243 if (ob->type == OB_MESH) {
1244 old = static_cast<Mesh *>(ob->data);
1245 if (old) {
1246 id_us_min(&old->id);
1247 }
1248 ob->data = mesh;
1249 id_us_plus((ID *)mesh);
1250 }
1251
1253
1255}
1256
1258{
1259 using namespace blender;
1260 using namespace blender::bke;
1261 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1262 AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
1263 if (!material_indices) {
1264 return;
1265 }
1266 if (material_indices.domain != AttrDomain::Face) {
1268 return;
1269 }
1270 MutableVArraySpan<int> indices_span(material_indices.varray);
1271 for (const int i : indices_span.index_range()) {
1272 if (indices_span[i] > 0 && indices_span[i] >= index) {
1273 indices_span[i]--;
1274 }
1275 }
1276 indices_span.save();
1277 material_indices.finish();
1278
1280}
1281
1283{
1284 using namespace blender;
1285 using namespace blender::bke;
1286 const AttributeAccessor attributes = mesh->attributes();
1287 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
1288 "material_index", AttrDomain::Face, 0);
1289 if (material_indices.is_single()) {
1290 return material_indices.get_internal_single() == index;
1291 }
1292 const VArraySpan<int> indices_span(material_indices);
1293 return indices_span.contains(index);
1294}
1295
1297{
1298 using namespace blender;
1299 using namespace blender::bke;
1300 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1301 attributes.remove("material_index");
1302
1304}
1305
1306void BKE_mesh_material_remap(Mesh *mesh, const uint *remap, uint remap_len)
1307{
1308 using namespace blender;
1309 using namespace blender::bke;
1310 const short remap_len_short = short(remap_len);
1311
1312#define MAT_NR_REMAP(n) \
1313 if (n < remap_len_short) { \
1314 BLI_assert(n >= 0 && remap[n] < remap_len_short); \
1315 n = remap[n]; \
1316 } \
1317 ((void)0)
1318
1319 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1320 BMIter iter;
1321 BMFace *efa;
1322
1323 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1324 MAT_NR_REMAP(efa->mat_nr);
1325 }
1326 }
1327 else {
1328 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1329 SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
1330 "material_index", AttrDomain::Face);
1331 if (!material_indices) {
1332 return;
1333 }
1334 for (const int i : material_indices.span.index_range()) {
1335 MAT_NR_REMAP(material_indices.span[i]);
1336 }
1337 material_indices.span.save();
1338 material_indices.finish();
1339 }
1340
1341#undef MAT_NR_REMAP
1342}
1343
1344namespace blender::bke {
1345
1346void mesh_smooth_set(Mesh &mesh, const bool use_smooth, const bool keep_sharp_edges)
1347{
1348 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1349 if (!keep_sharp_edges) {
1350 attributes.remove("sharp_edge");
1351 }
1352 attributes.remove("sharp_face");
1353 if (!use_smooth) {
1354 attributes.add<bool>("sharp_face",
1357 }
1358}
1359
1360void mesh_sharp_edges_set_from_angle(Mesh &mesh, const float angle, const bool keep_sharp_edges)
1361{
1362 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1363 if (angle >= M_PI) {
1364 mesh_smooth_set(mesh, true, keep_sharp_edges);
1365 return;
1366 }
1367 if (angle == 0.0f) {
1368 mesh_smooth_set(mesh, false, keep_sharp_edges);
1369 return;
1370 }
1371 if (!keep_sharp_edges) {
1372 attributes.remove("sharp_edge");
1373 }
1374 SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
1375 "sharp_edge", AttrDomain::Edge);
1376 const VArraySpan<bool> sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
1378 mesh.corner_verts(),
1379 mesh.corner_edges(),
1380 mesh.face_normals(),
1381 mesh.corner_to_face_map(),
1382 sharp_faces,
1383 angle,
1384 sharp_edges.span);
1385 sharp_edges.finish();
1386}
1387
1388} // namespace blender::bke
1389
1390std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
1391{
1392 using namespace blender;
1393 const int verts_num = BKE_mesh_wrapper_vert_len(this);
1394 if (verts_num == 0) {
1395 return std::nullopt;
1396 }
1397 this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
1398 switch (this->runtime->wrapper_type) {
1400 r_bounds = *BKE_editmesh_cache_calc_minmax(*this->runtime->edit_mesh,
1401 *this->runtime->edit_data);
1402 break;
1405 r_bounds = *bounds::min_max(this->vert_positions());
1406 break;
1407 }
1408 });
1409 return this->runtime->bounds_cache.data();
1410}
1411
1412void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)
1413{
1414 this->runtime->bounds_cache.ensure([&](blender::Bounds<float3> &r_data) { r_data = bounds; });
1415}
1416
1418{
1419 return mesh.runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH && mesh.runtime->edit_mesh &&
1420 mesh.runtime->edit_mesh->bm;
1421}
1422
1423std::optional<int> Mesh::material_index_max() const
1424{
1425 this->runtime->max_material_index.ensure([&](std::optional<int> &value) {
1426 if (use_bmesh_material_indices(*this)) {
1427 BMesh *bm = this->runtime->edit_mesh->bm;
1428 if (bm->totface == 0) {
1429 value = std::nullopt;
1430 return;
1431 }
1432 int max_material_index = 0;
1433 BMFace *efa;
1434 BMIter iter;
1435 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1436 max_material_index = std::max<int>(max_material_index, efa->mat_nr);
1437 }
1438 value = max_material_index;
1439 return;
1440 }
1441 if (this->faces_num == 0) {
1442 value = std::nullopt;
1443 return;
1444 }
1446 this->attributes()
1447 .lookup_or_default<int>("material_index", blender::bke::AttrDomain::Face, 0)
1448 .varray);
1449 if (value.has_value()) {
1450 value = std::clamp(*value, 0, MAXMAT);
1451 }
1452 });
1453 return this->runtime->max_material_index.data();
1454}
1455
1456const blender::VectorSet<int> &Mesh::material_indices_used() const
1457{
1458 using namespace blender;
1459 this->runtime->used_material_indices.ensure([&](VectorSet<int> &r_data) {
1460 const std::optional<int> max_material_index_opt = this->material_index_max();
1461 r_data.clear();
1462 if (!max_material_index_opt.has_value()) {
1463 return;
1464 }
1465 const int max_material_index = *max_material_index_opt;
1466 const auto clamp_material_index = [&](const int index) {
1467 return std::clamp<int>(index, 0, max_material_index);
1468 };
1469
1470 /* Find used indices in parallel and then create the vector set in the end. */
1471 Array<bool> used_indices(max_material_index + 1, false);
1472 if (use_bmesh_material_indices(*this)) {
1473 BMesh *bm = this->runtime->edit_mesh->bm;
1474 BMFace *efa;
1475 BMIter iter;
1476 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1477 used_indices[clamp_material_index(efa->mat_nr)] = true;
1478 }
1479 }
1480 else if (const VArray<int> material_indices =
1481 this->attributes()
1482 .lookup_or_default<int>("material_index", bke::AttrDomain::Face, 0)
1483 .varray)
1484 {
1485 if (const std::optional<int> single_material_index = material_indices.get_if_single()) {
1486 used_indices[clamp_material_index(*single_material_index)] = true;
1487 }
1488 else {
1489 VArraySpan<int> material_indices_span = material_indices;
1490 threading::parallel_for(
1491 material_indices_span.index_range(), 1024, [&](const IndexRange range) {
1492 for (const int i : range) {
1493 used_indices[clamp_material_index(material_indices_span[i])] = true;
1494 }
1495 });
1496 }
1497 }
1498 for (const int i : used_indices.index_range()) {
1499 if (used_indices[i]) {
1500 r_data.add_new(i);
1501 }
1502 }
1503 });
1504 return this->runtime->used_material_indices.data();
1505}
1506
1507namespace blender::bke {
1508
1509static void transform_positions(MutableSpan<float3> positions, const float4x4 &matrix)
1510{
1511 threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
1512 for (float3 &position : positions.slice(range)) {
1513 position = math::transform_point(matrix, position);
1514 }
1515 });
1516}
1517
1518static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
1519{
1520 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
1521 for (float3 &position : positions.slice(range)) {
1522 position += translation;
1523 }
1524 });
1525}
1526
1527void mesh_translate(Mesh &mesh, const float3 &translation, const bool do_shape_keys)
1528{
1529 if (math::is_zero(translation)) {
1530 return;
1531 }
1532
1533 std::optional<Bounds<float3>> bounds;
1534 if (mesh.runtime->bounds_cache.is_cached()) {
1535 bounds = mesh.runtime->bounds_cache.data();
1536 }
1537
1538 translate_positions(mesh.vert_positions_for_write(), translation);
1539
1540 if (do_shape_keys && mesh.key) {
1541 LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
1542 translate_positions({static_cast<float3 *>(kb->data), kb->totelem}, translation);
1543 }
1544 }
1545
1546 mesh.tag_positions_changed_uniformly();
1547
1548 if (bounds) {
1549 bounds->min += translation;
1550 bounds->max += translation;
1551 mesh.bounds_set_eager(*bounds);
1552 }
1553}
1554
1555void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
1556{
1557 transform_positions(mesh.vert_positions_for_write(), transform);
1558
1559 if (do_shape_keys && mesh.key) {
1560 LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
1561 transform_positions(MutableSpan(static_cast<float3 *>(kb->data), kb->totelem), transform);
1562 }
1563 }
1564 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1566
1567 mesh.tag_positions_changed();
1568}
1569
1570} // namespace blender::bke
1571
1576
1577/* -------------------------------------------------------------------- */
1578/* MSelect functions (currently used in weight paint mode) */
1579
1581{
1582 MEM_SAFE_FREE(mesh->mselect);
1583 mesh->totselect = 0;
1584}
1585
1587{
1588 using namespace blender;
1589 using namespace blender::bke;
1590 MSelect *mselect_src, *mselect_dst;
1591 int i_src, i_dst;
1592
1593 if (mesh->totselect == 0) {
1594 return;
1595 }
1596
1597 mselect_src = mesh->mselect;
1598 mselect_dst = MEM_malloc_arrayN<MSelect>(size_t(mesh->totselect), "Mesh selection history");
1599
1600 const AttributeAccessor attributes = mesh->attributes();
1601 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1602 ".select_vert", AttrDomain::Point, false);
1603 const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
1604 ".select_edge", AttrDomain::Edge, false);
1605 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
1606 ".select_poly", AttrDomain::Face, false);
1607
1608 for (i_src = 0, i_dst = 0; i_src < mesh->totselect; i_src++) {
1609 int index = mselect_src[i_src].index;
1610 switch (mselect_src[i_src].type) {
1611 case ME_VSEL: {
1612 if (select_vert[index]) {
1613 mselect_dst[i_dst] = mselect_src[i_src];
1614 i_dst++;
1615 }
1616 break;
1617 }
1618 case ME_ESEL: {
1619 if (select_edge[index]) {
1620 mselect_dst[i_dst] = mselect_src[i_src];
1621 i_dst++;
1622 }
1623 break;
1624 }
1625 case ME_FSEL: {
1626 if (select_poly[index]) {
1627 mselect_dst[i_dst] = mselect_src[i_src];
1628 i_dst++;
1629 }
1630 break;
1631 }
1632 default: {
1634 break;
1635 }
1636 }
1637 }
1638
1639 MEM_freeN(mselect_src);
1640
1641 if (i_dst == 0) {
1642 MEM_freeN(mselect_dst);
1643 mselect_dst = nullptr;
1644 }
1645 else if (i_dst != mesh->totselect) {
1646 mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
1647 }
1648
1649 mesh->totselect = i_dst;
1650 mesh->mselect = mselect_dst;
1651}
1652
1653int BKE_mesh_mselect_find(const Mesh *mesh, int index, int type)
1654{
1656
1657 for (int i = 0; i < mesh->totselect; i++) {
1658 if ((mesh->mselect[i].index == index) && (mesh->mselect[i].type == type)) {
1659 return i;
1660 }
1661 }
1662
1663 return -1;
1664}
1665
1667{
1669
1670 if (mesh->totselect) {
1671 if (mesh->mselect[mesh->totselect - 1].type == type) {
1672 return mesh->mselect[mesh->totselect - 1].index;
1673 }
1674 }
1675 return -1;
1676}
1677
1678void BKE_mesh_mselect_active_set(Mesh *mesh, int index, int type)
1679{
1680 const int msel_index = BKE_mesh_mselect_find(mesh, index, type);
1681
1682 if (msel_index == -1) {
1683 /* add to the end */
1684 mesh->mselect = (MSelect *)MEM_reallocN(mesh->mselect,
1685 sizeof(MSelect) * (mesh->totselect + 1));
1686 mesh->mselect[mesh->totselect].index = index;
1687 mesh->mselect[mesh->totselect].type = type;
1688 mesh->totselect++;
1689 }
1690 else if (msel_index != mesh->totselect - 1) {
1691 /* move to the end */
1692 std::swap(mesh->mselect[msel_index], mesh->mselect[mesh->totselect - 1]);
1693 }
1694
1695 BLI_assert((mesh->mselect[mesh->totselect - 1].index == index) &&
1696 (mesh->mselect[mesh->totselect - 1].type == type));
1697}
1698
1699void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
1700{
1701 r_count[0] = r_count[1] = r_count[2] = 0;
1702 if (mesh->runtime->edit_mesh) {
1703 BMesh *bm = mesh->runtime->edit_mesh->bm;
1704 r_count[0] = bm->totvertsel;
1705 r_count[1] = bm->totedgesel;
1706 r_count[2] = bm->totfacesel;
1707 }
1708 /* We could support faces in paint modes. */
1709}
1710
1711/* **** Depsgraph evaluation **** */
1712
1714{
1715 DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
1717 /* We are here because something did change in the mesh. This means we can not trust the existing
1718 * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
1719 * evaluated mesh and let objects to re-create it with updated settings. */
1720 if (mesh->runtime->mesh_eval != nullptr) {
1721 BKE_id_free(nullptr, mesh->runtime->mesh_eval);
1722 mesh->runtime->mesh_eval = nullptr;
1723 }
1724 if (DEG_is_active(depsgraph)) {
1725 Mesh *mesh_orig = DEG_get_original(mesh);
1726 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED) {
1728 copy_v3_v3(mesh_orig->texspace_location, mesh->texspace_location);
1729 copy_v3_v3(mesh_orig->texspace_size, mesh->texspace_size);
1730 }
1731 }
1732}
AttrDomainMask
#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:125
void CustomData_blend_write_prepare(CustomData &data, blender::bke::AttrDomain domain, int domain_size, blender::Vector< CustomDataLayer, 16 > &layers_to_write, blender::bke::AttributeStorage::BlendWriteData &write_data)
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)
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:94
void CustomData_reset(CustomData *data)
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
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_free(CustomData *data)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, 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)
bool CustomData_free_layer_named(CustomData *data, blender::StringRef name)
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:1632
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:71
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1656
std::optional< blender::Bounds< blender::float3 > > BKE_editmesh_cache_calc_minmax(const BMEditMesh &em, const blender::bke::EditMeshData &emd)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:165
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:44
IDTypeInfo IDType_ID_ME
@ LIB_ID_CREATE_LOCALIZE
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_SHAPEKEY
struct ID * BKE_id_copy_in_lib(Main *bmain, std::optional< Library * > owner_library, const ID *id, std::optional< const ID * > new_owner_id, ID **new_id_p, int flag)
Definition lib_id.cc:663
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1428
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:353
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1433
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:767
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1495
void id_us_min(ID *id)
Definition lib_id.cc:361
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1500
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2611
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER
LibraryForeachIDFlag BKE_lib_query_foreachid_process_flags_get(const LibraryForeachIDData *data)
Definition lib_query.cc:129
@ 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_sync_length(Main *bmain, Object *ob, 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
@ ME_WRAPPER_TYPE_SUBD
@ ME_WRAPPER_TYPE_BMESH
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:445
General operations, lookup, etc. for blender objects.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
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:87
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
#define M_PI
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.cc:41
char * BLI_strdupn(const char *str, size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:30
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
unsigned int uint
Platform independent time functions.
long int BLI_time_now_seconds_i(void)
Definition time.cc:75
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define STREQ(a, b)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5351
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:5244
#define BLO_read_struct_list(reader, struct_name, list)
#define BLO_read_struct_array(reader, struct_name, array_size, ptr_p)
void BLO_write_pointer_array(BlendWriter *writer, int64_t num, const void *data_ptr)
void BLO_read_pointer_array(BlendDataReader *reader, int64_t array_size, void **ptr_p)
Definition readfile.cc:5402
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)
#define BLT_I18NCONTEXT_ID_MESH
bool DEG_is_active(const Depsgraph *depsgraph)
Definition depsgraph.cc:323
void DEG_debug_print_eval(Depsgraph *depsgraph, const char *function_name, const char *object_name, const void *object_address)
T * DEG_get_original(T *id)
@ ID_TAG_COPIED_ON_EVAL
Definition DNA_ID.h:905
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:886
@ INDEX_ID_ME
Definition DNA_ID.h:1234
@ ID_ME
@ CD_MVERT_SKIN
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ CD_PROP_INT16_2D
#define DNA_struct_default_get(struct_name)
#define MAXMAT
@ ME_TEXSPACE_FLAG_AUTO
@ ME_TEXSPACE_FLAG_AUTO_EVALUATED
@ ME_VSEL
@ ME_FSEL
@ ME_ESEL
struct MDeformVert MDeformVert
@ MVERT_SKIN_ROOT
Object is a sort of wrapper for general info.
@ OB_MESH
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
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)
BMesh * BKE_mesh_to_bmesh(Mesh *mesh, const int active_shapekey, const bool add_key_index, const BMeshCreateParams *params)
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)
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)
bool BKE_mesh_attribute_required(const StringRef name)
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)
static void rename_seam_layer_to_old_name(const ListBase vertex_groups, const Span< CustomDataLayer > vert_layers, MutableSpan< CustomDataLayer > edge_layers, const Span< CustomDataLayer > face_layers, const Span< CustomDataLayer > corner_layers)
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)
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)
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)
static bool use_bmesh_material_indices(const 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)
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 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
BMesh const char void * data
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
BPy_StructRNA * depsgraph
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
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
AttributeSet attributes
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool contains(const T &value) const
Definition BLI_span.hh:277
static VArray ForSingle(T value, const int64_t size)
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
GAttributeWriter lookup_for_write(StringRef attribute_id)
bool remove(const StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const eCustomDataType data_type, const AttributeInit &initializer)
void add_shared(const ImplicitSharingInfo *sharing_info, const FunctionRef< void(MemoryCounter &shared_memory)> count_fn)
static ushort indices[]
#define this
#define FILTER_ID_MA
#define MEM_SAFE_FREE(v)
#define FILTER_ID_ME
#define CD_MASK_COLOR_ALL
#define MEM_reallocN(vmemh, len)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define FILTER_ID_KE
#define FILTER_ID_IM
static void transform_positions(const Span< blender::float3 > src, const blender::float4x4 &transform, blender::MutableSpan< blender::float3 > dst)
#define UINT_MAX
Definition hash_md5.cc:44
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
CCL_NAMESPACE_BEGIN ccl_device float invert(const float color, const float factor)
Definition invert.h:11
static char ** types
Definition makesdna.cc:71
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
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)
static void translate_positions(MutableSpan< float3 > positions, const float3 &translation)
void mesh_sharp_edges_set_from_angle(Mesh &mesh, float angle, bool keep_sharp_edges=false)
const AttributeAccessorFunctions & mesh_attribute_accessor_functions()
void mesh_remove_invalid_attribute_strings(Mesh &mesh)
static bool meta_data_matches(const std::optional< bke::AttributeMetaData > meta_data, const AttrDomainMask domains, const eCustomDataMask types)
void mesh_convert_storage_to_customdata(Mesh &mesh)
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)
void mesh_custom_normals_to_legacy(MutableSpan< CustomDataLayer > corner_layers)
Mesh * mesh_new_no_attributes(int verts_num, int edges_num, int faces_num, int corners_num)
void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
void mesh_sculpt_mask_to_legacy(MutableSpan< CustomDataLayer > vert_layers)
void transform_custom_normal_attribute(const float4x4 &transform, MutableAttributeAccessor &attributes)
void mesh_ensure_required_data_layers(Mesh &mesh)
static void transform_positions(MutableSpan< float3 > positions, const float4x4 &matrix)
void mesh_translate(Mesh &mesh, const float3 &translation, bool do_shape_keys)
void attribute_storage_blend_write_prepare(AttributeStorage &data, const Map< AttrDomain, Vector< CustomDataLayer, 16 > * > &layers_to_write, AttributeStorage::BlendWriteData &write_data)
std::optional< T > max(const VArray< T > &values)
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)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
short mat_nr
int totface
CustomDataExternal * external
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
float texspace_size[3]
float remesh_voxel_adaptivity
struct Mesh * texcomesh
int corners_num
CustomData edge_data
struct AttributeStorage attribute_storage
char symmetry
char texspace_flag
int edges_num
MeshRuntimeHandle * runtime
uint16_t flag
struct Material ** mat
char * active_uv_map_attribute
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
char * default_uv_map_attribute
float texspace_location[3]
int faces_num
struct MSelect * mselect
int verts_num
char * active_color_attribute
const ImplicitSharingInfo * face_offsets_sharing_info
i
Definition text_draw.cc:230
#define N_(msgid)
uint8_t flag
Definition wm_window.cc:139