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