diff options
23 files changed, 1113 insertions, 19 deletions
diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index b59447c3f1a..3baa257a151 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -2034,6 +2034,29 @@ class DATA_PT_gpencil_modifiers(ModifierButtonsPanel, Panel): row.prop(md, "pass_index", text="Pass") row.prop(md, "invert_pass", text="", icon="ARROW_LEFTRIGHT") + def GP_ARMATURE(self, layout, ob, md): + split = layout.split() + + col = split.column() + col.label(text="Object:") + col.prop(md, "object", text="") + col.prop(md, "use_deform_preserve_volume") + + col = split.column() + col.label(text="Bind To:") + col.prop(md, "use_vertex_groups", text="Vertex Groups") + col.prop(md, "use_bone_envelopes", text="Bone Envelopes") + + layout.separator() + + split = layout.split() + + row = split.row(align=True) + row.prop_search(md, "vertex_group", ob, "vertex_groups", text="") + sub = row.row(align=True) + sub.active = bool(md.vertex_group) + sub.prop(md, "invert_vertex_group", text="", icon='ARROW_LEFTRIGHT') + classes = ( DATA_PT_modifiers, diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 8d2cdd4b11b..60f312c9d6b 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3535,6 +3535,15 @@ class VIEW3D_MT_edit_armature_delete(Menu): # ********** Grease Pencil Stroke menus ********** +class VIEW3D_MT_gpencil_autoweights(Menu): + bl_label = "Generate Weights" + + def draw(self, context): + layout = self.layout + layout.operator("gpencil.generate_weights", text="With Empty Groups").mode = 'NAME' + layout.operator("gpencil.generate_weights", text="With Automatic Weights").mode = 'AUTO' + + class VIEW3D_MT_gpencil_simplify(Menu): bl_label = "Simplify" @@ -3704,6 +3713,9 @@ class VIEW3D_MT_weight_gpencil(Menu): layout.operator("gpencil.vertex_group_invert", text="Invert") layout.operator("gpencil.vertex_group_smooth", text="Smooth") + layout.separator() + layout.menu("VIEW3D_MT_gpencil_autoweights") + class VIEW3D_MT_gpencil_animation(Menu): bl_label = "Animation" @@ -5001,7 +5013,6 @@ class VIEW3D_MT_gpencil_sculpt_specials(Menu): def draw(self, context): layout = self.layout - is_3d_view = context.space_data.type == 'VIEW_3D' layout.operator_context = 'INVOKE_REGION_WIN' layout.menu("VIEW3D_MT_assign_material") @@ -5016,6 +5027,9 @@ class VIEW3D_MT_gpencil_sculpt_specials(Menu): layout.operator("gpencil.stroke_simplify_fixed", text="Simplify") layout.operator("gpencil.stroke_simplify", text="Simplify Adaptative") + if context.mode == 'GPENCIL_WEIGHT': + layout.separator() + layout.menu("VIEW3D_MT_gpencil_autoweights") classes = ( VIEW3D_HT_header, @@ -5161,6 +5175,7 @@ classes = ( VIEW3D_PT_object_type_visibility, VIEW3D_PT_grease_pencil, VIEW3D_PT_gpencil_multi_frame, + VIEW3D_MT_gpencil_autoweights, VIEW3D_MT_gpencil_edit_specials, VIEW3D_MT_gpencil_sculpt_specials, VIEW3D_PT_quad_view, diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index e98839e3dbc..2ca6a35eec5 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -44,6 +44,7 @@ struct Scene; struct BPoint; struct MDeformVert; struct Depsgraph; +struct bGPDstroke; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); @@ -73,7 +74,8 @@ void lattice_deform_verts(struct Object *laOb, struct Object *target, void armature_deform_verts(struct Object *armOb, struct Object *target, const struct Mesh *mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts, int deformflag, - float (*prevCos)[3], const char *defgrp_name); + float (*prevCos)[3], const char *defgrp_name, + struct bGPDstroke *gps); float (*BKE_lattice_vertexcos_get(struct Object *ob, int *r_numVerts))[3]; void BKE_lattice_vertexcos_apply(struct Object *ob, float (*vertexCos)[3]); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 7383d80cfa8..a3f7dbe70be 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -46,6 +46,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_lattice_types.h" #include "DNA_listBase.h" @@ -970,7 +971,7 @@ static void armature_bbone_defmats_cb(void *userdata, Link *iter, int index) void armature_deform_verts(Object *armOb, Object *target, const Mesh * mesh, float (*vertexCos)[3], float (*defMats)[3][3], int numVerts, int deformflag, - float (*prevCos)[3], const char *defgrp_name) + float (*prevCos)[3], const char *defgrp_name, bGPDstroke *gps) { bPoseChanDeform *pdef_info_array; bPoseChanDeform *pdef_info = NULL; @@ -1024,7 +1025,7 @@ void armature_deform_verts(Object *armOb, Object *target, const Mesh * mesh, flo /* get the def_nr for the overall armature vertex group if present */ armature_def_nr = defgroup_name_index(target, defgrp_name); - if (ELEM(target->type, OB_MESH, OB_LATTICE)) { + if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { defbase_tot = BLI_listbase_count(&target->defbase); if (target->type == OB_MESH) { @@ -1033,17 +1034,22 @@ void armature_deform_verts(Object *armOb, Object *target, const Mesh * mesh, flo if (dverts) target_totvert = me->totvert; } - else { + else if (target->type == OB_LATTICE) { Lattice *lt = target->data; dverts = lt->dvert; if (dverts) target_totvert = lt->pntsu * lt->pntsv * lt->pntsw; } + else if (target->type == OB_GPENCIL) { + dverts = gps->dvert; + if (dverts) + target_totvert = gps->totpoints; + } } /* get a vertex-deform-index to posechannel array */ if (deformflag & ARM_DEF_VGROUP) { - if (ELEM(target->type, OB_MESH, OB_LATTICE)) { + if (ELEM(target->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { /* if we have a Mesh, only use dverts if it has them */ if (mesh) { use_dverts = (mesh->dvert != NULL); diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 1cfbaed37fe..af82d8fa200 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -423,9 +423,10 @@ void BKE_gpencil_stroke_modifiers(Depsgraph *depsgraph, Object *ob, bGPDlayer *g /* some modifiers could require a recalc of fill triangulation data */ if (gpd->flag & GP_DATA_STROKE_FORCE_RECALC) { if (ELEM(md->type, - eGpencilModifierType_Hook, - eGpencilModifierType_Lattice, - eGpencilModifierType_Offset)) + eGpencilModifierType_Armature, + eGpencilModifierType_Hook, + eGpencilModifierType_Lattice, + eGpencilModifierType_Offset)) { gps->flag |= GP_STROKE_RECALC_CACHES; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c index 858a20dbbc3..7063d86e507 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c @@ -553,14 +553,14 @@ static DRWShadingGroup *DRW_gpencil_shgroup_point_create( static void gpencil_add_fill_shgroup( GpencilBatchCache *cache, DRWShadingGroup *fillgrp, Object *ob, bGPDlayer *gpl, bGPDframe *gpf, bGPDstroke *gps, - const float tintcolor[4], const bool onion, const bool custonion) + float opacity, const float tintcolor[4], const bool onion, const bool custonion) { MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1); if (gps->totpoints >= 3) { float tfill[4]; /* set color using material, tint color and opacity */ interp_v3_v3v3(tfill, gps->runtime.tmp_fill_rgba, tintcolor, tintcolor[3]); - tfill[3] = gps->runtime.tmp_fill_rgba[3] * gpl->opacity; + tfill[3] = gps->runtime.tmp_fill_rgba[3] * opacity; if ((tfill[3] > GPENCIL_ALPHA_OPACITY_THRESH) || (gp_style->fill_style > 0)) { const float *color; if (!onion) { @@ -866,7 +866,7 @@ static void gpencil_draw_strokes( if ((fillgrp) && (!stl->storage->simplify_fill)) { gpencil_add_fill_shgroup( cache, fillgrp, ob, gpl, derived_gpf, gps, - tintcolor, false, custonion); + opacity, tintcolor, false, custonion); } /* stroke */ if (strokegrp) { @@ -1219,6 +1219,7 @@ void DRW_gpencil_populate_datablock( const bool main_onion = v3d != NULL ? (v3d->gp_flag & V3D_GP_SHOW_ONION_SKIN) : true; const bool do_onion = (bool)((gpd->flag & GP_DATA_STROKE_WEIGHTMODE) == 0) && main_onion; const bool overlay = v3d != NULL ? (bool)((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) : true; + float opacity; /* check if playing animation */ bool playing = stl->storage->is_playing; @@ -1242,6 +1243,16 @@ void DRW_gpencil_populate_datablock( if (gpf == NULL) continue; + /* if pose mode, maybe the overlay to fade geometry is enabled */ + if ((draw_ctx->obact) && (draw_ctx->object_mode == OB_MODE_POSE) && + (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT)) + { + opacity = gpl->opacity * v3d->overlay.bone_select_alpha; + } + else { + opacity = gpl->opacity; + } + /* create GHash if need */ if (gpl->runtime.derived_data == NULL) { gpl->runtime.derived_data = (GHash *)BLI_ghash_str_new(gpl->info); @@ -1308,7 +1319,7 @@ void DRW_gpencil_populate_datablock( gpencil_draw_strokes( cache, e_data, vedata, ts, ob, gpd, gpl, gpf, derived_gpf, - gpl->opacity, gpl->tintcolor, false, cache_ob); + opacity, gpl->tintcolor, false, cache_ob); } diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 350dee07a2c..20fccfda6b9 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -34,6 +34,8 @@ #include "DNA_armature_types.h" #include "DNA_constraint_types.h" #include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" #include "BLI_blenlib.h" #include "BLI_ghash.h" @@ -51,6 +53,7 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_modifier.h" +#include "BKE_gpencil_modifier.h" #include "DEG_depsgraph.h" @@ -265,6 +268,46 @@ void ED_armature_bone_rename(Main *bmain, bArmature *arm, const char *oldnamep, break; } } + + /* fix grease pencil modifiers and vertex groups */ + if (ob->type == OB_GPENCIL) { + + bGPdata *gpd = (bGPdata *)ob->data; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if ((gpl->parent != NULL) && (gpl->parent->data == arm)) { + if (STREQ(gpl->parsubstr, oldname)) + BLI_strncpy(gpl->parsubstr, newname, MAXBONENAME); + } + } + + for (GpencilModifierData *gp_md = ob->greasepencil_modifiers.first; gp_md; gp_md = gp_md->next) { + switch (gp_md->type) { + case eGpencilModifierType_Armature: + { + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)gp_md; + if (mmd->object && mmd->object->data == arm) { + bDeformGroup *dg = defgroup_find_name(ob, oldname); + if (dg) { + BLI_strncpy(dg->name, newname, MAXBONENAME); + } + } + break; + } + case eGpencilModifierType_Hook: + { + HookGpencilModifierData *hgp_md = (HookGpencilModifierData *)gp_md; + if (hgp_md->object && (hgp_md->object->data == arm)) { + if (STREQ(hgp_md->subtarget, oldname)) + BLI_strncpy(hgp_md->subtarget, newname, MAXBONENAME); + } + break; + } + default: + break; + } + } + } + DEG_id_tag_update(&ob->id, DEG_TAG_COPY_ON_WRITE); } /* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 114e55c5704..cea2e5d4269 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -58,6 +58,7 @@ set(SRC gpencil_undo.c gpencil_utils.c gpencil_old.c + gpencil_armature.c gpencil_intern.h ) diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c new file mode 100644 index 00000000000..dcbbeaeaf57 --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -0,0 +1,677 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + * Operators for dealing with armatures and GP datablocks + */ + +/** \file blender/editors/gpencil/gpencil_armature.c + * \ingroup edgpencil + */ + + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_math.h" +#include "BLI_string_utils.h" + +#include "BLT_translation.h" + +#include "DNA_armature_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_action.h" +#include "BKE_armature.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "ED_gpencil.h" +#include "ED_object.h" +#include "ED_mesh.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "gpencil_intern.h" + +enum { + GP_ARMATURE_NAME = 0, + GP_ARMATURE_AUTO = 1 +}; + +#define DEFAULT_RATIO 0.10f +#define DEFAULT_DECAY 0.8f + +static int gpencil_bone_looper( + Object *ob, Bone *bone, void *data, + int(*bone_func)(Object *, Bone *, void *)) +{ + /* We want to apply the function bone_func to every bone + * in an armature -- feed bone_looper the first bone and + * a pointer to the bone_func and watch it go!. The int count + * can be useful for counting bones with a certain property + * (e.g. skinnable) + */ + int count = 0; + + if (bone) { + /* only do bone_func if the bone is non null */ + count += bone_func(ob, bone, data); + + /* try to execute bone_func for the first child */ + count += gpencil_bone_looper(ob, bone->childbase.first, data, bone_func); + + /* try to execute bone_func for the next bone at this + * depth of the recursion. + */ + count += gpencil_bone_looper(ob, bone->next, data, bone_func); + } + + return count; +} + +static int gpencil_bone_skinnable_cb(Object *UNUSED(ob), Bone *bone, void *datap) +{ + /* Bones that are deforming + * are regarded to be "skinnable" and are eligible for + * auto-skinning. + * + * This function performs 2 functions: + * + * a) It returns 1 if the bone is skinnable. + * If we loop over all bones with this + * function, we can count the number of + * skinnable bones. + * b) If the pointer data is non null, + * it is treated like a handle to a + * bone pointer -- the bone pointer + * is set to point at this bone, and + * the pointer the handle points to + * is incremented to point to the + * next member of an array of pointers + * to bones. This way we can loop using + * this function to construct an array of + * pointers to bones that point to all + * skinnable bones. + */ + Bone ***hbone; + int a, segments; + struct { Object *armob; void *list; int heat;} *data = datap; + + if (!(bone->flag & BONE_HIDDEN_P)) { + if (!(bone->flag & BONE_NO_DEFORM)) { + if (data->heat && data->armob->pose && + BKE_pose_channel_find_name(data->armob->pose, bone->name)) + { + segments = bone->segments; + } + else { + segments = 1; + } + + if (data->list != NULL) { + hbone = (Bone ***)&data->list; + + for (a = 0; a < segments; a++) { + **hbone = bone; + ++*hbone; + } + } + return segments; + } + } + return 0; +} + +static int vgroup_add_unique_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr)) +{ + /* This group creates a vertex group to ob that has the + * same name as bone (provided the bone is skinnable). + * If such a vertex group already exist the routine exits. + */ + if (!(bone->flag & BONE_NO_DEFORM)) { + if (!defgroup_find_name(ob, bone->name)) { + BKE_object_defgroup_add_name(ob, bone->name); + return 1; + } + } + return 0; +} + +static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap) +{ + /* Bones that are deforming + * are regarded to be "skinnable" and are eligible for + * auto-skinning. + * + * This function performs 2 functions: + * + * a) If the bone is skinnable, it creates + * a vertex group for ob that has + * the name of the skinnable bone + * (if one doesn't exist already). + * b) If the pointer data is non null, + * it is treated like a handle to a + * bDeformGroup pointer -- the + * bDeformGroup pointer is set to point + * to the deform group with the bone's + * name, and the pointer the handle + * points to is incremented to point to the + * next member of an array of pointers + * to bDeformGroups. This way we can loop using + * this function to construct an array of + * pointers to bDeformGroups, all with names + * of skinnable bones. + */ + bDeformGroup ***hgroup, *defgroup = NULL; + int a, segments; + struct { Object *armob; void *list; int heat; } *data = datap; + bArmature *arm = data->armob->data; + + if (!(bone->flag & BONE_HIDDEN_P)) { + if (!(bone->flag & BONE_NO_DEFORM)) { + if (data->heat && data->armob->pose && + BKE_pose_channel_find_name(data->armob->pose, bone->name)) + { + segments = bone->segments; + } + else { + segments = 1; + } + + if (arm->layer & bone->layer) { + if (!(defgroup = defgroup_find_name(ob, bone->name))) { + defgroup = BKE_object_defgroup_add_name(ob, bone->name); + } + else if (defgroup->flag & DG_LOCK_WEIGHT) { + /* In case vgroup already exists and is locked, do not modify it here. See T43814. */ + defgroup = NULL; + } + } + + if (data->list != NULL) { + hgroup = (bDeformGroup ***)&data->list; + + for (a = 0; a < segments; a++) { + **hgroup = defgroup; + ++*hgroup; + } + } + return segments; + } + } + return 0; +} + +/* get weight value depending of distance and decay value */ +static float get_weight(float dist, float decay_rad, float dif_rad) +{ + float weight = 1.0f; + if (dist < decay_rad) { + weight = 1.0f; + } + else { + weight = interpf(0.0f, 0.9f, (dist - decay_rad) / dif_rad); + } + + return weight; +} + +/* This functions implements the automatic computation of vertex group weights */ +static void gpencil_add_verts_to_dgroups( + const bContext *C, ReportList *reports, + Depsgraph *depsgraph, + Object *ob, Object *ob_arm, const float ratio, const float decay) +{ + bArmature *arm = ob_arm->data; + Bone **bonelist, *bone; + bDeformGroup **dgrouplist; + bDeformGroup *dgroup; + bPoseChannel *pchan; + bGPdata *gpd = (bGPdata *)ob->data; + bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + + Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = NULL; + float(*root)[3], (*tip)[3], (*verts)[3]; + float *radsqr; + int *selected; + float weight; + int numbones, i, j, segments = 0; + struct { Object *armob; void *list; int heat; } looper_data; + + looper_data.armob = ob_arm; + looper_data.heat = true; + looper_data.list = NULL; + + /* count the number of skinnable bones */ + numbones = gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb); + + if (numbones == 0) + return; + + /* create an array of pointer to bones that are skinnable + * and fill it with all of the skinnable bones */ + bonelist = MEM_callocN(numbones * sizeof(Bone *), "bonelist"); + looper_data.list = bonelist; + gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, gpencil_bone_skinnable_cb); + + /* create an array of pointers to the deform groups that + * correspond to the skinnable bones (creating them + * as necessary. */ + dgrouplist = MEM_callocN(numbones * sizeof(bDeformGroup *), "dgrouplist"); + + looper_data.list = dgrouplist; + gpencil_bone_looper(ob, arm->bonebase.first, &looper_data, dgroup_skinnable_cb); + + /* create an array of root and tip positions transformed into + * global coords */ + root = MEM_callocN(numbones * sizeof(float) * 3, "root"); + tip = MEM_callocN(numbones * sizeof(float) * 3, "tip"); + selected = MEM_callocN(numbones * sizeof(int), "selected"); + radsqr = MEM_callocN(numbones * sizeof(float), "radsqr"); + + for (j = 0; j < numbones; j++) { + bone = bonelist[j]; + dgroup = dgrouplist[j]; + + /* handle bbone */ + if (segments == 0) { + segments = 1; + bbone = NULL; + + if ((ob_arm->pose) && + (pchan = BKE_pose_channel_find_name(ob_arm->pose, bone->name))) + { + if (bone->segments > 1) { + segments = bone->segments; + b_bone_spline_setup(pchan, 1, bbone_array); + bbone = bbone_array; + } + } + } + + segments--; + + /* compute root and tip */ + if (bbone) { + mul_v3_m4v3(root[j], bone->arm_mat, bbone[segments].mat[3]); + if ((segments + 1) < bone->segments) { + mul_v3_m4v3(tip[j], bone->arm_mat, bbone[segments + 1].mat[3]); + } + else { + copy_v3_v3(tip[j], bone->arm_tail); + } + } + else { + copy_v3_v3(root[j], bone->arm_head); + copy_v3_v3(tip[j], bone->arm_tail); + } + + mul_m4_v3(ob_arm->obmat, root[j]); + mul_m4_v3(ob_arm->obmat, tip[j]); + + selected[j] = 1; + + /* calculate radius squared */ + radsqr[j] = len_squared_v3v3(root[j], tip[j]) * ratio; + } + + /* loop all strokes */ + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bGPDframe *init_gpf = gpl->actframe; + bGPDspoint *pt = NULL; + + if (is_multiedit) { + init_gpf = gpl->frames.first; + } + + for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + if ((gpf == gpl->actframe) || + ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) + { + + if (gpf == NULL) + continue; + + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) + continue; + + BKE_gpencil_dvert_ensure(gps); + + /* create verts array */ + verts = MEM_callocN(gps->totpoints * sizeof(*verts), __func__); + + /* transform stroke points to global space */ + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + copy_v3_v3(verts[i], &pt->x); + mul_m4_v3(ob->obmat, verts[i]); + } + + /* loop groups and assign weight */ + for (j = 0; j < numbones; j++) { + int def_nr = BLI_findindex(&ob->defbase, dgrouplist[j]); + if (def_nr < 0) { + continue; + } + + float decay_rad = radsqr[j] - (radsqr[j] * decay); + float dif_rad = radsqr[j] - decay_rad; + + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + MDeformVert *dvert = &gps->dvert[i]; + float dist = dist_squared_to_line_segment_v3(verts[i], root[j], tip[j]); + if (dist > radsqr[j]) { + /* if not in cylinder, check if inside extreme spheres */ + weight = 0.0f; + dist = len_squared_v3v3(root[j], verts[i]); + if (dist < radsqr[j]) { + weight = get_weight(dist, decay_rad, dif_rad); + } + else { + dist = len_squared_v3v3(tip[j], verts[i]); + if (dist < radsqr[j]) { + weight = get_weight(dist, decay_rad, dif_rad); + } + } + } + else { + /* inside bone cylinder */ + weight = get_weight(dist, decay_rad, dif_rad); + } + + /* assign weight */ + MDeformWeight *dw = defvert_verify_index(dvert, def_nr); + if (dw) { + dw->weight = weight; + } + } + } + MEM_SAFE_FREE(verts); + } + } + + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + + /* free the memory allocated */ + MEM_SAFE_FREE(bonelist); + MEM_SAFE_FREE(dgrouplist); + MEM_SAFE_FREE(root); + MEM_SAFE_FREE(tip); + MEM_SAFE_FREE(radsqr); + MEM_SAFE_FREE(selected); +} + +static void gpencil_object_vgroup_calc_from_armature( + const bContext *C, ReportList *reports, + Depsgraph *depsgraph, Object *ob, Object *ob_arm, + const int mode, const float ratio, const float decay) +{ + /* Lets try to create some vertex groups + * based on the bones of the parent armature. + */ + bArmature *arm = ob_arm->data; + + /* always create groups */ + const int defbase_tot = BLI_listbase_count(&ob->defbase); + int defbase_add; + /* Traverse the bone list, trying to create empty vertex + * groups corresponding to the bone. + */ + defbase_add = gpencil_bone_looper(ob, arm->bonebase.first, NULL, + vgroup_add_unique_bone_cb); + + if (defbase_add) { + /* its possible there are DWeight's outside the range of the current + * objects deform groups, in this case the new groups wont be empty */ + ED_vgroup_data_clamp_range(ob->data, defbase_tot); + } + + if (mode == GP_ARMATURE_AUTO) { + /* Traverse the bone list, trying to fill vertex groups + * with the corresponding vertice weights for which the + * bone is closest. + */ + gpencil_add_verts_to_dgroups(C, reports, depsgraph, ob, ob_arm, + ratio, decay); + } +} + +bool ED_gpencil_add_armature_weights( + const bContext *C, ReportList *reports, + Object *ob, Object *ob_arm, int mode) +{ + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Scene *scene = CTX_data_scene(C); + + /* if no armature modifier, add a new one */ + GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature); + if (md == NULL) { + md = ED_object_gpencil_modifier_add(reports, bmain, scene, + ob, "Armature", eGpencilModifierType_Armature); + if (md == NULL) { + BKE_report(reports, RPT_ERROR, + "Unable to add a new Armature modifier to object"); + return false; + } + DEG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); + } + + /* verify armature */ + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + if (mmd->object == NULL) { + mmd->object = ob_arm; + } + else { + if (ob_arm != mmd->object) { + BKE_report(reports, RPT_ERROR, + "The existing Armature modifier is already using a different Armature object"); + return false; + } + } + + /* add weights */ + gpencil_object_vgroup_calc_from_armature(C, reports, depsgraph, + ob, ob_arm, mode, + DEFAULT_RATIO, DEFAULT_DECAY); + + return true; +} +/* ***************** Generate armature weights ************************** */ +bool gpencil_generate_weights_poll(bContext *C) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *ob = CTX_data_active_object(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bGPdata *gpd = (bGPdata *)ob->data; + + if (BLI_listbase_count(&gpd->layers) == 0) { + return false; + } + + /* need some armature in the view layer */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object->type == OB_ARMATURE) { + return true; + } + } + + return false; +} + +static int gpencil_generate_weights_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = CTX_data_active_object(C); + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + bGPdata *gpd = (bGPdata *)ob->data; + Object *ob_arm = NULL; + + const int mode = RNA_enum_get(op->ptr, "mode"); + const float ratio = RNA_float_get(op->ptr, "ratio"); + const float decay = RNA_float_get(op->ptr, "decay"); + + /* sanity checks */ + if (ELEM(NULL, ob, gpd)) + return OPERATOR_CANCELLED; + + /* get armature */ + const int arm_idx = RNA_enum_get(op->ptr, "armature"); + if (arm_idx > 0) { + Base *base = BLI_findlink(&view_layer->object_bases, arm_idx - 1); + ob_arm = base->object; + } + else { + /* get armature from modifier */ + GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval, eGpencilModifierType_Armature); + if (md == NULL) { + BKE_report(op->reports, RPT_ERROR, + "The grease pencil object need an Armature modifier"); + return OPERATOR_CANCELLED; + } + + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + if (mmd->object == NULL) { + BKE_report(op->reports, RPT_ERROR, + "Armature modifier is not valid or wrong defined"); + return OPERATOR_CANCELLED; + } + + ob_arm = mmd->object; + } + + if (ob_arm == NULL) { + BKE_report(op->reports, RPT_ERROR, + "No Armature object in the view layer"); + return OPERATOR_CANCELLED; + } + + gpencil_object_vgroup_calc_from_armature(C, op->reports,depsgraph, + ob, ob_arm, mode, ratio, decay); + + /* notifiers */ + DEG_id_tag_update(&gpd->id, OB_RECALC_OB | OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +/* Dynamically populate an enum of Armatures */ +static const EnumPropertyItem *gpencil_armatures_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + EnumPropertyItem *item = NULL, item_tmp = { 0 }; + int totitem = 0; + int i = 0; + + if (C == NULL) { + return DummyRNA_DEFAULT_items; + } + + /* add default */ + item_tmp.identifier = "DEFAULT"; + item_tmp.name = "Default"; + item_tmp.value = 0; + RNA_enum_item_add(&item, &totitem, &item_tmp); + i++; + + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + Object *ob = base->object; + if (ob->type == OB_ARMATURE) { + item_tmp.identifier = item_tmp.name = ob->id.name + 2; + item_tmp.value = i; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + i++; + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void GPENCIL_OT_generate_weights(wmOperatorType *ot) +{ + static const EnumPropertyItem mode_type[] = { + {GP_ARMATURE_NAME, "NAME", 0, "Empty Groups", ""}, + {GP_ARMATURE_AUTO, "AUTO", 0, "Automatic Weights", ""}, + {0, NULL, 0, NULL, NULL} + }; + + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Generate Automatic Weights"; + ot->idname = "GPENCIL_OT_generate_weights"; + ot->description = "Generate automatic weights for armatures (requires armature modifier)"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gpencil_generate_weights_exec; + ot->poll = gpencil_generate_weights_poll; + + ot->prop = RNA_def_enum(ot->srna, "mode", mode_type, 0, "Mode", ""); + + prop = RNA_def_enum(ot->srna, "armature", DummyRNA_DEFAULT_items, 0, "Armature", "Armature to use"); + RNA_def_enum_funcs(prop, gpencil_armatures_enum_itemf); + + RNA_def_float(ot->srna, "ratio", DEFAULT_RATIO, 0.0f, 2.0f, "Ratio", + "Ratio between bone length and influence radius", 0.001f, 1.0f); + + RNA_def_float(ot->srna, "decay", DEFAULT_DECAY, 0.0f, 1.0f, "Decay", + "Factor to reduce influence depending of distance to bone axis", 0.0f, 1.0f); +} diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index d2c8435ed70..975b09ed5c8 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -422,6 +422,9 @@ void GPENCIL_OT_color_select(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot); +/* armatures */ +void GPENCIL_OT_generate_weights(struct wmOperatorType *ot); + /* ****************************************************** */ /* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index ca97a7948e5..2a82fa88ce5 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -785,6 +785,8 @@ void ED_operatortypes_gpencil(void) /* convert old 2.7 files to 2.8 */ WM_operatortype_append(GPENCIL_OT_convert_old_files); + /* armatures */ + WM_operatortype_append(GPENCIL_OT_generate_weights); } void ED_operatormacros_gpencil(void) diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 13f8233079b..25dc6743a33 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -49,6 +49,7 @@ struct Depsgraph; struct ScrArea; struct ARegion; struct RegionView3D; +struct ReportList; struct Scene; struct ToolSettings; struct ViewLayer; @@ -193,6 +194,14 @@ bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mod int ED_gpencil_session_active(void); int ED_undo_gpencil_step(struct bContext *C, int step, const char *name); +/* ------------ Grease-Pencil Armature weights ------------------ */ +bool ED_gpencil_add_armature_weights(const struct bContext *C, struct ReportList *reports, + struct Object *ob, struct Object *ob_arm, int mode); + +/* keep this aligned with gpencil_armature enum */ +#define GP_PAR_ARMATURE_NAME 0 +#define GP_PAR_ARMATURE_AUTO 1 + /* ------------ Transformation Utilities ------------ */ /* get difference matrix */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 9279a755b56..e022d65de63 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -109,6 +109,7 @@ #include "ED_armature.h" #include "ED_curve.h" +#include "ED_gpencil.h" #include "ED_keyframing.h" #include "ED_object.h" #include "ED_mesh.h" @@ -797,6 +798,23 @@ bool ED_object_parent_set(ReportList *reports, const bContext *C, Scene *scene, invert_m4_m4(ob->parentinv, workob.obmat); } + else if (pararm && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { + if (partype == PAR_ARMATURE_NAME) { + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_NAME); + } + else if ((partype == PAR_ARMATURE_AUTO) || + (partype == PAR_ARMATURE_ENVELOPE)) + { + WM_cursor_wait(1); + ED_gpencil_add_armature_weights(C, reports, ob, par, GP_PAR_ARMATURE_AUTO); + WM_cursor_wait(0); + } + /* get corrected inverse */ + ob->partype = PAROBJECT; + BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); + + invert_m4_m4(ob->parentinv, workob.obmat); + } else { /* calculate inverse parent matrix */ BKE_object_workob_calc_parent(depsgraph, scene, ob, &workob); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index d8715f2dfe0..2f7d8b7523c 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1094,6 +1094,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eGpencilModifierType_Offset: data.icon = ICON_MOD_DISPLACE; break; + case eGpencilModifierType_Armature: + data.icon = ICON_MOD_ARMATURE; + break; /* Default */ default: diff --git a/source/blender/gpencil_modifiers/CMakeLists.txt b/source/blender/gpencil_modifiers/CMakeLists.txt index 5ad91d4e01b..44689a1d091 100644 --- a/source/blender/gpencil_modifiers/CMakeLists.txt +++ b/source/blender/gpencil_modifiers/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC intern/MOD_gpencil_util.h intern/MOD_gpencil_util.c + intern/MOD_gpencilarmature.c intern/MOD_gpencilnoise.c intern/MOD_gpencilsubdiv.c intern/MOD_gpencilsimplify.c diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h index 73386601d10..968f7e73544 100644 --- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h +++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h @@ -44,6 +44,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror; extern GpencilModifierTypeInfo modifierType_Gpencil_Smooth; extern GpencilModifierTypeInfo modifierType_Gpencil_Hook; extern GpencilModifierTypeInfo modifierType_Gpencil_Offset; +extern GpencilModifierTypeInfo modifierType_Gpencil_Armature; /* MOD_gpencil_util.c */ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 9ddc6a1e3e4..5aa9073eacb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -77,6 +77,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) INIT_GP_TYPE(Smooth); INIT_GP_TYPE(Hook); INIT_GP_TYPE(Offset); + INIT_GP_TYPE(Armature); #undef INIT_GP_TYPE } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c new file mode 100644 index 00000000000..4ae48e73d0f --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -0,0 +1,205 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/gpencil_modifiers/intern/MOD_gpencilarmature.c + * \ingroup modifiers + */ + +#include <stdio.h> + +#include "DNA_armature_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_modifier_types.h" +#include "BLI_math.h" + +#include "BLI_listbase.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "BKE_lattice.h" +#include "BKE_context.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_modifier.h" +#include "BKE_library_query.h" +#include "BKE_scene.h" +#include "BKE_main.h" + +#include "MEM_guardedalloc.h" + +#include "MOD_gpencil_util.h" +#include "MOD_gpencil_modifiertypes.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +static void initData(GpencilModifierData *md) +{ + ArmatureGpencilModifierData *gpmd = (ArmatureGpencilModifierData *)md; + gpmd->object = NULL; + gpmd->deformflag = ARM_DEF_VGROUP; +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + BKE_gpencil_modifier_copyData_generic(md, target); +} + +static void gpencil_deform_verts( + ArmatureGpencilModifierData *mmd, Object *target, + bGPDstroke *gps) +{ + bGPDspoint *pt = gps->points; + float *all_vert_coords = MEM_callocN(sizeof(float) * 3 * gps->totpoints, __func__); + int i; + + BKE_gpencil_dvert_ensure(gps); + + /* prepare array of points */ + for (i = 0; i < gps->totpoints; i++, pt++) { + float *pt_coords = &all_vert_coords[3 * i]; + float co[3]; + copy_v3_v3(co, &pt->x); + copy_v3_v3(pt_coords, co); + } + + /* deform verts */ + armature_deform_verts(mmd->object, target, NULL, + (float(*)[3])all_vert_coords, + NULL, gps->totpoints, + mmd->deformflag, + (float(*)[3])mmd->prevCos, + mmd->vgname, gps); + + /* Apply deformed coordinates */ + pt = gps->points; + for (i = 0; i < gps->totpoints; i++, pt++) { + float *pt_coords = &all_vert_coords[3 * i]; + copy_v3_v3(&pt->x, pt_coords); + } + + MEM_SAFE_FREE(all_vert_coords); + +} + +/* deform stroke */ +static void deformStroke( + GpencilModifierData *md, Depsgraph *UNUSED(depsgraph), + Object *ob, bGPDlayer *UNUSED(gpl), bGPDstroke *gps) +{ + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + if (!mmd->object) { + return; + } + + gpencil_deform_verts(mmd, ob, gps); +} + +static void bakeModifier( + Main *bmain, Depsgraph *depsgraph, + GpencilModifierData *md, Object *ob) +{ + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) + return; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* apply armature effects on this frame + * NOTE: this assumes that we don't want armature animation on non-keyframed frames + */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* compute armature effects on this frame */ + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + deformStroke(md, depsgraph, ob, gpl, gps); + } + } + } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + + return !mmd->object; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + ArmatureGpencilModifierData *lmd = (ArmatureGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Armature Modifier"); +} + +static void foreachObjectLink( + GpencilModifierData *md, Object *ob, + ObjectWalkFunc walk, void *userData) +{ + ArmatureGpencilModifierData *mmd = (ArmatureGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Armature = { + /* name */ "Armature", + /* structName */ "ArmatureGpencilModifierData", + /* structSize */ sizeof(ArmatureGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ 0, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + + /* initData */ initData, + /* freeData */ NULL, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index 3727ca9a3f3..ae341b24e41 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -50,6 +50,7 @@ typedef enum GpencilModifierType { eGpencilModifierType_Hook = 12, eGpencilModifierType_Offset = 13, eGpencilModifierType_Mirror = 14, + eGpencilModifierType_Armature = 15, NUM_GREASEPENCIL_MODIFIER_TYPES } GpencilModifierType; @@ -408,4 +409,14 @@ typedef enum eSmoothGpencil_Flag { GP_SMOOTH_MOD_UV = (1 << 6), } eSmoothGpencil_Flag; +typedef struct ArmatureGpencilModifierData { + GpencilModifierData modifier; + short deformflag, multi; /* deformflag replaces armature->deformflag */ + int pad2; + struct Object *object; + float *prevCos; /* stored input of previous modifier, for vertexgroup blending */ + char vgname[64]; /* MAX_VGROUP_NAME */ + +} ArmatureGpencilModifierData; + #endif /* __DNA_GPENCIL_MODIFIER_TYPES_H__ */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 8036f9edaa7..55bd83ece69 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -613,6 +613,7 @@ extern StructRNA RNA_MirrorGpencilModifier; extern StructRNA RNA_SmoothGpencilModifier; extern StructRNA RNA_HookGpencilModifier; extern StructRNA RNA_OffsetGpencilModifier; +extern StructRNA RNA_ArmatureGpencilModifier; extern StructRNA RNA_ShaderFx; extern StructRNA RNA_ShaderFxBlur; extern StructRNA RNA_ShaderFxColorize; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index c4d1e93a2ef..ec8adeaddda 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -67,6 +67,7 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { {eGpencilModifierType_Simplify, "GP_SIMPLIFY", ICON_MOD_DECIM, "Simplify", "Simplify stroke reducing number of points"}, {eGpencilModifierType_Subdiv, "GP_SUBDIV", ICON_MOD_SUBSURF, "Subdivide", "Subdivide stroke adding more control points"}, {0, "", 0, N_("Deform"), "" }, + {eGpencilModifierType_Armature, "GP_ARMATURE", ICON_MOD_ARMATURE, "Armature", "Deform stroke points using armature object"}, {eGpencilModifierType_Hook, "GP_HOOK", ICON_HOOK, "Hook", "Deform stroke points using objects"}, {eGpencilModifierType_Lattice, "GP_LATTICE", ICON_MOD_LATTICE, "Lattice", "Deform strokes using lattice"}, {eGpencilModifierType_Mirror, "GP_MIRROR", ICON_MOD_MIRROR, "Mirror", "Duplicate strokes like a mirror"}, @@ -160,6 +161,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr) return &RNA_HookGpencilModifier; case eGpencilModifierType_Offset: return &RNA_OffsetGpencilModifier; + case eGpencilModifierType_Armature: + return &RNA_ArmatureGpencilModifier; /* Default */ case eGpencilModifierType_None: case NUM_GREASEPENCIL_MODIFIER_TYPES: @@ -227,6 +230,7 @@ RNA_GP_MOD_VGROUP_NAME_SET(Lattice, vgname); RNA_GP_MOD_VGROUP_NAME_SET(Smooth, vgname); RNA_GP_MOD_VGROUP_NAME_SET(Hook, vgname); RNA_GP_MOD_VGROUP_NAME_SET(Offset, vgname); +RNA_GP_MOD_VGROUP_NAME_SET(Armature, vgname); #undef RNA_GP_MOD_VGROUP_NAME_SET @@ -251,6 +255,7 @@ static void rna_##_type##GpencilModifier_##_prop##_set(PointerRNA *ptr, PointerR greasepencil_modifier_object_set(ptr->id.data, &tmd->_prop, _obtype, value); \ } +RNA_GP_MOD_OBJECT_SET(Armature, object, OB_ARMATURE); RNA_GP_MOD_OBJECT_SET(Lattice, object, OB_LATTICE); RNA_GP_MOD_OBJECT_SET(Mirror, object, OB_EMPTY); @@ -1261,6 +1266,60 @@ static void rna_def_modifier_gpencilhook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } + +static void rna_def_modifier_gpencilarmature(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "ArmatureGpencilModifier", "GpencilModifier"); + RNA_def_struct_ui_text(srna, "Armature Modifier", "Change stroke using armature to deform modifier"); + RNA_def_struct_sdna(srna, "ArmatureGpencilModifierData"); + RNA_def_struct_ui_icon(srna, ICON_MOD_ARMATURE); + + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); + RNA_def_property_ui_text(prop, "Object", "Armature object to deform with"); + RNA_def_property_pointer_funcs(prop, NULL, "rna_ArmatureGpencilModifier_object_set", NULL, "rna_Armature_object_poll"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_STATIC); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "use_bone_envelopes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_ENVELOPE); + RNA_def_property_ui_text(prop, "Use Bone Envelopes", "Bind Bone envelopes to armature modifier"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "use_vertex_groups", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_VGROUP); + RNA_def_property_ui_text(prop, "Use Vertex Groups", "Bind vertex groups to armature modifier"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "use_deform_preserve_volume", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_QUATERNION); + RNA_def_property_ui_text(prop, "Preserve Volume", "Deform rotation interpolation with quaternions"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + +#if 0 /* GPXX keep disabled now */ + prop = RNA_def_property(srna, "use_multi_modifier", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "multi", 0); + RNA_def_property_ui_text(prop, "Multi Modifier", + "Use same input as previous modifier, and mix results using overall vgroup"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); +#endif + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "vgname"); + RNA_def_property_ui_text(prop, "Vertex Group", + "Name of Vertex Group which determines influence of modifier per point"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ArmatureGpencilModifier_vgname_set"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); + + prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "deformflag", ARM_DEF_INVERT_VGROUP); + RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update"); +} + void RNA_def_greasepencil_modifier(BlenderRNA *brna) { StructRNA *srna; @@ -1330,6 +1389,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna) rna_def_modifier_gpencillattice(brna); rna_def_modifier_gpencilmirror(brna); rna_def_modifier_gpencilhook(brna); + rna_def_modifier_gpencilarmature(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 7a831d08c88..a7c79aa8e68 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2741,7 +2741,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_BONE_SELECT); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_ui_text(prop, "Bone Selection", "Show the Bone Selection Overlay"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); prop = RNA_def_property(srna, "bone_select_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "overlay.bone_select_alpha"); @@ -2749,7 +2749,7 @@ static void rna_def_space_view3d_overlay(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Opacity", "Opacity to use for bone selection"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_GPencil_update"); prop = RNA_def_property(srna, "show_motion_paths", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "overlay.flag", V3D_OVERLAY_HIDE_MOTION_PATHS); diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index c44b65dffec..7fa1705249c 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -122,7 +122,7 @@ static void deformVerts( MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ armature_deform_verts(amd->object, ctx->object, mesh, vertexCos, NULL, - numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name); + numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL); /* free cache */ if (amd->prevCos) { @@ -141,7 +141,7 @@ static void deformVertsEM( MOD_previous_vcos_store(md, vertexCos); /* if next modifier needs original vertices */ armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, NULL, - numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name); + numVerts, amd->deformflag, (float(*)[3])amd->prevCos, amd->defgrp_name, NULL); /* free cache */ if (amd->prevCos) { @@ -163,7 +163,7 @@ static void deformMatricesEM( Mesh *mesh_src = MOD_get_mesh_eval(ctx->object, em, mesh, NULL, false, false); armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, numVerts, - amd->deformflag, NULL, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name, NULL); if (mesh_src != mesh) { BKE_id_free(NULL, mesh_src); @@ -178,7 +178,7 @@ static void deformMatrices( Mesh *mesh_src = MOD_get_mesh_eval(ctx->object, NULL, mesh, NULL, false, false); armature_deform_verts(amd->object, ctx->object, mesh_src, vertexCos, defMats, numVerts, - amd->deformflag, NULL, amd->defgrp_name); + amd->deformflag, NULL, amd->defgrp_name, NULL); if (mesh_src != mesh) { BKE_id_free(NULL, mesh_src); |