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