[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53435] trunk/blender/source/blender/bmesh : Add BMLog for efficiently storing changes to vertices and faces
Nicholas Bishop
nicholasbishop at gmail.com
Sun Dec 30 19:24:09 CET 2012
Revision: 53435
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53435
Author: nicholasbishop
Date: 2012-12-30 18:24:08 +0000 (Sun, 30 Dec 2012)
Log Message:
-----------
Add BMLog for efficiently storing changes to vertices and faces
The BMLog is an interface for storing undo/redo steps as a BMesh is
modified. It only stores changes to the BMesh, not full copies.
Currently it supports the following types of changes:
- Adding and removing vertices
- Adding and removing faces
- Moving vertices
- Setting vertex paint-mask values
- Setting vertex hflags
Modified Paths:
--------------
trunk/blender/source/blender/bmesh/CMakeLists.txt
trunk/blender/source/blender/bmesh/SConscript
trunk/blender/source/blender/bmesh/bmesh.h
Added Paths:
-----------
trunk/blender/source/blender/bmesh/intern/bmesh_log.c
trunk/blender/source/blender/bmesh/intern/bmesh_log.h
Modified: trunk/blender/source/blender/bmesh/CMakeLists.txt
===================================================================
--- trunk/blender/source/blender/bmesh/CMakeLists.txt 2012-12-30 18:23:42 UTC (rev 53434)
+++ trunk/blender/source/blender/bmesh/CMakeLists.txt 2012-12-30 18:24:08 UTC (rev 53435)
@@ -31,6 +31,7 @@
../makesdna
../../../intern/guardedalloc
../../../extern/bullet2/src
+ ../../../extern/rangetree
../../../intern/opennl/extern
)
@@ -74,6 +75,8 @@
intern/bmesh_iterators.c
intern/bmesh_iterators.h
intern/bmesh_iterators_inline.h
+ intern/bmesh_log.c
+ intern/bmesh_log.h
intern/bmesh_marking.c
intern/bmesh_marking.h
intern/bmesh_mesh.c
Modified: trunk/blender/source/blender/bmesh/SConscript
===================================================================
--- trunk/blender/source/blender/bmesh/SConscript 2012-12-30 18:23:42 UTC (rev 53434)
+++ trunk/blender/source/blender/bmesh/SConscript 2012-12-30 18:24:08 UTC (rev 53435)
@@ -41,7 +41,9 @@
'../blenkernel',
'#/intern/guardedalloc',
'#/extern/bullet2/src',
- '#/intern/opennl/extern', ]
+ '#/extern/rangetree',
+ '#/intern/opennl/extern'
+ ]
defs = []
Modified: trunk/blender/source/blender/bmesh/bmesh.h
===================================================================
--- trunk/blender/source/blender/bmesh/bmesh.h 2012-12-30 18:23:42 UTC (rev 53434)
+++ trunk/blender/source/blender/bmesh/bmesh.h 2012-12-30 18:24:08 UTC (rev 53435)
@@ -254,6 +254,7 @@
#include "intern/bmesh_core.h"
#include "intern/bmesh_interp.h"
#include "intern/bmesh_iterators.h"
+#include "intern/bmesh_log.h"
#include "intern/bmesh_marking.h"
#include "intern/bmesh_mesh.h"
#include "intern/bmesh_mesh_conv.h"
Added: trunk/blender/source/blender/bmesh/intern/bmesh_log.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_log.c (rev 0)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_log.c 2012-12-30 18:24:08 UTC (rev 53435)
@@ -0,0 +1,962 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_mempool.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_customdata.h"
+
+#include "bmesh.h"
+#include "bmesh_log.h"
+#include "range_tree_c_api.h"
+
+struct BMLogEntry {
+ struct BMLogEntry *next, *prev;
+
+ /* The following GHashes map from an element ID to one of the log
+ * types above */
+
+ /* Elements that were in the previous entry, but have been
+ * deleted */
+ GHash *deleted_verts;
+ GHash *deleted_faces;
+ /* Elements that were not in the previous entry, but are in the
+ * result of this entry */
+ GHash *added_verts;
+ GHash *added_faces;
+
+ /* Vertices whose coordinates, mask value, or hflag have changed */
+ GHash *modified_verts;
+
+ BLI_mempool *pool_verts;
+ BLI_mempool *pool_faces;
+
+ /* This is only needed for dropping BMLogEntries while still in
+ * dynamic-topology mode, as that should release vert/face IDs
+ * back to the BMLog but no BMLog pointer is available at that
+ * time.
+ *
+ * This field is not guaranteed to be valid, any use of it should
+ * check for NULL. */
+ BMLog *log;
+};
+
+struct BMLog {
+ /* Tree of free IDs */
+ struct RangeTreeUInt *unused_ids;
+
+ /* Mapping from unique IDs to vertices and faces
+ *
+ * Each vertex and face in the log gets a unique unsigned integer
+ * assigned. That ID is taken from the set managed by the
+ * unused_ids range tree.
+ *
+ * The ID is needed because element pointers will change as they
+ * are created and deleted.
+ */
+ GHash *id_to_elem;
+ GHash *elem_to_id;
+
+ /* All BMLogEntrys, ordered from earliest to most recent */
+ ListBase entries;
+
+ /* The current log entry from entries list
+ *
+ * If null, then the original mesh from before any of the log
+ * entries is current (i.e. there is nothing left to undo.)
+ *
+ * If equal to the last entry in the entries list, then all log
+ * entries have been applied (i.e. there is nothing left to redo.)
+ */
+ BMLogEntry *current_entry;
+};
+
+typedef struct {
+ float co[3];
+ float mask;
+ char hflag;
+} BMLogVert;
+
+typedef struct {
+ unsigned int v_ids[3];
+} BMLogFace;
+
+/************************* Get/set element IDs ************************/
+
+/* Get the vertex's unique ID from the log */
+static unsigned int bm_log_vert_id_get(BMLog *log, BMVert *v)
+{
+ BLI_assert(BLI_ghash_haskey(log->elem_to_id, v));
+ return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, v));
+}
+
+/* Set the vertex's unique ID in the log */
+static void bm_log_vert_id_set(BMLog *log, BMVert *v, unsigned int id)
+{
+ void *vid = SET_INT_IN_POINTER(id);
+
+ BLI_ghash_remove(log->id_to_elem, vid, NULL, NULL);
+ BLI_ghash_insert(log->id_to_elem, vid, v);
+ BLI_ghash_remove(log->elem_to_id, v, NULL, NULL);
+ BLI_ghash_insert(log->elem_to_id, v, vid);
+}
+
+/* Get a vertex from its unique ID */
+static BMVert *bm_log_vert_from_id(BMLog *log, unsigned int id)
+{
+ void *key = SET_INT_IN_POINTER(id);
+ BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
+ return BLI_ghash_lookup(log->id_to_elem, key);
+}
+
+/* Get the face's unique ID from the log */
+static unsigned int bm_log_face_id_get(BMLog *log, BMFace *f)
+{
+ BLI_assert(BLI_ghash_haskey(log->elem_to_id, f));
+ return GET_INT_FROM_POINTER(BLI_ghash_lookup(log->elem_to_id, f));
+}
+
+/* Set the face's unique ID in the log */
+static void bm_log_face_id_set(BMLog *log, BMFace *f, unsigned int id)
+{
+ void *fid = SET_INT_IN_POINTER(id);
+
+ BLI_ghash_remove(log->id_to_elem, fid, NULL, NULL);
+ BLI_ghash_insert(log->id_to_elem, fid, f);
+ BLI_ghash_remove(log->elem_to_id, f, NULL, NULL);
+ BLI_ghash_insert(log->elem_to_id, f, fid);
+}
+
+/* Get a face from its unique ID */
+static BMFace *bm_log_face_from_id(BMLog *log, unsigned int id)
+{
+ void *key = SET_INT_IN_POINTER(id);
+ BLI_assert(BLI_ghash_haskey(log->id_to_elem, key));
+ return BLI_ghash_lookup(log->id_to_elem, key);
+}
+
+
+/************************ BMLogVert / BMLogFace ***********************/
+
+/* Get a vertex's paint-mask value
+ *
+ * Returns zero if no paint-mask layer is present */
+static float vert_mask_get(BMesh *bm, BMVert *v)
+{
+ CustomData *cd = &bm->vdata;
+ if (CustomData_has_layer(&bm->vdata, CD_PAINT_MASK)) {
+ float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK);
+ return *mask;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* Set a vertex's paint-mask value
+ *
+ * Has no effect is no paint-mask layer is present */
+static void vert_mask_set(BMesh *bm, BMVert *v, float new_mask)
+{
+ CustomData *cd = &bm->vdata;
+ if (CustomData_has_layer(cd, CD_PAINT_MASK)) {
+ float *mask = CustomData_bmesh_get(cd, v->head.data, CD_PAINT_MASK);
+ (*mask) = new_mask;
+ }
+}
+
+/* Update a BMLogVert with data from a BMVert */
+static void bm_log_vert_bmvert_copy(BMesh *bm, BMLogVert *lv, BMVert *v)
+{
+ copy_v3_v3(lv->co, v->co);
+ lv->mask = vert_mask_get(bm, v);
+ lv->hflag = v->head.hflag;
+}
+
+/* Allocate and initialize a BMLogVert */
+static BMLogVert *bm_log_vert_alloc(BMesh *bm, BMLog *log, BMVert *v)
+{
+ BMLogEntry *entry = log->current_entry;
+ BMLogVert *lv = BLI_mempool_alloc(entry->pool_verts);
+
+ bm_log_vert_bmvert_copy(bm, lv, v);
+
+ return lv;
+}
+
+/* Allocate and initialize a BMLogFace */
+static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
+{
+ BMLogEntry *entry = log->current_entry;
+ BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces);
+ BMVert *v[3];
+
+ BLI_assert(f->len == 3);
+
+ BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3);
+
+ lf->v_ids[0] = bm_log_vert_id_get(log, v[0]);
+ lf->v_ids[1] = bm_log_vert_id_get(log, v[1]);
+ lf->v_ids[2] = bm_log_vert_id_get(log, v[2]);
+
+ return lf;
+}
+
+
+/************************ Helpers for undo/redo ***********************/
+
+static void bm_log_verts_unmake(BMesh *bm, BMLog *log, GHash *verts)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, verts) {
+ void *key = BLI_ghashIterator_getKey(&gh_iter);
+ BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
+ unsigned int id = GET_INT_FROM_POINTER(key);
+ BMVert *v = bm_log_vert_from_id(log, id);
+
+ /* Ensure the log has the final values of the vertex before
+ * deleting it */
+ bm_log_vert_bmvert_copy(bm, lv, v);
+
+ BM_vert_kill(bm, v);
+ }
+}
+
+static void bm_log_faces_unmake(BMesh *bm, BMLog *log, GHash *faces)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, faces) {
+ void *key = BLI_ghashIterator_getKey(&gh_iter);
+ unsigned int id = GET_INT_FROM_POINTER(key);
+ BMFace *f = bm_log_face_from_id(log, id);
+
+ BM_face_kill(bm, f);
+ }
+}
+
+static void bm_log_verts_restore(BMesh *bm, BMLog *log, GHash *verts)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, verts) {
+ void *key = BLI_ghashIterator_getKey(&gh_iter);
+ BMLogVert *lv = BLI_ghashIterator_getValue(&gh_iter);
+ BMVert *v = BM_vert_create(bm, lv->co, NULL, 0);
+ v->head.hflag = lv->hflag;
+ vert_mask_set(bm, v, lv->mask);
+ bm_log_vert_id_set(log, v, GET_INT_FROM_POINTER(key));
+ }
+}
+
+static void bm_log_faces_restore(BMesh *bm, BMLog *log, GHash *faces)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, faces) {
+ void *key = BLI_ghashIterator_getKey(&gh_iter);
+ BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
+ BMVert *v[3] = {bm_log_vert_from_id(log, lf->v_ids[0]),
+ bm_log_vert_from_id(log, lf->v_ids[1]),
+ bm_log_vert_from_id(log, lf->v_ids[2])};
+ BMFace *f;
+
+ f = BM_face_create_quad_tri_v(bm, v, 3, NULL, FALSE);
+ bm_log_face_id_set(log, f, GET_INT_FROM_POINTER(key));
+ }
+}
+
+static void bm_log_vert_values_swap(BMesh *bm, BMLog *log, GHash *verts)
+{
+ GHashIterator gh_iter;
+ GHASH_ITER (gh_iter, verts) {
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list