From 29f3af95272590d26f610ae828b2eeee89c82a00 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Mon, 9 Mar 2020 16:27:24 +0100 Subject: GPencil: Refactor of Draw Engine, Vertex Paint and all internal functions This commit is a full refactor of the grease pencil modules including Draw Engine, Modifiers, VFX, depsgraph update, improvements in operators and conversion of Sculpt and Weight paint tools to real brushes. Also, a huge code cleanup has been done at all levels. Thanks to @fclem for his work and yo @pepeland and @mendio for the testing and help in the development. Differential Revision: https://developer.blender.org/D6293 --- .../gpencil_modifiers/intern/MOD_gpencil_util.c | 42 +-- .../gpencil_modifiers/intern/MOD_gpencil_util.h | 7 - .../gpencil_modifiers/intern/MOD_gpencilarmature.c | 9 +- .../gpencil_modifiers/intern/MOD_gpencilarray.c | 304 ++++++++++---------- .../gpencil_modifiers/intern/MOD_gpencilbuild.c | 36 ++- .../gpencil_modifiers/intern/MOD_gpencilcolor.c | 120 +++++--- .../gpencil_modifiers/intern/MOD_gpencilhook.c | 9 +- .../gpencil_modifiers/intern/MOD_gpencillattice.c | 9 +- .../gpencil_modifiers/intern/MOD_gpencilmirror.c | 30 +- .../gpencil_modifiers/intern/MOD_gpencilmultiply.c | 148 ++++------ .../gpencil_modifiers/intern/MOD_gpencilnoise.c | 227 +++++++-------- .../gpencil_modifiers/intern/MOD_gpenciloffset.c | 9 +- .../gpencil_modifiers/intern/MOD_gpencilopacity.c | 134 +++++---- .../gpencil_modifiers/intern/MOD_gpencilsimplify.c | 15 +- .../gpencil_modifiers/intern/MOD_gpencilsmooth.c | 52 +++- .../gpencil_modifiers/intern/MOD_gpencilsubdiv.c | 11 +- .../gpencil_modifiers/intern/MOD_gpencilthick.c | 79 ++---- .../gpencil_modifiers/intern/MOD_gpenciltint.c | 116 +++++--- .../intern/MOD_gpencilvertexcolor.c | 314 +++++++++++++++++++++ 19 files changed, 1001 insertions(+), 670 deletions(-) create mode 100644 source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c (limited to 'source/blender/gpencil_modifiers/intern') diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index 6f37cedba49..1462b6f72c9 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -72,6 +72,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) INIT_GP_TYPE(Armature); INIT_GP_TYPE(Time); INIT_GP_TYPE(Multiply); + INIT_GP_TYPE(Vertexcolor); #undef INIT_GP_TYPE } @@ -186,44 +187,3 @@ float get_modifier_point_weight(MDeformVert *dvert, bool inverse, int def_nr) return weight; } - -/* set material when apply modifiers (used in tint and color modifier) */ -void gpencil_apply_modifier_material( - Main *bmain, Object *ob, Material *mat, GHash *gh_color, bGPDstroke *gps, bool crt_material) -{ - MaterialGPencilStyle *gp_style = mat->gp_style; - - /* look for color */ - if (crt_material) { - Material *newmat = BLI_ghash_lookup(gh_color, mat->id.name); - if (newmat == NULL) { - BKE_object_material_slot_add(bmain, ob); - newmat = BKE_material_copy(bmain, mat); - newmat->preview = NULL; - - BKE_object_material_assign(bmain, ob, newmat, ob->totcol, BKE_MAT_ASSIGN_USERPREF); - - copy_v4_v4(newmat->gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); - copy_v4_v4(newmat->gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); - - BLI_ghash_insert(gh_color, mat->id.name, newmat); - DEG_id_tag_update(&newmat->id, ID_RECALC_COPY_ON_WRITE); - } - /* Reassign color index. */ - gps->mat_nr = BKE_gpencil_object_material_get_index(ob, newmat); - } - else { - /* reuse existing color (but update only first time) */ - if (BLI_ghash_lookup(gh_color, mat->id.name) == NULL) { - copy_v4_v4(gp_style->stroke_rgba, gps->runtime.tmp_stroke_rgba); - copy_v4_v4(gp_style->fill_rgba, gps->runtime.tmp_fill_rgba); - BLI_ghash_insert(gh_color, mat->id.name, mat); - } - /* update previews (icon and thumbnail) */ - if (mat->preview != NULL) { - mat->preview->flag[ICON_SIZE_ICON] |= PRV_CHANGED; - mat->preview->flag[ICON_SIZE_PREVIEW] |= PRV_CHANGED; - } - DEG_id_tag_update(&mat->id, ID_RECALC_COPY_ON_WRITE); - } -} diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index 2b1f8dbc71a..fc4522bc028 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -47,11 +47,4 @@ bool is_stroke_affected_by_modifier(struct Object *ob, float get_modifier_point_weight(struct MDeformVert *dvert, bool inverse, int def_nr); -void gpencil_apply_modifier_material(struct Main *bmain, - struct Object *ob, - struct Material *mat, - struct GHash *gh_color, - struct bGPDstroke *gps, - bool crt_material); - #endif /* __MOD_GPENCIL_UTIL_H__ */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index eceb45780cf..a8aad763422 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -116,6 +117,8 @@ static void deformStroke(GpencilModifierData *md, } gpencil_deform_verts(mmd, ob, gps); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) @@ -131,8 +134,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply armature effects on this frame * NOTE: this assumes that we don't want armature animation on non-keyframed frames */ @@ -140,7 +143,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute armature effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md_eval, depsgraph, object_eval, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 11ba639fa83..1fc8c19b542 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -27,6 +27,10 @@ #include "BLI_utildefines.h" +#include "BLI_ghash.h" +#include "BLI_hash.h" +#include "BLI_rand.h" + #include "BLI_blenlib.h" #include "BLI_rand.h" #include "BLI_math.h" @@ -54,26 +58,24 @@ #include "MOD_gpencil_util.h" #include "MOD_gpencil_modifiertypes.h" +typedef struct tmpStrokes { + struct tmpStrokes *next, *prev; + bGPDframe *gpf; + bGPDstroke *gps; +} tmpStrokes; + static void initData(GpencilModifierData *md) { ArrayGpencilModifierData *gpmd = (ArrayGpencilModifierData *)md; gpmd->count = 2; - gpmd->offset[0] = 1.0f; - gpmd->offset[1] = 0.0f; - gpmd->offset[2] = 0.0f; - gpmd->shift[0] = 0.0f; + gpmd->shift[0] = 1.0f; gpmd->shift[1] = 0.0f; gpmd->shift[2] = 0.0f; - gpmd->scale[0] = 1.0f; - gpmd->scale[1] = 1.0f; - gpmd->scale[2] = 1.0f; - gpmd->rnd_rot = 0.5f; - gpmd->rnd_size = 0.5f; + zero_v3(gpmd->offset); + zero_v3(gpmd->rnd_scale); gpmd->object = NULL; - - /* fill random values */ - BLI_array_frand(gpmd->rnd, 20, 1); - gpmd->rnd[0] = 1; + gpmd->flag |= GP_ARRAY_USE_RELATIVE; + gpmd->seed = 1; } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) @@ -90,46 +92,24 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob, float r_offset[4][4]) { float offset[3], rot[3], scale[3]; - int ri = mmd->rnd[0]; - float factor; - - offset[0] = mmd->offset[0] * elem_idx; - offset[1] = mmd->offset[1] * elem_idx; - offset[2] = mmd->offset[2] * elem_idx; - - /* rotation */ - if (mmd->flag & GP_ARRAY_RANDOM_ROT) { - factor = mmd->rnd_rot * mmd->rnd[ri]; - mul_v3_v3fl(rot, mmd->rot, factor); - add_v3_v3(rot, mmd->rot); - } - else { - copy_v3_v3(rot, mmd->rot); - } + ARRAY_SET_ITEMS(scale, 1.0f, 1.0f, 1.0f); + zero_v3(rot); - /* scale */ - if (mmd->flag & GP_ARRAY_RANDOM_SIZE) { - factor = mmd->rnd_size * mmd->rnd[ri]; - mul_v3_v3fl(scale, mmd->scale, factor); - add_v3_v3(scale, mmd->scale); + if (mmd->flag & GP_ARRAY_USE_OFFSET) { + offset[0] = mmd->offset[0] * elem_idx; + offset[1] = mmd->offset[1] * elem_idx; + offset[2] = mmd->offset[2] * elem_idx; } else { - copy_v3_v3(scale, mmd->scale); + zero_v3(offset); } - /* advance random index */ - mmd->rnd[0]++; - if (mmd->rnd[0] > 19) { - mmd->rnd[0] = 1; - } - - /* calculate matrix */ + /* Calculate matrix */ loc_eul_size_to_mat4(r_mat, offset, rot, scale); - copy_m4_m4(r_offset, r_mat); /* offset object */ - if (mmd->object) { + if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) { float mat_offset[4][4]; float obinv[4][4]; @@ -147,140 +127,158 @@ static void BKE_gpencil_instance_modifier_instance_tfm(Object *ob, /* array modifier - generate geometry callback (for viewport/rendering) */ static void generate_geometry(GpencilModifierData *md, - Depsgraph *UNUSED(depsgraph), - Object *ob, - bGPDlayer *gpl, - bGPDframe *gpf) + Depsgraph *depsgraph, + Scene *scene, + Object *ob) { ArrayGpencilModifierData *mmd = (ArrayGpencilModifierData *)md; ListBase stroke_cache = {NULL, NULL}; - bGPDstroke *gps; - int idx; - - /* Check which strokes we can use once, and store those results in an array - * for quicker checking of what's valid (since string comparisons are expensive) - */ - const int num_strokes = BLI_listbase_count(&gpf->strokes); - int num_valid = 0; + /* Load the strokes to be duplicated. */ + bGPdata *gpd = (bGPdata *)ob->data; + bool found = false; + + /* Get bounbox for relative offset. */ + float size[3] = {0.0f, 0.0f, 0.0f}; + if (mmd->flag & GP_ARRAY_USE_RELATIVE) { + BoundBox *bb = BKE_object_boundbox_get(ob); + const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; + BKE_boundbox_init_from_minmax(bb, min, max); + BKE_boundbox_calc_size_aabb(bb, size); + mul_v3_fl(size, 2.0f); + /* Need a minimum size (for flat drawings). */ + CLAMP3_MIN(size, 0.01f); + } - bool *valid_strokes = MEM_callocN(sizeof(bool) * num_strokes, __func__); + int seed = mmd->seed; + /* Make sure different modifiers get different seeds. */ + seed += BLI_hash_string(ob->id.name + 2); + seed += BLI_hash_string(md->name); - for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) { - /* Record whether this stroke can be used - * ATTENTION: The logic here is the inverse of what's used everywhere else! - */ - if (is_stroke_affected_by_modifier(ob, - mmd->layername, - mmd->materialname, - mmd->pass_index, - mmd->layer_pass, - 1, - gpl, - gps, - mmd->flag & GP_ARRAY_INVERT_LAYER, - mmd->flag & GP_ARRAY_INVERT_PASS, - mmd->flag & GP_ARRAY_INVERT_LAYERPASS, - mmd->flag & GP_ARRAY_INVERT_MATERIAL)) { - valid_strokes[idx] = true; - num_valid++; + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); + if (gpf == NULL) { + continue; + } + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + if (is_stroke_affected_by_modifier(ob, + mmd->layername, + mmd->materialname, + mmd->pass_index, + mmd->layer_pass, + 1, + gpl, + gps, + mmd->flag & GP_ARRAY_INVERT_LAYER, + mmd->flag & GP_ARRAY_INVERT_PASS, + mmd->flag & GP_ARRAY_INVERT_LAYERPASS, + mmd->flag & GP_ARRAY_INVERT_MATERIAL)) { + tmpStrokes *tmp = MEM_callocN(sizeof(tmpStrokes), __func__); + tmp->gpf = gpf; + tmp->gps = gps; + BLI_addtail(&stroke_cache, tmp); + + found = true; + } } } - /* Early exit if no strokes can be copied */ - if (num_valid == 0) { - if (G.debug & G_DEBUG) { - printf("GP Array Mod - No strokes to be included\n"); - } + if (found) { + /* Generate new instances of all existing strokes, + * keeping each instance together so they maintain + * the correct ordering relative to each other + */ + float current_offset[4][4]; + unit_m4(current_offset); - MEM_SAFE_FREE(valid_strokes); - return; - } + float rand_offset = BLI_hash_int_01(seed); - /* Generate new instances of all existing strokes, - * keeping each instance together so they maintain - * the correct ordering relative to each other - */ - float current_offset[4][4]; - unit_m4(current_offset); + for (int x = 0; x < mmd->count; x++) { + /* original strokes are at index = 0 */ + if (x == 0) { + continue; + } - for (int x = 0; x < mmd->count; x++) { - /* original strokes are at index = 0 */ - if (x == 0) { - continue; - } + /* Compute transforms for this instance */ + float mat[4][4]; + float mat_offset[4][4]; + BKE_gpencil_instance_modifier_instance_tfm(ob, mmd, x, mat, mat_offset); - /* Compute transforms for this instance */ - float mat[4][4]; - float mat_offset[4][4]; - BKE_gpencil_instance_modifier_instance_tfm(ob, mmd, x, mat, mat_offset); + if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) { + /* recalculate cumulative offset here */ + mul_m4_m4m4(current_offset, current_offset, mat_offset); + } + else { + copy_m4_m4(current_offset, mat); + } - if (mmd->object) { - /* recalculate cumulative offset here */ - mul_m4_m4m4(current_offset, current_offset, mat_offset); - } - else { - copy_m4_m4(current_offset, mat); - } - /* apply shift */ - madd_v3_v3fl(current_offset[3], mmd->shift, x); - - /* Duplicate original strokes to create this instance */ - for (gps = gpf->strokes.first, idx = 0; gps; gps = gps->next, idx++) { - /* check if stroke can be duplicated */ - if (valid_strokes[idx]) { - /* Calculate original stroke center (only first loop). */ - float r_min[3], r_max[3], center[3]; - if (x == 1) { - INIT_MINMAX(r_min, r_max); - BKE_gpencil_stroke_minmax(gps, false, r_min, r_max); - add_v3_v3v3(center, r_min, r_max); - mul_v3_fl(center, 0.5f); - sub_v3_v3v3(center, center, ob->obmat[3]); - } + /* Apply relative offset. */ + if (mmd->flag & GP_ARRAY_USE_RELATIVE) { + float relative[3]; + mul_v3_v3v3(relative, mmd->shift, size); + madd_v3_v3fl(current_offset[3], relative, x); + } + float rand[3][3]; + for (int j = 0; j < 3; j++) { + uint primes[3] = {2, 3, 7}; + double offset[3] = {0.0, 0.0, 0.0}; + double r[3]; + /* To ensure a nice distribution, we use halton sequence and offset using the seed. */ + BLI_halton_3d(primes, offset, x, r); + + for (int i = 0; i < 3; i++) { + rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f); + rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + } + } + /* Calculate Random matrix. */ + float mat_rnd[4][4]; + float loc[3], rot[3]; + float scale[3] = {1.0f, 1.0f, 1.0f}; + mul_v3_v3v3(loc, mmd->rnd_offset, rand[0]); + mul_v3_v3v3(rot, mmd->rnd_rot, rand[1]); + madd_v3_v3v3(scale, mmd->rnd_scale, rand[2]); + + loc_eul_size_to_mat4(mat_rnd, loc, rot, scale); + + /* Duplicate original strokes to create this instance. */ + LISTBASE_FOREACH_BACKWARD (tmpStrokes *, iter, &stroke_cache) { /* Duplicate stroke */ - bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps); + bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(iter->gps, true); /* Move points */ - for (int i = 0; i < gps->totpoints; i++) { + for (int i = 0; i < iter->gps->totpoints; i++) { bGPDspoint *pt = &gps_dst->points[i]; + /* Apply randomness matrix. */ + mul_m4_v3(mat_rnd, &pt->x); + /* Apply object local transform (Rot/Scale). */ - if (mmd->object) { + if ((mmd->flag & GP_ARRAY_USE_OB_OFFSET) && (mmd->object)) { mul_m4_v3(mat, &pt->x); } - /* Translate to object origin. */ - float fpt[3]; - sub_v3_v3v3(fpt, &pt->x, center); /* Global Rotate and scale. */ - mul_mat3_m4_v3(current_offset, fpt); + mul_mat3_m4_v3(current_offset, &pt->x); /* Global translate. */ - add_v3_v3(fpt, center); - add_v3_v3v3(&pt->x, fpt, current_offset[3]); + add_v3_v3(&pt->x, current_offset[3]); } - /* if replace material, use new one */ + /* If replace material, use new one. */ if ((mmd->mat_rpl > 0) && (mmd->mat_rpl <= ob->totcol)) { gps_dst->mat_nr = mmd->mat_rpl - 1; } - /* Add new stroke to cache, to be added to the frame once - * all duplicates have been made - */ - BLI_addtail(&stroke_cache, gps_dst); + /* Add new stroke. */ + BLI_addhead(&iter->gpf->strokes, gps_dst); + /* Calc bounding box. */ + BKE_gpencil_stroke_boundingbox_calc(gps_dst); } } - } - /* merge newly created stroke instances back into the main stroke list */ - if (mmd->flag & GP_ARRAY_KEEP_ONTOP) { - BLI_movelisttolist_reverse(&gpf->strokes, &stroke_cache); - } - else { - BLI_movelisttolist(&gpf->strokes, &stroke_cache); + /* Free temp data. */ + LISTBASE_FOREACH_MUTABLE (tmpStrokes *, tmp, &stroke_cache) { + BLI_freelinkN(&stroke_cache, tmp); + } } - - /* free temp data */ - MEM_SAFE_FREE(valid_strokes); } static void bakeModifier(Main *UNUSED(bmain), @@ -288,23 +286,17 @@ static void bakeModifier(Main *UNUSED(bmain), GpencilModifierData *md, Object *ob) { - - bGPdata *gpd = ob->data; - - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - generate_geometry(md, depsgraph, ob, gpl, gpf); - } - } + Scene *scene = DEG_get_evaluated_scene(depsgraph); + generate_geometry(md, depsgraph, scene, ob); } /* -------------------------------- */ /* Generic "generateStrokes" callback */ -static void generateStrokes( - GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, bGPDframe *gpf) +static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob) { - generate_geometry(md, depsgraph, ob, gpl, gpf); + Scene *scene = DEG_get_evaluated_scene(depsgraph); + generate_geometry(md, depsgraph, scene, ob); } static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index e3e7168330d..7e89d8e2d6f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -174,10 +174,8 @@ static void reduce_stroke_points(bGPDstroke *gps, gps->dvert = new_dvert; gps->totpoints = num_points; - /* mark stroke as needing to have its geometry caches rebuilt */ - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - gps->tot_triangles = 0; - MEM_SAFE_FREE(gps->triangles); + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* --------------------------------------------- */ @@ -400,19 +398,15 @@ static void build_concurrent(BuildGpencilModifierData *mmd, bGPDframe *gpf, floa } /* --------------------------------------------- */ - -/* Entry-point for Build Modifier */ -static void generateStrokes(GpencilModifierData *md, - Depsgraph *depsgraph, - Object *UNUSED(ob), - bGPDlayer *gpl, - bGPDframe *gpf) +static void generate_geometry(GpencilModifierData *md, + Depsgraph *depsgraph, + bGPDlayer *gpl, + bGPDframe *gpf) { BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md; const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW); const float ctime = DEG_get_ctime(depsgraph); - // printf("GP Build Modifier - %f\n", ctime); /* Early exit if it's an empty frame */ if (gpf->strokes.first == NULL) { @@ -459,7 +453,7 @@ static void generateStrokes(GpencilModifierData *md, * By default, the upper bound is given by the "maximum length" setting */ float start_frame = gpf->framenum + mmd->start_delay; - float end_frame = gpf->framenum + mmd->length; + float end_frame = start_frame + mmd->length; if (gpf->next) { /* Use the next frame or upper bound as end frame, whichever is lower/closer */ @@ -506,7 +500,6 @@ static void generateStrokes(GpencilModifierData *md, /* Determine how far along we are between the keyframes */ float fac = (ctime - start_frame) / (end_frame - start_frame); - // printf(" Progress on %d = %f (%f - %f)\n", gpf->framenum, fac, start_frame, end_frame); /* Time management mode */ switch (mmd->mode) { @@ -526,6 +519,21 @@ static void generateStrokes(GpencilModifierData *md, } } +/* Entry-point for Build Modifier */ +static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = (bGPdata *)ob->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); + if (gpf == NULL) { + continue; + } + generate_geometry(md, depsgraph, gpl, gpf); + } +} + /* ******************************************** */ GpencilModifierTypeInfo modifierType_Gpencil_Build = { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index d9869c92e06..3a930b40c8b 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_color.h" #include "BLI_math_vector.h" @@ -35,6 +34,7 @@ #include "DNA_gpencil_types.h" #include "DNA_gpencil_modifier_types.h" +#include "BKE_colortools.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_main.h" @@ -52,13 +52,28 @@ static void initData(GpencilModifierData *md) ARRAY_SET_ITEMS(gpmd->hsv, 0.5f, 1.0f, 1.0f); gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; - gpmd->flag |= GP_COLOR_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; + + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemapping_initialize(curve); + } } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + ColorGpencilModifierData *gmd = (ColorGpencilModifierData *)md; + ColorGpencilModifierData *tgmd = (ColorGpencilModifierData *)target; + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } /* color correction strokes */ @@ -72,6 +87,7 @@ static void deformStroke(GpencilModifierData *md, ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md; float hsv[3], factor[3]; + const bool use_curve = (mmd->flag & GP_COLOR_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -89,60 +105,76 @@ static void deformStroke(GpencilModifierData *md, } copy_v3_v3(factor, mmd->hsv); - /* keep initial values unchanged, subtracting the default values. */ - factor[0] -= 0.5f; - factor[1] -= 1.0f; - factor[2] -= 1.0f; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - rgb_to_hsv_v(gps->runtime.tmp_stroke_rgba, hsv); - add_v3_v3(hsv, factor); - CLAMP3(hsv, 0.0f, 1.0f); - hsv_to_rgb_v(hsv, gps->runtime.tmp_stroke_rgba); + /* Apply to Vertex Color. */ + /* Fill */ + if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; + } + + rgb_to_hsv_v(gps->vert_color_fill, hsv); + hsv[0] = fractf(hsv[0] + factor[0] + 0.5f); + hsv[1] = clamp_f(hsv[1] * factor[1], 0.0f, 1.0f); + hsv[2] = hsv[2] * factor[2]; + hsv_to_rgb_v(hsv, gps->vert_color_fill); } - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - rgb_to_hsv_v(gps->runtime.tmp_fill_rgba, hsv); - add_v3_v3(hsv, factor); - CLAMP3(hsv, 0.0f, 1.0f); - hsv_to_rgb_v(hsv, gps->runtime.tmp_fill_rgba); + /* Stroke */ + if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { + + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { + copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; + } + + /* Custom curve to modulate value. */ + float factor_value[3]; + copy_v3_v3(factor_value, factor); + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + float mixfac = BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + mul_v3_fl(factor_value, mixfac); + } + + rgb_to_hsv_v(pt->vert_color, hsv); + hsv[0] = fractf(hsv[0] + factor_value[0] + 0.5f); + hsv[1] = clamp_f(hsv[1] * factor_value[1], 0.0f, 1.0f); + hsv[2] = hsv[2] * factor_value[2]; + hsv_to_rgb_v(hsv, pt->vert_color); + } } } -static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) +static void bakeModifier(Main *UNUSED(bmain), + Depsgraph *depsgraph, + GpencilModifierData *md, + Object *ob) { - ColorGpencilModifierData *mmd = (ColorGpencilModifierData *)md; bGPdata *gpd = ob->data; - GHash *gh_color = BLI_ghash_str_new("GP_Color modifier"); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - - Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1); - if (mat == NULL) { - continue; - } - MaterialGPencilStyle *gp_style = mat->gp_style; - /* skip stroke if it doesn't have color info */ - if (ELEM(NULL, gp_style)) { - continue; - } - - copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_COLOR_CREATE_COLORS)); } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; +} + +static void freeData(GpencilModifierData *md) +{ + ColorGpencilModifierData *gpmd = (ColorGpencilModifierData *)md; + + if (gpmd->curve_intensity) { + BKE_curvemapping_free(gpmd->curve_intensity); } } @@ -161,7 +193,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Color = { /* remapTime */ NULL, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index ae51bad3ca3..41380ec4c68 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -263,6 +264,8 @@ static void deformStroke(GpencilModifierData *md, } gp_hook_co_apply(&tData, weight, pt); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* FIXME: Ideally we be doing this on a copy of the main depsgraph @@ -279,8 +282,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply hook effects on this frame * NOTE: this assumes that we don't want hook animation on non-keyframed frames */ @@ -288,7 +291,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute hook effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index dba554fec36..d87f3a8a199 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md, } calc_latt_deform((struct LatticeDeformData *)mmd->cache_data, &pt->x, mmd->strength * weight); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* FIXME: Ideally we be doing this on a copy of the main depsgraph @@ -125,8 +128,8 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData return; } - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply lattice effects on this frame * NOTE: this assumes that we don't want lattice animation on non-keyframed frames */ @@ -137,7 +140,7 @@ static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData BKE_gpencil_lattice_init(ob); /* compute lattice effects on this frame */ - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 42d45512dc5..0f9b1034352 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -113,12 +113,7 @@ static void update_position(Object *ob, MirrorGpencilModifierData *mmd, bGPDstro } } -/* Generic "generateStrokes" callback */ -static void generateStrokes(GpencilModifierData *md, - Depsgraph *UNUSED(depsgraph), - Object *ob, - bGPDlayer *gpl, - bGPDframe *gpf) +static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf) { MirrorGpencilModifierData *mmd = (MirrorGpencilModifierData *)md; bGPDstroke *gps, *gps_new = NULL; @@ -145,7 +140,7 @@ static void generateStrokes(GpencilModifierData *md, mmd->flag & GP_MIRROR_INVERT_PASS, mmd->flag & GP_MIRROR_INVERT_LAYERPASS, mmd->flag & GP_MIRROR_INVERT_MATERIAL)) { - gps_new = BKE_gpencil_stroke_duplicate(gps); + gps_new = BKE_gpencil_stroke_duplicate(gps, true); update_position(ob, mmd, gps_new, xi); BLI_addtail(&gpf->strokes, gps_new); } @@ -154,20 +149,35 @@ static void generateStrokes(GpencilModifierData *md, } } +/* Generic "generateStrokes" callback */ +static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = (bGPdata *)ob->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); + if (gpf == NULL) { + continue; + } + generate_geometry(md, ob, gpl, gpf); + } +} + static void bakeModifier(Main *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); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* apply mirror effects on this frame */ CFRA = gpf->framenum; BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* compute mirror effects on this frame */ - generateStrokes(md, depsgraph, ob, gpl, gpf); + generate_geometry(md, ob, gpl, gpf); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index 919dbf91862..16b0c4a5e38 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -66,7 +66,10 @@ static void initData(GpencilModifierData *md) MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md; mmd->duplications = 3; mmd->distance = 0.1f; - mmd->split_angle = 1.0f; + mmd->split_angle = DEG2RADF(1.0f); + mmd->fading_center = 0.5f; + mmd->fading_thickness = 0.5f; + mmd->fading_opacity = 0.5f; } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) @@ -74,60 +77,39 @@ static void copyData(const GpencilModifierData *md, GpencilModifierData *target) BKE_gpencil_modifier_copyData_generic(md, target); } -static void splitStroke(bGPDframe *gpf, bGPDstroke *gps, float split_angle) -{ - bGPDspoint *pt = gps->points; - bGPDstroke *new_gps = gps; - int i; - volatile float angle; - - if (split_angle <= FLT_EPSILON) { - return; - } - - for (i = 1; i < new_gps->totpoints - 1; i++) { - angle = angle_v3v3v3(&pt[i - 1].x, &pt[i].x, &pt[i + 1].x); - if (angle < split_angle) { - if (BKE_gpencil_split_stroke(gpf, new_gps, i, &new_gps)) { - pt = new_gps->points; - i = 0; - continue; /* then i == 1 again */ - } - } - } -} - static void minter_v3_v3v3v3_ref( - float *result, float *left, float *middle, float *right, float *stroke_normal) + float *result, float *prev, float *curr, float *next, float *stroke_normal) { - float left_arm[3], right_arm[3], inter1[3], inter2[3]; + float vec[3], inter1[3], inter2[3]; + ARRAY_SET_ITEMS(inter1, 0.0f, 0.0f, 0.0f); + ARRAY_SET_ITEMS(inter2, 0.0f, 0.0f, 0.0f); + float minter[3]; - if (left) { - sub_v3_v3v3(left_arm, middle, left); - cross_v3_v3v3(inter1, stroke_normal, left_arm); + if (prev) { + sub_v3_v3v3(vec, curr, prev); + cross_v3_v3v3(inter1, stroke_normal, vec); } - if (right) { - sub_v3_v3v3(right_arm, right, middle); - cross_v3_v3v3(inter2, stroke_normal, right_arm); + if (next) { + sub_v3_v3v3(vec, next, curr); + cross_v3_v3v3(inter2, stroke_normal, vec); } - if (!left) { + if (!prev) { normalize_v3(inter2); copy_v3_v3(result, inter2); return; } - - if (!right) { + if (!next) { normalize_v3(inter1); copy_v3_v3(result, inter1); return; } - interp_v3_v3v3(minter, inter1, inter2, 0.5); normalize_v3(minter); copy_v3_v3(result, minter); } -static void duplicateStroke(bGPDstroke *gps, +static void duplicateStroke(Object *ob, + bGPDstroke *gps, int count, float dist, float offset, @@ -138,14 +120,15 @@ static void duplicateStroke(bGPDstroke *gps, float fading_opacity) { int i; - bGPDstroke *new_gps; + bGPDstroke *new_gps = NULL; float stroke_normal[3]; - float minter[3]; bGPDspoint *pt; - float offset_factor; float thickness_factor; float opacity_factor; + /* Apply object scale to offset distance. */ + offset *= mat4_to_scale(ob->obmat); + BKE_gpencil_stroke_normal(gps, stroke_normal); if (len_v3(stroke_normal) < FLT_EPSILON) { add_v3_fl(stroke_normal, 1); @@ -160,6 +143,7 @@ static void duplicateStroke(bGPDstroke *gps, pt = gps->points; for (int j = 0; j < gps->totpoints; j++) { + float minter[3]; if (j == 0) { minter_v3_v3v3v3_ref(minter, NULL, &pt[j].x, &pt[j + 1].x, stroke_normal); } @@ -174,11 +158,11 @@ static void duplicateStroke(bGPDstroke *gps, sub_v3_v3v3(&t2_array[j * 3], &pt[j].x, minter); } - /* This ensures the original stroke is the last one to be processed. */ + /* This ensures the original stroke is the last one + * to be processed, since we duplicate its data. */ for (i = count - 1; i >= 0; i--) { if (i != 0) { - new_gps = BKE_gpencil_stroke_duplicate(gps); - new_gps->flag |= GP_STROKE_RECALC_GEOMETRY; + new_gps = BKE_gpencil_stroke_duplicate(gps, true); BLI_addtail(results, new_gps); } else { @@ -187,34 +171,26 @@ static void duplicateStroke(bGPDstroke *gps, pt = new_gps->points; - if (count == 1) { - offset_factor = 0; - } - else { - offset_factor = (float)i / (float)(count - 1); - } + float offset_fac = (count == 1) ? 0.5f : (i / (float)(count - 1)); if (fading) { - thickness_factor = (offset_factor > fading_center) ? - (interpf(1 - fading_thickness, 1.0f, offset_factor - fading_center)) : - (interpf( - 1.0f, 1 - fading_thickness, offset_factor - fading_center + 1)); - opacity_factor = (offset_factor > fading_center) ? - (interpf(1 - fading_opacity, 1.0f, offset_factor - fading_center)) : - (interpf(1.0f, 1 - fading_opacity, offset_factor - fading_center + 1)); + thickness_factor = interpf(1.0f - fading_thickness, 1.0f, fabsf(offset_fac - fading_center)); + opacity_factor = interpf(1.0f - fading_opacity, 1.0f, fabsf(offset_fac - fading_center)); } for (int j = 0; j < new_gps->totpoints; j++) { - interp_v3_v3v3(&pt[j].x, - &t1_array[j * 3], - &t2_array[j * 3], - interpf(1 + offset, offset, offset_factor)); + float fac = interpf(1 + offset, offset, offset_fac); + interp_v3_v3v3(&pt[j].x, &t1_array[j * 3], &t2_array[j * 3], fac); if (fading) { pt[j].pressure = gps->points[j].pressure * thickness_factor; pt[j].strength = gps->points[j].strength * opacity_factor; } } } + /* Calc geometry data. */ + if (new_gps != NULL) { + BKE_gpencil_stroke_geometry_update(new_gps); + } MEM_freeN(t1_array); MEM_freeN(t2_array); } @@ -224,11 +200,10 @@ static void bakeModifier(Main *UNUSED(bmain), GpencilModifierData *md, Object *ob) { - bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { ListBase duplicates = {0}; MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md; bGPDstroke *gps; @@ -247,11 +222,9 @@ static void bakeModifier(Main *UNUSED(bmain), mmd->flag & GP_MIRROR_INVERT_MATERIAL)) { continue; } - if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) { - splitStroke(gpf, gps, mmd->split_angle); - } if (mmd->duplications > 0) { - duplicateStroke(gps, + duplicateStroke(ob, + gps, mmd->duplications, mmd->distance, mmd->offset, @@ -262,23 +235,15 @@ static void bakeModifier(Main *UNUSED(bmain), mmd->fading_opacity); } } - if (duplicates.first) { - ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first; - ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last; - gpf->strokes.last = duplicates.first; + if (!BLI_listbase_is_empty(&duplicates)) { + BLI_movelisttolist(&gpf->strokes, &duplicates); } } } } /* -------------------------------- */ - -/* Generic "generateStrokes" callback */ -static void generateStrokes(GpencilModifierData *md, - Depsgraph *UNUSED(depsgraph), - Object *ob, - bGPDlayer *gpl, - bGPDframe *gpf) +static void generate_geometry(GpencilModifierData *md, Object *ob, bGPDlayer *gpl, bGPDframe *gpf) { MultiplyGpencilModifierData *mmd = (MultiplyGpencilModifierData *)md; bGPDstroke *gps; @@ -298,11 +263,9 @@ static void generateStrokes(GpencilModifierData *md, mmd->flag & GP_MIRROR_INVERT_MATERIAL)) { continue; } - if (mmd->flags & GP_MULTIPLY_ENABLE_ANGLE_SPLITTING) { - splitStroke(gpf, gps, mmd->split_angle); - } if (mmd->duplications > 0) { - duplicateStroke(gps, + duplicateStroke(ob, + gps, mmd->duplications, mmd->distance, mmd->offset, @@ -313,10 +276,23 @@ static void generateStrokes(GpencilModifierData *md, mmd->fading_opacity); } } - if (duplicates.first) { - ((bGPDstroke *)gpf->strokes.last)->next = duplicates.first; - ((bGPDstroke *)duplicates.first)->prev = gpf->strokes.last; - gpf->strokes.last = duplicates.first; + if (!BLI_listbase_is_empty(&duplicates)) { + BLI_movelisttolist(&gpf->strokes, &duplicates); + } +} + +/* Generic "generateStrokes" callback */ +static void generateStrokes(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = (bGPdata *)ob->data; + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + bGPDframe *gpf = BKE_gpencil_frame_retime_get(depsgraph, scene, ob, gpl); + if (gpf == NULL) { + continue; + } + generate_geometry(md, ob, gpl, gpf); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 157bd536609..9b3d37bf11f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -23,18 +23,23 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_ghash.h" #include "BLI_hash.h" #include "BLI_rand.h" +#include "MEM_guardedalloc.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 "BKE_colortools.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" @@ -57,13 +62,38 @@ static void initData(GpencilModifierData *md) gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; gpmd->vgname[0] = '\0'; - gpmd->step = 1; - gpmd->seed = 0; + gpmd->step = 4; + gpmd->seed = 1; + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemap_reset(curve->cm, &curve->clipr, CURVE_PRESET_BELL, CURVEMAP_SLOPE_POSITIVE); + BKE_curvemapping_initialize(curve); + } +} + +static void freeData(GpencilModifierData *md) +{ + NoiseGpencilModifierData *gpmd = (NoiseGpencilModifierData *)md; + + if (gpmd->curve_intensity) { + BKE_curvemapping_free(gpmd->curve_intensity); + } } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + NoiseGpencilModifierData *gmd = (NoiseGpencilModifierData *)md; + NoiseGpencilModifierData *tgmd = (NoiseGpencilModifierData *)target; + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } static bool dependsOnTime(GpencilModifierData *md) @@ -72,24 +102,36 @@ static bool dependsOnTime(GpencilModifierData *md) return (mmd->flag & GP_NOISE_USE_RANDOM) != 0; } +static float *noise_table(int len, int seed) +{ + float *table = MEM_callocN(sizeof(float) * len, __func__); + for (int i = 0; i < len; i++) { + table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + 1)); + } + return table; +} + +BLI_INLINE float table_sample(float *table, float x) +{ + return interpf(table[(int)ceilf(x)], table[(int)floor(x)], fractf(x)); +} + /* aply noise effect based on stroke direction */ static void deformStroke(GpencilModifierData *md, Depsgraph *depsgraph, Object *ob, bGPDlayer *gpl, - bGPDframe *UNUSED(gpf), + bGPDframe *gpf, bGPDstroke *gps) { NoiseGpencilModifierData *mmd = (NoiseGpencilModifierData *)md; - bGPDspoint *pt0, *pt1; MDeformVert *dvert = NULL; - float shift, vran, vdir; + /* Noise value in range [-1..1] */ float normal[3]; float vec1[3], vec2[3]; - int sc_frame = 0; - int stroke_seed = 0; const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); - const float unit_v3[3] = {1.0f, 1.0f, 1.0f}; + const bool invert_group = (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0; + const bool use_curve = (mmd->flag & GP_NOISE_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -106,134 +148,99 @@ static void deformStroke(GpencilModifierData *md, return; } - sc_frame = (int)DEG_get_ctime(depsgraph); + int seed = mmd->seed; + /* FIXME(fclem): This is really slow. We should get the stroke index in another way. */ + int stroke_seed = BLI_findindex(&gpf->strokes, gps); + seed += stroke_seed; - zero_v3(vec2); + /* Make sure different modifiers get different seeds. */ + seed += BLI_hash_string(ob->id.name + 2); + seed += BLI_hash_string(md->name); + + if (mmd->flag & GP_NOISE_USE_RANDOM) { + seed += ((int)DEG_get_ctime(depsgraph)) / mmd->step; + } + + /* Sanitize as it can create out of bound reads. */ + float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f); + + int len = ceilf(gps->totpoints * noise_scale) + 1; + float *noise_table_position = (mmd->factor > 0.0f) ? noise_table(len, seed + 2) : NULL; + float *noise_table_strength = (mmd->factor_strength > 0.0f) ? noise_table(len, seed + 3) : NULL; + float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL; + float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL; /* calculate stroke normal*/ if (gps->totpoints > 2) { BKE_gpencil_stroke_normal(gps, normal); } else { - copy_v3_v3(normal, unit_v3); + copy_v3_fl(normal, 1.0f); } /* move points */ for (int i = 0; i < gps->totpoints; i++) { - if (((i == 0) || (i == gps->totpoints - 1)) && ((mmd->flag & GP_NOISE_MOVE_EXTREME) == 0)) { - continue; - } - - /* first point is special */ - if (i == 0) { - if (gps->dvert) { - dvert = &gps->dvert[0]; - } - pt0 = (gps->totpoints > 1) ? &gps->points[1] : &gps->points[0]; - pt1 = &gps->points[0]; - } - else { - int prev_idx = i - 1; - CLAMP_MIN(prev_idx, 0); - if (gps->dvert) { - dvert = &gps->dvert[prev_idx]; - } - pt0 = &gps->points[prev_idx]; - pt1 = &gps->points[i]; - } - + bGPDspoint *pt = &gps->points[i]; /* verify vertex group */ - const float weight = get_modifier_point_weight( - dvert, (mmd->flag & GP_NOISE_INVERT_VGROUP) != 0, def_nr); + dvert = &gps->dvert[i]; + float weight = get_modifier_point_weight(dvert, invert_group, def_nr); if (weight < 0.0f) { continue; } - /* initial vector (p0 -> p1) */ - if (i == 0) { - sub_v3_v3v3(vec1, &pt0->x, &pt1->x); - } - else { - sub_v3_v3v3(vec1, &pt1->x, &pt0->x); + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); } - vran = len_v3(vec1); - /* Vector orthogonal to normal. */ - cross_v3_v3v3(vec2, vec1, normal); - normalize_v3(vec2); - /* Use random noise */ - if (mmd->flag & GP_NOISE_USE_RANDOM) { - stroke_seed = BLI_hash_int_2d((sc_frame / mmd->step) + gps->totpoints, mmd->seed + 1); - vran = BLI_hash_frand(stroke_seed); - if (mmd->flag & GP_NOISE_FULL_STROKE) { - vdir = BLI_hash_frand(stroke_seed + 3); - } - else { - int f = (BLI_hash_frand(stroke_seed + 3) * 10.0f) + i; - vdir = f % 2; + + if (mmd->factor > 0.0f) { + /* Offset point randomly around the bi-normal vector. */ + if (gps->totpoints == 1) { + copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f); } - } - else { - vran = 1.0f; - if (mmd->flag & GP_NOISE_FULL_STROKE) { - vdir = gps->totpoints % 2; + else if (i != gps->totpoints - 1) { + /* Initial vector (p1 -> p0). */ + sub_v3_v3v3(vec1, &gps->points[i].x, &gps->points[i + 1].x); + /* if vec2 is zero, set to something */ + if (len_squared_v3(vec1) < 1e-8f) { + copy_v3_fl3(vec1, 1.0f, 0.0f, 0.0f); + } } else { - vdir = i % 2; + /* Last point reuse the penultimate normal (still stored in vec1) + * because the previous point is already modified. */ } - } + /* Vector orthogonal to normal. */ + cross_v3_v3v3(vec2, vec1, normal); + normalize_v3(vec2); - /* if vec2 is zero, set to something */ - if (gps->totpoints < 3) { - if ((vec2[0] == 0.0f) && (vec2[1] == 0.0f) && (vec2[2] == 0.0f)) { - copy_v3_v3(vec2, unit_v3); - } + float noise = table_sample(noise_table_position, i * noise_scale); + madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f); } - /* apply randomness to location of the point */ - if (mmd->flag & GP_NOISE_MOD_LOCATION) { - /* factor is too sensitive, so need divide */ - shift = ((vran * mmd->factor) / 1000.0f) * weight; - if (vdir > 0.5f) { - mul_v3_fl(vec2, shift); - } - else { - mul_v3_fl(vec2, shift * -1.0f); - } - add_v3_v3(&pt1->x, vec2); + if (mmd->factor_thickness > 0.0f) { + float noise = table_sample(noise_table_thickness, i * noise_scale); + pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f); + CLAMP_MIN(pt->pressure, GPENCIL_STRENGTH_MIN); } - /* apply randomness to thickness */ - if (mmd->flag & GP_NOISE_MOD_THICKNESS) { - if (vdir > 0.5f) { - pt1->pressure -= pt1->pressure * vran * mmd->factor * weight; - } - else { - pt1->pressure += pt1->pressure * vran * mmd->factor * weight; - } - CLAMP_MIN(pt1->pressure, GPENCIL_STRENGTH_MIN); + if (mmd->factor_strength > 0.0f) { + float noise = table_sample(noise_table_strength, i * noise_scale); + pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f); + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } - /* apply randomness to color strength */ - if (mmd->flag & GP_NOISE_MOD_STRENGTH) { - if (vdir > 0.5f) { - pt1->strength -= pt1->strength * vran * mmd->factor * weight; - } - else { - pt1->strength += pt1->strength * vran * mmd->factor * weight; - } - CLAMP_MIN(pt1->strength, GPENCIL_STRENGTH_MIN); - } - /* apply randomness to uv rotation */ - if (mmd->flag & GP_NOISE_MOD_UV) { - if (vdir > 0.5f) { - pt1->uv_rot -= pt1->uv_rot * vran * mmd->factor * weight; - } - else { - pt1->uv_rot += pt1->uv_rot * vran * mmd->factor * weight; - } - CLAMP(pt1->uv_rot, -M_PI_2, M_PI_2); + if (mmd->factor_uvs > 0.0f) { + float noise = table_sample(noise_table_uvs, i * noise_scale); + pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2; + CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); } } + + MEM_SAFE_FREE(noise_table_position); + MEM_SAFE_FREE(noise_table_strength); + MEM_SAFE_FREE(noise_table_thickness); + MEM_SAFE_FREE(noise_table_uvs); } static void bakeModifier(struct Main *UNUSED(bmain), @@ -243,9 +250,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } @@ -267,7 +274,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Noise = { /* remapTime */ NULL, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ dependsOnTime, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 0979a2d90c9..5a9a1b68361 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -108,6 +109,8 @@ static void deformStroke(GpencilModifierData *md, mul_m4_v3(mat, &pt->x); } + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } static void bakeModifier(struct Main *UNUSED(bmain), @@ -117,9 +120,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 9647489358e..4b04e349067 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "DNA_meshdata_types.h" @@ -35,6 +34,7 @@ #include "DNA_gpencil_types.h" #include "DNA_gpencil_modifier_types.h" +#include "BKE_colortools.h" #include "BKE_deform.h" #include "BKE_material.h" #include "BKE_gpencil.h" @@ -54,13 +54,27 @@ static void initData(GpencilModifierData *md) gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; gpmd->vgname[0] = '\0'; - gpmd->flag |= GP_OPACITY_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemapping_initialize(curve); + } } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + OpacityGpencilModifierData *gmd = (OpacityGpencilModifierData *)md; + OpacityGpencilModifierData *tgmd = (OpacityGpencilModifierData *)target; + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } /* opacity strokes */ @@ -73,6 +87,7 @@ static void deformStroke(GpencilModifierData *md, { OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md; const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); + const bool use_curve = (mmd->flag & GP_OPACITY_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -89,98 +104,79 @@ static void deformStroke(GpencilModifierData *md, return; } - if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) { - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - gps->runtime.tmp_stroke_rgba[3] *= mmd->factor; - /* if factor is > 1, then force opacity */ - if (mmd->factor > 1.0f) { - gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f; - } - CLAMP(gps->runtime.tmp_stroke_rgba[3], 0.0f, 1.0f); - } - - if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - gps->runtime.tmp_fill_rgba[3] *= mmd->factor; - /* if factor is > 1, then force opacity */ - if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) { - gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f; - } - CLAMP(gps->runtime.tmp_fill_rgba[3], 0.0f, 1.0f); - } - - /* if opacity > 1.0, affect the strength of the stroke */ - if (mmd->factor > 1.0f) { - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - pt->strength += mmd->factor - 1.0f; - CLAMP(pt->strength, 0.0f, 1.0f); - } - } - } - /* Apply opacity by strength */ - else { - for (int i = 0; i < gps->totpoints; i++) { - bGPDspoint *pt = &gps->points[i]; - MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + /* Stroke using strength. */ + if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { /* verify vertex group */ float weight = get_modifier_point_weight( dvert, (mmd->flag & GP_OPACITY_INVERT_VGROUP) != 0, def_nr); if (weight < 0.0f) { continue; } + /* Custom curve to modulate value. */ + float factor_curve = mmd->factor; + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + factor_curve *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + } + if (def_nr < 0) { - pt->strength += mmd->factor - 1.0f; + if (mmd->flag & GP_OPACITY_NORMALIZE) { + pt->strength = factor_curve; + } + else { + pt->strength += factor_curve - 1.0f; + } } else { /* High factor values, change weight too. */ - if ((mmd->factor > 1.0f) && (weight < 1.0f)) { - weight += mmd->factor - 1.0f; + if ((factor_curve > 1.0f) && (weight < 1.0f)) { + weight += factor_curve - 1.0f; CLAMP(weight, 0.0f, 1.0f); } - pt->strength += (mmd->factor - 1) * weight; + if (mmd->flag & GP_OPACITY_NORMALIZE) { + pt->strength = factor_curve; + } + else { + pt->strength += (factor_curve - 1) * weight; + } } + CLAMP(pt->strength, 0.0f, 1.0f); } } + + /* Fill using opacity factor. */ + if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { + gps->fill_opacity_fac = mmd->factor; + CLAMP(gps->fill_opacity_fac, 0.0f, 1.0f); + } } -static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) +static void bakeModifier(Main *UNUSED(bmain), + Depsgraph *depsgraph, + GpencilModifierData *md, + Object *ob) { - OpacityGpencilModifierData *mmd = (OpacityGpencilModifierData *)md; bGPdata *gpd = ob->data; - GHash *gh_color = BLI_ghash_str_new("GP_Opacity modifier"); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - - Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1); - if (mat == NULL) { - continue; - } - MaterialGPencilStyle *gp_style = mat->gp_style; - /* skip stroke if it doesn't have color info */ - if (ELEM(NULL, gp_style)) { - continue; - } - - copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - if (mmd->opacity_mode == GP_OPACITY_MODE_MATERIAL) { - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_OPACITY_CREATE_COLORS)); - } } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; +} +static void freeData(GpencilModifierData *md) +{ + OpacityGpencilModifierData *gpmd = (OpacityGpencilModifierData *)md; + + if (gpmd->curve_intensity) { + BKE_curvemapping_free(gpmd->curve_intensity); } } @@ -199,7 +195,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Opacity = { /* remapTime */ NULL, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index 9594fc8581e..60e26407b63 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_scene_types.h" @@ -84,21 +85,21 @@ static void deformStroke(GpencilModifierData *md, switch (mmd->mode) { case GP_SIMPLIFY_FIXED: { for (int i = 0; i < mmd->step; i++) { - BKE_gpencil_simplify_fixed(gps); + BKE_gpencil_stroke_simplify_fixed(gps); } break; } case GP_SIMPLIFY_ADAPTIVE: { /* simplify stroke using Ramer-Douglas-Peucker algorithm */ - BKE_gpencil_simplify_stroke(gps, mmd->factor); + BKE_gpencil_stroke_simplify_adaptive(gps, mmd->factor); break; } case GP_SIMPLIFY_SAMPLE: { - BKE_gpencil_sample_stroke(gps, mmd->length, false); + BKE_gpencil_stroke_sample(gps, mmd->length, false); break; } case GP_SIMPLIFY_MERGE: { - BKE_gpencil_merge_distance_stroke(gpf, gps, mmd->distance, true); + BKE_gpencil_stroke_merge_distance(gpf, gps, mmd->distance, true); break; } default: @@ -113,9 +114,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index b6b5bf05a9d..896333318aa 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -23,6 +23,7 @@ #include +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -30,6 +31,7 @@ #include "DNA_gpencil_types.h" #include "DNA_gpencil_modifier_types.h" +#include "BKE_colortools.h" #include "BKE_deform.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" @@ -49,11 +51,27 @@ static void initData(GpencilModifierData *md) gpmd->materialname[0] = '\0'; gpmd->vgname[0] = '\0'; gpmd->step = 1; + + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemapping_initialize(curve); + } } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + SmoothGpencilModifierData *gmd = (SmoothGpencilModifierData *)md; + SmoothGpencilModifierData *tgmd = (SmoothGpencilModifierData *)target; + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } /* aply smooth effect based on stroke direction */ @@ -66,6 +84,7 @@ static void deformStroke(GpencilModifierData *md, { SmoothGpencilModifierData *mmd = (SmoothGpencilModifierData *)md; const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); + const bool use_curve = (mmd->flag & GP_SMOOTH_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -89,28 +108,34 @@ static void deformStroke(GpencilModifierData *md, MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; /* verify vertex group */ - const float weight = get_modifier_point_weight( + float weight = get_modifier_point_weight( dvert, (mmd->flag & GP_SMOOTH_INVERT_VGROUP) != 0, def_nr); if (weight < 0.0f) { continue; } + /* Custom curve to modulate value. */ + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + } + const float val = mmd->factor * weight; /* perform smoothing */ if (mmd->flag & GP_SMOOTH_MOD_LOCATION) { - BKE_gpencil_smooth_stroke(gps, i, val); + BKE_gpencil_stroke_smooth(gps, i, val); } if (mmd->flag & GP_SMOOTH_MOD_STRENGTH) { - BKE_gpencil_smooth_stroke_strength(gps, i, val); + BKE_gpencil_stroke_smooth_strength(gps, i, val); } if ((mmd->flag & GP_SMOOTH_MOD_THICKNESS) && (val > 0.0f)) { /* thickness need to repeat process several times */ for (int r2 = 0; r2 < r * 10; r2++) { - BKE_gpencil_smooth_stroke_thickness(gps, i, val); + BKE_gpencil_stroke_smooth_thickness(gps, i, val); } } if (mmd->flag & GP_SMOOTH_MOD_UV) { - BKE_gpencil_smooth_stroke_uv(gps, i, val); + BKE_gpencil_stroke_smooth_uv(gps, i, val); } } } @@ -124,15 +149,24 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } } } +static void freeData(GpencilModifierData *md) +{ + SmoothGpencilModifierData *gpmd = (SmoothGpencilModifierData *)md; + + if (gpmd->curve_intensity) { + BKE_curvemapping_free(gpmd->curve_intensity); + } +} + GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* name */ "Smooth", /* structName */ "SmoothGpencilModifierData", @@ -148,7 +182,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Smooth = { /* remapTime */ NULL, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 89d6565d0dd..25abf0b81eb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -84,7 +85,7 @@ static void deformStroke(GpencilModifierData *md, return; } - BKE_gpencil_subdivide(gps, mmd->level, mmd->flag); + BKE_gpencil_stroke_subdivide(gps, mmd->level, mmd->type); } static void bakeModifier(struct Main *UNUSED(bmain), @@ -94,9 +95,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } @@ -104,7 +105,7 @@ static void bakeModifier(struct Main *UNUSED(bmain), } GpencilModifierTypeInfo modifierType_Gpencil_Subdiv = { - /* name */ "Subdivision", + /* name */ "Subdivide", /* structName */ "SubdivGpencilModifierData", /* structSize */ sizeof(SubdivGpencilModifierData), /* type */ eGpencilModifierTypeType_Gpencil, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index 694b932a6bf..894dff46ac2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -23,6 +23,8 @@ #include +#include "BLI_listbase.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_meshdata_types.h" @@ -45,7 +47,8 @@ static void initData(GpencilModifierData *md) { ThickGpencilModifierData *gpmd = (ThickGpencilModifierData *)md; gpmd->pass_index = 0; - gpmd->thickness = 2; + gpmd->thickness_fac = 1.0f; + gpmd->thickness = 30; gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; gpmd->vgname[0] = '\0'; @@ -105,70 +108,38 @@ static void deformStroke(GpencilModifierData *md, return; } - /* Check to see if we normalize the whole stroke or only certain points along it. */ - bool gps_has_affected_points = false; - bool gps_has_unaffected_points = false; - - if (mmd->flag & GP_THICK_NORMALIZE) { - for (int i = 0; i < gps->totpoints; i++) { - MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; - const float weight = get_modifier_point_weight( - dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr); - if (weight < 0.0f) { - gps_has_unaffected_points = true; - } - else { - gps_has_affected_points = true; - } - - /* If both checks are true, we have what we need so we can stop looking. */ - if (gps_has_affected_points && gps_has_unaffected_points) { - break; - } - } - } - - /* If we are normalizing and all points of the stroke are affected, it's safe to reset thickness - */ - if (mmd->flag & GP_THICK_NORMALIZE && gps_has_affected_points && !gps_has_unaffected_points) { - gps->thickness = mmd->thickness; - } - /* Without this check, modifier alters the thickness of strokes which have no points in scope */ + float stroke_thickness_inv = 1.0f / max_ii(gps->thickness, 1); for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; - float curvef = 1.0f; /* Verify point is part of vertex group. */ - const float weight = get_modifier_point_weight( + float weight = get_modifier_point_weight( dvert, (mmd->flag & GP_THICK_INVERT_VGROUP) != 0, def_nr); if (weight < 0.0f) { continue; } + float curvef = 1.0f; + if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) { + /* Normalize value to evaluate curve. */ + float value = (float)i / (gps->totpoints - 1); + curvef = BKE_curvemapping_evaluateF(mmd->curve_thickness, 0, value); + } + + float target; if (mmd->flag & GP_THICK_NORMALIZE) { - if (gps_has_unaffected_points) { - /* Clamp value for very weird situations when stroke thickness can be zero. */ - CLAMP_MIN(gps->thickness, 1); - /* Calculate pressure value to match the width of strokes with reset thickness and 1.0 - * pressure. */ - pt->pressure = (float)mmd->thickness / (float)gps->thickness; - } - else { - /* Reset point pressure values so only stroke thickness counts. */ - pt->pressure = 1.0f; - } + target = mmd->thickness * stroke_thickness_inv; + target *= curvef; } else { - if ((mmd->flag & GP_THICK_CUSTOM_CURVE) && (mmd->curve_thickness)) { - /* Normalize value to evaluate curve. */ - float value = (float)i / (gps->totpoints - 1); - curvef = BKE_curvemapping_evaluateF(mmd->curve_thickness, 0, value); - } - - pt->pressure += mmd->thickness * weight * curvef; - CLAMP_MIN(pt->pressure, 0.1f); + target = pt->pressure * mmd->thickness_fac; + weight *= curvef; } + + pt->pressure = interpf(target, pt->pressure, weight); + + CLAMP_MIN(pt->pressure, 0.1f); } } @@ -179,9 +150,9 @@ static void bakeModifier(struct Main *UNUSED(bmain), { bGPdata *gpd = ob->data; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 8f3956276dd..96f1f004812 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" #include "BLI_blenlib.h" -#include "BLI_ghash.h" #include "BLI_math_vector.h" #include "DNA_scene_types.h" @@ -34,6 +33,7 @@ #include "DNA_gpencil_types.h" #include "DNA_gpencil_modifier_types.h" +#include "BKE_colortools.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_material.h" @@ -52,13 +52,28 @@ static void initData(GpencilModifierData *md) gpmd->layername[0] = '\0'; gpmd->materialname[0] = '\0'; ARRAY_SET_ITEMS(gpmd->rgb, 1.0f, 1.0f, 1.0f); - gpmd->flag |= GP_TINT_CREATE_COLORS; gpmd->modify_color = GP_MODIFY_COLOR_BOTH; + + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemapping_initialize(curve); + } } static void copyData(const GpencilModifierData *md, GpencilModifierData *target) { + TintGpencilModifierData *gmd = (TintGpencilModifierData *)md; + TintGpencilModifierData *tgmd = (TintGpencilModifierData *)target; + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + BKE_gpencil_modifier_copyData_generic(md, target); + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); } /* tint strokes */ @@ -70,6 +85,7 @@ static void deformStroke(GpencilModifierData *md, bGPDstroke *gps) { TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; + const bool use_curve = (mmd->flag & GP_TINT_CUSTOM_CURVE) != 0 && mmd->curve_intensity; if (!is_stroke_affected_by_modifier(ob, mmd->layername, @@ -86,69 +102,77 @@ static void deformStroke(GpencilModifierData *md, return; } - if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { - interp_v3_v3v3( - gps->runtime.tmp_stroke_rgba, gps->runtime.tmp_stroke_rgba, mmd->rgb, mmd->factor); - /* if factor is > 1, the alpha must be changed to get full tint */ - if (mmd->factor > 1.0f) { - gps->runtime.tmp_stroke_rgba[3] += mmd->factor - 1.0f; + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + + /* if factor > 1.0, affect the strength of the stroke */ + if (mmd->factor > 1.0f) { + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + pt->strength += mmd->factor - 1.0f; + CLAMP(pt->strength, 0.0f, 1.0f); } - CLAMP4(gps->runtime.tmp_stroke_rgba, 0.0f, 1.0f); } + /* Apply to Vertex Color. */ + float mixfac = mmd->factor; + + CLAMP(mixfac, 0.0, 1.0f); + /* Fill */ if (mmd->modify_color != GP_MODIFY_COLOR_STROKE) { - interp_v3_v3v3(gps->runtime.tmp_fill_rgba, gps->runtime.tmp_fill_rgba, mmd->rgb, mmd->factor); - /* if factor is > 1, the alpha must be changed to get full tint */ - if (mmd->factor > 1.0f && gps->runtime.tmp_fill_rgba[3] > 1e-5) { - gps->runtime.tmp_fill_rgba[3] += mmd->factor - 1.0f; + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; } - CLAMP4(gps->runtime.tmp_fill_rgba, 0.0f, 1.0f); + + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, mmd->rgb, mixfac); } - /* if factor > 1.0, affect the strength of the stroke */ - if (mmd->factor > 1.0f) { + /* Stroke */ + if (mmd->modify_color != GP_MODIFY_COLOR_FILL) { for (int i = 0; i < gps->totpoints; i++) { bGPDspoint *pt = &gps->points[i]; - pt->strength += mmd->factor - 1.0f; - CLAMP(pt->strength, 0.0f, 1.0f); + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { + copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; + } + + /* Custom curve to modulate value. */ + float mixvalue = mixfac; + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + mixvalue *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + } + + interp_v3_v3v3(pt->vert_color, pt->vert_color, mmd->rgb, mixvalue); } } } -static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) +static void bakeModifier(Main *UNUSED(bmain), + Depsgraph *depsgraph, + GpencilModifierData *md, + Object *ob) { - TintGpencilModifierData *mmd = (TintGpencilModifierData *)md; bGPdata *gpd = ob->data; - GHash *gh_color = BLI_ghash_str_new("GP_Tint modifier"); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { - - Material *mat = BKE_gpencil_material(ob, gps->mat_nr + 1); - if (mat == NULL) { - continue; - } - MaterialGPencilStyle *gp_style = mat->gp_style; - /* skip stroke if it doesn't have color info */ - if (ELEM(NULL, gp_style)) { - continue; - } - - copy_v4_v4(gps->runtime.tmp_stroke_rgba, gp_style->stroke_rgba); - copy_v4_v4(gps->runtime.tmp_fill_rgba, gp_style->fill_rgba); - + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { deformStroke(md, depsgraph, ob, gpl, gpf, gps); - - gpencil_apply_modifier_material( - bmain, ob, mat, gh_color, gps, (bool)(mmd->flag & GP_TINT_CREATE_COLORS)); } } } - /* free hash buffers */ - if (gh_color) { - BLI_ghash_free(gh_color, NULL, NULL); - gh_color = NULL; +} + +static void freeData(GpencilModifierData *md) +{ + TintGpencilModifierData *gpmd = (TintGpencilModifierData *)md; + + if (gpmd->curve_intensity) { + BKE_curvemapping_free(gpmd->curve_intensity); } } @@ -167,7 +191,7 @@ GpencilModifierTypeInfo modifierType_Gpencil_Tint = { /* remapTime */ NULL, /* initData */ initData, - /* freeData */ NULL, + /* freeData */ freeData, /* isDisabled */ NULL, /* updateDepsgraph */ NULL, /* dependsOnTime */ NULL, diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c new file mode 100644 index 00000000000..b279d90dd4f --- /dev/null +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilvertexcolor.c @@ -0,0 +1,314 @@ +/* + * 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) 2017, Blender Foundation + * This is a new part of Blender + */ + +/** \file + * \ingroup modifiers + */ + +#include + +#include "BLI_utildefines.h" + +#include "BLI_math.h" +#include "BLI_listbase.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 "BKE_action.h" +#include "BKE_colorband.h" +#include "BKE_colortools.h" +#include "BKE_deform.h" +#include "BKE_gpencil.h" +#include "BKE_gpencil_modifier.h" +#include "BKE_layer.h" +#include "BKE_lib_query.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_modifier.h" +#include "BKE_scene.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) +{ + VertexcolorGpencilModifierData *gpmd = (VertexcolorGpencilModifierData *)md; + gpmd->pass_index = 0; + gpmd->layername[0] = '\0'; + gpmd->materialname[0] = '\0'; + gpmd->vgname[0] = '\0'; + gpmd->object = NULL; + gpmd->radius = 1.0f; + gpmd->factor = 1.0f; + + /* Add default color ramp. */ + gpmd->colorband = BKE_colorband_add(false); + if (gpmd->colorband) { + BKE_colorband_init(gpmd->colorband, true); + CBData *ramp = gpmd->colorband->data; + ramp[0].r = ramp[0].g = ramp[0].b = ramp[0].a = 1.0f; + ramp[0].pos = 0.0f; + ramp[1].r = ramp[1].g = ramp[1].b = 0.0f; + ramp[1].a = 1.0f; + ramp[1].pos = 1.0f; + + gpmd->colorband->tot = 2; + } + + gpmd->curve_intensity = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + if (gpmd->curve_intensity) { + CurveMapping *curve = gpmd->curve_intensity; + BKE_curvemapping_initialize(curve); + } +} + +static void copyData(const GpencilModifierData *md, GpencilModifierData *target) +{ + VertexcolorGpencilModifierData *gmd = (VertexcolorGpencilModifierData *)md; + VertexcolorGpencilModifierData *tgmd = (VertexcolorGpencilModifierData *)target; + + MEM_SAFE_FREE(tgmd->colorband); + + if (tgmd->curve_intensity != NULL) { + BKE_curvemapping_free(tgmd->curve_intensity); + tgmd->curve_intensity = NULL; + } + + BKE_gpencil_modifier_copyData_generic(md, target); + + if (gmd->colorband) { + tgmd->colorband = MEM_dupallocN(gmd->colorband); + } + + tgmd->curve_intensity = BKE_curvemapping_copy(gmd->curve_intensity); +} + +/* deform stroke */ +static void deformStroke(GpencilModifierData *md, + Depsgraph *UNUSED(depsgraph), + Object *ob, + bGPDlayer *gpl, + bGPDframe *UNUSED(gpf), + bGPDstroke *gps) +{ + VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; + if (!mmd->object) { + return; + } + + const int def_nr = BKE_object_defgroup_name_index(ob, mmd->vgname); + const bool use_curve = (mmd->flag & GP_VERTEXCOL_CUSTOM_CURVE) != 0 && mmd->curve_intensity; + + if (!is_stroke_affected_by_modifier(ob, + mmd->layername, + mmd->materialname, + mmd->pass_index, + mmd->layer_pass, + 1, + gpl, + gps, + mmd->flag & GP_VERTEXCOL_INVERT_LAYER, + mmd->flag & GP_VERTEXCOL_INVERT_PASS, + mmd->flag & GP_VERTEXCOL_INVERT_LAYERPASS, + mmd->flag & GP_VERTEXCOL_INVERT_MATERIAL)) { + return; + } + MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); + + float coba_res[4]; + float matrix[4][4]; + mul_m4_m4m4(matrix, mmd->object->imat, ob->obmat); + + /* loop points and apply deform */ + bool fill_done = false; + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + MDeformVert *dvert = gps->dvert != NULL ? &gps->dvert[i] : NULL; + + if (!fill_done) { + /* Apply to fill. */ + if (mmd->mode != GPPAINT_MODE_STROKE) { + + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (gps->vert_color_fill[3] == 0.0f) && + (gp_style->fill_rgba[3] > 0.0f)) { + copy_v4_v4(gps->vert_color_fill, gp_style->fill_rgba); + gps->vert_color_fill[3] = 1.0f; + } + + float center[3]; + add_v3_v3v3(center, gps->boundbox_min, gps->boundbox_max); + mul_v3_fl(center, 0.5f); + float pt_loc[3]; + mul_v3_m4v3(pt_loc, matrix, &pt->x); + float dist = len_v3(pt_loc); + float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); + + BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); + interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, coba_res, mmd->factor); + gps->vert_color_fill[3] = mmd->factor; + /* If no stroke, cancel loop. */ + if (mmd->mode != GPPAINT_MODE_BOTH) { + break; + } + } + + fill_done = true; + } + + /* Verify vertex group. */ + if (mmd->mode != GPPAINT_MODE_FILL) { + float weight = get_modifier_point_weight( + dvert, (mmd->flag & GP_VERTEXCOL_INVERT_VGROUP) != 0, def_nr); + if (weight < 0.0f) { + continue; + } + /* Custom curve to modulate value. */ + if (use_curve) { + float value = (float)i / (gps->totpoints - 1); + weight *= BKE_curvemapping_evaluateF(mmd->curve_intensity, 0, value); + } + + /* Calc world position of point. */ + float pt_loc[3]; + mul_v3_m4v3(pt_loc, matrix, &pt->x); + float dist = len_v3(pt_loc); + + /* If not using Vertex Color, use the material color. */ + if ((gp_style != NULL) && (pt->vert_color[3] == 0.0f) && (gp_style->stroke_rgba[3] > 0.0f)) { + copy_v4_v4(pt->vert_color, gp_style->stroke_rgba); + pt->vert_color[3] = 1.0f; + } + + /* Calc the factor using the distance and get mix color. */ + float mix_factor = clamp_f(dist / mmd->radius, 0.0f, 1.0f); + BKE_colorband_evaluate(mmd->colorband, mix_factor, coba_res); + + interp_v3_v3v3(pt->vert_color, pt->vert_color, coba_res, mmd->factor * weight * coba_res[3]); + } + } +} + +/* FIXME: Ideally we be doing this on a copy of the main depsgraph + * (i.e. one where we don't have to worry about restoring state) + */ +static void bakeModifier(Main *bmain, Depsgraph *depsgraph, GpencilModifierData *md, Object *ob) +{ + VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; + Scene *scene = DEG_get_evaluated_scene(depsgraph); + bGPdata *gpd = ob->data; + int oldframe = (int)DEG_get_ctime(depsgraph); + + if (mmd->object == NULL) { + return; + } + + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + /* apply effects on this frame + * NOTE: this assumes that we don't want animation on non-keyframed frames + */ + CFRA = gpf->framenum; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); + + /* compute effects on this frame */ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + deformStroke(md, depsgraph, ob, gpl, gpf, gps); + } + } + } + + /* return frame state and DB to original state */ + CFRA = oldframe; + BKE_scene_graph_update_for_newframe(depsgraph, bmain); +} + +static void freeData(GpencilModifierData *md) +{ + VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; + if (mmd->colorband) { + MEM_freeN(mmd->colorband); + mmd->colorband = NULL; + } + if (mmd->curve_intensity) { + BKE_curvemapping_free(mmd->curve_intensity); + } +} + +static bool isDisabled(GpencilModifierData *md, int UNUSED(userRenderParams)) +{ + VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; + + return !mmd->object; +} + +static void updateDepsgraph(GpencilModifierData *md, const ModifierUpdateDepsgraphContext *ctx) +{ + VertexcolorGpencilModifierData *lmd = (VertexcolorGpencilModifierData *)md; + if (lmd->object != NULL) { + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Vertexcolor Modifier"); + DEG_add_object_relation(ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); + } + DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Vertexcolor Modifier"); +} + +static void foreachObjectLink(GpencilModifierData *md, + Object *ob, + ObjectWalkFunc walk, + void *userData) +{ + VertexcolorGpencilModifierData *mmd = (VertexcolorGpencilModifierData *)md; + + walk(userData, ob, &mmd->object, IDWALK_CB_NOP); +} + +GpencilModifierTypeInfo modifierType_Gpencil_Vertexcolor = { + /* name */ "Vertex Color", + /* structName */ "VertexcolorGpencilModifierData", + /* structSize */ sizeof(VertexcolorGpencilModifierData), + /* type */ eGpencilModifierTypeType_Gpencil, + /* flags */ eGpencilModifierTypeFlag_SupportsEditmode, + + /* copyData */ copyData, + + /* deformStroke */ deformStroke, + /* generateStrokes */ NULL, + /* bakeModifier */ bakeModifier, + /* remapTime */ NULL, + + /* initData */ initData, + /* freeData */ freeData, + /* isDisabled */ isDisabled, + /* updateDepsgraph */ updateDepsgraph, + /* dependsOnTime */ NULL, + /* foreachObjectLink */ foreachObjectLink, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, +}; -- cgit v1.2.3