Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / gpencil / gpencil_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  * The Original Code is Copyright (C) 2018, Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Antonio Vazquez
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * Operators for dealing with armatures and GP datablocks
26  */
27
28 /** \file blender/editors/gpencil/gpencil_armature.c
29  *  \ingroup edgpencil
30  */
31
32
33 #include <stdio.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <stddef.h>
37 #include <math.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_utildefines.h"
43 #include "BLI_ghash.h"
44 #include "BLI_math.h"
45 #include "BLI_string_utils.h"
46
47 #include "BLT_translation.h"
48
49 #include "DNA_armature_types.h"
50 #include "DNA_gpencil_types.h"
51 #include "DNA_meshdata_types.h"
52 #include "DNA_scene_types.h"
53
54 #include "BKE_main.h"
55 #include "BKE_action.h"
56 #include "BKE_armature.h"
57 #include "BKE_context.h"
58 #include "BKE_deform.h"
59 #include "BKE_gpencil.h"
60 #include "BKE_gpencil_modifier.h"
61 #include "BKE_object_deform.h"
62 #include "BKE_report.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67 #include "RNA_access.h"
68 #include "RNA_define.h"
69 #include "RNA_enum_types.h"
70
71 #include "ED_gpencil.h"
72 #include "ED_object.h"
73 #include "ED_mesh.h"
74
75 #include "DEG_depsgraph.h"
76 #include "DEG_depsgraph_query.h"
77
78 #include "gpencil_intern.h"
79
80 enum {
81         GP_ARMATURE_NAME = 0,
82         GP_ARMATURE_AUTO = 1
83 };
84
85 #define DEFAULT_RATIO 0.10f
86 #define DEFAULT_DECAY 0.8f
87
88 static int gpencil_bone_looper(
89         Object *ob, Bone *bone, void *data,
90         int(*bone_func)(Object *, Bone *, void *))
91 {
92         /* We want to apply the function bone_func to every bone
93          * in an armature -- feed bone_looper the first bone and
94          * a pointer to the bone_func and watch it go!. The int count
95          * can be useful for counting bones with a certain property
96          * (e.g. skinnable)
97          */
98         int count = 0;
99
100         if (bone) {
101                 /* only do bone_func if the bone is non null */
102                 count += bone_func(ob, bone, data);
103
104                 /* try to execute bone_func for the first child */
105                 count += gpencil_bone_looper(ob, bone->childbase.first, data, bone_func);
106
107                 /* try to execute bone_func for the next bone at this
108                  * depth of the recursion.
109                  */
110                 count += gpencil_bone_looper(ob, bone->next, data, bone_func);
111         }
112
113         return count;
114 }
115
116 static int gpencil_bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap)
117 {
118         /* Bones that are deforming
119          * are regarded to be "skinnable" and are eligible for
120          * auto-skinning.
121          *
122          * This function performs 2 functions:
123          *
124          *   a) It returns 1 if the bone is skinnable.
125          *      If we loop over all bones with this
126          *      function, we can count the number of
127          *      skinnable bones.
128          *   b) If the pointer data is non null,
129          *      it is treated like a handle to a
130          *      bone pointer -- the bone pointer
131          *      is set to point at this bone, and
132          *      the pointer the handle points to
133          *      is incremented to point to the
134          *      next member of an array of pointers
135          *      to bones. This way we can loop using
136          *      this function to construct an array of
137          *      pointers to bones that point to all
138          *      skinnable bones.
139          */
140         Bone ***hbone;
141         int a, segments;
142         struct { Object *armob; void *list; int heat;} *data = datap;
143
144         if (!(bone->flag & BONE_HIDDEN_P)) {
145                 if (!(bone->flag & BONE_NO_DEFORM)) {
146                         if (data->heat && data->armob->pose &&
147                             BKE_pose_channel_find_name(data->armob->pose, bone->name))
148                         {
149                                 segments = bone->segments;
150                         }
151                         else {
152                                 segments = 1;
153                         }
154
155                         if (data->list != NULL) {
156                                 hbone = (Bone ***)&data->list;
157
158                                 for (a = 0; a < segments; a++) {
159                                         **hbone = bone;
160                                         (*hbone)++;
161                                 }
162                         }
163                         return segments;
164                 }
165         }
166         return 0;
167 }
168
169 static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
170 {
171         /* This group creates a vertex group to ob that has the
172          * same name as bone (provided the bone is skinnable).
173          * If such a vertex group already exist the routine exits.
174          */
175         if (!(bone->flag & BONE_NO_DEFORM)) {
176                 if (!defgroup_find_name(ob, bone->name)) {
177                         BKE_object_defgroup_add_name(ob, bone->name);
178                         return 1;
179                 }
180         }
181         return 0;
182 }
183
184 static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
185 {
186         /* Bones that are deforming
187          * are regarded to be "skinnable" and are eligible for
188          * auto-skinning.
189          *
190          * This function performs 2 functions:
191          *
192          *   a) If the bone is skinnable, it creates
193          *      a vertex group for ob that has
194          *      the name of the skinnable bone
195          *      (if one doesn't exist already).
196          *   b) If the pointer data is non null,
197          *      it is treated like a handle to a
198          *      bDeformGroup pointer -- the
199          *      bDeformGroup pointer is set to point
200          *      to the deform group with the bone's
201          *      name, and the pointer the handle
202          *      points to is incremented to point to the
203          *      next member of an array of pointers
204          *      to bDeformGroups. This way we can loop using
205          *      this function to construct an array of
206          *      pointers to bDeformGroups, all with names
207          *      of skinnable bones.
208          */
209         bDeformGroup ***hgroup, *defgroup = NULL;
210         int a, segments;
211         struct { Object *armob; void *list; int heat; } *data = datap;
212         bArmature *arm = data->armob->data;
213
214         if (!(bone->flag & BONE_HIDDEN_P)) {
215                 if (!(bone->flag & BONE_NO_DEFORM)) {
216                         if (data->heat && data->armob->pose &&
217                             BKE_pose_channel_find_name(data->armob->pose, bone->name))
218                         {
219                                 segments = bone->segments;
220                         }
221                         else {
222                                 segments = 1;
223                         }
224
225                         if (arm->layer & bone->layer) {
226                                 if (!(defgroup = defgroup_find_name(ob, bone->name))) {
227                                         defgroup = BKE_object_defgroup_add_name(ob, bone->name);
228                                 }
229                                 else if (defgroup->flag & DG_LOCK_WEIGHT) {
230                                         /* In case vgroup already exists and is locked, do not modify it here. See T43814. */
231                                         defgroup = NULL;
232                                 }
233                         }
234
235                         if (data->list != NULL) {
236                                 hgroup = (bDeformGroup ***)&data->list;
237
238                                 for (a = 0; a < segments; a++) {
239                                         **hgroup = defgroup;
240                                         (*hgroup)++;
241                                 }
242                         }
243                         return segments;
244                 }
245         }
246         return 0;
247 }
248
249 /* get weight value depending of distance and decay value */
250 static float get_weight(float dist, float decay_rad, float dif_rad)
251 {
252         float weight = 1.0f;
253         if (dist < decay_rad) {
254                 weight = 1.0f;
255         }
256         else {
257                 weight = interpf(0.0f, 0.9f, (dist - decay_rad) / dif_rad);
258         }
259
260         return weight;
261 }
262
263 /* This functions implements the automatic computation of vertex group weights */
264 static void gpencil_add_verts_to_dgroups(
265         const bContext *C, Object *ob, Object *ob_arm, const float ratio, const float decay)
266 {
267         bArmature *arm = ob_arm->data;
268         Bone **bonelist, *bone;
269         bDeformGroup **dgrouplist;
270         bPoseChannel *pchan;
271         bGPdata *gpd = (bGPdata *)ob->data;
272         const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
273
274         Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL;
275         float(*root)[3], (*tip)[3], (*verts)[3];
276         float *radsqr;
277         int *selected;
278         float weight;
279         int numbones, i, j, segments = 0;
280         struct { Object *armob; void *list; int heat; } looper_data;
281
282         looper_data.armob = ob_arm;
283         looper_data.heat = true;
284         looper_data.list = NULL;
285
286         /* count the number of skinnable bones */
287         numbones = gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
288
289         if (numbones == 0)
290                 return;
291
292         /* create an array of pointer to bones that are skinnable
293          * and fill it with all of the skinnable bones */
294         bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist");
295         looper_data.list = bonelist;
296         gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb);
297
298         /* create an array of pointers to the deform groups that
299          * correspond to the skinnable bones (creating them
300          * as necessary. */
301         dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist");
302
303         looper_data.list = dgrouplist;
304         gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb);
305
306         /* create an array of root and tip positions transformed into
307          * global coords */
308         root = MEM_callocN(numbones * sizeof(float) * 3, "root");
309         tip = MEM_callocN(numbones * sizeof(float) * 3, "tip");
310         selected = MEM_callocN(numbones * sizeof(int), "selected");
311         radsqr = MEM_callocN(numbones * sizeof(float), "radsqr");
312
313         for (j = 0; j < numbones; j++) {
314                 bone = bonelist[j];
315
316                 /* handle bbone */
317                 if (segments == 0) {
318                         segments = 1;
319                         bbone = NULL;
320
321                         if ((ob_arm->pose) &&
322                             (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name)))
323                         {
324                                 if (bone->segments > 1) {
325                                         segments = bone->segments;
326                                         BKE_pchan_bbone_spline_setup(pchan, true, bbone_array);
327                                         bbone = bbone_array;
328                                 }
329                         }
330                 }
331
332                 segments--;
333
334                 /* compute root and tip */
335                 if (bbone) {
336                         mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]);
337                         if ((segments + 1) < bone->segments) {
338                                 mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]);
339                         }
340                         else {
341                                 copy_v3_v3(tip[j], bone->arm_tail);
342                         }
343                 }
344                 else {
345                         copy_v3_v3(root[j], bone->arm_head);
346                         copy_v3_v3(tip[j], bone->arm_tail);
347                 }
348
349                 mul_m4_v3(ob_arm->obmat, root[j]);
350                 mul_m4_v3(ob_arm->obmat, tip[j]);
351
352                 selected[j] = 1;
353
354                 /* calculate radius squared */
355                 radsqr[j] = len_squared_v3v3(root[j], tip[j]) * ratio;
356         }
357
358         /* loop all strokes */
359         for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
360                 bGPDframe *init_gpf = gpl->actframe;
361                 bGPDspoint *pt = NULL;
362
363                 if (is_multiedit) {
364                         init_gpf = gpl->frames.first;
365                 }
366
367                 for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
368                         if ((gpf == gpl->actframe) ||
369                             ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit)))
370                         {
371
372                                 if (gpf == NULL)
373                                         continue;
374
375                                 for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
376                                         /* skip strokes that are invalid for current view */
377                                         if (ED_gpencil_stroke_can_use(C, gps) == false)
378                                                 continue;
379
380                                         BKE_gpencil_dvert_ensure(gps);
381
382                                         /* create verts array */
383                                         verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__);
384
385                                         /* transform stroke points to global space */
386                                         for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
387                                                 copy_v3_v3(verts[i], &pt->x);
388                                                 mul_m4_v3(ob->obmat, verts[i]);
389                                         }
390
391                                         /* loop groups and assign weight */
392                                         for (j = 0; j < numbones; j++) {
393                                                 int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]);
394                                                 if (def_nr < 0) {
395                                                         continue;
396                                                 }
397
398                                                 float decay_rad = radsqr[j] - (radsqr[j] * decay);
399                                                 float dif_rad = radsqr[j] - decay_rad;
400
401                                                 for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
402                                                         MDeformVert *dvert = &gps->dvert[i];
403                                                         float dist = dist_squared_to_line_segment_v3(verts[i], root[j], tip[j]);
404                                                         if (dist > radsqr[j]) {
405                                                                 /* if not in cylinder, check if inside extreme spheres */
406                                                                 weight = 0.0f;
407                                                                 dist = len_squared_v3v3(root[j], verts[i]);
408                                                                 if (dist < radsqr[j]) {
409                                                                         weight = get_weight(dist, decay_rad, dif_rad);
410                                                                 }
411                                                                 else {
412                                                                         dist = len_squared_v3v3(tip[j], verts[i]);
413                                                                         if (dist < radsqr[j]) {
414                                                                                 weight = get_weight(dist, decay_rad, dif_rad);
415                                                                         }
416                                                                 }
417                                                         }
418                                                         else {
419                                                                 /* inside bone cylinder */
420                                                                 weight = get_weight(dist, decay_rad, dif_rad);
421                                                         }
422
423                                                         /* assign weight */
424                                                         MDeformWeight *dw = defvert_verify_index(dvert, def_nr);
425                                                         if (dw) {
426                                                                 dw->weight = weight;
427                                                         }
428                                                 }
429                                         }
430                                         MEM_SAFE_FREE(verts);
431                                 }
432                         }
433
434                         /* if not multiedit, exit loop*/
435                         if (!is_multiedit) {
436                                 break;
437                         }
438                 }
439         }
440
441         /* free the memory allocated */
442         MEM_SAFE_FREE(bonelist);
443         MEM_SAFE_FREE(dgrouplist);
444         MEM_SAFE_FREE(root);
445         MEM_SAFE_FREE(tip);
446         MEM_SAFE_FREE(radsqr);
447         MEM_SAFE_FREE(selected);
448 }
449
450 static void gpencil_object_vgroup_calc_from_armature(
451         const bContext *C,
452         Object *ob, Object *ob_arm,
453         const int mode, const float ratio, const float decay)
454 {
455         /* Lets try to create some vertex groups
456          * based on the bones of the parent armature.
457          */
458         bArmature *arm = ob_arm->data;
459
460         /* always create groups */
461         const int defbase_tot = BLI_listbase_count(&ob->defbase);
462         int defbase_add;
463         /* Traverse the bone list, trying to create empty vertex
464          * groups corresponding to the bone.
465          */
466         defbase_add = gpencil_bone_looper(
467                 ob, arm->bonebase.first, NULL,
468                 vgroup_add_unique_bone_cb);
469
470         if (defbase_add) {
471                 /* its possible there are DWeight's outside the range of the current
472                  * objects deform groups, in this case the new groups wont be empty */
473                 ED_vgroup_data_clamp_range(ob->data, defbase_tot);
474         }
475
476         if (mode == GP_ARMATURE_AUTO) {
477                 /* Traverse the bone list, trying to fill vertex groups
478                  * with the corresponding vertice weights for which the
479                  * bone is closest.
480                  */
481                 gpencil_add_verts_to_dgroups(
482                         C, ob, ob_arm,
483                         ratio, decay);
484         }
485 }
486
487 bool ED_gpencil_add_armature_weights(
488         const bContext *C, ReportList *reports,
489         Object *ob, Object *ob_arm, int mode)
490 {
491         Main *bmain = CTX_data_main(C);
492         Scene *scene = CTX_data_scene(C);
493
494         /* if no armature modifier, add a new one */
495         GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature);
496         if (md == NULL) {
497                 md = ED_object_gpencil_modifier_add(
498                         reports, bmain, scene,
499                         ob, "Armature", eGpencilModifierType_Armature);
500                 if (md == NULL) {
501                         BKE_report(reports, RPT_ERROR,
502                                    "Unable to add a new Armature modifier to object");
503                         return false;
504                 }
505                 DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
506         }
507
508         /* verify armature */
509         ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
510         if (mmd->object == NULL) {
511                 mmd->object = ob_arm;
512         }
513         else {
514                 if (ob_arm != mmd->object) {
515                         BKE_report(reports, RPT_ERROR,
516                                    "The existing Armature modifier is already using a different Armature object");
517                         return false;
518                 }
519         }
520
521         /* add weights */
522         gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, DEFAULT_RATIO, DEFAULT_DECAY);
523
524         return true;
525 }
526 /* ***************** Generate armature weights ************************** */
527 static bool gpencil_generate_weights_poll(bContext *C)
528 {
529         Object *ob = CTX_data_active_object(C);
530
531         if (ob->type != OB_GPENCIL) {
532                 return false;
533         }
534
535         ViewLayer *view_layer = CTX_data_view_layer(C);
536         bGPdata *gpd = (bGPdata *)ob->data;
537
538         if (BLI_listbase_count(&gpd->layers) == 0) {
539                 return false;
540         }
541
542         /* need some armature in the view layer */
543         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
544                 if (base->object->type == OB_ARMATURE) {
545                         return true;
546                 }
547         }
548
549         return false;
550 }
551
552 static int gpencil_generate_weights_exec(bContext *C, wmOperator *op)
553 {
554         Depsgraph *depsgraph = CTX_data_depsgraph(C);
555         ViewLayer *view_layer = CTX_data_view_layer(C);
556         Object *ob = CTX_data_active_object(C);
557         Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
558         bGPdata *gpd = (bGPdata *)ob->data;
559         Object *ob_arm = NULL;
560
561         const int mode = RNA_enum_get(op->ptr, "mode");
562         const float ratio = RNA_float_get(op->ptr, "ratio");
563         const float decay = RNA_float_get(op->ptr, "decay");
564
565         /* sanity checks */
566         if (ELEM(NULL, ob, gpd))
567                 return OPERATOR_CANCELLED;
568
569         /* get armature */
570         const int arm_idx = RNA_enum_get(op->ptr, "armature");
571         if (arm_idx > 0) {
572                 Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1);
573                 ob_arm = base->object;
574         }
575         else {
576                 /* get armature from modifier */
577                 GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval, eGpencilModifierType_Armature);
578                 if (md == NULL) {
579                         BKE_report(op->reports, RPT_ERROR,
580                                 "The grease pencil object need an Armature modifier");
581                         return OPERATOR_CANCELLED;
582                 }
583
584                 ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md;
585                 if (mmd->object == NULL) {
586                         BKE_report(op->reports, RPT_ERROR,
587                                 "Armature modifier is not valid or wrong defined");
588                         return OPERATOR_CANCELLED;
589                 }
590
591                 ob_arm = mmd->object;
592         }
593
594         if (ob_arm == NULL) {
595                 BKE_report(op->reports, RPT_ERROR,
596                            "No Armature object in the view layer");
597                 return OPERATOR_CANCELLED;
598         }
599
600         gpencil_object_vgroup_calc_from_armature(C, ob, ob_arm, mode, ratio, decay);
601
602         /* notifiers */
603         DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA);
604         WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
605
606         return OPERATOR_FINISHED;
607 }
608
609 /* Dynamically populate an enum of Armatures */
610 static const EnumPropertyItem *gpencil_armatures_enum_itemf(
611         bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
612 {
613         ViewLayer *view_layer = CTX_data_view_layer(C);
614         EnumPropertyItem *item = NULL, item_tmp = { 0 };
615         int totitem = 0;
616         int i = 0;
617
618         if (C == NULL) {
619                 return DummyRNA_DEFAULT_items;
620         }
621
622         /* add default */
623         item_tmp.identifier = "DEFAULT";
624         item_tmp.name = "Default";
625         item_tmp.value = 0;
626         RNA_enum_item_add(&item, &totitem, &item_tmp);
627         i++;
628
629         for (Base *base = view_layer->object_bases.first; base; base = base->next) {
630                 Object *ob = base->object;
631                 if (ob->type == OB_ARMATURE) {
632                         item_tmp.identifier = item_tmp.name = ob->id.name + 2;
633                         item_tmp.value = i;
634                         RNA_enum_item_add(&item, &totitem, &item_tmp);
635                 }
636                 i++;
637         }
638
639         RNA_enum_item_end(&item, &totitem);
640         *r_free = true;
641
642         return item;
643 }
644
645 void GPENCIL_OT_generate_weights(wmOperatorType *ot)
646 {
647         static const EnumPropertyItem mode_type[] = {
648                 {GP_ARMATURE_NAME, "NAME", 0, "Empty Groups", ""},
649                 {GP_ARMATURE_AUTO, "AUTO", 0, "Automatic Weights", ""},
650                 {0, NULL, 0, NULL, NULL}
651         };
652
653         PropertyRNA *prop;
654
655         /* identifiers */
656         ot->name = "Generate Automatic Weights";
657         ot->idname = "GPENCIL_OT_generate_weights";
658         ot->description = "Generate automatic weights for armatures (requires armature modifier)";
659
660         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
661
662         /* callbacks */
663         ot->exec = gpencil_generate_weights_exec;
664         ot->poll = gpencil_generate_weights_poll;
665
666         ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, 0, "Mode", "");
667
668         prop = RNA_def_enum(ot->srna, "armature", DummyRNA_DEFAULT_items, 0, "Armature", "Armature to use");
669         RNA_def_enum_funcs(prop, gpencil_armatures_enum_itemf);
670
671         RNA_def_float(
672                 ot->srna, "ratio", DEFAULT_RATIO, 0.0f, 2.0f, "Ratio",
673                 "Ratio between bone length and influence radius", 0.001f, 1.0f);
674
675         RNA_def_float(
676                 ot->srna, "decay", DEFAULT_DECAY, 0.0f, 1.0f, "Decay",
677                 "Factor to reduce influence depending of distance to bone axis", 0.0f, 1.0f);
678 }