Blender V4.5
bmesh_log.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
19
20#include "MEM_guardedalloc.h"
21
22#include "BLI_listbase.h"
23#include "BLI_map.hh"
24#include "BLI_math_vector.h"
25#include "BLI_pool.hh"
26#include "BLI_utildefines.h"
27
28#include "BKE_customdata.hh"
29
30#include "bmesh.hh"
31#include "bmesh_log.hh"
32
33#include "range_tree.h"
34
35#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
36
37struct BMLogFace;
38struct BMLogVert;
39
73
105
112
113struct BMLogFace {
114 std::array<uint, 3> v_ids;
115 char hflag;
116};
117
118/************************* Get/set element IDs ************************/
119
120/* Get the vertex's unique ID from the log */
122{
123 return log->elem_to_id.lookup(reinterpret_cast<BMElem *>(v));
124}
125
126/* Set the vertex's unique ID in the log */
127static void bm_log_vert_id_set(BMLog *log, BMVert *v, const uint id)
128{
129 log->id_to_elem.add_overwrite(id, reinterpret_cast<BMElem *>(v));
130 log->elem_to_id.add_overwrite(reinterpret_cast<BMElem *>(v), id);
131}
132
133/* Get a vertex from its unique ID */
135{
136 return reinterpret_cast<BMVert *>(log->id_to_elem.lookup(id));
137}
138
139/* Get the face's unique ID from the log */
141{
142 return log->elem_to_id.lookup(reinterpret_cast<BMElem *>(f));
143}
144
145/* Set the face's unique ID in the log */
146static void bm_log_face_id_set(BMLog *log, BMFace *f, const uint id)
147{
148 log->id_to_elem.add_overwrite(id, reinterpret_cast<BMElem *>(f));
149 log->elem_to_id.add_overwrite(reinterpret_cast<BMElem *>(f), id);
150}
151
152/* Get a face from its unique ID */
154{
155 return reinterpret_cast<BMFace *>(log->id_to_elem.lookup(id));
156}
157
158/************************ BMLogVert / BMLogFace ***********************/
159
160/* Get a vertex's paint-mask value
161 *
162 * Returns zero if no paint-mask layer is present */
163static float vert_mask_get(BMVert *v, const int cd_vert_mask_offset)
164{
165 if (cd_vert_mask_offset != -1) {
166 return BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
167 }
168 return 0.0f;
169}
170
171/* Set a vertex's paint-mask value
172 *
173 * Has no effect is no paint-mask layer is present */
174static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mask_offset)
175{
176 if (cd_vert_mask_offset != -1) {
177 BM_ELEM_CD_SET_FLOAT(v, cd_vert_mask_offset, new_mask);
178 }
179}
180
181/* Update a BMLogVert with data from a BMVert */
182static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
183{
184 copy_v3_v3(lv->position, v->co);
185 copy_v3_v3(lv->normal, v->no);
186 lv->mask = vert_mask_get(v, cd_vert_mask_offset);
187 lv->hflag = v->head.hflag;
188}
189
190/* Allocate and initialize a BMLogVert */
191static BMLogVert *bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
192{
193 BMLogEntry *entry = log->current_entry;
194 BMLogVert *lv = &entry->vert_pool.construct();
195 entry->allocated_verts.append(lv);
196
197 bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
198
199 return lv;
200}
201
202/* Allocate and initialize a BMLogFace */
204{
205 BMLogEntry *entry = log->current_entry;
206 BMLogFace *lf = &entry->face_pool.construct();
207 entry->allocated_faces.append(lf);
208 BMVert *v[3];
209
210 BLI_assert(f->len == 3);
211
212 // BM_iter_as_array(nullptr, BM_VERTS_OF_FACE, f, (void **)v, 3);
214
215 lf->v_ids[0] = bm_log_vert_id_get(log, v[0]);
216 lf->v_ids[1] = bm_log_vert_id_get(log, v[1]);
217 lf->v_ids[2] = bm_log_vert_id_get(log, v[2]);
218
219 lf->hflag = f->head.hflag;
220 return lf;
221}
222
223/************************ Helpers for undo/redo ***********************/
224
226 BMLog *log,
228{
229 const int cd_vert_mask_offset = CustomData_get_offset_named(
230 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
231
232 for (const auto item : verts.items()) {
233 BMVert *v = bm_log_vert_from_id(log, item.key);
234
235 /* Ensure the log has the final values of the vertex before
236 * deleting it */
237 bm_log_vert_bmvert_copy(item.value, v, cd_vert_mask_offset);
238
239 BM_vert_kill(bm, v);
240 }
241}
242
244 BMLog *log,
246{
247 for (const uint id : faces.keys()) {
249 std::array<BMEdge *, 3> e_tri;
250
251 BMLoop *l_iter = BM_FACE_FIRST_LOOP(f);
252 for (uint i = 0; i < e_tri.size(); i++, l_iter = l_iter->next) {
253 e_tri[i] = l_iter->e;
254 }
255
256 /* Remove any unused edges */
257 BM_face_kill(bm, f);
258 for (uint i = 0; i < e_tri.size(); i++) {
259 if (BM_edge_is_wire(e_tri[i])) {
260 BM_edge_kill(bm, e_tri[i]);
261 }
262 }
263 }
264}
265
267 BMLog *log,
269{
270 const int cd_vert_mask_offset = CustomData_get_offset_named(
271 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
272
273 for (const auto item : verts.items()) {
274 BMLogVert *lv = item.value;
275 BMVert *v = BM_vert_create(bm, lv->position, nullptr, BM_CREATE_NOP);
276 vert_mask_set(v, lv->mask, cd_vert_mask_offset);
277 v->head.hflag = lv->hflag;
278 copy_v3_v3(v->no, lv->normal);
279 bm_log_vert_id_set(log, v, item.key);
280 }
281}
282
284 BMLog *log,
286{
287 const int cd_face_sets = CustomData_get_offset_named(
288 &bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
289
290 for (const auto item : faces.items()) {
291 BMLogFace *lf = item.value;
292 BMVert *v[3] = {
293 bm_log_vert_from_id(log, lf->v_ids[0]),
294 bm_log_vert_from_id(log, lf->v_ids[1]),
295 bm_log_vert_from_id(log, lf->v_ids[2]),
296 };
297
298 BMFace *f = BM_face_create_verts(bm, v, 3, nullptr, BM_CREATE_NOP, true);
299 f->head.hflag = lf->hflag;
300 bm_log_face_id_set(log, f, item.key);
301
302 /* Ensure face sets have valid values. Fixes #80174. */
303 if (cd_face_sets != -1) {
304 BM_ELEM_CD_SET_INT(f, cd_face_sets, 1);
305 }
306 }
307}
308
310 BMLog *log,
312{
313 const int cd_vert_mask_offset = CustomData_get_offset_named(
314 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
315
316 for (const auto item : verts.items()) {
317 BMLogVert *lv = item.value;
318 BMVert *v = bm_log_vert_from_id(log, item.key);
319
320 swap_v3_v3(v->co, lv->position);
321 swap_v3_v3(v->no, lv->normal);
322 std::swap(v->head.hflag, lv->hflag);
323 float mask = lv->mask;
324 lv->mask = vert_mask_get(v, cd_vert_mask_offset);
325 vert_mask_set(v, mask, cd_vert_mask_offset);
326 }
327}
328
330{
331
332 for (const auto item : faces.items()) {
333 BMLogFace *lf = item.value;
334 BMFace *f = bm_log_face_from_id(log, item.key);
335
336 std::swap(f->head.hflag, lf->hflag);
337 }
338}
339
340/**********************************************************************/
341
342/* Assign unique IDs to all vertices and faces already in the BMesh */
344{
345 BMIter iter;
346
347 BMVert *v;
348 /* Generate vertex IDs */
349 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
350 uint id = range_tree_uint_take_any(log->unused_ids);
352 }
353
354 BMFace *f;
355 /* Generate face IDs */
356 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
357 uint id = range_tree_uint_take_any(log->unused_ids);
358 bm_log_face_id_set(log, f, id);
359 }
360}
361
362/* Allocate an empty log entry */
364{
365 BMLogEntry *entry = MEM_new<BMLogEntry>(__func__);
366
367 return entry;
368}
369
370/* Free the data in a log entry
371 *
372 * NOTE: does not free the log entry itself. */
373static void bm_log_entry_free(BMLogEntry *entry)
374{
375 BLI_assert(entry->vert_pool.size() == entry->allocated_verts.size());
376 BLI_assert(entry->face_pool.size() == entry->allocated_faces.size());
377
378 for (BMLogVert *log_vert : entry->allocated_verts) {
379 entry->vert_pool.destruct(*log_vert);
380 }
381
382 for (BMLogFace *log_face : entry->allocated_faces) {
383 entry->face_pool.destruct(*log_face);
384 }
385
386 BLI_assert(entry->vert_pool.is_empty());
387 BLI_assert(entry->face_pool.is_empty());
388}
389
390static int uint_compare(const void *a_v, const void *b_v)
391{
392 const uint *a = static_cast<const uint *>(a_v);
393 const uint *b = static_cast<const uint *>(b_v);
394 return *a < *b;
395}
396
397/* Remap IDs to contiguous indices
398 *
399 * E.g. if the vertex IDs are (4, 1, 10, 3), the mapping will be:
400 * 4 -> 2
401 * 1 -> 0
402 * 10 -> 3
403 * 3 -> 1
404 */
406{
408 qsort(ids, totid, sizeof(*ids), uint_compare);
409
410 for (uint i = 0; i < totid; i++) {
411 result.add(ids[i], i);
412 }
413
414 return result;
415}
416
417/***************************** Public API *****************************/
418
420{
421 BMLog *log = MEM_new<BMLog>(__func__);
422 const uint reserve_num = uint(bm->totvert + bm->totface);
423
424 log->unused_ids = range_tree_uint_alloc(0, uint(-1));
425 log->id_to_elem.reserve(reserve_num);
426 log->elem_to_id.reserve(reserve_num);
427
428 /* Assign IDs to all existing vertices and faces */
430
431 return log;
432}
433
435{
436 BMLog *log = entry->log;
437
438 if (log) {
439 /* Take all used IDs */
440 for (const uint id : entry->deleted_verts.keys()) {
441 range_tree_uint_retake(log->unused_ids, id);
442 }
443 for (const uint id : entry->deleted_faces.keys()) {
444 range_tree_uint_retake(log->unused_ids, id);
445 }
446 for (const uint id : entry->added_verts.keys()) {
447 range_tree_uint_retake(log->unused_ids, id);
448 }
449 for (const uint id : entry->added_faces.keys()) {
450 range_tree_uint_retake(log->unused_ids, id);
451 }
452 for (const uint id : entry->modified_verts.keys()) {
453 range_tree_uint_retake(log->unused_ids, id);
454 }
455 for (const uint id : entry->modified_faces.keys()) {
456 range_tree_uint_retake(log->unused_ids, id);
457 }
458
459 /* delete entries to avoid releasing ids in node cleanup */
460 entry->deleted_verts.clear();
461 entry->deleted_faces.clear();
462 entry->added_verts.clear();
463 entry->added_faces.clear();
464 entry->modified_verts.clear();
465
466 /* Is this last one needed? */
467 entry->modified_faces.clear();
468 }
469}
470
472{
474
475 if (entry->prev) {
476 log->current_entry = entry;
477 }
478 else {
479 log->current_entry = nullptr;
480 }
481
482 /* Let BMLog manage the entry list again */
483 log->entries.first = log->entries.last = entry;
484
485 {
486 while (entry->prev) {
487 entry = entry->prev;
488 log->entries.first = entry;
489 }
490 entry = static_cast<BMLogEntry *>(log->entries.last);
491 while (entry->next) {
492 entry = entry->next;
493 log->entries.last = entry;
494 }
495 }
496
497 for (entry = static_cast<BMLogEntry *>(log->entries.first); entry; entry = entry->next) {
498 entry->log = log;
499
500 /* Take all used IDs */
501 for (const uint id : entry->deleted_verts.keys()) {
502 range_tree_uint_retake(log->unused_ids, id);
503 }
504 for (const uint id : entry->deleted_faces.keys()) {
505 range_tree_uint_retake(log->unused_ids, id);
506 }
507 for (const uint id : entry->added_verts.keys()) {
508 range_tree_uint_retake(log->unused_ids, id);
509 }
510 for (const uint id : entry->added_faces.keys()) {
511 range_tree_uint_retake(log->unused_ids, id);
512 }
513 for (const uint id : entry->modified_verts.keys()) {
514 range_tree_uint_retake(log->unused_ids, id);
515 }
516 for (const uint id : entry->modified_faces.keys()) {
517 range_tree_uint_retake(log->unused_ids, id);
518 }
519 }
520
521 return log;
522}
523
525{
526 if (log->unused_ids) {
527 range_tree_uint_free(log->unused_ids);
528 }
529
530 /* Clear the BMLog references within each entry, but do not free
531 * the entries themselves */
532 LISTBASE_FOREACH (BMLogEntry *, entry, &log->entries) {
533 entry->log = nullptr;
534 }
535
536 MEM_delete(log);
537}
538
540{
541 BMIter bm_iter;
542
543 uint i;
544
545 BMVert *v;
546 /* Put all vertex IDs into an array */
547 uint *varr = MEM_malloc_arrayN<uint>(size_t(bm->totvert), __func__);
548 BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
549 varr[i] = bm_log_vert_id_get(log, v);
550 }
551
552 BMFace *f;
553 /* Put all face IDs into an array */
554 uint *farr = MEM_malloc_arrayN<uint>(size_t(bm->totface), __func__);
555 BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
556 farr[i] = bm_log_face_id_get(log, f);
557 }
558
559 /* Create BMVert index remap array */
561 varr, uint(bm->totvert));
562 BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
563 const uint id = bm_log_vert_id_get(log, v);
564 varr[i] = vert_compression_map.lookup(id);
565 }
566
567 /* Create BMFace index remap array */
569 farr, uint(bm->totface));
570 BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
571 const uint id = bm_log_face_id_get(log, f);
572 farr[i] = face_compression_map.lookup(id);
573 }
574
575 BM_mesh_remap(bm, varr, nullptr, farr);
576
577 MEM_freeN(varr);
578 MEM_freeN(farr);
579}
580
582{
583 /* WARNING: Deleting any entries after the current one is now handled by the
584 * UndoSystem: BKE_UNDOSYS_TYPE_SCULPT freeing here causes unnecessary complications. */
585
586 /* Create and append the new entry */
588 BLI_addtail(&log->entries, entry);
589 entry->log = log;
590 log->current_entry = entry;
591
592 return entry;
593}
594
596{
597 BMLog *log = entry->log;
598
599 if (!log) {
600 /* Unlink */
601 BLI_assert(!(entry->prev && entry->next));
602 if (entry->prev) {
603 entry->prev->next = nullptr;
604 }
605 else if (entry->next) {
606 entry->next->prev = nullptr;
607 }
608
609 bm_log_entry_free(entry);
610 MEM_delete(entry);
611 return;
612 }
613
614 if (!entry->prev) {
615 /* Release IDs of elements that are deleted by this
616 * entry. Since the entry is at the beginning of the undo
617 * stack, and it's being deleted, those elements can never be
618 * restored. Their IDs can go back into the pool. */
619
620 /* This would never happen usually since first entry of log is
621 * usually dyntopo enable, which, when reverted will free the log
622 * completely. However, it is possible have a stroke instead of
623 * dyntopo enable as first entry if nodes have been cleaned up
624 * after sculpting on a different object than A, B.
625 *
626 * The steps are:
627 * A dyntopo enable - sculpt
628 * B dyntopo enable - sculpt - undo (A objects operators get cleaned up)
629 * A sculpt (now A's log has a sculpt operator as first entry)
630 *
631 * Causing a cleanup at this point will call the code below, however
632 * this will invalidate the state of the log since the deleted vertices
633 * have been reclaimed already on step 2 (see BM_log_cleanup_entry)
634 *
635 * Also, design wise, a first entry should not have any deleted vertices since it
636 * should not have anything to delete them -from-
637 */
638 // bm_log_id_ghash_release(log, entry->deleted_faces);
639 // bm_log_id_ghash_release(log, entry->deleted_verts);
640 }
641 else if (!entry->next) {
642 /* Release IDs of elements that are added by this entry. Since
643 * the entry is at the end of the undo stack, and it's being
644 * deleted, those elements can never be restored. Their IDs
645 * can go back into the pool. */
646 for (const uint id : entry->added_faces.keys()) {
647 range_tree_uint_release(log->unused_ids, id);
648 }
649 for (const uint id : entry->added_verts.keys()) {
650 range_tree_uint_release(log->unused_ids, id);
651 }
652 }
653 else {
654 BLI_assert_msg(0, "Cannot drop BMLogEntry from middle");
655 }
656
657 if (log->current_entry == entry) {
658 log->current_entry = entry->prev;
659 }
660
661 bm_log_entry_free(entry);
662 BLI_remlink(&log->entries, entry);
663 MEM_delete(entry);
664}
665
667{
668 BMLogEntry *entry = log->current_entry;
669
670 if (entry) {
671 log->current_entry = entry->prev;
672
673 /* Delete added faces and verts */
676
677 /* Restore deleted verts and faces */
680
681 /* Restore vertex coordinates, mask, and hflag */
684 }
685}
686
688{
689 BMLogEntry *entry = log->current_entry;
690
691 if (!entry) {
692 /* Currently at the beginning of the undo stack, move to first entry */
693 entry = static_cast<BMLogEntry *>(log->entries.first);
694 }
695 else if (entry->next) {
696 /* Move to next undo entry */
697 entry = entry->next;
698 }
699 else {
700 /* Currently at the end of the undo stack, nothing left to redo */
701 return;
702 }
703
704 log->current_entry = entry;
705
706 if (entry) {
707 /* Re-delete previously deleted faces and verts */
710
711 /* Restore previously added verts and faces */
714
715 /* Restore vertex coordinates, mask, and hflag */
718 }
719}
720
721void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
722{
723 BMLogEntry *entry = log->current_entry;
724 const uint v_id = bm_log_vert_id_get(log, v);
725
726 /* Find or create the BMLogVert entry */
727 if (entry->added_verts.contains(v_id)) {
728 bm_log_vert_bmvert_copy(entry->added_verts.lookup(v_id), v, cd_vert_mask_offset);
729 }
730 else {
732 v_id, [&] { return bm_log_vert_alloc(log, v, cd_vert_mask_offset); });
733 }
734}
735
736void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
737{
738 const uint v_id = range_tree_uint_take_any(log->unused_ids);
739
740 bm_log_vert_id_set(log, v, v_id);
741 BMLogVert *lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
742 log->current_entry->added_verts.add(v_id, lv);
743}
744
746{
747 const uint f_id = bm_log_face_id_get(log, f);
748
750 log->current_entry->modified_faces.add(f_id, lf);
751}
752
754{
755 const uint f_id = range_tree_uint_take_any(log->unused_ids);
756
757 /* Only triangles are supported for now */
758 BLI_assert(f->len == 3);
759
760 bm_log_face_id_set(log, f, f_id);
762 log->current_entry->added_faces.add(f_id, lf);
763}
764
765void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
766{
767 BMLogEntry *entry = log->current_entry;
768 const uint v_id = bm_log_vert_id_get(log, v);
769
770 BLI_assert(!entry->added_verts.contains(v_id) ||
771 (entry->added_verts.contains(v_id) && entry->added_verts.lookup(v_id) != nullptr));
772
773 if (entry->added_verts.remove(v_id)) {
774 range_tree_uint_release(log->unused_ids, v_id);
775 }
776 else {
777 BMLogVert *lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
778 entry->deleted_verts.add(v_id, lv);
779
780 /* If the vertex was modified before deletion, ensure that the
781 * original vertex values are stored */
782 if (std::optional<BMLogVert *> lv_mod = entry->modified_verts.lookup_try(v_id)) {
783 *lv = *lv_mod.value();
784 entry->modified_verts.remove(v_id);
785 }
786 }
787}
788
790{
791 BMLogEntry *entry = log->current_entry;
792 const uint f_id = bm_log_face_id_get(log, f);
793
794 BLI_assert(!entry->added_faces.contains(f_id) ||
795 (entry->added_faces.contains(f_id) && entry->added_faces.lookup(f_id) != nullptr));
796
797 if (entry->added_faces.remove(f_id)) {
798 range_tree_uint_release(log->unused_ids, f_id);
799 }
800 else {
802 entry->deleted_faces.add(f_id, lf);
803 }
804}
805
807{
808 const int cd_vert_mask_offset = CustomData_get_offset_named(
809 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
810
811 /* avoid unnecessary resizing on initialization */
812 if (log->current_entry->added_verts.is_empty()) {
813 log->current_entry->added_verts.reserve(bm->totvert);
814 }
815
816 if (log->current_entry->added_faces.is_empty()) {
817 log->current_entry->added_faces.reserve(bm->totface);
818 }
819
820 BMIter bm_iter;
821 BMVert *v;
822 /* Log all vertices as newly created */
823 BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
824 BM_log_vert_added(log, v, cd_vert_mask_offset);
825 }
826
827 BMFace *f;
828 /* Log all faces as newly created */
829 BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
831 }
832}
833
835{
836 const int cd_vert_mask_offset = CustomData_get_offset_named(
837 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
838
839 BMIter bm_iter;
840 BMFace *f;
841 /* Log deletion of all faces */
842 BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
844 }
845
846 BMVert *v;
847 /* Log deletion of all vertices */
848 BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
849 BM_log_vert_removed(log, v, cd_vert_mask_offset);
850 }
851}
852
854{
855 BMLogEntry *entry = log->current_entry;
856 const uint v_id = bm_log_vert_id_get(log, v);
857
858 if (std::optional<BMLogVert *> log_vert = entry->modified_verts.lookup_try(v_id)) {
859 return log_vert.value()->position;
860 }
861 return nullptr;
862}
863
865{
866 BMLogEntry *entry = log->current_entry;
867 const uint v_id = bm_log_vert_id_get(log, v);
868
869 if (std::optional<BMLogVert *> log_vert = entry->modified_verts.lookup_try(v_id)) {
870 return &log_vert.value()->mask;
871 }
872 return nullptr;
873}
874
875void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
876{
877 BMLogEntry *entry = log->current_entry;
878 BLI_assert(entry);
879
880 const uint v_id = bm_log_vert_id_get(log, v);
881
882 BLI_assert(entry->modified_verts.contains(v_id));
883
884 const BMLogVert *lv = entry->modified_verts.lookup(v_id);
885 *r_co = lv->position;
886 *r_no = lv->normal;
887}
888
889/************************ Debugging and Testing ***********************/
890
891#ifndef NDEBUG
893{
894 return log->current_entry;
895}
896
898{
899 return log->unused_ids;
900}
901
902/* Print the list of entries, marking the current one
903 *
904 * Keep around for debugging */
905void BM_log_print(const BMLog *log, const char *description)
906{
907 const BMLogEntry *entry;
908 const char *current = " <-- current";
909 int i;
910
911 printf("%s:\n", description);
912 printf(" % 2d: [ initial ]%s\n", 0, (!log->current_entry) ? current : "");
913 for (entry = static_cast<const BMLogEntry *>(log->entries.first), i = 1; entry;
914 entry = entry->next, i++)
915 {
916 printf(" % 2d: [%p]%s\n", i, entry, (entry == log->current_entry) ? current : "");
917 }
918}
919
921{
922 if (bm) {
923 printf("BM { totvert=%d totedge=%d totloop=%d faces_num=%d\n",
924 bm->totvert,
925 bm->totedge,
926 bm->totloop,
927 bm->totface);
928
929 if (!bm->totvert) {
930 printf("%s: Warning: empty bmesh\n", __func__);
931 }
932 }
933 else {
934 printf("BM { totvert=unknown totedge=unknown totloop=unknown faces_num=unknown\n");
935 }
936
937 printf("v | added: %d, removed: %d, modified: %d\n",
938 int(entry->added_verts.size()),
939 int(entry->deleted_verts.size()),
940 int(entry->modified_verts.size()));
941 printf("f | added: %d, removed: %d, modified: %d\n",
942 int(entry->added_faces.size()),
943 int(entry->deleted_faces.size()),
944 int(entry->modified_faces.size()));
945 printf("}\n");
946}
947#endif
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void swap_v3_v3(float a[3], float b[3])
unsigned int uint
@ CD_PROP_FLOAT
@ CD_PROP_INT32
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_SET_FLOAT(ele, offset, f)
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
#define BM_ELEM_CD_SET_INT(ele, offset, f)
#define BM_FACE_FIRST_LOOP(p)
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)
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
@ BM_CREATE_NOP
Definition bmesh_core.hh:28
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
BMesh * bm
static int uint_compare(const void *a_v, const void *b_v)
Definition bmesh_log.cc:390
static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mask_offset)
Definition bmesh_log.cc:174
static BMLogEntry * bm_log_entry_create()
Definition bmesh_log.cc:363
void BM_log_all_added(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:806
static void bm_log_faces_unmake(BMesh *bm, BMLog *log, const blender::Map< uint, BMLogFace *, 0 > &faces)
Definition bmesh_log.cc:243
void BM_log_face_added(BMLog *log, BMFace *f)
Definition bmesh_log.cc:753
const float * BM_log_find_original_vert_mask(BMLog *log, BMVert *v)
Definition bmesh_log.cc:864
static void bm_log_face_id_set(BMLog *log, BMFace *f, const uint id)
Definition bmesh_log.cc:146
void BM_log_face_removed(BMLog *log, BMFace *f)
Definition bmesh_log.cc:789
RangeTreeUInt * BM_log_unused_ids(BMLog *log)
Definition bmesh_log.cc:897
static void bm_log_face_values_swap(BMLog *log, const blender::Map< uint, BMLogFace *, 0 > &faces)
Definition bmesh_log.cc:329
static void bm_log_faces_restore(BMesh *bm, BMLog *log, const blender::Map< uint, BMLogFace *, 0 > &faces)
Definition bmesh_log.cc:283
static void bm_log_assign_ids(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:343
void BM_log_free(BMLog *log)
Definition bmesh_log.cc:524
void BM_log_cleanup_entry(BMLogEntry *entry)
Definition bmesh_log.cc:434
static BMLogFace * bm_log_face_alloc(BMLog *log, BMFace *f)
Definition bmesh_log.cc:203
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
Definition bmesh_log.cc:875
static BMVert * bm_log_vert_from_id(BMLog *log, const uint id)
Definition bmesh_log.cc:134
static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, const blender::Map< uint, BMLogVert *, 0 > &verts)
Definition bmesh_log.cc:309
void BM_log_print(const BMLog *log, const char *description)
Definition bmesh_log.cc:905
BMLogEntry * BM_log_current_entry(BMLog *log)
Definition bmesh_log.cc:892
const float * BM_log_find_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:853
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:736
static void bm_log_verts_restore(BMesh *bm, BMLog *log, const blender::Map< uint, BMLogVert *, 0 > &verts)
Definition bmesh_log.cc:266
static float vert_mask_get(BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:163
void BM_log_face_modified(BMLog *log, BMFace *f)
Definition bmesh_log.cc:745
static void bm_log_vert_id_set(BMLog *log, BMVert *v, const uint id)
Definition bmesh_log.cc:127
static void bm_log_verts_unmake(BMesh *bm, BMLog *log, const blender::Map< uint, BMLogVert *, 0 > &verts)
Definition bmesh_log.cc:225
void BM_log_redo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:687
static blender::Map< uint, uint > bm_log_compress_ids_to_indices(uint *ids, uint totid)
Definition bmesh_log.cc:405
static BMLogVert * bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:191
void BM_log_print_entry(BMesh *bm, BMLogEntry *entry)
Definition bmesh_log.cc:920
static void bm_log_entry_free(BMLogEntry *entry)
Definition bmesh_log.cc:373
static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:182
static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
Definition bmesh_log.cc:121
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:539
static uint bm_log_face_id_get(BMLog *log, BMFace *f)
Definition bmesh_log.cc:140
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:765
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:721
void BM_log_entry_drop(BMLogEntry *entry)
Definition bmesh_log.cc:595
BMLog * BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
Definition bmesh_log.cc:471
BMLog * BM_log_create(BMesh *bm)
Definition bmesh_log.cc:419
static BMFace * bm_log_face_from_id(BMLog *log, const uint id)
Definition bmesh_log.cc:153
void BM_log_undo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:666
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:834
BMLogEntry * BM_log_entry_add(BMLog *log)
Definition bmesh_log.cc:581
void BM_mesh_remap(BMesh *bm, const uint *vert_idx, const uint *edge_idx, const uint *face_idx)
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3])
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v
void clear()
Definition BLI_map.hh:1038
std::optional< Value > lookup_try(const Key &key) const
Definition BLI_map.hh:531
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
Value & lookup_or_add_cb(const Key &key, const CreateValueF &create_value)
Definition BLI_map.hh:620
bool remove(const Key &key)
Definition BLI_map.hh:368
int64_t size() const
Definition BLI_map.hh:976
KeyIterator keys() const &
Definition BLI_map.hh:875
bool contains(const Key &key) const
Definition BLI_map.hh:353
int64_t size() const
void append(const T &value)
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
void destruct(T &value)
Definition BLI_pool.hh:63
int64_t size() const
Definition BLI_pool.hh:72
T & construct(ForwardT &&...value)
Definition BLI_pool.hh:45
bool is_empty() const
Definition BLI_pool.hh:80
static float verts[][3]
#define log
#define printf(...)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static char faces[256]
VecBase< float, 3 > float3
BMHeader head
blender::Pool< BMLogFace > face_pool
Definition bmesh_log.cc:58
BMLog * log
Definition bmesh_log.cc:71
BMLogEntry * next
Definition bmesh_log.cc:41
blender::Map< uint, BMLogFace *, 0 > modified_faces
Definition bmesh_log.cc:55
blender::Map< uint, BMLogVert *, 0 > added_verts
Definition bmesh_log.cc:50
blender::Map< uint, BMLogFace *, 0 > deleted_faces
Definition bmesh_log.cc:47
BMLogEntry * prev
Definition bmesh_log.cc:41
blender::Vector< BMLogVert *, 0 > allocated_verts
Definition bmesh_log.cc:60
blender::Pool< BMLogVert > vert_pool
Definition bmesh_log.cc:57
blender::Map< uint, BMLogVert *, 0 > deleted_verts
Definition bmesh_log.cc:46
blender::Vector< BMLogFace *, 0 > allocated_faces
Definition bmesh_log.cc:61
blender::Map< uint, BMLogFace *, 0 > added_faces
Definition bmesh_log.cc:51
blender::Map< uint, BMLogVert *, 0 > modified_verts
Definition bmesh_log.cc:54
std::array< uint, 3 > v_ids
Definition bmesh_log.cc:114
float mask
Definition bmesh_log.cc:110
blender::float3 position
Definition bmesh_log.cc:107
blender::float3 normal
Definition bmesh_log.cc:108
ListBase entries
Definition bmesh_log.cc:92
blender::Map< uint, BMElem *, 0 > id_to_elem
Definition bmesh_log.cc:88
RangeTreeUInt * unused_ids
Definition bmesh_log.cc:76
blender::Map< BMElem *, uint, 0 > elem_to_id
Definition bmesh_log.cc:89
BMLogEntry * current_entry
Definition bmesh_log.cc:103
struct BMEdge * e
struct BMLoop * next
i
Definition text_draw.cc:230