GPencil: New "Additive" mode for build modifier

The new mode only builds the new strokes in each frame. 

The code is assuming somebody uses "additive" drawing, so that each frame is different only in its NEW strokes. Already existing strokes are skipped. 

I used a simple solution: Count the number of strokes in the previous frame and ignore this many strokes in the current frame.

Differential Revision: https://developer.blender.org/D14252
This commit is contained in:
Marc Chéhab 2022-03-08 16:37:57 +01:00 committed by Antonio Vazquez
parent 5791835678
commit e74838d0d0
3 changed files with 47 additions and 11 deletions

View File

@ -180,23 +180,42 @@ typedef struct tStrokeBuildDetails {
int totpoints;
} tStrokeBuildDetails;
/* Sequential - Show strokes one after the other */
/* Sequential and additive - Show strokes one after the other. */
static void build_sequential(BuildGpencilModifierData *mmd,
bGPdata *gpd,
bGPDframe *gpf,
float fac)
float fac,
bool additive)
{
const size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
size_t tot_strokes = BLI_listbase_count(&gpf->strokes);
size_t start_stroke;
bGPDstroke *gps;
size_t i;
/* 1) Compute proportion of time each stroke should occupy */
/* 1) Determine which strokes to start with & total strokes to build. */
if (additive) {
if (gpf->prev) {
start_stroke = BLI_listbase_count(&gpf->prev->strokes);
} else {
start_stroke = 0;
}
if (start_stroke <= tot_strokes) {
tot_strokes = tot_strokes - start_stroke;
} else {
start_stroke = 0;
}
} else {
start_stroke = 0;
}
/* 2) Compute proportion of time each stroke should occupy */
/* NOTE: This assumes that the total number of points won't overflow! */
tStrokeBuildDetails *table = MEM_callocN(sizeof(tStrokeBuildDetails) * tot_strokes, __func__);
size_t totpoints = 0;
/* 1.1) First pass - Tally up points */
for (gps = gpf->strokes.first, i = 0; gps; gps = gps->next, i++) {
/* 2.1) First pass - Tally up points */
for (gps = BLI_findlink(&gpf->strokes, start_stroke), i = 0; gps; gps = gps->next, i++) {
tStrokeBuildDetails *cell = &table[i];
cell->gps = gps;
@ -205,7 +224,7 @@ static void build_sequential(BuildGpencilModifierData *mmd,
totpoints += cell->totpoints;
}
/* 1.2) Second pass - Compute the overall indices for points */
/* 2.2) Second pass - Compute the overall indices for points */
for (i = 0; i < tot_strokes; i++) {
tStrokeBuildDetails *cell = &table[i];
@ -218,7 +237,7 @@ static void build_sequential(BuildGpencilModifierData *mmd,
cell->end_idx = cell->start_idx + cell->totpoints - 1;
}
/* 2) Determine the global indices for points that should be visible */
/* 3) Determine the global indices for points that should be visible */
size_t first_visible = 0;
size_t last_visible = 0;
@ -248,7 +267,7 @@ static void build_sequential(BuildGpencilModifierData *mmd,
break;
}
/* 3) Go through all strokes, deciding which to keep, and/or how much of each to keep */
/* 4) Go through all strokes, deciding which to keep, and/or how much of each to keep */
for (i = 0; i < tot_strokes; i++) {
tStrokeBuildDetails *cell = &table[i];
@ -386,10 +405,14 @@ static void build_concurrent(BuildGpencilModifierData *mmd,
}
/* --------------------------------------------- */
static void generate_geometry(
GpencilModifierData *md, Depsgraph *depsgraph, bGPdata *gpd, bGPDlayer *gpl, bGPDframe *gpf)
{
BuildGpencilModifierData *mmd = (BuildGpencilModifierData *)md;
if (mmd->mode == GP_BUILD_MODE_ADDITIVE) {
mmd->transition = GP_BUILD_TRANSITION_GROW;
}
const bool reverse = (mmd->transition != GP_BUILD_TRANSITION_GROW);
const bool is_percentage = (mmd->flag & GP_BUILD_PERCENTAGE);
@ -494,13 +517,17 @@ static void generate_geometry(
/* Time management mode */
switch (mmd->mode) {
case GP_BUILD_MODE_SEQUENTIAL:
build_sequential(mmd, gpd, gpf, fac);
build_sequential(mmd, gpd, gpf, fac, false);
break;
case GP_BUILD_MODE_CONCURRENT:
build_concurrent(mmd, gpd, gpf, fac);
break;
case GP_BUILD_MODE_ADDITIVE:
build_sequential(mmd, gpd, gpf, fac, true);
break;
default:
printf("Unsupported build mode (%d) for GP Build Modifier: '%s'\n",
mmd->mode,
@ -544,7 +571,9 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemS(layout);
uiItemR(layout, ptr, "transition", 0, NULL, ICON_NONE);
if (mode == GP_BUILD_MODE_SEQUENTIAL || mode == GP_BUILD_MODE_CONCURRENT) {
uiItemR(layout, ptr, "transition", 0, NULL, ICON_NONE);
}
row = uiLayoutRow(layout, true);
uiLayoutSetActive(row, !use_percentage);
uiItemR(row, ptr, "start_delay", 0, NULL, ICON_NONE);

View File

@ -401,6 +401,8 @@ typedef enum eBuildGpencil_Mode {
GP_BUILD_MODE_SEQUENTIAL = 0,
/* All strokes start at the same time */
GP_BUILD_MODE_CONCURRENT = 1,
/* Only the new strokes are built */
GP_BUILD_MODE_ADDITIVE = 2,
} eBuildGpencil_Mode;
typedef enum eBuildGpencil_Transition {

View File

@ -2070,6 +2070,11 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna)
ICON_PARTICLE_TIP,
"Concurrent",
"Multiple strokes appear/disappear at once"},
{GP_BUILD_MODE_ADDITIVE,
"ADDITIVE",
ICON_PARTICLE_PATH,
"Additive",
"Builds only new strokes (assuming 'additive' drawing)."},
{0, NULL, 0, NULL, NULL},
};