doxygen: add newline after \file
[blender.git] / source / blender / editors / gizmo_library / gizmo_library_utils.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) 2015 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edgizmolib
22  *
23  * \name Gizmo Library Utilities
24  *
25  * \brief This file contains functions for common behaviors of gizmos.
26  */
27
28 #include "BLI_math.h"
29
30 #include "DNA_view3d_types.h"
31 #include "DNA_screen_types.h"
32
33 #include "BKE_context.h"
34
35 #include "RNA_access.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 #include "ED_view3d.h"
41
42 /* own includes */
43 #include "gizmo_library_intern.h"
44
45 /* factor for precision tweaking */
46 #define GIZMO_PRECISION_FAC 0.05f
47
48
49 BLI_INLINE float gizmo_offset_from_value_constr(
50         const float range_fac, const float min, const float range, const float value,
51         const bool inverted)
52 {
53         return inverted ? (range_fac * (min + range - value) / range) : (range_fac * (value / range));
54 }
55
56 BLI_INLINE float gizmo_value_from_offset_constr(
57         const float range_fac, const float min, const float range, const float value,
58         const bool inverted)
59 {
60         return inverted ? (min + range - (value * range / range_fac)) : (value * range / range_fac);
61 }
62
63 float gizmo_offset_from_value(
64         GizmoCommonData *data, const float value, const bool constrained, const bool inverted)
65 {
66         if (constrained)
67                 return gizmo_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
68
69         return value;
70 }
71
72 float gizmo_value_from_offset(
73         GizmoCommonData *data, GizmoInteraction *inter, const float offset,
74         const bool constrained, const bool inverted, const bool use_precision)
75 {
76         const float max = data->min + data->range;
77
78         if (use_precision) {
79                 /* add delta offset of this step to total precision_offset */
80                 inter->precision_offset += offset - inter->prev_offset;
81         }
82         inter->prev_offset = offset;
83
84         float ofs_new = inter->init_offset + offset - inter->precision_offset * (1.0f - GIZMO_PRECISION_FAC);
85         float value;
86
87         if (constrained) {
88                 value = gizmo_value_from_offset_constr(data->range_fac, data->min, data->range, ofs_new, inverted);
89         }
90         else {
91                 value = ofs_new;
92         }
93
94         /* clamp to custom range */
95         if (data->is_custom_range_set) {
96                 CLAMP(value, data->min, max);
97         }
98
99         return value;
100 }
101
102 void gizmo_property_data_update(
103         wmGizmo *gz, GizmoCommonData *data, wmGizmoProperty *gz_prop,
104         const bool constrained, const bool inverted)
105 {
106         if (gz_prop->custom_func.value_get_fn != NULL) {
107                 /* pass  */
108         }
109         else if (gz_prop->prop != NULL) {
110                 /* pass  */
111         }
112         else {
113                 data->offset = 0.0f;
114                 return;
115         }
116
117         float value = WM_gizmo_target_property_float_get(gz, gz_prop);
118
119         if (constrained) {
120                 if (data->is_custom_range_set == false) {
121                         float range[2];
122                         if (WM_gizmo_target_property_float_range_get(gz, gz_prop, range)) {
123                                 data->range = range[1] - range[0];
124                                 data->min = range[0];
125                         }
126                         else {
127                                 BLI_assert(0);
128                         }
129                 }
130                 data->offset = gizmo_offset_from_value_constr(data->range_fac, data->min, data->range, value, inverted);
131         }
132         else {
133                 data->offset = value;
134         }
135 }
136
137 void gizmo_property_value_reset(
138         bContext *C, const wmGizmo *gz, GizmoInteraction *inter,
139         wmGizmoProperty *gz_prop)
140 {
141         WM_gizmo_target_property_float_set(C, gz, gz_prop, inter->init_value);
142 }
143
144 /* -------------------------------------------------------------------- */
145
146 void gizmo_color_get(
147         const wmGizmo *gz, const bool highlight,
148         float r_col[4])
149 {
150         if (highlight && !(gz->flag & WM_GIZMO_DRAW_HOVER)) {
151                 copy_v4_v4(r_col, gz->color_hi);
152         }
153         else {
154                 copy_v4_v4(r_col, gz->color);
155         }
156 }
157
158 /* -------------------------------------------------------------------- */
159
160 /**
161  * Takes mouse coordinates and returns them in relation to the gizmo.
162  * Both 2D & 3D supported, use so we can use 2D gizmos in the 3D view.
163  */
164 bool gizmo_window_project_2d(
165         bContext *C, const struct wmGizmo *gz, const float mval[2], int axis, bool use_offset,
166         float r_co[2])
167 {
168         float mat[4][4];
169         {
170                 float mat_identity[4][4];
171                 struct WM_GizmoMatrixParams params = {NULL};
172                 if (use_offset == false) {
173                         unit_m4(mat_identity);
174                         params.matrix_offset = mat_identity;
175                 }
176                 WM_gizmo_calc_matrix_final_params(gz, &params, mat);
177         }
178
179         /* rotate mouse in relation to the center and relocate it */
180         if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
181                 /* For 3d views, transform 2D mouse pos onto plane. */
182                 ARegion *ar = CTX_wm_region(C);
183
184                 float plane[4], co[3];
185                 plane_from_point_normal_v3(plane, mat[3], mat[2]);
186                 bool clip_ray = ((RegionView3D *)ar->regiondata)->is_persp;
187                 if (ED_view3d_win_to_3d_on_plane(ar, plane, mval, clip_ray, co)) {
188                         float imat[4][4];
189                         invert_m4_m4(imat, mat);
190                         mul_m4_v3(imat, co);
191                         r_co[0] = co[(axis + 1) % 3];
192                         r_co[1] = co[(axis + 2) % 3];
193                         return true;
194                 }
195                 return false;
196         }
197         else {
198                 float co[3] = {mval[0], mval[1], 0.0f};
199                 float imat[4][4];
200                 invert_m4_m4(imat, mat);
201                 mul_m4_v3(imat, co);
202                 copy_v2_v2(r_co, co);
203                 return true;
204         }
205 }
206
207 bool gizmo_window_project_3d(
208         bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset,
209         float r_co[3])
210 {
211         float mat[4][4];
212         {
213                 float mat_identity[4][4];
214                 struct WM_GizmoMatrixParams params = {NULL};
215                 if (use_offset == false) {
216                         unit_m4(mat_identity);
217                         params.matrix_offset = mat_identity;
218                 }
219                 WM_gizmo_calc_matrix_final_params(gz, &params, mat);
220         }
221
222         if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
223                 View3D *v3d = CTX_wm_view3d(C);
224                 ARegion *ar = CTX_wm_region(C);
225                 /* Note: we might want a custom reference point passed in,
226                  * instead of the gizmo center. */
227                 ED_view3d_win_to_3d(v3d, ar, mat[3], mval, r_co);
228                 invert_m4(mat);
229                 mul_m4_v3(mat, r_co);
230                 return true;
231         }
232         else {
233                 float co[3] = {mval[0], mval[1], 0.0f};
234                 float imat[4][4];
235                 invert_m4_m4(imat, mat);
236                 mul_m4_v3(imat, co);
237                 copy_v2_v2(r_co, co);
238                 return true;
239         }
240 }