Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / mesh / editmesh_bisect.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 by Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/mesh/editmesh_bisect.c
27  *  \ingroup edmesh
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_object_types.h"
33
34 #include "BLI_math.h"
35
36 #include "BLT_translation.h"
37
38 #include "BKE_global.h"
39 #include "BKE_context.h"
40 #include "BKE_editmesh.h"
41 #include "BKE_report.h"
42
43 #include "RNA_define.h"
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "ED_mesh.h"
50 #include "ED_screen.h"
51 #include "ED_view3d.h"
52
53 #include "mesh_intern.h"  /* own include */
54
55 #define USE_MANIPULATOR
56
57 #ifdef USE_MANIPULATOR
58 #include "ED_manipulator_library.h"
59 #include "ED_util.h"
60 #endif
61
62 static int mesh_bisect_exec(bContext *C, wmOperator *op);
63
64 /* -------------------------------------------------------------------- */
65 /* Model Helpers */
66
67 typedef struct {
68         /* modal only */
69         BMBackup mesh_backup;
70         bool is_first;
71         short twtype;
72 } BisectData;
73
74 static bool mesh_bisect_interactive_calc(
75         bContext *C, wmOperator *op,
76         BMEditMesh *em,
77         float plane_co[3], float plane_no[3])
78 {
79         wmGesture *gesture = op->customdata;
80         BisectData *opdata;
81
82         View3D *v3d = CTX_wm_view3d(C);
83         ARegion *ar = CTX_wm_region(C);
84         RegionView3D *rv3d = ar->regiondata;
85
86         int x_start = RNA_int_get(op->ptr, "xstart");
87         int y_start = RNA_int_get(op->ptr, "ystart");
88         int x_end = RNA_int_get(op->ptr, "xend");
89         int y_end = RNA_int_get(op->ptr, "yend");
90
91         /* reference location (some point in front of the view) for finding a point on a plane */
92         const float *co_ref = rv3d->ofs;
93         float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2];
94         float co_a[3], co_b[3];
95         const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
96
97         opdata = gesture->userdata;
98
99         /* view vector */
100         ED_view3d_win_to_vector(ar, co_a_ss, co_a);
101
102         /* view delta */
103         sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss);
104         ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac);
105
106         /* cross both to get a normal */
107         cross_v3_v3v3(plane_no, co_a, co_b);
108         normalize_v3(plane_no);  /* not needed but nicer for user */
109
110         /* point on plane, can use either start or endpoint */
111         ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co);
112
113         if (opdata->is_first == false)
114                 EDBM_redo_state_restore(opdata->mesh_backup, em, false);
115
116         opdata->is_first = false;
117
118         return true;
119 }
120
121 static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
122 {
123         Object *obedit = CTX_data_edit_object(C);
124         BMEditMesh *em = BKE_editmesh_from_object(obedit);
125         int ret;
126
127         if (em->bm->totedgesel == 0) {
128                 BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required");
129                 return OPERATOR_CANCELLED;
130         }
131
132         /* if the properties are set or there is no rv3d,
133          * skip model and exec immediately */
134
135         if ((CTX_wm_region_view3d(C) == NULL) ||
136             (RNA_struct_property_is_set(op->ptr, "plane_co") &&
137              RNA_struct_property_is_set(op->ptr, "plane_no")))
138         {
139                 return mesh_bisect_exec(C, op);
140         }
141
142         ret = WM_gesture_straightline_invoke(C, op, event);
143         if (ret & OPERATOR_RUNNING_MODAL) {
144                 View3D *v3d = CTX_wm_view3d(C);
145
146                 wmGesture *gesture = op->customdata;
147                 BisectData *opdata;
148
149
150                 opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data");
151                 opdata->mesh_backup = EDBM_redo_state_store(em);
152                 opdata->is_first = true;
153                 gesture->userdata = opdata;
154
155                 /* misc other vars */
156                 G.moving = G_TRANSFORM_EDIT;
157                 opdata->twtype = v3d->twtype;
158                 v3d->twtype = 0;
159
160                 /* initialize modal callout */
161                 ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Click and drag to draw cut line"));
162         }
163         return ret;
164 }
165
166 static void edbm_bisect_exit(bContext *C, BisectData *opdata)
167 {
168         View3D *v3d = CTX_wm_view3d(C);
169         EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
170         v3d->twtype = opdata->twtype;
171         G.moving = 0;
172 }
173
174 static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
175 {
176         wmGesture *gesture = op->customdata;
177         BisectData *opdata = gesture->userdata;
178         BisectData opdata_back = *opdata;  /* annoyance, WM_gesture_straightline_modal, frees */
179         int ret;
180
181         ret = WM_gesture_straightline_modal(C, op, event);
182
183         /* update or clear modal callout */
184         if (event->type == EVT_MODAL_MAP) {
185                 if (event->val == GESTURE_MODAL_BEGIN) {
186                         ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Release to confirm cut line"));
187                 }
188                 else {
189                         ED_area_headerprint(CTX_wm_area(C), NULL);
190                 }
191         }
192
193         if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
194                 edbm_bisect_exit(C, &opdata_back);
195
196 #ifdef USE_MANIPULATOR
197                 /* Setup manipulators */
198                 {
199                         View3D *v3d = CTX_wm_view3d(C);
200                         if (v3d && (v3d->twtype & V3D_MANIPULATOR_DRAW)) {
201                                 WM_manipulator_group_add("MESH_WGT_bisect");
202                         }
203                 }
204 #endif
205         }
206
207         return ret;
208 }
209
210 /* End Model Helpers */
211 /* -------------------------------------------------------------------- */
212
213
214
215 static int mesh_bisect_exec(bContext *C, wmOperator *op)
216 {
217         Scene *scene = CTX_data_scene(C);
218
219         /* both can be NULL, fallbacks values are used */
220         View3D *v3d = CTX_wm_view3d(C);
221         RegionView3D *rv3d = ED_view3d_context_rv3d(C);
222
223         Object *obedit = CTX_data_edit_object(C);
224         BMEditMesh *em = BKE_editmesh_from_object(obedit);
225         BMesh *bm;
226         BMOperator bmop;
227         float plane_co[3];
228         float plane_no[3];
229         float imat[4][4];
230
231         const float thresh = RNA_float_get(op->ptr, "threshold");
232         const bool use_fill = RNA_boolean_get(op->ptr, "use_fill");
233         const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner");
234         const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer");
235
236         PropertyRNA *prop_plane_co;
237         PropertyRNA *prop_plane_no;
238
239         prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
240         if (RNA_property_is_set(op->ptr, prop_plane_co)) {
241                 RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co);
242         }
243         else {
244                 copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d));
245                 RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
246         }
247
248         prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
249         if (RNA_property_is_set(op->ptr, prop_plane_no)) {
250                 RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no);
251         }
252         else {
253                 if (rv3d) {
254                         copy_v3_v3(plane_no, rv3d->viewinv[1]);
255                 }
256                 else {
257                         /* fallback... */
258                         plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f;
259                 }
260                 RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
261         }
262
263
264
265         /* -------------------------------------------------------------------- */
266         /* Modal support */
267         /* Note: keep this isolated, exec can work wihout this */
268         if ((op->customdata != NULL) &&
269             mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no))
270         {
271                 /* write back to the props */
272                 RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
273                 RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
274         }
275         /* End Modal */
276         /* -------------------------------------------------------------------- */
277
278
279
280         bm = em->bm;
281
282         invert_m4_m4(imat, obedit->obmat);
283         mul_m4_v3(imat, plane_co);
284         mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
285
286         EDBM_op_init(em, &bmop, op,
287                      "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
288                      BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer);
289         BMO_op_exec(bm, &bmop);
290
291         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
292
293         if (use_fill) {
294                 float normal_fill[3];
295                 BMOperator bmop_fill;
296                 BMOperator bmop_attr;
297
298                 normalize_v3_v3(normal_fill, plane_no);
299                 if (clear_outer == true && clear_inner == false) {
300                         negate_v3(normal_fill);
301                 }
302
303                 /* Fill */
304                 BMO_op_initf(
305                         bm, &bmop_fill, 0,
306                         "triangle_fill edges=%S normal=%v use_dissolve=%b",
307                         &bmop, "geom_cut.out", normal_fill, true);
308                 BMO_op_exec(bm, &bmop_fill);
309
310                 /* Copy Attributes */
311                 BMO_op_initf(bm, &bmop_attr, 0,
312                              "face_attribute_fill faces=%S use_normals=%b use_data=%b",
313                              &bmop_fill, "geom.out", false, true);
314                 BMO_op_exec(bm, &bmop_attr);
315
316                 BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
317
318                 BMO_op_finish(bm, &bmop_attr);
319                 BMO_op_finish(bm, &bmop_fill);
320         }
321
322         BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
323
324         if (!EDBM_op_finish(em, &bmop, op, true)) {
325                 return OPERATOR_CANCELLED;
326         }
327         else {
328                 EDBM_update_generic(em, true, true);
329                 EDBM_selectmode_flush(em);
330                 return OPERATOR_FINISHED;
331         }
332 }
333
334 #ifdef USE_MANIPULATOR
335 static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt);
336 #endif
337
338 void MESH_OT_bisect(struct wmOperatorType *ot)
339 {
340         PropertyRNA *prop;
341
342         /* identifiers */
343         ot->name = "Bisect";
344         ot->description = "Cut geometry along a plane (click-drag to define plane)";
345         ot->idname = "MESH_OT_bisect";
346
347         /* api callbacks */
348         ot->exec = mesh_bisect_exec;
349         ot->invoke = mesh_bisect_invoke;
350         ot->modal = mesh_bisect_modal;
351         ot->cancel = WM_gesture_straightline_cancel;
352         ot->poll = ED_operator_editmesh;
353
354         /* flags */
355         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
356
357
358         prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -1e12f, 1e12f,
359                                     "Plane Point", "A point on the plane", -1e4f, 1e4f);
360         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
361         prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -1.0f, 1.0f,
362                                     "Plane Normal", "The direction the plane points", -1.0f, 1.0f);
363         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
364
365         RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut");
366         RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane");
367         RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry in front of the plane");
368
369         RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1);
370
371         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
372
373 #ifdef USE_MANIPULATOR
374         WM_manipulatorgrouptype_append(MESH_WGT_bisect);
375 #endif
376 }
377
378
379 #ifdef USE_MANIPULATOR
380
381 /* -------------------------------------------------------------------- */
382
383 /** \name Bisect Manipulator
384  * \{ */
385
386 typedef struct ManipulatorGroup {
387         /* Arrow to change plane depth. */
388         struct wmManipulator *translate_z;
389         /* Translate XYZ */
390         struct wmManipulator *translate_c;
391         /* For grabbing the manipulator and moving freely. */
392         struct wmManipulator *rotate_c;
393
394         /* We could store more vars here! */
395         struct {
396                 bContext *context;
397                 wmOperator *op;
398                 PropertyRNA *prop_plane_co;
399                 PropertyRNA *prop_plane_no;
400
401                 float rotate_axis[3];
402                 float rotate_up[3];
403         } data;
404 } ManipulatorGroup;
405
406 /**
407  * XXX. calling redo from property updates is not great.
408  * This is needed because changing the RNA doesn't cause a redo
409  * and we're not using operator UI which does just this.
410  */
411 static void manipulator_bisect_exec(ManipulatorGroup *man)
412 {
413         wmOperator *op = man->data.op;
414         if (op == WM_operator_last_redo((bContext *)man->data.context)) {
415                 ED_undo_operator_repeat((bContext *)man->data.context, op);
416         }
417 }
418
419 static void manipulator_mesh_bisect_update_from_op(ManipulatorGroup *man)
420 {
421         wmOperator *op = man->data.op;
422
423         float plane_co[3], plane_no[3];
424
425         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
426         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
427
428         WM_manipulator_set_matrix_location(man->translate_z, plane_co);
429         WM_manipulator_set_matrix_location(man->translate_c, plane_co);
430         WM_manipulator_set_matrix_location(man->rotate_c, plane_co);
431
432         WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no);
433
434         WM_manipulator_set_scale(man->translate_c, 0.2);
435
436         RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context);
437         if (rv3d) {
438                 normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]);
439                 normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]);
440
441                 /* ensure its orthogonal */
442                 project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis);
443                 normalize_v3(man->data.rotate_up);
444
445                 WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no);
446
447                 float plane_no_cross[3];
448                 cross_v3_v3v3(plane_no_cross, plane_no, man->data.rotate_axis);
449
450                 WM_manipulator_set_matrix_offset_rotation_from_yz_axis(man->rotate_c, plane_no_cross, man->data.rotate_axis);
451                 RNA_enum_set(man->rotate_c->ptr, "draw_options",
452                              ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR |
453                              ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y);
454         }
455 }
456
457 /* depth callbacks */
458 static void manipulator_bisect_prop_depth_get(
459         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
460         void *value_p)
461 {
462         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
463         wmOperator *op = man->data.op;
464         float *value = value_p;
465
466         BLI_assert(mpr_prop->type->array_length == 1);
467         UNUSED_VARS_NDEBUG(mpr_prop);
468
469         float plane_co[3], plane_no[3];
470         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
471         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
472
473         value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]);
474 }
475
476 static void manipulator_bisect_prop_depth_set(
477         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
478         const void *value_p)
479 {
480         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
481         wmOperator *op = man->data.op;
482         const float *value = value_p;
483
484         BLI_assert(mpr_prop->type->array_length == 1);
485         UNUSED_VARS_NDEBUG(mpr_prop);
486
487         float plane_co[3], plane[4];
488         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
489         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane);
490         normalize_v3(plane);
491
492         plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]);
493
494         /* Keep our location, may be offset simply to be inside the viewport. */
495         closest_to_plane_normalized_v3(plane_co, plane, plane_co);
496
497         RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, plane_co);
498
499         manipulator_bisect_exec(man);
500 }
501
502 /* translate callbacks */
503 static void manipulator_bisect_prop_translate_get(
504         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
505         void *value_p)
506 {
507         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
508         wmOperator *op = man->data.op;
509
510         BLI_assert(mpr_prop->type->array_length == 3);
511         UNUSED_VARS_NDEBUG(mpr_prop);
512
513         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, value_p);
514 }
515
516 static void manipulator_bisect_prop_translate_set(
517         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
518         const void *value_p)
519 {
520         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
521         wmOperator *op = man->data.op;
522
523         BLI_assert(mpr_prop->type->array_length == 3);
524         UNUSED_VARS_NDEBUG(mpr_prop);
525
526         RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, value_p);
527
528         manipulator_bisect_exec(man);
529 }
530
531 /* angle callbacks */
532 static void manipulator_bisect_prop_angle_get(
533         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
534         void *value_p)
535 {
536         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
537         wmOperator *op = man->data.op;
538         float *value = value_p;
539
540         BLI_assert(mpr_prop->type->array_length == 1);
541         UNUSED_VARS_NDEBUG(mpr_prop);
542
543         float plane_no[4];
544         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
545         normalize_v3(plane_no);
546
547         float plane_no_proj[3];
548         project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
549
550         if (!is_zero_v3(plane_no_proj)) {
551                 const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
552                 value[0] = angle;
553         }
554         else {
555                 value[0] = 0.0f;
556         }
557 }
558
559 static void manipulator_bisect_prop_angle_set(
560         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
561         const void *value_p)
562 {
563         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
564         wmOperator *op = man->data.op;
565         const float *value = value_p;
566
567         BLI_assert(mpr_prop->type->array_length == 1);
568         UNUSED_VARS_NDEBUG(mpr_prop);
569
570         float plane_no[4];
571         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
572         normalize_v3(plane_no);
573
574         float plane_no_proj[3];
575         project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
576
577         if (!is_zero_v3(plane_no_proj)) {
578                 const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
579                 const float angle_delta = angle - angle_compat_rad(value[0], angle);
580                 if (angle_delta != 0.0f) {
581                         float mat[3][3];
582                         axis_angle_normalized_to_mat3(mat, man->data.rotate_axis, angle_delta);
583                         mul_m3_v3(mat, plane_no);
584
585                         /* re-normalize - seems acceptable */
586                         RNA_property_float_set_array(op->ptr, man->data.prop_plane_no, plane_no);
587
588                         manipulator_bisect_exec(man);
589                 }
590         }
591 }
592
593 static bool manipulator_mesh_bisect_poll(const bContext *C, wmManipulatorGroupType *wgt)
594 {
595         wmOperator *op = WM_operator_last_redo(C);
596         if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
597                 WM_manipulator_group_remove_ptr_delayed(wgt);
598                 return false;
599         }
600         return true;
601 }
602
603 static void manipulator_mesh_bisect_setup(const bContext *C, wmManipulatorGroup *mgroup)
604 {
605         wmOperator *op = WM_operator_last_redo(C);
606
607         if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
608                 return;
609         }
610
611         struct ManipulatorGroup *man = MEM_callocN(sizeof(ManipulatorGroup), __func__);
612         mgroup->customdata = man;
613
614         const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
615         const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true);
616         const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
617
618         man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, "translate_z", NULL);
619         man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, "translate_c", NULL);
620         man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, "rotate_c", NULL);
621
622         RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
623         RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING);
624
625         WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true);
626         WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true);
627
628         {
629                 man->data.context = (bContext *)C;
630                 man->data.op = op;
631                 man->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
632                 man->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
633         }
634
635         manipulator_mesh_bisect_update_from_op(man);
636
637         /* Setup property callbacks */
638         {
639                 WM_manipulator_target_property_def_func(
640                         man->translate_z, "offset",
641                         &(const struct wmManipulatorPropertyFnParams) {
642                             .value_get_fn = manipulator_bisect_prop_depth_get,
643                             .value_set_fn = manipulator_bisect_prop_depth_set,
644                             .range_get_fn = NULL,
645                             .user_data = NULL,
646                         });
647
648                 WM_manipulator_target_property_def_func(
649                         man->translate_c, "offset",
650                         &(const struct wmManipulatorPropertyFnParams) {
651                             .value_get_fn = manipulator_bisect_prop_translate_get,
652                             .value_set_fn = manipulator_bisect_prop_translate_set,
653                             .range_get_fn = NULL,
654                             .user_data = NULL,
655                         });
656
657                 WM_manipulator_target_property_def_func(
658                         man->rotate_c, "offset",
659                         &(const struct wmManipulatorPropertyFnParams) {
660                             .value_get_fn = manipulator_bisect_prop_angle_get,
661                             .value_set_fn = manipulator_bisect_prop_angle_set,
662                             .range_get_fn = NULL,
663                             .user_data = NULL,
664                         });
665         }
666 }
667
668 static void manipulator_mesh_bisect_draw_prepare(
669         const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
670 {
671         ManipulatorGroup *man = mgroup->customdata;
672         manipulator_mesh_bisect_update_from_op(man);
673 }
674
675 static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt)
676 {
677         wgt->name = "Mesh Bisect";
678         wgt->idname = "MESH_WGT_bisect";
679
680         wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
681
682         wgt->mmap_params.spaceid = SPACE_VIEW3D;
683         wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
684
685         wgt->poll = manipulator_mesh_bisect_poll;
686         wgt->setup = manipulator_mesh_bisect_setup;
687         wgt->draw_prepare = manipulator_mesh_bisect_draw_prepare;
688 }
689
690 /** \} */
691
692 #endif  /* USE_MANIPULATOR */