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