7a002a9cfc8b0f57279a949aaee7307fdc56c67d
[blender.git] / source / blender / editors / manipulator_library / manipulator_types / grab3d_manipulator.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  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file grab3d_manipulator.c
22  *  \ingroup wm
23  *
24  * \name Grab Manipulator
25  *
26  * 3D Manipulator, also works in 2D views.
27  *
28  * \brief Simple manipulator to grab and translate.
29  *
30  * - `matrix[0]` is derived from Y and Z.
31  * - `matrix[1]` currently not used.
32  * - `matrix[2]` is the widget direction (for all manipulators).
33  *
34  */
35
36 #include "BIF_gl.h"
37 #include "BIF_glutil.h"
38
39 #include "BKE_context.h"
40
41 #include "BLI_math.h"
42
43 #include "ED_screen.h"
44 #include "ED_view3d.h"
45 #include "ED_manipulator_library.h"
46
47 #include "GPU_select.h"
48
49 #include "GPU_matrix.h"
50
51 #include "GPU_immediate.h"
52 #include "GPU_immediate_util.h"
53
54 #include "MEM_guardedalloc.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 /* own includes */
63 #include "../manipulator_geometry.h"
64 #include "../manipulator_library_intern.h"
65
66 static void manipulator_grab_modal(
67         bContext *C, wmManipulator *mpr, const wmEvent *event,
68         eWM_ManipulatorTweak tweak_flag);
69
70 typedef struct GrabInteraction {
71         float init_mval[2];
72
73         /* only for when using properties */
74         float init_prop_co[3];
75
76         float init_matrix_basis[4][4];
77         float init_scale_final;
78
79         /* final output values, used for drawing */
80         struct {
81                 float co_final[3];
82         } output;
83 } GrabInteraction;
84
85 #define DIAL_RESOLUTION 32
86
87 /* -------------------------------------------------------------------- */
88
89 static void grab_geom_draw(
90         const wmManipulator *mpr, const float color[4], const bool select)
91 {
92 #ifdef USE_MANIPULATOR_CUSTOM_DIAL
93         UNUSED_VARS(grab3d, col, axis_modal_mat);
94         wm_manipulator_geometryinfo_draw(&wm_manipulator_geom_data_grab3d, select);
95 #else
96         const int draw_style = RNA_enum_get(mpr->ptr, "draw_style");
97         const int draw_options = RNA_enum_get(mpr->ptr, "draw_options");
98         const bool filled = (draw_options & ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL) != 0;
99
100         glLineWidth(mpr->line_width);
101
102         Gwn_VertFormat *format = immVertexFormat();
103         uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
104
105         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
106
107         immUniformColor4fv(color);
108
109         if (draw_style == ED_MANIPULATOR_GRAB_STYLE_RING_2D) {
110                 if (filled) {
111                         imm_draw_circle_fill(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
112                 }
113                 else {
114                         imm_draw_circle_wire(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
115                 }
116         }
117         else if (draw_style == ED_MANIPULATOR_GRAB_STYLE_CROSS_2D) {
118                 immBegin(GWN_PRIM_LINES, 4);
119                 immVertex2f(pos,  1.0f,  1.0f);
120                 immVertex2f(pos, -1.0f, -1.0f);
121
122                 immVertex2f(pos, -1.0f,  1.0f);
123                 immVertex2f(pos,  1.0f, -1.0f);
124                 immEnd();
125         }
126         else {
127                 BLI_assert(0);
128         }
129
130         immUnbindProgram();
131
132         UNUSED_VARS(select);
133 #endif
134 }
135
136 static void grab3d_get_translate(
137         const wmManipulator *mpr, const wmEvent *event, const ARegion *ar,
138         float co_delta[3])
139 {
140         GrabInteraction *inter = mpr->interaction_data;
141         const float mval_delta[2] = {
142             event->mval[0] - inter->init_mval[0],
143             event->mval[1] - inter->init_mval[1],
144         };
145
146         RegionView3D *rv3d = ar->regiondata;
147         const float *co_ref = inter->init_prop_co;
148         const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
149
150         ED_view3d_win_to_delta(ar, mval_delta, co_delta, zfac);
151 }
152
153 static void grab3d_draw_intern(
154         const bContext *UNUSED(C), wmManipulator *mpr,
155         const bool select, const bool highlight)
156 {
157         float color[4];
158         float matrix_final[4][4];
159
160         manipulator_color_get(mpr, highlight, color);
161
162         WM_manipulator_calc_matrix_final(mpr, matrix_final);
163
164         gpuPushMatrix();
165         gpuMultMatrix(matrix_final);
166         glEnable(GL_BLEND);
167
168         grab_geom_draw(mpr, color, select);
169         glDisable(GL_BLEND);
170         gpuPopMatrix();
171
172         if (mpr->interaction_data) {
173                 GrabInteraction *inter = mpr->interaction_data;
174
175                 WM_manipulator_calc_matrix_final_params(
176                         mpr, &((struct WM_ManipulatorMatrixParams) {
177                             .matrix_basis = inter->init_matrix_basis,
178                             .scale_final = &inter->init_scale_final,
179                         }), matrix_final);
180
181                 gpuPushMatrix();
182                 gpuMultMatrix(matrix_final);
183                 glEnable(GL_BLEND);
184                 grab_geom_draw(mpr, (const float [4]){0.5f, 0.5f, 0.5f, 0.5f}, select);
185                 glDisable(GL_BLEND);
186                 gpuPopMatrix();
187         }
188 }
189
190 static void manipulator_grab_draw_select(const bContext *C, wmManipulator *mpr, int select_id)
191 {
192         GPU_select_load_id(select_id);
193         grab3d_draw_intern(C, mpr, true, false);
194 }
195
196 static void manipulator_grab_draw(const bContext *C, wmManipulator *mpr)
197 {
198         const bool is_modal = mpr->state & WM_MANIPULATOR_STATE_MODAL;
199         const bool is_highlight = (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) != 0;
200
201         (void)is_modal;
202
203         glEnable(GL_BLEND);
204         grab3d_draw_intern(C, mpr, false, is_highlight);
205         glDisable(GL_BLEND);
206 }
207
208 static void manipulator_grab_modal(
209         bContext *C, wmManipulator *mpr, const wmEvent *event,
210         eWM_ManipulatorTweak UNUSED(tweak_flag))
211 {
212         GrabInteraction *inter = mpr->interaction_data;
213
214         if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
215                 grab3d_get_translate(mpr, event, CTX_wm_region(C), mpr->matrix_basis[3]);
216         }
217         else {
218                 float mval_proj_init[2], mval_proj_curr[2];
219                 if ((manipulator_window_project_2d(
220                          C, mpr, inter->init_mval, 2, false, mval_proj_init) == false) ||
221                     (manipulator_window_project_2d(
222                          C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, false, mval_proj_curr) == false))
223                 {
224                         return;
225                 }
226                 sub_v2_v2v2(mpr->matrix_basis[3], mval_proj_curr, mval_proj_init);
227                 mpr->matrix_basis[3][2] = 0.0f;
228         }
229
230         add_v3_v3v3(inter->output.co_final, inter->init_prop_co, mpr->matrix_basis[3]);
231
232         /* set the property for the operator and call its modal function */
233         wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
234         if (WM_manipulator_target_property_is_valid(mpr_prop)) {
235                 WM_manipulator_target_property_value_set_array(C, mpr, mpr_prop, inter->output.co_final);
236         }
237 }
238
239 static void manipulator_grab_invoke(
240         bContext *UNUSED(C), wmManipulator *mpr, const wmEvent *event)
241 {
242         GrabInteraction *inter = MEM_callocN(sizeof(GrabInteraction), __func__);
243
244         inter->init_mval[0] = event->mval[0];
245         inter->init_mval[1] = event->mval[1];
246
247         copy_m4_m4(inter->init_matrix_basis, mpr->matrix_basis);
248         inter->init_scale_final = mpr->scale_final;
249
250         wmManipulatorProperty *mpr_prop = WM_manipulator_target_property_find(mpr, "offset");
251         if (WM_manipulator_target_property_is_valid(mpr_prop)) {
252                 WM_manipulator_target_property_value_get_array(mpr, mpr_prop, inter->init_prop_co);
253         }
254
255         mpr->interaction_data = inter;
256 }
257
258
259 static int manipulator_grab_test_select(
260         bContext *C, wmManipulator *mpr, const wmEvent *event)
261 {
262         float point_local[2];
263
264         if (manipulator_window_project_2d(
265                 C, mpr, (const float[2]){UNPACK2(event->mval)}, 2, true, point_local) == false)
266         {
267                 return 0;
268         }
269
270         if (len_squared_v2(point_local) < SQUARE(mpr->scale_final)) {
271                 return true;
272         }
273
274         return 0;
275 }
276
277 static void manipulator_grab_property_update(wmManipulator *mpr, wmManipulatorProperty *mpr_prop)
278 {
279         WM_manipulator_target_property_value_get_array(mpr, mpr_prop, mpr->matrix_basis[3]);
280 }
281
282 static int manipulator_grab_cursor_get(wmManipulator *UNUSED(mpr))
283 {
284         return BC_HANDCURSOR;
285 }
286
287 /* -------------------------------------------------------------------- */
288 /** \name Grab Manipulator API
289  *
290  * \{ */
291
292 static void MANIPULATOR_WT_grab_3d(wmManipulatorType *wt)
293 {
294         /* identifiers */
295         wt->idname = "MANIPULATOR_WT_grab_3d";
296
297         /* api callbacks */
298         wt->draw = manipulator_grab_draw;
299         wt->draw_select = manipulator_grab_draw_select;
300         wt->test_select = manipulator_grab_test_select;
301         wt->invoke = manipulator_grab_invoke;
302         wt->property_update = manipulator_grab_property_update;
303         wt->modal = manipulator_grab_modal;
304         wt->cursor_get = manipulator_grab_cursor_get;
305
306         wt->struct_size = sizeof(wmManipulator);
307
308         /* rna */
309         static EnumPropertyItem rna_enum_draw_style[] = {
310                 {ED_MANIPULATOR_GRAB_STYLE_RING_2D, "RING_2D", 0, "Ring", ""},
311                 {ED_MANIPULATOR_GRAB_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""},
312                 {0, NULL, 0, NULL, NULL}
313         };
314         static EnumPropertyItem rna_enum_draw_options[] = {
315                 {ED_MANIPULATOR_GRAB_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
316                 {0, NULL, 0, NULL, NULL}
317         };
318
319         RNA_def_enum(wt->srna, "draw_style", rna_enum_draw_style, ED_MANIPULATOR_GRAB_STYLE_RING_2D, "Draw Style", "");
320         RNA_def_enum_flag(wt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
321
322         WM_manipulatortype_target_property_def(wt, "offset", PROP_FLOAT, 3);
323 }
324
325 void ED_manipulatortypes_grab_3d(void)
326 {
327         WM_manipulatortype_append(MANIPULATOR_WT_grab_3d);
328 }
329
330 /** \} */ // Grab Manipulator API