Blender  V3.3
editcurve_paint.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "DNA_object_types.h"
8 #include "DNA_scene_types.h"
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "BLI_blenlib.h"
13 #include "BLI_math.h"
14 #include "BLI_mempool.h"
15 
16 #include "BKE_context.h"
17 #include "BKE_curve.h"
18 #include "BKE_fcurve.h"
19 #include "BKE_report.h"
20 
21 #include "DEG_depsgraph.h"
22 
23 #include "WM_api.h"
24 #include "WM_types.h"
25 
26 #include "ED_curve.h"
27 #include "ED_screen.h"
28 #include "ED_space_api.h"
29 #include "ED_view3d.h"
30 
31 #include "GPU_batch.h"
32 #include "GPU_batch_presets.h"
33 #include "GPU_immediate.h"
34 #include "GPU_immediate_util.h"
35 #include "GPU_matrix.h"
36 #include "GPU_state.h"
37 
38 #include "curve_intern.h"
39 
40 #include "UI_resources.h"
41 
42 #include "RNA_access.h"
43 #include "RNA_define.h"
44 #include "RNA_prototypes.h"
45 
46 #include "RNA_enum_types.h"
47 
48 #define USE_SPLINE_FIT
49 
50 #ifdef USE_SPLINE_FIT
51 # include "curve_fit_nd.h"
52 #endif
53 
54 /* Distance between input samples */
55 #define STROKE_SAMPLE_DIST_MIN_PX 1
56 #define STROKE_SAMPLE_DIST_MAX_PX 3
57 
58 /* Distance between start/end points to consider cyclic */
59 #define STROKE_CYCLIC_DIST_PX 8
60 
61 /* -------------------------------------------------------------------- */
65 struct StrokeElem {
66  float mval[2];
67  float location_world[3];
68  float location_local[3];
69 
70  /* surface normal, may be zero'd */
71  float normal_world[3];
72  float normal_local[3];
73 
74  float pressure;
75 };
76 
77 struct CurveDrawData {
79  short curve_type;
80 
81  /* projecting 2D into 3D space */
82  struct {
83  /* use a plane or project to the surface */
84  bool use_plane;
85  float plane[4];
86 
87  /* use 'rv3d->depths', note that this will become 'damaged' while drawing, but that's OK. */
88  bool use_depth;
89 
90  /* offset projection by this value */
91  bool use_offset;
92  float offset[3]; /* world-space */
96 
97  /* cursor sampling */
98  struct {
99  /* use substeps, needed for nicely interpolating depth */
102 
103  struct {
104  float min, max, range;
106 
107  struct {
108  float mval[2];
109  /* Used in case we can't calculate the depth. */
110  float location_world[3];
111 
113 
114  const struct StrokeElem *selem;
115  } prev;
116 
119  enum {
122  } state;
123 
124  /* StrokeElem */
126 
128 };
129 
130 static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd,
131  const float pressure)
132 {
133  const Curve *cu = cdd->vc.obedit->data;
134  return ((pressure * cdd->radius.range) + cdd->radius.min) * cu->bevel_radius;
135 }
136 
137 static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
138 {
139  return stroke_elem_radius_from_pressure(cdd, selem->pressure);
140 }
141 
142 static void stroke_elem_pressure_set(const struct CurveDrawData *cdd,
143  struct StrokeElem *selem,
144  float pressure)
145 {
146  if ((cdd->project.surface_offset != 0.0f) && !cdd->project.use_surface_offset_absolute &&
147  !is_zero_v3(selem->normal_local)) {
148  const float adjust = stroke_elem_radius_from_pressure(cdd, pressure) -
150  madd_v3_v3fl(selem->location_local, selem->normal_local, adjust);
151  mul_v3_m4v3(selem->location_world, cdd->vc.obedit->obmat, selem->location_local);
152  }
153  selem->pressure = pressure;
154 }
155 
156 static void stroke_elem_interp(struct StrokeElem *selem_out,
157  const struct StrokeElem *selem_a,
158  const struct StrokeElem *selem_b,
159  float t)
160 {
161  interp_v2_v2v2(selem_out->mval, selem_a->mval, selem_b->mval, t);
162  interp_v3_v3v3(selem_out->location_world, selem_a->location_world, selem_b->location_world, t);
163  interp_v3_v3v3(selem_out->location_local, selem_a->location_local, selem_b->location_local, t);
164  selem_out->pressure = interpf(selem_a->pressure, selem_b->pressure, t);
165 }
166 
170 static bool stroke_elem_project(const struct CurveDrawData *cdd,
171  const int mval_i[2],
172  const float mval_fl[2],
173  float surface_offset,
174  const float radius,
175  float r_location_world[3],
176  float r_normal_world[3])
177 {
178  ARegion *region = cdd->vc.region;
179 
180  bool is_location_world_set = false;
181 
182  /* project to 'location_world' */
183  if (cdd->project.use_plane) {
184  /* get the view vector to 'location' */
186  region, cdd->project.plane, mval_fl, true, r_location_world)) {
187  if (r_normal_world) {
188  zero_v3(r_normal_world);
189  }
190  is_location_world_set = true;
191  }
192  }
193  else {
194  const ViewDepths *depths = cdd->depths;
195  if (depths && ((uint)mval_i[0] < depths->w) && ((uint)mval_i[1] < depths->h)) {
196  float depth_fl = 1.0f;
197  ED_view3d_depth_read_cached(depths, mval_i, 0, &depth_fl);
198  const double depth = (double)depth_fl;
199  if ((depth > depths->depth_range[0]) && (depth < depths->depth_range[1])) {
200  if (ED_view3d_depth_unproject_v3(region, mval_i, depth, r_location_world)) {
201  is_location_world_set = true;
202  if (r_normal_world) {
203  zero_v3(r_normal_world);
204  }
205 
206  if (surface_offset != 0.0f) {
207  const float offset = cdd->project.use_surface_offset_absolute ? 1.0f : radius;
208  float normal[3];
209  if (ED_view3d_depth_read_cached_normal(region, depths, mval_i, normal)) {
210  madd_v3_v3fl(r_location_world, normal, offset * surface_offset);
211  if (r_normal_world) {
212  copy_v3_v3(r_normal_world, normal);
213  }
214  }
215  }
216  }
217  }
218  }
219  }
220 
221  if (is_location_world_set) {
222  if (cdd->project.use_offset) {
223  add_v3_v3(r_location_world, cdd->project.offset);
224  }
225  }
226 
227  return is_location_world_set;
228 }
229 
230 static bool stroke_elem_project_fallback(const struct CurveDrawData *cdd,
231  const int mval_i[2],
232  const float mval_fl[2],
233  const float surface_offset,
234  const float radius,
235  const float location_fallback_depth[3],
236  float r_location_world[3],
237  float r_location_local[3],
238  float r_normal_world[3],
239  float r_normal_local[3])
240 {
241  bool is_depth_found = stroke_elem_project(
242  cdd, mval_i, mval_fl, surface_offset, radius, r_location_world, r_normal_world);
243  if (is_depth_found == false) {
245  cdd->vc.v3d, cdd->vc.region, location_fallback_depth, mval_fl, r_location_world);
246  zero_v3(r_normal_local);
247  }
248  mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world);
249 
250  if (!is_zero_v3(r_normal_world)) {
251  copy_v3_v3(r_normal_local, r_normal_world);
252  mul_transposed_mat3_m4_v3(cdd->vc.obedit->obmat, r_normal_local);
253  normalize_v3(r_normal_local);
254  }
255  else {
256  zero_v3(r_normal_local);
257  }
258 
259  return is_depth_found;
260 }
261 
265 static bool stroke_elem_project_fallback_elem(const struct CurveDrawData *cdd,
266  const float location_fallback_depth[3],
267  struct StrokeElem *selem)
268 {
269  const int mval_i[2] = {UNPACK2(selem->mval)};
270  const float radius = stroke_elem_radius(cdd, selem);
271  return stroke_elem_project_fallback(cdd,
272  mval_i,
273  selem->mval,
274  cdd->project.surface_offset,
275  radius,
276  location_fallback_depth,
277  selem->location_world,
278  selem->location_local,
279  selem->normal_world,
280  selem->normal_local);
281 }
282 
285 /* -------------------------------------------------------------------- */
289 static void curve_draw_stroke_to_operator_elem(wmOperator *op, const struct StrokeElem *selem)
290 {
291  PointerRNA itemptr;
292  RNA_collection_add(op->ptr, "stroke", &itemptr);
293 
294  RNA_float_set_array(&itemptr, "mouse", selem->mval);
295  RNA_float_set_array(&itemptr, "location", selem->location_world);
296  RNA_float_set(&itemptr, "pressure", selem->pressure);
297 }
298 
300 {
301  struct CurveDrawData *cdd = op->customdata;
302 
303  struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
304 
305  RNA_float_get_array(itemptr, "mouse", selem->mval);
306  RNA_float_get_array(itemptr, "location", selem->location_world);
307  mul_v3_m4v3(selem->location_local, cdd->vc.obedit->imat, selem->location_world);
308  selem->pressure = RNA_float_get(itemptr, "pressure");
309 }
310 
312 {
313  struct CurveDrawData *cdd = op->customdata;
314 
315  BLI_mempool_iter iter;
316  const struct StrokeElem *selem;
317 
319  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
321  }
322 }
323 
325 {
326  RNA_BEGIN (op->ptr, itemptr, "stroke") {
328  }
329  RNA_END;
330 }
331 
334 /* -------------------------------------------------------------------- */
338 static void curve_draw_stroke_3d(const struct bContext *UNUSED(C),
339  ARegion *UNUSED(region),
340  void *arg)
341 {
342  wmOperator *op = arg;
343  struct CurveDrawData *cdd = op->customdata;
344 
345  const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
346 
347  if (stroke_len == 0) {
348  return;
349  }
350 
351  Object *obedit = cdd->vc.obedit;
352  Curve *cu = obedit->data;
353 
354  if (cu->bevel_radius > 0.0f) {
355  BLI_mempool_iter iter;
356  const struct StrokeElem *selem;
357 
358  const float location_zero[3] = {0};
359  const float *location_prev = location_zero;
360 
361  float color[3];
363 
364  GPUBatch *sphere = GPU_batch_preset_sphere(0);
366  GPU_batch_uniform_3fv(sphere, "color", color);
367 
368  /* scale to edit-mode space */
369  GPU_matrix_push();
370  GPU_matrix_mul(obedit->obmat);
371 
373  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
374  GPU_matrix_translate_3f(selem->location_local[0] - location_prev[0],
375  selem->location_local[1] - location_prev[1],
376  selem->location_local[2] - location_prev[2]);
377 
378  const float radius = stroke_elem_radius(cdd, selem);
379 
380  GPU_matrix_push();
381  GPU_matrix_scale_1f(radius);
382  GPU_batch_draw(sphere);
383  GPU_matrix_pop();
384 
385  location_prev = selem->location_local;
386  }
387 
388  GPU_matrix_pop();
389  }
390 
391  if (stroke_len > 1) {
392  float(*coord_array)[3] = MEM_mallocN(sizeof(*coord_array) * stroke_len, __func__);
393 
394  {
395  BLI_mempool_iter iter;
396  const struct StrokeElem *selem;
397  int i;
399  for (selem = BLI_mempool_iterstep(&iter), i = 0; selem;
400  selem = BLI_mempool_iterstep(&iter), i++) {
401  copy_v3_v3(coord_array[i], selem->location_world);
402  }
403  }
404 
405  {
409 
412  GPU_line_smooth(true);
413  GPU_line_width(3.0f);
414 
415  imm_cpack(0x0);
416  immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
417  for (int i = 0; i < stroke_len; i++) {
418  immVertex3fv(pos, coord_array[i]);
419  }
420  immEnd();
421 
422  GPU_line_width(1.0f);
423 
424  imm_cpack(0xffffffff);
425  immBegin(GPU_PRIM_LINE_STRIP, stroke_len);
426  for (int i = 0; i < stroke_len; i++) {
427  immVertex3fv(pos, coord_array[i]);
428  }
429  immEnd();
430 
431  /* Reset defaults */
434  GPU_line_smooth(false);
435 
437  }
438 
439  MEM_freeN(coord_array);
440  }
441 }
442 
443 static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
444 {
445  struct CurveDrawData *cdd = op->customdata;
446  Object *obedit = cdd->vc.obedit;
447 
448  invert_m4_m4(obedit->imat, obedit->obmat);
449 
450  struct StrokeElem *selem = BLI_mempool_calloc(cdd->stroke_elem_pool);
451 
452  ARRAY_SET_ITEMS(selem->mval, event->mval[0], event->mval[1]);
453 
454  /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */
455  selem->pressure = event->tablet.pressure;
456 
457  bool is_depth_found = stroke_elem_project_fallback_elem(
458  cdd, cdd->prev.location_world_valid, selem);
459 
460  if (is_depth_found) {
461  /* use the depth if a fallback wasn't used */
463  }
465 
466  float len_sq = len_squared_v2v2(cdd->prev.mval, selem->mval);
467  copy_v2_v2(cdd->prev.mval, selem->mval);
468 
469  if (cdd->sample.use_substeps && cdd->prev.selem) {
470  const struct StrokeElem selem_target = *selem;
471  struct StrokeElem *selem_new_last = selem;
472  if (len_sq >= square_f(STROKE_SAMPLE_DIST_MAX_PX)) {
473  int n = (int)ceil(sqrt((double)len_sq)) / STROKE_SAMPLE_DIST_MAX_PX;
474 
475  for (int i = 1; i < n; i++) {
476  struct StrokeElem *selem_new = selem_new_last;
477  stroke_elem_interp(selem_new, cdd->prev.selem, &selem_target, (float)i / n);
478 
479  const bool is_depth_found_substep = stroke_elem_project_fallback_elem(
480  cdd, cdd->prev.location_world_valid, selem_new);
481  if (is_depth_found == false) {
482  if (is_depth_found_substep) {
484  }
485  }
486 
487  selem_new_last = BLI_mempool_calloc(cdd->stroke_elem_pool);
488  }
489  }
490  selem = selem_new_last;
491  *selem_new_last = selem_target;
492  }
493 
494  cdd->prev.selem = selem;
495 
497 }
498 
499 static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
500 {
501  struct CurveDrawData *cdd = op->customdata;
503 
504  /* add first point */
505  curve_draw_event_add(op, event);
506 
509  RegionView3D *rv3d = cdd->vc.rv3d;
510 
511  cdd->project.use_depth = false;
512  cdd->project.use_plane = true;
513 
514  float normal[3] = {0.0f};
515  if (ELEM(cps->surface_plane,
518  if (ED_view3d_depth_read_cached_normal(cdd->vc.region, cdd->depths, event->mval, normal)) {
520  float cross_a[3], cross_b[3];
521  cross_v3_v3v3(cross_a, rv3d->viewinv[2], normal);
522  cross_v3_v3v3(cross_b, normal, cross_a);
523  copy_v3_v3(normal, cross_b);
524  }
525  }
526  }
527 
528  /* CURVE_PAINT_SURFACE_PLANE_VIEW or fallback */
529  if (is_zero_v3(normal)) {
530  copy_v3_v3(normal, rv3d->viewinv[2]);
531  }
532 
535 
536  /* Special case for when we only have offset applied on the first-hit,
537  * the remaining stroke must be offset too. */
538  if (cdd->project.surface_offset != 0.0f) {
539  const float mval_fl[2] = {UNPACK2(event->mval)};
540 
541  float location_no_offset[3];
542 
543  if (stroke_elem_project(cdd, event->mval, mval_fl, 0.0f, 0.0f, location_no_offset, NULL)) {
544  sub_v3_v3v3(cdd->project.offset, cdd->prev.location_world_valid, location_no_offset);
545  if (!is_zero_v3(cdd->project.offset)) {
546  cdd->project.use_offset = true;
547  }
548  }
549  }
550  /* end special case */
551  }
552 
553  cdd->init_event_type = event->type;
554  cdd->state = CURVE_DRAW_PAINTING;
555 }
556 
557 static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
558 {
559  BLI_assert(op->customdata == NULL);
560 
561  struct CurveDrawData *cdd = MEM_callocN(sizeof(*cdd), __func__);
563 
564  if (is_invoke) {
566  if (ELEM(NULL, cdd->vc.region, cdd->vc.rv3d, cdd->vc.v3d, cdd->vc.win, cdd->vc.scene)) {
567  MEM_freeN(cdd);
568  BKE_report(op->reports, RPT_ERROR, "Unable to access 3D viewport");
569  return false;
570  }
571  }
572  else {
573  cdd->vc.bmain = CTX_data_main(C);
574  cdd->vc.depsgraph = depsgraph;
575  cdd->vc.scene = CTX_data_scene(C);
578 
579  /* Using an empty stroke complicates logic later,
580  * it's simplest to disallow early on (see: T94085). */
581  if (RNA_collection_is_empty(op->ptr, "stroke")) {
582  MEM_freeN(cdd);
583  BKE_report(op->reports, RPT_ERROR, "The \"stroke\" cannot be empty");
584  return false;
585  }
586  }
587 
588  op->customdata = cdd;
589 
591 
592  cdd->curve_type = cps->curve_type;
593 
594  cdd->radius.min = cps->radius_min;
595  cdd->radius.max = cps->radius_max;
596  cdd->radius.range = cps->radius_max - cps->radius_min;
600 
602  sizeof(struct StrokeElem), 0, 512, BLI_MEMPOOL_ALLOW_ITER);
603 
604  return true;
605 }
606 
607 static void curve_draw_exit(wmOperator *op)
608 {
609  struct CurveDrawData *cdd = op->customdata;
610  if (cdd) {
611  if (cdd->draw_handle_view) {
614  }
615 
616  if (cdd->stroke_elem_pool) {
618  }
619 
620  if (cdd->depths) {
622  }
623  MEM_freeN(cdd);
624  op->customdata = NULL;
625  }
626 }
627 
632 {
633  struct CurveDrawData *cdd = op->customdata;
635  PropertyRNA *prop;
636 
637  prop = RNA_struct_find_property(op->ptr, "fit_method");
638  if (!RNA_property_is_set(op->ptr, prop)) {
639  RNA_property_enum_set(op->ptr, prop, cps->fit_method);
640  }
641 
642  prop = RNA_struct_find_property(op->ptr, "corner_angle");
643  if (!RNA_property_is_set(op->ptr, prop)) {
644  const float corner_angle = (cps->flag & CURVE_PAINT_FLAG_CORNERS_DETECT) ? cps->corner_angle :
645  (float)M_PI;
646  RNA_property_float_set(op->ptr, prop, corner_angle);
647  }
648 
649  prop = RNA_struct_find_property(op->ptr, "error_threshold");
650  if (!RNA_property_is_set(op->ptr, prop)) {
651 
652  /* Error isn't set so we'll have to calculate it from the pixel values. */
653  BLI_mempool_iter iter;
654  const struct StrokeElem *selem, *selem_prev;
655 
656  float len_3d = 0.0f, len_2d = 0.0f;
657  float scale_px; /* pixel to local space scale */
658 
659  int i = 0;
661  selem_prev = BLI_mempool_iterstep(&iter);
662  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
663  len_3d += len_v3v3(selem->location_local, selem_prev->location_local);
664  len_2d += len_v2v2(selem->mval, selem_prev->mval);
665  selem_prev = selem;
666  }
667  scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f;
668  float error_threshold = (cps->error_threshold * U.dpi_fac) * scale_px;
669  RNA_property_float_set(op->ptr, prop, error_threshold);
670  }
671 
672  prop = RNA_struct_find_property(op->ptr, "use_cyclic");
673  if (!RNA_property_is_set(op->ptr, prop)) {
674  bool use_cyclic = false;
675 
676  if (BLI_mempool_len(cdd->stroke_elem_pool) > 2) {
677  BLI_mempool_iter iter;
678  const struct StrokeElem *selem, *selem_first, *selem_last;
679 
681  selem_first = selem_last = BLI_mempool_iterstep(&iter);
682  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
683  selem_last = selem;
684  }
685 
686  if (len_squared_v2v2(selem_first->mval, selem_last->mval) <=
687  square_f(STROKE_CYCLIC_DIST_PX * U.dpi_fac)) {
688  use_cyclic = true;
689  }
690  }
691 
692  RNA_property_boolean_set(op->ptr, prop, use_cyclic);
693  }
694 
695  if ((cps->radius_taper_start != 0.0f) || (cps->radius_taper_end != 0.0f)) {
696  /* NOTE: we could try to de-duplicate the length calculations above. */
697  const int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
698 
699  BLI_mempool_iter iter;
700  struct StrokeElem *selem, *selem_prev;
701 
702  float *lengths = MEM_mallocN(sizeof(float) * stroke_len, __func__);
703  struct StrokeElem **selem_array = MEM_mallocN(sizeof(*selem_array) * stroke_len, __func__);
704  lengths[0] = 0.0f;
705 
706  float len_3d = 0.0f;
707 
708  int i = 1;
710  selem_prev = BLI_mempool_iterstep(&iter);
711  selem_array[0] = selem_prev;
712  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter), i++) {
713  const float len_3d_segment = len_v3v3(selem->location_local, selem_prev->location_local);
714  len_3d += len_3d_segment;
715  lengths[i] = len_3d;
716  selem_array[i] = selem;
717  selem_prev = selem;
718  }
719 
720  if (cps->radius_taper_start != 0.0f) {
721  const float len_taper_max = cps->radius_taper_start * len_3d;
722  for (i = 0; i < stroke_len && lengths[i] < len_taper_max; i++) {
723  const float pressure_new = selem_array[i]->pressure * (lengths[i] / len_taper_max);
724  stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
725  }
726  }
727 
728  if (cps->radius_taper_end != 0.0f) {
729  const float len_taper_max = cps->radius_taper_end * len_3d;
730  const float len_taper_min = len_3d - len_taper_max;
731  for (i = stroke_len - 1; i > 0 && lengths[i] > len_taper_min; i--) {
732  const float pressure_new = selem_array[i]->pressure *
733  ((len_3d - lengths[i]) / len_taper_max);
734  stroke_elem_pressure_set(cdd, selem_array[i], pressure_new);
735  }
736  }
737 
738  MEM_freeN(lengths);
739  MEM_freeN(selem_array);
740  }
741 }
742 
744 {
745  if (op->customdata == NULL) {
746  if (!curve_draw_init(C, op, false)) {
747  return OPERATOR_CANCELLED;
748  }
749  }
750 
751  struct CurveDrawData *cdd = op->customdata;
752 
754  Object *obedit = cdd->vc.obedit;
755  Curve *cu = obedit->data;
756  ListBase *nurblist = object_editcurve_get(obedit);
757 
758  int stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
759 
760  const bool is_3d = (cu->flag & CU_3D) != 0;
761  invert_m4_m4(obedit->imat, obedit->obmat);
762 
763  if (BLI_mempool_len(cdd->stroke_elem_pool) == 0) {
765  stroke_len = BLI_mempool_len(cdd->stroke_elem_pool);
766  }
767 
768  /* Deselect all existing curves. */
770 
771  const float radius_min = cps->radius_min;
772  const float radius_max = cps->radius_max;
773  const float radius_range = cps->radius_max - cps->radius_min;
774 
775  Nurb *nu = MEM_callocN(sizeof(Nurb), __func__);
776  nu->pntsv = 0;
777  nu->resolu = cu->resolu;
778  nu->resolv = cu->resolv;
779  nu->flag |= CU_SMOOTH;
780 
781  const bool use_pressure_radius = (cps->flag & CURVE_PAINT_FLAG_PRESSURE_RADIUS) ||
782  ((cps->radius_taper_start != 0.0f) ||
783  (cps->radius_taper_end != 0.0f));
784 
785  if (cdd->curve_type == CU_BEZIER) {
786  nu->type = CU_BEZIER;
787 
788 #ifdef USE_SPLINE_FIT
789 
790  /* Allow to interpolate multiple channels */
791  int dims = 3;
792  struct {
793  int radius;
794  } coords_indices;
795  coords_indices.radius = use_pressure_radius ? dims++ : -1;
796 
797  float *coords = MEM_mallocN(sizeof(*coords) * stroke_len * dims, __func__);
798 
799  float *cubic_spline = NULL;
800  uint cubic_spline_len = 0;
801 
802  /* error in object local space */
803  const int fit_method = RNA_enum_get(op->ptr, "fit_method");
804  const float error_threshold = RNA_float_get(op->ptr, "error_threshold");
805  const float corner_angle = RNA_float_get(op->ptr, "corner_angle");
806  const bool use_cyclic = RNA_boolean_get(op->ptr, "use_cyclic");
807 
808  {
809  BLI_mempool_iter iter;
810  const struct StrokeElem *selem;
811  float *co = coords;
812 
814  for (selem = BLI_mempool_iterstep(&iter); selem;
815  selem = BLI_mempool_iterstep(&iter), co += dims) {
816  copy_v3_v3(co, selem->location_local);
817  if (coords_indices.radius != -1) {
818  co[coords_indices.radius] = selem->pressure;
819  }
820 
821  /* remove doubles */
822  if ((co != coords) && UNLIKELY(memcmp(co, co - dims, sizeof(float) * dims) == 0)) {
823  co -= dims;
824  stroke_len--;
825  }
826  }
827  }
828 
829  uint *corners = NULL;
830  uint corners_len = 0;
831 
832  if ((fit_method == CURVE_PAINT_FIT_METHOD_SPLIT) && (corner_angle < (float)M_PI)) {
833  /* this could be configurable... */
834  const float corner_radius_min = error_threshold / 8;
835  const float corner_radius_max = error_threshold * 2;
836  const uint samples_max = 16;
837 
838  curve_fit_corners_detect_fl(coords,
839  stroke_len,
840  dims,
841  corner_radius_min,
842  corner_radius_max,
843  samples_max,
844  corner_angle,
845  &corners,
846  &corners_len);
847  }
848 
849  uint *corners_index = NULL;
850  uint corners_index_len = 0;
851  uint calc_flag = CURVE_FIT_CALC_HIGH_QUALIY;
852 
853  if ((stroke_len > 2) && use_cyclic) {
854  calc_flag |= CURVE_FIT_CALC_CYCLIC;
855  }
856 
857  int result;
858  if (fit_method == CURVE_PAINT_FIT_METHOD_REFIT) {
859  result = curve_fit_cubic_to_points_refit_fl(coords,
860  stroke_len,
861  dims,
862  error_threshold,
863  calc_flag,
864  NULL,
865  0,
866  corner_angle,
867  &cubic_spline,
868  &cubic_spline_len,
869  NULL,
870  &corners_index,
871  &corners_index_len);
872  }
873  else {
874  result = curve_fit_cubic_to_points_fl(coords,
875  stroke_len,
876  dims,
877  error_threshold,
878  calc_flag,
879  corners,
880  corners_len,
881  &cubic_spline,
882  &cubic_spline_len,
883  NULL,
884  &corners_index,
885  &corners_index_len);
886  }
887 
888  MEM_freeN(coords);
889  if (corners) {
890  free(corners);
891  }
892 
893  if (result == 0) {
894  nu->pntsu = cubic_spline_len;
895  nu->bezt = MEM_callocN(sizeof(BezTriple) * nu->pntsu, __func__);
896 
897  float *co = cubic_spline;
898  BezTriple *bezt = nu->bezt;
899  for (int j = 0; j < cubic_spline_len; j++, bezt++, co += (dims * 3)) {
900  const float *handle_l = co + (dims * 0);
901  const float *pt = co + (dims * 1);
902  const float *handle_r = co + (dims * 2);
903 
904  copy_v3_v3(bezt->vec[0], handle_l);
905  copy_v3_v3(bezt->vec[1], pt);
906  copy_v3_v3(bezt->vec[2], handle_r);
907 
908  if (coords_indices.radius != -1) {
909  bezt->radius = (pt[coords_indices.radius] * cdd->radius.range) + cdd->radius.min;
910  }
911  else {
912  bezt->radius = radius_max;
913  }
914 
915  bezt->h1 = bezt->h2 = HD_ALIGN; /* will set to free in second pass */
916  bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
917  }
918 
919  if (corners_index) {
920  /* ignore the first and last */
921  uint i_start = 0, i_end = corners_index_len;
922 
923  if ((corners_index_len >= 2) && (calc_flag & CURVE_FIT_CALC_CYCLIC) == 0) {
924  i_start += 1;
925  i_end -= 1;
926  }
927 
928  for (uint i = i_start; i < i_end; i++) {
929  bezt = &nu->bezt[corners_index[i]];
930  bezt->h1 = bezt->h2 = HD_FREE;
931  }
932  }
933 
934  if (calc_flag & CURVE_FIT_CALC_CYCLIC) {
935  nu->flagu |= CU_NURB_CYCLIC;
936  }
937  }
938 
939  if (corners_index) {
940  free(corners_index);
941  }
942 
943  if (cubic_spline) {
944  free(cubic_spline);
945  }
946 
947 #else
948  nu->pntsu = stroke_len;
949  nu->bezt = MEM_callocN(nu->pntsu * sizeof(BezTriple), __func__);
950 
951  BezTriple *bezt = nu->bezt;
952 
953  {
954  BLI_mempool_iter iter;
955  const struct StrokeElem *selem;
956 
958  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
959  copy_v3_v3(bezt->vec[1], selem->location_local);
960  if (!is_3d) {
961  bezt->vec[1][2] = 0.0f;
962  }
963 
964  if (use_pressure_radius) {
965  bezt->radius = selem->pressure;
966  }
967  else {
968  bezt->radius = radius_max;
969  }
970 
971  bezt->h1 = bezt->h2 = HD_AUTO;
972 
973  bezt->f1 |= SELECT;
974  bezt->f2 |= SELECT;
975  bezt->f3 |= SELECT;
976 
977  bezt++;
978  }
979  }
980 #endif
981 
983  }
984  else { /* CU_POLY */
985  BLI_mempool_iter iter;
986  const struct StrokeElem *selem;
987 
988  nu->pntsu = stroke_len;
989  nu->pntsv = 1;
990  nu->type = CU_POLY;
991  nu->bp = MEM_callocN(nu->pntsu * sizeof(BPoint), __func__);
992 
993  /* Misc settings. */
994  nu->resolu = cu->resolu;
995  nu->resolv = 1;
996  nu->orderu = 4;
997  nu->orderv = 1;
998 
999  BPoint *bp = nu->bp;
1000 
1002  for (selem = BLI_mempool_iterstep(&iter); selem; selem = BLI_mempool_iterstep(&iter)) {
1003  copy_v3_v3(bp->vec, selem->location_local);
1004  if (!is_3d) {
1005  bp->vec[2] = 0.0f;
1006  }
1007 
1008  if (use_pressure_radius) {
1009  bp->radius = (selem->pressure * radius_range) + radius_min;
1010  }
1011  else {
1012  bp->radius = cps->radius_max;
1013  }
1014  bp->f1 = SELECT;
1015  bp->vec[3] = 1.0f;
1016 
1017  bp++;
1018  }
1019 
1021  }
1022 
1023  BLI_addtail(nurblist, nu);
1024 
1025  BKE_curve_nurb_active_set(cu, nu);
1026  cu->actvert = nu->pntsu - 1;
1027 
1029  DEG_id_tag_update(obedit->data, 0);
1030 
1031  curve_draw_exit(op);
1032 
1033  return OPERATOR_FINISHED;
1034 }
1035 
1036 static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1037 {
1038  if (RNA_struct_property_is_set(op->ptr, "stroke")) {
1039  return curve_draw_exec(C, op);
1040  }
1041 
1042  if (!curve_draw_init(C, op, true)) {
1043  return OPERATOR_CANCELLED;
1044  }
1045 
1046  struct CurveDrawData *cdd = op->customdata;
1047 
1049 
1050  const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input");
1051 
1052  /* Fallback (in case we can't find the depth on first test). */
1053  {
1054  const float mval_fl[2] = {UNPACK2(event->mval)};
1055  float center[3];
1056  negate_v3_v3(center, cdd->vc.rv3d->ofs);
1057  ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.region, center, mval_fl, cdd->prev.location_world);
1059  }
1060 
1064 
1065  {
1066  View3D *v3d = cdd->vc.v3d;
1067  RegionView3D *rv3d = cdd->vc.rv3d;
1068  Object *obedit = cdd->vc.obedit;
1069  Curve *cu = obedit->data;
1070 
1071  const float *plane_no = NULL;
1072  const float *plane_co = NULL;
1073 
1074  if (CU_IS_2D(cu)) {
1075  /* 2D overrides other options */
1076  plane_co = obedit->obmat[3];
1077  plane_no = obedit->obmat[2];
1078  cdd->project.use_plane = true;
1079  }
1080  else {
1081  if ((cps->depth_mode == CURVE_PAINT_PROJECT_SURFACE) && (v3d->shading.type > OB_WIRE)) {
1082  /* needed or else the draw matrix can be incorrect */
1084 
1086  cdd->vc.region,
1087  cdd->vc.v3d,
1088  NULL,
1090  &cdd->depths);
1091 
1092  if (cdd->depths != NULL) {
1093  cdd->project.use_depth = true;
1094  }
1095  else {
1096  BKE_report(op->reports, RPT_WARNING, "Unable to access depth buffer, using view plane");
1097  cdd->project.use_depth = false;
1098  }
1099  }
1100 
1101  /* use view plane (when set or as fallback when surface can't be found) */
1102  if (cdd->project.use_depth == false) {
1103  plane_co = cdd->vc.scene->cursor.location;
1104  plane_no = rv3d->viewinv[2];
1105  cdd->project.use_plane = true;
1106  }
1107 
1108  if (cdd->project.use_depth && (cdd->curve_type != CU_POLY)) {
1109  cdd->sample.use_substeps = true;
1110  }
1111  }
1112 
1113  if (cdd->project.use_plane) {
1114  normalize_v3_v3(cdd->project.plane, plane_no);
1115  cdd->project.plane[3] = -dot_v3v3(cdd->project.plane, plane_co);
1116  }
1117  }
1118 
1119  if (is_modal == false) {
1120  curve_draw_event_add_first(op, event);
1121  }
1122 
1123  /* add temp handler */
1125 
1126  return OPERATOR_RUNNING_MODAL;
1127 }
1128 
1130 {
1131  curve_draw_exit(op);
1132 }
1133 
1134 /* Modal event handling of frame changing */
1135 static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
1136 {
1138  struct CurveDrawData *cdd = op->customdata;
1139 
1140  UNUSED_VARS(C, op);
1141 
1142  if (event->type == cdd->init_event_type) {
1143  if (event->val == KM_RELEASE) {
1145 
1147 
1149 
1150  curve_draw_exec(C, op);
1151 
1152  return OPERATOR_FINISHED;
1153  }
1154  }
1155  else if (ELEM(event->type, EVT_ESCKEY, RIGHTMOUSE)) {
1157  curve_draw_cancel(C, op);
1158  return OPERATOR_CANCELLED;
1159  }
1160  else if (ELEM(event->type, LEFTMOUSE)) {
1161  if (event->val == KM_PRESS) {
1162  curve_draw_event_add_first(op, event);
1163  }
1164  }
1165  else if (ISMOUSE_MOTION(event->type)) {
1166  if (cdd->state == CURVE_DRAW_PAINTING) {
1167  const float mval_fl[2] = {UNPACK2(event->mval)};
1169  curve_draw_event_add(op, event);
1170  }
1171  }
1172  }
1173 
1174  return ret;
1175 }
1176 
1178 {
1179  /* identifiers */
1180  ot->name = "Draw Curve";
1181  ot->idname = "CURVE_OT_draw";
1182  ot->description = "Draw a freehand spline";
1183 
1184  /* api callbacks */
1185  ot->exec = curve_draw_exec;
1190 
1191  /* flags */
1193 
1194  /* properties */
1195  PropertyRNA *prop;
1196 
1197  prop = RNA_def_float_distance(ot->srna,
1198  "error_threshold",
1199  0.0f,
1200  0.0f,
1201  10.0f,
1202  "Error",
1203  "Error distance threshold (in object units)",
1204  0.0001f,
1205  10.0f);
1206  RNA_def_property_ui_range(prop, 0.0, 10, 1, 4);
1207 
1208  RNA_def_enum(ot->srna,
1209  "fit_method",
1212  "Fit Method",
1213  "");
1214 
1215  prop = RNA_def_float_distance(
1216  ot->srna, "corner_angle", DEG2RADF(70.0f), 0.0f, M_PI, "Corner Angle", "", 0.0f, M_PI);
1218 
1219  prop = RNA_def_boolean(ot->srna, "use_cyclic", true, "Cyclic", "");
1221 
1222  prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
1224 
1225  prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1227 }
1228 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
void BKE_nurb_handles_calc(struct Nurb *nu)
Definition: curve.cc:3995
#define CU_IS_2D(cu)
Definition: BKE_curve.h:67
void BKE_nurb_knot_calc_u(struct Nurb *nu)
Definition: curve.cc:1234
void BKE_curve_nurb_active_set(struct Curve *cu, const struct Nurb *nu)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
sqrt(x)+1/max(0
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE float square_f(float a)
MINLINE float interpf(float a, float b, float t)
#define M_PI
Definition: BLI_math_base.h:20
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:946
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
#define DEG2RADF(_deg)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], float t)
Definition: math_vector.c:14
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL()
Definition: BLI_mempool.c:498
@ BLI_MEMPOOL_ALLOW_ITER
Definition: BLI_mempool.h:107
void * BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: BLI_mempool.c:577
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:434
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int elem_num, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
Definition: BLI_mempool.c:253
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:707
void * BLI_mempool_calloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
Definition: BLI_mempool.c:347
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK2(a)
#define UNUSED_VARS(...)
#define ARRAY_SET_ITEMS(...)
#define UNUSED(x)
#define UNLIKELY(x)
#define ELEM(...)
typedef double(DMatrix)[4][4]
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ CU_BEZIER
@ CU_POLY
@ CU_SMOOTH
@ CU_NURB_CYCLIC
@ HD_FREE
@ HD_AUTO
@ HD_ALIGN
@ CU_3D
@ OB_WIRE
Object is a sort of wrapper for general info.
@ CURVE_PAINT_SURFACE_PLANE_NORMAL_SURFACE
@ CURVE_PAINT_SURFACE_PLANE_NORMAL_VIEW
@ CURVE_PAINT_PROJECT_SURFACE
@ CURVE_PAINT_FLAG_DEPTH_STROKE_ENDPOINTS
@ CURVE_PAINT_FLAG_DEPTH_STROKE_OFFSET_ABS
@ CURVE_PAINT_FLAG_CORNERS_DETECT
@ CURVE_PAINT_FLAG_PRESSURE_RADIUS
@ CURVE_PAINT_FIT_METHOD_REFIT
@ CURVE_PAINT_FIT_METHOD_SPLIT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
bool ED_operator_editcurve(struct bContext *C)
Definition: screen_ops.c:606
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
#define REGION_DRAW_POST_VIEW
Definition: ED_space_api.h:62
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:226
bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle)
Definition: spacetypes.c:241
bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region, const float plane[4], const float mval[2], bool do_clip, float r_out[3])
bool ED_view3d_depth_read_cached(const ViewDepths *vd, const int mval[2], int margin, float *r_depth)
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
bool ED_view3d_depth_read_cached_normal(const struct ARegion *region, const ViewDepths *depths, const int mval[2], float r_normal[3])
void ED_view3d_depths_free(ViewDepths *depths)
Definition: view3d_draw.c:2366
@ V3D_DEPTH_NO_GPENCIL
Definition: ED_view3d.h:182
bool ED_view3d_depth_unproject_v3(const struct ARegion *region, const int mval[2], double depth, float r_location_world[3])
void ED_view3d_win_to_3d(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
void view3d_operator_needs_opengl(const struct bContext *C)
void ED_view3d_depth_override(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, struct Object *obact, eV3DDepthOverrideMode mode, struct ViewDepths **r_depths)
Definition: view3d_draw.c:2294
NSNotificationCenter * center
GPUBatch
Definition: GPU_batch.h:78
void GPU_batch_program_set_builtin(GPUBatch *batch, eGPUBuiltinShader shader_id)
Definition: gpu_batch.cc:287
void GPU_batch_draw(GPUBatch *batch)
Definition: gpu_batch.cc:223
#define GPU_batch_uniform_3fv(batch, name, val)
Definition: GPU_batch.h:151
struct GPUBatch * GPU_batch_preset_sphere(int lod) ATTR_WARN_UNUSED_RESULT
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immEnd(void)
void imm_cpack(uint x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:126
#define GPU_matrix_mul(x)
Definition: GPU_matrix.h:224
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:119
void GPU_matrix_scale_1f(float factor)
Definition: gpu_matrix.cc:209
void GPU_matrix_translate_3f(float x, float y, float z)
Definition: gpu_matrix.cc:188
@ GPU_PRIM_LINE_STRIP
Definition: GPU_primitive.h:22
@ GPU_SHADER_3D_UNIFORM_COLOR
Definition: GPU_shader.h:230
@ GPU_BLEND_NONE
Definition: GPU_state.h:60
@ GPU_BLEND_ALPHA
Definition: GPU_state.h:62
void GPU_blend(eGPUBlend blend)
Definition: gpu_state.cc:39
void GPU_line_width(float width)
Definition: gpu_state.cc:158
void GPU_line_smooth(bool enable)
Definition: gpu_state.cc:75
@ GPU_DEPTH_LESS_EQUAL
Definition: GPU_state.h:86
@ GPU_DEPTH_NONE
Definition: GPU_state.h:83
void GPU_depth_test(eGPUDepthTest test)
Definition: gpu_state.cc:65
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert a color
#define RNA_BEGIN(sptr, itemptr, propname)
Definition: RNA_access.h:543
#define RNA_END
Definition: RNA_access.h:550
@ PROP_SKIP_SAVE
Definition: RNA_types.h:218
@ PROP_HIDDEN
Definition: RNA_types.h:216
@ PROP_ANGLE
Definition: RNA_types.h:145
#define C
Definition: RandGen.cpp:25
void UI_GetThemeColor3fv(int colorid, float col[3])
Definition: resources.c:1165
@ TH_WIRE
Definition: UI_resources.h:69
@ KM_PRESS
Definition: WM_types.h:267
@ KM_RELEASE
Definition: WM_types.h:268
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
unsigned int U
Definition: btGjkEpa3.h:78
#define SELECT
const Depsgraph * depsgraph
ListBase * object_editcurve_get(Object *ob)
Definition: editcurve.c:74
static bool stroke_elem_project(const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], float surface_offset, const float radius, float r_location_world[3], float r_normal_world[3])
static void curve_draw_stroke_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
#define STROKE_CYCLIC_DIST_PX
static void curve_draw_exec_precalc(wmOperator *op)
static void curve_draw_cancel(bContext *UNUSED(C), wmOperator *op)
static int curve_draw_exec(bContext *C, wmOperator *op)
static bool stroke_elem_project_fallback_elem(const struct CurveDrawData *cdd, const float location_fallback_depth[3], struct StrokeElem *selem)
static bool stroke_elem_project_fallback(const struct CurveDrawData *cdd, const int mval_i[2], const float mval_fl[2], const float surface_offset, const float radius, const float location_fallback_depth[3], float r_location_world[3], float r_location_local[3], float r_normal_world[3], float r_normal_local[3])
static float stroke_elem_radius(const struct CurveDrawData *cdd, const struct StrokeElem *selem)
#define STROKE_SAMPLE_DIST_MIN_PX
static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void curve_draw_stroke_to_operator_elem(wmOperator *op, const struct StrokeElem *selem)
static void stroke_elem_pressure_set(const struct CurveDrawData *cdd, struct StrokeElem *selem, float pressure)
static void curve_draw_event_add(wmOperator *op, const wmEvent *event)
void CURVE_OT_draw(wmOperatorType *ot)
static void curve_draw_stroke_from_operator_elem(wmOperator *op, PointerRNA *itemptr)
static void curve_draw_stroke_to_operator(wmOperator *op)
static bool curve_draw_init(bContext *C, wmOperator *op, bool is_invoke)
static void stroke_elem_interp(struct StrokeElem *selem_out, const struct StrokeElem *selem_a, const struct StrokeElem *selem_b, float t)
static float stroke_elem_radius_from_pressure(const struct CurveDrawData *cdd, const float pressure)
static int curve_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void curve_draw_stroke_from_operator(wmOperator *op)
#define STROKE_SAMPLE_DIST_MAX_PX
static void curve_draw_event_add_first(wmOperator *op, const wmEvent *event)
static void curve_draw_exit(wmOperator *op)
bool ED_curve_deselect_all_multi(struct bContext *C)
uint pos
IconTextureDrawCall normal
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
return ret
bool RNA_collection_is_empty(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5250
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
Definition: rna_access.c:3421
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
void RNA_collection_add(PointerRNA *ptr, const char *name, PointerRNA *r_value)
Definition: rna_access.c:5215
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2180
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
Definition: rna_access.c:2790
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:4052
PropertyRNA * RNA_def_collection_runtime(StructOrFunctionRNA *cont_, const char *identifier, StructRNA *type, const char *ui_name, const char *ui_description)
Definition: rna_define.c:4221
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1490
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1534
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1664
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
const EnumPropertyItem rna_enum_curve_fit_method_items[]
Definition: rna_scene.c:241
struct ARegionType * type
uint8_t f1
float vec[4]
float radius
uint8_t h1
uint8_t f3
float vec[3][3]
uint8_t f1
uint8_t f2
uint8_t h2
const struct StrokeElem * selem
bool use_surface_offset_absolute
struct CurveDrawData::@335 sample
ViewDepths * depths
struct CurveDrawData::@337 prev
struct CurveDrawData::@336 radius
enum CurveDrawData::@338 state
struct CurveDrawData::@334 project
float location_world[3]
void * draw_handle_view
float location_world_valid[3]
ViewContext vc
BLI_mempool * stroke_elem_pool
short resolv
short resolu
float bevel_radius
short flagu
short orderu
short orderv
short flag
short type
BezTriple * bezt
BPoint * bp
short resolu
short resolv
float imat[4][4]
float obmat[4][4]
void * data
float viewinv[4][4]
struct ToolSettings * toolsettings
View3DCursor cursor
float normal_world[3]
float normal_local[3]
float mval[2]
float location_local[3]
float location_world[3]
struct CurvePaintSettings curve_paint_settings
View3DShading shading
struct Depsgraph * depsgraph
Definition: ED_view3d.h:64
struct Scene * scene
Definition: ED_view3d.h:65
struct ARegion * region
Definition: ED_view3d.h:69
struct ViewLayer * view_layer
Definition: ED_view3d.h:66
struct Main * bmain
Definition: ED_view3d.h:59
struct Object * obedit
Definition: ED_view3d.h:68
struct wmWindow * win
Definition: ED_view3d.h:71
struct View3D * v3d
Definition: ED_view3d.h:70
struct RegionView3D * rv3d
Definition: ED_view3d.h:72
unsigned short w
Definition: ED_view3d.h:78
double depth_range[2]
Definition: ED_view3d.h:81
unsigned short h
Definition: ED_view3d.h:78
short val
Definition: WM_types.h:680
int mval[2]
Definition: WM_types.h:684
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:191
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:200
@ WM_CURSOR_PAINT_BRUSH
Definition: wm_cursors.h:33
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
#define ISMOUSE_MOTION(event_type)
@ RIGHTMOUSE
@ LEFTMOUSE
@ EVT_ESCKEY
wmOperatorType * ot
Definition: wm_files.c:3479