Blender V4.3
mesh_convert.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "CLG_log.h"
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_curve_types.h"
14#include "DNA_key_types.h"
15#include "DNA_material_types.h"
16#include "DNA_meta_types.h"
17#include "DNA_object_types.h"
19#include "DNA_scene_types.h"
20
21#include "BLI_index_range.hh"
22#include "BLI_listbase.h"
23#include "BLI_span.hh"
24#include "BLI_string.h"
25#include "BLI_utildefines.h"
26
27#include "BLT_translation.hh"
28
29#include "BKE_curves.hh"
30#include "BKE_deform.hh"
31#include "BKE_displist.h"
32#include "BKE_editmesh.hh"
33#include "BKE_geometry_set.hh"
35#include "BKE_key.hh"
36#include "BKE_lib_id.hh"
37#include "BKE_lib_query.hh"
38#include "BKE_main.hh"
39#include "BKE_material.h"
40#include "BKE_mball.hh"
41#include "BKE_mesh.hh"
42#include "BKE_mesh_runtime.hh"
43#include "BKE_mesh_wrapper.hh"
44#include "BKE_modifier.hh"
45#include "BKE_object_types.hh"
46/* these 2 are only used by conversion functions */
47#include "BKE_curve.hh"
48/* -- */
49#include "BKE_object.hh"
50/* -- */
51#include "BKE_pointcloud.hh"
52
53#include "BKE_curve_to_mesh.hh"
54
55#include "DEG_depsgraph.hh"
57
58using blender::float3;
61using blender::Span;
63
64static CLG_LogRef LOG = {"bke.mesh_convert"};
65
66static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase)
67{
68 using namespace blender;
69 using namespace blender::bke;
70 int a, b, ofs;
71 const bool conv_polys = (
72 /* 2D polys are filled with #DispList.type == #DL_INDEX3. */
73 (CU_DO_2DFILL(cu) == false) ||
74 /* surf polys are never filled */
76
77 /* count */
78 int totvert = 0;
79 int totedge = 0;
80 int faces_num = 0;
81 int totloop = 0;
82 LISTBASE_FOREACH (const DispList *, dl, dispbase) {
83 if (dl->type == DL_SEGM) {
84 totvert += dl->parts * dl->nr;
85 totedge += dl->parts * (dl->nr - 1);
86 }
87 else if (dl->type == DL_POLY) {
88 if (conv_polys) {
89 totvert += dl->parts * dl->nr;
90 totedge += dl->parts * dl->nr;
91 }
92 }
93 else if (dl->type == DL_SURF) {
94 if (dl->parts != 0) {
95 int tot;
96 totvert += dl->parts * dl->nr;
97 tot = (((dl->flag & DL_CYCL_U) ? 1 : 0) + (dl->nr - 1)) *
98 (((dl->flag & DL_CYCL_V) ? 1 : 0) + (dl->parts - 1));
99 faces_num += tot;
100 totloop += tot * 4;
101 }
102 }
103 else if (dl->type == DL_INDEX3) {
104 int tot;
105 totvert += dl->nr;
106 tot = dl->parts;
107 faces_num += tot;
108 totloop += tot * 3;
109 }
110 }
111
112 if (totvert == 0) {
113 return BKE_mesh_new_nomain(0, 0, 0, 0);
114 }
115
116 Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, faces_num, totloop);
117 MutableSpan<float3> positions = mesh->vert_positions_for_write();
118 MutableSpan<blender::int2> edges = mesh->edges_for_write();
119 MutableSpan<int> face_offsets = mesh->face_offsets_for_write();
120 MutableSpan<int> corner_verts = mesh->corner_verts_for_write();
121
122 MutableAttributeAccessor attributes = mesh->attributes_for_write();
123 SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>(
124 "material_index", AttrDomain::Face);
125 SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
126 "sharp_face", AttrDomain::Face);
127 SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_span<float2>(
128 DATA_("UVMap"), AttrDomain::Corner);
129 MutableSpan<float2> uv_map = uv_attribute.span;
130
131 int dst_vert = 0;
132 int dst_edge = 0;
133 int dst_poly = 0;
134 int dst_loop = 0;
135 LISTBASE_FOREACH (const DispList *, dl, dispbase) {
136 const bool is_smooth = (dl->rt & CU_SMOOTH) != 0;
137
138 if (dl->type == DL_SEGM) {
139 const int startvert = dst_vert;
140 a = dl->parts * dl->nr;
141 const float *data = dl->verts;
142 while (a--) {
143 copy_v3_v3(positions[dst_vert], data);
144 data += 3;
145 dst_vert++;
146 }
147
148 for (a = 0; a < dl->parts; a++) {
149 ofs = a * dl->nr;
150 for (b = 1; b < dl->nr; b++) {
151 edges[dst_edge][0] = startvert + ofs + b - 1;
152 edges[dst_edge][1] = startvert + ofs + b;
153
154 dst_edge++;
155 }
156 }
157 }
158 else if (dl->type == DL_POLY) {
159 if (conv_polys) {
160 const int startvert = dst_vert;
161 a = dl->parts * dl->nr;
162 const float *data = dl->verts;
163 while (a--) {
164 copy_v3_v3(positions[dst_vert], data);
165 data += 3;
166 dst_vert++;
167 }
168
169 for (a = 0; a < dl->parts; a++) {
170 ofs = a * dl->nr;
171 for (b = 0; b < dl->nr; b++) {
172 edges[dst_edge][0] = startvert + ofs + b;
173 if (b == dl->nr - 1) {
174 edges[dst_edge][1] = startvert + ofs;
175 }
176 else {
177 edges[dst_edge][1] = startvert + ofs + b + 1;
178 }
179 dst_edge++;
180 }
181 }
182 }
183 }
184 else if (dl->type == DL_INDEX3) {
185 const int startvert = dst_vert;
186 a = dl->nr;
187 const float *data = dl->verts;
188 while (a--) {
189 copy_v3_v3(positions[dst_vert], data);
190 data += 3;
191 dst_vert++;
192 }
193
194 a = dl->parts;
195 const int *index = dl->index;
196 while (a--) {
197 corner_verts[dst_loop + 0] = startvert + index[0];
198 corner_verts[dst_loop + 1] = startvert + index[2];
199 corner_verts[dst_loop + 2] = startvert + index[1];
200 face_offsets[dst_poly] = dst_loop;
201 material_indices.span[dst_poly] = dl->col;
202
203 for (int i = 0; i < 3; i++) {
204 uv_map[dst_loop + i][0] = (corner_verts[dst_loop + i] - startvert) / float(dl->nr - 1);
205 uv_map[dst_loop + i][1] = 0.0f;
206 }
207
208 sharp_faces.span[dst_poly] = !is_smooth;
209 dst_poly++;
210 dst_loop += 3;
211 index += 3;
212 }
213 }
214 else if (dl->type == DL_SURF) {
215 const int startvert = dst_vert;
216 a = dl->parts * dl->nr;
217 const float *data = dl->verts;
218 while (a--) {
219 copy_v3_v3(positions[dst_vert], data);
220 data += 3;
221 dst_vert++;
222 }
223
224 for (a = 0; a < dl->parts; a++) {
225
226 if ((dl->flag & DL_CYCL_V) == 0 && a == dl->parts - 1) {
227 break;
228 }
229
230 int p1, p2, p3, p4;
231 if (dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */
232 p1 = startvert + dl->nr * a; /* p4 -> p3 -> */
233 p2 = p1 + dl->nr - 1; /* -----> next row */
234 p3 = p1 + dl->nr;
235 p4 = p2 + dl->nr;
236 b = 0;
237 }
238 else {
239 p2 = startvert + dl->nr * a;
240 p1 = p2 + 1;
241 p4 = p2 + dl->nr;
242 p3 = p1 + dl->nr;
243 b = 1;
244 }
245 if ((dl->flag & DL_CYCL_V) && a == dl->parts - 1) {
246 p3 -= dl->parts * dl->nr;
247 p4 -= dl->parts * dl->nr;
248 }
249
250 for (; b < dl->nr; b++) {
251 corner_verts[dst_loop + 0] = p1;
252 corner_verts[dst_loop + 1] = p3;
253 corner_verts[dst_loop + 2] = p4;
254 corner_verts[dst_loop + 3] = p2;
255 face_offsets[dst_poly] = dst_loop;
256 material_indices.span[dst_poly] = dl->col;
257
258 int orco_sizeu = dl->nr - 1;
259 int orco_sizev = dl->parts - 1;
260
261 /* exception as handled in convertblender.c too */
262 if (dl->flag & DL_CYCL_U) {
263 orco_sizeu++;
264 if (dl->flag & DL_CYCL_V) {
265 orco_sizev++;
266 }
267 }
268 else if (dl->flag & DL_CYCL_V) {
269 orco_sizev++;
270 }
271
272 for (int i = 0; i < 4; i++) {
273 /* find uv based on vertex index into grid array */
274 int v = corner_verts[dst_loop + i] - startvert;
275
276 uv_map[dst_loop + i][0] = (v / dl->nr) / float(orco_sizev);
277 uv_map[dst_loop + i][1] = (v % dl->nr) / float(orco_sizeu);
278
279 /* cyclic correction */
280 if (ELEM(i, 1, 2) && uv_map[dst_loop + i][0] == 0.0f) {
281 uv_map[dst_loop + i][0] = 1.0f;
282 }
283 if (ELEM(i, 0, 1) && uv_map[dst_loop + i][1] == 0.0f) {
284 uv_map[dst_loop + i][1] = 1.0f;
285 }
286 }
287
288 sharp_faces.span[dst_poly] = !is_smooth;
289 dst_poly++;
290 dst_loop += 4;
291
292 p4 = p3;
293 p3++;
294 p2 = p1;
295 p1++;
296 }
297 }
298 }
299 }
300
301 if (faces_num) {
302 mesh_calc_edges(*mesh, true, false);
303 }
304
305 material_indices.finish();
306 sharp_faces.finish();
307 uv_attribute.finish();
308
309 return mesh;
310}
311
320{
321 mesh->texspace_flag = cu->texspace_flag & ~CU_TEXSPACE_FLAG_AUTO;
322 copy_v3_v3(mesh->texspace_location, cu->texspace_location);
323 copy_v3_v3(mesh->texspace_size, cu->texspace_size);
325}
326
328{
329 const Curve *cu = (const Curve *)ob->data;
330
331 Mesh *mesh = mesh_nurbs_displist_to_mesh(cu, dispbase);
333 mesh->mat = (Material **)MEM_dupallocN(cu->mat);
334 mesh->totcol = cu->totcol;
335
336 return mesh;
337}
338
340{
341 ListBase disp = {nullptr, nullptr};
342
343 if (ob->runtime->curve_cache) {
344 disp = ob->runtime->curve_cache->disp;
345 }
346
348}
349
350struct EdgeLink {
352 const void *edge;
353};
354
359
360static void prependPolyLineVert(ListBase *lb, uint index)
361{
362 VertLink *vl = MEM_cnew<VertLink>("VertLink");
363 vl->index = index;
364 BLI_addhead(lb, vl);
365}
366
367static void appendPolyLineVert(ListBase *lb, uint index)
368{
369 VertLink *vl = MEM_cnew<VertLink>("VertLink");
370 vl->index = index;
371 BLI_addtail(lb, vl);
372}
373
374void BKE_mesh_to_curve_nurblist(const Mesh *mesh, ListBase *nurblist, const int edge_users_test)
375{
376 const Span<float3> positions = mesh->vert_positions();
377 const Span<blender::int2> mesh_edges = mesh->edges();
378 const blender::OffsetIndices polys = mesh->faces();
379 const Span<int> corner_edges = mesh->corner_edges();
380
381 /* only to detect edge polylines */
382 int *edge_users;
383
384 ListBase edges = {nullptr, nullptr};
385
386 /* get boundary edges */
387 edge_users = (int *)MEM_calloc_arrayN(mesh_edges.size(), sizeof(int), __func__);
388 for (const int i : polys.index_range()) {
389 for (const int edge : corner_edges.slice(polys[i])) {
390 edge_users[edge]++;
391 }
392 }
393
394 /* create edges from all faces (so as to find edges not in any faces) */
395 for (const int i : mesh_edges.index_range()) {
396 if (edge_users[i] == edge_users_test) {
397 EdgeLink *edl = MEM_cnew<EdgeLink>("EdgeLink");
398 edl->edge = &mesh_edges[i];
399
400 BLI_addtail(&edges, edl);
401 }
402 }
403 MEM_freeN(edge_users);
404
405 if (edges.first) {
406 while (edges.first) {
407 /* each iteration find a polyline and add this as a nurbs poly spline */
408
409 ListBase polyline = {nullptr, nullptr}; /* store a list of VertLink's */
410 bool closed = false;
411 int faces_num = 0;
412 blender::int2 &edge_current = *(blender::int2 *)((EdgeLink *)edges.last)->edge;
413 uint startVert = edge_current[0];
414 uint endVert = edge_current[1];
415 bool ok = true;
416
417 appendPolyLineVert(&polyline, startVert);
418 faces_num++;
419 appendPolyLineVert(&polyline, endVert);
420 faces_num++;
421 BLI_freelinkN(&edges, edges.last);
422
423 while (ok) { /* while connected edges are found... */
424 EdgeLink *edl = (EdgeLink *)edges.last;
425 ok = false;
426 while (edl) {
427 EdgeLink *edl_prev = edl->prev;
428
429 const blender::int2 &edge = *(blender::int2 *)edl->edge;
430
431 if (edge[0] == endVert) {
432 endVert = edge[1];
433 appendPolyLineVert(&polyline, endVert);
434 faces_num++;
435 BLI_freelinkN(&edges, edl);
436 ok = true;
437 }
438 else if (edge[1] == endVert) {
439 endVert = edge[0];
440 appendPolyLineVert(&polyline, endVert);
441 faces_num++;
442 BLI_freelinkN(&edges, edl);
443 ok = true;
444 }
445 else if (edge[0] == startVert) {
446 startVert = edge[1];
447 prependPolyLineVert(&polyline, startVert);
448 faces_num++;
449 BLI_freelinkN(&edges, edl);
450 ok = true;
451 }
452 else if (edge[1] == startVert) {
453 startVert = edge[0];
454 prependPolyLineVert(&polyline, startVert);
455 faces_num++;
456 BLI_freelinkN(&edges, edl);
457 ok = true;
458 }
459
460 edl = edl_prev;
461 }
462 }
463
464 /* Now we have a polyline, make into a curve */
465 if (startVert == endVert) {
466 BLI_freelinkN(&polyline, polyline.last);
467 faces_num--;
468 closed = true;
469 }
470
471 /* --- nurbs --- */
472 {
473 Nurb *nu;
474 BPoint *bp;
475 VertLink *vl;
476
477 /* create new 'nurb' within the curve */
478 nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), __func__));
479
480 nu->pntsu = faces_num;
481 nu->pntsv = 1;
482 nu->orderu = 4;
483 nu->flagu = CU_NURB_ENDPOINT | (closed ? CU_NURB_CYCLIC : 0); /* endpoint */
484 nu->resolu = 12;
485
486 nu->bp = (BPoint *)MEM_calloc_arrayN(faces_num, sizeof(BPoint), "bpoints");
487
488 /* add points */
489 vl = (VertLink *)polyline.first;
490 int i;
491 for (i = 0, bp = nu->bp; i < faces_num; i++, bp++, vl = (VertLink *)vl->next) {
492 copy_v3_v3(bp->vec, positions[vl->index]);
493 bp->f1 = SELECT;
494 bp->radius = bp->weight = 1.0;
495 }
496 BLI_freelistN(&polyline);
497
498 /* add nurb to curve */
499 BLI_addtail(nurblist, nu);
500 }
501 /* --- done with nurbs --- */
502 }
503 }
504}
505
506void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
507{
508 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
509 if (!ob_eval) {
510 return;
511 }
512 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob_eval);
513 if (!mesh_eval) {
514 return;
515 }
516
517 ListBase nurblist = {nullptr, nullptr};
518
519 BKE_mesh_to_curve_nurblist(mesh_eval, &nurblist, 0);
520 BKE_mesh_to_curve_nurblist(mesh_eval, &nurblist, 1);
521
522 if (nurblist.first) {
523 Curve *cu = BKE_curve_add(bmain, ob->id.name + 2, OB_CURVES_LEGACY);
524 cu->flag |= CU_3D;
525
526 cu->nurb = nurblist;
527
528 id_us_min(&((Mesh *)ob->data)->id);
529 ob->data = cu;
531
533 }
534}
535
536void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
537{
538 BLI_assert(ob->type == OB_MESH);
539 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
540 if (!ob_eval) {
541 return;
542 }
543 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
544 if (!mesh_eval) {
545 return;
546 }
547
548 PointCloud *pointcloud = (PointCloud *)BKE_pointcloud_add(bmain, ob->id.name + 2);
549
550 CustomData_free(&pointcloud->pdata, pointcloud->totpoint);
551 pointcloud->totpoint = mesh_eval->verts_num;
553 &mesh_eval->vert_data, &pointcloud->pdata, CD_MASK_PROP_ALL, mesh_eval->verts_num);
554
555 BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)pointcloud);
556
557 id_us_min(&((Mesh *)ob->data)->id);
558 ob->data = pointcloud;
559 ob->type = OB_POINTCLOUD;
560
562}
563
564void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene * /*scene*/, Object *ob)
565{
567
568 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
570 *ob_eval);
571
572 Mesh *mesh = BKE_mesh_add(bmain, ob->id.name + 2);
573
574 if (const PointCloud *points = geometry.get_pointcloud()) {
575 mesh->verts_num = points->totpoint;
576 CustomData_merge(&points->pdata, &mesh->vert_data, CD_MASK_PROP_ALL, points->totpoint);
577 }
578
579 BKE_id_materials_copy(bmain, (ID *)ob->data, (ID *)mesh);
580
581 id_us_min(&((PointCloud *)ob->data)->id);
582 ob->data = mesh;
583 ob->type = OB_MESH;
584
586}
587
588/* Create a temporary object to be used for nurbs-to-mesh conversion. */
590{
591 const Curve *curve = (const Curve *)object->data;
592
593 /* Create a temporary object which can be evaluated and modified by generic
594 * curve evaluation (hence the #LIB_ID_COPY_SET_COPIED_ON_WRITE flag). */
595 Object *temp_object = (Object *)BKE_id_copy_ex(
596 nullptr, &object->id, nullptr, LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_SET_COPIED_ON_WRITE);
597
598 /* Remove all modifiers, since we don't want them to be applied. */
600
601 /* Need to create copy of curve itself as well, since it will be changed by the curve evaluation
602 * process. NOTE: Copies the data, but not the shape-keys. */
603 temp_object->data = BKE_id_copy_ex(nullptr,
604 (const ID *)object->data,
605 nullptr,
607 Curve *temp_curve = (Curve *)temp_object->data;
608
609 /* Make sure texture space is calculated for a copy of curve, it will be used for the final
610 * result. */
611 BKE_curve_texspace_calc(temp_curve);
612
613 /* Temporarily set edit so we get updates from edit mode, but also because for text data-blocks
614 * copying it while in edit mode gives invalid data structures. */
615 temp_curve->editfont = curve->editfont;
616 temp_curve->editnurb = curve->editnurb;
617
618 return temp_object;
619}
620
621static void object_for_curve_to_mesh_free(Object *temp_object)
622{
623 /* Clear edit mode pointers that were explicitly copied to the temporary curve. */
624 ID *final_object_data = static_cast<ID *>(temp_object->data);
625 if (GS(final_object_data->name) == ID_CU_LEGACY) {
626 Curve &curve = *reinterpret_cast<Curve *>(final_object_data);
627 curve.editfont = nullptr;
628 curve.editnurb = nullptr;
629 }
630
631 /* Only free the final object data if it is *not* stored in the #data_eval field. This is still
632 * necessary because #temp_object's data could be replaced by a #Curve data-block that isn't also
633 * assigned to #data_eval. */
634 const bool object_data_stored_in_data_eval = final_object_data ==
635 temp_object->runtime->data_eval;
636
637 BKE_id_free(nullptr, temp_object);
638 if (!object_data_stored_in_data_eval) {
639 BKE_id_free(nullptr, final_object_data);
640 }
641}
642
647{
648 BLI_assert(GS(static_cast<ID *>(object.data)->name) == ID_CU_LEGACY);
649 Curve &curve = *static_cast<Curve *>(object.data);
650 /* Clear all modifiers for the bevel object.
651 *
652 * This is because they can not be reliably evaluated for an original object (at least because
653 * the state of dependencies is not know).
654 *
655 * So we create temporary copy of the object which will use same data as the original bevel, but
656 * will have no modifiers. */
657 Object bevel_object = blender::dna::shallow_zero_initialize();
658 blender::bke::ObjectRuntime bevel_runtime;
659 if (curve.bevobj != nullptr) {
660 bevel_object = blender::dna::shallow_copy(*curve.bevobj);
661 bevel_runtime = *curve.bevobj->runtime;
662 bevel_object.runtime = &bevel_runtime;
663
664 BLI_listbase_clear(&bevel_object.modifiers);
665 BKE_object_runtime_reset(&bevel_object);
666 curve.bevobj = &bevel_object;
667 }
668
669 /* Same thing for taper. */
670 Object taper_object = blender::dna::shallow_zero_initialize();
671 blender::bke::ObjectRuntime taper_runtime;
672 if (curve.taperobj != nullptr) {
673 taper_object = blender::dna::shallow_copy(*curve.taperobj);
674 taper_runtime = *curve.taperobj->runtime;
675 taper_object.runtime = &taper_runtime;
676
677 BLI_listbase_clear(&taper_object.modifiers);
678 BKE_object_runtime_reset(&taper_object);
679 curve.taperobj = &taper_object;
680 }
681
682 /* NOTE: We don't have dependency graph or scene here, so we pass nullptr. This is all fine since
683 * they are only used for modifier stack, which we have explicitly disabled for all objects.
684 *
685 * TODO(sergey): This is a very fragile logic, but proper solution requires re-writing quite a
686 * bit of internal functions (#BKE_mesh_nomain_to_mesh) and also Mesh From Curve operator.
687 * Brecht says hold off with that. */
688 BKE_displist_make_curveTypes(nullptr, nullptr, &object, true);
689
690 if (bevel_object.runtime) {
691 BKE_object_runtime_free_data(&bevel_object);
692 }
693 if (taper_object.runtime) {
694 BKE_object_runtime_free_data(&taper_object);
695 }
696}
697
699{
700 if (blender::bke::GeometrySet *geometry_set_eval = object->runtime->geometry_set_eval) {
701 return geometry_set_eval->get_curves();
702 }
703 return nullptr;
704}
705
707{
708 if (const Mesh *mesh = BKE_object_get_evaluated_mesh(evaluated_object)) {
709 return BKE_mesh_copy_for_eval(*mesh);
710 }
711 if (const Curves *curves = get_evaluated_curves_from_object(evaluated_object)) {
712 return blender::bke::curve_to_wire_mesh(curves->geometry.wrap());
713 }
714 return nullptr;
715}
716
718{
719 /* If the object is evaluated, it should either have an evaluated mesh or curve data already.
720 * The mesh can be duplicated, or the curve converted to wire mesh edges. */
721 if (DEG_is_evaluated_object(object)) {
723 }
724
725 /* Otherwise, create a temporary "fake" evaluated object and try again. This might have
726 * different results, since in order to avoid having adverse affects to other original objects,
727 * modifiers are cleared. An alternative would be to create a temporary depsgraph only for this
728 * object and its dependencies. */
729 Object *temp_object = object_for_curve_to_mesh_create(object);
730 ID *temp_data = static_cast<ID *>(temp_object->data);
731 curve_to_mesh_eval_ensure(*temp_object);
732
733 /* If evaluating the curve replaced object data with different data, free the original data. */
734 if (temp_data != temp_object->data) {
735 if (GS(temp_data->name) == ID_CU_LEGACY) {
736 /* Clear edit mode pointers that were explicitly copied to the temporary curve. */
737 Curve *curve = reinterpret_cast<Curve *>(temp_data);
738 curve->editfont = nullptr;
739 curve->editnurb = nullptr;
740 }
741 BKE_id_free(nullptr, temp_data);
742 }
743
745
747
748 return mesh;
749}
750
752{
753 /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta
754 * balls and all evaluated child meta balls (since polygonization is only stored in the mother
755 * ball).
756 *
757 * Create empty mesh so script-authors don't run into None objects. */
758 if (!DEG_is_evaluated_object(object)) {
759 return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
760 }
761
762 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object);
763 if (mesh_eval == nullptr) {
764 return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2);
765 }
766
767 return BKE_mesh_copy_for_eval(*mesh_eval);
768}
769
770static Mesh *mesh_new_from_mesh(Object *object, const Mesh *mesh)
771{
772 /* While we could copy this into the new mesh,
773 * add the data to 'mesh' so future calls to this function don't need to re-convert the data. */
774 if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) {
775 BKE_mesh_wrapper_ensure_mdata(const_cast<Mesh *>(mesh));
776 }
777 else {
778 mesh = BKE_mesh_wrapper_ensure_subdivision(const_cast<Mesh *>(mesh));
779 }
780
781 Mesh *mesh_result = (Mesh *)BKE_id_copy_ex(
782 nullptr, &mesh->id, nullptr, LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT);
783 /* NOTE: Materials should already be copied. */
784 /* Copy original mesh name. This is because edit meshes might not have one properly set name. */
785 STRNCPY(mesh_result->id.name, ((ID *)object->data)->name);
786 return mesh_result;
787}
788
790 Object *object,
791 const bool preserve_origindex)
792{
793 if (DEG_is_original_id(&object->id)) {
794 return mesh_new_from_mesh(object, (Mesh *)object->data);
795 }
796
797 if (depsgraph == nullptr) {
798 return nullptr;
799 }
800
801 Object object_for_eval = blender::dna::shallow_copy(*object);
802 blender::bke::ObjectRuntime runtime = *object->runtime;
803 object_for_eval.runtime = &runtime;
804
805 if (object_for_eval.runtime->data_orig != nullptr) {
806 object_for_eval.data = object_for_eval.runtime->data_orig;
807 }
808
811 if (preserve_origindex) {
812 mask.vmask |= CD_MASK_ORIGINDEX;
813 mask.emask |= CD_MASK_ORIGINDEX;
814 mask.lmask |= CD_MASK_ORIGINDEX;
815 mask.pmask |= CD_MASK_ORIGINDEX;
816 }
817 Mesh *result = blender::bke::mesh_create_eval_final(depsgraph, scene, &object_for_eval, &mask);
819}
820
822 Object *object,
823 const bool preserve_all_data_layers,
824 const bool preserve_origindex)
825{
826 /* This function tries to reevaluate the object from the original data. If the original object
827 * was not a mesh object, this won't work because it uses mesh object evaluation which assumes
828 * the type of the original object data. */
829 if (!(object->runtime->data_orig && GS(object->runtime->data_orig->name) != ID_ME) &&
830 (preserve_all_data_layers || preserve_origindex))
831 {
832 return mesh_new_from_mesh_object_with_layers(depsgraph, object, preserve_origindex);
833 }
834 const Mesh *mesh_input = (const Mesh *)object->data;
835 /* If we are in edit mode, use evaluated mesh from edit structure, matching to what
836 * viewport is using for visualization. */
837 if (mesh_input->runtime->edit_mesh != nullptr) {
838 if (const Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(object)) {
839 mesh_input = editmesh_eval_final;
840 }
841 }
842 return mesh_new_from_mesh(object, mesh_input);
843}
844
846 Object *object,
847 const bool preserve_all_data_layers,
848 const bool preserve_origindex)
849{
850 Mesh *new_mesh = nullptr;
851 switch (object->type) {
852 case OB_FONT:
853 case OB_CURVES_LEGACY:
854 case OB_SURF:
855 new_mesh = mesh_new_from_curve_type_object(object);
856 break;
857 case OB_MBALL:
858 new_mesh = mesh_new_from_mball_object(object);
859 break;
860 case OB_MESH:
861 new_mesh = mesh_new_from_mesh_object(
862 depsgraph, object, preserve_all_data_layers, preserve_origindex);
863 break;
864 default:
865 /* Object does not have geometry data. */
866 return nullptr;
867 }
868 if (new_mesh == nullptr) {
869 /* Happens in special cases like request of mesh for non-mother meta ball. */
870 return nullptr;
871 }
872
873 /* The result must have 0 users, since it's just a mesh which is free-dangling data-block.
874 * All the conversion functions are supposed to ensure mesh is not counted. */
875 BLI_assert(new_mesh->id.us == 0);
876
877 /* It is possible that mesh came from modifier stack evaluation, which preserves edit_mesh
878 * pointer (which allows draw manager to access edit mesh when drawing). Normally this does
879 * not cause ownership problems because evaluated object runtime is keeping track of the real
880 * ownership.
881 *
882 * Here we are constructing a mesh which is supposed to be independent, which means no shared
883 * ownership is allowed, so we make sure edit mesh is reset to nullptr (which is similar to as if
884 * one duplicates the objects and applies all the modifiers). */
885 new_mesh->runtime->edit_mesh = nullptr;
886
887 return new_mesh;
888}
889
891{
892 ID **id_p = cb_data->id_pointer;
893 if (*id_p == nullptr) {
894 return IDWALK_RET_NOP;
895 }
896 *id_p = DEG_get_original_id(*id_p);
897
898 return IDWALK_RET_NOP;
899}
900
902{
903 ID **id_p = cb_data->id_pointer;
904 if (*id_p == nullptr) {
905 return IDWALK_RET_NOP;
906 }
907
908 const int cb_flag = cb_data->cb_flag;
909 if (cb_flag & IDWALK_CB_USER) {
910 id_us_plus(*id_p);
911 }
912 else if (cb_flag & IDWALK_CB_USER_ONE) {
913 /* NOTE: in that context, that one should not be needed (since there should be at least already
914 * one USER_ONE user of that ID), but better be consistent. */
915 id_us_ensure_real(*id_p);
916 }
917 return IDWALK_RET_NOP;
918}
919
921 Depsgraph *depsgraph,
922 Object *object,
923 bool preserve_all_data_layers)
924{
926
927 Mesh *mesh = BKE_mesh_new_from_object(depsgraph, object, preserve_all_data_layers, false);
928 if (mesh == nullptr) {
929 /* Unable to convert the object to a mesh, return an empty one. */
930 Mesh *mesh_in_bmain = BKE_mesh_add(bmain, ((ID *)object->data)->name + 2);
931 id_us_min(&mesh_in_bmain->id);
932 return mesh_in_bmain;
933 }
934
935 /* Make sure mesh only points to original data-blocks. Also increase user count of materials and
936 * other possibly referenced data-blocks.
937 *
938 * Changing to original data-blocks is required to have bmain in a consistent state, where
939 * everything is only allowed to reference original data-blocks.
940 *
941 * Note that user-count updates have to be done *after* the mesh has been transferred to Main
942 * database (since doing reference-counting on non-Main IDs is forbidden). */
944 nullptr, &mesh->id, foreach_libblock_make_original_callback, nullptr, IDWALK_NOP);
945
946 /* Add the mesh to 'bmain'. We do it in a bit longer way since there is no simple and clear way
947 * of adding existing data-blocks to the 'bmain'. So we create new empty mesh (which guarantees
948 * all the naming and order and flags) and move the temporary mesh in place there. */
949 Mesh *mesh_in_bmain = BKE_mesh_add(bmain, mesh->id.name + 2);
950
951 /* NOTE: BKE_mesh_nomain_to_mesh() does not copy materials and instead preserves them in the
952 * destination mesh. So we "steal" materials before calling it.
953 *
954 * TODO(sergey): We really ought to have a function which gets an ID and accepts it into #Main.
955 */
956 mesh_in_bmain->mat = mesh->mat;
957 mesh_in_bmain->totcol = mesh->totcol;
958 mesh->mat = nullptr;
959
960 BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, nullptr);
961
962 /* Anonymous attributes shouldn't exist on original data. */
963 mesh_in_bmain->attributes_for_write().remove_anonymous();
964
965 /* User-count is required because so far mesh was in a limbo, where library management does
966 * not perform any user management (i.e. copy of a mesh will not increase users of materials). */
968 nullptr, &mesh_in_bmain->id, foreach_libblock_make_usercounts_callback, nullptr, IDWALK_NOP);
969
970 /* Make sure user count from BKE_mesh_add() is the one we expect here and bring it down to 0. */
971 BLI_assert(mesh_in_bmain->id.us == 1);
972 id_us_min(&mesh_in_bmain->id);
973
974 return mesh_in_bmain;
975}
976
977static void copy_loose_vert_hint(const Mesh &src, Mesh &dst)
978{
979 const auto &src_cache = src.runtime->loose_verts_cache;
980 if (src_cache.is_cached() && src_cache.data().count == 0) {
981 dst.tag_loose_verts_none();
982 }
983}
984
985static void copy_loose_edge_hint(const Mesh &src, Mesh &dst)
986{
987 const auto &src_cache = src.runtime->loose_edges_cache;
988 if (src_cache.is_cached() && src_cache.data().count == 0) {
989 dst.tag_loose_edges_none();
990 }
991}
992
993static void copy_overlapping_hint(const Mesh &src, Mesh &dst)
994{
995 if (src.no_overlapping_topology()) {
996 dst.tag_overlapping_none();
997 }
998}
999
1000static KeyBlock *keyblock_ensure_from_uid(Key &key, const int uid, const StringRefNull name)
1001{
1002 if (KeyBlock *kb = BKE_keyblock_find_uid(&key, uid)) {
1003 return kb;
1004 }
1005 KeyBlock *kb = BKE_keyblock_add(&key, name.c_str());
1006 kb->uid = uid;
1007 return kb;
1008}
1009
1010static int find_object_active_key_uid(const Key &key, const Object &object)
1011{
1012 const int active_kb_index = object.shapenr - 1;
1013 const KeyBlock *kb = (const KeyBlock *)BLI_findlink(&key.block, active_kb_index);
1014 if (!kb) {
1015 CLOG_ERROR(&LOG, "Could not find object's active shapekey %d", active_kb_index);
1016 return -1;
1017 }
1018 return kb->uid;
1019}
1020
1022 const CustomData &custom_data,
1023 Key &key_dst,
1024 const int actshape_uid)
1025{
1026 using namespace blender::bke;
1027 for (const int i : IndexRange(CustomData_number_of_layers(&custom_data, CD_SHAPEKEY))) {
1028 const int layer_index = CustomData_get_layer_index_n(&custom_data, CD_SHAPEKEY, i);
1029 const CustomDataLayer &layer = custom_data.layers[layer_index];
1030
1031 KeyBlock *kb = keyblock_ensure_from_uid(key_dst, layer.uid, layer.name);
1032 MEM_SAFE_FREE(kb->data);
1033
1034 kb->totelem = mesh.verts_num;
1035 kb->data = MEM_malloc_arrayN(kb->totelem, sizeof(float3), __func__);
1036 MutableSpan<float3> kb_coords(static_cast<float3 *>(kb->data), kb->totelem);
1037 if (kb->uid == actshape_uid) {
1038 mesh.attributes().lookup<float3>("position").varray.materialize(kb_coords);
1039 }
1040 else {
1041 kb_coords.copy_from({static_cast<const float3 *>(layer.data), mesh.verts_num});
1042 }
1043 }
1044
1045 LISTBASE_FOREACH (KeyBlock *, kb, &key_dst.block) {
1046 if (kb->totelem != mesh.verts_num) {
1047 MEM_SAFE_FREE(kb->data);
1048 kb->totelem = mesh.verts_num;
1049 kb->data = MEM_cnew_array<float3>(kb->totelem, __func__);
1050 CLOG_ERROR(&LOG, "Data for shape key '%s' on mesh missing from evaluated mesh ", kb->name);
1051 }
1052 }
1053}
1054
1055void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
1056{
1057 using namespace blender::bke;
1058 BLI_assert(mesh_src->id.tag & ID_TAG_NO_MAIN);
1059 if (ob) {
1060 BLI_assert(mesh_dst == ob->data);
1061 }
1062
1063 const bool verts_num_changed = mesh_dst->verts_num != mesh_src->verts_num;
1064
1066
1067 mesh_dst->verts_num = mesh_src->verts_num;
1068 mesh_dst->edges_num = mesh_src->edges_num;
1069 mesh_dst->faces_num = mesh_src->faces_num;
1070 mesh_dst->corners_num = mesh_src->corners_num;
1071
1072 /* Using #CD_MASK_MESH ensures that only data that should exist in Main meshes is moved. */
1075 &mesh_src->vert_data, &mesh_dst->vert_data, mask.vmask, mesh_src->verts_num);
1077 &mesh_src->edge_data, &mesh_dst->edge_data, mask.emask, mesh_src->edges_num);
1079 &mesh_src->face_data, &mesh_dst->face_data, mask.pmask, mesh_src->faces_num);
1081 &mesh_src->corner_data, &mesh_dst->corner_data, mask.lmask, mesh_src->corners_num);
1082 std::swap(mesh_dst->face_offset_indices, mesh_src->face_offset_indices);
1083 std::swap(mesh_dst->runtime->face_offsets_sharing_info,
1084 mesh_src->runtime->face_offsets_sharing_info);
1085
1086 /* Make sure attribute names are moved. */
1087 std::swap(mesh_dst->active_color_attribute, mesh_src->active_color_attribute);
1088 std::swap(mesh_dst->default_color_attribute, mesh_src->default_color_attribute);
1089 std::swap(mesh_dst->vertex_group_names, mesh_src->vertex_group_names);
1090
1091 BKE_mesh_copy_parameters(mesh_dst, mesh_src);
1092
1093 /* For original meshes, shape key data is stored in the #Key data-block, so it
1094 * must be moved from the storage in #CustomData layers used for evaluation. */
1095 if (Key *key_dst = mesh_dst->key) {
1096 if (CustomData_has_layer(&mesh_src->vert_data, CD_SHAPEKEY)) {
1097 /* If no object, set to -1 so we don't mess up any shapekey layers. */
1098 const int uid_active = ob ? find_object_active_key_uid(*key_dst, *ob) : -1;
1099 move_shapekey_layers_to_keyblocks(*mesh_dst, mesh_src->vert_data, *key_dst, uid_active);
1100 }
1101 else if (verts_num_changed) {
1102 CLOG_WARN(&LOG, "Shape key data lost when replacing mesh '%s' in Main", mesh_src->id.name);
1103 id_us_min(&mesh_dst->key->id);
1104 mesh_dst->key = nullptr;
1105 }
1106 }
1107
1108 /* Caches can have a large memory impact and aren't necessarily used, so don't indiscriminately
1109 * store all of them in the #Main data-base mesh. However, some caches are quite small and
1110 * copying them is "free" relative to how much work would be required if the data was needed. */
1111 copy_loose_vert_hint(*mesh_src, *mesh_dst);
1112 copy_loose_edge_hint(*mesh_src, *mesh_dst);
1113 copy_overlapping_hint(*mesh_src, *mesh_dst);
1114
1115 BKE_id_free(nullptr, mesh_src);
1116}
1117
1118void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
1119{
1120 BLI_assert(mesh_src->id.tag & ID_TAG_NO_MAIN);
1121
1122 const int totvert = mesh_src->verts_num;
1123
1124 if (totvert == 0 || mesh_dst->verts_num == 0 || mesh_dst->verts_num != totvert) {
1125 return;
1126 }
1127
1128 if (kb->data) {
1129 MEM_freeN(kb->data);
1130 }
1131 kb->data = MEM_malloc_arrayN(mesh_dst->key->elemsize, mesh_dst->verts_num, "kb->data");
1132 kb->totelem = totvert;
1133 MutableSpan(static_cast<float3 *>(kb->data), kb->totelem).copy_from(mesh_src->vert_positions());
1134}
#define CU_DO_2DFILL(cu)
Definition BKE_curve.hh:89
void BKE_curve_texspace_calc(Curve *cu)
Definition curve.cc:466
short BKE_curve_type_get(const Curve *cu)
Definition curve.cc:416
Curve * BKE_curve_add(Main *bmain, const char *name, int type)
Definition curve.cc:386
Low-level operations for curves.
int CustomData_get_layer_index_n(const CustomData *data, eCustomDataType type, int n)
void CustomData_init_from(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
void CustomData_free(CustomData *data, int totelem)
bool CustomData_merge(const CustomData *source, CustomData *dest, eCustomDataMask mask, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
int CustomData_number_of_layers(const CustomData *data, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_MESH
support for deformation groups and hooks.
display list (or rather multi purpose list) stuff.
void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, bool for_render)
@ DL_CYCL_V
@ DL_CYCL_U
@ DL_SURF
@ DL_INDEX3
@ DL_POLY
@ DL_SEGM
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
Definition key.cc:1831
KeyBlock * BKE_keyblock_find_uid(Key *key, int uid)
Definition key.cc:1937
@ LIB_ID_COPY_SET_COPIED_ON_WRITE
@ LIB_ID_COPY_LOCALIZE
@ LIB_ID_CREATE_NO_USER_REFCOUNT
@ LIB_ID_CREATE_NO_MAIN
void BKE_id_free(Main *bmain, void *idv)
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_ensure_real(ID *id)
Definition lib_id.cc:306
ID * BKE_id_copy_ex(Main *bmain, const ID *id, ID **new_id_p, int flag)
Definition lib_id.cc:760
void id_us_min(ID *id)
Definition lib_id.cc:359
void * BKE_id_new_nomain(short type, const char *name)
Definition lib_id.cc:1487
@ IDWALK_RET_NOP
@ IDWALK_CB_USER_ONE
@ IDWALK_CB_USER
void BKE_library_foreach_ID_link(Main *bmain, ID *id, blender::FunctionRef< LibraryIDLinkCallback > callback, void *user_data, int flag)
Definition lib_query.cc:416
@ IDWALK_NOP
General operations, lookup, etc. for materials.
void BKE_id_materials_copy(struct Main *bmain, struct ID *id_src, struct ID *id_dst)
void BKE_mesh_clear_geometry_and_metadata(Mesh *mesh)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_add(Main *bmain, const char *name)
void BKE_mesh_copy_parameters(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
void BKE_mesh_texspace_calc(Mesh *mesh)
@ ME_WRAPPER_TYPE_BMESH
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
Mesh * BKE_mesh_wrapper_ensure_subdivision(Mesh *mesh)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh_no_subsurf(const Object *object_eval)
void BKE_object_runtime_reset(Object *object)
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
void BKE_object_runtime_free_data(Object *object)
void BKE_object_free_modifiers(Object *ob, int flag)
const Mesh * BKE_object_get_editmesh_eval_final(const Object *object)
void BKE_object_free_derived_caches(Object *ob)
General operations for point clouds.
void * BKE_pointcloud_add(Main *bmain, const char *name)
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define STRNCPY(dst, src)
Definition BLI_string.h:593
unsigned int uint
#define ELEM(...)
#define DATA_(msgid)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
bool DEG_is_original_id(const ID *id)
ID * DEG_get_original_id(ID *id)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
bool DEG_is_evaluated_object(const Object *object)
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:945
@ ID_CU_LEGACY
@ ID_ME
@ CU_SMOOTH
@ CU_3D
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
#define CD_MASK_ORIGINDEX
#define CD_MASK_PROP_ALL
Object is a sort of wrapper for general info.
@ OB_MBALL
@ OB_SURF
@ OB_FONT
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES_LEGACY
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:726
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
local_group_size(16, 16) .push_constant(Type b
#define SELECT
const Depsgraph * depsgraph
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define GS(x)
Definition iris.cc:202
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
void BKE_mesh_to_pointcloud(Main *bmain, Depsgraph *depsgraph, Scene *, Object *ob)
static Mesh * mesh_new_from_mesh_object(Depsgraph *depsgraph, Object *object, const bool preserve_all_data_layers, const bool preserve_origindex)
static void copy_loose_edge_hint(const Mesh &src, Mesh &dst)
void BKE_mesh_to_curve_nurblist(const Mesh *mesh, ListBase *nurblist, const int edge_users_test)
void BKE_pointcloud_to_mesh(Main *bmain, Depsgraph *depsgraph, Scene *, Object *ob)
Mesh * BKE_mesh_new_nomain_from_curve(const Object *ob)
static Mesh * mesh_new_from_mball_object(Object *object)
static Mesh * mesh_new_from_mesh(Object *object, const Mesh *mesh)
static Object * object_for_curve_to_mesh_create(const Object *object)
static void mesh_copy_texture_space_from_curve_type(const Curve *cu, Mesh *mesh)
void BKE_mesh_nomain_to_meshkey(Mesh *mesh_src, Mesh *mesh_dst, KeyBlock *kb)
static void appendPolyLineVert(ListBase *lb, uint index)
static KeyBlock * keyblock_ensure_from_uid(Key &key, const int uid, const StringRefNull name)
static Mesh * mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase)
static void curve_to_mesh_eval_ensure(Object &object)
void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
static int foreach_libblock_make_original_callback(LibraryIDLinkCallbackData *cb_data)
Mesh * BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *dispbase)
Mesh * BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, const bool preserve_all_data_layers, const bool preserve_origindex)
static void copy_overlapping_hint(const Mesh &src, Mesh &dst)
static void prependPolyLineVert(ListBase *lb, uint index)
void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *, Object *ob)
static void move_shapekey_layers_to_keyblocks(const Mesh &mesh, const CustomData &custom_data, Key &key_dst, const int actshape_uid)
static int find_object_active_key_uid(const Key &key, const Object &object)
static Mesh * mesh_new_from_evaluated_curve_type_object(const Object *evaluated_object)
static void copy_loose_vert_hint(const Mesh &src, Mesh &dst)
static int foreach_libblock_make_usercounts_callback(LibraryIDLinkCallbackData *cb_data)
static CLG_LogRef LOG
static Mesh * mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph, Object *object, const bool preserve_origindex)
static const Curves * get_evaluated_curves_from_object(const Object *object)
static Mesh * mesh_new_from_curve_type_object(const Object *object)
Mesh * BKE_mesh_new_from_object_to_bmain(Main *bmain, Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers)
static void object_for_curve_to_mesh_free(Object *temp_object)
GeometrySet object_get_evaluated_geometry_set(const Object &object)
Mesh * curve_to_wire_mesh(const CurvesGeometry &curve, const bke::AttributeFilter &attribute_filter={})
Mesh * mesh_create_eval_final(Depsgraph *depsgraph, const Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
uint8_t f1
float vec[4]
struct Material ** mat
short totcol
struct EditFont * editfont
char texspace_flag
EditNurb * editnurb
ListBase nurb
float texspace_size[3]
float texspace_location[3]
CustomDataLayer * layers
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
int us
Definition DNA_ID.h:435
char name[66]
Definition DNA_ID.h:425
void * data
int elemsize
ListBase block
void * last
void * first
int corners_num
CustomData edge_data
char texspace_flag
int edges_num
MeshRuntimeHandle * runtime
struct Material ** mat
CustomData corner_data
CustomData face_data
char * default_color_attribute
ListBase vertex_group_names
int * face_offset_indices
CustomData vert_data
short totcol
struct Key * key
int faces_num
int verts_num
char * active_color_attribute
short flagu
short orderu
BPoint * bp
short resolu
ObjectRuntimeHandle * runtime
ListBase modifiers
struct CustomData pdata