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