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