Fix gizmos showing for non-visible objects
[blender.git] / source / blender / editors / space_view3d / view3d_gizmo_armature.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 blender/editors/space_view3d/view3d_gizmo_armature.c
22  *  \ingroup spview3d
23  */
24
25 #include "BLI_blenlib.h"
26 #include "BLI_math.h"
27 #include "BLI_utildefines.h"
28
29 #include "BKE_armature.h"
30 #include "BKE_action.h"
31 #include "BKE_context.h"
32 #include "BKE_object.h"
33
34 #include "DNA_object_types.h"
35 #include "DNA_armature_types.h"
36
37 #include "ED_armature.h"
38 #include "ED_screen.h"
39 #include "ED_gizmo_library.h"
40
41 #include "UI_resources.h"
42
43 #include "MEM_guardedalloc.h"
44
45 #include "RNA_access.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "view3d_intern.h"  /* own include */
51
52
53 /* -------------------------------------------------------------------- */
54
55 /** \name Armature Spline Gizmo
56  *
57  * \{ */
58
59 /*
60  * TODO(campbell): Current conversion is a approximation (usable not correct),
61  * we'll need to take the next/previous bones into account to get the tangent directions.
62  * First last matrices from 'BKE_pchan_bbone_spline_setup' are close but also not quite accurate
63  * since they're not at either end-points on the curve.
64  *
65  * Likely we'll need a function especially to get the first/last orientations.
66  */
67
68 #define BBONE_SCALE_Y 3.0f
69
70 struct BoneSplineHandle {
71         wmGizmo *gizmo;
72         bPoseChannel *pchan;
73         /* We could remove, keep since at the moment for checking the conversion. */
74         float co[3];
75         int index;
76 };
77
78 struct BoneSplineWidgetGroup {
79         struct BoneSplineHandle handles[2];
80 };
81
82 static void gizmo_bbone_offset_get(
83         const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
84         void *value_p)
85 {
86         struct BoneSplineHandle *bh = gz_prop->custom_func.user_data;
87         bPoseChannel *pchan = bh->pchan;
88
89         float *value = value_p;
90         BLI_assert(gz_prop->type->array_length == 3);
91
92         if (bh->index == 0) {
93                 bh->co[1] = pchan->bone->ease1 / BBONE_SCALE_Y;
94                 bh->co[0] = pchan->curveInX;
95                 bh->co[2] = pchan->curveInY;
96         }
97         else {
98                 bh->co[1] = -pchan->bone->ease2 / BBONE_SCALE_Y;
99                 bh->co[0] = pchan->curveOutX;
100                 bh->co[2] = pchan->curveOutY;
101         }
102         copy_v3_v3(value, bh->co);
103 }
104
105 static void gizmo_bbone_offset_set(
106         const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop,
107         const void *value_p)
108 {
109         struct BoneSplineHandle *bh = gz_prop->custom_func.user_data;
110         bPoseChannel *pchan = bh->pchan;
111
112         const float *value = value_p;
113
114         BLI_assert(gz_prop->type->array_length == 3);
115         copy_v3_v3(bh->co, value);
116
117         if (bh->index == 0) {
118                 pchan->bone->ease1 = max_ff(0.0f, bh->co[1] * BBONE_SCALE_Y);
119                 pchan->curveInX = bh->co[0];
120                 pchan->curveInY = bh->co[2];
121         }
122         else {
123                 pchan->bone->ease2 = max_ff(0.0f, -bh->co[1] * BBONE_SCALE_Y);
124                 pchan->curveOutX = bh->co[0];
125                 pchan->curveOutY = bh->co[2];
126         }
127
128 }
129
130 static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType *UNUSED(gzgt))
131 {
132         View3D *v3d = CTX_wm_view3d(C);
133         if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
134             (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
135         {
136                 return false;
137         }
138
139         ViewLayer *view_layer = CTX_data_view_layer(C);
140         Base *base = BASACT(view_layer);
141         if (base && BASE_VISIBLE(v3d, base)) {
142                 Object *ob = BKE_object_pose_armature_get(base->object);
143                 if (ob) {
144                         const bArmature *arm = ob->data;
145                         if (arm->drawtype == ARM_B_BONE) {
146                                 bPoseChannel *pchan = BKE_pose_channel_active(ob);
147                                 if (pchan && pchan->bone->segments > 1) {
148                                         return true;
149                                 }
150                         }
151                 }
152         }
153         return false;
154 }
155
156
157 static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *gzgroup)
158 {
159         ViewLayer *view_layer = CTX_data_view_layer(C);
160         Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
161         bPoseChannel *pchan = BKE_pose_channel_active(ob);
162
163         const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
164
165         struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__);
166         gzgroup->customdata = bspline_group;
167
168         /* Handles */
169         for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
170                 wmGizmo *gz;
171                 gz = bspline_group->handles[i].gizmo = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
172                 RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
173                 RNA_enum_set(gz->ptr, "draw_options",
174                              ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW);
175                 WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
176
177                 UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
178                 UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
179
180                 gz->scale_basis = 0.06f;
181
182                 if (i == 0) {
183                         copy_v3_v3(gz->matrix_basis[3], pchan->loc);
184                 }
185         }
186 }
187
188 static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup *gzgroup)
189 {
190         ViewLayer *view_layer = CTX_data_view_layer(C);
191         Object *ob = BKE_object_pose_armature_get(OBACT(view_layer));
192
193         if (!gzgroup->customdata)
194                 return;
195
196         struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
197         bPoseChannel *pchan = BKE_pose_channel_active(ob);
198
199         /* Handles */
200         for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
201                 wmGizmo *gz = bspline_group->handles[i].gizmo;
202                 bspline_group->handles[i].pchan = pchan;
203                 bspline_group->handles[i].index = i;
204
205                 float mat[4][4];
206                 mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat);
207                 copy_m4_m4(gz->matrix_space, mat);
208
209                 /* need to set property here for undo. TODO would prefer to do this in _init */
210                 WM_gizmo_target_property_def_func(
211                         gz, "offset",
212                         &(const struct wmGizmoPropertyFnParams) {
213                             .value_get_fn = gizmo_bbone_offset_get,
214                             .value_set_fn = gizmo_bbone_offset_set,
215                             .range_get_fn = NULL,
216                             .user_data = &bspline_group->handles[i],
217                         });
218         }
219 }
220
221 void VIEW3D_GGT_armature_spline(wmGizmoGroupType *gzgt)
222 {
223         gzgt->name = "Armature Spline Widgets";
224         gzgt->idname = "VIEW3D_GGT_armature_spline";
225
226         gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
227                      WM_GIZMOGROUPTYPE_3D);
228
229         gzgt->poll = WIDGETGROUP_armature_spline_poll;
230         gzgt->setup = WIDGETGROUP_armature_spline_setup;
231         gzgt->refresh = WIDGETGROUP_armature_spline_refresh;
232 }
233
234 /** \} */