Cleanup: rename gizmo access functions
[blender.git] / source / blender / editors / gizmo_library / gizmo_types / grab3d_gizmo.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_gizmo.c
22  *  \ingroup wm
23  *
24  * \name Grab Gizmo
25  *
26  * 3D Gizmo, also works in 2D views.
27  *
28  * \brief Simple gizmo 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 gizmos).
33  *
34  */
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_math.h"
39
40 #include "BKE_context.h"
41
42 #include "BIF_gl.h"
43 #include "BIF_glutil.h"
44
45 #include "GPU_immediate.h"
46 #include "GPU_immediate_util.h"
47 #include "GPU_matrix.h"
48 #include "GPU_select.h"
49 #include "GPU_state.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "ED_screen.h"
58 #include "ED_view3d.h"
59 #include "ED_gizmo_library.h"
60
61 /* own includes */
62 #include "../gizmo_geometry.h"
63 #include "../gizmo_library_intern.h"
64
65 typedef struct GrabGizmo3D {
66         wmGizmo gizmo;
67         /* Added to 'matrix_basis' when calculating the matrix. */
68         float prop_co[3];
69 } GrabGizmo3D;
70
71 static void gizmo_grab_matrix_basis_get(const wmGizmo *gz, float r_matrix[4][4])
72 {
73         GrabGizmo3D *grab = (GrabGizmo3D *)gz;
74
75         copy_m4_m4(r_matrix, grab->gizmo.matrix_basis);
76         add_v3_v3(r_matrix[3], grab->prop_co);
77 }
78
79 static int gizmo_grab_modal(
80         bContext *C, wmGizmo *gz, const wmEvent *event,
81         eWM_GizmoFlagTweak tweak_flag);
82
83 typedef struct GrabInteraction {
84         float init_mval[2];
85
86         /* only for when using properties */
87         float init_prop_co[3];
88
89         float init_matrix_final[4][4];
90 } GrabInteraction;
91
92 #define DIAL_RESOLUTION 32
93
94 /* -------------------------------------------------------------------- */
95
96 static void grab_geom_draw(
97         const wmGizmo *gz, const float color[4], const bool select, const int draw_options)
98 {
99 #ifdef USE_GIZMO_CUSTOM_DIAL
100         UNUSED_VARS(grab3d, col, axis_modal_mat);
101         wm_gizmo_geometryinfo_draw(&wm_gizmo_geom_data_grab3d, select);
102 #else
103         const int draw_style = RNA_enum_get(gz->ptr, "draw_style");
104         const bool filled = (draw_options & ED_GIZMO_GRAB_DRAW_FLAG_FILL) != 0;
105
106         GPU_line_width(gz->line_width);
107
108         GPUVertFormat *format = immVertexFormat();
109         uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
110
111         immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
112
113         immUniformColor4fv(color);
114
115         if (draw_style == ED_GIZMO_GRAB_STYLE_RING_2D) {
116                 if (filled) {
117                         imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
118                 }
119                 else {
120                         imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION);
121                 }
122         }
123         else if (draw_style == ED_GIZMO_GRAB_STYLE_CROSS_2D) {
124                 immBegin(GPU_PRIM_LINES, 4);
125                 immVertex2f(pos,  1.0f,  1.0f);
126                 immVertex2f(pos, -1.0f, -1.0f);
127
128                 immVertex2f(pos, -1.0f,  1.0f);
129                 immVertex2f(pos,  1.0f, -1.0f);
130                 immEnd();
131         }
132         else {
133                 BLI_assert(0);
134         }
135
136         immUnbindProgram();
137
138         UNUSED_VARS(select);
139 #endif
140 }
141
142 static void grab3d_get_translate(
143         const wmGizmo *gz, const wmEvent *event, const ARegion *ar,
144         float co_delta[3])
145 {
146         GrabInteraction *inter = gz->interaction_data;
147         const float mval_delta[2] = {
148             event->mval[0] - inter->init_mval[0],
149             event->mval[1] - inter->init_mval[1],
150         };
151
152         RegionView3D *rv3d = ar->regiondata;
153         float co_ref[3];
154         mul_v3_mat3_m4v3(co_ref, gz->matrix_space, inter->init_prop_co);
155         const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
156
157         ED_view3d_win_to_delta(ar, mval_delta, co_delta, zfac);
158
159         float matrix_space_inv[3][3];
160         copy_m3_m4(matrix_space_inv, gz->matrix_space);
161         invert_m3(matrix_space_inv);
162         mul_m3_v3(matrix_space_inv, co_delta);
163 }
164
165 static void grab3d_draw_intern(
166         const bContext *C, wmGizmo *gz,
167         const bool select, const bool highlight)
168 {
169         GrabInteraction *inter = gz->interaction_data;
170         const int draw_options = RNA_enum_get(gz->ptr, "draw_options");
171         const bool align_view = (draw_options & ED_GIZMO_GRAB_DRAW_FLAG_ALIGN_VIEW) != 0;
172         float color[4];
173         float matrix_final[4][4];
174         float matrix_align[4][4];
175
176         gizmo_color_get(gz, highlight, color);
177         WM_gizmo_calc_matrix_final(gz, matrix_final);
178
179         GPU_matrix_push();
180         GPU_matrix_mul(matrix_final);
181
182         if (align_view) {
183                 float matrix_final_unit[4][4];
184                 RegionView3D *rv3d = CTX_wm_region_view3d(C);
185                 normalize_m4_m4(matrix_final_unit, matrix_final);
186                 mul_m4_m4m4(matrix_align, rv3d->viewmat, matrix_final_unit);
187                 zero_v3(matrix_align[3]);
188                 transpose_m4(matrix_align);
189                 GPU_matrix_mul(matrix_align);
190         }
191
192         GPU_blend(true);
193         grab_geom_draw(gz, color, select, draw_options);
194         GPU_blend(false);
195         GPU_matrix_pop();
196
197         if (gz->interaction_data) {
198                 GPU_matrix_push();
199                 GPU_matrix_mul(inter->init_matrix_final);
200
201                 if (align_view) {
202                         GPU_matrix_mul(matrix_align);
203                 }
204
205                 GPU_blend(true);
206                 grab_geom_draw(gz, (const float[4]){0.5f, 0.5f, 0.5f, 0.5f}, select, draw_options);
207                 GPU_blend(false);
208                 GPU_matrix_pop();
209         }
210 }
211
212 static void gizmo_grab_draw_select(const bContext *C, wmGizmo *gz, int select_id)
213 {
214         GPU_select_load_id(select_id);
215         grab3d_draw_intern(C, gz, true, false);
216 }
217
218 static void gizmo_grab_draw(const bContext *C, wmGizmo *gz)
219 {
220         const bool is_modal = gz->state & WM_GIZMO_STATE_MODAL;
221         const bool is_highlight = (gz->state & WM_GIZMO_STATE_HIGHLIGHT) != 0;
222
223         (void)is_modal;
224
225         GPU_blend(true);
226         grab3d_draw_intern(C, gz, false, is_highlight);
227         GPU_blend(false);
228 }
229
230 static int gizmo_grab_modal(
231         bContext *C, wmGizmo *gz, const wmEvent *event,
232         eWM_GizmoFlagTweak UNUSED(tweak_flag))
233 {
234         GrabGizmo3D *grab = (GrabGizmo3D *)gz;
235         GrabInteraction *inter = gz->interaction_data;
236         ARegion *ar = CTX_wm_region(C);
237
238         float prop_delta[3];
239         if (CTX_wm_area(C)->spacetype == SPACE_VIEW3D) {
240                 grab3d_get_translate(gz, event, ar, prop_delta);
241         }
242         else {
243                 float mval_proj_init[2], mval_proj_curr[2];
244                 if ((gizmo_window_project_2d(
245                          C, gz, inter->init_mval, 2, false, mval_proj_init) == false) ||
246                     (gizmo_window_project_2d(
247                          C, gz, (const float[2]){UNPACK2(event->mval)}, 2, false, mval_proj_curr) == false))
248                 {
249                         return OPERATOR_RUNNING_MODAL;
250                 }
251                 sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init);
252                 prop_delta[2] = 0.0f;
253         }
254         add_v3_v3v3(grab->prop_co, inter->init_prop_co, prop_delta);
255
256         /* set the property for the operator and call its modal function */
257         wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
258         if (WM_gizmo_target_property_is_valid(gz_prop)) {
259                 WM_gizmo_target_property_float_set_array(C, gz, gz_prop, grab->prop_co);
260         }
261         else {
262                 zero_v3(grab->prop_co);
263         }
264
265         ED_region_tag_redraw(ar);
266
267         return OPERATOR_RUNNING_MODAL;
268 }
269
270 static int gizmo_grab_invoke(
271         bContext *UNUSED(C), wmGizmo *gz, const wmEvent *event)
272 {
273         GrabInteraction *inter = MEM_callocN(sizeof(GrabInteraction), __func__);
274
275         inter->init_mval[0] = event->mval[0];
276         inter->init_mval[1] = event->mval[1];
277
278 #if 0
279         copy_v3_v3(inter->init_prop_co, grab->prop_co);
280 #else
281         wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, "offset");
282         if (WM_gizmo_target_property_is_valid(gz_prop)) {
283                 WM_gizmo_target_property_float_get_array(gz, gz_prop, inter->init_prop_co);
284         }
285 #endif
286
287         WM_gizmo_calc_matrix_final(gz, inter->init_matrix_final);
288
289         gz->interaction_data = inter;
290
291         return OPERATOR_RUNNING_MODAL;
292 }
293
294
295 static int gizmo_grab_test_select(
296         bContext *C, wmGizmo *gz, const int mval[2])
297 {
298         float point_local[2];
299
300         if (gizmo_window_project_2d(
301                 C, gz, (const float[2]){UNPACK2(mval)}, 2, true, point_local) == false)
302         {
303                 return -1;
304         }
305
306         /* The 'gz->scale_final' is already applied when projecting. */
307         if (len_squared_v2(point_local) < 1.0f) {
308                 return 0;
309         }
310
311         return -1;
312 }
313
314 static void gizmo_grab_property_update(wmGizmo *gz, wmGizmoProperty *gz_prop)
315 {
316         GrabGizmo3D *grab = (GrabGizmo3D *)gz;
317         if (WM_gizmo_target_property_is_valid(gz_prop)) {
318                 WM_gizmo_target_property_float_get_array(gz, gz_prop, grab->prop_co);
319         }
320         else {
321                 zero_v3(grab->prop_co);
322         }
323 }
324
325 static int gizmo_grab_cursor_get(wmGizmo *UNUSED(gz))
326 {
327         return BC_NSEW_SCROLLCURSOR;
328 }
329
330 /* -------------------------------------------------------------------- */
331 /** \name Grab Gizmo API
332  *
333  * \{ */
334
335 static void GIZMO_GT_grab_3d(wmGizmoType *gzt)
336 {
337         /* identifiers */
338         gzt->idname = "GIZMO_GT_grab_3d";
339
340         /* api callbacks */
341         gzt->draw = gizmo_grab_draw;
342         gzt->draw_select = gizmo_grab_draw_select;
343         gzt->test_select = gizmo_grab_test_select;
344         gzt->matrix_basis_get = gizmo_grab_matrix_basis_get;
345         gzt->invoke = gizmo_grab_invoke;
346         gzt->property_update = gizmo_grab_property_update;
347         gzt->modal = gizmo_grab_modal;
348         gzt->cursor_get = gizmo_grab_cursor_get;
349
350         gzt->struct_size = sizeof(GrabGizmo3D);
351
352         /* rna */
353         static EnumPropertyItem rna_enum_draw_style[] = {
354                 {ED_GIZMO_GRAB_STYLE_RING_2D, "RING_2D", 0, "Ring", ""},
355                 {ED_GIZMO_GRAB_STYLE_CROSS_2D, "CROSS_2D", 0, "Ring", ""},
356                 {0, NULL, 0, NULL, NULL}
357         };
358         static EnumPropertyItem rna_enum_draw_options[] = {
359                 {ED_GIZMO_GRAB_DRAW_FLAG_FILL, "FILL", 0, "Filled", ""},
360                 {ED_GIZMO_GRAB_DRAW_FLAG_ALIGN_VIEW, "ALIGN_VIEW", 0, "Align View", ""},
361                 {0, NULL, 0, NULL, NULL}
362         };
363
364         RNA_def_enum(gzt->srna, "draw_style", rna_enum_draw_style, ED_GIZMO_GRAB_STYLE_RING_2D, "Draw Style", "");
365         RNA_def_enum_flag(gzt->srna, "draw_options", rna_enum_draw_options, 0, "Draw Options", "");
366
367         WM_gizmotype_target_property_def(gzt, "offset", PROP_FLOAT, 3);
368 }
369
370 void ED_gizmotypes_grab_3d(void)
371 {
372         WM_gizmotype_append(GIZMO_GT_grab_3d);
373 }
374
375 /** \} */ // Grab Gizmo API