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