Commit: f16a50ba946ae4ddea18d4f7058fef3a359078b8 Author: Falk David Date: Wed Jul 22 16:10:25 2020 +0200 Branches: soc-2020-greasepencil-curve https://developer.blender.org/rBf16a50ba946ae4ddea18d4f7058fef3a359078b8
GPencil: Implement adaptive editcurve resolution With adaptive curve resolution the arclength of a curve segment is used to calculate the number of points between two control points. This means that in general the stroke points are more spaced out. =================================================================== M release/scripts/startup/bl_ui/space_view3d.py M source/blender/blenkernel/BKE_gpencil_curve.h M source/blender/blenkernel/intern/gpencil_curve.c M source/blender/blenkernel/intern/gpencil_geom.c M source/blender/editors/gpencil/gpencil_edit_curve.c M source/blender/editors/gpencil/gpencil_select.c M source/blender/editors/gpencil/gpencil_utils.c M source/blender/makesdna/DNA_gpencil_types.h M source/blender/makesrna/intern/rna_gpencil.c =================================================================== diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 007b8c933ce..0faca0b3413 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -6990,6 +6990,7 @@ class VIEW3D_PT_gpencil_curve_edit(Panel): layout = self.layout col = layout.column(align=True) + col.prop(gpd, "use_adaptive_curve_resolution") col.prop(gpd, "edit_curve_resolution") col.prop(gpd, "curve_edit_threshold") diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h index b066e901211..28791acc47a 100644 --- a/source/blender/blenkernel/BKE_gpencil_curve.h +++ b/source/blender/blenkernel/BKE_gpencil_curve.h @@ -50,7 +50,7 @@ void BKE_gpencil_editcurve_stroke_sync_selection(struct bGPDstroke *gps, struct void BKE_gpencil_stroke_editcurve_sync_selection(struct bGPDstroke *gps, struct bGPDcurve *gpc); void BKE_gpencil_strokes_selected_update_editcurve(struct bGPdata *gpd); void BKE_gpencil_strokes_selected_sync_selection_editcurve(struct bGPdata *gpd); -void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps); +void BKE_gpencil_stroke_update_geometry_from_editcurve(struct bGPDstroke *gps, const uint resolution, bool is_adaptive); void BKE_gpencil_editcurve_recalculate_handles(struct bGPDstroke *gps); void BKE_gpencil_editcurve_subdivide(struct bGPDstroke *gps, const int cuts); diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c index eb3c78f2827..e38c79f3a0f 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -665,6 +665,7 @@ static void gpencil_interpolate_fl_from_to( float *r = point_offset; for (int i = 0; i <= it; i++) { float fac = (float)i / (float)it; + // fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth *r = interpf(to, from, fac); r = POINTER_OFFSET(r, stride); } @@ -677,12 +678,27 @@ static void gpencil_interpolate_v4_from_to( float *r = point_offset; for (int i = 0; i <= it; i++) { float fac = (float)i / (float)it; + // fac = 3.0f * fac * fac - 2.0f * fac * fac * fac; // smooth interp_v4_v4v4(r, from, to, fac); r = POINTER_OFFSET(r, stride); } } -static void gpencil_calculate_stroke_points_curve_point( +static float gpencil_approximate_curve_segment_arclength(bGPDcurve_point *cpt_start, + bGPDcurve_point *cpt_end) +{ + BezTriple *bezt_start = &cpt_start->bezt; + BezTriple *bezt_end = &cpt_end->bezt; + + float chord_len = len_v3v3(bezt_start->vec[1], bezt_end->vec[1]); + float net_len = len_v3v3(bezt_start->vec[1], bezt_start->vec[2]); + net_len += len_v3v3(bezt_start->vec[2], bezt_end->vec[0]); + net_len += len_v3v3(bezt_end->vec[0], bezt_end->vec[1]); + + return (chord_len + net_len) / 2.0f; +} + +static void gpencil_calculate_stroke_points_curve_segment( bGPDcurve_point *cpt, bGPDcurve_point *cpt_next, float *points_offset, int resolu, int stride) { /* sample points on all 3 axis between two curve points */ @@ -714,51 +730,141 @@ static void gpencil_calculate_stroke_points_curve_point( stride); } -/** - * Recalculate stroke points with the editcurve of the stroke. - */ -void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps) +static float *gpencil_stroke_points_from_editcurve_adaptive_resolu( + bGPDcurve_point *curve_point_array, + int curve_point_array_len, + int resolution, + bool is_cyclic, + int *r_points_len) { - if (gps == NULL || gps->editcurve == NULL) { - return; + /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */ + const uint stride = sizeof(float[9]); + const uint cpt_last = curve_point_array_len - 1; + const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1; + int *segment_point_lengths = MEM_callocN(sizeof(int) * num_segments, __func__); + + uint points_len = 0; + for (int i = 0; i < cpt_last; i++) { + bGPDcurve_point *cpt = &curve_point_array[i]; + bGPDcurve_point *cpt_next = &curve_point_array[i + 1]; + float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next); + int segment_resolu = (int)floorf(arclen * resolution); + + segment_point_lengths[i] = segment_resolu; + points_len += segment_resolu; } - bGPDcurve *editcurve = gps->editcurve; - bGPDcurve_point *curve_point_array = editcurve->curve_points; - int curve_point_array_len = editcurve->tot_curve_points; - int resolu = editcurve->resolution; - bool is_cyclic = gps->flag & GP_STROKE_CYCLIC; + if (is_cyclic) { + bGPDcurve_point *cpt = &curve_point_array[cpt_last]; + bGPDcurve_point *cpt_next = &curve_point_array[0]; + float arclen = gpencil_approximate_curve_segment_arclength(cpt, cpt_next); + int segment_resolu = (int)floorf(arclen * resolution); - const uint array_last = curve_point_array_len - 1; + segment_point_lengths[cpt_last] = segment_resolu; + points_len += segment_resolu; + } + points_len += 1; + + float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__); + float *points_offset = &r_points[0][0]; + int point_index = 0; + for (int i = 0; i < cpt_last; i++) { + bGPDcurve_point *cpt_curr = &curve_point_array[i]; + bGPDcurve_point *cpt_next = &curve_point_array[i + 1]; + int segment_resolu = segment_point_lengths[i]; + gpencil_calculate_stroke_points_curve_segment( + cpt_curr, cpt_next, points_offset, segment_resolu, stride); + /* update the index */ + cpt_curr->point_index = point_index; + point_index += segment_resolu; + points_offset = POINTER_OFFSET(points_offset, segment_resolu * stride); + } + + bGPDcurve_point *cpt_curr = &curve_point_array[cpt_last]; + cpt_curr->point_index = point_index; + if (is_cyclic) { + bGPDcurve_point *cpt_next = &curve_point_array[0]; + int segment_resolu = segment_point_lengths[cpt_last]; + gpencil_calculate_stroke_points_curve_segment( + cpt_curr, cpt_next, points_offset, segment_resolu, stride); + } + + MEM_freeN(segment_point_lengths); + + *r_points_len = points_len; + return (float(*))r_points; +} + +/** + * Helper: calculate the points on a curve with a fixed resolution. + */ +static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point *curve_point_array, + int curve_point_array_len, + int resolution, + bool is_cyclic, + int *r_points_len) +{ /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */ const uint stride = sizeof(float[9]); - const uint resolu_stride = resolu * stride; + const uint array_last = curve_point_array_len - 1; + const uint resolu_stride = resolution * stride; const uint points_len = BKE_curve_calc_coords_axis_len( - curve_point_array_len, resolu, is_cyclic, false); + curve_point_array_len, resolution, is_cyclic, false); - float(*points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__); - float *points_offset = &points[0][0]; + float(*r_points)[9] = MEM_callocN((stride * points_len * (is_cyclic ? 2 : 1)), __func__); + float *points_offset = &r_points[0][0]; for (unsigned int i = 0; i < array_last; i++) { bGPDcurve_point *cpt_curr = &curve_point_array[i]; bGPDcurve_point *cpt_next = &curve_point_array[i + 1]; - gpencil_calculate_stroke_points_curve_point(cpt_curr, cpt_next, points_offset, resolu, stride); + gpencil_calculate_stroke_points_curve_segment( + cpt_curr, cpt_next, points_offset, resolution, stride); /* update the index */ - cpt_curr->point_index = i * resolu; + cpt_curr->point_index = i * resolution; points_offset = POINTER_OFFSET(points_offset, resolu_stride); } + bGPDcurve_point *cpt_curr = &curve_point_array[array_last]; + cpt_curr->point_index = array_last * resolution; if (is_cyclic) { - bGPDcurve_point *cpt_curr = &curve_point_array[array_last]; bGPDcurve_point *cpt_next = &curve_point_array[0]; + gpencil_calculate_stroke_points_curve_segment( + cpt_curr, cpt_next, points_offset, resolution, stride); + } + + *r_points_len = points_len; + return (float(*))r_points; +} + +/** + * Recalculate stroke points with the editcurve of the stroke. + */ +void BKE_gpencil_stroke_update_geometry_from_editcurve(bGPDstroke *gps, + const uint resolution, + bool adaptive) +{ + if (gps == NULL || gps->editcurve == NULL) { + return; + } - gpencil_calculate_stroke_points_curve_point(cpt_curr, cpt_next, points_offset, resolu, stride); + bGPDcurve *editcurve = gps->editcurve; + bGPDcurve_point *curve_point_array = editcurve->curve_points; + int curve_point_array_len = editcurve->tot_curve_points; + bool is_cyclic = gps->flag & GP_STROKE_CYCLIC; - cpt_curr->point_index = array_last * resolu; + int points_len = 0; + float(*points)[9] = NULL; + if (adaptive) { + points = (float(*)[9])gpencil_stroke_points_from_editcurve_adaptive_resolu( + curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len); } else { - bGPDcurve_point *cpt_curr = &curve_point_array[array_last]; - cpt_curr->point_index = array_last * resolu; + points = (float(*)[9])gpencil_stroke_points_from_editcurve_fixed_resolu( + curve_point_array, curve_point_array_len, resolution, is_cyclic, &points_len); + } + + if (points == NULL || points_len == 0) { + return; } /* resize stroke point array */ @@ -1012,7 +1118,7 @@ void BKE_gpencil_strokes_selected_update_editcurve(bGPdata *gpd) if (!(gps->flag & GP_STROKE_SELECT)) { continue; } - + / @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs