Merge branch 'blender2.7'
[blender.git] / source / blender / editors / mesh / editmesh_extrude_spin.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 by Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edmesh
22  */
23
24 #include "DNA_object_types.h"
25
26 #include "BLI_math.h"
27
28 #include "BKE_context.h"
29 #include "BKE_report.h"
30 #include "BKE_editmesh.h"
31 #include "BKE_layer.h"
32
33 #include "RNA_define.h"
34 #include "RNA_access.h"
35 #include "RNA_enum_types.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 #include "ED_mesh.h"
41 #include "ED_screen.h"
42 #include "ED_view3d.h"
43
44 #include "UI_resources.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "mesh_intern.h"  /* own include */
49
50 #define USE_GIZMO
51
52 /* -------------------------------------------------------------------- */
53 /** \name Spin Operator
54  * \{ */
55
56 static int edbm_spin_exec(bContext *C, wmOperator *op)
57 {
58         ViewLayer *view_layer = CTX_data_view_layer(C);
59         float cent[3], axis[3];
60         float d[3] = {0.0f, 0.0f, 0.0f};
61
62         RNA_float_get_array(op->ptr, "center", cent);
63         RNA_float_get_array(op->ptr, "axis", axis);
64         const int steps = RNA_int_get(op->ptr, "steps");
65         const float angle = RNA_float_get(op->ptr, "angle");
66         const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip");
67         const bool dupli = RNA_boolean_get(op->ptr, "dupli");
68         const bool use_auto_merge = (
69                 RNA_boolean_get(op->ptr, "use_auto_merge") &&
70                 (dupli == false) &&
71                 (steps >= 3) &&
72                 fabsf((fabsf(angle) - (float)(M_PI * 2))) <= 1e-6f);
73
74         if (is_zero_v3(axis)) {
75                 BKE_report(op->reports, RPT_ERROR, "Invalid/unset axis");
76                 return OPERATOR_CANCELLED;
77         }
78
79         uint objects_len = 0;
80         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
81
82         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
83                 Object *obedit = objects[ob_index];
84                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
85                 BMesh *bm = em->bm;
86                 BMOperator spinop;
87
88                 /* keep the values in worldspace since we're passing the obmat */
89                 if (!EDBM_op_init(
90                             em, &spinop, op,
91                             "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i angle=%f space=%m4 "
92                             "use_normal_flip=%b use_duplicate=%b use_merge=%b",
93                             BM_ELEM_SELECT, cent, axis, d, steps, -angle, obedit->obmat,
94                             use_normal_flip, dupli, use_auto_merge))
95                 {
96                         continue;
97                 }
98                 BMO_op_exec(bm, &spinop);
99                 if (use_auto_merge == false) {
100                         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
101                         BMO_slot_buffer_hflag_enable(bm, spinop.slots_out, "geom_last.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
102                 }
103                 if (!EDBM_op_finish(em, &spinop, op, true)) {
104                         continue;
105                 }
106
107                 EDBM_update_generic(em, true, true);
108         }
109
110         MEM_freeN(objects);
111
112         return OPERATOR_FINISHED;
113 }
114
115 /* get center and axis, in global coords */
116 static int edbm_spin_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
117 {
118         Scene *scene = CTX_data_scene(C);
119         View3D *v3d = CTX_wm_view3d(C);
120         RegionView3D *rv3d = ED_view3d_context_rv3d(C);
121
122         PropertyRNA *prop;
123         prop = RNA_struct_find_property(op->ptr, "center");
124         if (!RNA_property_is_set(op->ptr, prop)) {
125                 RNA_property_float_set_array(op->ptr, prop, scene->cursor.location);
126         }
127         if (rv3d) {
128                 prop = RNA_struct_find_property(op->ptr, "axis");
129                 if (!RNA_property_is_set(op->ptr, prop)) {
130                         RNA_property_float_set_array(op->ptr, prop, rv3d->viewinv[2]);
131                 }
132         }
133
134
135 #ifdef USE_GIZMO
136         /* Start with zero angle, drag out the value. */
137         prop = RNA_struct_find_property(op->ptr, "angle");
138         if (!RNA_property_is_set(op->ptr, prop)) {
139                 RNA_property_float_set(op->ptr, prop, 0.0f);
140         }
141 #endif
142
143         int ret = edbm_spin_exec(C, op);
144
145 #ifdef USE_GIZMO
146         if (ret & OPERATOR_FINISHED) {
147                 /* Setup gizmos */
148                 if (v3d && ((v3d->gizmo_flag & V3D_GIZMO_HIDE) == 0)) {
149                         wmGizmoGroupType *gzgt = WM_gizmogrouptype_find("MESH_GGT_spin_redo", false);
150                         if (!WM_gizmo_group_type_ensure_ptr(gzgt)) {
151                                 struct Main *bmain = CTX_data_main(C);
152                                 WM_gizmo_group_type_reinit_ptr(bmain, gzgt);
153                         }
154                 }
155         }
156 #endif
157
158         return ret;
159 }
160
161 static bool edbm_spin_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
162 {
163         const char *prop_id = RNA_property_identifier(prop);
164         const bool dupli = RNA_boolean_get(op->ptr, "dupli");
165
166         if (dupli) {
167                 if (STREQ(prop_id, "use_auto_merge") ||
168                     STREQ(prop_id, "use_normal_flip"))
169                 {
170                         return false;
171                 }
172         }
173         return true;
174 }
175
176 void MESH_OT_spin(wmOperatorType *ot)
177 {
178         PropertyRNA *prop;
179
180         /* identifiers */
181         ot->name = "Spin";
182         ot->description = "Extrude selected vertices in a circle around the cursor in indicated viewport";
183         ot->idname = "MESH_OT_spin";
184
185         /* api callbacks */
186         ot->invoke = edbm_spin_invoke;
187         ot->exec = edbm_spin_exec;
188         ot->poll = ED_operator_editmesh;
189         ot->poll_property = edbm_spin_poll_property;
190
191         /* flags */
192         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
193
194         /* props */
195         RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
196         RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
197         prop = RNA_def_float(ot->srna, "angle", DEG2RADF(90.0f), -1e12f, 1e12f, "Angle", "Rotation for each step",
198                              DEG2RADF(-360.0f), DEG2RADF(360.0f));
199         RNA_def_property_subtype(prop, PROP_ANGLE);
200         RNA_def_boolean(ot->srna, "use_auto_merge", true, "Auto Merge", "Merge first/last when the angle is a full revolution");
201         RNA_def_boolean(ot->srna, "use_normal_flip", 0, "Flip Normals", "");
202
203         RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -1e12f, 1e12f,
204                                  "Center", "Center in global view space", -1e4f, 1e4f);
205         RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f);
206
207         WM_gizmogrouptype_append(MESH_GGT_spin);
208 #ifdef USE_GIZMO
209         WM_gizmogrouptype_append(MESH_GGT_spin_redo);
210 #endif
211 }
212
213 /** \} */