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