Merge branch 'master' into blender2.8
[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 'b_bone_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         Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
133         if (ob != NULL) {
134                 const bArmature *arm = ob->data;
135                 if (arm->drawtype == ARM_B_BONE) {
136                         bPoseChannel *pchan = BKE_pose_channel_active(ob);
137                         if (pchan && pchan->bone->segments > 1) {
138                                 View3D *v3d = CTX_wm_view3d(C);
139                                 if ((v3d->flag2 & V3D_RENDER_OVERRIDE) ||
140                                     (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_CONTEXT)))
141                                 {
142                                         /* pass */
143                                 }
144                                 else {
145                                         return true;
146                                 }
147                         }
148                 }
149         }
150         return false;
151 }
152
153
154 static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *gzgroup)
155 {
156         Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
157         bPoseChannel *pchan = BKE_pose_channel_active(ob);
158
159         const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true);
160
161         struct BoneSplineWidgetGroup *bspline_group = MEM_callocN(sizeof(struct BoneSplineWidgetGroup), __func__);
162         gzgroup->customdata = bspline_group;
163
164         /* Handles */
165         for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
166                 wmGizmo *gz;
167                 gz = bspline_group->handles[i].gizmo = WM_gizmo_new_ptr(gzt_move, gzgroup, NULL);
168                 RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_RING_2D);
169                 RNA_enum_set(gz->ptr, "draw_options",
170                              ED_GIZMO_MOVE_DRAW_FLAG_FILL | ED_GIZMO_MOVE_DRAW_FLAG_ALIGN_VIEW);
171                 WM_gizmo_set_flag(gz, WM_GIZMO_DRAW_VALUE, true);
172
173                 UI_GetThemeColor3fv(TH_GIZMO_PRIMARY, gz->color);
174                 UI_GetThemeColor3fv(TH_GIZMO_HI, gz->color_hi);
175
176                 gz->scale_basis = 0.06f;
177
178                 if (i == 0) {
179                         copy_v3_v3(gz->matrix_basis[3], pchan->loc);
180                 }
181         }
182 }
183
184 static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup *gzgroup)
185 {
186         Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
187
188         if (!gzgroup->customdata)
189                 return;
190
191         struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata;
192         bPoseChannel *pchan = BKE_pose_channel_active(ob);
193
194         /* Handles */
195         for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) {
196                 wmGizmo *gz = bspline_group->handles[i].gizmo;
197                 bspline_group->handles[i].pchan = pchan;
198                 bspline_group->handles[i].index = i;
199
200                 float mat[4][4];
201                 mul_m4_m4m4(mat, ob->obmat, (i == 0) ? pchan->disp_mat : pchan->disp_tail_mat);
202                 copy_m4_m4(gz->matrix_space, mat);
203
204                 /* need to set property here for undo. TODO would prefer to do this in _init */
205                 WM_gizmo_target_property_def_func(
206                         gz, "offset",
207                         &(const struct wmGizmoPropertyFnParams) {
208                             .value_get_fn = gizmo_bbone_offset_get,
209                             .value_set_fn = gizmo_bbone_offset_set,
210                             .range_get_fn = NULL,
211                             .user_data = &bspline_group->handles[i],
212                         });
213         }
214 }
215
216 void VIEW3D_GGT_armature_spline(wmGizmoGroupType *gzgt)
217 {
218         gzgt->name = "Armature Spline Widgets";
219         gzgt->idname = "VIEW3D_GGT_armature_spline";
220
221         gzgt->flag = (WM_GIZMOGROUPTYPE_PERSISTENT |
222                      WM_GIZMOGROUPTYPE_3D);
223
224         gzgt->poll = WIDGETGROUP_armature_spline_poll;
225         gzgt->setup = WIDGETGROUP_armature_spline_setup;
226         gzgt->refresh = WIDGETGROUP_armature_spline_refresh;
227 }
228
229 /** \} */