GPencil: Split Curve geometry functions to new file
authorAntonio Vazquez <blendergit@gmail.com>
Wed, 6 May 2020 16:13:59 +0000 (18:13 +0200)
committerAntonio Vazquez <blendergit@gmail.com>
Wed, 6 May 2020 16:14:05 +0000 (18:14 +0200)
This prepare the code for future curve editors

source/blender/blenkernel/BKE_gpencil_curve.h [new file with mode: 0644]
source/blender/blenkernel/BKE_gpencil_geom.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/gpencil_curve.c [new file with mode: 0644]
source/blender/blenkernel/intern/gpencil_geom.c
source/blender/editors/object/object_add.c
source/blender/makesrna/intern/rna_object_api.c

diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h
new file mode 100644 (file)
index 0000000..cf6f907
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+#ifndef __BKE_GPENCIL_CURVE_H__
+#define __BKE_GPENCIL_CURVE_H__
+
+/** \file
+ * \ingroup bke
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Main;
+struct Object;
+struct Scene;
+
+void BKE_gpencil_convert_curve(struct Main *bmain,
+                               struct Scene *scene,
+                               struct Object *ob_gp,
+                               struct Object *ob_cu,
+                               const bool gpencil_lines,
+                               const bool use_collections,
+                               const bool only_stroke);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*  __BKE_GPENCIL_CURVE_H__ */
index 8c52e6d458ba0935966e203a4bc8def50449c7d2..b26016aa26c9dc05d44c1f2b9b00b62bbc8bb129 100644 (file)
@@ -98,14 +98,6 @@ bool BKE_gpencil_stroke_shrink(struct bGPDstroke *gps, const float dist);
 
 float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
 
 
 float BKE_gpencil_stroke_length(const struct bGPDstroke *gps, bool use_3d);
 
-void BKE_gpencil_convert_curve(struct Main *bmain,
-                               struct Scene *scene,
-                               struct Object *ob_gp,
-                               struct Object *ob_cu,
-                               const bool gpencil_lines,
-                               const bool use_collections,
-                               const bool only_stroke);
-
 #ifdef __cplusplus
 }
 #endif
 #ifdef __cplusplus
 }
 #endif
index 07c7767f348b45e61c44baa4c316a0e05b6d8bcb..9716e5f5d3f51ef0aa27b75d4de89b3dc47a4789 100644 (file)
@@ -122,6 +122,7 @@ set(SRC
   intern/font.c
   intern/freestyle.c
   intern/gpencil.c
   intern/font.c
   intern/freestyle.c
   intern/gpencil.c
+  intern/gpencil_curve.c
   intern/gpencil_geom.c
   intern/gpencil_modifier.c
   intern/hair.c
   intern/gpencil_geom.c
   intern/gpencil_modifier.c
   intern/hair.c
@@ -308,6 +309,7 @@ set(SRC
   BKE_freestyle.h
   BKE_global.h
   BKE_gpencil.h
   BKE_freestyle.h
   BKE_global.h
   BKE_gpencil.h
+  BKE_gpencil_curve.h
   BKE_gpencil_geom.h
   BKE_gpencil_modifier.h
   BKE_hair.h
   BKE_gpencil_geom.h
   BKE_gpencil_modifier.h
   BKE_hair.h
diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c
new file mode 100644 (file)
index 0000000..99fbe31
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2008, Blender Foundation
+ * This is a new part of Blender
+ */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <math.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BKE_collection.h"
+#include "BKE_curve.h"
+#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+
+#include "DEG_depsgraph_query.h"
+
+/* Helper: Check materials with same color. */
+static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
+{
+  Material *ma = NULL;
+  float color_cu[4];
+  linearrgb_to_srgb_v3_v3(color_cu, color);
+  float hsv1[4];
+  rgb_to_hsv_v(color_cu, hsv1);
+  hsv1[3] = color[3];
+
+  for (int i = 1; i <= ob_gp->totcol; i++) {
+    ma = BKE_object_material_get(ob_gp, i);
+    MaterialGPencilStyle *gp_style = ma->gp_style;
+    /* Check color with small tolerance (better in HSV). */
+    float hsv2[4];
+    rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
+    hsv2[3] = gp_style->fill_rgba[3];
+    if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
+        (compare_v4v4(hsv1, hsv2, 0.01f))) {
+      *r_mat = ma;
+      return i - 1;
+    }
+  }
+
+  *r_mat = NULL;
+  return -1;
+}
+
+/* Helper: Add gpencil material using curve material as base. */
+static Material *gpencil_add_from_curve_material(Main *bmain,
+                                                 Object *ob_gp,
+                                                 const float cu_color[4],
+                                                 const bool gpencil_lines,
+                                                 const bool fill,
+                                                 int *r_idx)
+{
+  Material *mat_gp = BKE_gpencil_object_material_new(
+      bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
+  MaterialGPencilStyle *gp_style = mat_gp->gp_style;
+
+  /* Stroke color. */
+  if (gpencil_lines) {
+    ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
+    gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+  }
+  else {
+    linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
+    gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+  }
+
+  /* Fill color. */
+  linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
+  /* Fill is false if the original curve hasn't material assigned, so enable it. */
+  if (fill) {
+    gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+  }
+
+  /* Check at least one is enabled. */
+  if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
+      ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
+    gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+  }
+
+  return mat_gp;
+}
+
+/* Helper: Create new stroke section. */
+static void gpencil_add_new_points(bGPDstroke *gps,
+                                   float *coord_array,
+                                   float pressure,
+                                   int init,
+                                   int totpoints,
+                                   const float init_co[3],
+                                   bool last)
+{
+  for (int i = 0; i < totpoints; i++) {
+    bGPDspoint *pt = &gps->points[i + init];
+    copy_v3_v3(&pt->x, &coord_array[3 * i]);
+    /* Be sure the last point is not on top of the first point of the curve or
+     * the close of the stroke will produce glitches. */
+    if ((last) && (i > 0) && (i == totpoints - 1)) {
+      float dist = len_v3v3(init_co, &pt->x);
+      if (dist < 0.1f) {
+        /* Interpolate between previous point and current to back slightly. */
+        bGPDspoint *pt_prev = &gps->points[i + init - 1];
+        interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
+      }
+    }
+
+    pt->pressure = pressure;
+    pt->strength = 1.0f;
+  }
+}
+
+/* Helper: Get the first collection that includes the object. */
+static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
+{
+  Collection *mycol = NULL;
+  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
+    LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
+      if ((mycol == NULL) && (cob->ob == ob)) {
+        mycol = collection;
+      }
+    }
+  }
+  FOREACH_SCENE_COLLECTION_END;
+
+  return mycol;
+}
+
+/* Helper: Convert one spline to grease pencil stroke. */
+static void gpencil_convert_spline(Main *bmain,
+                                   Object *ob_gp,
+                                   Object *ob_cu,
+                                   const bool gpencil_lines,
+                                   const bool only_stroke,
+                                   bGPDframe *gpf,
+                                   Nurb *nu)
+{
+  Curve *cu = (Curve *)ob_cu->data;
+  bool cyclic = true;
+
+  /* Create Stroke. */
+  bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
+  gps->thickness = 10.0f;
+  gps->fill_opacity_fac = 1.0f;
+  gps->hardeness = 1.0f;
+  gps->uv_scale = 1.0f;
+
+  ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
+  ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
+  gps->inittime = 0.0f;
+
+  gps->flag &= ~GP_STROKE_SELECT;
+  gps->flag |= GP_STROKE_3DSPACE;
+
+  gps->mat_nr = 0;
+  /* Count total points
+   * The total of points must consider that last point of each segment is equal to the first
+   * point of next segment.
+   */
+  int totpoints = 0;
+  int segments = 0;
+  int resolu = nu->resolu + 1;
+  segments = nu->pntsu;
+  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+    segments--;
+    cyclic = false;
+  }
+  totpoints = (resolu * segments) - (segments - 1);
+
+  /* Materials
+   * Notice: The color of the material is the color of viewport and not the final shader color.
+   */
+  Material *mat_gp = NULL;
+  bool fill = true;
+  /* Check if grease pencil has a material with same color.*/
+  float color[4];
+  if ((cu->mat) && (*cu->mat)) {
+    Material *mat_cu = *cu->mat;
+    copy_v4_v4(color, &mat_cu->r);
+  }
+  else {
+    /* Gray (unassigned from SVG add-on) */
+    zero_v4(color);
+    add_v3_fl(color, 0.6f);
+    color[3] = 1.0f;
+    fill = false;
+  }
+
+  /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
+   * there is only one color, the stroke must not be closed, fill to false and use for
+   * stroke the fill color.
+   */
+  bool do_stroke = false;
+  if (ob_cu->totcol == 1) {
+    Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
+    if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
+      do_stroke = true;
+    }
+  }
+
+  int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
+  if ((ob_cu->totcol > 0) && (r_idx < 0)) {
+    Material *mat_curve = BKE_object_material_get(ob_cu, 1);
+    mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
+
+    if ((mat_curve) && (mat_curve->gp_style != NULL)) {
+      MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
+      MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
+
+      copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
+      gp_style_gp->fill_style = gp_style_cur->fill_style;
+      gp_style_gp->mix_factor = gp_style_cur->mix_factor;
+    }
+
+    /* If object has more than 1 material, use second material for stroke color. */
+    if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
+      mat_curve = BKE_object_material_get(ob_cu, 2);
+      if (mat_curve) {
+        linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+        mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+      }
+    }
+    else if ((only_stroke) || (do_stroke)) {
+      /* Also use the first color if the fill is none for stroke color. */
+      if (ob_cu->totcol > 0) {
+        mat_curve = BKE_object_material_get(ob_cu, 1);
+        if (mat_curve) {
+          copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
+          mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
+          /* Set fill and stroke depending of curve type (3D or 2D). */
+          if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
+            mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
+            mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
+          }
+          else {
+            mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
+            mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
+          }
+        }
+      }
+    }
+  }
+  CLAMP_MIN(r_idx, 0);
+
+  /* Assign material index to stroke. */
+  gps->mat_nr = r_idx;
+
+  /* Add stroke to frame.*/
+  BLI_addtail(&gpf->strokes, gps);
+
+  float *coord_array = NULL;
+  float init_co[3];
+
+  switch (nu->type) {
+    case CU_POLY: {
+      /* Allocate memory for storage points. */
+      gps->totpoints = nu->pntsu;
+      gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+      /* Increase thickness for this type. */
+      gps->thickness = 10.0f;
+
+      /* Get all curve points */
+      for (int s = 0; s < gps->totpoints; s++) {
+        BPoint *bp = &nu->bp[s];
+        bGPDspoint *pt = &gps->points[s];
+        copy_v3_v3(&pt->x, bp->vec);
+        pt->pressure = bp->radius;
+        pt->strength = 1.0f;
+      }
+      break;
+    }
+    case CU_BEZIER: {
+      /* Allocate memory for storage points. */
+      gps->totpoints = totpoints;
+      gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+      int init = 0;
+      resolu = nu->resolu + 1;
+      segments = nu->pntsu;
+      if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
+        segments--;
+      }
+      /* Get all interpolated curve points of Beziert */
+      for (int s = 0; s < segments; s++) {
+        int inext = (s + 1) % nu->pntsu;
+        BezTriple *prevbezt = &nu->bezt[s];
+        BezTriple *bezt = &nu->bezt[inext];
+        bool last = (bool)(s == segments - 1);
+
+        coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
+
+        for (int j = 0; j < 3; j++) {
+          BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
+                                        prevbezt->vec[2][j],
+                                        bezt->vec[0][j],
+                                        bezt->vec[1][j],
+                                        coord_array + j,
+                                        resolu - 1,
+                                        3 * sizeof(float));
+        }
+        /* Save first point coordinates. */
+        if (s == 0) {
+          copy_v3_v3(init_co, &coord_array[0]);
+        }
+        /* Add points to the stroke */
+        gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
+        /* Free memory. */
+        MEM_SAFE_FREE(coord_array);
+
+        /* As the last point of segment is the first point of next segment, back one array
+         * element to avoid duplicated points on the same location.
+         */
+        init += resolu - 1;
+      }
+      break;
+    }
+    case CU_NURBS: {
+      if (nu->pntsv == 1) {
+
+        int nurb_points;
+        if (nu->flagu & CU_NURB_CYCLIC) {
+          resolu++;
+          nurb_points = nu->pntsu * resolu;
+        }
+        else {
+          nurb_points = (nu->pntsu - 1) * resolu;
+        }
+        /* Get all curve points. */
+        coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
+        BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
+
+        /* Allocate memory for storage points. */
+        gps->totpoints = nurb_points - 1;
+        gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
+
+        /* Add points. */
+        gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
+
+        MEM_SAFE_FREE(coord_array);
+      }
+      break;
+    }
+    default: {
+      break;
+    }
+  }
+  /* Cyclic curve, close stroke. */
+  if ((cyclic) && (!do_stroke)) {
+    BKE_gpencil_stroke_close(gps);
+  }
+
+  /* Recalc fill geometry. */
+  BKE_gpencil_stroke_geometry_update(gps);
+}
+
+/* Convert a curve object to grease pencil stroke.
+ *
+ * \param bmain: Main thread pointer
+ * \param scene: Original scene.
+ * \param ob_gp: Grease pencil object to add strokes.
+ * \param ob_cu: Curve to convert.
+ * \param gpencil_lines: Use lines for strokes.
+ * \param use_collections: Create layers using collection names.
+ * \param only_stroke: The material must be only stroke without fill.
+ */
+void BKE_gpencil_convert_curve(Main *bmain,
+                               Scene *scene,
+                               Object *ob_gp,
+                               Object *ob_cu,
+                               const bool gpencil_lines,
+                               const bool use_collections,
+                               const bool only_stroke)
+{
+  if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
+    return;
+  }
+
+  Curve *cu = (Curve *)ob_cu->data;
+  bGPdata *gpd = (bGPdata *)ob_gp->data;
+  bGPDlayer *gpl = NULL;
+
+  /* If the curve is empty, cancel. */
+  if (cu->nurb.first == NULL) {
+    return;
+  }
+
+  /* Check if there is an active layer. */
+  if (use_collections) {
+    Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
+    if (collection != NULL) {
+      gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
+      if (gpl == NULL) {
+        gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
+      }
+    }
+  }
+
+  if (gpl == NULL) {
+    gpl = BKE_gpencil_layer_active_get(gpd);
+    if (gpl == NULL) {
+      gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
+    }
+  }
+
+  /* Check if there is an active frame and add if needed. */
+  bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
+
+  /* Read all splines of the curve and create a stroke for each. */
+  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
+    gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
+  }
+
+  /* Tag for recalculation */
+  DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+}
+
+/** \} */
index 413e28c431bedf3ab164ffafef88384e802dff4a..d200e4e3a1534f09fe7b6ff833fbe347908b66ee 100644 (file)
 #include "BLI_math_vector.h"
 #include "BLI_polyfill_2d.h"
 
 #include "BLI_math_vector.h"
 #include "BLI_polyfill_2d.h"
 
-#include "BLT_translation.h"
-
 #include "DNA_gpencil_types.h"
 #include "DNA_meshdata_types.h"
 
 #include "DNA_gpencil_types.h"
 #include "DNA_meshdata_types.h"
 
-#include "BKE_collection.h"
-#include "BKE_curve.h"
 #include "BKE_deform.h"
 #include "BKE_gpencil.h"
 #include "BKE_gpencil_geom.h"
 #include "BKE_deform.h"
 #include "BKE_gpencil.h"
 #include "BKE_gpencil_geom.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
 #include "BKE_object.h"
 
 #include "DEG_depsgraph_query.h"
 #include "BKE_object.h"
 
 #include "DEG_depsgraph_query.h"
@@ -1586,404 +1580,6 @@ void BKE_gpencil_stroke_merge_distance(bGPDframe *gpf,
   BKE_gpencil_stroke_geometry_update(gps);
 }
 
   BKE_gpencil_stroke_geometry_update(gps);
 }
 
-/* Helper: Check materials with same color. */
-static int gpencil_check_same_material_color(Object *ob_gp, float color[4], Material **r_mat)
-{
-  Material *ma = NULL;
-  float color_cu[4];
-  linearrgb_to_srgb_v3_v3(color_cu, color);
-  float hsv1[4];
-  rgb_to_hsv_v(color_cu, hsv1);
-  hsv1[3] = color[3];
-
-  for (int i = 1; i <= ob_gp->totcol; i++) {
-    ma = BKE_object_material_get(ob_gp, i);
-    MaterialGPencilStyle *gp_style = ma->gp_style;
-    /* Check color with small tolerance (better in HSV). */
-    float hsv2[4];
-    rgb_to_hsv_v(gp_style->fill_rgba, hsv2);
-    hsv2[3] = gp_style->fill_rgba[3];
-    if ((gp_style->fill_style == GP_MATERIAL_FILL_STYLE_SOLID) &&
-        (compare_v4v4(hsv1, hsv2, 0.01f))) {
-      *r_mat = ma;
-      return i - 1;
-    }
-  }
-
-  *r_mat = NULL;
-  return -1;
-}
-
-/* Helper: Add gpencil material using curve material as base. */
-static Material *gpencil_add_from_curve_material(Main *bmain,
-                                                 Object *ob_gp,
-                                                 const float cu_color[4],
-                                                 const bool gpencil_lines,
-                                                 const bool fill,
-                                                 int *r_idx)
-{
-  Material *mat_gp = BKE_gpencil_object_material_new(
-      bmain, ob_gp, (fill) ? "Material" : "Unassigned", r_idx);
-  MaterialGPencilStyle *gp_style = mat_gp->gp_style;
-
-  /* Stroke color. */
-  if (gpencil_lines) {
-    ARRAY_SET_ITEMS(gp_style->stroke_rgba, 0.0f, 0.0f, 0.0f, 1.0f);
-    gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
-  }
-  else {
-    linearrgb_to_srgb_v4(gp_style->stroke_rgba, cu_color);
-    gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
-  }
-
-  /* Fill color. */
-  linearrgb_to_srgb_v4(gp_style->fill_rgba, cu_color);
-  /* Fill is false if the original curve hasn't material assigned, so enable it. */
-  if (fill) {
-    gp_style->flag |= GP_MATERIAL_FILL_SHOW;
-  }
-
-  /* Check at least one is enabled. */
-  if (((gp_style->flag & GP_MATERIAL_STROKE_SHOW) == 0) &&
-      ((gp_style->flag & GP_MATERIAL_FILL_SHOW) == 0)) {
-    gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
-  }
-
-  return mat_gp;
-}
-
-/* Helper: Create new stroke section. */
-static void gpencil_add_new_points(bGPDstroke *gps,
-                                   float *coord_array,
-                                   float pressure,
-                                   int init,
-                                   int totpoints,
-                                   const float init_co[3],
-                                   bool last)
-{
-  for (int i = 0; i < totpoints; i++) {
-    bGPDspoint *pt = &gps->points[i + init];
-    copy_v3_v3(&pt->x, &coord_array[3 * i]);
-    /* Be sure the last point is not on top of the first point of the curve or
-     * the close of the stroke will produce glitches. */
-    if ((last) && (i > 0) && (i == totpoints - 1)) {
-      float dist = len_v3v3(init_co, &pt->x);
-      if (dist < 0.1f) {
-        /* Interpolate between previous point and current to back slightly. */
-        bGPDspoint *pt_prev = &gps->points[i + init - 1];
-        interp_v3_v3v3(&pt->x, &pt_prev->x, &pt->x, 0.95f);
-      }
-    }
-
-    pt->pressure = pressure;
-    pt->strength = 1.0f;
-  }
-}
-
-/* Helper: Get the first collection that includes the object. */
-static Collection *gpencil_get_parent_collection(Scene *scene, Object *ob)
-{
-  Collection *mycol = NULL;
-  FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
-    LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
-      if ((mycol == NULL) && (cob->ob == ob)) {
-        mycol = collection;
-      }
-    }
-  }
-  FOREACH_SCENE_COLLECTION_END;
-
-  return mycol;
-}
-
-/* Helper: Convert one spline to grease pencil stroke. */
-static void gpencil_convert_spline(Main *bmain,
-                                   Object *ob_gp,
-                                   Object *ob_cu,
-                                   const bool gpencil_lines,
-                                   const bool only_stroke,
-                                   bGPDframe *gpf,
-                                   Nurb *nu)
-{
-  Curve *cu = (Curve *)ob_cu->data;
-  bool cyclic = true;
-
-  /* Create Stroke. */
-  bGPDstroke *gps = MEM_callocN(sizeof(bGPDstroke), "bGPDstroke");
-  gps->thickness = 10.0f;
-  gps->fill_opacity_fac = 1.0f;
-  gps->hardeness = 1.0f;
-  gps->uv_scale = 1.0f;
-
-  ARRAY_SET_ITEMS(gps->aspect_ratio, 1.0f, 1.0f);
-  ARRAY_SET_ITEMS(gps->caps, GP_STROKE_CAP_ROUND, GP_STROKE_CAP_ROUND);
-  gps->inittime = 0.0f;
-
-  gps->flag &= ~GP_STROKE_SELECT;
-  gps->flag |= GP_STROKE_3DSPACE;
-
-  gps->mat_nr = 0;
-  /* Count total points
-   * The total of points must consider that last point of each segment is equal to the first
-   * point of next segment.
-   */
-  int totpoints = 0;
-  int segments = 0;
-  int resolu = nu->resolu + 1;
-  segments = nu->pntsu;
-  if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
-    segments--;
-    cyclic = false;
-  }
-  totpoints = (resolu * segments) - (segments - 1);
-
-  /* Materials
-   * Notice: The color of the material is the color of viewport and not the final shader color.
-   */
-  Material *mat_gp = NULL;
-  bool fill = true;
-  /* Check if grease pencil has a material with same color.*/
-  float color[4];
-  if ((cu->mat) && (*cu->mat)) {
-    Material *mat_cu = *cu->mat;
-    copy_v4_v4(color, &mat_cu->r);
-  }
-  else {
-    /* Gray (unassigned from SVG add-on) */
-    zero_v4(color);
-    add_v3_fl(color, 0.6f);
-    color[3] = 1.0f;
-    fill = false;
-  }
-
-  /* Special case: If the color was created by the SVG add-on and the name contains '_stroke' and
-   * there is only one color, the stroke must not be closed, fill to false and use for
-   * stroke the fill color.
-   */
-  bool do_stroke = false;
-  if (ob_cu->totcol == 1) {
-    Material *ma_stroke = BKE_object_material_get(ob_cu, 1);
-    if ((ma_stroke) && (strstr(ma_stroke->id.name, "_stroke") != NULL)) {
-      do_stroke = true;
-    }
-  }
-
-  int r_idx = gpencil_check_same_material_color(ob_gp, color, &mat_gp);
-  if ((ob_cu->totcol > 0) && (r_idx < 0)) {
-    Material *mat_curve = BKE_object_material_get(ob_cu, 1);
-    mat_gp = gpencil_add_from_curve_material(bmain, ob_gp, color, gpencil_lines, fill, &r_idx);
-
-    if ((mat_curve) && (mat_curve->gp_style != NULL)) {
-      MaterialGPencilStyle *gp_style_cur = mat_curve->gp_style;
-      MaterialGPencilStyle *gp_style_gp = mat_gp->gp_style;
-
-      copy_v4_v4(gp_style_gp->mix_rgba, gp_style_cur->mix_rgba);
-      gp_style_gp->fill_style = gp_style_cur->fill_style;
-      gp_style_gp->mix_factor = gp_style_cur->mix_factor;
-    }
-
-    /* If object has more than 1 material, use second material for stroke color. */
-    if ((!only_stroke) && (ob_cu->totcol > 1) && (BKE_object_material_get(ob_cu, 2))) {
-      mat_curve = BKE_object_material_get(ob_cu, 2);
-      if (mat_curve) {
-        linearrgb_to_srgb_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
-        mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
-      }
-    }
-    else if ((only_stroke) || (do_stroke)) {
-      /* Also use the first color if the fill is none for stroke color. */
-      if (ob_cu->totcol > 0) {
-        mat_curve = BKE_object_material_get(ob_cu, 1);
-        if (mat_curve) {
-          copy_v3_v3(mat_gp->gp_style->stroke_rgba, &mat_curve->r);
-          mat_gp->gp_style->stroke_rgba[3] = mat_curve->a;
-          /* Set fill and stroke depending of curve type (3D or 2D). */
-          if ((cu->flag & CU_3D) || ((cu->flag & (CU_FRONT | CU_BACK)) == 0)) {
-            mat_gp->gp_style->flag |= GP_MATERIAL_STROKE_SHOW;
-            mat_gp->gp_style->flag &= ~GP_MATERIAL_FILL_SHOW;
-          }
-          else {
-            mat_gp->gp_style->flag &= ~GP_MATERIAL_STROKE_SHOW;
-            mat_gp->gp_style->flag |= GP_MATERIAL_FILL_SHOW;
-          }
-        }
-      }
-    }
-  }
-  CLAMP_MIN(r_idx, 0);
-
-  /* Assign material index to stroke. */
-  gps->mat_nr = r_idx;
-
-  /* Add stroke to frame.*/
-  BLI_addtail(&gpf->strokes, gps);
-
-  float *coord_array = NULL;
-  float init_co[3];
-
-  switch (nu->type) {
-    case CU_POLY: {
-      /* Allocate memory for storage points. */
-      gps->totpoints = nu->pntsu;
-      gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-      /* Increase thickness for this type. */
-      gps->thickness = 10.0f;
-
-      /* Get all curve points */
-      for (int s = 0; s < gps->totpoints; s++) {
-        BPoint *bp = &nu->bp[s];
-        bGPDspoint *pt = &gps->points[s];
-        copy_v3_v3(&pt->x, bp->vec);
-        pt->pressure = bp->radius;
-        pt->strength = 1.0f;
-      }
-      break;
-    }
-    case CU_BEZIER: {
-      /* Allocate memory for storage points. */
-      gps->totpoints = totpoints;
-      gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
-      int init = 0;
-      resolu = nu->resolu + 1;
-      segments = nu->pntsu;
-      if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
-        segments--;
-      }
-      /* Get all interpolated curve points of Beziert */
-      for (int s = 0; s < segments; s++) {
-        int inext = (s + 1) % nu->pntsu;
-        BezTriple *prevbezt = &nu->bezt[s];
-        BezTriple *bezt = &nu->bezt[inext];
-        bool last = (bool)(s == segments - 1);
-
-        coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__);
-
-        for (int j = 0; j < 3; j++) {
-          BKE_curve_forward_diff_bezier(prevbezt->vec[1][j],
-                                        prevbezt->vec[2][j],
-                                        bezt->vec[0][j],
-                                        bezt->vec[1][j],
-                                        coord_array + j,
-                                        resolu - 1,
-                                        3 * sizeof(float));
-        }
-        /* Save first point coordinates. */
-        if (s == 0) {
-          copy_v3_v3(init_co, &coord_array[0]);
-        }
-        /* Add points to the stroke */
-        gpencil_add_new_points(gps, coord_array, bezt->radius, init, resolu, init_co, last);
-        /* Free memory. */
-        MEM_SAFE_FREE(coord_array);
-
-        /* As the last point of segment is the first point of next segment, back one array
-         * element to avoid duplicated points on the same location.
-         */
-        init += resolu - 1;
-      }
-      break;
-    }
-    case CU_NURBS: {
-      if (nu->pntsv == 1) {
-
-        int nurb_points;
-        if (nu->flagu & CU_NURB_CYCLIC) {
-          resolu++;
-          nurb_points = nu->pntsu * resolu;
-        }
-        else {
-          nurb_points = (nu->pntsu - 1) * resolu;
-        }
-        /* Get all curve points. */
-        coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__);
-        BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3]));
-
-        /* Allocate memory for storage points. */
-        gps->totpoints = nurb_points - 1;
-        gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points");
-
-        /* Add points. */
-        gpencil_add_new_points(gps, coord_array, 1.0f, 0, gps->totpoints, init_co, false);
-
-        MEM_SAFE_FREE(coord_array);
-      }
-      break;
-    }
-    default: {
-      break;
-    }
-  }
-  /* Cyclic curve, close stroke. */
-  if ((cyclic) && (!do_stroke)) {
-    BKE_gpencil_stroke_close(gps);
-  }
-
-  /* Recalc fill geometry. */
-  BKE_gpencil_stroke_geometry_update(gps);
-}
-
-/* Convert a curve object to grease pencil stroke.
- *
- * \param bmain: Main thread pointer
- * \param scene: Original scene.
- * \param ob_gp: Grease pencil object to add strokes.
- * \param ob_cu: Curve to convert.
- * \param gpencil_lines: Use lines for strokes.
- * \param use_collections: Create layers using collection names.
- * \param only_stroke: The material must be only stroke without fill.
- */
-void BKE_gpencil_convert_curve(Main *bmain,
-                               Scene *scene,
-                               Object *ob_gp,
-                               Object *ob_cu,
-                               const bool gpencil_lines,
-                               const bool use_collections,
-                               const bool only_stroke)
-{
-  if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) {
-    return;
-  }
-
-  Curve *cu = (Curve *)ob_cu->data;
-  bGPdata *gpd = (bGPdata *)ob_gp->data;
-  bGPDlayer *gpl = NULL;
-
-  /* If the curve is empty, cancel. */
-  if (cu->nurb.first == NULL) {
-    return;
-  }
-
-  /* Check if there is an active layer. */
-  if (use_collections) {
-    Collection *collection = gpencil_get_parent_collection(scene, ob_cu);
-    if (collection != NULL) {
-      gpl = BKE_gpencil_layer_named_get(gpd, collection->id.name + 2);
-      if (gpl == NULL) {
-        gpl = BKE_gpencil_layer_addnew(gpd, collection->id.name + 2, true);
-      }
-    }
-  }
-
-  if (gpl == NULL) {
-    gpl = BKE_gpencil_layer_active_get(gpd);
-    if (gpl == NULL) {
-      gpl = BKE_gpencil_layer_addnew(gpd, DATA_("GP_Layer"), true);
-    }
-  }
-
-  /* Check if there is an active frame and add if needed. */
-  bGPDframe *gpf = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY);
-
-  /* Read all splines of the curve and create a stroke for each. */
-  LISTBASE_FOREACH (Nurb *, nu, &cu->nurb) {
-    gpencil_convert_spline(bmain, ob_gp, ob_cu, gpencil_lines, only_stroke, gpf, nu);
-  }
-
-  /* Tag for recalculation */
-  DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
-}
-
 /* Apply Transforms */
 void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
 {
 /* Apply Transforms */
 void BKE_gpencil_transform(bGPdata *gpd, float mat[4][4])
 {
index 64abd01983cee9fb7f86c2cdd00728c23d0deb4c..bd5ef23948d701a59411f09604632e668e9b19de 100644 (file)
@@ -64,7 +64,7 @@
 #include "BKE_duplilist.h"
 #include "BKE_effect.h"
 #include "BKE_font.h"
 #include "BKE_duplilist.h"
 #include "BKE_effect.h"
 #include "BKE_font.h"
-#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_curve.h"
 #include "BKE_hair.h"
 #include "BKE_key.h"
 #include "BKE_lattice.h"
 #include "BKE_hair.h"
 #include "BKE_key.h"
 #include "BKE_lattice.h"
index bc8f6d4e3aea85ab16dd4ea9806134c91a79dc9f..b26018394b7338a62f782d7440d4c66d9d1584d5 100644 (file)
@@ -36,7 +36,7 @@
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 
 #include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 
-#include "BKE_gpencil_geom.h"
+#include "BKE_gpencil_curve.h"
 #include "BKE_layer.h"
 
 #include "DEG_depsgraph.h"
 #include "BKE_layer.h"
 
 #include "DEG_depsgraph.h"