Blender V5.0
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_array_utils.hh"
24#include "BLI_bounds.hh"
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.h"
31#include "BLI_math_vector.hh"
32#include "BLI_memory_counter.hh"
33#include "BLI_resource_scope.hh"
34#include "BLI_set.hh"
35#include "BLI_span.hh"
36#include "BLI_string.h"
37#include "BLI_task.hh"
38#include "BLI_time.h"
39#include "BLI_utildefines.h"
40#include "BLI_vector.hh"
41#include "BLI_virtual_array.hh"
42
43#include "BLT_translation.hh"
44
45#include "BKE_anim_data.hh"
47#include "BKE_attribute.hh"
49#include "BKE_attribute_math.hh"
53#include "BKE_bpath.hh"
54#include "BKE_deform.hh"
55#include "BKE_editmesh.hh"
56#include "BKE_editmesh_cache.hh"
57#include "BKE_global.hh"
58#include "BKE_idtype.hh"
59#include "BKE_key.hh"
60#include "BKE_lib_id.hh"
61#include "BKE_lib_query.hh"
62#include "BKE_main.hh"
63#include "BKE_material.hh"
64#include "BKE_mesh.hh"
66#include "BKE_mesh_runtime.hh"
67#include "BKE_mesh_wrapper.hh"
68#include "BKE_modifier.hh"
69#include "BKE_multires.hh"
70#include "BKE_object.hh"
71#include "BKE_paint_bvh.hh"
72
73#include "DEG_depsgraph.hh"
75
76#include "BLO_read_write.hh"
77
79#define STACK_FIXED_DEPTH 100
80
81using blender::float3;
82using blender::int2;
85using blender::Span;
87using blender::VArray;
88using blender::Vector;
89
90static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata);
91
92static void mesh_init_data(ID *id)
93{
94 Mesh *mesh = reinterpret_cast<Mesh *>(id);
95
97
99
105
108
110}
111
112static void mesh_copy_data(Main *bmain,
113 std::optional<Library *> owner_library,
114 ID *id_dst,
115 const ID *id_src,
116 const int flag)
117{
118 Mesh *mesh_dst = reinterpret_cast<Mesh *>(id_dst);
119 const Mesh *mesh_src = reinterpret_cast<const Mesh *>(id_src);
120
121 mesh_dst->runtime = new blender::bke::MeshRuntime();
122 mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only;
123 /* Subd runtime.mesh_eval is not copied, will need to be reevaluated. */
124 mesh_dst->runtime->wrapper_type = (mesh_src->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) ?
126 mesh_src->runtime->wrapper_type;
127 mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data;
128 mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra;
129 /* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or
130 * node, but we still need to be able to draw face center vertices and "optimal edges"
131 * differently. The tags may be cleared explicitly when the topology is changed. */
132 mesh_dst->runtime->subsurf_face_dot_tags = mesh_src->runtime->subsurf_face_dot_tags;
133 mesh_dst->runtime->subsurf_optimal_display_edges =
134 mesh_src->runtime->subsurf_optimal_display_edges;
135 if ((mesh_src->id.tag & ID_TAG_NO_MAIN) == 0) {
136 /* This is a direct copy of a main mesh, so for now it has the same topology. */
137 mesh_dst->runtime->deformed_only = true;
138 }
139 /* This option is set for run-time meshes that have been copied from the current object's mode.
140 * Currently this is used for edit-mesh although it could be used for sculpt or other
141 * kinds of data specific to an object's mode.
142 *
143 * The flag signals that the mesh hasn't been modified from the data that generated it,
144 * allowing us to use the object-mode data for drawing.
145 *
146 * While this could be the caller's responsibility, keep here since it's
147 * highly unlikely we want to create a duplicate and not use it for drawing. */
148 mesh_dst->runtime->is_original_bmesh = false;
149
150 /* Share various derived caches between the source and destination mesh for improved performance
151 * when the source is persistent and edits to the destination mesh don't affect the caches.
152 * Caches will be "un-shared" as necessary later on. */
153 mesh_dst->runtime->bounds_cache = mesh_src->runtime->bounds_cache;
154 mesh_dst->runtime->vert_normals_cache = mesh_src->runtime->vert_normals_cache;
155 mesh_dst->runtime->vert_normals_true_cache = mesh_src->runtime->vert_normals_true_cache;
156 mesh_dst->runtime->face_normals_cache = mesh_src->runtime->face_normals_cache;
157 mesh_dst->runtime->face_normals_true_cache = mesh_src->runtime->face_normals_true_cache;
158 mesh_dst->runtime->corner_normals_cache = mesh_src->runtime->corner_normals_cache;
159 mesh_dst->runtime->loose_verts_cache = mesh_src->runtime->loose_verts_cache;
160 mesh_dst->runtime->verts_no_face_cache = mesh_src->runtime->verts_no_face_cache;
161 mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache;
162 mesh_dst->runtime->corner_tris_cache = mesh_src->runtime->corner_tris_cache;
163 mesh_dst->runtime->corner_tri_faces_cache = mesh_src->runtime->corner_tri_faces_cache;
164 mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache;
165 mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache;
166 mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache;
167 mesh_dst->runtime->corner_to_face_map_cache = mesh_src->runtime->corner_to_face_map_cache;
168 mesh_dst->runtime->bvh_cache_verts = mesh_src->runtime->bvh_cache_verts;
169 mesh_dst->runtime->bvh_cache_edges = mesh_src->runtime->bvh_cache_edges;
170 mesh_dst->runtime->bvh_cache_faces = mesh_src->runtime->bvh_cache_faces;
171 mesh_dst->runtime->bvh_cache_corner_tris = mesh_src->runtime->bvh_cache_corner_tris;
172 mesh_dst->runtime->bvh_cache_corner_tris_no_hidden =
173 mesh_src->runtime->bvh_cache_corner_tris_no_hidden;
174 mesh_dst->runtime->bvh_cache_loose_verts = mesh_src->runtime->bvh_cache_loose_verts;
175 mesh_dst->runtime->bvh_cache_loose_verts_no_hidden =
176 mesh_src->runtime->bvh_cache_loose_verts_no_hidden;
177 mesh_dst->runtime->bvh_cache_loose_edges = mesh_src->runtime->bvh_cache_loose_edges;
178 mesh_dst->runtime->bvh_cache_loose_edges_no_hidden =
179 mesh_src->runtime->bvh_cache_loose_edges_no_hidden;
180 mesh_dst->runtime->max_material_index = mesh_src->runtime->max_material_index;
181 if (mesh_src->runtime->bake_materials) {
182 mesh_dst->runtime->bake_materials = std::make_unique<blender::bke::bake::BakeMaterialsList>(
183 *mesh_src->runtime->bake_materials);
184 }
185
186 /* Only do tessface if we have no faces. */
187 const bool do_tessface = ((mesh_src->totface_legacy != 0) && (mesh_src->faces_num == 0));
188
190
191 if (mesh_src->id.tag & ID_TAG_NO_MAIN) {
192 /* For copies in depsgraph, keep data like #CD_ORIGINDEX and #CD_ORCO. */
194
195 /* Meshes copied during evaluation pass the edit mesh pointer to determine whether a mapping
196 * from the evaluated to the original state is possible. */
197 mesh_dst->runtime->edit_mesh = mesh_src->runtime->edit_mesh;
198 if (const blender::bke::EditMeshData *edit_data = mesh_src->runtime->edit_data.get()) {
199 mesh_dst->runtime->edit_data = std::make_unique<blender::bke::EditMeshData>(*edit_data);
200 }
201 }
202
203 mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat);
204
206 mesh_dst->active_color_attribute = static_cast<char *>(
208 mesh_dst->default_color_attribute = static_cast<char *>(
210 mesh_dst->active_uv_map_attribute = static_cast<char *>(
212 mesh_dst->default_uv_map_attribute = static_cast<char *>(
214
216 &mesh_src->vert_data, &mesh_dst->vert_data, mask.vmask, mesh_dst->verts_num);
218 &mesh_src->edge_data, &mesh_dst->edge_data, mask.emask, mesh_dst->edges_num);
220 &mesh_src->corner_data, &mesh_dst->corner_data, mask.lmask, mesh_dst->corners_num);
222 &mesh_src->face_data, &mesh_dst->face_data, mask.pmask, mesh_dst->faces_num);
223 new (&mesh_dst->attribute_storage.wrap())
226 mesh_src->runtime->face_offsets_sharing_info,
227 &mesh_dst->face_offset_indices,
228 &mesh_dst->runtime->face_offsets_sharing_info);
229 if (do_tessface) {
231 &mesh_src->fdata_legacy, &mesh_dst->fdata_legacy, mask.fmask, mesh_dst->totface_legacy);
232 }
233 else {
234 mesh_tessface_clear_intern(mesh_dst, false);
235 }
236
237 mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
238
239 if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) {
240 BKE_id_copy_in_lib(bmain,
241 owner_library,
242 &mesh_src->key->id,
243 &mesh_dst->id,
244 reinterpret_cast<ID **>(&mesh_dst->key),
245 flag);
246 }
247}
248
249static void mesh_free_data(ID *id)
250{
251 Mesh *mesh = reinterpret_cast<Mesh *>(id);
252
263 mesh->attribute_storage.wrap().~AttributeStorage();
264 if (mesh->face_offset_indices) {
266 &mesh->runtime->face_offsets_sharing_info);
267 }
268 MEM_SAFE_FREE(mesh->mselect);
269 MEM_SAFE_FREE(mesh->mat);
270 delete mesh->runtime;
271}
272
274{
275 Mesh *mesh = reinterpret_cast<Mesh *>(id);
276
279 for (int i = 0; i < mesh->totcol; i++) {
281 }
282}
283
284static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data)
285{
286 Mesh *mesh = reinterpret_cast<Mesh *>(id);
287 if (mesh->corner_data.external) {
290 sizeof(mesh->corner_data.external->filepath));
291 }
292}
293
295{
296 Mesh *mesh = reinterpret_cast<Mesh *>(id);
297#if 0
298 /* In the future we'll be able to use just this. */
299 mesh->attribute_storage.wrap().foreach_working_space_color(fn);
300#else
301 auto convert_domain = [&fn](CustomData *customdata, size_t size) {
302 for (int i = 0; i < customdata->totlayer; i++) {
303 CustomDataLayer *layer = &customdata->layers[i];
304 if (layer->data && layer->type == CD_PROP_COLOR) {
306 *reinterpret_cast<blender::ImplicitSharingPtr<> *>(&layer->sharing_info),
307 reinterpret_cast<blender::ColorGeometry4f *&>(layer->data),
308 size);
309 }
310 }
311 };
312
313 convert_domain(&mesh->vert_data, mesh->verts_num);
314 convert_domain(&mesh->edge_data, mesh->edges_num);
315 convert_domain(&mesh->face_data, mesh->faces_num);
316 convert_domain(&mesh->corner_data, mesh->corners_num);
317#endif
318}
319
320static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address)
321{
322 using namespace blender;
323 using namespace blender::bke;
324 Mesh *mesh = reinterpret_cast<Mesh *>(id);
325 const bool is_undo = BLO_write_is_undo(writer);
326
327 ResourceScope scope;
328 Vector<CustomDataLayer, 16> vert_layers;
329 Vector<CustomDataLayer, 16> edge_layers;
330 Vector<CustomDataLayer, 16> loop_layers;
331 Vector<CustomDataLayer, 16> face_layers;
332 bke::AttributeStorage::BlendWriteData attribute_data{scope};
333
334 /* Cache only - don't write. */
335 mesh->mface = nullptr;
336 mesh->totface_legacy = 0;
337 mesh->fdata_legacy = CustomData{};
338
339 /* Convert from the format still used at runtime (flags on #CustomDataLayer) to the format
340 * reserved for future runtime use (names stored on #Mesh). */
341 if (const char *name = CustomData_get_active_layer_name(&mesh->corner_data, CD_PROP_FLOAT2)) {
342 mesh->active_uv_map_attribute = const_cast<char *>(
343 scope.allocator().copy_string(name).c_str());
344 }
345 else {
346 mesh->active_uv_map_attribute = nullptr;
347 }
348 if (const char *name = CustomData_get_render_layer_name(&mesh->corner_data, CD_PROP_FLOAT2)) {
349 mesh->default_uv_map_attribute = const_cast<char *>(
350 scope.allocator().copy_string(name).c_str());
351 }
352 else {
353 mesh->default_uv_map_attribute = nullptr;
354 }
355
356 /* Do not store actual geometry data in case this is a library override ID. */
357 if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) {
358 mesh->verts_num = 0;
359 mesh->vert_data = CustomData{};
360
361 mesh->edges_num = 0;
362 mesh->edge_data = CustomData{};
363
364 mesh->corners_num = 0;
365 mesh->corner_data = CustomData{};
366
367 mesh->faces_num = 0;
368 mesh->face_data = CustomData{};
369 mesh->face_offset_indices = nullptr;
370 }
371 else {
372 attribute_storage_blend_write_prepare(mesh->attribute_storage.wrap(), attribute_data);
374 mesh->vert_data, AttrDomain::Point, mesh->verts_num, vert_layers, attribute_data);
376 mesh->edge_data, AttrDomain::Edge, mesh->edges_num, edge_layers, attribute_data);
378 mesh->face_data, AttrDomain::Face, mesh->faces_num, face_layers, attribute_data);
380 mesh->corner_data, AttrDomain::Corner, mesh->corners_num, loop_layers, attribute_data);
381 if (!is_undo) {
383 attribute_data, mesh->edge_data, mesh->face_data, edge_layers, face_layers);
384 }
385 if (attribute_data.attributes.is_empty()) {
386 mesh->attribute_storage.dna_attributes = nullptr;
387 mesh->attribute_storage.dna_attributes_num = 0;
388 }
389 else {
390 mesh->attribute_storage.dna_attributes = attribute_data.attributes.data();
391 mesh->attribute_storage.dna_attributes_num = attribute_data.attributes.size();
392 }
393 }
394
395 const blender::bke::MeshRuntime *mesh_runtime = mesh->runtime;
396 mesh->runtime = nullptr;
397
398 BLO_write_shared_tag(writer, mesh->face_offset_indices);
399
400 BLO_write_id_struct(writer, Mesh, id_address, &mesh->id);
401 BKE_id_blend_write(writer, &mesh->id);
402
403 BKE_defbase_blend_write(writer, &mesh->vertex_group_names);
404 BLO_write_string(writer, mesh->active_color_attribute);
405 BLO_write_string(writer, mesh->default_color_attribute);
406 BLO_write_string(writer, mesh->active_uv_map_attribute);
407 BLO_write_string(writer, mesh->default_uv_map_attribute);
408
409 BLO_write_pointer_array(writer, mesh->totcol, mesh->mat);
410 BLO_write_struct_array(writer, MSelect, mesh->totselect, mesh->mselect);
411
413 writer, &mesh->vert_data, vert_layers, mesh->verts_num, CD_MASK_MESH.vmask, &mesh->id);
415 writer, &mesh->edge_data, edge_layers, mesh->edges_num, CD_MASK_MESH.emask, &mesh->id);
416 /* `fdata` is cleared above but written so slots align. */
418 writer, &mesh->fdata_legacy, {}, mesh->totface_legacy, CD_MASK_MESH.fmask, &mesh->id);
420 writer, &mesh->corner_data, loop_layers, mesh->corners_num, CD_MASK_MESH.lmask, &mesh->id);
422 writer, &mesh->face_data, face_layers, mesh->faces_num, CD_MASK_MESH.pmask, &mesh->id);
423
424 mesh->attribute_storage.wrap().blend_write(*writer, attribute_data);
425
426 if (mesh->face_offset_indices) {
428 writer,
429 mesh->face_offset_indices,
430 sizeof(int) * mesh->faces_num,
431 mesh_runtime->face_offsets_sharing_info,
432 [&]() { BLO_write_int32_array(writer, mesh->faces_num + 1, mesh->face_offset_indices); });
433 }
434}
435
436static void mesh_blend_read_data(BlendDataReader *reader, ID *id)
437{
438 Mesh *mesh = reinterpret_cast<Mesh *>(id);
439 BLO_read_pointer_array(reader, mesh->totcol, (void **)&mesh->mat);
440 /* This check added for python created meshes. */
441 if (!mesh->mat) {
442 mesh->totcol = 0;
443 }
444
445 /* Deprecated pointers to custom data layers are read here for backward compatibility
446 * with files where these were owning pointers rather than a view into custom data. */
447 BLO_read_struct_array(reader, MVert, mesh->verts_num, &mesh->mvert);
448 BLO_read_struct_array(reader, MEdge, mesh->edges_num, &mesh->medge);
449 BLO_read_struct_array(reader, MFace, mesh->totface_legacy, &mesh->mface);
450 BLO_read_struct_array(reader, MTFace, mesh->totface_legacy, &mesh->mtface);
451 BLO_read_struct_array(reader, MDeformVert, mesh->verts_num, &mesh->dvert);
452 BLO_read_struct_array(reader, TFace, mesh->totface_legacy, &mesh->tface);
453 BLO_read_struct_array(reader, MCol, mesh->totface_legacy, &mesh->mcol);
454
455 BLO_read_struct_array(reader, MSelect, mesh->totselect, &mesh->mselect);
456
457 BLO_read_struct_list(reader, bDeformGroup, &mesh->vertex_group_names);
458
459 CustomData_blend_read(reader, &mesh->vert_data, mesh->verts_num);
460 CustomData_blend_read(reader, &mesh->edge_data, mesh->edges_num);
461 CustomData_blend_read(reader, &mesh->fdata_legacy, mesh->totface_legacy);
462 CustomData_blend_read(reader, &mesh->corner_data, mesh->corners_num);
463 CustomData_blend_read(reader, &mesh->face_data, mesh->faces_num);
464 mesh->attribute_storage.wrap().blend_read(*reader);
465 if (mesh->deform_verts().is_empty()) {
466 /* Vertex group data was also an owning pointer in old Blender versions.
467 * Don't read them again if they were read as part of #CustomData. */
468 BKE_defvert_blend_read(reader, mesh->verts_num, mesh->dvert);
469 }
470 BLO_read_string(reader, &mesh->active_color_attribute);
471 BLO_read_string(reader, &mesh->default_color_attribute);
472 BLO_read_string(reader, &mesh->active_uv_map_attribute);
473 BLO_read_string(reader, &mesh->default_uv_map_attribute);
474
475 /* Forward compatibility. To be removed when runtime format changes. */
477
478 mesh->texspace_flag &= ~ME_TEXSPACE_FLAG_AUTO_EVALUATED;
479
480 mesh->runtime = new blender::bke::MeshRuntime();
481
482 if (mesh->face_offset_indices) {
483 mesh->runtime->face_offsets_sharing_info = BLO_read_shared(
484 reader, &mesh->face_offset_indices, [&]() {
485 BLO_read_int32_array(reader, mesh->faces_num + 1, &mesh->face_offset_indices);
486 return blender::implicit_sharing::info_for_mem_free(mesh->face_offset_indices);
487 });
488 }
489
490 if (mesh->mselect == nullptr) {
491 mesh->totselect = 0;
492 }
493
494 /* NOTE: this is endianness-sensitive. */
495 /* Each legacy TFace would need to undo the automatic DNA switch of its array of four uint32_t
496 * RGBA colors. */
497}
498
500 /*id_code*/ Mesh::id_type,
501 /*id_filter*/ FILTER_ID_ME,
502 /*dependencies_id_types*/ FILTER_ID_ME | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_KE,
503 /*main_listbase_index*/ INDEX_ID_ME,
504 /*struct_size*/ sizeof(Mesh),
505 /*name*/ "Mesh",
506 /*name_plural*/ N_("meshes"),
507 /*translation_context*/ BLT_I18NCONTEXT_ID_MESH,
509 /*asset_type_info*/ nullptr,
510
511 /*init_data*/ mesh_init_data,
512 /*copy_data*/ mesh_copy_data,
513 /*free_data*/ mesh_free_data,
514 /*make_local*/ nullptr,
515 /*foreach_id*/ mesh_foreach_id,
516 /*foreach_cache*/ nullptr,
517 /*foreach_path*/ mesh_foreach_path,
518 /*foreach_working_space_color*/ mesh_foreach_working_space_color,
519 /*owner_pointer_get*/ nullptr,
520
521 /*blend_write*/ mesh_blend_write,
522 /*blend_read_data*/ mesh_blend_read_data,
523 /*blend_read_after_liblink*/ nullptr,
524
525 /*blend_read_undo_preserve*/ nullptr,
526
527 /*lib_override_apply_post*/ nullptr,
528};
529
531{
532 return ELEM(name, "position", ".corner_vert", ".corner_edge", ".edge_verts");
533}
534
536{
537 BMesh *bm = mesh->runtime->edit_mesh ? mesh->runtime->edit_mesh->bm : nullptr;
538 MVertSkin *vs;
539
540 if (bm) {
541 if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) {
542 BMVert *v;
543 BMIter iter;
544
546
547 /* Mark an arbitrary vertex as root */
548 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
549 vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN);
550 vs->flag |= MVERT_SKIN_ROOT;
551 break;
552 }
553 }
554 }
555 else {
556 if (!CustomData_has_layer(&mesh->vert_data, CD_MVERT_SKIN)) {
558 &mesh->vert_data, CD_MVERT_SKIN, CD_SET_DEFAULT, mesh->verts_num);
559
560 /* Mark an arbitrary vertex as root */
561 if (vs) {
562 vs->flag |= MVERT_SKIN_ROOT;
563 }
564 }
565 }
566}
567
569{
570 if (mesh->runtime->edit_mesh) {
572 &mesh->runtime->edit_mesh->bm->ldata, CD_PROP_INT16_2D, "custom_normal");
573 }
574
575 return mesh->attributes().contains("custom_normal");
576}
577
578namespace blender::bke {
579
581 const StringRef id,
582 AttrDomain domain,
583 bke::AttrType data_type)
584{
586 return;
587 }
590 {
591 return;
592 }
593 if (mesh.default_color_attribute) {
594 return;
595 }
596 mesh.default_color_attribute = BLI_strdupn(id.data(), id.size());
597}
598
600{
601 MutableAttributeAccessor attributes = mesh.attributes_for_write();
602 AttributeInitConstruct attribute_init;
603
604 /* Try to create attributes if they do not exist. */
605 attributes.add("position", AttrDomain::Point, bke::AttrType::Float3, attribute_init);
606 attributes.add(".edge_verts", AttrDomain::Edge, bke::AttrType::Int32_2D, attribute_init);
607 attributes.add(".corner_vert", AttrDomain::Corner, bke::AttrType::Int32, attribute_init);
608 attributes.add(".corner_edge", AttrDomain::Corner, bke::AttrType::Int32, attribute_init);
609}
610
611static bool meta_data_matches(const std::optional<bke::AttributeMetaData> meta_data,
612 const AttrDomainMask domains,
613 const eCustomDataMask types)
614{
615 if (!meta_data) {
616 return false;
617 }
618 if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & domains)) {
619 return false;
620 }
621 if (!(CD_TYPE_AS_MASK(*attr_type_to_custom_data_type(meta_data->data_type)) & types)) {
622 return false;
623 }
624 return true;
625}
626
628{
629 bke::AttributeAccessor attributes = mesh.attributes();
630 if (!meta_data_matches(attributes.lookup_meta_data(mesh.active_color_attribute),
633 {
634 MEM_SAFE_FREE(mesh.active_color_attribute);
635 }
636 if (!meta_data_matches(attributes.lookup_meta_data(mesh.default_color_attribute),
639 {
640 MEM_SAFE_FREE(mesh.default_color_attribute);
641 }
642}
643
645{
646 return bounds::merge(a, b);
647}
648
650{
651 return {float3(std::numeric_limits<float>::max()), float3(std::numeric_limits<float>::lowest())};
652}
653
662
663static void partition_faces_recursively(const Span<float3> face_centers,
664 MutableSpan<int> face_indices,
666 int node_index,
667 int depth,
668 const std::optional<Bounds<float3>> &bounds_precalc,
669 const Span<int> material_indices,
670 int target_group_size)
671{
672 if (face_indices.size() <= target_group_size || depth >= STACK_FIXED_DEPTH - 1) {
673 if (!blender::bke::pbvh::leaf_needs_material_split(face_indices, material_indices)) {
674 groups[node_index].children_offset = 0;
675 groups[node_index].faces = Array<int>(face_indices.size(), NoInitialization());
676 std::copy(face_indices.begin(), face_indices.end(), groups[node_index].faces.begin());
677 return;
678 }
679 }
680
681 const int children_start = groups.size();
682 groups[node_index].children_offset = children_start;
683
684 groups.resize(groups.size() + 2);
685 groups[children_start].parent = node_index;
686 groups[children_start + 1].parent = node_index;
687
688 int split;
689 if (!(face_indices.size() <= target_group_size || depth >= STACK_FIXED_DEPTH - 1)) {
691 if (bounds_precalc) {
692 bounds = *bounds_precalc;
693 }
694 else {
696 face_indices.index_range(),
697 1024,
699 [&](const IndexRange range, Bounds<float3> value) {
700 for (const int face : face_indices.slice(range)) {
701 math::min_max(face_centers[face], value.min, value.max);
702 }
703 return value;
704 },
706 }
707 const int axis = math::dominant_axis(bounds.max - bounds.min);
708
710 face_centers, face_indices, axis, math::midpoint(bounds.min[axis], bounds.max[axis]));
711 }
712 else {
713 split = blender::bke::pbvh::partition_material_indices(material_indices, face_indices);
714 }
715
716 partition_faces_recursively(face_centers,
717 face_indices.take_front(split),
718 groups,
719 children_start,
720 depth + 1,
721 std::nullopt,
722 material_indices,
723 target_group_size);
724 partition_faces_recursively(face_centers,
725 face_indices.drop_front(split),
726 groups,
727 children_start + 1,
728 depth + 1,
729 std::nullopt,
730 material_indices,
731 target_group_size);
732}
733
734static void build_vertex_groups_for_leaves(const int verts_num,
736 const Span<int> corner_verts,
738{
739 Vector<int> leaf_indices;
740 for (const int i : groups.index_range()) {
741 if (groups[i].children_offset == 0 && !groups[i].faces.is_empty()) {
742 leaf_indices.append(i);
743 }
744 }
745
746 Array<Array<int>> verts_per_leaf(leaf_indices.size(), NoInitialization());
747
748 threading::parallel_for(leaf_indices.index_range(), 8, [&](const IndexRange range) {
749 Set<int> verts;
750 for (const int i : range) {
751 const int group_idx = leaf_indices[i];
752 NonContiguousGroup &group = groups[group_idx];
753 verts.clear();
754 int corners_count = 0;
755
756 for (const int face_index : group.faces) {
757 const IndexRange face = faces[face_index];
758 verts.add_multiple(corner_verts.slice(face));
759 corners_count += face.size();
760 }
761
762 new (&verts_per_leaf[i]) Array<int>(verts.size());
763 std::copy(verts.begin(), verts.end(), verts_per_leaf[i].begin());
764 std::sort(verts_per_leaf[i].begin(), verts_per_leaf[i].end());
765 group.corner_count = corners_count;
766 }
767 });
768
769 Vector<int> owned_verts;
770 Vector<int> shared_verts;
771 BitVector<> vert_used(verts_num);
772
773 for (const int i : leaf_indices.index_range()) {
774 const int group_idx = leaf_indices[i];
775 NonContiguousGroup &group = groups[group_idx];
776 owned_verts.clear();
777 shared_verts.clear();
778
779 for (const int vert : verts_per_leaf[i]) {
780 if (vert_used[vert]) {
781 shared_verts.append(vert);
782 }
783 else {
784 vert_used[vert].set();
785 owned_verts.append(vert);
786 }
787 }
788
789 if (!owned_verts.is_empty()) {
790 group.unique_verts = Array<int>(owned_verts.size());
791 std::copy(owned_verts.begin(), owned_verts.end(), group.unique_verts.begin());
792 }
793
794 if (!shared_verts.is_empty()) {
795 group.shared_verts = Array<int>(shared_verts.size());
796 std::copy(shared_verts.begin(), shared_verts.end(), group.shared_verts.begin());
797 }
798 }
799}
800
802{
803 const Span<float3> vert_positions = mesh.vert_positions();
804 const OffsetIndices<int> faces = mesh.faces();
805 const Span<int> corner_verts = mesh.corner_verts();
806
807 if (faces.is_empty()) {
808 return {};
809 }
810
811 Array<float3> face_centers(faces.size());
813 faces.index_range(),
814 1024,
816 [&](const IndexRange range, const Bounds<float3> &init) {
817 Bounds<float3> current = init;
818 for (const int face : range) {
820 vert_positions, corner_verts.slice(faces[face]));
821 face_centers[face] = bounds.center();
822 current = bounds::merge(current, bounds);
823 }
824 return current;
825 },
827
828 Array<int> prim_face_indices(mesh.faces_num);
829 array_utils::fill_index_range<int>(prim_face_indices);
830
832 groups.resize(1);
833 groups[0].parent = -1;
834 groups[0].children_offset = 0;
835
836 const AttributeAccessor attributes = mesh.attributes();
837 const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
838
840 face_centers, prim_face_indices, groups, 0, 0, bounds, material_index, 2500);
841
842 build_vertex_groups_for_leaves(mesh.verts_num, faces, corner_verts, groups);
843
844 return groups;
845}
846
848{
850
851 Vector<int> new_vert_order;
852 new_vert_order.reserve(mesh.verts_num);
853
854 Vector<int> new_face_order;
855 new_face_order.reserve(mesh.faces_num);
856
857 BitVector<> added_verts(mesh.verts_num, false);
858
859 Vector<int> group_unique_offsets;
860 group_unique_offsets.reserve(local_groups.size() + 1);
861 group_unique_offsets.append(0);
862
863 Vector<int> group_face_offsets;
864 group_face_offsets.reserve(local_groups.size() + 1);
865 group_face_offsets.append(0);
866
867 for (const int group_index : local_groups.index_range()) {
868 const NonContiguousGroup &local_group = local_groups[group_index];
869
870 for (const int vert_idx : local_group.unique_verts) {
871 if (!added_verts[vert_idx]) {
872 new_vert_order.append(vert_idx);
873 added_verts[vert_idx].set();
874 }
875 }
876 group_unique_offsets.append(new_vert_order.size());
877
878 for (const int vert_idx : local_group.shared_verts) {
879 if (!added_verts[vert_idx]) {
880 new_vert_order.append(vert_idx);
881 added_verts[vert_idx].set();
882 }
883 }
884
885 for (const int face_idx : local_group.faces) {
886 new_face_order.append(face_idx);
887 }
888 group_face_offsets.append(new_face_order.size());
889 }
890
891 for (const int vert : IndexRange(mesh.verts_num)) {
892 if (!added_verts[vert]) {
893 new_vert_order.append(vert);
894 added_verts[vert].set();
895 }
896 }
897
898 Array<int> vert_reverse_map(mesh.verts_num);
899 for (const int i : IndexRange(mesh.verts_num)) {
900 vert_reverse_map[new_vert_order[i]] = i;
901 }
902
903 MutableSpan edges = mesh.edges_for_write();
904 for (int2 &edge : edges) {
905 edge.x = vert_reverse_map[edge.x];
906 edge.y = vert_reverse_map[edge.y];
907 }
908
909 MutableSpan<int> corner_verts = mesh.corner_verts_for_write();
910 Array<int> new_corner_verts(corner_verts.size());
911 const OffsetIndices<int> old_faces = mesh.faces();
912
913 int new_corner_idx = 0;
914 for (const int old_face_idx : new_face_order) {
915 const IndexRange face = old_faces[old_face_idx];
916 for (const int corner : face) {
917 new_corner_verts[new_corner_idx] = vert_reverse_map[corner_verts[corner]];
918 new_corner_idx++;
919 }
920 }
921 corner_verts.copy_from(new_corner_verts);
922
923 MutableSpan<int> face_offsets = mesh.face_offsets_for_write();
924 Vector<int> face_sizes(new_face_order.size());
925 gather_group_sizes(old_faces, new_face_order, face_sizes);
926 face_offsets.take_front(face_sizes.size()).copy_from(face_sizes);
928
929 MutableAttributeAccessor attributes_for_write = mesh.attributes_for_write();
930 attributes_for_write.foreach_attribute([&](const bke::AttributeIter &iter) {
931 if (iter.domain == bke::AttrDomain::Face) {
932 bke::GSpanAttributeWriter attribute = attributes_for_write.lookup_for_write_span(iter.name);
933 const CPPType &type = attribute.span.type();
934 GArray<> new_values(type, new_face_order.size());
935 bke::attribute_math::gather(attribute.span, new_face_order, new_values.as_mutable_span());
936 attribute.span.copy_from(new_values.as_span());
937 attribute.finish();
938 }
939 else if (iter.domain == bke::AttrDomain::Point) {
940 bke::GSpanAttributeWriter attribute = attributes_for_write.lookup_for_write_span(iter.name);
941 const CPPType &type = attribute.span.type();
942 GArray<> new_values(type, new_vert_order.size());
943 bke::attribute_math::gather(attribute.span, new_vert_order, new_values.as_mutable_span());
944 attribute.span.copy_from(new_values.as_span());
945 attribute.finish();
946 }
947 else if (iter.domain == bke::AttrDomain::Corner && iter.name != ".corner_vert") {
948 bke::GSpanAttributeWriter attribute = attributes_for_write.lookup_for_write_span(iter.name);
949 GMutableSpan attribute_data = attribute.span;
950 const CPPType &type = attribute_data.type();
951 GArray<> new_values(type, attribute_data.size());
952
953 int new_corner_idx = 0;
954 for (const int old_face_idx : new_face_order) {
955 const IndexRange face = old_faces[old_face_idx];
956 for (const int old_corner_idx : face) {
957 type.copy_construct(attribute_data[old_corner_idx], new_values[new_corner_idx]);
958 new_corner_idx++;
959 }
960 }
961 attribute_data.copy_from(new_values.as_span());
962 attribute.finish();
963 }
964 });
965
966 for (NonContiguousGroup &local_group : local_groups) {
967 for (int &vert_idx : local_group.unique_verts) {
968 vert_idx = vert_reverse_map[vert_idx];
969 }
970 for (int &vert_idx : local_group.shared_verts) {
971 vert_idx = vert_reverse_map[vert_idx];
972 }
973 }
974
975 Array<MeshGroup> nodes(local_groups.size());
976
977 for (const int node_idx : local_groups.index_range()) {
978 const NonContiguousGroup &local_group = local_groups[node_idx];
979 MeshGroup &node = nodes[node_idx];
980
981 node.parent = local_group.parent;
982 node.children_offset = local_group.children_offset;
983 node.corners_count = local_group.corner_count;
984 node.unique_verts = IndexRange(0, 0);
985 node.faces = IndexRange(0, 0);
986 if (local_group.children_offset == 0 && !local_group.faces.is_empty()) {
987 int unique_start = (node_idx == 0) ? 0 : group_unique_offsets[node_idx];
988 int unique_end = group_unique_offsets[node_idx + 1];
989 node.unique_verts = IndexRange(unique_start, unique_end - unique_start);
990
991 int face_start = (node_idx == 0) ? 0 : group_face_offsets[node_idx];
992 int face_end = group_face_offsets[node_idx + 1];
993 node.faces = IndexRange(face_start, face_end - face_start);
994
995 if (!local_group.shared_verts.is_empty()) {
996 node.shared_verts = Array<int>(local_group.shared_verts.size());
997 for (const int j : local_group.shared_verts.index_range()) {
998 node.shared_verts[j] = local_group.shared_verts[j];
999 }
1000 }
1001 }
1002 }
1003
1004 mesh.tag_positions_changed();
1005 mesh.tag_topology_changed();
1006 mesh.runtime->spatial_groups = std::make_unique<Array<MeshGroup>>(std::move(nodes));
1007}
1008
1009} // namespace blender::bke
1010
1024{
1025 CustomData_free(&mesh.vert_data);
1026 CustomData_free(&mesh.edge_data);
1027 CustomData_free(&mesh.fdata_legacy);
1028 CustomData_free(&mesh.corner_data);
1029 CustomData_free(&mesh.face_data);
1030 mesh.attribute_storage.wrap() = blender::bke::AttributeStorage();
1031 if (mesh.face_offset_indices) {
1033 &mesh.runtime->face_offsets_sharing_info);
1034 }
1035 MEM_SAFE_FREE(mesh.mselect);
1036
1037 mesh.verts_num = 0;
1038 mesh.edges_num = 0;
1039 mesh.totface_legacy = 0;
1040 mesh.corners_num = 0;
1041 mesh.faces_num = 0;
1042 mesh.act_face = -1;
1043 mesh.totselect = 0;
1044}
1045
1047{
1048 BLI_freelistN(&mesh.vertex_group_names);
1049 MEM_SAFE_FREE(mesh.active_color_attribute);
1050 MEM_SAFE_FREE(mesh.default_color_attribute);
1051}
1052
1058
1065
1066static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata)
1067{
1068 if (free_customdata) {
1069 CustomData_free(&mesh->fdata_legacy);
1070 }
1071 else {
1072 CustomData_reset(&mesh->fdata_legacy);
1073 }
1074
1075 mesh->totface_legacy = 0;
1076}
1077
1078Mesh *BKE_mesh_add(Main *bmain, const char *name)
1079{
1080 return BKE_id_new<Mesh>(bmain, name);
1081}
1082
1084{
1085 BLI_assert(mesh->face_offset_indices == nullptr);
1086 BLI_assert(mesh->runtime->face_offsets_sharing_info == nullptr);
1087 if (mesh->faces_num == 0) {
1088 return;
1089 }
1090 mesh->face_offset_indices = MEM_malloc_arrayN<int>(size_t(mesh->faces_num) + 1, __func__);
1091 mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
1092 mesh->face_offset_indices);
1093
1094#ifndef NDEBUG
1095 /* Fill offsets with obviously bad values to simplify finding missing initialization. */
1096 mesh->face_offsets_for_write().fill(-1);
1097#endif
1098 /* Set common values for convenience. */
1099 mesh->face_offset_indices[0] = 0;
1100 mesh->face_offset_indices[mesh->faces_num] = mesh->corners_num;
1101}
1102
1103Span<float3> Mesh::vert_positions() const
1104{
1105 return {static_cast<const float3 *>(
1107 this->verts_num};
1108}
1109MutableSpan<float3> Mesh::vert_positions_for_write()
1110{
1111 return {static_cast<float3 *>(CustomData_get_layer_named_for_write(
1112 &this->vert_data, CD_PROP_FLOAT3, "position", this->verts_num)),
1113 this->verts_num};
1114}
1115
1116Span<int2> Mesh::edges() const
1117{
1118 return {static_cast<const int2 *>(
1119 CustomData_get_layer_named(&this->edge_data, CD_PROP_INT32_2D, ".edge_verts")),
1120 this->edges_num};
1121}
1122MutableSpan<int2> Mesh::edges_for_write()
1123{
1124 return {static_cast<int2 *>(CustomData_get_layer_named_for_write(
1125 &this->edge_data, CD_PROP_INT32_2D, ".edge_verts", this->edges_num)),
1126 this->edges_num};
1127}
1128
1129OffsetIndices<int> Mesh::faces() const
1130{
1131 return Span(this->face_offset_indices, this->faces_num + 1);
1132}
1133Span<int> Mesh::face_offsets() const
1134{
1135 if (this->faces_num == 0) {
1136 return {};
1137 }
1138 return {this->face_offset_indices, this->faces_num + 1};
1139}
1140MutableSpan<int> Mesh::face_offsets_for_write()
1141{
1142 if (this->faces_num == 0) {
1143 return {};
1144 }
1146 &this->face_offset_indices, &this->runtime->face_offsets_sharing_info, this->faces_num + 1);
1147 return {this->face_offset_indices, this->faces_num + 1};
1148}
1149
1150Span<int> Mesh::corner_verts() const
1151{
1152 return {static_cast<const int *>(
1153 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_vert")),
1154 this->corners_num};
1155}
1156MutableSpan<int> Mesh::corner_verts_for_write()
1157{
1158 return {static_cast<int *>(CustomData_get_layer_named_for_write(
1159 &this->corner_data, CD_PROP_INT32, ".corner_vert", this->corners_num)),
1160 this->corners_num};
1161}
1162
1163Span<int> Mesh::corner_edges() const
1164{
1165 return {static_cast<const int *>(
1166 CustomData_get_layer_named(&this->corner_data, CD_PROP_INT32, ".corner_edge")),
1167 this->corners_num};
1168}
1169MutableSpan<int> Mesh::corner_edges_for_write()
1170{
1171 return {static_cast<int *>(CustomData_get_layer_named_for_write(
1172 &this->corner_data, CD_PROP_INT32, ".corner_edge", this->corners_num)),
1173 this->corners_num};
1174}
1175
1176Span<MDeformVert> Mesh::deform_verts() const
1177{
1178 const MDeformVert *dverts = static_cast<const MDeformVert *>(
1180 if (!dverts) {
1181 return {};
1182 }
1183 return {dverts, this->verts_num};
1184}
1185MutableSpan<MDeformVert> Mesh::deform_verts_for_write()
1186{
1187 MDeformVert *dvert = static_cast<MDeformVert *>(
1189 if (dvert) {
1190 return {dvert, this->verts_num};
1191 }
1192 return {static_cast<MDeformVert *>(CustomData_add_layer(
1194 this->verts_num};
1195}
1196
1197void Mesh::count_memory(blender::MemoryCounter &memory) const
1198{
1199 memory.add_shared(this->runtime->face_offsets_sharing_info,
1200 this->face_offsets().size_in_bytes());
1201 CustomData_count_memory(this->vert_data, this->verts_num, memory);
1202 CustomData_count_memory(this->edge_data, this->edges_num, memory);
1203 CustomData_count_memory(this->face_data, this->faces_num, memory);
1204 CustomData_count_memory(this->corner_data, this->corners_num, memory);
1205}
1206
1208{
1209 return blender::bke::AttributeAccessor(this, blender::bke::mesh_attribute_accessor_functions());
1210}
1211
1212blender::bke::MutableAttributeAccessor Mesh::attributes_for_write()
1213{
1214 return blender::bke::MutableAttributeAccessor(this,
1216}
1217
1218Mesh *BKE_mesh_new_nomain(const int verts_num,
1219 const int edges_num,
1220 const int faces_num,
1221 const int corners_num)
1222{
1223 Mesh *mesh = static_cast<Mesh *>(BKE_libblock_alloc(
1226
1227 mesh->verts_num = verts_num;
1228 mesh->edges_num = edges_num;
1229 mesh->faces_num = faces_num;
1230 mesh->corners_num = corners_num;
1231
1234
1235 return mesh;
1236}
1237
1238namespace blender::bke {
1239
1240Mesh *mesh_new_no_attributes(const int verts_num,
1241 const int edges_num,
1242 const int faces_num,
1243 const int corners_num)
1244{
1245 Mesh *mesh = BKE_mesh_new_nomain(0, 0, faces_num, 0);
1246 mesh->verts_num = verts_num;
1247 mesh->edges_num = edges_num;
1248 mesh->corners_num = corners_num;
1249 CustomData_free_layer_named(&mesh->vert_data, "position");
1250 CustomData_free_layer_named(&mesh->edge_data, ".edge_verts");
1251 CustomData_free_layer_named(&mesh->corner_data, ".corner_vert");
1252 CustomData_free_layer_named(&mesh->corner_data, ".corner_edge");
1253 return mesh;
1254}
1255
1256} // namespace blender::bke
1257
1258static void copy_attribute_names(const Mesh &mesh_src, Mesh &mesh_dst)
1259{
1260 if (mesh_src.active_color_attribute) {
1263 }
1264 if (mesh_src.default_color_attribute) {
1267 }
1268}
1269
1270void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
1271{
1272 /* Copy general settings. */
1273 me_dst->editflag = me_src->editflag;
1274 me_dst->flag = me_src->flag;
1275 me_dst->remesh_voxel_size = me_src->remesh_voxel_size;
1277 me_dst->remesh_mode = me_src->remesh_mode;
1278 me_dst->symmetry = me_src->symmetry;
1279
1282
1283 /* Copy texture space. */
1284 me_dst->texspace_flag = me_src->texspace_flag;
1286 copy_v3_v3(me_dst->texspace_size, me_src->texspace_size);
1287
1290}
1291
1292void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
1293{
1294 /* User counts aren't handled, don't copy into a mesh from #G_MAIN. */
1296
1297 BKE_mesh_copy_parameters(me_dst, me_src);
1298 copy_attribute_names(*me_src, *me_dst);
1299
1300 /* Copy vertex group names. */
1303
1304 /* Copy materials. */
1305 if (me_dst->mat != nullptr) {
1306 MEM_freeN(me_dst->mat);
1307 }
1308 me_dst->mat = (Material **)MEM_dupallocN(me_src->mat);
1309 me_dst->totcol = me_src->totcol;
1310
1311 me_dst->runtime->edit_mesh = me_src->runtime->edit_mesh;
1312}
1313
1315 const int verts_num,
1316 const int edges_num,
1317 const int tessface_num,
1318 const int faces_num,
1319 const int corners_num,
1321{
1322 /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */
1323 const bool do_tessface = (tessface_num ||
1324 ((me_src->totface_legacy != 0) && (me_src->faces_num == 0)));
1325
1326 Mesh *me_dst = BKE_id_new_nomain<Mesh>(nullptr);
1327
1328 me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect);
1329
1330 me_dst->verts_num = verts_num;
1331 me_dst->edges_num = edges_num;
1332 me_dst->faces_num = faces_num;
1333 me_dst->corners_num = corners_num;
1334 me_dst->totface_legacy = tessface_num;
1335
1336 BKE_mesh_copy_parameters_for_eval(me_dst, me_src);
1337
1339 &me_src->vert_data, &me_dst->vert_data, mask.vmask, CD_SET_DEFAULT, verts_num);
1341 &me_src->edge_data, &me_dst->edge_data, mask.emask, CD_SET_DEFAULT, edges_num);
1343 &me_src->face_data, &me_dst->face_data, mask.pmask, CD_SET_DEFAULT, faces_num);
1345 &me_src->corner_data, &me_dst->corner_data, mask.lmask, CD_SET_DEFAULT, corners_num);
1346 if (do_tessface) {
1348 &me_src->fdata_legacy, &me_dst->fdata_legacy, mask.fmask, CD_SET_DEFAULT, tessface_num);
1349 }
1350 else {
1351 mesh_tessface_clear_intern(me_dst, false);
1352 }
1353
1354 /* The destination mesh should at least have valid primary CD layers,
1355 * even in cases where the source mesh does not. */
1358 if (do_tessface && !CustomData_get_layer(&me_dst->fdata_legacy, CD_MFACE)) {
1360 }
1361
1362 return me_dst;
1363}
1364
1366 const int verts_num,
1367 const int edges_num,
1368 const int faces_num,
1369 const int corners_num)
1370{
1372 me_src, verts_num, edges_num, 0, faces_num, corners_num, CD_MASK_EVERYTHING);
1373}
1374
1376{
1377 return reinterpret_cast<Mesh *>(
1378 BKE_id_copy_ex(nullptr, &source.id, nullptr, LIB_ID_COPY_LOCALIZE));
1379}
1380
1382 const BMeshCreateParams *create_params,
1383 const BMeshFromMeshParams *convert_params)
1384{
1386
1387 BMesh *bm = BM_mesh_create(&allocsize, create_params);
1388 BM_mesh_bm_from_me(bm, mesh, convert_params);
1389
1390 return bm;
1391}
1392
1394 const int active_shapekey,
1395 const bool add_key_index,
1397{
1398 BMeshFromMeshParams bmesh_from_mesh_params{};
1399 bmesh_from_mesh_params.calc_face_normal = false;
1400 bmesh_from_mesh_params.calc_vert_normal = false;
1401 bmesh_from_mesh_params.add_key_index = add_key_index;
1402 bmesh_from_mesh_params.use_shapekey = true;
1403 bmesh_from_mesh_params.active_shapekey = active_shapekey;
1404 return BKE_mesh_to_bmesh_ex(mesh, params, &bmesh_from_mesh_params);
1405}
1406
1409 const Mesh *me_settings)
1410{
1411 BLI_assert(params->calc_object_remap == false);
1412 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
1413 BM_mesh_bm_to_me(nullptr, bm, mesh, params);
1415 return mesh;
1416}
1417
1419 const CustomData_MeshMasks *cd_mask_extra,
1420 const Mesh *me_settings)
1421{
1422 Mesh *mesh = BKE_id_new_nomain<Mesh>(nullptr);
1423 BM_mesh_bm_to_me_for_eval(*bm, *mesh, cd_mask_extra);
1425 return mesh;
1426}
1427
1429{
1431 return;
1432 }
1434 range_vn_i(indices, size, 0);
1435}
1436
1442
1444{
1445 ensure_orig_index_layer(mesh->vert_data, mesh->verts_num);
1446 ensure_orig_index_layer(mesh->edge_data, mesh->edges_num);
1447 ensure_orig_index_layer(mesh->face_data, mesh->faces_num);
1448}
1449
1451{
1452 using namespace blender;
1453 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) {
1454 const Bounds<float3> bounds = mesh->bounds_min_max().value_or(
1455 Bounds(float3(-1.0f), float3(1.0f)));
1456
1457 float texspace_location[3], texspace_size[3];
1458 mid_v3_v3v3(texspace_location, bounds.min, bounds.max);
1459
1460 texspace_size[0] = (bounds.max[0] - bounds.min[0]) / 2.0f;
1461 texspace_size[1] = (bounds.max[1] - bounds.min[1]) / 2.0f;
1462 texspace_size[2] = (bounds.max[2] - bounds.min[2]) / 2.0f;
1463
1464 for (int a = 0; a < 3; a++) {
1465 if (texspace_size[a] == 0.0f) {
1466 texspace_size[a] = 1.0f;
1467 }
1468 else if (texspace_size[a] > 0.0f && texspace_size[a] < 0.00001f) {
1469 texspace_size[a] = 0.00001f;
1470 }
1471 else if (texspace_size[a] < 0.0f && texspace_size[a] > -0.00001f) {
1472 texspace_size[a] = -0.00001f;
1473 }
1474 }
1475
1476 copy_v3_v3(mesh->texspace_location, texspace_location);
1477 copy_v3_v3(mesh->texspace_size, texspace_size);
1478
1479 mesh->texspace_flag |= ME_TEXSPACE_FLAG_AUTO_EVALUATED;
1480 }
1481}
1482
1484{
1485 if ((mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO) &&
1486 !(mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED))
1487 {
1489 }
1490}
1491
1492void BKE_mesh_texspace_get(Mesh *mesh, float r_texspace_location[3], float r_texspace_size[3])
1493{
1495
1496 if (r_texspace_location) {
1497 copy_v3_v3(r_texspace_location, mesh->texspace_location);
1498 }
1499 if (r_texspace_size) {
1500 copy_v3_v3(r_texspace_size, mesh->texspace_size);
1501 }
1502}
1503
1505 char **r_texspace_flag,
1506 float **r_texspace_location,
1507 float **r_texspace_size)
1508{
1510
1511 if (r_texspace_flag != nullptr) {
1512 *r_texspace_flag = &mesh->texspace_flag;
1513 }
1514 if (r_texspace_location != nullptr) {
1515 *r_texspace_location = mesh->texspace_location;
1516 }
1517 if (r_texspace_size != nullptr) {
1518 *r_texspace_size = mesh->texspace_size;
1519 }
1520}
1521
1523{
1524 const Mesh *mesh = static_cast<const Mesh *>(ob->data);
1525 const Mesh *tme = mesh->texcomesh ? mesh->texcomesh : mesh;
1526
1528 const Span<float3> positions = tme->vert_positions();
1529 result.as_mutable_span().take_front(positions.size()).copy_from(positions);
1530 result.as_mutable_span().drop_front(positions.size()).fill(float3(0));
1531
1532 return result;
1533}
1534
1536{
1537 float texspace_location[3], texspace_size[3];
1538
1540 mesh->texcomesh ? mesh->texcomesh : mesh, texspace_location, texspace_size);
1541
1542 if (invert) {
1543 for (const int a : orco.index_range()) {
1544 float3 &co = orco[a];
1545 madd_v3_v3v3v3(co, texspace_location, co, texspace_size);
1546 }
1547 }
1548 else {
1549 for (const int a : orco.index_range()) {
1550 float3 &co = orco[a];
1551 co[0] = (co[0] - texspace_location[0]) / texspace_size[0];
1552 co[1] = (co[1] - texspace_location[1]) / texspace_size[1];
1553 co[2] = (co[2] - texspace_location[2]) / texspace_size[2];
1554 }
1555 }
1556}
1557
1558void BKE_mesh_orco_verts_transform(Mesh *mesh, float (*orco)[3], int totvert, bool invert)
1559{
1560 BKE_mesh_orco_verts_transform(mesh, {reinterpret_cast<float3 *>(orco), totvert}, invert);
1561}
1562
1564{
1565 if (CustomData_has_layer(&mesh->vert_data, CD_ORCO)) {
1566 return;
1567 }
1568
1569 /* Orcos are stored in normalized 0..1 range by convention. */
1571 BKE_mesh_orco_verts_transform(mesh, orcodata, false);
1572 float3 *data = static_cast<float3 *>(
1573 CustomData_add_layer(&mesh->vert_data, CD_ORCO, CD_CONSTRUCT, mesh->verts_num));
1574 MutableSpan(data, mesh->verts_num).copy_from(orcodata);
1575}
1576
1578{
1579 if (ob == nullptr) {
1580 return nullptr;
1581 }
1582 if (ob->type == OB_MESH) {
1583 return static_cast<Mesh *>(ob->data);
1584 }
1585
1586 return nullptr;
1587}
1588
1590{
1591 Mesh *old = nullptr;
1592
1593 if (ob == nullptr) {
1594 return;
1595 }
1596
1598
1599 if (ob->type == OB_MESH) {
1600 old = static_cast<Mesh *>(ob->data);
1601 if (old) {
1602 id_us_min(&old->id);
1603 }
1604 ob->data = mesh;
1605 id_us_plus((ID *)mesh);
1606 }
1607
1609
1611}
1612
1614{
1615 using namespace blender;
1616 using namespace blender::bke;
1617 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1618 AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
1619 if (!material_indices) {
1620 return;
1621 }
1622 if (material_indices.domain != AttrDomain::Face) {
1624 return;
1625 }
1626 MutableVArraySpan<int> indices_span(material_indices.varray);
1627 for (const int i : indices_span.index_range()) {
1628 if (indices_span[i] > 0 && indices_span[i] >= index) {
1629 indices_span[i]--;
1630 }
1631 }
1632 indices_span.save();
1633 material_indices.finish();
1634
1636}
1637
1639{
1640 using namespace blender;
1641 using namespace blender::bke;
1642 const AttributeAccessor attributes = mesh->attributes();
1643 const VArray<int> material_indices = *attributes.lookup_or_default<int>(
1644 "material_index", AttrDomain::Face, 0);
1645 if (material_indices.is_single()) {
1646 return material_indices.get_internal_single() == index;
1647 }
1648 const VArraySpan<int> indices_span(material_indices);
1649 return indices_span.contains(index);
1650}
1651
1653{
1654 using namespace blender;
1655 using namespace blender::bke;
1656 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1657 attributes.remove("material_index");
1658
1660}
1661
1662void BKE_mesh_material_remap(Mesh *mesh, const uint *remap, uint remap_len)
1663{
1664 using namespace blender;
1665 using namespace blender::bke;
1666 const short remap_len_short = short(remap_len);
1667
1668#define MAT_NR_REMAP(n) \
1669 if (n < remap_len_short) { \
1670 BLI_assert(n >= 0 && remap[n] < remap_len_short); \
1671 n = remap[n]; \
1672 } \
1673 ((void)0)
1674
1675 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1676 BMIter iter;
1677 BMFace *efa;
1678
1679 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1680 MAT_NR_REMAP(efa->mat_nr);
1681 }
1682 }
1683 else {
1684 MutableAttributeAccessor attributes = mesh->attributes_for_write();
1685 SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
1686 "material_index", AttrDomain::Face);
1687 if (!material_indices) {
1688 return;
1689 }
1690 for (const int i : material_indices.span.index_range()) {
1691 MAT_NR_REMAP(material_indices.span[i]);
1692 }
1693 material_indices.span.save();
1694 material_indices.finish();
1695 }
1696
1697#undef MAT_NR_REMAP
1698}
1699
1700namespace blender::bke {
1701
1702void mesh_smooth_set(Mesh &mesh, const bool use_smooth, const bool keep_sharp_edges)
1703{
1704 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1705 if (!keep_sharp_edges) {
1706 attributes.remove("sharp_edge");
1707 }
1708 attributes.remove("sharp_face");
1709 if (!use_smooth) {
1710 attributes.add<bool>("sharp_face",
1713 }
1714}
1715
1716void mesh_sharp_edges_set_from_angle(Mesh &mesh, const float angle, const bool keep_sharp_edges)
1717{
1718 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1719 if (angle >= M_PI) {
1720 mesh_smooth_set(mesh, true, keep_sharp_edges);
1721 return;
1722 }
1723 if (angle == 0.0f) {
1724 mesh_smooth_set(mesh, false, keep_sharp_edges);
1725 return;
1726 }
1727 if (!keep_sharp_edges) {
1728 attributes.remove("sharp_edge");
1729 }
1730 SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
1731 "sharp_edge", AttrDomain::Edge);
1732 const VArraySpan<bool> sharp_faces = *attributes.lookup<bool>("sharp_face", AttrDomain::Face);
1734 mesh.corner_verts(),
1735 mesh.corner_edges(),
1736 mesh.face_normals(),
1737 mesh.corner_to_face_map(),
1738 sharp_faces,
1739 angle,
1740 sharp_edges.span);
1741 sharp_edges.finish();
1742}
1743
1744} // namespace blender::bke
1745
1746std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
1747{
1748 using namespace blender;
1749 const int verts_num = BKE_mesh_wrapper_vert_len(this);
1750 if (verts_num == 0) {
1751 return std::nullopt;
1752 }
1753 this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
1754 switch (this->runtime->wrapper_type) {
1756 r_bounds = *BKE_editmesh_cache_calc_minmax(*this->runtime->edit_mesh,
1757 *this->runtime->edit_data);
1758 break;
1761 r_bounds = *bounds::min_max(this->vert_positions());
1762 break;
1763 }
1764 });
1765 return this->runtime->bounds_cache.data();
1766}
1767
1768void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)
1769{
1770 this->runtime->bounds_cache.ensure([&](blender::Bounds<float3> &r_data) { r_data = bounds; });
1771}
1772
1774{
1775 return mesh.runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH && mesh.runtime->edit_mesh &&
1776 mesh.runtime->edit_mesh->bm;
1777}
1778
1779std::optional<int> Mesh::material_index_max() const
1780{
1781 this->runtime->max_material_index.ensure([&](std::optional<int> &value) {
1782 if (use_bmesh_material_indices(*this)) {
1783 BMesh *bm = this->runtime->edit_mesh->bm;
1784 if (bm->totface == 0) {
1785 value = std::nullopt;
1786 return;
1787 }
1788 int max_material_index = 0;
1789 BMFace *efa;
1790 BMIter iter;
1791 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1792 max_material_index = std::max<int>(max_material_index, efa->mat_nr);
1793 }
1794 value = max_material_index;
1795 return;
1796 }
1797 if (this->faces_num == 0) {
1798 value = std::nullopt;
1799 return;
1800 }
1802 this->attributes()
1803 .lookup_or_default<int>("material_index", blender::bke::AttrDomain::Face, 0)
1804 .varray);
1805 if (value.has_value()) {
1806 value = std::clamp(*value, 0, MAXMAT);
1807 }
1808 });
1809 return this->runtime->max_material_index.data();
1810}
1811
1812const blender::VectorSet<int> &Mesh::material_indices_used() const
1813{
1814 using namespace blender;
1815 this->runtime->used_material_indices.ensure([&](VectorSet<int> &r_data) {
1816 const std::optional<int> max_material_index_opt = this->material_index_max();
1817 r_data.clear();
1818 if (!max_material_index_opt.has_value()) {
1819 return;
1820 }
1821 const int max_material_index = *max_material_index_opt;
1822 const auto clamp_material_index = [&](const int index) {
1823 return std::clamp<int>(index, 0, max_material_index);
1824 };
1825
1826 /* Find used indices in parallel and then create the vector set in the end. */
1827 Array<bool> used_indices(max_material_index + 1, false);
1828 if (use_bmesh_material_indices(*this)) {
1829 BMesh *bm = this->runtime->edit_mesh->bm;
1830 BMFace *efa;
1831 BMIter iter;
1832 BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1833 used_indices[clamp_material_index(efa->mat_nr)] = true;
1834 }
1835 }
1836 else if (const VArray<int> material_indices =
1837 this->attributes()
1838 .lookup_or_default<int>("material_index", bke::AttrDomain::Face, 0)
1839 .varray)
1840 {
1841 if (const std::optional<int> single_material_index = material_indices.get_if_single()) {
1842 used_indices[clamp_material_index(*single_material_index)] = true;
1843 }
1844 else {
1845 VArraySpan<int> material_indices_span = material_indices;
1846 threading::parallel_for(
1847 material_indices_span.index_range(), 1024, [&](const IndexRange range) {
1848 for (const int i : range) {
1849 used_indices[clamp_material_index(material_indices_span[i])] = true;
1850 }
1851 });
1852 }
1853 }
1854 for (const int i : used_indices.index_range()) {
1855 if (used_indices[i]) {
1856 r_data.add_new(i);
1857 }
1858 }
1859 });
1860 return this->runtime->used_material_indices.data();
1861}
1862
1863namespace blender::bke {
1864
1865static void translate_positions(MutableSpan<float3> positions, const float3 &translation)
1866{
1867 threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
1868 for (float3 &position : positions.slice(range)) {
1869 position += translation;
1870 }
1871 });
1872}
1873
1874void mesh_translate(Mesh &mesh, const float3 &translation, const bool do_shape_keys)
1875{
1876 if (math::is_zero(translation)) {
1877 return;
1878 }
1879
1880 std::optional<Bounds<float3>> bounds;
1881 if (mesh.runtime->bounds_cache.is_cached()) {
1882 bounds = mesh.runtime->bounds_cache.data();
1883 }
1884
1885 translate_positions(mesh.vert_positions_for_write(), translation);
1886
1887 if (do_shape_keys && mesh.key) {
1888 LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
1889 translate_positions({static_cast<float3 *>(kb->data), kb->totelem}, translation);
1890 }
1891 }
1892
1893 mesh.tag_positions_changed_uniformly();
1894
1895 if (bounds) {
1896 bounds->min += translation;
1897 bounds->max += translation;
1898 mesh.bounds_set_eager(*bounds);
1899 }
1900}
1901
1902void mesh_transform(Mesh &mesh, const float4x4 &transform, bool do_shape_keys)
1903{
1904 math::transform_points(transform, mesh.vert_positions_for_write());
1905
1906 if (do_shape_keys && mesh.key) {
1907 LISTBASE_FOREACH (KeyBlock *, kb, &mesh.key->block) {
1908 math::transform_points(transform, MutableSpan(static_cast<float3 *>(kb->data), kb->totelem));
1909 }
1910 }
1911 MutableAttributeAccessor attributes = mesh.attributes_for_write();
1913
1914 mesh.tag_positions_changed();
1915}
1916
1917} // namespace blender::bke
1918
1923
1924/* -------------------------------------------------------------------- */
1925/* MSelect functions (currently used in weight paint mode) */
1926
1928{
1929 MEM_SAFE_FREE(mesh->mselect);
1930 mesh->totselect = 0;
1931}
1932
1934{
1935 using namespace blender;
1936 using namespace blender::bke;
1937 MSelect *mselect_src, *mselect_dst;
1938 int i_src, i_dst;
1939
1940 if (mesh->totselect == 0) {
1941 return;
1942 }
1943
1944 mselect_src = mesh->mselect;
1945 mselect_dst = MEM_malloc_arrayN<MSelect>(size_t(mesh->totselect), "Mesh selection history");
1946
1947 const AttributeAccessor attributes = mesh->attributes();
1948 const VArray<bool> select_vert = *attributes.lookup_or_default<bool>(
1949 ".select_vert", AttrDomain::Point, false);
1950 const VArray<bool> select_edge = *attributes.lookup_or_default<bool>(
1951 ".select_edge", AttrDomain::Edge, false);
1952 const VArray<bool> select_poly = *attributes.lookup_or_default<bool>(
1953 ".select_poly", AttrDomain::Face, false);
1954
1955 for (i_src = 0, i_dst = 0; i_src < mesh->totselect; i_src++) {
1956 int index = mselect_src[i_src].index;
1957 switch (mselect_src[i_src].type) {
1958 case ME_VSEL: {
1959 if (select_vert[index]) {
1960 mselect_dst[i_dst] = mselect_src[i_src];
1961 i_dst++;
1962 }
1963 break;
1964 }
1965 case ME_ESEL: {
1966 if (select_edge[index]) {
1967 mselect_dst[i_dst] = mselect_src[i_src];
1968 i_dst++;
1969 }
1970 break;
1971 }
1972 case ME_FSEL: {
1973 if (select_poly[index]) {
1974 mselect_dst[i_dst] = mselect_src[i_src];
1975 i_dst++;
1976 }
1977 break;
1978 }
1979 default: {
1981 break;
1982 }
1983 }
1984 }
1985
1986 MEM_freeN(mselect_src);
1987
1988 if (i_dst == 0) {
1989 MEM_freeN(mselect_dst);
1990 mselect_dst = nullptr;
1991 }
1992 else if (i_dst != mesh->totselect) {
1993 mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst);
1994 }
1995
1996 mesh->totselect = i_dst;
1997 mesh->mselect = mselect_dst;
1998}
1999
2000int BKE_mesh_mselect_find(const Mesh *mesh, int index, int type)
2001{
2003
2004 for (int i = 0; i < mesh->totselect; i++) {
2005 if ((mesh->mselect[i].index == index) && (mesh->mselect[i].type == type)) {
2006 return i;
2007 }
2008 }
2009
2010 return -1;
2011}
2012
2014{
2016
2017 if (mesh->totselect) {
2018 if (mesh->mselect[mesh->totselect - 1].type == type) {
2019 return mesh->mselect[mesh->totselect - 1].index;
2020 }
2021 }
2022 return -1;
2023}
2024
2025void BKE_mesh_mselect_active_set(Mesh *mesh, int index, int type)
2026{
2027 const int msel_index = BKE_mesh_mselect_find(mesh, index, type);
2028
2029 if (msel_index == -1) {
2030 /* add to the end */
2031 mesh->mselect = (MSelect *)MEM_reallocN(mesh->mselect,
2032 sizeof(MSelect) * (mesh->totselect + 1));
2033 mesh->mselect[mesh->totselect].index = index;
2034 mesh->mselect[mesh->totselect].type = type;
2035 mesh->totselect++;
2036 }
2037 else if (msel_index != mesh->totselect - 1) {
2038 /* move to the end */
2039 std::swap(mesh->mselect[msel_index], mesh->mselect[mesh->totselect - 1]);
2040 }
2041
2042 BLI_assert((mesh->mselect[mesh->totselect - 1].index == index) &&
2043 (mesh->mselect[mesh->totselect - 1].type == type));
2044}
2045
2046void BKE_mesh_count_selected_items(const Mesh *mesh, int r_count[3])
2047{
2048 r_count[0] = r_count[1] = r_count[2] = 0;
2049 if (mesh->runtime->edit_mesh) {
2050 BMesh *bm = mesh->runtime->edit_mesh->bm;
2051 r_count[0] = bm->totvertsel;
2052 r_count[1] = bm->totedgesel;
2053 r_count[2] = bm->totfacesel;
2054 }
2055 /* We could support faces in paint modes. */
2056}
2057
2058/* **** Depsgraph evaluation **** */
2059
2061{
2062 DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh);
2064 /* We are here because something did change in the mesh. This means we can not trust the existing
2065 * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the
2066 * evaluated mesh and let objects to re-create it with updated settings. */
2067 if (mesh->runtime->mesh_eval != nullptr) {
2068 BKE_id_free(nullptr, mesh->runtime->mesh_eval);
2069 mesh->runtime->mesh_eval = nullptr;
2070 }
2071 if (DEG_is_active(depsgraph)) {
2072 Mesh *mesh_orig = DEG_get_original(mesh);
2073 if (mesh->texspace_flag & ME_TEXSPACE_FLAG_AUTO_EVALUATED) {
2075 copy_v3_v3(mesh_orig->texspace_location, mesh->texspace_location);
2076 copy_v3_v3(mesh_orig->texspace_size, mesh->texspace_size);
2077 }
2078 }
2079}
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
eCustomDataMask CD_TYPE_AS_MASK(eCustomDataType type)
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:96
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)
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
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
const char * CustomData_get_active_layer_name(const CustomData *data, eCustomDataType 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:1595
void BKE_defgroup_copy_list(ListBase *outbase, const ListBase *inbase)
Definition deform.cc:73
void BKE_defvert_blend_read(BlendDataReader *reader, int count, MDeformVert *mdverts)
Definition deform.cc:1619
std::optional< blender::Bounds< blender::float3 > > BKE_editmesh_cache_calc_minmax(const BMEditMesh &em, const blender::bke::EditMeshData &emd)
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
IDTypeInfo IDType_ID_ME
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:675
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1447
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:358
void BKE_libblock_init_empty(ID *id) ATTR_NONNULL(1)
Definition lib_id.cc:1452
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:777
void * BKE_id_new(Main *bmain, short type, const char *name)
Definition lib_id.cc:1514
@ LIB_ID_CREATE_LOCALIZE
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_COPY_SHAPEKEY
void id_us_min(ID *id)
Definition lib_id.cc:366
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1519
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
#define BKE_LIB_FOREACHID_PROCESS_IDSUPER(data_, id_super_, cb_flag_)
@ IDWALK_CB_NEVER_SELF
@ IDWALK_CB_USER
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:327
General operations, lookup, etc. for blender objects.
A BVH for high poly meshes.
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
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
unsigned int uint
Platform independent time functions.
long int BLI_time_now_seconds_i(void)
Definition time.cc:123
#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:5828
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define BLO_write_struct_array(writer, struct_name, array_size, data_ptr)
void BLO_write_shared_tag(BlendWriter *writer, const void *data)
#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:5880
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:997
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:978
#define FILTER_ID_MA
Definition DNA_ID.h:1208
#define FILTER_ID_ME
Definition DNA_ID.h:1211
@ INDEX_ID_ME
Definition DNA_ID.h:1325
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
#define FILTER_ID_KE
Definition DNA_ID.h:1232
#define FILTER_ID_IM
Definition DNA_ID.h:1204
@ ID_ME
#define CD_MASK_COLOR_ALL
@ CD_MVERT_SKIN
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_MDEFORMVERT
@ CD_PROP_COLOR
@ CD_PROP_INT32
@ CD_PROP_FLOAT2
@ CD_PROP_INT16_2D
#define DNA_struct_default_get(struct_name)
#define MAXMAT
@ ME_TEXSPACE_FLAG_AUTO
@ ME_TEXSPACE_FLAG_AUTO_EVALUATED
struct MDeformVert MDeformVert
@ MVERT_SKIN_ROOT
@ ME_VSEL
@ ME_FSEL
@ ME_ESEL
Object is a sort of wrapper for general info.
@ OB_MESH
static void split(const char *text, const char *seps, char ***str, int *count)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
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)
void BKE_mesh_mselect_active_set(Mesh *mesh, int index, int type)
static void mesh_foreach_working_space_color(ID *id, const IDTypeForeachColorFunctionCallback &fn)
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)
#define STACK_FIXED_DEPTH
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
int64_t size() const
Definition BLI_array.hh:256
IndexRange index_range() const
Definition BLI_array.hh:360
const T * begin() const
Definition BLI_array.hh:321
bool is_empty() const
Definition BLI_array.hh:264
BoundBox bounds
AttributeSet attributes
LinearAllocator & allocator()
void copy_construct(const void *src, void *dst) const
GMutableSpan as_mutable_span()
GSpan as_span() const
void copy_from(GSpan values)
const CPPType & type() const
constexpr int64_t size() const
Definition BLI_span.hh:493
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr MutableSpan drop_front(const int64_t n) const
Definition BLI_span.hh:607
constexpr T * end() const
Definition BLI_span.hh:548
constexpr T * begin() const
Definition BLI_span.hh:544
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
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 from_single(T value, const int64_t size)
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
void resize(const int64_t new_size)
void reserve(const int64_t min_capacity)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GAttributeWriter lookup_for_write(StringRef attribute_id)
bool add(const StringRef attribute_id, const AttrDomain domain, const AttrType data_type, const AttributeInit &initializer)
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
bool remove(const StringRef attribute_id)
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
void add_shared(const ImplicitSharingInfo *sharing_info, const FunctionRef< void(MemoryCounter &shared_memory)> count_fn)
static ushort indices[]
#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)
static char faces[256]
void fill_index_range(MutableSpan< T > span, const T start=0)
void gather(GSpan src, Span< int > map, GMutableSpan dst)
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)
Bounds< float3 > calc_face_bounds(const Span< float3 > vert_positions, const Span< int > face_verts)
int partition_along_axis(const Span< float3 > face_centers, MutableSpan< int > faces, const int axis, const float middle)
Definition pbvh.cc:61
bool leaf_needs_material_split(const Span< int > faces, const Span< int > material_indices)
Definition pbvh.cc:133
int partition_material_indices(const Span< int > material_indices, MutableSpan< int > faces)
Definition pbvh.cc:72
std::optional< eCustomDataType > attr_type_to_custom_data_type(AttrType attr_type)
static Bounds< float3 > merge_bounds(const Bounds< float3 > &a, const Bounds< float3 > &b)
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)
static Vector< NonContiguousGroup > compute_local_mesh_groups(Mesh &mesh)
const AttributeAccessorFunctions & mesh_attribute_accessor_functions()
void mesh_freestyle_marks_to_legacy(AttributeStorage::BlendWriteData &attr_write_data, CustomData &edge_data, CustomData &face_data, Vector< CustomDataLayer, 16 > &edge_layers, Vector< CustomDataLayer, 16 > &face_layers)
void attribute_storage_blend_write_prepare(AttributeStorage &data, AttributeStorage::BlendWriteData &write_data)
static Bounds< float3 > negative_bounds()
static void build_vertex_groups_for_leaves(const int verts_num, const OffsetIndices< int > faces, const Span< int > corner_verts, Vector< NonContiguousGroup > &groups)
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)
static void partition_faces_recursively(const Span< float3 > face_centers, MutableSpan< int > face_indices, Vector< NonContiguousGroup > &groups, int node_index, int depth, const std::optional< Bounds< float3 > > &bounds_precalc, const Span< int > material_indices, int target_group_size)
void mesh_convert_storage_to_customdata(Mesh &mesh)
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
void mesh_apply_spatial_organization(Mesh &mesh)
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 transform_custom_normal_attribute(const float4x4 &transform, MutableAttributeAccessor &attributes)
void mesh_ensure_required_data_layers(Mesh &mesh)
void mesh_ensure_default_color_attribute_on_add(Mesh &mesh, StringRef id, AttrDomain domain, bke::AttrType data_type)
void mesh_translate(Mesh &mesh, const float3 &translation, bool do_shape_keys)
Bounds< T > merge(const Bounds< T > &a, const Bounds< T > &b)
Definition BLI_bounds.hh:26
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)
T midpoint(const T &a, const T &b)
void min_max(const T &value, T &min, T &max)
int dominant_axis(const VecBase< T, 3 > &a)
void transform_points(const float4x4 &transform, MutableSpan< float3 > points, bool use_threading=true)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
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
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
MatBase< float, 4, 4 > float4x4
VecBase< int32_t, 2 > int2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
VecBase< float, 3 > float3
static void init(bNodeTree *, bNode *node)
const char * name
short mat_nr
int totface
const ImplicitSharingInfoHandle * sharing_info
CustomDataLayer * layers
CustomDataExternal * external
const blender::FunctionRef< void(blender::ImplicitSharingPtr<> &sharing_info, blender::ColorGeometry4f *&data, size_t size)> implicit_sharing_array
Definition DNA_ID.h:414
int tag
Definition DNA_ID.h:442
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:145