GPencil: New Outline modifier

This modifier converts any stroke (no fill strokes) into perimeter
from camera view.  Also, it's possible to define an alternative 
material for the outline.

There is an option to include a target object to manipulate the start 
point of the strokes. The start point will be the nearest point 
to the target object.

Reviewed By: mendio, frogstomp

Maniphest Tasks: T100826

Differential Revision: https://developer.blender.org/D15882

Note: Icon will be updated in T101155
This commit is contained in:
Antonio Vazquez 2022-09-27 16:42:00 +02:00
parent 75a6d3abf7
commit 5f7259a001
Notes: blender-bot 2023-02-13 14:34:45 +01:00
Referenced by issue #100826, GPencil: New Outline modifier
8 changed files with 534 additions and 0 deletions

View File

@ -47,6 +47,7 @@ set(SRC
intern/MOD_gpencilnoise.c
intern/MOD_gpenciloffset.c
intern/MOD_gpencilopacity.c
intern/MOD_gpenciloutline.c
intern/MOD_gpencilshrinkwrap.c
intern/MOD_gpencilsimplify.c
intern/MOD_gpencilsmooth.c

View File

@ -20,6 +20,7 @@ extern GpencilModifierTypeInfo modifierType_Gpencil_Color;
extern GpencilModifierTypeInfo modifierType_Gpencil_Array;
extern GpencilModifierTypeInfo modifierType_Gpencil_Build;
extern GpencilModifierTypeInfo modifierType_Gpencil_Opacity;
extern GpencilModifierTypeInfo modifierType_Gpencil_Outline;
extern GpencilModifierTypeInfo modifierType_Gpencil_Lattice;
extern GpencilModifierTypeInfo modifierType_Gpencil_Length;
extern GpencilModifierTypeInfo modifierType_Gpencil_Mirror;

View File

@ -41,6 +41,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[])
INIT_GP_TYPE(Array);
INIT_GP_TYPE(Build);
INIT_GP_TYPE(Opacity);
INIT_GP_TYPE(Outline);
INIT_GP_TYPE(Lattice);
INIT_GP_TYPE(Length);
INIT_GP_TYPE(Mirror);

View File

@ -0,0 +1,342 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
/** \file
* \ingroup modifiers
*/
#include <stdio.h>
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLT_translation.h"
#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_gpencil_geom.h"
#include "BKE_gpencil_modifier.h"
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "BKE_modifier.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "MOD_gpencil_modifiertypes.h"
#include "MOD_gpencil_ui_common.h"
#include "MOD_gpencil_util.h"
static void initData(GpencilModifierData *md)
{
OutlineGpencilModifierData *gpmd = (OutlineGpencilModifierData *)md;
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(gpmd, modifier));
MEMCPY_STRUCT_AFTER(gpmd, DNA_struct_default_get(OutlineGpencilModifierData), modifier);
}
static void copyData(const GpencilModifierData *md, GpencilModifierData *target)
{
BKE_gpencil_modifier_copydata_generic(md, target);
}
static void free_old_strokes(Depsgraph *depsgraph, Object *ob, bGPdata *gpd)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
/* Free old strokes. */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
if (gpf == NULL) {
continue;
}
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
if (gps->flag & GP_STROKE_TAG) {
BLI_remlink(&gpf->strokes, gps);
BKE_gpencil_free_stroke(gps);
}
}
}
}
static void convert_stroke(GpencilModifierData *md,
Object *ob,
bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *gps,
float viewmat[4][4],
float diff_mat[4][4])
{
OutlineGpencilModifierData *mmd = (OutlineGpencilModifierData *)md;
bGPdata *gpd = (bGPdata *)ob->data;
const bool keep = (mmd->flag & GP_OUTLINE_KEEP_SHAPE) != 0;
if (!is_stroke_affected_by_modifier(ob,
mmd->layername,
mmd->material,
mmd->pass_index,
mmd->layer_pass,
1,
gpl,
gps,
mmd->flag & GP_OUTLINE_INVERT_LAYER,
mmd->flag & GP_OUTLINE_INVERT_PASS,
mmd->flag & GP_OUTLINE_INVERT_LAYERPASS,
mmd->flag & GP_OUTLINE_INVERT_MATERIAL)) {
return;
}
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1);
const bool is_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
/* Only strokes type, no fill strokes. */
if (!is_stroke) {
return;
}
/* Duplicate the stroke to apply any layer thickness change. */
bGPDstroke *gps_duplicate = BKE_gpencil_stroke_duplicate(gps, true, false);
/* Apply layer thickness change. */
gps_duplicate->thickness += gpl->line_change;
/* Apply object scale to thickness. */
gps_duplicate->thickness *= mat4_to_scale(ob->obmat);
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
/* Stroke. */
const float ovr_thickness = keep ? mmd->thickness : 0.0f;
bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
viewmat, gpd, gpl, gps_duplicate, mmd->subdiv, diff_mat, ovr_thickness);
gps_perimeter->flag &= ~GP_STROKE_SELECT;
gps_perimeter->runtime.gps_orig = gps->runtime.gps_orig;
/* Assign material. */
if (mmd->outline_material) {
Material *ma = mmd->outline_material;
int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob, ma->id.name + 2);
if (mat_idx > -1) {
gps_perimeter->mat_nr = mat_idx;
}
else {
gps_perimeter->mat_nr = gps->mat_nr;
}
}
else {
gps_perimeter->mat_nr = gps->mat_nr;
}
/* Sample stroke. */
if (mmd->sample_length > 0.0f) {
BKE_gpencil_stroke_sample(gpd, gps_perimeter, mmd->sample_length, false, 0);
}
/* Set stroke thickness. */
gps_perimeter->thickness = mmd->thickness;
/* Set pressure constant. */
int orig_idx = -1;
float min_distance = FLT_MAX;
bGPDspoint *pt;
for (int i = 0; i < gps_perimeter->totpoints; i++) {
pt = &gps_perimeter->points[i];
pt->pressure = 1.0f;
pt->runtime.pt_orig = NULL;
/* If any target object is defined, find the nearest point. */
if (mmd->object) {
float wpt[3];
mul_v3_m4v3(wpt, diff_mat, &pt->x);
float dist = len_squared_v3v3(wpt, mmd->object->loc);
if (dist < min_distance) {
min_distance = dist;
orig_idx = i;
}
}
}
if (orig_idx > 0) {
BKE_gpencil_stroke_start_set(gps_perimeter, orig_idx);
BKE_gpencil_stroke_geometry_update(gpd, gps_perimeter);
}
/* Add perimeter stroke to frame. */
BLI_insertlinkafter(&gpf->strokes, gps, gps_perimeter);
/* Free Temp stroke. */
BKE_gpencil_free_stroke(gps_duplicate);
/* Tag original stroke to be removed. */
gps->flag |= GP_STROKE_TAG;
}
static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob)
{
bGPdata *gpd = (bGPdata *)ob->data;
/* Calc camera view matrix. */
Scene *scene = DEG_get_evaluated_scene(depsgraph);
/* Ensure the camera is the right one. */
BKE_scene_camera_switch_update(scene);
if (!scene->camera) {
return;
}
Object *cam_ob = scene->camera;
float viewmat[4][4];
invert_m4_m4(viewmat, cam_ob->obmat);
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl);
if (gpf == NULL) {
continue;
}
/* Prepare transform matrix. */
float diff_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
}
}
/* Delete original strokes. */
free_old_strokes(depsgraph, ob, gpd);
}
static void bakeModifier(Main *UNUSED(bmain),
Depsgraph *depsgraph,
GpencilModifierData *md,
Object *ob)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
bGPdata *gpd = ob->data;
int oldframe = (int)DEG_get_ctime(depsgraph);
/* Calc camera view matrix. */
if (!scene->camera) {
return;
}
Object *cam_ob = scene->camera;
float viewmat[4][4];
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
scene->r.cfra = gpf->framenum;
BKE_scene_graph_update_for_newframe(depsgraph);
/* Ensure the camera is the right one. */
BKE_scene_camera_switch_update(scene);
invert_m4_m4(viewmat, cam_ob->obmat);
/* Prepare transform matrix. */
float diff_mat[4][4];
BKE_gpencil_layer_transform_matrix_get(depsgraph, ob, gpl, diff_mat);
/* Compute all strokes of this frame. */
LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) {
convert_stroke(md, ob, gpl, gpf, gps, viewmat, diff_mat);
}
}
}
/* Delete original strokes. */
free_old_strokes(depsgraph, ob, gpd);
/* Return frame state and DB to original state. */
scene->r.cfra = oldframe;
BKE_scene_graph_update_for_newframe(depsgraph);
}
static void foreachIDLink(GpencilModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
{
OutlineGpencilModifierData *mmd = (OutlineGpencilModifierData *)md;
walk(userData, ob, (ID **)&mmd->material, IDWALK_CB_USER);
walk(userData, ob, (ID **)&mmd->outline_material, IDWALK_CB_USER);
walk(userData, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
}
static void updateDepsgraph(GpencilModifierData *md,
const ModifierUpdateDepsgraphContext *ctx,
const int UNUSED(mode))
{
OutlineGpencilModifierData *lmd = (OutlineGpencilModifierData *)md;
if (ctx->scene->camera) {
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
DEG_add_object_relation(
ctx->node, ctx->scene->camera, DEG_OB_COMP_PARAMETERS, "Outline Modifier");
}
if (lmd->object != NULL) {
DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
}
DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Outline Modifier");
}
static void panel_draw(const bContext *UNUSED(C), Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA *ptr = gpencil_modifier_panel_get_property_pointers(panel, NULL);
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "thickness", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "use_keep_shape", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "subdivision", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "sample_length", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "outline_material", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE);
gpencil_modifier_panel_end(layout, ptr);
}
static void mask_panel_draw(const bContext *UNUSED(C), Panel *panel)
{
gpencil_modifier_masking_panel_draw(panel, true, false);
}
static void panelRegister(ARegionType *region_type)
{
PanelType *panel_type = gpencil_modifier_panel_register(
region_type, eGpencilModifierType_Outline, panel_draw);
gpencil_modifier_subpanel_register(
region_type, "mask", "Influence", NULL, mask_panel_draw, panel_type);
}
GpencilModifierTypeInfo modifierType_Gpencil_Outline = {
/* name */ N_("Outline"),
/* structName */ "OutlineGpencilModifierData",
/* structSize */ sizeof(OutlineGpencilModifierData),
/* type */ eGpencilModifierTypeType_Gpencil,
/* flags */ eGpencilModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformStroke */ NULL,
/* generateStrokes */ generateStrokes,
/* bakeModifier */ bakeModifier,
/* remapTime */ NULL,
/* initData */ initData,
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* foreachIDLink */ foreachIDLink,
/* foreachTexLink */ NULL,
/* panelRegister */ panelRegister,
};

View File

@ -172,6 +172,19 @@
.curve_intensity = NULL, \
}
#define _DNA_DEFAULT_OutlineGpencilModifierData \
{ \
.material = NULL, \
.layername = "", \
.pass_index = 0, \
.flag = GP_OUTLINE_KEEP_SHAPE, \
.thickness = 1, \
.sample_length = 0.0f, \
.subdiv = 3, \
.layer_pass = 0, \
.outline_material = NULL, \
}
#define _DNA_DEFAULT_SimplifyGpencilModifierData \
{ \
.material = NULL, \

View File

@ -47,6 +47,7 @@ typedef enum GpencilModifierType {
eGpencilModifierType_WeightAngle = 23,
eGpencilModifierType_Shrinkwrap = 24,
eGpencilModifierType_Envelope = 25,
eGpencilModifierType_Outline = 26,
/* Keep last. */
NUM_GREASEPENCIL_MODIFIER_TYPES,
} GpencilModifierType;
@ -313,6 +314,38 @@ typedef enum eOpacityGpencil_Flag {
GP_OPACITY_WEIGHT_FACTOR = (1 << 8),
} eOpacityGpencil_Flag;
typedef struct OutlineGpencilModifierData {
GpencilModifierData modifier;
/** Target stroke origin. */
struct Object *object;
/** Material for filtering. */
struct Material *material;
/** Layer name. */
char layername[64];
/** Custom index for passes. */
int pass_index;
/** Flags. */
int flag;
/** Thickness. */
int thickness;
/** Sample Length. */
float sample_length;
/** Subdivisions. */
int subdiv;
/** Custom index for passes. */
int layer_pass;
/** Material for outline. */
struct Material *outline_material;
} OutlineGpencilModifierData;
typedef enum eOutlineGpencil_Flag {
GP_OUTLINE_INVERT_LAYER = (1 << 0),
GP_OUTLINE_INVERT_PASS = (1 << 1),
GP_OUTLINE_INVERT_LAYERPASS = (1 << 2),
GP_OUTLINE_INVERT_MATERIAL = (1 << 3),
GP_OUTLINE_KEEP_SHAPE = (1 << 4),
} eOutlineGpencil_Flag;
typedef struct ArrayGpencilModifierData {
GpencilModifierData modifier;
struct Object *object;

View File

@ -302,6 +302,7 @@ SDNA_DEFAULT_DECL_STRUCT(MultiplyGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(NoiseGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(OffsetGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(OpacityGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(OutlineGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(SimplifyGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(SmoothGpencilModifierData);
SDNA_DEFAULT_DECL_STRUCT(SubdivGpencilModifierData);
@ -542,6 +543,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(NoiseGpencilModifierData),
SDNA_DEFAULT_DECL(OffsetGpencilModifierData),
SDNA_DEFAULT_DECL(OpacityGpencilModifierData),
SDNA_DEFAULT_DECL(OutlineGpencilModifierData),
SDNA_DEFAULT_DECL(SimplifyGpencilModifierData),
SDNA_DEFAULT_DECL(SmoothGpencilModifierData),
SDNA_DEFAULT_DECL(SubdivGpencilModifierData),

View File

@ -105,6 +105,11 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = {
ICON_GP_MULTIFRAME_EDITING,
"Multiple Strokes",
"Produce multiple strokes along one stroke"},
{eGpencilModifierType_Outline,
"GP_OUTLINE",
ICON_MOD_SKIN,
"Outline",
"Convert stroke to perimeter"},
{eGpencilModifierType_Simplify,
"GP_SIMPLIFY",
ICON_MOD_SIMPLIFY,
@ -286,6 +291,8 @@ static StructRNA *rna_GpencilModifier_refine(struct PointerRNA *ptr)
return &RNA_BuildGpencilModifier;
case eGpencilModifierType_Opacity:
return &RNA_OpacityGpencilModifier;
case eGpencilModifierType_Outline:
return &RNA_OutlineGpencilModifier;
case eGpencilModifierType_Lattice:
return &RNA_LatticeGpencilModifier;
case eGpencilModifierType_Length:
@ -668,6 +675,37 @@ static void rna_OpacityGpencilModifier_material_set(PointerRNA *ptr,
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
static void rna_OutlineGpencilModifier_object_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *UNUSED(reports))
{
OutlineGpencilModifierData *omd = ptr->data;
Object *ob = (Object *)value.data;
omd->object = ob;
id_lib_extern((ID *)ob);
}
static void rna_OutlineGpencilModifier_material_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *reports)
{
OutlineGpencilModifierData *omd = (OutlineGpencilModifierData *)ptr->data;
Material **ma_target = &omd->material;
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
static void rna_OutlineStrokeGpencilModifier_material_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *reports)
{
OutlineGpencilModifierData *omd = (OutlineGpencilModifierData *)ptr->data;
Material **ma_target = &omd->outline_material;
rna_GpencilModifier_material_set(ptr, value, ma_target, reports);
}
static void rna_LatticeGpencilModifier_material_set(PointerRNA *ptr,
PointerRNA value,
struct ReportList *reports)
@ -1972,6 +2010,108 @@ static void rna_def_modifier_gpencilopacity(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_gpenciloutline(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "OutlineGpencilModifier", "GpencilModifier");
RNA_def_struct_ui_text(srna, "Outline Modifier", "Outline of Strokes modifier from camera view");
RNA_def_struct_sdna(srna, "OutlineGpencilModifierData");
// TODO: add new icon
RNA_def_struct_ui_icon(srna, ICON_MOD_SKIN);
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "layer", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "layername");
RNA_def_property_ui_text(prop, "Layer", "Layer name");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop,
NULL,
"rna_OutlineGpencilModifier_material_set",
NULL,
"rna_GpencilModifier_material_poll");
RNA_def_property_ui_text(prop, "Material", "Material used for filtering effect");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "pass_index");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Pass", "Pass index");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_layers", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OUTLINE_INVERT_LAYER);
RNA_def_property_ui_text(prop, "Inverse Layers", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_materials", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OUTLINE_INVERT_MATERIAL);
RNA_def_property_ui_text(prop, "Inverse Materials", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_material_pass", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OUTLINE_INVERT_PASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "layer_pass", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "layer_pass");
RNA_def_property_range(prop, 0, 100);
RNA_def_property_ui_text(prop, "Pass", "Layer pass index");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "invert_layer_pass", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OUTLINE_INVERT_LAYERPASS);
RNA_def_property_ui_text(prop, "Inverse Pass", "Inverse filter");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "thickness", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "thickness");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_text(prop, "Thickness", "Thickness of the perimeter stroke");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "sample_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sample_length");
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 0.1f, 2);
RNA_def_property_ui_text(prop, "Sample Length", "");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "subdivision", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "subdiv");
RNA_def_property_range(prop, 0, 10);
RNA_def_property_ui_text(prop, "Subdivisions", "Number of subdivisions");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_keep_shape", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_OUTLINE_KEEP_SHAPE);
RNA_def_property_ui_text(prop, "Keep Shape", "Try to keep global shape");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "outline_material", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop,
NULL,
"rna_OutlineStrokeGpencilModifier_material_set",
NULL,
"rna_GpencilModifier_material_poll");
RNA_def_property_ui_text(prop, "Outline Material", "Material used for outline strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Target Object", "Target object to define stroke start");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_pointer_funcs(prop, NULL, "rna_OutlineGpencilModifier_object_set", NULL, NULL);
RNA_def_property_update(prop, 0, "rna_GpencilModifier_dependency_update");
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_gpencilarray(BlenderRNA *brna)
{
StructRNA *srna;
@ -4353,6 +4493,7 @@ void RNA_def_greasepencil_modifier(BlenderRNA *brna)
rna_def_modifier_gpencilarray(brna);
rna_def_modifier_gpencilbuild(brna);
rna_def_modifier_gpencilopacity(brna);
rna_def_modifier_gpenciloutline(brna);
rna_def_modifier_gpencillattice(brna);
rna_def_modifier_gpencilmirror(brna);
rna_def_modifier_gpencilhook(brna);