GPencil: New conversion to outline in draw mode
This new option converts the stroke to outline perimeter as soon as is drawn. If no alternative material is set, the actual material is used. The algorithm is similar to the new operator in D15664 Reviewed By: pepeland Differential Revision: https://developer.blender.org/D15738
This commit is contained in:
parent
377b81ac07
commit
613b6ad9e5
|
@ -1742,6 +1742,12 @@ class VIEW3D_PT_tools_grease_pencil_brush_post_processing(View3DPanel, Panel):
|
|||
col1 = col.column(align=True)
|
||||
col1.prop(gp_settings, "use_trim")
|
||||
|
||||
row = col.row(heading="Outline", align=True)
|
||||
row.prop(gp_settings, "use_settings_outline", text="")
|
||||
row2 = row.row(align=True)
|
||||
row2.enabled = gp_settings.use_settings_outline
|
||||
row2.prop(gp_settings, "material_alt", text="")
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_grease_pencil_brush_random(View3DPanel, Panel):
|
||||
bl_context = ".greasepencil_paint"
|
||||
|
|
|
@ -186,6 +186,7 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data)
|
|||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->paint_curve, IDWALK_CB_USER);
|
||||
if (brush->gpencil_settings) {
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material_alt, IDWALK_CB_USER);
|
||||
}
|
||||
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex));
|
||||
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data,
|
||||
|
@ -346,6 +347,7 @@ static void brush_blend_read_lib(BlendLibReader *reader, ID *id)
|
|||
else {
|
||||
brush->gpencil_settings->material = nullptr;
|
||||
}
|
||||
BLO_read_id_address(reader, brush->id.lib, &brush->gpencil_settings->material_alt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,6 +360,7 @@ static void brush_blend_read_expand(BlendExpander *expander, ID *id)
|
|||
BLO_expand(expander, brush->paint_curve);
|
||||
if (brush->gpencil_settings != nullptr) {
|
||||
BLO_expand(expander, brush->gpencil_settings->material);
|
||||
BLO_expand(expander, brush->gpencil_settings->material_alt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -704,6 +707,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
|
|||
/* Set vertex mix factor. */
|
||||
brush->gpencil_settings->vertex_mode = GPPAINT_MODE_BOTH;
|
||||
brush->gpencil_settings->vertex_factor = 1.0f;
|
||||
brush->gpencil_settings->material_alt = nullptr;
|
||||
|
||||
switch (type) {
|
||||
case GP_BRUSH_PRESET_AIRBRUSH: {
|
||||
|
|
|
@ -918,6 +918,64 @@ static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps)
|
|||
}
|
||||
}
|
||||
|
||||
static bGPDstroke *gpencil_stroke_to_outline(tGPsdata *p, bGPDstroke *gps)
|
||||
{
|
||||
bGPDlayer *gpl = p->gpl;
|
||||
RegionView3D *rv3d = p->region->regiondata;
|
||||
Brush *brush = p->brush;
|
||||
BrushGpencilSettings *gpencil_settings = brush->gpencil_settings;
|
||||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(p->ob, gps->mat_nr + 1);
|
||||
const bool is_stroke = ((gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0);
|
||||
|
||||
if (!is_stroke) {
|
||||
return gps;
|
||||
}
|
||||
|
||||
/* 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(p->ob->obmat);
|
||||
CLAMP_MIN(gps_duplicate->thickness, 1.0f);
|
||||
|
||||
/* Stroke. */
|
||||
float diff_mat[4][4];
|
||||
unit_m4(diff_mat);
|
||||
bGPDstroke *gps_perimeter = BKE_gpencil_stroke_perimeter_from_view(
|
||||
rv3d, p->gpd, gpl, gps_duplicate, 3, diff_mat);
|
||||
/* Assign material. */
|
||||
if (gpencil_settings->material_alt == NULL) {
|
||||
gps_perimeter->mat_nr = gps->mat_nr;
|
||||
}
|
||||
else {
|
||||
Material *ma = gpencil_settings->material_alt;
|
||||
int mat_idx = BKE_gpencil_material_find_index_by_name_prefix(p->ob, ma->id.name + 2);
|
||||
if (mat_idx > -1) {
|
||||
gps_perimeter->mat_nr = mat_idx;
|
||||
}
|
||||
else {
|
||||
gps_perimeter->mat_nr = gps->mat_nr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set pressure constant. */
|
||||
bGPDspoint *pt;
|
||||
for (int i = 0; i < gps_perimeter->totpoints; i++) {
|
||||
pt = &gps_perimeter->points[i];
|
||||
pt->pressure = 1.0f;
|
||||
}
|
||||
|
||||
/* Remove original stroke. */
|
||||
BKE_gpencil_free_stroke(gps);
|
||||
|
||||
/* Free Temp stroke. */
|
||||
BKE_gpencil_free_stroke(gps_duplicate);
|
||||
|
||||
return gps_perimeter;
|
||||
}
|
||||
|
||||
/* make a new stroke from the buffer data */
|
||||
static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
||||
{
|
||||
|
@ -1221,6 +1279,23 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
BKE_gpencil_stroke_simplify_adaptive(gpd, gps, brush->gpencil_settings->simplify_f);
|
||||
}
|
||||
|
||||
/* Set material index. */
|
||||
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
|
||||
if (gps->mat_nr < 0) {
|
||||
if (p->ob->actcol - 1 < 0) {
|
||||
gps->mat_nr = 0;
|
||||
}
|
||||
else {
|
||||
gps->mat_nr = p->ob->actcol - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert to Outline. */
|
||||
if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_SETTINGS) &&
|
||||
(brush->gpencil_settings->flag & GP_BRUSH_OUTLINE_STROKE)) {
|
||||
gps = gpencil_stroke_to_outline(p, gps);
|
||||
}
|
||||
|
||||
/* reproject to plane (only in 3d space) */
|
||||
gpencil_reproject_toplane(p, gps);
|
||||
/* change position relative to parent object */
|
||||
|
@ -1235,17 +1310,6 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
|
|||
}
|
||||
}
|
||||
|
||||
/* Save material index */
|
||||
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(p->ob, p->brush);
|
||||
if (gps->mat_nr < 0) {
|
||||
if (p->ob->actcol - 1 < 0) {
|
||||
gps->mat_nr = 0;
|
||||
}
|
||||
else {
|
||||
gps->mat_nr = p->ob->actcol - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* add stroke to frame, usually on tail of the listbase, but if on back is enabled the stroke
|
||||
* is added on listbase head because the drawing order is inverse and the head stroke is the
|
||||
* first to draw. This is very useful for artist when drawing the background.
|
||||
|
|
|
@ -87,6 +87,8 @@ typedef enum eGPDbrush_Flag {
|
|||
GP_BRUSH_OCCLUDE_ERASER = (1 << 15),
|
||||
/* Post process trim stroke */
|
||||
GP_BRUSH_TRIM_STROKE = (1 << 16),
|
||||
/* Post process convert to outline stroke */
|
||||
GP_BRUSH_OUTLINE_STROKE = (1 << 17),
|
||||
} eGPDbrush_Flag;
|
||||
|
||||
typedef enum eGPDbrush_Flag2 {
|
||||
|
|
|
@ -135,6 +135,8 @@ typedef struct BrushGpencilSettings {
|
|||
/* optional link of material to replace default in context */
|
||||
/** Material. */
|
||||
struct Material *material;
|
||||
/** Material Alternative for secondary operations. */
|
||||
struct Material *material_alt;
|
||||
} BrushGpencilSettings;
|
||||
|
||||
typedef struct BrushCurvesSculptSettings {
|
||||
|
|
|
@ -1820,6 +1820,12 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Trim Stroke Ends", "Trim intersecting stroke ends");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "use_settings_outline", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_OUTLINE_STROKE);
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
RNA_def_property_ui_text(prop, "Outline", "Convert stroke to perimeter");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
|
||||
prop = RNA_def_property(srna, "direction", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_bitflag_sdna(prop, NULL, "sculpt_flag");
|
||||
RNA_def_property_enum_items(prop, prop_direction_items);
|
||||
|
@ -1883,6 +1889,15 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
|
|||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_Brush_material_update");
|
||||
|
||||
/* Secondary Material */
|
||||
prop = RNA_def_property(srna, "material_alt", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Material");
|
||||
RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_BrushGpencilSettings_material_poll");
|
||||
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK | PROP_CONTEXT_UPDATE);
|
||||
RNA_def_property_ui_text(prop, "Material", "Material used for secondary uses for this brush");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_Brush_material_update");
|
||||
|
||||
prop = RNA_def_property(srna, "show_fill_boundary", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_FILL_SHOW_HELPLINES);
|
||||
RNA_def_property_boolean_default(prop, true);
|
||||
|
|
Loading…
Reference in New Issue