[Bf-blender-cvs] [3626cb3c75c] temp-gpencil-bezier-v2: WIP: sculpt curves
Falk David
noreply at git.blender.org
Fri Feb 12 01:18:21 CET 2021
Commit: 3626cb3c75c2766e1d794fcd201c205a4a855c01
Author: Falk David
Date: Wed Feb 10 00:44:44 2021 +0100
Branches: temp-gpencil-bezier-v2
https://developer.blender.org/rB3626cb3c75c2766e1d794fcd201c205a4a855c01
WIP: sculpt curves
===================================================================
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
===================================================================
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
index 32fbd4af880..0c5eaabe8c9 100644
--- a/source/blender/blenkernel/intern/gpencil_curve.c
+++ b/source/blender/blenkernel/intern/gpencil_curve.c
@@ -56,15 +56,6 @@
#include "DEG_depsgraph_query.h"
-/* We treat pressure, strength and vertex colors as dimensions in the curve fitting like the
- * position. But this means that e.g. a high pressure will change the shape of the
- * higher-dimensional fitted curve which will in turn change the shape of the projected
- * 3-dimensional curve. But we don't really want the pressure or something else than the position
- * to influence the shape. So this COORD_FITTING_INFLUENCE will "dampen" the effect of the other
- * attributes affecting the shape. Ideally, we fit the other attributes separate from the position.
- */
-#define COORD_FITTING_INFLUENCE 20.0f
-
/* -------------------------------------------------------------------- */
/** \name Convert to curve object
* \{ */
@@ -573,29 +564,76 @@ void BKE_gpencil_convert_curve(Main *bmain,
/** \name Edit-Curve Kernel Functions
* \{ */
+typedef struct tCurveFitPoint {
+ float x, y, z;
+ float pressure;
+ float strength;
+ float color[4];
+} tCurveFitPoint;
+
+#define CURVE_FIT_POINT_DIM 9
+
+/* We treat pressure, strength and vertex colors as dimensions in the curve fitting like the
+ * position. But this means that e.g. a high pressure will change the shape of the
+ * higher-dimensional fitted curve which will in turn change the shape of the projected
+ * 3-dimensional curve. But we don't really want the pressure or something else than the position
+ * to influence the shape. So this COORD_FITTING_INFLUENCE will "dampen" the effect of the other
+ * attributes affecting the shape. Ideally, we fit the other attributes separate from the position.
+ */
+#define COORD_FITTING_INFLUENCE 20.0f
+
typedef struct tGPCurveSegment {
+ struct tGPCurveSegment *next, *prev;
+
float *point_array;
uint32_t point_array_len;
- uint32_t start_idx, end_idx;
- uint32_t length;
+ bGPDcurve_point *curve_points;
float *cubic_array;
uint32_t cubic_array_len;
+
uint32_t *cubic_orig_index;
uint32_t *corners_index_array;
uint32_t corners_index_len;
-} tGPCurvePointIsland;
+
+} tGPCurveSegment;
+
+static void gpencil_free_curve_segment(tGPCurveSegment *tcs)
+{
+ if (tcs == NULL) {
+ return;
+ }
+
+ if (tcs->point_array != NULL) {
+ MEM_freeN(tcs->point_array);
+ }
+ if (tcs->curve_points != NULL) {
+ MEM_freeN(tcs->curve_points);
+ }
+ if (tcs->cubic_array != NULL) {
+ MEM_freeN(tcs->cubic_array);
+ }
+ if (tcs->cubic_orig_index != NULL) {
+ MEM_freeN(tcs->cubic_orig_index);
+ }
+ if (tcs->corners_index_array != NULL) {
+ MEM_freeN(tcs->corners_index_array);
+ }
+
+ MEM_freeN(tcs);
+}
static int gpencil_count_tagged_curve_segments(bGPDstroke *gps)
{
bGPDcurve *gpc = gps->editcurve;
/* Handle single point edgecase. */
if (gpc->tot_curve_points == 1) {
- return (&gps->points[0]->flag & GP_SPOINT_TAG) ? 1 : 0;
+ return (gps->points[0].flag & GP_SPOINT_TAG) ? 1 : 0;
}
/* Iterate over segments. */
const int tot_segments = gpc->tot_curve_points - 1;
+ int count = 0;
for (int i = 0; i < tot_segments; i++) {
int start_idx = gpc->curve_points[i].point_index;
int end_idx = gpc->curve_points[i + 1].point_index;
@@ -704,6 +742,91 @@ static bGPDcurve *gpencil_stroke_editcurve_generate_edgecases(bGPDstroke *gps)
return NULL;
}
+static tGPCurveSegment *gpencil_generate_curve_segment(bGPDstroke *gps,
+ const float diag_length,
+ const float error_threshold,
+ const float corner_angle,
+ const uint32_t start_idx,
+ const uint32_t end_idx,
+ const uint32_t offset)
+{
+ const uint32_t length = end_idx - start_idx + 1;
+
+ tGPCurveSegment *tcs = MEM_callocN(sizeof(tGPCurveSegment), __func__);
+ tcs->point_array_len = length * CURVE_FIT_POINT_DIM;
+ tcs->point_array = MEM_callocN(sizeof(float) * tcs->point_array_len, __func__);
+
+ float tmp_vec[3];
+ for (int i = 0; i < length; i++) {
+ bGPDspoint *pt = &gps->points[i + start_idx];
+ int row = i * CURVE_FIT_POINT_DIM;
+ tCurveFitPoint *cfpt = (tCurveFitPoint *)&tcs->point_array[row];
+ /* normalize coordinate to 0..1 */
+ sub_v3_v3v3(tmp_vec, &pt->x, gps->boundbox_min);
+ mul_v3_v3fl(&cfpt->x, tmp_vec, COORD_FITTING_INFLUENCE / diag_length);
+ cfpt->pressure = pt->pressure / diag_length;
+
+ /* strength and color are already normalized */
+ cfpt->strength = pt->strength / diag_length;
+ mul_v4_v4fl(cfpt->color, pt->vert_color, 1.0f / diag_length);
+ }
+
+ int r = curve_fit_cubic_to_points_refit_fl(tcs->point_array,
+ length,
+ CURVE_FIT_POINT_DIM,
+ error_threshold,
+ CURVE_FIT_CALC_HIGH_QUALIY,
+ NULL,
+ 0,
+ corner_angle,
+ &tcs->cubic_array,
+ &tcs->cubic_array_len,
+ &tcs->cubic_orig_index,
+ &tcs->corners_index_array,
+ &tcs->corners_index_len);
+
+ if (r != 0 || tcs->cubic_array_len < 1) {
+ gpencil_free_curve_segment(tcs);
+ return NULL;
+ }
+
+ tcs->curve_points = MEM_callocN(sizeof(bGPDcurve_point) * tcs->cubic_array_len, __func__);
+
+ for (int i = 0; i < tcs->cubic_array_len; i++) {
+ bGPDcurve_point *cpt = &tcs->curve_points[i];
+ BezTriple *bezt = &cpt->bezt;
+ tCurveFitPoint *curve_point = (tCurveFitPoint *)&tcs->cubic_array[i * 3 * CURVE_FIT_POINT_DIM];
+
+ for (int j = 0; j < 3; j++) {
+ float *bez = &curve_point[j].x;
+ madd_v3_v3v3fl(bezt->vec[j], gps->boundbox_min, bez, diag_length / COORD_FITTING_INFLUENCE);
+ }
+
+ tCurveFitPoint *ctrl_point = &curve_point[1];
+ cpt->pressure = ctrl_point->pressure * diag_length;
+ cpt->strength = ctrl_point->strength * diag_length;
+ mul_v4_v4fl(cpt->vert_color, ctrl_point->color, diag_length);
+
+ /* default handle type */
+ bezt->h1 = HD_ALIGN;
+ bezt->h2 = HD_ALIGN;
+
+ cpt->point_index = tcs->cubic_orig_index[i] + offset;
+ }
+
+ /* Set handle type to HD_FREE for corner handles. */
+ if (tcs->corners_index_len > 0 && tcs->corners_index_array != NULL) {
+ for (int i = 0; i < tcs->corners_index_len; i++) {
+ bGPDcurve_point *cpt = &tcs->curve_points[tcs->corners_index_array[i]];
+ BezTriple *bezt = &cpt->bezt;
+ bezt->h1 = HD_FREE;
+ bezt->h2 = HD_FREE;
+ }
+ }
+
+ return tcs;
+}
+
/**
* Creates a bGPDcurve by doing a cubic curve fitting on the grease pencil stroke points.
*/
@@ -837,40 +960,107 @@ bGPDcurve *BKE_gpencil_stroke_editcurve_regenerate(bGPDstroke *gps,
bGPDcurve *gpc = gps->editcurve;
const int tot_segments = gpc->tot_curve_points - 1;
- int point_offset = 0;
- for (int i = 0; i < tot_segments; i++) {
- int start_idx = gpc->curve_points[i].point_index;
- int end_idx = gpc->curve_points[i + 1].point_index;
- int segment_length = end_idx - start_idx + 1;
- bool regen = false;
- for (int j = start_idx; j <= end_idx; j++) {
- bGPDspoint *pt = &gps->points[j];
- if ((pt->flag & GP_SPOINT_TAG)) {
- /* Regenerate this segment. */
+ float diag_length = len_v3v3(gps->boundbox_min, gps->boundbox_max);
- /* Allocate points */
+ ListBase curve_segments = {NULL, NULL};
- /* Call curve_fit_nd */
+ /* TODO: If the stroke is cyclic we need to move the start of the curve to the last curve point
+ * that is not tagged. */
- /* Append all the resulting curve segments to listbase */
+ tGPCurveSegment *tcs;
+ int new_tot_curve_points = 0, pt_offset = 0;
+ for (int i = 0; i < tot_segments; i++) {
+ int start_idx = gpc->curve_points[i].point_index;
+ bGPDspoint *start_pt = &gps->points[start_idx];
- regen = true;
+ bool regen = false;
+ if ((start_pt->flag & GP_SPOINT_TAG)) {
+ regen = true;
+ }
+
+ /* Find end point. */
+ int end_idx = start_idx;
+ for (int j = i + 1; j < gpc->tot_curve_points; j++, i++) {
+ end_idx = gpc->curve_points[j].point_index;
+ bGPDspoint *pt = &gps->points[end_idx];
+ if ((pt->flag & GP_SPOINT_TAG) == 0) {
break;
}
+ regen = true;
}
if (!regen) {
- /* Save this segment. */
+ /* Check if there are marked points between the control points. If there are, the segment
+ * must be regenerated. */
+ for (int k = start_idx + 1; k < end_idx; k++) {
+ bGPDspoint *pt = &gps->points[k];
+ if ((pt->flag & GP_SPOINT_TAG)) {
+ regen = true;
+ tcs = gpencil_generate_curve_segment(
+ gps, diag_length, error_threshold, corner_angle, start_idx, end_idx, pt_offset);
+ break;
+ }
+ }
+ }
+ else {
+ /* Regenerate this segment. */
+ regen = true;
+ tcs = gpencil_generate_curve_segment(
+ gps, diag_length, error_threshold, corner_angle, start_idx, end_idx, pt_offset);
+ }
- /* append curve segment to list base */
+ if (!regen) {
+ int start_cidx = i;
+ /* Find end point. This time for curve points that have not moved. */
+ int end_cidx = start_cidx;
+ for (int j = start_cidx + 1; j < gpc->tot_curve_points; j++, i++) {
+ bGPDspoint *pt = &gps->points[gpc->curve_points[j].point_index];
+ if (pt->flag & GP_SPOINT_TAG) {
+ break;
+ }
+ end_cidx = j;
+ }
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list