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_select.c')
-rw-r--r--source/blender/editors/hair/hair_select.c502
1 files changed, 502 insertions, 0 deletions
diff --git a/source/blender/editors/hair/hair_select.c b/source/blender/editors/hair/hair_select.c
new file mode 100644
index 00000000000..986e669f3a7
--- /dev/null
+++ b/source/blender/editors/hair/hair_select.c
@@ -0,0 +1,502 @@
+/*
+ * ***** 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_select.c
+ * \ingroup edhair
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_editstrands.h"
+
+#include "bmesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_object.h"
+#include "ED_physics.h"
+#include "ED_view3d.h"
+
+#include "hair_intern.h"
+
+BLI_INLINE bool apply_select_action_flag(BMVert *v, int action)
+{
+ bool cursel = BM_elem_flag_test_bool(v, BM_ELEM_SELECT);
+ bool newsel;
+
+ switch (action) {
+ case SEL_SELECT:
+ newsel = true;
+ break;
+ case SEL_DESELECT:
+ newsel = false;
+ break;
+ case SEL_INVERT:
+ newsel = !cursel;
+ break;
+ case SEL_TOGGLE:
+ /* toggle case should be converted to SELECT or DESELECT based on global state */
+ BLI_assert(false);
+ break;
+ }
+
+ if (newsel != cursel) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, newsel);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* poll function */
+typedef bool (*PollVertexCb)(void *userdata, struct BMVert *v);
+/* distance metric function */
+typedef bool (*DistanceVertexCb)(void *userdata, struct BMVert *v, float *dist);
+typedef void (*ActionVertexCb)(void *userdata, struct BMVert *v, int action);
+
+static int hair_select_verts_filter(BMEditStrands *edit, HairEditSelectMode select_mode, int action, PollVertexCb cb, void *userdata)
+{
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+ int tot = 0;
+
+ bm->selectmode = BM_VERT;
+
+ switch (select_mode) {
+ case HAIR_SELECT_STRAND:
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!cb(userdata, v))
+ continue;
+
+ if (apply_select_action_flag(v, action))
+ ++tot;
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+ if (!cb(userdata, v))
+ continue;
+
+ if (apply_select_action_flag(v, action))
+ ++tot;
+ }
+ break;
+ }
+
+ BM_mesh_select_mode_flush(bm);
+
+ return tot;
+}
+
+static bool hair_select_verts_closest(BMEditStrands *edit, HairEditSelectMode select_mode, int action, DistanceVertexCb cb, ActionVertexCb action_cb, void *userdata)
+{
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+
+ float dist;
+ BMVert *closest_v = NULL;
+ float closest_dist = FLT_MAX;
+
+ bm->selectmode = BM_VERT;
+
+ switch (select_mode) {
+ case HAIR_SELECT_STRAND:
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!cb(userdata, v, &dist))
+ continue;
+
+ if (dist < closest_dist) {
+ closest_v = v;
+ closest_dist = dist;
+ }
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+ if (!cb(userdata, v, &dist))
+ continue;
+
+ if (dist < closest_dist) {
+ closest_v = v;
+ closest_dist = dist;
+ }
+ }
+ break;
+ }
+
+ if (closest_v) {
+ action_cb(userdata, closest_v, action);
+
+ BM_mesh_select_mode_flush(bm);
+ return true;
+ }
+ else
+ return false;
+}
+
+static void hair_deselect_all(BMEditStrands *edit)
+{
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, false);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/************************ select/deselect all operator ************************/
+
+static bool poll_vertex_all(void *UNUSED(userdata), struct BMVert *UNUSED(v))
+{
+ return true;
+}
+
+static int select_all_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ int action = RNA_enum_get(op->ptr, "action");
+
+ if (!edit)
+ return 0;
+
+ /* toggle action depends on current global selection state */
+ if (action == SEL_TOGGLE) {
+ if (edit->bm->totvertsel == 0)
+ action = SEL_SELECT;
+ else
+ action = SEL_DESELECT;
+ }
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_all, NULL);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void HAIR_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select/Deselect All";
+ ot->idname = "HAIR_OT_select_all";
+ ot->description = "Select/Deselect all hair vertices";
+
+ /* api callbacks */
+ ot->exec = select_all_exec;
+ ot->poll = hair_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ WM_operator_properties_select_all(ot);
+}
+
+/************************ mouse select operator ************************/
+
+typedef struct DistanceVertexCirleData {
+ HairViewData viewdata;
+ float mval[2];
+ float radsq;
+} DistanceVertexCirleData;
+
+static bool distance_vertex_circle(void *userdata, struct BMVert *v, float *dist)
+{
+ DistanceVertexCirleData *data = userdata;
+
+ return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, dist);
+}
+
+static void closest_vertex_select(void *UNUSED(userdata), struct BMVert *v, int action)
+{
+ apply_select_action_flag(v, action);
+}
+
+int ED_hair_mouse_select(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ float select_radius = ED_view3d_select_dist_px();
+
+ DistanceVertexCirleData data;
+ int action;
+
+ if (!extend && !deselect && !toggle) {
+ hair_deselect_all(edit);
+ }
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radsq = select_radius * select_radius;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (deselect)
+ action = SEL_DESELECT;
+ else
+ action = SEL_INVERT;
+
+ hair_select_verts_closest(edit, settings->select_mode, action, distance_vertex_circle, closest_vertex_select, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/************************ select linked operator ************************/
+
+static void linked_vertices_select(void *UNUSED(userdata), struct BMVert *v, int action)
+{
+ BMVert *lv;
+
+ apply_select_action_flag(v, action);
+
+ for (lv = BM_strands_vert_prev(v); lv; lv = BM_strands_vert_prev(lv))
+ apply_select_action_flag(lv, action);
+ for (lv = BM_strands_vert_next(v); lv; lv = BM_strands_vert_next(lv))
+ apply_select_action_flag(lv, action);
+}
+
+static int select_linked_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ float select_radius = ED_view3d_select_dist_px();
+
+ DistanceVertexCirleData data;
+ int location[2];
+ int action;
+
+ RNA_int_get_array(op->ptr, "location", location);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = location[0];
+ data.mval[1] = location[1];
+ data.radsq = select_radius * select_radius;
+
+ action = RNA_boolean_get(op->ptr, "deselect") ? SEL_DESELECT : SEL_SELECT;
+
+ hair_select_verts_closest(edit, settings->select_mode, action, distance_vertex_circle, linked_vertices_select, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ return select_linked_exec(C, op);
+}
+
+void HAIR_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Linked";
+ ot->idname = "HAIR_OT_select_linked";
+ ot->description = "Select connected vertices";
+
+ /* api callbacks */
+ ot->exec = select_linked_exec;
+ ot->invoke = select_linked_invoke;
+ ot->poll = hair_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect linked keys rather than selecting them");
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "", 0, 16384);
+}
+
+/************************ border select operator ************************/
+
+typedef struct PollVertexRectData {
+ HairViewData viewdata;
+ rcti rect;
+} PollVertexRectData;
+
+static bool poll_vertex_inside_rect(void *userdata, struct BMVert *v)
+{
+ PollVertexRectData *data = userdata;
+
+ return hair_test_vertex_inside_rect(&data->viewdata, &data->rect, v);
+}
+
+int ED_hair_border_select(bContext *C, rcti *rect, bool select, bool extend)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ PollVertexRectData data;
+ int action;
+
+ if (!extend && select)
+ hair_deselect_all(edit);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.rect = *rect;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (select)
+ action = SEL_INVERT;
+ else
+ action = SEL_DESELECT;
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_rect, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+/************************ circle select operator ************************/
+
+typedef struct PollVertexCirleData {
+ HairViewData viewdata;
+ float mval[2];
+ float radsq;
+} PollVertexCirleData;
+
+static bool poll_vertex_inside_circle(void *userdata, struct BMVert *v)
+{
+ PollVertexCirleData *data = userdata;
+ float dist;
+
+ return hair_test_vertex_inside_circle(&data->viewdata, data->mval, data->radsq, v, &dist);
+}
+
+int ED_hair_circle_select(bContext *C, bool select, const int mval[2], float radius)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+ int action = select ? SEL_SELECT : SEL_DESELECT;
+
+ PollVertexCirleData data;
+ int tot;
+
+ if (!edit)
+ return 0;
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radsq = radius * radius;
+
+ tot = hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_circle, &data);
+
+ return tot;
+}
+
+/************************ lasso select operator ************************/
+
+typedef struct PollVertexLassoData {
+ HairViewData viewdata;
+ const int (*mcoords)[2];
+ short moves;
+} PollVertexLassoData;
+
+static bool poll_vertex_inside_lasso(void *userdata, struct BMVert *v)
+{
+ PollVertexLassoData *data = userdata;
+
+ return hair_test_vertex_inside_lasso(&data->viewdata, data->mcoords, data->moves, v);
+}
+
+int ED_hair_lasso_select(bContext *C, const int mcoords[][2], const short moves, bool extend, bool select)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ BMEditStrands *edit = BKE_editstrands_from_object(ob);
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ PollVertexLassoData data;
+ int action;
+
+ if (!extend && select)
+ hair_deselect_all(edit);
+
+ hair_init_viewdata(C, &data.viewdata);
+ data.mcoords = mcoords;
+ data.moves = moves;
+
+ if (extend)
+ action = SEL_SELECT;
+ else if (select)
+ action = SEL_INVERT;
+ else
+ action = SEL_DESELECT;
+
+ hair_select_verts_filter(edit, settings->select_mode, action, poll_vertex_inside_lasso, &data);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW | NA_SELECTED, ob);
+
+ return OPERATOR_FINISHED;
+}