Blender  V2.93
sculpt_uv.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) Blender Foundation, 2002-2009
17  * All rights reserved.
18  * UV Sculpt tools
19  */
20 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_ghash.h"
28 #include "BLI_math.h"
29 #include "BLI_utildefines.h"
30 
31 #include "DNA_brush_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 
36 #include "BKE_brush.h"
37 #include "BKE_colortools.h"
38 #include "BKE_context.h"
39 #include "BKE_customdata.h"
40 #include "BKE_editmesh.h"
41 #include "BKE_mesh_mapping.h"
42 #include "BKE_paint.h"
43 
44 #include "DEG_depsgraph.h"
45 
46 #include "ED_image.h"
47 #include "ED_mesh.h"
48 #include "ED_screen.h"
49 
50 #include "WM_api.h"
51 #include "WM_types.h"
52 
53 #include "RNA_access.h"
54 #include "RNA_define.h"
55 
56 #include "paint_intern.h"
57 #include "uvedit_intern.h"
58 
59 #include "UI_view2d.h"
60 
61 #define MARK_BOUNDARY 1
62 
63 typedef struct UvAdjacencyElement {
64  /* pointer to original uvelement */
66  /* uv pointer for convenience. Caution, this points to the original UVs! */
67  float *uv;
68  /* general use flag (Used to check if Element is boundary here) */
69  char flag;
71 
72 typedef struct UvEdge {
75  /* general use flag
76  * (Used to check if edge is boundary here, and propagates to adjacency elements) */
77  char flag;
79 
80 typedef struct UVInitialStrokeElement {
81  /* index to unique uv */
82  int uv;
83 
84  /* strength of brush on initial position */
85  float strength;
86 
87  /* initial uv position */
88  float initial_uv[2];
90 
91 typedef struct UVInitialStroke {
92  /* Initial Selection,for grab brushes for instance */
94 
95  /* total initially selected UVs*/
97 
98  /* initial mouse coordinates */
99  float init_coord[2];
101 
102 /* custom data for uv smoothing brush */
103 typedef struct UvSculptData {
104  /* Contains the first of each set of coincident uvs.
105  * These will be used to perform smoothing on and propagate the changes
106  * to their coincident uvs */
108 
109  /* ...Is what it says */
111 
112  /* Edges used for adjacency info, used with laplacian smoothing */
114 
115  /* need I say more? */
117 
118  /* data for initial stroke, used by tools like grab */
120 
121  /* timer to be used for airbrush-type brush */
123 
124  /* to determine quickly adjacent uvs */
126 
127  /* uvsmooth Paint for fast reference */
129 
130  /* tool to use. duplicating here to change if modifier keys are pressed */
131  char tool;
132 
133  /* store invert flag here */
134  char invert;
136 
137 /*********** Improved Laplacian Relaxation Operator ************************/
138 /* original code by Raul Fernandez Hernandez "farsthary" *
139  * adapted to uv smoothing by Antony Riakiatakis *
140  ***************************************************************************/
141 
142 typedef struct Temp_UvData {
143  float sum_co[2], p[2], b[2], sum_b[2];
144  int ncounter;
146 
148  UvSculptData *sculptdata,
149  const float mouse_coord[2],
150  float alpha,
151  float radius,
152  float aspectRatio)
153 {
154  Temp_UVData *tmp_uvdata;
155  float diff[2];
156  int i;
157  float radius_root = sqrtf(radius);
158  Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
159 
160  tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData),
161  "Temporal data");
162 
163  /* counting neighbors */
164  for (i = 0; i < sculptdata->totalUvEdges; i++) {
165  UvEdge *tmpedge = sculptdata->uvedges + i;
166  tmp_uvdata[tmpedge->uv1].ncounter++;
167  tmp_uvdata[tmpedge->uv2].ncounter++;
168 
169  add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
170  add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
171  }
172 
173  for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
174  copy_v2_v2(diff, tmp_uvdata[i].sum_co);
175  mul_v2_fl(diff, 1.0f / tmp_uvdata[i].ncounter);
176  copy_v2_v2(tmp_uvdata[i].p, diff);
177 
178  tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
179  tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
180  }
181 
182  for (i = 0; i < sculptdata->totalUvEdges; i++) {
183  UvEdge *tmpedge = sculptdata->uvedges + i;
184  add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
185  add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
186  }
187 
188  for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
189  float dist;
190  /* This is supposed to happen only if "Pin Edges" is on,
191  * since we have initialization on stroke start.
192  * If ever uv brushes get their own mode we should check for toolsettings option too. */
193  if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
194  continue;
195  }
196 
197  sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
198  diff[1] /= aspectRatio;
199  if ((dist = dot_v2v2(diff, diff)) <= radius) {
201  float strength;
202  strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
203 
204  sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
205  strength *
206  (tmp_uvdata[i].p[0] -
207  0.5f * (tmp_uvdata[i].b[0] +
208  tmp_uvdata[i].sum_b[0] / tmp_uvdata[i].ncounter));
209  sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
210  strength *
211  (tmp_uvdata[i].p[1] -
212  0.5f * (tmp_uvdata[i].b[1] +
213  tmp_uvdata[i].sum_b[1] / tmp_uvdata[i].ncounter));
214 
215  for (element = sculptdata->uv[i].element; element; element = element->next) {
216  MLoopUV *luv;
217  BMLoop *l;
218 
219  if (element->separate && element != sculptdata->uv[i].element) {
220  break;
221  }
222 
223  l = element->l;
225  copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
226  }
227  }
228  }
229 
230  MEM_freeN(tmp_uvdata);
231 }
232 
234  UvSculptData *sculptdata,
235  const float mouse_coord[2],
236  float alpha,
237  float radius,
238  float aspectRatio)
239 {
240  Temp_UVData *tmp_uvdata;
241  float diff[2];
242  int i;
243  float radius_root = sqrtf(radius);
244  Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
245 
246  tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData),
247  "Temporal data");
248 
249  /* counting neighbors */
250  for (i = 0; i < sculptdata->totalUvEdges; i++) {
251  UvEdge *tmpedge = sculptdata->uvedges + i;
252  tmp_uvdata[tmpedge->uv1].ncounter++;
253  tmp_uvdata[tmpedge->uv2].ncounter++;
254 
255  add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
256  add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
257  }
258 
259  /* Original Lacplacian algorithm included removal of normal component of translation.
260  * here it is not needed since we translate along the UV plane always. */
261  for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
262  copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
263  mul_v2_fl(tmp_uvdata[i].p, 1.0f / tmp_uvdata[i].ncounter);
264  }
265 
266  for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
267  float dist;
268  /* This is supposed to happen only if "Pin Edges" is on,
269  * since we have initialization on stroke start.
270  * If ever uv brushes get their own mode we should check for toolsettings option too. */
271  if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
272  continue;
273  }
274 
275  sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
276  diff[1] /= aspectRatio;
277  if ((dist = dot_v2v2(diff, diff)) <= radius) {
279  float strength;
280  strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
281 
282  sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
283  strength * tmp_uvdata[i].p[0];
284  sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
285  strength * tmp_uvdata[i].p[1];
286 
287  for (element = sculptdata->uv[i].element; element; element = element->next) {
288  MLoopUV *luv;
289  BMLoop *l;
290 
291  if (element->separate && element != sculptdata->uv[i].element) {
292  break;
293  }
294 
295  l = element->l;
297  copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
298  }
299  }
300  }
301 
302  MEM_freeN(tmp_uvdata);
303 }
304 
306  wmOperator *op,
307  const wmEvent *event,
308  Object *obedit)
309 {
310  float co[2], radius, radius_root;
312  ARegion *region = CTX_wm_region(C);
313  BMEditMesh *em = BKE_editmesh_from_object(obedit);
314  uint tool;
315  UvSculptData *sculptdata = (UvSculptData *)op->customdata;
316  SpaceImage *sima;
317  int invert;
318  int width, height;
319  float aspectRatio;
320  float alpha, zoomx, zoomy;
321  Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
322  ToolSettings *toolsettings = CTX_data_tool_settings(C);
323  tool = sculptdata->tool;
324  invert = sculptdata->invert ? -1 : 1;
325  alpha = BKE_brush_alpha_get(scene, brush);
326  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
327 
328  sima = CTX_wm_space_image(C);
330  ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
331 
332  radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
333  aspectRatio = width / (float)height;
334 
335  /* We will compare squares to save some computation */
336  radius = radius * radius;
337  radius_root = sqrtf(radius);
338 
339  /*
340  * Pinch Tool
341  */
342  if (tool == UV_SCULPT_TOOL_PINCH) {
343  int i;
344  alpha *= invert;
345  for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
346  float dist, diff[2];
347  /* This is supposed to happen only if "Lock Borders" is on,
348  * since we have initialization on stroke start.
349  * If ever uv brushes get their own mode we should check for toolsettings option too. */
350  if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
351  continue;
352  }
353 
354  sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
355  diff[1] /= aspectRatio;
356  if ((dist = dot_v2v2(diff, diff)) <= radius) {
358  float strength;
359  strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
361 
362  sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
363  sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f;
364 
365  for (element = sculptdata->uv[i].element; element; element = element->next) {
366  MLoopUV *luv;
367  BMLoop *l;
368 
369  if (element->separate && element != sculptdata->uv[i].element) {
370  break;
371  }
372 
373  l = element->l;
375  copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
376  }
377  }
378  }
379  }
380 
381  /*
382  * Smooth Tool
383  */
384  else if (tool == UV_SCULPT_TOOL_RELAX) {
385  uint method = toolsettings->uv_relax_method;
386  if (method == UV_SCULPT_TOOL_RELAX_HC) {
387  HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
388  }
389  else {
390  laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
391  }
392  }
393 
394  /*
395  * Grab Tool
396  */
397  else if (tool == UV_SCULPT_TOOL_GRAB) {
398  int i;
399  float diff[2];
400  sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
401 
402  for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) {
404  int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
405  float strength = sculptdata->initial_stroke->initialSelection[i].strength;
406  sculptdata->uv[uvindex].uv[0] =
407  sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0];
408  sculptdata->uv[uvindex].uv[1] =
409  sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1];
410 
411  for (element = sculptdata->uv[uvindex].element; element; element = element->next) {
412  MLoopUV *luv;
413  BMLoop *l;
414 
415  if (element->separate && element != sculptdata->uv[uvindex].element) {
416  break;
417  }
418 
419  l = element->l;
421  copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
422  }
423  }
424  }
425 }
426 
428 {
430  if (data->timer) {
432  }
433  if (data->elementMap) {
434  BM_uv_element_map_free(data->elementMap);
435  }
436  if (data->uv) {
437  MEM_freeN(data->uv);
438  }
439  if (data->uvedges) {
440  MEM_freeN(data->uvedges);
441  }
442  if (data->initial_stroke) {
443  if (data->initial_stroke->initialSelection) {
444  MEM_freeN(data->initial_stroke->initialSelection);
445  }
446  MEM_freeN(data->initial_stroke);
447  }
448 
449  MEM_freeN(data);
450  op->customdata = NULL;
451 }
452 
454  UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands)
455 {
456  UvElement *element = BM_uv_element_get(map, efa, l);
457  if (!element || (doIslands && element->island != island_index)) {
458  return -1;
459  }
460  return element - map->buf;
461 }
462 
463 static uint uv_edge_hash(const void *key)
464 {
465  const UvEdge *edge = key;
466  return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
467 }
468 
469 static bool uv_edge_compare(const void *a, const void *b)
470 {
471  const UvEdge *edge1 = a;
472  const UvEdge *edge2 = b;
473 
474  if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
475  return false;
476  }
477  return true;
478 }
479 
481 {
483  Object *obedit = CTX_data_edit_object(C);
485  UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
486  BMEditMesh *em = BKE_editmesh_from_object(obedit);
487  BMesh *bm = em->bm;
488 
489  op->customdata = data;
490 
492 
493  if (data) {
494  int counter = 0, i;
495  ARegion *region = CTX_wm_region(C);
496  float co[2];
497  BMFace *efa;
498  MLoopUV *luv;
499  BMLoop *l;
500  BMIter iter, liter;
501 
502  UvEdge *edges;
503  GHash *edgeHash;
504  GHashIterator gh_iter;
505 
506  bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
507  int island_index = 0;
508  /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
509  int *uniqueUv;
510  data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ?
513  data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
514 
515  data->uvsculpt = &ts->uvsculpt->paint;
516 
517  if (do_island_optimization) {
518  /* We will need island information */
519  if (ts->uv_flag & UV_SYNC_SELECTION) {
520  data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, true);
521  }
522  else {
523  data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, true);
524  }
525  }
526  else {
527  if (ts->uv_flag & UV_SYNC_SELECTION) {
528  data->elementMap = BM_uv_element_map_create(bm, scene, false, false, true, false);
529  }
530  else {
531  data->elementMap = BM_uv_element_map_create(bm, scene, true, false, true, false);
532  }
533  }
534 
535  if (!data->elementMap) {
537  return NULL;
538  }
539 
540  /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
541  UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
542 
543  /* we need to find the active island here */
544  if (do_island_optimization) {
546  UvNearestHit hit = UV_NEAREST_HIT_INIT_MAX(&region->v2d);
547  uv_find_nearest_vert(scene, obedit, co, 0.0f, &hit);
548 
549  element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
550  island_index = element->island;
551  }
552 
553  /* Count 'unique' uvs */
554  for (i = 0; i < data->elementMap->totalUVs; i++) {
555  if (data->elementMap->buf[i].separate &&
556  (!do_island_optimization || data->elementMap->buf[i].island == island_index)) {
557  counter++;
558  }
559  }
560 
561  /* Allocate the unique uv buffers */
562  data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs");
563  uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs,
564  "uv_brush_unique_uv_map");
565  edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
566  /* we have at most totalUVs edges */
567  edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges");
568  if (!data->uv || !uniqueUv || !edgeHash || !edges) {
569  if (edges) {
570  MEM_freeN(edges);
571  }
572  if (uniqueUv) {
573  MEM_freeN(uniqueUv);
574  }
575  if (edgeHash) {
576  BLI_ghash_free(edgeHash, NULL, NULL);
577  }
579  return NULL;
580  }
581 
582  data->totalUniqueUvs = counter;
583  /* So that we can use this as index for the UvElements */
584  counter = -1;
585  /* initialize the unique UVs */
586  for (i = 0; i < bm->totvert; i++) {
587  UvElement *element = data->elementMap->vert[i];
588  for (; element; element = element->next) {
589  if (element->separate) {
590  if (do_island_optimization && (element->island != island_index)) {
591  /* skip this uv if not on the active island */
592  for (; element->next && !(element->next->separate); element = element->next) {
593  /* pass */
594  }
595  continue;
596  }
597 
598  l = element->l;
600 
601  counter++;
602  data->uv[counter].element = element;
603  data->uv[counter].flag = 0;
604  data->uv[counter].uv = luv->uv;
605  }
606  /* pointer arithmetic to the rescue, as always :)*/
607  uniqueUv[element - data->elementMap->buf] = counter;
608  }
609  }
610 
611  /* Now, on to generate our uv connectivity data */
612  counter = 0;
613  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
614  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
615  int offset1, itmp1 = uv_element_offset_from_face_get(
616  data->elementMap, efa, l, island_index, do_island_optimization);
617  int offset2, itmp2 = uv_element_offset_from_face_get(
618  data->elementMap, efa, l->next, island_index, do_island_optimization);
619  char *flag;
620 
621  /* Skip edge if not found(unlikely) or not on valid island */
622  if (itmp1 == -1 || itmp2 == -1) {
623  continue;
624  }
625 
626  offset1 = uniqueUv[itmp1];
627  offset2 = uniqueUv[itmp2];
628 
629  edges[counter].flag = 0;
630  /* using an order policy, sort uvs according to address space. This avoids
631  * Having two different UvEdges with the same uvs on different positions */
632  if (offset1 < offset2) {
633  edges[counter].uv1 = offset1;
634  edges[counter].uv2 = offset2;
635  }
636  else {
637  edges[counter].uv1 = offset2;
638  edges[counter].uv2 = offset1;
639  }
640  /* Hack! Set the value of the key to its flag.
641  * Now we can set the flag when an edge exists twice :) */
642  flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
643  if (flag) {
644  *flag = 1;
645  }
646  else {
647  /* Hack mentioned */
648  BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
649  }
650  counter++;
651  }
652  }
653 
654  MEM_freeN(uniqueUv);
655 
656  /* Allocate connectivity data, we allocate edges once */
657  data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash),
658  "uv_brush_edge_connectivity_data");
659  if (!data->uvedges) {
660  BLI_ghash_free(edgeHash, NULL, NULL);
661  MEM_freeN(edges);
663  return NULL;
664  }
665 
666  /* fill the edges with data */
667  i = 0;
668  GHASH_ITER (gh_iter, edgeHash) {
669  data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
670  }
671  data->totalUvEdges = BLI_ghash_len(edgeHash);
672 
673  /* cleanup temporary stuff */
674  BLI_ghash_free(edgeHash, NULL, NULL);
675  MEM_freeN(edges);
676 
677  /* transfer boundary edge property to uvs */
679  for (i = 0; i < data->totalUvEdges; i++) {
680  if (!data->uvedges[i].flag) {
681  data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
682  data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
683  }
684  }
685  }
686 
687  /* Allocate initial selection for grab tool */
688  if (data->tool == UV_SCULPT_TOOL_GRAB) {
689  float radius, radius_root;
690  UvSculptData *sculptdata = (UvSculptData *)op->customdata;
691  SpaceImage *sima;
692  int width, height;
693  float aspectRatio;
694  float alpha, zoomx, zoomy;
695  Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
696 
697  alpha = BKE_brush_alpha_get(scene, brush);
698 
699  radius = BKE_brush_size_get(scene, brush);
700  sima = CTX_wm_space_image(C);
702  ED_space_image_get_zoom(sima, region, &zoomx, &zoomy);
703 
704  aspectRatio = width / (float)height;
705  radius /= (width * zoomx);
706  radius = radius * radius;
707  radius_root = sqrtf(radius);
708 
709  /* Allocate selection stack */
710  data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke),
711  "uv_sculpt_initial_stroke");
712  if (!data->initial_stroke) {
714  }
715  data->initial_stroke->initialSelection = MEM_mallocN(
716  sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs,
717  "uv_sculpt_initial_selection");
718  if (!data->initial_stroke->initialSelection) {
720  }
721 
722  copy_v2_v2(data->initial_stroke->init_coord, co);
723 
724  counter = 0;
725 
726  for (i = 0; i < data->totalUniqueUvs; i++) {
727  float dist, diff[2];
728  if (data->uv[i].flag & MARK_BOUNDARY) {
729  continue;
730  }
731 
732  sub_v2_v2v2(diff, data->uv[i].uv, co);
733  diff[1] /= aspectRatio;
734  if ((dist = dot_v2v2(diff, diff)) <= radius) {
735  float strength;
736  strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
737 
738  data->initial_stroke->initialSelection[counter].uv = i;
739  data->initial_stroke->initialSelection[counter].strength = strength;
740  copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
741  counter++;
742  }
743  }
744 
745  data->initial_stroke->totalInitialSelected = counter;
746  }
747  }
748 
749  return op->customdata;
750 }
751 
752 static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
753 {
755  Object *obedit = CTX_data_edit_object(C);
756 
757  if (!(data = uv_sculpt_stroke_init(C, op, event))) {
758  return OPERATOR_CANCELLED;
759  }
760 
761  uv_sculpt_stroke_apply(C, op, event, obedit);
762 
764 
765  if (!data->timer) {
767  return OPERATOR_CANCELLED;
768  }
770 
771  return OPERATOR_RUNNING_MODAL;
772 }
773 
774 static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
775 {
777  Object *obedit = CTX_data_edit_object(C);
778 
779  switch (event->type) {
780  case LEFTMOUSE:
781  case MIDDLEMOUSE:
782  case RIGHTMOUSE:
784  return OPERATOR_FINISHED;
785 
786  case MOUSEMOVE:
787  case INBETWEEN_MOUSEMOVE:
788  uv_sculpt_stroke_apply(C, op, event, obedit);
789  break;
790  case TIMER:
791  if (event->customdata == data->timer) {
792  uv_sculpt_stroke_apply(C, op, event, obedit);
793  }
794  break;
795  default:
796  return OPERATOR_RUNNING_MODAL;
797  }
798 
800  WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
801  DEG_id_tag_update(obedit->data, 0);
802  return OPERATOR_RUNNING_MODAL;
803 }
804 
806 {
808  /* While these values could be initialized on demand,
809  * the only case this would be useful is running from the operator search popup.
810  * This is such a corner case that it's simpler to check a brush has already been created
811  * (something the tool system ensures). */
814  Brush *brush = BKE_paint_brush(&ts->uvsculpt->paint);
815  if (brush != NULL) {
816  return true;
817  }
818  }
819  return false;
820 }
821 
823 {
824  static const EnumPropertyItem stroke_mode_items[] = {
825  {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
827  "INVERT",
828  0,
829  "Invert",
830  "Invert action of brush for duration of stroke"},
832  "RELAX",
833  0,
834  "Relax",
835  "Switch brush to relax mode for duration of stroke"},
836  {0},
837  };
838 
839  /* identifiers */
840  ot->name = "Sculpt UVs";
841  ot->description = "Sculpt UVs using a brush";
842  ot->idname = "SCULPT_OT_uv_sculpt_stroke";
843 
844  /* api callbacks */
848 
849  /* flags */
851 
852  /* props */
853  RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
854 }
typedef float(TangentPoint)[2]
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)
float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len)
Definition: brush.c:2464
void BKE_curvemapping_init(struct CurveMapping *cumap)
Definition: colortools.c:1200
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1208
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
struct Brush * BKE_paint_brush(struct Paint *paint)
Definition: paint.c:604
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:146
unsigned int BLI_ghashutil_uinthash(unsigned int key)
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:169
GHash * BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:718
unsigned int BLI_ghash_len(GHash *gh) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:744
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:756
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:1008
void * BLI_ghash_lookup(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:803
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE float dot_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float normalize_v2(float r[2])
unsigned int uint
Definition: BLI_sys_types.h:83
void DEG_id_tag_update(struct ID *id, int flag)
@ UV_SCULPT_TOOL_GRAB
@ UV_SCULPT_TOOL_RELAX
@ UV_SCULPT_TOOL_PINCH
@ CD_MLOOPUV
Object is a sort of wrapper for general info.
#define UV_SCULPT_TOOL_RELAX_HC
#define UV_SCULPT_LOCK_BORDERS
#define UV_SCULPT_ALL_ISLANDS
#define UV_SYNC_SELECTION
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_space_image_get_zoom(struct SpaceImage *sima, const struct ARegion *region, float *r_zoomx, float *r_zoomy)
void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_height)
Definition: image_edit.c:215
struct UvElement * BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, struct BMLoop *l)
struct UvElementMap * BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, const bool face_selected, const bool uv_selected, const bool use_winding, const bool do_islands)
void BM_uv_element_map_free(struct UvElementMap *element_map)
bool ED_operator_uvedit_space_image(struct bContext *C)
Definition: screen_ops.c:518
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:667
_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 width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMLoop * l
Scene scene
static CCL_NAMESPACE_BEGIN const double alpha
#define sqrtf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt=1)
@ BRUSH_STROKE_SMOOTH
Definition: paint_intern.h:313
@ BRUSH_STROKE_NORMAL
Definition: paint_intern.h:311
@ BRUSH_STROKE_INVERT
Definition: paint_intern.h:312
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, const float mouse_coord[2], float alpha, float radius, float aspectRatio)
Definition: sculpt_uv.c:147
static bool uv_sculpt_stroke_poll(bContext *C)
Definition: sculpt_uv.c:805
static UvSculptData * uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
Definition: sculpt_uv.c:480
struct UVInitialStroke UVInitialStroke
struct Temp_UvData Temp_UVData
static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: sculpt_uv.c:774
struct UvEdge UvEdge
void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
Definition: sculpt_uv.c:822
struct UvAdjacencyElement UvAdjacencyElement
static bool uv_edge_compare(const void *a, const void *b)
Definition: sculpt_uv.c:469
static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: sculpt_uv.c:752
struct UvSculptData UvSculptData
static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, const float mouse_coord[2], float alpha, float radius, float aspectRatio)
Definition: sculpt_uv.c:233
static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *event, Object *obedit)
Definition: sculpt_uv.c:305
static uint uv_edge_hash(const void *key)
Definition: sculpt_uv.c:463
static int uv_element_offset_from_face_get(UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands)
Definition: sculpt_uv.c:453
#define MARK_BOUNDARY
Definition: sculpt_uv.c:61
static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
Definition: sculpt_uv.c:427
struct UVInitialStrokeElement UVInitialStrokeElement
struct BMesh * bm
Definition: BKE_editmesh.h:52
void * data
Definition: bmesh_class.h:63
BMHeader head
Definition: bmesh_class.h:157
struct BMLoop * next
Definition: bmesh_class.h:245
int totvert
Definition: bmesh_class.h:297
CustomData ldata
Definition: bmesh_class.h:337
char uv_sculpt_tool
struct CurveMapping * curve
struct Brush * brush
struct ToolSettings * toolsettings
float sum_co[2]
Definition: sculpt_uv.c:143
int ncounter
Definition: sculpt_uv.c:144
float p[2]
Definition: sculpt_uv.c:143
float sum_b[2]
Definition: sculpt_uv.c:143
float b[2]
Definition: sculpt_uv.c:143
UvSculpt * uvsculpt
float init_coord[2]
Definition: sculpt_uv.c:99
int totalInitialSelected
Definition: sculpt_uv.c:96
UVInitialStrokeElement * initialSelection
Definition: sculpt_uv.c:93
UvElement * element
Definition: sculpt_uv.c:65
char flag
Definition: sculpt_uv.c:77
uint uv1
Definition: sculpt_uv.c:73
uint uv2
Definition: sculpt_uv.c:74
struct UvElement * buf
struct BMLoop * l
Definition: uvedit_intern.h:43
struct BMFace * efa
Definition: uvedit_intern.h:42
int totalUniqueUvs
Definition: sculpt_uv.c:110
UVInitialStroke * initial_stroke
Definition: sculpt_uv.c:119
Paint * uvsculpt
Definition: sculpt_uv.c:128
UvElementMap * elementMap
Definition: sculpt_uv.c:125
UvAdjacencyElement * uv
Definition: sculpt_uv.c:107
int totalUvEdges
Definition: sculpt_uv.c:116
UvEdge * uvedges
Definition: sculpt_uv.c:113
wmTimer * timer
Definition: sculpt_uv.c:122
int mval[2]
Definition: WM_types.h:583
short type
Definition: WM_types.h:577
void * customdata
Definition: WM_types.h:631
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
struct PointerRNA * ptr
CCL_NAMESPACE_BEGIN ccl_device float invert(float color, float factor)
Definition: svm_invert.h:19
bool uv_find_nearest_vert(struct Scene *scene, struct Object *obedit, const float co[2], const float penalty_dist, struct UvNearestHit *hit)
#define UV_NEAREST_HIT_INIT_MAX(v2d)
Definition: uvedit_intern.h:65
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ TIMER
@ MOUSEMOVE
@ LEFTMOUSE
@ MIDDLEMOUSE
@ INBETWEEN_MOUSEMOVE
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1669
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632