svn merge ^/trunk/blender -r43564:43609
[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_editVert.h"
38 #include "BLI_math.h"
39 #include "BLI_ghash.h"
40
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_brush_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], float alpha, float radius, float aspectRatio){
160         Temp_UVData *tmp_uvdata;
161         float diff[2];
162         int i;
163         float radius_root = sqrt(radius);
164         Brush *brush = paint_brush(sculptdata->uvsculpt);
165
166         tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
167
168         /* counting neighbors */
169         for (i = 0; i < sculptdata->totalUvEdges; i++){
170                 UvEdge *tmpedge = sculptdata->uvedges+i;
171                 tmp_uvdata[tmpedge->uv1].ncounter++;
172                 tmp_uvdata[tmpedge->uv2].ncounter++;
173
174                 add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
175                 add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
176         }
177
178         for (i = 0; i < sculptdata->totalUniqueUvs; i++){
179                 copy_v2_v2(diff,tmp_uvdata[i].sum_co);
180                 mul_v2_fl(diff,1.f/tmp_uvdata[i].ncounter);
181                 copy_v2_v2(tmp_uvdata[i].p,diff);
182
183                 tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
184                 tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
185         }
186
187         for (i = 0; i < sculptdata->totalUvEdges; i++){
188                 UvEdge *tmpedge = sculptdata->uvedges+i;
189                 add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
190                 add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
191         }
192
193         for (i = 0; i < sculptdata->totalUniqueUvs; i++){
194                 float dist;
195                 /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
196                  * If ever uv brushes get their own mode we should check for toolsettings option too */
197                 if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
198                         continue;
199                 }
200
201                 sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
202                 diff[1] /= aspectRatio;
203                 if((dist = dot_v2v2(diff, diff)) <= radius){
204                         UvElement *element;
205                         float strength;
206                         strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
207
208                         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));
209                         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));
210
211                         for(element = sculptdata->uv[i].element; element; element = element->next){
212 #if 0 /* BMESH_TODO */
213                                 MTFace *mt;
214                                 if(element->separate && element != sculptdata->uv[i].element)
215                                         break;
216                                 mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
217                                 copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
218 #else
219                                 (void)em;
220 #endif /* BMESH_TODO */
221                         }
222                 }
223         }
224
225         MEM_freeN(tmp_uvdata);
226
227         return;
228 }
229
230 static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
231 {
232         Temp_UVData *tmp_uvdata;
233         float diff[2];
234         int i;
235         float radius_root = sqrt(radius);
236         Brush *brush = paint_brush(sculptdata->uvsculpt);
237
238         tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
239
240         /* counting neighbors */
241         for (i = 0; i < sculptdata->totalUvEdges; i++){
242                 UvEdge *tmpedge = sculptdata->uvedges+i;
243                 tmp_uvdata[tmpedge->uv1].ncounter++;
244                 tmp_uvdata[tmpedge->uv2].ncounter++;
245
246                 add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
247                 add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
248         }
249
250         /* Original Lacplacian algorithm included removal of normal component of translation. here it is not
251          * needed since we translate along the UV plane always.*/
252         for (i = 0; i < sculptdata->totalUniqueUvs; i++){
253                 copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
254                 mul_v2_fl(tmp_uvdata[i].p, 1.f/tmp_uvdata[i].ncounter);
255         }
256
257         for (i = 0; i < sculptdata->totalUniqueUvs; i++){
258                 float dist;
259                 /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
260                  * If ever uv brushes get their own mode we should check for toolsettings option too */
261                 if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
262                         continue;
263                 }
264
265                 sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
266                 diff[1] /= aspectRatio;
267                 if((dist = dot_v2v2(diff, diff)) <= radius){
268                         UvElement *element;
269                         float strength;
270                         strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
271
272                         sculptdata->uv[i].uv[0] = (1.0-strength)*sculptdata->uv[i].uv[0] + strength*tmp_uvdata[i].p[0];
273                         sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*tmp_uvdata[i].p[1];
274
275                         for(element = sculptdata->uv[i].element; element; element = element->next){
276 #if 0 /* BMESH_TODO */
277                                 MTFace *mt;
278                                 if(element->separate && element != sculptdata->uv[i].element)
279                                         break;
280                                 mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
281                                 copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
282 #else
283                                 (void)em;
284 #endif /* BMESH_TODO */
285                         }
286                 }
287         }
288
289         MEM_freeN(tmp_uvdata);
290
291         return;
292 }
293
294
295 static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, Object *obedit)
296 {
297         float co[2], radius, radius_root;
298         Scene *scene = CTX_data_scene(C);
299         ARegion *ar = CTX_wm_region(C);
300         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
301         unsigned int tool;
302         UvSculptData *sculptdata = (UvSculptData *)op->customdata;
303         SpaceImage *sima;
304         int invert;
305         int width, height;
306         float aspectRatio;
307         float alpha, zoomx, zoomy;
308         Brush *brush = paint_brush(sculptdata->uvsculpt);
309         ToolSettings *toolsettings = CTX_data_tool_settings(C);
310         tool = sculptdata->tool;
311         invert = sculptdata->invert? -1 : 1;
312         alpha = brush_alpha(scene, brush);
313         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
314
315         sima = CTX_wm_space_image(C);
316         ED_space_image_size(sima, &width, &height);
317         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
318
319         radius = brush_size(scene, brush)/(width*zoomx);
320         aspectRatio = width/(float)height;
321
322         /* We will compare squares to save some computation */
323         radius = radius*radius;
324         radius_root = sqrt(radius);
325
326         /*
327          * Pinch Tool
328          */
329         if(tool == UV_SCULPT_TOOL_PINCH){
330                 int i;
331                 alpha *= invert;
332                 for (i = 0; i < sculptdata->totalUniqueUvs; i++){
333                         float dist, diff[2];
334                         /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start
335                          * If ever uv brushes get their own mode we should check for toolsettings option too */
336                         if(sculptdata->uv[i].flag & MARK_BOUNDARY){
337                                 continue;
338                         }
339
340                         sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
341                         diff[1] /= aspectRatio;
342                         if((dist = dot_v2v2(diff, diff)) <= radius){
343                                 UvElement *element;
344                                 float strength;
345                                 strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
346                                 normalize_v2(diff);
347
348                                 sculptdata->uv[i].uv[0] -= strength*diff[0]*0.001;
349                                 sculptdata->uv[i].uv[1] -= strength*diff[1]*0.001;
350
351                                 for(element = sculptdata->uv[i].element; element; element = element->next){
352 #if 0 /* BMESH_TODO*/
353                                         MTFace *mt;
354                                         if(element->separate && element != sculptdata->uv[i].element)
355                                                 break;
356                                         mt = CustomData_em_get(&bm->fdata, element->face->data, CD_MTFACE);
357                                         copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
358 #endif
359                                 }
360                         }
361                 }
362         }
363
364         /*
365          * Smooth Tool
366          */
367         else if(tool == UV_SCULPT_TOOL_RELAX){
368                 unsigned int method = toolsettings->uv_relax_method;
369                 if(method == UV_SCULPT_TOOL_RELAX_HC){
370                         HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
371                 }else{
372                         laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
373                 }
374         }
375
376         /*
377          * Grab Tool
378          */
379         else if(tool == UV_SCULPT_TOOL_GRAB){
380                 int i;
381                 float diff[2];
382                 sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
383
384                 for(i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++ ){
385                         UvElement *element;
386                         int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
387                         float strength = sculptdata->initial_stroke->initialSelection[i].strength;
388                         sculptdata->uv[uvindex].uv[0] = sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength*diff[0];
389                         sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength*diff[1];
390
391                         for(element = sculptdata->uv[uvindex].element; element; element = element->next){
392 #if 0 /* BMESH_TODO */
393                                 MTFace *mt;
394                                 if(element->separate && element != sculptdata->uv[uvindex].element)
395                                         break;
396                                 mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
397                                 copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[uvindex].uv);
398 #endif /* BMESH_TODO */
399                         }
400                 }
401         }
402 }
403
404
405 static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
406 {
407         UvSculptData *data = op->customdata;
408         if(data->timer){
409                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
410         }
411         if(data->elementMap)
412         {
413                 EDBM_free_uv_element_map(data->elementMap);
414         }
415         if(data->uv){
416                 MEM_freeN(data->uv);
417         }
418         if(data->uvedges){
419                 MEM_freeN(data->uvedges);
420         }
421         if(data->initial_stroke){
422                 if(data->initial_stroke->initialSelection){
423                         MEM_freeN(data->initial_stroke->initialSelection);
424                 }
425                 MEM_freeN(data->initial_stroke);
426         }
427
428         MEM_freeN(data);
429         op->customdata = NULL;
430 }
431
432 static int get_uv_element_offset_from_face(UvElementMap *map, BMFace *efa, int index, int island_index, int doIslands){
433         UvElement *element = ED_get_uv_element(map, efa, index);
434         if(!element || (doIslands && element->island != island_index)){
435                 return -1;
436         }
437         return element - map->buf;
438 }
439
440
441 static unsigned int     uv_edge_hash(const void *key){
442         UvEdge *edge = (UvEdge *)key;
443         return 
444                 BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
445                 BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
446 }
447
448 static int uv_edge_compare(const void *a, const void *b){
449         UvEdge *edge1 = (UvEdge *)a;
450         UvEdge *edge2 = (UvEdge *)b;
451
452         if((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)){
453                 return 0;
454         }
455         return 1;
456 }
457
458
459 static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent *event)
460 {
461         Scene *scene = CTX_data_scene(C);
462         Object *obedit = CTX_data_edit_object(C);
463         ToolSettings *ts = scene->toolsettings;
464         UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
465         BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
466         BMesh *bm = em->bm;
467
468         op->customdata = data;
469
470         if(data){
471                 int counter = 0, i;
472                 ARegion *ar= CTX_wm_region(C);
473                 float co[2];
474                 EditFace *efa;
475                 UvEdge *edges;
476                 GHash *edgeHash;
477                 GHashIterator* ghi;
478                 MTFace *mt;
479                 int do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
480                 int island_index = 0;
481                 /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
482                 int *uniqueUv;
483                 data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH)? UV_SCULPT_TOOL_RELAX : ts->uv_sculpt_tool;
484                 data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT)? 1 : 0;
485
486                 data->uvsculpt = &ts->uvsculpt->paint;
487
488                 if(do_island_optimization){
489                         /* We will need island information */
490                         if(ts->uv_flag & UV_SYNC_SELECTION){
491                                 data->elementMap = EDBM_make_uv_element_map(em, 0, 1);
492                         }else{
493                                 data->elementMap = EDBM_make_uv_element_map(em, 1, 1);
494                         }
495                 }else {
496                         if(ts->uv_flag & UV_SYNC_SELECTION){
497                                 data->elementMap = EDBM_make_uv_element_map(em, 0, 0);
498                         }else{
499                                 data->elementMap = EDBM_make_uv_element_map(em, 1, 0);
500                         }
501                 }
502
503                 if(!data->elementMap){
504                         uv_sculpt_stroke_exit(C, op);
505                         return NULL;
506                 }
507
508                 /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
509                 UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
510
511                 /* we need to find the active island here */
512                 if(do_island_optimization){
513                         UvElement *element;
514                         NearestHit hit;
515                         Image *ima= CTX_data_edit_image(C);
516                         uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
517
518                         element = ED_get_uv_element(data->elementMap, hit.efa, hit.lindex);
519                         island_index = element->island;
520                 }
521
522
523                 /* Count 'unique' uvs */
524                 for(i = 0; i < data->elementMap->totalUVs; i++){
525                         if(data->elementMap->buf[i].separate
526                         && (!do_island_optimization || data->elementMap->buf[i].island == island_index)){
527                                 counter++;
528                         }
529                 }
530
531                 /* Allocate the unique uv buffers */
532                 data->uv = MEM_mallocN(sizeof(*data->uv)*counter, "uv_brush_unique_uvs");
533                 uniqueUv = MEM_mallocN(sizeof(*uniqueUv)*data->elementMap->totalUVs, "uv_brush_unique_uv_map");
534                 edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
535                 /* we have at most totalUVs edges */
536                 edges = MEM_mallocN(sizeof(*edges)*data->elementMap->totalUVs, "uv_brush_all_edges");
537                 if(!data->uv || !uniqueUv || !edgeHash || !edges){
538                         if(edges){
539                                 MEM_freeN(edges);
540                         }
541                         if(uniqueUv){
542                                 MEM_freeN(uniqueUv);
543                         }
544                         if(edgeHash){
545                                 MEM_freeN(edgeHash);
546                         }
547                         uv_sculpt_stroke_exit(C, op);
548                         return NULL;
549                 }
550
551                 data->totalUniqueUvs = counter;
552                 /* So that we can use this as index for the UvElements */
553                 counter = -1;
554                 /* initialize the unique UVs */
555                 for(i = 0; i < bm->totvert; i++){
556                         UvElement *element = data->elementMap->vert[i];
557                         for(; element; element = element->next){
558                                 if(element->separate){
559                                         if(do_island_optimization && (element->island != island_index)){
560                                                 /* skip this uv if not on the active island */
561                                                 for(; element->next && !(element->next->separate); element = element->next)
562                                                         ;
563                                                 continue;
564                                         }
565 #if 0 /* BMESH_TODO */
566                                         efa = element->face;
567                                         mt = CustomData_em_get(&bm->fdata, efa->data, CD_MTFACE);
568
569                                         counter++;
570                                         data->uv[counter].element = element;
571                                         data->uv[counter].flag = 0;
572                                         data->uv[counter].uv = mt->uv[element->tfindex];
573 #else
574                                         (void)efa;
575                                         (void)mt;
576 #endif /* BMESH_TODO */
577                                 }
578                                 /* pointer arithmetic to the rescue, as always :)*/
579                                 uniqueUv[element - data->elementMap->buf] = counter;
580                         }
581                 }
582
583 #if 0 /* BMESH_TODO */
584                 /* Now, on to generate our uv connectivity data */
585                 for(efa = em->faces.first, counter = 0; efa; efa = efa->next){
586                         int nverts = efa->v4 ? 4 : 3;
587                         for(i = 0; i < nverts; i++){
588                                 int offset1, itmp1 = get_uv_element_offset_from_face(data->elementMap, efa, i, island_index, do_island_optimization);
589                                 int offset2, itmp2 = get_uv_element_offset_from_face(data->elementMap, efa, (i+1)%nverts, island_index, do_island_optimization);
590
591                                 /* Skip edge if not found(unlikely) or not on valid island */
592                                 if(itmp1 == -1 || itmp2 == -1)
593                                         continue;
594
595                                 offset1 = uniqueUv[itmp1];
596                                 offset2 = uniqueUv[itmp2];
597
598                                 edges[counter].flag = 0;
599                                 /* using an order policy, sort uvs according to address space. This avoids
600                                  * Having two different UvEdges with the same uvs on different positions  */
601                                 if(offset1 < offset2){
602                                         edges[counter].uv1 = offset1;
603                                         edges[counter].uv2 = offset2;
604                                 }
605                                 else{
606                                         edges[counter].uv1 = offset2;
607                                         edges[counter].uv2 = offset1;
608                                 }
609                                 /* Hack! Set the value of the key to its flag. Now we can set the flag when an edge exists twice :) */
610                                 if(BLI_ghash_haskey(edgeHash, &edges[counter])){
611                                         char *flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
612                                         *flag = 1;
613                                 }
614                                 else{
615                                         /* Hack mentioned */
616                                         BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
617                                 }
618                                 counter++;
619                         }
620                 }
621 #endif /* BMESH_TODO */
622
623                 MEM_freeN(uniqueUv);
624
625                 /* Allocate connectivity data, we allocate edges once */
626                 data->uvedges = MEM_mallocN(sizeof(*data->uvedges)*BLI_ghash_size(edgeHash), "uv_brush_edge_connectivity_data");
627                 if(!data->uvedges){
628                         BLI_ghash_free(edgeHash, NULL, NULL);
629                         MEM_freeN(edges);
630                         uv_sculpt_stroke_exit(C, op);
631                         return NULL;
632                 }
633                 ghi = BLI_ghashIterator_new(edgeHash);
634                 if(!ghi){
635                         BLI_ghash_free(edgeHash, NULL, NULL);
636                         MEM_freeN(edges);
637                         uv_sculpt_stroke_exit(C, op);
638                         return NULL;
639                 }
640                 /* fill the edges with data */
641                 for(i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){
642                         data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
643                 }
644                 data->totalUvEdges = BLI_ghash_size(edgeHash);
645
646                 /* cleanup temporary stuff */
647                 BLI_ghashIterator_free(ghi);
648                 BLI_ghash_free(edgeHash, NULL, NULL);
649                 MEM_freeN(edges);
650
651                 /* transfer boundary edge property to uvs */
652                 if(ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS){
653                         for(i = 0; i < data->totalUvEdges; i++){
654                                 if(!data->uvedges[i].flag){
655                                         data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
656                                         data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
657                                 }
658                         }
659                 }
660
661                 /* Allocate initial selection for grab tool */
662                 if(data->tool){
663                         float radius, radius_root;
664                         UvSculptData *sculptdata = (UvSculptData *)op->customdata;
665                         SpaceImage *sima;
666                         int width, height;
667                         float aspectRatio;
668                         float alpha, zoomx, zoomy;
669                         Brush *brush = paint_brush(sculptdata->uvsculpt);
670
671                         alpha = brush_alpha(scene, brush);
672
673                         radius = brush_size(scene, brush);
674                         sima = CTX_wm_space_image(C);
675                         ED_space_image_size(sima, &width, &height);
676                         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
677
678                         aspectRatio = width/(float)height;
679                         radius /= (width*zoomx);
680                         radius = radius*radius;
681                         radius_root = sqrt(radius);
682
683                         /* Allocate selection stack */
684                         data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke");
685                         if(!data->initial_stroke){
686                                 uv_sculpt_stroke_exit(C, op);
687                         }
688                         data->initial_stroke->initialSelection = MEM_mallocN(sizeof(*data->initial_stroke->initialSelection)*data->totalUniqueUvs, "uv_sculpt_initial_selection");
689                         if(!data->initial_stroke->initialSelection){
690                                 uv_sculpt_stroke_exit(C, op);
691                         }
692
693                         copy_v2_v2(data->initial_stroke->init_coord, co);
694
695                         counter = 0;
696
697                         for(i = 0; i < data->totalUniqueUvs; i++){
698                                 float dist, diff[2];
699                                 if(data->uv[i].flag & MARK_BOUNDARY){
700                                         continue;
701                                 }
702
703                                 sub_v2_v2v2(diff, data->uv[i].uv, co);
704                                 diff[1] /= aspectRatio;
705                                 if((dist = dot_v2v2(diff, diff)) <= radius){
706                                         float strength;
707                                         strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
708
709                                         data->initial_stroke->initialSelection[counter].uv = i;
710                                         data->initial_stroke->initialSelection[counter].strength = strength;
711                                         copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
712                                         counter++;
713                                 }
714                         }
715
716                         data->initial_stroke->totalInitialSelected = counter;
717                 }
718         }
719
720         return op->customdata;
721 }
722
723 static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
724 {
725         UvSculptData *data;
726         Object *obedit = CTX_data_edit_object(C);
727
728         if(!(data = uv_sculpt_stroke_init(C, op, event))) {
729                 return OPERATOR_CANCELLED;
730         }
731
732         uv_sculpt_stroke_apply(C, op, event, obedit);
733
734         data->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
735
736         if(!data->timer){
737                 uv_sculpt_stroke_exit(C, op);
738                 return OPERATOR_CANCELLED;
739         }
740         WM_event_add_modal_handler(C, op);
741
742         return OPERATOR_RUNNING_MODAL;
743 }
744
745
746 static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
747 {
748         UvSculptData *data = (UvSculptData *)op->customdata;
749         Object *obedit = CTX_data_edit_object(C);
750
751         switch(event->type) {
752                 case LEFTMOUSE:
753                 case MIDDLEMOUSE:
754                 case RIGHTMOUSE:
755                         uv_sculpt_stroke_exit(C, op);
756                         return OPERATOR_FINISHED;
757
758                 case MOUSEMOVE:
759                 case INBETWEEN_MOUSEMOVE:
760                         uv_sculpt_stroke_apply(C, op, event, obedit);
761                         break;
762                 case TIMER:
763                         if(event->customdata == data->timer)
764                                 uv_sculpt_stroke_apply(C, op, event, obedit);
765                         break;
766                 default:
767                         return OPERATOR_RUNNING_MODAL;
768         }
769
770         ED_region_tag_redraw(CTX_wm_region(C));
771         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
772         DAG_id_tag_update(obedit->data, 0);
773         return OPERATOR_RUNNING_MODAL;
774 }
775
776 void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
777 {
778         static EnumPropertyItem stroke_mode_items[] = {
779                 {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
780                 {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
781                 {BRUSH_STROKE_SMOOTH, "RELAX", 0, "Relax", "Switch brush to relax mode for duration of stroke"},
782                 {0}
783         };
784
785         /* identifiers */
786         ot->name = "Sculpt UVs";
787         ot->description = "Sculpt UVs using a brush";
788         ot->idname = "SCULPT_OT_uv_sculpt_stroke";
789
790         /* api callbacks */
791         ot->invoke = uv_sculpt_stroke_invoke;
792         ot->modal = uv_sculpt_stroke_modal;
793         ot->poll = uv_sculpt_poll;
794
795         /* flags */
796         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
797
798         /* props */
799         RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL, "Mode", "Stroke Mode");
800 }