Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/hair/hair_mirror.c')
-rw-r--r--source/blender/editors/hair/hair_mirror.c210
1 files changed, 210 insertions, 0 deletions
diff --git a/source/blender/editors/hair/hair_mirror.c b/source/blender/editors/hair/hair_mirror.c
new file mode 100644
index 00000000000..7f5b14e4b37
--- /dev/null
+++ b/source/blender/editors/hair/hair_mirror.c
@@ -0,0 +1,210 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/hair/hair_mirror.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "BKE_editmesh_bvh.h"
+#include "BKE_editstrands.h"
+
+#include "ED_physics.h"
+#include "ED_util.h"
+
+#include "bmesh.h"
+
+#include "hair_intern.h"
+
+/* TODO use_topology is not yet implemented for strands.
+ * Native strand topology is not very useful for this.
+ * Instead, the topology of the scalp mesh should be used for finding mirrored strand roots,
+ * then the arc- or parametric length of a vertex from the root to find mirrored verts.
+ */
+
+#define BM_SEARCH_MAXDIST_MIRR 0.00002f
+#define BM_CD_LAYER_ID "__mirror_index"
+/**
+ * \param edit Edit strands.
+ * \param use_self Allow a vertex to point to its self (middle verts).
+ * \param use_select Restrict to selected verts.
+ * \param use_topology Use topology mirror.
+ * \param maxdist Distance for close point test.
+ * \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts).
+ */
+void ED_strands_mirror_cache_begin_ex(BMEditStrands *edit, const int axis, const bool use_self, const bool use_select,
+ /* extra args */
+ const bool UNUSED(use_topology), float maxdist, int *r_index)
+{
+ BMesh *bm = edit->bm;
+ BMIter iter;
+ BMVert *v;
+ int cd_vmirr_offset;
+ int i;
+
+ /* one or the other is used depending if topo is enabled */
+ struct BMBVHTree *tree = NULL;
+
+ BM_mesh_elem_table_ensure(bm, BM_VERT);
+
+ if (r_index == NULL) {
+ const char *layer_id = BM_CD_LAYER_ID;
+ edit->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
+ if (edit->mirror_cdlayer == -1) {
+ BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, layer_id);
+ edit->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id);
+ }
+
+ cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT,
+ edit->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT));
+
+ bm->vdata.layers[edit->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY;
+ }
+
+ BM_mesh_elem_index_ensure(bm, BM_VERT);
+
+ tree = BKE_bmbvh_new(edit->bm, NULL, 0, 0, NULL, false);
+
+#define VERT_INTPTR(_v, _i) r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset);
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BLI_assert(BM_elem_index_get(v) == i);
+
+ /* temporary for testing, check for selection */
+ if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ /* do nothing */
+ }
+ else {
+ BMVert *v_mirr;
+ float co[3];
+ int *idx = VERT_INTPTR(v, i);
+
+ copy_v3_v3(co, v->co);
+ co[axis] *= -1.0f;
+ v_mirr = BKE_bmbvh_find_vert_closest(tree, co, maxdist);
+
+ if (v_mirr && (use_self || (v_mirr != v))) {
+ const int i_mirr = BM_elem_index_get(v_mirr);
+ *idx = i_mirr;
+ idx = VERT_INTPTR(v_mirr, i_mirr);
+ *idx = i;
+ }
+ else {
+ *idx = -1;
+ }
+ }
+
+ }
+
+#undef VERT_INTPTR
+
+ BKE_bmbvh_free(tree);
+}
+
+void ED_strands_mirror_cache_begin(BMEditStrands *edit, const int axis,
+ const bool use_self, const bool use_select,
+ const bool use_topology)
+{
+ ED_strands_mirror_cache_begin_ex(edit, axis,
+ use_self, use_select,
+ /* extra args */
+ use_topology, BM_SEARCH_MAXDIST_MIRR, NULL);
+}
+
+BMVert *ED_strands_mirror_get(BMEditStrands *edit, BMVert *v)
+{
+ const int *mirr = CustomData_bmesh_get_layer_n(&edit->bm->vdata, v->head.data, edit->mirror_cdlayer);
+
+ BLI_assert(edit->mirror_cdlayer != -1); /* invalid use */
+
+ if (mirr && *mirr >= 0 && *mirr < edit->bm->totvert) {
+ if (!edit->bm->vtable) {
+ printf("err: should only be called between "
+ "ED_strands_mirror_cache_begin and ED_strands_mirror_cache_end\n");
+ return NULL;
+ }
+
+ return edit->bm->vtable[*mirr];
+ }
+
+ return NULL;
+}
+
+BMEdge *ED_strands_mirror_get_edge(BMEditStrands *edit, BMEdge *e)
+{
+ BMVert *v1_mirr = ED_strands_mirror_get(edit, e->v1);
+ if (v1_mirr) {
+ BMVert *v2_mirr = ED_strands_mirror_get(edit, e->v2);
+ if (v2_mirr) {
+ return BM_edge_exists(v1_mirr, v2_mirr);
+ }
+ }
+
+ return NULL;
+}
+
+void ED_strands_mirror_cache_clear(BMEditStrands *edit, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&edit->bm->vdata, v->head.data, edit->mirror_cdlayer);
+
+ BLI_assert(edit->mirror_cdlayer != -1); /* invalid use */
+
+ if (mirr) {
+ *mirr = -1;
+ }
+}
+
+void ED_strands_mirror_cache_end(BMEditStrands *edit)
+{
+ edit->mirror_cdlayer = -1;
+}
+
+void ED_strands_mirror_apply(BMEditStrands *edit, const int sel_from, const int sel_to)
+{
+ BMIter iter;
+ BMVert *v;
+
+ BLI_assert((edit->bm->vtable != NULL) && ((edit->bm->elem_table_dirty & BM_VERT) == 0));
+
+ BM_ITER_MESH (v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
+ BMVert *mirr = ED_strands_mirror_get(edit, v);
+ if (mirr) {
+ if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
+ copy_v3_v3(mirr->co, v->co);
+ mirr->co[0] *= -1.0f;
+ }
+ }
+ }
+ }
+}