Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/properties_data_modifier.py23
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py17
-rw-r--r--source/blender/blenkernel/BKE_lattice.h4
-rw-r--r--source/blender/blenkernel/intern/armature.c14
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c7
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c19
-rw-r--r--source/blender/editors/armature/armature_naming.c43
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt1
-rw-r--r--source/blender/editors/gpencil/gpencil_armature.c677
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h3
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c2
-rw-r--r--source/blender/editors/include/ED_gpencil.h9
-rw-r--r--source/blender/editors/object/object_relations.c18
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c3
-rw-r--r--source/blender/gpencil_modifiers/CMakeLists.txt1
-rw-r--r--source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c1
-rw-r--r--source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c205
-rw-r--r--source/blender/makesdna/DNA_gpencil_modifier_types.h11
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_gpencil_modifier.c60
-rw-r--r--source/blender/makesrna/intern/rna_space.c4
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c8
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);