doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / mesh / editface.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, Campbell Barton
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28
29 #include <math.h>
30 #include <string.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_math.h"
36 #include "BLI_heap.h"
37 #include "BLI_edgehash.h"
38 #include "BLI_editVert.h"
39 #include "BLI_utildefines.h"
40
41 #include "IMB_imbuf_types.h"
42 #include "IMB_imbuf.h"
43
44 #include "DNA_meshdata_types.h"
45 #include "DNA_object_types.h"
46 #include "DNA_scene_types.h"
47
48 #include "BKE_DerivedMesh.h"
49 #include "BKE_global.h"
50 #include "BKE_mesh.h"
51 #include "BKE_context.h"
52
53 #include "BIF_gl.h"
54
55 #include "ED_mesh.h"
56 #include "ED_screen.h"
57 #include "ED_view3d.h"
58
59 #include "WM_api.h"
60 #include "WM_types.h"
61
62 /* own include */
63 #include "mesh_intern.h"
64
65 /* copy the face flags, most importantly selection from the mesh to the final derived mesh,
66  * use in object mode when selecting faces (while painting) */
67 void paintface_flush_flags(Object *ob)
68 {
69         Mesh *me= get_mesh(ob);
70         DerivedMesh *dm= ob->derivedFinal;
71         MFace *faces, *mf, *mf_orig;
72         int *index_array = NULL;
73         int totface;
74         int i;
75         
76         if(me==NULL || dm==NULL)
77                 return;
78
79         index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
80
81         if(!index_array)
82                 return;
83         
84         faces = dm->getFaceArray(dm);
85         totface = dm->getNumFaces(dm);
86         
87         mf= faces;
88         
89         for (i= 0; i<totface; i++, mf++) { /* loop over derived mesh faces */
90                 mf_orig= me->mface + index_array[i];
91                 mf->flag= mf_orig->flag;
92         }
93 }
94
95 /* returns 0 if not found, otherwise 1 */
96 static int facesel_face_pick(struct bContext *C, Mesh *me, short *mval, unsigned int *index, short rect)
97 {
98         ViewContext vc;
99         view3d_set_viewcontext(C, &vc);
100
101         if (!me || me->totface==0)
102                 return 0;
103
104 // XXX  if (v3d->flag & V3D_INVALID_BACKBUF) {
105 // XXX drawview.c!              check_backbuf();
106 // XXX          persp(PERSP_VIEW);
107 // XXX  }
108
109         if (rect) {
110                 /* sample rect to increase changes of selecting, so that when clicking
111                    on an edge in the backbuf, we can still select a face */
112
113                 int dist;
114                 *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totface+1, &dist,0,NULL, NULL);
115         }
116         else {
117                 /* sample only on the exact position */
118                 *index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
119         }
120
121         if ((*index)<=0 || (*index)>(unsigned int)me->totface)
122                 return 0;
123
124         (*index)--;
125         
126         return 1;
127 }
128
129 /* last_sel, use em->act_face otherwise get the last selected face in the editselections
130  * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
131 MTFace *EM_get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy)
132 {
133         EditFace *efa = NULL;
134         
135         if(!EM_texFaceCheck(em))
136                 return NULL;
137         
138         efa = EM_get_actFace(em, sloppy);
139         
140         if (efa) {
141                 if (mcol) {
142                         if (CustomData_has_layer(&em->fdata, CD_MCOL))
143                                 *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
144                         else
145                                 *mcol = NULL;
146                 }
147                 if (act_efa) *act_efa = efa; 
148                 return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
149         }
150         if (act_efa) *act_efa= NULL;
151         if(mcol) *mcol = NULL;
152         return NULL;
153 }
154
155 void paintface_unhide(Scene *scene)
156 {
157         Mesh *me;
158         MFace *mface;
159         int a;
160         
161         me= get_mesh(OBACT);
162         if(me==0 || me->totface==0) return;
163         
164         mface= me->mface;
165         a= me->totface;
166         while(a--) {
167                 if(mface->flag & ME_HIDE) {
168                         mface->flag |= ME_FACE_SEL;
169                         mface->flag -= ME_HIDE;
170                 }
171                 mface++;
172         }
173
174         paintface_flush_flags(OBACT);
175 }
176
177 void paintface_hide(Scene *scene)
178 {
179         Mesh *me;
180         MFace *mface;
181         int a;
182         int shift=0, alt= 0; // XXX
183         
184         me= get_mesh(OBACT);
185         if(me==0 || me->totface==0) return;
186         
187         if(alt) {
188                 paintface_unhide(scene);
189                 return;
190         }
191         
192         mface= me->mface;
193         a= me->totface;
194         while(a--) {
195                 if(mface->flag & ME_HIDE);
196                 else {
197                         if(shift) {
198                                 if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
199                         }
200                         else {
201                                 if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
202                         }
203                 }
204                 if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
205                 
206                 mface++;
207         }
208         
209         paintface_flush_flags(OBACT);
210 }
211
212 /* Set tface seams based on edge data, uses hash table to find seam edges. */
213
214 static void hash_add_face(EdgeHash *ehash, MFace *mf)
215 {
216         BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
217         BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
218         if(mf->v4) {
219                 BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
220                 BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
221         }
222         else
223                 BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
224 }
225
226
227 static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
228 {
229         MFace *mf;
230         int a, doit=1, mark=0;
231         char *linkflag;
232         EdgeHash *ehash, *seamhash;
233         MEdge *med;
234
235         ehash= BLI_edgehash_new();
236         seamhash = BLI_edgehash_new();
237         linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
238
239         for(med=me->medge, a=0; a < me->totedge; a++, med++)
240                 if(med->flag & ME_SEAM)
241                         BLI_edgehash_insert(seamhash, med->v1, med->v2, NULL);
242
243         if (mode==0 || mode==1) {
244                 /* only put face under cursor in array */
245                 mf= ((MFace*)me->mface) + index;
246                 hash_add_face(ehash, mf);
247                 linkflag[index]= 1;
248         }
249         else {
250                 /* fill array by selection */
251                 mf= me->mface;
252                 for(a=0; a<me->totface; a++, mf++) {
253                         if(mf->flag & ME_HIDE);
254                         else if(mf->flag & ME_FACE_SEL) {
255                                 hash_add_face(ehash, mf);
256                                 linkflag[a]= 1;
257                         }
258                 }
259         }
260
261         while(doit) {
262                 doit= 0;
263
264                 /* expand selection */
265                 mf= me->mface;
266                 for(a=0; a<me->totface; a++, mf++) {
267                         if(mf->flag & ME_HIDE)
268                                 continue;
269
270                         if(!linkflag[a]) {
271                                 mark= 0;
272
273                                 if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
274                                         if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
275                                                 mark= 1;
276                                 if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
277                                         if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
278                                                 mark= 1;
279                                 if(mf->v4) {
280                                         if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
281                                                 if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
282                                                         mark= 1;
283                                         if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
284                                                 if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
285                                                         mark= 1;
286                                 }
287                                 else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1))
288                                         if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
289                                                 mark = 1;
290
291                                 if(mark) {
292                                         linkflag[a]= 1;
293                                         hash_add_face(ehash, mf);
294                                         doit= 1;
295                                 }
296                         }
297                 }
298
299         }
300
301         BLI_edgehash_free(ehash, NULL);
302         BLI_edgehash_free(seamhash, NULL);
303
304         if(mode==0 || mode==2) {
305                 for(a=0, mf=me->mface; a<me->totface; a++, mf++)
306                         if(linkflag[a])
307                                 mf->flag |= ME_FACE_SEL;
308                         else
309                                 mf->flag &= ~ME_FACE_SEL;
310         }
311         else if(mode==1) {
312                 for(a=0, mf=me->mface; a<me->totface; a++, mf++)
313                         if(linkflag[a] && (mf->flag & ME_FACE_SEL))
314                                 break;
315
316                 if (a<me->totface) {
317                         for(a=0, mf=me->mface; a<me->totface; a++, mf++)
318                                 if(linkflag[a])
319                                         mf->flag &= ~ME_FACE_SEL;
320                 }
321                 else {
322                         for(a=0, mf=me->mface; a<me->totface; a++, mf++)
323                                 if(linkflag[a])
324                                         mf->flag |= ME_FACE_SEL;
325                 }
326         }
327
328         MEM_freeN(linkflag);
329 }
330
331 void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[2]), int mode)
332 {
333         Mesh *me;
334         unsigned int index=0;
335
336         me = get_mesh(ob);
337         if(me==0 || me->totface==0) return;
338
339         if (mode==0 || mode==1) {
340                 // XXX - Causes glitches, not sure why
341                 /*
342                 if (!facesel_face_pick(C, me, mval, &index, 1))
343                         return;
344                 */
345         }
346
347         select_linked_tfaces_with_seams(mode, me, index);
348
349         paintface_flush_flags(ob);
350 }
351
352 /* note: caller needs to run paintface_flush_flags(ob) after this */
353 void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
354 {
355         Mesh *me;
356         MFace *mface;
357         int a;
358
359         me= get_mesh(ob);
360         if(me==0) return;
361         
362         if (action == SEL_TOGGLE) {
363                 action = SEL_SELECT;
364
365                 mface= me->mface;
366                 a= me->totface;
367                 while(a--) {
368                         if((mface->flag & ME_HIDE) == 0 && mface->flag & ME_FACE_SEL) {
369                                 action = SEL_DESELECT;
370                                 break;
371                         }
372                         mface++;
373                 }
374         }
375         
376         mface= me->mface;
377         a= me->totface;
378         while(a--) {
379                 if((mface->flag & ME_HIDE) == 0) {
380                         switch (action) {
381                         case SEL_SELECT:
382                                 mface->flag |= ME_FACE_SEL;
383                                 break;
384                         case SEL_DESELECT:
385                                 mface->flag &= ~ME_FACE_SEL;
386                                 break;
387                         case SEL_INVERT:
388                                 mface->flag ^= ME_FACE_SEL;
389                                 break;
390                         }
391                 }
392                 mface++;
393         }
394
395         if(flush_flags) {
396                 paintface_flush_flags(ob);
397         }
398 }
399
400 void paintface_select_swap(Scene *scene)
401 {
402         Mesh *me;
403         MFace *mface;
404         int a;
405                 
406         me= get_mesh(OBACT);
407         if(me==0) return;
408         
409         mface= me->mface;
410         a= me->totface;
411         while(a--) {
412                 if(mface->flag & ME_HIDE);
413                 else {
414                         if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
415                         else mface->flag |= ME_FACE_SEL;
416                 }
417                 mface++;
418         }
419         
420         paintface_flush_flags(OBACT);
421 }
422
423 int paintface_minmax(Object *ob, float *min, float *max)
424 {
425         Mesh *me= get_mesh(ob);
426         MFace *mf;
427         MVert *mv;
428         int a, ok=0;
429         float vec[3];
430
431         if(me==NULL)
432                 return ok;
433
434         mv= me->mvert;
435         mf= me->mface;
436         for (a=me->totface; a>0; a--, mf++) {
437                 if ((mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL)) == 0) {
438                         int i= mf->v4 ? 3:2;
439                         do {
440                                 mul_v3_m4v3(vec, ob->obmat, (mv + (*(&mf->v1 + i)))->co);
441                                 DO_MINMAX(vec, min, max);
442                         } while (i--);
443                         ok= 1;
444                 }
445         }
446         return ok;
447 }
448
449 /* ******************** edge loop shortest path ********************* */
450
451 #define ME_SEAM_DONE 2          /* reuse this flag */
452
453 static float edgetag_cut_cost(int e1, int e2, int vert)
454 {
455         EditVert *v = EM_get_vert_for_index(vert);
456         EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
457         EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
458         EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
459         float cost, d1[3], d2[3];
460
461         cost = len_v3v3(v1->co, v->co);
462         cost += len_v3v3(v->co, v2->co);
463
464         sub_v3_v3v3(d1, v->co, v1->co);
465         sub_v3_v3v3(d2, v2->co, v->co);
466
467         cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
468
469         return cost;
470 }
471
472 static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
473 {
474         int startadj, endadj = nedges[vertnum+1];
475
476         for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
477                 int adjnum = edges[startadj];
478                 EditEdge *eedadj = EM_get_edge_for_index(adjnum);
479                 float newcost;
480
481                 if (eedadj->f2 & ME_SEAM_DONE)
482                         continue;
483
484                 newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum);
485
486                 if (cost[adjnum] > newcost) {
487                         cost[adjnum] = newcost;
488                         prevedge[adjnum] = mednum;
489                         BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
490                 }
491         }
492 }
493
494 void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
495 {
496         
497         switch (scene->toolsettings->edge_mode) {
498         case EDGE_MODE_SELECT:
499                 EM_select_edge(eed, val);
500                 break;
501         case EDGE_MODE_TAG_SEAM:
502                 if (val)                {eed->seam = 255;}
503                 else                    {eed->seam = 0;}
504                 break;
505         case EDGE_MODE_TAG_SHARP:
506                 if (val)                {eed->sharp = 1;}
507                 else                    {eed->sharp = 0;}
508                 break;                          
509         case EDGE_MODE_TAG_CREASE:      
510                 if (val)                {eed->crease = 1.0f;}
511                 else                    {eed->crease = 0.0f;}
512                 break;
513         case EDGE_MODE_TAG_BEVEL:
514                 if (val)                {eed->bweight = 1.0f;}
515                 else                    {eed->bweight = 0.0f;}
516                 break;
517         }
518 }
519
520 int edgetag_context_check(Scene *scene, EditEdge *eed)
521 {
522         switch (scene->toolsettings->edge_mode) {
523         case EDGE_MODE_SELECT:
524                 return (eed->f & SELECT) ? 1 : 0;
525         case EDGE_MODE_TAG_SEAM:
526                 return eed->seam ? 1 : 0;
527         case EDGE_MODE_TAG_SHARP:
528                 return eed->sharp ? 1 : 0;
529         case EDGE_MODE_TAG_CREASE:      
530                 return eed->crease ? 1 : 0;
531         case EDGE_MODE_TAG_BEVEL:
532                 return eed->bweight ? 1 : 0;
533         }
534         return 0;
535 }
536
537
538 int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
539 {
540         EditEdge *eed;
541         EditVert *ev;
542         
543         Heap *heap;
544         float *cost;
545         int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
546
547
548         /* we need the vert */
549         for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
550                 ev->tmp.l = totvert;
551                 totvert++;
552         }
553
554         for (eed= em->edges.first; eed; eed = eed->next) {
555                 eed->f2 = 0;
556                 if (eed->h) {
557                         eed->f2 |= ME_SEAM_DONE;
558                 }
559                 eed->tmp.l = totedge;
560                 totedge++;
561         }
562
563         /* alloc */
564         nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
565         edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
566         prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
567         cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
568
569         /* count edges, compute adjacent edges offsets and fill adjacent edges */
570         for (eed= em->edges.first; eed; eed = eed->next) {
571                 nedges[eed->v1->tmp.l+1]++;
572                 nedges[eed->v2->tmp.l+1]++;
573         }
574
575         for (a=1; a<totvert; a++) {
576                 int newswap = nedges[a+1];
577                 nedges[a+1] = nedgeswap + nedges[a];
578                 nedgeswap = newswap;
579         }
580         nedges[0] = nedges[1] = 0;
581
582         for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
583                 edges[nedges[eed->v1->tmp.l+1]++] = a;
584                 edges[nedges[eed->v2->tmp.l+1]++] = a;
585
586                 cost[a] = 1e20f;
587                 prevedge[a] = -1;
588         }
589
590         /* regular dijkstra shortest path, but over edges instead of vertices */
591         heap = BLI_heap_new();
592         BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
593         cost[source->tmp.l] = 0.0f;
594
595         EM_init_index_arrays(em, 1, 1, 0);
596
597
598         while (!BLI_heap_empty(heap)) {
599                 mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
600                 eed = EM_get_edge_for_index( mednum );
601
602                 if (mednum == target->tmp.l)
603                         break;
604
605                 if (eed->f2 & ME_SEAM_DONE)
606                         continue;
607
608                 eed->f2 |= ME_SEAM_DONE;
609
610                 edgetag_add_adjacent(heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
611                 edgetag_add_adjacent(heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
612         }
613         
614         
615         MEM_freeN(nedges);
616         MEM_freeN(edges);
617         MEM_freeN(cost);
618         BLI_heap_free(heap, NULL);
619
620         for (eed= em->edges.first; eed; eed = eed->next) {
621                 eed->f2 &= ~ME_SEAM_DONE;
622         }
623
624         if (mednum != target->tmp.l) {
625                 MEM_freeN(prevedge);
626                 EM_free_index_arrays();
627                 return 0;
628         }
629
630         /* follow path back to source and mark as seam */
631         if (mednum == target->tmp.l) {
632                 short allseams = 1;
633
634                 mednum = target->tmp.l;
635                 do {
636                         eed = EM_get_edge_for_index( mednum );
637                         if (!edgetag_context_check(scene, eed)) {
638                                 allseams = 0;
639                                 break;
640                         }
641                         mednum = prevedge[mednum];
642                 } while (mednum != source->tmp.l);
643
644                 mednum = target->tmp.l;
645                 do {
646                         eed = EM_get_edge_for_index( mednum );
647                         if (allseams)
648                                 edgetag_context_set(scene, eed, 0);
649                         else
650                                 edgetag_context_set(scene, eed, 1);
651                         mednum = prevedge[mednum];
652                 } while (mednum != -1);
653         }
654
655         MEM_freeN(prevedge);
656         EM_free_index_arrays();
657         return 1;
658 }
659
660 /* *************************************** */
661 #if 0
662 static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
663 {
664         BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
665         BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
666         if (mf->v4) {
667                 BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
668                 BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
669         }
670         else
671                 BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
672 }
673
674 void seam_mark_clear_tface(Scene *scene, short mode)
675 {
676         Mesh *me;
677         MFace *mf;
678         MEdge *med;
679         int a;
680         
681         me= get_mesh(OBACT);
682         if(me==0 ||  me->totface==0) return;
683
684         if (mode == 0)
685                 mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
686
687         if (mode != 1 && mode != 2)
688                 return;
689
690         if (mode == 2) {
691                 EdgeHash *ehash = BLI_edgehash_new();
692
693                 for (a=0, mf=me->mface; a<me->totface; a++, mf++)
694                         if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
695                                 seam_edgehash_insert_face(ehash, mf);
696
697                 for (a=0, med=me->medge; a<me->totedge; a++, med++)
698                         if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
699                                 med->flag &= ~ME_SEAM;
700
701                 BLI_edgehash_free(ehash, NULL);
702         }
703         else {
704                 /* mark edges that are on both selected and deselected faces */
705                 EdgeHash *ehash1 = BLI_edgehash_new();
706                 EdgeHash *ehash2 = BLI_edgehash_new();
707
708                 for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
709                         if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
710                                 seam_edgehash_insert_face(ehash1, mf);
711                         else
712                                 seam_edgehash_insert_face(ehash2, mf);
713                 }
714
715                 for (a=0, med=me->medge; a<me->totedge; a++, med++)
716                         if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
717                                 BLI_edgehash_haskey(ehash2, med->v1, med->v2))
718                                 med->flag |= ME_SEAM;
719
720                 BLI_edgehash_free(ehash1, NULL);
721                 BLI_edgehash_free(ehash2, NULL);
722         }
723
724 // XXX  if (G.rt == 8)
725 //              unwrap_lscm(1);
726
727         me->drawflag |= ME_DRAWSEAMS;
728 }
729 #endif
730
731 int paintface_mouse_select(struct bContext *C, Object *ob, short mval[2], int extend)
732 {
733         Mesh *me;
734         MFace *mface, *msel;
735         unsigned int a, index;
736         
737         /* Get the face under the cursor */
738         me = get_mesh(ob);
739
740         if (!facesel_face_pick(C, me, mval, &index, 1))
741                 return 0;
742         
743         msel= (((MFace*)me->mface)+index);
744         if (msel->flag & ME_HIDE) return 0;
745         
746         /* clear flags */
747         mface = me->mface;
748         a = me->totface;
749         if (!extend) {
750                 while (a--) {
751                         mface->flag &= ~ME_FACE_SEL;
752                         mface++;
753                 }
754         }
755         
756         me->act_face = (int)index;
757
758         if (extend) {
759                 if (msel->flag & ME_FACE_SEL)
760                         msel->flag &= ~ME_FACE_SEL;
761                 else
762                         msel->flag |= ME_FACE_SEL;
763         }
764         else msel->flag |= ME_FACE_SEL;
765         
766         /* image window redraw */
767         
768         paintface_flush_flags(ob);
769         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
770         ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
771         return 1;
772 }
773
774 int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
775 {
776         Mesh *me;
777         MFace *mface;
778         struct ImBuf *ibuf;
779         unsigned int *rt;
780         int a, index;
781         char *selar;
782         int sx= rect->xmax-rect->xmin+1;
783         int sy= rect->ymax-rect->ymin+1;
784
785         me= get_mesh(vc->obact);
786
787         if(me==NULL || me->totface==0 || sx*sy <= 0)
788                 return OPERATOR_CANCELLED;
789
790         selar= MEM_callocN(me->totface+1, "selar");
791
792         if (extend == 0 && select)
793                 paintface_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
794
795         view3d_validate_backbuf(vc);
796
797         ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
798         rt = ibuf->rect;
799         glReadPixels(rect->xmin+vc->ar->winrct.xmin,  rect->ymin+vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
800         if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
801
802         a= sx*sy;
803         while(a--) {
804                 if(*rt) {
805                         index= WM_framebuffer_to_index(*rt);
806                         if(index<=me->totface) selar[index]= 1;
807                 }
808                 rt++;
809         }
810
811         mface= me->mface;
812         for(a=1; a<=me->totface; a++, mface++) {
813                 if(selar[a]) {
814                         if(mface->flag & ME_HIDE);
815                         else {
816                                 if(select) mface->flag |= ME_FACE_SEL;
817                                 else mface->flag &= ~ME_FACE_SEL;
818                         }
819                 }
820         }
821
822         IMB_freeImBuf(ibuf);
823         MEM_freeN(selar);
824
825 #ifdef __APPLE__        
826         glReadBuffer(GL_BACK);
827 #endif
828
829         paintface_flush_flags(vc->obact);
830
831         return OPERATOR_FINISHED;
832 }