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