Cleanup: Move scenes' foreach_id handling of toolsettings into own func.
[blender.git] / source / blender / editors / curve / editcurve_paint.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 /** \file
18  * \ingroup edcurve
19  */
20
21 #include "DNA_object_types.h"
22 #include "DNA_scene_types.h"
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_blenlib.h"
27 #include "BLI_math.h"
28 #include "BLI_mempool.h"
29
30 #include "BKE_context.h"
31 #include "BKE_curve.h"
32 #include "BKE_fcurve.h"
33 #include "BKE_report.h"
34
35 #include "DEG_depsgraph.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 #include "ED_curve.h"
41 #include "ED_screen.h"
42 #include "ED_space_api.h"
43 #include "ED_view3d.h"
44
45 #include "GPU_batch.h"
46 #include "GPU_batch_presets.h"
47 #include "GPU_immediate.h"
48 #include "GPU_immediate_util.h"
49 #include "GPU_matrix.h"
50 #include "GPU_state.h"
51
52 #include "curve_intern.h"
53
54 #include "UI_resources.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58
59 #include "RNA_enum_types.h"
60
61 #define USE_SPLINE_FIT
62
63 #ifdef USE_SPLINE_FIT
64 #  include "curve_fit_nd.h"
65 #endif
66
67 /* Distance between input samples */
68 #define STROKE_SAMPLE_DIST_MIN_PX 1
69 #define STROKE_SAMPLE_DIST_MAX_PX 3
70
71 /* Distance between start/end points to consider cyclic */
72 #define STROKE_CYCLIC_DIST_PX 8
73
74 /* -------------------------------------------------------------------- */
75 /** \name StrokeElem / #RNA_OperatorStrokeElement Conversion Functions
76  * \{ */
77
78 struct StrokeElem {
79   float mval[2];
80   float location_world[3];
81   float location_local[3];
82
83   /* surface normal, may be zero'd */
84   float normal_world[3];
85   float normal_local[3];
86
87   float pressure;
88 };
89
90 struct CurveDrawData {
91   short init_event_type;
92   short curve_type;
93
94   /* projecting 2D into 3D space */
95   struct {
96     /* use a plane or project to the surface */
97     bool use_plane;
98     float plane[4];
99
100     /* use 'rv3d->depths', note that this will become 'damaged' while drawing, but that's OK. */
101     bool use_depth;
102
103     /* offset projection by this value */
104     bool use_offset;
105     float offset[3]; /* worldspace */
106     float surface_offset;
107     bool use_surface_offset_absolute;
108   } project;
109
110   /* cursor sampling */
111   struct {
112     /* use substeps, needed for nicely interpolating depth */
113     bool use_substeps;
114   } sample;
115
116   struct {
117     float min, max, range;
118   } radius;
119
120   struct {
121     float mouse[2];
122     /* Used in case we can't calculate the depth. */
123     float location_world[3];
124
125     float location_world_valid[3];
126
127     const struct StrokeElem *selem;
128   } prev;
129
130   ViewContext vc;
131   enum {
132     CURVE_DRAW_IDLE = 0,
133     CURVE_DRAW_PAINTING = 1,
134   } state;
135
136   /* StrokeElem */
137   BLI_mempool *stroke_elem_pool;
138
139   void *draw_handle_view;
140 };
141
142 static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd,
143                                               const float pressure)
144 {
145   const Curve *cu = cdd->vc.obedit->data;
146   return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->ext2;
147 }
148
149 static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
150 {
151   return stroke_elem_radius_from_pressure(cdd, selem->pressure);
152 }
153
154 static void stroke_elem_pressure_set(const struct CurveDrawData *cdd,
155                                      struct StrokeElem *selem,
156                                      float pressure)
157 {
158   if ((cdd->project.surface_offset != 0.0f) && !cdd->project.use_surface_offset_absolute &&
159       !is_zero_v3(selem->normal_local)) {
160     const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) -
161                          stroke_elem_radius_from_pressure(cdd, selem->pressure);
162     madd_v3_v3fl(selem->location_local, selem->normal_local, adjust);
163     mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local);
164   }
165   selem->pressure = pressure;
166 }
167
168 static void stroke_elem_interp(struct StrokeElem *selem_out,
169                                const struct StrokeElem *selem_a,
170                                const struct StrokeElem *selem_b,
171                                float t)
172 {
173   interp_v2_v2v2(selem_out->mval, selem_a->mval, selem_b->mval, t);
174   interp_v3_v3v3(selem_out->location_world, selem_a->location_world, selem_b->location_world, t);
175   interp_v3_v3v3(selem_out->location_local, selem_a->location_local, selem_b->location_local, t);
176   selem_out->pressure = interpf(selem_a->pressure, selem_b->pressure, t);
177 }
178
179 /**
180  * Sets the depth from #StrokeElem.mval
181  */
182 static bool stroke_elem_project(const struct CurveDrawData *cdd,
183                                 const int mval_i[2],
184                                 const float mval_fl[2],
185                                 float surface_offset,
186                                 const float radius,
187                                 float r_location_world[3],
188                                 float r_normal_world[3])
189 {
190   ARegion *region = cdd->vc.region;
191   RegionView3D *rv3d = cdd->vc.rv3d;
192
193   bool is_location_world_set = false;
194
195   /* project to 'location_world' */
196   if (cdd->project.use_plane) {
197     /* get the view vector to 'location' */
198     if (ED_view3d_win_to_3d_on_plane(
199             region, cdd->project.plane, mval_fl, true, r_location_world)) {
200       if (r_normal_world) {
201         zero_v3(r_normal_world);
202       }
203       is_location_world_set = true;
204     }
205   }
206   else {
207     const ViewDepths *depths = rv3d->depths;
208     if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
209       const double depth = (double)ED_view3d_depth_read_cached(&cdd->vc, mval_i);
210       if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
211         if (ED_view3d_depth_unproject(region, mval_i, depth, r_location_world)) {
212           is_location_world_set = true;
213           if (r_normal_world) {
214             zero_v3(r_normal_world);
215           }
216
217           if (surface_offset != 0.0f) {
218             const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
219             float normal[3];
220             if (ED_view3d_depth_read_cached_normal(&cdd->vc, mval_i, normal)) {
221               madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
222               if (r_normal_world) {
223                 copy_v3_v3(r_normal_world, normal);
224               }
225             }
226           }
227         }
228       }
229     }
230   }
231
232   if (is_location_world_set) {
233     if (cdd->project.use_offset) {
234       add_v3_v3(r_location_world, cdd->project.offset);
235     }
236   }
237
238   return is_location_world_set;
239 }
240
241 static bool stroke_elem_project_fallback(const struct CurveDrawData *cdd,
242                                          const int mval_i[2],
243                                          const float mval_fl[2],
244                                          const float surface_offset,
245                                          const float radius,
246                                          const float location_fallback_depth[3],
247                                          float r_location_world[3],
248                                          float r_location_local[3],
249                                          float r_normal_world[3],
250                                          float r_normal_local[3])
251 {
252   bool is_depth_found = stroke_elem_project(
253       cdd, mval_i, mval_fl, surface_offset, radius, r_location_world, r_normal_world);
254   if (is_depth_found == false) {
255     ED_view3d_win_to_3d(
256         cdd->vc.v3d, cdd->vc.region, location_fallback_depth, mval_fl, r_location_world);
257     zero_v3(r_normal_local);
258   }
259   mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
260
261   if (!is_zero_v3(r_normal_world)) {
262     copy_v3_v3(r_normal_local, r_normal_world);
263     mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local);
264     normalize_v3(r_normal_local);
265   }
266   else {
267     zero_v3(r_normal_local);
268   }
269
270   return is_depth_found;
271 }
272
273 /**
274  * \note #StrokeElem.mval & #StrokeElem.pressure must be set first.
275  */
276 static bool stroke_elem_project_fallback_elem(const struct CurveDrawData *cdd,
277                                               const float location_fallback_depth[3],
278                                               struct StrokeElem *selem)
279 {
280   const int mval_i[2] = {UNPACK2(selem->mval)};
281   const float radius = stroke_elem_radius(cdd, selem);
282   return stroke_elem_project_fallback(cdd,
283                                       mval_i,
284                                       selem->mval,
285                                       cdd->project.surface_offset,
286                                       radius,
287                                       location_fallback_depth,
288                                       selem->location_world,
289                                       selem->location_local,
290                                       selem->normal_world,
291                                       selem->normal_local);
292 }
293
294 /** \} */
295
296 /* -------------------------------------------------------------------- */
297 /** \name Operator/Stroke Conversion
298  * \{ */
299
300 static void curve_draw_stroke_to_operator_elem(wmOperator *op, const struct StrokeElem *selem)
301 {
302   PointerRNA itemptr;
303   RNA_collection_add(op->ptr, "stroke", &itemptr);
304
305   RNA_float_set_array(&itemptr, "mouse", selem->mval);
306   RNA_float_set_array(&itemptr, "location", selem->location_world);
307   RNA_float_set(&itemptr, "pressure", selem->pressure);
308 }
309
310 static void curve_draw_stroke_from_operator_elem(wmOperator *op, PointerRNA *itemptr)
311 {
312   struct CurveDrawData *cdd = op->customdata;
313
314   struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
315
316   RNA_float_get_array(itemptr, "mouse", selem->mval);
317   RNA_float_get_array(itemptr, "location", selem->location_world);
318   mul_v3_m4v3(selem->location_local, cdd->vc.obedit->imat, selem->location_world);
319   selem->pressure = RNA_float_get(itemptr, "pressure");
320 }
321
322 static void curve_draw_stroke_to_operator(wmOperator *op)
323 {
324   struct CurveDrawData *cdd = op->customdata;
325
326   BLI_mempool_iter iter;
327   const struct StrokeElem *selem;
328
329   BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
330   for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
331     curve_draw_stroke_to_operator_elem(op, selem);
332   }
333 }
334
335 static void curve_draw_stroke_from_operator(wmOperator *op)
336 {
337   RNA_BEGIN (op->ptr, itemptr, "stroke") {
338     curve_draw_stroke_from_operator_elem(op, &itemptr);
339   }
340   RNA_END;
341 }
342
343 /** \} */
344
345 /* -------------------------------------------------------------------- */
346 /** \name Operator Callbacks & Helpers
347  * \{ */
348
349 static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
350                                  ARegion *UNUSED(region),
351                                  void *arg)
352 {
353   wmOperator *op = arg;
354   struct CurveDrawData *cdd = op->customdata;
355
356   const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
357
358   if (stroke_len == 0) {
359     return;
360   }
361
362   Object *obedit = cdd->vc.obedit;
363   Curve *cu = obedit->data;
364
365   if (cu->ext2 > 0.0f) {
366     BLI_mempool_iter iter;
367     const struct StrokeElem *selem;
368
369     const float location_zero[3] = {0};
370     const float *location_prev = location_zero;
371
372     float color[3];
373     UI_GetThemeColor3fv(TH_WIRE, color);
374
375     GPUBatch *sphere = GPU_batch_preset_sphere(0);
376     GPU_batch_program_set_builtin(sphere, GPU_SHADER_3D_UNIFORM_COLOR);
377     GPU_batch_uniform_3fv(sphere, "color", color);
378
379     /* scale to edit-mode space */
380     GPU_matrix_push();
381     GPU_matrix_mul(obedit->obmat);
382
383     BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
384     for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
385       GPU_matrix_translate_3f(selem->location_local[0] - location_prev[0],
386                               selem->location_local[1] - location_prev[1],
387                               selem->location_local[2] - location_prev[2]);
388       location_prev = selem->location_local;
389
390       const float radius = stroke_elem_radius(cdd, selem);
391
392       GPU_matrix_push();
393       GPU_matrix_scale_1f(radius);
394       GPU_batch_draw(sphere);
395       GPU_matrix_pop();
396
397       location_prev = selem->location_local;
398     }
399
400     GPU_matrix_pop();
401   }
402
403   if (stroke_len > 1) {
404     float(*coord_array)[3] = MEM_mallocN(sizeof(*coord_array) * stroke_len, __func__);
405
406     {
407       BLI_mempool_iter iter;
408       const struct StrokeElem *selem;
409       int i;
410       BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
411       for (selem = BLI_mempool_iterstep(&iter), i = 0; selem;
412            selem = BLI_mempool_iterstep(&iter), i++) {
413         copy_v3_v3(coord_array[i], selem->location_world);
414       }
415     }
416
417     {
418       GPUVertFormat *format = immVertexFormat();
419       uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
420       immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
421
422       GPU_depth_test(GPU_DEPTH_NONE);
423       GPU_blend(GPU_BLEND_ALPHA);
424       GPU_line_smooth(true);
425       GPU_line_width(3.0f);
426
427       imm_cpack(0x0);
428       immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
429       for (int i = 0; i < stroke_len; i++) {
430         immVertex3fv(pos, coord_array[i]);
431       }
432       immEnd();
433
434       GPU_line_width(1.0f);
435
436       imm_cpack(0xffffffff);
437       immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
438       for (int i = 0; i < stroke_len; i++) {
439         immVertex3fv(pos, coord_array[i]);
440       }
441       immEnd();
442
443       /* Reset defaults */
444       GPU_depth_test(GPU_DEPTH_LESS_EQUAL);
445       GPU_blend(GPU_BLEND_NONE);
446       GPU_line_smooth(false);
447
448       immUnbindProgram();
449     }
450
451     MEM_freeN(coord_array);
452   }
453 }
454
455 static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
456 {
457   struct CurveDrawData *cdd = op->customdata;
458   Object *obedit = cdd->vc.obedit;
459
460   invert_m4_m4(obedit->imat, obedit->obmat);
461
462   struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
463
464   ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
465
466   /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
467   selem->pressure = event->tablet.pressure;
468
469   bool is_depth_found = stroke_elem_project_fallback_elem(
470       cdd, cdd->prev.location_world_valid, selem);
471
472   if (is_depth_found) {
473     /* use the depth if a fallback wasn't used */
474     copy_v3_v3(cdd->prev.location_world_valid, selem->location_world);
475   }
476   copy_v3_v3(cdd->prev.location_world, selem->location_world);
477
478   float len_sq = len_squared_v2v2(cdd->prev.mouse, selem->mval);
479   copy_v2_v2(cdd->prev.mouse, selem->mval);
480
481   if (cdd->sample.use_substeps && cdd->prev.selem) {
482     const struct StrokeElem selem_target = *selem;
483     struct StrokeElem *selem_new_last = selem;
484     if (len_sq >= square_f(STROKE_SAMPLE_DIST_MAX_PX)) {
485       int n = (int)ceil(sqrt((double)len_sq)) / STROKE_SAMPLE_DIST_MAX_PX;
486
487       for (int i = 1; i < n; i++) {
488         struct StrokeElem *selem_new = selem_new_last;
489         stroke_elem_interp(selem_new, cdd->prev.selem, &selem_target, (float)i / n);
490
491         const bool is_depth_found_substep = stroke_elem_project_fallback_elem(
492             cdd, cdd->prev.location_world_valid, selem_new);
493         if (is_depth_found == false) {
494           if (is_depth_found_substep) {
495             copy_v3_v3(cdd->prev.location_world_valid, selem_new->location_world);
496           }
497         }
498
499         selem_new_last = BLI_mempool_calloc(cdd->stroke_elem_pool);
500       }
501     }
502     selem = selem_new_last;
503     *selem_new_last = selem_target;
504   }
505
506   cdd->prev.selem = selem;
507
508   ED_region_tag_redraw(cdd->vc.region);
509 }
510
511 static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
512 {
513   struct CurveDrawData *cdd = op->customdata;
514   const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
515
516   /* add first point */
517   curve_draw_event_add(op, event);
518
519   if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) && cdd->project.use_depth &&
520       (cps->flag & CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS)) {
521     RegionView3D *rv3d = cdd->vc.rv3d;
522
523     cdd->project.use_depth = false;
524     cdd->project.use_plane = true;
525
526     float normal[3] = {0.0f};
527     if (ELEM(cps->surface_plane,
528              CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW,
529              CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE)) {
530       if (ED_view3d_depth_read_cached_normal(&cdd->vc, event->mval, normal)) {
531         if (cps->surface_plane == CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW) {
532           float cross_a[3], cross_b[3];
533           cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
534           cross_v3_v3v3(cross_b, normal, cross_a);
535           copy_v3_v3(normal, cross_b);
536         }
537       }
538     }
539
540     /* CURVE_PAINT_SURFACE_PLANE_VIEW or fallback */
541     if (is_zero_v3(normal)) {
542       copy_v3_v3(normal, rv3d->viewinv[2]);
543     }
544
545     normalize_v3_v3(cdd->project.plane, normal);
546     cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, cdd->prev.location_world_valid);
547
548     /* Special case for when we only have offset applied on the first-hit,
549      * the remaining stroke must be offset too. */
550     if (cdd->project.surface_offset != 0.0f) {
551       const float mval_fl[2] = {UNPACK2(event->mval)};
552
553       float location_no_offset[3];
554
555       if (stroke_elem_project(cdd, event->mval, mval_fl, 0.0f, 0.0f, location_no_offset, NULL)) {
556         sub_v3_v3v3(cdd->project.offset, cdd->prev.location_world_valid, location_no_offset);
557         if (!is_zero_v3(cdd->project.offset)) {
558           cdd->project.use_offset = true;
559         }
560       }
561     }
562     /* end special case */
563   }
564
565   cdd->init_event_type = event->type;
566   cdd->state = CURVE_DRAW_PAINTING;
567 }
568
569 static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
570 {
571   BLI_assert(op->customdata == NULL);
572
573   struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
574   Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
575
576   if (is_invoke) {
577     ED_view3d_viewcontext_init(C, &cdd->vc, depsgraph);
578     if (ELEM(NULL, cdd->vc.region, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
579       MEM_freeN(cdd);
580       BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
581       return false;
582     }
583   }
584   else {
585     cdd->vc.bmain = CTX_data_main(C);
586     cdd->vc.depsgraph = depsgraph;
587     cdd->vc.scene = CTX_data_scene(C);
588     cdd->vc.view_layer = CTX_data_view_layer(C);
589     cdd->vc.obedit = CTX_data_edit_object(C);
590   }
591
592   op->customdata = cdd;
593
594   const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
595
596   cdd->curve_type = cps->curve_type;
597
598   cdd->radius.min = cps->radius_min;
599   cdd->radius.max = cps->radius_max;
600   cdd->radius.range = cps->radius_max - cps->radius_min;
601   cdd->project.surface_offset = cps->surface_offset;
602   cdd->project.use_surface_offset_absolute = (cps->flag &
603                                               CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS) != 0;
604
605   cdd->stroke_elem_pool = BLI_mempool_create(
606       sizeof(struct StrokeElem), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
607
608   return true;
609 }
610
611 static void curve_draw_exit(wmOperator *op)
612 {
613   struct CurveDrawData *cdd = op->customdata;
614   if (cdd) {
615     if (cdd->draw_handle_view) {
616       ED_region_draw_cb_exit(cdd->vc.region->type, cdd->draw_handle_view);
617       WM_cursor_modal_restore(cdd->vc.win);
618     }
619
620     if (cdd->stroke_elem_pool) {
621       BLI_mempool_destroy(cdd->stroke_elem_pool);
622     }
623
624     MEM_freeN(cdd);
625     op->customdata = NULL;
626   }
627 }
628
629 /**
630  * Initialize values before calling 'exec' (when running interactively).
631  */
632 static void curve_draw_exec_precalc(wmOperator *op)
633 {
634   struct CurveDrawData *cdd = op->customdata;
635   const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
636   PropertyRNA *prop;
637
638   prop = RNA_struct_find_property(op->ptr, "fit_method");
639   if (!RNA_property_is_set(op->ptr, prop)) {
640     RNA_property_enum_set(op->ptr, prop, cps->fit_method);
641   }
642
643   prop = RNA_struct_find_property(op->ptr, "corner_angle");
644   if (!RNA_property_is_set(op->ptr, prop)) {
645     const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle :
646                                                                                (float)M_PI;
647     RNA_property_float_set(op->ptr, prop, corner_angle);
648   }
649
650   prop = RNA_struct_find_property(op->ptr, "error_threshold");
651   if (!RNA_property_is_set(op->ptr, prop)) {
652
653     /* error isnt set so we'll have to calculate it from the pixel values */
654     BLI_mempool_iter iter;
655     const struct StrokeElem *selem, *selem_prev;
656
657     float len_3d = 0.0f, len_2d = 0.0f;
658     float scale_px; /* pixel to local space scale */
659
660     int i = 0;
661     BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
662     selem_prev = BLI_mempool_iterstep(&iter);
663     for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
664       len_3d += len_v3v3(selem->location_local, selem_prev->location_local);
665       len_2d += len_v2v2(selem->mval, selem_prev->mval);
666       selem_prev = selem;
667     }
668     scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f;
669     float error_threshold = (cps->error_threshold * U.dpi_fac) * scale_px;
670     RNA_property_float_set(op->ptr, prop, error_threshold);
671   }
672
673   prop = RNA_struct_find_property(op->ptr, "use_cyclic");
674   if (!RNA_property_is_set(op->ptr, prop)) {
675     bool use_cyclic = false;
676
677     if (BLI_mempool_len(cdd->stroke_elem_pool) > 2) {
678       BLI_mempool_iter iter;
679       const struct StrokeElem *selem, *selem_first, *selem_last;
680
681       BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
682       selem_first = selem_last = BLI_mempool_iterstep(&iter);
683       for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
684         selem_last = selem;
685       }
686
687       if (len_squared_v2v2(selem_first->mval, selem_last->mval) <=
688           square_f(STROKE_CYCLIC_DIST_PX * U.dpi_fac)) {
689         use_cyclic = true;
690       }
691     }
692
693     RNA_property_boolean_set(op->ptr, prop, use_cyclic);
694   }
695
696   if ((cps->radius_taper_start != 0.0f) || (cps->radius_taper_end != 0.0f)) {
697     /* note, we could try to de-duplicate the length calculations above */
698     const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
699
700     BLI_mempool_iter iter;
701     struct StrokeElem *selem, *selem_prev;
702
703     float *lengths = MEM_mallocN(sizeof(float) * stroke_len, __func__);
704     struct StrokeElem **selem_array = MEM_mallocN(sizeof(*selem_array) * stroke_len, __func__);
705     lengths[0] = 0.0f;
706
707     float len_3d = 0.0f;
708
709     int i = 1;
710     BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
711     selem_prev = BLI_mempool_iterstep(&iter);
712     selem_array[0] = selem_prev;
713     for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
714       const float len_3d_segment = len_v3v3(selem->location_local, selem_prev->location_local);
715       len_3d += len_3d_segment;
716       lengths[i] = len_3d;
717       selem_array[i] = selem;
718       selem_prev = selem;
719     }
720
721     if (cps->radius_taper_start != 0.0f) {
722       const float len_taper_max = cps->radius_taper_start * len_3d;
723       for (i = 0; i < stroke_len && lengths[i] < len_taper_max; i++) {
724         const float pressure_new = selem_array[i]->pressure * (lengths[i] / len_taper_max);
725         stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
726       }
727     }
728
729     if (cps->radius_taper_end != 0.0f) {
730       const float len_taper_max = cps->radius_taper_end * len_3d;
731       const float len_taper_min = len_3d - len_taper_max;
732       for (i = stroke_len - 1; i > 0 && lengths[i] > len_taper_min; i--) {
733         const float pressure_new = selem_array[i]->pressure *
734                                    ((len_3d - lengths[i]) / len_taper_max);
735         stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
736       }
737     }
738
739     MEM_freeN(lengths);
740     MEM_freeN(selem_array);
741   }
742 }
743
744 static int curve_draw_exec(bContext *C, wmOperator *op)
745 {
746   if (op->customdata == NULL) {
747     if (!curve_draw_init(C, op, false)) {
748       return OPERATOR_CANCELLED;
749     }
750   }
751
752   struct CurveDrawData *cdd = op->customdata;
753
754   const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
755   Object *obedit = cdd->vc.obedit;
756   Curve *cu = obedit->data;
757   ListBase *nurblist = object_editcurve_get(obedit);
758
759   int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
760
761   const bool is_3d = (cu->flag & CU_3D) != 0;
762   invert_m4_m4(obedit->imat, obedit->obmat);
763
764   if (BLI_mempool_len(cdd->stroke_elem_pool) == 0) {
765     curve_draw_stroke_from_operator(op);
766     stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
767   }
768
769   /* Deselect all existing curves. */
770   ED_curve_deselect_all_multi(C);
771
772   const float radius_min = cps->radius_min;
773   const float radius_max = cps->radius_max;
774   const float radius_range = cps->radius_max - cps->radius_min;
775
776   Nurb *nu = MEM_callocN(sizeof(Nurb), __func__);
777   nu->pntsv = 0;
778   nu->resolu = cu->resolu;
779   nu->resolv = cu->resolv;
780   nu->flag |= CU_SMOOTH;
781
782   const bool use_pressure_radius = (cps->flag & CURVE_PAINT_FLAG_PRESSURE_RADIUS) ||
783                                    ((cps->radius_taper_start != 0.0f) ||
784                                     (cps->radius_taper_end != 0.0f));
785
786   if (cdd->curve_type == CU_BEZIER) {
787     nu->type = CU_BEZIER;
788
789 #ifdef USE_SPLINE_FIT
790
791     /* Allow to interpolate multiple channels */
792     int dims = 3;
793     struct {
794       int radius;
795     } coords_indices;
796     coords_indices.radius = use_pressure_radius ? dims++ : -1;
797
798     float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
799
800     float *cubic_spline = NULL;
801     uint cubic_spline_len = 0;
802
803     /* error in object local space */
804     const int fit_method = RNA_enum_get(op->ptr, "fit_method");
805     const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
806     const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
807     const bool use_cyclic = RNA_boolean_get(op->ptr, "use_cyclic");
808
809     {
810       BLI_mempool_iter iter;
811       const struct StrokeElem *selem;
812       float *co = coords;
813
814       BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
815       for (selem = BLI_mempool_iterstep(&iter); selem;
816            selem = BLI_mempool_iterstep(&iter), co += dims) {
817         copy_v3_v3(co, selem->location_local);
818         if (coords_indices.radius != -1) {
819           co[coords_indices.radius] = selem->pressure;
820         }
821
822         /* remove doubles */
823         if ((co != coords) && UNLIKELY(memcmp(co, co - dims, sizeof(float) * dims) == 0)) {
824           co -= dims;
825           stroke_len--;
826         }
827       }
828     }
829
830     uint *corners = NULL;
831     uint corners_len = 0;
832
833     if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
834       /* this could be configurable... */
835       const float corner_radius_min = error_threshold / 8;
836       const float corner_radius_max = error_threshold * 2;
837       const uint samples_max = 16;
838
839       curve_fit_corners_detect_fl(coords,
840                                   stroke_len,
841                                   dims,
842                                   corner_radius_min,
843                                   corner_radius_max,
844                                   samples_max,
845                                   corner_angle,
846                                   &corners,
847                                   &corners_len);
848     }
849
850     uint *corners_index = NULL;
851     uint corners_index_len = 0;
852     uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
853
854     if ((stroke_len > 2) && use_cyclic) {
855       calc_flag |= CURVE_FIT_CALC_CYCLIC;
856     }
857
858     int result;
859     if (fit_method == CURVE_PAINT_FIT_METHOD_REFIT) {
860       result = curve_fit_cubic_to_points_refit_fl(coords,
861                                                   stroke_len,
862                                                   dims,
863                                                   error_threshold,
864                                                   calc_flag,
865                                                   NULL,
866                                                   0,
867                                                   corner_angle,
868                                                   &cubic_spline,
869                                                   &cubic_spline_len,
870                                                   NULL,
871                                                   &corners_index,
872                                                   &corners_index_len);
873     }
874     else {
875       result = curve_fit_cubic_to_points_fl(coords,
876                                             stroke_len,
877                                             dims,
878                                             error_threshold,
879                                             calc_flag,
880                                             corners,
881                                             corners_len,
882                                             &cubic_spline,
883                                             &cubic_spline_len,
884                                             NULL,
885                                             &corners_index,
886                                             &corners_index_len);
887     }
888
889     MEM_freeN(coords);
890     if (corners) {
891       free(corners);
892     }
893
894     if (result == 0) {
895       nu->pntsu = cubic_spline_len;
896       nu->bezt = MEM_callocN(sizeof(BezTriple) * nu->pntsu, __func__);
897
898       float *co = cubic_spline;
899       BezTriple *bezt = nu->bezt;
900       for (int j = 0; j < cubic_spline_len; j++, bezt++, co += (dims * 3)) {
901         const float *handle_l = co + (dims * 0);
902         const float *pt = co + (dims * 1);
903         const float *handle_r = co + (dims * 2);
904
905         copy_v3_v3(bezt->vec[0], handle_l);
906         copy_v3_v3(bezt->vec[1], pt);
907         copy_v3_v3(bezt->vec[2], handle_r);
908
909         if (coords_indices.radius != -1) {
910           bezt->radius = (pt[coords_indices.radius] * cdd->radius.range) + cdd->radius.min;
911         }
912         else {
913           bezt->radius = radius_max;
914         }
915
916         bezt->h1 = bezt->h2 = HD_ALIGN; /* will set to free in second pass */
917         bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
918       }
919
920       if (corners_index) {
921         /* ignore the first and last */
922         uint i_start = 0, i_end = corners_index_len;
923
924         if ((corners_index_len >= 2) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
925           i_start += 1;
926           i_end -= 1;
927         }
928
929         for (uint i = i_start; i < i_end; i++) {
930           bezt = &nu->bezt[corners_index[i]];
931           bezt->h1 = bezt->h2 = HD_FREE;
932         }
933       }
934
935       if (calc_flag & CURVE_FIT_CALC_CYCLIC) {
936         nu->flagu |= CU_NURB_CYCLIC;
937       }
938     }
939
940     if (corners_index) {
941       free(corners_index);
942     }
943
944     if (cubic_spline) {
945       free(cubic_spline);
946     }
947
948 #else
949     nu->pntsu = stroke_len;
950     nu->bezt = MEM_callocN(nu->pntsu * sizeof(BezTriple), __func__);
951
952     BezTriple *bezt = nu->bezt;
953
954     {
955       BLI_mempool_iter iter;
956       const struct StrokeElem *selem;
957
958       BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
959       for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
960         copy_v3_v3(bezt->vec[1], selem->location_local);
961         if (!is_3d) {
962           bezt->vec[1][2] = 0.0f;
963         }
964
965         if (use_pressure_radius) {
966           bezt->radius = selem->pressure;
967         }
968         else {
969           bezt->radius = radius_max;
970         }
971
972         bezt->h1 = bezt->h2 = HD_AUTO;
973
974         bezt->f1 |= SELECT;
975         bezt->f2 |= SELECT;
976         bezt->f3 |= SELECT;
977
978         bezt++;
979       }
980     }
981 #endif
982
983     BKE_nurb_handles_calc(nu);
984   }
985   else { /* CU_POLY */
986     BLI_mempool_iter iter;
987     const struct StrokeElem *selem;
988
989     nu->pntsu = stroke_len;
990     nu->pntsv = 1;
991     nu->type = CU_POLY;
992     nu->bp = MEM_callocN(nu->pntsu * sizeof(BPoint), __func__);
993
994     /* Misc settings. */
995     nu->resolu = cu->resolu;
996     nu->resolv = 1;
997     nu->orderu = 4;
998     nu->orderv = 1;
999
1000     BPoint *bp = nu->bp;
1001
1002     BLI_mempool_iternew(cdd->stroke_elem_pool, &iter);
1003     for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
1004       copy_v3_v3(bp->vec, selem->location_local);
1005       if (!is_3d) {
1006         bp->vec[2] = 0.0f;
1007       }
1008
1009       if (use_pressure_radius) {
1010         bp->radius = (selem->pressure * radius_range) + radius_min;
1011       }
1012       else {
1013         bp->radius = cps->radius_max;
1014       }
1015       bp->f1 = SELECT;
1016       bp->vec[3] = 1.0f;
1017
1018       bp++;
1019     }
1020
1021     BKE_nurb_knot_calc_u(nu);
1022   }
1023
1024   BLI_addtail(nurblist, nu);
1025
1026   BKE_curve_nurb_active_set(cu, nu);
1027   cu->actvert = nu->pntsu - 1;
1028
1029   WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1030   DEG_id_tag_update(obedit->data, 0);
1031
1032   curve_draw_exit(op);
1033
1034   return OPERATOR_FINISHED;
1035 }
1036
1037 static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1038 {
1039   if (RNA_struct_property_is_set(op->ptr, "stroke")) {
1040     return curve_draw_exec(C, op);
1041   }
1042
1043   if (!curve_draw_init(C, op, true)) {
1044     return OPERATOR_CANCELLED;
1045   }
1046
1047   struct CurveDrawData *cdd = op->customdata;
1048
1049   const CurvePaintSettings *cps = &cdd->vc.scene->toolsettings->curve_paint_settings;
1050
1051   const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1052
1053   /* Fallback (in case we can't find the depth on first test). */
1054   {
1055     const float mval_fl[2] = {UNPACK2(event->mval)};
1056     float center[3];
1057     negate_v3_v3(center, cdd->vc.rv3d->ofs);
1058     ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.region, center, mval_fl, cdd->prev.location_world);
1059     copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world);
1060   }
1061
1062   cdd->draw_handle_view = ED_region_draw_cb_activate(
1063       cdd->vc.region->type, curve_draw_stroke_3d, op, REGION_DRAW_POST_VIEW);
1064   WM_cursor_modal_set(cdd->vc.win, WM_CURSOR_PAINT_BRUSH);
1065
1066   {
1067     View3D *v3d = cdd->vc.v3d;
1068     RegionView3D *rv3d = cdd->vc.rv3d;
1069     Object *obedit = cdd->vc.obedit;
1070     Curve *cu = obedit->data;
1071
1072     const float *plane_no = NULL;
1073     const float *plane_co = NULL;
1074
1075     if ((cu->flag & CU_3D) == 0) {
1076       /* 2D overrides other options */
1077       plane_co = obedit->obmat[3];
1078       plane_no = obedit->obmat[2];
1079       cdd->project.use_plane = true;
1080     }
1081     else {
1082       if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) && (v3d->shading.type > OB_WIRE)) {
1083         /* needed or else the draw matrix can be incorrect */
1084         view3d_operator_needs_opengl(C);
1085
1086         ED_view3d_autodist_init(cdd->vc.depsgraph, cdd->vc.region, cdd->vc.v3d, 0);
1087
1088         if (cdd->vc.rv3d->depths) {
1089           cdd->vc.rv3d->depths->damaged = true;
1090         }
1091
1092         ED_view3d_depth_update(cdd->vc.region);
1093
1094         if (cdd->vc.rv3d->depths != NULL) {
1095           cdd->project.use_depth = true;
1096         }
1097         else {
1098           BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
1099           cdd->project.use_depth = false;
1100         }
1101       }
1102
1103       /* use view plane (when set or as fallback when surface can't be found) */
1104       if (cdd->project.use_depth == false) {
1105         plane_co = cdd->vc.scene->cursor.location;
1106         plane_no = rv3d->viewinv[2];
1107         cdd->project.use_plane = true;
1108       }
1109
1110       if (cdd->project.use_depth && (cdd->curve_type != CU_POLY)) {
1111         cdd->sample.use_substeps = true;
1112       }
1113     }
1114
1115     if (cdd->project.use_plane) {
1116       normalize_v3_v3(cdd->project.plane, plane_no);
1117       cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, plane_co);
1118     }
1119   }
1120
1121   if (is_modal == false) {
1122     curve_draw_event_add_first(op, event);
1123   }
1124
1125   /* add temp handler */
1126   WM_event_add_modal_handler(C, op);
1127
1128   return OPERATOR_RUNNING_MODAL;
1129 }
1130
1131 static void curve_draw_cancel(bContext *UNUSED(C), wmOperator *op)
1132 {
1133   curve_draw_exit(op);
1134 }
1135
1136 /* Modal event handling of frame changing */
1137 static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
1138 {
1139   int ret = OPERATOR_RUNNING_MODAL;
1140   struct CurveDrawData *cdd = op->customdata;
1141
1142   UNUSED_VARS(C, op);
1143
1144   if (event->type == cdd->init_event_type) {
1145     if (event->val == KM_RELEASE) {
1146       ED_region_tag_redraw(cdd->vc.region);
1147
1148       curve_draw_exec_precalc(op);
1149
1150       curve_draw_stroke_to_operator(op);
1151
1152       curve_draw_exec(C, op);
1153
1154       return OPERATOR_FINISHED;
1155     }
1156   }
1157   else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
1158     ED_region_tag_redraw(cdd->vc.region);
1159     curve_draw_cancel(C, op);
1160     return OPERATOR_CANCELLED;
1161   }
1162   else if (ELEM(event->type, LEFTMOUSE)) {
1163     if (event->val == KM_PRESS) {
1164       curve_draw_event_add_first(op, event);
1165     }
1166   }
1167   else if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
1168     if (cdd->state == CURVE_DRAW_PAINTING) {
1169       const float mval_fl[2] = {UNPACK2(event->mval)};
1170       if (len_squared_v2v2(mval_fl, cdd->prev.mouse) > square_f(STROKE_SAMPLE_DIST_MIN_PX)) {
1171         curve_draw_event_add(op, event);
1172       }
1173     }
1174   }
1175
1176   return ret;
1177 }
1178
1179 void CURVE_OT_draw(wmOperatorType *ot)
1180 {
1181   /* identifiers */
1182   ot->name = "Draw Curve";
1183   ot->idname = "CURVE_OT_draw";
1184   ot->description = "Draw a freehand spline";
1185
1186   /* api callbacks */
1187   ot->exec = curve_draw_exec;
1188   ot->invoke = curve_draw_invoke;
1189   ot->cancel = curve_draw_cancel;
1190   ot->modal = curve_draw_modal;
1191   ot->poll = ED_operator_editcurve;
1192
1193   /* flags */
1194   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1195
1196   /* properties */
1197   PropertyRNA *prop;
1198
1199   prop = RNA_def_float_distance(ot->srna,
1200                                 "error_threshold",
1201                                 0.0f,
1202                                 0.0f,
1203                                 10.0f,
1204                                 "Error",
1205                                 "Error distance threshold (in object units)",
1206                                 0.0001f,
1207                                 10.0f);
1208   RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
1209
1210   RNA_def_enum(ot->srna,
1211                "fit_method",
1212                rna_enum_curve_fit_method_items,
1213                CURVE_PAINT_FIT_METHOD_REFIT,
1214                "Fit Method",
1215                "");
1216
1217   prop = RNA_def_float_distance(
1218       ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
1219   RNA_def_property_subtype(prop, PROP_ANGLE);
1220
1221   prop = RNA_def_boolean(ot->srna, "use_cyclic", true, "Cyclic", "");
1222   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1223
1224   prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1225   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1226
1227   prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1228   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1229 }
1230
1231 /** \} */