diff options
author | Antonio Vazquez <blendergit@gmail.com> | 2020-03-09 18:27:24 +0300 |
---|---|---|
committer | Antonio Vazquez <blendergit@gmail.com> | 2020-03-09 18:27:24 +0300 |
commit | 29f3af95272590d26f610ae828b2eeee89c82a00 (patch) | |
tree | a696a58a2561c48f7ec6166e369e22081e0a64d8 /source/blender/editors/gpencil/gpencil_fill.c | |
parent | dcb93126876879d969a30a7865700abd072066f8 (diff) |
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
Diffstat (limited to 'source/blender/editors/gpencil/gpencil_fill.c')
-rw-r--r-- | source/blender/editors/gpencil/gpencil_fill.c | 170 |
1 files changed, 125 insertions, 45 deletions
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index d76ab85ad31..c928c1e933a 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -134,6 +134,9 @@ typedef struct tGPDfill { /* scaling factor */ short fill_factor; + /* Frame to use. */ + int active_cfra; + /** number of elements currently in cache */ short sbuffer_used; /** temporary points */ @@ -228,7 +231,6 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) Object *ob = tgpf->ob; bGPdata *gpd = tgpf->gpd; - int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph); tGPDdraw tgpw; tgpw.rv3d = tgpf->rv3d; @@ -245,9 +247,9 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) GPU_blend(true); - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { /* calculate parent position */ - ED_gpencil_parent_location(tgpw.depsgraph, ob, gpd, gpl, tgpw.diff_mat); + BKE_gpencil_parent_matrix_get(tgpw.depsgraph, ob, gpl, tgpw.diff_mat); /* do not draw layer if hidden */ if (gpl->flag & GP_LAYER_HIDE) { @@ -256,25 +258,25 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) /* if active layer and no keyframe, create a new one */ if (gpl == tgpf->gpl) { - if ((gpl->actframe == NULL) || (gpl->actframe->framenum != cfra_eval)) { - BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_ADD_NEW); + if ((gpl->actframe == NULL) || (gpl->actframe->framenum != tgpf->active_cfra)) { + BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); } } /* get frame to draw */ - bGPDframe *gpf = BKE_gpencil_layer_getframe(gpl, cfra_eval, GP_GETFRAME_USE_PREV); + bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, tgpf->active_cfra, GP_GETFRAME_USE_PREV); if (gpf == NULL) { continue; } - for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { /* check if stroke can be drawn */ if ((gps->points == NULL) || (gps->totpoints < 2)) { continue; } /* check if the color is visible */ MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, gps->mat_nr + 1); - if ((gp_style == NULL) || (gp_style->flag & GP_STYLE_COLOR_HIDE)) { + if ((gp_style == NULL) || (gp_style->flag & GP_MATERIAL_HIDE)) { continue; } @@ -291,7 +293,7 @@ static void gp_draw_datablock(tGPDfill *tgpf, const float ink[4]) tgpw.onion = true; tgpw.custonion = true; - bool textured_stroke = (gp_style->stroke_style == GP_STYLE_STROKE_STYLE_TEXTURE); + bool textured_stroke = (gp_style->stroke_style == GP_MATERIAL_STROKE_STYLE_TEXTURE); /* normal strokes */ if (((tgpf->fill_draw_mode == GP_FILL_DMODE_STROKE) || @@ -666,6 +668,62 @@ static void gpencil_boundaryfill_area(tGPDfill *tgpf) BLI_stack_free(stack); } +/* Check if there are some pixel not filled with green. If no points, means nothing to fill. */ +static bool gpencil_check_borders(tGPDfill *tgpf) +{ + ImBuf *ibuf; + void *lock; + ibuf = BKE_image_acquire_ibuf(tgpf->ima, NULL, &lock); + int idx; + int pixel = 0; + float color[4]; + bool found = false; + + /* horizontal lines */ + for (idx = 0; idx < ibuf->x; idx++) { + /* bottom line */ + get_pixel(ibuf, idx, color); + if (color[1] != 1.0f) { + found = true; + break; + } + /* top line */ + pixel = idx + (ibuf->x * (ibuf->y - 1)); + get_pixel(ibuf, pixel, color); + if (color[1] != 1.0f) { + found = true; + break; + } + } + if (!found) { + /* vertical lines */ + for (idx = 0; idx < ibuf->y; idx++) { + /* left line */ + get_pixel(ibuf, ibuf->x * idx, color); + if (color[1] != 1.0f) { + found = true; + break; + } + /* right line */ + pixel = ibuf->x * idx + (ibuf->x - 1); + get_pixel(ibuf, pixel, color); + if (color[1] != 1.0f) { + found = true; + break; + } + } + } + + /* release ibuf */ + if (ibuf) { + BKE_image_release_ibuf(tgpf->ima, ibuf, lock); + } + + tgpf->ima->id.tag |= LIB_TAG_DOIT; + + return found; +} + /* clean external border of image to avoid infinite loops */ static void gpencil_clean_borders(tGPDfill *tgpf) { @@ -1006,8 +1064,6 @@ static void gpencil_points_from_stack(tGPDfill *tgpf) /* create a grease pencil stroke using points in buffer */ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) { - const int cfra_eval = (int)DEG_get_ctime(tgpf->depsgraph); - ToolSettings *ts = tgpf->scene->toolsettings; const char *align_flag = &ts->gpencil_v3d_align; const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); @@ -1026,16 +1082,23 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) return; } - /* get frame or create a new one */ - tgpf->gpf = BKE_gpencil_layer_getframe(tgpf->gpl, cfra_eval, GP_GETFRAME_ADD_NEW); + /* Get frame or create a new one. */ + tgpf->gpf = BKE_gpencil_layer_frame_get(tgpf->gpl, tgpf->active_cfra, GP_GETFRAME_ADD_NEW); + + /* Set frame as selected. */ + tgpf->gpf->flag |= GP_FRAME_SELECT; /* create new stroke */ bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke"); gps->thickness = brush->size; - gps->gradient_f = brush->gpencil_settings->gradient_f; - copy_v2_v2(gps->gradient_s, brush->gpencil_settings->gradient_s); + gps->fill_opacity_fac = 1.0f; + gps->hardeness = brush->gpencil_settings->hardeness; + copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio); gps->inittime = 0.0f; + /* Apply the vertex color to fill. */ + ED_gpencil_fill_vertex_color_set(ts, brush, gps); + /* the polygon must be closed, so enabled cyclic */ gps->flag |= GP_STROKE_CYCLIC; gps->flag |= GP_STROKE_3DSPACE; @@ -1054,11 +1117,6 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gps->totpoints = tgpf->sbuffer_used; gps->points = MEM_callocN(sizeof(bGPDspoint) * tgpf->sbuffer_used, "gp_stroke_points"); - /* initialize triangle memory to dummy data */ - gps->tot_triangles = 0; - gps->triangles = NULL; - gps->flag |= GP_STROKE_RECALC_GEOMETRY; - /* add stroke to frame */ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) || (tgpf->on_back == true)) { BLI_addhead(&tgpf->gpf->strokes, gps); @@ -1093,6 +1151,9 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) pt->strength = 1.0f; pt->time = 0.0f; + /* Apply the vertex color to point. */ + ED_gpencil_point_vertex_color_set(ts, brush, pt); + if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr); if (dw) { @@ -1115,7 +1176,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) float smoothfac = 1.0f; for (int r = 0; r < 1; r++) { for (int i = 0; i < gps->totpoints; i++) { - BKE_gpencil_smooth_stroke(gps, i, smoothfac - reduce); + BKE_gpencil_stroke_smooth(gps, i, smoothfac - reduce); } reduce += 0.25f; // reduce the factor } @@ -1124,7 +1185,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) if ((tgpf->lock_axis > GP_LOCKAXIS_VIEW) && ((ts->gpencil_v3d_align & GP_PROJECT_DEPTH_VIEW) == 0)) { float origin[3]; - ED_gp_get_drawing_reference(tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin); + ED_gpencil_drawing_reference_get( + tgpf->scene, tgpf->ob, tgpf->gpl, ts->gpencil_v3d_align, origin); ED_gp_project_stroke_to_plane( tgpf->scene, tgpf->ob, tgpf->rv3d, gps, origin, tgpf->lock_axis - 1); } @@ -1132,7 +1194,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* if parented change position relative to parent object */ for (int a = 0; a < tgpf->sbuffer_used; a++) { pt = &gps->points[a]; - gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpd, tgpf->gpl, pt); + gp_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } /* if camera view, reproject flat to view to avoid perspective effect */ @@ -1142,14 +1204,17 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) /* simplify stroke */ for (int b = 0; b < tgpf->fill_simplylvl; b++) { - BKE_gpencil_simplify_fixed(gps); + BKE_gpencil_stroke_simplify_fixed(gps); } + + /* Calc geometry data. */ + BKE_gpencil_stroke_geometry_update(gps); } /* ----------------------- */ /* Drawing */ /* Helper: Draw status message while the user is running the operator */ -static void gpencil_fill_status_indicators(bContext *C, tGPDfill *UNUSED(tgpf)) +static void gpencil_fill_status_indicators(bContext *C) { const char *status_str = TIP_("Fill: ESC/RMB cancel, LMB Fill, Shift Draw on Back"); ED_workspace_status_text(C, status_str); @@ -1228,10 +1293,11 @@ static tGPDfill *gp_session_init_fill(bContext *C, wmOperator *UNUSED(op)) /* set GP datablock */ tgpf->gpd = gpd; - tgpf->gpl = BKE_gpencil_layer_getactive(gpd); + tgpf->gpl = BKE_gpencil_layer_active_get(gpd); if (tgpf->gpl == NULL) { tgpf->gpl = BKE_gpencil_layer_addnew(tgpf->gpd, DATA_("GP_Layer"), true); } + tgpf->lock_axis = ts->gp_sculpt.lock_axis; tgpf->oldkey = -1; @@ -1339,7 +1405,7 @@ static int gpencil_fill_init(bContext *C, wmOperator *op) tGPDfill *tgpf; /* cannot paint in locked layer */ bGPdata *gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd); if ((gpl) && (gpl->flag & GP_LAYER_LOCKED)) { return 0; } @@ -1401,7 +1467,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_PAINT_BRUSH); - gpencil_fill_status_indicators(C, tgpf); + gpencil_fill_status_indicators(C); DEG_id_tag_update(&tgpf->gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -1416,6 +1482,7 @@ static int gpencil_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) { tGPDfill *tgpf = op->customdata; + Scene *scene = tgpf->scene; int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through */ @@ -1426,7 +1493,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) break; case LEFTMOUSE: tgpf->on_back = RNA_boolean_get(op->ptr, "on_back"); - /* first time the event is not enabled to show help lines */ + /* first time the event is not enabled to show help lines. */ if ((tgpf->oldkey != -1) || ((tgpf->flag & GP_BRUSH_FILL_SHOW_HELPLINES) == 0)) { ARegion *region = BKE_area_find_region_xy( CTX_wm_area(C), RGN_TYPE_ANY, event->x, event->y); @@ -1437,42 +1504,55 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) in_bounds = BLI_rcti_isect_pt(®ion->winrct, event->x, event->y); if ((in_bounds) && (region->regiontype == RGN_TYPE_WINDOW)) { - /* TODO GPXX: Verify the mouse click is right for any window size */ tgpf->center[0] = event->mval[0]; tgpf->center[1] = event->mval[1]; + /* Set active frame as current for filling. */ + tgpf->active_cfra = CFRA; + /* render screen to temp image */ if (gp_render_offscreen(tgpf)) { /* apply boundary fill */ gpencil_boundaryfill_area(tgpf); - /* clean borders to avoid infinite loops */ - gpencil_clean_borders(tgpf); + /* Check if detected some border to fill. */ + if (gpencil_check_borders(tgpf)) { - /* analyze outline */ - gpencil_get_outline_points(tgpf); + /* clean borders to avoid infinite loops */ + gpencil_clean_borders(tgpf); - /* create array of points from stack */ - gpencil_points_from_stack(tgpf); + /* analyze outline */ + gpencil_get_outline_points(tgpf); - /* create z-depth array for reproject */ - gpencil_get_depth_array(tgpf); + /* create array of points from stack */ + gpencil_points_from_stack(tgpf); - /* create stroke and reproject */ - gpencil_stroke_from_buffer(tgpf); - } + /* create z-depth array for reproject */ + gpencil_get_depth_array(tgpf); - /* restore size */ - tgpf->region->winx = (short)tgpf->bwinx; - tgpf->region->winy = (short)tgpf->bwiny; - tgpf->region->winrct = tgpf->brect; + /* create stroke and reproject */ + gpencil_stroke_from_buffer(tgpf); + } + else { + BKE_report(op->reports, RPT_ERROR, "Fill canceled. No edges detected"); + } + } /* free temp stack data */ if (tgpf->stack) { BLI_stack_free(tgpf->stack); } + /* Free memory. */ + MEM_SAFE_FREE(tgpf->sbuffer); + MEM_SAFE_FREE(tgpf->depth_arr); + + /* restore size */ + tgpf->region->winx = (short)tgpf->bwinx; + tgpf->region->winy = (short)tgpf->bwiny; + tgpf->region->winrct = tgpf->brect; + /* push undo data */ gpencil_undo_push(tgpf->gpd); |