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