Blender V4.3
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
20#include "MEM_guardedalloc.h"
21
22#include "BLI_ghash.h"
23#include "BLI_listbase.h"
24#include "BLI_math_vector.h"
25#include "BLI_mempool.h"
26#include "BLI_utildefines.h"
27
28#include "BKE_customdata.hh"
29
30#include "bmesh.hh"
31#include "bmesh_log.hh"
32#include "range_tree.h"
33
34#include "BLI_strict_flags.h" /* Keep last. */
35
36struct BMLogEntry {
38
39 /* The following #GHash members map from an element ID to one of the log types above. */
40
47
51
54
64};
65
97
98struct BMLogVert {
99 float co[3];
100 float no[3];
101 char hflag;
102 float mask;
103};
104
105struct BMLogFace {
107 char hflag;
108};
109
110/************************* Get/set element IDs ************************/
111
112/* bypass actual hashing, the keys don't overlap */
113#define logkey_hash BLI_ghashutil_inthash_p_simple
114#define logkey_cmp BLI_ghashutil_intcmp
115
116/* Get the vertex's unique ID from the log */
118{
119 BLI_assert(BLI_ghash_haskey(log->elem_to_id, v));
120 return POINTER_AS_UINT(BLI_ghash_lookup(log->elem_to_id, v));
121}
122
123/* Set the vertex's unique ID in the log */
125{
126 void *vid = POINTER_FROM_UINT(id);
127
128 BLI_ghash_reinsert(log->id_to_elem, vid, v, nullptr, nullptr);
129 BLI_ghash_reinsert(log->elem_to_id, v, vid, nullptr, nullptr);
130}
131
132/* Get a vertex from its unique ID */
134{
135 void *key = POINTER_FROM_UINT(id);
136 BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
137 return static_cast<BMVert *>(BLI_ghash_lookup(log->id_to_elem, key));
138}
139
140/* Get the face's unique ID from the log */
142{
143 BLI_assert(BLI_ghash_haskey(log->elem_to_id, f));
144 return POINTER_AS_UINT(BLI_ghash_lookup(log->elem_to_id, f));
145}
146
147/* Set the face's unique ID in the log */
149{
150 void *fid = POINTER_FROM_UINT(id);
151
152 BLI_ghash_reinsert(log->id_to_elem, fid, f, nullptr, nullptr);
153 BLI_ghash_reinsert(log->elem_to_id, f, fid, nullptr, nullptr);
154}
155
156/* Get a face from its unique ID */
158{
159 void *key = POINTER_FROM_UINT(id);
160 BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
161 return static_cast<BMFace *>(BLI_ghash_lookup(log->id_to_elem, key));
162}
163
164/************************ BMLogVert / BMLogFace ***********************/
165
166/* Get a vertex's paint-mask value
167 *
168 * Returns zero if no paint-mask layer is present */
169static float vert_mask_get(BMVert *v, const int cd_vert_mask_offset)
170{
171 if (cd_vert_mask_offset != -1) {
172 return BM_ELEM_CD_GET_FLOAT(v, cd_vert_mask_offset);
173 }
174 return 0.0f;
175}
176
177/* Set a vertex's paint-mask value
178 *
179 * Has no effect is no paint-mask layer is present */
180static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mask_offset)
181{
182 if (cd_vert_mask_offset != -1) {
183 BM_ELEM_CD_SET_FLOAT(v, cd_vert_mask_offset, new_mask);
184 }
185}
186
187/* Update a BMLogVert with data from a BMVert */
188static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
189{
190 copy_v3_v3(lv->co, v->co);
191 copy_v3_v3(lv->no, v->no);
192 lv->mask = vert_mask_get(v, cd_vert_mask_offset);
193 lv->hflag = v->head.hflag;
194}
195
196/* Allocate and initialize a BMLogVert */
197static BMLogVert *bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
198{
199 BMLogEntry *entry = log->current_entry;
200 BMLogVert *lv = static_cast<BMLogVert *>(BLI_mempool_alloc(entry->pool_verts));
201
202 bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
203
204 return lv;
205}
206
207/* Allocate and initialize a BMLogFace */
209{
210 BMLogEntry *entry = log->current_entry;
211 BMLogFace *lf = static_cast<BMLogFace *>(BLI_mempool_alloc(entry->pool_faces));
212 BMVert *v[3];
213
214 BLI_assert(f->len == 3);
215
216 // BM_iter_as_array(nullptr, BM_VERTS_OF_FACE, f, (void **)v, 3);
218
219 lf->v_ids[0] = bm_log_vert_id_get(log, v[0]);
220 lf->v_ids[1] = bm_log_vert_id_get(log, v[1]);
221 lf->v_ids[2] = bm_log_vert_id_get(log, v[2]);
222
223 lf->hflag = f->head.hflag;
224 return lf;
225}
226
227/************************ Helpers for undo/redo ***********************/
228
230{
231 const int cd_vert_mask_offset = CustomData_get_offset_named(
232 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
233
234 GHashIterator gh_iter;
235 GHASH_ITER (gh_iter, verts) {
236 void *key = BLI_ghashIterator_getKey(&gh_iter);
237 BMLogVert *lv = static_cast<BMLogVert *>(BLI_ghashIterator_getValue(&gh_iter));
238 uint id = POINTER_AS_UINT(key);
240
241 /* Ensure the log has the final values of the vertex before
242 * deleting it */
243 bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
244
245 BM_vert_kill(bm, v);
246 }
247}
248
249static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
250{
251 GHashIterator gh_iter;
252 GHASH_ITER (gh_iter, faces) {
253 void *key = BLI_ghashIterator_getKey(&gh_iter);
254 uint id = POINTER_AS_UINT(key);
256 BMEdge *e_tri[3];
257 BMLoop *l_iter;
258 int i;
259
260 l_iter = BM_FACE_FIRST_LOOP(f);
261 for (i = 0; i < 3; i++, l_iter = l_iter->next) {
262 e_tri[i] = l_iter->e;
263 }
264
265 /* Remove any unused edges */
266 BM_face_kill(bm, f);
267 for (i = 0; i < 3; i++) {
268 if (BM_edge_is_wire(e_tri[i])) {
269 BM_edge_kill(bm, e_tri[i]);
270 }
271 }
272 }
273}
274
276{
277 const int cd_vert_mask_offset = CustomData_get_offset_named(
278 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
279
280 GHashIterator gh_iter;
281 GHASH_ITER (gh_iter, verts) {
282 void *key = BLI_ghashIterator_getKey(&gh_iter);
283 BMLogVert *lv = static_cast<BMLogVert *>(BLI_ghashIterator_getValue(&gh_iter));
284 BMVert *v = BM_vert_create(bm, lv->co, nullptr, BM_CREATE_NOP);
285 vert_mask_set(v, lv->mask, cd_vert_mask_offset);
286 v->head.hflag = lv->hflag;
287 copy_v3_v3(v->no, lv->no);
289 }
290}
291
293{
294 GHashIterator gh_iter;
295 const int cd_face_sets = CustomData_get_offset_named(
296 &bm->pdata, CD_PROP_INT32, ".sculpt_face_set");
297
298 GHASH_ITER (gh_iter, faces) {
299 void *key = BLI_ghashIterator_getKey(&gh_iter);
300 BMLogFace *lf = static_cast<BMLogFace *>(BLI_ghashIterator_getValue(&gh_iter));
301 BMVert *v[3] = {
305 };
306 BMFace *f;
307
308 f = BM_face_create_verts(bm, v, 3, nullptr, BM_CREATE_NOP, true);
309 f->head.hflag = lf->hflag;
311
312 /* Ensure face sets have valid values. Fixes #80174. */
313 if (cd_face_sets != -1) {
314 BM_ELEM_CD_SET_INT(f, cd_face_sets, 1);
315 }
316 }
317}
318
320{
321 const int cd_vert_mask_offset = CustomData_get_offset_named(
322 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
323
324 GHashIterator gh_iter;
325 GHASH_ITER (gh_iter, verts) {
326 void *key = BLI_ghashIterator_getKey(&gh_iter);
327 BMLogVert *lv = static_cast<BMLogVert *>(BLI_ghashIterator_getValue(&gh_iter));
328 uint id = POINTER_AS_UINT(key);
330 float mask;
331
332 swap_v3_v3(v->co, lv->co);
333 swap_v3_v3(v->no, lv->no);
334 std::swap(v->head.hflag, lv->hflag);
335 mask = lv->mask;
336 lv->mask = vert_mask_get(v, cd_vert_mask_offset);
337 vert_mask_set(v, mask, cd_vert_mask_offset);
338 }
339}
340
342{
343 GHashIterator gh_iter;
344 GHASH_ITER (gh_iter, faces) {
345 void *key = BLI_ghashIterator_getKey(&gh_iter);
346 BMLogFace *lf = static_cast<BMLogFace *>(BLI_ghashIterator_getValue(&gh_iter));
347 uint id = POINTER_AS_UINT(key);
349
350 std::swap(f->head.hflag, lf->hflag);
351 }
352}
353
354/**********************************************************************/
355
356/* Assign unique IDs to all vertices and faces already in the BMesh */
358{
359 BMIter iter;
360 BMVert *v;
361 BMFace *f;
362
363 /* Generate vertex IDs */
364 BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
365 uint id = range_tree_uint_take_any(log->unused_ids);
367 }
368
369 /* Generate face IDs */
370 BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
371 uint id = range_tree_uint_take_any(log->unused_ids);
372 bm_log_face_id_set(log, f, id);
373 }
374}
375
376/* Allocate an empty log entry */
378{
379 BMLogEntry *entry = static_cast<BMLogEntry *>(MEM_callocN(sizeof(BMLogEntry), __func__));
380
383 entry->added_verts = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
384 entry->added_faces = BLI_ghash_new(logkey_hash, logkey_cmp, __func__);
387
388 entry->pool_verts = BLI_mempool_create(sizeof(BMLogVert), 0, 64, BLI_MEMPOOL_NOP);
389 entry->pool_faces = BLI_mempool_create(sizeof(BMLogFace), 0, 64, BLI_MEMPOOL_NOP);
390
391 return entry;
392}
393
394/* Free the data in a log entry
395 *
396 * NOTE: does not free the log entry itself. */
397static void bm_log_entry_free(BMLogEntry *entry)
398{
399 BLI_ghash_free(entry->deleted_verts, nullptr, nullptr);
400 BLI_ghash_free(entry->deleted_faces, nullptr, nullptr);
401 BLI_ghash_free(entry->added_verts, nullptr, nullptr);
402 BLI_ghash_free(entry->added_faces, nullptr, nullptr);
403 BLI_ghash_free(entry->modified_verts, nullptr, nullptr);
404 BLI_ghash_free(entry->modified_faces, nullptr, nullptr);
405
408}
409
410static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
411{
412 GHashIterator gh_iter;
413
414 GHASH_ITER (gh_iter, id_ghash) {
415 void *key = BLI_ghashIterator_getKey(&gh_iter);
416 uint id = POINTER_AS_UINT(key);
417
418 range_tree_uint_retake(unused_ids, id);
419 }
420}
421
422static int uint_compare(const void *a_v, const void *b_v)
423{
424 const uint *a = static_cast<const uint *>(a_v);
425 const uint *b = static_cast<const uint *>(b_v);
426 return (*a) < (*b);
427}
428
429/* Remap IDs to contiguous indices
430 *
431 * E.g. if the vertex IDs are (4, 1, 10, 3), the mapping will be:
432 * 4 -> 2
433 * 1 -> 0
434 * 10 -> 3
435 * 3 -> 1
436 */
438{
439 GHash *map = BLI_ghash_int_new_ex(__func__, totid);
440 uint i;
441
442 qsort(ids, totid, sizeof(*ids), uint_compare);
443
444 for (i = 0; i < totid; i++) {
445 void *key = POINTER_FROM_UINT(ids[i]);
446 void *val = POINTER_FROM_UINT(i);
447 BLI_ghash_insert(map, key, val);
448 }
449
450 return map;
451}
452
453/* Release all ID keys in id_ghash */
454static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
455{
456 GHashIterator gh_iter;
457
458 GHASH_ITER (gh_iter, id_ghash) {
459 void *key = BLI_ghashIterator_getKey(&gh_iter);
460 uint id = POINTER_AS_UINT(key);
461 range_tree_uint_release(log->unused_ids, id);
462 }
463}
464
465/***************************** Public API *****************************/
466
468{
469 BMLog *log = static_cast<BMLog *>(MEM_callocN(sizeof(*log), __func__));
470 const uint reserve_num = uint(bm->totvert + bm->totface);
471
472 log->unused_ids = range_tree_uint_alloc(0, uint(-1));
473 log->id_to_elem = BLI_ghash_new_ex(logkey_hash, logkey_cmp, __func__, reserve_num);
474 log->elem_to_id = BLI_ghash_ptr_new_ex(__func__, reserve_num);
475
476 /* Assign IDs to all existing vertices and faces */
478
479 return log;
480}
481
483{
484 BMLog *log = entry->log;
485
486 if (log) {
487 /* Take all used IDs */
488 bm_log_id_ghash_retake(log->unused_ids, entry->deleted_verts);
489 bm_log_id_ghash_retake(log->unused_ids, entry->deleted_faces);
490 bm_log_id_ghash_retake(log->unused_ids, entry->added_verts);
491 bm_log_id_ghash_retake(log->unused_ids, entry->added_faces);
492 bm_log_id_ghash_retake(log->unused_ids, entry->modified_verts);
493 bm_log_id_ghash_retake(log->unused_ids, entry->modified_faces);
494
495 /* delete entries to avoid releasing ids in node cleanup */
496 BLI_ghash_clear(entry->deleted_verts, nullptr, nullptr);
497 BLI_ghash_clear(entry->deleted_faces, nullptr, nullptr);
498 BLI_ghash_clear(entry->added_verts, nullptr, nullptr);
499 BLI_ghash_clear(entry->added_faces, nullptr, nullptr);
500 BLI_ghash_clear(entry->modified_verts, nullptr, nullptr);
501 }
502}
503
505{
507
508 if (entry->prev) {
509 log->current_entry = entry;
510 }
511 else {
512 log->current_entry = nullptr;
513 }
514
515 /* Let BMLog manage the entry list again */
516 log->entries.first = log->entries.last = entry;
517
518 {
519 while (entry->prev) {
520 entry = entry->prev;
521 log->entries.first = entry;
522 }
523 entry = static_cast<BMLogEntry *>(log->entries.last);
524 while (entry->next) {
525 entry = entry->next;
526 log->entries.last = entry;
527 }
528 }
529
530 for (entry = static_cast<BMLogEntry *>(log->entries.first); entry; entry = entry->next) {
531 entry->log = log;
532
533 /* Take all used IDs */
534 bm_log_id_ghash_retake(log->unused_ids, entry->deleted_verts);
535 bm_log_id_ghash_retake(log->unused_ids, entry->deleted_faces);
536 bm_log_id_ghash_retake(log->unused_ids, entry->added_verts);
537 bm_log_id_ghash_retake(log->unused_ids, entry->added_faces);
538 bm_log_id_ghash_retake(log->unused_ids, entry->modified_verts);
539 bm_log_id_ghash_retake(log->unused_ids, entry->modified_faces);
540 }
541
542 return log;
543}
544
546{
547 if (log->unused_ids) {
548 range_tree_uint_free(log->unused_ids);
549 }
550
551 if (log->id_to_elem) {
552 BLI_ghash_free(log->id_to_elem, nullptr, nullptr);
553 }
554
555 if (log->elem_to_id) {
556 BLI_ghash_free(log->elem_to_id, nullptr, nullptr);
557 }
558
559 /* Clear the BMLog references within each entry, but do not free
560 * the entries themselves */
561 LISTBASE_FOREACH (BMLogEntry *, entry, &log->entries) {
562 entry->log = nullptr;
563 }
564
565 MEM_freeN(log);
566}
567
569{
570 return BLI_listbase_count(&log->entries);
571}
572
574{
575 uint *varr;
576 uint *farr;
577
578 GHash *id_to_idx;
579
580 BMIter bm_iter;
581 BMVert *v;
582 BMFace *f;
583
584 uint i;
585
586 /* Put all vertex IDs into an array */
587 varr = static_cast<uint *>(MEM_mallocN(sizeof(int) * size_t(bm->totvert), __func__));
588 BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
589 varr[i] = bm_log_vert_id_get(log, v);
590 }
591
592 /* Put all face IDs into an array */
593 farr = static_cast<uint *>(MEM_mallocN(sizeof(int) * size_t(bm->totface), __func__));
594 BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
595 farr[i] = bm_log_face_id_get(log, f);
596 }
597
598 /* Create BMVert index remap array */
599 id_to_idx = bm_log_compress_ids_to_indices(varr, uint(bm->totvert));
600 BM_ITER_MESH_INDEX (v, &bm_iter, bm, BM_VERTS_OF_MESH, i) {
601 const uint id = bm_log_vert_id_get(log, v);
602 const void *key = POINTER_FROM_UINT(id);
603 const void *val = BLI_ghash_lookup(id_to_idx, key);
604 varr[i] = POINTER_AS_UINT(val);
605 }
606 BLI_ghash_free(id_to_idx, nullptr, nullptr);
607
608 /* Create BMFace index remap array */
609 id_to_idx = bm_log_compress_ids_to_indices(farr, uint(bm->totface));
610 BM_ITER_MESH_INDEX (f, &bm_iter, bm, BM_FACES_OF_MESH, i) {
611 const uint id = bm_log_face_id_get(log, f);
612 const void *key = POINTER_FROM_UINT(id);
613 const void *val = BLI_ghash_lookup(id_to_idx, key);
614 farr[i] = POINTER_AS_UINT(val);
615 }
616 BLI_ghash_free(id_to_idx, nullptr, nullptr);
617
618 BM_mesh_remap(bm, varr, nullptr, farr);
619
620 MEM_freeN(varr);
621 MEM_freeN(farr);
622}
623
625{
626 /* WARNING: this is now handled by the UndoSystem: BKE_UNDOSYS_TYPE_SCULPT
627 * freeing here causes unnecessary complications. */
628 BMLogEntry *entry;
629#if 0
630 /* Delete any entries after the current one */
631 entry = log->current_entry;
632 if (entry) {
634 for (entry = entry->next; entry; entry = next) {
635 next = entry->next;
636 bm_log_entry_free(entry);
637 BLI_freelinkN(&log->entries, entry);
638 }
639 }
640#endif
641
642 /* Create and append the new entry */
643 entry = bm_log_entry_create();
644 BLI_addtail(&log->entries, entry);
645 entry->log = log;
646 log->current_entry = entry;
647
648 return entry;
649}
650
652{
653 BMLog *log = entry->log;
654
655 if (!log) {
656 /* Unlink */
657 BLI_assert(!(entry->prev && entry->next));
658 if (entry->prev) {
659 entry->prev->next = nullptr;
660 }
661 else if (entry->next) {
662 entry->next->prev = nullptr;
663 }
664
665 bm_log_entry_free(entry);
666 MEM_freeN(entry);
667 return;
668 }
669
670 if (!entry->prev) {
671 /* Release IDs of elements that are deleted by this
672 * entry. Since the entry is at the beginning of the undo
673 * stack, and it's being deleted, those elements can never be
674 * restored. Their IDs can go back into the pool. */
675
676 /* This would never happen usually since first entry of log is
677 * usually dyntopo enable, which, when reverted will free the log
678 * completely. However, it is possible have a stroke instead of
679 * dyntopo enable as first entry if nodes have been cleaned up
680 * after sculpting on a different object than A, B.
681 *
682 * The steps are:
683 * A dyntopo enable - sculpt
684 * B dyntopo enable - sculpt - undo (A objects operators get cleaned up)
685 * A sculpt (now A's log has a sculpt operator as first entry)
686 *
687 * Causing a cleanup at this point will call the code below, however
688 * this will invalidate the state of the log since the deleted vertices
689 * have been reclaimed already on step 2 (see BM_log_cleanup_entry)
690 *
691 * Also, design wise, a first entry should not have any deleted vertices since it
692 * should not have anything to delete them -from-
693 */
694 // bm_log_id_ghash_release(log, entry->deleted_faces);
695 // bm_log_id_ghash_release(log, entry->deleted_verts);
696 }
697 else if (!entry->next) {
698 /* Release IDs of elements that are added by this entry. Since
699 * the entry is at the end of the undo stack, and it's being
700 * deleted, those elements can never be restored. Their IDs
701 * can go back into the pool. */
704 }
705 else {
706 BLI_assert_msg(0, "Cannot drop BMLogEntry from middle");
707 }
708
709 if (log->current_entry == entry) {
710 log->current_entry = entry->prev;
711 }
712
713 bm_log_entry_free(entry);
714 BLI_freelinkN(&log->entries, entry);
715}
716
718{
719 BMLogEntry *entry = log->current_entry;
720
721 if (entry) {
722 log->current_entry = entry->prev;
723
724 /* Delete added faces and verts */
727
728 /* Restore deleted verts and faces */
731
732 /* Restore vertex coordinates, mask, and hflag */
735 }
736}
737
739{
740 BMLogEntry *entry = log->current_entry;
741
742 if (!entry) {
743 /* Currently at the beginning of the undo stack, move to first entry */
744 entry = static_cast<BMLogEntry *>(log->entries.first);
745 }
746 else if (entry->next) {
747 /* Move to next undo entry */
748 entry = entry->next;
749 }
750 else {
751 /* Currently at the end of the undo stack, nothing left to redo */
752 return;
753 }
754
755 log->current_entry = entry;
756
757 if (entry) {
758 /* Re-delete previously deleted faces and verts */
761
762 /* Restore previously added verts and faces */
765
766 /* Restore vertex coordinates, mask, and hflag */
769 }
770}
771
772void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
773{
774 BMLogEntry *entry = log->current_entry;
775 BMLogVert *lv;
776 uint v_id = bm_log_vert_id_get(log, v);
777 void *key = POINTER_FROM_UINT(v_id);
778 void **val_p;
779
780 /* Find or create the BMLogVert entry */
781 if ((lv = static_cast<BMLogVert *>(BLI_ghash_lookup(entry->added_verts, key)))) {
782 bm_log_vert_bmvert_copy(lv, v, cd_vert_mask_offset);
783 }
784 else if (!BLI_ghash_ensure_p(entry->modified_verts, key, &val_p)) {
785 lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
786 *val_p = lv;
787 }
788}
789
790void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
791{
792 BMLogVert *lv;
793 uint v_id = range_tree_uint_take_any(log->unused_ids);
794 void *key = POINTER_FROM_UINT(v_id);
795
796 bm_log_vert_id_set(log, v, v_id);
797 lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
798 BLI_ghash_insert(log->current_entry->added_verts, key, lv);
799}
800
802{
803 BMLogFace *lf;
804 uint f_id = bm_log_face_id_get(log, f);
805 void *key = POINTER_FROM_UINT(f_id);
806
807 lf = bm_log_face_alloc(log, f);
808 BLI_ghash_insert(log->current_entry->modified_faces, key, lf);
809}
810
812{
813 BMLogFace *lf;
814 uint f_id = range_tree_uint_take_any(log->unused_ids);
815 void *key = POINTER_FROM_UINT(f_id);
816
817 /* Only triangles are supported for now */
818 BLI_assert(f->len == 3);
819
820 bm_log_face_id_set(log, f, f_id);
821 lf = bm_log_face_alloc(log, f);
822 BLI_ghash_insert(log->current_entry->added_faces, key, lf);
823}
824
825void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
826{
827 BMLogEntry *entry = log->current_entry;
828 uint v_id = bm_log_vert_id_get(log, v);
829 void *key = POINTER_FROM_UINT(v_id);
830
831 /* if it has a key, it shouldn't be nullptr */
832 BLI_assert(!!BLI_ghash_lookup(entry->added_verts, key) ==
833 !!BLI_ghash_haskey(entry->added_verts, key));
834
835 if (BLI_ghash_remove(entry->added_verts, key, nullptr, nullptr)) {
836 range_tree_uint_release(log->unused_ids, v_id);
837 }
838 else {
839 BMLogVert *lv, *lv_mod;
840
841 lv = bm_log_vert_alloc(log, v, cd_vert_mask_offset);
842 BLI_ghash_insert(entry->deleted_verts, key, lv);
843
844 /* If the vertex was modified before deletion, ensure that the
845 * original vertex values are stored */
846 if ((lv_mod = static_cast<BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key)))) {
847 (*lv) = (*lv_mod);
848 BLI_ghash_remove(entry->modified_verts, key, nullptr, nullptr);
849 }
850 }
851}
852
854{
855 BMLogEntry *entry = log->current_entry;
856 uint f_id = bm_log_face_id_get(log, f);
857 void *key = POINTER_FROM_UINT(f_id);
858
859 /* if it has a key, it shouldn't be nullptr */
860 BLI_assert(!!BLI_ghash_lookup(entry->added_faces, key) ==
861 !!BLI_ghash_haskey(entry->added_faces, key));
862
863 if (BLI_ghash_remove(entry->added_faces, key, nullptr, nullptr)) {
864 range_tree_uint_release(log->unused_ids, f_id);
865 }
866 else {
867 BMLogFace *lf;
868
869 lf = bm_log_face_alloc(log, f);
870 BLI_ghash_insert(entry->deleted_faces, key, lf);
871 }
872}
873
875{
876 const int cd_vert_mask_offset = CustomData_get_offset_named(
877 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
878 BMIter bm_iter;
879 BMVert *v;
880 BMFace *f;
881
882 /* avoid unnecessary resizing on initialization */
883 if (BLI_ghash_len(log->current_entry->added_verts) == 0) {
884 BLI_ghash_reserve(log->current_entry->added_verts, uint(bm->totvert));
885 }
886
887 if (BLI_ghash_len(log->current_entry->added_faces) == 0) {
888 BLI_ghash_reserve(log->current_entry->added_faces, uint(bm->totface));
889 }
890
891 /* Log all vertices as newly created */
892 BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
893 BM_log_vert_added(log, v, cd_vert_mask_offset);
894 }
895
896 /* Log all faces as newly created */
897 BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
899 }
900}
901
903{
904 const int cd_vert_mask_offset = CustomData_get_offset_named(
905 &bm->vdata, CD_PROP_FLOAT, ".sculpt_mask");
906 BMIter bm_iter;
907 BMVert *v;
908 BMFace *f;
909
910 /* Log deletion of all faces */
911 BM_ITER_MESH (f, &bm_iter, bm, BM_FACES_OF_MESH) {
913 }
914
915 /* Log deletion of all vertices */
916 BM_ITER_MESH (v, &bm_iter, bm, BM_VERTS_OF_MESH) {
917 BM_log_vert_removed(log, v, cd_vert_mask_offset);
918 }
919}
920
922{
923 BMLogEntry *entry = log->current_entry;
924 const BMLogVert *lv;
925 uint v_id = bm_log_vert_id_get(log, v);
926 void *key = POINTER_FROM_UINT(v_id);
927
928 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
929 return lv == nullptr ? nullptr : lv->co;
930}
931
933{
934 BMLogEntry *entry = log->current_entry;
935 const BMLogVert *lv;
936 uint v_id = bm_log_vert_id_get(log, v);
937 void *key = POINTER_FROM_UINT(v_id);
938
939 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
940 return lv == nullptr ? nullptr : &lv->mask;
941}
942
944{
945 BMLogEntry *entry = log->current_entry;
946 const BMLogVert *lv;
947 uint v_id = bm_log_vert_id_get(log, v);
948 void *key = POINTER_FROM_UINT(v_id);
949
950 BLI_assert(entry);
951
953
954 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
955 return lv->co;
956}
957
959{
960 BMLogEntry *entry = log->current_entry;
961 const BMLogVert *lv;
962 uint v_id = bm_log_vert_id_get(log, v);
963 void *key = POINTER_FROM_UINT(v_id);
964
965 BLI_assert(entry);
966
968
969 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
970 return lv->no;
971}
972
974{
975 BMLogEntry *entry = log->current_entry;
976 const BMLogVert *lv;
977 uint v_id = bm_log_vert_id_get(log, v);
978 void *key = POINTER_FROM_UINT(v_id);
979
980 BLI_assert(entry);
981
983
984 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
985 return lv->mask;
986}
987
988void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
989{
990 BMLogEntry *entry = log->current_entry;
991 const BMLogVert *lv;
992 uint v_id = bm_log_vert_id_get(log, v);
993 void *key = POINTER_FROM_UINT(v_id);
994
995 BLI_assert(entry);
996
998
999 lv = static_cast<const BMLogVert *>(BLI_ghash_lookup(entry->modified_verts, key));
1000 *r_co = lv->co;
1001 *r_no = lv->no;
1002}
1003
1004/************************ Debugging and Testing ***********************/
1005
1007{
1008 return log->current_entry;
1009}
1010
1012{
1013 return log->unused_ids;
1014}
1015
1016#if 0
1017/* Print the list of entries, marking the current one
1018 *
1019 * Keep around for debugging */
1020void bm_log_print(const BMLog *log, const char *description)
1021{
1022 const BMLogEntry *entry;
1023 const char *current = " <-- current";
1024 int i;
1025
1026 printf("%s:\n", description);
1027 printf(" % 2d: [ initial ]%s\n", 0, (!log->current_entry) ? current : "");
1028 for (entry = log->entries.first, i = 1; entry; entry = entry->next, i++) {
1029 printf(" % 2d: [%p]%s\n", i, entry, (entry == log->current_entry) ? current : "");
1030 }
1031}
1032#endif
1033
1035{
1036 if (bm) {
1037 printf("BM { totvert=%d totedge=%d totloop=%d faces_num=%d\n",
1038 bm->totvert,
1039 bm->totedge,
1040 bm->totloop,
1041 bm->totface);
1042
1043 if (!bm->totvert) {
1044 printf("%s: Warning: empty bmesh\n", __func__);
1045 }
1046 }
1047 else {
1048 printf("BM { totvert=unknown totedge=unknown totloop=unknown faces_num=unknown\n");
1049 }
1050
1051 printf("v | added: %d, removed: %d, modified: %d\n",
1052 int(BLI_ghash_len(entry->added_verts)),
1053 int(BLI_ghash_len(entry->deleted_verts)),
1054 int(BLI_ghash_len(entry->modified_verts)));
1055 printf("f | added: %d, removed: %d, modified: %d\n",
1056 int(BLI_ghash_len(entry->added_faces)),
1057 int(BLI_ghash_len(entry->deleted_faces)),
1058 int(BLI_ghash_len(entry->modified_faces)));
1059 printf("}\n");
1060}
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:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:819
bool BLI_ghash_reinsert(GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:712
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:855
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:322
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:686
GHash * BLI_ghash_int_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_reserve(GHash *gh, unsigned int nentries_reserve)
Definition BLI_ghash.c:696
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:678
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:702
bool BLI_ghash_remove(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:787
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.c:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:752
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void swap_v3_v3(float a[3], float b[3])
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
@ BLI_MEMPOOL_NOP
Definition BLI_mempool.h:86
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
unsigned int uint
#define POINTER_AS_UINT(i)
#define POINTER_FROM_UINT(i)
@ 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:43
@ BM_CREATE_NOP
Definition bmesh_core.hh:24
#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
ATTR_WARN_UNUSED_RESULT BMesh * bm
static int uint_compare(const void *a_v, const void *b_v)
Definition bmesh_log.cc:422
static void vert_mask_set(BMVert *v, const float new_mask, const int cd_vert_mask_offset)
Definition bmesh_log.cc:180
static BMLogEntry * bm_log_entry_create()
Definition bmesh_log.cc:377
void BM_log_all_added(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:874
void BM_log_face_added(BMLog *log, BMFace *f)
Definition bmesh_log.cc:811
const float * BM_log_find_original_vert_mask(BMLog *log, BMVert *v)
Definition bmesh_log.cc:932
static void bm_log_face_values_swap(BMLog *log, GHash *faces)
Definition bmesh_log.cc:341
void BM_log_face_removed(BMLog *log, BMFace *f)
Definition bmesh_log.cc:853
RangeTreeUInt * BM_log_unused_ids(BMLog *log)
#define logkey_cmp
Definition bmesh_log.cc:114
static void bm_log_assign_ids(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:357
void BM_log_free(BMLog *log)
Definition bmesh_log.cc:545
static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
Definition bmesh_log.cc:249
static void bm_log_face_id_set(BMLog *log, BMFace *f, uint id)
Definition bmesh_log.cc:148
void BM_log_cleanup_entry(BMLogEntry *entry)
Definition bmesh_log.cc:482
static BMLogFace * bm_log_face_alloc(BMLog *log, BMFace *f)
Definition bmesh_log.cc:208
void BM_log_original_vert_data(BMLog *log, BMVert *v, const float **r_co, const float **r_no)
Definition bmesh_log.cc:988
float BM_log_original_mask(BMLog *log, BMVert *v)
Definition bmesh_log.cc:973
static BMFace * bm_log_face_from_id(BMLog *log, uint id)
Definition bmesh_log.cc:157
static GHash * bm_log_compress_ids_to_indices(uint *ids, uint totid)
Definition bmesh_log.cc:437
BMLogEntry * BM_log_current_entry(BMLog *log)
const float * BM_log_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:943
const float * BM_log_find_original_vert_co(BMLog *log, BMVert *v)
Definition bmesh_log.cc:921
void BM_log_vert_added(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:790
static BMVert * bm_log_vert_from_id(BMLog *log, uint id)
Definition bmesh_log.cc:133
static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
Definition bmesh_log.cc:275
static float vert_mask_get(BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:169
void BM_log_face_modified(BMLog *log, BMFace *f)
Definition bmesh_log.cc:801
const float * BM_log_original_vert_no(BMLog *log, BMVert *v)
Definition bmesh_log.cc:958
void BM_log_redo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:738
static BMLogVert * bm_log_vert_alloc(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:197
static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
Definition bmesh_log.cc:292
void BM_log_print_entry(BMesh *bm, BMLogEntry *entry)
static void bm_log_entry_free(BMLogEntry *entry)
Definition bmesh_log.cc:397
static void bm_log_vert_bmvert_copy(BMLogVert *lv, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:188
static uint bm_log_vert_id_get(BMLog *log, BMVert *v)
Definition bmesh_log.cc:117
void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:573
static uint bm_log_face_id_get(BMLog *log, BMFace *f)
Definition bmesh_log.cc:141
void BM_log_vert_removed(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:825
void BM_log_vert_before_modified(BMLog *log, BMVert *v, const int cd_vert_mask_offset)
Definition bmesh_log.cc:772
static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
Definition bmesh_log.cc:319
void BM_log_entry_drop(BMLogEntry *entry)
Definition bmesh_log.cc:651
static void bm_log_id_ghash_release(BMLog *log, GHash *id_ghash)
Definition bmesh_log.cc:454
BMLog * BM_log_from_existing_entries_create(BMesh *bm, BMLogEntry *entry)
Definition bmesh_log.cc:504
BMLog * BM_log_create(BMesh *bm)
Definition bmesh_log.cc:467
#define logkey_hash
Definition bmesh_log.cc:113
static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
Definition bmesh_log.cc:410
void BM_log_undo(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:717
int BM_log_length(const BMLog *log)
Definition bmesh_log.cc:568
void BM_log_before_all_removed(BMesh *bm, BMLog *log)
Definition bmesh_log.cc:902
static void bm_log_vert_id_set(BMLog *log, BMVert *v, uint id)
Definition bmesh_log.cc:124
BMLogEntry * BM_log_entry_add(BMLog *log)
Definition bmesh_log.cc:624
static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
Definition bmesh_log.cc:229
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
local_group_size(16, 16) .push_constant(Type b
#define printf
static float verts[][3]
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 log(float3 v)
ccl_device_inline float4 mask(const int4 mask, const float4 a)
static ulong * next
BMHeader head
GHash * modified_verts
Definition bmesh_log.cc:49
BMLog * log
Definition bmesh_log.cc:63
BMLogEntry * next
Definition bmesh_log.cc:37
BLI_mempool * pool_faces
Definition bmesh_log.cc:53
GHash * added_faces
Definition bmesh_log.cc:46
BLI_mempool * pool_verts
Definition bmesh_log.cc:52
GHash * deleted_verts
Definition bmesh_log.cc:42
BMLogEntry * prev
Definition bmesh_log.cc:37
GHash * added_verts
Definition bmesh_log.cc:45
GHash * modified_faces
Definition bmesh_log.cc:50
GHash * deleted_faces
Definition bmesh_log.cc:43
uint v_ids[3]
Definition bmesh_log.cc:106
float mask
Definition bmesh_log.cc:102
float no[3]
Definition bmesh_log.cc:100
float co[3]
Definition bmesh_log.cc:99
GHash * elem_to_id
Definition bmesh_log.cc:81
ListBase entries
Definition bmesh_log.cc:84
GHash * id_to_elem
Definition bmesh_log.cc:80
RangeTreeUInt * unused_ids
Definition bmesh_log.cc:68
BMLogEntry * current_entry
Definition bmesh_log.cc:95
struct BMEdge * e
struct BMLoop * next
float co[3]
float no[3]
BMHeader head
int totvert
CustomData vdata
int totedge
int totloop
CustomData pdata
int totface