Fix a bug in the T34039 hack in case when a modifier key is not mapped.
[blender.git] / source / blender / editors / sculpt_paint / sculpt_uv.c
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
21 /** \file
22  * \ingroup edsculpt
23  */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_utildefines.h"
28 #include "BLI_math.h"
29 #include "BLI_ghash.h"
30
31 #include "DNA_object_types.h"
32 #include "DNA_scene_types.h"
33 #include "DNA_brush_types.h"
34 #include "DNA_meshdata_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_screen.h"
47 #include "ED_image.h"
48 #include "ED_mesh.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 */
65   UvElement *element;
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;
70 } UvAdjacencyElement;
71
72 typedef struct UvEdge {
73   unsigned int uv1;
74   unsigned int uv2;
75   /* general use flag
76    * (Used to check if edge is boundary here, and propagates to adjacency elements) */
77   char flag;
78 } UvEdge;
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];
89 } UVInitialStrokeElement;
90
91 typedef struct UVInitialStroke {
92   /* Initial Selection,for grab brushes for instance */
93   UVInitialStrokeElement *initialSelection;
94
95   /* total initially selected UVs*/
96   int totalInitialSelected;
97
98   /* initial mouse coordinates */
99   float init_coord[2];
100 } UVInitialStroke;
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 */
107   UvAdjacencyElement *uv;
108
109   /* ...Is what it says */
110   int totalUniqueUvs;
111
112   /* Edges used for adjacency info, used with laplacian smoothing */
113   UvEdge *uvedges;
114
115   /* need I say more? */
116   int totalUvEdges;
117
118   /* data for initial stroke, used by tools like grab */
119   UVInitialStroke *initial_stroke;
120
121   /* timer to be used for airbrush-type brush */
122   wmTimer *timer;
123
124   /* to determine quickly adjacent uvs */
125   UvElementMap *elementMap;
126
127   /* uvsmooth Paint for fast reference */
128   Paint *uvsculpt;
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;
135 } UvSculptData;
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;
145 } Temp_UVData;
146
147 static void HC_relaxation_iteration_uv(BMEditMesh *em,
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.f / 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) {
200       UvElement *element;
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;
224         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
225         copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
226       }
227     }
228   }
229
230   MEM_freeN(tmp_uvdata);
231
232   return;
233 }
234
235 static void laplacian_relaxation_iteration_uv(BMEditMesh *em,
236                                               UvSculptData *sculptdata,
237                                               const float mouse_coord[2],
238                                               float alpha,
239                                               float radius,
240                                               float aspectRatio)
241 {
242   Temp_UVData *tmp_uvdata;
243   float diff[2];
244   int i;
245   float radius_root = sqrtf(radius);
246   Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
247
248   tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData),
249                                           "Temporal data");
250
251   /* counting neighbors */
252   for (i = 0; i < sculptdata->totalUvEdges; i++) {
253     UvEdge *tmpedge = sculptdata->uvedges + i;
254     tmp_uvdata[tmpedge->uv1].ncounter++;
255     tmp_uvdata[tmpedge->uv2].ncounter++;
256
257     add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
258     add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
259   }
260
261   /* Original Lacplacian algorithm included removal of normal component of translation.
262    * here it is not needed since we translate along the UV plane always. */
263   for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
264     copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
265     mul_v2_fl(tmp_uvdata[i].p, 1.f / tmp_uvdata[i].ncounter);
266   }
267
268   for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
269     float dist;
270     /* This is supposed to happen only if "Pin Edges" is on,
271      * since we have initialization on stroke start.
272      * If ever uv brushes get their own mode we should check for toolsettings option too. */
273     if ((sculptdata->uv[i].flag & MARK_BOUNDARY)) {
274       continue;
275     }
276
277     sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
278     diff[1] /= aspectRatio;
279     if ((dist = dot_v2v2(diff, diff)) <= radius) {
280       UvElement *element;
281       float strength;
282       strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
283
284       sculptdata->uv[i].uv[0] = (1.0f - strength) * sculptdata->uv[i].uv[0] +
285                                 strength * tmp_uvdata[i].p[0];
286       sculptdata->uv[i].uv[1] = (1.0f - strength) * sculptdata->uv[i].uv[1] +
287                                 strength * tmp_uvdata[i].p[1];
288
289       for (element = sculptdata->uv[i].element; element; element = element->next) {
290         MLoopUV *luv;
291         BMLoop *l;
292
293         if (element->separate && element != sculptdata->uv[i].element) {
294           break;
295         }
296
297         l = element->l;
298         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
299         copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
300       }
301     }
302   }
303
304   MEM_freeN(tmp_uvdata);
305
306   return;
307 }
308
309 static void uv_sculpt_stroke_apply(bContext *C,
310                                    wmOperator *op,
311                                    const wmEvent *event,
312                                    Object *obedit)
313 {
314   float co[2], radius, radius_root;
315   Scene *scene = CTX_data_scene(C);
316   ARegion *ar = CTX_wm_region(C);
317   BMEditMesh *em = BKE_editmesh_from_object(obedit);
318   unsigned int tool;
319   UvSculptData *sculptdata = (UvSculptData *)op->customdata;
320   SpaceImage *sima;
321   int invert;
322   int width, height;
323   float aspectRatio;
324   float alpha, zoomx, zoomy;
325   Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
326   ToolSettings *toolsettings = CTX_data_tool_settings(C);
327   tool = sculptdata->tool;
328   invert = sculptdata->invert ? -1 : 1;
329   alpha = BKE_brush_alpha_get(scene, brush);
330   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
331
332   sima = CTX_wm_space_image(C);
333   ED_space_image_get_size(sima, &width, &height);
334   ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
335
336   radius = BKE_brush_size_get(scene, brush) / (width * zoomx);
337   aspectRatio = width / (float)height;
338
339   /* We will compare squares to save some computation */
340   radius = radius * radius;
341   radius_root = sqrtf(radius);
342
343   /*
344    * Pinch Tool
345    */
346   if (tool == UV_SCULPT_TOOL_PINCH) {
347     int i;
348     alpha *= invert;
349     for (i = 0; i < sculptdata->totalUniqueUvs; i++) {
350       float dist, diff[2];
351       /* This is supposed to happen only if "Lock Borders" is on,
352        * since we have initialization on stroke start.
353        * If ever uv brushes get their own mode we should check for toolsettings option too. */
354       if (sculptdata->uv[i].flag & MARK_BOUNDARY) {
355         continue;
356       }
357
358       sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
359       diff[1] /= aspectRatio;
360       if ((dist = dot_v2v2(diff, diff)) <= radius) {
361         UvElement *element;
362         float strength;
363         strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
364         normalize_v2(diff);
365
366         sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
367         sculptdata->uv[i].uv[1] -= strength * diff[1] * 0.001f;
368
369         for (element = sculptdata->uv[i].element; element; element = element->next) {
370           MLoopUV *luv;
371           BMLoop *l;
372
373           if (element->separate && element != sculptdata->uv[i].element) {
374             break;
375           }
376
377           l = element->l;
378           luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
379           copy_v2_v2(luv->uv, sculptdata->uv[i].uv);
380         }
381       }
382     }
383   }
384
385   /*
386    * Smooth Tool
387    */
388   else if (tool == UV_SCULPT_TOOL_RELAX) {
389     unsigned int method = toolsettings->uv_relax_method;
390     if (method == UV_SCULPT_TOOL_RELAX_HC) {
391       HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
392     }
393     else {
394       laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
395     }
396   }
397
398   /*
399    * Grab Tool
400    */
401   else if (tool == UV_SCULPT_TOOL_GRAB) {
402     int i;
403     float diff[2];
404     sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
405
406     for (i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++) {
407       UvElement *element;
408       int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
409       float strength = sculptdata->initial_stroke->initialSelection[i].strength;
410       sculptdata->uv[uvindex].uv[0] =
411           sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength * diff[0];
412       sculptdata->uv[uvindex].uv[1] =
413           sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength * diff[1];
414
415       for (element = sculptdata->uv[uvindex].element; element; element = element->next) {
416         MLoopUV *luv;
417         BMLoop *l;
418
419         if (element->separate && element != sculptdata->uv[uvindex].element) {
420           break;
421         }
422
423         l = element->l;
424         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
425         copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv);
426       }
427     }
428   }
429 }
430
431 static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
432 {
433   UvSculptData *data = op->customdata;
434   if (data->timer) {
435     WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
436   }
437   if (data->elementMap) {
438     BM_uv_element_map_free(data->elementMap);
439   }
440   if (data->uv) {
441     MEM_freeN(data->uv);
442   }
443   if (data->uvedges) {
444     MEM_freeN(data->uvedges);
445   }
446   if (data->initial_stroke) {
447     if (data->initial_stroke->initialSelection) {
448       MEM_freeN(data->initial_stroke->initialSelection);
449     }
450     MEM_freeN(data->initial_stroke);
451   }
452
453   MEM_freeN(data);
454   op->customdata = NULL;
455 }
456
457 static int uv_element_offset_from_face_get(
458     UvElementMap *map, BMFace *efa, BMLoop *l, int island_index, const bool doIslands)
459 {
460   UvElement *element = BM_uv_element_get(map, efa, l);
461   if (!element || (doIslands && element->island != island_index)) {
462     return -1;
463   }
464   return element - map->buf;
465 }
466
467 static unsigned int uv_edge_hash(const void *key)
468 {
469   const UvEdge *edge = key;
470   return (BLI_ghashutil_uinthash(edge->uv2) + BLI_ghashutil_uinthash(edge->uv1));
471 }
472
473 static bool uv_edge_compare(const void *a, const void *b)
474 {
475   const UvEdge *edge1 = a;
476   const UvEdge *edge2 = b;
477
478   if ((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)) {
479     return 0;
480   }
481   return 1;
482 }
483
484 static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wmEvent *event)
485 {
486   Scene *scene = CTX_data_scene(C);
487   Object *obedit = CTX_data_edit_object(C);
488   ToolSettings *ts = scene->toolsettings;
489   UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
490   BMEditMesh *em = BKE_editmesh_from_object(obedit);
491   BMesh *bm = em->bm;
492
493   op->customdata = data;
494
495   BKE_curvemapping_initialize(ts->uvsculpt->paint.brush->curve);
496
497   if (data) {
498     int counter = 0, i;
499     ARegion *ar = CTX_wm_region(C);
500     float co[2];
501     BMFace *efa;
502     MLoopUV *luv;
503     BMLoop *l;
504     BMIter iter, liter;
505
506     UvEdge *edges;
507     GHash *edgeHash;
508     GHashIterator gh_iter;
509
510     bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
511     int island_index = 0;
512     /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
513     int *uniqueUv;
514     data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ?
515                      UV_SCULPT_TOOL_RELAX :
516                      ts->uvsculpt->paint.brush->uv_sculpt_tool;
517     data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
518
519     data->uvsculpt = &ts->uvsculpt->paint;
520
521     if (do_island_optimization) {
522       /* We will need island information */
523       if (ts->uv_flag & UV_SYNC_SELECTION) {
524         data->elementMap = BM_uv_element_map_create(bm, false, true, true);
525       }
526       else {
527         data->elementMap = BM_uv_element_map_create(bm, true, true, true);
528       }
529     }
530     else {
531       if (ts->uv_flag & UV_SYNC_SELECTION) {
532         data->elementMap = BM_uv_element_map_create(bm, false, true, false);
533       }
534       else {
535         data->elementMap = BM_uv_element_map_create(bm, true, true, false);
536       }
537     }
538
539     if (!data->elementMap) {
540       uv_sculpt_stroke_exit(C, op);
541       return NULL;
542     }
543
544     /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
545     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
546
547     /* we need to find the active island here */
548     if (do_island_optimization) {
549       UvElement *element;
550       UvNearestHit hit = UV_NEAREST_HIT_INIT;
551       Image *ima = CTX_data_edit_image(C);
552       uv_find_nearest_vert(scene, ima, obedit, co, 0.0f, &hit);
553
554       element = BM_uv_element_get(data->elementMap, hit.efa, hit.l);
555       island_index = element->island;
556     }
557
558     /* Count 'unique' uvs */
559     for (i = 0; i < data->elementMap->totalUVs; i++) {
560       if (data->elementMap->buf[i].separate &&
561           (!do_island_optimization || data->elementMap->buf[i].island == island_index)) {
562         counter++;
563       }
564     }
565
566     /* Allocate the unique uv buffers */
567     data->uv = MEM_mallocN(sizeof(*data->uv) * counter, "uv_brush_unique_uvs");
568     uniqueUv = MEM_mallocN(sizeof(*uniqueUv) * data->elementMap->totalUVs,
569                            "uv_brush_unique_uv_map");
570     edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
571     /* we have at most totalUVs edges */
572     edges = MEM_mallocN(sizeof(*edges) * data->elementMap->totalUVs, "uv_brush_all_edges");
573     if (!data->uv || !uniqueUv || !edgeHash || !edges) {
574       if (edges) {
575         MEM_freeN(edges);
576       }
577       if (uniqueUv) {
578         MEM_freeN(uniqueUv);
579       }
580       if (edgeHash) {
581         BLI_ghash_free(edgeHash, NULL, NULL);
582       }
583       uv_sculpt_stroke_exit(C, op);
584       return NULL;
585     }
586
587     data->totalUniqueUvs = counter;
588     /* So that we can use this as index for the UvElements */
589     counter = -1;
590     /* initialize the unique UVs */
591     for (i = 0; i < bm->totvert; i++) {
592       UvElement *element = data->elementMap->vert[i];
593       for (; element; element = element->next) {
594         if (element->separate) {
595           if (do_island_optimization && (element->island != island_index)) {
596             /* skip this uv if not on the active island */
597             for (; element->next && !(element->next->separate); element = element->next) {
598               /* pass */
599             }
600             continue;
601           }
602
603           l = element->l;
604           luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
605
606           counter++;
607           data->uv[counter].element = element;
608           data->uv[counter].flag = 0;
609           data->uv[counter].uv = luv->uv;
610         }
611         /* pointer arithmetic to the rescue, as always :)*/
612         uniqueUv[element - data->elementMap->buf] = counter;
613       }
614     }
615
616     /* Now, on to generate our uv connectivity data */
617     counter = 0;
618     BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
619       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
620         int offset1, itmp1 = uv_element_offset_from_face_get(
621                          data->elementMap, efa, l, island_index, do_island_optimization);
622         int offset2, itmp2 = uv_element_offset_from_face_get(
623                          data->elementMap, efa, l->next, island_index, do_island_optimization);
624         char *flag;
625
626         /* Skip edge if not found(unlikely) or not on valid island */
627         if (itmp1 == -1 || itmp2 == -1) {
628           continue;
629         }
630
631         offset1 = uniqueUv[itmp1];
632         offset2 = uniqueUv[itmp2];
633
634         edges[counter].flag = 0;
635         /* using an order policy, sort uvs according to address space. This avoids
636          * Having two different UvEdges with the same uvs on different positions  */
637         if (offset1 < offset2) {
638           edges[counter].uv1 = offset1;
639           edges[counter].uv2 = offset2;
640         }
641         else {
642           edges[counter].uv1 = offset2;
643           edges[counter].uv2 = offset1;
644         }
645         /* Hack! Set the value of the key to its flag.
646          * Now we can set the flag when an edge exists twice :) */
647         flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
648         if (flag) {
649           *flag = 1;
650         }
651         else {
652           /* Hack mentioned */
653           BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
654         }
655         counter++;
656       }
657     }
658
659     MEM_freeN(uniqueUv);
660
661     /* Allocate connectivity data, we allocate edges once */
662     data->uvedges = MEM_mallocN(sizeof(*data->uvedges) * BLI_ghash_len(edgeHash),
663                                 "uv_brush_edge_connectivity_data");
664     if (!data->uvedges) {
665       BLI_ghash_free(edgeHash, NULL, NULL);
666       MEM_freeN(edges);
667       uv_sculpt_stroke_exit(C, op);
668       return NULL;
669     }
670
671     /* fill the edges with data */
672     i = 0;
673     GHASH_ITER (gh_iter, edgeHash) {
674       data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
675     }
676     data->totalUvEdges = BLI_ghash_len(edgeHash);
677
678     /* cleanup temporary stuff */
679     BLI_ghash_free(edgeHash, NULL, NULL);
680     MEM_freeN(edges);
681
682     /* transfer boundary edge property to uvs */
683     if (ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS) {
684       for (i = 0; i < data->totalUvEdges; i++) {
685         if (!data->uvedges[i].flag) {
686           data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
687           data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
688         }
689       }
690     }
691
692     /* Allocate initial selection for grab tool */
693     if (data->tool == UV_SCULPT_TOOL_GRAB) {
694       float radius, radius_root;
695       UvSculptData *sculptdata = (UvSculptData *)op->customdata;
696       SpaceImage *sima;
697       int width, height;
698       float aspectRatio;
699       float alpha, zoomx, zoomy;
700       Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
701
702       alpha = BKE_brush_alpha_get(scene, brush);
703
704       radius = BKE_brush_size_get(scene, brush);
705       sima = CTX_wm_space_image(C);
706       ED_space_image_get_size(sima, &width, &height);
707       ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
708
709       aspectRatio = width / (float)height;
710       radius /= (width * zoomx);
711       radius = radius * radius;
712       radius_root = sqrtf(radius);
713
714       /* Allocate selection stack */
715       data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke),
716                                          "uv_sculpt_initial_stroke");
717       if (!data->initial_stroke) {
718         uv_sculpt_stroke_exit(C, op);
719       }
720       data->initial_stroke->initialSelection = MEM_mallocN(
721           sizeof(*data->initial_stroke->initialSelection) * data->totalUniqueUvs,
722           "uv_sculpt_initial_selection");
723       if (!data->initial_stroke->initialSelection) {
724         uv_sculpt_stroke_exit(C, op);
725       }
726
727       copy_v2_v2(data->initial_stroke->init_coord, co);
728
729       counter = 0;
730
731       for (i = 0; i < data->totalUniqueUvs; i++) {
732         float dist, diff[2];
733         if (data->uv[i].flag & MARK_BOUNDARY) {
734           continue;
735         }
736
737         sub_v2_v2v2(diff, data->uv[i].uv, co);
738         diff[1] /= aspectRatio;
739         if ((dist = dot_v2v2(diff, diff)) <= radius) {
740           float strength;
741           strength = alpha * BKE_brush_curve_strength_clamped(brush, sqrtf(dist), radius_root);
742
743           data->initial_stroke->initialSelection[counter].uv = i;
744           data->initial_stroke->initialSelection[counter].strength = strength;
745           copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
746           counter++;
747         }
748       }
749
750       data->initial_stroke->totalInitialSelected = counter;
751     }
752   }
753
754   return op->customdata;
755 }
756
757 static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
758 {
759   UvSculptData *data;
760   Object *obedit = CTX_data_edit_object(C);
761
762   if (!(data = uv_sculpt_stroke_init(C, op, event))) {
763     return OPERATOR_CANCELLED;
764   }
765
766   uv_sculpt_stroke_apply(C, op, event, obedit);
767
768   data->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
769
770   if (!data->timer) {
771     uv_sculpt_stroke_exit(C, op);
772     return OPERATOR_CANCELLED;
773   }
774   WM_event_add_modal_handler(C, op);
775
776   return OPERATOR_RUNNING_MODAL;
777 }
778
779 static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
780 {
781   UvSculptData *data = (UvSculptData *)op->customdata;
782   Object *obedit = CTX_data_edit_object(C);
783
784   switch (event->type) {
785     case LEFTMOUSE:
786     case MIDDLEMOUSE:
787     case RIGHTMOUSE:
788       uv_sculpt_stroke_exit(C, op);
789       return OPERATOR_FINISHED;
790
791     case MOUSEMOVE:
792     case INBETWEEN_MOUSEMOVE:
793       uv_sculpt_stroke_apply(C, op, event, obedit);
794       break;
795     case TIMER:
796       if (event->customdata == data->timer) {
797         uv_sculpt_stroke_apply(C, op, event, obedit);
798       }
799       break;
800     default:
801       return OPERATOR_RUNNING_MODAL;
802   }
803
804   ED_region_tag_redraw(CTX_wm_region(C));
805   WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
806   DEG_id_tag_update(obedit->data, 0);
807   return OPERATOR_RUNNING_MODAL;
808 }
809
810 void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
811 {
812   static const EnumPropertyItem stroke_mode_items[] = {
813       {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Regular", "Apply brush normally"},
814       {BRUSH_STROKE_INVERT,
815        "INVERT",
816        0,
817        "Invert",
818        "Invert action of brush for duration of stroke"},
819       {BRUSH_STROKE_SMOOTH,
820        "RELAX",
821        0,
822        "Relax",
823        "Switch brush to relax mode for duration of stroke"},
824       {0},
825   };
826
827   /* identifiers */
828   ot->name = "Sculpt UVs";
829   ot->description = "Sculpt UVs using a brush";
830   ot->idname = "SCULPT_OT_uv_sculpt_stroke";
831
832   /* api callbacks */
833   ot->invoke = uv_sculpt_stroke_invoke;
834   ot->modal = uv_sculpt_stroke_modal;
835   ot->poll = ED_operator_uvedit_space_image;
836
837   /* flags */
838   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
839
840   /* props */
841   RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
842 }