[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