Blender  V3.3
sculpt_boundary.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2020 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_blenlib.h"
11 #include "BLI_edgehash.h"
12 #include "BLI_math.h"
13 #include "BLI_task.h"
14 
15 #include "DNA_brush_types.h"
16 #include "DNA_mesh_types.h"
17 #include "DNA_meshdata_types.h"
18 #include "DNA_object_types.h"
19 
20 #include "BKE_brush.h"
21 #include "BKE_ccg.h"
22 #include "BKE_colortools.h"
23 #include "BKE_context.h"
24 #include "BKE_mesh.h"
25 #include "BKE_multires.h"
26 #include "BKE_node.h"
27 #include "BKE_object.h"
28 #include "BKE_paint.h"
29 #include "BKE_pbvh.h"
30 #include "BKE_scene.h"
31 
32 #include "paint_intern.h"
33 #include "sculpt_intern.h"
34 
35 #include "GPU_immediate.h"
36 #include "GPU_immediate_util.h"
37 #include "GPU_matrix.h"
38 #include "GPU_state.h"
39 
40 #include "bmesh.h"
41 
42 #include <math.h>
43 #include <stdlib.h>
44 
45 #define BOUNDARY_VERTEX_NONE -1
46 #define BOUNDARY_STEPS_NONE -1
47 
53  float radius_sq;
55 
57  SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
58 {
60 
61  if (!SCULPT_vertex_visible_get(ss, to_v)) {
62  return false;
63  }
64 
65  if (!is_duplicate) {
66  data->floodfill_steps[to_v] = data->floodfill_steps[from_v] + 1;
67  }
68  else {
69  data->floodfill_steps[to_v] = data->floodfill_steps[from_v];
70  }
71 
72  if (SCULPT_vertex_is_boundary(ss, to_v)) {
73  if (data->floodfill_steps[to_v] < data->boundary_initial_vertex_steps) {
74  data->boundary_initial_vertex_steps = data->floodfill_steps[to_v];
75  data->boundary_initial_vertex = to_v;
76  }
77  }
78 
79  const float len_sq = len_squared_v3v3(SCULPT_vertex_co_get(ss, data->initial_vertex),
80  SCULPT_vertex_co_get(ss, to_v));
81  return len_sq < data->radius_sq;
82 }
83 
84 /* From a vertex index anywhere in the mesh, returns the closest vertex in a mesh boundary inside
85  * the given radius, if it exists. */
87  const int initial_vertex,
88  const float radius)
89 {
90 
91  if (SCULPT_vertex_is_boundary(ss, initial_vertex)) {
92  return initial_vertex;
93  }
94 
95  SculptFloodFill flood;
96  SCULPT_floodfill_init(ss, &flood);
97  SCULPT_floodfill_add_initial(&flood, initial_vertex);
98 
100  .initial_vertex = initial_vertex,
101  .boundary_initial_vertex = BOUNDARY_VERTEX_NONE,
102  .boundary_initial_vertex_steps = INT_MAX,
103  .radius_sq = radius * radius,
104  };
105 
107  SCULPT_vertex_count_get(ss), sizeof(int), "floodfill steps");
108 
110  SCULPT_floodfill_free(&flood);
111 
112  MEM_freeN(fdata.floodfill_steps);
113  return fdata.boundary_initial_vertex;
114 }
115 
116 /* Used to allocate the memory of the boundary index arrays. This was decided considered the most
117  * common use cases for the brush deformers, taking into account how many vertices those
118  * deformations usually need in the boundary. */
120 
122  const int new_index,
123  const float distance,
124  GSet *included_vertices)
125 {
126 
127  boundary->vertices[boundary->num_vertices] = new_index;
128  if (boundary->distance) {
129  boundary->distance[new_index] = distance;
130  }
131  if (included_vertices) {
132  BLI_gset_add(included_vertices, POINTER_FROM_INT(new_index));
133  }
134  boundary->num_vertices++;
135  if (boundary->num_vertices >= boundary->vertices_capacity) {
137  boundary->vertices = MEM_reallocN_id(
138  boundary->vertices, boundary->vertices_capacity * sizeof(int), "boundary indices");
139  }
140 };
141 
142 static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
143 {
144 
145  boundary->edges[boundary->num_edges].v1 = v1;
146  boundary->edges[boundary->num_edges].v2 = v2;
147  boundary->num_edges++;
148 
149  if (boundary->num_edges >= boundary->edges_capacity) {
151  boundary->edges = MEM_reallocN_id(boundary->edges,
152  boundary->edges_capacity * sizeof(SculptBoundaryPreviewEdge),
153  "boundary edges");
154  }
155 };
156 
162  const int initial_vertex)
163 {
164 
165  if (!SCULPT_vertex_visible_get(ss, initial_vertex)) {
166  return false;
167  }
168 
169  int neighbor_count = 0;
170  int boundary_vertex_count = 0;
172  SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, initial_vertex, ni) {
173  if (SCULPT_vertex_visible_get(ss, ni.index)) {
174  neighbor_count++;
175  if (SCULPT_vertex_is_boundary(ss, ni.index)) {
176  boundary_vertex_count++;
177  }
178  }
179  }
181 
182  /* Corners are ambiguous as it can't be decide which boundary should be active. The flood fill
183  * should also stop at corners. */
184  if (neighbor_count <= 2) {
185  return false;
186  }
187 
188  /* Non manifold geometry in the mesh boundary.
189  * The deformation result will be unpredictable and not very useful. */
190  if (boundary_vertex_count > 2) {
191  return false;
192  }
193 
194  return true;
195 }
196 
197 /* Flood fill that adds to the boundary data all the vertices from a boundary and its duplicates.
198  */
199 
200 typedef struct BoundaryFloodFillData {
204 
206 
208 
210  SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
211 {
212  BoundaryFloodFillData *data = userdata;
213  SculptBoundary *boundary = data->boundary;
214  if (!SCULPT_vertex_is_boundary(ss, to_v)) {
215  return false;
216  }
217  const float edge_len = len_v3v3(SCULPT_vertex_co_get(ss, from_v),
218  SCULPT_vertex_co_get(ss, to_v));
219  const float distance_boundary_to_dst = boundary->distance ?
220  boundary->distance[from_v] + edge_len :
221  0.0f;
222  sculpt_boundary_index_add(boundary, to_v, distance_boundary_to_dst, data->included_vertices);
223  if (!is_duplicate) {
224  sculpt_boundary_preview_edge_add(boundary, from_v, to_v);
225  }
227 }
228 
230  SculptBoundary *boundary,
231  const bool init_boundary_distances,
232  const int initial_boundary_index)
233 {
234 
235  const int totvert = SCULPT_vertex_count_get(ss);
236  boundary->vertices = MEM_malloc_arrayN(
237  BOUNDARY_INDICES_BLOCK_SIZE, sizeof(int), "boundary indices");
238  if (init_boundary_distances) {
239  boundary->distance = MEM_calloc_arrayN(totvert, sizeof(float), "boundary distances");
240  }
241  boundary->edges = MEM_malloc_arrayN(
242  BOUNDARY_INDICES_BLOCK_SIZE, sizeof(SculptBoundaryPreviewEdge), "boundary edges");
243 
244  GSet *included_vertices = BLI_gset_int_new_ex("included vertices", BOUNDARY_INDICES_BLOCK_SIZE);
245  SculptFloodFill flood;
246  SCULPT_floodfill_init(ss, &flood);
247 
248  boundary->initial_vertex = initial_boundary_index;
250  SCULPT_vertex_co_get(ss, boundary->initial_vertex));
251  sculpt_boundary_index_add(boundary, initial_boundary_index, 0.0f, included_vertices);
252  SCULPT_floodfill_add_initial(&flood, initial_boundary_index);
253 
254  BoundaryFloodFillData fdata = {
255  .boundary = boundary,
256  .included_vertices = included_vertices,
257  .last_visited_vertex = BOUNDARY_VERTEX_NONE,
258 
259  };
260 
261  SCULPT_floodfill_execute(ss, &flood, boundary_floodfill_cb, &fdata);
262  SCULPT_floodfill_free(&flood);
263 
264  /* Check if the boundary loops into itself and add the extra preview edge to close the loop. */
269  if (BLI_gset_haskey(included_vertices, POINTER_FROM_INT(ni.index)) &&
272  boundary->forms_loop = true;
273  }
274  }
276  }
277 
278  BLI_gset_free(included_vertices, NULL);
279 }
280 
288  SculptBoundary *boundary,
289  const int initial_vertex,
290  const float radius)
291 {
292  const int totvert = SCULPT_vertex_count_get(ss);
293 
294  const bool has_duplicates = BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS;
295 
296  boundary->edit_info = MEM_malloc_arrayN(
297  totvert, sizeof(SculptBoundaryEditInfo), "Boundary edit info");
298 
299  for (int i = 0; i < totvert; i++) {
302  }
303 
304  GSQueue *current_iteration = BLI_gsqueue_new(sizeof(int));
305  GSQueue *next_iteration = BLI_gsqueue_new(sizeof(int));
306 
307  /* Initialized the first iteration with the vertices already in the boundary. This is propagation
308  * step 0. */
309  BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices");
310  for (int i = 0; i < boundary->num_vertices; i++) {
311  boundary->edit_info[boundary->vertices[i]].original_vertex = boundary->vertices[i];
312  boundary->edit_info[boundary->vertices[i]].num_propagation_steps = 0;
313 
314  /* This ensures that all duplicate vertices in the boundary have the same original_vertex
315  * index, so the deformation for them will be the same. */
316  if (has_duplicates) {
317  SculptVertexNeighborIter ni_duplis;
318  SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN (ss, boundary->vertices[i], ni_duplis) {
319  if (ni_duplis.is_duplicate) {
320  boundary->edit_info[ni_duplis.index].original_vertex = boundary->vertices[i];
321  }
322  }
324  }
325 
326  BLI_gsqueue_push(current_iteration, &boundary->vertices[i]);
327  }
328 
329  int num_propagation_steps = 0;
330  float accum_distance = 0.0f;
331 
332  while (true) {
333  /* Stop adding steps to edit info. This happens when a steps is further away from the boundary
334  * than the brush radius or when the entire mesh was already processed. */
335  if (accum_distance > radius || BLI_gsqueue_is_empty(current_iteration)) {
336  boundary->max_propagation_steps = num_propagation_steps;
337  break;
338  }
339 
340  while (!BLI_gsqueue_is_empty(current_iteration)) {
341  int from_v;
342  BLI_gsqueue_pop(current_iteration, &from_v);
343 
346  const bool is_visible = SCULPT_vertex_visible_get(ss, ni.index);
347  if (!is_visible ||
349  continue;
350  }
351  boundary->edit_info[ni.index].original_vertex =
352  boundary->edit_info[from_v].original_vertex;
353 
354  BLI_BITMAP_ENABLE(visited_vertices, ni.index);
355 
356  if (ni.is_duplicate) {
357  /* Grids duplicates handling. */
358  boundary->edit_info[ni.index].num_propagation_steps =
359  boundary->edit_info[from_v].num_propagation_steps;
360  }
361  else {
362  boundary->edit_info[ni.index].num_propagation_steps =
363  boundary->edit_info[from_v].num_propagation_steps + 1;
364 
365  BLI_gsqueue_push(next_iteration, &ni.index);
366 
367  /* When copying the data to the neighbor for the next iteration, it has to be copied to
368  * all its duplicates too. This is because it is not possible to know if the updated
369  * neighbor or one if its uninitialized duplicates is going to come first in order to
370  * copy the data in the from_v neighbor iterator. */
371  if (has_duplicates) {
372  SculptVertexNeighborIter ni_duplis;
374  if (ni_duplis.is_duplicate) {
375  boundary->edit_info[ni_duplis.index].original_vertex =
376  boundary->edit_info[from_v].original_vertex;
377  boundary->edit_info[ni_duplis.index].num_propagation_steps =
378  boundary->edit_info[from_v].num_propagation_steps + 1;
379  }
380  }
382  }
383 
384  /* Check the distance using the vertex that was propagated from the initial vertex that
385  * was used to initialize the boundary. */
386  if (boundary->edit_info[from_v].original_vertex == initial_vertex) {
387  boundary->pivot_vertex = ni.index;
389  accum_distance += len_v3v3(SCULPT_vertex_co_get(ss, from_v),
390  SCULPT_vertex_co_get(ss, ni.index));
391  }
392  }
393  }
395  }
396 
397  /* Copy the new vertices to the queue to be processed in the next iteration. */
398  while (!BLI_gsqueue_is_empty(next_iteration)) {
399  int next_v;
400  BLI_gsqueue_pop(next_iteration, &next_v);
401  BLI_gsqueue_push(current_iteration, &next_v);
402  }
403 
404  num_propagation_steps++;
405  }
406 
407  MEM_SAFE_FREE(visited_vertices);
408 
409  BLI_gsqueue_free(current_iteration);
410  BLI_gsqueue_free(next_iteration);
411 }
412 
413 /* This functions assigns a falloff factor to each one of the SculptBoundaryEditInfo structs based
414  * on the brush curve and its propagation steps. The falloff goes from the boundary into the mesh.
415  */
417  SculptBoundary *boundary,
418  Brush *brush,
419  const float radius)
420 {
421  const int totvert = SCULPT_vertex_count_get(ss);
423 
424  for (int i = 0; i < totvert; i++) {
425  if (boundary->edit_info[i].num_propagation_steps != -1) {
427  brush, boundary->edit_info[i].num_propagation_steps, boundary->max_propagation_steps);
428  }
429 
430  if (boundary->edit_info[i].original_vertex == boundary->initial_vertex) {
431  /* All vertices that are propagated from the original vertex won't be affected by the
432  * boundary falloff, so there is no need to calculate anything else. */
433  continue;
434  }
435 
436  if (!boundary->distance) {
437  /* There are falloff modes that do not require to modify the previously calculated falloff
438  * based on boundary distances. */
439  continue;
440  }
441 
442  const float boundary_distance = boundary->distance[boundary->edit_info[i].original_vertex];
443  float falloff_distance = 0.0f;
444  float direction = 1.0f;
445 
446  switch (brush->boundary_falloff_type) {
448  falloff_distance = boundary_distance;
449  break;
451  const int div = boundary_distance / radius;
452  const float mod = fmodf(boundary_distance, radius);
453  falloff_distance = div % 2 == 0 ? mod : radius - mod;
454  } break;
456  const int div = boundary_distance / radius;
457  const float mod = fmodf(boundary_distance, radius);
458  falloff_distance = div % 2 == 0 ? mod : radius - mod;
459  /* Inverts the faloff in the intervals 1 2 5 6 9 10 ... */
460  if (((div - 1) & 2) == 0) {
461  direction = -1.0f;
462  }
463  } break;
465  /* For constant falloff distances are not allocated, so this should never happen. */
466  BLI_assert(false);
467  }
468 
469  boundary->edit_info[i].strength_factor *= direction * BKE_brush_curve_strength(
470  brush, falloff_distance, radius);
471  }
472 }
473 
475  Brush *brush,
476  const int initial_vertex,
477  const float radius)
478 {
479  SculptSession *ss = object->sculpt;
480 
481  if (initial_vertex == BOUNDARY_VERTEX_NONE) {
482  return NULL;
483  }
484 
487 
488  const int boundary_initial_vertex = sculpt_boundary_get_closest_boundary_vertex(
489  ss, initial_vertex, radius);
490 
491  if (boundary_initial_vertex == BOUNDARY_VERTEX_NONE) {
492  return NULL;
493  }
494 
495  /* Starting from a vertex that is the limit of a boundary is ambiguous, so return NULL instead of
496  * forcing a random active boundary from a corner. */
497  if (!sculpt_boundary_is_vertex_in_editable_boundary(ss, initial_vertex)) {
498  return NULL;
499  }
500 
501  SculptBoundary *boundary = MEM_callocN(sizeof(SculptBoundary), "Boundary edit data");
502 
503  const bool init_boundary_distances = brush ? brush->boundary_falloff_type !=
505  false;
506 
507  sculpt_boundary_indices_init(ss, boundary, init_boundary_distances, boundary_initial_vertex);
508 
509  const float boundary_radius = brush ? radius * (1.0f + brush->boundary_offset) : radius;
510  sculpt_boundary_edit_data_init(ss, boundary, boundary_initial_vertex, boundary_radius);
511 
512  return boundary;
513 }
514 
516 {
517  MEM_SAFE_FREE(boundary->vertices);
518  MEM_SAFE_FREE(boundary->edges);
519  MEM_SAFE_FREE(boundary->distance);
520  MEM_SAFE_FREE(boundary->edit_info);
523  MEM_SAFE_FREE(boundary->slide.directions);
524  MEM_SAFE_FREE(boundary);
525 }
526 
527 /* These functions initialize the required vectors for the desired deformation using the
528  * SculptBoundaryEditInfo. They calculate the data using the vertices that have the
529  * max_propagation_steps value and them this data is copied to the rest of the vertices using the
530  * original vertex index. */
532 {
533  const int totvert = SCULPT_vertex_count_get(ss);
535  totvert, sizeof(float[3]), "pivot rotation axis");
536  boundary->bend.pivot_positions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "pivot positions");
537 
538  for (int i = 0; i < totvert; i++) {
539  if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
540  continue;
541  }
542  float dir[3];
543  float normal[3];
545  sub_v3_v3v3(dir,
547  SCULPT_vertex_co_get(ss, i));
549  boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex], dir, normal);
551  copy_v3_v3(boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex],
552  SCULPT_vertex_co_get(ss, i));
553  }
554 
555  for (int i = 0; i < totvert; i++) {
557  continue;
558  }
559  copy_v3_v3(boundary->bend.pivot_positions[i],
560  boundary->bend.pivot_positions[boundary->edit_info[i].original_vertex]);
561  copy_v3_v3(boundary->bend.pivot_rotation_axis[i],
562  boundary->bend.pivot_rotation_axis[boundary->edit_info[i].original_vertex]);
563  }
564 }
565 
567 {
568  const int totvert = SCULPT_vertex_count_get(ss);
569  boundary->slide.directions = MEM_calloc_arrayN(totvert, sizeof(float[3]), "slide directions");
570 
571  for (int i = 0; i < totvert; i++) {
572  if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) {
573  continue;
574  }
575  sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex],
577  SCULPT_vertex_co_get(ss, i));
578  normalize_v3(boundary->slide.directions[boundary->edit_info[i].original_vertex]);
579  }
580 
581  for (int i = 0; i < totvert; i++) {
583  continue;
584  }
585  copy_v3_v3(boundary->slide.directions[i],
586  boundary->slide.directions[boundary->edit_info[i].original_vertex]);
587  }
588 }
589 
591 {
592  zero_v3(boundary->twist.pivot_position);
593  float(*poly_verts)[3] = MEM_malloc_arrayN(
594  boundary->num_vertices, sizeof(float[3]), "poly verts");
595  for (int i = 0; i < boundary->num_vertices; i++) {
596  add_v3_v3(boundary->twist.pivot_position, SCULPT_vertex_co_get(ss, boundary->vertices[i]));
597  copy_v3_v3(poly_verts[i], SCULPT_vertex_co_get(ss, boundary->vertices[i]));
598  }
599  mul_v3_fl(boundary->twist.pivot_position, 1.0f / boundary->num_vertices);
600  if (boundary->forms_loop) {
601  normal_poly_v3(boundary->twist.rotation_axis, poly_verts, boundary->num_vertices);
602  }
603  else {
604  sub_v3_v3v3(boundary->twist.rotation_axis,
605  SCULPT_vertex_co_get(ss, boundary->pivot_vertex),
606  SCULPT_vertex_co_get(ss, boundary->initial_vertex));
607  normalize_v3(boundary->twist.rotation_axis);
608  }
609  MEM_freeN(poly_verts);
610 }
611 
613  SculptBoundary *boundary)
614 {
615  float plane[4];
616  float pos[3];
617  float normal[3];
622  return dist_signed_to_plane_v3(pos, plane);
623 }
624 
625 /* Deformation tasks callbacks. */
626 static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata,
627  const int n,
628  const TaskParallelTLS *__restrict UNUSED(tls))
629 {
630  SculptThreadedTaskData *data = userdata;
631  SculptSession *ss = data->ob->sculpt;
632  const int symm_area = ss->cache->mirror_symmetry_pass;
633  SculptBoundary *boundary = ss->cache->boundaries[symm_area];
635  const Brush *brush = data->brush;
636 
637  const float strength = ss->cache->bstrength;
638 
639  PBVHVertexIter vd;
640  SculptOrigVertData orig_data;
641  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
642 
643  const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
644  float angle_factor = disp / ss->cache->radius;
645  /* Angle Snapping when inverting the brush. */
646  if (ss->cache->invert) {
647  angle_factor = floorf(angle_factor * 10) / 10.0f;
648  }
649  const float angle = angle_factor * M_PI;
650 
651  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
652  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
653  continue;
654  }
655 
656  SCULPT_orig_vert_data_update(&orig_data, &vd);
658  orig_data.co, boundary->initial_vertex_position, symm)) {
659  continue;
660  }
661 
662  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
663  const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
664  float t_orig_co[3];
665  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
666  sub_v3_v3v3(t_orig_co, orig_data.co, boundary->bend.pivot_positions[vd.index]);
667  rotate_v3_v3v3fl(target_co,
668  t_orig_co,
669  boundary->bend.pivot_rotation_axis[vd.index],
670  angle * boundary->edit_info[vd.index].strength_factor * mask * automask);
671  add_v3_v3(target_co, boundary->bend.pivot_positions[vd.index]);
672 
673  if (vd.mvert) {
675  }
676  }
678 }
679 
680 static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata,
681  const int n,
682  const TaskParallelTLS *__restrict UNUSED(tls))
683 {
684  SculptThreadedTaskData *data = userdata;
685  SculptSession *ss = data->ob->sculpt;
686  const int symm_area = ss->cache->mirror_symmetry_pass;
687  SculptBoundary *boundary = ss->cache->boundaries[symm_area];
689  const Brush *brush = data->brush;
690 
691  const float strength = ss->cache->bstrength;
692 
693  PBVHVertexIter vd;
694  SculptOrigVertData orig_data;
695  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
696 
697  const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
698 
699  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
700  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
701  continue;
702  }
703 
704  SCULPT_orig_vert_data_update(&orig_data, &vd);
706  orig_data.co, boundary->initial_vertex_position, symm)) {
707  continue;
708  }
709 
710  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
711  const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
712  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
713  madd_v3_v3v3fl(target_co,
714  orig_data.co,
715  boundary->slide.directions[vd.index],
716  boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
717  strength);
718 
719  if (vd.mvert) {
721  }
722  }
724 }
725 
726 static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata,
727  const int n,
728  const TaskParallelTLS *__restrict UNUSED(tls))
729 {
730  SculptThreadedTaskData *data = userdata;
731  SculptSession *ss = data->ob->sculpt;
732  const int symm_area = ss->cache->mirror_symmetry_pass;
733  SculptBoundary *boundary = ss->cache->boundaries[symm_area];
735  const Brush *brush = data->brush;
736 
737  const float strength = ss->cache->bstrength;
738 
739  PBVHVertexIter vd;
740  SculptOrigVertData orig_data;
741  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
742 
743  const float disp = sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
744 
745  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
746  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
747  continue;
748  }
749 
750  SCULPT_orig_vert_data_update(&orig_data, &vd);
752  orig_data.co, boundary->initial_vertex_position, symm)) {
753  continue;
754  }
755 
756  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
757  const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
758  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
759  madd_v3_v3v3fl(target_co,
760  orig_data.co,
761  orig_data.no,
762  boundary->edit_info[vd.index].strength_factor * disp * mask * automask *
763  strength);
764 
765  if (vd.mvert) {
767  }
768  }
770 }
771 
772 static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata,
773  const int n,
774  const TaskParallelTLS *__restrict UNUSED(tls))
775 {
776  SculptThreadedTaskData *data = userdata;
777  SculptSession *ss = data->ob->sculpt;
778  const int symm_area = ss->cache->mirror_symmetry_pass;
779  SculptBoundary *boundary = ss->cache->boundaries[symm_area];
781  const Brush *brush = data->brush;
782 
783  const float strength = ss->cache->bstrength;
784 
785  PBVHVertexIter vd;
786  SculptOrigVertData orig_data;
787  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
788 
789  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
790  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
791  continue;
792  }
793 
794  SCULPT_orig_vert_data_update(&orig_data, &vd);
796  orig_data.co, boundary->initial_vertex_position, symm)) {
797  continue;
798  }
799 
800  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
801  const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
802  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
803  madd_v3_v3v3fl(target_co,
804  orig_data.co,
806  boundary->edit_info[vd.index].strength_factor * mask * automask * strength);
807 
808  if (vd.mvert) {
810  }
811  }
813 }
814 
815 static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata,
816  const int n,
817  const TaskParallelTLS *__restrict UNUSED(tls))
818 {
819  SculptThreadedTaskData *data = userdata;
820  SculptSession *ss = data->ob->sculpt;
821  const int symm_area = ss->cache->mirror_symmetry_pass;
822  SculptBoundary *boundary = ss->cache->boundaries[symm_area];
824  const Brush *brush = data->brush;
825 
826  const float strength = ss->cache->bstrength;
827 
828  PBVHVertexIter vd;
829  SculptOrigVertData orig_data;
830  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
831 
832  const float disp = strength * sculpt_boundary_displacement_from_grab_delta_get(ss, boundary);
833  float angle_factor = disp / ss->cache->radius;
834  /* Angle Snapping when inverting the brush. */
835  if (ss->cache->invert) {
836  angle_factor = floorf(angle_factor * 10) / 10.0f;
837  }
838  const float angle = angle_factor * M_PI;
839 
840  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
841  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
842  continue;
843  }
844 
845  SCULPT_orig_vert_data_update(&orig_data, &vd);
847  orig_data.co, boundary->initial_vertex_position, symm)) {
848  continue;
849  }
850 
851  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
852  const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index);
853  float t_orig_co[3];
854  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
855  sub_v3_v3v3(t_orig_co, orig_data.co, boundary->twist.pivot_position);
856  rotate_v3_v3v3fl(target_co,
857  t_orig_co,
858  boundary->twist.rotation_axis,
859  angle * mask * automask * boundary->edit_info[vd.index].strength_factor);
860  add_v3_v3(target_co, boundary->twist.pivot_position);
861 
862  if (vd.mvert) {
864  }
865  }
867 }
868 
869 static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata,
870  const int n,
871  const TaskParallelTLS *__restrict UNUSED(tls))
872 {
873  SculptThreadedTaskData *data = userdata;
874  SculptSession *ss = data->ob->sculpt;
875  const int symmetry_pass = ss->cache->mirror_symmetry_pass;
876  const SculptBoundary *boundary = ss->cache->boundaries[symmetry_pass];
878  const Brush *brush = data->brush;
879 
880  const float strength = ss->cache->bstrength;
881 
882  PBVHVertexIter vd;
883  SculptOrigVertData orig_data;
884  SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n], SCULPT_UNDO_COORDS);
885 
886  BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
887  if (boundary->edit_info[vd.index].num_propagation_steps == -1) {
888  continue;
889  }
890 
891  SCULPT_orig_vert_data_update(&orig_data, &vd);
893  orig_data.co, boundary->initial_vertex_position, symm)) {
894  continue;
895  }
896 
897  float coord_accum[3] = {0.0f, 0.0f, 0.0f};
898  int total_neighbors = 0;
899  const int current_propagation_steps = boundary->edit_info[vd.index].num_propagation_steps;
902  if (current_propagation_steps == boundary->edit_info[ni.index].num_propagation_steps) {
903  add_v3_v3(coord_accum, SCULPT_vertex_co_get(ss, ni.index));
904  total_neighbors++;
905  }
906  }
908 
909  if (total_neighbors == 0) {
910  continue;
911  }
912  float disp[3];
913  float avg[3];
914  const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f;
915  mul_v3_v3fl(avg, coord_accum, 1.0f / total_neighbors);
916  sub_v3_v3v3(disp, avg, vd.co);
917  float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd);
919  target_co, vd.co, disp, boundary->edit_info[vd.index].strength_factor * mask * strength);
920 
921  if (vd.mvert) {
923  }
924  }
926 }
927 
928 void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
929 {
930  SculptSession *ss = ob->sculpt;
931  Brush *brush = BKE_paint_brush(&sd->paint);
932 
933  const int symm_area = ss->cache->mirror_symmetry_pass;
935 
936  int initial_vertex;
937  if (ss->cache->mirror_symmetry_pass == 0) {
938  initial_vertex = SCULPT_active_vertex_get(ss);
939  }
940  else {
941  float location[3];
942  flip_v3_v3(location, SCULPT_active_vertex_co_get(ss), symm_area);
943  initial_vertex = SCULPT_nearest_vertex_get(
944  sd, ob, location, ss->cache->radius_squared, false);
945  }
946 
947  ss->cache->boundaries[symm_area] = SCULPT_boundary_data_init(
948  ob, brush, initial_vertex, ss->cache->initial_radius);
949 
950  if (ss->cache->boundaries[symm_area]) {
951 
952  switch (brush->boundary_deform_type) {
954  sculpt_boundary_bend_data_init(ss, ss->cache->boundaries[symm_area]);
955  break;
957  sculpt_boundary_slide_data_init(ss, ss->cache->boundaries[symm_area]);
958  break;
960  sculpt_boundary_twist_data_init(ss, ss->cache->boundaries[symm_area]);
961  break;
964  /* Do nothing. These deform modes don't need any extra data to be precomputed. */
965  break;
966  }
967 
969  ss, ss->cache->boundaries[symm_area], brush, ss->cache->initial_radius);
970  }
971  }
972 
973  /* No active boundary under the cursor. */
974  if (!ss->cache->boundaries[symm_area]) {
975  return;
976  }
977 
979  .sd = sd,
980  .ob = ob,
981  .brush = brush,
982  .nodes = nodes,
983  };
984 
985  TaskParallelSettings settings;
986  BKE_pbvh_parallel_range_settings(&settings, true, totnode);
987 
988  switch (brush->boundary_deform_type) {
991  break;
994  break;
997  break;
1000  break;
1003  break;
1006  break;
1007  }
1008 }
1009 
1011  SculptSession *ss,
1012  const float outline_col[3],
1013  const float outline_alpha)
1014 {
1015  if (!ss->boundary_preview) {
1016  return;
1017  }
1018  immUniformColor3fvAlpha(outline_col, outline_alpha);
1019  GPU_line_width(2.0f);
1021  for (int i = 0; i < ss->boundary_preview->num_edges; i++) {
1024  }
1025  immEnd();
1026 }
1027 
1029 {
1030  if (!ss->boundary_preview) {
1031  return;
1032  }
1033  immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f);
1034  GPU_line_width(2.0f);
1038  immEnd();
1039 }
typedef float(TangentPoint)[2]
float BKE_brush_curve_strength(const struct Brush *br, float p, float len)
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1235
General operations, lookup, etc. for blender objects.
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:607
A BVH for high poly meshes.
#define BKE_pbvh_vertex_iter_begin(pbvh, node, vi, mode)
Definition: BKE_pbvh.h:439
PBVHType BKE_pbvh_type(const PBVH *pbvh)
Definition: pbvh.c:1798
#define BKE_pbvh_vertex_iter_end
Definition: BKE_pbvh.h:509
void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, int index)
Definition: pbvh.c:1967
#define PBVH_ITER_UNIQUE
Definition: BKE_pbvh.h:391
@ PBVH_GRIDS
Definition: BKE_pbvh.h:235
void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, bool use_threading, int totnode)
Definition: pbvh.c:3211
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
struct GSet GSet
Definition: BLI_ghash.h:340
GSet * BLI_gset_int_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1007
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
void BLI_gsqueue_free(GSQueue *queue)
Definition: gsqueue.c:90
GSQueue * BLI_gsqueue_new(size_t elem_size)
Definition: gsqueue.c:69
void BLI_gsqueue_push(GSQueue *queue, const void *item)
Definition: gsqueue.c:97
void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
Definition: gsqueue.c:131
bool BLI_gsqueue_is_empty(const GSQueue *queue)
Definition: gsqueue.c:159
#define M_PI
Definition: BLI_math_base.h:20
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:209
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition: math_geom.c:461
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
Definition: math_geom.c:71
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], float angle)
Definition: math_vector.c:800
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void madd_v3_v3v3fl(float r[3], const float a[3], const float b[3], float f)
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
#define POINTER_FROM_INT(i)
#define UNUSED(x)
@ BRUSH_BOUNDARY_DEFORM_GRAB
@ BRUSH_BOUNDARY_DEFORM_TWIST
@ BRUSH_BOUNDARY_DEFORM_BEND
@ BRUSH_BOUNDARY_DEFORM_EXPAND
@ BRUSH_BOUNDARY_DEFORM_INFLATE
@ BRUSH_BOUNDARY_DEFORM_SMOOTH
@ BRUSH_BOUNDARY_FALLOFF_CONSTANT
@ BRUSH_BOUNDARY_FALLOFF_LOOP
@ BRUSH_BOUNDARY_FALLOFF_LOOP_INVERT
@ BRUSH_BOUNDARY_FALLOFF_RADIUS
Object is a sort of wrapper for general info.
ePaintSymmetryFlags
void immUniformColor4f(float r, float g, float b, float a)
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)
_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 v1
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
void GPU_line_width(float width)
Definition: gpu_state.cc:158
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
uint pos
IconTextureDrawCall normal
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:32
void *(* MEM_reallocN_id)(void *vmemh, size_t len, const char *str)
Definition: mallocn.c:29
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define fmodf(x, y)
Definition: metal/compat.h:230
#define floorf(x)
Definition: metal/compat.h:224
T distance(const T &a, const T &b)
BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm)
Definition: paint_intern.h:392
const float * SCULPT_vertex_co_get(SculptSession *ss, int index)
Definition: sculpt.c:125
int SCULPT_vertex_count_get(SculptSession *ss)
Definition: sculpt.c:111
void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter)
Definition: sculpt.c:1300
void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node, SculptUndoType type)
Definition: sculpt.c:1290
void SCULPT_boundary_info_ensure(Object *object)
Definition: sculpt.c:5848
int SCULPT_active_vertex_get(SculptSession *ss)
Definition: sculpt.c:271
int SCULPT_nearest_vertex_get(Sculpt *sd, Object *ob, const float co[3], float max_distance, bool use_original)
Definition: sculpt.c:983
void SCULPT_floodfill_init(SculptSession *ss, SculptFloodFill *flood)
Definition: sculpt.c:1072
void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index)
Definition: sculpt.c:1081
const float * SCULPT_active_vertex_co_get(SculptSession *ss)
Definition: sculpt.c:279
void SCULPT_vertex_random_access_ensure(SculptSession *ss)
Definition: sculpt.c:103
bool SCULPT_vertex_visible_get(SculptSession *ss, int index)
Definition: sculpt.c:356
float * SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, const int deform_target, PBVHVertexIter *iter)
Definition: sculpt.c:304
void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3])
Definition: sculpt.c:171
bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index)
Definition: sculpt.c:865
void SCULPT_floodfill_free(SculptFloodFill *flood)
Definition: sculpt.c:1174
bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(StrokeCache *cache)
Definition: sculpt.c:918
char SCULPT_mesh_symmetry_xyz_get(Object *object)
Definition: sculpt.c:317
bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm)
Definition: sculpt.c:923
void SCULPT_floodfill_execute(SculptSession *ss, SculptFloodFill *flood, bool(*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), void *userdata)
Definition: sculpt.c:1143
float SCULPT_automasking_factor_get(AutomaskingCache *automasking, SculptSession *ss, int vert)
static void sculpt_boundary_falloff_factor_init(SculptSession *ss, SculptBoundary *boundary, Brush *brush, const float radius)
static void sculpt_boundary_preview_edge_add(SculptBoundary *boundary, const int v1, const int v2)
static bool boundary_initial_vertex_floodfill_cb(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
static bool boundary_floodfill_cb(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata)
void SCULPT_boundary_data_free(SculptBoundary *boundary)
#define BOUNDARY_STEPS_NONE
static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *boundary)
static void do_boundary_brush_smooth_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static int sculpt_boundary_get_closest_boundary_vertex(SculptSession *ss, const int initial_vertex, const float radius)
static void do_boundary_brush_slide_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
#define BOUNDARY_VERTEX_NONE
static void sculpt_boundary_twist_data_init(SculptSession *ss, SculptBoundary *boundary)
void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, SculptSession *ss)
static void do_boundary_brush_bend_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
void SCULPT_do_boundary_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
struct BoundaryFloodFillData BoundaryFloodFillData
static void sculpt_boundary_index_add(SculptBoundary *boundary, const int new_index, const float distance, GSet *included_vertices)
struct BoundaryInitialVertexFloodFillData BoundaryInitialVertexFloodFillData
static int BOUNDARY_INDICES_BLOCK_SIZE
static void do_boundary_brush_twist_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
static float sculpt_boundary_displacement_from_grab_delta_get(SculptSession *ss, SculptBoundary *boundary)
SculptBoundary * SCULPT_boundary_data_init(Object *object, Brush *brush, const int initial_vertex, const float radius)
static void sculpt_boundary_bend_data_init(SculptSession *ss, SculptBoundary *boundary)
static void do_boundary_brush_grab_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls))
void SCULPT_boundary_edges_preview_draw(const uint gpuattr, SculptSession *ss, const float outline_col[3], const float outline_alpha)
static void sculpt_boundary_edit_data_init(SculptSession *ss, SculptBoundary *boundary, const int initial_vertex, const float radius)
static bool sculpt_boundary_is_vertex_in_editable_boundary(SculptSession *ss, const int initial_vertex)
static void sculpt_boundary_indices_init(SculptSession *ss, SculptBoundary *boundary, const bool init_boundary_distances, const int initial_boundary_index)
#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator)
#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator)
#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator)
@ SCULPT_UNDO_COORDS
SculptBoundary * boundary
struct CurveMapping * curve
int boundary_falloff_type
float boundary_offset
int deform_target
int boundary_deform_type
struct SculptSession * sculpt
struct MVert * mvert
Definition: BKE_pbvh.h:428
float * co
Definition: BKE_pbvh.h:430
float * mask
Definition: BKE_pbvh.h:433
float rotation_axis[3]
Definition: BKE_paint.h:468
int vertices_capacity
Definition: BKE_paint.h:418
int initial_vertex
Definition: BKE_paint.h:435
struct SculptBoundary::@51 twist
int max_propagation_steps
Definition: BKE_paint.h:449
struct SculptBoundaryEditInfo * edit_info
Definition: BKE_paint.h:453
float pivot_position[3]
Definition: BKE_paint.h:469
float initial_vertex_position[3]
Definition: BKE_paint.h:445
float(* pivot_rotation_axis)[3]
Definition: BKE_paint.h:457
float initial_pivot_position[3]
Definition: BKE_paint.h:446
int * vertices
Definition: BKE_paint.h:417
struct SculptBoundary::@50 slide
struct SculptBoundary::@49 bend
int edges_capacity
Definition: BKE_paint.h:428
float * distance
Definition: BKE_paint.h:424
SculptBoundaryPreviewEdge * edges
Definition: BKE_paint.h:427
float(* directions)[3]
Definition: BKE_paint.h:463
float(* pivot_positions)[3]
Definition: BKE_paint.h:458
const float * co
Definition: sculpt_intern.h:87
const float * no
Definition: sculpt_intern.h:88
SculptBoundary * boundary_preview
Definition: BKE_paint.h:602
struct StrokeCache * cache
Definition: BKE_paint.h:563
struct PBVH * pbvh
Definition: BKE_paint.h:550
Paint paint
float initial_radius
float initial_location[3]
float radius_squared
int mirror_symmetry_pass
struct SculptBoundary * boundaries[PAINT_SYMM_AREAS]
float grab_delta_symmetry[3]
AutomaskingCache * automasking
ccl_device_inline int mod(int x, int m)
Definition: util/math.h:490