diff options
Diffstat (limited to 'source/blender/blenkernel/intern/gpencil_geom.c')
-rw-r--r-- | source/blender/blenkernel/intern/gpencil_geom.c | 273 |
1 files changed, 178 insertions, 95 deletions
diff --git a/source/blender/blenkernel/intern/gpencil_geom.c b/source/blender/blenkernel/intern/gpencil_geom.c index 4dcd94fdeec..be5a148f6f9 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.c +++ b/source/blender/blenkernel/intern/gpencil_geom.c @@ -523,7 +523,7 @@ bool BKE_gpencil_stroke_sample(bGPdata *gpd, bGPDstroke *gps, const float dist, gps->totpoints = i; /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); return true; } @@ -708,7 +708,7 @@ bool BKE_gpencil_stroke_split(bGPdata *gpd, * Keep the end point. */ BKE_gpencil_stroke_trim_points(gps, 0, old_count); - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); return true; } @@ -1376,29 +1376,25 @@ void BKE_gpencil_stroke_uv_update(bGPDstroke *gps) * Recalc all internal geometry data for the stroke * \param gpd: Grease pencil data-block * \param gps: Grease pencil stroke + * \param flag: eGPStrokeGeoUpdateFlag flag (use GP_GEO_UPDATE_DEFAULT=0 for the default) */ -void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps) +void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, + bGPDstroke *gps, + const eGPStrokeGeoUpdateFlag flag) { if (gps == NULL) { return; } - if (gps->editcurve != NULL) { - if (GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd)) { - /* curve geometry was updated: stroke needs recalculation */ - if (gps->flag & GP_STROKE_NEEDS_CURVE_UPDATE) { - bool is_adaptive = gpd->flag & GP_DATA_CURVE_ADAPTIVE_RESOLUTION; - BKE_gpencil_stroke_update_geometry_from_editcurve( - gps, gpd->curve_edit_resolution, is_adaptive); - gps->flag &= ~GP_STROKE_NEEDS_CURVE_UPDATE; - } - } - else { - /* stroke geometry was updated: editcurve needs recalculation */ - gps->editcurve->flag |= GP_CURVE_NEEDS_STROKE_UPDATE; - } + /* Update curve points first if it's a bezier stroke. */ + if (GPENCIL_STROKE_TYPE_BEZIER(gps) && GP_GEO_UPDATE_POLYLINE_REGENERATE_ANY(flag)) { + /* Regenerate the polyline points from the curve data. */ + const uint resolution = gpd->curve_edit_resolution; + const bool is_adaptive = gpd->flag & GP_DATA_CURVE_ADAPTIVE_RESOLUTION; + BKE_gpencil_stroke_update_geometry_from_editcurve(gps, resolution, is_adaptive, flag); } + /* Triangulate the stroke. */ if (gps->totpoints > 2) { BKE_gpencil_stroke_fill_triangulate(gps); } @@ -1407,7 +1403,7 @@ void BKE_gpencil_stroke_geometry_update(bGPdata *gpd, bGPDstroke *gps) MEM_SAFE_FREE(gps->triangles); } - /* calc uv data along the stroke */ + /* Calc UV data along the stroke. */ BKE_gpencil_stroke_uv_update(gps); /* Calc stroke bounding box. */ @@ -1559,7 +1555,7 @@ bool BKE_gpencil_stroke_trim(bGPdata *gpd, bGPDstroke *gps) MEM_SAFE_FREE(old_dvert); } - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); return intersect; } @@ -1736,7 +1732,7 @@ void BKE_gpencil_dissolve_points(bGPdata *gpd, bGPDframe *gpf, bGPDstroke *gps, gps->totpoints = tot; /* triangles cache needs to be recalculated */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } } @@ -1884,7 +1880,7 @@ void BKE_gpencil_stroke_simplify_adaptive(bGPdata *gpd, bGPDstroke *gps, float e gps->totpoints = j; /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); @@ -1950,7 +1946,7 @@ void BKE_gpencil_stroke_simplify_fixed(bGPdata *gpd, bGPDstroke *gps) gps->totpoints = j; /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); MEM_SAFE_FREE(old_points); MEM_SAFE_FREE(old_dvert); @@ -2072,7 +2068,7 @@ void BKE_gpencil_stroke_subdivide(bGPdata *gpd, bGPDstroke *gps, int level, int } /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } /* Merge by distance ------------------------------------- */ @@ -2157,7 +2153,7 @@ void BKE_gpencil_stroke_merge_distance(bGPdata *gpd, } /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } typedef struct GpEdge { @@ -2372,7 +2368,7 @@ static void gpencil_generate_edgeloops(Object *ob, pt->strength = 1.0f; } - BKE_gpencil_stroke_geometry_update(gpd, gps_stroke); + BKE_gpencil_stroke_geometry_update(gpd, gps_stroke, GP_GEO_UPDATE_DEFAULT); } /* Free memory. */ @@ -2557,7 +2553,7 @@ bool BKE_gpencil_convert_mesh(Main *bmain, BKE_gpencil_stroke_subdivide(gpd, gps_fill, 1, GP_SUBDIV_SIMPLE); } - BKE_gpencil_stroke_geometry_update(gpd, gps_fill); + BKE_gpencil_stroke_geometry_update(gpd, gps_fill, GP_GEO_UPDATE_DEFAULT); } } } @@ -2614,7 +2610,7 @@ void BKE_gpencil_transform(bGPdata *gpd, const float mat[4][4]) } /* Distortion may mean we need to re-triangulate. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } } } @@ -2706,7 +2702,7 @@ void BKE_gpencil_point_coords_apply(bGPdata *gpd, const GPencilPointCoordinates } /* Distortion may mean we need to re-triangulate. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } } } @@ -2743,7 +2739,7 @@ void BKE_gpencil_point_coords_apply_with_mat4(bGPdata *gpd, } /* Distortion may mean we need to re-triangulate. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } } } @@ -2768,49 +2764,108 @@ void BKE_gpencil_stroke_set_random_color(bGPDstroke *gps) } } +static void gpencil_flip_beztriple(BezTriple *bezt) +{ + /* Flip handle position. */ + float tmp[3]; + copy_v3_v3(tmp, bezt->vec[0]); + copy_v3_v3(bezt->vec[0], bezt->vec[2]); + copy_v3_v3(bezt->vec[2], tmp); + + /* Flip type and slection flag. */ + SWAP(uint8_t, bezt->h1, bezt->h2); + SWAP(uint8_t, bezt->f1, bezt->f3); +} + /* Flip stroke. */ void BKE_gpencil_stroke_flip(bGPDstroke *gps) { - int end = gps->totpoints - 1; - - for (int i = 0; i < gps->totpoints / 2; i++) { - bGPDspoint *point, *point2; - bGPDspoint pt; - - /* save first point */ - point = &gps->points[i]; - pt.x = point->x; - pt.y = point->y; - pt.z = point->z; - pt.flag = point->flag; - pt.pressure = point->pressure; - pt.strength = point->strength; - pt.time = point->time; - copy_v4_v4(pt.vert_color, point->vert_color); - - /* replace first point with last point */ - point2 = &gps->points[end]; - point->x = point2->x; - point->y = point2->y; - point->z = point2->z; - point->flag = point2->flag; - point->pressure = point2->pressure; - point->strength = point2->strength; - point->time = point2->time; - copy_v4_v4(point->vert_color, point2->vert_color); - - /* replace last point with first saved before */ - point = &gps->points[end]; - point->x = pt.x; - point->y = pt.y; - point->z = pt.z; - point->flag = pt.flag; - point->pressure = pt.pressure; - point->strength = pt.strength; - point->time = pt.time; - copy_v4_v4(point->vert_color, pt.vert_color); - - end--; + if (GPENCIL_STROKE_TYPE_BEZIER(gps)) { + bGPDcurve *gpc = gps->editcurve; + + int end = gpc->tot_curve_points - 1; + for (int i = 0; i < gpc->tot_curve_points / 2; i++) { + bGPDcurve_point *cpt_first = &gpc->curve_points[i]; + bGPDcurve_point *cpt_last = &gpc->curve_points[end]; + bGPDcurve_point temp; + + memcpy(&temp.bezt, &cpt_first->bezt, sizeof(BezTriple)); + temp.pressure = cpt_first->pressure; + temp.strength = cpt_first->strength; + temp.point_index = cpt_first->point_index; + temp.flag = cpt_first->flag; + temp.uv_fac = cpt_first->uv_fac; + temp.uv_rot = cpt_first->uv_rot; + copy_v2_v2(temp.uv_fill, cpt_first->uv_fill); + copy_v4_v4(temp.vert_color, cpt_first->vert_color); + + memcpy(&cpt_first->bezt, &cpt_last->bezt, sizeof(BezTriple)); + gpencil_flip_beztriple(&cpt_first->bezt); + cpt_first->pressure = cpt_last->pressure; + cpt_first->strength = cpt_last->strength; + cpt_first->point_index = cpt_last->point_index; + cpt_first->flag = cpt_last->flag; + cpt_first->uv_fac = cpt_last->uv_fac; + cpt_first->uv_rot = cpt_last->uv_rot; + copy_v2_v2(cpt_first->uv_fill, cpt_last->uv_fill); + copy_v4_v4(cpt_first->vert_color, cpt_last->vert_color); + + memcpy(&cpt_last->bezt, &temp.bezt, sizeof(BezTriple)); + gpencil_flip_beztriple(&cpt_last->bezt); + cpt_last->pressure = temp.pressure; + cpt_last->strength = temp.strength; + cpt_last->point_index = temp.point_index; + cpt_last->flag = temp.flag; + cpt_last->uv_fac = temp.uv_fac; + cpt_last->uv_rot = temp.uv_rot; + copy_v2_v2(cpt_last->uv_fill, temp.uv_fill); + copy_v4_v4(cpt_last->vert_color, temp.vert_color); + + end--; + } + } + else { + int end = gps->totpoints - 1; + + for (int i = 0; i < gps->totpoints / 2; i++) { + bGPDspoint *point, *point2; + bGPDspoint pt; + + /* save first point */ + point = &gps->points[i]; + pt.x = point->x; + pt.y = point->y; + pt.z = point->z; + pt.flag = point->flag; + pt.pressure = point->pressure; + pt.strength = point->strength; + pt.time = point->time; + copy_v4_v4(pt.vert_color, point->vert_color); + + /* replace first point with last point */ + point2 = &gps->points[end]; + point->x = point2->x; + point->y = point2->y; + point->z = point2->z; + point->flag = point2->flag; + point->pressure = point2->pressure; + point->strength = point2->strength; + point->time = point2->time; + copy_v4_v4(point->vert_color, point2->vert_color); + + /* replace last point with first saved before */ + point = &gps->points[end]; + point->x = pt.x; + point->y = pt.y; + point->z = pt.z; + point->flag = pt.flag; + point->pressure = pt.pressure; + point->strength = pt.strength; + point->time = pt.time; + copy_v4_v4(point->vert_color, pt.vert_color); + + end--; + } } } @@ -2901,7 +2956,7 @@ static void gpencil_stroke_join_islands(bGPdata *gpd, /* add new stroke at head */ BLI_addhead(&gpf->strokes, join_stroke); /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, join_stroke); + BKE_gpencil_stroke_geometry_update(gpd, join_stroke, GP_GEO_UPDATE_DEFAULT); /* remove first stroke */ BLI_remlink(&gpf->strokes, gps_first); @@ -3053,7 +3108,7 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, } else { /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, new_stroke); + BKE_gpencil_stroke_geometry_update(gpd, new_stroke, GP_GEO_UPDATE_DEFAULT); if (next_stroke) { BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); @@ -3137,10 +3192,10 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, sizeof(bGPDcurve_point) * island_length); BKE_gpencil_editcurve_recalculate_handles(new_stroke); - new_stroke->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; + BKE_gpencil_curve_sync_selection(gpd, new_stroke); /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, new_stroke); + BKE_gpencil_stroke_geometry_update(gpd, new_stroke, GP_GEO_UPDATE_DEFAULT); if (next_stroke) { BLI_insertlinkbefore(&gpf->strokes, next_stroke, new_stroke); @@ -3170,10 +3225,10 @@ void BKE_gpencil_curve_delete_tagged_points(bGPdata *gpd, sizeof(bGPDcurve_point) * first_tot_points); BKE_gpencil_editcurve_recalculate_handles(gps_last); - gps_last->flag |= GP_STROKE_NEEDS_CURVE_UPDATE; + BKE_gpencil_curve_sync_selection(gpd, gps_last); /* Calc geometry data. */ - BKE_gpencil_stroke_geometry_update(gpd, gps_last); + BKE_gpencil_stroke_geometry_update(gpd, gps_last, GP_GEO_UPDATE_DEFAULT); /* remove first one */ BLI_remlink(&gpf->strokes, gps_first); @@ -3241,7 +3296,6 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, { bGPDspoint point; bGPDspoint *pt; - int i; const float delta[3] = {1.0f, 1.0f, 1.0f}; float deltatime = 0.0f; @@ -3250,6 +3304,11 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, return; } + /* Cannot join strokes of different types for now... */ + if (GPENCIL_STROKE_TYPE_BEZIER(gps_a) != GPENCIL_STROKE_TYPE_BEZIER(gps_b)) { + return; + } + if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0)) { return; } @@ -3302,28 +3361,52 @@ void BKE_gpencil_stroke_join(bGPDstroke *gps_a, BKE_gpencil_stroke_flip(gps_b); } - /* don't visibly link the first and last points? */ - if (leave_gaps) { - /* 1st: add one tail point to start invisible area */ - point = gps_a->points[gps_a->totpoints - 1]; - deltatime = point.time; + const float thickness_ratio = (fit_thickness && gps_a->thickness > 0.0f) ? + (float)gps_b->thickness / (float)gps_a->thickness : + 1.0f; + + if (GPENCIL_STROKE_TYPE_BEZIER(gps_a)) { + /* TODO: Support leave gaps. */ + bGPDcurve *gpc_a = gps_a->editcurve; + bGPDcurve *gpc_b = gps_b->editcurve; - gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f); + int old_num_points = gpc_a->tot_curve_points; + gpc_a->tot_curve_points += gpc_b->tot_curve_points; + gpc_a->curve_points = MEM_recallocN(gpc_a->curve_points, + sizeof(bGPDcurve_point) * gpc_a->tot_curve_points); - /* 2nd: add one head point to finish invisible area */ - point = gps_b->points[0]; - gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime); + memcpy(gpc_a->curve_points + old_num_points, + gpc_b->curve_points, + sizeof(bGPDcurve_point) * gpc_b->tot_curve_points); + /* TODO: copy dvert curve data. */ + + /* Rescale other points. */ + for (int i = old_num_points; i < gpc_a->tot_curve_points; i++) { + bGPDcurve_point *cpt = &gpc_a->curve_points[i]; + cpt->pressure *= thickness_ratio; + } } + else { + /* don't visibly link the first and last points? */ + if (leave_gaps) { + /* 1st: add one tail point to start invisible area */ + point = gps_a->points[gps_a->totpoints - 1]; + deltatime = point.time; - const float ratio = (fit_thickness && gps_a->thickness > 0.0f) ? - (float)gps_b->thickness / (float)gps_a->thickness : - 1.0f; + gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f); - /* 3rd: add all points */ - for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { - MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL; - gpencil_stroke_copy_point( - gps_a, dvert, pt, delta, pt->pressure * ratio, pt->strength, deltatime); + /* 2nd: add one head point to finish invisible area */ + point = gps_b->points[0]; + gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime); + } + + /* 3rd: add all points */ + for (int i = 0; i < gps_b->totpoints && pt; i++) { + pt = &gps_b->points[i]; + MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL; + gpencil_stroke_copy_point( + gps_a, dvert, pt, delta, pt->pressure * thickness_ratio, pt->strength, deltatime); + } } } @@ -3556,7 +3639,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, } /* Update the geometry of the stroke. */ - BKE_gpencil_stroke_geometry_update(gpd, gps); + BKE_gpencil_stroke_geometry_update(gpd, gps, GP_GEO_UPDATE_DEFAULT); } /** @@ -4067,7 +4150,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, MEM_freeN(perimeter_points); /* Triangles cache needs to be recalculated. */ - BKE_gpencil_stroke_geometry_update(gpd, perimeter_stroke); + BKE_gpencil_stroke_geometry_update(gpd, perimeter_stroke, GP_GEO_UPDATE_DEFAULT); perimeter_stroke->flag |= GP_STROKE_SELECT | GP_STROKE_CYCLIC; |