GPencil: Use default material when slot material is empty

When a material slot is empty, the default material is used.

The default color used is Gray to get a good contrast in dense scenes with dark and white background.

Reviewers: brecht, dfelinto, mendio, pepeland

Differential Revision: https://developer.blender.org/D5625
This commit is contained in:
Antonio Vazquez 2019-08-30 14:19:07 +02:00
parent 4608220c9b
commit d5d3dc4189
15 changed files with 129 additions and 49 deletions

View File

@ -892,7 +892,8 @@ class GreasePencilMaterialsPanel:
if is_view3d and brush is not None:
gp_settings = brush.gpencil_settings
if gp_settings.use_material_pin is False:
ma = ob.material_slots[ob.active_material_index].material
if ob.active_material_index > 0:
ma = ob.material_slots[ob.active_material_index].material
else:
ma = gp_settings.material

View File

@ -155,7 +155,7 @@ struct Material *BKE_gpencil_brush_material_get(struct Brush *brush);
void BKE_gpencil_brush_material_set(struct Brush *brush, struct Material *material);
/* Object */
struct Material *BKE_gpencil_object_material_ensure_active(struct Main *bmain, struct Object *ob);
struct Material *BKE_gpencil_object_material_ensure_active(struct Object *ob);
struct Material *BKE_gpencil_object_material_ensure_from_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
@ -179,8 +179,7 @@ struct Material *BKE_gpencil_object_material_ensure_from_active_input_toolsettin
struct Material *BKE_gpencil_object_material_ensure_from_active_input_brush(struct Main *bmain,
struct Object *ob,
struct Brush *brush);
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Main *bmain,
struct Object *ob);
struct Material *BKE_gpencil_object_material_ensure_from_active_input_material(struct Object *ob);
/* object boundbox */
bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]);

View File

@ -38,6 +38,7 @@ struct bNode;
/* materials */
void init_def_material(void);
void BKE_material_gpencil_default_free(void);
void BKE_material_free(struct Material *ma);
void test_object_materials(struct Main *bmain, struct Object *ob, struct ID *id);
void test_all_objects_materials(struct Main *bmain, struct ID *id);
@ -46,6 +47,7 @@ void BKE_material_resize_object(struct Main *bmain,
const short totcol,
bool do_id_user);
void BKE_material_init(struct Material *ma);
void BKE_material_gpencil_init(struct Material *ma);
void BKE_material_remap_object(struct Object *ob, const unsigned int *remap);
void BKE_material_remap_object_calc(struct Object *ob_dst,
struct Object *ob_src,
@ -92,6 +94,7 @@ bool BKE_object_material_slot_add(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_remove(struct Main *bmain, struct Object *ob);
bool BKE_object_material_slot_used(struct ID *id, short actcol);
struct Material *BKE_material_gpencil_get(struct Object *ob, short act);
struct MaterialGPencilStyle *BKE_material_gpencil_settings_get(struct Object *ob, short act);
void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
@ -123,6 +126,7 @@ struct Depsgraph;
void BKE_material_eval(struct Depsgraph *depsgraph, struct Material *material);
extern struct Material defmaterial;
extern struct Material defgpencil_material;
#ifdef __cplusplus
}

View File

@ -1161,38 +1161,34 @@ Material *BKE_gpencil_object_material_ensure_from_active_input_brush(Main *bmain
brush->gpencil_settings->flag &= ~GP_BRUSH_MATERIAL_PINNED;
}
}
return BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
return BKE_gpencil_object_material_ensure_from_active_input_material(ob);
}
/**
* Guaranteed to return a material assigned to object. Returns never NULL.
* Only use this for materials unrelated to user input.
*/
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Main *bmain, Object *ob)
Material *BKE_gpencil_object_material_ensure_from_active_input_material(Object *ob)
{
Material *ma = give_current_material(ob, ob->actcol);
if (ma) {
return ma;
}
/* If the slot is empty, remove because will be added again,
* if not, we will get an empty slot. */
if ((ob->totcol > 0) && (ob->actcol == ob->totcol)) {
BKE_object_material_slot_remove(bmain, ob);
}
return BKE_gpencil_object_material_new(bmain, ob, "Material", NULL);
return &defgpencil_material;
}
/* Get active color, and add all default settings if we don't find anything */
Material *BKE_gpencil_object_material_ensure_active(Main *bmain, Object *ob)
Material *BKE_gpencil_object_material_ensure_active(Object *ob)
{
Material *ma = NULL;
/* sanity checks */
if (ELEM(NULL, bmain, ob)) {
if (ob == NULL) {
return NULL;
}
ma = BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
ma = BKE_gpencil_object_material_ensure_from_active_input_material(ob);
if (ma->gp_style == NULL) {
BKE_material_init_gpencil_settings(ma);
}
@ -2008,6 +2004,7 @@ void BKE_gpencil_material_index_reassign(bGPdata *gpd, int totcol, int index)
/* reassign strokes */
if ((gps->mat_nr > index) || (gps->mat_nr > totcol - 1)) {
gps->mat_nr--;
CLAMP_MIN(gps->mat_nr, 0);
}
}
}

View File

@ -71,6 +71,7 @@
/* used in UI and render */
Material defmaterial;
Material defgpencil_material;
static CLG_LogRef LOG = {"bke.material"};
@ -78,6 +79,13 @@ static CLG_LogRef LOG = {"bke.material"};
void init_def_material(void)
{
BKE_material_init(&defmaterial);
BKE_material_gpencil_init(&defgpencil_material);
}
/* Free the GPencil data of the deafult material, creator.c */
void BKE_material_gpencil_default_free(void)
{
MEM_SAFE_FREE(defgpencil_material.gp_style);
}
/** Free (or release) any data used by this material (does not free the material itself). */
@ -144,6 +152,16 @@ void BKE_material_init(Material *ma)
ma->blend_shadow = MA_BS_SOLID;
}
void BKE_material_gpencil_init(Material *ma)
{
BKE_material_init(ma);
/* grease pencil settings */
strcpy(ma->id.name, "MADefault GPencil");
BKE_material_init_gpencil_settings(ma);
add_v3_fl(&ma->gp_style->stroke_rgba[0], 0.6f);
}
Material *BKE_material_add(Main *bmain, const char *name)
{
Material *ma;
@ -580,6 +598,17 @@ Material *give_current_material(Object *ob, short act)
return ma_p ? *ma_p : NULL;
}
Material *BKE_material_gpencil_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
if (ma != NULL) {
return ma;
}
else {
return &defgpencil_material;
}
}
MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
{
Material *ma = give_current_material(ob, act);
@ -591,7 +620,7 @@ MaterialGPencilStyle *BKE_material_gpencil_settings_get(Object *ob, short act)
return ma->gp_style;
}
else {
return NULL;
return defgpencil_material.gp_style;
}
}
@ -1070,10 +1099,6 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob)
}
/* check indices from gpencil */
else if (ob->type == OB_GPENCIL) {
/* need one color */
if (ob->totcol == 0) {
BKE_gpencil_object_material_ensure_from_active_input_material(bmain, ob);
}
BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1);
}

View File

@ -54,7 +54,7 @@ static int gpencil_monkey_color(
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}

View File

@ -53,7 +53,7 @@ static int gp_stroke_material(Main *bmain, Object *ob, const ColorTemplate *pct,
short *totcol = give_totcolp(ob);
Material *ma = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (STREQ(ma->id.name, pct->name)) {
return i;
}

View File

@ -538,10 +538,12 @@ static int gp_layer_duplicate_object_exec(bContext *C, wmOperator *op)
* otherwise add the slot with the material
*/
Material *ma_src = give_current_material(ob_src, gps_src->mat_nr + 1);
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
if (ma_src != NULL) {
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
/* Reassign the stroke material to the right slot in destination object. */
gps_dst->mat_nr = idx;
/* Reassign the stroke material to the right slot in destination object. */
gps_dst->mat_nr = idx;
}
/* add new stroke to frame */
BLI_addtail(&gpf_dst->strokes, gps_dst);
@ -1423,7 +1425,7 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
if (name[0] == '\0') {
ma = give_current_material(ob, ob->actcol);
ma = BKE_material_gpencil_get(ob, ob->actcol);
}
else {
ma = (Material *)BKE_libblock_find_name(bmain, ID_MA, name);
@ -1543,9 +1545,10 @@ static int gp_stroke_lock_color_exec(bContext *C, wmOperator *UNUSED(op))
}
/* unlock color */
Material *tmp_ma = give_current_material(ob, gps->mat_nr + 1);
tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
if (tmp_ma) {
tmp_ma->gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;
DEG_id_tag_update(&tmp_ma->id, ID_RECALC_COPY_ON_WRITE);
}
}
}
}
@ -2295,7 +2298,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
short *totcol = give_totcolp(ob_src);
for (short i = 0; i < *totcol; i++) {
Material *tmp_ma = give_current_material(ob_src, i + 1);
Material *tmp_ma = BKE_material_gpencil_get(ob_src, i + 1);
BKE_gpencil_object_material_ensure(bmain, ob_dst, tmp_ma);
}
@ -2329,7 +2332,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op)
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* Reassign material. Look old material and try to find in destination. */
ma_src = give_current_material(ob_src, gps->mat_nr + 1);
ma_src = BKE_material_gpencil_get(ob_src, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
bGPDspoint *pt;
@ -2437,7 +2440,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
}
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@ -2457,7 +2460,7 @@ static int gpencil_lock_layer_exec(bContext *C, wmOperator *UNUSED(op))
continue;
}
ma = give_current_material(ob, gps->mat_nr + 1);
ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
gp_style = ma->gp_style;
@ -2500,7 +2503,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
Object *ob = CTX_data_active_object(C);
Material *active_ma = give_current_material(ob, ob->actcol);
Material *active_ma = BKE_material_gpencil_get(ob, ob->actcol);
MaterialGPencilStyle *active_color = BKE_material_gpencil_settings_get(ob, ob->actcol);
MaterialGPencilStyle *gp_style;
@ -2520,7 +2523,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
Material *ma = NULL;
short *totcol = give_totcolp(ob);
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
/* Skip if this is the active one */
if ((ma == NULL) || (ma == active_ma)) {
continue;
@ -2540,7 +2543,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
if (isolate) {
/* Set flags on all "other" colors */
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@ -2557,7 +2560,7 @@ static int gpencil_color_isolate_exec(bContext *C, wmOperator *op)
else {
/* Clear flags - Restore everything else */
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma == NULL) {
continue;
}
@ -2622,7 +2625,7 @@ static int gpencil_color_hide_exec(bContext *C, wmOperator *op)
/* hide unselected */
MaterialGPencilStyle *color = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
color = ma->gp_style;
if (active_color != color) {
@ -2685,7 +2688,7 @@ static int gpencil_color_reveal_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_HIDE;
@ -2738,7 +2741,7 @@ static int gpencil_color_lock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag |= GP_STYLE_COLOR_LOCKED;
@ -2791,7 +2794,7 @@ static int gpencil_color_unlock_all_exec(bContext *C, wmOperator *UNUSED(op))
MaterialGPencilStyle *gp_style = NULL;
for (short i = 0; i < *totcol; i++) {
ma = give_current_material(ob, i + 1);
ma = BKE_material_gpencil_get(ob, i + 1);
if (ma) {
gp_style = ma->gp_style;
gp_style->flag &= ~GP_STYLE_COLOR_LOCKED;

View File

@ -1191,10 +1191,15 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
GHash *ma_to_name = gp_strokes_copypastebuf_colors_material_to_name_create(bmain);
for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
if (ED_gpencil_stroke_can_use(C, gps)) {
Material *ma = give_current_material(ob, gps->mat_nr + 1);
/* Avoid default material. */
if (ma == NULL) {
continue;
}
char **ma_name_val;
if (!BLI_ghash_ensure_p(
gp_strokes_copypastebuf_colors, &gps->mat_nr, (void ***)&ma_name_val)) {
Material *ma = give_current_material(ob, gps->mat_nr + 1);
char *ma_name = BLI_ghash_lookup(ma_to_name, ma);
*ma_name_val = MEM_dupallocN(ma_name);
}
@ -1361,7 +1366,7 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
/* Remap material */
Material *ma = BLI_ghash_lookup(new_colors, POINTER_FROM_INT(new_stroke->mat_nr));
new_stroke->mat_nr = BKE_gpencil_object_material_get_index(ob, ma);
BLI_assert(new_stroke->mat_nr >= 0); /* have to add the material first */
CLAMP_MIN(new_stroke->mat_nr, 0);
}
}
}
@ -4068,7 +4073,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
/* add duplicate materials */
/* XXX same material can be in multiple slots. */
ma = give_current_material(ob, gps->mat_nr + 1);
ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
@ -4141,7 +4146,7 @@ static int gp_stroke_separate_exec(bContext *C, wmOperator *op)
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
ma = give_current_material(ob, gps->mat_nr + 1);
ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
gps->mat_nr = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma);
}
}

View File

@ -48,6 +48,7 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "ED_gpencil.h"
#include "ED_screen.h"
@ -1038,7 +1039,15 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
gps->flag |= GP_STROKE_CYCLIC;
gps->flag |= GP_STROKE_3DSPACE;
gps->mat_nr = BKE_gpencil_object_material_ensure(tgpf->bmain, tgpf->ob, tgpf->mat);
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpf->ob, brush);
if (gps->mat_nr < 0) {
if (tgpf->ob->actcol - 1 < 0) {
gps->mat_nr = 0;
}
else {
gps->mat_nr = tgpf->ob->actcol - 1;
}
}
/* allocate memory for storage points */
gps->totpoints = tgpf->sbuffer_used;
@ -1346,8 +1355,28 @@ static int gpencil_fill_init(bContext *C, wmOperator *op)
/* start of interactive part of operator */
static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = CTX_data_active_object(C);
ToolSettings *ts = CTX_data_tool_settings(C);
Brush *brush = BKE_paint_brush(&ts->gp_paint->paint);
tGPDfill *tgpf = NULL;
/* Fill tool needs a material (cannot use default material) */
bool valid = true;
if ((brush) && (brush->gpencil_settings->flag & GP_BRUSH_MATERIAL_PINNED)) {
if (brush->gpencil_settings->material == NULL) {
valid = false;
}
}
else {
if (give_current_material(ob, ob->actcol) == NULL) {
valid = false;
}
}
if (!valid) {
BKE_report(op->reports, RPT_ERROR, "Fill tool needs active material.");
return OPERATOR_CANCELLED;
}
/* try to initialize context data needed */
if (!gpencil_fill_init(C, op)) {
gpencil_fill_exit(C, op);

View File

@ -449,7 +449,7 @@ static bool gp_strokes_merge_poll(bContext *C)
/* check material */
Material *ma = NULL;
ma = give_current_material(ob, ob->actcol);
ma = BKE_material_gpencil_get(ob, ob->actcol);
if ((ma == NULL) || (ma->gp_style == NULL)) {
return false;
}

View File

@ -1244,6 +1244,14 @@ static void gp_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;
}
}
/* calculate UVs along the stroke */
ED_gpencil_calc_stroke_uv(obact, gps);

View File

@ -330,7 +330,15 @@ static void gp_primitive_set_initdata(bContext *C, tGPDprimitive *tgpi)
gps->flag |= GP_STROKE_3DSPACE;
gps->mat_nr = BKE_gpencil_object_material_get_index(tgpi->ob, tgpi->mat);
gps->mat_nr = BKE_gpencil_object_material_get_index_from_brush(tgpi->ob, tgpi->brush);
if (gps->mat_nr < 0) {
if (tgpi->ob->actcol - 1 < 0) {
gps->mat_nr = 0;
}
else {
gps->mat_nr = tgpi->ob->actcol - 1;
}
}
/* allocate memory for storage points, but keep empty */
gps->totpoints = 0;

View File

@ -2064,7 +2064,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat)
if (ED_gpencil_stroke_color_use(ob, gpl, gps) == false) {
continue;
}
gps_ma = give_current_material(ob, gps->mat_nr + 1);
gps_ma = BKE_material_gpencil_get(ob, gps->mat_nr + 1);
/* update */
if ((gps_ma) && (gps_ma == mat)) {
ED_gpencil_calc_stroke_uv(ob, gps);

View File

@ -524,6 +524,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
BKE_addon_pref_type_free();
BKE_keyconfig_pref_type_free();
BKE_material_gpencil_default_free();
wm_operatortype_free();
wm_dropbox_free();