Blender  V3.3
curves_sculpt_ops.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_kdtree.h"
4 #include "BLI_rand.hh"
5 #include "BLI_utildefines.h"
6 #include "BLI_vector_set.hh"
7 
8 #include "BKE_brush.h"
9 #include "BKE_bvhutils.h"
10 #include "BKE_context.h"
11 #include "BKE_curves.hh"
12 #include "BKE_modifier.h"
13 #include "BKE_object.h"
14 #include "BKE_paint.h"
15 
16 #include "WM_api.h"
17 #include "WM_message.h"
18 #include "WM_toolsystem.h"
19 
20 #include "ED_curves.h"
21 #include "ED_curves_sculpt.h"
22 #include "ED_image.h"
23 #include "ED_object.h"
24 #include "ED_screen.h"
25 #include "ED_space_api.h"
26 #include "ED_view3d.h"
27 
28 #include "DEG_depsgraph.h"
29 #include "DEG_depsgraph_query.h"
30 
31 #include "DNA_brush_types.h"
32 #include "DNA_curves_types.h"
33 #include "DNA_screen_types.h"
34 
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37 #include "RNA_enum_types.h"
38 
39 #include "curves_sculpt_intern.h"
40 #include "curves_sculpt_intern.hh"
41 #include "paint_intern.h"
42 
43 #include "UI_interface.h"
44 #include "UI_resources.h"
45 
46 #include "GPU_immediate.h"
47 #include "GPU_immediate_util.h"
48 #include "GPU_matrix.h"
49 #include "GPU_state.h"
50 
51 /* -------------------------------------------------------------------- */
56 {
57  const Object *ob = CTX_data_active_object(C);
58  return ob && ob->mode & OB_MODE_SCULPT_CURVES;
59 }
60 
62 {
63  if (!CURVES_SCULPT_mode_poll(C)) {
64  return false;
65  }
66  if (CTX_wm_region_view3d(C) == nullptr) {
67  return false;
68  }
69  return true;
70 }
71 
74 namespace blender::ed::sculpt_paint {
75 
77 
78 /* -------------------------------------------------------------------- */
82 float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
83 {
84  if (BKE_brush_use_size_pressure(&brush)) {
85  return stroke_extension.pressure;
86  }
87  return 1.0f;
88 }
89 
91  const Brush &brush,
92  const StrokeExtension &stroke_extension)
93 {
94  return BKE_brush_size_get(&scene, &brush) * brush_radius_factor(brush, stroke_extension);
95 }
96 
97 float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension)
98 {
99  if (BKE_brush_use_alpha_pressure(&brush)) {
100  return stroke_extension.pressure;
101  }
102  return 1.0f;
103 }
104 
106  const Brush &brush,
107  const StrokeExtension &stroke_extension)
108 {
109  return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
110 }
111 
112 static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(
113  bContext &C, wmOperator &op, const StrokeExtension &stroke_start)
114 {
115  const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
116 
117  const Scene &scene = *CTX_data_scene(&C);
118  const CurvesSculpt &curves_sculpt = *scene.toolsettings->curves_sculpt;
119  const Brush &brush = *BKE_paint_brush_for_read(&curves_sculpt.paint);
120  switch (brush.curves_sculpt_tool) {
122  return new_comb_operation();
124  return new_delete_operation();
126  return new_snake_hook_operation();
128  return new_add_operation();
130  return new_grow_shrink_operation(mode, C);
132  return new_selection_paint_operation(mode, C);
134  return new_pinch_operation(mode, C);
136  return new_smooth_operation();
138  return new_puff_operation();
140  return new_density_operation(mode, C, stroke_start);
142  return new_slide_operation();
143  }
145  return {};
146 }
147 
149  std::unique_ptr<CurvesSculptStrokeOperation> operation;
151 };
152 
154  float out[3],
155  const float mouse[2],
156  bool UNUSED(force_original))
157 {
158  out[0] = mouse[0];
159  out[1] = mouse[1];
160  out[2] = 0;
161  UNUSED_VARS(C);
162  return true;
163 }
164 
165 static bool stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
166 {
167  UNUSED_VARS(C, op, mouse);
168  return true;
169 }
170 
172  wmOperator *op,
173  PaintStroke *UNUSED(stroke),
174  PointerRNA *stroke_element)
175 {
177  op->customdata);
178 
179  StrokeExtension stroke_extension;
180  RNA_float_get_array(stroke_element, "mouse", stroke_extension.mouse_position);
181  stroke_extension.pressure = RNA_float_get(stroke_element, "pressure");
182  stroke_extension.reports = op->reports;
183 
184  if (!op_data->operation) {
185  stroke_extension.is_first = true;
186  op_data->operation = start_brush_operation(*C, *op, stroke_extension);
187  }
188  else {
189  stroke_extension.is_first = false;
190  }
191 
192  if (op_data->operation) {
193  op_data->operation->on_stroke_extended(*C, stroke_extension);
194  }
195 }
196 
197 static void stroke_done(const bContext *C, PaintStroke *stroke)
198 {
199  UNUSED_VARS(C, stroke);
200 }
201 
202 static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
203 {
204  const Paint *paint = BKE_paint_get_active_from_context(C);
205  const Brush *brush = BKE_paint_brush_for_read(paint);
206  if (brush == nullptr) {
207  return OPERATOR_CANCELLED;
208  }
209 
210  SculptCurvesBrushStrokeData *op_data = MEM_new<SculptCurvesBrushStrokeData>(__func__);
211  op_data->stroke = paint_stroke_new(C,
212  op,
216  nullptr,
217  stroke_done,
218  event->type);
219  op->customdata = op_data;
220 
221  int return_value = op->type->modal(C, op, event);
222  if (return_value == OPERATOR_FINISHED) {
223  if (op->customdata != nullptr) {
224  paint_stroke_free(C, op, op_data->stroke);
225  MEM_delete(op_data);
226  }
227  return OPERATOR_FINISHED;
228  }
229 
231  return OPERATOR_RUNNING_MODAL;
232 }
233 
234 static int sculpt_curves_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
235 {
237  op->customdata);
238  int return_value = paint_stroke_modal(C, op, event, &op_data->stroke);
239  if (ELEM(return_value, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
240  MEM_delete(op_data);
241  op->customdata = nullptr;
242  }
243  return return_value;
244 }
245 
247 {
248  if (op->customdata != nullptr) {
250  op->customdata);
251  paint_stroke_cancel(C, op, op_data->stroke);
252  MEM_delete(op_data);
253  }
254 }
255 
257 {
258  ot->name = "Stroke Curves Sculpt";
259  ot->idname = "SCULPT_CURVES_OT_brush_stroke";
260  ot->description = "Sculpt curves using a brush";
261 
265 
267 
269 }
270 
273 /* -------------------------------------------------------------------- */
278 {
280  wmMsgBus *mbus = CTX_wm_message_bus(C);
281 
284  CurvesSculpt *curves_sculpt = scene->toolsettings->curves_sculpt;
285 
287 
289 
290  /* Necessary to change the object mode on the evaluated object. */
292  WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
294 }
295 
297 {
299  ob->mode = OB_MODE_OBJECT;
300 }
301 
303 {
305  wmMsgBus *mbus = CTX_wm_message_bus(C);
306 
307  const bool is_mode_set = ob->mode == OB_MODE_SCULPT_CURVES;
308 
309  if (is_mode_set) {
311  return OPERATOR_CANCELLED;
312  }
313  }
314 
315  if (is_mode_set) {
317  }
318  else {
320  }
321 
323 
324  /* Necessary to change the object mode on the evaluated object. */
326  WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode);
328  return OPERATOR_FINISHED;
329 }
330 
332 {
333  ot->name = "Curve Sculpt Mode Toggle";
334  ot->idname = "CURVES_OT_sculptmode_toggle";
335  ot->description = "Enter/Exit sculpt mode for curves";
336 
339 
341 }
342 
345 namespace select_random {
346 
348 {
350 
351  const int seed = RNA_int_get(op->ptr, "seed");
352  RandomNumberGenerator rng{static_cast<uint32_t>(seed)};
353 
354  const bool partial = RNA_boolean_get(op->ptr, "partial");
355  const bool constant_per_curve = RNA_boolean_get(op->ptr, "constant_per_curve");
356  const float probability = RNA_float_get(op->ptr, "probability");
357  const float min_value = RNA_float_get(op->ptr, "min");
358  const auto next_partial_random_value = [&]() {
359  return rng.get_float() * (1.0f - min_value) + min_value;
360  };
361  const auto next_bool_random_value = [&]() { return rng.get_float() <= probability; };
362 
363  for (Curves *curves_id : unique_curves) {
364  CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
365  const bool was_anything_selected = curves::has_anything_selected(*curves_id);
366  switch (curves_id->selection_domain) {
367  case ATTR_DOMAIN_POINT: {
368  MutableSpan<float> selection = curves.selection_point_float_for_write();
369  if (!was_anything_selected) {
370  selection.fill(1.0f);
371  }
372  if (partial) {
373  if (constant_per_curve) {
374  for (const int curve_i : curves.curves_range()) {
375  const float random_value = next_partial_random_value();
376  const IndexRange points = curves.points_for_curve(curve_i);
377  for (const int point_i : points) {
378  selection[point_i] *= random_value;
379  }
380  }
381  }
382  else {
383  for (const int point_i : selection.index_range()) {
384  const float random_value = next_partial_random_value();
385  selection[point_i] *= random_value;
386  }
387  }
388  }
389  else {
390  if (constant_per_curve) {
391  for (const int curve_i : curves.curves_range()) {
392  const bool random_value = next_bool_random_value();
393  const IndexRange points = curves.points_for_curve(curve_i);
394  if (!random_value) {
395  selection.slice(points).fill(0.0f);
396  }
397  }
398  }
399  else {
400  for (const int point_i : selection.index_range()) {
401  const bool random_value = next_bool_random_value();
402  if (!random_value) {
403  selection[point_i] = 0.0f;
404  }
405  }
406  }
407  }
408  break;
409  }
410  case ATTR_DOMAIN_CURVE: {
411  MutableSpan<float> selection = curves.selection_curve_float_for_write();
412  if (!was_anything_selected) {
413  selection.fill(1.0f);
414  }
415  if (partial) {
416  for (const int curve_i : curves.curves_range()) {
417  const float random_value = next_partial_random_value();
418  selection[curve_i] *= random_value;
419  }
420  }
421  else {
422  for (const int curve_i : curves.curves_range()) {
423  const bool random_value = next_bool_random_value();
424  if (!random_value) {
425  selection[curve_i] = 0.0f;
426  }
427  }
428  }
429  break;
430  }
431  }
432  MutableSpan<float> selection = curves_id->selection_domain == ATTR_DOMAIN_POINT ?
433  curves.selection_point_float_for_write() :
434  curves.selection_curve_float_for_write();
435  const bool was_any_selected = std::any_of(
436  selection.begin(), selection.end(), [](const float v) { return v > 0.0f; });
437  if (was_any_selected) {
438  for (float &v : selection) {
439  v *= rng.get_float();
440  }
441  }
442  else {
443  for (float &v : selection) {
444  v = rng.get_float();
445  }
446  }
447 
448  /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
449  * attribute for now. */
450  DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
451  WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
452  }
453  return OPERATOR_FINISHED;
454 }
455 
457 {
458  uiLayout *layout = op->layout;
459 
460  uiItemR(layout, op->ptr, "seed", 0, nullptr, ICON_NONE);
461  uiItemR(layout, op->ptr, "constant_per_curve", 0, nullptr, ICON_NONE);
462  uiItemR(layout, op->ptr, "partial", 0, nullptr, ICON_NONE);
463 
464  if (RNA_boolean_get(op->ptr, "partial")) {
465  uiItemR(layout, op->ptr, "min", UI_ITEM_R_SLIDER, "Min", ICON_NONE);
466  }
467  else {
468  uiItemR(layout, op->ptr, "probability", UI_ITEM_R_SLIDER, "Probability", ICON_NONE);
469  }
470 }
471 
472 } // namespace select_random
473 
475 {
476  ot->name = "Select Random";
477  ot->idname = __func__;
478  ot->description = "Randomizes existing selection or create new random selection";
479 
483 
485 
487  "seed",
488  0,
489  INT32_MIN,
490  INT32_MAX,
491  "Seed",
492  "Source of randomness",
493  INT32_MIN,
494  INT32_MAX);
496  ot->srna, "partial", false, "Partial", "Allow points or curves to be selected partially");
498  "probability",
499  0.5f,
500  0.0f,
501  1.0f,
502  "Probability",
503  "Chance of every point or curve being included in the selection",
504  0.0f,
505  1.0f);
507  "min",
508  0.0f,
509  0.0f,
510  1.0f,
511  "Min",
512  "Minimum value for the random selection",
513  0.0f,
514  1.0f);
516  "constant_per_curve",
517  true,
518  "Constant per Curve",
519  "The generated random number is the same for every control point of a curve");
520 }
521 
522 namespace select_end {
523 static bool select_end_poll(bContext *C)
524 {
526  return false;
527  }
528  const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data);
529  if (curves_id->selection_domain != ATTR_DOMAIN_POINT) {
530  CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode");
531  return false;
532  }
533  return true;
534 }
535 
537 {
539  const bool end_points = RNA_boolean_get(op->ptr, "end_points");
540  const int amount = RNA_int_get(op->ptr, "amount");
541 
542  for (Curves *curves_id : unique_curves) {
543  CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry);
544  const bool was_anything_selected = curves::has_anything_selected(*curves_id);
545  MutableSpan<float> selection = curves.selection_point_float_for_write();
546  if (!was_anything_selected) {
547  selection.fill(1.0f);
548  }
549  threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
550  for (const int curve_i : range) {
551  const IndexRange points = curves.points_for_curve(curve_i);
552  if (end_points) {
553  selection.slice(points.drop_back(amount)).fill(0.0f);
554  }
555  else {
556  selection.slice(points.drop_front(amount)).fill(0.0f);
557  }
558  }
559  });
560 
561  /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
562  * attribute for now. */
563  DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
564  WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
565  }
566 
567  return OPERATOR_FINISHED;
568 }
569 } // namespace select_end
570 
572 {
573  ot->name = "Select End";
574  ot->idname = __func__;
575  ot->description = "Select end points of curves";
576 
579 
581 
583  "end_points",
584  true,
585  "End Points",
586  "Select points at the end of the curve as opposed to the beginning");
587  RNA_def_int(
588  ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX);
589 }
590 
591 namespace select_grow {
592 
599 
602 };
603 
607 };
608 
610  const float distance,
611  MutableSpan<float> points_selection)
612 {
613  if (distance > 0.0f) {
615  data.unselected_point_indices.index_range(), 256, [&](const IndexRange range) {
616  for (const int i : range) {
617  const int point_i = data.unselected_point_indices[i];
618  const float distance_to_selected = data.distances_to_selected[i];
619  const float selection = distance_to_selected <= distance ? 1.0f : 0.0f;
620  points_selection[point_i] = selection;
621  }
622  });
624  data.selected_point_indices.index_range(), 512, [&](const IndexRange range) {
625  for (const int point_i : data.selected_point_indices.as_span().slice(range)) {
626  points_selection[point_i] = 1.0f;
627  }
628  });
629  }
630  else {
632  data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
633  for (const int i : range) {
634  const int point_i = data.selected_point_indices[i];
635  const float distance_to_unselected = data.distances_to_unselected[i];
636  const float selection = distance_to_unselected <= -distance ? 0.0f : 1.0f;
637  points_selection[point_i] = selection;
638  }
639  });
641  data.unselected_point_indices.index_range(), 512, [&](const IndexRange range) {
642  for (const int point_i : data.unselected_point_indices.as_span().slice(range)) {
643  points_selection[point_i] = 0.0f;
644  }
645  });
646  }
647 }
648 
649 static int select_grow_update(bContext *C, wmOperator *op, const float mouse_diff_x)
650 {
651  GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
652 
653  for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
654  Curves &curves_id = *curve_op_data->curves_id;
656  const float distance = curve_op_data->pixel_to_distance_factor * mouse_diff_x;
657 
658  /* Grow or shrink selection based on precomputed distances. */
659  switch (curves_id.selection_domain) {
660  case ATTR_DOMAIN_POINT: {
661  MutableSpan<float> points_selection = curves.selection_point_float_for_write();
662  update_points_selection(*curve_op_data, distance, points_selection);
663  break;
664  }
665  case ATTR_DOMAIN_CURVE: {
666  Array<float> new_points_selection(curves.points_num());
667  update_points_selection(*curve_op_data, distance, new_points_selection);
668  /* Propagate grown point selection to the curve selection. */
669  MutableSpan<float> curves_selection = curves.selection_curve_float_for_write();
670  for (const int curve_i : curves.curves_range()) {
671  const IndexRange points = curves.points_for_curve(curve_i);
672  const Span<float> points_selection = new_points_selection.as_span().slice(points);
673  const float max_selection = *std::max_element(points_selection.begin(),
674  points_selection.end());
675  curves_selection[curve_i] = max_selection;
676  }
677  break;
678  }
679  }
680 
681  /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
682  * attribute for now. */
684  WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
685  }
686 
687  return OPERATOR_FINISHED;
688 }
689 
690 static void select_grow_invoke_per_curve(Curves &curves_id,
691  Object &curves_ob,
692  const ARegion &region,
693  const View3D &v3d,
694  const RegionView3D &rv3d,
695  GrowOperatorDataPerCurve &curve_op_data)
696 {
697  curve_op_data.curves_id = &curves_id;
699  const Span<float3> positions = curves.positions();
700 
701  /* Find indices of selected and unselected points. */
702  switch (curves_id.selection_domain) {
703  case ATTR_DOMAIN_POINT: {
704  const VArray<float> points_selection = curves.selection_point_float();
705  curve_op_data.original_selection.reinitialize(points_selection.size());
706  points_selection.materialize(curve_op_data.original_selection);
707  for (const int point_i : points_selection.index_range()) {
708  const float point_selection = points_selection[point_i];
709  if (point_selection > 0.0f) {
710  curve_op_data.selected_point_indices.append(point_i);
711  }
712  else {
713  curve_op_data.unselected_point_indices.append(point_i);
714  }
715  }
716 
717  break;
718  }
719  case ATTR_DOMAIN_CURVE: {
720  const VArray<float> curves_selection = curves.selection_curve_float();
721  curve_op_data.original_selection.reinitialize(curves_selection.size());
722  curves_selection.materialize(curve_op_data.original_selection);
723  for (const int curve_i : curves_selection.index_range()) {
724  const float curve_selection = curves_selection[curve_i];
725  const IndexRange points = curves.points_for_curve(curve_i);
726  if (curve_selection > 0.0f) {
727  for (const int point_i : points) {
728  curve_op_data.selected_point_indices.append(point_i);
729  }
730  }
731  else {
732  for (const int point_i : points) {
733  curve_op_data.unselected_point_indices.append(point_i);
734  }
735  }
736  }
737  break;
738  }
739  }
740 
742  1024 < curve_op_data.selected_point_indices.size() +
743  curve_op_data.unselected_point_indices.size(),
744  [&]() {
745  /* Build KD-tree for the selected points. */
746  KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.selected_point_indices.size());
747  BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
748  for (const int point_i : curve_op_data.selected_point_indices) {
749  const float3 &position = positions[point_i];
750  BLI_kdtree_3d_insert(kdtree, point_i, position);
751  }
752  BLI_kdtree_3d_balance(kdtree);
753 
754  /* For each unselected point, compute the distance to the closest selected point. */
755  curve_op_data.distances_to_selected.reinitialize(
756  curve_op_data.unselected_point_indices.size());
758  256,
759  [&](const IndexRange range) {
760  for (const int i : range) {
761  const int point_i = curve_op_data.unselected_point_indices[i];
762  const float3 &position = positions[point_i];
763  KDTreeNearest_3d nearest;
764  BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
765  curve_op_data.distances_to_selected[i] = nearest.dist;
766  }
767  });
768  },
769  [&]() {
770  /* Build KD-tree for the unselected points. */
771  KDTree_3d *kdtree = BLI_kdtree_3d_new(curve_op_data.unselected_point_indices.size());
772  BLI_SCOPED_DEFER([&]() { BLI_kdtree_3d_free(kdtree); });
773  for (const int point_i : curve_op_data.unselected_point_indices) {
774  const float3 &position = positions[point_i];
775  BLI_kdtree_3d_insert(kdtree, point_i, position);
776  }
777  BLI_kdtree_3d_balance(kdtree);
778 
779  /* For each selected point, compute the distance to the closest unselected point. */
780  curve_op_data.distances_to_unselected.reinitialize(
781  curve_op_data.selected_point_indices.size());
783  curve_op_data.selected_point_indices.index_range(), 256, [&](const IndexRange range) {
784  for (const int i : range) {
785  const int point_i = curve_op_data.selected_point_indices[i];
786  const float3 &position = positions[point_i];
787  KDTreeNearest_3d nearest;
788  BLI_kdtree_3d_find_nearest(kdtree, position, &nearest);
789  curve_op_data.distances_to_unselected[i] = nearest.dist;
790  }
791  });
792  });
793 
794  float4x4 curves_to_world_mat = curves_ob.obmat;
795  float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
796 
797  float4x4 projection;
798  ED_view3d_ob_project_mat_get(&rv3d, &curves_ob, projection.values);
799 
800  /* Compute how mouse movements in screen space are converted into grow/shrink distances in
801  * object space. */
802  curve_op_data.pixel_to_distance_factor = threading::parallel_reduce(
803  curve_op_data.selected_point_indices.index_range(),
804  256,
805  FLT_MAX,
806  [&](const IndexRange range, float pixel_to_distance_factor) {
807  for (const int i : range) {
808  const int point_i = curve_op_data.selected_point_indices[i];
809  const float3 &pos_cu = positions[point_i];
810 
811  float2 pos_re;
812  ED_view3d_project_float_v2_m4(&region, pos_cu, pos_re, projection.values);
813  if (pos_re.x < 0 || pos_re.y < 0 || pos_re.x > region.winx || pos_re.y > region.winy) {
814  continue;
815  }
816  /* Compute how far this point moves in curve space when it moves one unit in screen
817  * space. */
818  const float2 pos_offset_re = pos_re + float2(1, 0);
819  float3 pos_offset_wo;
820  ED_view3d_win_to_3d(
821  &v3d, &region, curves_to_world_mat * pos_cu, pos_offset_re, pos_offset_wo);
822  const float3 pos_offset_cu = world_to_curves_mat * pos_offset_wo;
823  const float dist_cu = math::distance(pos_cu, pos_offset_cu);
824  const float dist_re = math::distance(pos_re, pos_offset_re);
825  const float factor = dist_cu / dist_re;
826  math::min_inplace(pixel_to_distance_factor, factor);
827  }
828  return pixel_to_distance_factor;
829  },
830  [](const float a, const float b) { return std::min(a, b); });
831 }
832 
833 static int select_grow_invoke(bContext *C, wmOperator *op, const wmEvent *event)
834 {
835  Object *active_ob = CTX_data_active_object(C);
836  ARegion *region = CTX_wm_region(C);
837  View3D *v3d = CTX_wm_view3d(C);
839 
840  GrowOperatorData *op_data = MEM_new<GrowOperatorData>(__func__);
841  op->customdata = op_data;
842 
843  op_data->initial_mouse_x = event->xy[0];
844 
845  Curves &curves_id = *static_cast<Curves *>(active_ob->data);
846  auto curve_op_data = std::make_unique<GrowOperatorDataPerCurve>();
847  select_grow_invoke_per_curve(curves_id, *active_ob, *region, *v3d, *rv3d, *curve_op_data);
848  op_data->per_curve.append(std::move(curve_op_data));
849 
851  return OPERATOR_RUNNING_MODAL;
852 }
853 
854 static int select_grow_modal(bContext *C, wmOperator *op, const wmEvent *event)
855 {
856  GrowOperatorData &op_data = *static_cast<GrowOperatorData *>(op->customdata);
857  const int mouse_x = event->xy[0];
858  const int mouse_diff_x = mouse_x - op_data.initial_mouse_x;
859  switch (event->type) {
860  case MOUSEMOVE: {
861  select_grow_update(C, op, mouse_diff_x);
862  break;
863  }
864  case LEFTMOUSE: {
865  MEM_delete(&op_data);
866  return OPERATOR_FINISHED;
867  }
868  case EVT_ESCKEY:
869  case RIGHTMOUSE: {
870  /* Undo operator by resetting the selection to the original value. */
871  for (std::unique_ptr<GrowOperatorDataPerCurve> &curve_op_data : op_data.per_curve) {
872  Curves &curves_id = *curve_op_data->curves_id;
874  switch (curves_id.selection_domain) {
875  case ATTR_DOMAIN_POINT: {
876  MutableSpan<float> points_selection = curves.selection_point_float_for_write();
877  points_selection.copy_from(curve_op_data->original_selection);
878  break;
879  }
880  case ATTR_DOMAIN_CURVE: {
881  MutableSpan<float> curves_seletion = curves.selection_curve_float_for_write();
882  curves_seletion.copy_from(curve_op_data->original_selection);
883  break;
884  }
885  }
886 
887  /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic
888  * attribute for now. */
890  WM_event_add_notifier(C, NC_GEOM | ND_DATA, &curves_id);
891  }
892  MEM_delete(&op_data);
893  return OPERATOR_CANCELLED;
894  }
895  }
896  return OPERATOR_RUNNING_MODAL;
897 }
898 
899 } // namespace select_grow
900 
902 {
903  ot->name = "Select Grow";
904  ot->idname = __func__;
905  ot->description = "Select curves which are close to curves that are selected already";
906 
910 
912 
913  PropertyRNA *prop;
914  prop = RNA_def_float(ot->srna,
915  "distance",
916  0.1f,
917  -FLT_MAX,
918  FLT_MAX,
919  "Distance",
920  "By how much to grow the selection",
921  -10.0f,
922  10.f);
924 }
925 
926 namespace min_distance_edit {
927 
929 {
931  return false;
932  }
935  if (brush == nullptr) {
936  return false;
937  }
939  return false;
940  }
941  return true;
942 }
943 
948 
952 
955 
958  void *cursor;
959 
963 };
964 
966 {
968  ARegion *region = op_data.region;
969 
970  const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
971  const float brush_radius = BKE_brush_size_get(scene, op_data.brush);
972 
973  float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
974  if (math::is_zero(tangent_x_cu)) {
975  tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
976  }
977  tangent_x_cu = math::normalize(tangent_x_cu);
978  const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
979 
980  /* Sample a few points to get a good estimate of how large the grid has to be. */
981  Vector<float3> points_wo;
982  points_wo.append(op_data.pos_cu + min_distance * tangent_x_cu);
983  points_wo.append(op_data.pos_cu + min_distance * tangent_y_cu);
984  points_wo.append(op_data.pos_cu - min_distance * tangent_x_cu);
985  points_wo.append(op_data.pos_cu - min_distance * tangent_y_cu);
986 
987  Vector<float2> points_re;
988  for (const float3 &pos_wo : points_wo) {
989  float2 pos_re;
990  ED_view3d_project_v2(region, pos_wo, pos_re);
991  points_re.append(pos_re);
992  }
993 
994  float2 origin_re;
995  ED_view3d_project_v2(region, op_data.pos_cu, origin_re);
996 
997  int needed_points = 0;
998  for (const float2 &pos_re : points_re) {
999  const float distance = math::length(pos_re - origin_re);
1000  const int needed_points_iter = (brush_radius * 2.0f) / distance;
1001 
1002  if (needed_points_iter > needed_points) {
1003  needed_points = needed_points_iter;
1004  }
1005  }
1006 
1007  /* Limit to a hard-coded number since it only adds noise at some point. */
1008  return std::min(300, needed_points);
1009 }
1010 
1011 static void min_distance_edit_draw(bContext *C, int UNUSED(x), int UNUSED(y), void *customdata)
1012 {
1014  MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(customdata);
1015 
1016  const float min_distance = op_data.brush->curves_sculpt_settings->minimum_distance;
1017 
1018  float3 tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 0, 1});
1019  if (math::is_zero(tangent_x_cu)) {
1020  tangent_x_cu = math::cross(op_data.normal_cu, float3{0, 1, 0});
1021  }
1022  tangent_x_cu = math::normalize(tangent_x_cu);
1023  const float3 tangent_y_cu = math::normalize(math::cross(op_data.normal_cu, tangent_x_cu));
1024 
1025  const int points_per_side = calculate_points_per_side(C, op_data);
1026  const int points_per_axis_num = 2 * points_per_side + 1;
1027 
1028  Vector<float3> points_wo;
1029  for (const int x_i : IndexRange(points_per_axis_num)) {
1030  for (const int y_i : IndexRange(points_per_axis_num)) {
1031  const float x_iter = min_distance * (x_i - (points_per_axis_num - 1) / 2.0f);
1032  const float y_iter = min_distance * (y_i - (points_per_axis_num - 1) / 2.0f);
1033 
1034  const float3 point_pos_cu = op_data.pos_cu + op_data.normal_cu * 0.0001f +
1035  x_iter * tangent_x_cu + y_iter * tangent_y_cu;
1036  const float3 point_pos_wo = op_data.curves_to_world_mat * point_pos_cu;
1037  points_wo.append(point_pos_wo);
1038  }
1039  }
1040 
1041  float4 circle_col = float4(op_data.brush->add_col);
1042  float circle_alpha = op_data.brush->cursor_overlay_alpha;
1043  float brush_radius_re = BKE_brush_size_get(scene, op_data.brush);
1044 
1045  /* Draw the grid. */
1046  GPU_matrix_push();
1049 
1050  ARegion *region = op_data.region;
1051  RegionView3D *rv3d = op_data.rv3d;
1052  wmWindow *win = CTX_wm_window(C);
1053 
1054  /* It does the same as: `view3d_operator_needs_opengl(C);`. */
1055  wmViewport(&region->winrct);
1057  GPU_matrix_set(rv3d->viewmat);
1058 
1059  GPUVertFormat *format3d = immVertexFormat();
1060 
1061  const uint pos3d = GPU_vertformat_attr_add(format3d, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
1062  const uint col3d = GPU_vertformat_attr_add(format3d, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
1063 
1065 
1066  GPU_point_size(3.0f);
1067  immBegin(GPU_PRIM_POINTS, points_wo.size());
1068 
1069  float3 brush_origin_wo = op_data.curves_to_world_mat * op_data.pos_cu;
1070  float2 brush_origin_re;
1071  ED_view3d_project_v2(region, brush_origin_wo, brush_origin_re);
1072 
1073  /* Smooth alpha transition until the brush edge. */
1074  const int alpha_border_re = 20;
1075  const float dist_to_inner_border_re = brush_radius_re - alpha_border_re;
1076 
1077  for (const float3 &pos_wo : points_wo) {
1078  float2 pos_re;
1079  ED_view3d_project_v2(region, pos_wo, pos_re);
1080 
1081  const float dist_to_point_re = math::distance(pos_re, brush_origin_re);
1082  const float alpha = 1.0f - ((dist_to_point_re - dist_to_inner_border_re) / alpha_border_re);
1083 
1084  immAttr4f(col3d, 0.9f, 0.9f, 0.9f, alpha);
1085  immVertex3fv(pos3d, pos_wo);
1086  }
1087  immEnd();
1088  immUnbindProgram();
1089 
1090  /* Reset the drawing settings. */
1091  GPU_point_size(1.0f);
1093  GPU_matrix_pop();
1094 
1095  int4 scissor;
1096  GPU_scissor_get(scissor);
1097  wmWindowViewport(win);
1098  GPU_scissor(scissor[0], scissor[1], scissor[2], scissor[3]);
1099 
1100  /* Draw the brush circle. */
1101  GPU_matrix_translate_2f((float)op_data.initial_mouse.x, (float)op_data.initial_mouse.y);
1102 
1105 
1107 
1108  immUniformColor3fvAlpha(circle_col, circle_alpha);
1109  imm_draw_circle_wire_2d(pos2d, 0.0f, 0.0f, brush_radius_re, 80);
1110 
1111  immUnbindProgram();
1113 }
1114 
1115 static int min_distance_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1116 {
1118  ARegion *region = CTX_wm_region(C);
1119  View3D *v3d = CTX_wm_view3d(C);
1121 
1122  Object &curves_ob_orig = *CTX_data_active_object(C);
1123  Curves &curves_id_orig = *static_cast<Curves *>(curves_ob_orig.data);
1124  Object &surface_ob_orig = *curves_id_orig.surface;
1125  Object *surface_ob_eval = DEG_get_evaluated_object(depsgraph, &surface_ob_orig);
1126  if (surface_ob_eval == nullptr) {
1127  return OPERATOR_CANCELLED;
1128  }
1129  Mesh *surface_me_eval = BKE_object_get_evaluated_mesh(surface_ob_eval);
1130  if (surface_me_eval == nullptr) {
1131  return OPERATOR_CANCELLED;
1132  }
1133 
1134  BVHTreeFromMesh surface_bvh_eval;
1135  BKE_bvhtree_from_mesh_get(&surface_bvh_eval, surface_me_eval, BVHTREE_FROM_LOOPTRI, 2);
1136  BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh_eval); });
1137 
1138  const int2 mouse_pos_int_re{event->mval};
1139  const float2 mouse_pos_re{mouse_pos_int_re};
1140 
1141  float3 ray_start_wo, ray_end_wo;
1143  depsgraph, region, v3d, mouse_pos_re, ray_start_wo, ray_end_wo, true);
1144 
1145  const CurvesSurfaceTransforms transforms{curves_ob_orig, &surface_ob_orig};
1146 
1147  const float3 ray_start_su = transforms.world_to_surface * ray_start_wo;
1148  const float3 ray_end_su = transforms.world_to_surface * ray_end_wo;
1149  const float3 ray_direction_su = math::normalize(ray_end_su - ray_start_su);
1150 
1151  BVHTreeRayHit ray_hit;
1152  ray_hit.dist = FLT_MAX;
1153  ray_hit.index = -1;
1154  BLI_bvhtree_ray_cast(surface_bvh_eval.tree,
1155  ray_start_su,
1156  ray_direction_su,
1157  0.0f,
1158  &ray_hit,
1159  surface_bvh_eval.raycast_callback,
1160  &surface_bvh_eval);
1161  if (ray_hit.index == -1) {
1162  WM_report(RPT_ERROR, "Cursor must be over the surface mesh");
1163  return OPERATOR_CANCELLED;
1164  }
1165 
1166  const float3 hit_pos_su = ray_hit.co;
1167  const float3 hit_normal_su = ray_hit.no;
1168 
1169  const float3 hit_pos_cu = transforms.surface_to_curves * hit_pos_su;
1170  const float3 hit_normal_cu = math::normalize(transforms.surface_to_curves_normal *
1171  hit_normal_su);
1172 
1173  MinDistanceEditData *op_data = MEM_new<MinDistanceEditData>(__func__);
1174  op_data->curves_to_world_mat = transforms.curves_to_world;
1175  op_data->normal_cu = hit_normal_cu;
1176  op_data->pos_cu = hit_pos_cu;
1177  op_data->initial_mouse = event->xy;
1180 
1181  if (op_data->initial_minimum_distance <= 0.0f) {
1182  op_data->initial_minimum_distance = 0.01f;
1183  }
1184 
1185  op->customdata = op_data;
1186 
1187  /* Temporarily disable other paint cursors. */
1189  op_data->orig_paintcursors = wm->paintcursors;
1191 
1192  /* Add minimum distance paint cursor. */
1193  op_data->cursor = WM_paint_cursor_activate(
1195 
1196  op_data->region = CTX_wm_region(C);
1197  op_data->rv3d = CTX_wm_region_view3d(C);
1198 
1200  ED_region_tag_redraw(region);
1201  return OPERATOR_RUNNING_MODAL;
1202 }
1203 
1204 static int min_distance_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
1205 {
1206  ARegion *region = CTX_wm_region(C);
1207  MinDistanceEditData &op_data = *static_cast<MinDistanceEditData *>(op->customdata);
1208 
1209  auto finish = [&]() {
1211 
1212  /* Remove own cursor. */
1213  WM_paint_cursor_end(static_cast<wmPaintCursor *>(op_data.cursor));
1214  /* Restore original paint cursors. */
1215  wm->paintcursors = op_data.orig_paintcursors;
1216 
1217  ED_region_tag_redraw(region);
1218  MEM_freeN(&op_data);
1219  };
1220 
1221  switch (event->type) {
1222  case MOUSEMOVE: {
1223  const int2 mouse_pos_int_re{event->xy};
1224  const float2 mouse_pos_re{mouse_pos_int_re};
1225 
1226  const float mouse_diff_x = mouse_pos_int_re.x - op_data.initial_mouse.x;
1227  const float factor = powf(2, mouse_diff_x / UI_UNIT_X / 10.0f);
1229  factor;
1230 
1231  ED_region_tag_redraw(region);
1233  break;
1234  }
1235  case LEFTMOUSE: {
1236  if (event->val == KM_PRESS) {
1237  finish();
1238  return OPERATOR_FINISHED;
1239  }
1240  break;
1241  }
1242  case RIGHTMOUSE:
1243  case EVT_ESCKEY: {
1245  finish();
1247  return OPERATOR_CANCELLED;
1248  }
1249  }
1250 
1251  return OPERATOR_RUNNING_MODAL;
1252 }
1253 
1254 } // namespace min_distance_edit
1255 
1257 {
1258  ot->name = "Edit Minimum Distance";
1259  ot->idname = __func__;
1260  ot->description = "Change the minimum distance used by the density brush";
1261 
1265 
1267 }
1268 
1269 } // namespace blender::ed::sculpt_paint
1270 
1271 /* -------------------------------------------------------------------- */
1276 {
1277  using namespace blender::ed::sculpt_paint;
1284 }
1285 
@ ATTR_DOMAIN_CURVE
Definition: BKE_attribute.h:31
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
bool BKE_brush_use_size_pressure(const struct Brush *brush)
float BKE_brush_alpha_get(const struct Scene *scene, const struct Brush *brush)
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
bool BKE_brush_use_alpha_pressure(const struct Brush *brush)
void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
Definition: bvhutils.cc:1410
@ BVHTREE_FROM_LOOPTRI
Definition: BKE_bvhutils.h:73
BVHTree * BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, const struct Mesh *mesh, BVHCacheType bvh_cache_type, int tree_type)
Definition: bvhutils.cc:1213
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:770
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg)
Definition: context.c:1042
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
Low-level operations for curves.
General operations, lookup, etc. for blender objects.
struct Mesh * BKE_object_get_evaluated_mesh(const struct Object *object)
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint)
Definition: paint.c:1042
struct Paint * BKE_paint_get_active_from_context(const struct bContext *C)
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
Definition: BLI_kdopbvh.c:1942
A KD-tree for nearest neighbor search.
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
#define BLI_SCOPED_DEFER(function_to_defer)
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED_VARS(...)
#define UNUSED(x)
#define ELEM(...)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ CURVES_SCULPT_TOOL_SMOOTH
@ CURVES_SCULPT_TOOL_SELECTION_PAINT
@ CURVES_SCULPT_TOOL_DENSITY
@ CURVES_SCULPT_TOOL_GROW_SHRINK
@ CURVES_SCULPT_TOOL_DELETE
@ CURVES_SCULPT_TOOL_PINCH
@ CURVES_SCULPT_TOOL_SNAKE_HOOK
@ CURVES_SCULPT_TOOL_ADD
@ CURVES_SCULPT_TOOL_COMB
@ CURVES_SCULPT_TOOL_PUFF
@ CURVES_SCULPT_TOOL_SLIDE
struct CurvesGeometry CurvesGeometry
@ OB_MODE_SCULPT_CURVES
@ OB_MODE_OBJECT
#define RGN_TYPE_ANY
#define SPACE_TYPE_ANY
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_paint_cursor_start(struct Paint *p, bool(*poll)(struct bContext *C))
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports)
Definition: object_modes.c:161
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], bool do_clip_planes)
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_v2(const struct ARegion *region, const float world[3], float r_region_co[2])
void immUnbindProgram(void)
void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
void immAttr4f(uint attr_id, float x, float y, float z, float w)
GPUVertFormat * immVertexFormat(void)
void immVertex3fv(uint attr_id, const float data[3])
void immBegin(GPUPrimType, uint vertex_len)
void immUniformColor3fvAlpha(const float rgb[3], float a)
void immEnd(void)
void imm_draw_circle_wire_2d(uint shdr_pos, float x, float y, float radius, int nsegments)
_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 y
void GPU_matrix_pop(void)
Definition: gpu_matrix.cc:126
void GPU_matrix_pop_projection(void)
Definition: gpu_matrix.cc:140
#define GPU_matrix_set(x)
Definition: GPU_matrix.h:225
void GPU_matrix_push(void)
Definition: gpu_matrix.cc:119
#define GPU_matrix_projection_set(x)
Definition: GPU_matrix.h:226
void GPU_matrix_translate_2f(float x, float y)
Definition: gpu_matrix.cc:174
void GPU_matrix_push_projection(void)
Definition: gpu_matrix.cc:133
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_SHADER_2D_UNIFORM_COLOR
Definition: GPU_shader.h:201
@ GPU_SHADER_3D_POINT_FIXED_SIZE_VARYING_COLOR
Definition: GPU_shader.h:329
float float4x4[4][4]
float float4[4]
@ 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_scissor(int x, int y, int width, int height)
Definition: gpu_state.cc:185
void GPU_point_size(float size)
Definition: gpu_state.cc:164
void GPU_scissor_get(int coords[4])
Definition: gpu_state.cc:254
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
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 curves
@ PROP_DISTANCE
Definition: RNA_types.h:149
#define C
Definition: RandGen.cpp:25
@ UI_ITEM_R_SLIDER
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
#define UI_UNIT_X
@ KM_PRESS
Definition: WM_types.h:267
@ OPTYPE_DEPENDS_ON_CURSOR
Definition: WM_types.h:184
@ 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
#define ND_MODE
Definition: WM_types.h:393
#define NC_SCENE
Definition: WM_types.h:328
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
ATTR_WARN_UNUSED_RESULT const BMVert * v
static unsigned long seed
Definition: btSoftBody.h:39
Span< T > as_span() const
Definition: BLI_array.hh:231
void reinitialize(const int64_t new_size)
Definition: BLI_array.hh:387
constexpr T * end() const
Definition: BLI_span.hh:557
constexpr void fill(const T &value)
Definition: BLI_span.hh:527
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition: BLI_span.hh:581
constexpr void copy_from(Span< T > values)
Definition: BLI_span.hh:707
constexpr T * begin() const
Definition: BLI_span.hh:553
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr Span slice(int64_t start, int64_t size) const
Definition: BLI_span.hh:142
constexpr const T * end() const
Definition: BLI_span.hh:212
constexpr const T * begin() const
Definition: BLI_span.hh:208
IndexRange index_range() const
void materialize(MutableSpan< T > r_span) const
int64_t size() const
Definition: BLI_vector.hh:694
void append(const T &value)
Definition: BLI_vector.hh:433
IndexRange index_range() const
Definition: BLI_vector.hh:920
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
#define powf(x, y)
Definition: cuda/compat.h:103
bool CURVES_SCULPT_mode_poll_view3d(bContext *C)
bool CURVES_SCULPT_mode_poll(bContext *C)
void ED_operatortypes_sculpt_curves()
Scene scene
const Depsgraph * depsgraph
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
static unsigned a[3]
Definition: RandGen.cpp:78
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
bool editable_curves_poll(bContext *C)
Definition: curves_ops.cc:128
bool has_anything_selected(const Curves &curves_id)
Definition: curves_ops.cc:852
VectorSet< Curves * > get_unique_editable_curves(const bContext &C)
Definition: curves_ops.cc:76
bool curves_with_surface_poll(bContext *C)
Definition: curves_ops.cc:123
bool curves_poll(bContext *C)
Definition: curves_ops.cc:133
static void min_distance_edit_draw(bContext *C, int UNUSED(x), int UNUSED(y), void *customdata)
static int min_distance_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int min_distance_edit_modal(bContext *C, wmOperator *op, const wmEvent *event)
static int calculate_points_per_side(bContext *C, MinDistanceEditData &op_data)
static bool select_end_poll(bContext *C)
static int select_end_exec(bContext *C, wmOperator *op)
static int select_grow_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int select_grow_update(bContext *C, wmOperator *op, const float mouse_diff_x)
static void update_points_selection(const GrowOperatorDataPerCurve &data, const float distance, MutableSpan< float > points_selection)
static void select_grow_invoke_per_curve(Curves &curves_id, Object &curves_ob, const ARegion &region, const View3D &v3d, const RegionView3D &rv3d, GrowOperatorDataPerCurve &curve_op_data)
static int select_grow_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void select_random_ui(bContext *UNUSED(C), wmOperator *op)
static int select_random_exec(bContext *C, wmOperator *op)
std::unique_ptr< CurvesSculptStrokeOperation > new_add_operation()
static void curves_sculptmode_exit(bContext *C)
std::unique_ptr< CurvesSculptStrokeOperation > new_pinch_operation(const BrushStrokeMode brush_mode, const bContext &C)
static void SCULPT_CURVES_OT_select_end(wmOperatorType *ot)
std::unique_ptr< CurvesSculptStrokeOperation > new_comb_operation()
static int sculpt_curves_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
float brush_radius_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
static void SCULPT_CURVES_OT_select_grow(wmOperatorType *ot)
static void stroke_done(const bContext *C, PaintStroke *stroke)
static void CURVES_OT_sculptmode_toggle(wmOperatorType *ot)
static void curves_sculptmode_enter(bContext *C)
std::unique_ptr< CurvesSculptStrokeOperation > new_snake_hook_operation()
std::unique_ptr< CurvesSculptStrokeOperation > new_grow_shrink_operation(const BrushStrokeMode brush_mode, const bContext &C)
static int curves_sculptmode_toggle_exec(bContext *C, wmOperator *op)
static bool stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
static std::unique_ptr< CurvesSculptStrokeOperation > start_brush_operation(bContext &C, wmOperator &op, const StrokeExtension &stroke_start)
std::unique_ptr< CurvesSculptStrokeOperation > new_smooth_operation()
std::unique_ptr< CurvesSculptStrokeOperation > new_delete_operation()
std::unique_ptr< CurvesSculptStrokeOperation > new_selection_paint_operation(const BrushStrokeMode brush_mode, const bContext &C)
float brush_strength_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
static bool stroke_get_location(bContext *C, float out[3], const float mouse[2], bool UNUSED(force_original))
static int sculpt_curves_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void SCULPT_CURVES_OT_select_random(wmOperatorType *ot)
static void SCULPT_CURVES_OT_min_distance_edit(wmOperatorType *ot)
static void sculpt_curves_stroke_cancel(bContext *C, wmOperator *op)
std::unique_ptr< CurvesSculptStrokeOperation > new_slide_operation()
std::unique_ptr< CurvesSculptStrokeOperation > new_puff_operation()
static void stroke_update_step(bContext *C, wmOperator *op, PaintStroke *UNUSED(stroke), PointerRNA *stroke_element)
float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
std::unique_ptr< CurvesSculptStrokeOperation > new_density_operation(const BrushStrokeMode brush_mode, const bContext &C, const StrokeExtension &stroke_start)
static void SCULPT_CURVES_OT_brush_stroke(struct wmOperatorType *ot)
vec_base< T, 3 > cross(const vec_base< T, 3 > &a, const vec_base< T, 3 > &b)
T length(const vec_base< T, Size > &a)
T distance(const T &a, const T &b)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
bool is_zero(const T &a)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
void parallel_invoke(Functions &&...functions)
Definition: BLI_task.hh:99
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition: BLI_task.hh:73
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
MutableSpan< float3 > positions
void paint_stroke_cancel(struct bContext *C, struct wmOperator *op, struct PaintStroke *stroke)
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event, struct PaintStroke **stroke_p)
struct PaintStroke * paint_stroke_new(struct bContext *C, struct wmOperator *op, StrokeGetLocation get_location, StrokeTestStart test_start, StrokeUpdateStep update_step, StrokeRedraw redraw, StrokeDone done, int event_type)
Definition: paint_stroke.c:874
BrushStrokeMode
Definition: paint_intern.h:448
void paint_stroke_free(struct bContext *C, struct wmOperator *op, struct PaintStroke *stroke)
void paint_stroke_operator_properties(struct wmOperatorType *ot)
Definition: paint_utils.c:188
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(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:3836
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_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype)
Definition: rna_define.c:1534
#define min(a, b)
Definition: sort.c:35
#define INT32_MAX
Definition: stdint.h:137
unsigned int uint32_t
Definition: stdint.h:80
#define INT32_MIN
Definition: stdint.h:136
BVHTree_RayCastCallback raycast_callback
Definition: BKE_bvhutils.h:54
struct BVHTree * tree
Definition: BKE_bvhutils.h:50
float co[3]
Definition: BLI_kdopbvh.h:68
float no[3]
Definition: BLI_kdopbvh.h:70
float add_col[4]
int cursor_overlay_alpha
char curves_sculpt_tool
struct BrushCurvesSculptSettings * curves_sculpt_settings
CurvesGeometry geometry
char selection_domain
struct Object * surface
void * data
float viewmat[4][4]
float winmat[4][4]
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
std::unique_ptr< CurvesSculptStrokeOperation > operation
Vector< std::unique_ptr< GrowOperatorDataPerCurve > > per_curve
short val
Definition: WM_types.h:680
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
void(* ui)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:954
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_report(eReportType type, const char *message)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ MOUSEMOVE
@ LEFTMOUSE
@ EVT_ESCKEY
wmOperatorType * ot
Definition: wm_files.c:3479
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))
bool WM_paint_cursor_end(wmPaintCursor *handle)
wmPaintCursor * WM_paint_cursor_activate(short space_type, short region_type, bool(*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata)
void wmViewport(const rcti *winrct)
Definition: wm_subwindow.c:21
void wmWindowViewport(wmWindow *win)
Definition: wm_subwindow.c:72
void WM_toolsystem_update_from_context_view3d(bContext *C)