[Bf-blender-cvs] [dad4b61] soc-2014-shapekey: Proportional editing distance for BMeshes

Grigory Revzin noreply at git.blender.org
Tue May 13 14:07:26 CEST 2014


Commit: dad4b619f55a12ab619994b59dbc8ba143e94090
Author: Grigory Revzin
Date:   Sat May 3 21:05:25 2014 +0400
https://developer.blender.org/rBdad4b619f55a12ab619994b59dbc8ba143e94090

Proportional editing distance for BMeshes

Connected, projected and simple falloff distance calculation can now be
done from bmesh_pe.h.

Temporary terrible code alterations to test the falloff routines in transform engine

===================================================================

M	source/blender/bmesh/CMakeLists.txt
M	source/blender/bmesh/bmesh.h
A	source/blender/bmesh/intern/bmesh_pe.c
A	source/blender/bmesh/intern/bmesh_pe.h
M	source/blender/editors/transform/transform_conversions.c

===================================================================

diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 2cd256e..abe97e0 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -118,6 +118,8 @@ set(SRC
 	intern/bmesh_walkers.h
 	intern/bmesh_walkers_impl.c
 	intern/bmesh_walkers_private.h
+	intern/bmesh_pe.h
+	intern/bmesh_pe.c
 
 	intern/bmesh_operator_api.h
 	intern/bmesh_error.h
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 8b5250b..e325375 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -258,7 +258,7 @@ extern "C" {
 #include "intern/bmesh_polygon.h"
 #include "intern/bmesh_queries.h"
 #include "intern/bmesh_walkers.h"
-
+#include "intern/bmesh_pe.h"
 #include "intern/bmesh_inline.h"
 
 #ifdef __cplusplus
diff --git a/source/blender/bmesh/intern/bmesh_pe.c b/source/blender/bmesh/intern/bmesh_pe.c
new file mode 100644
index 0000000..3a7b5aa
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_pe.c
@@ -0,0 +1,273 @@
+/*
+* ***** 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.
+*
+* Contributor(s): Grigory Revzin.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+#include <float.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_math.h"
+#include "MEM_guardedalloc.h"
+
+#include "bmesh.h"
+
+
+static bool vtx_dist_add(BMVert *v, BMVert *v_other,
+	float *dists, const float *dists_prev,
+	float loc_to_world_mtx[3][3])
+{
+	if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) &&
+		(BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0))
+	{
+		const int i = BM_elem_index_get(v);
+		const int i_other = BM_elem_index_get(v_other);
+		float vec[3];
+		float dist_other;
+		sub_v3_v3v3(vec, v->co, v_other->co);
+		mul_m3_v3(loc_to_world_mtx, vec);
+
+		dist_other = dists_prev[i] + len_v3(vec);
+		if (dist_other < dists[i_other]) {
+			dists[i_other] = dist_other;
+			return true;
+		}
+	}
+	return false;
+}
+
+
+void BM_prop_dist_calc_connected(BMesh *bm, float loc_to_world_mtx[3][3], float *dists)
+{
+	/* need to be very careful of feedback loops here, store previous dist's to avoid feedback */
+	float *dists_prev = MEM_mallocN(bm->totvert * sizeof(float), __func__);
+
+	BLI_LINKSTACK_DECLARE(queue, BMVert *);
+
+	/* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */
+	BLI_LINKSTACK_DECLARE(queue_next, BMVert *);
+
+	BLI_LINKSTACK_INIT(queue);
+	BLI_LINKSTACK_INIT(queue_next);
+
+	{
+		BMIter viter;
+		BMVert *v;
+		int i;
+
+		BM_ITER_MESH_INDEX(v, &viter, bm, BM_VERTS_OF_MESH, i) {
+			BM_elem_index_set(v, i); /* set_inline */
+			BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+			if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+				dists[i] = FLT_MAX;
+			}
+			else {
+				BLI_LINKSTACK_PUSH(queue, v);
+				dists[i] = 0.0f;
+			}
+		}
+	}
+
+	do {
+		BMVert *v;
+		LinkNode *lnk;
+
+		memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
+
+		while ((v = BLI_LINKSTACK_POP(queue))) {
+			BMIter iter;
+			BMEdge *e;
+			BMLoop *l;
+
+			/* connected edge-verts */
+			BM_ITER_ELEM(e, &iter, v, BM_EDGES_OF_VERT) {
+				if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
+					BMVert *v_other = BM_edge_other_vert(e, v);
+					/* */
+					if (vtx_dist_add(v, v_other, dists, dists_prev, loc_to_world_mtx)) {
+						if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+							BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+							BLI_LINKSTACK_PUSH(queue_next, v_other);
+						}
+					}
+				}
+			}
+
+			/* connected face-verts (excluding adjacent verts) */
+			BM_ITER_ELEM(l, &iter, v, BM_LOOPS_OF_VERT) {
+				if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len > 3)) {
+					BMLoop *l_end = l->prev;
+					l = l->next->next;
+					do {
+						BMVert *v_other = l->v;
+						if (vtx_dist_add(v, v_other, dists, dists_prev, loc_to_world_mtx)) {
+							if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) {
+								BM_elem_flag_enable(v_other, BM_ELEM_TAG);
+								BLI_LINKSTACK_PUSH(queue_next, v_other);
+							}
+						}
+					} while ((l = l->next) != l_end);
+				}
+			}
+		}
+
+		/* clear for the next loop */
+		for (lnk = queue_next; lnk; lnk = lnk->next) {
+			BM_elem_flag_disable((BMVert *)lnk->link, BM_ELEM_TAG);
+		}
+
+		BLI_LINKSTACK_SWAP(queue, queue_next);
+
+		/* none should be tagged now since 'queue_next' is empty */
+		BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0);
+
+	} while (BLI_LINKSTACK_SIZE(queue));
+
+	BLI_LINKSTACK_FREE(queue);
+	BLI_LINKSTACK_FREE(queue_next);
+
+	MEM_freeN(dists_prev);
+}
+
+void move_selected_verts_to_top(BMesh *bm, int *indexes)
+{
+	BMVert *v;
+	BMIter viter;
+	int a, b, ix;
+
+	b = bm->totvert - 1;
+	a = 0;
+
+	BM_ITER_MESH(v, &viter, bm, BM_VERTS_OF_MESH) {
+		/* if the vert is selected, get its index to top, otherwise to bottom */
+		ix = BM_elem_index_get(v);
+		if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+			indexes[a] = ix;
+			++a;
+		}
+		else {
+			indexes[b] = ix;
+			--b;
+		}
+	}
+}
+
+float dist_proj_sq(float a[3], float b[3], float loc_to_world_mtx[3][3], float proj_plane_n[3])
+{
+	float v[3], v1[3];
+	sub_v3_v3v3(v, a, b);
+	mul_m3_v3(loc_to_world_mtx, v);
+	project_v3_v3v3(v1, v, proj_plane_n);
+	sub_v3_v3(v, v1);
+	return len_squared_v3(v);
+}
+
+float dist_sq(float a[3], float b[3])
+{
+	float v[3];
+	sub_v3_v3v3(v, a, b);
+	return len_squared_v3(v);
+}
+
+float dist_transform(float a[3], float b[3], float loc_to_world_mtx[3][3]) 
+{
+	float v[3];
+	sub_v3_v3v3(v, a, b);
+	mul_v3_m3v3(v, loc_to_world_mtx, v);
+	return len_v3(v);
+}
+
+
+void BM_prop_dist_calc(BMesh *bm, float loc_to_world_mtx[3][3], float proj_plane_n[3], float dists[])
+{
+	int a, b;
+	BMVert *unsel_vert, *sel_vert, *decision_vert;
+	float dist, dist_max;
+	int *vindexes;
+
+	if (bm->totvertsel == bm->totvert) {
+		memset(dists, 0.0f, sizeof(float)* bm->totvert);
+		return;
+	}
+
+	vindexes = MEM_mallocN(sizeof(int) * bm->totvert, __func__);
+
+	memset(dists, FLT_MAX, sizeof(float) * bm->totvert);
+	
+	move_selected_verts_to_top(bm, vindexes);
+	/* we have to loop over all vertices for each vertex, ahh n^2 
+	 * to counter this, we are trying to reduce the loop count by stopping once we are through the selected vertices 
+	 */
+
+	/* some dupli code, but it saves from checking the proj_plane_n on every loop */
+	if (proj_plane_n) {
+		for (a = bm->totvertsel; a < bm->totvert; ++a) {	
+			unsel_vert = BM_vert_at_index(bm, vindexes[a]);
+
+			if (BM_elem_flag_test_bool(unsel_vert, BM_ELEM_HIDDEN))
+				continue;
+
+			dist_max = FLT_MAX;
+
+			for (b = 0; b < bm->totvertsel; ++b) {
+				sel_vert = BM_vert_at_index(bm, vindexes[b]);
+				dist = dist_proj_sq(sel_vert->co, unsel_vert->co, loc_to_world_mtx, proj_plane_n);
+				if (dist <= dist_max) {
+					dist_max = dist;
+				}
+			}
+
+			dists[vindexes[a]] = sqrtf(dist_max);
+		}
+	}
+	else {
+		for (a = bm->totvertsel; a < bm->totvert; ++a) {
+			/* all unselected verts are at the end now */
+			unsel_vert = BM_vert_at_index(bm, vindexes[a]);
+
+			if (BM_elem_flag_test_bool(unsel_vert, BM_ELEM_HIDDEN))
+				continue;
+
+			dist_max = FLT_MAX;
+
+			for (b = 0; b < bm->totvertsel; ++b) {
+				/* all selected verts are at the beginning */
+				sel_vert = BM_vert_at_index(bm, vindexes[b]);
+				/* can use the localspace mesh here - linear transforms never change the relationships between distances - 
+				 *  why do mul_m3_v3 if we don't have to? */
+				dist = dist_sq(sel_vert->co, unsel_vert->co);
+
+				if (dist <= dist_max) {
+					dist_max = dist;
+					decision_vert = BM_vert_at_index(bm, vindexes[b]);
+				}
+			}
+			dists[vindexes[a]] = dist_transform(decision_vert->co, unsel_vert->co, loc_to_world_mtx);
+		}
+	}
+	
+	/* set distance to selected vertices to zero */
+	for (b = 0; b < bm->totvertsel; ++b)
+		dists[vindexes[b]] = 0.0f;
+
+	MEM_freeN(vindexes);
+}
diff --git a/source/blender/bmesh/intern/bmesh_pe.h b/source/blender/bmesh/intern/bmesh_pe.h
new file mode 100644
index 0000000..11c905a
--- /dev/null
+++ b/source/blender/bmesh/intern/bmesh_pe.h
@@ -0,0 +1,29 @@
+/*
+* ***** 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.
+*
+* Contributor(s): Grigory Revzin.
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+
+typedef struct BMesh BMesh;
+
+void BM_prop_dist_calc_connected(BMesh *bm, float loc_to_world_mtx[3][3], float *dists);
+
+void BM_prop_dist_calc(BMesh *bm, float loc_to_world_mtx[3][3], float proj_plane_n[3], float dists[]);
+
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 949ee79..3affa04 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -210,12 +210,35 @@ static void sor

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list