Blender V5.0
bmesh_py_types.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_math_geom.h"
10#include "BLI_math_matrix.h"
11#include "BLI_math_vector.h"
12#include "BLI_sort.h"
13#include "BLI_string_utils.hh"
14
15#include "DNA_material_types.h"
16#include "DNA_mesh_types.h"
17#include "DNA_object_types.h"
18#include "DNA_scene_types.h"
19
20#include "BKE_customdata.hh"
21#include "BKE_global.hh"
22#include "BKE_lib_id.hh"
23#include "BKE_mesh.h"
24#include "BKE_mesh_runtime.hh"
25#include "BKE_mesh_types.hh"
26#include "BKE_object.hh"
27
28#include "DEG_depsgraph.hh"
30
31#include "bmesh.hh"
32
33#include <Python.h>
34
35#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
36
38
41
42#include "bmesh_py_types.hh" /* own include */
46
48
49/* Common Flags
50 * ************ */
51
52/* scene does not use BM_* flags. */
54 {1, "VERT"},
55 {2, "EDGE"},
56 {4, "FACE"},
57 {0, nullptr},
58};
59
61 {BM_VERT, "VERT"},
62 {BM_EDGE, "EDGE"},
63 {BM_FACE, "FACE"},
64 {0, nullptr},
65};
66
68 {BM_VERT, "VERT"},
69 {BM_LOOP, "EDGE"},
70 {BM_FACE, "FACE"},
71 {BM_LOOP, "LOOP"},
72 {0, nullptr},
73};
74
76#define BPY_BM_HTYPE_NOLOOP "'VERT', 'EDGE', 'FACE'"
77
79#define BPY_BM_HFLAG_ALL_STR "'SELECT', 'HIDE', 'SEAM', 'SMOOTH', 'TAG'"
80
82 {BM_ELEM_SELECT, "SELECT"},
83 {BM_ELEM_HIDDEN, "HIDE"},
84 {BM_ELEM_SEAM, "SEAM"},
85 {BM_ELEM_SMOOTH, "SMOOTH"},
86 {BM_ELEM_TAG, "TAG"},
87 {0, nullptr},
88};
89
90/* This could/should be shared with `scene.toolsettings.uv_sticky_select_mode`.
91 * however it relies on using the RNA API. */
93 {UV_STICKY_LOCATION, "SHARED_LOCATION"},
94 {UV_STICKY_DISABLE, "DISABLED"},
95 {UV_STICKY_VERT, "SHARED_VERTEX"},
96 {0, nullptr},
97};
98
99/* py-type definitions
100 * ******************* */
101
102/* getseters
103 * ========= */
104
105/* bmesh elems
106 * ----------- */
107
109 /* Wrap. */
110 bpy_bm_elem_select_doc,
111 "Selected state of this element.\n"
112 "\n"
113 ":type: bool\n");
115 /* Wrap. */
116 bpy_bm_elem_hide_doc,
117 "Hidden state of this element.\n"
118 "\n"
119 ":type: bool\n");
121 /* Wrap. */
122 bpy_bm_elem_tag_doc,
123 "Generic attribute scripts can use for own logic\n"
124 "\n"
125 ":type: bool\n");
127 /* Wrap. */
128 bpy_bm_elem_smooth_doc,
129 "Smooth state of this element.\n"
130 "\n"
131 ":type: bool\n");
133 /* Wrap. */
134 bpy_bm_elem_seam_doc,
135 "Seam for UV unwrapping.\n"
136 "\n"
137 ":type: bool\n");
139 /* Wrap. */
140 bpy_bm_elem_uv_select_doc,
141 "UV selected state of this element.\n"
142 "\n"
143 ":type: bool\n");
144
145static PyObject *bpy_bm_elem_hflag_get(BPy_BMElem *self, void *flag)
146{
147 const char hflag = char(POINTER_AS_INT(flag));
148
150
151 return PyBool_FromLong(BM_elem_flag_test(self->ele, hflag));
152}
153
154static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag)
155{
156 const char hflag = char(POINTER_AS_INT(flag));
157 int param;
158
160
161 if ((param = PyC_Long_AsBool(value)) == -1) {
162 return -1;
163 }
164
165 if (hflag == BM_ELEM_SELECT) {
166 BM_elem_select_set(self->bm, self->ele, param);
167 }
168 else {
169 BM_elem_flag_set(self->ele, hflag, param);
170 }
171 return 0;
172}
173
175 /* Wrap. */
176 bpy_bm_elem_index_doc,
177 "Index of this element.\n"
178 "\n"
179 ":type: int\n"
180 "\n"
181 ".. note::\n"
182 "\n"
183 " This value is not necessarily valid, while editing the mesh it can become *dirty*.\n"
184 "\n"
185 " It's also possible to assign any number to this attribute for a scripts internal logic.\n"
186 "\n"
187 " To ensure the value is up to date - see :class:`bmesh.types.BMElemSeq.index_update`.\n");
188static PyObject *bpy_bm_elem_index_get(BPy_BMElem *self, void * /*flag*/)
189{
191
192 return PyLong_FromLong(BM_elem_index_get(self->ele));
193}
194
195static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void * /*flag*/)
196{
197 int param;
198
200
201 if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
202 /* error is set */
203 return -1;
204 }
205
206 BM_elem_index_set(self->ele, param); /* set_dirty! */
207
208 /* when setting the index assume its set invalid */
209 self->bm->elem_index_dirty |= self->ele->head.htype;
210
211 return 0;
212}
213
214/* type specific get/sets
215 * ---------------------- */
216
217/* Mesh
218 * ^^^^ */
219
220/* doc-strings for all uses of this function */
221
223 /* Wrap. */
224 bpy_bmvertseq_doc,
225 "This meshes vert sequence (read-only).\n"
226 "\n"
227 ":type: :class:`bmesh.types.BMVertSeq`\n");
228static PyObject *bpy_bmvertseq_get(BPy_BMesh *self, void * /*closure*/)
229{
232}
233
235 /* Wrap. */
236 bpy_bmedgeseq_doc,
237 "This meshes edge sequence (read-only).\n"
238 "\n"
239 ":type: :class:`bmesh.types.BMEdgeSeq`\n");
240static PyObject *bpy_bmedgeseq_get(BPy_BMesh *self, void * /*closure*/)
241{
244}
245
247 /* Wrap. */
248 bpy_bmfaceseq_doc,
249 "This meshes face sequence (read-only).\n"
250 "\n"
251 ":type: :class:`bmesh.types.BMFaceSeq`\n");
252static PyObject *bpy_bmfaceseq_get(BPy_BMesh *self, void * /*closure*/)
253{
256}
257
259 /* Wrap. */
260 bpy_bmloopseq_doc,
261 "This meshes loops (read-only).\n"
262 "\n"
263 ":type: :class:`bmesh.types.BMLoopSeq`\n"
264 "\n"
265 ".. note::\n"
266 "\n"
267 " Loops must be accessed via faces, this is only exposed for layer access.\n");
268static PyObject *bpy_bmloopseq_get(BPy_BMesh *self, void * /*closure*/)
269{
272}
273
274/* vert */
276 /* Wrap. */
277 bpy_bmvert_link_edges_doc,
278 "Edges connected to this vertex (read-only).\n"
279 "\n"
280 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMEdge`\n");
282 /* Wrap. */
283 bpy_bmvert_link_faces_doc,
284 "Faces connected to this vertex (read-only).\n"
285 "\n"
286 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMFace`\n");
288 /* Wrap. */
289 bpy_bmvert_link_loops_doc,
290 "Loops that use this vertex (read-only).\n"
291 "\n"
292 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMLoop`\n");
293/* edge */
295 /* Wrap. */
296 bpy_bmedge_verts_doc,
297 "Verts this edge uses (always 2), (read-only).\n"
298 "\n"
299 ":type: :class:`bmesh.types.BMElemSeq` of "
300 ":class:`bmesh.types.BMVert`\n");
302 /* Wrap. */
303 bpy_bmedge_link_faces_doc,
304 "Faces connected to this edge, (read-only).\n"
305 "\n"
306 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMFace`\n");
308 /* Wrap. */
309 bpy_bmedge_link_loops_doc,
310 "Loops connected to this edge, (read-only).\n"
311 "\n"
312 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMLoop`\n");
313/* face */
315 /* Wrap. */
316 bpy_bmface_verts_doc,
317 "Verts of this face, (read-only).\n"
318 "\n"
319 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMVert`\n");
321 /* Wrap. */
322 bpy_bmface_edges_doc,
323 "Edges of this face, (read-only).\n"
324 "\n"
325 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMEdge`\n");
327 /* Wrap. */
328 bpy_bmface_loops_doc,
329 "Loops of this face, (read-only).\n"
330 "\n"
331 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMLoop`\n");
332/* loop */
334 /* Wrap. */
335 bpy_bmloops_link_loops_doc,
336 "Loops connected to this loop, (read-only).\n"
337 "\n"
338 ":type: :class:`bmesh.types.BMElemSeq` of :class:`bmesh.types.BMLoop`\n");
339
345
347 /* Wrap. */
348 bpy_bm_is_valid_doc,
349 "True when this element is valid (hasn't been removed).\n"
350 "\n"
351 ":type: bool\n");
352static PyObject *bpy_bm_is_valid_get(BPy_BMGeneric *self, void * /*closure*/)
353{
354 return PyBool_FromLong(BPY_BM_IS_VALID(self));
355}
356
358 /* Wrap. */
359 bpy_bmesh_is_wrapped_doc,
360 "True when this mesh is owned by blender (typically the editmode BMesh).\n"
361 "\n"
362 ":type: bool\n");
363static PyObject *bpy_bmesh_is_wrapped_get(BPy_BMesh *self, void * /*closure*/)
364{
366
367 return PyBool_FromLong(self->flag & BPY_BMFLAG_IS_WRAPPED);
368}
369
371 /* Wrap. */
372 bpy_bmesh_select_mode_doc,
373 "The selection mode, cannot be assigned an empty set.\n"
374 "\n"
375 ":type: set[Literal[" BPY_BM_HTYPE_NOLOOP "]]\n");
376static PyObject *bpy_bmesh_select_mode_get(BPy_BMesh *self, void * /*closure*/)
377{
379
381}
382
383static int bpy_bmesh_select_mode_set(BPy_BMesh *self, PyObject *value, void * /*closure*/)
384{
385 int flag = 0;
387
388 if (PyC_FlagSet_ToBitfield(bpy_bm_scene_vert_edge_face_flags, value, &flag, "bm.select_mode") ==
389 -1)
390 {
391 return -1;
392 }
393 if (flag == 0) {
394 PyErr_SetString(PyExc_TypeError, "bm.select_mode: cannot assign an empty value");
395 return -1;
396 }
397
398 self->bm->selectmode = flag;
399 return 0;
400}
401
403 /* Wrap. */
404 bpy_bmesh_select_history_doc,
405 "Sequence of selected items (the last is displayed as active).\n"
406 "\n"
407 ":type: "
408 ":class:`bmesh.types.BMEditSelSeq`\n");
409static PyObject *bpy_bmesh_select_history_get(BPy_BMesh *self, void * /*closure*/)
410{
412
414}
415
416static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *value, void * /*closure*/)
417{
419
420 return BPy_BMEditSel_Assign(self, value);
421}
422
424 /* Wrap. */
425 bpy_bmesh_uv_select_sync_valid_doc,
426 "When true, the UV selection has been synchronized. "
427 "Setting to False means the UV selection will be ignored. "
428 "While setting to true is supported it is up to the script author to "
429 "ensure a correct selection state before doing so.\n"
430 ":type: "
431 "bool\n");
432static PyObject *bpy_bmesh_uv_select_sync_valid_get(BPy_BMesh *self, void * /*closure*/)
433{
435
436 return PyBool_FromLong(self->bm->uv_select_sync_valid);
437}
438
439static int bpy_bmesh_uv_select_sync_valid_set(BPy_BMesh *self, PyObject *value, void * /*closure*/)
440{
442
443 int param;
444 if ((param = PyC_Long_AsBool(value)) == -1) {
445 return -1;
446 }
447 self->bm->uv_select_sync_valid = param;
448 return 0;
449}
450
451/* Vert
452 * ^^^^ */
453
455 /* Wrap. */
456 bpy_bmvert_co_doc,
457 "The coordinates for this vertex as a 3D, wrapped vector.\n"
458 "\n"
459 ":type: "
460 ":class:`mathutils.Vector`\n");
461static PyObject *bpy_bmvert_co_get(BPy_BMVert *self, void * /*closure*/)
462{
464 return Vector_CreatePyObject_wrap(self->v->co, 3, nullptr);
465}
466
467static int bpy_bmvert_co_set(BPy_BMVert *self, PyObject *value, void * /*closure*/)
468{
470
471 if (mathutils_array_parse(self->v->co, 3, 3, value, "BMVert.co") != -1) {
472 return 0;
473 }
474
475 return -1;
476}
477
479 /* Wrap. */
480 bpy_bmvert_normal_doc,
481 "The normal for this vertex as a 3D, wrapped vector.\n"
482 "\n"
483 ":type: :class:`mathutils.Vector`\n");
484static PyObject *bpy_bmvert_normal_get(BPy_BMVert *self, void * /*closure*/)
485{
487 return Vector_CreatePyObject_wrap(self->v->no, 3, nullptr);
488}
489
490static int bpy_bmvert_normal_set(BPy_BMVert *self, PyObject *value, void * /*closure*/)
491{
493
494 if (mathutils_array_parse(self->v->no, 3, 3, value, "BMVert.normal") != -1) {
495 return 0;
496 }
497
498 return -1;
499}
500
502 /* Wrap. */
503 bpy_bmvert_is_manifold_doc,
504 "True when this vertex is manifold (read-only).\n"
505 "\n"
506 ":type: bool\n");
507static PyObject *bpy_bmvert_is_manifold_get(BPy_BMVert *self, void * /*closure*/)
508{
510 return PyBool_FromLong(BM_vert_is_manifold(self->v));
511}
512
514 /* Wrap. */
515 bpy_bmvert_is_wire_doc,
516 "True when this vertex is not connected to any faces (read-only).\n"
517 "\n"
518 ":type: bool\n");
519static PyObject *bpy_bmvert_is_wire_get(BPy_BMVert *self, void * /*closure*/)
520{
522 return PyBool_FromLong(BM_vert_is_wire(self->v));
523}
524
526 /* Wrap. */
527 bpy_bmvert_is_boundary_doc,
528 "True when this vertex is connected to boundary edges (read-only).\n"
529 "\n"
530 ":type: bool\n");
531static PyObject *bpy_bmvert_is_boundary_get(BPy_BMVert *self, void * /*closure*/)
532{
534 return PyBool_FromLong(BM_vert_is_boundary(self->v));
535}
536
537/* Edge
538 * ^^^^ */
539
541 /* Wrap. */
542 bpy_bmedge_is_manifold_doc,
543 "True when this edge is manifold (read-only).\n"
544 "\n"
545 ":type: bool\n");
546static PyObject *bpy_bmedge_is_manifold_get(BPy_BMEdge *self, void * /*closure*/)
547{
549 return PyBool_FromLong(BM_edge_is_manifold(self->e));
550}
551
553 /* Wrap. */
554 bpy_bmedge_is_contiguous_doc,
555 "True when this edge is manifold, between two faces with the same winding "
556 "(read-only).\n"
557 "\n"
558 ":type: bool\n");
559static PyObject *bpy_bmedge_is_contiguous_get(BPy_BMEdge *self, void * /*closure*/)
560{
562 return PyBool_FromLong(BM_edge_is_contiguous(self->e));
563}
564
566 /* Wrap. */
567 bpy_bmedge_is_convex_doc,
568 "True when this edge joins two convex faces, depends on a valid face normal (read-only).\n"
569 "\n"
570 ":type: bool\n");
571static PyObject *bpy_bmedge_is_convex_get(BPy_BMEdge *self, void * /*closure*/)
572{
574 return PyBool_FromLong(BM_edge_is_convex(self->e));
575}
576
578 /* Wrap. */
579 bpy_bmedge_is_wire_doc,
580 "True when this edge is not connected to any faces (read-only).\n"
581 "\n"
582 ":type: bool\n");
583static PyObject *bpy_bmedge_is_wire_get(BPy_BMEdge *self, void * /*closure*/)
584{
586 return PyBool_FromLong(BM_edge_is_wire(self->e));
587}
588
590 /* Wrap. */
591 bpy_bmedge_is_boundary_doc,
592 "True when this edge is at the boundary of a face (read-only).\n"
593 "\n"
594 ":type: bool\n");
595static PyObject *bpy_bmedge_is_boundary_get(BPy_BMEdge *self, void * /*closure*/)
596{
598 return PyBool_FromLong(BM_edge_is_boundary(self->e));
599}
600
601/* Face
602 * ^^^^ */
603
605 /* Warp. */
606 bpy_bmface_normal_doc,
607 "The normal for this face as a 3D, wrapped vector.\n"
608 "\n"
609 ":type: :class:`mathutils.Vector`\n");
610static PyObject *bpy_bmface_normal_get(BPy_BMFace *self, void * /*closure*/)
611{
613 return Vector_CreatePyObject_wrap(self->f->no, 3, nullptr);
614}
615
616static int bpy_bmface_normal_set(BPy_BMFace *self, PyObject *value, void * /*closure*/)
617{
619
620 if (mathutils_array_parse(self->f->no, 3, 3, value, "BMFace.normal") != -1) {
621 return 0;
622 }
623
624 return -1;
625}
626
628 /* Wrap. */
629 bpy_bmface_material_index_doc,
630 "The face's material index.\n"
631 "\n"
632 ":type: int\n");
633static PyObject *bpy_bmface_material_index_get(BPy_BMFace *self, void * /*closure*/)
634{
636 return PyLong_FromLong(self->f->mat_nr);
637}
638
639static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value, void * /*closure*/)
640{
641 int param;
642
644
645 if (((param = PyC_Long_AsI32(value)) == -1) && PyErr_Occurred()) {
646 /* error is set */
647 return -1;
648 }
649
650 if ((param < 0) || (param > MAXMAT)) {
651 /* normally we clamp but in this case raise an error */
652 PyErr_SetString(PyExc_ValueError, "material index outside of usable range (0 - 32766)");
653 return -1;
654 }
655
656 self->f->mat_nr = short(param);
657 return 0;
658}
659
660/* Loop
661 * ^^^^ */
662
664 /* Wrap. */
665 bpy_bmloop_vert_doc,
666 "The loop's vertex (read-only).\n"
667 "\n"
668 ":type: :class:`bmesh.types.BMVert`\n");
669static PyObject *bpy_bmloop_vert_get(BPy_BMLoop *self, void * /*closure*/)
670{
672 return BPy_BMVert_CreatePyObject(self->bm, self->l->v);
673}
674
676 /* Wrap. */
677 bpy_bmloop_edge_doc,
678 "The loop's edge (between this loop and the next), (read-only).\n"
679 "\n"
680 ":type: :class:`bmesh.types.BMEdge`\n");
681static PyObject *bpy_bmloop_edge_get(BPy_BMLoop *self, void * /*closure*/)
682{
684 return BPy_BMEdge_CreatePyObject(self->bm, self->l->e);
685}
686
688 /* Wrap. */
689 bpy_bmloop_face_doc,
690 "The face this loop makes (read-only).\n"
691 "\n"
692 ":type: :class:`bmesh.types.BMFace`\n");
693static PyObject *bpy_bmloop_face_get(BPy_BMLoop *self, void * /*closure*/)
694{
696 return BPy_BMFace_CreatePyObject(self->bm, self->l->f);
697}
698
700 /* Wrap. */
701 bpy_bmloop_link_loop_next_doc,
702 "The next face corner (read-only).\n"
703 "\n"
704 ":type: :class:`bmesh.types.BMLoop`\n");
705static PyObject *bpy_bmloop_link_loop_next_get(BPy_BMLoop *self, void * /*closure*/)
706{
708 return BPy_BMLoop_CreatePyObject(self->bm, self->l->next);
709}
710
712 /* Wrap. */
713 bpy_bmloop_link_loop_prev_doc,
714 "The previous face corner (read-only).\n"
715 "\n"
716 ":type: :class:`bmesh.types.BMLoop`\n");
717static PyObject *bpy_bmloop_link_loop_prev_get(BPy_BMLoop *self, void * /*closure*/)
718{
720 return BPy_BMLoop_CreatePyObject(self->bm, self->l->prev);
721}
722
724 /* Wrap. */
725 bpy_bmloop_link_loop_radial_next_doc,
726 "The next loop around the edge (read-only).\n"
727 "\n"
728 ":type: :class:`bmesh.types.BMLoop`\n");
729static PyObject *bpy_bmloop_link_loop_radial_next_get(BPy_BMLoop *self, void * /*closure*/)
730{
732 return BPy_BMLoop_CreatePyObject(self->bm, self->l->radial_next);
733}
734
736 /* Wrap. */
737 bpy_bmloop_link_loop_radial_prev_doc,
738 "The previous loop around the edge (read-only).\n"
739 "\n"
740 ":type: :class:`bmesh.types.BMLoop`\n");
741static PyObject *bpy_bmloop_link_loop_radial_prev_get(BPy_BMLoop *self, void * /*closure*/)
742{
744 return BPy_BMLoop_CreatePyObject(self->bm, self->l->radial_prev);
745}
746
748 /* Wrap. */
749 bpy_bmloop_is_convex_doc,
750 "True when this loop is at the convex corner of a face, depends on a valid face "
751 "normal (read-only).\n"
752 "\n"
753 ":type: bool\n");
754static PyObject *bpy_bmloop_is_convex_get(BPy_BMLoop *self, void * /*closure*/)
755{
757 return PyBool_FromLong(BM_loop_is_convex(self->l));
758}
759
760/* ElemSeq
761 * ^^^^^^^ */
762
763/* NOTE: use for bmvert/edge/face/loop seq's use these, not bmelemseq directly. */
765 /* Wrap. */
766 bpy_bmelemseq_layers_vert_doc,
767 "custom-data layers (read-only).\n"
768 "\n"
769 ":type: :class:`bmesh.types.BMLayerAccessVert`\n");
771 /* Wrap. */
772 bpy_bmelemseq_layers_edge_doc,
773 "custom-data layers (read-only).\n"
774 "\n"
775 ":type: :class:`bmesh.types.BMLayerAccessEdge`\n");
777 /* Wrap. */
778 bpy_bmelemseq_layers_face_doc,
779 "custom-data layers (read-only).\n"
780 "\n"
781 ":type: :class:`bmesh.types.BMLayerAccessFace`\n");
783 /* Wrap. */
784 bpy_bmelemseq_layers_loop_doc,
785 "custom-data layers (read-only).\n"
786 "\n"
787 ":type: :class:`bmesh.types.BMLayerAccessLoop`\n");
788static PyObject *bpy_bmelemseq_layers_get(BPy_BMElemSeq *self, void *htype)
789{
791
793}
794
795/* FaceSeq
796 * ^^^^^^^ */
797
799 /* Wrap. */
800 bpy_bmfaceseq_active_doc,
801 "active face.\n"
802 "\n"
803 ":type: :class:`bmesh.types.BMFace` | None\n");
804static PyObject *bpy_bmfaceseq_active_get(BPy_BMElemSeq *self, void * /*closure*/)
805{
806 BMesh *bm = self->bm;
808
809 if (bm->act_face) {
810 return BPy_BMElem_CreatePyObject(bm, (BMHeader *)bm->act_face);
811 }
812
813 Py_RETURN_NONE;
814}
815
816static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void * /*closure*/)
817{
818 const char *error_prefix = "faces.active = f";
819 BMesh *bm = self->bm;
820 if (value == Py_None) {
821 bm->act_face = nullptr;
822 return 0;
823 }
824 if (BPy_BMFace_Check(value)) {
825 BPY_BM_CHECK_SOURCE_INT(bm, error_prefix, value);
826
827 bm->act_face = ((BPy_BMFace *)value)->f;
828 return 0;
829 }
830
831 PyErr_Format(PyExc_TypeError,
832 "%s: expected BMFace or None, not %.200s",
833 error_prefix,
834 Py_TYPE(value)->tp_name);
835 return -1;
836}
837
838static PyGetSetDef bpy_bmesh_getseters[] = {
839 {"verts", (getter)bpy_bmvertseq_get, (setter) nullptr, bpy_bmvertseq_doc, nullptr},
840 {"edges", (getter)bpy_bmedgeseq_get, (setter) nullptr, bpy_bmedgeseq_doc, nullptr},
841 {"faces", (getter)bpy_bmfaceseq_get, (setter) nullptr, bpy_bmfaceseq_doc, nullptr},
842 {"loops", (getter)bpy_bmloopseq_get, (setter) nullptr, bpy_bmloopseq_doc, nullptr},
843 {"select_mode",
846 bpy_bmesh_select_mode_doc,
847 nullptr},
848
849 {"select_history",
852 bpy_bmesh_select_history_doc,
853 nullptr},
854
855 {"uv_select_sync_valid",
858 bpy_bmesh_uv_select_sync_valid_doc,
859 nullptr},
860
861 /* readonly checks */
862 {"is_wrapped",
864 (setter) nullptr,
865 bpy_bmesh_is_wrapped_doc,
866 nullptr}, /* as with mathutils */
867 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
868
869 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
870};
871
872static PyGetSetDef bpy_bmvert_getseters[] = {
873 /* generic */
874 {"select",
875 (getter)bpy_bm_elem_hflag_get,
876 (setter)bpy_bm_elem_hflag_set,
877 bpy_bm_elem_select_doc,
878 (void *)BM_ELEM_SELECT},
879 {"hide",
880 (getter)bpy_bm_elem_hflag_get,
881 (setter)bpy_bm_elem_hflag_set,
882 bpy_bm_elem_hide_doc,
883 (void *)BM_ELEM_HIDDEN},
884 {"tag",
885 (getter)bpy_bm_elem_hflag_get,
886 (setter)bpy_bm_elem_hflag_set,
887 bpy_bm_elem_tag_doc,
888 (void *)BM_ELEM_TAG},
889 {"index",
890 (getter)bpy_bm_elem_index_get,
891 (setter)bpy_bm_elem_index_set,
892 bpy_bm_elem_index_doc,
893 nullptr},
894
895 {"co", (getter)bpy_bmvert_co_get, (setter)bpy_bmvert_co_set, bpy_bmvert_co_doc, nullptr},
896 {"normal",
897 (getter)bpy_bmvert_normal_get,
898 (setter)bpy_bmvert_normal_set,
899 bpy_bmvert_normal_doc,
900 nullptr},
901
902 /* connectivity data */
903 {"link_edges",
905 (setter) nullptr,
906 bpy_bmvert_link_edges_doc,
907 (void *)BM_EDGES_OF_VERT},
908 {"link_faces",
910 (setter) nullptr,
911 bpy_bmvert_link_faces_doc,
912 (void *)BM_FACES_OF_VERT},
913 {"link_loops",
915 (setter) nullptr,
916 bpy_bmvert_link_loops_doc,
917 (void *)BM_LOOPS_OF_VERT},
918
919 /* readonly checks */
920 {"is_manifold",
922 (setter) nullptr,
923 bpy_bmvert_is_manifold_doc,
924 nullptr},
925 {"is_wire", (getter)bpy_bmvert_is_wire_get, (setter) nullptr, bpy_bmvert_is_wire_doc, nullptr},
926 {"is_boundary",
928 (setter) nullptr,
929 bpy_bmvert_is_boundary_doc,
930 nullptr},
931 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
932
933 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
934};
935
936static PyGetSetDef bpy_bmedge_getseters[] = {
937 /* generic */
938 {"select",
939 (getter)bpy_bm_elem_hflag_get,
940 (setter)bpy_bm_elem_hflag_set,
941 bpy_bm_elem_select_doc,
942 (void *)BM_ELEM_SELECT},
943 {"hide",
944 (getter)bpy_bm_elem_hflag_get,
945 (setter)bpy_bm_elem_hflag_set,
946 bpy_bm_elem_hide_doc,
947 (void *)BM_ELEM_HIDDEN},
948 {"tag",
949 (getter)bpy_bm_elem_hflag_get,
950 (setter)bpy_bm_elem_hflag_set,
951 bpy_bm_elem_tag_doc,
952 (void *)BM_ELEM_TAG},
953 {"index",
954 (getter)bpy_bm_elem_index_get,
955 (setter)bpy_bm_elem_index_set,
956 bpy_bm_elem_index_doc,
957 nullptr},
958
959 {"smooth",
960 (getter)bpy_bm_elem_hflag_get,
961 (setter)bpy_bm_elem_hflag_set,
962 bpy_bm_elem_smooth_doc,
963 (void *)BM_ELEM_SMOOTH},
964 {"seam",
965 (getter)bpy_bm_elem_hflag_get,
966 (setter)bpy_bm_elem_hflag_set,
967 bpy_bm_elem_seam_doc,
968 (void *)BM_ELEM_SEAM},
969
970 /* connectivity data */
971 {"verts",
973 (setter) nullptr,
974 bpy_bmedge_verts_doc,
975 (void *)BM_VERTS_OF_EDGE},
976
977 {"link_faces",
979 (setter) nullptr,
980 bpy_bmedge_link_faces_doc,
981 (void *)BM_FACES_OF_EDGE},
982 {"link_loops",
984 (setter) nullptr,
985 bpy_bmedge_link_loops_doc,
986 (void *)BM_LOOPS_OF_EDGE},
987
988 /* readonly checks */
989 {"is_manifold",
991 (setter) nullptr,
992 bpy_bmedge_is_manifold_doc,
993 nullptr},
994 {"is_contiguous",
996 (setter) nullptr,
997 bpy_bmedge_is_contiguous_doc,
998 nullptr},
999 {"is_convex",
1001 (setter) nullptr,
1002 bpy_bmedge_is_convex_doc,
1003 nullptr},
1004 {"is_wire", (getter)bpy_bmedge_is_wire_get, (setter) nullptr, bpy_bmedge_is_wire_doc, nullptr},
1005 {"is_boundary",
1007 (setter) nullptr,
1008 bpy_bmedge_is_boundary_doc,
1009 nullptr},
1010 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
1011
1012 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1013};
1014
1015static PyGetSetDef bpy_bmface_getseters[] = {
1016 /* generic */
1017 {"select",
1018 (getter)bpy_bm_elem_hflag_get,
1019 (setter)bpy_bm_elem_hflag_set,
1020 bpy_bm_elem_select_doc,
1021 (void *)BM_ELEM_SELECT},
1022 {"hide",
1023 (getter)bpy_bm_elem_hflag_get,
1024 (setter)bpy_bm_elem_hflag_set,
1025 bpy_bm_elem_hide_doc,
1026 (void *)BM_ELEM_HIDDEN},
1027 {"tag",
1028 (getter)bpy_bm_elem_hflag_get,
1029 (setter)bpy_bm_elem_hflag_set,
1030 bpy_bm_elem_tag_doc,
1031 (void *)BM_ELEM_TAG},
1032 {"uv_select",
1033 (getter)bpy_bm_elem_hflag_get,
1034 (setter)bpy_bm_elem_hflag_set,
1035 bpy_bm_elem_uv_select_doc,
1036 (void *)BM_ELEM_SELECT_UV},
1037 {"index",
1038 (getter)bpy_bm_elem_index_get,
1039 (setter)bpy_bm_elem_index_set,
1040 bpy_bm_elem_index_doc,
1041 nullptr},
1042
1043 {"smooth",
1044 (getter)bpy_bm_elem_hflag_get,
1045 (setter)bpy_bm_elem_hflag_set,
1046 bpy_bm_elem_smooth_doc,
1047 (void *)BM_ELEM_SMOOTH},
1048
1049 {"normal",
1050 (getter)bpy_bmface_normal_get,
1051 (setter)bpy_bmface_normal_set,
1052 bpy_bmface_normal_doc,
1053 nullptr},
1054
1055 {"material_index",
1058 bpy_bmface_material_index_doc,
1059 nullptr},
1060
1061 /* connectivity data */
1062 {"verts",
1063 (getter)bpy_bmelemseq_elem_get,
1064 (setter) nullptr,
1065 bpy_bmface_verts_doc,
1066 (void *)BM_VERTS_OF_FACE},
1067 {"edges",
1068 (getter)bpy_bmelemseq_elem_get,
1069 (setter) nullptr,
1070 bpy_bmface_edges_doc,
1071 (void *)BM_EDGES_OF_FACE},
1072 {"loops",
1073 (getter)bpy_bmelemseq_elem_get,
1074 (setter) nullptr,
1075 bpy_bmface_loops_doc,
1076 (void *)BM_LOOPS_OF_FACE},
1077
1078 /* readonly checks */
1079 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
1080
1081 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1082};
1083
1084static PyGetSetDef bpy_bmloop_getseters[] = {
1085/* generic */
1086/* flags are available but not used for loops. */
1087#if 0
1088 {"select",
1089 (getter)bpy_bm_elem_hflag_get,
1090 (setter)bpy_bm_elem_hflag_set,
1091 bpy_bm_elem_select_doc,
1092 (void *)BM_ELEM_SELECT},
1093 {"hide",
1094 (getter)bpy_bm_elem_hflag_get,
1095 (setter)bpy_bm_elem_hflag_set,
1096 bpy_bm_elem_hide_doc,
1097 (void *)BM_ELEM_HIDDEN},
1098#endif
1099 {"tag",
1100 (getter)bpy_bm_elem_hflag_get,
1101 (setter)bpy_bm_elem_hflag_set,
1102 bpy_bm_elem_tag_doc,
1103 (void *)BM_ELEM_TAG},
1104 {"uv_select_vert",
1105 (getter)bpy_bm_elem_hflag_get,
1106 (setter)bpy_bm_elem_hflag_set,
1107 bpy_bm_elem_uv_select_doc,
1108 (void *)BM_ELEM_SELECT_UV},
1109 {"uv_select_edge",
1110 (getter)bpy_bm_elem_hflag_get,
1111 (setter)bpy_bm_elem_hflag_set,
1112 bpy_bm_elem_uv_select_doc,
1113 (void *)BM_ELEM_SELECT_UV_EDGE},
1114 {"index",
1115 (getter)bpy_bm_elem_index_get,
1116 (setter)bpy_bm_elem_index_set,
1117 bpy_bm_elem_index_doc,
1118 nullptr},
1119
1120 {"vert", (getter)bpy_bmloop_vert_get, (setter) nullptr, bpy_bmloop_vert_doc, nullptr},
1121 {"edge", (getter)bpy_bmloop_edge_get, (setter) nullptr, bpy_bmloop_edge_doc, nullptr},
1122 {"face", (getter)bpy_bmloop_face_get, (setter) nullptr, bpy_bmloop_face_doc, nullptr},
1123
1124 /* connectivity data */
1125 {"link_loops",
1126 (getter)bpy_bmelemseq_elem_get,
1127 (setter) nullptr,
1128 bpy_bmloops_link_loops_doc,
1129 (void *)BM_LOOPS_OF_LOOP},
1130 {"link_loop_next",
1132 (setter) nullptr,
1133 bpy_bmloop_link_loop_next_doc,
1134 nullptr},
1135 {"link_loop_prev",
1137 (setter) nullptr,
1138 bpy_bmloop_link_loop_prev_doc,
1139 nullptr},
1140 {"link_loop_radial_next",
1142 (setter) nullptr,
1143 bpy_bmloop_link_loop_radial_next_doc,
1144 nullptr},
1145 {"link_loop_radial_prev",
1147 (setter) nullptr,
1148 bpy_bmloop_link_loop_radial_prev_doc,
1149 nullptr},
1150
1151 /* readonly checks */
1152 {"is_convex",
1154 (setter) nullptr,
1155 bpy_bmloop_is_convex_doc,
1156 nullptr},
1157 {"is_valid", (getter)bpy_bm_is_valid_get, (setter) nullptr, bpy_bm_is_valid_doc, nullptr},
1158
1159 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1160};
1161
1162static PyGetSetDef bpy_bmvertseq_getseters[] = {
1163 {"layers",
1165 (setter) nullptr,
1166 bpy_bmelemseq_layers_vert_doc,
1167 (void *)BM_VERT},
1168 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1169};
1170static PyGetSetDef bpy_bmedgeseq_getseters[] = {
1171 {"layers",
1173 (setter) nullptr,
1174 bpy_bmelemseq_layers_edge_doc,
1175 (void *)BM_EDGE},
1176 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1177};
1178static PyGetSetDef bpy_bmfaceseq_getseters[] = {
1179 {"layers",
1181 (setter) nullptr,
1182 bpy_bmelemseq_layers_face_doc,
1183 (void *)BM_FACE},
1184 /* face only */
1185 {"active",
1188 bpy_bmfaceseq_active_doc,
1189 nullptr},
1190 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1191};
1192static PyGetSetDef bpy_bmloopseq_getseters[] = {
1193 {"layers",
1195 (setter) nullptr,
1196 bpy_bmelemseq_layers_loop_doc,
1197 (void *)BM_LOOP},
1198 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
1199};
1200
1201/* Methods
1202 * ======= */
1203
1204/* Mesh
1205 * ---- */
1206
1208 /* Wrap. */
1209 bpy_bmesh_copy_doc,
1210 ".. method:: copy()\n"
1211 "\n"
1212 " :return: A copy of this BMesh.\n"
1213 " :rtype: :class:`bmesh.types.BMesh`\n");
1215{
1217
1218 BMesh *bm = self->bm;
1219 BMesh *bm_copy = BM_mesh_copy(bm);
1220
1221 if (bm_copy) {
1223 }
1224
1225 PyErr_SetString(PyExc_SystemError, "Unable to copy BMesh, internal error");
1226 return nullptr;
1227}
1228
1230 /* Wrap. */
1231 bpy_bmesh_clear_doc,
1232 ".. method:: clear()\n"
1233 "\n"
1234 " Clear all mesh data.\n");
1236{
1238
1239 BMesh *bm = self->bm;
1240
1242
1243 Py_RETURN_NONE;
1244}
1245
1247 /* Wrap. */
1248 bpy_bmesh_free_doc,
1249 ".. method:: free()\n"
1250 "\n"
1251 " Explicitly free the BMesh data from memory, causing exceptions on further access.\n"
1252 "\n"
1253 " .. note::\n"
1254 "\n"
1255 " The BMesh is freed automatically, typically when the script finishes executing.\n"
1256 " However in some cases its hard to predict when this will be and its useful to\n"
1257 " explicitly free the data.\n");
1259{
1260 if (self->bm) {
1261 BMesh *bm = self->bm;
1262
1264
1265 if (self->flag & BPY_BMFLAG_IS_WRAPPED) {
1266 /* Ensure further access doesn't return this invalid object, see: #105715. */
1267 bm->py_handle = nullptr;
1268 }
1269 else {
1271 }
1272
1274 }
1275
1276 Py_RETURN_NONE;
1277}
1278
1280 /* Wrap. */
1281 bpy_bmesh_to_mesh_doc,
1282 ".. method:: to_mesh(mesh)\n"
1283 "\n"
1284 " Writes this BMesh data into an existing Mesh data-block.\n"
1285 "\n"
1286 " :arg mesh: The mesh data to write into.\n"
1287 " :type mesh: :class:`bpy.types.Mesh`\n");
1288static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
1289{
1290 PyObject *py_mesh;
1291 Mesh *mesh;
1292
1294
1295 if (!PyArg_ParseTuple(args, "O:to_mesh", &py_mesh) ||
1296 !(mesh = static_cast<Mesh *>(PyC_RNA_AsPointer(py_mesh, "Mesh"))))
1297 {
1298 return nullptr;
1299 }
1300
1301 /* we could allow this but its almost certainly _not_ what script authors want */
1302 if (mesh->runtime->edit_mesh) {
1303 PyErr_Format(PyExc_ValueError, "to_mesh(): Mesh '%s' is in editmode", mesh->id.name + 2);
1304 return nullptr;
1305 }
1306
1307 BMesh *bm = self->bm;
1308
1309 Main *bmain = nullptr;
1311 params.update_shapekey_indices = true;
1312 if (mesh->id.tag & ID_TAG_NO_MAIN) {
1313 /* Mesh might be coming from a self-contained source like object.to_mesh(). No need to remap
1314 * anything in this case. */
1315 }
1316 else {
1318 bmain = G_MAIN; /* XXX UGLY! */
1319 params.calc_object_remap = true;
1320 }
1321
1322 BM_mesh_bm_to_me(bmain, bm, mesh, &params);
1323
1324 /* We could have the user do this but if they forget blender can easy crash
1325 * since the references arrays for the objects evaluated meshes are now invalid. */
1327
1328 Py_RETURN_NONE;
1329}
1330
1332 /* Wrap. */
1333 bpy_bmesh_from_object_doc,
1334 ".. method:: from_object(object, depsgraph, *, "
1335 "cage=False, face_normals=True, vertex_normals=True)\n"
1336 "\n"
1337 " Initialize this bmesh from existing object data-block (only meshes are currently "
1338 "supported).\n"
1339 "\n"
1340 " :arg object: The object data to load.\n"
1341 " :type object: :class:`bpy.types.Object`\n"
1342 " :type depsgraph: :class:`bpy.types.Depsgraph`\n"
1343 " :arg cage: Get the mesh as a deformed cage.\n"
1344 " :type cage: bool\n"
1345 " :arg face_normals: Calculate face normals.\n"
1346 " :type face_normals: bool\n"
1347 " :arg vertex_normals: Calculate vertex normals.\n"
1348 " :type vertex_normals: bool\n");
1349static PyObject *bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
1350{
1351 static const char *kwlist[] = {
1352 "object", "depsgraph", "cage", "face_normals", "vertex_normals", nullptr};
1353 PyObject *py_object;
1354 PyObject *py_depsgraph;
1355 Object *ob, *ob_eval;
1356 Depsgraph *depsgraph;
1357 Scene *scene_eval;
1358 const Mesh *mesh_eval;
1359 bool use_cage = false;
1360 bool use_fnorm = true;
1361 bool use_vert_normal = true;
1362 const CustomData_MeshMasks data_masks = CD_MASK_BMESH;
1363
1365
1366 if (!PyArg_ParseTupleAndKeywords(args,
1367 kw,
1368 "OO|$O&O&O&:from_object",
1369 (char **)kwlist,
1370 &py_object,
1371 &py_depsgraph,
1373 &use_cage,
1375 &use_fnorm,
1377 &use_vert_normal) ||
1378 !(ob = static_cast<Object *>(PyC_RNA_AsPointer(py_object, "Object"))) ||
1379 !(depsgraph = static_cast<Depsgraph *>(PyC_RNA_AsPointer(py_depsgraph, "Depsgraph"))))
1380 {
1381 return nullptr;
1382 }
1383
1384 if (ob->type != OB_MESH) {
1385 PyErr_SetString(PyExc_ValueError,
1386 "from_object(...): currently only mesh objects are supported");
1387 return nullptr;
1388 }
1389
1390 const bool use_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER;
1391 scene_eval = DEG_get_evaluated_scene(depsgraph);
1392 ob_eval = DEG_get_evaluated(depsgraph, ob);
1393 bool need_free = false;
1394
1395 /* Write the display mesh into the dummy mesh */
1396 if (use_render) {
1397 if (use_cage) {
1398 PyErr_SetString(PyExc_ValueError,
1399 "from_object(...): cage arg is unsupported when dependency graph "
1400 "evaluation mode is RENDER");
1401 return nullptr;
1402 }
1403
1404 mesh_eval = BKE_mesh_new_from_object(depsgraph, ob_eval, true, false, true);
1405 need_free = true;
1406 }
1407 else {
1408 if (use_cage) {
1409 mesh_eval = blender::bke::mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &data_masks);
1410 }
1411 else {
1412 mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
1413 }
1414 }
1415
1416 if (mesh_eval == nullptr) {
1417 PyErr_Format(PyExc_ValueError,
1418 "from_object(...): Object '%s' has no usable mesh data",
1419 ob->id.name + 2);
1420 return nullptr;
1421 }
1422
1423 BMesh *bm = self->bm;
1424
1426 params.calc_face_normal = use_fnorm;
1427 params.calc_vert_normal = use_vert_normal;
1428 BM_mesh_bm_from_me(bm, mesh_eval, &params);
1429
1430 if (need_free) {
1431 BKE_id_free(nullptr, (Mesh *)mesh_eval);
1432 }
1433
1434 Py_RETURN_NONE;
1435}
1436
1438 /* Wrap. */
1439 bpy_bmesh_from_mesh_doc,
1440 ".. method:: from_mesh(mesh, *, "
1441 "face_normals=True, vertex_normals=True, use_shape_key=False, shape_key_index=0)\n"
1442 "\n"
1443 " Initialize this bmesh from existing mesh data-block.\n"
1444 "\n"
1445 " :arg mesh: The mesh data to load.\n"
1446 " :type mesh: :class:`bpy.types.Mesh`\n"
1447 " :type face_normals: bool\n"
1448 " :type vertex_normals: bool\n"
1449 " :arg use_shape_key: Use the locations from a shape key.\n"
1450 " :type use_shape_key: bool\n"
1451 " :arg shape_key_index: The shape key index to use.\n"
1452 " :type shape_key_index: int\n"
1453 "\n"
1454 " .. note::\n"
1455 "\n"
1456 " Multiple calls can be used to join multiple meshes.\n"
1457 "\n"
1458 " Custom-data layers are only copied from ``mesh`` on initialization.\n"
1459 " Further calls will copy custom-data to matching layers, layers missing on the target "
1460 "mesh won't be added.\n");
1461static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
1462{
1463 static const char *kwlist[] = {
1464 "mesh", "face_normals", "vertex_normals", "use_shape_key", "shape_key_index", nullptr};
1465 PyObject *py_mesh;
1466 Mesh *mesh;
1467 bool use_fnorm = true;
1468 bool use_vert_normal = true;
1469 bool use_shape_key = false;
1470 int shape_key_index = 0;
1471
1473
1474 if (!PyArg_ParseTupleAndKeywords(args,
1475 kw,
1476 "O|$O&O&O&i:from_mesh",
1477 (char **)kwlist,
1478 &py_mesh,
1480 &use_fnorm,
1482 &use_vert_normal,
1484 &use_shape_key,
1485 &shape_key_index) ||
1486 !(mesh = static_cast<Mesh *>(PyC_RNA_AsPointer(py_mesh, "Mesh"))))
1487 {
1488 return nullptr;
1489 }
1490
1491 BMesh *bm = self->bm;
1492
1494 params.calc_face_normal = use_fnorm;
1495 params.calc_vert_normal = use_vert_normal;
1496 params.use_shapekey = use_shape_key;
1497 params.active_shapekey = shape_key_index + 1;
1498 BM_mesh_bm_from_me(bm, mesh, &params);
1499
1500 Py_RETURN_NONE;
1501}
1502
1504 /* Wrap. */
1505 bpy_bmesh_select_flush_mode_doc,
1506 ".. method:: select_flush_mode(*, flush_down=False)\n"
1507 "\n"
1508 " Flush selection based on the current mode current "
1509 ":class:`bmesh.types.BMesh.select_mode`.\n"
1510 "\n"
1511 " :arg flush_down: Flush selection down from faces to edges & verts or from edges to verts. "
1512 "This option is ignored when vertex selection mode is enabled.\n"
1513 " :type flush_down: bool\n");
1514static PyObject *bpy_bmesh_select_flush_mode(BPy_BMesh *self, PyObject *args, PyObject *kw)
1515{
1517
1518 bool flush_down = false;
1520
1521 static const char *kwlist[] = {
1522 "flush_down",
1523 nullptr,
1524 };
1525 if (!PyArg_ParseTupleAndKeywords(args,
1526 kw,
1527 "|$"
1528 "O&" /* `flush_down` */
1529 ":select_flush_mode",
1530 (char **)kwlist,
1532 &flush_down))
1533 {
1534 return nullptr;
1535 }
1536
1537 if (flush_down) {
1539 }
1540
1541 BM_mesh_select_mode_flush_ex(self->bm, self->bm->selectmode, flag);
1542
1543 Py_RETURN_NONE;
1544}
1545
1547 /* Wrap. */
1548 bpy_bmesh_select_flush_doc,
1549 ".. method:: select_flush(select)\n"
1550 "\n"
1551 " Flush selection from vertices, independent of the current selection mode.\n"
1552 "\n"
1553 " :arg select: flush selection or de-selected elements.\n"
1554 " :type select: bool\n");
1555static PyObject *bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
1556{
1557 int param;
1558
1560
1561 if ((param = PyC_Long_AsBool(value)) == -1) {
1562 return nullptr;
1563 }
1565 Py_RETURN_NONE;
1566}
1567
1568/* ---------------------------------------------------------------------- */
1571
1573 /* Wrap. */
1574 bpy_bmesh_uv_select_flush_mode_doc,
1575 ".. method:: uv_select_flush_mode(*, flush_down=False)\n"
1576 "\n"
1577 " Flush selection based on the current mode current :class:`BMesh.select_mode`.\n"
1578 "\n"
1579 " :arg flush_down: Flush selection down from faces to edges & verts or from edges to verts. "
1580 "This option is ignored when vertex selection mode is enabled.\n"
1581 " :type flush_down: bool\n");
1582static PyObject *bpy_bmesh_uv_select_flush_mode(BPy_BMesh *self, PyObject *args, PyObject *kw)
1583{
1585 BMesh *bm = self->bm;
1586
1587 bool flush_down = false;
1588 static const char *kwlist[] = {
1589 "flush_down",
1590 nullptr,
1591 };
1592 if (!PyArg_ParseTupleAndKeywords(args,
1593 kw,
1594 "|$"
1595 "O&" /* `flush_down` */
1596 ":uv_select_flush_mode",
1597 (char **)kwlist,
1599 &flush_down))
1600 {
1601 return nullptr;
1602 }
1603
1604 BM_mesh_uvselect_mode_flush_ex(bm, bm->selectmode, flush_down);
1605 Py_RETURN_NONE;
1606}
1607
1609 /* Wrap. */
1610 bpy_bmesh_uv_select_flush_doc,
1611 ".. method:: uv_select_flush(select)\n"
1612 "\n"
1613 " Flush selection from UV vertices to edges & faces independent of the selection mode.\n"
1614 "\n"
1615 " :arg select: Flush selection or de-selected elements.\n"
1616 " :type select: bool\n"
1617 "\n"
1618 " .. note::\n"
1619 "\n"
1620 " - |UV_SELECT_SYNC_TO_MESH_NEEDED|\n");
1621static PyObject *bpy_bmesh_uv_select_flush(BPy_BMesh *self, PyObject *value)
1622{
1623 const char *error_prefix = "uv_select_flush(...)";
1624 int param;
1625
1627
1628 if ((param = PyC_Long_AsBool(value)) == -1) {
1629 return nullptr;
1630 }
1631 BMesh *bm = self->bm;
1632 /* While sync doesn't need to be valid,
1633 * failing to make it valid causes selection functions to assert, so require it to be valid. */
1634 if (bpy_bm_check_uv_select_sync_valid(bm, error_prefix) == -1) {
1635 return nullptr;
1636 }
1638 Py_RETURN_NONE;
1639}
1640
1642 /* Wrap. */
1643 bpy_bmesh_uv_select_flush_shared_doc,
1644 ".. method:: uv_select_flush_shared(select)\n"
1645 "\n"
1646 " Flush selection from UV vertices to contiguous UV's independent of the selection mode.\n"
1647 "\n"
1648 " :arg select: Flush selection or de-selected elements.\n"
1649 " :type select: bool\n"
1650 "\n"
1651 " .. note::\n"
1652 "\n"
1653 " - |UV_SELECT_SYNC_TO_MESH_NEEDED|\n");
1654static PyObject *bpy_bmesh_uv_select_flush_shared(BPy_BMesh *self, PyObject *value)
1655{
1656 const char *error_prefix = "uv_select_flush_shared(...)";
1657 int param;
1658
1660
1661 if ((param = PyC_Long_AsBool(value)) == -1) {
1662 return nullptr;
1663 }
1664 BMesh *bm = self->bm;
1665 /* While sync doesn't need to be valid,
1666 * failing to make it valid causes selection functions to assert, so require it to be valid. */
1667 if (bpy_bm_check_uv_select_sync_valid(bm, error_prefix) == -1) {
1668 return nullptr;
1669 }
1670 if (param) {
1672 }
1673 else {
1675 }
1676 Py_RETURN_NONE;
1677}
1678
1680 /* Wrap. */
1681 bpy_bmesh_uv_select_sync_from_mesh_doc,
1682 ".. method:: uv_select_sync_from_mesh(*, "
1683 "sticky_select_mode='SHARED_LOCATION')\n"
1684 "\n"
1685 " Sync selection from mesh to UVs.\n"
1686 "\n"
1687 " :arg sticky_select_mode: Behavior when flushing from the mesh to UV selection "
1688 "|UV_STICKY_SELECT_MODE_REF|. "
1689 "This should only be used when preparing to create a UV selection.\n"
1690 " :type sticky_select_mode: |UV_STICKY_SELECT_MODE_TYPE|\n"
1691 "\n"
1692 " .. note::\n"
1693 "\n"
1694 " - |UV_SELECT_SYNC_TO_MESH_NEEDED|\n");
1695static PyObject *bpy_bmesh_uv_select_sync_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
1696{
1697 static const char *kwlist[] = {
1698 "sticky_select_mode",
1699 nullptr,
1700 };
1701
1703
1705
1706 if (!PyArg_ParseTupleAndKeywords(args,
1707 kw,
1708 "|$" /* Optional keyword only arguments. */
1709 "O&" /* `sticky_select_mode` */
1710 ":uv_select_sync_from_mesh",
1711 (char **)kwlist,
1713 &uv_sticky_select_mode))
1714 {
1715 return nullptr;
1716 }
1717
1718 BMesh *bm = self->bm;
1719 switch (uv_sticky_select_mode.value_found) {
1720 case UV_STICKY_LOCATION: {
1721 const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_PROP_FLOAT2);
1722 if (cd_loop_uv_offset == -1) {
1723 PyErr_SetString(PyExc_ValueError, "sticky_select_mode='SHARED_LOCATION' requires UV's");
1724 return nullptr;
1725 }
1727 break;
1728 }
1729 case UV_STICKY_DISABLE: {
1731 break;
1732 }
1733 case UV_STICKY_VERT: {
1735 break;
1736 }
1737 }
1738
1739 Py_RETURN_NONE;
1740}
1741
1743 /* Wrap. */
1744 bpy_bmesh_uv_select_sync_to_mesh_doc,
1745 ".. method:: uv_select_sync_to_mesh()\n"
1746 "\n"
1747 " Sync selection from UVs to the mesh.\n");
1749{
1750 const char *error_prefix = "uv_select_sync_to_mesh(...)";
1751
1753
1754 BMesh *bm = self->bm;
1755 if (bpy_bm_check_uv_select_sync_valid(bm, error_prefix) == -1) {
1756 return nullptr;
1757 }
1759 Py_RETURN_NONE;
1760}
1761
1763 /* Wrap. */
1764 bpy_bmesh_uv_select_foreach_set_doc,
1765 ".. method:: uv_select_foreach_set(select, /, *, "
1766 "loop_verts=(), loop_edges=(), faces=(), sticky_select_mode='SHARED_LOCATION')\n"
1767 "\n"
1768 " Set the UV selection state for loop-vertices, loop-edges & faces.\n"
1769 "\n"
1770 " This is a close equivalent to selecting in the UV editor.\n"
1771 "\n"
1772 " :arg select: The selection state to set.\n"
1773 " :type select: bool\n"
1774 " :arg loop_verts: Loop verts to operate on.\n"
1775 " :type loop_verts: Iterable[:class:`bmesh.types.BMLoop`]\n"
1776 " :arg loop_edges: Loop edges to operate on.\n"
1777 " :type loop_edges: Iterable[:class:`bmesh.types.BMLoop`]\n"
1778 " :arg faces: Faces to operate on.\n"
1779 " :type faces: Iterable[:class:`bmesh.types.BMFace`]\n"
1780 " :arg sticky_select_mode: See |UV_STICKY_SELECT_MODE_REF|.\n"
1781 " :type sticky_select_mode: |UV_STICKY_SELECT_MODE_TYPE|\n"
1782 "\n"
1783 " .. note::\n"
1784 "\n"
1785 " - |UV_SELECT_FLUSH_MODE_NEEDED|\n"
1786 " - |UV_SELECT_SYNC_TO_MESH_NEEDED|\n");
1787static PyObject *bpy_bmesh_uv_select_foreach_set(BPy_BMesh *self, PyObject *args, PyObject *kw)
1788{
1789 const char *error_prefix = "uv_select_foreach_set(...)";
1790 static const char *kwlist[] = {
1791 "", /* `select` */
1792 "loop_verts",
1793 "loop_edges",
1794 "faces",
1795 "sticky_select_mode",
1796 nullptr,
1797 };
1798 BMesh *bm;
1799 bool use_select = false;
1800 PyObject *py_loop_verts = nullptr;
1801 PyObject *py_loop_edges = nullptr;
1802 PyObject *py_faces = nullptr;
1804
1806
1807 if (!PyArg_ParseTupleAndKeywords(args,
1808 kw,
1809 "O&" /* `select` */
1810 "|$" /* Optional keyword only arguments. */
1811 "O" /* `loop_verts` */
1812 "O" /* `loop_edges` */
1813 "O" /* `faces` */
1814 "O&" /* `sticky_select_mode` */
1815 ":uv_select_foreach_set",
1816 (char **)kwlist,
1818 &use_select,
1819 &py_loop_verts,
1820 &py_loop_edges,
1821 &py_faces,
1823 &uv_sticky_select_mode))
1824 {
1825 return nullptr;
1826 }
1827
1828 bm = self->bm;
1829 if (bpy_bm_check_uv_select_sync_valid(bm, error_prefix) == -1) {
1830 return nullptr;
1831 }
1832 const bool shared = uv_sticky_select_mode.value_found == UV_STICKY_LOCATION;
1833 const int cd_loop_uv_offset = shared ? bpy_bm_uv_layer_offset_or_error(bm, error_prefix) : -1;
1834 if (shared && (cd_loop_uv_offset == -1)) {
1835 return nullptr;
1836 }
1837
1838 Py_ssize_t loop_vert_array_num = 0;
1839 Py_ssize_t loop_edge_array_num = 0;
1840 Py_ssize_t face_array_num = 0;
1841 BMLoop **loop_vert_array = nullptr;
1842 BMLoop **loop_edge_array = nullptr;
1843 BMFace **face_array = nullptr;
1844
1845 bool ok = true;
1846 if (ok && py_loop_verts) {
1847 BMesh *bm_test = nullptr;
1848 if (!(loop_vert_array = BPy_BMLoop_PySeq_As_Array(&bm_test,
1849 py_loop_verts,
1850 0,
1851 PY_SSIZE_T_MAX,
1852 &loop_vert_array_num,
1853 true,
1854 true,
1855 error_prefix)))
1856 {
1857 ok = false;
1858 }
1859 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
1860 ok = false;
1861 }
1862 }
1863 if (ok && py_loop_edges) {
1864 BMesh *bm_test = nullptr;
1865 if (!(loop_edge_array = BPy_BMLoop_PySeq_As_Array(&bm_test,
1866 py_loop_edges,
1867 0,
1868 PY_SSIZE_T_MAX,
1869 &loop_edge_array_num,
1870 true,
1871 true,
1872 error_prefix)))
1873 {
1874 ok = false;
1875 }
1876 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
1877 ok = false;
1878 }
1879 }
1880 if (ok && py_faces) {
1881 BMesh *bm_test = nullptr;
1882 if (!(face_array = BPy_BMFace_PySeq_As_Array(
1883 &bm_test, py_faces, 0, PY_SSIZE_T_MAX, &face_array_num, true, true, error_prefix)))
1884 {
1885 ok = false;
1886 }
1887 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
1888 ok = false;
1889 }
1890 }
1891
1892 /* TODO: support different "sticky" modes. */
1893 if (ok) {
1895 use_select,
1896 cd_loop_uv_offset,
1897 blender::Span(loop_vert_array, loop_vert_array_num),
1898 blender::Span(loop_edge_array, loop_edge_array_num),
1899 blender::Span(face_array, face_array_num));
1900 }
1901
1902 PyMem_FREE(loop_vert_array);
1903 PyMem_FREE(loop_edge_array);
1904 PyMem_FREE(face_array);
1905
1906 if (ok == false) {
1907 /* The error has been raised. */
1908 return nullptr;
1909 }
1910 Py_RETURN_NONE;
1911}
1912
1914 /* Wrap. */
1915 bpy_bmesh_uv_select_foreach_set_from_mesh_doc,
1916 ".. method:: uv_select_foreach_set_from_mesh(select, /, *, "
1917 "verts=(), edges=(), faces=(), sticky_select_mode='SHARED_LOCATION')\n"
1918 "\n"
1919 " Select or de-select mesh elements, updating the UV selection.\n"
1920 "\n"
1921 " An equivalent to selecting from the 3D viewport "
1922 "for selection operations that support maintaining a synchronized UV selection.\n"
1923 "\n"
1924 " :arg select: The selection state to set.\n"
1925 " :type select: bool\n"
1926 " :arg verts: Verts to operate on.\n"
1927 " :type verts: Iterable[:class:`bmesh.types.BMVert`]\n"
1928 " :arg edges: Edges to operate on.\n"
1929 " :type edges: Iterable[:class:`bmesh.types.BMEdge`]\n"
1930 " :arg faces: Faces to operate on.\n"
1931 " :type faces: Iterable[:class:`bmesh.types.BMFace`]\n"
1932 " :arg sticky_select_mode: See |UV_STICKY_SELECT_MODE_REF|.\n"
1933 " :type sticky_select_mode: |UV_STICKY_SELECT_MODE_TYPE|\n");
1935 PyObject *args,
1936 PyObject *kw)
1937{
1938 const char *error_prefix = "uv_select_foreach_set_from_mesh(...)";
1939 static const char *kwlist[] = {
1940 "", /* `select` */
1941 "verts",
1942 "edges",
1943 "faces",
1944 "sticky_select_mode",
1945 nullptr,
1946 };
1947 bool use_select = false;
1948 PyObject *py_verts = nullptr;
1949 PyObject *py_edges = nullptr;
1950 PyObject *py_faces = nullptr;
1952
1954
1955 if (!PyArg_ParseTupleAndKeywords(args,
1956 kw,
1957 "O&" /* `select` */
1958 "|$" /* Optional keyword only arguments. */
1959 "O" /* `verts` */
1960 "O" /* `edges` */
1961 "O" /* `faces` */
1962 "O&" /* `sticky_select_mode` */
1963 ":uv_select_foreach_set_from_mesh",
1964 (char **)kwlist,
1966 &use_select,
1967 &py_verts,
1968 &py_edges,
1969 &py_faces,
1971 &uv_sticky_select_mode))
1972 {
1973 return nullptr;
1974 }
1975
1976 BMesh *bm = self->bm;
1977 if (bpy_bm_check_uv_select_sync_valid(bm, error_prefix) == -1) {
1978 return nullptr;
1979 }
1980 const bool shared = uv_sticky_select_mode.value_found == UV_STICKY_LOCATION;
1981 const int cd_loop_uv_offset = shared ? bpy_bm_uv_layer_offset_or_error(bm, error_prefix) : -1;
1982 if (shared && (cd_loop_uv_offset == -1)) {
1983 return nullptr;
1984 }
1985
1986 Py_ssize_t vert_array_num = 0;
1987 Py_ssize_t edge_array_num = 0;
1988 Py_ssize_t face_array_num = 0;
1989 BMVert **vert_array = nullptr;
1990 BMEdge **edge_array = nullptr;
1991 BMFace **face_array = nullptr;
1992
1993 bool ok = true;
1994 if (ok && py_verts) {
1995 BMesh *bm_test = nullptr;
1996 if (!(vert_array = BPy_BMVert_PySeq_As_Array(
1997 &bm_test, py_verts, 0, PY_SSIZE_T_MAX, &vert_array_num, true, true, error_prefix)))
1998 {
1999 ok = false;
2000 }
2001 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
2002 ok = false;
2003 }
2004 }
2005 if (ok && py_edges) {
2006 BMesh *bm_test = nullptr;
2007 if (!(edge_array = BPy_BMEdge_PySeq_As_Array(
2008 &bm_test, py_edges, 0, PY_SSIZE_T_MAX, &edge_array_num, true, true, error_prefix)))
2009 {
2010 ok = false;
2011 }
2012 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
2013 ok = false;
2014 }
2015 }
2016 if (ok && py_faces) {
2017 BMesh *bm_test = nullptr;
2018 if (!(face_array = BPy_BMFace_PySeq_As_Array(
2019 &bm_test, py_faces, 0, PY_SSIZE_T_MAX, &face_array_num, true, true, error_prefix)))
2020 {
2021 ok = false;
2022 }
2023 else if (bm_test && bpy_bm_check_bm_match_or_error(bm, bm_test, error_prefix) == -1) {
2024 ok = false;
2025 }
2026 }
2027
2028 if (ok) {
2029 const BMUVSelectPickParams uv_pick_params = {
2030 /*cd_loop_uv_offset*/ cd_loop_uv_offset,
2031 /*shared*/ shared,
2032 };
2034 use_select,
2035 uv_pick_params,
2036 blender::Span(vert_array, vert_array_num),
2037 blender::Span(edge_array, edge_array_num),
2038 blender::Span(face_array, face_array_num));
2039 }
2040
2041 PyMem_FREE(vert_array);
2042 PyMem_FREE(edge_array);
2043 PyMem_FREE(face_array);
2044
2045 if (ok == false) {
2046 /* The error has been raised. */
2047 return nullptr;
2048 }
2049 Py_RETURN_NONE;
2050}
2051
2053
2055 /* Wrap. */
2056 bpy_bmesh_normal_update_doc,
2057 ".. method:: normal_update()\n"
2058 "\n"
2059 " Update normals of mesh faces and verts.\n"
2060 "\n"
2061 " .. note::\n"
2062 "\n"
2063 " The normal of any vertex where :attr:`is_wire` is True will be a zero vector.\n");
2065{
2067
2069
2070 Py_RETURN_NONE;
2071}
2072
2074 /* Wrap. */
2075 bpy_bmesh_transform_doc,
2076 ".. method:: transform(matrix, *, filter=None)\n"
2077 "\n"
2078 " Transform the mesh (optionally filtering flagged data only).\n"
2079 "\n"
2080 " :arg matrix: 4x4x transform matrix.\n"
2081 " :type matrix: :class:`mathutils.Matrix`\n"
2082 " :arg filter: Flag to filter vertices."
2083 ".\n"
2084 " :type filter: set[Literal[" BPY_BM_HFLAG_ALL_STR "]]\n");
2085static PyObject *bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject *kw)
2086{
2087 static const char *kwlist[] = {"matrix", "filter", nullptr};
2088
2089 MatrixObject *mat;
2090 PyObject *filter = nullptr;
2091 int filter_flags = 0;
2092
2094
2095 if (!PyArg_ParseTupleAndKeywords(
2096 args, kw, "O!|$O!:transform", (char **)kwlist, &matrix_Type, &mat, &PySet_Type, &filter))
2097 {
2098 return nullptr;
2099 }
2100
2101 BMVert *eve;
2102 BMIter iter;
2103 void *mat_ptr;
2104
2105 if (BaseMath_ReadCallback(mat) == -1) {
2106 return nullptr;
2107 }
2108 if (mat->col_num != 4 || mat->row_num != 4) {
2109 PyErr_SetString(PyExc_ValueError, "expected a 4x4 matrix");
2110 return nullptr;
2111 }
2112
2113 if (filter != nullptr &&
2114 PyC_FlagSet_ToBitfield(bpy_bm_hflag_all_flags, filter, &filter_flags, "bm.transform") == -1)
2115 {
2116 return nullptr;
2117 }
2118
2119 mat_ptr = mat->matrix;
2120
2121 if (!filter_flags) {
2122 BM_ITER_MESH (eve, &iter, self->bm, BM_VERTS_OF_MESH) {
2123 mul_m4_v3((float (*)[4])mat_ptr, eve->co);
2124 }
2125 }
2126 else {
2127 const char filter_flags_ch = char(filter_flags);
2128 BM_ITER_MESH (eve, &iter, self->bm, BM_VERTS_OF_MESH) {
2129 if (BM_elem_flag_test(eve, filter_flags_ch)) {
2130 mul_m4_v3((float (*)[4])mat_ptr, eve->co);
2131 }
2132 }
2133 }
2134
2135 Py_RETURN_NONE;
2136}
2137
2139 /* Wrap. */
2140 bpy_bmesh_calc_volume_doc,
2141 ".. method:: calc_volume(*, signed=False)\n"
2142 "\n"
2143 " Calculate mesh volume based on face normals.\n"
2144 "\n"
2145 " :arg signed: when signed is true, negative values may be returned.\n"
2146 " :type signed: bool\n"
2147 " :return: The volume of the mesh.\n"
2148 " :rtype: float\n");
2149static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObject *kw)
2150{
2151 static const char *kwlist[] = {"signed", nullptr};
2152 PyObject *is_signed = Py_False;
2153
2155
2156 if (!PyArg_ParseTupleAndKeywords(
2157 args, kw, "|$O!:calc_volume", (char **)kwlist, &PyBool_Type, &is_signed))
2158 {
2159 return nullptr;
2160 }
2161
2162 return PyFloat_FromDouble(BM_mesh_calc_volume(self->bm, is_signed != Py_False));
2163}
2164
2166 /* Wrap. */
2167 bpy_bmesh_calc_loop_triangles_doc,
2168 ".. method:: calc_loop_triangles()\n"
2169 "\n"
2170 " Calculate triangle tessellation from quads/ngons.\n"
2171 "\n"
2172 " :return: The triangulated faces.\n"
2173 " :rtype: list[tuple[:class:`bmesh.types.BMLoop`, "
2174 ":class:`bmesh.types.BMLoop`, "
2175 ":class:`bmesh.types.BMLoop`]]\n");
2177{
2178 int corner_tris_tot;
2179
2180 PyObject *ret;
2181
2183
2184 BMesh *bm = self->bm;
2185
2186 corner_tris_tot = poly_to_tri_count(bm->totface, bm->totloop);
2187 blender::Array<std::array<BMLoop *, 3>> corner_tris(corner_tris_tot);
2188 BM_mesh_calc_tessellation(bm, corner_tris);
2189
2190 ret = PyList_New(corner_tris_tot);
2191 for (int i = 0; i < corner_tris_tot; i++) {
2192 PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, corner_tris[i].data(), 3));
2193 }
2194
2195 return ret;
2196}
2197
2198/* Elem
2199 * ---- */
2200
2202 /* Wrap. */
2203 bpy_bm_elem_select_set_doc,
2204 ".. method:: select_set(select)\n"
2205 "\n"
2206 " Set the selection.\n"
2207 " This is different from the *select* attribute because it updates the selection "
2208 "state of associated geometry.\n"
2209 "\n"
2210 " :arg select: Select or de-select.\n"
2211 " :type select: bool\n"
2212 "\n"
2213 " .. note::\n"
2214 "\n"
2215 " This only flushes down, so selecting a face will select all its "
2216 "vertices but de-selecting a vertex "
2217 " won't de-select all the faces that use it, before finishing with a mesh "
2218 "typically flushing is still needed.\n");
2219static PyObject *bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value)
2220{
2221 int param;
2222
2224
2225 if ((param = PyC_Long_AsBool(value)) == -1) {
2226 return nullptr;
2227 }
2228
2229 BM_elem_select_set(self->bm, self->ele, param);
2230
2231 Py_RETURN_NONE;
2232}
2233
2235 /* Wrap. */
2236 bpy_bm_elem_hide_set_doc,
2237 ".. method:: hide_set(hide)\n"
2238 "\n"
2239 " Set the hide state.\n"
2240 " This is different from the *hide* attribute because it updates the selection and "
2241 "hide state of associated geometry.\n"
2242 "\n"
2243 " :arg hide: Hidden or visible.\n"
2244 " :type hide: bool\n");
2245static PyObject *bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value)
2246{
2247 int param;
2248
2250
2251 if ((param = PyC_Long_AsBool(value)) == -1) {
2252 return nullptr;
2253 }
2254
2255 BM_elem_hide_set(self->bm, self->ele, param);
2256
2257 Py_RETURN_NONE;
2258}
2259
2261 /* Wrap. */
2262 bpy_bm_elem_copy_from_doc,
2263 ".. method:: copy_from(other)\n"
2264 "\n"
2265 " Copy values from another element of matching type.\n");
2267{
2269
2270 if (Py_TYPE(self) != Py_TYPE(value)) {
2271 PyErr_Format(PyExc_TypeError,
2272 "expected element of type '%.200s' not '%.200s'",
2273 Py_TYPE(self)->tp_name,
2274 Py_TYPE(value)->tp_name);
2275 return nullptr;
2276 }
2277
2278 if (value->ele != self->ele) {
2279 switch (self->ele->head.htype) {
2280 case BM_VERT: {
2282 value->bm->vdata, self->bm->vdata, CD_MASK_BM_ELEM_PYPTR);
2284 cd_vert_map,
2285 reinterpret_cast<const BMVert *>(value->ele),
2286 reinterpret_cast<BMVert *>(self->ele));
2287 break;
2288 }
2289 case BM_EDGE: {
2291 value->bm->edata, self->bm->edata, CD_MASK_BM_ELEM_PYPTR);
2293 cd_edge_map,
2294 reinterpret_cast<const BMEdge *>(value->ele),
2295 reinterpret_cast<BMEdge *>(self->ele));
2296 break;
2297 }
2298 case BM_FACE: {
2300 value->bm->pdata, self->bm->pdata, CD_MASK_BM_ELEM_PYPTR);
2302 cd_face_map,
2303 reinterpret_cast<const BMFace *>(value->ele),
2304 reinterpret_cast<BMFace *>(self->ele));
2305 break;
2306 }
2307 case BM_LOOP: {
2309 value->bm->ldata, self->bm->ldata, CD_MASK_BM_ELEM_PYPTR);
2311 cd_loop_map,
2312 reinterpret_cast<const BMLoop *>(value->ele),
2313 reinterpret_cast<BMLoop *>(self->ele));
2314 break;
2315 }
2316 }
2317 }
2318
2319 Py_RETURN_NONE;
2320}
2321
2322/* Vert
2323 * ---- */
2324
2326 /* Wrap. */
2327 bpy_bmvert_copy_from_vert_interp_doc,
2328 ".. method:: copy_from_vert_interp(vert_pair, fac)\n"
2329 "\n"
2330 " Interpolate the customdata from a vert between 2 other verts.\n"
2331 "\n"
2332 " :arg vert_pair: The verts between which to interpolate data from.\n"
2333 " :type vert_pair: Sequence[:class:`bmesh.types.BMVert`]\n"
2334 " :type fac: float\n");
2335static PyObject *bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *args)
2336{
2337 const char *error_prefix = "BMVert.copy_from_vert_interp(...)";
2338 PyObject *vert_seq;
2339 float fac;
2340
2342
2343 if (!PyArg_ParseTuple(args, "Of:BMVert.copy_from_vert_interp", &vert_seq, &fac)) {
2344 return nullptr;
2345 }
2346
2347 BMesh *bm = self->bm;
2348
2349 Py_ssize_t vert_seq_num; /* Always 2. */
2350 BMVert **vert_array = BPy_BMVert_PySeq_As_Array(
2351 &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix);
2352
2353 if (vert_array == nullptr) {
2354 return nullptr;
2355 }
2356
2357 BM_data_interp_from_verts(bm, vert_array[0], vert_array[1], self->v, clamp_f(fac, 0.0f, 1.0f));
2358
2359 PyMem_FREE(vert_array);
2360 Py_RETURN_NONE;
2361}
2362
2364 /* Wrap. */
2365 bpy_bmvert_copy_from_face_interp_doc,
2366 ".. method:: copy_from_face_interp(face)\n"
2367 "\n"
2368 " Interpolate the customdata from a face onto this loop (the loops vert should "
2369 "overlap the face).\n"
2370 "\n"
2371 " :arg face: The face to interpolate data from.\n"
2372 " :type face: :class:`bmesh.types.BMFace`\n");
2373static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *args)
2374{
2375 const char *error_prefix = "copy_from_face_interp(...)";
2376 BPy_BMFace *py_face = nullptr;
2377
2379
2380 if (!PyArg_ParseTuple(args, "O!:BMVert.copy_from_face_interp", &BPy_BMFace_Type, &py_face)) {
2381 return nullptr;
2382 }
2383
2384 BMesh *bm = self->bm;
2385
2386 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face);
2387
2388 BM_vert_interp_from_face(bm, self->v, py_face->f);
2389
2390 Py_RETURN_NONE;
2391}
2392
2394 /* Wrap. */
2395 bpy_bmvert_calc_edge_angle_doc,
2396 ".. method:: calc_edge_angle(fallback=None)\n"
2397 "\n"
2398 " Return the angle between this vert's two connected edges.\n"
2399 "\n"
2400 " :arg fallback: return this when the vert doesn't have 2 edges\n"
2401 " (instead of raising a :exc:`ValueError`).\n"
2402 " :type fallback: Any\n"
2403 " :return: Angle between edges in radians.\n"
2404 " :rtype: float\n");
2405static PyObject *bpy_bmvert_calc_edge_angle(BPy_BMVert *self, PyObject *args)
2406{
2407 const float angle_invalid = -1.0f;
2408 float angle;
2409 PyObject *fallback = nullptr;
2410
2412
2413 if (!PyArg_ParseTuple(args, "|O:calc_edge_angle", &fallback)) {
2414 return nullptr;
2415 }
2416
2417 angle = BM_vert_calc_edge_angle_ex(self->v, angle_invalid);
2418
2419 if (angle == angle_invalid) {
2420 /* avoid exception */
2421 if (fallback) {
2422 Py_INCREF(fallback);
2423 return fallback;
2424 }
2425
2426 PyErr_SetString(PyExc_ValueError,
2427 "BMVert.calc_edge_angle(): "
2428 "vert must connect to exactly 2 edges");
2429 return nullptr;
2430 }
2431
2432 return PyFloat_FromDouble(angle);
2433}
2434
2436 /* Wrap. */
2437 bpy_bmvert_calc_shell_factor_doc,
2438 ".. method:: calc_shell_factor()\n"
2439 "\n"
2440 " Return a multiplier calculated based on the sharpness of the vertex.\n"
2441 " Where a flat surface gives 1.0, and higher values sharper edges.\n"
2442 " This is used to maintain shell thickness when offsetting verts along their normals.\n"
2443 "\n"
2444 " :return: offset multiplier\n"
2445 " :rtype: float\n");
2447{
2449 return PyFloat_FromDouble(BM_vert_calc_shell_factor(self->v));
2450}
2451
2453 /* Wrap. */
2454 bpy_bmvert_normal_update_doc,
2455 ".. method:: normal_update()\n"
2456 "\n"
2457 " Update vertex normal.\n"
2458 " This does not update the normals of adjoining faces.\n"
2459 "\n"
2460 " .. note::\n"
2461 "\n"
2462 " The vertex normal will be a zero vector if vertex :attr:`is_wire` is True.\n");
2464{
2466
2468
2469 Py_RETURN_NONE;
2470}
2471
2472/* Edge
2473 * ---- */
2474
2476 /* Wrap. */
2477 bpy_bmedge_calc_length_doc,
2478 ".. method:: calc_length()\n"
2479 "\n"
2480 " :return: The length between both verts.\n"
2481 " :rtype: float\n");
2483{
2485 return PyFloat_FromDouble(len_v3v3(self->e->v1->co, self->e->v2->co));
2486}
2487
2489 /* Wrap. */
2490 bpy_bmedge_calc_face_angle_doc,
2491 ".. method:: calc_face_angle(fallback=None)\n"
2492 "\n"
2493 " :arg fallback: return this when the edge doesn't have 2 faces\n"
2494 " (instead of raising a :exc:`ValueError`).\n"
2495 " :type fallback: Any\n"
2496 " :return: The angle between 2 connected faces in radians.\n"
2497 " :rtype: float\n");
2498static PyObject *bpy_bmedge_calc_face_angle(BPy_BMEdge *self, PyObject *args)
2499{
2500 const float angle_invalid = -1.0f;
2501 float angle;
2502 PyObject *fallback = nullptr;
2503
2505
2506 if (!PyArg_ParseTuple(args, "|O:calc_face_angle", &fallback)) {
2507 return nullptr;
2508 }
2509
2510 angle = BM_edge_calc_face_angle_ex(self->e, angle_invalid);
2511
2512 if (angle == angle_invalid) {
2513 /* avoid exception */
2514 if (fallback) {
2515 Py_INCREF(fallback);
2516 return fallback;
2517 }
2518
2519 PyErr_SetString(PyExc_ValueError,
2520 "BMEdge.calc_face_angle(): "
2521 "edge doesn't use 2 faces");
2522 return nullptr;
2523 }
2524
2525 return PyFloat_FromDouble(angle);
2526}
2527
2529 /* Wrap. */
2530 bpy_bmedge_calc_face_angle_signed_doc,
2531 ".. method:: calc_face_angle_signed(fallback=None)\n"
2532 "\n"
2533 " :arg fallback: return this when the edge doesn't have 2 faces\n"
2534 " (instead of raising a :exc:`ValueError`).\n"
2535 " :type fallback: Any\n"
2536 " :return: The angle between 2 connected faces in radians (negative for concave join).\n"
2537 " :rtype: float\n");
2538static PyObject *bpy_bmedge_calc_face_angle_signed(BPy_BMEdge *self, PyObject *args)
2539{
2540 const float angle_invalid = -FLT_MAX;
2541 float angle;
2542 PyObject *fallback = nullptr;
2543
2545
2546 if (!PyArg_ParseTuple(args, "|O:calc_face_angle_signed", &fallback)) {
2547 return nullptr;
2548 }
2549
2550 angle = BM_edge_calc_face_angle_signed_ex(self->e, angle_invalid);
2551
2552 if (angle == angle_invalid) {
2553 /* avoid exception */
2554 if (fallback) {
2555 Py_INCREF(fallback);
2556 return fallback;
2557 }
2558
2559 PyErr_SetString(PyExc_ValueError,
2560 "BMEdge.calc_face_angle_signed(): "
2561 "edge doesn't use 2 faces");
2562 return nullptr;
2563 }
2564
2565 return PyFloat_FromDouble(angle);
2566}
2567
2569 /* Wrap. */
2570 bpy_bmedge_calc_tangent_doc,
2571 ".. method:: calc_tangent(loop)\n"
2572 "\n"
2573 " Return the tangent at this edge relative to a face (pointing inward into the face).\n"
2574 " This uses the face normal for calculation.\n"
2575 "\n"
2576 " :arg loop: The loop used for tangent calculation.\n"
2577 " :type loop: :class:`bmesh.types.BMLoop`\n"
2578 " :return: a normalized vector.\n"
2579 " :rtype: :class:`mathutils.Vector`\n");
2580static PyObject *bpy_bmedge_calc_tangent(BPy_BMEdge *self, PyObject *args)
2581{
2582 BPy_BMLoop *py_loop;
2584
2585 if (!PyArg_ParseTuple(args, "O!:BMEdge.calc_face_tangent", &BPy_BMLoop_Type, &py_loop)) {
2586 return nullptr;
2587 }
2588
2589 float vec[3];
2590 BPY_BM_CHECK_OBJ(py_loop);
2591 /* no need to check if they are from the same mesh or even connected */
2592 BM_edge_calc_face_tangent(self->e, py_loop->l, vec);
2593 return Vector_CreatePyObject(vec, 3, nullptr);
2594}
2595
2597 /* Wrap. */
2598 bpy_bmedge_other_vert_doc,
2599 ".. method:: other_vert(vert)\n"
2600 "\n"
2601 " Return the other vertex on this edge or None if the vertex is not used by this edge.\n"
2602 "\n"
2603 " :arg vert: a vert in this edge.\n"
2604 " :type vert: :class:`bmesh.types.BMVert`\n"
2605 " :return: The edges other vert.\n"
2606 " :rtype: :class:`bmesh.types.BMVert` | None\n");
2608{
2609 const char *error_prefix = "BMEdge.other_vert(...)";
2610 BMVert *other;
2612
2613 if (!BPy_BMVert_Check(value)) {
2614 PyErr_Format(PyExc_TypeError,
2615 "%s: BMVert expected, not '%.200s'",
2616 error_prefix,
2617 Py_TYPE(value)->tp_name);
2618 return nullptr;
2619 }
2620
2621 BPY_BM_CHECK_SOURCE_OBJ(self->bm, error_prefix, value);
2622
2623 other = BM_edge_other_vert(self->e, value->v);
2624
2625 if (other) {
2626 return BPy_BMVert_CreatePyObject(self->bm, other);
2627 }
2628
2629 /* could raise an exception here */
2630 Py_RETURN_NONE;
2631}
2632
2634 /* Wrap. */
2635 bpy_bmedge_normal_update_doc,
2636 ".. method:: normal_update()\n"
2637 "\n"
2638 " Update normals of all connected faces and the edge verts.\n"
2639 "\n"
2640 " .. note::\n"
2641 "\n"
2642 " The normal of edge vertex will be a zero vector if vertex :attr:`is_wire` is True.\n");
2644{
2646
2648
2649 Py_RETURN_NONE;
2650}
2651
2652/* Face
2653 * ---- */
2654
2656 /* Wrap. */
2657 bpy_bmface_copy_from_face_interp_doc,
2658 ".. method:: copy_from_face_interp(face, vert=True)\n"
2659 "\n"
2660 " Interpolate the customdata from another face onto this one (faces should overlap).\n"
2661 "\n"
2662 " :arg face: The face to interpolate data from.\n"
2663 " :type face: :class:`bmesh.types.BMFace`\n"
2664 " :arg vert: When True, also copy vertex data.\n"
2665 " :type vert: bool\n");
2666static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *args)
2667{
2668 const char *error_prefix = "BMFace.copy_from_face_interp(...)";
2669 BPy_BMFace *py_face = nullptr;
2670 bool do_vertex = true;
2671
2673
2674 if (!PyArg_ParseTuple(args,
2675 "O!|O&:BMFace.copy_from_face_interp",
2677 &py_face,
2679 &do_vertex))
2680 {
2681 return nullptr;
2682 }
2683
2684 BMesh *bm = self->bm;
2685
2686 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face);
2687
2688 BM_face_interp_from_face(bm, self->f, py_face->f, do_vertex);
2689
2690 Py_RETURN_NONE;
2691}
2692
2694 /* Wrap. */
2695 bpy_bmface_copy_doc,
2696 ".. method:: copy(*, verts=True, edges=True)\n"
2697 "\n"
2698 " Make a copy of this face.\n"
2699 "\n"
2700 " :arg verts: When set, the faces verts will be duplicated too.\n"
2701 " :type verts: bool\n"
2702 " :arg edges: When set, the faces edges will be duplicated too.\n"
2703 " :type edges: bool\n"
2704 " :return: The newly created face.\n"
2705 " :rtype: :class:`bmesh.types.BMFace`\n");
2706static PyObject *bpy_bmface_copy(BPy_BMFace *self, PyObject *args, PyObject *kw)
2707{
2708 static const char *kwlist[] = {"verts", "edges", nullptr};
2709
2710 BMesh *bm = self->bm;
2711 bool do_verts = true;
2712 bool do_edges = true;
2713
2714 BMFace *f_cpy;
2716
2717 if (!PyArg_ParseTupleAndKeywords(args,
2718 kw,
2719 "|$O&O&:BMFace.copy",
2720 (char **)kwlist,
2722 &do_verts,
2724 &do_edges))
2725 {
2726 return nullptr;
2727 }
2728
2729 f_cpy = BM_face_copy(bm, self->f, do_verts, do_edges);
2730
2731 if (f_cpy) {
2732 return BPy_BMFace_CreatePyObject(bm, f_cpy);
2733 }
2734
2735 PyErr_SetString(PyExc_ValueError, "BMFace.copy(): couldn't create the new face, internal error");
2736 return nullptr;
2737}
2738
2740 /* Wrap. */
2741 bpy_bmface_uv_select_set_doc,
2742 ".. method:: uv_select_set(select)\n"
2743 "\n"
2744 " Select the face.\n"
2745 "\n"
2746 " :arg select: Select or de-select.\n"
2747 " :type select: bool\n"
2748 "\n"
2749 " .. note::\n"
2750 "\n"
2751 " Currently this only flushes down, so selecting a face will select all its "
2752 "vertices but de-selecting a vertex "
2753 " won't de-select all the faces that use it, before finishing with a mesh "
2754 "typically flushing is still needed.\n");
2755static PyObject *bpy_bmface_uv_select_set(BPy_BMFace *self, PyObject *value)
2756{
2757 BMesh *bm = self->bm;
2759 int param;
2760 if ((param = PyC_Long_AsBool(value)) == -1) {
2761 return nullptr;
2762 }
2763 BM_face_uvselect_set(bm, self->f, param);
2764 Py_RETURN_NONE;
2765}
2766
2768 /* Wrap. */
2769 bpy_bmface_calc_area_doc,
2770 ".. method:: calc_area()\n"
2771 "\n"
2772 " Return the area of the face.\n"
2773 "\n"
2774 " :return: Return the area of the face.\n"
2775 " :rtype: float\n");
2777{
2779 return PyFloat_FromDouble(BM_face_calc_area(self->f));
2780}
2781
2783 /* Wrap. */
2784 bpy_bmface_calc_perimeter_doc,
2785 ".. method:: calc_perimeter()\n"
2786 "\n"
2787 " Return the perimeter of the face.\n"
2788 "\n"
2789 " :return: Return the perimeter of the face.\n"
2790 " :rtype: float\n");
2792{
2794 return PyFloat_FromDouble(BM_face_calc_perimeter(self->f));
2795}
2796
2798 /* Wrap. */
2799 bpy_bmface_calc_tangent_edge_doc,
2800 ".. method:: calc_tangent_edge()\n"
2801 "\n"
2802 " Return face tangent based on longest edge.\n"
2803 "\n"
2804 " :return: a normalized vector.\n"
2805 " :rtype: :class:`mathutils.Vector`\n");
2807{
2808 float tangent[3];
2809
2812 return Vector_CreatePyObject(tangent, 3, nullptr);
2813}
2814
2816 /* Wrap. */
2817 bpy_bmface_calc_tangent_edge_pair_doc,
2818 ".. method:: calc_tangent_edge_pair()\n"
2819 "\n"
2820 " Return face tangent based on the two longest disconnected edges.\n"
2821 "\n"
2822 " - Tris: Use the edge pair with the most similar lengths.\n"
2823 " - Quads: Use the longest edge pair.\n"
2824 " - NGons: Use the two longest disconnected edges.\n"
2825 "\n"
2826 " :return: a normalized vector.\n"
2827 " :rtype: :class:`mathutils.Vector`\n");
2829{
2830 float tangent[3];
2831
2834 return Vector_CreatePyObject(tangent, 3, nullptr);
2835}
2836
2838 /* Wrap. */
2839 bpy_bmface_calc_tangent_edge_diagonal_doc,
2840 ".. method:: calc_tangent_edge_diagonal()\n"
2841 "\n"
2842 " Return face tangent based on the edge farthest from any vertex.\n"
2843 "\n"
2844 " :return: a normalized vector.\n"
2845 " :rtype: :class:`mathutils.Vector`\n");
2847{
2848 float tangent[3];
2849
2852 return Vector_CreatePyObject(tangent, 3, nullptr);
2853}
2854
2856 /* Wrap. */
2857 bpy_bmface_calc_tangent_vert_diagonal_doc,
2858 ".. method:: calc_tangent_vert_diagonal()\n"
2859 "\n"
2860 " Return face tangent based on the two most distant vertices.\n"
2861 "\n"
2862 " :return: a normalized vector.\n"
2863 " :rtype: :class:`mathutils.Vector`\n");
2865{
2866 float tangent[3];
2867
2870 return Vector_CreatePyObject(tangent, 3, nullptr);
2871}
2872
2874 /* Wrap. */
2875 bpy_bmface_calc_center_median_doc,
2876 ".. method:: calc_center_median()\n"
2877 "\n"
2878 " Return median center of the face.\n"
2879 "\n"
2880 " :return: a 3D vector.\n"
2881 " :rtype: :class:`mathutils.Vector`\n");
2883{
2884 float cent[3];
2885
2888 return Vector_CreatePyObject(cent, 3, nullptr);
2889}
2890
2892 /* Wrap. */
2893 bpy_bmface_calc_center_median_weighted_doc,
2894 ".. method:: calc_center_median_weighted()\n"
2895 "\n"
2896 " Return median center of the face weighted by edge lengths.\n"
2897 "\n"
2898 " :return: a 3D vector.\n"
2899 " :rtype: :class:`mathutils.Vector`\n");
2901{
2902 float cent[3];
2903
2906 return Vector_CreatePyObject(cent, 3, nullptr);
2907}
2908
2910 /* Wrap. */
2911 bpy_bmface_calc_center_bounds_doc,
2912 ".. method:: calc_center_bounds()\n"
2913 "\n"
2914 " Return bounds center of the face.\n"
2915 "\n"
2916 " :return: a 3D vector.\n"
2917 " :rtype: :class:`mathutils.Vector`\n");
2919{
2920 float cent[3];
2921
2924 return Vector_CreatePyObject(cent, 3, nullptr);
2925}
2926
2928 /* Wrap. */
2929 bpy_bmface_normal_update_doc,
2930 ".. method:: normal_update()\n"
2931 "\n"
2932 " Update face normal based on the positions of the face verts.\n"
2933 " This does not update the normals of face verts.\n");
2935{
2937
2939
2940 Py_RETURN_NONE;
2941}
2942
2944 /* Wrap. */
2945 bpy_bmface_normal_flip_doc,
2946 ".. method:: normal_flip()\n"
2947 "\n"
2948 " Reverses winding of a face, which flips its normal.\n");
2950{
2952
2953 BM_face_normal_flip(self->bm, self->f);
2954
2955 Py_RETURN_NONE;
2956}
2957
2958/* Loop
2959 * ---- */
2960
2962 /* Wrap. */
2963 bpy_bmloop_copy_from_face_interp_doc,
2964 ".. method:: copy_from_face_interp(face, vert=True, multires=True)\n"
2965 "\n"
2966 " Interpolate the customdata from a face onto this loop (the loops vert should "
2967 "overlap the face).\n"
2968 "\n"
2969 " :arg face: The face to interpolate data from.\n"
2970 " :type face: :class:`bmesh.types.BMFace`\n"
2971 " :arg vert: When enabled, interpolate the loops vertex data (optional).\n"
2972 " :type vert: bool\n"
2973 " :arg multires: When enabled, interpolate the loops multires data (optional).\n"
2974 " :type multires: bool\n");
2975static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *args)
2976{
2977 const char *error_prefix = "BMLoop.copy_from_face_interp(face)";
2978 BPy_BMFace *py_face = nullptr;
2979 bool do_vertex = true;
2980 bool do_multires = true;
2981
2983
2984 if (!PyArg_ParseTuple(args,
2985 "O!|O&O&:BMLoop.copy_from_face_interp",
2987 &py_face,
2989 &do_vertex,
2991 &do_multires))
2992 {
2993 return nullptr;
2994 }
2995
2996 BMesh *bm = self->bm;
2997
2998 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, py_face);
2999
3000 BM_loop_interp_from_face(bm, self->l, py_face->f, do_vertex, do_multires);
3001
3002 Py_RETURN_NONE;
3003}
3004
3006 /* Wrap. */
3007 bpy_bmloop_uv_select_vert_set_doc,
3008 ".. method:: uv_select_vert_set(select)\n"
3009 "\n"
3010 " Select the UV vertex.\n"
3011 "\n"
3012 " :arg select: Select or de-select.\n"
3013 " :type select: bool\n"
3014 "\n"
3015 " .. note::\n"
3016 "\n"
3017 " Currently this only flushes down, so selecting an edge will select all its "
3018 "vertices but de-selecting a vertex "
3019 " won't de-select the edges & faces that use it, before finishing with a mesh "
3020 "typically flushing with :class:`bmesh.types.BMesh.uv_select_flush_mode` is still needed.\n");
3021static PyObject *bpy_bmloop_uv_select_vert_set(BPy_BMLoop *self, PyObject *value)
3022{
3023 BMesh *bm = self->bm;
3025 int param;
3026 if ((param = PyC_Long_AsBool(value)) == -1) {
3027 return nullptr;
3028 }
3029
3030 /* There is no flushing version of this function. */
3032
3033 Py_RETURN_NONE;
3034}
3035
3037 /* Wrap. */
3038 bpy_bmloop_uv_select_edge_set_doc,
3039 ".. method:: uv_select_edge_set(select)\n"
3040 "\n"
3041 " Set the UV edge selection state.\n"
3042 "\n"
3043 " :arg select: Select or de-select.\n"
3044 " :type select: bool\n"
3045 "\n"
3046 " .. note::\n"
3047 "\n"
3048 " This only flushes down, so selecting an edge will select all its "
3049 "vertices but de-selecting a vertex "
3050 "won't de-select the faces that use it, before finishing with a mesh "
3051 "typically flushing with :class:`bmesh.types.BMesh.uv_select_flush_mode` is still needed.\n");
3052static PyObject *bpy_bmloop_uv_select_edge_set(BPy_BMLoop *self, PyObject *value)
3053{
3054 BMesh *bm = self->bm;
3056 int param;
3057 if ((param = PyC_Long_AsBool(value)) == -1) {
3058 return nullptr;
3059 }
3060 BM_loop_edge_uvselect_set(bm, self->l, param);
3061 Py_RETURN_NONE;
3062}
3063
3065 /* Wrap. */
3066 bpy_bmloop_calc_angle_doc,
3067 ".. method:: calc_angle()\n"
3068 "\n"
3069 " Return the angle at this loops corner of the face.\n"
3070 " This is calculated so sharper corners give lower angles.\n"
3071 "\n"
3072 " :return: The angle in radians.\n"
3073 " :rtype: float\n");
3075{
3077 return PyFloat_FromDouble(BM_loop_calc_face_angle(self->l));
3078}
3079
3081 /* Wrap. */
3082 bpy_bmloop_calc_normal_doc,
3083 ".. method:: calc_normal()\n"
3084 "\n"
3085 " Return normal at this loops corner of the face.\n"
3086 " Falls back to the face normal for straight lines.\n"
3087 "\n"
3088 " :return: a normalized vector.\n"
3089 " :rtype: :class:`mathutils.Vector`\n");
3091{
3092 float vec[3];
3095 return Vector_CreatePyObject(vec, 3, nullptr);
3096}
3097
3099 /* Wrap. */
3100 bpy_bmloop_calc_tangent_doc,
3101 ".. method:: calc_tangent()\n"
3102 "\n"
3103 " Return the tangent at this loops corner of the face (pointing inward into the face).\n"
3104 " Falls back to the face normal for straight lines.\n"
3105 "\n"
3106 " :return: a normalized vector.\n"
3107 " :rtype: :class:`mathutils.Vector`\n");
3109{
3110 float vec[3];
3113 return Vector_CreatePyObject(vec, 3, nullptr);
3114}
3115
3116/* Vert Seq
3117 * -------- */
3119 /* Wrap. */
3120 bpy_bmvertseq_new_doc,
3121 ".. method:: new(co=(0.0, 0.0, 0.0), example=None)\n"
3122 "\n"
3123 " Create a new vertex.\n"
3124 "\n"
3125 " :arg co: The initial location of the vertex (optional argument).\n"
3126 " :type co: float triplet\n"
3127 " :arg example: Existing vert to initialize settings.\n"
3128 " :type example: :class:`bmesh.types.BMVert`\n"
3129 " :return: The newly created vertex.\n"
3130 " :rtype: :class:`bmesh.types.BMVert`\n");
3131static PyObject *bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args)
3132{
3133 PyObject *py_co = nullptr;
3134 BPy_BMVert *py_vert_example = nullptr; /* optional */
3135
3137
3138 if (!PyArg_ParseTuple(args, "|OO!:verts.new", &py_co, &BPy_BMVert_Type, &py_vert_example)) {
3139 return nullptr;
3140 }
3141
3142 BMesh *bm = self->bm;
3143 BMVert *v;
3144 float co[3] = {0.0f, 0.0f, 0.0f};
3145
3146 if (py_vert_example) {
3147 BPY_BM_CHECK_OBJ(py_vert_example);
3148 }
3149
3150 if (py_co && mathutils_array_parse(co, 3, 3, py_co, "verts.new(co)") == -1) {
3151 return nullptr;
3152 }
3153
3154 v = BM_vert_create(bm, co, nullptr, BM_CREATE_NOP);
3155
3156 if (v == nullptr) {
3157 PyErr_SetString(PyExc_ValueError,
3158 "faces.new(verts): couldn't create the new face, internal error");
3159 return nullptr;
3160 }
3161
3162 if (py_vert_example) {
3163 if (py_vert_example->bm == bm) {
3164 BM_elem_attrs_copy(bm, py_vert_example->v, v);
3165 }
3166 else {
3168 py_vert_example->bm->vdata, bm->vdata);
3169 BM_elem_attrs_copy(bm, cd_vert_map, py_vert_example->v, v);
3170 }
3171 }
3172
3174}
3175
3176/* Edge Seq
3177 * -------- */
3179 /* Wrap. */
3180 bpy_bmedgeseq_new_doc,
3181 ".. method:: new(verts, example=None)\n"
3182 "\n"
3183 " Create a new edge from a given pair of verts.\n"
3184 "\n"
3185 " :arg verts: Vertex pair.\n"
3186 " :type verts: Sequence[:class:`bmesh.types.BMVert`]\n"
3187 " :arg example: Existing edge to initialize settings (optional argument).\n"
3188 " :type example: :class:`bmesh.types.BMEdge`\n"
3189 " :return: The newly created edge.\n"
3190 " :rtype: :class:`bmesh.types.BMEdge`\n");
3191static PyObject *bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args)
3192{
3193 const char *error_prefix = "edges.new(...)";
3194 PyObject *vert_seq;
3195 BPy_BMEdge *py_edge_example = nullptr; /* optional */
3196
3198
3199 if (!PyArg_ParseTuple(args, "O|O!:edges.new", &vert_seq, &BPy_BMEdge_Type, &py_edge_example)) {
3200 return nullptr;
3201 }
3202
3203 BMesh *bm = self->bm;
3204 BMEdge *e;
3205 PyObject *ret = nullptr;
3206
3207 if (py_edge_example) {
3208 BPY_BM_CHECK_OBJ(py_edge_example);
3209 }
3210
3211 Py_ssize_t vert_seq_num; /* Always 2. */
3212 BMVert **vert_array = BPy_BMVert_PySeq_As_Array(
3213 &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix);
3214 if (vert_array == nullptr) {
3215 return nullptr;
3216 }
3217
3218 if (BM_edge_exists(vert_array[0], vert_array[1])) {
3219 PyErr_SetString(PyExc_ValueError, "edges.new(): this edge exists");
3220 goto cleanup;
3221 }
3222
3223 e = BM_edge_create(bm, vert_array[0], vert_array[1], nullptr, BM_CREATE_NOP);
3224
3225 if (e == nullptr) {
3226 PyErr_SetString(PyExc_ValueError,
3227 "faces.new(verts): couldn't create the new face, internal error");
3228 goto cleanup;
3229 }
3230
3231 if (py_edge_example) {
3232 if (py_edge_example->bm == bm) {
3233 BM_elem_attrs_copy(bm, py_edge_example->e, e);
3234 }
3235 else {
3237 py_edge_example->bm->edata, bm->edata);
3238 BM_elem_attrs_copy(bm, cd_edge_map, py_edge_example->e, e);
3239 }
3240 }
3241
3243
3244cleanup:
3245 if (vert_array) {
3246 PyMem_FREE(vert_array);
3247 }
3248 return ret;
3249}
3250
3251/* Face Seq
3252 * -------- */
3254 /* Wrap. */
3255 bpy_bmfaceseq_new_doc,
3256 ".. method:: new(verts, example=None)\n"
3257 "\n"
3258 " Create a new face from a given set of verts.\n"
3259 "\n"
3260 " :arg verts: Sequence of 3 or more verts.\n"
3261 " :type verts: Sequence[:class:`bmesh.types.BMVert`]\n"
3262 " :arg example: Existing face to initialize settings (optional argument).\n"
3263 " :type example: :class:`bmesh.types.BMFace`\n"
3264 " :return: The newly created face.\n"
3265 " :rtype: :class:`bmesh.types.BMFace`\n");
3266static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
3267{
3268 const char *error_prefix = "faces.new(...)";
3269 PyObject *vert_seq;
3270 BPy_BMFace *py_face_example = nullptr; /* optional */
3271
3273
3274 if (!PyArg_ParseTuple(args, "O|O!:faces.new", &vert_seq, &BPy_BMFace_Type, &py_face_example)) {
3275 return nullptr;
3276 }
3277
3278 BMesh *bm = self->bm;
3279
3280 PyObject *ret = nullptr;
3281
3282 BMFace *f_new;
3283
3284 if (py_face_example) {
3285 BPY_BM_CHECK_OBJ(py_face_example);
3286 }
3287
3288 Py_ssize_t vert_seq_num;
3289 BMVert **vert_array = BPy_BMVert_PySeq_As_Array(
3290 &bm, vert_seq, 3, PY_SSIZE_T_MAX, &vert_seq_num, true, true, error_prefix);
3291 if (vert_array == nullptr) {
3292 return nullptr;
3293 }
3294
3295 /* check if the face exists */
3296 if (BM_face_exists(vert_array, vert_seq_num) != nullptr) {
3297 PyErr_Format(PyExc_ValueError, "%s: face already exists", error_prefix);
3298 goto cleanup;
3299 }
3300
3301 /* Go ahead and make the face!
3302 * --------------------------- */
3303
3304 f_new = BM_face_create_verts(bm,
3305 vert_array,
3306 vert_seq_num,
3307 py_face_example ? py_face_example->f : nullptr,
3309 true);
3310
3311 if (UNLIKELY(f_new == nullptr)) {
3312 PyErr_Format(
3313 PyExc_ValueError, "%s: couldn't create the new face, internal error", error_prefix);
3314 goto cleanup;
3315 }
3316
3318
3319/* pass through */
3320cleanup:
3321 if (vert_array) {
3322 PyMem_FREE(vert_array);
3323 }
3324 return ret;
3325}
3326
3327/* Elem Seq
3328 * -------- */
3329
3331 /* Wrap. */
3332 bpy_bmvertseq_remove_doc,
3333 ".. method:: remove(vert)\n"
3334 "\n"
3335 " Remove a vert.\n"
3336 "\n"
3337 " :type vert: :class:`bmesh.types.BMVert`\n");
3339{
3340 const char *error_prefix = "verts.remove(vert)";
3342
3343 if (!BPy_BMVert_Check(value)) {
3344 return nullptr;
3345 }
3346
3347 BMesh *bm = self->bm;
3348
3349 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value);
3350
3351 BM_vert_kill(bm, value->v);
3353
3354 Py_RETURN_NONE;
3355}
3356
3358 /* Wrap. */
3359 bpy_bmedgeseq_remove_doc,
3360 ".. method:: remove(edge)\n"
3361 "\n"
3362 " Remove an edge.\n"
3363 "\n"
3364 " :type edge: :class:`bmesh.types.BMEdge`\n");
3366{
3367 const char *error_prefix = "edges.remove(...)";
3369
3370 if (!BPy_BMEdge_Check(value)) {
3371 return nullptr;
3372 }
3373
3374 BMesh *bm = self->bm;
3375
3376 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value);
3377
3378 BM_edge_kill(bm, value->e);
3380
3381 Py_RETURN_NONE;
3382}
3383
3385 /* Wrap. */
3386 bpy_bmfaceseq_remove_doc,
3387 ".. method:: remove(face)\n"
3388 "\n"
3389 " Remove a face.\n"
3390 "\n"
3391 " :type face: :class:`bmesh.types.BMFace`\n");
3393{
3394 const char *error_prefix = "faces.remove(...)";
3396
3397 if (!BPy_BMFace_Check(value)) {
3398 return nullptr;
3399 }
3400
3401 BMesh *bm = self->bm;
3402
3403 BPY_BM_CHECK_SOURCE_OBJ(bm, error_prefix, value);
3404
3405 BM_face_kill(bm, value->f);
3407
3408 Py_RETURN_NONE;
3409}
3410
3412 /* Wrap. */
3413 bpy_bmedgeseq_get__method_doc,
3414 ".. method:: get(verts, fallback=None)\n"
3415 "\n"
3416 " Return an edge which uses the **verts** passed.\n"
3417 "\n"
3418 " :arg verts: Sequence of verts.\n"
3419 " :type verts: Sequence[:class:`bmesh.types.BMVert`]\n"
3420 " :arg fallback: Return this value if nothing is found.\n"
3421 " :return: The edge found or None\n"
3422 " :rtype: :class:`bmesh.types.BMEdge`\n");
3423static PyObject *bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args)
3424{
3425 const char *error_prefix = "edges.get(...)";
3426 PyObject *vert_seq;
3427 PyObject *fallback = Py_None; /* optional */
3428
3430
3431 if (!PyArg_ParseTuple(args, "O|O:edges.get", &vert_seq, &fallback)) {
3432 return nullptr;
3433 }
3434
3435 BMesh *bm = self->bm;
3436 BMEdge *e;
3437 PyObject *ret = nullptr;
3438
3439 Py_ssize_t vert_seq_num; /* Always 2. */
3440 BMVert **vert_array = BPy_BMVert_PySeq_As_Array(
3441 &bm, vert_seq, 2, 2, &vert_seq_num, true, true, error_prefix);
3442
3443 if (vert_array == nullptr) {
3444 return nullptr;
3445 }
3446
3447 if ((e = BM_edge_exists(vert_array[0], vert_array[1]))) {
3449 }
3450 else {
3451 ret = fallback;
3452 Py_INCREF(ret);
3453 }
3454
3455 PyMem_FREE(vert_array);
3456 return ret;
3457}
3458
3460 /* Wrap. */
3461 bpy_bmfaceseq_get__method_doc,
3462 ".. method:: get(verts, fallback=None)\n"
3463 "\n"
3464 " Return a face which uses the **verts** passed.\n"
3465 "\n"
3466 " :arg verts: Sequence of verts.\n"
3467 " :type verts: Sequence[:class:`bmesh.types.BMVert`]\n"
3468 " :arg fallback: Return this value if nothing is found.\n"
3469 " :return: The face found or None\n"
3470 " :rtype: :class:`bmesh.types.BMFace`\n");
3471static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
3472{
3473 const char *error_prefix = "faces.get(...)";
3474 PyObject *vert_seq;
3475 PyObject *fallback = Py_None; /* optional */
3476
3478
3479 if (!PyArg_ParseTuple(args, "O|O:faces.get", &vert_seq, &fallback)) {
3480 return nullptr;
3481 }
3482
3483 BMesh *bm = self->bm;
3484 BMFace *f = nullptr;
3485 PyObject *ret = nullptr;
3486
3487 Py_ssize_t vert_seq_num;
3488 BMVert **vert_array = BPy_BMVert_PySeq_As_Array(
3489 &bm, vert_seq, 1, PY_SSIZE_T_MAX, &vert_seq_num, true, true, error_prefix);
3490
3491 if (vert_array == nullptr) {
3492 return nullptr;
3493 }
3494
3495 f = BM_face_exists(vert_array, vert_seq_num);
3496 if (f != nullptr) {
3498 }
3499 else {
3500 ret = fallback;
3501 Py_INCREF(ret);
3502 }
3503
3504 PyMem_FREE(vert_array);
3505 return ret;
3506}
3507
3509 /* Wrap. */
3510 bpy_bmelemseq_index_update_doc,
3511 ".. method:: index_update()\n"
3512 "\n"
3513 " Initialize the index values of this sequence.\n"
3514 "\n"
3515 " This is the equivalent of looping over all elements and assigning the index values.\n"
3516 "\n"
3517 " .. code-block:: python\n"
3518 "\n"
3519 " for index, ele in enumerate(sequence):\n"
3520 " ele.index = index\n"
3521 "\n"
3522 " .. note::\n"
3523 "\n"
3524 " Running this on sequences besides "
3525 ":class:`bmesh.types.BMesh.verts`, "
3526 ":class:`bmesh.types.BMesh.edges`, "
3527 ":class:`bmesh.types.BMesh.faces`\n"
3528 " works but won't result in each element having a valid index, instead its order in the "
3529 "sequence will be set.\n");
3531{
3532 BMesh *bm = self->bm;
3533
3535
3536 switch ((BMIterType)self->itype) {
3537 case BM_VERTS_OF_MESH:
3539 break;
3540 case BM_EDGES_OF_MESH:
3542 break;
3543 case BM_FACES_OF_MESH:
3545 break;
3546 default: {
3547 BMIter iter;
3548 BMElem *ele;
3549 int index = 0;
3550 const char htype = bm_iter_itype_htype_map[self->itype];
3551
3552 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
3553 BM_elem_index_set(ele, index); /* set_dirty! */
3554 index++;
3555 }
3556
3557 /* since this isn't the normal vert/edge/face loops,
3558 * we're setting dirty values here. so tag as dirty. */
3559 bm->elem_index_dirty |= htype;
3560
3561 break;
3562 }
3563 }
3564
3565 Py_RETURN_NONE;
3566}
3567
3569 /* Wrap. */
3570 bpy_bmelemseq_ensure_lookup_table_doc,
3571 ".. method:: ensure_lookup_table()\n"
3572 "\n"
3573 " Ensure internal data needed for int subscription is initialized with "
3574 "verts/edges/faces, eg ``bm.verts[index]``.\n"
3575 "\n"
3576 " This needs to be called again after adding/removing data in this sequence.\n");
3578{
3580
3582
3583 Py_RETURN_NONE;
3584}
3585
3587 /* Wrap. */
3588 bpy_bmelemseq_sort_doc,
3589 ".. method:: sort(*, key=None, reverse=False)\n"
3590 "\n"
3591 " Sort the elements of this sequence, using an optional custom sort key.\n"
3592 " Indices of elements are not changed, :class:`bmesh.types.BMElemSeq.index_update` "
3593 "can be used for that.\n"
3594 "\n"
3595 " :arg key: The key that sets the ordering of the elements.\n"
3596 " :type key: Callable[["
3597 ":class:`bmesh.types.BMVert` | "
3598 ":class:`bmesh.types.BMEdge` | "
3599 ":class:`bmesh.types.BMFace`], int] | None\n"
3600 " :arg reverse: Reverse the order of the elements\n"
3601 " :type reverse: bool\n"
3602 "\n"
3603 " .. note::\n"
3604 "\n"
3605 " When the 'key' argument is not provided, the elements are reordered following their "
3606 "current index value.\n"
3607 " In particular this can be used by setting indices manually before calling this "
3608 "method.\n"
3609 "\n"
3610 " .. warning::\n"
3611 "\n"
3612 " Existing references to the N'th element, will continue to point the data at that "
3613 "index.\n");
3614
3615/* Use a static variable here because there is the need to sort some array
3616 * doing comparisons on elements of another array, qsort_r would have been
3617 * wonderful to use here, but unfortunately it is not standard and it's not
3618 * portable across different platforms.
3619 *
3620 * If a portable alternative to qsort_r becomes available, remove this static
3621 * var hack!
3622 *
3623 * NOTE: the functions below assumes the keys array has been allocated and it
3624 * has enough elements to complete the task.
3625 */
3626
3627static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v,
3628 const void *index2_v,
3629 void *keys_v)
3630{
3631 const double *keys = static_cast<const double *>(keys_v);
3632 const int *index1 = (int *)index1_v;
3633 const int *index2 = (int *)index2_v;
3634
3635 if (keys[*index1] < keys[*index2]) {
3636 return -1;
3637 }
3638 if (keys[*index1] > keys[*index2]) {
3639 return 1;
3640 }
3641
3642 return 0;
3643}
3644
3645static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v,
3646 const void *index2_v,
3647 void *keys_v)
3648{
3649 return -bpy_bmelemseq_sort_cmp_by_keys_ascending(index1_v, index2_v, keys_v);
3650}
3651
3652static PyObject *bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObject *kw)
3653{
3654 static const char *kwlist[] = {"key", "reverse", nullptr};
3655 PyObject *keyfunc = nullptr; /* optional */
3656 bool do_reverse = false; /* optional */
3657
3658 const char htype = bm_iter_itype_htype_map[self->itype];
3659 int n_elem;
3660
3661 BMIter iter;
3662 BMElem *ele;
3663
3664 double *keys;
3665 int *elem_idx;
3666 uint *elem_map_idx;
3667 int (*elem_idx_compare_by_keys)(const void *, const void *, void *);
3668
3669 uint *vert_idx = nullptr;
3670 uint *edge_idx = nullptr;
3671 uint *face_idx = nullptr;
3672 int i;
3673
3674 BMesh *bm = self->bm;
3675
3677
3678 if (args != nullptr) {
3679 if (!PyArg_ParseTupleAndKeywords(args,
3680 kw,
3681 "|$OO&:BMElemSeq.sort",
3682 (char **)kwlist,
3683 &keyfunc,
3685 &do_reverse))
3686 {
3687 return nullptr;
3688 }
3689 if (keyfunc == Py_None) {
3690 keyfunc = nullptr;
3691 }
3692 }
3693
3694 if (keyfunc != nullptr && !PyCallable_Check(keyfunc)) {
3695 PyErr_SetString(PyExc_TypeError, "the 'key' argument is not a callable object");
3696 return nullptr;
3697 }
3698
3699 n_elem = BM_mesh_elem_count(bm, htype);
3700 if (n_elem <= 1) {
3701 /* 0 or 1 elements: sorted already */
3702 Py_RETURN_NONE;
3703 }
3704
3705 keys = static_cast<double *>(PyMem_MALLOC(sizeof(*keys) * n_elem));
3706 if (keys == nullptr) {
3707 PyErr_NoMemory();
3708 return nullptr;
3709 }
3710
3711 i = 0;
3712 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
3713 if (keyfunc != nullptr) {
3714 PyObject *py_elem;
3715 PyObject *index;
3716
3717 py_elem = BPy_BMElem_CreatePyObject(self->bm, (BMHeader *)ele);
3718 index = PyObject_CallFunctionObjArgs(keyfunc, py_elem, nullptr);
3719 Py_DECREF(py_elem);
3720 if (index == nullptr) {
3721 /* No need to set the exception here,
3722 * PyObject_CallFunctionObjArgs() does that */
3723 PyMem_FREE(keys);
3724 return nullptr;
3725 }
3726
3727 if ((keys[i] = PyFloat_AsDouble(index)) == -1 && PyErr_Occurred()) {
3728 PyErr_SetString(PyExc_ValueError,
3729 "the value returned by the 'key' function is not a number");
3730 Py_DECREF(index);
3731 PyMem_FREE(keys);
3732 return nullptr;
3733 }
3734
3735 Py_DECREF(index);
3736 }
3737 else {
3738 /* If the 'key' function is not provided we sort
3739 * according to the current index values */
3740 keys[i] = ele->head.index;
3741 }
3742
3743 i++;
3744 }
3745
3746 elem_idx = static_cast<int *>(PyMem_MALLOC(sizeof(*elem_idx) * n_elem));
3747 if (elem_idx == nullptr) {
3748 PyErr_NoMemory();
3749 PyMem_FREE(keys);
3750 return nullptr;
3751 }
3752
3753 /* Initialize the element index array */
3754 range_vn_i(elem_idx, n_elem, 0);
3755
3756 /* Sort the index array according to the order of the 'keys' array */
3757 if (do_reverse) {
3758 elem_idx_compare_by_keys = bpy_bmelemseq_sort_cmp_by_keys_descending;
3759 }
3760 else {
3761 elem_idx_compare_by_keys = bpy_bmelemseq_sort_cmp_by_keys_ascending;
3762 }
3763
3764 BLI_qsort_r(elem_idx, n_elem, sizeof(*elem_idx), elem_idx_compare_by_keys, keys);
3765
3766 elem_map_idx = static_cast<uint *>(PyMem_MALLOC(sizeof(*elem_map_idx) * n_elem));
3767 if (elem_map_idx == nullptr) {
3768 PyErr_NoMemory();
3769 PyMem_FREE(elem_idx);
3770 PyMem_FREE(keys);
3771 return nullptr;
3772 }
3773
3774 /* Initialize the map array
3775 *
3776 * We need to know the index such that if used as the new_index in
3777 * BM_mesh_remap() will give the order of the sorted keys like in
3778 * elem_idx */
3779 for (i = 0; i < n_elem; i++) {
3780 elem_map_idx[elem_idx[i]] = i;
3781 }
3782
3783 switch ((BMIterType)self->itype) {
3784 case BM_VERTS_OF_MESH:
3785 vert_idx = elem_map_idx;
3786 break;
3787 case BM_EDGES_OF_MESH:
3788 edge_idx = elem_map_idx;
3789 break;
3790 case BM_FACES_OF_MESH:
3791 face_idx = elem_map_idx;
3792 break;
3793 default:
3794 PyErr_Format(PyExc_TypeError, "element type %d not supported", self->itype);
3795 PyMem_FREE(elem_map_idx);
3796 PyMem_FREE(elem_idx);
3797 PyMem_FREE(keys);
3798 return nullptr;
3799 }
3800
3801 BM_mesh_remap(bm, vert_idx, edge_idx, face_idx);
3802
3803 PyMem_FREE(elem_map_idx);
3804 PyMem_FREE(elem_idx);
3805 PyMem_FREE(keys);
3806
3807 Py_RETURN_NONE;
3808}
3809
3810#ifdef __GNUC__
3811# ifdef __clang__
3812# pragma clang diagnostic push
3813# pragma clang diagnostic ignored "-Wcast-function-type"
3814# else
3815# pragma GCC diagnostic push
3816# pragma GCC diagnostic ignored "-Wcast-function-type"
3817# endif
3818#endif
3819
3820static PyMethodDef bpy_bmesh_methods[] = {
3821 /* utility */
3822 {"copy", (PyCFunction)bpy_bmesh_copy, METH_NOARGS, bpy_bmesh_copy_doc},
3823 {"clear", (PyCFunction)bpy_bmesh_clear, METH_NOARGS, bpy_bmesh_clear_doc},
3824 {"free", (PyCFunction)bpy_bmesh_free, METH_NOARGS, bpy_bmesh_free_doc},
3825
3826 /* conversion */
3827 {"from_object",
3828 (PyCFunction)bpy_bmesh_from_object,
3829 METH_VARARGS | METH_KEYWORDS,
3830 bpy_bmesh_from_object_doc},
3831 {"from_mesh",
3832 (PyCFunction)bpy_bmesh_from_mesh,
3833 METH_VARARGS | METH_KEYWORDS,
3834 bpy_bmesh_from_mesh_doc},
3835 {"to_mesh", (PyCFunction)bpy_bmesh_to_mesh, METH_VARARGS, bpy_bmesh_to_mesh_doc},
3836
3837 /* Mesh select methods. */
3838 {"select_flush_mode",
3839 (PyCFunction)bpy_bmesh_select_flush_mode,
3840 METH_VARARGS | METH_KEYWORDS,
3841 bpy_bmesh_select_flush_mode_doc},
3842 {"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc},
3843
3844 /* UV select methods. */
3845 {"uv_select_flush_mode",
3846 (PyCFunction)bpy_bmesh_uv_select_flush_mode,
3847 METH_VARARGS | METH_KEYWORDS,
3848 bpy_bmesh_uv_select_flush_mode_doc},
3849 {"uv_select_flush",
3850 (PyCFunction)bpy_bmesh_uv_select_flush,
3851 METH_O,
3852 bpy_bmesh_uv_select_flush_doc},
3853 {"uv_select_flush_shared",
3855 METH_O,
3856 bpy_bmesh_uv_select_flush_shared_doc},
3857
3858 {"uv_select_sync_from_mesh",
3860 METH_VARARGS | METH_KEYWORDS,
3861 bpy_bmesh_uv_select_sync_from_mesh_doc},
3862 {"uv_select_sync_to_mesh",
3864 METH_NOARGS,
3865 bpy_bmesh_uv_select_sync_to_mesh_doc},
3866 {"uv_select_foreach_set",
3868 METH_VARARGS | METH_KEYWORDS,
3869 bpy_bmesh_uv_select_foreach_set_doc},
3870 {"uv_select_foreach_set_from_mesh",
3872 METH_VARARGS | METH_KEYWORDS,
3873 bpy_bmesh_uv_select_foreach_set_from_mesh_doc},
3874
3875 /* meshdata */
3876 {"normal_update",
3877 (PyCFunction)bpy_bmesh_normal_update,
3878 METH_NOARGS,
3879 bpy_bmesh_normal_update_doc},
3880 {"transform",
3881 (PyCFunction)bpy_bmesh_transform,
3882 METH_VARARGS | METH_KEYWORDS,
3883 bpy_bmesh_transform_doc},
3884
3885 /* calculations */
3886 {"calc_volume",
3887 (PyCFunction)bpy_bmesh_calc_volume,
3888 METH_VARARGS | METH_KEYWORDS,
3889 bpy_bmesh_calc_volume_doc},
3890 {"calc_loop_triangles",
3891 (PyCFunction)bpy_bmesh_calc_loop_triangles,
3892 METH_NOARGS,
3893 bpy_bmesh_calc_loop_triangles_doc},
3894 {nullptr, nullptr, 0, nullptr},
3895};
3896
3897static PyMethodDef bpy_bmvert_methods[] = {
3898 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3899 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3900 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3901 {"copy_from_face_interp",
3903 METH_VARARGS,
3904 bpy_bmvert_copy_from_face_interp_doc},
3905 {"copy_from_vert_interp",
3907 METH_VARARGS,
3908 bpy_bmvert_copy_from_vert_interp_doc},
3909
3910 {"calc_edge_angle",
3911 (PyCFunction)bpy_bmvert_calc_edge_angle,
3912 METH_VARARGS,
3913 bpy_bmvert_calc_edge_angle_doc},
3914 {"calc_shell_factor",
3915 (PyCFunction)bpy_bmvert_calc_shell_factor,
3916 METH_NOARGS,
3917 bpy_bmvert_calc_shell_factor_doc},
3918
3919 {"normal_update",
3920 (PyCFunction)bpy_bmvert_normal_update,
3921 METH_NOARGS,
3922 bpy_bmvert_normal_update_doc},
3923
3924 {nullptr, nullptr, 0, nullptr},
3925};
3926
3927static PyMethodDef bpy_bmedge_methods[] = {
3928 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3929 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3930 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3931
3932 {"other_vert", (PyCFunction)bpy_bmedge_other_vert, METH_O, bpy_bmedge_other_vert_doc},
3933
3934 {"calc_length", (PyCFunction)bpy_bmedge_calc_length, METH_NOARGS, bpy_bmedge_calc_length_doc},
3935 {"calc_face_angle",
3936 (PyCFunction)bpy_bmedge_calc_face_angle,
3937 METH_VARARGS,
3938 bpy_bmedge_calc_face_angle_doc},
3939 {"calc_face_angle_signed",
3941 METH_VARARGS,
3942 bpy_bmedge_calc_face_angle_signed_doc},
3943 {"calc_tangent",
3944 (PyCFunction)bpy_bmedge_calc_tangent,
3945 METH_VARARGS,
3946 bpy_bmedge_calc_tangent_doc},
3947
3948 {"normal_update",
3949 (PyCFunction)bpy_bmedge_normal_update,
3950 METH_NOARGS,
3951 bpy_bmedge_normal_update_doc},
3952
3953 {nullptr, nullptr, 0, nullptr},
3954};
3955
3956static PyMethodDef bpy_bmface_methods[] = {
3957 {"select_set", (PyCFunction)bpy_bm_elem_select_set, METH_O, bpy_bm_elem_select_set_doc},
3958 {"hide_set", (PyCFunction)bpy_bm_elem_hide_set, METH_O, bpy_bm_elem_hide_set_doc},
3959
3960 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
3961 {"copy_from_face_interp",
3963 METH_VARARGS,
3964 bpy_bmface_copy_from_face_interp_doc},
3965
3966 {"copy", (PyCFunction)bpy_bmface_copy, METH_VARARGS | METH_KEYWORDS, bpy_bmface_copy_doc},
3967
3968 {"uv_select_set", (PyCFunction)bpy_bmface_uv_select_set, METH_O, bpy_bmface_uv_select_set_doc},
3969
3970 {"calc_area", (PyCFunction)bpy_bmface_calc_area, METH_NOARGS, bpy_bmface_calc_area_doc},
3971 {"calc_perimeter",
3972 (PyCFunction)bpy_bmface_calc_perimeter,
3973 METH_NOARGS,
3974 bpy_bmface_calc_perimeter_doc},
3975 {"calc_tangent_edge",
3976 (PyCFunction)bpy_bmface_calc_tangent_edge,
3977 METH_NOARGS,
3978 bpy_bmface_calc_tangent_edge_doc},
3979 {"calc_tangent_edge_pair",
3981 METH_NOARGS,
3982 bpy_bmface_calc_tangent_edge_pair_doc},
3983 {"calc_tangent_edge_diagonal",
3985 METH_NOARGS,
3986 bpy_bmface_calc_tangent_edge_diagonal_doc},
3987 {"calc_tangent_vert_diagonal",
3989 METH_NOARGS,
3990 bpy_bmface_calc_tangent_vert_diagonal_doc},
3991 {"calc_center_median",
3992 (PyCFunction)bpy_bmface_calc_center_mean,
3993 METH_NOARGS,
3994 bpy_bmface_calc_center_median_doc},
3995 {"calc_center_median_weighted",
3997 METH_NOARGS,
3998 bpy_bmface_calc_center_median_weighted_doc},
3999 {"calc_center_bounds",
4000 (PyCFunction)bpy_bmface_calc_center_bounds,
4001 METH_NOARGS,
4002 bpy_bmface_calc_center_bounds_doc},
4003
4004 {"normal_update",
4005 (PyCFunction)bpy_bmface_normal_update,
4006 METH_NOARGS,
4007 bpy_bmface_normal_update_doc},
4008 {"normal_flip", (PyCFunction)bpy_bmface_normal_flip, METH_NOARGS, bpy_bmface_normal_flip_doc},
4009
4010 {nullptr, nullptr, 0, nullptr},
4011};
4012
4013static PyMethodDef bpy_bmloop_methods[] = {
4014 {"copy_from", (PyCFunction)bpy_bm_elem_copy_from, METH_O, bpy_bm_elem_copy_from_doc},
4015 {"copy_from_face_interp",
4017 METH_VARARGS,
4018 bpy_bmloop_copy_from_face_interp_doc},
4019
4020 {"uv_select_vert_set",
4021 (PyCFunction)bpy_bmloop_uv_select_vert_set,
4022 METH_O,
4023 bpy_bmloop_uv_select_vert_set_doc},
4024 {"uv_select_edge_set",
4025 (PyCFunction)bpy_bmloop_uv_select_edge_set,
4026 METH_O,
4027 bpy_bmloop_uv_select_edge_set_doc},
4028
4029 {"calc_angle", (PyCFunction)bpy_bmloop_calc_angle, METH_NOARGS, bpy_bmloop_calc_angle_doc},
4030 {"calc_normal", (PyCFunction)bpy_bmloop_calc_normal, METH_NOARGS, bpy_bmloop_calc_normal_doc},
4031 {"calc_tangent",
4032 (PyCFunction)bpy_bmloop_calc_tangent,
4033 METH_NOARGS,
4034 bpy_bmloop_calc_tangent_doc},
4035 {nullptr, nullptr, 0, nullptr},
4036};
4037
4038static PyMethodDef bpy_bmelemseq_methods[] = {
4039 /* odd function, initializes index values */
4040 {"index_update",
4041 (PyCFunction)bpy_bmelemseq_index_update,
4042 METH_NOARGS,
4043 bpy_bmelemseq_index_update_doc},
4044 {nullptr, nullptr, 0, nullptr},
4045};
4046
4047static PyMethodDef bpy_bmvertseq_methods[] = {
4048 {"new", (PyCFunction)bpy_bmvertseq_new, METH_VARARGS, bpy_bmvertseq_new_doc},
4049 {"remove", (PyCFunction)bpy_bmvertseq_remove, METH_O, bpy_bmvertseq_remove_doc},
4050
4051 /* odd function, initializes index values */
4052 {"index_update",
4053 (PyCFunction)bpy_bmelemseq_index_update,
4054 METH_NOARGS,
4055 bpy_bmelemseq_index_update_doc},
4056 {"ensure_lookup_table",
4058 METH_NOARGS,
4059 bpy_bmelemseq_ensure_lookup_table_doc},
4060 {"sort",
4061 (PyCFunction)bpy_bmelemseq_sort,
4062 METH_VARARGS | METH_KEYWORDS,
4063 bpy_bmelemseq_sort_doc},
4064 {nullptr, nullptr, 0, nullptr},
4065};
4066
4067static PyMethodDef bpy_bmedgeseq_methods[] = {
4068 {"new", (PyCFunction)bpy_bmedgeseq_new, METH_VARARGS, bpy_bmedgeseq_new_doc},
4069 {"remove", (PyCFunction)bpy_bmedgeseq_remove, METH_O, bpy_bmedgeseq_remove_doc},
4070 /* 'bpy_bmelemseq_get' for different purpose */
4071 {"get", (PyCFunction)bpy_bmedgeseq_get__method, METH_VARARGS, bpy_bmedgeseq_get__method_doc},
4072
4073 /* odd function, initializes index values */
4074 {"index_update",
4075 (PyCFunction)bpy_bmelemseq_index_update,
4076 METH_NOARGS,
4077 bpy_bmelemseq_index_update_doc},
4078 {"ensure_lookup_table",
4080 METH_NOARGS,
4081 bpy_bmelemseq_ensure_lookup_table_doc},
4082 {"sort",
4083 (PyCFunction)bpy_bmelemseq_sort,
4084 METH_VARARGS | METH_KEYWORDS,
4085 bpy_bmelemseq_sort_doc},
4086 {nullptr, nullptr, 0, nullptr},
4087};
4088
4089static PyMethodDef bpy_bmfaceseq_methods[] = {
4090 {"new", (PyCFunction)bpy_bmfaceseq_new, METH_VARARGS, bpy_bmfaceseq_new_doc},
4091 {"remove", (PyCFunction)bpy_bmfaceseq_remove, METH_O, bpy_bmfaceseq_remove_doc},
4092 /* 'bpy_bmelemseq_get' for different purpose */
4093 {"get", (PyCFunction)bpy_bmfaceseq_get__method, METH_VARARGS, bpy_bmfaceseq_get__method_doc},
4094
4095 /* odd function, initializes index values */
4096 {"index_update",
4097 (PyCFunction)bpy_bmelemseq_index_update,
4098 METH_NOARGS,
4099 bpy_bmelemseq_index_update_doc},
4100 {"ensure_lookup_table",
4102 METH_NOARGS,
4103 bpy_bmelemseq_ensure_lookup_table_doc},
4104 {"sort",
4105 (PyCFunction)bpy_bmelemseq_sort,
4106 METH_VARARGS | METH_KEYWORDS,
4107 bpy_bmelemseq_sort_doc},
4108 {nullptr, nullptr, 0, nullptr},
4109};
4110
4111static PyMethodDef bpy_bmloopseq_methods[] = {
4112 /* odd function, initializes index values */
4113 /* no: index_update() function since we can't iterate over loops */
4114 /* no: sort() function since we can't iterate over loops */
4115 {nullptr, nullptr, 0, nullptr},
4116};
4117
4118#ifdef __GNUC__
4119# ifdef __clang__
4120# pragma clang diagnostic pop
4121# else
4122# pragma GCC diagnostic pop
4123# endif
4124#endif
4125
4126/* Sequences
4127 * ========= */
4128
4129/* BMElemSeq / Iter
4130 * ---------------- */
4131
4132static PyTypeObject *bpy_bm_itype_as_pytype(const char itype)
4133{
4134 /* should cover all types */
4135 switch ((BMIterType)itype) {
4136 case BM_VERTS_OF_MESH:
4137 case BM_VERTS_OF_FACE:
4138 case BM_VERTS_OF_EDGE:
4139 return &BPy_BMVert_Type;
4140
4141 case BM_EDGES_OF_MESH:
4142 case BM_EDGES_OF_FACE:
4143 case BM_EDGES_OF_VERT:
4144 return &BPy_BMEdge_Type;
4145
4146 case BM_FACES_OF_MESH:
4147 case BM_FACES_OF_EDGE:
4148 case BM_FACES_OF_VERT:
4149 return &BPy_BMFace_Type;
4150
4151 // case BM_ALL_LOOPS_OF_FACE:
4152 case BM_LOOPS_OF_FACE:
4153 case BM_LOOPS_OF_EDGE:
4154 case BM_LOOPS_OF_VERT:
4155 case BM_LOOPS_OF_LOOP:
4156 return &BPy_BMLoop_Type;
4157 }
4158
4159 return nullptr;
4160}
4161
4163{
4165
4166 /* first check if the size is known */
4167 switch ((BMIterType)self->itype) {
4168 /* main-types */
4169 case BM_VERTS_OF_MESH:
4170 return self->bm->totvert;
4171 case BM_EDGES_OF_MESH:
4172 return self->bm->totedge;
4173 case BM_FACES_OF_MESH:
4174 return self->bm->totface;
4175
4176 /* sub-types */
4177 case BM_VERTS_OF_FACE:
4178 case BM_EDGES_OF_FACE:
4179 case BM_LOOPS_OF_FACE:
4180 BPY_BM_CHECK_INT(self->py_ele);
4181 return ((BMFace *)self->py_ele->ele)->len;
4182
4183 case BM_VERTS_OF_EDGE:
4184 return 2;
4185
4186 default:
4187 /* quiet compiler */
4188 break;
4189 }
4190
4191 /* loop over all items, avoid this if we can */
4192 {
4193 BMIter iter;
4194 BMHeader *ele;
4195 Py_ssize_t tot = 0;
4196
4197 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
4198 tot++;
4199 }
4200 return tot;
4201 }
4202}
4203
4204static PyObject *bpy_bmelemseq_subscript_int(BPy_BMElemSeq *self, Py_ssize_t keynum)
4205{
4207
4208 if (keynum < 0) {
4209 /* only get length on negative value, may loop entire seq */
4210 keynum += bpy_bmelemseq_length(self);
4211 }
4212 if (keynum >= 0) {
4213 if (self->itype <= BM_FACES_OF_MESH) {
4214 if ((self->bm->elem_table_dirty & bm_iter_itype_htype_map[self->itype]) == 0) {
4215 BMHeader *ele = nullptr;
4216 switch (self->itype) {
4217 case BM_VERTS_OF_MESH:
4218 if (keynum < self->bm->totvert) {
4219 ele = (BMHeader *)self->bm->vtable[keynum];
4220 }
4221 break;
4222 case BM_EDGES_OF_MESH:
4223 if (keynum < self->bm->totedge) {
4224 ele = (BMHeader *)self->bm->etable[keynum];
4225 }
4226 break;
4227 case BM_FACES_OF_MESH:
4228 if (keynum < self->bm->totface) {
4229 ele = (BMHeader *)self->bm->ftable[keynum];
4230 }
4231 break;
4232 }
4233 if (ele) {
4234 return BPy_BMElem_CreatePyObject(self->bm, ele);
4235 }
4236 /* fall through to index error below */
4237 }
4238 else {
4239 PyErr_SetString(PyExc_IndexError,
4240 "BMElemSeq[index]: outdated internal index table, "
4241 "run ensure_lookup_table() first");
4242 return nullptr;
4243 }
4244 }
4245 else {
4246 BMHeader *ele = static_cast<BMHeader *>(BM_iter_at_index(
4247 self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr, keynum));
4248 if (ele) {
4249 return BPy_BMElem_CreatePyObject(self->bm, ele);
4250 }
4251 }
4252 }
4253
4254 PyErr_Format(PyExc_IndexError, "BMElemSeq[index]: index %d out of range", keynum);
4255 return nullptr;
4256}
4257
4259 Py_ssize_t start,
4260 Py_ssize_t stop)
4261{
4262 BMIter iter;
4263 int count = 0;
4264 bool ok;
4265
4266 PyObject *list;
4267 BMHeader *ele;
4268
4270
4271 list = PyList_New(0);
4272
4273 ok = BM_iter_init(&iter, self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr);
4274
4275 BLI_assert(ok == true);
4276
4277 if (UNLIKELY(ok == false)) {
4278 return list;
4279 }
4280
4281 /* first loop up-until the start */
4282 for (ok = true; ok; ok = (BM_iter_step(&iter) != nullptr)) {
4283 if (count == start) {
4284 break;
4285 }
4286 count++;
4287 }
4288
4289 /* add items until stop */
4290 while ((ele = static_cast<BMHeader *>(BM_iter_step(&iter)))) {
4291 PyList_APPEND(list, BPy_BMElem_CreatePyObject(self->bm, ele));
4292
4293 count++;
4294 if (count == stop) {
4295 break;
4296 }
4297 }
4298
4299 return list;
4300}
4301
4302static PyObject *bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key)
4303{
4304 /* don't need error check here */
4305 if (PyIndex_Check(key)) {
4306 const Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
4307 if (i == -1 && PyErr_Occurred()) {
4308 return nullptr;
4309 }
4311 }
4312 if (PySlice_Check(key)) {
4313 PySliceObject *key_slice = (PySliceObject *)key;
4314 Py_ssize_t step = 1;
4315
4316 if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
4317 return nullptr;
4318 }
4319 if (step != 1) {
4320 PyErr_SetString(PyExc_TypeError, "BMElemSeq[slice]: slice steps not supported");
4321 return nullptr;
4322 }
4323 if (key_slice->start == Py_None && key_slice->stop == Py_None) {
4324 return bpy_bmelemseq_subscript_slice(self, 0, PY_SSIZE_T_MAX);
4325 }
4326
4327 Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
4328
4329 /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
4330 if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) {
4331 return nullptr;
4332 }
4333 if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop)) {
4334 return nullptr;
4335 }
4336
4337 if (start < 0 || stop < 0) {
4338 /* only get the length for negative values */
4339 const Py_ssize_t len = bpy_bmelemseq_length(self);
4340 if (start < 0) {
4341 start += len;
4342 CLAMP_MIN(start, 0);
4343 }
4344 if (stop < 0) {
4345 stop += len;
4346 CLAMP_MIN(stop, 0);
4347 }
4348 }
4349
4350 if (stop - start <= 0) {
4351 return PyList_New(0);
4352 }
4353
4354 return bpy_bmelemseq_subscript_slice(self, start, stop);
4355 }
4356
4357 PyErr_SetString(PyExc_AttributeError, "BMElemSeq[key]: invalid key, key must be an int");
4358 return nullptr;
4359}
4360
4361static int bpy_bmelemseq_contains(BPy_BMElemSeq *self, PyObject *value)
4362{
4364
4365 if (Py_TYPE(value) == bpy_bm_itype_as_pytype(self->itype)) {
4366 BPy_BMElem *value_bm_ele = (BPy_BMElem *)value;
4367 if (value_bm_ele->bm == self->bm) {
4368 BMElem *ele, *ele_test = value_bm_ele->ele;
4369 BMIter iter;
4370 BM_ITER_BPY_BM_SEQ (ele, &iter, self) {
4371 if (ele == ele_test) {
4372 return 1;
4373 }
4374 }
4375 }
4376 }
4377
4378 return 0;
4379}
4380
4381/* BMElem (customdata)
4382 * ------------------- */
4383
4385{
4387
4388 return BPy_BMLayerItem_GetItem(self, key);
4389}
4390
4391static int bpy_bmelem_ass_subscript(BPy_BMElem *self, BPy_BMLayerItem *key, PyObject *value)
4392{
4394
4395 return BPy_BMLayerItem_SetItem(self, key, value);
4396}
4397
4398static PySequenceMethods bpy_bmelemseq_as_sequence = {
4399 /*sq_length*/ (lenfunc)bpy_bmelemseq_length,
4400 /*sq_concat*/ nullptr,
4401 /*sq_repeat*/ nullptr,
4402 /* Only set this so `PySequence_Check()` returns True. */
4403 /*sq_item*/ (ssizeargfunc)bpy_bmelemseq_subscript_int,
4404 /*was_sq_slice*/ nullptr,
4405 /*sq_ass_item*/ nullptr,
4406 /*was_sq_ass_slice*/ nullptr,
4407 /*sq_contains*/ (objobjproc)bpy_bmelemseq_contains,
4408 /*sq_inplace_concat*/ nullptr,
4409 /*sq_inplace_repeat*/ nullptr,
4410};
4411
4412static PyMappingMethods bpy_bmelemseq_as_mapping = {
4413 /*mp_length*/ (lenfunc)bpy_bmelemseq_length,
4414 /*mp_subscript*/ (binaryfunc)bpy_bmelemseq_subscript,
4415 /*mp_ass_subscript*/ (objobjargproc) nullptr,
4416};
4417
4418/* for customdata access */
4419static PyMappingMethods bpy_bm_elem_as_mapping = {
4420 /*mp_length*/ (lenfunc) nullptr, /* Keep this empty, messes up `if elem: ...` test. */
4421 /*mp_subscript*/ (binaryfunc)bpy_bmelem_subscript,
4422 /*mp_ass_subscript*/ (objobjargproc)bpy_bmelem_ass_subscript,
4423};
4424
4425/* Iterator
4426 * -------- */
4427
4429{
4430 BPy_BMIter *py_iter;
4431
4433 py_iter = (BPy_BMIter *)BPy_BMIter_CreatePyObject(self->bm);
4435 &(py_iter->iter), self->bm, self->itype, self->py_ele ? self->py_ele->ele : nullptr);
4436 return (PyObject *)py_iter;
4437}
4438
4440{
4441 BMHeader *ele = static_cast<BMHeader *>(BM_iter_step(&self->iter));
4442 if (ele == nullptr) {
4443 PyErr_SetNone(PyExc_StopIteration);
4444 return nullptr;
4445 }
4446
4447 return BPy_BMElem_CreatePyObject(self->bm, ele);
4448}
4449
4450/* Deallocate Functions
4451 * ==================== */
4452
4454{
4455 BMesh *bm = self->bm;
4456
4457 /* The mesh has not been freed by #BMesh. */
4458 if (bm) {
4460
4463 }
4466 }
4469 }
4472 }
4473
4474 bm->py_handle = nullptr;
4475
4476 if ((self->flag & BPY_BMFLAG_IS_WRAPPED) == 0) {
4478 }
4479 }
4480
4481 PyObject_DEL(self);
4482}
4483
4485{
4486 BMesh *bm = self->bm;
4487 if (bm) {
4488 void **ptr = static_cast<void **>(
4489 CustomData_bmesh_get(&bm->vdata, self->ele->head.data, CD_BM_ELEM_PYPTR));
4490 if (ptr) {
4491 *ptr = nullptr;
4492 }
4493 }
4494 PyObject_DEL(self);
4495}
4496
4498{
4499 BMesh *bm = self->bm;
4500 if (bm) {
4501 void **ptr = static_cast<void **>(
4502 CustomData_bmesh_get(&bm->edata, self->ele->head.data, CD_BM_ELEM_PYPTR));
4503 if (ptr) {
4504 *ptr = nullptr;
4505 }
4506 }
4507 PyObject_DEL(self);
4508}
4509
4511{
4512 BMesh *bm = self->bm;
4513 if (bm) {
4514 void **ptr = static_cast<void **>(
4515 CustomData_bmesh_get(&bm->pdata, self->ele->head.data, CD_BM_ELEM_PYPTR));
4516 if (ptr) {
4517 *ptr = nullptr;
4518 }
4519 }
4520 PyObject_DEL(self);
4521}
4522
4524{
4525 BMesh *bm = self->bm;
4526 if (bm) {
4527 void **ptr = static_cast<void **>(
4528 CustomData_bmesh_get(&bm->ldata, self->ele->head.data, CD_BM_ELEM_PYPTR));
4529 if (ptr) {
4530 *ptr = nullptr;
4531 }
4532 }
4533 PyObject_DEL(self);
4534}
4535
4537{
4538 Py_XDECREF(self->py_ele);
4539
4540 PyObject_DEL(self);
4541}
4542
4543/* not sure where this should go */
4544static Py_hash_t bpy_bm_elem_hash(PyObject *self)
4545{
4546 return Py_HashPointer(((BPy_BMElem *)self)->ele);
4547}
4548
4549static Py_hash_t bpy_bm_hash(PyObject *self)
4550{
4551 return Py_HashPointer(((BPy_BMesh *)self)->bm);
4552}
4553
4554/* Type Doc-strings
4555 * ================ */
4556
4558 /* Wrap. */
4559 bpy_bmesh_doc,
4560 "The BMesh data structure\n");
4562 /* Wrap. */
4563 bpy_bmvert_doc,
4564 "The BMesh vertex type\n");
4566 /* Wrap. */
4567 bpy_bmedge_doc,
4568 "The BMesh edge connecting 2 verts\n");
4570 /* Wrap. */
4571 bpy_bmface_doc,
4572 "The BMesh face with 3 or more sides\n");
4574 /* Wrap. */
4575 bpy_bmloop_doc,
4576 "This is normally accessed from :class:`bmesh.types.BMFace.loops` where each face loop "
4577 "represents a corner of the face.\n");
4579 /* Wrap. */
4580 bpy_bmelemseq_doc,
4581 "General sequence type used for accessing any sequence of\n"
4582 ":class:`bmesh.types.BMVert`, "
4583 ":class:`bmesh.types.BMEdge`, "
4584 ":class:`bmesh.types.BMFace`, "
4585 ":class:`bmesh.types.BMLoop`.\n"
4586 "\n"
4587 "When accessed via "
4588 ":class:`bmesh.types.BMesh.verts`, "
4589 ":class:`bmesh.types.BMesh.edges`, "
4590 ":class:`bmesh.types.BMesh.faces`\n"
4591 "there are also functions to create/remove items.\n");
4593 /* Wrap. */
4594 bpy_bmiter_doc,
4595 "Internal BMesh type for looping over verts/faces/edges,\n"
4596 "used for iterating over :class:`bmesh.types.BMElemSeq` types.\n");
4597
4599{
4600 BMesh *bm = self->bm;
4601
4602 if (bm) {
4603 return PyUnicode_FromFormat("<BMesh(%p), totvert=%d, totedge=%d, totface=%d, totloop=%d>",
4604 bm,
4605 bm->totvert,
4606 bm->totedge,
4607 bm->totface,
4608 bm->totloop);
4609 }
4610
4611 return PyUnicode_FromFormat("<BMesh dead at %p>", self);
4612}
4613
4615{
4616 BMesh *bm = self->bm;
4617
4618 if (bm) {
4619 BMVert *v = self->v;
4620 return PyUnicode_FromFormat("<BMVert(%p), index=%d>", v, BM_elem_index_get(v));
4621 }
4622
4623 return PyUnicode_FromFormat("<BMVert dead at %p>", self);
4624}
4625
4627{
4628 BMesh *bm = self->bm;
4629
4630 if (bm) {
4631 BMEdge *e = self->e;
4632 return PyUnicode_FromFormat("<BMEdge(%p), index=%d, verts=(%p/%d, %p/%d)>",
4633 e,
4635 e->v1,
4636 BM_elem_index_get(e->v1),
4637 e->v2,
4638 BM_elem_index_get(e->v2));
4639 }
4640
4641 return PyUnicode_FromFormat("<BMEdge dead at %p>", self);
4642}
4643
4645{
4646 BMesh *bm = self->bm;
4647
4648 if (bm) {
4649 BMFace *f = self->f;
4650 return PyUnicode_FromFormat(
4651 "<BMFace(%p), index=%d, totverts=%d>", f, BM_elem_index_get(f), f->len);
4652 }
4653
4654 return PyUnicode_FromFormat("<BMFace dead at %p>", self);
4655}
4656
4658{
4659 BMesh *bm = self->bm;
4660
4661 if (bm) {
4662 BMLoop *l = self->l;
4663 return PyUnicode_FromFormat("<BMLoop(%p), index=%d, vert=%p/%d, edge=%p/%d, face=%p/%d>",
4664 l,
4666 l->v,
4667 BM_elem_index_get(l->v),
4668 l->e,
4669 BM_elem_index_get(l->e),
4670 l->f,
4671 BM_elem_index_get(l->f));
4672 }
4673
4674 return PyUnicode_FromFormat("<BMLoop dead at %p>", self);
4675}
4676
4677/* Types
4678 * ===== */
4679
4680PyTypeObject BPy_BMesh_Type;
4681PyTypeObject BPy_BMVert_Type;
4682PyTypeObject BPy_BMEdge_Type;
4683PyTypeObject BPy_BMFace_Type;
4684PyTypeObject BPy_BMLoop_Type;
4690PyTypeObject BPy_BMIter_Type;
4691
4693{
4694 BPy_BMesh_Type.tp_basicsize = sizeof(BPy_BMesh);
4695 BPy_BMVert_Type.tp_basicsize = sizeof(BPy_BMVert);
4696 BPy_BMEdge_Type.tp_basicsize = sizeof(BPy_BMEdge);
4697 BPy_BMFace_Type.tp_basicsize = sizeof(BPy_BMFace);
4698 BPy_BMLoop_Type.tp_basicsize = sizeof(BPy_BMLoop);
4699 BPy_BMElemSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
4700 BPy_BMVertSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
4701 BPy_BMEdgeSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
4702 BPy_BMFaceSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
4703 BPy_BMLoopSeq_Type.tp_basicsize = sizeof(BPy_BMElemSeq);
4704 BPy_BMIter_Type.tp_basicsize = sizeof(BPy_BMIter);
4705
4706 BPy_BMesh_Type.tp_name = "BMesh";
4707 BPy_BMVert_Type.tp_name = "BMVert";
4708 BPy_BMEdge_Type.tp_name = "BMEdge";
4709 BPy_BMFace_Type.tp_name = "BMFace";
4710 BPy_BMLoop_Type.tp_name = "BMLoop";
4711 BPy_BMElemSeq_Type.tp_name = "BMElemSeq";
4712 BPy_BMVertSeq_Type.tp_name = "BMVertSeq";
4713 BPy_BMEdgeSeq_Type.tp_name = "BMEdgeSeq";
4714 BPy_BMFaceSeq_Type.tp_name = "BMFaceSeq";
4715 BPy_BMLoopSeq_Type.tp_name = "BMLoopSeq";
4716 BPy_BMIter_Type.tp_name = "BMIter";
4717
4718 BPy_BMesh_Type.tp_doc = bpy_bmesh_doc;
4719 BPy_BMVert_Type.tp_doc = bpy_bmvert_doc;
4720 BPy_BMEdge_Type.tp_doc = bpy_bmedge_doc;
4721 BPy_BMFace_Type.tp_doc = bpy_bmface_doc;
4722 BPy_BMLoop_Type.tp_doc = bpy_bmloop_doc;
4723 BPy_BMElemSeq_Type.tp_doc = bpy_bmelemseq_doc;
4724 BPy_BMVertSeq_Type.tp_doc = nullptr;
4725 BPy_BMEdgeSeq_Type.tp_doc = nullptr;
4726 BPy_BMFaceSeq_Type.tp_doc = nullptr;
4727 BPy_BMLoopSeq_Type.tp_doc = nullptr;
4728 BPy_BMIter_Type.tp_doc = bpy_bmiter_doc;
4729
4730 BPy_BMesh_Type.tp_repr = (reprfunc)bpy_bmesh_repr;
4731 BPy_BMVert_Type.tp_repr = (reprfunc)bpy_bmvert_repr;
4732 BPy_BMEdge_Type.tp_repr = (reprfunc)bpy_bmedge_repr;
4733 BPy_BMFace_Type.tp_repr = (reprfunc)bpy_bmface_repr;
4734 BPy_BMLoop_Type.tp_repr = (reprfunc)bpy_bmloop_repr;
4735 BPy_BMElemSeq_Type.tp_repr = nullptr;
4736 BPy_BMVertSeq_Type.tp_repr = nullptr;
4737 BPy_BMEdgeSeq_Type.tp_repr = nullptr;
4738 BPy_BMFaceSeq_Type.tp_repr = nullptr;
4739 BPy_BMLoopSeq_Type.tp_repr = nullptr;
4740 BPy_BMIter_Type.tp_repr = nullptr;
4741
4747 BPy_BMElemSeq_Type.tp_getset = nullptr;
4752 BPy_BMIter_Type.tp_getset = nullptr;
4753
4754 BPy_BMesh_Type.tp_methods = bpy_bmesh_methods;
4764 BPy_BMIter_Type.tp_methods = nullptr;
4765
4766 /* #BPy_BMElem_Check() uses #bpy_bm_elem_hash() to check types.
4767 * if this changes update the macro. */
4768 BPy_BMesh_Type.tp_hash = bpy_bm_hash;
4773 BPy_BMElemSeq_Type.tp_hash = nullptr;
4774 BPy_BMVertSeq_Type.tp_hash = nullptr;
4775 BPy_BMEdgeSeq_Type.tp_hash = nullptr;
4776 BPy_BMFaceSeq_Type.tp_hash = nullptr;
4777 BPy_BMLoopSeq_Type.tp_hash = nullptr;
4778 BPy_BMIter_Type.tp_hash = nullptr;
4779
4784 BPy_BMLoopSeq_Type.tp_as_sequence =
4785 nullptr; /* this is not a seq really, only for layer access */
4786
4791 BPy_BMLoopSeq_Type.tp_as_mapping = nullptr; /* this is not a seq really, only for layer access */
4792
4793 /* layer access */
4794 BPy_BMVert_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4795 BPy_BMEdge_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4796 BPy_BMFace_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4797 BPy_BMLoop_Type.tp_as_mapping = &bpy_bm_elem_as_mapping;
4798
4799 BPy_BMElemSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4800 BPy_BMVertSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4801 BPy_BMEdgeSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4802 BPy_BMFaceSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter;
4803 BPy_BMLoopSeq_Type.tp_iter = nullptr; /* no mapping */
4804
4805 /* Only 1 iterator so far. */
4806 BPy_BMIter_Type.tp_iternext = (iternextfunc)bpy_bmiter_next;
4807 BPy_BMIter_Type.tp_iter = PyObject_SelfIter;
4808
4809 BPy_BMesh_Type.tp_dealloc = (destructor)bpy_bmesh_dealloc;
4810 BPy_BMVert_Type.tp_dealloc = (destructor)bpy_bmvert_dealloc;
4811 BPy_BMEdge_Type.tp_dealloc = (destructor)bpy_bmedge_dealloc;
4812 BPy_BMFace_Type.tp_dealloc = (destructor)bpy_bmface_dealloc;
4813 BPy_BMLoop_Type.tp_dealloc = (destructor)bpy_bmloop_dealloc;
4814 BPy_BMElemSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4815 BPy_BMVertSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4816 BPy_BMEdgeSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4817 BPy_BMFaceSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4818 BPy_BMLoopSeq_Type.tp_dealloc = (destructor)bpy_bmelemseq_dealloc;
4819 BPy_BMIter_Type.tp_dealloc = nullptr;
4820
4821 BPy_BMesh_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4822 BPy_BMVert_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4823 BPy_BMEdge_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4824 BPy_BMFace_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4825 BPy_BMLoop_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4826 BPy_BMElemSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4827 BPy_BMVertSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4828 BPy_BMEdgeSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4829 BPy_BMFaceSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4830 BPy_BMLoopSeq_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4831 BPy_BMIter_Type.tp_flags = Py_TPFLAGS_DEFAULT;
4832
4833 PyType_Ready(&BPy_BMesh_Type);
4834 PyType_Ready(&BPy_BMVert_Type);
4835 PyType_Ready(&BPy_BMEdge_Type);
4836 PyType_Ready(&BPy_BMFace_Type);
4837 PyType_Ready(&BPy_BMLoop_Type);
4838 PyType_Ready(&BPy_BMElemSeq_Type);
4839 PyType_Ready(&BPy_BMVertSeq_Type);
4840 PyType_Ready(&BPy_BMEdgeSeq_Type);
4841 PyType_Ready(&BPy_BMFaceSeq_Type);
4842 PyType_Ready(&BPy_BMLoopSeq_Type);
4843 PyType_Ready(&BPy_BMIter_Type);
4844}
4845
4846/* bmesh.types submodule
4847 * ********************* */
4848
4849/* This exists to declare substitutions. */
4851 /* Wrap. */
4852 BPy_BM_types_module_doc,
4853 "\n"
4854 ".. |UV_STICKY_SELECT_MODE_REF| replace:: "
4855 "(:class:`bpy.types.ToolSettings.uv_sticky_select_mode` which may be passed in directly).\n"
4856 "\n"
4857 ".. |UV_STICKY_SELECT_MODE_TYPE| replace:: "
4858 "Literal['SHARED_LOCATION', 'DISABLED', 'SHARED_VERTEX']\n"
4859 "\n"
4860 ".. |UV_SELECT_FLUSH_MODE_NEEDED| replace:: "
4861 "This function selection-mode independent, "
4862 "typically :class:`bmesh.types.BMesh.uv_select_flush_mode` should be called afterwards.\n"
4863 "\n"
4864 ".. |UV_SELECT_SYNC_TO_MESH_NEEDED| replace:: "
4865 "This function doesn't flush the selection to the mesh, "
4866 "typically :class:`bmesh.types.BMesh.uv_select_sync_to_mesh` should be called afterwards.\n");
4867static PyModuleDef BPy_BM_types_module_def = {
4868 /*m_base*/ PyModuleDef_HEAD_INIT,
4869 /*m_name*/ "bmesh.types",
4870 /*m_doc*/ BPy_BM_types_module_doc,
4871 /*m_size*/ 0,
4872 /*m_methods*/ nullptr,
4873 /*m_slots*/ nullptr,
4874 /*m_traverse*/ nullptr,
4875 /*m_clear*/ nullptr,
4876 /*m_free*/ nullptr,
4877};
4878
4880{
4881 PyObject *submodule;
4882
4883 submodule = PyModule_Create(&BPy_BM_types_module_def);
4884
4885 /* `bmesh_py_types.cc` */
4886 PyModule_AddType(submodule, &BPy_BMesh_Type);
4887 PyModule_AddType(submodule, &BPy_BMVert_Type);
4888 PyModule_AddType(submodule, &BPy_BMEdge_Type);
4889 PyModule_AddType(submodule, &BPy_BMFace_Type);
4890 PyModule_AddType(submodule, &BPy_BMLoop_Type);
4891 PyModule_AddType(submodule, &BPy_BMElemSeq_Type);
4892 PyModule_AddType(submodule, &BPy_BMVertSeq_Type);
4893 PyModule_AddType(submodule, &BPy_BMEdgeSeq_Type);
4894 PyModule_AddType(submodule, &BPy_BMFaceSeq_Type);
4895 PyModule_AddType(submodule, &BPy_BMLoopSeq_Type);
4896 PyModule_AddType(submodule, &BPy_BMIter_Type);
4897 /* `bmesh_py_types_select.cc` */
4898 PyModule_AddType(submodule, &BPy_BMEditSelSeq_Type);
4899 PyModule_AddType(submodule, &BPy_BMEditSelIter_Type);
4900 /* `bmesh_py_types_customdata.cc` */
4901 PyModule_AddType(submodule, &BPy_BMLayerAccessVert_Type);
4902 PyModule_AddType(submodule, &BPy_BMLayerAccessEdge_Type);
4903 PyModule_AddType(submodule, &BPy_BMLayerAccessFace_Type);
4904 PyModule_AddType(submodule, &BPy_BMLayerAccessLoop_Type);
4905 PyModule_AddType(submodule, &BPy_BMLayerCollection_Type);
4906 PyModule_AddType(submodule, &BPy_BMLayerItem_Type);
4907 /* `bmesh_py_types_meshdata.cc` */
4908 PyModule_AddType(submodule, &BPy_BMLoopUV_Type);
4909 PyModule_AddType(submodule, &BPy_BMDeformVert_Type);
4910
4911 return submodule;
4912}
4913
4914/* Utility Functions
4915 * ***************** */
4916
4918{
4919 BPy_BMesh *self;
4920
4921 if (bm->py_handle) {
4922 self = static_cast<BPy_BMesh *>(bm->py_handle);
4923 Py_INCREF(self);
4924 }
4925 else {
4926 self = PyObject_New(BPy_BMesh, &BPy_BMesh_Type);
4927 self->bm = bm;
4928 self->flag = flag;
4929
4930 bm->py_handle = self; /* point back */
4931
4932/* avoid allocating layers when we don't have to */
4933#if 0
4938#endif
4939 }
4940
4941 return (PyObject *)self;
4942}
4943
4945{
4947
4948 void **ptr = static_cast<void **>(
4949 CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BM_ELEM_PYPTR));
4950
4951 /* bmesh may free layers, ensure we have one to store ourself */
4952 if (UNLIKELY(ptr == nullptr)) {
4954 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BM_ELEM_PYPTR));
4955 }
4956
4957 if (*ptr != nullptr) {
4958 self = static_cast<BPy_BMVert *>(*ptr);
4959 Py_INCREF(self);
4960 }
4961 else {
4962 self = PyObject_New(BPy_BMVert, &BPy_BMVert_Type);
4963 BLI_assert(v != nullptr);
4964 self->bm = bm;
4965 self->v = v;
4966 *ptr = self;
4967 }
4968 return (PyObject *)self;
4969}
4970
4972{
4974
4975 void **ptr = static_cast<void **>(
4976 CustomData_bmesh_get(&bm->edata, e->head.data, CD_BM_ELEM_PYPTR));
4977
4978 /* bmesh may free layers, ensure we have one to store ourself */
4979 if (UNLIKELY(ptr == nullptr)) {
4981 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->edata, e->head.data, CD_BM_ELEM_PYPTR));
4982 }
4983
4984 if (*ptr != nullptr) {
4985 self = static_cast<BPy_BMEdge *>(*ptr);
4986 Py_INCREF(self);
4987 }
4988 else {
4989 self = PyObject_New(BPy_BMEdge, &BPy_BMEdge_Type);
4990 BLI_assert(e != nullptr);
4991 self->bm = bm;
4992 self->e = e;
4993 *ptr = self;
4994 }
4995 return (PyObject *)self;
4996}
4997
4999{
5001
5002 void **ptr = static_cast<void **>(
5004
5005 /* bmesh may free layers, ensure we have one to store ourself */
5006 if (UNLIKELY(ptr == nullptr)) {
5008 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->pdata, f->head.data, CD_BM_ELEM_PYPTR));
5009 }
5010
5011 if (*ptr != nullptr) {
5012 self = static_cast<BPy_BMFace *>(*ptr);
5013 Py_INCREF(self);
5014 }
5015 else {
5016 self = PyObject_New(BPy_BMFace, &BPy_BMFace_Type);
5017 BLI_assert(f != nullptr);
5018 self->bm = bm;
5019 self->f = f;
5020 *ptr = self;
5021 }
5022 return (PyObject *)self;
5023}
5024
5026{
5028
5029 void **ptr = static_cast<void **>(
5030 CustomData_bmesh_get(&bm->ldata, l->head.data, CD_BM_ELEM_PYPTR));
5031
5032 /* bmesh may free layers, ensure we have one to store ourself */
5033 if (UNLIKELY(ptr == nullptr)) {
5035 ptr = static_cast<void **>(CustomData_bmesh_get(&bm->ldata, l->head.data, CD_BM_ELEM_PYPTR));
5036 }
5037
5038 if (*ptr != nullptr) {
5039 self = static_cast<BPy_BMLoop *>(*ptr);
5040 Py_INCREF(self);
5041 }
5042 else {
5043 self = PyObject_New(BPy_BMLoop, &BPy_BMLoop_Type);
5044 BLI_assert(l != nullptr);
5045 self->bm = bm;
5046 self->l = l;
5047 *ptr = self;
5048 }
5049 return (PyObject *)self;
5050}
5051
5052PyObject *BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype)
5053{
5055 self->bm = bm;
5056 self->py_ele = py_ele; /* can be nullptr */
5057 self->itype = itype;
5058 Py_XINCREF(py_ele);
5059 return (PyObject *)self;
5060}
5061
5063{
5065 self->bm = bm;
5066 self->py_ele = nullptr; /* unused */
5067 self->itype = BM_VERTS_OF_MESH;
5068 return (PyObject *)self;
5069}
5070
5072{
5074 self->bm = bm;
5075 self->py_ele = nullptr; /* unused */
5076 self->itype = BM_EDGES_OF_MESH;
5077 return (PyObject *)self;
5078}
5079
5081{
5083 self->bm = bm;
5084 self->py_ele = nullptr; /* unused */
5085 self->itype = BM_FACES_OF_MESH;
5086 return (PyObject *)self;
5087}
5088
5090{
5092 self->bm = bm;
5093 self->py_ele = nullptr; /* unused */
5094 self->itype = 0; /* should never be passed to the iterator function */
5095 return (PyObject *)self;
5096}
5097
5099{
5100 BPy_BMIter *self = PyObject_New(BPy_BMIter, &BPy_BMIter_Type);
5101 self->bm = bm;
5102 /* caller must initialize 'iter' member */
5103 return (PyObject *)self;
5104}
5105
5107{
5108 switch (ele->htype) {
5109 case BM_VERT:
5110 return BPy_BMVert_CreatePyObject(bm, (BMVert *)ele);
5111 case BM_EDGE:
5112 return BPy_BMEdge_CreatePyObject(bm, (BMEdge *)ele);
5113 case BM_FACE:
5114 return BPy_BMFace_CreatePyObject(bm, (BMFace *)ele);
5115 case BM_LOOP:
5116 return BPy_BMLoop_CreatePyObject(bm, (BMLoop *)ele);
5117 default:
5119 PyErr_SetString(PyExc_SystemError, "internal error");
5120 return nullptr;
5121 }
5122}
5123
5125{
5126 if (LIKELY(self->bm)) {
5127
5128/* far too slow to enable by default but handy
5129 * to uncomment for debugging tricky errors,
5130 * note that this will throw error on entering a
5131 * function where the actual error will be caused by
5132 * the previous action. */
5133#if 0
5134 if (BM_mesh_is_valid(self->bm) == false) {
5135 PyErr_Format(
5136 PyExc_ReferenceError, "BMesh used by %.200s has become invalid", Py_TYPE(self)->tp_name);
5137 return -1;
5138 }
5139#endif
5140
5141 return 0;
5142 }
5143
5144 PyErr_Format(
5145 PyExc_ReferenceError, "BMesh data of type %.200s has been removed", Py_TYPE(self)->tp_name);
5146 return -1;
5147}
5148
5150 const char *error_prefix,
5151 void **args,
5152 uint args_tot)
5153{
5154 int ret = 0;
5155
5156 while (args_tot--) {
5157 BPy_BMGeneric *py_bm_elem = static_cast<BPy_BMGeneric *>(args[args_tot]);
5158 if (py_bm_elem) {
5159
5160 BLI_assert(BPy_BMesh_Check(py_bm_elem) || BPy_BMElem_Check(py_bm_elem));
5161
5162 ret = bpy_bm_generic_valid_check(py_bm_elem);
5163 if (UNLIKELY(ret == -1)) {
5164 break;
5165 }
5166
5167 if (UNLIKELY(py_bm_elem->bm != bm_source)) {
5168 /* could give more info here */
5169 PyErr_Format(PyExc_ValueError,
5170 "%.200s: BMesh data of type %.200s is from another mesh",
5171 error_prefix,
5172 Py_TYPE(py_bm_elem)->tp_name);
5173 ret = -1;
5174 break;
5175 }
5176 }
5177 }
5178
5179 return ret;
5180}
5181
5182int bpy_bm_check_uv_select_sync_valid(BMesh *bm, const char *error_prefix)
5183{
5184 int ret = 0;
5185 if (bm->uv_select_sync_valid == false) {
5186 PyErr_Format(PyExc_ValueError, "%s: bm.uv_select_sync_valid: must be true", error_prefix);
5187 ret = -1;
5188 }
5189 return ret;
5190}
5191
5192int bpy_bm_uv_layer_offset_or_error(BMesh *bm, const char *error_prefix)
5193{
5194 const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_PROP_FLOAT2);
5195 if (cd_loop_uv_offset == -1) {
5196 PyErr_Format(PyExc_ValueError, "%s: failed, no UV layer found", error_prefix);
5197 }
5198 return cd_loop_uv_offset;
5199}
5200
5201int bpy_bm_check_bm_match_or_error(BMesh *bm_a, BMesh *bm_b, const char *error_prefix)
5202{
5203 if (bm_a != bm_b) {
5204 PyErr_Format(PyExc_ValueError, "%s: elements must be from a singe BMesh", error_prefix);
5205 return -1;
5206 }
5207 return 0;
5208}
5209
5211{
5212 self->bm = nullptr;
5213}
5214
5216 PyObject *seq_fast,
5217 Py_ssize_t min,
5218 Py_ssize_t max,
5219 Py_ssize_t *r_seq_num,
5220 const char htype,
5221 const bool do_unique_check,
5222 const bool do_bm_check,
5223 const char *error_prefix)
5224{
5225 BMesh *bm = (r_bm && *r_bm) ? *r_bm : nullptr;
5226 PyObject **seq_fast_items = PySequence_Fast_ITEMS(seq_fast);
5227 const Py_ssize_t seq_num = PySequence_Fast_GET_SIZE(seq_fast);
5228 Py_ssize_t i, i_last_dirty = PY_SSIZE_T_MAX;
5229
5230 BPy_BMElem *item;
5231 BMElem **alloc;
5232
5233 *r_seq_num = 0;
5234
5235 if (seq_num < min || seq_num > max) {
5236 PyErr_Format(PyExc_TypeError,
5237 "%s: sequence incorrect size, expected [%d - %d], given %d",
5238 error_prefix,
5239 min,
5240 max,
5241 seq_num);
5242 return nullptr;
5243 }
5244
5245 /* from now on, use goto */
5246 alloc = static_cast<BMElem **>(PyMem_MALLOC(seq_num * sizeof(BPy_BMElem **)));
5247
5248 for (i = 0; i < seq_num; i++) {
5249 item = (BPy_BMElem *)seq_fast_items[i];
5250
5251 if (!BPy_BMElem_CheckHType(Py_TYPE(item), htype)) {
5252 PyErr_Format(PyExc_TypeError,
5253 "%s: expected %.200s, not '%.200s'",
5254 error_prefix,
5256 Py_TYPE(item)->tp_name);
5257 goto err_cleanup;
5258 }
5259 else if (!BPY_BM_IS_VALID(item)) {
5260 PyErr_Format(
5261 PyExc_TypeError, "%s: %d %s has been removed", error_prefix, i, Py_TYPE(item)->tp_name);
5262 goto err_cleanup;
5263 }
5264 /* trick so we can ensure all items have the same mesh,
5265 * and allows us to pass the 'bm' as nullptr. */
5266 else if (do_bm_check && (bm && bm != item->bm)) {
5267 PyErr_Format(PyExc_ValueError,
5268 "%s: %d %s is from another mesh",
5269 error_prefix,
5270 i,
5272 goto err_cleanup;
5273 }
5274
5275 if (bm == nullptr) {
5276 bm = item->bm;
5277 }
5278
5279 alloc[i] = item->ele;
5280
5281 if (do_unique_check) {
5283 i_last_dirty = i;
5284 }
5285 }
5286
5287 if (do_unique_check) {
5288 /* check for double verts! */
5289 bool ok = true;
5290 for (i = 0; i < seq_num; i++) {
5291 if (UNLIKELY(BM_elem_flag_test(alloc[i], BM_ELEM_INTERNAL_TAG) == false)) {
5292 ok = false;
5293 }
5294
5295 /* ensure we don't leave this enabled */
5297 }
5298
5299 if (ok == false) {
5300 /* Cleared above. */
5301 i_last_dirty = PY_SSIZE_T_MAX;
5302 PyErr_Format(PyExc_ValueError,
5303 "%s: found the same %.200s used multiple times",
5304 error_prefix,
5306 goto err_cleanup;
5307 }
5308 }
5309
5310 *r_seq_num = seq_num;
5311 if (r_bm) {
5312 *r_bm = bm;
5313 }
5314 return alloc;
5315
5316err_cleanup:
5317 if (do_unique_check && (i_last_dirty != PY_SSIZE_T_MAX)) {
5318 for (i = 0; i <= i_last_dirty; i++) {
5320 }
5321 }
5322 PyMem_FREE(alloc);
5323 return nullptr;
5324}
5325
5327 PyObject *seq,
5328 Py_ssize_t min,
5329 Py_ssize_t max,
5330 Py_ssize_t *r_seq_num,
5331 const char htype,
5332 const bool do_unique_check,
5333 const bool do_bm_check,
5334 const char *error_prefix)
5335{
5336 PyObject *seq_fast;
5337 PyObject *ret;
5338
5339 if (!(seq_fast = PySequence_Fast(seq, error_prefix))) {
5340 return nullptr;
5341 }
5342
5343 ret = static_cast<PyObject *>(BPy_BMElem_PySeq_As_Array_FAST(
5344 r_bm, seq_fast, min, max, r_seq_num, htype, do_unique_check, do_bm_check, error_prefix));
5345
5346 Py_DECREF(seq_fast);
5347 return ret;
5348}
5349
5351 PyObject *seq,
5352 Py_ssize_t min,
5353 Py_ssize_t max,
5354 Py_ssize_t *r_seq_num,
5355 bool do_unique_check,
5356 bool do_bm_check,
5357 const char *error_prefix)
5358{
5359 return static_cast<BMVert **>(BPy_BMElem_PySeq_As_Array(
5360 r_bm, seq, min, max, r_seq_num, BM_VERT, do_unique_check, do_bm_check, error_prefix));
5361}
5363 PyObject *seq,
5364 Py_ssize_t min,
5365 Py_ssize_t max,
5366 Py_ssize_t *r_seq_num,
5367 bool do_unique_check,
5368 bool do_bm_check,
5369 const char *error_prefix)
5370{
5371 return static_cast<BMEdge **>(BPy_BMElem_PySeq_As_Array(
5372 r_bm, seq, min, max, r_seq_num, BM_EDGE, do_unique_check, do_bm_check, error_prefix));
5373}
5375 PyObject *seq,
5376 Py_ssize_t min,
5377 Py_ssize_t max,
5378 Py_ssize_t *r_seq_num,
5379 bool do_unique_check,
5380 bool do_bm_check,
5381 const char *error_prefix)
5382{
5383 return static_cast<BMFace **>(BPy_BMElem_PySeq_As_Array(
5384 r_bm, seq, min, max, r_seq_num, BM_FACE, do_unique_check, do_bm_check, error_prefix));
5385}
5387 PyObject *seq,
5388 Py_ssize_t min,
5389 Py_ssize_t max,
5390 Py_ssize_t *r_seq_num,
5391 bool do_unique_check,
5392 bool do_bm_check,
5393 const char *error_prefix)
5394{
5395 return static_cast<BMLoop **>(BPy_BMElem_PySeq_As_Array(
5396 r_bm, seq, min, max, r_seq_num, BM_LOOP, do_unique_check, do_bm_check, error_prefix));
5397}
5398
5399PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_num)
5400{
5401 Py_ssize_t i;
5402 PyObject *ret = PyTuple_New(elem_num);
5403 for (i = 0; i < elem_num; i++) {
5404 PyTuple_SET_ITEM(ret, i, BPy_BMElem_CreatePyObject(bm, elem[i]));
5405 }
5406 return ret;
5407}
5408PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_num)
5409{
5410 Py_ssize_t i;
5411 PyObject *ret = PyTuple_New(elem_num);
5412 for (i = 0; i < elem_num; i++) {
5413 PyTuple_SET_ITEM(ret, i, BPy_BMVert_CreatePyObject(bm, elem[i]));
5414 }
5415 return ret;
5416}
5417PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_num)
5418{
5419 Py_ssize_t i;
5420 PyObject *ret = PyTuple_New(elem_num);
5421 for (i = 0; i < elem_num; i++) {
5422 PyTuple_SET_ITEM(ret, i, BPy_BMEdge_CreatePyObject(bm, elem[i]));
5423 }
5424
5425 return ret;
5426}
5427PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_num)
5428{
5429 Py_ssize_t i;
5430 PyObject *ret = PyTuple_New(elem_num);
5431 for (i = 0; i < elem_num; i++) {
5432 PyTuple_SET_ITEM(ret, i, BPy_BMFace_CreatePyObject(bm, elem[i]));
5433 }
5434
5435 return ret;
5436}
5437PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_num)
5438{
5439 Py_ssize_t i;
5440 PyObject *ret = PyTuple_New(elem_num);
5441 for (i = 0; i < elem_num; i++) {
5442 PyTuple_SET_ITEM(ret, i, BPy_BMLoop_CreatePyObject(bm, elem[i]));
5443 }
5444
5445 return ret;
5446}
5447
5448int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
5449{
5450 return (((htype & BM_VERT) && (type == &BPy_BMVert_Type)) ||
5451 ((htype & BM_EDGE) && (type == &BPy_BMEdge_Type)) ||
5452 ((htype & BM_FACE) && (type == &BPy_BMFace_Type)) ||
5453 ((htype & BM_LOOP) && (type == &BPy_BMLoop_Type)));
5454}
5455
5456char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
5457{
5458 /* Zero to ensure string is always null terminated. */
5459 const char *ret_array[4];
5460 int i = 0;
5461 if (htype & BM_VERT) {
5462 ret_array[i++] = BPy_BMVert_Type.tp_name;
5463 }
5464 if (htype & BM_EDGE) {
5465 ret_array[i++] = BPy_BMEdge_Type.tp_name;
5466 }
5467 if (htype & BM_FACE) {
5468 ret_array[i++] = BPy_BMFace_Type.tp_name;
5469 }
5470 if (htype & BM_LOOP) {
5471 ret_array[i++] = BPy_BMLoop_Type.tp_name;
5472 }
5473 ret[0] = '(';
5474 int ret_ofs = BLI_string_join_array_by_sep_char(ret + 1, 30, '/', ret_array, i) + 1;
5475 ret[ret_ofs] = ')';
5476 ret[ret_ofs + 1] = '\0';
5477 return ret;
5478}
5479char *BPy_BMElem_StringFromHType(const char htype)
5480{
5481 /* Zero to ensure string is always null terminated. */
5482 static char ret[32];
5483 return BPy_BMElem_StringFromHType_ex(htype, ret);
5484}
5485
5486/* -------------------------------------------------------------------- */
5487/* keep at bottom */
5488
5489/* This function is called on free, it should stay quite fast */
5491{
5492 if (self->flag & BPY_BMFLAG_IS_WRAPPED) {
5493 /* Currently NOP - this works without warnings now. */
5494 }
5495}
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
BMCustomDataCopyMap CustomData_bmesh_copy_map_calc(const CustomData &src, const CustomData &dst, eCustomDataMask mask_exclude=0)
void * CustomData_bmesh_get(const CustomData *data, void *block, eCustomDataType type)
const CustomData_MeshMasks CD_MASK_BMESH
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
#define G_MAIN
void BKE_id_free(Main *bmain, void *idv)
bool BKE_id_is_in_global_main(ID *id)
Definition lib_id.cc:2500
Mesh * BKE_mesh_new_from_object(Depsgraph *depsgraph, Object *object, bool preserve_all_data_layers, bool preserve_origindex, bool ensure_subdivision)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE float clamp_f(float value, float min, float max)
MINLINE int poly_to_tri_count(int poly_count, int corner_count)
void mul_m4_v3(const float M[4][4], float r[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void range_vn_i(int *array_tar, int size, int start)
void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
Definition sort.cc:77
size_t BLI_string_join_array_by_sep_char(char *result, size_t result_maxncpy, char sep, const char *strings[], uint strings_num) ATTR_NONNULL()
unsigned int uint
#define POINTER_AS_INT(i)
#define UNLIKELY(x)
#define CLAMP_MIN(a, b)
#define LIKELY(x)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ DAG_EVAL_RENDER
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_TAG_NO_MAIN
Definition DNA_ID.h:978
@ ID_RECALC_GEOMETRY_ALL_MODES
Definition DNA_ID.h:1181
#define CD_MASK_BM_ELEM_PYPTR
@ CD_BM_ELEM_PYPTR
@ CD_PROP_FLOAT2
#define MAXMAT
Object is a sort of wrapper for general info.
@ OB_MESH
@ UV_STICKY_VERT
@ UV_STICKY_LOCATION
@ UV_STICKY_DISABLE
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
#define BM_ELEM_SELECT_UV_EDGE
@ BM_ELEM_HIDDEN
@ BM_ELEM_SEAM
@ BM_ELEM_SELECT
@ BM_ELEM_SMOOTH
@ BM_ELEM_INTERNAL_TAG
@ BM_ELEM_SELECT_UV
@ BM_ELEM_TAG
@ BM_LOOP
void BM_elem_attrs_copy(BMesh *bm, const BMCustomDataCopyMap &map, const BMVert *src, BMVert *dst)
BMesh * BM_mesh_copy(BMesh *bm_old)
void BM_vert_kill(BMesh *bm, BMVert *v)
void BM_face_kill(BMesh *bm, BMFace *f)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
BMFace * BM_face_copy(BMesh *bm_dst, const BMCustomDataCopyMap &cd_face_map, const BMCustomDataCopyMap &cd_loop_map, BMFace *f, const bool copy_verts, const bool copy_edges)
void BM_edge_kill(BMesh *bm, BMEdge *e)
BMVert * BM_vert_create(BMesh *bm, const float co[3], const BMVert *v_example, const eBMCreateFlag create_flag)
Main function for creating a new vertex.
Definition bmesh_core.cc:41
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
#define BM_elem_index_get(ele)
#define BM_elem_flag_disable(ele, hflag)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_index_set(ele, index)
#define BM_elem_flag_test(ele, hflag)
#define BM_elem_flag_enable(ele, hflag)
void BM_data_layer_free(BMesh *bm, CustomData *data, int type)
void BM_vert_interp_from_face(BMesh *bm, BMVert *v_dst, const BMFace *f_src)
void BM_data_layer_add(BMesh *bm, CustomData *data, int type)
void BM_face_interp_from_face(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const bool do_vertex)
void BM_loop_interp_from_face(BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
void BM_data_interp_from_verts(BMesh *bm, const BMVert *v_src_1, const BMVert *v_src_2, BMVert *v_dst, const float fac)
Data, Interpolate From Verts.
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
const char bm_iter_itype_htype_map[BM_ITYPE_MAX]
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_iter_init(iter, bm, itype, data)
BMIterType
BMesh Iterators.
@ BM_LOOPS_OF_LOOP
@ BM_FACES_OF_EDGE
@ BM_FACES_OF_VERT
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_VERTS_OF_FACE
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_EDGES_OF_FACE
@ BM_LOOPS_OF_FACE
BMesh const char void * data
BMesh * bm
BMesh const char itype
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode, BMSelectFlushFlag flag)
Select Mode Flush.
void BM_mesh_select_flush_from_verts(BMesh *bm, const bool select)
BMSelectFlushFlag
#define BM_elem_hide_set(bm, ele, hide)
#define BMSelectFlushFlag_Default
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_mesh_clear(BMesh *bm)
BMesh Clear Mesh.
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
int BM_mesh_elem_count(BMesh *bm, const char htype)
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *mesh, const BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *mesh, const BMeshToMeshParams *params)
void BM_mesh_normals_update(BMesh *bm)
void BM_mesh_calc_tessellation(BMesh *bm, MutableSpan< std::array< BMLoop *, 3 > > looptris)
bool BM_mesh_is_valid(BMesh *bm)
#define BM_FACE
#define BM_EDGE
#define BM_VERT
void BM_face_calc_tangent_from_vert_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3])
void BM_vert_normal_update(BMVert *v)
void BM_face_calc_tangent_from_edge_pair(const BMFace *f, float r_tangent[3])
void BM_face_normal_update(BMFace *f)
void BM_face_normal_flip(BMesh *bm, BMFace *f)
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_tangent_from_edge(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
void BM_face_calc_tangent_from_edge_diagonal(const BMFace *f, float r_tangent[3])
void BM_face_calc_center_median_weighted(const BMFace *f, float r_cent[3])
float BM_face_calc_perimeter(const BMFace *f)
void BM_edge_normals_update(BMEdge *e)
static Py_hash_t bpy_bm_hash(PyObject *self)
PyObject * BPy_BMEdgeSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmedge_calc_face_angle_signed(BPy_BMEdge *self, PyObject *args)
PyDoc_STRVAR(bpy_bm_elem_select_doc, "Selected state of this element.\n" "\n" ":type: bool\n")
static void bpy_bmvert_dealloc(BPy_BMElem *self)
PyObject * BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f)
static PyObject * bpy_bmvert_normal_update(BPy_BMVert *self)
static PyObject * bpy_bmloop_vert_get(BPy_BMLoop *self, void *)
static Py_hash_t bpy_bm_elem_hash(PyObject *self)
static PyObject * bpy_bmloop_link_loop_prev_get(BPy_BMLoop *self, void *)
PyC_FlagSet bpy_bm_htype_all_flags[]
static PyMappingMethods bpy_bmelemseq_as_mapping
static PyObject * bpy_bmesh_normal_update(BPy_BMesh *self)
static PyObject * bpy_bmface_calc_center_bounds(BPy_BMFace *self)
static int bpy_bmvert_co_set(BPy_BMVert *self, PyObject *value, void *)
static PyObject * bpy_bmface_normal_update(BPy_BMFace *self)
static PyObject * bpy_bmvertseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmesh_clear(BPy_BMesh *self)
PyObject * BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop *const *elem, Py_ssize_t elem_num)
static PyObject * bpy_bmesh_select_history_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmesh_calc_loop_triangles(BPy_BMElem *self)
PyObject * BPy_BMLoopSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmvert_calc_edge_angle(BPy_BMVert *self, PyObject *args)
PyObject * BPy_BMFaceSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmloop_link_loop_radial_next_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmloop_calc_tangent(BPy_BMLoop *self)
static PyObject * bpy_bmelemseq_iter(BPy_BMElemSeq *self)
static PyGetSetDef bpy_bmvertseq_getseters[]
PyObject * BPy_BMElem_CreatePyObject(BMesh *bm, BMHeader *ele)
static PyObject * bpy_bmface_calc_tangent_vert_diagonal(BPy_BMFace *self)
static PyGetSetDef bpy_bmloopseq_getseters[]
static PyObject * bpy_bmloop_calc_normal(BPy_BMLoop *self)
PyObject * BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_num)
PyObject * BPy_BMesh_CreatePyObject(BMesh *bm, int flag)
static PyObject * bpy_bmedge_is_contiguous_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmvert_is_boundary_get(BPy_BMVert *self, void *)
PyTypeObject BPy_BMesh_Type
PyObject * BPy_BMElemSeq_CreatePyObject(BMesh *bm, BPy_BMElem *py_ele, const char itype)
static PyObject * bpy_bmelemseq_subscript(BPy_BMElemSeq *self, PyObject *key)
static int bpy_bm_elem_index_set(BPy_BMElem *self, PyObject *value, void *)
static PyModuleDef BPy_BM_types_module_def
static PyObject * bpy_bmloop_is_convex_get(BPy_BMLoop *self, void *)
PyC_FlagSet bpy_bm_htype_vert_edge_face_flags[]
PyObject * BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v)
PyObject * BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l)
static PyMethodDef bpy_bmedgeseq_methods[]
static PyObject * bpy_bmvert_calc_shell_factor(BPy_BMVert *self)
static PyObject * bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmesh_uv_select_flush_mode(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmface_normal_get(BPy_BMFace *self, void *)
static PyObject * bpy_bmloop_edge_get(BPy_BMLoop *self, void *)
static PyMappingMethods bpy_bm_elem_as_mapping
static PyObject * bpy_bmesh_uv_select_flush(BPy_BMesh *self, PyObject *value)
static PyObject * bpy_bmloop_calc_angle(BPy_BMLoop *self)
static PyObject * bpy_bm_elem_hide_set(BPy_BMElem *self, PyObject *value)
void * BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, const char htype, const bool do_unique_check, const bool do_bm_check, const char *error_prefix)
char * BPy_BMElem_StringFromHType(const char htype)
void * BPy_BMElem_PySeq_As_Array_FAST(BMesh **r_bm, PyObject *seq_fast, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, const char htype, const bool do_unique_check, const bool do_bm_check, const char *error_prefix)
static int bpy_bmelem_ass_subscript(BPy_BMElem *self, BPy_BMLayerItem *key, PyObject *value)
static PyObject * bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value)
static PyObject * bpy_bmloop_link_loop_next_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmloop_link_loop_radial_prev_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmedge_calc_face_angle(BPy_BMEdge *self, PyObject *args)
static PyObject * bpy_bmelemseq_elem_get(BPy_BMElem *self, void *itype)
static void bm_dealloc_editmode_warn(BPy_BMesh *self)
static PyObject * bpy_bmedge_is_wire_get(BPy_BMEdge *self, void *)
PyTypeObject BPy_BMVertSeq_Type
PyTypeObject BPy_BMLoopSeq_Type
static PyObject * bpy_bmface_repr(BPy_BMFace *self)
static void bpy_bmedge_dealloc(BPy_BMElem *self)
static int bpy_bmvert_normal_set(BPy_BMVert *self, PyObject *value, void *)
static PyObject * bpy_bmesh_repr(BPy_BMesh *self)
static PyGetSetDef bpy_bmvert_getseters[]
PyObject * BPy_BMVertSeq_CreatePyObject(BMesh *bm)
static PyObject * bpy_bmedge_normal_update(BPy_BMEdge *self)
static PyObject * bpy_bmedge_repr(BPy_BMEdge *self)
static PyMethodDef bpy_bmedge_methods[]
static void bpy_bmloop_dealloc(BPy_BMElem *self)
static Py_ssize_t bpy_bmelemseq_length(BPy_BMElemSeq *self)
char * BPy_BMElem_StringFromHType_ex(const char htype, char ret[32])
static PyObject * bpy_bmvert_is_wire_get(BPy_BMVert *self, void *)
static PyGetSetDef bpy_bmesh_getseters[]
void bpy_bm_generic_invalidate(BPy_BMGeneric *self)
static PyObject * bpy_bmface_uv_select_set(BPy_BMFace *self, PyObject *value)
PyObject * BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_num)
void BPy_BM_init_types()
static PyMethodDef bpy_bmvert_methods[]
static PyObject * bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value)
static PyObject * bpy_bmesh_uv_select_flush_shared(BPy_BMesh *self, PyObject *value)
static int bpy_bmface_normal_set(BPy_BMFace *self, PyObject *value, void *)
static PyObject * bpy_bmloop_face_get(BPy_BMLoop *self, void *)
static PyObject * bpy_bmesh_copy(BPy_BMesh *self)
static PyObject * bpy_bmedge_calc_tangent(BPy_BMEdge *self, PyObject *args)
static PyObject * bpy_bm_elem_hflag_get(BPy_BMElem *self, void *flag)
PyTypeObject BPy_BMEdgeSeq_Type
static PyObject * bpy_bmvert_is_manifold_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmesh_uv_select_foreach_set(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmedge_is_convex_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmedgeseq_get__method(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmface_calc_tangent_edge_diagonal(BPy_BMFace *self)
static PyObject * bpy_bmesh_select_flush(BPy_BMesh *self, PyObject *value)
PyTypeObject BPy_BMEdge_Type
static PyObject * bpy_bmedge_calc_length(BPy_BMEdge *self)
static PyMethodDef bpy_bmelemseq_methods[]
static PyObject * bpy_bmedgeseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmvertseq_new(BPy_BMElemSeq *self, PyObject *args)
int bpy_bm_uv_layer_offset_or_error(BMesh *bm, const char *error_prefix)
static PyObject * bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
static PyObject * bpy_bmface_calc_tangent_edge_pair(BPy_BMFace *self)
static PyTypeObject * bpy_bm_itype_as_pytype(const char itype)
static PyObject * bpy_bmface_normal_flip(BPy_BMFace *self)
BMVert ** BPy_BMVert_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
BMEdge ** BPy_BMEdge_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
static PyObject * bpy_bmedge_is_manifold_get(BPy_BMEdge *self, void *)
int bpy_bm_check_bm_match_or_error(BMesh *bm_a, BMesh *bm_b, const char *error_prefix)
static PyGetSetDef bpy_bmfaceseq_getseters[]
static PyObject * bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value)
static PyObject * bpy_bmloop_repr(BPy_BMLoop *self)
static PyGetSetDef bpy_bmedge_getseters[]
PyObject * BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_num)
static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void *)
static PyObject * bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
static PyObject * bpy_bmesh_uv_select_sync_valid_get(BPy_BMesh *self, void *)
static PyObject * bpy_bm_is_valid_get(BPy_BMGeneric *self, void *)
static int bpy_bmelemseq_sort_cmp_by_keys_descending(const void *index1_v, const void *index2_v, void *keys_v)
static PyObject * bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmesh_transform(BPy_BMElem *self, PyObject *args, PyObject *kw)
int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, uint args_tot)
static PyObject * bpy_bmvert_co_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmesh_select_mode_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmedgeseq_new(BPy_BMElemSeq *self, PyObject *args)
static PyMethodDef bpy_bmfaceseq_methods[]
static PyObject * bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmloop_uv_select_vert_set(BPy_BMLoop *self, PyObject *value)
static PyMethodDef bpy_bmloopseq_methods[]
static PyObject * bpy_bmedge_is_boundary_get(BPy_BMEdge *self, void *)
static PyObject * bpy_bmface_copy(BPy_BMFace *self, PyObject *args, PyObject *kw)
static PyGetSetDef bpy_bmedgeseq_getseters[]
static PyObject * bpy_bmelemseq_subscript_slice(BPy_BMElemSeq *self, Py_ssize_t start, Py_ssize_t stop)
static void bpy_bmelemseq_dealloc(BPy_BMElemSeq *self)
BMLoop ** BPy_BMLoop_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
static PyObject * bpy_bmloop_uv_select_edge_set(BPy_BMLoop *self, PyObject *value)
static int bpy_bmesh_uv_select_sync_valid_set(BPy_BMesh *self, PyObject *value, void *)
int bpy_bm_generic_valid_check(BPy_BMGeneric *self)
static PyObject * bpy_bmelemseq_subscript_int(BPy_BMElemSeq *self, Py_ssize_t keynum)
static PyObject * bpy_bmface_calc_perimeter(BPy_BMFace *self)
static void bpy_bmface_dealloc(BPy_BMElem *self)
PyTypeObject BPy_BMFaceSeq_Type
PyTypeObject BPy_BMVert_Type
PyTypeObject BPy_BMIter_Type
static PyC_StringEnumItems bpy_bm_uv_select_sticky_items[]
static PyObject * bpy_bmesh_uv_select_sync_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
static int bpy_bmface_material_index_set(BPy_BMFace *self, PyObject *value, void *)
static PyObject * bpy_bmvert_copy_from_vert_interp(BPy_BMVert *self, PyObject *args)
static int bpy_bmesh_select_history_set(BPy_BMesh *self, PyObject *value, void *)
static PyMethodDef bpy_bmface_methods[]
static PyMethodDef bpy_bmloop_methods[]
static PyObject * bpy_bmface_calc_center_mean(BPy_BMFace *self)
static PyObject * bpy_bmesh_select_flush_mode(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bm_elem_index_get(BPy_BMElem *self, void *)
int bpy_bm_check_uv_select_sync_valid(BMesh *bm, const char *error_prefix)
static PyObject * bpy_bmface_calc_tangent_edge(BPy_BMFace *self)
#define BPY_BM_HFLAG_ALL_STR
static PyObject * bpy_bmelemseq_sort(BPy_BMElemSeq *self, PyObject *args, PyObject *kw)
PyTypeObject BPy_BMElemSeq_Type
static PyMethodDef bpy_bmesh_methods[]
static PyObject * bpy_bmfaceseq_active_get(BPy_BMElemSeq *self, void *)
static PyObject * bpy_bmloopseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmvert_normal_get(BPy_BMVert *self, void *)
static PyObject * bpy_bmelemseq_ensure_lookup_table(BPy_BMElemSeq *self)
static PyGetSetDef bpy_bmface_getseters[]
static PyObject * bpy_bmfaceseq_get(BPy_BMesh *self, void *)
static PyObject * bpy_bmiter_next(BPy_BMIter *self)
static PyObject * bpy_bmesh_free(BPy_BMesh *self)
PyObject * BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_num)
PyTypeObject BPy_BMFace_Type
static PyObject * bpy_bmesh_from_object(BPy_BMesh *self, PyObject *args, PyObject *kw)
static int bpy_bmesh_select_mode_set(BPy_BMesh *self, PyObject *value, void *)
static int bpy_bmelemseq_sort_cmp_by_keys_ascending(const void *index1_v, const void *index2_v, void *keys_v)
static PyObject * bpy_bmface_calc_center_median_weighted(BPy_BMFace *self)
static void bpy_bmesh_dealloc(BPy_BMesh *self)
static PyGetSetDef bpy_bmloop_getseters[]
static PyObject * bpy_bmface_calc_area(BPy_BMFace *self)
PyTypeObject BPy_BMLoop_Type
static PyObject * bpy_bmesh_uv_select_sync_to_mesh(BPy_BMesh *self)
PyObject * BPy_BMIter_CreatePyObject(BMesh *bm)
static int bpy_bmelemseq_contains(BPy_BMElemSeq *self, PyObject *value)
static PyObject * bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *args)
#define BPY_BM_HTYPE_NOLOOP
PyC_FlagSet bpy_bm_hflag_all_flags[]
static PyMethodDef bpy_bmvertseq_methods[]
static PyObject * bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *args)
PyC_FlagSet bpy_bm_scene_vert_edge_face_flags[]
int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype)
static PyObject * bpy_bm_elem_select_set(BPy_BMElem *self, PyObject *value)
static PySequenceMethods bpy_bmelemseq_as_sequence
static PyObject * bpy_bmelem_subscript(BPy_BMElem *self, BPy_BMLayerItem *key)
static PyObject * bpy_bmelemseq_layers_get(BPy_BMElemSeq *self, void *htype)
static PyObject * bpy_bmface_material_index_get(BPy_BMFace *self, void *)
static PyObject * bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value)
PyObject * BPyInit_bmesh_types()
PyObject * BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e)
BMFace ** BPy_BMFace_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ssize_t max, Py_ssize_t *r_seq_num, bool do_unique_check, bool do_bm_check, const char *error_prefix)
static PyObject * bpy_bmesh_uv_select_foreach_set_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
static PyObject * bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *args)
static PyObject * bpy_bmesh_is_wrapped_get(BPy_BMesh *self, void *)
static int bpy_bm_elem_hflag_set(BPy_BMElem *self, PyObject *value, void *flag)
static PyObject * bpy_bm_elem_copy_from(BPy_BMElem *self, BPy_BMElem *value)
static PyObject * bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args)
static PyObject * bpy_bmvert_repr(BPy_BMVert *self)
#define BPy_BMFace_Check(v)
#define BPY_BM_CHECK_OBJ(obj)
#define BPY_BM_CHECK_SOURCE_INT(bm, errmsg,...)
#define BPy_BMVert_Check(v)
#define BPy_BMElem_Check(v)
@ BPY_BMFLAG_IS_WRAPPED
@ BPY_BMFLAG_NOP
#define BPy_BMesh_Check(v)
#define BPy_BMEdge_Check(v)
#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg,...)
#define BPY_BM_IS_VALID(obj)
#define BM_ITER_BPY_BM_SEQ(ele, iter, bpy_bmelemseq)
#define BPY_BM_CHECK_INT(obj)
PyTypeObject BPy_BMLayerCollection_Type
PyObject * BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
PyTypeObject BPy_BMLayerItem_Type
PyTypeObject BPy_BMLayerAccessLoop_Type
PyTypeObject BPy_BMLayerAccessVert_Type
int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *py_value)
PyTypeObject BPy_BMLayerAccessFace_Type
PyTypeObject BPy_BMLayerAccessEdge_Type
PyObject * BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
BMElem.__getitem__() / setitem().
PyTypeObject BPy_BMDeformVert_Type
PyTypeObject BPy_BMLoopUV_Type
int BPy_BMEditSel_Assign(BPy_BMesh *self, PyObject *value)
PyTypeObject BPy_BMEditSelSeq_Type
PyTypeObject BPy_BMEditSelIter_Type
PyObject * BPy_BMEditSel_CreatePyObject(BMesh *bm)
bool BM_vert_is_wire(const BMVert *v)
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
BM_loop_calc_face_tangent.
BMFace * BM_face_exists(BMVert *const *varr, int len)
bool BM_vert_is_manifold(const BMVert *v)
float BM_vert_calc_shell_factor(const BMVert *v)
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
float BM_vert_calc_edge_angle_ex(const BMVert *v, const float fallback)
BMESH VERT/EDGE ANGLE.
float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
bool BM_loop_is_convex(const BMLoop *l)
double BM_mesh_calc_volume(BMesh *bm, bool is_signed)
float BM_loop_calc_face_angle(const BMLoop *l)
float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback)
BMESH EDGE/FACE ANGLE.
void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3])
BMESH EDGE/FACE TANGENT.
float BM_loop_calc_face_normal(const BMLoop *l, float r_normal[3])
BM_loop_calc_face_normal.
bool BM_vert_is_boundary(const BMVert *v)
bool BM_edge_is_convex(const BMEdge *e)
BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_mesh_uvselect_sync_from_mesh_sticky_vert(BMesh *bm)
void BM_face_uvselect_set(BMesh *bm, BMFace *f, bool select)
void BM_mesh_uvselect_sync_from_mesh_sticky_disabled(BMesh *bm)
void BM_mesh_uvselect_sync_to_mesh(BMesh *bm)
void BM_mesh_uvselect_flush_shared_only_deselect(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_uvselect_flush_shared_only_select(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_uvselect_mode_flush_ex(BMesh *bm, const short selectmode, const bool flush_down)
void BM_mesh_uvselect_flush_from_verts(BMesh *bm, const bool select)
void BM_mesh_uvselect_set_elem_shared(BMesh *bm, bool select, const int cd_loop_uv_offset, const blender::Span< BMLoop * > loop_verts, const blender::Span< BMLoop * > loop_edges, const blender::Span< BMFace * > faces)
void BM_loop_edge_uvselect_set(BMesh *bm, BMLoop *l, bool select)
void BM_mesh_uvselect_sync_from_mesh_sticky_location(BMesh *bm, const int cd_loop_uv_offset)
void BM_mesh_uvselect_set_elem_from_mesh(BMesh *bm, const bool select, const BMUVSelectPickParams &params, const blender::VectorList< BMVert * > &verts, const blender::VectorList< BMEdge * > &edges, const blender::VectorList< BMFace * > &faces)
void BM_loop_vert_uvselect_set_noflush(BMesh *bm, BMLoop *l, bool select)
PyObject * self
BPy_StructRNA * depsgraph
#define filter
#define shared
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
int count
int mathutils_array_parse(float *array, int array_num_min, int array_num_max, PyObject *value, const char *error_prefix)
Definition mathutils.cc:96
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:141
PyTypeObject matrix_Type
PyObject * Vector_CreatePyObject(const float *vec, const int vec_num, PyTypeObject *base_type)
PyObject * Vector_CreatePyObject_wrap(float *vec, const int vec_num, PyTypeObject *base_type)
Mesh * mesh_get_eval_deform(Depsgraph *depsgraph, const Scene *scene, Object *ob, const CustomData_MeshMasks *dataMask)
void * PyC_RNA_AsPointer(PyObject *value, const char *type_name)
int PyC_ParseStringEnum(PyObject *o, void *p)
int PyC_Long_AsBool(PyObject *value)
int PyC_FlagSet_ToBitfield(const PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix)
int PyC_ParseBool(PyObject *o, void *p)
PyObject * PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
header-only compatibility defines.
#define Py_HashPointer
Py_DECREF(oname)
header-only utilities
return ret
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
BMHeader head
BMHeader head
void * data
float co[3]
CustomData vdata
CustomData edata
CustomData pdata
CustomData ldata
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
PyObject_VAR_HEAD BMesh * bm
int tag
Definition DNA_ID.h:442
char name[258]
Definition DNA_ID.h:432
MeshRuntimeHandle * runtime
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
uint len
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145