~ubuntu-branches/ubuntu/utopic/blender/utopic-proposed

« back to all changes in this revision

Viewing changes to source/blender/editors/mesh/editmesh_tools.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-04-28 12:11:12 UTC
  • mto: (14.1.6 experimental) (1.5.1)
  • mto: This revision was merged to the branch mainline in revision 34.
  • Revision ID: package-import@ubuntu.com-20120428121112-2zi0vp8b6vejda8i
Tags: upstream-2.63
ImportĀ upstreamĀ versionĀ 2.63

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 *
21
21
 * The Original Code is: all of this file.
22
22
 *
23
 
 * Contributor(s): Johnny Matthews, Geoffrey Bantle.
 
23
 * Contributor(s): Joseph Eagar
24
24
 *
25
25
 * ***** END GPL LICENSE BLOCK *****
26
26
 */
29
29
 *  \ingroup edmesh
30
30
 */
31
31
 
32
 
 
33
 
/*
34
 
 
35
 
editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
36
 
 
37
 
*/
38
 
 
39
 
#include <stdlib.h>
40
 
#include <string.h>
41
 
#include <math.h>
42
 
#include <float.h>
43
 
 
44
 
#include "BLO_sys_types.h" // for intptr_t support
45
 
 
46
 
#include "DNA_meshdata_types.h"
 
32
#include "MEM_guardedalloc.h"
 
33
 
 
34
#include "DNA_material_types.h"
 
35
#include "DNA_mesh_types.h"
47
36
#include "DNA_modifier_types.h"
48
37
#include "DNA_object_types.h"
49
38
#include "DNA_scene_types.h"
50
 
#include "DNA_key_types.h"
51
 
 
52
 
#include "MEM_guardedalloc.h"
53
39
 
54
40
#include "RNA_define.h"
55
41
#include "RNA_access.h"
56
42
 
57
43
#include "BLI_blenlib.h"
58
44
#include "BLI_math.h"
59
 
#include "BLI_utildefines.h"
60
 
#include "BLI_editVert.h"
61
45
#include "BLI_rand.h"
62
 
#include "BLI_ghash.h"
63
 
#include "BLI_linklist.h"
64
 
#include "BLI_heap.h"
65
 
#include "BLI_scanfill.h"
66
46
 
 
47
#include "BKE_material.h"
67
48
#include "BKE_context.h"
 
49
#include "BKE_cdderivedmesh.h"
68
50
#include "BKE_depsgraph.h"
69
 
#include "BKE_global.h"
70
 
#include "BKE_key.h"
71
 
#include "BKE_mesh.h"
72
 
#include "BKE_bmesh.h"
 
51
#include "BKE_object.h"
73
52
#include "BKE_report.h"
74
 
 
 
53
#include "BKE_texture.h"
 
54
#include "BKE_main.h"
 
55
#include "BKE_tessmesh.h"
75
56
 
76
57
#include "WM_api.h"
77
58
#include "WM_types.h"
78
59
 
79
60
#include "ED_mesh.h"
 
61
#include "ED_object.h"
80
62
#include "ED_screen.h"
81
63
#include "ED_transform.h"
 
64
#include "ED_uvedit.h"
82
65
#include "ED_view3d.h"
83
 
#include "ED_object.h"
84
66
 
 
67
#include "RE_render_ext.h"
85
68
 
86
69
#include "mesh_intern.h"
87
70
 
88
 
/* XXX */
89
 
static void waitcursor(int UNUSED(val)) {}
90
 
#define add_numbut(a, b, c, d, e, f, g) {}
91
 
 
92
 
/* XXX */
93
 
 
94
 
/* RNA corner cut enum property - used in multiple files for tools
95
 
 * that need this property for esubdivideflag() */
96
 
EnumPropertyItem corner_type_items[] = {
97
 
        {SUBDIV_CORNER_PATH,  "PATH", 0, "Path", ""},
98
 
        {SUBDIV_CORNER_INNERVERT,  "INNER_VERTEX", 0, "Inner Vertex", ""},
99
 
        {SUBDIV_CORNER_FAN,  "FAN",  0, "Fan", ""},
100
 
        {0, NULL, 0, NULL, NULL}};
101
 
 
102
 
 
103
 
/* local prototypes ---------------*/
104
 
static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa);
105
 
int EdgeLoopDelete(EditMesh *em, wmOperator *op);
106
 
 
107
 
/********* qsort routines *********/
108
 
 
109
 
 
110
 
typedef struct xvertsort {
111
 
        float x;
112
 
        EditVert *v1;
113
 
} xvertsort;
114
 
 
115
 
static int vergxco(const void *v1, const void *v2)
116
 
{
117
 
        const xvertsort *x1=v1, *x2=v2;
118
 
 
119
 
        if( x1->x > x2->x ) return 1;
120
 
        else if( x1->x < x2->x) return -1;
121
 
        return 0;
122
 
}
123
 
 
124
 
struct facesort {
125
 
        uintptr_t x;
126
 
        struct EditFace *efa;
 
71
/* allow accumulated normals to form a new direction but don't
 
72
 * accept direct opposite directions else they will cancel each other out */
 
73
static void add_normal_aligned(float nor[3], const float add[3])
 
74
{
 
75
        if (dot_v3v3(nor, add) < -0.9999f) {
 
76
                sub_v3_v3(nor, add);
 
77
        }
 
78
        else {
 
79
                add_v3_v3(nor, add);
 
80
        }
 
81
}
 
82
 
 
83
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
 
84
{
 
85
        Object *obedit = CTX_data_edit_object(C);
 
86
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
87
        int cuts = RNA_int_get(op->ptr, "number_cuts");
 
88
        float smooth = 0.292f * RNA_float_get(op->ptr, "smoothness");
 
89
        float fractal = RNA_float_get(op->ptr, "fractal") / 2.5f;
 
90
 
 
91
        if (RNA_boolean_get(op->ptr, "quadtri") && 
 
92
            RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
 
93
        {
 
94
                RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
 
95
        }
 
96
        
 
97
        BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
 
98
                           smooth, fractal,
 
99
                           cuts,
 
100
                           SUBDIV_SELECT_ORIG, RNA_enum_get(op->ptr, "quadcorner"),
 
101
                           RNA_boolean_get(op->ptr, "quadtri"), TRUE,
 
102
                           RNA_int_get(op->ptr, "seed"));
 
103
 
 
104
        EDBM_update_generic(C, em, TRUE);
 
105
 
 
106
        return OPERATOR_FINISHED;
 
107
}
 
108
 
 
109
/* Note, these values must match delete_mesh() event values */
 
110
static EnumPropertyItem prop_mesh_cornervert_types[] = {
 
111
        {SUBD_INNERVERT,     "INNERVERT", 0,      "Inner Vert", ""},
 
112
        {SUBD_PATH,          "PATH", 0,           "Path", ""},
 
113
        {SUBD_STRAIGHT_CUT,  "STRAIGHT_CUT", 0,   "Straight Cut", ""},
 
114
        {SUBD_FAN,           "FAN", 0,            "Fan", ""},
 
115
        {0, NULL, 0, NULL, NULL}
127
116
};
128
117
 
129
 
 
130
 
static int vergface(const void *v1, const void *v2)
131
 
{
132
 
        const struct facesort *x1=v1, *x2=v2;
133
 
 
134
 
        if( x1->x > x2->x ) return 1;
135
 
        else if( x1->x < x2->x) return -1;
136
 
        return 0;
137
 
}
138
 
 
139
 
 
140
 
/* *********************************** */
141
 
 
142
 
static void convert_to_triface(EditMesh *em, int direction)
143
 
{
144
 
        EditFace *efa, *efan, *next;
145
 
        float fac;
146
 
 
147
 
        efa= em->faces.last;
148
 
        while(efa) {
149
 
                next= efa->prev;
150
 
                if(efa->v4) {
151
 
                        if(efa->f & SELECT) {
152
 
                                /* choose shortest diagonal for split */
153
 
                                fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co);
154
 
                                /* this makes sure exact squares get split different in both cases */
155
 
                                if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) {
156
 
                                        efan= EM_face_from_faces(em, efa, NULL, 0, 1, 2, -1);
157
 
                                        if(efa->f & SELECT) EM_select_face(efan, 1);
158
 
                                        efan= EM_face_from_faces(em, efa, NULL, 0, 2, 3, -1);
159
 
                                        if(efa->f & SELECT) EM_select_face(efan, 1);
160
 
                                }
161
 
                                else {
162
 
                                        efan= EM_face_from_faces(em, efa, NULL, 0, 1, 3, -1);
163
 
                                        if(efa->f & SELECT) EM_select_face(efan, 1);
164
 
                                        efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1);
165
 
                                        if(efa->f & SELECT) EM_select_face(efan, 1);
166
 
                                }
167
 
 
168
 
                                BLI_remlink(&em->faces, efa);
169
 
                                free_editface(em, efa);
170
 
                        }
171
 
                }
172
 
                efa= next;
173
 
        }
174
 
 
175
 
        EM_fgon_flags(em);      // redo flags and indices for fgons
176
 
 
177
 
 
178
 
}
179
 
 
180
 
int removedoublesflag(EditMesh *em, short flag, short automerge, float limit)           /* return amount */
181
 
{
182
 
        /*
183
 
                flag -          Test with vert->flags
184
 
                automerge -     Alternative operation, merge unselected into selected.
185
 
                                        Used for "Auto Weld" mode. warning.
186
 
                limit -         Quick manhattan distance between verts.
187
 
        */
188
 
 
189
 
        /* all verts with (flag & 'flag') are being evaluated */
190
 
        EditVert *eve, *v1, *nextve;
191
 
        EditEdge *eed, *e1, *nexted;
192
 
        EditFace *efa, *nextvl;
193
 
        xvertsort *sortblock, *sb, *sb1;
194
 
        struct facesort *vlsortblock, *vsb, *vsb1;
195
 
        int a, b, test, amount;
196
 
 
197
 
 
198
 
        /* flag 128 is cleared, count */
199
 
 
200
 
        /* Normal non weld operation */
201
 
        eve= em->verts.first;
202
 
        amount= 0;
203
 
        while(eve) {
204
 
                eve->f &= ~128;
205
 
                if(eve->h==0 && (automerge || (eve->f & flag))) amount++;
206
 
                eve= eve->next;
207
 
        }
208
 
        if(amount==0) return 0;
209
 
 
210
 
        /* allocate memory and qsort */
211
 
        sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
212
 
        eve= em->verts.first;
213
 
        while(eve) {
214
 
                if(eve->h==0 && (automerge || (eve->f & flag))) {
215
 
                        sb->x= eve->co[0]+eve->co[1]+eve->co[2];
216
 
                        sb->v1= eve;
217
 
                        sb++;
218
 
                }
219
 
                eve= eve->next;
220
 
        }
221
 
        qsort(sortblock, amount, sizeof(xvertsort), vergxco);
222
 
 
223
 
 
224
 
        /* test for doubles */
225
 
        sb= sortblock;
226
 
        if (automerge) {
227
 
                for(a=0; a<amount; a++, sb++) {
228
 
                        eve= sb->v1;
229
 
                        if( (eve->f & 128)==0 ) {
230
 
                                sb1= sb+1;
231
 
                                for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) {
232
 
                                        if(sb1->x - sb->x > limit) break;
233
 
 
234
 
                                        /* when automarge, only allow unselected->selected */
235
 
                                        v1= sb1->v1;
236
 
                                        if( (v1->f & 128)==0 ) {
237
 
                                                if ((eve->f & flag)==0 && (v1->f & flag)==1) {
238
 
                                                        if(     (float)fabs(v1->co[0]-eve->co[0])<=limit &&
239
 
                                                                (float)fabs(v1->co[1]-eve->co[1])<=limit &&
240
 
                                                                (float)fabs(v1->co[2]-eve->co[2])<=limit)
241
 
                                                        {       /* unique bit */
242
 
                                                                eve->f|= 128;
243
 
                                                                eve->tmp.v = v1;
244
 
                                                        }
245
 
                                                } else if(      (eve->f & flag)==1 && (v1->f & flag)==0 ) {
246
 
                                                        if(     (float)fabs(v1->co[0]-eve->co[0])<=limit &&
247
 
                                                                (float)fabs(v1->co[1]-eve->co[1])<=limit &&
248
 
                                                                (float)fabs(v1->co[2]-eve->co[2])<=limit)
249
 
                                                        {       /* unique bit */
250
 
                                                                v1->f|= 128;
251
 
                                                                v1->tmp.v = eve;
252
 
                                                        }
253
 
                                                }
254
 
                                        }
255
 
                                }
256
 
                        }
257
 
                }
258
 
        } else {
259
 
                for(a=0; a<amount; a++, sb++) {
260
 
                        eve= sb->v1;
261
 
                        if( (eve->f & 128)==0 ) {
262
 
                                sb1= sb+1;
263
 
                                for(b=a+1; b<amount; b++, sb1++) {
264
 
                                        /* first test: simpel dist */
265
 
                                        if(sb1->x - sb->x > limit) break;
266
 
                                        v1= sb1->v1;
267
 
 
268
 
                                        /* second test: is vertex allowed */
269
 
                                        if( (v1->f & 128)==0 ) {
270
 
                                                if(     (float)fabs(v1->co[0]-eve->co[0])<=limit &&
271
 
                                                        (float)fabs(v1->co[1]-eve->co[1])<=limit &&
272
 
                                                        (float)fabs(v1->co[2]-eve->co[2])<=limit)
273
 
                                                {
274
 
                                                        v1->f|= 128;
275
 
                                                        v1->tmp.v = eve;
276
 
                                                }
277
 
                                        }
278
 
                                }
279
 
                        }
280
 
                }
281
 
        }
282
 
        MEM_freeN(sortblock);
283
 
 
284
 
        if (!automerge)
285
 
                for(eve = em->verts.first; eve; eve=eve->next)
286
 
                        if((eve->f & flag) && (eve->f & 128))
287
 
                                EM_data_interp_from_verts(em, eve, eve->tmp.v, eve->tmp.v, 0.5f);
288
 
 
289
 
        /* test edges and insert again */
290
 
        eed= em->edges.first;
291
 
        while(eed) {
292
 
                eed->f2= 0;
293
 
                eed= eed->next;
294
 
        }
295
 
        eed= em->edges.last;
296
 
        while(eed) {
297
 
                nexted= eed->prev;
298
 
 
299
 
                if(eed->f2==0) {
300
 
                        if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
301
 
                                remedge(em, eed);
302
 
 
303
 
                                if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v;
304
 
                                if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v;
305
 
                                e1= addedgelist(em, eed->v1, eed->v2, eed);
306
 
 
307
 
                                if(e1) {
308
 
                                        e1->f2= 1;
309
 
                                        if(eed->f & SELECT)
310
 
                                                e1->f |= SELECT;
311
 
                                }
312
 
                                if(e1!=eed) free_editedge(em, eed);
313
 
                        }
314
 
                }
315
 
                eed= nexted;
316
 
        }
317
 
 
318
 
        /* first count amount of test faces */
319
 
        efa= (struct EditFace *)em->faces.first;
320
 
        amount= 0;
321
 
        while(efa) {
322
 
                efa->f1= 0;
323
 
                if(efa->v1->f & 128) efa->f1= 1;
324
 
                else if(efa->v2->f & 128) efa->f1= 1;
325
 
                else if(efa->v3->f & 128) efa->f1= 1;
326
 
                else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1;
327
 
 
328
 
                if(efa->f1==1) amount++;
329
 
                efa= efa->next;
330
 
        }
331
 
 
332
 
        /* test faces for double vertices, and if needed remove them */
333
 
        efa= (struct EditFace *)em->faces.first;
334
 
        while(efa) {
335
 
                nextvl= efa->next;
336
 
                if(efa->f1==1) {
337
 
 
338
 
                        if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v;
339
 
                        if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v;
340
 
                        if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v;
341
 
                        if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v;
342
 
 
343
 
                        test= 0;
344
 
                        if(efa->v1==efa->v2) test+=1;
345
 
                        if(efa->v2==efa->v3) test+=2;
346
 
                        if(efa->v3==efa->v1) test+=4;
347
 
                        if(efa->v4==efa->v1) test+=8;
348
 
                        if(efa->v3==efa->v4) test+=16;
349
 
                        if(efa->v2==efa->v4) test+=32;
350
 
 
351
 
                        if(test) {
352
 
                                if(efa->v4) {
353
 
                                        if(test==1 || test==2) {
354
 
                                                efa->v2= efa->v3;
355
 
                                                efa->v3= efa->v4;
356
 
                                                efa->v4= 0;
357
 
 
358
 
                                                EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3);
359
 
 
360
 
                                                test= 0;
361
 
                                        }
362
 
                                        else if(test==8 || test==16) {
363
 
                                                efa->v4= 0;
364
 
                                                test= 0;
365
 
                                        }
366
 
                                        else {
367
 
                                                BLI_remlink(&em->faces, efa);
368
 
                                                free_editface(em, efa);
369
 
                                                amount--;
370
 
                                        }
371
 
                                }
372
 
                                else {
373
 
                                        BLI_remlink(&em->faces, efa);
374
 
                                        free_editface(em, efa);
375
 
                                        amount--;
376
 
                                }
377
 
                        }
378
 
 
379
 
                        if(test==0) {
380
 
                                /* set edge pointers */
381
 
                                efa->e1= findedgelist(em, efa->v1, efa->v2);
382
 
                                efa->e2= findedgelist(em, efa->v2, efa->v3);
383
 
                                if(efa->v4==0) {
384
 
                                        efa->e3= findedgelist(em, efa->v3, efa->v1);
385
 
                                        efa->e4= 0;
386
 
                                }
387
 
                                else {
388
 
                                        efa->e3= findedgelist(em, efa->v3, efa->v4);
389
 
                                        efa->e4= findedgelist(em, efa->v4, efa->v1);
390
 
                                }
391
 
                        }
392
 
                }
393
 
                efa= nextvl;
394
 
        }
395
 
 
396
 
        /* double faces: sort block */
397
 
        /* count again, now all selected faces */
398
 
        amount= 0;
399
 
        efa= em->faces.first;
400
 
        while(efa) {
401
 
                efa->f1= 0;
402
 
                if(faceselectedOR(efa, 1)) {
403
 
                        efa->f1= 1;
404
 
                        amount++;
405
 
                }
406
 
                efa= efa->next;
407
 
        }
408
 
 
409
 
        if(amount) {
410
 
                /* double faces: sort block */
411
 
                vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub");
412
 
                efa= em->faces.first;
413
 
                while(efa) {
414
 
                        if(efa->f1 & 1) {
415
 
                                if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4);
416
 
                                else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3);
417
 
 
418
 
                                vsb->efa= efa;
419
 
                                vsb++;
420
 
                        }
421
 
                        efa= efa->next;
422
 
                }
423
 
 
424
 
                qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
425
 
 
426
 
                vsb= vlsortblock;
427
 
                for(a=0; a<amount; a++) {
428
 
                        efa= vsb->efa;
429
 
                        if( (efa->f1 & 128)==0 ) {
430
 
                                vsb1= vsb+1;
431
 
 
432
 
                                for(b=a+1; b<amount; b++) {
433
 
 
434
 
                                        /* first test: same pointer? */
435
 
                                        if(vsb->x != vsb1->x) break;
436
 
 
437
 
                                        /* second test: is test permitted? */
438
 
                                        efa= vsb1->efa;
439
 
                                        if( (efa->f1 & 128)==0 ) {
440
 
                                                if( compareface(efa, vsb->efa)) efa->f1 |= 128;
441
 
 
442
 
                                        }
443
 
                                        vsb1++;
444
 
                                }
445
 
                        }
446
 
                        vsb++;
447
 
                }
448
 
 
449
 
                MEM_freeN(vlsortblock);
450
 
 
451
 
                /* remove double faces */
452
 
                efa= (struct EditFace *)em->faces.first;
453
 
                while(efa) {
454
 
                        nextvl= efa->next;
455
 
                        if(efa->f1 & 128) {
456
 
                                BLI_remlink(&em->faces, efa);
457
 
                                free_editface(em, efa);
458
 
                        }
459
 
                        efa= nextvl;
460
 
                }
461
 
        }
462
 
 
463
 
        /* remove double vertices */
464
 
        a= 0;
465
 
        eve= (struct EditVert *)em->verts.first;
466
 
        while(eve) {
467
 
                nextve= eve->next;
468
 
                if(automerge || eve->f & flag) {
469
 
                        if(eve->f & 128) {
470
 
                                a++;
471
 
                                BLI_remlink(&em->verts, eve);
472
 
                                free_editvert(em, eve);
473
 
                        }
474
 
                }
475
 
                eve= nextve;
476
 
        }
477
 
 
478
 
        return a;       /* amount */
479
 
}
480
 
 
481
 
static int removedoublesflag_exec(bContext *C, wmOperator *op)
482
 
{
483
 
        Object *obedit= CTX_data_edit_object(C);
484
 
        EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
485
 
        int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
486
 
 
487
 
        int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
488
 
        
489
 
        if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
490
 
                recalc_editnormals(em);
491
 
 
492
 
                DAG_id_tag_update(obedit->data, 0);
493
 
                WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
494
 
        }
495
 
 
496
 
        BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices");
497
 
 
498
 
        BKE_mesh_end_editmesh(obedit->data, em);
499
 
 
500
 
        return OPERATOR_FINISHED;
501
 
}
502
 
 
503
 
void MESH_OT_remove_doubles(wmOperatorType *ot)
 
118
void MESH_OT_subdivide(wmOperatorType *ot)
504
119
{
505
120
        PropertyRNA *prop;
506
121
 
507
122
        /* identifiers */
508
 
        ot->name= "Remove Doubles";
509
 
        ot->description= "Remove duplicate vertices";
510
 
        ot->idname= "MESH_OT_remove_doubles";
511
 
 
512
 
        /* api callbacks */
513
 
        ot->exec= removedoublesflag_exec;
514
 
        ot->poll= ED_operator_editmesh;
515
 
 
516
 
        /* flags */
517
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
518
 
 
519
 
        prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f);
520
 
        RNA_def_property_ui_range(prop,  0.000001f, 50.0f, 0.001, 5);
521
 
}
522
 
 
523
 
// XXX is this needed?
524
 
/* called from buttons */
525
 
static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
526
 
{
527
 
        xvertsort *sortblock = userData;
528
 
 
529
 
        sortblock[index].x = x;
530
 
}
531
 
 
532
 
/* all verts with (flag & 'flag') are sorted */
533
 
static void xsortvert_flag(bContext *C, int flag)
534
 
{
535
 
        ViewContext vc;
536
 
        EditVert *eve;
537
 
        xvertsort *sortblock;
538
 
        ListBase tbase;
539
 
        int i, amount;
540
 
 
541
 
        em_setup_viewcontext(C, &vc);
542
 
 
543
 
        amount = BLI_countlist(&vc.em->verts);
544
 
        sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
545
 
        for (i=0,eve= vc.em->verts.first; eve; i++,eve=eve->next)
546
 
                if(eve->f & flag)
547
 
                        sortblock[i].v1 = eve;
548
 
 
549
 
        ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
550
 
        mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
551
 
 
552
 
        qsort(sortblock, amount, sizeof(xvertsort), vergxco);
553
 
 
554
 
                /* make temporal listbase */
555
 
        tbase.first= tbase.last= 0;
556
 
        for (i=0; i<amount; i++) {
557
 
                eve = sortblock[i].v1;
558
 
 
559
 
                if (eve) {
560
 
                        BLI_remlink(&vc.em->verts, eve);
561
 
                        BLI_addtail(&tbase, eve);
562
 
                }
563
 
        }
564
 
 
565
 
        BLI_movelisttolist(&vc.em->verts, &tbase);
566
 
 
567
 
        MEM_freeN(sortblock);
568
 
 
569
 
}
570
 
 
571
 
static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
572
 
{
573
 
        xsortvert_flag(C, SELECT);
574
 
        return OPERATOR_FINISHED;
575
 
}
576
 
 
577
 
void MESH_OT_vertices_sort(wmOperatorType *ot)
578
 
{
579
 
        /* identifiers */
580
 
        ot->name= "Vertex Sort";
581
 
        ot->description= "Sort vertex order";
582
 
        ot->idname= "MESH_OT_vertices_sort";
583
 
 
584
 
        /* api callbacks */
585
 
        ot->exec= mesh_vertices_sort_exec;
586
 
 
587
 
        ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
588
 
 
589
 
        /* flags */
590
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
591
 
}
592
 
 
593
 
 
594
 
/* called from buttons */
595
 
static void hashvert_flag(EditMesh *em, int flag)
596
 
{
597
 
        /* switch vertex order using hash table */
598
 
        EditVert *eve;
599
 
        struct xvertsort *sortblock, *sb, onth, *newsort;
600
 
        ListBase tbase;
601
 
        int amount, a, b;
602
 
 
603
 
        /* count */
604
 
        eve= em->verts.first;
605
 
        amount= 0;
606
 
        while(eve) {
607
 
                if(eve->f & flag) amount++;
608
 
                eve= eve->next;
609
 
        }
610
 
        if(amount==0) return;
611
 
 
612
 
        /* allocate memory */
613
 
        sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
614
 
        eve= em->verts.first;
615
 
        while(eve) {
616
 
                if(eve->f & flag) {
617
 
                        sb->v1= eve;
618
 
                        sb++;
619
 
                }
620
 
                eve= eve->next;
621
 
        }
622
 
 
623
 
        BLI_srand(1);
624
 
 
625
 
        sb= sortblock;
626
 
        for(a=0; a<amount; a++, sb++) {
627
 
                b= (int)(amount*BLI_drand());
628
 
                if(b>=0 && b<amount) {
629
 
                        newsort= sortblock+b;
630
 
                        onth= *sb;
631
 
                        *sb= *newsort;
632
 
                        *newsort= onth;
633
 
                }
634
 
        }
635
 
 
636
 
        /* make temporal listbase */
637
 
        tbase.first= tbase.last= 0;
638
 
        sb= sortblock;
639
 
        while(amount--) {
640
 
                eve= sb->v1;
641
 
                BLI_remlink(&em->verts, eve);
642
 
                BLI_addtail(&tbase, eve);
643
 
                sb++;
644
 
        }
645
 
 
646
 
        BLI_movelisttolist(&em->verts, &tbase);
647
 
 
648
 
        MEM_freeN(sortblock);
649
 
 
650
 
}
651
 
 
652
 
static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
653
 
{
654
 
        Object *obedit= CTX_data_edit_object(C);
655
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
656
 
        hashvert_flag(em, SELECT);
657
 
        return OPERATOR_FINISHED;
658
 
}
659
 
 
660
 
void MESH_OT_vertices_randomize(wmOperatorType *ot)
661
 
{
662
 
        /* identifiers */
663
 
        ot->name= "Vertex Randomize";
664
 
        ot->description= "Randomize vertex order";
665
 
        ot->idname= "MESH_OT_vertices_randomize";
666
 
 
667
 
        /* api callbacks */
668
 
        ot->exec= mesh_vertices_randomize_exec;
669
 
 
670
 
        ot->poll= ED_operator_editmesh;
671
 
 
672
 
        /* flags */
673
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
674
 
}
675
 
 
 
123
        ot->name = "Subdivide";
 
124
        ot->description = "Subdivide selected edges";
 
125
        ot->idname = "MESH_OT_subdivide";
 
126
 
 
127
        /* api callbacks */
 
128
        ot->exec = edbm_subdivide_exec;
 
129
        ot->poll = ED_operator_editmesh;
 
130
 
 
131
        /* flags */
 
132
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
133
 
 
134
        /* properties */
 
135
        prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
 
136
        /* avoid re-using last var because it can cause _very_ high poly meshes and annoy users (or worse crash) */
 
137
        RNA_def_property_flag(prop, PROP_SKIP_SAVE);
 
138
 
 
139
        RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
 
140
 
 
141
        RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
 
142
        RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT,
 
143
                     "Quad Corner Type", "How to subdivide quad corners (anything other than Straight Cut will prevent ngons)");
 
144
 
 
145
        RNA_def_float(ot->srna, "fractal", 0.0f, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
 
146
        RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
 
147
}
 
148
 
 
149
 
 
150
void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em)
 
151
{
 
152
        BMIter iter;
 
153
        BMVert *eve;
 
154
 
 
155
        BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 
156
                if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 
157
                        float mval[2], vec[3], no_dummy[3];
 
158
                        int dist_dummy;
 
159
                        mul_v3_m4v3(vec, obedit->obmat, eve->co);
 
160
                        project_float_noclip(ar, vec, mval);
 
161
                        if (snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) {
 
162
                                mul_v3_m4v3(eve->co, obedit->imat, vec);
 
163
                        }
 
164
                }
 
165
        }
 
166
}
 
167
 
 
168
 
 
169
/* individual face extrude */
 
170
/* will use vertex normals for extrusion directions, so *nor is unaffected */
 
171
static short edbm_extrude_face_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
 
172
{
 
173
        BMOIter siter;
 
174
        BMIter liter;
 
175
        BMFace *f;
 
176
        BMLoop *l;
 
177
        BMOperator bmop;
 
178
 
 
179
        EDBM_op_init(em, &bmop, op, "extrude_face_indiv faces=%hf", hflag);
 
180
 
 
181
        /* deselect original verts */
 
182
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
183
 
 
184
        BMO_op_exec(em->bm, &bmop);
 
185
        
 
186
        BMO_ITER (f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
 
187
                BM_face_select_set(em->bm, f, TRUE);
 
188
 
 
189
                /* set face vertex normals to face normal */
 
190
                BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
 
191
                        copy_v3_v3(l->v->no, f->no);
 
192
                }
 
193
        }
 
194
 
 
195
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
196
                return 0;
 
197
        }
 
198
 
 
199
        return 's'; // s is shrink/fatten
 
200
}
 
201
 
 
202
/* extrudes individual edges */
 
203
static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
 
204
{
 
205
        BMOperator bmop;
 
206
 
 
207
        EDBM_op_init(em, &bmop, op, "extrude_edge_only edges=%he", hflag);
 
208
 
 
209
        /* deselect original verts */
 
210
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
211
 
 
212
        BMO_op_exec(em->bm, &bmop);
 
213
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_VERT | BM_EDGE, BM_ELEM_SELECT, TRUE);
 
214
 
 
215
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
216
                return 0;
 
217
        }
 
218
 
 
219
        return 'n'; // n is normal grab
 
220
}
 
221
 
 
222
/* extrudes individual vertices */
 
223
static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
 
224
{
 
225
        BMOperator bmop;
 
226
 
 
227
        EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag);
 
228
 
 
229
        /* deselect original verts */
 
230
        BMO_slot_buffer_hflag_disable(em->bm, &bmop, "verts", BM_VERT, BM_ELEM_SELECT, TRUE);
 
231
 
 
232
        BMO_op_exec(em->bm, &bmop);
 
233
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_VERT, BM_ELEM_SELECT, TRUE);
 
234
 
 
235
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
236
                return 0;
 
237
        }
 
238
 
 
239
        return 'g'; // g is grab
 
240
}
 
241
 
 
242
static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
 
243
{
 
244
        BMesh *bm = em->bm;
 
245
        BMIter iter;
 
246
        BMOIter siter;
 
247
        BMOperator extop;
 
248
        BMEdge *edge;
 
249
        BMFace *f;
 
250
        ModifierData *md;
 
251
        BMElem *ele;
 
252
        
 
253
        BMO_op_init(bm, &extop, "extrude_face_region");
 
254
        BMO_slot_buffer_from_enabled_hflag(bm, &extop, "edgefacein", BM_VERT | BM_EDGE | BM_FACE, hflag);
 
255
 
 
256
        /* If a mirror modifier with clipping is on, we need to adjust some 
 
257
         * of the cases above to handle edges on the line of symmetry.
 
258
         */
 
259
        md = obedit->modifiers.first;
 
260
        for (; md; md = md->next) {
 
261
                if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
 
262
                        MirrorModifierData *mmd = (MirrorModifierData *) md;
 
263
                
 
264
                        if (mmd->flag & MOD_MIR_CLIPPING) {
 
265
                                float mtx[4][4];
 
266
                                if (mmd->mirror_ob) {
 
267
                                        float imtx[4][4];
 
268
                                        invert_m4_m4(imtx, mmd->mirror_ob->obmat);
 
269
                                        mult_m4_m4m4(mtx, imtx, obedit->obmat);
 
270
                                }
 
271
 
 
272
                                for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
 
273
                                     edge;
 
274
                                     edge = BM_iter_step(&iter))
 
275
                                {
 
276
                                        if (BM_elem_flag_test(edge, hflag) &&
 
277
                                            BM_edge_is_boundary(edge) &&
 
278
                                            BM_elem_flag_test(edge->l->f, hflag))
 
279
                                        {
 
280
                                                float co1[3], co2[3];
 
281
 
 
282
                                                copy_v3_v3(co1, edge->v1->co);
 
283
                                                copy_v3_v3(co2, edge->v2->co);
 
284
 
 
285
                                                if (mmd->mirror_ob) {
 
286
                                                        mul_v3_m4v3(co1, mtx, co1);
 
287
                                                        mul_v3_m4v3(co2, mtx, co2);
 
288
                                                }
 
289
 
 
290
                                                if (mmd->flag & MOD_MIR_AXIS_X) {
 
291
                                                        if ((fabsf(co1[0]) < mmd->tolerance) &&
 
292
                                                            (fabsf(co2[0]) < mmd->tolerance))
 
293
                                                        {
 
294
                                                                BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
 
295
                                                        }
 
296
                                                }
 
297
                                                if (mmd->flag & MOD_MIR_AXIS_Y) {
 
298
                                                        if ((fabsf(co1[1]) < mmd->tolerance) &&
 
299
                                                            (fabsf(co2[1]) < mmd->tolerance))
 
300
                                                        {
 
301
                                                                BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
 
302
                                                        }
 
303
                                                }
 
304
                                                if (mmd->flag & MOD_MIR_AXIS_Z) {
 
305
                                                        if ((fabsf(co1[2]) < mmd->tolerance) &&
 
306
                                                            (fabsf(co2[2]) < mmd->tolerance))
 
307
                                                        {
 
308
                                                                BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
 
309
                                                        }
 
310
                                                }
 
311
                                        }
 
312
                                }
 
313
                        }
 
314
                }
 
315
        }
 
316
 
 
317
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
318
 
 
319
        BMO_op_exec(bm, &extop);
 
320
 
 
321
        zero_v3(nor);
 
322
        
 
323
        BMO_ITER (ele, &siter, bm, &extop, "geomout", BM_ALL) {
 
324
                BM_elem_select_set(bm, ele, TRUE);
 
325
 
 
326
                if (ele->head.htype == BM_FACE) {
 
327
                        f = (BMFace *)ele;
 
328
                        add_normal_aligned(nor, f->no);
 
329
                };
 
330
        }
 
331
 
 
332
        normalize_v3(nor);
 
333
 
 
334
        BMO_op_finish(bm, &extop);
 
335
 
 
336
        /* grab / normal constraint */
 
337
        return is_zero_v3(nor) ? 'g' : 'n';
 
338
}
 
339
 
 
340
static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
 
341
{
 
342
        BMIter iter;
 
343
        BMEdge *eed;
 
344
                
 
345
        /* ensure vert flags are consistent for edge selections */
 
346
        BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 
347
                if (BM_elem_flag_test(eed, hflag)) {
 
348
                        if (hflag & BM_ELEM_SELECT) {
 
349
                                BM_vert_select_set(em->bm, eed->v1, TRUE);
 
350
                                BM_vert_select_set(em->bm, eed->v2, TRUE);
 
351
                        }
 
352
 
 
353
                        BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT);
 
354
                        BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT);
 
355
                }
 
356
                else {
 
357
                        if (BM_elem_flag_test(eed->v1, hflag) && BM_elem_flag_test(eed->v2, hflag)) {
 
358
                                if (hflag & BM_ELEM_SELECT) {
 
359
                                        BM_edge_select_set(em->bm, eed, TRUE);
 
360
                                }
 
361
 
 
362
                                BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT);
 
363
                        }
 
364
                }
 
365
        }
 
366
 
 
367
        return edbm_extrude_edge(obedit, em, hflag, nor);
 
368
}
 
369
 
 
370
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
 
371
{
 
372
        Object *obedit = CTX_data_edit_object(C);
 
373
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
374
        RegionView3D *rv3d = CTX_wm_region_view3d(C);
 
375
                
 
376
        int steps = RNA_int_get(op->ptr, "steps");
 
377
        
 
378
        float offs = RNA_float_get(op->ptr, "offset");
 
379
        float dvec[3], tmat[3][3], bmat[3][3], nor[3] = {0.0, 0.0, 0.0};
 
380
        short a;
 
381
 
 
382
        /* dvec */
 
383
        normalize_v3_v3(dvec, rv3d->persinv[2]);
 
384
        mul_v3_fl(dvec, offs);
 
385
 
 
386
        /* base correction */
 
387
        copy_m3_m4(bmat, obedit->obmat);
 
388
        invert_m3_m3(tmat, bmat);
 
389
        mul_m3_v3(tmat, dvec);
 
390
 
 
391
        for (a = 0; a < steps; a++) {
 
392
                edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor);
 
393
                //BMO_op_callf(em->bm, "extrude_face_region edgefacein=%hef", BM_ELEM_SELECT);
 
394
                BMO_op_callf(em->bm, "translate vec=%v verts=%hv", (float *)dvec, BM_ELEM_SELECT);
 
395
                //extrudeflag(obedit, em, SELECT, nor);
 
396
                //translateflag(em, SELECT, dvec);
 
397
        }
 
398
        
 
399
        EDBM_mesh_normals_update(em);
 
400
 
 
401
        EDBM_update_generic(C, em, TRUE);
 
402
 
 
403
        return OPERATOR_FINISHED;
 
404
}
 
405
 
 
406
void MESH_OT_extrude_repeat(wmOperatorType *ot)
 
407
{
 
408
        /* identifiers */
 
409
        ot->name = "Extrude Repeat Mesh";
 
410
        ot->description = "Extrude selected vertices, edges or faces repeatedly";
 
411
        ot->idname = "MESH_OT_extrude_repeat";
 
412
        
 
413
        /* api callbacks */
 
414
        ot->exec = edbm_extrude_repeat_exec;
 
415
        ot->poll = ED_operator_editmesh_view3d;
 
416
        
 
417
        /* flags */
 
418
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
419
        
 
420
        /* props */
 
421
        RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
 
422
        RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
 
423
}
676
424
 
677
425
/* generic extern called extruder */
678
 
static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type)
 
426
static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
679
427
{
680
 
        float nor[3]= {0.0, 0.0, 0.0};
681
 
        short transmode= 0;
682
 
 
683
 
        if(type<1) return;
684
 
 
685
 
        if(type==1)  transmode= extrudeflag(obedit, em, SELECT, nor, 0);
686
 
        else if(type==4) transmode= extrudeflag_verts_indiv(em, SELECT, nor);
687
 
        else if(type==3) transmode= extrudeflag_edges_indiv(em, SELECT, nor);
688
 
        else transmode= extrudeflag_face_indiv(em, SELECT, nor);
689
 
 
690
 
        EM_stats_update(em);
691
 
 
692
 
        if(transmode==0) {
693
 
                BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
694
 
        }
695
 
        else {
696
 
                EM_fgon_flags(em);
697
 
 
698
 
                        /* We need to force immediate calculation here because
699
 
                        * transform may use derived objects (which are now stale).
700
 
                        *
701
 
                        * This shouldn't be necessary, derived queries should be
702
 
                        * automatically building this data if invalid. Or something.
703
 
                        */
704
 
                DAG_id_tag_update(obedit->data, 0);
 
428
        short nr, transmode = 0;
 
429
        float stacknor[3] = {0.0f, 0.0f, 0.0f};
 
430
        float *nor = norin ? norin : stacknor;
 
431
 
 
432
        zero_v3(nor);
 
433
 
 
434
        if (em->selectmode & SCE_SELECT_VERTEX) {
 
435
                if (em->bm->totvertsel == 0) nr = 0;
 
436
                else if (em->bm->totvertsel == 1) nr = 4;
 
437
                else if (em->bm->totedgesel == 0) nr = 4;
 
438
                else if (em->bm->totfacesel == 0)
 
439
                        nr = 3;  // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
 
440
                else if (em->bm->totfacesel == 1)
 
441
                        nr = 1;  // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
 
442
                else 
 
443
                        nr = 1;  // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
 
444
        }
 
445
        else if (em->selectmode & SCE_SELECT_EDGE) {
 
446
                if (em->bm->totedgesel == 0) nr = 0;
 
447
                
 
448
                nr = 1;
 
449
#if 0
 
450
                else if (em->totedgesel == 1) nr = 3;
 
451
                else if (em->totfacesel == 0) nr = 3;
 
452
                else if (em->totfacesel == 1)
 
453
                        nr = 1;  // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
 
454
                else
 
455
                        nr = 1;  // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
 
456
#endif
 
457
        }
 
458
        else {
 
459
                if (em->bm->totfacesel == 0) nr = 0;
 
460
                else if (em->bm->totfacesel == 1) nr = 1;
 
461
                else
 
462
                        nr = 1;  // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
 
463
        }
 
464
 
 
465
        if (nr < 1) return 'g';
 
466
 
 
467
        if (nr == 1 && (em->selectmode & SCE_SELECT_VERTEX))
 
468
                transmode = edbm_extrude_vert(obedit, em, BM_ELEM_SELECT, nor);
 
469
        else if (nr == 1) transmode = edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor);
 
470
        else if (nr == 4) transmode = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
 
471
        else if (nr == 3) transmode = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
 
472
        else transmode = edbm_extrude_face_indiv(em, op, BM_ELEM_SELECT, nor);
 
473
        
 
474
        if (transmode == 0) {
 
475
                BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
 
476
        }
 
477
        else {
 
478
                
 
479
                /* We need to force immediate calculation here because
 
480
                 * transform may use derived objects (which are now stale).
 
481
                 *
 
482
                 * This shouldn't be necessary, derived queries should be
 
483
                 * automatically building this data if invalid. Or something.
 
484
                 */
 
485
//              DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 
486
                object_handle_update(scene, obedit);
705
487
 
706
488
                /* individual faces? */
707
489
//              BIF_TransformSetUndo("Extrude");
708
 
                if(type==2) {
 
490
                if (nr == 2) {
709
491
//                      initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
710
492
//                      Transform();
711
493
                }
712
494
                else {
713
495
//                      initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
714
 
                        if(transmode=='n') {
 
496
                        if (transmode == 'n') {
715
497
                                mul_m4_v3(obedit->obmat, nor);
716
 
                                sub_v3_v3(nor, obedit->obmat[3]);
 
498
                                sub_v3_v3v3(nor, nor, obedit->obmat[3]);
717
499
//                              BIF_setSingleAxisConstraint(nor, "along normal");
718
500
                        }
719
501
//                      Transform();
720
502
                }
721
503
        }
722
 
 
723
 
}
724
 
 
725
 
// XXX should be a menu item
726
 
static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
727
 
{
728
 
        Object *obedit= CTX_data_edit_object(C);
729
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
730
504
        
731
 
        extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
732
 
 
733
 
        BKE_mesh_end_editmesh(obedit->data, em);
734
 
 
735
 
        DAG_id_tag_update(obedit->data, 0);
736
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
737
 
 
738
 
        return OPERATOR_FINISHED;
 
505
        return transmode;
739
506
}
740
507
 
741
508
/* extrude without transform */
742
 
static int mesh_extrude_exec(bContext *C, wmOperator *op)
743
 
{
744
 
        Object *obedit= CTX_data_edit_object(C);
745
 
        EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
746
 
 
747
 
        extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
748
 
 
749
 
        DAG_id_tag_update(obedit->data, 0);
750
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
751
 
 
752
 
        BKE_mesh_end_editmesh(obedit->data, em);
753
 
        return OPERATOR_FINISHED;
754
 
}
755
 
 
756
 
static EnumPropertyItem extrude_items[] = {
757
 
                {1, "REGION", 0, "Region", ""},
758
 
                {2, "FACES", 0, "Individual Faces", ""},
759
 
                {3, "EDGES", 0, "Only Edges", ""},
760
 
                {4, "VERTS", 0, "Only Vertices", ""},
761
 
                {0, NULL, 0, NULL, NULL}};
762
 
 
763
 
 
764
 
static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
765
 
{
766
 
        EnumPropertyItem *item= NULL;
767
 
        Object *obedit= CTX_data_edit_object(C);
768
 
        EditMesh *em;
769
 
 
770
 
        int totitem= 0;
771
 
 
772
 
        if(obedit==NULL || obedit->type != OB_MESH)
773
 
                return extrude_items;
774
 
 
775
 
        em = BKE_mesh_get_editmesh(obedit->data);
776
 
 
777
 
        EM_stats_update(em);
778
 
 
779
 
        if(em->selectmode & SCE_SELECT_VERTEX) {
780
 
                if(em->totvertsel==0) {}
781
 
                else if(em->totvertsel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
782
 
                else if(em->totedgesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
783
 
                else if(em->totfacesel==0) {
784
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
785
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
786
 
                }
787
 
                else if(em->totfacesel==1) {
788
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
789
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
790
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
791
 
                }
792
 
                else {
793
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
794
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
795
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
796
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
797
 
                }
798
 
        }
799
 
        else if(em->selectmode & SCE_SELECT_EDGE) {
800
 
                if (em->totedgesel==0) {}
801
 
                else if (em->totedgesel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
802
 
                else if(em->totfacesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
803
 
                else if(em->totfacesel==1) {
804
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
805
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
806
 
                }
807
 
                else {
808
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
809
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
810
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
811
 
                }
812
 
        }
813
 
        else {
814
 
                if (em->totfacesel == 0) {}
815
 
                else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); }
816
 
                else {
817
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
818
 
                        RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
819
 
                }
820
 
        }
821
 
 
822
 
        if(item) {
823
 
                RNA_enum_item_end(&item, &totitem);
824
 
                *free= 1;
825
 
                return item;
826
 
        }
827
 
        else {
828
 
                return NULL;
829
 
        }
830
 
}
831
 
 
832
 
void MESH_OT_extrude(wmOperatorType *ot)
833
 
{
834
 
        PropertyRNA *prop;
835
 
 
836
 
        /* identifiers */
837
 
        ot->name= "Extrude";
838
 
        ot->description= "Extrude selected vertices, edges or faces";
839
 
        ot->idname= "MESH_OT_extrude";
840
 
 
841
 
        /* api callbacks */
842
 
        ot->invoke= mesh_extrude_invoke;
843
 
        ot->exec= mesh_extrude_exec;
844
 
        ot->poll= ED_operator_editmesh;
845
 
 
846
 
        /* flags */
847
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
848
 
 
849
 
        /* properties */
850
 
        prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", "");
851
 
        RNA_def_property_flag(prop, PROP_HIDDEN);
852
 
        RNA_def_enum_funcs(prop, mesh_extrude_itemf);
853
 
        ot->prop= prop;
854
 
}
855
 
 
856
 
static int split_mesh(bContext *C, wmOperator *UNUSED(op))
857
 
{
858
 
        Object *obedit= CTX_data_edit_object(C);
859
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
860
 
 
861
 
        WM_cursor_wait(1);
862
 
 
863
 
        /* make duplicate first */
864
 
        adduplicateflag(em, SELECT);
865
 
        /* old faces have flag 128 set, delete them */
866
 
        delfaceflag(em, 128);
867
 
        recalc_editnormals(em);
868
 
 
869
 
        WM_cursor_wait(0);
870
 
 
871
 
        DAG_id_tag_update(obedit->data, 0);
872
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
873
 
 
874
 
        BKE_mesh_end_editmesh(obedit->data, em);
875
 
        return OPERATOR_FINISHED;
876
 
}
877
 
 
878
 
void MESH_OT_split(wmOperatorType *ot)
879
 
{
880
 
        /* identifiers */
881
 
        ot->name= "Split";
882
 
        ot->description= "Split selected geometry into separate disconnected mesh";
883
 
        ot->idname= "MESH_OT_split";
884
 
 
885
 
        /* api callbacks */
886
 
        ot->exec= split_mesh;
887
 
        ot->poll= ED_operator_editmesh;
888
 
 
889
 
        /* flags */
890
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
891
 
}
892
 
 
893
 
 
894
 
static int extrude_repeat_mesh_exec(bContext *C, wmOperator *op)
895
 
{
896
 
        Object *obedit= CTX_data_edit_object(C);
897
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
898
 
 
899
 
        int steps = RNA_int_get(op->ptr,"steps");
900
 
 
901
 
        float offs = RNA_float_get(op->ptr,"offset");
902
 
 
903
 
        float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
904
 
        short a;
905
 
 
906
 
        /* dvec */
907
 
        RNA_float_get_array(op->ptr, "direction", dvec);
908
 
        normalize_v3(dvec);
909
 
        dvec[0]*= offs;
910
 
        dvec[1]*= offs;
911
 
        dvec[2]*= offs;
912
 
 
913
 
        /* base correction */
914
 
        copy_m3_m4(bmat, obedit->obmat);
915
 
        invert_m3_m3(tmat, bmat);
916
 
        mul_m3_v3(tmat, dvec);
917
 
 
918
 
        for(a=0; a<steps; a++) {
919
 
                extrudeflag(obedit, em, SELECT, nor, 0);
920
 
                translateflag(em, SELECT, dvec);
921
 
        }
922
 
 
923
 
        recalc_editnormals(em);
924
 
 
925
 
        EM_fgon_flags(em);
926
 
 
927
 
        DAG_id_tag_update(obedit->data, 0);
928
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
929
 
 
930
 
        BKE_mesh_end_editmesh(obedit->data, em);
931
 
        return OPERATOR_FINISHED;
932
 
}
933
 
 
934
 
/* get center and axis, in global coords */
935
 
static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
936
 
{
937
 
        RegionView3D *rv3d= ED_view3d_context_rv3d(C);
938
 
 
939
 
        if(rv3d)
940
 
                RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]);
941
 
 
942
 
        return extrude_repeat_mesh_exec(C, op);
943
 
}
944
 
 
945
 
void MESH_OT_extrude_repeat(wmOperatorType *ot)
946
 
{
947
 
        /* identifiers */
948
 
        ot->name= "Extrude Repeat Mesh";
949
 
        ot->description= "Extrude selected vertices, edges or faces repeatedly";
950
 
        ot->idname= "MESH_OT_extrude_repeat";
951
 
 
952
 
        /* api callbacks */
953
 
        ot->invoke= extrude_repeat_mesh_invoke;
954
 
        ot->exec= extrude_repeat_mesh_exec;
955
 
        ot->poll= ED_operator_editmesh;
956
 
 
957
 
        /* flags */
958
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
959
 
 
960
 
        /* props */
961
 
        RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, 100.0f);
962
 
        RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, 180);
963
 
        RNA_def_float_vector(ot->srna, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "Direction of extrude", -FLT_MAX, FLT_MAX);
964
 
}
965
 
 
966
 
/* ************************** spin operator ******************** */
967
 
 
968
 
 
969
 
static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli )
970
 
{
971
 
        Object *obedit= CTX_data_edit_object(C);
972
 
        ToolSettings *ts= CTX_data_tool_settings(C);
973
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
974
 
        EditVert *eve,*nextve;
975
 
        float nor[3]= {0.0f, 0.0f, 0.0f};
976
 
        float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3];
977
 
        float cent[3], bmat[3][3];
978
 
        float phi;
979
 
        short a, ok= 1;
980
 
 
981
 
        RNA_float_get_array(op->ptr, "center", cent);
982
 
 
983
 
        /* imat and center and size */
984
 
        copy_m3_m4(bmat, obedit->obmat);
985
 
        invert_m3_m3(imat,bmat);
986
 
 
987
 
        cent[0]-= obedit->obmat[3][0];
988
 
        cent[1]-= obedit->obmat[3][1];
989
 
        cent[2]-= obedit->obmat[3][2];
990
 
        mul_m3_v3(imat, cent);
991
 
 
992
 
        phi= degr*(float)M_PI/360.0f;
993
 
        phi/= steps;
994
 
        if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
995
 
 
996
 
        RNA_float_get_array(op->ptr, "axis", n);
997
 
        normalize_v3(n);
998
 
 
999
 
        q[0]= (float)cos(phi);
1000
 
        si= (float)sin(phi);
1001
 
        q[1]= n[0]*si;
1002
 
        q[2]= n[1]*si;
1003
 
        q[3]= n[2]*si;
1004
 
        quat_to_mat3( cmat,q);
1005
 
 
1006
 
        mul_m3_m3m3(tmat,cmat,bmat);
1007
 
        mul_m3_m3m3(bmat,imat,tmat);
1008
 
 
1009
 
        if(dupli==0)
1010
 
                if(ts->editbutflag & B_KEEPORIG)
1011
 
                        adduplicateflag(em, 1);
1012
 
 
1013
 
        for(a=0; a<steps; a++) {
1014
 
                if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0);
1015
 
                else adduplicateflag(em, SELECT);
1016
 
 
1017
 
                if(ok==0)
1018
 
                        break;
1019
 
 
1020
 
                rotateflag(em, SELECT, cent, bmat);
1021
 
                if(dvec) {
1022
 
                        mul_m3_v3(bmat,dvec);
1023
 
                        translateflag(em, SELECT, dvec);
1024
 
                }
1025
 
        }
1026
 
 
1027
 
        if(ok==0) {
1028
 
                /* no vertices or only loose ones selected, remove duplicates */
1029
 
                eve= em->verts.first;
1030
 
                while(eve) {
1031
 
                        nextve= eve->next;
1032
 
                        if(eve->f & SELECT) {
1033
 
                                BLI_remlink(&em->verts,eve);
1034
 
                                free_editvert(em, eve);
1035
 
                        }
1036
 
                        eve= nextve;
1037
 
                }
1038
 
        }
1039
 
        else {
1040
 
                recalc_editnormals(em);
1041
 
 
1042
 
                EM_fgon_flags(em);
1043
 
 
1044
 
                DAG_id_tag_update(obedit->data, 0);
1045
 
        }
1046
 
 
1047
 
        BKE_mesh_end_editmesh(obedit->data, em);
1048
 
        return ok;
1049
 
}
1050
 
 
1051
 
static int spin_mesh_exec(bContext *C, wmOperator *op)
1052
 
{
1053
 
        Object *obedit= CTX_data_edit_object(C);
1054
 
        int ok;
1055
 
 
1056
 
        ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
1057
 
        if(ok==0) {
1058
 
                BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
1059
 
                return OPERATOR_CANCELLED;
1060
 
        }
1061
 
 
1062
 
        DAG_id_tag_update(obedit->data, 0);
1063
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1064
 
 
1065
 
        return OPERATOR_FINISHED;
1066
 
}
1067
 
 
1068
 
/* get center and axis, in global coords */
1069
 
static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
509
static int edbm_extrude_region_exec(bContext *C, wmOperator *op)
1070
510
{
1071
511
        Scene *scene = CTX_data_scene(C);
1072
 
        View3D *v3d = CTX_wm_view3d(C);
1073
 
        RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1074
 
 
1075
 
        RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
1076
 
        RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
1077
 
 
1078
 
        return spin_mesh_exec(C, op);
1079
 
}
1080
 
 
1081
 
void MESH_OT_spin(wmOperatorType *ot)
1082
 
{
1083
 
        /* identifiers */
1084
 
        ot->name= "Spin";
1085
 
        ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport";
1086
 
        ot->idname= "MESH_OT_spin";
1087
 
 
1088
 
        /* api callbacks */
1089
 
        ot->invoke= spin_mesh_invoke;
1090
 
        ot->exec= spin_mesh_exec;
1091
 
        ot->poll= EM_view3d_poll;
1092
 
 
1093
 
        /* flags */
1094
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1095
 
 
1096
 
        /* props */
1097
 
        RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128);
1098
 
        RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
1099
 
        RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
1100
 
 
1101
 
        RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
1102
 
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
1103
 
 
1104
 
}
1105
 
 
1106
 
static int screw_mesh_exec(bContext *C, wmOperator *op)
1107
 
{
1108
 
        Object *obedit= CTX_data_edit_object(C);
1109
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
1110
 
        EditVert *eve,*v1=0,*v2=0;
1111
 
        EditEdge *eed;
1112
 
        float dvec[3], nor[3];
1113
 
        int steps, turns;
1114
 
 
1115
 
        turns= RNA_int_get(op->ptr, "turns");
1116
 
        steps= RNA_int_get(op->ptr, "steps");
1117
 
 
1118
 
        /* clear flags */
1119
 
        for(eve= em->verts.first; eve; eve= eve->next)
1120
 
                eve->f1= 0;
1121
 
 
1122
 
        /* edges set flags in verts */
1123
 
        for(eed= em->edges.first; eed; eed= eed->next) {
1124
 
                if(eed->v1->f & SELECT) {
1125
 
                        if(eed->v2->f & SELECT) {
1126
 
                                /* watch: f1 is a byte */
1127
 
                                if(eed->v1->f1<2) eed->v1->f1++;
1128
 
                                if(eed->v2->f1<2) eed->v2->f1++;
1129
 
                        }
1130
 
                }
1131
 
        }
1132
 
        /* find two vertices with eve->f1==1, more or less is wrong */
1133
 
        for(eve= em->verts.first; eve; eve= eve->next) {
1134
 
                if(eve->f1==1) {
1135
 
                        if(v1==NULL) v1= eve;
1136
 
                        else if(v2==NULL) v2= eve;
1137
 
                        else {
1138
 
                                v1= NULL;
1139
 
                                break;
1140
 
                        }
1141
 
                }
1142
 
        }
1143
 
        if(v1==NULL || v2==NULL) {
1144
 
                BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too");
1145
 
                BKE_mesh_end_editmesh(obedit->data, em);
1146
 
                return OPERATOR_CANCELLED;
1147
 
        }
1148
 
 
1149
 
        /* calculate dvec */
1150
 
        dvec[0]= ( v1->co[0]- v2->co[0] )/steps;
1151
 
        dvec[1]= ( v1->co[1]- v2->co[1] )/steps;
1152
 
        dvec[2]= ( v1->co[2]- v2->co[2] )/steps;
1153
 
 
1154
 
        VECCOPY(nor, obedit->obmat[2]);
1155
 
 
1156
 
        if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) {
1157
 
                negate_v3(dvec);
1158
 
        }
1159
 
 
1160
 
        if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
1161
 
                DAG_id_tag_update(obedit->data, 0);
1162
 
                WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1163
 
 
1164
 
                BKE_mesh_end_editmesh(obedit->data, em);
 
512
        Object *obedit = CTX_data_edit_object(C);
 
513
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
514
        
 
515
        edbm_extrude_mesh(scene, obedit, em, op, NULL);
 
516
 
 
517
        /* This normally happens when pushing undo but modal operators
 
518
         * like this one don't push undo data until after modal mode is
 
519
         * done.*/
 
520
        EDBM_mesh_normals_update(em);
 
521
 
 
522
        EDBM_update_generic(C, em, TRUE);
 
523
        
 
524
        return OPERATOR_FINISHED;
 
525
}
 
526
 
 
527
void MESH_OT_extrude_region(wmOperatorType *ot)
 
528
{
 
529
        /* identifiers */
 
530
        ot->name = "Extrude Region";
 
531
        ot->idname = "MESH_OT_extrude_region";
 
532
        ot->description = "Extrude region of faces";
 
533
        
 
534
        /* api callbacks */
 
535
        //ot->invoke = mesh_extrude_region_invoke;
 
536
        ot->exec = edbm_extrude_region_exec;
 
537
        ot->poll = ED_operator_editmesh;
 
538
        
 
539
        /* flags */
 
540
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
541
 
 
542
        RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 
543
}
 
544
 
 
545
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
 
546
{
 
547
        Object *obedit = CTX_data_edit_object(C);
 
548
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
549
        float nor[3];
 
550
 
 
551
        edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
 
552
        
 
553
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
554
        
 
555
        return OPERATOR_FINISHED;
 
556
}
 
557
 
 
558
void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
 
559
{
 
560
        /* identifiers */
 
561
        ot->name = "Extrude Only Vertices";
 
562
        ot->idname = "MESH_OT_extrude_verts_indiv";
 
563
        ot->description = "Extrude individual vertices only";
 
564
        
 
565
        /* api callbacks */
 
566
        ot->exec = edbm_extrude_verts_exec;
 
567
        ot->poll = ED_operator_editmesh;
 
568
        
 
569
        /* flags */
 
570
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
571
 
 
572
        /* to give to transform */
 
573
        RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 
574
}
 
575
 
 
576
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
 
577
{
 
578
        Object *obedit = CTX_data_edit_object(C);
 
579
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
580
        float nor[3];
 
581
 
 
582
        edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
 
583
        
 
584
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
585
        
 
586
        return OPERATOR_FINISHED;
 
587
}
 
588
 
 
589
void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
 
590
{
 
591
        /* identifiers */
 
592
        ot->name = "Extrude Only Edges";
 
593
        ot->idname = "MESH_OT_extrude_edges_indiv";
 
594
        ot->description = "Extrude individual edges only";
 
595
        
 
596
        /* api callbacks */
 
597
        ot->exec = edbm_extrude_edges_exec;
 
598
        ot->poll = ED_operator_editmesh;
 
599
        
 
600
        /* flags */
 
601
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
602
 
 
603
        /* to give to transform */
 
604
        RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 
605
}
 
606
 
 
607
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
 
608
{
 
609
        Object *obedit = CTX_data_edit_object(C);
 
610
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
611
        float nor[3];
 
612
 
 
613
        edbm_extrude_face_indiv(em, op, BM_ELEM_SELECT, nor);
 
614
        
 
615
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
616
        
 
617
        return OPERATOR_FINISHED;
 
618
}
 
619
 
 
620
void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
 
621
{
 
622
        /* identifiers */
 
623
        ot->name = "Extrude Individual Faces";
 
624
        ot->idname = "MESH_OT_extrude_faces_indiv";
 
625
        ot->description = "Extrude individual faces only";
 
626
        
 
627
        /* api callbacks */
 
628
        ot->exec = edbm_extrude_faces_exec;
 
629
        ot->poll = ED_operator_editmesh;
 
630
        
 
631
        /* flags */
 
632
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
633
 
 
634
        RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
 
635
}
 
636
 
 
637
/* ******************** (de)select all operator **************** */
 
638
 
 
639
static int edbm_select_all_exec(bContext *C, wmOperator *op)
 
640
{
 
641
        Object *obedit = CTX_data_edit_object(C);
 
642
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
643
        int action = RNA_enum_get(op->ptr, "action");
 
644
        
 
645
        switch (action) {
 
646
                case SEL_TOGGLE:
 
647
                        EDBM_select_toggle_all(em);
 
648
                        break;
 
649
                case SEL_SELECT:
 
650
                        EDBM_flag_enable_all(em, BM_ELEM_SELECT);
 
651
                        break;
 
652
                case SEL_DESELECT:
 
653
                        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
654
                        break;
 
655
                case SEL_INVERT:
 
656
                        EDBM_select_swap(em);
 
657
                        EDBM_selectmode_flush(em);
 
658
                        break;
 
659
        }
 
660
 
 
661
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
662
 
 
663
        return OPERATOR_FINISHED;
 
664
}
 
665
 
 
666
void MESH_OT_select_all(wmOperatorType *ot)
 
667
{
 
668
        /* identifiers */
 
669
        ot->name = "(De)select All";
 
670
        ot->idname = "MESH_OT_select_all";
 
671
        ot->description = "(De)select all vertices, edges or faces";
 
672
        
 
673
        /* api callbacks */
 
674
        ot->exec = edbm_select_all_exec;
 
675
        ot->poll = ED_operator_editmesh;
 
676
        
 
677
        /* flags */
 
678
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
679
 
 
680
        WM_operator_properties_select_all(ot);
 
681
}
 
682
 
 
683
static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
 
684
{
 
685
        Object *obedit = CTX_data_edit_object(C);
 
686
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
687
 
 
688
        if (EDBM_select_interior_faces(em)) {
 
689
                WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
 
690
 
1165
691
                return OPERATOR_FINISHED;
1166
692
        }
1167
693
        else {
1168
 
                BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
1169
 
                BKE_mesh_end_editmesh(obedit->data, em);
1170
694
                return OPERATOR_CANCELLED;
1171
695
        }
1172
 
}
1173
 
 
1174
 
/* get center and axis, in global coords */
1175
 
static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1176
 
{
1177
 
        Scene *scene = CTX_data_scene(C);
1178
 
        View3D *v3d = CTX_wm_view3d(C);
1179
 
        RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1180
 
 
1181
 
        RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
1182
 
        RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
1183
 
 
1184
 
        return screw_mesh_exec(C, op);
1185
 
}
1186
 
 
1187
 
void MESH_OT_screw(wmOperatorType *ot)
1188
 
{
1189
 
        /* identifiers */
1190
 
        ot->name= "Screw";
1191
 
        ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport";
1192
 
        ot->idname= "MESH_OT_screw";
1193
 
 
1194
 
        /* api callbacks */
1195
 
        ot->invoke= screw_mesh_invoke;
1196
 
        ot->exec= screw_mesh_exec;
1197
 
        ot->poll= EM_view3d_poll;
1198
 
 
1199
 
        /* flags */
1200
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1201
 
 
1202
 
        /*props */
1203
 
        RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
1204
 
        RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
1205
 
 
1206
 
        RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
1207
 
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
1208
 
}
1209
 
 
1210
 
static void erase_edges(EditMesh *em, ListBase *l)
1211
 
{
1212
 
        EditEdge *ed, *nexted;
1213
 
 
1214
 
        ed = (EditEdge *) l->first;
1215
 
        while(ed) {
1216
 
                nexted= ed->next;
1217
 
                if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
1218
 
                        remedge(em, ed);
1219
 
                        free_editedge(em, ed);
1220
 
                }
1221
 
                ed= nexted;
1222
 
        }
1223
 
}
1224
 
 
1225
 
static void erase_faces(EditMesh *em, ListBase *l)
1226
 
{
1227
 
        EditFace *f, *nextf;
1228
 
 
1229
 
        f = (EditFace *) l->first;
1230
 
 
1231
 
        while(f) {
1232
 
                nextf= f->next;
1233
 
                if( faceselectedOR(f, SELECT) ) {
1234
 
                        BLI_remlink(l, f);
1235
 
                        free_editface(em, f);
1236
 
                }
1237
 
                f = nextf;
1238
 
        }
1239
 
}
1240
 
 
1241
 
static void erase_vertices(EditMesh *em, ListBase *l)
1242
 
{
1243
 
        EditVert *v, *nextv;
1244
 
 
1245
 
        v = (EditVert *) l->first;
1246
 
        while(v) {
1247
 
                nextv= v->next;
1248
 
                if(v->f & 1) {
1249
 
                        BLI_remlink(l, v);
1250
 
                        free_editvert(em, v);
1251
 
                }
1252
 
                v = nextv;
1253
 
        }
1254
 
}
1255
 
 
1256
 
static void delete_mesh(EditMesh *em, wmOperator *op, int event)
1257
 
{
1258
 
        EditFace *efa, *nextvl;
1259
 
        EditVert *eve,*nextve;
1260
 
        EditEdge *eed,*nexted;
1261
 
        int count;
1262
 
        /* const char *str="Erase"; */
1263
 
 
1264
 
 
1265
 
        if(event<1) return;
1266
 
 
1267
 
        if(event==10 ) {
1268
 
                /* str= "Erase Vertices"; */
1269
 
                erase_edges(em, &em->edges);
1270
 
                erase_faces(em, &em->faces);
1271
 
                erase_vertices(em, &em->verts);
1272
 
        }
1273
 
        else if(event==6) {
1274
 
                if(!EdgeLoopDelete(em, op))
1275
 
                        return;
1276
 
 
1277
 
                /* str= "Erase Edge Loop"; */
1278
 
        }
1279
 
        else if(event==4) {
1280
 
                /* str= "Erase Edges & Faces"; */
1281
 
                efa= em->faces.first;
1282
 
                while(efa) {
1283
 
                        nextvl= efa->next;
1284
 
                        /* delete only faces with 1 or more edges selected */
1285
 
                        count= 0;
1286
 
                        if(efa->e1->f & SELECT) count++;
1287
 
                        if(efa->e2->f & SELECT) count++;
1288
 
                        if(efa->e3->f & SELECT) count++;
1289
 
                        if(efa->e4 && (efa->e4->f & SELECT)) count++;
1290
 
                        if(count) {
1291
 
                                BLI_remlink(&em->faces, efa);
1292
 
                                free_editface(em, efa);
1293
 
                        }
1294
 
                        efa= nextvl;
1295
 
                }
1296
 
                eed= em->edges.first;
1297
 
                while(eed) {
1298
 
                        nexted= eed->next;
1299
 
                        if(eed->f & SELECT) {
1300
 
                                remedge(em, eed);
1301
 
                                free_editedge(em, eed);
1302
 
                        }
1303
 
                        eed= nexted;
1304
 
                }
1305
 
                efa= em->faces.first;
1306
 
                while(efa) {
1307
 
                        nextvl= efa->next;
1308
 
                        event=0;
1309
 
                        if( efa->v1->f & SELECT) event++;
1310
 
                        if( efa->v2->f & SELECT) event++;
1311
 
                        if( efa->v3->f & SELECT) event++;
1312
 
                        if(efa->v4 && (efa->v4->f & SELECT)) event++;
1313
 
 
1314
 
                        if(event>1) {
1315
 
                                BLI_remlink(&em->faces, efa);
1316
 
                                free_editface(em, efa);
1317
 
                        }
1318
 
                        efa= nextvl;
1319
 
                }
1320
 
        }
1321
 
        else if(event==1) {
1322
 
                /* str= "Erase Edges"; */
1323
 
                // faces first
1324
 
                efa= em->faces.first;
1325
 
                while(efa) {
1326
 
                        nextvl= efa->next;
1327
 
                        event=0;
1328
 
                        if( efa->e1->f & SELECT) event++;
1329
 
                        if( efa->e2->f & SELECT) event++;
1330
 
                        if( efa->e3->f & SELECT) event++;
1331
 
                        if(efa->e4 && (efa->e4->f & SELECT)) event++;
1332
 
 
1333
 
                        if(event) {
1334
 
                                BLI_remlink(&em->faces, efa);
1335
 
                                free_editface(em, efa);
1336
 
                        }
1337
 
                        efa= nextvl;
1338
 
                }
1339
 
                eed= em->edges.first;
1340
 
                while(eed) {
1341
 
                        nexted= eed->next;
1342
 
                        if(eed->f & SELECT) {
1343
 
                                remedge(em, eed);
1344
 
                                free_editedge(em, eed);
1345
 
                        }
1346
 
                        eed= nexted;
1347
 
                }
1348
 
                /* to remove loose vertices: */
1349
 
                eed= em->edges.first;
1350
 
                while(eed) {
1351
 
                        if( eed->v1->f & SELECT) eed->v1->f-=SELECT;
1352
 
                        if( eed->v2->f & SELECT) eed->v2->f-=SELECT;
1353
 
                        eed= eed->next;
1354
 
                }
1355
 
                eve= em->verts.first;
1356
 
                while(eve) {
1357
 
                        nextve= eve->next;
1358
 
                        if(eve->f & SELECT) {
1359
 
                                BLI_remlink(&em->verts,eve);
1360
 
                                free_editvert(em, eve);
1361
 
                        }
1362
 
                        eve= nextve;
1363
 
                }
1364
 
 
1365
 
        }
1366
 
        else if(event==2) {
1367
 
                /* str="Erase Faces"; */
1368
 
                delfaceflag(em, SELECT);
1369
 
        }
1370
 
        else if(event==3) {
1371
 
                /* str= "Erase All"; */
1372
 
                if(em->verts.first) free_vertlist(em, &em->verts);
1373
 
                if(em->edges.first) free_edgelist(em, &em->edges);
1374
 
                if(em->faces.first) free_facelist(em, &em->faces);
1375
 
                if(em->selected.first) BLI_freelistN(&(em->selected));
1376
 
        }
1377
 
        else if(event==5) {
1378
 
                /* str= "Erase Only Faces"; */
1379
 
                efa= em->faces.first;
1380
 
                while(efa) {
1381
 
                        nextvl= efa->next;
1382
 
                        if(efa->f & SELECT) {
1383
 
                                BLI_remlink(&em->faces, efa);
1384
 
                                free_editface(em, efa);
1385
 
                        }
1386
 
                        efa= nextvl;
1387
 
                }
1388
 
        }
1389
 
 
1390
 
        recalc_editnormals(em);
1391
 
 
1392
 
        EM_fgon_flags(em);      // redo flags and indices for fgons
 
696
 
 
697
}
 
698
 
 
699
void MESH_OT_select_interior_faces(wmOperatorType *ot)
 
700
{
 
701
        /* identifiers */
 
702
        ot->name = "Select Interior Faces";
 
703
        ot->idname = "MESH_OT_select_interior_faces";
 
704
        ot->description = "Select faces where all edges have more than 2 face users";
 
705
 
 
706
        /* api callbacks */
 
707
        ot->exec = edbm_faces_select_interior_exec;
 
708
        ot->poll = ED_operator_editmesh;
 
709
 
 
710
        /* flags */
 
711
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
712
}
 
713
 
 
714
/* *************** add-click-mesh (extrude) operator ************** */
 
715
static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
 
716
{
 
717
        ViewContext vc;
 
718
        BMVert *v1;
 
719
        BMIter iter;
 
720
        float min[3], max[3];
 
721
        int done = 0;
 
722
        short use_proj;
 
723
        
 
724
        em_setup_viewcontext(C, &vc);
 
725
        
 
726
        use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
 
727
                    (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
 
728
 
 
729
        INIT_MINMAX(min, max);
 
730
        
 
731
        BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) {
 
732
                if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) {
 
733
                        DO_MINMAX(v1->co, min, max);
 
734
                        done = 1;
 
735
                }
 
736
        }
 
737
 
 
738
        /* call extrude? */
 
739
        if (done) {
 
740
                const short rot_src = RNA_boolean_get(op->ptr, "rotate_source");
 
741
                BMEdge *eed;
 
742
                float vec[3], cent[3], mat[3][3];
 
743
                float nor[3] = {0.0, 0.0, 0.0};
 
744
 
 
745
                /* 2D normal calc */
 
746
                float mval_f[2];
 
747
 
 
748
                mval_f[0] = (float)event->mval[0];
 
749
                mval_f[1] = (float)event->mval[1];
 
750
 
 
751
                /* check for edges that are half selected, use for rotation */
 
752
                done = 0;
 
753
                BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) {
 
754
                        if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
 
755
                                float co1[3], co2[3];
 
756
                                mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
 
757
                                mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
 
758
                                project_float_noclip(vc.ar, co1, co1);
 
759
                                project_float_noclip(vc.ar, co2, co2);
 
760
 
 
761
                                /* 2D rotate by 90d while adding.
 
762
                                 *  (x, y) = (y, -x)
 
763
                                 *
 
764
                                 * accumulate the screenspace normal in 2D,
 
765
                                 * with screenspace edge length weighting the result. */
 
766
                                if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
 
767
                                        nor[0] +=  (co1[1] - co2[1]);
 
768
                                        nor[1] += -(co1[0] - co2[0]);
 
769
                                }
 
770
                                else {
 
771
                                        nor[0] +=  (co2[1] - co1[1]);
 
772
                                        nor[1] += -(co2[0] - co1[0]);
 
773
                                }
 
774
                        }
 
775
                        done = 1;
 
776
                }
 
777
 
 
778
                if (done) {
 
779
                        float view_vec[3], cross[3];
 
780
 
 
781
                        /* convert the 2D nomal into 3D */
 
782
                        mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
 
783
                        mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
 
784
 
 
785
                        /* correct the normal to be aligned on the view plane */
 
786
                        copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
 
787
                        mul_mat3_m4_v3(vc.obedit->imat, view_vec);
 
788
                        cross_v3_v3v3(cross, nor, view_vec);
 
789
                        cross_v3_v3v3(nor, view_vec, cross);
 
790
                        normalize_v3(nor);
 
791
                }
 
792
                
 
793
                /* center */
 
794
                mid_v3_v3v3(cent, min, max);
 
795
                copy_v3_v3(min, cent);
 
796
 
 
797
                mul_m4_v3(vc.obedit->obmat, min);  /* view space */
 
798
                view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
 
799
                mul_m4_v3(vc.obedit->imat, min); // back in object space
 
800
 
 
801
                sub_v3_v3(min, cent);
 
802
                
 
803
                /* calculate rotation */
 
804
                unit_m3(mat);
 
805
                if (done) {
 
806
                        float angle;
 
807
 
 
808
                        normalize_v3_v3(vec, min);
 
809
 
 
810
                        angle = angle_normalized_v3v3(vec, nor);
 
811
 
 
812
                        if (angle != 0.0f) {
 
813
                                float axis[3];
 
814
 
 
815
                                cross_v3_v3v3(axis, nor, vec);
 
816
 
 
817
                                /* halve the rotation if its applied twice */
 
818
                                if (rot_src) {
 
819
                                        angle *= 0.5f;
 
820
                                }
 
821
 
 
822
                                axis_angle_to_mat3(mat, axis, angle);
 
823
                        }
 
824
                }
 
825
                
 
826
                if (rot_src) {
 
827
                        EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
 
828
                                      BM_ELEM_SELECT, cent, mat);
 
829
 
 
830
                        /* also project the source, for retopo workflow */
 
831
                        if (use_proj)
 
832
                                EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
 
833
                }
 
834
 
 
835
                edbm_extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor);
 
836
                EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
 
837
                              BM_ELEM_SELECT, cent, mat);
 
838
                EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v",
 
839
                              BM_ELEM_SELECT, min);
 
840
        }
 
841
        else {
 
842
                float *curs = give_cursor(vc.scene, vc.v3d);
 
843
                BMOperator bmop;
 
844
                BMOIter oiter;
 
845
                
 
846
                copy_v3_v3(min, curs);
 
847
                view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0);
 
848
 
 
849
                invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
 
850
                mul_m4_v3(vc.obedit->imat, min); // back in object space
 
851
                
 
852
                EDBM_op_init(vc.em, &bmop, op, "makevert co=%v", min);
 
853
                BMO_op_exec(vc.em->bm, &bmop);
 
854
 
 
855
                BMO_ITER (v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
 
856
                        BM_vert_select_set(vc.em->bm, v1, TRUE);
 
857
                }
 
858
 
 
859
                if (!EDBM_op_finish(vc.em, &bmop, op, TRUE)) {
 
860
                        return OPERATOR_CANCELLED;
 
861
                }
 
862
        }
 
863
 
 
864
        if (use_proj)
 
865
                EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
 
866
 
 
867
        /* This normally happens when pushing undo but modal operators
 
868
         * like this one don't push undo data until after modal mode is
 
869
         * done. */
 
870
        EDBM_mesh_normals_update(vc.em);
 
871
 
 
872
        EDBM_update_generic(C, vc.em, TRUE);
 
873
 
 
874
        return OPERATOR_FINISHED;
 
875
}
 
876
 
 
877
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
 
878
{
 
879
        /* identifiers */
 
880
        ot->name = "Duplicate or Extrude at 3D Cursor";
 
881
        ot->idname = "MESH_OT_dupli_extrude_cursor";
 
882
        ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
 
883
        
 
884
        /* api callbacks */
 
885
        ot->invoke = edbm_dupli_extrude_cursor_invoke;
 
886
        ot->poll = ED_operator_editmesh;
 
887
        
 
888
        /* flags */
 
889
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
890
 
 
891
        RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
1393
892
}
1394
893
 
1395
894
/* Note, these values must match delete_mesh() event values */
1396
895
static EnumPropertyItem prop_mesh_delete_types[] = {
1397
 
        {10,"VERT",             0, "Vertices", ""},
1398
 
        {1, "EDGE",             0, "Edges", ""},
1399
 
        {2, "FACE",             0, "Faces", ""},
1400
 
        {3, "ALL",              0, "All", ""},
1401
 
        {4, "EDGE_FACE",0, "Edges & Faces", ""},
1402
 
        {5, "ONLY_FACE",0, "Only Faces", ""},
1403
 
        {6, "EDGE_LOOP",0, "Edge Loop", ""},
 
896
        {0, "VERT",      0, "Vertices", ""},
 
897
        {1,  "EDGE",      0, "Edges", ""},
 
898
        {2,  "FACE",      0, "Faces", ""},
 
899
        {3,  "EDGE_FACE", 0, "Edges & Faces", ""},
 
900
        {4,  "ONLY_FACE", 0, "Only Faces", ""},
1404
901
        {0, NULL, 0, NULL, NULL}
1405
902
};
1406
903
 
1407
 
static int delete_mesh_exec(bContext *C, wmOperator *op)
 
904
static int edbm_delete_exec(bContext *C, wmOperator *op)
1408
905
{
1409
 
        Object *obedit= CTX_data_edit_object(C);
1410
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
1411
 
        int type= RNA_enum_get(op->ptr, "type");
1412
 
 
1413
 
        if(type==6)
1414
 
                return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL);
1415
 
 
1416
 
        delete_mesh(em, op, type);
1417
 
 
1418
 
        DAG_id_tag_update(obedit->data, 0);
1419
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1420
 
 
1421
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
906
        Object *obedit = CTX_data_edit_object(C);
 
907
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
908
        int type = RNA_enum_get(op->ptr, "type");
 
909
 
 
910
        if (type == 0) {
 
911
                if (!EDBM_op_callf(em, op, "del geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
 
912
                        return OPERATOR_CANCELLED;
 
913
        }
 
914
        else if (type == 1) {
 
915
                if (!EDBM_op_callf(em, op, "del geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) /* Erase Edges */
 
916
                        return OPERATOR_CANCELLED;
 
917
        }
 
918
        else if (type == 2) {
 
919
                if (!EDBM_op_callf(em, op, "del geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) /* Erase Faces */
 
920
                        return OPERATOR_CANCELLED;
 
921
        }
 
922
        else if (type == 3) {
 
923
                if (!EDBM_op_callf(em, op, "del geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) /* Edges and Faces */
 
924
                        return OPERATOR_CANCELLED;
 
925
        }
 
926
        else if (type == 4) {
 
927
                //"Erase Only Faces";
 
928
                if (!EDBM_op_callf(em, op, "del geom=%hf context=%i",
 
929
                                   BM_ELEM_SELECT, DEL_ONLYFACES))
 
930
                        return OPERATOR_CANCELLED;
 
931
        }
 
932
 
 
933
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
934
 
 
935
        EDBM_update_generic(C, em, TRUE);
 
936
        
1422
937
        return OPERATOR_FINISHED;
1423
938
}
1424
939
 
1425
940
void MESH_OT_delete(wmOperatorType *ot)
1426
941
{
1427
942
        /* identifiers */
1428
 
        ot->name= "Delete";
1429
 
        ot->description= "Delete selected vertices, edges or faces";
1430
 
        ot->idname= "MESH_OT_delete";
1431
 
 
1432
 
        /* api callbacks */
1433
 
        ot->invoke= WM_menu_invoke;
1434
 
        ot->exec= delete_mesh_exec;
1435
 
 
1436
 
        ot->poll= ED_operator_editmesh;
1437
 
 
1438
 
        /* flags */
1439
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1440
 
 
1441
 
        /*props */
1442
 
        ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1443
 
}
1444
 
 
1445
 
 
1446
 
/*GB*/
1447
 
/*-------------------------------------------------------------------------------*/
1448
 
/*--------------------------- Edge Based Subdivide ------------------------------*/
1449
 
 
1450
 
#define EDGENEW 2
1451
 
#define FACENEW 2
1452
 
#define EDGEINNER  4
1453
 
#define EDGEOLD  8
1454
 
 
1455
 
/*used by faceloop cut to select only edges valid for edge slide*/
1456
 
#define DOUBLEOPFILL 16
1457
 
 
1458
 
/* calculates offset for co, based on fractal, sphere or smooth settings  */
1459
 
static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int beauty, float perc)
1460
 
{
1461
 
        float tvec[3], fac;
1462
 
 
1463
 
        if(beauty & B_SMOOTH) {
1464
 
                /* we calculate an offset vector tvec[], to be added to *co */
1465
 
                float len, nor[3], nor1[3], nor2[3];
1466
 
 
1467
 
                sub_v3_v3v3(nor, edge->v1->co, edge->v2->co);
1468
 
                len= 0.5f*normalize_v3(nor);
1469
 
 
1470
 
                copy_v3_v3(nor1, edge->v1->no);
1471
 
                copy_v3_v3(nor2, edge->v2->no);
1472
 
 
1473
 
                /* cosine angle */
1474
 
                fac=  dot_v3v3(nor, nor1);
1475
 
                mul_v3_v3fl(tvec, nor1, fac);
1476
 
 
1477
 
                /* cosine angle */
1478
 
                fac= -dot_v3v3(nor, nor2);
1479
 
                madd_v3_v3fl(tvec, nor2, fac);
1480
 
 
1481
 
                /* falloff for multi subdivide */
1482
 
                smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc)));
1483
 
 
1484
 
                mul_v3_fl(tvec, smooth * len);
1485
 
 
1486
 
                add_v3_v3(co, tvec);
1487
 
        }
1488
 
        else if(beauty & B_SPHERE) { /* subdivide sphere */
1489
 
                normalize_v3(co);
1490
 
                mul_v3_fl(co, smooth);
1491
 
        }
1492
 
 
1493
 
        if(beauty & B_FRACTAL) {
1494
 
                fac= fractal*len_v3v3(edge->v1->co, edge->v2->co);
1495
 
                tvec[0]= fac*(float)(0.5-BLI_drand());
1496
 
                tvec[1]= fac*(float)(0.5-BLI_drand());
1497
 
                tvec[2]= fac*(float)(0.5-BLI_drand());
1498
 
                add_v3_v3(co, tvec);
1499
 
        }
1500
 
}
1501
 
 
1502
 
/* assumes in the edge is the correct interpolated vertices already */
1503
 
/* percent defines the interpolation, smooth, fractal and beauty are for special options */
1504
 
/* results in new vertex with correct coordinate, vertex normal and weight group info */
1505
 
static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smooth, float fractal, int beauty, float percent)
1506
 
{
1507
 
        EditVert *ev;
1508
 
        float co[3];
1509
 
 
1510
 
        interp_v3_v3v3(co, edge->v1->co, edge->v2->co, percent);
1511
 
 
1512
 
        /* offset for smooth or sphere or fractal */
1513
 
        alter_co(co, edge, smooth, fractal, beauty, percent);
1514
 
 
1515
 
        /* clip if needed by mirror modifier */
1516
 
        if (edge->v1->f2) {
1517
 
                if ( edge->v1->f2 & edge->v2->f2 & 1) {
1518
 
                        co[0]= 0.0f;
1519
 
                }
1520
 
                if ( edge->v1->f2 & edge->v2->f2 & 2) {
1521
 
                        co[1]= 0.0f;
1522
 
                }
1523
 
                if ( edge->v1->f2 & edge->v2->f2 & 4) {
1524
 
                        co[2]= 0.0f;
1525
 
                }
1526
 
        }
1527
 
 
1528
 
        ev = addvertlist(em, co, NULL);
1529
 
 
1530
 
        /* vert data (vgroups, ..) */
1531
 
        EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent);
1532
 
 
1533
 
        /* normal */
1534
 
        interp_v3_v3v3(ev->no, edge->v1->no, edge->v2->no, percent);
1535
 
        normalize_v3(ev->no);
1536
 
 
1537
 
        return ev;
1538
 
}
1539
 
 
1540
 
static void flipvertarray(EditVert** arr, short size)
1541
 
{
1542
 
        EditVert *hold;
1543
 
        int i;
1544
 
 
1545
 
        for(i=0; i<size/2; i++) {
1546
 
                hold = arr[i];
1547
 
                arr[i] = arr[size-i-1];
1548
 
                arr[size-i-1] = hold;
1549
 
        }
1550
 
}
1551
 
 
1552
 
static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
1553
 
{
1554
 
        float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
1555
 
        float *v4 = source->v4? source->v4->co: NULL;
1556
 
        float w[4][4];
1557
 
 
1558
 
        CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
1559
 
 
1560
 
        target->mat_nr = source->mat_nr;
1561
 
        target->flag   = source->flag;
1562
 
        target->h          = source->h;
1563
 
 
1564
 
        interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co);
1565
 
        interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co);
1566
 
        interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co);
1567
 
        if (target->v4)
1568
 
                interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co);
1569
 
 
1570
 
        CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3);
1571
 
        CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
1572
 
}
1573
 
 
1574
 
static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
1575
 
{
1576
 
        EditEdge *cedge=NULL;
1577
 
        EditVert *v[4], **verts;
1578
 
        EditFace *hold;
1579
 
        short start=0, /* end, */ /* UNUSED */ left, right, vertsize,i;
1580
 
 
1581
 
        v[0] = efa->v1;
1582
 
        v[1] = efa->v2;
1583
 
        v[2] = efa->v3;
1584
 
        v[3] = efa->v4;
1585
 
 
1586
 
        if(efa->e1->f & SELECT)   { cedge = efa->e1; start = 0;}
1587
 
        else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
1588
 
        else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
1589
 
        else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
1590
 
 
1591
 
        // Point verts to the array of new verts for cedge
1592
 
        verts = BLI_ghash_lookup(gh, cedge);
1593
 
        //This is the index size of the verts array
1594
 
        vertsize = numcuts+2;
1595
 
 
1596
 
        // Is the original v1 the same as the first vert on the selected edge?
1597
 
        // if not, the edge is running the opposite direction in this face so flip
1598
 
        // the array to the correct direction
1599
 
 
1600
 
        if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
1601
 
        /* end  = (start+1)%4; */ /* UNUSED */
1602
 
        left   = (start+2)%4;
1603
 
        right  = (start+3)%4;
1604
 
 
1605
 
        /*
1606
 
        We should have something like this now
1607
 
 
1608
 
                          end            start
1609
 
                           3   2   1   0
1610
 
                           |---*---*---|
1611
 
                           |               |
1612
 
                           |               |
1613
 
                           |               |
1614
 
                           -------------
1615
 
                          left     right
1616
 
 
1617
 
        where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
1618
 
        and 0,1,2... are the indexes of the new verts stored in verts
1619
 
 
1620
 
        We will fill this case like this or this depending on even or odd cuts
1621
 
 
1622
 
                           |---*---*---|                  |---*---|
1623
 
                           |  /  \  |             |  / \  |
1624
 
                           | /     \ |            | /   \ |
1625
 
                           |/            \|               |/     \|
1626
 
                           -------------                  ---------
1627
 
        */
1628
 
 
1629
 
        // Make center face
1630
 
        if(vertsize % 2 == 0) {
1631
 
                hold = addfacelist(em, verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL);
1632
 
                hold->e2->f2 |= EDGEINNER;
1633
 
                hold->e4->f2 |= EDGEINNER;
1634
 
        }else{
1635
 
                hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
1636
 
                hold->e1->f2 |= EDGEINNER;
1637
 
                hold->e3->f2 |= EDGEINNER;
1638
 
        }
1639
 
        facecopy(em, efa,hold);
1640
 
 
1641
 
        // Make side faces
1642
 
        for(i=0;i<(vertsize-1)/2;i++) {
1643
 
                hold = addfacelist(em, verts[i],verts[i+1],v[right],NULL,NULL,NULL);
1644
 
                facecopy(em, efa,hold);
1645
 
                if(i+1 != (vertsize-1)/2) {
1646
 
                        if(seltype == SUBDIV_SELECT_INNER) {
1647
 
                                hold->e2->f2 |= EDGEINNER;
1648
 
                        }
1649
 
                }
1650
 
                hold = addfacelist(em, verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
1651
 
                facecopy(em, efa,hold);
1652
 
                if(i+1 != (vertsize-1)/2) {
1653
 
                        if(seltype == SUBDIV_SELECT_INNER) {
1654
 
                                hold->e3->f2 |= EDGEINNER;
1655
 
                        }
1656
 
                }
1657
 
        }
1658
 
}
1659
 
 
1660
 
static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
1661
 
{
1662
 
        EditEdge *cedge=NULL;
1663
 
        EditVert *v[3], **verts;
1664
 
        EditFace *hold;
1665
 
        short start=0, /* end, */ /* UNUSED */ op, vertsize,i;
1666
 
 
1667
 
        v[0] = efa->v1;
1668
 
        v[1] = efa->v2;
1669
 
        v[2] = efa->v3;
1670
 
 
1671
 
        if(efa->e1->f & SELECT)   { cedge = efa->e1; start = 0;}
1672
 
        else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
1673
 
        else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
1674
 
 
1675
 
        // Point verts to the array of new verts for cedge
1676
 
        verts = BLI_ghash_lookup(gh, cedge);
1677
 
        //This is the index size of the verts array
1678
 
        vertsize = numcuts+2;
1679
 
 
1680
 
        // Is the original v1 the same as the first vert on the selected edge?
1681
 
        // if not, the edge is running the opposite direction in this face so flip
1682
 
        // the array to the correct direction
1683
 
 
1684
 
        if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
1685
 
        /* end = (start+1)%3; */ /* UNUSED */
1686
 
        op = (start+2)%3;
1687
 
 
1688
 
        /*
1689
 
        We should have something like this now
1690
 
 
1691
 
                          end            start
1692
 
                           3   2   1   0
1693
 
                           |---*---*---|
1694
 
                           \               |
1695
 
                                 \               |
1696
 
                                   \       |
1697
 
                                         \       |
1698
 
                                           \   |
1699
 
                                                 \ |
1700
 
                                                   |op
1701
 
 
1702
 
        where start,end,op are indexes of EditFace->v1, etc (stored in v)
1703
 
        and 0,1,2... are the indexes of the new verts stored in verts
1704
 
 
1705
 
        We will fill this case like this or this depending on even or odd cuts
1706
 
 
1707
 
                           3   2   1   0
1708
 
                           |---*---*---|
1709
 
                           \    \  \   |
1710
 
                                 \      \ \  |
1711
 
                                   \   \ \ |
1712
 
                                         \  \ \|
1713
 
                                           \ \\|
1714
 
                                                 \ |
1715
 
                                                   |op
1716
 
        */
1717
 
 
1718
 
        // Make side faces
1719
 
        for(i=0;i<(vertsize-1);i++) {
1720
 
                hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL);
1721
 
                if(i+1 != vertsize-1) {
1722
 
                        if(seltype == SUBDIV_SELECT_INNER) {
1723
 
                                hold->e2->f2 |= EDGEINNER;
1724
 
                        }
1725
 
                }
1726
 
                facecopy(em, efa,hold);
1727
 
        }
1728
 
}
1729
 
 
1730
 
static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1731
 
{
1732
 
        EditEdge *cedge[2]={NULL, NULL};
1733
 
        EditVert *v[4], **verts[2];
1734
 
        EditFace *hold;
1735
 
        short start=0, /*end,*/ left, /* right,*/ vertsize,i;
1736
 
 
1737
 
        v[0] = efa->v1;
1738
 
        v[1] = efa->v2;
1739
 
        v[2] = efa->v3;
1740
 
        v[3] = efa->v4;
1741
 
 
1742
 
        if(efa->e1->f & SELECT)   { cedge[0] = efa->e1;  cedge[1] = efa->e3; start = 0;}
1743
 
        else if(efa->e2->f & SELECT)      { cedge[0] = efa->e2;  cedge[1] = efa->e4; start = 1;}
1744
 
 
1745
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
1746
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
1747
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
1748
 
        //This is the index size of the verts array
1749
 
        vertsize = numcuts+2;
1750
 
 
1751
 
        // Is the original v1 the same as the first vert on the selected edge?
1752
 
        // if not, the edge is running the opposite direction in this face so flip
1753
 
        // the array to the correct direction
1754
 
 
1755
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1756
 
        /* end  = (start+1)%4; */ /* UNUSED */
1757
 
        left   = (start+2)%4;
1758
 
        /* right  = (start+3)%4; */ /* UNUSED */
1759
 
        if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
1760
 
        /*
1761
 
        We should have something like this now
1762
 
 
1763
 
                          end            start
1764
 
                           3   2   1   0
1765
 
                           |---*---*---|
1766
 
                           |               |
1767
 
                           |               |
1768
 
                           |               |
1769
 
                           |---*---*---|
1770
 
                           0   1   2   3
1771
 
                          left     right
1772
 
 
1773
 
        We will fill this case like this or this depending on even or odd cuts
1774
 
 
1775
 
                           |---*---*---|
1776
 
                           |   |   |   |
1777
 
                           |   |   |   |
1778
 
                           |   |   |   |
1779
 
                           |---*---*---|
1780
 
        */
1781
 
 
1782
 
        // Make side faces
1783
 
        for(i=0;i<vertsize-1;i++) {
1784
 
                hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL);
1785
 
                if(i < vertsize-2) {
1786
 
                        hold->e2->f2 |= EDGEINNER;
1787
 
                        hold->e2->f2 |= DOUBLEOPFILL;
1788
 
                }
1789
 
                facecopy(em, efa,hold);
1790
 
        }
1791
 
}
1792
 
 
1793
 
static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1794
 
{
1795
 
        EditEdge *cedge[2]={NULL, NULL};
1796
 
        EditVert *v[4], **verts[2];
1797
 
        EditFace *hold;
1798
 
        short start=0, start2=0, vertsize,i;
1799
 
        int ctrl= 0; // XXX
1800
 
 
1801
 
        v[0] = efa->v1;
1802
 
        v[1] = efa->v2;
1803
 
        v[2] = efa->v3;
1804
 
        v[3] = efa->v4;
1805
 
 
1806
 
        if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1;  cedge[1] = efa->e2; start = 0; start2 = 1;}
1807
 
        if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2;  cedge[1] = efa->e3; start = 1; start2 = 2;}
1808
 
        if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3;  cedge[1] = efa->e4; start = 2; start2 = 3;}
1809
 
        if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4;  cedge[1] = efa->e1; start = 3; start2 = 0;}
1810
 
 
1811
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
1812
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
1813
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
1814
 
        //This is the index size of the verts array
1815
 
        vertsize = numcuts+2;
1816
 
 
1817
 
        // Is the original v1 the same as the first vert on the selected edge?
1818
 
        // if not, the edge is running the opposite direction in this face so flip
1819
 
        // the array to the correct direction
1820
 
 
1821
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1822
 
        if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1823
 
        /*
1824
 
        We should have something like this now
1825
 
 
1826
 
                           end           start
1827
 
                                3   2   1   0
1828
 
                start2 0|---*---*---|
1829
 
                                |                  |
1830
 
                           1*              |
1831
 
                                |                  |
1832
 
                           2*              |
1833
 
                                |                  |
1834
 
                 end2  3|-----------|
1835
 
 
1836
 
        We will fill this case like this or this depending on even or odd cuts
1837
 
                           |---*---*---|
1838
 
                           | /   /   / |
1839
 
                           *   /   /   |
1840
 
                           | /   /       |
1841
 
                           *   /           |
1842
 
                           | /           |
1843
 
                           |-----------|
1844
 
        */
1845
 
 
1846
 
        // Make outside tris
1847
 
        hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
1848
 
        /* when ctrl is depressed, only want verts on the cutline selected */
1849
 
        if (ctrl)
1850
 
                hold->e3->f2 |= EDGEINNER;
1851
 
        facecopy(em, efa,hold);
1852
 
        hold = addfacelist(em, verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
1853
 
        /* when ctrl is depressed, only want verts on the cutline selected */
1854
 
        if (ctrl)
1855
 
                hold->e1->f2 |= EDGEINNER;
1856
 
        facecopy(em, efa,hold);
1857
 
        //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
1858
 
        //      hold->e1->h |= EM_FGON;
1859
 
        //}
1860
 
        // Make side faces
1861
 
 
1862
 
        for(i=0;i<numcuts;i++) {
1863
 
                hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
1864
 
                hold->e2->f2 |= EDGEINNER;
1865
 
                facecopy(em, efa,hold);
1866
 
        }
1867
 
        //EM_fgon_flags(em);
1868
 
 
1869
 
}
1870
 
 
1871
 
static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1872
 
{
1873
 
        EditEdge *cedge[2]={NULL, NULL};
1874
 
        EditVert *v[4], *op=NULL, **verts[2];
1875
 
        EditFace *hold;
1876
 
        short start=0, start2=0, /* vertsize, */ /* UNUSED */ i;
1877
 
 
1878
 
        v[0] = efa->v1;
1879
 
        v[1] = efa->v2;
1880
 
        v[2] = efa->v3;
1881
 
        v[3] = efa->v4;
1882
 
 
1883
 
        if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1;  cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
1884
 
        if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2;  cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
1885
 
        if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3;  cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
1886
 
        if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4;  cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
1887
 
 
1888
 
 
1889
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
1890
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
1891
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
1892
 
        //This is the index size of the verts array
1893
 
        /* vertsize = numcuts+2; */ /* UNUSED */
1894
 
 
1895
 
        // Is the original v1 the same as the first vert on the selected edge?
1896
 
        // if not, the edge is running the opposite direction in this face so flip
1897
 
        // the array to the correct direction
1898
 
 
1899
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1900
 
        if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1901
 
        /*
1902
 
        We should have something like this now
1903
 
 
1904
 
                           end           start
1905
 
                                3   2   1   0
1906
 
                start2 0|---*---*---|
1907
 
                                |                  |
1908
 
                           1*              |
1909
 
                                |                  |
1910
 
                           2*              |
1911
 
                                |                  |
1912
 
                 end2  3|-----------|op
1913
 
 
1914
 
        We will fill this case like this or this (warning horrible ascii art follows)
1915
 
                           |---*---*---|
1916
 
                           | \  \   \  |
1917
 
                           *---\  \  \ |
1918
 
                           |   \ \ \  \|
1919
 
                           *---- \ \  \ |
1920
 
                           |    ---  \\\|
1921
 
                           |-----------|
1922
 
        */
1923
 
 
1924
 
        for(i=0;i<=numcuts;i++) {
1925
 
                hold = addfacelist(em, op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
1926
 
                hold->e1->f2 |= EDGEINNER;
1927
 
                facecopy(em, efa,hold);
1928
 
 
1929
 
                hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
1930
 
                hold->e3->f2 |= EDGEINNER;
1931
 
                facecopy(em, efa,hold);
1932
 
        }
1933
 
}
1934
 
 
1935
 
static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1936
 
{
1937
 
        EditEdge *cedge[2]={NULL, NULL};
1938
 
        EditVert *v[4], *op=NULL, **verts[2],**inner;
1939
 
        EditFace *hold;
1940
 
        short start=0, start2=0, /* vertsize, */ /* UNUSED */ i;
1941
 
        float co[3];
1942
 
 
1943
 
        v[0] = efa->v1;
1944
 
        v[1] = efa->v2;
1945
 
        v[2] = efa->v3;
1946
 
        v[3] = efa->v4;
1947
 
 
1948
 
        if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1;  cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
1949
 
        if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2;  cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
1950
 
        if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3;  cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
1951
 
        if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4;  cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
1952
 
 
1953
 
 
1954
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
1955
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
1956
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
1957
 
        //This is the index size of the verts array
1958
 
        /* vertsize = numcuts+2; */ /* UNUSED */
1959
 
 
1960
 
        // Is the original v1 the same as the first vert on the selected edge?
1961
 
        // if not, the edge is running the opposite direction in this face so flip
1962
 
        // the array to the correct direction
1963
 
 
1964
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1965
 
        if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1966
 
        /*
1967
 
        We should have something like this now
1968
 
 
1969
 
                           end           start
1970
 
                                3   2   1   0
1971
 
                start2 0|---*---*---|
1972
 
                                |                  |
1973
 
                           1*              |
1974
 
                                |                  |
1975
 
                           2*              |
1976
 
                                |                  |
1977
 
                 end2  3|-----------|op
1978
 
 
1979
 
        We will fill this case like this or this (warning horrible ascii art follows)
1980
 
                           |---*-----*---|
1981
 
                           | *     /     |
1982
 
                           *   \ /       |
1983
 
                           |    *        |
1984
 
                           | /    \          |
1985
 
                           *        \    |
1986
 
                           |           \ |
1987
 
                           |-------------|
1988
 
        */
1989
 
 
1990
 
        // Add Inner Vert(s)
1991
 
        inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts");
1992
 
 
1993
 
        for(i=0;i<numcuts;i++) {
1994
 
                co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ;
1995
 
                co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ;
1996
 
                co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ;
1997
 
                inner[i] = addvertlist(em, co, NULL);
1998
 
                inner[i]->f2 |= EDGEINNER;
1999
 
 
2000
 
                EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
2001
 
        }
2002
 
 
2003
 
        // Add Corner Quad
2004
 
        hold = addfacelist(em, verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
2005
 
        hold->e2->f2 |= EDGEINNER;
2006
 
        hold->e3->f2 |= EDGEINNER;
2007
 
        facecopy(em, efa,hold);
2008
 
        // Add Bottom Quads
2009
 
        hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
2010
 
        hold->e2->f2 |= EDGEINNER;
2011
 
        facecopy(em, efa,hold);
2012
 
 
2013
 
        hold = addfacelist(em, op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
2014
 
        hold->e2->f2 |= EDGEINNER;
2015
 
        facecopy(em, efa,hold);
2016
 
 
2017
 
        //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2018
 
        //      hold->e1->h |= EM_FGON;
2019
 
        //}
2020
 
        // Add Fill Quads (if # cuts > 1)
2021
 
 
2022
 
        for(i=0;i<numcuts-1;i++) {
2023
 
                hold = addfacelist(em, inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
2024
 
                hold->e1->f2 |= EDGEINNER;
2025
 
                hold->e3->f2 |= EDGEINNER;
2026
 
                facecopy(em, efa,hold);
2027
 
 
2028
 
                hold = addfacelist(em, inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
2029
 
                hold->e2->f2 |= EDGEINNER;
2030
 
                hold->e4->f2 |= EDGEINNER;
2031
 
                facecopy(em, efa,hold);
2032
 
 
2033
 
                //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2034
 
                //      hold->e1->h |= EM_FGON;
2035
 
                //}
2036
 
        }
2037
 
 
2038
 
        //EM_fgon_flags(em);
2039
 
 
2040
 
        MEM_freeN(inner);
2041
 
}
2042
 
 
2043
 
static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
2044
 
{
2045
 
        EditEdge *cedge[2]={NULL, NULL};
2046
 
        EditVert *v[3], **verts[2];
2047
 
        EditFace *hold;
2048
 
        short start=0, start2=0, vertsize,i;
2049
 
 
2050
 
        v[0] = efa->v1;
2051
 
        v[1] = efa->v2;
2052
 
        v[2] = efa->v3;
2053
 
 
2054
 
        if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1;  cedge[1] = efa->e2; start = 0; start2 = 1;}
2055
 
        if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2;  cedge[1] = efa->e3; start = 1; start2 = 2;}
2056
 
        if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3;  cedge[1] = efa->e1; start = 2; start2 = 0;}
2057
 
 
2058
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
2059
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
2060
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
2061
 
        //This is the index size of the verts array
2062
 
        vertsize = numcuts+2;
2063
 
 
2064
 
        // Is the original v1 the same as the first vert on the selected edge?
2065
 
        // if not, the edge is running the opposite direction in this face so flip
2066
 
        // the array to the correct direction
2067
 
 
2068
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
2069
 
        if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
2070
 
        /*
2071
 
        We should have something like this now
2072
 
 
2073
 
                           end           start
2074
 
                                3   2   1   0
2075
 
                start2 0|---*---*---|
2076
 
                                |                /
2077
 
                           1*      /
2078
 
                                |        /
2079
 
                           2*   /
2080
 
                                | /
2081
 
                 end2  3|
2082
 
 
2083
 
        We will fill this case like this or this depending on even or odd cuts
2084
 
                           |---*---*---|
2085
 
                           | /   /   /
2086
 
                           *   /   /
2087
 
                           | /   /
2088
 
                           *   /
2089
 
                           | /
2090
 
                           |
2091
 
        */
2092
 
 
2093
 
        // Make outside tri
2094
 
        hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
2095
 
        hold->e3->f2 |= EDGEINNER;
2096
 
        facecopy(em, efa,hold);
2097
 
        // Make side faces
2098
 
 
2099
 
        for(i=0;i<numcuts;i++) {
2100
 
                hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
2101
 
                hold->e2->f2 |= EDGEINNER;
2102
 
                facecopy(em, efa,hold);
2103
 
        }
2104
 
}
2105
 
 
2106
 
static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
2107
 
{
2108
 
        EditEdge *cedge[3]={0};
2109
 
        EditVert *v[4], **verts[3];
2110
 
        EditFace *hold;
2111
 
        short start=0, start2=0, start3=0, vertsize, i, repeats;
2112
 
 
2113
 
        v[0] = efa->v1;
2114
 
        v[1] = efa->v2;
2115
 
        v[2] = efa->v3;
2116
 
        v[3] = efa->v4;
2117
 
 
2118
 
        if(!(efa->e1->f & SELECT)) {
2119
 
                cedge[0] = efa->e2;
2120
 
                cedge[1] = efa->e3;
2121
 
                cedge[2] = efa->e4;
2122
 
                start = 1;start2 = 2;start3 = 3;
2123
 
        }
2124
 
        if(!(efa->e2->f & SELECT)) {
2125
 
                cedge[0] = efa->e3;
2126
 
                cedge[1] = efa->e4;
2127
 
                cedge[2] = efa->e1;
2128
 
                start = 2;start2 = 3;start3 = 0;
2129
 
        }
2130
 
        if(!(efa->e3->f & SELECT)) {
2131
 
                cedge[0] = efa->e4;
2132
 
                cedge[1] = efa->e1;
2133
 
                cedge[2] = efa->e2;
2134
 
                start = 3;start2 = 0;start3 = 1;
2135
 
        }
2136
 
        if(!(efa->e4->f & SELECT)) {
2137
 
                cedge[0] = efa->e1;
2138
 
                cedge[1] = efa->e2;
2139
 
                cedge[2] = efa->e3;
2140
 
                start = 0;start2 = 1;start3 = 2;
2141
 
        }
2142
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
2143
 
        verts[0] = BLI_ghash_lookup(gh, cedge[0]);
2144
 
        verts[1] = BLI_ghash_lookup(gh, cedge[1]);
2145
 
        verts[2] = BLI_ghash_lookup(gh, cedge[2]);
2146
 
        //This is the index size of the verts array
2147
 
        vertsize = numcuts+2;
2148
 
 
2149
 
        // Is the original v1 the same as the first vert on the selected edge?
2150
 
        // if not, the edge is running the opposite direction in this face so flip
2151
 
        // the array to the correct direction
2152
 
 
2153
 
        if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
2154
 
        if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
2155
 
        if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);}
2156
 
        /*
2157
 
         We should have something like this now
2158
 
 
2159
 
         start2
2160
 
         3   2   1   0
2161
 
         start3 0|---*---*---|3
2162
 
         |                 |
2163
 
         1*                *2
2164
 
         |                 |
2165
 
         2*                *1
2166
 
         |                 |
2167
 
         3|-----------|0 start
2168
 
 
2169
 
         We will fill this case like this or this depending on even or odd cuts
2170
 
         there are a couple of differences. For odd cuts, there is a tri in the
2171
 
         middle as well as 1 quad at the bottom (not including the extra quads
2172
 
         for odd cuts > 1
2173
 
 
2174
 
         For even cuts, there is a quad in the middle and 2 quads on the bottom
2175
 
 
2176
 
         they are numbered here for clarity
2177
 
 
2178
 
         1 outer tris and bottom quads
2179
 
         2 inner tri or quad
2180
 
         3 repeating quads
2181
 
 
2182
 
         |---*---*---*---|
2183
 
         |1/   /  \   \ 1|
2184
 
         |/ 3 / \  3 \|
2185
 
         *  /   2   \   *
2186
 
         | /              \  |
2187
 
         |/                     \ |
2188
 
         *---------------*
2189
 
         |        3             |
2190
 
         |                         |
2191
 
         *---------------*
2192
 
         |                         |
2193
 
         |        1             |
2194
 
         |                         |
2195
 
         |---------------|
2196
 
 
2197
 
         |---*---*---*---*---|
2198
 
         | 1/   /        \   \ 1|
2199
 
         | /   /           \   \ |
2200
 
         |/ 3 /          \ 3 \|
2201
 
         *   /             \   *
2202
 
         |  /                    \  |
2203
 
         | /       2       \ |
2204
 
         |/                              \|
2205
 
         *-------------------*
2206
 
         |                                 |
2207
 
         |               3               |
2208
 
         |                                 |
2209
 
         *-------------------*
2210
 
         |                                 |
2211
 
         |               1               |
2212
 
         |                                 |
2213
 
         *-------------------*
2214
 
         |                                 |
2215
 
         |              1                 |
2216
 
         |                                 |
2217
 
         |-------------------|
2218
 
 
2219
 
         */
2220
 
 
2221
 
        // Make outside tris
2222
 
        hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
2223
 
        hold->e3->f2 |= EDGEINNER;
2224
 
        facecopy(em, efa,hold);
2225
 
        hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
2226
 
        hold->e3->f2 |= EDGEINNER;
2227
 
        facecopy(em, efa,hold);
2228
 
        // Make bottom quad
2229
 
        hold = addfacelist(em, verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
2230
 
        hold->e2->f2 |= EDGEINNER;
2231
 
        facecopy(em, efa,hold);
2232
 
        //If it is even cuts, add the 2nd lower quad
2233
 
        if(numcuts % 2 == 0) {
2234
 
                hold = addfacelist(em, verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
2235
 
                hold->e2->f2 |= EDGEINNER;
2236
 
                facecopy(em, efa,hold);
2237
 
                // Also Make inner quad
2238
 
                hold = addfacelist(em, verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
2239
 
                hold->e3->f2 |= EDGEINNER;
2240
 
                //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2241
 
                //      hold->e3->h |= EM_FGON;
2242
 
                //}
2243
 
                facecopy(em, efa,hold);
2244
 
                repeats = (numcuts / 2) -1;
2245
 
        } else {
2246
 
                // Make inner tri
2247
 
                hold = addfacelist(em, verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
2248
 
                hold->e2->f2 |= EDGEINNER;
2249
 
                //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2250
 
                //      hold->e2->h |= EM_FGON;
2251
 
                //}
2252
 
                facecopy(em, efa,hold);
2253
 
                repeats = ((numcuts+1) / 2)-1;
2254
 
        }
2255
 
 
2256
 
        // cuts for 1 and 2 do not have the repeating quads
2257
 
        if(numcuts < 3) {repeats = 0;}
2258
 
        for(i=0;i<repeats;i++) {
2259
 
                //Make side repeating Quads
2260
 
                hold = addfacelist(em, verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
2261
 
                hold->e2->f2 |= EDGEINNER;
2262
 
                facecopy(em, efa,hold);
2263
 
                hold = addfacelist(em, verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
2264
 
                hold->e4->f2 |= EDGEINNER;
2265
 
                facecopy(em, efa,hold);
2266
 
        }
2267
 
        // Do repeating bottom quads
2268
 
        for(i=0;i<repeats;i++) {
2269
 
                if(numcuts % 2 == 1) {
2270
 
                        hold = addfacelist(em, verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
2271
 
                } else {
2272
 
                        hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
2273
 
                }
2274
 
                hold->e2->f2 |= EDGEINNER;
2275
 
                facecopy(em, efa,hold);
2276
 
        }
2277
 
        //EM_fgon_flags(em);
2278
 
}
2279
 
 
2280
 
static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
2281
 
{
2282
 
        EditVert **verts[4], ***innerverts;
2283
 
        EditFace *hold;
2284
 
        EditEdge temp;
2285
 
        short /* vertsize, */ /* UNUSED */ i, j;
2286
 
 
2287
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
2288
 
        verts[0] = BLI_ghash_lookup(gh, efa->e1);
2289
 
        verts[1] = BLI_ghash_lookup(gh, efa->e2);
2290
 
        verts[2] = BLI_ghash_lookup(gh, efa->e3);
2291
 
        verts[3] = BLI_ghash_lookup(gh, efa->e4);
2292
 
 
2293
 
        //This is the index size of the verts array
2294
 
        /* vertsize = numcuts+2; */ /* UNUSED */
2295
 
 
2296
 
        // Is the original v1 the same as the first vert on the selected edge?
2297
 
        // if not, the edge is running the opposite direction in this face so flip
2298
 
        // the array to the correct direction
2299
 
 
2300
 
        if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
2301
 
        if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
2302
 
        if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);}
2303
 
        if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
2304
 
        /*
2305
 
        We should have something like this now
2306
 
                                          1
2307
 
 
2308
 
                                3   2   1   0
2309
 
                           0|---*---*---|0
2310
 
                                |           |
2311
 
                           1*           *1
2312
 
                         2  |           |   4
2313
 
                           2*           *2
2314
 
                                |           |
2315
 
                           3|---*---*---|3
2316
 
                                3   2   1   0
2317
 
 
2318
 
                                          3
2319
 
        // we will fill a 2 dim array of editvert*s to make filling easier
2320
 
        //  the innervert order is shown
2321
 
 
2322
 
                                0   0---1---2---3
2323
 
                                        |   |   |   |
2324
 
                                1   0---1---2---3
2325
 
                                        |   |   |   |
2326
 
                                2   0---1---2---3
2327
 
                                        |   |   |   |
2328
 
                                3   0---1---2---3
2329
 
 
2330
 
         */
2331
 
        innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array");
2332
 
        for(i=0;i<numcuts+2;i++) {
2333
 
                innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array");
2334
 
        }
2335
 
 
2336
 
        // first row is e1 last row is e3
2337
 
        for(i=0;i<numcuts+2;i++) {
2338
 
                innerverts[0][i]                  = verts[0][(numcuts+1)-i];
2339
 
                innerverts[numcuts+1][i]  = verts[2][(numcuts+1)-i];
2340
 
        }
2341
 
 
2342
 
        for(i=1;i<=numcuts;i++) {
2343
 
                /* we create a fake edge for the next loop */
2344
 
                temp.v2 = innerverts[i][0]                      = verts[1][i];
2345
 
                temp.v1 = innerverts[i][numcuts+1]  = verts[3][i];
2346
 
 
2347
 
                for(j=1;j<=numcuts;j++) {
2348
 
                        float percent= (float)j/(float)(numcuts+1);
2349
 
 
2350
 
                        innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent);
2351
 
                }
2352
 
        }
2353
 
        // Fill with faces
2354
 
        for(i=0;i<numcuts+1;i++) {
2355
 
                for(j=0;j<numcuts+1;j++) {
2356
 
                        hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
2357
 
                        hold->e1->f2 = EDGENEW;
2358
 
                        hold->e2->f2 = EDGENEW;
2359
 
                        hold->e3->f2 = EDGENEW;
2360
 
                        hold->e4->f2 = EDGENEW;
2361
 
 
2362
 
                        if(i != 0) { hold->e1->f2 |= EDGEINNER; }
2363
 
                        if(j != 0) { hold->e2->f2 |= EDGEINNER; }
2364
 
                        if(i != numcuts) { hold->e3->f2 |= EDGEINNER; }
2365
 
                        if(j != numcuts) { hold->e4->f2 |= EDGEINNER; }
2366
 
 
2367
 
                        facecopy(em, efa,hold);
2368
 
                }
2369
 
        }
2370
 
        // Clean up our dynamic multi-dim array
2371
 
        for(i=0;i<numcuts+2;i++) {
2372
 
                MEM_freeN(innerverts[i]);
2373
 
        }
2374
 
        MEM_freeN(innerverts);
2375
 
}
2376
 
 
2377
 
static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
2378
 
{
2379
 
        EditVert **verts[3], ***innerverts;
2380
 
        short /* vertsize, */ /* UNUSED */ i, j;
2381
 
        EditFace *hold;
2382
 
        EditEdge temp;
2383
 
 
2384
 
        // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
2385
 
        verts[0] = BLI_ghash_lookup(gh, efa->e1);
2386
 
        verts[1] = BLI_ghash_lookup(gh, efa->e2);
2387
 
        verts[2] = BLI_ghash_lookup(gh, efa->e3);
2388
 
 
2389
 
        //This is the index size of the verts array
2390
 
        /* vertsize = numcuts+2; */ /* UNUSED */
2391
 
 
2392
 
        // Is the original v1 the same as the first vert on the selected edge?
2393
 
        // if not, the edge is running the opposite direction in this face so flip
2394
 
        // the array to the correct direction
2395
 
 
2396
 
        if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
2397
 
        if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
2398
 
        if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);}
2399
 
        /*
2400
 
        We should have something like this now
2401
 
                                           3
2402
 
 
2403
 
                                3   2   1   0
2404
 
                           0|---*---*---|3
2405
 
                                |                 /
2406
 
                  1     1*              *2
2407
 
                                |         /
2408
 
                           2*   *1         2
2409
 
                                |  /
2410
 
                           3|/
2411
 
                                 0
2412
 
 
2413
 
        we will fill a 2 dim array of editvert*s to make filling easier
2414
 
 
2415
 
                                                3
2416
 
 
2417
 
                         0  0---1---2---3---4
2418
 
                                | / | /  |/  | /
2419
 
                         1  0---1----2---3
2420
 
           1            | /  | / | /
2421
 
                         2  0----1---2   2
2422
 
                                |  / |  /
2423
 
                                |/   |/
2424
 
                         3  0---1
2425
 
                                |  /
2426
 
                                |/
2427
 
                         4  0
2428
 
 
2429
 
        */
2430
 
 
2431
 
        innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array");
2432
 
        for(i=0;i<numcuts+2;i++) {
2433
 
                  innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array");
2434
 
        }
2435
 
        //top row is e3 backwards
2436
 
        for(i=0;i<numcuts+2;i++) {
2437
 
                  innerverts[0][i]                = verts[2][(numcuts+1)-i];
2438
 
        }
2439
 
 
2440
 
        for(i=1;i<=numcuts+1;i++) {
2441
 
                //fake edge, first vert is from e1, last is from e2
2442
 
                temp.v1= innerverts[i][0]                         = verts[0][i];
2443
 
                temp.v2= innerverts[i][(numcuts+1)-i]  = verts[1][(numcuts+1)-i];
2444
 
 
2445
 
                for(j=1;j<(numcuts+1)-i;j++) {
2446
 
                        float percent= (float)j/(float)((numcuts+1)-i);
2447
 
 
2448
 
                        innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent);
2449
 
                }
2450
 
        }
2451
 
 
2452
 
        // Now fill the verts with happy little tris :)
2453
 
        for(i=0;i<=numcuts+1;i++) {
2454
 
                for(j=0;j<(numcuts+1)-i;j++) {
2455
 
                        //We always do the first tri
2456
 
                        hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
2457
 
                        hold->e1->f2 |= EDGENEW;
2458
 
                        hold->e2->f2 |= EDGENEW;
2459
 
                        hold->e3->f2 |= EDGENEW;
2460
 
                        if(i != 0) { hold->e1->f2 |= EDGEINNER; }
2461
 
                        if(j != 0) { hold->e2->f2 |= EDGEINNER; }
2462
 
                        if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;}
2463
 
 
2464
 
                        facecopy(em, efa,hold);
2465
 
                        //if there are more to come, we do the 2nd
2466
 
                        if(j+1 <= numcuts-i) {
2467
 
                                hold = addfacelist(em, innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
2468
 
                                facecopy(em, efa,hold);
2469
 
                                hold->e1->f2 |= EDGENEW;
2470
 
                                hold->e2->f2 |= EDGENEW;
2471
 
                                hold->e3->f2 |= EDGENEW;
2472
 
                        }
2473
 
                }
2474
 
        }
2475
 
 
2476
 
        // Clean up our dynamic multi-dim array
2477
 
        for(i=0;i<numcuts+2;i++) {
2478
 
                MEM_freeN(innerverts[i]);
2479
 
        }
2480
 
        MEM_freeN(innerverts);
2481
 
}
2482
 
 
2483
 
//Next two fill types are for knife exact only and are provided to allow for knifing through vertices
2484
 
//This means there is no multicut!
2485
 
static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2)
2486
 
{
2487
 
        EditFace *hold;
2488
 
        /*
2489
 
                Depending on which two vertices have been knifed through (v1 and v2), we
2490
 
                triangulate like the patterns below.
2491
 
                                X-------|       |-------X
2492
 
                                | \     |       |     / |
2493
 
                                |   \   |       |   /   |
2494
 
                                |         \     |       | /         |
2495
 
                                --------X       X--------
2496
 
        */
2497
 
 
2498
 
        if(v1 == 1 && v2 == 3){
2499
 
                hold= addfacelist(em, efa->v1, efa->v2, efa->v3, 0, efa, NULL);
2500
 
                hold->e1->f2 |= EDGENEW;
2501
 
                hold->e2->f2 |= EDGENEW;
2502
 
                hold->e3->f2 |= EDGENEW;
2503
 
                hold->e3->f2 |= EDGEINNER;
2504
 
                facecopy(em, efa, hold);
2505
 
 
2506
 
                hold= addfacelist(em, efa->v1, efa->v3, efa->v4, 0, efa, NULL);
2507
 
                hold->e1->f2 |= EDGENEW;
2508
 
                hold->e2->f2 |= EDGENEW;
2509
 
                hold->e3->f2 |= EDGENEW;
2510
 
                hold->e1->f2 |= EDGEINNER;
2511
 
                facecopy(em, efa, hold);
2512
 
        }
2513
 
        else{
2514
 
                hold= addfacelist(em, efa->v1, efa->v2, efa->v4, 0, efa, NULL);
2515
 
                hold->e1->f2 |= EDGENEW;
2516
 
                hold->e2->f2 |= EDGENEW;
2517
 
                hold->e3->f2 |= EDGENEW;
2518
 
                hold->e2->f2 |= EDGEINNER;
2519
 
                facecopy(em, efa, hold);
2520
 
 
2521
 
                hold= addfacelist(em, efa->v2, efa->v3, efa->v4, 0, efa, NULL);
2522
 
                hold->e1->f2 |= EDGENEW;
2523
 
                hold->e2->f2 |= EDGENEW;
2524
 
                hold->e3->f2 |= EDGENEW;
2525
 
                hold->e3->f2 |= EDGEINNER;
2526
 
                facecopy(em, efa, hold);
2527
 
        }
2528
 
}
2529
 
 
2530
 
static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
2531
 
{
2532
 
        EditEdge *cedge=NULL;
2533
 
        EditVert *v[4], **verts;
2534
 
        EditFace *hold;
2535
 
        short start=0, end, left, right /* , vertsize */ /* UNUSED */;
2536
 
 
2537
 
        v[0] = efa->v1;
2538
 
        v[1] = efa->v2;
2539
 
        v[2] = efa->v3;
2540
 
        v[3] = efa->v4;
2541
 
 
2542
 
        if(efa->e1->f & SELECT)   { cedge = efa->e1; start = 0;}
2543
 
        else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
2544
 
        else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
2545
 
        else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
2546
 
 
2547
 
        // Point verts to the array of new verts for cedge
2548
 
        verts = BLI_ghash_lookup(gh, cedge);
2549
 
        //This is the index size of the verts array
2550
 
        /* vertsize = 3; */ /* UNUSED */
2551
 
 
2552
 
        // Is the original v1 the same as the first vert on the selected edge?
2553
 
        // if not, the edge is running the opposite direction in this face so flip
2554
 
        // the array to the correct direction
2555
 
 
2556
 
        if(verts[0] != v[start]) {flipvertarray(verts,3);}
2557
 
        end     = (start+1)%4;
2558
 
        left   = (start+2)%4;
2559
 
        right  = (start+3)%4;
2560
 
 
2561
 
/*
2562
 
        We should have something like this now
2563
 
 
2564
 
                          end            start
2565
 
                           2     1     0
2566
 
                           |-----*-----|
2567
 
                           |               |
2568
 
                           |               |
2569
 
                           |               |
2570
 
                           -------------
2571
 
                          left     right
2572
 
 
2573
 
        where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
2574
 
        and 0,1,2 are the indexes of the new verts stored in verts. We fill like
2575
 
        this, depending on whether its vertex 'left' or vertex 'right' thats
2576
 
        been knifed through...
2577
 
 
2578
 
                                |---*---|       |---*---|
2579
 
                                |  /    |       |    \  |
2580
 
                                | /             |       |         \ |
2581
 
                                |/              |       |          \|
2582
 
                                X--------       --------X
2583
 
*/
2584
 
 
2585
 
        if(v[left]->f1){
2586
 
                //triangle is composed of cutvert, end and left
2587
 
                hold = addfacelist(em, verts[1],v[end],v[left],NULL, NULL,NULL);
2588
 
                hold->e1->f2 |= EDGENEW;
2589
 
                hold->e2->f2 |= EDGENEW;
2590
 
                hold->e3->f2 |= EDGENEW;
2591
 
                hold->e3->f2 |= EDGEINNER;
2592
 
                facecopy(em, efa, hold);
2593
 
 
2594
 
                //quad is composed of cutvert, left, right and start
2595
 
                hold = addfacelist(em, verts[1],v[left],v[right],v[start], NULL, NULL);
2596
 
                hold->e1->f2 |= EDGENEW;
2597
 
                hold->e2->f2 |= EDGENEW;
2598
 
                hold->e3->f2 |= EDGENEW;
2599
 
                hold->e4->f2 |= EDGENEW;
2600
 
                hold->e1->f2 |= EDGEINNER;
2601
 
                facecopy(em, efa, hold);
2602
 
        }
2603
 
        else if(v[right]->f1){
2604
 
                //triangle is composed of cutvert, right and start
2605
 
                hold = addfacelist(em, verts[1],v[right],v[start], NULL, NULL, NULL);
2606
 
                hold->e1->f2 |= EDGENEW;
2607
 
                hold->e2->f2 |= EDGENEW;
2608
 
                hold->e3->f2 |= EDGENEW;
2609
 
                hold->e1->f2 |= EDGEINNER;
2610
 
                facecopy(em, efa, hold);
2611
 
                //quad is composed of cutvert, end, left, right
2612
 
                hold = addfacelist(em, verts[1],v[end], v[left], v[right], NULL, NULL);
2613
 
                hold->e1->f2 |= EDGENEW;
2614
 
                hold->e2->f2 |= EDGENEW;
2615
 
                hold->e3->f2 |= EDGENEW;
2616
 
                hold->e4->f2 |= EDGENEW;
2617
 
                hold->e4->f2 |= EDGEINNER;
2618
 
                facecopy(em, efa, hold);
2619
 
        }
2620
 
 
2621
 
}
2622
 
 
2623
 
// This function takes an example edge, the current point to create and
2624
 
// the total # of points to create, then creates the point and return the
2625
 
// editvert pointer to it.
2626
 
static EditVert *subdivideedgenum(EditMesh *em, EditEdge *edge, int curpoint, int totpoint, float smooth, float fractal, int beauty)
2627
 
{
2628
 
        EditVert *ev;
2629
 
        float percent;
2630
 
 
2631
 
        if (beauty & (B_PERCENTSUBD) && totpoint == 1)
2632
 
                //percent=(float)(edge->tmp.l)/32768.0f;
2633
 
                percent= edge->tmp.fp;
2634
 
        else
2635
 
                percent= (float)curpoint/(float)(totpoint+1);
2636
 
 
2637
 
        ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent);
2638
 
        ev->f = edge->v1->f;
2639
 
 
2640
 
        return ev;
2641
 
}
2642
 
 
2643
 
void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype)
2644
 
{
2645
 
        EditFace *ef;
2646
 
        EditEdge *eed, *cedge, *sort[4];
2647
 
        EditVert *eve, **templist;
2648
 
        struct GHash *gh;
2649
 
        float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3];
2650
 
        int i, j, edgecount, touchcount, facetype,hold;
2651
 
        ModifierData *md= obedit->modifiers.first;
2652
 
        int ctrl= 0; // XXX
2653
 
 
2654
 
        //Set faces f1 to 0 cause we need it later
2655
 
        for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
2656
 
        for(eve=em->verts.first; eve; eve=eve->next) {
2657
 
                if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */
2658
 
                        eve->f1 = 0;
2659
 
                eve->f2 = 0;
2660
 
        }
2661
 
 
2662
 
        for (; md; md=md->next) {
2663
 
                if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
2664
 
                        MirrorModifierData *mmd = (MirrorModifierData*) md;
2665
 
 
2666
 
                        if(mmd->flag & MOD_MIR_CLIPPING) {
2667
 
                                for (eve= em->verts.first; eve; eve= eve->next) {
2668
 
                                        eve->f2= 0;
2669
 
 
2670
 
                                        if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1;
2671
 
                                        if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2;
2672
 
                                        if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4;
2673
 
 
2674
 
                                }
2675
 
                        }
2676
 
                }
2677
 
        }
2678
 
 
2679
 
        //Flush vertex flags upward to the edges
2680
 
        for(eed = em->edges.first;eed;eed = eed->next) {
2681
 
                //if(eed->f & flag && eed->v1->f == eed->v2->f) {
2682
 
                //      eed->f |= eed->v1->f;
2683
 
                // }
2684
 
                eed->f2 = 0;
2685
 
                if(eed->f & flag) {
2686
 
                        eed->f2 |= EDGEOLD;
2687
 
                }
2688
 
        }
2689
 
 
2690
 
        // We store an array of verts for each edge that is subdivided,
2691
 
        // we put this array as a value in a ghash which is keyed by the EditEdge*
2692
 
 
2693
 
        // Now for beauty subdivide deselect edges based on length
2694
 
        if(beauty & B_BEAUTY) {
2695
 
                for(ef = em->faces.first;ef;ef = ef->next) {
2696
 
                        if(!ef->v4) {
2697
 
                                continue;
2698
 
                        }
2699
 
                        if(ef->f & SELECT) {
2700
 
                                VECCOPY(v1mat, ef->v1->co);
2701
 
                                VECCOPY(v2mat, ef->v2->co);
2702
 
                                VECCOPY(v3mat, ef->v3->co);
2703
 
                                VECCOPY(v4mat, ef->v4->co);
2704
 
                                mul_mat3_m4_v3(obedit->obmat, v1mat);
2705
 
                                mul_mat3_m4_v3(obedit->obmat, v2mat);
2706
 
                                mul_mat3_m4_v3(obedit->obmat, v3mat);
2707
 
                                mul_mat3_m4_v3(obedit->obmat, v4mat);
2708
 
 
2709
 
                                length[0] = len_v3v3(v1mat, v2mat);
2710
 
                                length[1] = len_v3v3(v2mat, v3mat);
2711
 
                                length[2] = len_v3v3(v3mat, v4mat);
2712
 
                                length[3] = len_v3v3(v4mat, v1mat);
2713
 
                                sort[0] = ef->e1;
2714
 
                                sort[1] = ef->e2;
2715
 
                                sort[2] = ef->e3;
2716
 
                                sort[3] = ef->e4;
2717
 
 
2718
 
 
2719
 
                                // Beauty Short Edges
2720
 
                                if(beauty & B_BEAUTY_SHORT) {
2721
 
                                        for(j=0;j<2;j++) {
2722
 
                                                hold = -1;
2723
 
                                                for(i=0;i<4;i++) {
2724
 
                                                        if(length[i] < 0) {
2725
 
                                                                continue;
2726
 
                                                        } else if(hold == -1) {
2727
 
                                                                hold = i;
2728
 
                                                        } else {
2729
 
                                                                if(length[hold] < length[i]) {
2730
 
                                                                        hold = i;
2731
 
                                                                }
2732
 
                                                        }
2733
 
                                                }
2734
 
                                                if (hold > -1) {
2735
 
                                                        sort[hold]->f &= ~SELECT;
2736
 
                                                        sort[hold]->f2 |= EDGENEW;
2737
 
                                                        length[hold] = -1;
2738
 
                                                }
2739
 
                                        }
2740
 
                                }
2741
 
 
2742
 
                                // Beauty Long Edges
2743
 
                                else {
2744
 
                                        for(j=0;j<2;j++) {
2745
 
                                                hold = -1;
2746
 
                                                for(i=0;i<4;i++) {
2747
 
                                                        if(length[i] < 0) {
2748
 
                                                                continue;
2749
 
                                                        } else if(hold == -1) {
2750
 
                                                                hold = i;
2751
 
                                                        } else {
2752
 
                                                                if(length[hold] > length[i]) {
2753
 
                                                                        hold = i;
2754
 
                                                                }
2755
 
                                                        }
2756
 
                                                }
2757
 
                                                if (hold > -1) {
2758
 
                                                        sort[hold]->f &= ~SELECT;
2759
 
                                                        sort[hold]->f2 |= EDGENEW;
2760
 
                                                        length[hold] = -1;
2761
 
                                                }
2762
 
                                        }
2763
 
                                }
2764
 
                        }
2765
 
                }
2766
 
        }
2767
 
 
2768
 
        gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh");
2769
 
 
2770
 
        // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut
2771
 
        if(beauty & B_KNIFE) {
2772
 
                for(eed= em->edges.first;eed;eed=eed->next) {
2773
 
                        if( eed->tmp.fp == 0 ) {
2774
 
                                EM_select_edge(eed,0);
2775
 
                        }
2776
 
                }
2777
 
        }
2778
 
        // So for each edge, if it is selected, we allocate an array of size cuts+2
2779
 
        // so we can have a place for the v1, the new verts and v2
2780
 
        for(eed=em->edges.first;eed;eed = eed->next) {
2781
 
                if(eed->f & flag) {
2782
 
                        templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist");
2783
 
                        templist[0] = eed->v1;
2784
 
                        for(i=0;i<numcuts;i++) {
2785
 
                                // This function creates the new vert and returns it back
2786
 
                                // to the array
2787
 
                                templist[i+1] = subdivideedgenum(em, eed, i+1, numcuts, smooth, fractal, beauty);
2788
 
                                //while we are here, we can copy edge info from the original edge
2789
 
                                cedge = addedgelist(em, templist[i],templist[i+1],eed);
2790
 
                                // Also set the edge f2 to EDGENEW so that we can use this info later
2791
 
                                cedge->f2 = EDGENEW;
2792
 
                        }
2793
 
                        templist[i+1] = eed->v2;
2794
 
                        //Do the last edge too
2795
 
                        cedge = addedgelist(em, templist[i],templist[i+1],eed);
2796
 
                        cedge->f2 = EDGENEW;
2797
 
                        // Now that the edge is subdivided, we can put its verts in the ghash
2798
 
                        BLI_ghash_insert(gh, eed, templist);
2799
 
                }
2800
 
        }
2801
 
 
2802
 
//      DAG_id_tag_update(obedit->data, 0);
2803
 
        // Now for each face in the mesh we need to figure out How many edges were cut
2804
 
        // and which filling method to use for that face
2805
 
        for(ef = em->faces.first;ef;ef = ef->next) {
2806
 
                edgecount = 0;
2807
 
                facetype = 3;
2808
 
                if(ef->e1->f & flag) {edgecount++;}
2809
 
                if(ef->e2->f & flag) {edgecount++;}
2810
 
                if(ef->e3->f & flag) {edgecount++;}
2811
 
                if(ef->v4) {
2812
 
                        facetype = 4;
2813
 
                        if(ef->e4->f & flag) {edgecount++;}
2814
 
                }
2815
 
                if(facetype == 4) {
2816
 
                        switch(edgecount) {
2817
 
                                case 0:
2818
 
                                        if(beauty & B_KNIFE && numcuts == 1){
2819
 
                                                /*Test for when knifing through two opposite verts but no edges*/
2820
 
                                                touchcount = 0;
2821
 
                                                if(ef->v1->f1) touchcount++;
2822
 
                                                if(ef->v2->f1) touchcount++;
2823
 
                                                if(ef->v3->f1) touchcount++;
2824
 
                                                if(ef->v4->f1) touchcount++;
2825
 
                                                if(touchcount == 2){
2826
 
                                                        if(ef->v1->f1 && ef->v3->f1){
2827
 
                                                                ef->f1 = SELECT;
2828
 
                                                                fill_quad_doublevert(em, ef, 1, 3);
2829
 
                                                        }
2830
 
                                                        else if(ef->v2->f1 && ef->v4->f1){
2831
 
                                                                ef->f1 = SELECT;
2832
 
                                                                fill_quad_doublevert(em, ef, 2, 4);
2833
 
                                                        }
2834
 
                                                }
2835
 
                                        }
2836
 
                                        break;
2837
 
 
2838
 
                                case 1:
2839
 
                                        if(beauty & B_KNIFE && numcuts == 1){
2840
 
                                                /*Test for when knifing through an edge and one vert*/
2841
 
                                                touchcount = 0;
2842
 
                                                if(ef->v1->f1) touchcount++;
2843
 
                                                if(ef->v2->f1) touchcount++;
2844
 
                                                if(ef->v3->f1) touchcount++;
2845
 
                                                if(ef->v4->f1) touchcount++;
2846
 
 
2847
 
                                                if(touchcount == 1){
2848
 
                                                        if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) ||
2849
 
                                                                (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) ||
2850
 
                                                                (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) ||
2851
 
                                                                (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){
2852
 
 
2853
 
                                                                ef->f1 = SELECT;
2854
 
                                                                fill_quad_singlevert(em, ef, gh);
2855
 
                                                        }
2856
 
                                                        else{
2857
 
                                                                ef->f1 = SELECT;
2858
 
                                                                fill_quad_single(em, ef, gh, numcuts, seltype);
2859
 
                                                        }
2860
 
                                                }
2861
 
                                                else{
2862
 
                                                        ef->f1 = SELECT;
2863
 
                                                        fill_quad_single(em, ef, gh, numcuts, seltype);
2864
 
                                                }
2865
 
                                        }
2866
 
                                        else{
2867
 
                                                ef->f1 = SELECT;
2868
 
                                                fill_quad_single(em, ef, gh, numcuts, seltype);
2869
 
                                        }
2870
 
                                        break;
2871
 
                                case 2: ef->f1 = SELECT;
2872
 
                                        // if there are 2, we check if edge 1 and 3 are either both on or off that way
2873
 
                                        // we can tell if the selected pair is Adjacent or Opposite of each other
2874
 
                                        if((ef->e1->f & flag && ef->e3->f & flag) ||
2875
 
                                           (ef->e2->f & flag && ef->e4->f & flag)) {
2876
 
                                                fill_quad_double_op(em, ef, gh, numcuts);
2877
 
                                        }else{
2878
 
                                                switch(corner_pattern) {
2879
 
                                                        case 0: fill_quad_double_adj_path(em, ef, gh, numcuts); break;
2880
 
                                                        case 1: fill_quad_double_adj_inner(em, ef, gh, numcuts); break;
2881
 
                                                        case 2: fill_quad_double_adj_fan(em, ef, gh, numcuts); break;
2882
 
                                                }
2883
 
 
2884
 
                                        }
2885
 
                                                break;
2886
 
                                case 3: ef->f1 = SELECT;
2887
 
                                        fill_quad_triple(em, ef, gh, numcuts);
2888
 
                                        break;
2889
 
                                case 4: ef->f1 = SELECT;
2890
 
                                        fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty);
2891
 
                                        break;
2892
 
                        }
2893
 
                } else {
2894
 
                        switch(edgecount) {
2895
 
                                case 0: break;
2896
 
                                case 1: ef->f1 = SELECT;
2897
 
                                        fill_tri_single(em, ef, gh, numcuts, seltype);
2898
 
                                        break;
2899
 
                                case 2: ef->f1 = SELECT;
2900
 
                                        fill_tri_double(em, ef, gh, numcuts);
2901
 
                                        break;
2902
 
                                case 3: ef->f1 = SELECT;
2903
 
                                        fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty);
2904
 
                                        break;
2905
 
                        }
2906
 
                }
2907
 
        }
2908
 
 
2909
 
        // Delete Old Edges and Faces
2910
 
        for(eed = em->edges.first;eed;eed = eed->next) {
2911
 
                if(BLI_ghash_haskey(gh,eed)) {
2912
 
                        eed->f1 = SELECT;
2913
 
                } else {
2914
 
                        eed->f1 = 0;
2915
 
                }
2916
 
        }
2917
 
        free_tagged_edges_faces(em, em->edges.first, em->faces.first);
2918
 
 
2919
 
        if(seltype == SUBDIV_SELECT_ORIG  && !ctrl) {
2920
 
                /* bugfix: vertex could get flagged as "not-selected"
2921
 
                // solution: clear flags before, not at the same time as setting SELECT flag -dg
2922
 
                */
2923
 
                for(eed = em->edges.first;eed;eed = eed->next) {
2924
 
                        if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) {
2925
 
                                eed->f &= !flag;
2926
 
                                EM_select_edge(eed,0);
2927
 
                        }
2928
 
                }
2929
 
                for(eed = em->edges.first;eed;eed = eed->next) {
2930
 
                        if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) {
2931
 
                                eed->f |= flag;
2932
 
                                EM_select_edge(eed,1);
2933
 
                        }
2934
 
                }
2935
 
        } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) {
2936
 
                for(eed = em->edges.first;eed;eed = eed->next) {
2937
 
                        if(eed->f2 & EDGEINNER) {
2938
 
                                eed->f |= flag;
2939
 
                                EM_select_edge(eed,1);
2940
 
                                if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT;
2941
 
                                if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT;
2942
 
                        }else{
2943
 
                                eed->f &= !flag;
2944
 
                                EM_select_edge(eed,0);
2945
 
                        }
2946
 
                }
2947
 
        } else if(seltype == SUBDIV_SELECT_LOOPCUT){
2948
 
                for(eed = em->edges.first;eed;eed = eed->next) {
2949
 
                        if(eed->f2 & DOUBLEOPFILL){
2950
 
                                eed->f |= flag;
2951
 
                                EM_select_edge(eed,1);
2952
 
                        }else{
2953
 
                                eed->f &= !flag;
2954
 
                                EM_select_edge(eed,0);
2955
 
                        }
2956
 
                }
2957
 
        }
2958
 
        if(em->selectmode & SCE_SELECT_VERTEX) {
2959
 
                for(eed = em->edges.first;eed;eed = eed->next) {
2960
 
                        if(eed->f & SELECT) {
2961
 
                                eed->v1->f |= SELECT;
2962
 
                                eed->v2->f |= SELECT;
2963
 
                        }
2964
 
                }
2965
 
        }
2966
 
 
2967
 
        //fix hide flags for edges. First pass, hide edges of hidden faces
2968
 
        for(ef=em->faces.first; ef; ef=ef->next){
2969
 
                if(ef->h){
2970
 
                        ef->e1->h |= 1;
2971
 
                        ef->e2->h |= 1;
2972
 
                        ef->e3->h |= 1;
2973
 
                        if(ef->e4) ef->e4->h |= 1;
2974
 
                }
2975
 
        }
2976
 
        //second pass: unhide edges of visible faces adjacent to hidden faces
2977
 
        for(ef=em->faces.first; ef; ef=ef->next){
2978
 
                if(ef->h == 0){
2979
 
                        ef->e1->h &= ~1;
2980
 
                        ef->e2->h &= ~1;
2981
 
                        ef->e3->h &= ~1;
2982
 
                        if(ef->e4) ef->e4->h &= ~1;
2983
 
                }
2984
 
        }
2985
 
 
2986
 
        //third pass: unhide edges that have both verts visible
2987
 
        //(these were missed if all faces were hidden, bug #21976)
2988
 
        for(eed=em->edges.first; eed; eed=eed->next){
2989
 
                if(eed->v1->h == 0 && eed->v2->h == 0)
2990
 
                        eed->h &= ~1;
2991
 
        }
2992
 
 
2993
 
        // Free the ghash and call MEM_freeN on all the value entries to return
2994
 
        // that memory
2995
 
        BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
2996
 
 
2997
 
        EM_selectmode_flush(em);
2998
 
        for(ef=em->faces.first;ef;ef = ef->next) {
2999
 
                if(ef->e4) {
3000
 
                        if(  (ef->e1->f & SELECT && ef->e2->f & SELECT) &&
3001
 
                         (ef->e3->f & SELECT && ef->e4->f & SELECT) ) {
3002
 
                                ef->f |= SELECT;
3003
 
                        }
3004
 
                } else {
3005
 
                        if(  (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
3006
 
                                ef->f |= SELECT;
3007
 
                        }
3008
 
                }
3009
 
        }
3010
 
 
3011
 
        recalc_editnormals(em);
3012
 
}
3013
 
 
3014
 
static int count_selected_edges(EditEdge *ed)
3015
 
{
3016
 
        int totedge = 0;
3017
 
        while(ed) {
3018
 
                ed->tmp.p = 0;
3019
 
                if( ed->f & SELECT ) totedge++;
3020
 
                ed= ed->next;
3021
 
        }
3022
 
        return totedge;
3023
 
}
3024
 
 
3025
 
/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */
3026
 
typedef EditFace *EVPtr;
3027
 
typedef EVPtr EVPTuple[2];
3028
 
 
3029
 
/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces)
3030
 
        sharing one edge.
3031
 
        arguments: selected edge list, face list.
3032
 
        Edges will also be tagged accordingly (see eed->f2)               */
3033
 
 
3034
 
static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
3035
 
{
3036
 
        EditEdge *e1, *e2, *e3;
3037
 
        EVPtr *evp;
3038
 
        int i = 0;
3039
 
 
3040
 
        /* run through edges, if selected, set pointer edge-> facearray */
3041
 
        while(eed) {
3042
 
                eed->f2= 0;
3043
 
                eed->f1= 0;
3044
 
                if( eed->f & SELECT ) {
3045
 
                        eed->tmp.p = (EditVert *) (&efaa[i]);
3046
 
                        i++;
3047
 
                }
3048
 
                else eed->tmp.p = NULL;
3049
 
 
3050
 
                eed= eed->next;
3051
 
        }
3052
 
 
3053
 
 
3054
 
        /* find edges pointing to 2 faces by procedure:
3055
 
 
3056
 
        - run through faces and their edges, increase
3057
 
          face counter e->f1 for each face
3058
 
        */
3059
 
 
3060
 
        while(efa) {
3061
 
                efa->f1= 0;
3062
 
                if(efa->v4==0 && (efa->f & SELECT)) {  /* if selected triangle */
3063
 
                        e1= efa->e1;
3064
 
                        e2= efa->e2;
3065
 
                        e3= efa->e3;
3066
 
                        if(e1->f2<3 && e1->tmp.p) {
3067
 
                                if(e1->f2<2) {
3068
 
                                        evp= (EVPtr *) e1->tmp.p;
3069
 
                                        evp[(int)e1->f2] = efa;
3070
 
                                }
3071
 
                                e1->f2+= 1;
3072
 
                        }
3073
 
                        if(e2->f2<3 && e2->tmp.p) {
3074
 
                                if(e2->f2<2) {
3075
 
                                        evp= (EVPtr *) e2->tmp.p;
3076
 
                                        evp[(int)e2->f2]= efa;
3077
 
                                }
3078
 
                                e2->f2+= 1;
3079
 
                        }
3080
 
                        if(e3->f2<3 && e3->tmp.p) {
3081
 
                                if(e3->f2<2) {
3082
 
                                        evp= (EVPtr *) e3->tmp.p;
3083
 
                                        evp[(int)e3->f2]= efa;
3084
 
                                }
3085
 
                                e3->f2+= 1;
3086
 
                        }
3087
 
                }
3088
 
                else {
3089
 
                        /* set to 3 to make sure these are not flipped or joined */
3090
 
                        efa->e1->f2= 3;
3091
 
                        efa->e2->f2= 3;
3092
 
                        efa->e3->f2= 3;
3093
 
                        if (efa->e4) efa->e4->f2= 3;
3094
 
                }
3095
 
 
3096
 
                efa= efa->next;
3097
 
        }
3098
 
        return i;
3099
 
}
3100
 
 
3101
 
 
3102
 
/* returns vertices of two adjacent triangles forming a quad
3103
 
   - can be righthand or lefthand
3104
 
 
3105
 
                        4-----3
3106
 
                        |\      |
3107
 
                        | \ 2 | <- efa1
3108
 
                        |  \  |
3109
 
          efa-> | 1 \ |
3110
 
                        |       \|
3111
 
                        1-----2
3112
 
 
3113
 
*/
3114
 
#define VTEST(face, num, other) \
3115
 
        (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
3116
 
 
3117
 
static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex)
3118
 
{
3119
 
        if VTEST(efa, 1, efa1) {
3120
 
                *v1= efa->v1;
3121
 
                *v2= efa->v2;
3122
 
                vindex[0]= 0;
3123
 
                vindex[1]= 1;
3124
 
        }
3125
 
        else if VTEST(efa, 2, efa1) {
3126
 
                *v1= efa->v2;
3127
 
                *v2= efa->v3;
3128
 
                vindex[0]= 1;
3129
 
                vindex[1]= 2;
3130
 
        }
3131
 
        else if VTEST(efa, 3, efa1) {
3132
 
                *v1= efa->v3;
3133
 
                *v2= efa->v1;
3134
 
                vindex[0]= 2;
3135
 
                vindex[1]= 0;
3136
 
        }
3137
 
 
3138
 
        if VTEST(efa1, 1, efa) {
3139
 
                *v3= efa1->v1;
3140
 
                *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
3141
 
                vindex[2]= 0;
3142
 
                vindex[3]= (efa1->v2 == *v2)? 2: 1;
3143
 
        }
3144
 
        else if VTEST(efa1, 2, efa) {
3145
 
                *v3= efa1->v2;
3146
 
                *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
3147
 
                vindex[2]= 1;
3148
 
                vindex[3]= (efa1->v3 == *v2)? 0: 2;
3149
 
        }
3150
 
        else if VTEST(efa1, 3, efa) {
3151
 
                *v3= efa1->v3;
3152
 
                *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
3153
 
                vindex[2]= 2;
3154
 
                vindex[3]= (efa1->v1 == *v2)? 1: 0;
3155
 
        }
3156
 
        else
3157
 
                *v3= *v4= NULL;
3158
 
}
3159
 
 
3160
 
/* Helper functions for edge/quad edit features*/
3161
 
static void untag_edges(EditFace *f)
3162
 
{
3163
 
        f->e1->f1 = 0;
3164
 
        f->e2->f1 = 0;
3165
 
        f->e3->f1 = 0;
3166
 
        if (f->e4) f->e4->f1 = 0;
3167
 
}
3168
 
 
3169
 
/** remove and free list of tagged edges and faces */
3170
 
static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
3171
 
{
3172
 
        EditEdge *nexted;
3173
 
        EditFace *nextvl;
3174
 
 
3175
 
        while(efa) {
3176
 
                nextvl= efa->next;
3177
 
                if(efa->f1) {
3178
 
                        BLI_remlink(&em->faces, efa);
3179
 
                        free_editface(em, efa);
3180
 
                }
3181
 
                else
3182
 
                        /* avoid deleting edges that are still in use */
3183
 
                        untag_edges(efa);
3184
 
                efa= nextvl;
3185
 
        }
3186
 
 
3187
 
        while(eed) {
3188
 
                nexted= eed->next;
3189
 
                if(eed->f1) {
3190
 
                        remedge(em, eed);
3191
 
                        free_editedge(em, eed);
3192
 
                }
3193
 
                eed= nexted;
3194
 
        }
3195
 
}
3196
 
 
3197
 
 
3198
 
/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
3199
 
static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit)
3200
 
{
3201
 
 
3202
 
        /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
3203
 
        /*Note: this is more complicated than it needs to be and should be cleaned up...*/
3204
 
        float   measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff,
3205
 
                        edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff,
3206
 
                        minarea, maxarea, areaA, areaB;
3207
 
 
3208
 
        /*First Test: Normal difference*/
3209
 
        normal_tri_v3( noA1,v1->co, v2->co, v3->co);
3210
 
        normal_tri_v3( noA2,v1->co, v3->co, v4->co);
3211
 
 
3212
 
        if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
3213
 
        else normalADiff = RAD2DEGF(angle_v3v3(noA1, noA2));
3214
 
                //if(!normalADiff) normalADiff = 179;
3215
 
        normal_tri_v3( noB1,v2->co, v3->co, v4->co);
3216
 
        normal_tri_v3( noB2,v4->co, v1->co, v2->co);
3217
 
 
3218
 
        if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
3219
 
        else normalBDiff = RAD2DEGF(angle_v3v3(noB1, noB2));
3220
 
                //if(!normalBDiff) normalBDiff = 179;
3221
 
 
3222
 
        measure += (normalADiff/360) + (normalBDiff/360);
3223
 
        if(measure > limit) return measure;
3224
 
 
3225
 
        /*Second test: Colinearity*/
3226
 
        sub_v3_v3v3(edgeVec1, v1->co, v2->co);
3227
 
        sub_v3_v3v3(edgeVec2, v2->co, v3->co);
3228
 
        sub_v3_v3v3(edgeVec3, v3->co, v4->co);
3229
 
        sub_v3_v3v3(edgeVec4, v4->co, v1->co);
3230
 
 
3231
 
        diff = 0.0;
3232
 
 
3233
 
        diff = (
3234
 
                fabsf(RAD2DEGF(angle_v3v3(edgeVec1, edgeVec2)) - 90) +
3235
 
                fabsf(RAD2DEGF(angle_v3v3(edgeVec2, edgeVec3)) - 90) +
3236
 
                fabsf(RAD2DEGF(angle_v3v3(edgeVec3, edgeVec4)) - 90) +
3237
 
                fabsf(RAD2DEGF(angle_v3v3(edgeVec4, edgeVec1)) - 90)) / 360;
3238
 
        if(!diff) return 0.0;
3239
 
 
3240
 
        measure +=  diff;
3241
 
        if(measure > limit) return measure;
3242
 
 
3243
 
        /*Third test: Concavity*/
3244
 
        areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co);
3245
 
        areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co);
3246
 
 
3247
 
        if(areaA <= areaB) minarea = areaA;
3248
 
        else minarea = areaB;
3249
 
 
3250
 
        if(areaA >= areaB) maxarea = areaA;
3251
 
        else maxarea = areaB;
3252
 
 
3253
 
        if(!maxarea) measure += 1;
3254
 
        else measure += (1 - (minarea / maxarea));
3255
 
 
3256
 
        return measure;
3257
 
}
3258
 
 
3259
 
#define T2QUV_LIMIT 0.005f
3260
 
#define T2QCOL_LIMIT 3
3261
 
static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
3262
 
{
3263
 
        /*Test to see if the per-face attributes for the joining edge match within limit*/
3264
 
        MTFace *tf1, *tf2;
3265
 
        unsigned int *col1, *col2;
3266
 
        short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2];
3267
 
 
3268
 
        tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE);
3269
 
        tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE);
3270
 
 
3271
 
        col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL);
3272
 
        col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL);
3273
 
 
3274
 
        /*store indices for faceedges*/
3275
 
        f1->v1->f1 = 0;
3276
 
        f1->v2->f1 = 1;
3277
 
        f1->v3->f1 = 2;
3278
 
 
3279
 
        fe1[0] = eed->v1->f1;
3280
 
        fe1[1] = eed->v2->f1;
3281
 
 
3282
 
        f2->v1->f1 = 0;
3283
 
        f2->v2->f1 = 1;
3284
 
        f2->v3->f1 = 2;
3285
 
 
3286
 
        fe2[0] = eed->v1->f1;
3287
 
        fe2[1] = eed->v2->f1;
3288
 
 
3289
 
        /*compare faceedges for each face attribute. Additional per face attributes can be added later*/
3290
 
        /*do UVs*/
3291
 
        if(flag & B_JOINTRIA_UV){
3292
 
 
3293
 
                if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
3294
 
                else if(tf1->tpage != tf2->tpage); /*do nothing*/
3295
 
                else{
3296
 
                        for(i = 0; i < 2; i++){
3297
 
                                if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] &&
3298
 
                                        tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV;
3299
 
                        }
3300
 
                }
3301
 
        }
3302
 
 
3303
 
        /*do VCOLs*/
3304
 
        if(flag & B_JOINTRIA_VCOL){
3305
 
                if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
3306
 
                else{
3307
 
                        char *f1vcol, *f2vcol;
3308
 
                        for(i = 0; i < 2; i++){
3309
 
                                f1vcol = (char *)&(col1[fe1[i]]);
3310
 
                                f2vcol = (char *)&(col2[fe2[i]]);
3311
 
 
3312
 
                                /*compare f1vcol with f2vcol*/
3313
 
                                if(     f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] &&
3314
 
                                        f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] &&
3315
 
                                        f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL;
3316
 
                        }
3317
 
                }
3318
 
        }
3319
 
 
3320
 
        if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1;
3321
 
        return 0;
3322
 
}
3323
 
 
3324
 
static int fplcmp(const void *v1, const void *v2)
3325
 
{
3326
 
        const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
3327
 
 
3328
 
        if( e1->crease > e2->crease) return 1;
3329
 
        else if( e1->crease < e2->crease) return -1;
3330
 
 
3331
 
        return 0;
3332
 
}
3333
 
 
3334
 
/*Bitflags for edges.*/
3335
 
#define T2QDELETE       1
3336
 
#define T2QCOMPLEX      2
3337
 
#define T2QJOIN         4
3338
 
void join_triangles(EditMesh *em)
3339
 
{
3340
 
        EditVert *v1, *v2, *v3, *v4, *eve;
3341
 
        EditEdge *eed, **edsortblock = NULL, **edb = NULL;
3342
 
        EditFace *efa;
3343
 
        EVPTuple *efaar = NULL;
3344
 
        EVPtr *efaa = NULL;
3345
 
        float *creases = NULL;
3346
 
        float measure; /*Used to set tolerance*/
3347
 
        float limit = 0.8f; // XXX scene->toolsettings->jointrilimit;
3348
 
        int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
3349
 
 
3350
 
        /*if we take a long time on very dense meshes we want waitcursor to display*/
3351
 
        waitcursor(1);
3352
 
 
3353
 
        totseledge = count_selected_edges(em->edges.first);
3354
 
        if(totseledge==0) return;
3355
 
 
3356
 
        /*abusing crease value to store weights for edge pairs. Nasty*/
3357
 
        for(eed=em->edges.first; eed; eed=eed->next) totedge++;
3358
 
        if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
3359
 
        for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
3360
 
                creases[i] = eed->crease;
3361
 
                eed->crease = 0.0;
3362
 
        }
3363
 
 
3364
 
        /*clear temp flags*/
3365
 
        for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0;
3366
 
        for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0;
3367
 
        for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0;
3368
 
 
3369
 
        /*For every selected 2 manifold edge, create pointers to its two faces.*/
3370
 
        efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad");
3371
 
        ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
3372
 
        complexedges = 0;
3373
 
 
3374
 
        if(ok){
3375
 
 
3376
 
 
3377
 
                /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/
3378
 
                for(eed=em->edges.first; eed; eed=eed->next){
3379
 
                        /* eed->f2 is 2 only if this edge is part of exactly two
3380
 
                           triangles, and both are selected, and it has EVPTuple assigned */
3381
 
                        if(eed->f2 == 2){
3382
 
                                efaa= (EVPtr *) eed->tmp.p;
3383
 
                                efaa[0]->tmp.l++;
3384
 
                                efaa[1]->tmp.l++;
3385
 
                        }
3386
 
                }
3387
 
 
3388
 
                for(eed=em->edges.first; eed; eed=eed->next){
3389
 
                        if(eed->f2 == 2){
3390
 
                                efaa= (EVPtr *) eed->tmp.p;
3391
 
                                v1 = v2 = v3 = v4 = NULL;
3392
 
                                givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
3393
 
                                if(v1 && v2 && v3 && v4){
3394
 
                                        /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/
3395
 
                                        if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){
3396
 
                                                eed->f1 |= T2QJOIN;
3397
 
                                                efaa[0]->f1 = 1; //mark for join
3398
 
                                                efaa[1]->f1 = 1; //mark for join
3399
 
                                        }
3400
 
                                        else{
3401
 
 
3402
 
                                                /*      The face pair is part of a 'complex' island, so the rules for dealing with it are more involved.
3403
 
                                                        Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria:
3404
 
 
3405
 
                                                        1: the two faces do not share the same material
3406
 
                                                        2: the edge joining the two faces is marked as sharp.
3407
 
                                                        3: the two faces UV's do not make a good match
3408
 
                                                        4: the two faces Vertex colors do not make a good match
3409
 
 
3410
 
                                                        If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function.
3411
 
                                                        This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user
3412
 
                                                        the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the
3413
 
                                                        same faces in the current pair later.
3414
 
 
3415
 
                                                        This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of
3416
 
                                                        the python scripts bundled with Blender releases.
3417
 
                                                */
3418
 
 
3419
 
// XXX                                          if(scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
3420
 
//                                              else if(scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
3421
 
//                                              else if(((scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
3422
 
                                                compareFaceAttribs(em, efaa[0], efaa[1], eed); // XXX == 0); /*do nothing*/
3423
 
//                                              else{
3424
 
                                                        measure = measure_facepair(v1, v2, v3, v4, limit);
3425
 
                                                        if(measure < limit){
3426
 
                                                                complexedges++;
3427
 
                                                                eed->f1 |= T2QCOMPLEX;
3428
 
                                                                eed->crease = measure; /*we dont mark edges for join yet*/
3429
 
                                                        }
3430
 
//                                              }
3431
 
                                        }
3432
 
                                }
3433
 
                        }
3434
 
                }
3435
 
 
3436
 
                /*Quicksort the complex edges according to their weighting*/
3437
 
                if(complexedges){
3438
 
                        edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
3439
 
                        for(eed = em->edges.first; eed; eed=eed->next){
3440
 
                                if(eed->f1 & T2QCOMPLEX){
3441
 
                                        *edb = eed;
3442
 
                                        edb++;
3443
 
                                }
3444
 
                        }
3445
 
                        qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp);
3446
 
                        /*now go through and mark the edges who get the highest weighting*/
3447
 
                        for(edb=edsortblock, i=0; i < complexedges; edb++, i++){
3448
 
                                efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/
3449
 
                                if( !efaa[0]->f1 && !efaa[1]->f1){
3450
 
                                        efaa[0]->f1 = 1; //mark for join
3451
 
                                        efaa[1]->f1 = 1; //mark for join
3452
 
                                        (*edb)->f1 |= T2QJOIN;
3453
 
                                }
3454
 
                        }
3455
 
                }
3456
 
 
3457
 
                /*finally go through all edges marked for join (simple and complex) and create new faces*/
3458
 
                for(eed=em->edges.first; eed; eed=eed->next){
3459
 
                        if(eed->f1 & T2QJOIN){
3460
 
                                efaa= (EVPtr *)eed->tmp.p;
3461
 
                                v1 = v2 = v3 = v4 = NULL;
3462
 
                                givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
3463
 
                                if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/
3464
 
                                        /*flag for delete*/
3465
 
                                        eed->f1 |= T2QDELETE;
3466
 
                                        /*create new quad and select*/
3467
 
                                        efa = EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
3468
 
                                        EM_select_face(efa,1);
3469
 
                                }
3470
 
                                else{
3471
 
                                                efaa[0]->f1 = 0;
3472
 
                                                efaa[1]->f1 = 0;
3473
 
                                }
3474
 
                        }
3475
 
                }
3476
 
        }
3477
 
 
3478
 
        /*free data and cleanup*/
3479
 
        if(creases){
3480
 
                for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
3481
 
                MEM_freeN(creases);
3482
 
        }
3483
 
        for(eed=em->edges.first; eed; eed=eed->next){
3484
 
                if(eed->f1 & T2QDELETE) eed->f1 = 1;
3485
 
                else eed->f1 = 0;
3486
 
        }
3487
 
        free_tagged_edges_faces(em, em->edges.first, em->faces.first);
3488
 
        if(efaar) MEM_freeN(efaar);
3489
 
        if(edsortblock) MEM_freeN(edsortblock);
3490
 
 
3491
 
        EM_selectmode_flush(em);
3492
 
 
3493
 
}
3494
 
/* ******************** END TRIANGLE TO QUAD ************************************* */
3495
 
 
3496
 
#define FACE_MARKCLEAR(f) (f->f1 = 1)
3497
 
 
3498
 
/* quick hack, basically a copy of beautify_fill */
3499
 
static void edge_flip(EditMesh *em)
3500
 
{
3501
 
        EditVert *v1, *v2, *v3, *v4;
3502
 
        EditEdge *eed, *nexted;
3503
 
        EditFace *efa, *w;
3504
 
        //void **efaar, **efaa;
3505
 
        EVPTuple *efaar;
3506
 
        EVPtr *efaa;
3507
 
        int totedge, ok, vindex[4];
3508
 
 
3509
 
        /* - all selected edges with two faces
3510
 
         * - find the faces: store them in edges (using datablock)
3511
 
         * - per edge: - test convex
3512
 
         *                         - test edge: flip?
3513
 
                                                - if true: remedge,  addedge, all edges at the edge get new face pointers
3514
 
         */
3515
 
 
3516
 
        EM_selectmode_flush(em);        // makes sure in selectmode 'face' the edges of selected faces are selected too
3517
 
 
3518
 
        totedge = count_selected_edges(em->edges.first);
3519
 
        if(totedge==0) return;
3520
 
 
3521
 
        /* temporary array for : edge -> face[1], face[2] */
3522
 
        efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
3523
 
 
3524
 
        ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
3525
 
 
3526
 
        eed= em->edges.first;
3527
 
        while(eed) {
3528
 
                nexted= eed->next;
3529
 
 
3530
 
                if(eed->f2==2) {  /* points to 2 faces */
3531
 
 
3532
 
                        efaa= (EVPtr *) eed->tmp.p;
3533
 
 
3534
 
                        /* don't do it if flagged */
3535
 
 
3536
 
                        ok= 1;
3537
 
                        efa= efaa[0];
3538
 
                        if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
3539
 
                        efa= efaa[1];
3540
 
                        if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
3541
 
 
3542
 
                        if(ok) {
3543
 
                                /* test convex */
3544
 
                                givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
3545
 
 
3546
 
/*
3547
 
                4-----3         4-----3
3548
 
                |\      |               |       /|
3549
 
                | \ 1 |         | 1 / |
3550
 
                |  \  |  ->     |  /  |
3551
 
                | 0 \ |         | / 0 |
3552
 
                |       \|              |/      |
3553
 
                1-----2         1-----2
3554
 
*/
3555
 
                                /* make new faces */
3556
 
                                if (v1 && v2 && v3) {
3557
 
                                        if( convex(v1->co, v2->co, v3->co, v4->co) ) {
3558
 
                                                if(exist_face(em, v1, v2, v3, v4)==0) {
3559
 
                                                        /* outch this may break seams */
3560
 
                                                        w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
3561
 
                                                                vindex[1], 4+vindex[2], -1);
3562
 
 
3563
 
                                                        EM_select_face(w, 1);
3564
 
 
3565
 
                                                        /* outch this may break seams */
3566
 
                                                        w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
3567
 
                                                                4+vindex[2], 4+vindex[3], -1);
3568
 
 
3569
 
                                                        EM_select_face(w, 1);
3570
 
                                                }
3571
 
                                                /* tag as to-be-removed */
3572
 
                                                FACE_MARKCLEAR(efaa[1]);
3573
 
                                                FACE_MARKCLEAR(efaa[0]);
3574
 
                                                eed->f1 = 1;
3575
 
 
3576
 
                                        } /* endif test convex */
3577
 
                                }
3578
 
                        }
3579
 
                }
3580
 
                eed= nexted;
3581
 
        }
3582
 
 
3583
 
        /* clear tagged edges and faces: */
3584
 
        free_tagged_edges_faces(em, em->edges.first, em->faces.first);
3585
 
 
3586
 
        MEM_freeN(efaar);
3587
 
}
3588
 
 
3589
 
#define DIRECTION_CW    1
3590
 
#define DIRECTION_CCW   2
3591
 
 
3592
 
static const EnumPropertyItem direction_items[]= {
 
943
        ot->name = "Delete";
 
944
        ot->description = "Delete selected vertices, edges or faces";
 
945
        ot->idname = "MESH_OT_delete";
 
946
        
 
947
        /* api callbacks */
 
948
        ot->invoke = WM_menu_invoke;
 
949
        ot->exec = edbm_delete_exec;
 
950
        
 
951
        ot->poll = ED_operator_editmesh;
 
952
        
 
953
        /* flags */
 
954
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
955
 
 
956
        /* props */
 
957
        ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
 
958
}
 
959
 
 
960
static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
 
961
{
 
962
        Object *obedit = CTX_data_edit_object(C);
 
963
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
964
 
 
965
        if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
 
966
                return OPERATOR_CANCELLED;
 
967
 
 
968
        EDBM_update_generic(C, em, TRUE);
 
969
 
 
970
        return OPERATOR_FINISHED;
 
971
}
 
972
 
 
973
void MESH_OT_edge_collapse(wmOperatorType *ot)
 
974
{
 
975
        /* identifiers */
 
976
        ot->name = "Edge Collapse";
 
977
        ot->description = "Collapse selected edges";
 
978
        ot->idname = "MESH_OT_edge_collapse";
 
979
 
 
980
        /* api callbacks */
 
981
        ot->exec = edbm_collapse_edge_exec;
 
982
        ot->poll = ED_operator_editmesh;
 
983
 
 
984
        /* flags */
 
985
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
986
}
 
987
 
 
988
static int edbm_collapse_edge_loop_exec(bContext *C, wmOperator *op)
 
989
{
 
990
        Object *obedit = CTX_data_edit_object(C);
 
991
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
992
 
 
993
        if (!EDBM_op_callf(em, op, "dissolve_edge_loop edges=%he", BM_ELEM_SELECT))
 
994
                return OPERATOR_CANCELLED;
 
995
 
 
996
        EDBM_update_generic(C, em, TRUE);
 
997
 
 
998
        return OPERATOR_FINISHED;
 
999
}
 
1000
 
 
1001
void MESH_OT_edge_collapse_loop(wmOperatorType *ot)
 
1002
{
 
1003
        /* identifiers */
 
1004
        ot->name = "Edge Collapse Loop";
 
1005
        ot->description = "Collapse selected edge loops";
 
1006
        ot->idname = "MESH_OT_edge_collapse_loop";
 
1007
 
 
1008
        /* api callbacks */
 
1009
        ot->exec = edbm_collapse_edge_loop_exec;
 
1010
        ot->poll = ED_operator_editmesh;
 
1011
 
 
1012
        /* flags */
 
1013
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1014
}
 
1015
 
 
1016
static int edbm_add_edge_face__smooth_get(BMesh *bm)
 
1017
{
 
1018
        BMEdge *e;
 
1019
        BMIter iter;
 
1020
 
 
1021
        unsigned int vote_on_smooth[2] = {0, 0};
 
1022
 
 
1023
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
 
1024
                if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l)
 
1025
                {
 
1026
                        vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
 
1027
                }
 
1028
        }
 
1029
 
 
1030
        return (vote_on_smooth[0] < vote_on_smooth[1]);
 
1031
}
 
1032
 
 
1033
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
 
1034
{
 
1035
        BMOperator bmop;
 
1036
        Object *obedit = CTX_data_edit_object(C);
 
1037
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1038
        const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
 
1039
        /* when this is used to dissolve we could avoid this, but checking isnt too slow */
 
1040
 
 
1041
        if (!EDBM_op_init(em, &bmop, op,
 
1042
                          "contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
 
1043
                          BM_ELEM_SELECT, em->mat_nr, use_smooth))
 
1044
        {
 
1045
                return OPERATOR_CANCELLED;
 
1046
        }
 
1047
        
 
1048
        BMO_op_exec(em->bm, &bmop);
 
1049
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_FACE, BM_ELEM_SELECT, TRUE);
 
1050
 
 
1051
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1052
                return OPERATOR_CANCELLED;
 
1053
        }
 
1054
 
 
1055
        EDBM_update_generic(C, em, TRUE);
 
1056
        
 
1057
        return OPERATOR_FINISHED;
 
1058
}
 
1059
 
 
1060
void MESH_OT_edge_face_add(wmOperatorType *ot)
 
1061
{
 
1062
        /* identifiers */
 
1063
        ot->name = "Make Edge/Face";
 
1064
        ot->description = "Add an edge or face to selected";
 
1065
        ot->idname = "MESH_OT_edge_face_add";
 
1066
        
 
1067
        /* api callbacks */
 
1068
        ot->exec = edbm_add_edge_face_exec;
 
1069
        ot->poll = ED_operator_editmesh;
 
1070
        
 
1071
        /* flags */
 
1072
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1073
}
 
1074
 
 
1075
/* ************************* SEAMS AND EDGES **************** */
 
1076
 
 
1077
static int edbm_mark_seam(bContext *C, wmOperator *op)
 
1078
{
 
1079
        Scene *scene = CTX_data_scene(C);
 
1080
        Object *obedit = CTX_data_edit_object(C);
 
1081
        Mesh *me = ((Mesh *)obedit->data);
 
1082
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1083
        BMesh *bm = em->bm;
 
1084
        BMEdge *eed;
 
1085
        BMIter iter;
 
1086
        int clear = RNA_boolean_get(op->ptr, "clear");
 
1087
        
 
1088
        /* auto-enable seams drawing */
 
1089
        if (clear == 0) {
 
1090
                me->drawflag |= ME_DRAWSEAMS;
 
1091
        }
 
1092
 
 
1093
        if (clear) {
 
1094
                BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
 
1095
                        if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
 
1096
                                continue;
 
1097
                        
 
1098
                        BM_elem_flag_disable(eed, BM_ELEM_SEAM);
 
1099
                }
 
1100
        }
 
1101
        else {
 
1102
                BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
 
1103
                        if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
 
1104
                                continue;
 
1105
                        BM_elem_flag_enable(eed, BM_ELEM_SEAM);
 
1106
                }
 
1107
        }
 
1108
 
 
1109
        ED_uvedit_live_unwrap(scene, obedit);
 
1110
        EDBM_update_generic(C, em, TRUE);
 
1111
 
 
1112
        return OPERATOR_FINISHED;
 
1113
}
 
1114
 
 
1115
void MESH_OT_mark_seam(wmOperatorType *ot)
 
1116
{
 
1117
        /* identifiers */
 
1118
        ot->name = "Mark Seam";
 
1119
        ot->idname = "MESH_OT_mark_seam";
 
1120
        ot->description = "(Un)mark selected edges as a seam";
 
1121
        
 
1122
        /* api callbacks */
 
1123
        ot->exec = edbm_mark_seam;
 
1124
        ot->poll = ED_operator_editmesh;
 
1125
        
 
1126
        /* flags */
 
1127
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1128
        
 
1129
        RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 
1130
}
 
1131
 
 
1132
static int edbm_mark_sharp(bContext *C, wmOperator *op)
 
1133
{
 
1134
        Object *obedit = CTX_data_edit_object(C);
 
1135
        Mesh *me = ((Mesh *)obedit->data);
 
1136
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1137
        BMesh *bm = em->bm;
 
1138
        BMEdge *eed;
 
1139
        BMIter iter;
 
1140
        int clear = RNA_boolean_get(op->ptr, "clear");
 
1141
 
 
1142
        /* auto-enable sharp edge drawing */
 
1143
        if (clear == 0) {
 
1144
                me->drawflag |= ME_DRAWSHARP;
 
1145
        }
 
1146
 
 
1147
        if (!clear) {
 
1148
                BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
 
1149
                        if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
 
1150
                                continue;
 
1151
                        
 
1152
                        BM_elem_flag_disable(eed, BM_ELEM_SMOOTH);
 
1153
                }
 
1154
        }
 
1155
        else {
 
1156
                BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
 
1157
                        if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN))
 
1158
                                continue;
 
1159
                        
 
1160
                        BM_elem_flag_enable(eed, BM_ELEM_SMOOTH);
 
1161
                }
 
1162
        }
 
1163
 
 
1164
        EDBM_update_generic(C, em, TRUE);
 
1165
 
 
1166
        return OPERATOR_FINISHED;
 
1167
}
 
1168
 
 
1169
void MESH_OT_mark_sharp(wmOperatorType *ot)
 
1170
{
 
1171
        /* identifiers */
 
1172
        ot->name = "Mark Sharp";
 
1173
        ot->idname = "MESH_OT_mark_sharp";
 
1174
        ot->description = "(Un)mark selected edges as sharp";
 
1175
        
 
1176
        /* api callbacks */
 
1177
        ot->exec = edbm_mark_sharp;
 
1178
        ot->poll = ED_operator_editmesh;
 
1179
        
 
1180
        /* flags */
 
1181
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1182
        
 
1183
        RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 
1184
}
 
1185
 
 
1186
 
 
1187
static int edbm_vert_connect(bContext *C, wmOperator *op)
 
1188
{
 
1189
        Object *obedit = CTX_data_edit_object(C);
 
1190
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1191
        BMesh *bm = em->bm;
 
1192
        BMOperator bmop;
 
1193
        int len = 0;
 
1194
        
 
1195
        if (!EDBM_op_init(em, &bmop, op, "connectverts verts=%hv", BM_ELEM_SELECT)) {
 
1196
                return OPERATOR_CANCELLED;
 
1197
        }
 
1198
        BMO_op_exec(bm, &bmop);
 
1199
        len = BMO_slot_get(&bmop, "edgeout")->len;
 
1200
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1201
                return OPERATOR_CANCELLED;
 
1202
        }
 
1203
        
 
1204
        EDBM_update_generic(C, em, TRUE);
 
1205
 
 
1206
        return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 
1207
}
 
1208
 
 
1209
void MESH_OT_vert_connect(wmOperatorType *ot)
 
1210
{
 
1211
        /* identifiers */
 
1212
        ot->name = "Vertex Connect";
 
1213
        ot->idname = "MESH_OT_vert_connect";
 
1214
        ot->description = "Connect 2 vertices of a face by an edge, splitting the face in two";
 
1215
        
 
1216
        /* api callbacks */
 
1217
        ot->exec = edbm_vert_connect;
 
1218
        ot->poll = ED_operator_editmesh;
 
1219
        
 
1220
        /* flags */
 
1221
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1222
}
 
1223
 
 
1224
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
 
1225
{
 
1226
        Object *obedit = CTX_data_edit_object(C);
 
1227
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1228
        BMesh *bm = em->bm;
 
1229
        BMOperator bmop;
 
1230
        int len = 0;
 
1231
        
 
1232
        if (!EDBM_op_init(em, &bmop, op, "edgesplit edges=%he", BM_ELEM_SELECT)) {
 
1233
                return OPERATOR_CANCELLED;
 
1234
        }
 
1235
        BMO_op_exec(bm, &bmop);
 
1236
        len = BMO_slot_get(&bmop, "edgeout")->len;
 
1237
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1238
                return OPERATOR_CANCELLED;
 
1239
        }
 
1240
        
 
1241
        EDBM_update_generic(C, em, TRUE);
 
1242
 
 
1243
        return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 
1244
}
 
1245
 
 
1246
void MESH_OT_edge_split(wmOperatorType *ot)
 
1247
{
 
1248
        /* identifiers */
 
1249
        ot->name = "Edge Split";
 
1250
        ot->idname = "MESH_OT_edge_split";
 
1251
        
 
1252
        /* api callbacks */
 
1253
        ot->exec = edbm_edge_split_exec;
 
1254
        ot->poll = ED_operator_editmesh;
 
1255
        
 
1256
        /* flags */
 
1257
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1258
}
 
1259
 
 
1260
/****************** add duplicate operator ***************/
 
1261
 
 
1262
static int edbm_duplicate_exec(bContext *C, wmOperator *op)
 
1263
{
 
1264
        Object *ob = CTX_data_edit_object(C);
 
1265
        BMEditMesh *em = BMEdit_FromObject(ob);
 
1266
        BMOperator bmop;
 
1267
 
 
1268
        EDBM_op_init(em, &bmop, op, "dupe geom=%hvef", BM_ELEM_SELECT);
 
1269
        
 
1270
        BMO_op_exec(em->bm, &bmop);
 
1271
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
1272
 
 
1273
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "newout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
1274
 
 
1275
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1276
                return OPERATOR_CANCELLED;
 
1277
        }
 
1278
 
 
1279
        EDBM_update_generic(C, em, TRUE);
 
1280
        
 
1281
        return OPERATOR_FINISHED;
 
1282
}
 
1283
 
 
1284
static int edbm_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
1285
{
 
1286
        WM_cursor_wait(1);
 
1287
        edbm_duplicate_exec(C, op);
 
1288
        WM_cursor_wait(0);
 
1289
        
 
1290
        return OPERATOR_FINISHED;
 
1291
}
 
1292
 
 
1293
void MESH_OT_duplicate(wmOperatorType *ot)
 
1294
{
 
1295
        /* identifiers */
 
1296
        ot->name = "Duplicate";
 
1297
        ot->description = "Duplicate selected vertices, edges or faces";
 
1298
        ot->idname = "MESH_OT_duplicate";
 
1299
        
 
1300
        /* api callbacks */
 
1301
        ot->invoke = edbm_duplicate_invoke;
 
1302
        ot->exec = edbm_duplicate_exec;
 
1303
        
 
1304
        ot->poll = ED_operator_editmesh;
 
1305
        
 
1306
        /* to give to transform */
 
1307
        RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
 
1308
}
 
1309
 
 
1310
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
 
1311
{
 
1312
        Object *obedit = CTX_data_edit_object(C);
 
1313
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1314
        
 
1315
        if (!EDBM_op_callf(em, op, "reversefaces faces=%hf", BM_ELEM_SELECT))
 
1316
                return OPERATOR_CANCELLED;
 
1317
        
 
1318
        EDBM_update_generic(C, em, TRUE);
 
1319
 
 
1320
        return OPERATOR_FINISHED;
 
1321
}
 
1322
 
 
1323
void MESH_OT_flip_normals(wmOperatorType *ot)
 
1324
{
 
1325
        /* identifiers */
 
1326
        ot->name = "Flip Normals";
 
1327
        ot->description = "Flip the direction of selected faces' normals (and of their vertices)";
 
1328
        ot->idname = "MESH_OT_flip_normals";
 
1329
        
 
1330
        /* api callbacks */
 
1331
        ot->exec = edbm_flip_normals_exec;
 
1332
        ot->poll = ED_operator_editmesh;
 
1333
        
 
1334
        /* flags */
 
1335
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1336
}
 
1337
 
 
1338
static const EnumPropertyItem direction_items[] = {
3593
1339
        {DIRECTION_CW, "CW", 0, "Clockwise", ""},
3594
1340
        {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
3595
1341
        {0, NULL, 0, NULL, NULL}};
3596
1342
 
3597
 
#define AXIS_X          1
3598
 
#define AXIS_Y          2
3599
 
 
3600
 
static const EnumPropertyItem axis_items_xy[]= {
3601
 
        {AXIS_X, "X", 0, "X", ""},
3602
 
        {AXIS_Y, "Y", 0, "Y", ""},
3603
 
        {0, NULL, 0, NULL, NULL}};
3604
 
 
3605
 
static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
3606
 
{
3607
 
        EditVert **verts[2];
3608
 
        EditFace *face[2], *efa /* , *newFace[2] */ /* UNUSED */;
3609
 
        EditEdge **edges[2], **hiddenedges, *srchedge;
3610
 
        int facecount, p1, p2, p3, p4, fac1, fac2, i, j;
3611
 
        int numhidden, numshared, p[2][4];
3612
 
 
3613
 
        /* check to make sure that the edge is only part of 2 faces */
3614
 
        facecount = 0;
3615
 
        for(efa = em->faces.first;efa;efa = efa->next) {
3616
 
                if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) {
3617
 
                        if(facecount >= 2) {
3618
 
                                /* more than two faces with this edge */
3619
 
                                return;
3620
 
                        }
3621
 
                        else {
3622
 
                                face[facecount] = efa;
3623
 
                                facecount++;
3624
 
                        }
3625
 
                }
3626
 
        }
3627
 
 
3628
 
        if(facecount < 2)
3629
 
                return;
3630
 
 
3631
 
        /* how many edges does each face have */
3632
 
        if(face[0]->e4) fac1= 4;
3633
 
        else fac1= 3;
3634
 
 
3635
 
        if(face[1]->e4) fac2= 4;
3636
 
        else fac2= 3;
3637
 
 
3638
 
        /* make a handy array for verts and edges */
3639
 
        verts[0]= &face[0]->v1;
3640
 
        edges[0]= &face[0]->e1;
3641
 
        verts[1]= &face[1]->v1;
3642
 
        edges[1]= &face[1]->e1;
3643
 
 
3644
 
        /* we don't want to rotate edges between faces that share more than one edge */
3645
 
        numshared= 0;
3646
 
        for(i=0; i<fac1; i++)
3647
 
                for(j=0; j<fac2; j++)
3648
 
                        if (edges[0][i] == edges[1][j])
3649
 
                                numshared++;
3650
 
 
3651
 
        if(numshared > 1)
3652
 
                return;
3653
 
 
3654
 
        /* we want to construct an array of vertex indicis in both faces, starting at
3655
 
           the last vertex of the edge being rotated.
3656
 
           - first we find the two vertices that lie on the rotating edge
3657
 
           - then we make sure they are ordered according to the face vertex order
3658
 
           - and then we construct the array */
3659
 
        p1= p2= p3= p4= 0;
3660
 
 
3661
 
        for(i=0; i<4; i++) {
3662
 
                if(eed->v1 == verts[0][i]) p1 = i;
3663
 
                if(eed->v2 == verts[0][i]) p2 = i;
3664
 
                if(eed->v1 == verts[1][i]) p3 = i;
3665
 
                if(eed->v2 == verts[1][i]) p4 = i;
3666
 
        }
3667
 
 
3668
 
        if((p1+1)%fac1 == p2)
3669
 
                SWAP(int, p1, p2);
3670
 
        if((p3+1)%fac2 == p4)
3671
 
                SWAP(int, p3, p4);
3672
 
 
3673
 
        for (i = 0; i < 4; i++) {
3674
 
                p[0][i]= (p1 + i)%fac1;
3675
 
                p[1][i]= (p3 + i)%fac2;
3676
 
        }
3677
 
 
3678
 
        /* create an Array of the Edges who have h set prior to rotate */
3679
 
        numhidden = 0;
3680
 
        for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next)
3681
 
                if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT)))
3682
 
                        numhidden++;
3683
 
 
3684
 
        hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
3685
 
        if(!hiddenedges) {
3686
 
                BKE_report(op->reports, RPT_ERROR, "Memory allocation failed");
3687
 
                return;
3688
 
        }
3689
 
 
3690
 
        numhidden = 0;
3691
 
        for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
3692
 
                if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT))
3693
 
                        hiddenedges[numhidden++] = srchedge;
3694
 
 
3695
 
        /* create the 2 new faces */
3696
 
        if(fac1 == 3 && fac2 == 3) {
3697
 
                /* no need of reverse setup */
3698
 
 
3699
 
                /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
3700
 
                /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
3701
 
        }
3702
 
        else if(fac1 == 4 && fac2 == 3) {
3703
 
                if(dir == DIRECTION_CCW) {
3704
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
3705
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
3706
 
                } else if (dir == DIRECTION_CW) {
3707
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
3708
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
3709
 
 
3710
 
                        verts[0][p[0][2]]->f |= SELECT;
3711
 
                        verts[1][p[1][1]]->f |= SELECT;
3712
 
                }
3713
 
        }
3714
 
        else if(fac1 == 3 && fac2 == 4) {
3715
 
                if(dir == DIRECTION_CCW) {
3716
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
3717
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
3718
 
                } else if (dir == DIRECTION_CW) {
3719
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
3720
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
3721
 
 
3722
 
                        verts[0][p[0][1]]->f |= SELECT;
3723
 
                        verts[1][p[1][2]]->f |= SELECT;
3724
 
                }
3725
 
 
3726
 
        }
3727
 
        else if(fac1 == 4 && fac2 == 4) {
3728
 
                if(dir == DIRECTION_CCW) {
3729
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
3730
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
3731
 
                } else if (dir == DIRECTION_CW) {
3732
 
                        /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
3733
 
                        /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
3734
 
 
3735
 
                        verts[0][p[0][2]]->f |= SELECT;
3736
 
                        verts[1][p[1][2]]->f |= SELECT;
3737
 
                }
3738
 
        }
3739
 
        else
3740
 
                return; /* This should never happen */
3741
 
 
3742
 
        if(dir == DIRECTION_CCW || (fac1 == 3 && fac2 == 3)) {
3743
 
                verts[0][p[0][1]]->f |= SELECT;
3744
 
                verts[1][p[1][1]]->f |= SELECT;
3745
 
        }
3746
 
 
3747
 
        /* copy old edge's flags to new center edge*/
3748
 
        for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) {
3749
 
                if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) {
3750
 
                        srchedge->f = eed->f;
3751
 
                        srchedge->h = eed->h;
3752
 
                        srchedge->dir = eed->dir;
3753
 
                        srchedge->seam = eed->seam;
3754
 
                        srchedge->crease = eed->crease;
3755
 
                        srchedge->bweight = eed->bweight;
3756
 
                }
3757
 
        }
3758
 
 
3759
 
        /* resetting hidden flag */
3760
 
        for(numhidden--; numhidden>=0; numhidden--)
3761
 
                hiddenedges[numhidden]->h= 1;
3762
 
 
3763
 
        /* check for orhphan edges */
3764
 
        for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
3765
 
                srchedge->f1= -1;
3766
 
 
3767
 
        /* cleanup */
3768
 
        MEM_freeN(hiddenedges);
3769
 
 
3770
 
        /* get rid of the old edge and faces*/
3771
 
        remedge(em, eed);
3772
 
        free_editedge(em, eed);
3773
 
        BLI_remlink(&em->faces, face[0]);
3774
 
        free_editface(em, face[0]);
3775
 
        BLI_remlink(&em->faces, face[1]);
3776
 
        free_editface(em, face[1]);
3777
 
}
3778
 
 
3779
1343
/* only accepts 1 selected edge, or 2 selected faces */
3780
 
static int edge_rotate_selected(bContext *C, wmOperator *op)
 
1344
static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op)
3781
1345
{
3782
 
        Object *obedit= CTX_data_edit_object(C);
3783
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
3784
 
        EditEdge *eed;
3785
 
        EditFace *efa;
3786
 
        int dir = RNA_enum_get(op->ptr, "direction"); // dir == 2 when clockwise and ==1 for counter CW.
3787
 
        short edgeCount = 0;
 
1346
        Object *obedit = CTX_data_edit_object(C);
 
1347
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1348
        BMOperator bmop;
 
1349
        BMEdge *eed;
 
1350
        BMIter iter;
 
1351
        const int do_ccw = RNA_enum_get(op->ptr, "direction") == 1;
 
1352
        int tot = 0;
3788
1353
 
3789
 
        /*clear new flag for new edges, count selected edges */
3790
 
        for(eed= em->edges.first; eed; eed= eed->next) {
3791
 
                eed->f1= 0;
3792
 
                eed->f2 &= ~2;
3793
 
                if(eed->f & SELECT) edgeCount++;
 
1354
        if (em->bm->totedgesel == 0) {
 
1355
                BKE_report(op->reports, RPT_ERROR, "Select edges or face pairs for edge loops to rotate about");
 
1356
                return OPERATOR_CANCELLED;
3794
1357
        }
3795
1358
 
3796
 
        if(edgeCount>1) {
3797
 
                /* more selected edges, check faces */
3798
 
                for(efa= em->faces.first; efa; efa= efa->next) {
3799
 
                        if(efa->f & SELECT) {
3800
 
                                efa->e1->f1++;
3801
 
                                efa->e2->f1++;
3802
 
                                efa->e3->f1++;
3803
 
                                if(efa->e4) efa->e4->f1++;
3804
 
                        }
3805
 
                }
3806
 
                edgeCount= 0;
3807
 
                for(eed= em->edges.first; eed; eed= eed->next) {
3808
 
                        if(eed->f1==2) edgeCount++;
3809
 
                }
3810
 
                if(edgeCount==1) {
3811
 
                        for(eed= em->edges.first; eed; eed= eed->next) {
3812
 
                                if(eed->f1==2) {
3813
 
                                        edge_rotate(em, op, eed,dir);
3814
 
                                        break;
 
1359
        /* first see if we have two adjacent faces */
 
1360
        BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 
1361
                BM_elem_flag_disable(eed, BM_ELEM_TAG);
 
1362
                if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
 
1363
                        BMFace *fa, *fb;
 
1364
                        if (BM_edge_face_pair(eed, &fa, &fb)) {
 
1365
                                /* if both faces are selected we rotate between them,
 
1366
                                 * otherwise - rotate between 2 unselected - but not mixed */
 
1367
                                if (BM_elem_flag_test(fa, BM_ELEM_SELECT) == BM_elem_flag_test(fb, BM_ELEM_SELECT)) {
 
1368
                                        BM_elem_flag_enable(eed, BM_ELEM_TAG);
 
1369
                                        tot++;
3815
1370
                                }
3816
1371
                        }
3817
1372
                }
3818
 
                else
3819
 
                {
3820
 
                        BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
3821
 
                        BKE_mesh_end_editmesh(obedit->data, em);
3822
 
                        return OPERATOR_CANCELLED;
3823
 
                }
3824
 
        }
3825
 
        else if(edgeCount==1) {
3826
 
                for(eed= em->edges.first; eed; eed= eed->next) {
3827
 
                        if(eed->f & SELECT) {
3828
 
                                EM_select_edge(eed, 0);
3829
 
                                edge_rotate(em, op, eed,dir);
3830
 
                                break;
3831
 
                        }
3832
 
                }
3833
 
        }
3834
 
        else  {
3835
 
                BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
3836
 
                BKE_mesh_end_editmesh(obedit->data, em);
3837
 
                return OPERATOR_CANCELLED;
3838
 
        }
3839
 
 
3840
 
        /* flush selected vertices (again) to edges/faces */
3841
 
        EM_select_flush(em);
3842
 
 
3843
 
        BKE_mesh_end_editmesh(obedit->data, em);
3844
 
 
3845
 
        DAG_id_tag_update(obedit->data, 0);
3846
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
1373
        }
 
1374
        
 
1375
        /* ok, we don't have two adjacent faces, but we do have two selected ones.
 
1376
         * that's an error condition.*/
 
1377
        if (tot == 0) {
 
1378
                BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
 
1379
                return OPERATOR_CANCELLED;
 
1380
        }
 
1381
        
 
1382
        EDBM_op_init(em, &bmop, op, "edgerotate edges=%he ccw=%b", BM_ELEM_TAG, do_ccw);
 
1383
 
 
1384
        /* avoids leaving old verts selected which can be a problem running multiple times,
 
1385
         * since this means the edges become selected around the face which then attempt to rotate */
 
1386
        BMO_slot_buffer_hflag_disable(em->bm, &bmop, "edges", BM_EDGE, BM_ELEM_SELECT, TRUE);
 
1387
 
 
1388
        BMO_op_exec(em->bm, &bmop);
 
1389
        /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */
 
1390
        BMO_slot_buffer_hflag_disable(em->bm, &bmop, "edgeout", BM_EDGE, BM_ELEM_HIDDEN, TRUE);
 
1391
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_EDGE, BM_ELEM_SELECT, TRUE);
 
1392
        EDBM_selectmode_flush(em);
 
1393
 
 
1394
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1395
                return OPERATOR_CANCELLED;
 
1396
        }
 
1397
 
 
1398
        EDBM_update_generic(C, em, TRUE);
3847
1399
 
3848
1400
        return OPERATOR_FINISHED;
3849
1401
}
3851
1403
void MESH_OT_edge_rotate(wmOperatorType *ot)
3852
1404
{
3853
1405
        /* identifiers */
3854
 
        ot->name= "Rotate Selected Edge";
3855
 
        ot->description= "Rotate selected edge or adjoining faces";
3856
 
        ot->idname= "MESH_OT_edge_rotate";
3857
 
 
3858
 
        /* api callbacks */
3859
 
        ot->exec= edge_rotate_selected;
3860
 
        ot->poll= ED_operator_editmesh;
3861
 
 
3862
 
        /* flags */
3863
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3864
 
 
3865
 
        /* props */
3866
 
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around");
3867
 
}
3868
 
 
3869
 
 
3870
 
/******************* BEVEL CODE STARTS HERE ********************/
3871
 
 
3872
 
  /* XXX old bevel not ported yet */
3873
 
 
3874
 
static void UNUSED_FUNCTION(bevel_menu)(EditMesh *em)
3875
 
{
3876
 
        BME_Mesh *bm;
3877
 
        BME_TransData_Head *td;
3878
 
//      TransInfo *t;
3879
 
        int options, res, gbm_free = 0;
3880
 
 
3881
 
//      t = BIF_GetTransInfo();
3882
 
        if (!G.editBMesh) {
3883
 
                G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
3884
 
                gbm_free = 1;
3885
 
        }
3886
 
 
3887
 
        G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT;
3888
 
        G.editBMesh->res = 1;
3889
 
 
3890
 
        while(G.editBMesh->options & BME_BEVEL_RUNNING) {
3891
 
                options = G.editBMesh->options;
3892
 
                res = G.editBMesh->res;
3893
 
                bm = BME_editmesh_to_bmesh(em);
3894
 
//              BIF_undo_push("Pre-Bevel");
3895
 
                free_editMesh(em);
3896
 
                BME_bevel(bm,0.1f,res,options,0,0,&td);
3897
 
                BME_bmesh_to_editmesh(bm, td, em);
3898
 
                EM_selectmode_flush(em);
3899
 
                G.editBMesh->bm = bm;
3900
 
                G.editBMesh->td = td;
3901
 
//              initTransform(TFM_BEVEL,CTX_BMESH);
3902
 
//              Transform();
3903
 
                BME_free_transdata(td);
3904
 
                BME_free_mesh(bm);
3905
 
//              if (t->state != TRANS_CONFIRM) {
3906
 
//                      BIF_undo();
3907
 
//              }
3908
 
                if (options == G.editBMesh->options) {
3909
 
                        G.editBMesh->options &= ~BME_BEVEL_RUNNING;
3910
 
                }
3911
 
        }
3912
 
 
3913
 
        if (gbm_free) {
3914
 
                MEM_freeN(G.editBMesh);
3915
 
                G.editBMesh = NULL;
3916
 
        }
3917
 
}
3918
 
 
3919
 
 
3920
 
/* *********** END BEVEL *********/
3921
 
 
3922
 
/* this utility function checks to see if 2 edit edges share a face,
3923
 
returns 1 if they do
3924
 
returns 0 if they do not, or if the function is passed the same edge 2 times
3925
 
*/
3926
 
short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2)
3927
 
{
3928
 
        EditFace *search=NULL;
3929
 
 
3930
 
        search = em->faces.first;
3931
 
        if (e1 == e2){
3932
 
                return 0 ;
3933
 
        }
3934
 
        while(search){
3935
 
                if(
3936
 
                   ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
3937
 
                   ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
3938
 
                   ) {
3939
 
                        return 1;
3940
 
                }
3941
 
                search = search->next;
3942
 
        }
3943
 
        return 0;
3944
 
}
3945
 
 
3946
 
int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op))
3947
 
{
3948
 
#if 0 //XXX won't work with new edgeslide
3949
 
 
3950
 
        /* temporal flag setting so we keep UVs when deleting edge loops,
3951
 
        * this is a bit of a hack but it works how you would want in almost all cases */
3952
 
        //      short uvcalc_flag_orig = 0; // XXX scene->toolsettings->uvcalc_flag;
3953
 
        //      scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
3954
 
 
3955
 
        if(!EdgeSlide(em, op, 1, 1)) {
3956
 
                return 0;
3957
 
        }
3958
 
 
3959
 
        /* restore uvcalc flag */
3960
 
        //      scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
3961
 
 
3962
 
        EM_select_more(em);
3963
 
        removedoublesflag(em, 1,0, 0.001);
3964
 
        EM_select_flush(em);
3965
 
        //      DAG_id_tag_update(obedit->data, 0);
3966
 
        return 1;
3967
 
#endif
3968
 
        return 0;
3969
 
}
3970
 
 
3971
 
 
3972
 
/* -------------------- More tools ------------------ */
3973
 
#if 0
3974
 
void mesh_set_face_flags(EditMesh *em, short mode)
3975
 
{
3976
 
        EditFace *efa;
3977
 
        MTFace *tface;
3978
 
        short   m_tex=0, m_shared=0,
3979
 
                        m_light=0, m_invis=0, m_collision=0,
3980
 
                        m_twoside=0, m_obcolor=0, m_halo=0,
3981
 
                        m_billboard=0, m_shadow=0, m_text=0,
3982
 
                        m_sort=0;
3983
 
        short flag = 0, change = 0;
3984
 
 
3985
 
// XXX  if (!EM_texFaceCheck()) {
3986
 
//              error("not a mesh with uv/image layers");
3987
 
//              return;
3988
 
//      }
3989
 
 
3990
 
        add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL);
3991
 
        add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL);
3992
 
        add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL);
3993
 
        add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL);
3994
 
        add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL);
3995
 
        add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL);
3996
 
        add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL);
3997
 
        add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL);
3998
 
        add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL);
3999
 
        add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL);
4000
 
        add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL);
4001
 
        add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL);
4002
 
 
4003
 
        if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW))
4004
 
                return;
4005
 
 
4006
 
        /* these 2 cant both be on */
4007
 
        if (mode) /* are we seeting*/
4008
 
                if (m_halo)
4009
 
                        m_billboard = 0;
4010
 
 
4011
 
        if (m_tex)                      flag |= TF_TEX;
4012
 
        if (m_shared)           flag |= TF_SHAREDCOL;
4013
 
        if (m_light)            flag |= TF_LIGHT;
4014
 
        if (m_invis)            flag |= TF_INVISIBLE;
4015
 
        if (m_collision)        flag |= TF_DYNAMIC;
4016
 
        if (m_twoside)          flag |= TF_TWOSIDE;
4017
 
        if (m_obcolor)          flag |= TF_OBCOL;
4018
 
        if (m_halo)                     flag |= TF_BILLBOARD;
4019
 
        if (m_billboard)        flag |= TF_BILLBOARD2;
4020
 
        if (m_shadow)           flag |= TF_SHADOW;
4021
 
        if (m_text)                     flag |= TF_BMFONT;
4022
 
        if (m_sort)                     flag |= TF_ALPHASORT;
4023
 
 
4024
 
        if (flag==0)
4025
 
                return;
4026
 
 
4027
 
        efa= em->faces.first;
4028
 
        while(efa) {
4029
 
                if(efa->f & SELECT) {
4030
 
                        tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4031
 
                        if (mode)       tface->mode |= flag;
4032
 
                        else            tface->mode &= ~flag;
4033
 
                        change = 1;
4034
 
                }
4035
 
                efa= efa->next;
4036
 
        }
4037
 
 
4038
 
}
4039
 
#endif
4040
 
 
4041
 
/********************** Rip Operator *************************/
4042
 
 
4043
 
/* helper to find edge for edge_rip */
4044
 
static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2])
4045
 
{
4046
 
        float vec1[2], vec2[2], mvalf[2];
4047
 
 
4048
 
        ED_view3d_project_float(ar, co1, vec1, mat);
4049
 
        ED_view3d_project_float(ar, co2, vec2, mat);
4050
 
        mvalf[0]= (float)mval[0];
4051
 
        mvalf[1]= (float)mval[1];
4052
 
 
4053
 
        return dist_to_line_segment_v2(mvalf, vec1, vec2);
4054
 
}
4055
 
 
4056
 
/* helper for below */
4057
 
static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
4058
 
{
4059
 
        /* put new vertices & edges in best face */
4060
 
        if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
4061
 
        if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
4062
 
        if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
4063
 
        if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
4064
 
 
4065
 
        sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
4066
 
        sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
4067
 
        if(sefa->v4) {
4068
 
                sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
4069
 
                sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
4070
 
        }
4071
 
        else
4072
 
                sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
4073
 
 
4074
 
}
4075
 
 
4076
 
/* based on mouse cursor position, it defines how is being ripped */
4077
 
static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
4078
 
{
4079
 
        ARegion *ar= CTX_wm_region(C);
4080
 
        RegionView3D *rv3d= ar->regiondata;
4081
 
        Object *obedit= CTX_data_edit_object(C);
4082
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
4083
 
        EditVert *eve, *nextve;
4084
 
        EditEdge *eed, *seed= NULL;
4085
 
        EditFace *efa, *sefa= NULL;
4086
 
        float projectMat[4][4], vec[3], dist, mindist;
4087
 
        short doit= 1;
4088
 
        int *mval= event->mval;
4089
 
 
4090
 
        /* select flush... vertices are important */
4091
 
        EM_selectmode_set(em);
4092
 
 
4093
 
        ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
4094
 
 
4095
 
        /* find best face, exclude triangles and break on face select or faces with 2 edges select */
4096
 
        mindist= 1000000.0f;
4097
 
        for(efa= em->faces.first; efa; efa=efa->next) {
4098
 
                if( efa->f & 1)
4099
 
                        break;
4100
 
                if(efa->v4 && faceselectedOR(efa, SELECT) ) {
4101
 
                        int totsel=0;
4102
 
 
4103
 
                        if(efa->e1->f & SELECT) totsel++;
4104
 
                        if(efa->e2->f & SELECT) totsel++;
4105
 
                        if(efa->e3->f & SELECT) totsel++;
4106
 
                        if(efa->e4->f & SELECT) totsel++;
4107
 
 
4108
 
                        if(totsel>1)
4109
 
                                break;
4110
 
                        ED_view3d_project_float(ar, efa->cent, vec, projectMat);
4111
 
                        dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
4112
 
                        if(dist<mindist) {
4113
 
                                mindist= dist;
4114
 
                                sefa= efa;
4115
 
                        }
4116
 
                }
4117
 
        }
4118
 
 
4119
 
        if(efa) {
4120
 
                BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way");
4121
 
                BKE_mesh_end_editmesh(obedit->data, em);
4122
 
                return OPERATOR_CANCELLED;
4123
 
        }
4124
 
        if(sefa==NULL) {
4125
 
                BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included");
4126
 
                BKE_mesh_end_editmesh(obedit->data, em);
4127
 
                return OPERATOR_CANCELLED;
4128
 
        }
4129
 
 
4130
 
 
4131
 
        /* duplicate vertices, new vertices get selected */
4132
 
        for(eve = em->verts.last; eve; eve= eve->prev) {
4133
 
                eve->tmp.v = NULL;
4134
 
                if(eve->f & SELECT) {
4135
 
                        eve->tmp.v = addvertlist(em, eve->co, eve);
4136
 
                        eve->f &= ~SELECT;
4137
 
                        eve->tmp.v->f |= SELECT;
4138
 
                }
4139
 
        }
4140
 
 
4141
 
        /* find the best candidate edge */
4142
 
        /* or one of sefa edges is selected... */
4143
 
        if(sefa->e1->f & SELECT) seed= sefa->e2;
4144
 
        if(sefa->e2->f & SELECT) seed= sefa->e1;
4145
 
        if(sefa->e3->f & SELECT) seed= sefa->e2;
4146
 
        if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
4147
 
 
4148
 
        /* or we do the distance trick */
4149
 
        if(seed==NULL) {
4150
 
                mindist= 1000000.0f;
4151
 
                if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
4152
 
                        dist = mesh_rip_edgedist(ar, projectMat,
4153
 
                                                                         sefa->e1->v1->co,
4154
 
                                                                         sefa->e1->v2->co, mval);
4155
 
                        if(dist<mindist) {
4156
 
                                seed= sefa->e1;
4157
 
                                mindist= dist;
4158
 
                        }
4159
 
                }
4160
 
                if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
4161
 
                        dist = mesh_rip_edgedist(ar, projectMat,
4162
 
                                                                         sefa->e2->v1->co,
4163
 
                                                                         sefa->e2->v2->co, mval);
4164
 
                        if(dist<mindist) {
4165
 
                                seed= sefa->e2;
4166
 
                                mindist= dist;
4167
 
                        }
4168
 
                }
4169
 
                if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
4170
 
                        dist= mesh_rip_edgedist(ar, projectMat,
4171
 
                                                                        sefa->e3->v1->co,
4172
 
                                                                        sefa->e3->v2->co, mval);
4173
 
                        if(dist<mindist) {
4174
 
                                seed= sefa->e3;
4175
 
                                mindist= dist;
4176
 
                        }
4177
 
                }
4178
 
                if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
4179
 
                        dist= mesh_rip_edgedist(ar, projectMat,
4180
 
                                                                        sefa->e4->v1->co,
4181
 
                                                                        sefa->e4->v2->co, mval);
4182
 
                        if(dist<mindist) {
4183
 
                                seed= sefa->e4;
4184
 
                                mindist= dist;
4185
 
                        }
4186
 
                }
4187
 
        }
4188
 
 
4189
 
        if(seed==NULL) {        // never happens?
4190
 
                BKE_report(op->reports, RPT_WARNING, "No proper edge found to start");
4191
 
                BKE_mesh_end_editmesh(obedit->data, em);
4192
 
                return OPERATOR_CANCELLED;
4193
 
        }
4194
 
 
4195
 
        faceloop_select(em, seed, 2);   // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
4196
 
 
4197
 
        /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
4198
 
        for(eed = em->edges.last; eed; eed= eed->prev) {
4199
 
                eed->tmp.v = NULL;
4200
 
                if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
4201
 
                        EditEdge *newed;
4202
 
 
4203
 
                        newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
4204
 
                                                           eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
4205
 
                        if(eed->f & SELECT) {
4206
 
                                EM_select_edge(eed, 0);
4207
 
                                EM_remove_selection(em, eed, EDITEDGE);
4208
 
                                EM_select_edge(newed, 1);
4209
 
                        }
4210
 
                        eed->tmp.v = (EditVert *)newed;
4211
 
                }
4212
 
        }
4213
 
 
4214
 
        /* first clear edges to help finding neighbours */
4215
 
        for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
4216
 
 
4217
 
        /* put new vertices & edges && flag in best face */
4218
 
        mesh_rip_setface(em, sefa);
4219
 
 
4220
 
        /* starting with neighbours of best face, we loop over the seam */
4221
 
        sefa->f1= 2;
4222
 
        doit= 1;
4223
 
        while(doit) {
4224
 
                doit= 0;
4225
 
 
4226
 
                for(efa= em->faces.first; efa; efa=efa->next) {
4227
 
                        /* new vert in face */
4228
 
                        if (efa->v1->tmp.v || efa->v2->tmp.v ||
4229
 
                                efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
4230
 
                                /* face is tagged with loop */
4231
 
                                if(efa->f1==1) {
4232
 
                                        mesh_rip_setface(em, efa);
4233
 
                                        efa->f1= 2;
4234
 
                                        doit= 1;
4235
 
                                }
4236
 
                        }
4237
 
                }
4238
 
        }
4239
 
 
4240
 
        /* remove loose edges, that were part of a ripped face */
4241
 
        for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
4242
 
        for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
4243
 
        for(efa= em->faces.first; efa; efa=efa->next) {
4244
 
                efa->e1->f1= 1;
4245
 
                efa->e2->f1= 1;
4246
 
                efa->e3->f1= 1;
4247
 
                if(efa->e4) efa->e4->f1= 1;
4248
 
        }
4249
 
 
4250
 
        for(eed = em->edges.last; eed; eed= seed) {
4251
 
                seed= eed->prev;
4252
 
                if(eed->f1==0) {
4253
 
                        if(eed->v1->tmp.v || eed->v2->tmp.v ||
4254
 
                           (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
4255
 
                                remedge(em, eed);
4256
 
                                free_editedge(em, eed);
4257
 
                                eed= NULL;
4258
 
                        }
4259
 
                }
4260
 
                if(eed) {
4261
 
                        eed->v1->f1= 1;
4262
 
                        eed->v2->f1= 1;
4263
 
                }
4264
 
        }
4265
 
 
4266
 
        /* and remove loose selected vertices, that got duplicated accidentally */
4267
 
        for(eve = em->verts.first; eve; eve= nextve) {
4268
 
                nextve= eve->next;
4269
 
                if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
4270
 
                        BLI_remlink(&em->verts,eve);
4271
 
                        free_editvert(em, eve);
4272
 
                }
4273
 
        }
4274
 
 
4275
 
        DAG_id_tag_update(obedit->data, 0);
4276
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
4277
 
 
4278
 
        BKE_mesh_end_editmesh(obedit->data, em);
4279
 
 
4280
 
//      RNA_enum_set(op->ptr, "proportional", 0);
4281
 
//      RNA_boolean_set(op->ptr, "mirror", FALSE);
4282
 
//      WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
4283
 
 
4284
 
        return OPERATOR_FINISHED;
4285
 
}
4286
 
 
4287
 
void MESH_OT_rip(wmOperatorType *ot)
4288
 
{
4289
 
        /* identifiers */
4290
 
        ot->name= "Rip";
4291
 
        ot->description= "Rip selection from mesh (quads only)";
4292
 
        ot->idname= "MESH_OT_rip";
4293
 
 
4294
 
        /* api callbacks */
4295
 
        ot->invoke= mesh_rip_invoke;
4296
 
        ot->poll= EM_view3d_poll;
4297
 
 
4298
 
        /* flags */
4299
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
4300
 
 
4301
 
        /* to give to transform */
4302
 
        /* XXX Transform this in a macro */
4303
 
        Transform_Properties(ot, P_CONSTRAINT|P_MIRROR);
4304
 
}
4305
 
 
4306
 
 
4307
 
/************************ Shape Operators *************************/
4308
 
 
4309
 
static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
4310
 
{
4311
 
        EditVert *ev = NULL;
4312
 
        Mesh* me = (Mesh*)obedit->data;
4313
 
        Key*  ky = NULL;
4314
 
        KeyBlock* kb = NULL;
4315
 
 
4316
 
 
4317
 
        if(me->key){
4318
 
                ky = me->key;
4319
 
        } else {
4320
 
                BKE_report(op->reports, RPT_WARNING, "Object Has No Key");
4321
 
                return;
4322
 
        }
4323
 
 
4324
 
        if(ky->block.first){
4325
 
                for(ev = em->verts.first; ev ; ev = ev->next){
4326
 
                        if(ev->f & SELECT){
4327
 
                                for(kb=ky->block.first;kb;kb = kb->next){
4328
 
                                        float *data;
4329
 
                                        data = kb->data;
4330
 
                                        VECCOPY(data+(ev->keyindex*3),ev->co);
4331
 
                                }
4332
 
                        }
4333
 
                }
4334
 
        } else {
4335
 
                BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
4336
 
                return;
4337
 
        }
4338
 
 
4339
 
#if 0
4340
 
        //TAG Mesh Objects that share this data
4341
 
        for(base = scene->base.first; base; base = base->next){
4342
 
                if(base->object && base->object->data == me){
4343
 
                        base->object->recalc = OB_RECALC_DATA;
4344
 
                }
4345
 
        }
4346
 
#endif
4347
 
 
4348
 
        DAG_id_tag_update(obedit->data, 0);
4349
 
        return;
4350
 
}
4351
 
 
4352
 
 
4353
 
static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
4354
 
{
4355
 
        Object *obedit= CTX_data_edit_object(C);
4356
 
        Mesh *me= obedit->data;
4357
 
        EditMesh *em= BKE_mesh_get_editmesh(me);
4358
 
 
4359
 
        shape_propagate(obedit, em, op);
4360
 
 
4361
 
        DAG_id_tag_update(&me->id, 0);
4362
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
4363
 
 
4364
 
        return OPERATOR_FINISHED;
4365
 
}
4366
 
 
4367
 
 
4368
 
void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
4369
 
{
4370
 
        /* identifiers */
4371
 
        ot->name= "Shape Propagate";
4372
 
        ot->description= "Apply selected vertex locations to all other shape keys";
4373
 
        ot->idname= "MESH_OT_shape_propagate_to_all";
4374
 
 
4375
 
        /* api callbacks */
4376
 
        ot->exec= shape_propagate_to_all_exec;
4377
 
        ot->poll= ED_operator_editmesh;
4378
 
 
4379
 
        /* flags */
4380
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
4381
 
}
4382
 
 
4383
 
static int blend_from_shape_exec(bContext *C, wmOperator *op)
4384
 
{
4385
 
        Object *obedit= CTX_data_edit_object(C);
4386
 
        Mesh *me= obedit->data;
4387
 
        Key *key= me->key;
4388
 
        EditMesh *em= BKE_mesh_get_editmesh(me);
4389
 
        EditVert *eve;
4390
 
        KeyBlock *kb, *refkb= NULL;
4391
 
        float *data, *refdata= NULL, co[3];
4392
 
        float blend= RNA_float_get(op->ptr, "blend");
4393
 
        int shape= RNA_enum_get(op->ptr, "shape");
4394
 
        int add= RNA_boolean_get(op->ptr, "add");
4395
 
        int blended= 0;
4396
 
 
4397
 
        if(key && (kb= BLI_findlink(&key->block, shape))) {
4398
 
                data= kb->data;
4399
 
 
4400
 
                if(add) {
4401
 
                        refkb= BLI_findlink(&key->block, kb->relative);
4402
 
                        if(refkb)
4403
 
                                refdata = refkb->data;
4404
 
                }
4405
 
 
4406
 
                for(eve=em->verts.first; eve; eve=eve->next){
4407
 
                        if(eve->f & SELECT) {
4408
 
                                if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) {
4409
 
                                        copy_v3_v3(co, data + eve->keyindex*3);
4410
 
 
4411
 
                                        if(add) {
4412
 
                                                /* in add mode, we add relative shape key offset */
4413
 
                                                if(refdata && eve->keyindex < refkb->totelem)
4414
 
                                                        sub_v3_v3v3(co, co, refdata + eve->keyindex*3);
4415
 
 
4416
 
                                                madd_v3_v3fl(eve->co, co, blend);
4417
 
                                        }
4418
 
                                        else {
4419
 
                                                /* in blend mode, we interpolate to the shape key */
4420
 
                                                interp_v3_v3v3(eve->co, eve->co, co, blend);
4421
 
                                        }
4422
 
 
4423
 
                                        blended= 1;
4424
 
                                }
4425
 
                        }
4426
 
                }
4427
 
        }
4428
 
 
4429
 
        BKE_mesh_end_editmesh(me, em);
4430
 
 
4431
 
        if(!blended)
4432
 
                return OPERATOR_CANCELLED;
4433
 
 
4434
 
        DAG_id_tag_update(&me->id, 0);
4435
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
4436
 
 
4437
 
        return OPERATOR_FINISHED;
4438
 
}
4439
 
 
4440
 
static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
4441
 
{       
4442
 
        Object *obedit= CTX_data_edit_object(C);
4443
 
        Mesh *me= (obedit) ? obedit->data : NULL;
4444
 
        Key *key;
4445
 
        KeyBlock *kb, *actkb;
4446
 
        EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
4447
 
        int totitem= 0, a;
4448
 
 
4449
 
        if(obedit && obedit->type == OB_MESH) {
4450
 
                key= me->key;
4451
 
                actkb= ob_get_keyblock(obedit);
4452
 
 
4453
 
                if(key && actkb) {
4454
 
                        for(kb=key->block.first, a=0; kb; kb=kb->next, a++) {
4455
 
                                if(kb != actkb) {
4456
 
                                        tmp.value= a;
4457
 
                                        tmp.identifier= kb->name;
4458
 
                                        tmp.name= kb->name;
4459
 
                                        RNA_enum_item_add(&item, &totitem, &tmp);
4460
 
                                }
4461
 
                        }
4462
 
                }
4463
 
        }
4464
 
 
4465
 
        RNA_enum_item_end(&item, &totitem);
4466
 
        *free= 1;
4467
 
 
4468
 
        return item;
4469
 
}
4470
 
 
4471
 
void MESH_OT_blend_from_shape(wmOperatorType *ot)
4472
 
{
4473
 
        PropertyRNA *prop;
4474
 
        static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
4475
 
 
4476
 
        /* identifiers */
4477
 
        ot->name= "Blend From Shape";
4478
 
        ot->description= "Blend in shape from a shape key";
4479
 
        ot->idname= "MESH_OT_blend_from_shape";
4480
 
 
4481
 
        /* api callbacks */
4482
 
        ot->exec= blend_from_shape_exec;
4483
 
        ot->invoke= WM_operator_props_popup;
4484
 
        ot->poll= ED_operator_editmesh;
4485
 
 
4486
 
        /* flags */
4487
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
4488
 
 
4489
 
        /* properties */
4490
 
        prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending");
4491
 
        RNA_def_enum_funcs(prop, shape_itemf);
4492
 
        RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
4493
 
        RNA_def_boolean(ot->srna, "add", 0, "Add", "Add rather than blend between shapes");
4494
 
}
4495
 
 
4496
 
/************************ Merge Operator *************************/
4497
 
 
4498
 
/* Collection Routines|Currently used by the improved merge code*/
4499
 
/* buildEdge_collection() creates a list of lists*/
4500
 
/* these lists are filled with edges that are topologically connected.*/
4501
 
/* This whole tool needs to be redone, its rather poorly implemented...*/
4502
 
 
4503
 
typedef struct Collection{
4504
 
        struct Collection *next, *prev;
4505
 
        int index;
4506
 
        ListBase collectionbase;
4507
 
} Collection;
4508
 
 
4509
 
typedef struct CollectedEdge{
4510
 
        struct CollectedEdge *next, *prev;
4511
 
        EditEdge *eed;
4512
 
} CollectedEdge;
4513
 
 
4514
 
#define MERGELIMIT 0.000001
4515
 
 
4516
 
static void build_edgecollection(EditMesh *em, ListBase *allcollections)
4517
 
{
4518
 
        EditEdge *eed;
4519
 
        Collection *edgecollection, *newcollection;
4520
 
        CollectedEdge *newedge;
4521
 
 
4522
 
        int currtag = 1;
4523
 
        short ebalanced = 0;
4524
 
        short collectionfound = 0;
4525
 
 
4526
 
        for (eed=em->edges.first; eed; eed = eed->next){
4527
 
                eed->tmp.l = 0;
4528
 
                eed->v1->tmp.l = 0;
4529
 
                eed->v2->tmp.l = 0;
4530
 
        }
4531
 
 
4532
 
        /*1st pass*/
4533
 
        for(eed=em->edges.first; eed; eed=eed->next){
4534
 
                        if(eed->f&SELECT){
4535
 
                                eed->v1->tmp.l = currtag;
4536
 
                                eed->v2->tmp.l = currtag;
4537
 
                                currtag +=1;
4538
 
                        }
4539
 
        }
4540
 
 
4541
 
        /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */
4542
 
        while(ebalanced == 0){
4543
 
                ebalanced = 1;
4544
 
                for(eed=em->edges.first; eed; eed = eed->next){
4545
 
                        if(eed->f&SELECT){
4546
 
                                if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{
4547
 
                                        if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l;
4548
 
                                        else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l;
4549
 
                                        ebalanced = 0;
4550
 
                                }
4551
 
                        }
4552
 
                }
4553
 
        }
4554
 
 
4555
 
        /*3rd pass, set all the edge flags (unnessecary?)*/
4556
 
        for(eed=em->edges.first; eed; eed = eed->next){
4557
 
                if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l;
4558
 
        }
4559
 
 
4560
 
        for(eed=em->edges.first; eed; eed=eed->next){
4561
 
                if(eed->f&SELECT){
4562
 
                        if(allcollections->first){
4563
 
                                for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){
4564
 
                                        if(edgecollection->index == eed->tmp.l){
4565
 
                                                newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
4566
 
                                                newedge->eed = eed;
4567
 
                                                BLI_addtail(&(edgecollection->collectionbase), newedge);
4568
 
                                                collectionfound = 1;
4569
 
                                                break;
4570
 
                                        }
4571
 
                                        else collectionfound = 0;
4572
 
                                }
4573
 
                        }
4574
 
                        if(allcollections->first == NULL || collectionfound == 0){
4575
 
                                newcollection = MEM_mallocN(sizeof(Collection), "element collection");
4576
 
                                newcollection->index = eed->tmp.l;
4577
 
                                newcollection->collectionbase.first = 0;
4578
 
                                newcollection->collectionbase.last = 0;
4579
 
 
4580
 
                                newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
4581
 
                                newedge->eed = eed;
4582
 
 
4583
 
                                BLI_addtail(&(newcollection->collectionbase), newedge);
4584
 
                                BLI_addtail(allcollections, newcollection);
4585
 
                        }
4586
 
                }
4587
 
 
4588
 
        }
4589
 
}
4590
 
 
4591
 
static void freecollections(ListBase *allcollections)
4592
 
{
4593
 
        struct Collection *curcollection;
4594
 
 
4595
 
        for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next)
4596
 
                BLI_freelistN(&(curcollection->collectionbase));
4597
 
        BLI_freelistN(allcollections);
4598
 
}
4599
 
 
4600
 
/*Begin UV Edge Collapse Code
4601
 
        Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail
4602
 
        in areas such as the boundaries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
4603
 
        The welded UV edges can then be sorted and collapsed.
4604
 
*/
4605
 
typedef struct wUV{
4606
 
        struct wUV *next, *prev;
4607
 
        ListBase nodes;
4608
 
        float u, v; /*cached copy of UV coordinates pointed to by nodes*/
4609
 
        EditVert *eve;
4610
 
        int f;
4611
 
} wUV;
4612
 
 
4613
 
typedef struct wUVNode{
4614
 
        struct wUVNode *next, *prev;
4615
 
        float *u; /*pointer to original tface data*/
4616
 
        float *v; /*pointer to original tface data*/
4617
 
} wUVNode;
4618
 
 
4619
 
typedef struct wUVEdge{
4620
 
        struct wUVEdge *next, *prev;
4621
 
        float v1uv[2], v2uv[2]; /*nasty.*/
4622
 
        struct wUV *v1, *v2; /*oriented same as editedge*/
4623
 
        EditEdge *eed;
4624
 
        int f;
4625
 
} wUVEdge;
4626
 
 
4627
 
typedef struct wUVEdgeCollect{ /*used for grouping*/
4628
 
        struct wUVEdgeCollect *next, *prev;
4629
 
        wUVEdge *uved;
4630
 
        int id;
4631
 
} wUVEdgeCollect;
4632
 
 
4633
 
static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
4634
 
{
4635
 
        wUV *curwvert, *newwvert;
4636
 
        wUVNode *newnode;
4637
 
        int found;
4638
 
        MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4639
 
 
4640
 
        found = 0;
4641
 
 
4642
 
        for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
4643
 
                if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){
4644
 
                        newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
4645
 
                        newnode->u = &(tf->uv[tfindex][0]);
4646
 
                        newnode->v = &(tf->uv[tfindex][1]);
4647
 
                        BLI_addtail(&(curwvert->nodes), newnode);
4648
 
                        found = 1;
4649
 
                        break;
4650
 
                }
4651
 
        }
4652
 
 
4653
 
        if(!found){
4654
 
                newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
4655
 
                newnode->u = &(tf->uv[tfindex][0]);
4656
 
                newnode->v = &(tf->uv[tfindex][1]);
4657
 
 
4658
 
                newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert");
4659
 
                newwvert->u = *(newnode->u);
4660
 
                newwvert->v = *(newnode->v);
4661
 
                newwvert->eve = eve;
4662
 
 
4663
 
                BLI_addtail(&(newwvert->nodes), newnode);
4664
 
                BLI_addtail(uvverts, newwvert);
4665
 
 
4666
 
        }
4667
 
}
4668
 
 
4669
 
static void build_weldedUVs(EditMesh *em, ListBase *uvverts)
4670
 
{
4671
 
        EditFace *efa;
4672
 
        for(efa=em->faces.first; efa; efa=efa->next){
4673
 
                if(efa->v1->f1) append_weldedUV(em, efa, efa->v1, 0, uvverts);
4674
 
                if(efa->v2->f1) append_weldedUV(em, efa, efa->v2, 1, uvverts);
4675
 
                if(efa->v3->f1) append_weldedUV(em, efa, efa->v3, 2, uvverts);
4676
 
                if(efa->v4 && efa->v4->f1) append_weldedUV(em, efa, efa->v4, 3, uvverts);
4677
 
        }
4678
 
}
4679
 
 
4680
 
static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges)
4681
 
{
4682
 
        wUVEdge *curwedge, *newwedge;
4683
 
        int v1tfindex, v2tfindex, found;
4684
 
        MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4685
 
 
4686
 
        found = 0;
4687
 
 
4688
 
        if(eed->v1 == efa->v1) v1tfindex = 0;
4689
 
        else if(eed->v1 == efa->v2) v1tfindex = 1;
4690
 
        else if(eed->v1 == efa->v3) v1tfindex = 2;
4691
 
        else /* if(eed->v1 == efa->v4) */ v1tfindex = 3;
4692
 
 
4693
 
        if(eed->v2 == efa->v1) v2tfindex = 0;
4694
 
        else if(eed->v2 == efa->v2) v2tfindex = 1;
4695
 
        else if(eed->v2 == efa->v3) v2tfindex = 2;
4696
 
        else /* if(eed->v2 == efa->v4) */ v2tfindex = 3;
4697
 
 
4698
 
        for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
4699
 
                        if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){
4700
 
                                found = 1;
4701
 
                                break; //do nothing, we don't need another welded uv edge
4702
 
                        }
4703
 
        }
4704
 
 
4705
 
        if(!found){
4706
 
                newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge");
4707
 
                newwedge->v1uv[0] = tf->uv[v1tfindex][0];
4708
 
                newwedge->v1uv[1] = tf->uv[v1tfindex][1];
4709
 
                newwedge->v2uv[0] = tf->uv[v2tfindex][0];
4710
 
                newwedge->v2uv[1] = tf->uv[v2tfindex][1];
4711
 
                newwedge->eed = eed;
4712
 
 
4713
 
                BLI_addtail(uvedges, newwedge);
4714
 
        }
4715
 
}
4716
 
 
4717
 
static void build_weldedUVEdges(EditMesh *em, ListBase *uvedges, ListBase *uvverts)
4718
 
{
4719
 
        wUV *curwvert;
4720
 
        wUVEdge *curwedge;
4721
 
        EditFace *efa;
4722
 
 
4723
 
        for(efa=em->faces.first; efa; efa=efa->next){
4724
 
                if(efa->e1->f1) append_weldedUVEdge(em, efa, efa->e1, uvedges);
4725
 
                if(efa->e2->f1) append_weldedUVEdge(em, efa, efa->e2, uvedges);
4726
 
                if(efa->e3->f1) append_weldedUVEdge(em, efa, efa->e3, uvedges);
4727
 
                if(efa->e4 && efa->e4->f1) append_weldedUVEdge(em, efa, efa->e4, uvedges);
4728
 
        }
4729
 
 
4730
 
 
4731
 
        //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers
4732
 
        for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
4733
 
                for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
4734
 
                        if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){
4735
 
                                curwedge->v1 = curwvert;
4736
 
                                break;
4737
 
                        }
4738
 
                }
4739
 
                for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
4740
 
                        if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){
4741
 
                                curwedge->v2 = curwvert;
4742
 
                                break;
4743
 
                        }
4744
 
                }
4745
 
        }
4746
 
}
4747
 
 
4748
 
static void free_weldedUVs(ListBase *uvverts)
4749
 
{
4750
 
        wUV *curwvert;
4751
 
        for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes));
4752
 
        BLI_freelistN(uvverts);
4753
 
}
4754
 
 
4755
 
static void collapse_edgeuvs(EditMesh *em)
4756
 
{
4757
 
        ListBase uvedges, uvverts, allcollections;
4758
 
        wUVEdge *curwedge;
4759
 
        wUVNode *curwnode;
4760
 
        wUVEdgeCollect *collectedwuve, *newcollectedwuve;
4761
 
        Collection *wuvecollection, *newcollection;
4762
 
        int curtag, balanced, collectionfound= 0, vcount;
4763
 
        float avg[2];
4764
 
 
4765
 
        if (!EM_texFaceCheck(em))
4766
 
                return;
4767
 
 
4768
 
        uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
4769
 
 
4770
 
        build_weldedUVs(em, &uvverts);
4771
 
        build_weldedUVEdges(em, &uvedges, &uvverts);
4772
 
 
4773
 
        curtag = 0;
4774
 
 
4775
 
        for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
4776
 
                curwedge->v1->f = curtag;
4777
 
                curwedge->v2->f = curtag;
4778
 
                curtag +=1;
4779
 
        }
4780
 
 
4781
 
        balanced = 0;
4782
 
        while(!balanced){
4783
 
                balanced = 1;
4784
 
                for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
4785
 
                        if(curwedge->v1->f != curwedge->v2->f){
4786
 
                                if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f;
4787
 
                                else curwedge->v2->f = curwedge->v1->f;
4788
 
                                balanced = 0;
4789
 
                        }
4790
 
                }
4791
 
        }
4792
 
 
4793
 
        for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f;
4794
 
 
4795
 
 
4796
 
        for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
4797
 
                if(allcollections.first){
4798
 
                        for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
4799
 
                                if(wuvecollection->index == curwedge->f){
4800
 
                                        newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
4801
 
                                        newcollectedwuve->uved = curwedge;
4802
 
                                        BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve);
4803
 
                                        collectionfound = 1;
4804
 
                                        break;
4805
 
                                }
4806
 
 
4807
 
                                else collectionfound = 0;
4808
 
                        }
4809
 
                }
4810
 
                if(allcollections.first == NULL || collectionfound == 0){
4811
 
                        newcollection = MEM_callocN(sizeof(Collection), "element collection");
4812
 
                        newcollection->index = curwedge->f;
4813
 
                        newcollection->collectionbase.first = 0;
4814
 
                        newcollection->collectionbase.last = 0;
4815
 
 
4816
 
                        newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
4817
 
                        newcollectedwuve->uved = curwedge;
4818
 
 
4819
 
                        BLI_addtail(&(newcollection->collectionbase), newcollectedwuve);
4820
 
                        BLI_addtail(&allcollections, newcollection);
4821
 
                }
4822
 
        }
4823
 
 
4824
 
        for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
4825
 
 
4826
 
                vcount = avg[0] = avg[1] = 0;
4827
 
 
4828
 
                for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
4829
 
                        avg[0] += collectedwuve->uved->v1uv[0];
4830
 
                        avg[1] += collectedwuve->uved->v1uv[1];
4831
 
 
4832
 
                        avg[0] += collectedwuve->uved->v2uv[0];
4833
 
                        avg[1] += collectedwuve->uved->v2uv[1];
4834
 
 
4835
 
                        vcount +=2;
4836
 
 
4837
 
                }
4838
 
 
4839
 
                avg[0] /= vcount; avg[1] /= vcount;
4840
 
 
4841
 
                for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
4842
 
                        for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){
4843
 
                                *(curwnode->u) = avg[0];
4844
 
                                *(curwnode->v) = avg[1];
4845
 
                        }
4846
 
                        for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){
4847
 
                                *(curwnode->u) = avg[0];
4848
 
                                *(curwnode->v) = avg[1];
4849
 
                        }
4850
 
                }
4851
 
        }
4852
 
 
4853
 
        free_weldedUVs(&uvverts);
4854
 
        BLI_freelistN(&uvedges);
4855
 
        freecollections(&allcollections);
4856
 
}
4857
 
 
4858
 
/*End UV Edge collapse code*/
4859
 
 
4860
 
static void collapseuvs(EditMesh *em, EditVert *mergevert)
4861
 
{
4862
 
        EditFace *efa;
4863
 
        MTFace *tf;
4864
 
        int uvcount;
4865
 
        float uvav[2];
4866
 
 
4867
 
        if (!EM_texFaceCheck(em))
4868
 
                return;
4869
 
 
4870
 
        uvcount = 0;
4871
 
        uvav[0] = 0;
4872
 
        uvav[1] = 0;
4873
 
 
4874
 
        for(efa = em->faces.first; efa; efa=efa->next){
4875
 
                tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4876
 
 
4877
 
                if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) {
4878
 
                        uvav[0] += tf->uv[0][0];
4879
 
                        uvav[1] += tf->uv[0][1];
4880
 
                        uvcount += 1;
4881
 
                }
4882
 
                if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){
4883
 
                        uvav[0] += tf->uv[1][0];
4884
 
                        uvav[1] += tf->uv[1][1];
4885
 
                        uvcount += 1;
4886
 
                }
4887
 
                if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){
4888
 
                        uvav[0] += tf->uv[2][0];
4889
 
                        uvav[1] += tf->uv[2][1];
4890
 
                        uvcount += 1;
4891
 
                }
4892
 
                if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){
4893
 
                        uvav[0] += tf->uv[3][0];
4894
 
                        uvav[1] += tf->uv[3][1];
4895
 
                        uvcount += 1;
4896
 
                }
4897
 
        }
4898
 
 
4899
 
        if(uvcount > 0) {
4900
 
                uvav[0] /= uvcount;
4901
 
                uvav[1] /= uvcount;
4902
 
 
4903
 
                for(efa = em->faces.first; efa; efa=efa->next){
4904
 
                        tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4905
 
 
4906
 
                        if(efa->v1->f1){
4907
 
                                tf->uv[0][0] = uvav[0];
4908
 
                                tf->uv[0][1] = uvav[1];
4909
 
                        }
4910
 
                        if(efa->v2->f1){
4911
 
                                tf->uv[1][0] = uvav[0];
4912
 
                                tf->uv[1][1] = uvav[1];
4913
 
                        }
4914
 
                        if(efa->v3->f1){
4915
 
                                tf->uv[2][0] = uvav[0];
4916
 
                                tf->uv[2][1] = uvav[1];
4917
 
                        }
4918
 
                        if(efa->v4 && efa->v4->f1){
4919
 
                                tf->uv[3][0] = uvav[0];
4920
 
                                tf->uv[3][1] = uvav[1];
4921
 
                        }
4922
 
                }
4923
 
        }
4924
 
}
4925
 
 
4926
 
static int collapseEdges(EditMesh *em)
4927
 
{
4928
 
        EditVert *eve;
4929
 
        EditEdge *eed;
4930
 
 
4931
 
        ListBase allcollections;
4932
 
        CollectedEdge *curredge;
4933
 
        Collection *edgecollection;
4934
 
 
4935
 
        int totedges, mergecount,vcount /*, groupcount*/;
4936
 
        float avgcount[3];
4937
 
 
4938
 
        allcollections.first = 0;
4939
 
        allcollections.last = 0;
4940
 
 
4941
 
        mergecount = 0;
4942
 
 
4943
 
        build_edgecollection(em, &allcollections);
4944
 
        /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/
4945
 
 
4946
 
 
4947
 
        for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){
4948
 
                totedges = BLI_countlist(&(edgecollection->collectionbase));
4949
 
                mergecount += totedges;
4950
 
                avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0;
4951
 
 
4952
 
                vcount = 0;
4953
 
 
4954
 
                for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
4955
 
                        avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0];
4956
 
                        avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1];
4957
 
                        avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2];
4958
 
 
4959
 
                        avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0];
4960
 
                        avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1];
4961
 
                        avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2];
4962
 
 
4963
 
                        vcount +=2;
4964
 
                }
4965
 
 
4966
 
                avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount;
4967
 
 
4968
 
                for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
4969
 
                        VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount);
4970
 
                        VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount);
4971
 
                }
4972
 
 
4973
 
                if (EM_texFaceCheck(em)) {
4974
 
                        /*uv collapse*/
4975
 
                        for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
4976
 
                        for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
4977
 
                        for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
4978
 
                                curredge->eed->v1->f1 = 1;
4979
 
                                curredge->eed->v2->f1 = 1;
4980
 
                                curredge->eed->f1 = 1;
4981
 
                        }
4982
 
                        collapse_edgeuvs(em);
4983
 
                }
4984
 
 
4985
 
        }
4986
 
        freecollections(&allcollections);
4987
 
        removedoublesflag(em, 1, 0, MERGELIMIT);
4988
 
 
4989
 
        return mergecount;
4990
 
}
4991
 
 
4992
 
static int merge_firstlast(EditMesh *em, int first, int uvmerge)
4993
 
{
4994
 
        EditVert *eve,*mergevert;
4995
 
        EditSelection *ese;
 
1406
        ot->name = "Rotate Selected Edge";
 
1407
        ot->description = "Rotate selected edge or adjoining faces";
 
1408
        ot->idname = "MESH_OT_edge_rotate";
 
1409
 
 
1410
        /* api callbacks */
 
1411
        ot->exec = edbm_edge_rotate_selected_exec;
 
1412
        ot->poll = ED_operator_editmesh;
 
1413
 
 
1414
        /* flags */
 
1415
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1416
 
 
1417
        /* props */
 
1418
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around");
 
1419
}
 
1420
 
 
1421
 
 
1422
static int edbm_hide_exec(bContext *C, wmOperator *op)
 
1423
{
 
1424
        Object *obedit = CTX_data_edit_object(C);
 
1425
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1426
        
 
1427
        EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
 
1428
 
 
1429
        EDBM_update_generic(C, em, TRUE);
 
1430
 
 
1431
        return OPERATOR_FINISHED;
 
1432
}
 
1433
 
 
1434
void MESH_OT_hide(wmOperatorType *ot)
 
1435
{
 
1436
        /* identifiers */
 
1437
        ot->name = "Hide Selection";
 
1438
        ot->idname = "MESH_OT_hide";
 
1439
        ot->description = "Hide (un)selected vertices, edges or faces";
 
1440
        
 
1441
        /* api callbacks */
 
1442
        ot->exec = edbm_hide_exec;
 
1443
        ot->poll = ED_operator_editmesh;
 
1444
 
 
1445
        /* flags */
 
1446
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1447
        
 
1448
        /* props */
 
1449
        RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
 
1450
}
 
1451
 
 
1452
static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
 
1453
{
 
1454
        Object *obedit = CTX_data_edit_object(C);
 
1455
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1456
        
 
1457
        EDBM_mesh_reveal(em);
 
1458
 
 
1459
        EDBM_update_generic(C, em, TRUE);
 
1460
 
 
1461
        return OPERATOR_FINISHED;
 
1462
}
 
1463
 
 
1464
void MESH_OT_reveal(wmOperatorType *ot)
 
1465
{
 
1466
        /* identifiers */
 
1467
        ot->name = "Reveal Hidden";
 
1468
        ot->idname = "MESH_OT_reveal";
 
1469
        ot->description = "Reveal all hidden vertices, edges and faces";
 
1470
        
 
1471
        /* api callbacks */
 
1472
        ot->exec = edbm_reveal_exec;
 
1473
        ot->poll = ED_operator_editmesh;
 
1474
        
 
1475
        /* flags */
 
1476
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1477
}
 
1478
 
 
1479
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
 
1480
{
 
1481
        Object *obedit = CTX_data_edit_object(C);
 
1482
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1483
        
 
1484
        /* doflip has to do with bmesh_rationalize_normals, it's an internal
 
1485
         * thing */
 
1486
        if (!EDBM_op_callf(em, op, "righthandfaces faces=%hf do_flip=%b", BM_ELEM_SELECT, TRUE))
 
1487
                return OPERATOR_CANCELLED;
 
1488
 
 
1489
        if (RNA_boolean_get(op->ptr, "inside"))
 
1490
                EDBM_op_callf(em, op, "reversefaces faces=%hf", BM_ELEM_SELECT);
 
1491
 
 
1492
        EDBM_update_generic(C, em, TRUE);
 
1493
 
 
1494
        return OPERATOR_FINISHED;
 
1495
}
 
1496
 
 
1497
void MESH_OT_normals_make_consistent(wmOperatorType *ot)
 
1498
{
 
1499
        /* identifiers */
 
1500
        ot->name = "Make Normals Consistent";
 
1501
        ot->description = "Make face and vertex normals point either outside or inside the mesh";
 
1502
        ot->idname = "MESH_OT_normals_make_consistent";
 
1503
        
 
1504
        /* api callbacks */
 
1505
        ot->exec = edbm_normals_make_consistent_exec;
 
1506
        ot->poll = ED_operator_editmesh;
 
1507
        
 
1508
        /* flags */
 
1509
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1510
        
 
1511
        RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
 
1512
}
 
1513
 
 
1514
 
 
1515
 
 
1516
static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
 
1517
{
 
1518
        Object *obedit = CTX_data_edit_object(C);
 
1519
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1520
        ModifierData *md;
 
1521
        int mirrx = FALSE, mirry = FALSE, mirrz = FALSE;
 
1522
        int i, repeat;
 
1523
        float clipdist = 0.0f;
 
1524
 
 
1525
        /* mirror before smooth */
 
1526
        if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
 
1527
                EDBM_verts_mirror_cache_begin(em, TRUE);
 
1528
        }
 
1529
 
 
1530
        /* if there is a mirror modifier with clipping, flag the verts that
 
1531
         * are within tolerance of the plane(s) of reflection 
 
1532
         */
 
1533
        for (md = obedit->modifiers.first; md; md = md->next) {
 
1534
                if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
 
1535
                        MirrorModifierData *mmd = (MirrorModifierData *)md;
 
1536
                
 
1537
                        if (mmd->flag & MOD_MIR_CLIPPING) {
 
1538
                                if (mmd->flag & MOD_MIR_AXIS_X)
 
1539
                                        mirrx = TRUE;
 
1540
                                if (mmd->flag & MOD_MIR_AXIS_Y)
 
1541
                                        mirry = TRUE;
 
1542
                                if (mmd->flag & MOD_MIR_AXIS_Z)
 
1543
                                        mirrz = TRUE;
 
1544
 
 
1545
                                clipdist = mmd->tolerance;
 
1546
                        }
 
1547
                }
 
1548
        }
 
1549
 
 
1550
        repeat = RNA_int_get(op->ptr, "repeat");
 
1551
        if (!repeat)
 
1552
                repeat = 1;
 
1553
        
 
1554
        for (i = 0; i < repeat; i++) {
 
1555
                if (!EDBM_op_callf(em, op,
 
1556
                                   "vertexsmooth verts=%hv mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b clipdist=%f",
 
1557
                                   BM_ELEM_SELECT, mirrx, mirry, mirrz, clipdist))
 
1558
                {
 
1559
                        return OPERATOR_CANCELLED;
 
1560
                }
 
1561
        }
 
1562
 
 
1563
        /* apply mirror */
 
1564
        if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
 
1565
                EDBM_verts_mirror_apply(em, BM_ELEM_SELECT, 0);
 
1566
                EDBM_verts_mirror_cache_end(em);
 
1567
        }
 
1568
 
 
1569
        EDBM_update_generic(C, em, TRUE);
 
1570
 
 
1571
        return OPERATOR_FINISHED;
 
1572
}       
 
1573
        
 
1574
void MESH_OT_vertices_smooth(wmOperatorType *ot)
 
1575
{
 
1576
        /* identifiers */
 
1577
        ot->name = "Smooth Vertex";
 
1578
        ot->description = "Flatten angles of selected vertices";
 
1579
        ot->idname = "MESH_OT_vertices_smooth";
 
1580
        
 
1581
        /* api callbacks */
 
1582
        ot->exec = edbm_do_smooth_vertex_exec;
 
1583
        ot->poll = ED_operator_editmesh;
 
1584
        
 
1585
        /* flags */
 
1586
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1587
 
 
1588
        RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
 
1589
}
 
1590
 
 
1591
/********************** Smooth/Solid Operators *************************/
 
1592
 
 
1593
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
 
1594
{
 
1595
        BMIter iter;
 
1596
        BMFace *efa;
 
1597
 
 
1598
        if (em == NULL) return;
 
1599
        
 
1600
        BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
 
1601
                if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
 
1602
                        BM_elem_flag_set(efa, BM_ELEM_SMOOTH, smooth);
 
1603
                }
 
1604
        }
 
1605
}
 
1606
 
 
1607
static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
 
1608
{
 
1609
        Object *obedit = CTX_data_edit_object(C);
 
1610
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1611
 
 
1612
        mesh_set_smooth_faces(em, 1);
 
1613
 
 
1614
        EDBM_update_generic(C, em, FALSE);
 
1615
 
 
1616
        return OPERATOR_FINISHED;
 
1617
}
 
1618
 
 
1619
void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
 
1620
{
 
1621
        /* identifiers */
 
1622
        ot->name = "Shade Smooth";
 
1623
        ot->description = "Display faces smooth (using vertex normals)";
 
1624
        ot->idname = "MESH_OT_faces_shade_smooth";
 
1625
 
 
1626
        /* api callbacks */
 
1627
        ot->exec = edbm_faces_shade_smooth_exec;
 
1628
        ot->poll = ED_operator_editmesh;
 
1629
 
 
1630
        /* flags */
 
1631
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1632
}
 
1633
 
 
1634
static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
 
1635
{
 
1636
        Object *obedit = CTX_data_edit_object(C);
 
1637
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1638
 
 
1639
        mesh_set_smooth_faces(em, 0);
 
1640
 
 
1641
        EDBM_update_generic(C, em, FALSE);
 
1642
 
 
1643
        return OPERATOR_FINISHED;
 
1644
}
 
1645
 
 
1646
void MESH_OT_faces_shade_flat(wmOperatorType *ot)
 
1647
{
 
1648
        /* identifiers */
 
1649
        ot->name = "Shade Flat";
 
1650
        ot->description = "Display faces flat";
 
1651
        ot->idname = "MESH_OT_faces_shade_flat";
 
1652
 
 
1653
        /* api callbacks */
 
1654
        ot->exec = edbm_faces_shade_flat_exec;
 
1655
        ot->poll = ED_operator_editmesh;
 
1656
 
 
1657
        /* flags */
 
1658
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1659
}
 
1660
 
 
1661
 
 
1662
/********************** UV/Color Operators *************************/
 
1663
 
 
1664
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
 
1665
{
 
1666
        Object *ob = CTX_data_edit_object(C);
 
1667
        BMEditMesh *em = BMEdit_FromObject(ob);
 
1668
        BMOperator bmop;
 
1669
 
 
1670
        /* get the direction from RNA */
 
1671
        int dir = RNA_enum_get(op->ptr, "direction");
 
1672
 
 
1673
        /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
 
1674
        EDBM_op_init(em, &bmop, op, "face_rotateuvs faces=%hf dir=%i", BM_ELEM_SELECT, dir);
 
1675
 
 
1676
        /* execute the operator */
 
1677
        BMO_op_exec(em->bm, &bmop);
 
1678
 
 
1679
        /* finish the operator */
 
1680
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1681
                return OPERATOR_CANCELLED;
 
1682
        }
 
1683
 
 
1684
        EDBM_update_generic(C, em, FALSE);
 
1685
 
 
1686
        /* we succeeded */
 
1687
        return OPERATOR_FINISHED;
 
1688
}
 
1689
 
 
1690
static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
 
1691
{
 
1692
        Object *ob = CTX_data_edit_object(C);
 
1693
        BMEditMesh *em = BMEdit_FromObject(ob);
 
1694
        BMOperator bmop;
 
1695
 
 
1696
        /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
 
1697
        EDBM_op_init(em, &bmop, op, "face_reverseuvs faces=%hf", BM_ELEM_SELECT);
 
1698
 
 
1699
        /* execute the operator */
 
1700
        BMO_op_exec(em->bm, &bmop);
 
1701
 
 
1702
        /* finish the operator */
 
1703
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1704
                return OPERATOR_CANCELLED;
 
1705
        }
 
1706
 
 
1707
        EDBM_update_generic(C, em, FALSE);
 
1708
 
 
1709
        /* we succeeded */
 
1710
        return OPERATOR_FINISHED;
 
1711
}
 
1712
 
 
1713
static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
 
1714
{
 
1715
        Object *ob = CTX_data_edit_object(C);
 
1716
        BMEditMesh *em = BMEdit_FromObject(ob);
 
1717
        BMOperator bmop;
 
1718
 
 
1719
        /* get the direction from RNA */
 
1720
        int dir = RNA_enum_get(op->ptr, "direction");
 
1721
 
 
1722
        /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
 
1723
        EDBM_op_init(em, &bmop, op, "face_rotatecolors faces=%hf dir=%i", BM_ELEM_SELECT, dir);
 
1724
 
 
1725
        /* execute the operator */
 
1726
        BMO_op_exec(em->bm, &bmop);
 
1727
 
 
1728
        /* finish the operator */
 
1729
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1730
                return OPERATOR_CANCELLED;
 
1731
        }
 
1732
 
 
1733
        /* dependencies graph and notification stuff */
 
1734
        EDBM_update_generic(C, em, FALSE);
 
1735
 
 
1736
        /* we succeeded */
 
1737
        return OPERATOR_FINISHED;
 
1738
}
 
1739
 
 
1740
 
 
1741
static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
 
1742
{
 
1743
        Object *ob = CTX_data_edit_object(C);
 
1744
        BMEditMesh *em = BMEdit_FromObject(ob);
 
1745
        BMOperator bmop;
 
1746
 
 
1747
        /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
 
1748
        EDBM_op_init(em, &bmop, op, "face_reversecolors faces=%hf", BM_ELEM_SELECT);
 
1749
 
 
1750
        /* execute the operator */
 
1751
        BMO_op_exec(em->bm, &bmop);
 
1752
 
 
1753
        /* finish the operator */
 
1754
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
1755
                return OPERATOR_CANCELLED;
 
1756
        }
 
1757
 
 
1758
        EDBM_update_generic(C, em, FALSE);
 
1759
 
 
1760
        /* we succeeded */
 
1761
        return OPERATOR_FINISHED;
 
1762
}
 
1763
 
 
1764
void MESH_OT_uvs_rotate(wmOperatorType *ot)
 
1765
{
 
1766
        /* identifiers */
 
1767
        ot->name = "Rotate UVs";
 
1768
        ot->idname = "MESH_OT_uvs_rotate";
 
1769
        ot->description = "Rotate UV coordinates inside faces";
 
1770
 
 
1771
        /* api callbacks */
 
1772
        ot->exec = edbm_rotate_uvs_exec;
 
1773
        ot->poll = ED_operator_editmesh;
 
1774
 
 
1775
        /* flags */
 
1776
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1777
 
 
1778
        /* props */
 
1779
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around");
 
1780
}
 
1781
 
 
1782
//void MESH_OT_uvs_mirror(wmOperatorType *ot)
 
1783
void MESH_OT_uvs_reverse(wmOperatorType *ot)
 
1784
{
 
1785
        /* identifiers */
 
1786
        ot->name = "Reverse UVs";
 
1787
        ot->idname = "MESH_OT_uvs_reverse";
 
1788
        ot->description = "Flip direction of UV coordinates inside faces";
 
1789
 
 
1790
        /* api callbacks */
 
1791
        ot->exec = edbm_reverse_uvs_exec;
 
1792
        ot->poll = ED_operator_editmesh;
 
1793
 
 
1794
        /* flags */
 
1795
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1796
 
 
1797
        /* props */
 
1798
        //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
 
1799
}
 
1800
 
 
1801
void MESH_OT_colors_rotate(wmOperatorType *ot)
 
1802
{
 
1803
        /* identifiers */
 
1804
        ot->name = "Rotate Colors";
 
1805
        ot->idname = "MESH_OT_colors_rotate";
 
1806
        ot->description = "Rotate vertex colors inside faces";
 
1807
 
 
1808
        /* api callbacks */
 
1809
        ot->exec = edbm_rotate_colors_exec;
 
1810
        ot->poll = ED_operator_editmesh;
 
1811
 
 
1812
        /* flags */
 
1813
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1814
 
 
1815
        /* props */
 
1816
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CCW, "Direction", "Direction to rotate edge around");
 
1817
}
 
1818
 
 
1819
void MESH_OT_colors_reverse(wmOperatorType *ot)
 
1820
{
 
1821
        /* identifiers */
 
1822
        ot->name = "Reverse Colors";
 
1823
        ot->idname = "MESH_OT_colors_reverse";
 
1824
        ot->description = "Flip direction of vertex colors inside faces";
 
1825
 
 
1826
        /* api callbacks */
 
1827
        ot->exec = edbm_reverse_colors_exec;
 
1828
        ot->poll = ED_operator_editmesh;
 
1829
 
 
1830
        /* flags */
 
1831
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
1832
 
 
1833
        /* props */
 
1834
        //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
 
1835
}
 
1836
 
 
1837
 
 
1838
static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
 
1839
{
 
1840
        BMVert *mergevert;
 
1841
        BMEditSelection *ese;
4996
1842
 
4997
1843
        /* do sanity check in mergemenu in edit.c ?*/
4998
 
        if(first == 0){
4999
 
                ese = em->selected.last;
5000
 
                mergevert= (EditVert*)ese->data;
5001
 
        }
5002
 
        else{
5003
 
                ese = em->selected.first;
5004
 
                mergevert = (EditVert*)ese->data;
5005
 
        }
5006
 
 
5007
 
        if(mergevert->f&SELECT){
5008
 
                for (eve=em->verts.first; eve; eve=eve->next){
5009
 
                        if (eve->f&SELECT)
5010
 
                        VECCOPY(eve->co,mergevert->co);
5011
 
                }
5012
 
        }
5013
 
 
5014
 
        if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){
5015
 
 
5016
 
                for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
5017
 
                for(eve=em->verts.first; eve; eve=eve->next){
5018
 
                        if(eve->f&SELECT) eve->f1 = 1;
5019
 
                }
5020
 
                collapseuvs(em, mergevert);
5021
 
        }
5022
 
 
5023
 
        return removedoublesflag(em, 1, 0, MERGELIMIT);
 
1844
        if (first == 0) {
 
1845
                ese = em->bm->selected.last;
 
1846
                mergevert = (BMVert *)ese->ele;
 
1847
        }
 
1848
        else {
 
1849
                ese = em->bm->selected.first;
 
1850
                mergevert = (BMVert *)ese->ele;
 
1851
        }
 
1852
 
 
1853
        if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
 
1854
                return OPERATOR_CANCELLED;
 
1855
        
 
1856
        if (uvmerge) {
 
1857
                if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_ELEM_SELECT, mergevert))
 
1858
                        return OPERATOR_CANCELLED;
 
1859
        }
 
1860
 
 
1861
        if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, mergevert->co))
 
1862
                return OPERATOR_CANCELLED;
 
1863
 
 
1864
        return OPERATOR_FINISHED;
5024
1865
}
5025
1866
 
5026
 
static void em_snap_to_center(EditMesh *em)
 
1867
static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, 
 
1868
                        int target, int uvmerge, wmOperator *wmop)
5027
1869
{
5028
 
        EditVert *eve;
5029
 
        float cent[3] = {0.0f, 0.0f, 0.0f};
5030
 
        int i=0;
 
1870
        BMIter iter;
 
1871
        BMVert *v;
 
1872
        float *vco = NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f};
5031
1873
 
5032
 
        for (eve=em->verts.first; eve; eve=eve->next) {
5033
 
                if (eve->f & SELECT) {
5034
 
                        add_v3_v3(cent, eve->co);
 
1874
        if (target) {
 
1875
                vco = give_cursor(scene, v3d);
 
1876
                copy_v3_v3(co, vco);
 
1877
                mul_m4_v3(ob->imat, co);
 
1878
        }
 
1879
        else {
 
1880
                float fac;
 
1881
                int i = 0;
 
1882
                BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
 
1883
                        if (!BM_elem_flag_test(v, BM_ELEM_SELECT))
 
1884
                                continue;
 
1885
                        add_v3_v3(cent, v->co);
5035
1886
                        i++;
5036
1887
                }
5037
 
        }
5038
 
 
5039
 
        if (!i)
5040
 
                return;
5041
 
 
5042
 
        mul_v3_fl(cent, 1.0f / (float)i);
5043
 
 
5044
 
        for (eve=em->verts.first; eve; eve=eve->next) {
5045
 
                if (eve->f & SELECT) {
5046
 
                        VECCOPY(eve->co, cent);
5047
 
                }
5048
 
        }
 
1888
                
 
1889
                if (!i)
 
1890
                        return OPERATOR_CANCELLED;
 
1891
 
 
1892
                fac = 1.0f / (float)i;
 
1893
                mul_v3_fl(cent, fac);
 
1894
                copy_v3_v3(co, cent);
 
1895
                vco = co;
 
1896
        }
 
1897
 
 
1898
        if (!vco)
 
1899
                return OPERATOR_CANCELLED;
 
1900
        
 
1901
        if (uvmerge) {
 
1902
                if (!EDBM_op_callf(em, wmop, "vert_average_facedata verts=%hv", BM_ELEM_SELECT))
 
1903
                        return OPERATOR_CANCELLED;
 
1904
        }
 
1905
 
 
1906
        if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, co))
 
1907
                return OPERATOR_CANCELLED;
 
1908
 
 
1909
        return OPERATOR_FINISHED;
5049
1910
}
5050
1911
 
5051
 
static void em_snap_to_cursor(EditMesh *em, bContext *C)
 
1912
static int edbm_merge_exec(bContext *C, wmOperator *op)
5052
1913
{
5053
1914
        Scene *scene = CTX_data_scene(C);
5054
 
        Object *ob= CTX_data_edit_object(C);
5055
1915
        View3D *v3d = CTX_wm_view3d(C);
5056
 
        EditVert *eve;
5057
 
        float co[3], *vco, invmat[4][4];
5058
 
                
5059
 
        invert_m4_m4(invmat, ob->obmat);
5060
 
 
5061
 
        vco = give_cursor(scene, v3d);
5062
 
        VECCOPY(co, vco);
5063
 
        mul_m4_v3(invmat, co);
5064
 
 
5065
 
        for (eve=em->verts.first; eve; eve=eve->next) {
5066
 
                if (eve->f & SELECT) {
5067
 
                        VECCOPY(eve->co, co);
5068
 
                }
5069
 
        }
5070
 
}
5071
 
 
5072
 
static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge)
5073
 
{
5074
 
        EditVert *eve;
5075
 
 
5076
 
        // XXX not working
5077
 
        if(target) em_snap_to_cursor(em, C);
5078
 
        else em_snap_to_center(em);
5079
 
 
5080
 
        if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){
5081
 
                for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0;
5082
 
                for(eve=em->verts.first; eve; eve=eve->next){
5083
 
                                if(eve->f&SELECT) eve->f1 = 1;
5084
 
                }
5085
 
                collapseuvs(em, NULL);
5086
 
        }
5087
 
 
5088
 
        return removedoublesflag(em, 1, 0, MERGELIMIT);
5089
 
}
5090
 
#undef MERGELIMIT
5091
 
 
5092
 
static int merge_exec(bContext *C, wmOperator *op)
5093
 
{
5094
 
        Object *obedit= CTX_data_edit_object(C);
5095
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5096
 
        int count= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
5097
 
        EditSelection *ese;
5098
 
        int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
5099
 
 
5100
 
        switch(RNA_enum_get(op->ptr, "type")) {
 
1916
        Object *obedit = CTX_data_edit_object(C);
 
1917
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
1918
        int status = 0, uvs = RNA_boolean_get(op->ptr, "uvs");
 
1919
 
 
1920
        switch (RNA_enum_get(op->ptr, "type")) {
5101
1921
                case 3:
5102
 
                        count = merge_target(C, em, 0, uvs);
 
1922
                        status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
5103
1923
                        break;
5104
1924
                case 4:
5105
 
                        count = merge_target(C, em, 1, uvs);
 
1925
                        status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
5106
1926
                        break;
5107
1927
                case 1:
5108
 
                        ese= (EditSelection *)em->selected.last;
5109
 
                        if(ese && ese->type == EDITVERT) {
5110
 
                                count = merge_firstlast(em, 0, uvs);
5111
 
                        } else {
5112
 
                                BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
5113
 
                        }
 
1928
                        status = merge_firstlast(em, 0, uvs, op);
5114
1929
                        break;
5115
1930
                case 6:
5116
 
                        ese= (EditSelection *)em->selected.first;
5117
 
                        if(ese && ese->type == EDITVERT) {
5118
 
                                count = merge_firstlast(em, 1, uvs);
5119
 
                        }
5120
 
                        else {
5121
 
                                BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
5122
 
                        }
 
1931
                        status = merge_firstlast(em, 1, uvs, op);
5123
1932
                        break;
5124
1933
                case 5:
5125
 
                        count = collapseEdges(em);
 
1934
                        status = 1;
 
1935
                        if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
 
1936
                                status = 0;
5126
1937
                        break;
5127
1938
        }
5128
1939
 
5129
 
        if (!(totvert != em->totvert || totedge != em->totedge || totface != em->totface))
 
1940
        if (!status)
5130
1941
                return OPERATOR_CANCELLED;
5131
1942
 
5132
 
        recalc_editnormals(em);
5133
 
        
5134
 
        BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices");
5135
 
 
5136
 
        BKE_mesh_end_editmesh(obedit->data, em);
5137
 
 
5138
 
        DAG_id_tag_update(obedit->data, 0);
5139
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
1943
        EDBM_update_generic(C, em, TRUE);
5140
1944
 
5141
1945
        return OPERATOR_FINISHED;
5142
1946
}
5143
1947
 
5144
 
static EnumPropertyItem merge_type_items[]= {
 
1948
static EnumPropertyItem merge_type_items[] = {
5145
1949
        {6, "FIRST", 0, "At First", ""},
5146
1950
        {1, "LAST", 0, "At Last", ""},
5147
1951
        {3, "CENTER", 0, "At Center", ""},
5149
1953
        {5, "COLLAPSE", 0, "Collapse", ""},
5150
1954
        {0, NULL, 0, NULL, NULL}};
5151
1955
 
5152
 
static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
 
1956
static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), int *free)
5153
1957
{       
5154
 
        Object *obedit= CTX_data_edit_object(C);
5155
 
        EnumPropertyItem *item= NULL;
5156
 
        int totitem= 0;
5157
 
 
5158
 
        if (C==NULL) {
 
1958
        Object *obedit;
 
1959
        EnumPropertyItem *item = NULL;
 
1960
        int totitem = 0;
 
1961
        
 
1962
        if (!C) /* needed for docs */
5159
1963
                return merge_type_items;
5160
 
        }
5161
 
 
5162
 
        if(obedit && obedit->type == OB_MESH) {
5163
 
                EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
5164
 
 
5165
 
                if(em->selectmode & SCE_SELECT_VERTEX) {
5166
 
                        if(em->selected.first && em->selected.last &&
5167
 
                                ((EditSelection*)em->selected.first)->type == EDITVERT && ((EditSelection*)em->selected.last)->type == EDITVERT) {
5168
 
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
5169
 
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
5170
 
                        }
5171
 
                        else if(em->selected.first && ((EditSelection*)em->selected.first)->type == EDITVERT)
5172
 
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
5173
 
                        else if(em->selected.last && ((EditSelection*)em->selected.last)->type == EDITVERT)
5174
 
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
 
1964
        
 
1965
        obedit = CTX_data_edit_object(C);
 
1966
        if (obedit && obedit->type == OB_MESH) {
 
1967
                BMEditMesh *em = BMEdit_FromObject(obedit);
 
1968
 
 
1969
                if (em->selectmode & SCE_SELECT_VERTEX) {
 
1970
                        if (em->bm->selected.first && em->bm->selected.last &&
 
1971
                            ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT &&
 
1972
                            ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT)
 
1973
                        {
 
1974
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
 
1975
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
 
1976
                        }
 
1977
                        else if (em->bm->selected.first && ((BMEditSelection *)em->bm->selected.first)->htype == BM_VERT) {
 
1978
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
 
1979
                        }
 
1980
                        else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == BM_VERT) {
 
1981
                                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
 
1982
                        }
5175
1983
                }
5176
1984
 
5177
1985
                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
5178
1986
                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
5179
1987
                RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
 
1988
                RNA_enum_item_end(&item, &totitem);
 
1989
 
 
1990
                *free = 1;
 
1991
 
 
1992
                return item;
5180
1993
        }
5181
 
 
5182
 
        RNA_enum_item_end(&item, &totitem);
5183
 
        *free= 1;
5184
 
 
5185
 
        return item;
 
1994
        
 
1995
        return NULL;
5186
1996
}
5187
1997
 
5188
1998
void MESH_OT_merge(wmOperatorType *ot)
5189
1999
{
5190
 
        PropertyRNA *prop;
5191
 
 
5192
2000
        /* identifiers */
5193
 
        ot->name= "Merge";
5194
 
        ot->description= "Merge selected vertices";
5195
 
        ot->idname= "MESH_OT_merge";
 
2001
        ot->name = "Merge";
 
2002
        ot->description = "Merge selected vertices";
 
2003
        ot->idname = "MESH_OT_merge";
5196
2004
 
5197
2005
        /* api callbacks */
5198
 
        ot->exec= merge_exec;
5199
 
        ot->invoke= WM_menu_invoke;
5200
 
        ot->poll= ED_operator_editmesh;
 
2006
        ot->exec = edbm_merge_exec;
 
2007
        ot->invoke = WM_menu_invoke;
 
2008
        ot->poll = ED_operator_editmesh;
5201
2009
 
5202
2010
        /* flags */
5203
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
2011
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
5204
2012
 
5205
2013
        /* properties */
5206
 
        prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
5207
 
        RNA_def_enum_funcs(prop, merge_type_itemf);
5208
 
        ot->prop= prop;
5209
 
        RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge");
 
2014
        ot->prop = RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use");
 
2015
        RNA_def_enum_funcs(ot->prop, merge_type_itemf);
 
2016
        RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge");
 
2017
}
 
2018
 
 
2019
 
 
2020
static int edbm_remove_doubles_exec(bContext *C, wmOperator *op)
 
2021
{
 
2022
        Object *obedit = CTX_data_edit_object(C);
 
2023
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
2024
        BMOperator bmop;
 
2025
        int count;
 
2026
 
 
2027
        EDBM_op_init(em, &bmop, op, "finddoubles verts=%hv dist=%f", BM_ELEM_SELECT, RNA_float_get(op->ptr, "mergedist"));
 
2028
        BMO_op_exec(em->bm, &bmop);
 
2029
 
 
2030
        count = BMO_slot_map_count(em->bm, &bmop, "targetmapout");
 
2031
 
 
2032
        if (!EDBM_op_callf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
 
2033
                BMO_op_finish(em->bm, &bmop);
 
2034
                return OPERATOR_CANCELLED;
 
2035
        }
 
2036
 
 
2037
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
2038
                return OPERATOR_CANCELLED;
 
2039
        }
 
2040
        
 
2041
        BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count == 1) ? "ex" : "ices");
 
2042
 
 
2043
        EDBM_update_generic(C, em, TRUE);
 
2044
 
 
2045
        return OPERATOR_FINISHED;
 
2046
}
 
2047
 
 
2048
void MESH_OT_remove_doubles(wmOperatorType *ot)
 
2049
{
 
2050
        /* identifiers */
 
2051
        ot->name = "Remove Doubles";
 
2052
        ot->description = "Remove duplicate vertices";
 
2053
        ot->idname = "MESH_OT_remove_doubles";
 
2054
 
 
2055
        /* api callbacks */
 
2056
        ot->exec = edbm_remove_doubles_exec;
 
2057
        ot->poll = ED_operator_editmesh;
 
2058
 
 
2059
        /* flags */
 
2060
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2061
 
 
2062
        RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f, 
 
2063
                      "Merge Distance",
 
2064
                      "Minimum distance between elements to merge", 0.00001, 10.0);
5210
2065
}
5211
2066
 
5212
2067
/************************ Vertex Path Operator *************************/
5213
2068
 
5214
2069
typedef struct PathNode {
5215
 
        int u;
5216
 
        int visited;
 
2070
        /* int u; */       /* UNUSED */
 
2071
        /* int visited; */ /* UNUSED */
5217
2072
        ListBase edges;
5218
2073
} PathNode;
5219
2074
 
5223
2078
        float w;
5224
2079
} PathEdge;
5225
2080
 
5226
 
#define PATH_SELECT_EDGE_LENGTH 0
5227
 
#define PATH_SELECT_TOPOLOGICAL 1
5228
 
 
5229
 
static int select_vertex_path_exec(bContext *C, wmOperator *op)
 
2081
 
 
2082
 
 
2083
static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op)
5230
2084
{
5231
 
        Object *obedit= CTX_data_edit_object(C);
5232
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5233
 
        EditVert *eve, *s, *t;
5234
 
        EditEdge *eed;
5235
 
        PathEdge *newpe, *currpe;
5236
 
        PathNode *currpn;
5237
 
        PathNode *Q;
5238
 
        int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
5239
 
        int unbalanced, totnodes;
5240
 
        float *cost;
5241
 
        int type= RNA_enum_get(op->ptr, "type");
5242
 
        Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
5243
 
 
5244
 
        s = t = NULL;
5245
 
        for(eve=em->verts.first; eve; eve=eve->next) {
5246
 
                if(eve->f&SELECT) {
5247
 
                        if(s == NULL) s= eve;
5248
 
                        else if(t == NULL) t= eve;
5249
 
                        else {
5250
 
                                /* more than two vertices are selected,
5251
 
                                   show warning message and cancel operator */
5252
 
                                s = t = NULL;
5253
 
                                break;
5254
 
                        }
5255
 
 
5256
 
                }
5257
 
 
5258
 
                /*need to find out if t is actually reachable by s....*/
5259
 
                eve->f1 = 0;
5260
 
        }
5261
 
 
5262
 
        if(s != NULL && t != NULL) {
5263
 
                s->f1 = 1;
5264
 
 
5265
 
                unbalanced = 1;
5266
 
                totnodes = 1;
5267
 
                while(unbalanced){
5268
 
                        unbalanced = 0;
5269
 
                        for(eed=em->edges.first; eed; eed=eed->next){
5270
 
                                if(!eed->h){
5271
 
                                        if(eed->v1->f1 && !eed->v2->f1){
5272
 
                                                        eed->v2->f1 = 1;
5273
 
                                                        totnodes++;
5274
 
                                                        unbalanced = 1;
5275
 
                                        }
5276
 
                                        else if(eed->v2->f1 && !eed->v1->f1){
5277
 
                                                        eed->v1->f1 = 1;
5278
 
                                                        totnodes++;
5279
 
                                                        unbalanced = 1;
5280
 
                                        }
5281
 
                                }
5282
 
                        }
5283
 
                }
5284
 
 
5285
 
                if(s->f1 && t->f1){ /* t can be reached by s */
5286
 
                        Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
5287
 
                        totnodes = 0;
5288
 
                        for(eve=em->verts.first; eve; eve=eve->next){
5289
 
                                if(eve->f1){
5290
 
                                        Q[totnodes].u = totnodes;
5291
 
                                        Q[totnodes].edges.first = 0;
5292
 
                                        Q[totnodes].edges.last = 0;
5293
 
                                        Q[totnodes].visited = 0;
5294
 
                                        eve->tmp.p = &(Q[totnodes]);
5295
 
                                        totnodes++;
5296
 
                                }
5297
 
                                else eve->tmp.p = NULL;
5298
 
                        }
5299
 
 
5300
 
                        for(eed=em->edges.first; eed; eed=eed->next){
5301
 
                                if(!eed->h){
5302
 
                                        if(eed->v1->f1){
5303
 
                                                currpn = ((PathNode*)eed->v1->tmp.p);
5304
 
 
5305
 
                                                newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
5306
 
                                                newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
5307
 
                                                if (type == PATH_SELECT_EDGE_LENGTH) {
5308
 
                                                                newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
5309
 
                                                }
5310
 
                                                else newpe->w = 1;
5311
 
                                                newpe->next = 0;
5312
 
                                                newpe->prev = 0;
5313
 
                                                BLI_addtail(&(currpn->edges), newpe);
5314
 
                                        }
5315
 
                                        if(eed->v2->f1){
5316
 
                                                currpn = ((PathNode*)eed->v2->tmp.p);
5317
 
                                                newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
5318
 
                                                newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
5319
 
                                                if (type == PATH_SELECT_EDGE_LENGTH) {
5320
 
                                                                newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
5321
 
                                                }
5322
 
                                                else newpe->w = 1;
5323
 
                                                newpe->next = 0;
5324
 
                                                newpe->prev = 0;
5325
 
                                                BLI_addtail(&(currpn->edges), newpe);
5326
 
                                        }
5327
 
                                }
5328
 
                        }
5329
 
 
5330
 
                        heap = BLI_heap_new();
5331
 
                        cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
5332
 
                        previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
5333
 
 
5334
 
                        for(v=0; v < totnodes; v++){
5335
 
                                cost[v] = 1000000;
5336
 
                                previous[v] = -1; /*array of indices*/
5337
 
                        }
5338
 
 
5339
 
                        pnindex = ((PathNode*)s->tmp.p)->u;
5340
 
                        cost[pnindex] = 0;
5341
 
                        BLI_heap_insert(heap,  0.0f, SET_INT_IN_POINTER(pnindex));
5342
 
 
5343
 
                        while( !BLI_heap_empty(heap) ){
5344
 
 
5345
 
                                pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
5346
 
                                currpn = &(Q[pnindex]);
5347
 
 
5348
 
                                if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
5349
 
                                        break;
5350
 
 
5351
 
                                for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
5352
 
                                        if(!Q[currpe->v].visited){
5353
 
                                                if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
5354
 
                                                        cost[currpe->v] = cost[currpn->u] + currpe->w;
5355
 
                                                        previous[currpe->v] = currpn->u;
5356
 
                                                        Q[currpe->v].visited = 1;
5357
 
                                                        BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
5358
 
                                                }
5359
 
                                        }
5360
 
                                }
5361
 
                        }
5362
 
 
5363
 
                        pathvert = ((PathNode*)t->tmp.p)->u;
5364
 
                        while(pathvert != -1){
5365
 
                                for(eve=em->verts.first; eve; eve=eve->next){
5366
 
                                        if(eve->f1){
5367
 
                                                if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
5368
 
                                        }
5369
 
                                }
5370
 
                                pathvert = previous[pathvert];
5371
 
                        }
5372
 
 
5373
 
                        for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
5374
 
                        MEM_freeN(Q);
5375
 
                        MEM_freeN(cost);
5376
 
                        MEM_freeN(previous);
5377
 
                        BLI_heap_free(heap, NULL);
5378
 
                        EM_select_flush(em);
5379
 
                }
5380
 
        }
5381
 
        else {
5382
 
                BKE_mesh_end_editmesh(obedit->data, em);
5383
 
                BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected");
5384
 
                return OPERATOR_CANCELLED;
5385
 
        }
5386
 
 
5387
 
        WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5388
 
        BKE_mesh_end_editmesh(obedit->data, em);
5389
 
 
 
2085
        Object *ob = CTX_data_edit_object(C);
 
2086
        BMEditMesh *em = BMEdit_FromObject(ob);
 
2087
        BMOperator bmop;
 
2088
        BMEditSelection *sv, *ev;
 
2089
 
 
2090
        /* get the type from RNA */
 
2091
        int type = RNA_enum_get(op->ptr, "type");
 
2092
 
 
2093
        sv = em->bm->selected.last;
 
2094
        if (sv != NULL)
 
2095
                ev = sv->prev;
 
2096
        else return OPERATOR_CANCELLED;
 
2097
        if (ev == NULL)
 
2098
                return OPERATOR_CANCELLED;
 
2099
 
 
2100
        if ((sv->htype != BM_VERT) || (ev->htype != BM_VERT))
 
2101
                return OPERATOR_CANCELLED;
 
2102
 
 
2103
        /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
 
2104
        EDBM_op_init(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%i", sv->ele, ev->ele, type);
 
2105
 
 
2106
        /* execute the operator */
 
2107
        BMO_op_exec(em->bm, &bmop);
 
2108
 
 
2109
        /* DO NOT clear the existing selection */
 
2110
        /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
 
2111
 
 
2112
        /* select the output */
 
2113
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
2114
 
 
2115
        /* finish the operator */
 
2116
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
2117
                return OPERATOR_CANCELLED;
 
2118
        }
 
2119
 
 
2120
        EDBM_selectmode_flush(em);
 
2121
 
 
2122
        EDBM_update_generic(C, em, FALSE);
 
2123
 
 
2124
        /* we succeeded */
5390
2125
        return OPERATOR_FINISHED;
5391
2126
}
5392
2127
 
5393
2128
void MESH_OT_select_vertex_path(wmOperatorType *ot)
5394
2129
{
5395
2130
        static const EnumPropertyItem type_items[] = {
5396
 
                {PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
5397
 
                {PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
5398
 
                {0, NULL, 0, NULL, NULL}};
 
2131
                {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
 
2132
                {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
 
2133
                {0, NULL, 0, NULL, NULL}
 
2134
        };
5399
2135
 
5400
2136
        /* identifiers */
5401
 
        ot->name= "Select Vertex Path";
5402
 
        ot->description= "Select shortest path between two vertices by distance type";
5403
 
        ot->idname= "MESH_OT_select_vertex_path";
 
2137
        ot->name = "Select Vertex Path";
 
2138
        ot->idname = "MESH_OT_select_vertex_path";
 
2139
        ot->description = "Selected vertex path between two vertices";
5404
2140
 
5405
2141
        /* api callbacks */
5406
 
        ot->exec= select_vertex_path_exec;
5407
 
        ot->poll= ED_operator_editmesh;
 
2142
        ot->exec = edbm_select_vertex_path_exec;
 
2143
        ot->poll = ED_operator_editmesh;
5408
2144
 
5409
2145
        /* flags */
5410
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
2146
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
5411
2147
 
5412
2148
        /* properties */
5413
 
        ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance");
5414
 
}
5415
 
 
5416
 
/********************** Region/Loop Operators *************************/
5417
 
 
5418
 
static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
5419
 
{
5420
 
        Object *obedit= CTX_data_edit_object(C);
5421
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5422
 
        EditEdge *eed;
5423
 
        EditFace *efa;
5424
 
        int selected= 0;
5425
 
 
5426
 
        for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
5427
 
 
5428
 
        for(efa=em->faces.first; efa; efa=efa->next){
5429
 
                if(efa->f&SELECT){
5430
 
                        efa->e1->f1++;
5431
 
                        efa->e2->f1++;
5432
 
                        efa->e3->f1++;
5433
 
                        if(efa->e4)
5434
 
                                efa->e4->f1++;
5435
 
 
5436
 
                        selected= 1;
5437
 
                }
5438
 
        }
5439
 
 
5440
 
        if(!selected)
5441
 
                return OPERATOR_CANCELLED;
5442
 
 
5443
 
        EM_clear_flag_all(em, SELECT);
5444
 
 
5445
 
        for(eed=em->edges.first; eed; eed=eed->next){
5446
 
                if(eed->f1 == 1) EM_select_edge(eed, 1);
5447
 
        }
5448
 
 
5449
 
        em->selectmode = SCE_SELECT_EDGE;
5450
 
        CTX_data_tool_settings(C)->selectmode= em->selectmode;
5451
 
        EM_selectmode_set(em);
5452
 
 
5453
 
        BKE_mesh_end_editmesh(obedit->data, em);
5454
 
 
5455
 
        WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5456
 
 
5457
 
        return OPERATOR_FINISHED;
5458
 
}
5459
 
 
5460
 
void MESH_OT_region_to_loop(wmOperatorType *ot)
5461
 
{
5462
 
        /* identifiers */
5463
 
        ot->name= "Region to Loop";
5464
 
        ot->description= "Select a region as a loop of connected edges";
5465
 
        ot->idname= "MESH_OT_region_to_loop";
5466
 
 
5467
 
        /* api callbacks */
5468
 
        ot->exec= region_to_loop;
5469
 
        ot->poll= ED_operator_editmesh;
5470
 
 
5471
 
        /* flags */
5472
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5473
 
}
5474
 
 
5475
 
static int validate_loop(EditMesh *em, Collection *edgecollection)
5476
 
{
5477
 
        EditEdge *eed;
5478
 
        EditFace *efa;
5479
 
        CollectedEdge *curredge;
5480
 
 
5481
 
        /*1st test*/
5482
 
        for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5483
 
                curredge->eed->v1->f1 = 0;
5484
 
                curredge->eed->v2->f1 = 0;
5485
 
        }
5486
 
        for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5487
 
                curredge->eed->v1->f1++;
5488
 
                curredge->eed->v2->f1++;
5489
 
        }
5490
 
        for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5491
 
                if(curredge->eed->v1->f1 > 2) return(0); else
5492
 
                if(curredge->eed->v2->f1 > 2) return(0);
5493
 
        }
5494
 
 
5495
 
        /*2nd test*/
5496
 
        for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0;
5497
 
        for(efa=em->faces.first; efa; efa=efa->next){
5498
 
                efa->e1->f1++;
5499
 
                efa->e2->f1++;
5500
 
                efa->e3->f1++;
5501
 
                if(efa->e4) efa->e4->f1++;
5502
 
        }
5503
 
        for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5504
 
                if(curredge->eed->f1 > 2) return(0);
5505
 
        }
5506
 
        return(1);
5507
 
}
5508
 
 
5509
 
static int loop_bisect(EditMesh *em, Collection *edgecollection)
5510
 
{
5511
 
        EditFace *efa, *sf1, *sf2;
5512
 
        EditEdge *eed, *sed;
5513
 
        CollectedEdge *curredge;
5514
 
        int totsf1, totsf2, unbalanced,balancededges;
5515
 
 
5516
 
        for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
5517
 
        for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = 0;
5518
 
 
5519
 
        for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
5520
 
 
5521
 
        sf1 = sf2 = NULL;
5522
 
        sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
5523
 
 
5524
 
        for(efa=em->faces.first; efa; efa=efa->next){
5525
 
                if(sf2) break;
5526
 
                else if(sf1){
5527
 
                        if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
5528
 
                }
5529
 
                else{
5530
 
                        if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa;
5531
 
                }
5532
 
        }
5533
 
 
5534
 
        if(sf1==NULL || sf2==NULL)
5535
 
                return(-1);
5536
 
 
5537
 
        if(!(sf1->e1->f1)) sf1->e1->f2 = 1;
5538
 
        if(!(sf1->e2->f1)) sf1->e2->f2 = 1;
5539
 
        if(!(sf1->e3->f1)) sf1->e3->f2 = 1;
5540
 
        if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1;
5541
 
        sf1->f1 = 1;
5542
 
        totsf1 = 1;
5543
 
 
5544
 
        if(!(sf2->e1->f1)) sf2->e1->f2 = 2;
5545
 
        if(!(sf2->e2->f1)) sf2->e2->f2 = 2;
5546
 
        if(!(sf2->e3->f1)) sf2->e3->f2 = 2;
5547
 
        if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2;
5548
 
        sf2->f1 = 2;
5549
 
        totsf2 = 1;
5550
 
 
5551
 
        /*do sf1*/
5552
 
        unbalanced = 1;
5553
 
        while(unbalanced){
5554
 
                unbalanced = 0;
5555
 
                for(efa=em->faces.first; efa; efa=efa->next){
5556
 
                        balancededges = 0;
5557
 
                        if(efa->f1 == 0){
5558
 
                                if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){
5559
 
                                        balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1;
5560
 
                                        balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1;
5561
 
                                        balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1;
5562
 
                                        if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1;
5563
 
                                        if(balancededges){
5564
 
                                                unbalanced = 1;
5565
 
                                                efa->f1 = 1;
5566
 
                                                totsf1++;
5567
 
                                        }
5568
 
                                }
5569
 
                        }
5570
 
                }
5571
 
        }
5572
 
 
5573
 
        /*do sf2*/
5574
 
        unbalanced = 1;
5575
 
        while(unbalanced){
5576
 
                unbalanced = 0;
5577
 
                for(efa=em->faces.first; efa; efa=efa->next){
5578
 
                        balancededges = 0;
5579
 
                        if(efa->f1 == 0){
5580
 
                                if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){
5581
 
                                        balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2;
5582
 
                                        balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2;
5583
 
                                        balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2;
5584
 
                                        if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2;
5585
 
                                        if(balancededges){
5586
 
                                                unbalanced = 1;
5587
 
                                                efa->f1 = 2;
5588
 
                                                totsf2++;
5589
 
                                        }
5590
 
                                }
5591
 
                        }
5592
 
                }
5593
 
        }
5594
 
 
5595
 
        if(totsf1 < totsf2) return(1);
5596
 
        else return(2);
5597
 
}
5598
 
 
5599
 
static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
5600
 
{
5601
 
        Object *obedit= CTX_data_edit_object(C);
5602
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5603
 
 
5604
 
 
5605
 
        EditFace *efa;
5606
 
        ListBase allcollections={NULL,NULL};
5607
 
        Collection *edgecollection;
5608
 
        int testflag;
5609
 
 
5610
 
        build_edgecollection(em, &allcollections);
5611
 
 
5612
 
        for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
5613
 
                if(validate_loop(em, edgecollection)){
5614
 
                        testflag = loop_bisect(em, edgecollection);
5615
 
                        for(efa=em->faces.first; efa; efa=efa->next){
5616
 
                                if(efa->f1 == testflag){
5617
 
                                        if(efa->f&SELECT) EM_select_face(efa, 0);
5618
 
                                        else EM_select_face(efa,1);
5619
 
                                }
5620
 
                        }
5621
 
                }
5622
 
        }
5623
 
 
5624
 
        for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/
5625
 
                if(efa->f&SELECT) EM_select_face(efa,1);
5626
 
        }
5627
 
 
5628
 
        freecollections(&allcollections);
5629
 
        BKE_mesh_end_editmesh(obedit->data, em);
5630
 
 
5631
 
        WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5632
 
 
5633
 
        return OPERATOR_FINISHED;
5634
 
}
5635
 
 
5636
 
void MESH_OT_loop_to_region(wmOperatorType *ot)
5637
 
{
5638
 
        /* identifiers */
5639
 
        ot->name= "Loop to Region";
5640
 
        ot->description= "Select a loop of connected edges as a region";
5641
 
        ot->idname= "MESH_OT_loop_to_region";
5642
 
 
5643
 
        /* api callbacks */
5644
 
        ot->exec= loop_to_region;
5645
 
        ot->poll= ED_operator_editmesh;
5646
 
 
5647
 
        /* flags */
5648
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5649
 
}
5650
 
 
5651
 
/********************** UV/Color Operators *************************/
5652
 
 
5653
 
// XXX please check if these functions do what you want them to
5654
 
/* texface and vertex color editmode tools for the face menu */
5655
 
 
5656
 
static int mesh_rotate_uvs(bContext *C, wmOperator *op)
5657
 
{
5658
 
        Object *obedit= CTX_data_edit_object(C);
5659
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5660
 
 
5661
 
        EditFace *efa;
5662
 
        short change = 0;
5663
 
        MTFace *tf;
5664
 
        float u1, v1;
5665
 
        int dir= RNA_enum_get(op->ptr, "direction");
5666
 
 
5667
 
        if (!EM_texFaceCheck(em)) {
5668
 
                BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
5669
 
                BKE_mesh_end_editmesh(obedit->data, em);
5670
 
                return OPERATOR_CANCELLED;
5671
 
        }
5672
 
 
5673
 
        for(efa=em->faces.first; efa; efa=efa->next) {
5674
 
                if (efa->f & SELECT) {
5675
 
                        tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
5676
 
                        u1= tf->uv[0][0];
5677
 
                        v1= tf->uv[0][1];
5678
 
 
5679
 
                        if (dir == DIRECTION_CCW) {
5680
 
                                if(efa->v4) {
5681
 
                                        tf->uv[0][0]= tf->uv[3][0];
5682
 
                                        tf->uv[0][1]= tf->uv[3][1];
5683
 
 
5684
 
                                        tf->uv[3][0]= tf->uv[2][0];
5685
 
                                        tf->uv[3][1]= tf->uv[2][1];
5686
 
                                } else {
5687
 
                                        tf->uv[0][0]= tf->uv[2][0];
5688
 
                                        tf->uv[0][1]= tf->uv[2][1];
5689
 
                                }
5690
 
 
5691
 
                                tf->uv[2][0]= tf->uv[1][0];
5692
 
                                tf->uv[2][1]= tf->uv[1][1];
5693
 
 
5694
 
                                tf->uv[1][0]= u1;
5695
 
                                tf->uv[1][1]= v1;
5696
 
                        } else {
5697
 
                                tf->uv[0][0]= tf->uv[1][0];
5698
 
                                tf->uv[0][1]= tf->uv[1][1];
5699
 
 
5700
 
                                tf->uv[1][0]= tf->uv[2][0];
5701
 
                                tf->uv[1][1]= tf->uv[2][1];
5702
 
 
5703
 
                                if(efa->v4) {
5704
 
                                        tf->uv[2][0]= tf->uv[3][0];
5705
 
                                        tf->uv[2][1]= tf->uv[3][1];
5706
 
 
5707
 
                                        tf->uv[3][0]= u1;
5708
 
                                        tf->uv[3][1]= v1;
5709
 
                                }
5710
 
                                else {
5711
 
                                        tf->uv[2][0]= u1;
5712
 
                                        tf->uv[2][1]= v1;
5713
 
                                }
5714
 
                        }
5715
 
                        change = 1;
5716
 
                }
5717
 
        }
5718
 
 
5719
 
        BKE_mesh_end_editmesh(obedit->data, em);
5720
 
 
5721
 
        if(!change)
5722
 
                return OPERATOR_CANCELLED;
5723
 
 
5724
 
        DAG_id_tag_update(obedit->data, 0);
5725
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5726
 
 
5727
 
        return OPERATOR_FINISHED;
5728
 
}
5729
 
 
5730
 
static int mesh_mirror_uvs(bContext *C, wmOperator *op)
5731
 
{
5732
 
        Object *obedit= CTX_data_edit_object(C);
5733
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5734
 
 
5735
 
        EditFace *efa;
5736
 
        short change = 0;
5737
 
        MTFace *tf;
5738
 
        float u1, v1;
5739
 
        int axis= RNA_enum_get(op->ptr, "axis");
5740
 
 
5741
 
        if (!EM_texFaceCheck(em)) {
5742
 
                BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers");
5743
 
                BKE_mesh_end_editmesh(obedit->data, em);
5744
 
                return OPERATOR_CANCELLED;
5745
 
        }
5746
 
 
5747
 
        for(efa=em->faces.first; efa; efa=efa->next) {
5748
 
                if (efa->f & SELECT) {
5749
 
                        tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
5750
 
                        if (axis == AXIS_Y) {
5751
 
                                u1= tf->uv[1][0];
5752
 
                                v1= tf->uv[1][1];
5753
 
                                if(efa->v4) {
5754
 
 
5755
 
                                        tf->uv[1][0]= tf->uv[2][0];
5756
 
                                        tf->uv[1][1]= tf->uv[2][1];
5757
 
 
5758
 
                                        tf->uv[2][0]= u1;
5759
 
                                        tf->uv[2][1]= v1;
5760
 
 
5761
 
                                        u1= tf->uv[3][0];
5762
 
                                        v1= tf->uv[3][1];
5763
 
 
5764
 
                                        tf->uv[3][0]= tf->uv[0][0];
5765
 
                                        tf->uv[3][1]= tf->uv[0][1];
5766
 
 
5767
 
                                        tf->uv[0][0]= u1;
5768
 
                                        tf->uv[0][1]= v1;
5769
 
                                }
5770
 
                                else {
5771
 
                                        tf->uv[1][0]= tf->uv[2][0];
5772
 
                                        tf->uv[1][1]= tf->uv[2][1];
5773
 
                                        tf->uv[2][0]= u1;
5774
 
                                        tf->uv[2][1]= v1;
5775
 
                                }
5776
 
 
5777
 
                        } else {
5778
 
                                u1= tf->uv[0][0];
5779
 
                                v1= tf->uv[0][1];
5780
 
                                if(efa->v4) {
5781
 
 
5782
 
                                        tf->uv[0][0]= tf->uv[1][0];
5783
 
                                        tf->uv[0][1]= tf->uv[1][1];
5784
 
 
5785
 
                                        tf->uv[1][0]= u1;
5786
 
                                        tf->uv[1][1]= v1;
5787
 
 
5788
 
                                        u1= tf->uv[3][0];
5789
 
                                        v1= tf->uv[3][1];
5790
 
 
5791
 
                                        tf->uv[3][0]= tf->uv[2][0];
5792
 
                                        tf->uv[3][1]= tf->uv[2][1];
5793
 
 
5794
 
                                        tf->uv[2][0]= u1;
5795
 
                                        tf->uv[2][1]= v1;
5796
 
                                }
5797
 
                                else {
5798
 
                                        tf->uv[0][0]= tf->uv[1][0];
5799
 
                                        tf->uv[0][1]= tf->uv[1][1];
5800
 
                                        tf->uv[1][0]= u1;
5801
 
                                        tf->uv[1][1]= v1;
5802
 
                                }
5803
 
                        }
5804
 
                        change = 1;
5805
 
                }
5806
 
        }
5807
 
 
5808
 
        BKE_mesh_end_editmesh(obedit->data, em);
5809
 
 
5810
 
        if(!change)
5811
 
                return OPERATOR_CANCELLED;
5812
 
 
5813
 
        DAG_id_tag_update(obedit->data, 0);
5814
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5815
 
 
5816
 
        return OPERATOR_FINISHED;
5817
 
}
5818
 
 
5819
 
static int mesh_rotate_colors(bContext *C, wmOperator *op)
5820
 
{
5821
 
        Object *obedit= CTX_data_edit_object(C);
5822
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5823
 
 
5824
 
        EditFace *efa;
5825
 
        short change = 0;
5826
 
        MCol tmpcol, *mcol;
5827
 
        int dir= RNA_enum_get(op->ptr, "direction");
5828
 
 
5829
 
        if (!EM_vertColorCheck(em)) {
5830
 
                BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
5831
 
                BKE_mesh_end_editmesh(obedit->data, em);
5832
 
                return OPERATOR_CANCELLED;
5833
 
        }
5834
 
 
5835
 
        for(efa=em->faces.first; efa; efa=efa->next) {
5836
 
                if (efa->f & SELECT) {
5837
 
                        mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
5838
 
                        tmpcol= mcol[0];
5839
 
 
5840
 
                        if (dir == DIRECTION_CCW) {
5841
 
                                if(efa->v4) {
5842
 
                                        mcol[0]= mcol[3];
5843
 
                                        mcol[3]= mcol[2];
5844
 
                                } else {
5845
 
                                        mcol[0]= mcol[2];
5846
 
                                }
5847
 
                                mcol[2]= mcol[1];
5848
 
                                mcol[1]= tmpcol;
5849
 
                        } else {
5850
 
                                mcol[0]= mcol[1];
5851
 
                                mcol[1]= mcol[2];
5852
 
 
5853
 
                                if(efa->v4) {
5854
 
                                        mcol[2]= mcol[3];
5855
 
                                        mcol[3]= tmpcol;
5856
 
                                }
5857
 
                                else
5858
 
                                        mcol[2]= tmpcol;
5859
 
                        }
5860
 
                        change = 1;
5861
 
                }
5862
 
        }
5863
 
 
5864
 
        BKE_mesh_end_editmesh(obedit->data, em);
5865
 
 
5866
 
        if(!change)
5867
 
                return OPERATOR_CANCELLED;
5868
 
 
5869
 
        DAG_id_tag_update(obedit->data, 0);
5870
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5871
 
 
5872
 
        return OPERATOR_FINISHED;
5873
 
}
5874
 
 
5875
 
 
5876
 
static int mesh_mirror_colors(bContext *C, wmOperator *op)
5877
 
{
5878
 
        Object *obedit= CTX_data_edit_object(C);
5879
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5880
 
 
5881
 
        EditFace *efa;
5882
 
        short change = 0;
5883
 
        MCol tmpcol, *mcol;
5884
 
        int axis= RNA_enum_get(op->ptr, "axis");
5885
 
 
5886
 
        if (!EM_vertColorCheck(em)) {
5887
 
                BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
5888
 
                BKE_mesh_end_editmesh(obedit->data, em);
5889
 
                return OPERATOR_CANCELLED;
5890
 
        }
5891
 
 
5892
 
        for(efa=em->faces.first; efa; efa=efa->next) {
5893
 
                if (efa->f & SELECT) {
5894
 
                        mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
5895
 
                        if (axis == AXIS_Y) {
5896
 
                                tmpcol= mcol[1];
5897
 
                                mcol[1]= mcol[2];
5898
 
                                mcol[2]= tmpcol;
5899
 
 
5900
 
                                if(efa->v4) {
5901
 
                                        tmpcol= mcol[0];
5902
 
                                        mcol[0]= mcol[3];
5903
 
                                        mcol[3]= tmpcol;
5904
 
                                }
5905
 
                        } else {
5906
 
                                tmpcol= mcol[0];
5907
 
                                mcol[0]= mcol[1];
5908
 
                                mcol[1]= tmpcol;
5909
 
 
5910
 
                                if(efa->v4) {
5911
 
                                        tmpcol= mcol[2];
5912
 
                                        mcol[2]= mcol[3];
5913
 
                                        mcol[3]= tmpcol;
5914
 
                                }
5915
 
                        }
5916
 
                        change = 1;
5917
 
                }
5918
 
        }
5919
 
 
5920
 
        BKE_mesh_end_editmesh(obedit->data, em);
5921
 
 
5922
 
        if(!change)
5923
 
                return OPERATOR_CANCELLED;
5924
 
 
5925
 
        DAG_id_tag_update(obedit->data, 0);
5926
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5927
 
 
5928
 
        return OPERATOR_FINISHED;
5929
 
}
5930
 
 
5931
 
void MESH_OT_uvs_rotate(wmOperatorType *ot)
5932
 
{
5933
 
        /* identifiers */
5934
 
        ot->name= "Rotate UVs";
5935
 
        ot->description= "Rotate selected UVs";
5936
 
        ot->idname= "MESH_OT_uvs_rotate";
5937
 
 
5938
 
        /* api callbacks */
5939
 
        ot->exec= mesh_rotate_uvs;
5940
 
        ot->poll= ED_operator_editmesh;
5941
 
 
5942
 
        /* flags */
5943
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5944
 
 
5945
 
        /* props */
5946
 
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around");
5947
 
}
5948
 
 
5949
 
void MESH_OT_uvs_mirror(wmOperatorType *ot)
5950
 
{
5951
 
        /* identifiers */
5952
 
        ot->name= "Mirror UVs";
5953
 
        ot->description= "Mirror selected UVs";
5954
 
        ot->idname= "MESH_OT_uvs_mirror";
5955
 
 
5956
 
        /* api callbacks */
5957
 
        ot->exec= mesh_mirror_uvs;
5958
 
        ot->poll= ED_operator_editmesh;
5959
 
 
5960
 
        /* flags */
5961
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5962
 
 
5963
 
        /* props */
5964
 
        RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
5965
 
}
5966
 
 
5967
 
void MESH_OT_colors_rotate(wmOperatorType *ot)
5968
 
{
5969
 
        /* identifiers */
5970
 
        ot->name= "Rotate Colors";
5971
 
        ot->description= "Rotate UV/image color layer";
5972
 
        ot->idname= "MESH_OT_colors_rotate";
5973
 
 
5974
 
        /* api callbacks */
5975
 
        ot->exec= mesh_rotate_colors;
5976
 
        ot->poll= ED_operator_editmesh;
5977
 
 
5978
 
        /* flags */
5979
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5980
 
 
5981
 
        /* props */
5982
 
        RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around");
5983
 
}
5984
 
 
5985
 
void MESH_OT_colors_mirror(wmOperatorType *ot)
5986
 
{
5987
 
        /* identifiers */
5988
 
        ot->name= "Mirror Colors";
5989
 
        ot->description= "Mirror UV/image color layer";
5990
 
        ot->idname= "MESH_OT_colors_mirror";
5991
 
 
5992
 
        /* api callbacks */
5993
 
        ot->exec= mesh_mirror_colors;
5994
 
        ot->poll= ED_operator_editmesh;
5995
 
 
5996
 
        /* flags */
5997
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5998
 
 
5999
 
        /* props */
6000
 
        RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around");
6001
 
}
6002
 
 
6003
 
/********************** Subdivide Operator *************************/
6004
 
 
6005
 
static int subdivide_exec(bContext *C, wmOperator *op)
6006
 
{
6007
 
        ToolSettings *ts= CTX_data_tool_settings(C);
6008
 
        Object *obedit= CTX_data_edit_object(C);
6009
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6010
 
        int cuts= RNA_int_get(op->ptr,"number_cuts");
6011
 
        float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
6012
 
        float fractal= RNA_float_get(op->ptr, "fractal")/100;
6013
 
        int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
6014
 
        int flag= 0;
6015
 
 
6016
 
        if(smooth != 0.0f)
6017
 
                flag |= B_SMOOTH;
6018
 
        if(fractal != 0.0f)
6019
 
                flag |= B_FRACTAL;
6020
 
 
6021
 
        esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0);
6022
 
 
6023
 
        DAG_id_tag_update(obedit->data, 0);
6024
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6025
 
 
6026
 
        return OPERATOR_FINISHED;
6027
 
}
6028
 
 
6029
 
void MESH_OT_subdivide(wmOperatorType *ot)
 
2149
        RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance");
 
2150
}
 
2151
/********************** Rip Operator *************************/
 
2152
 
 
2153
/************************ Shape Operators *************************/
 
2154
 
 
2155
/* BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
 
2156
static void shape_propagate(BMEditMesh *em, wmOperator *op)
 
2157
{
 
2158
        BMIter iter;
 
2159
        BMVert *eve = NULL;
 
2160
        float *co;
 
2161
        int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
 
2162
 
 
2163
        if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
 
2164
                BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
 
2165
                return;
 
2166
        }
 
2167
        
 
2168
        BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 
2169
                if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
 
2170
                        continue;
 
2171
 
 
2172
                for (i = 0; i < totshape; i++) {
 
2173
                        co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
 
2174
                        copy_v3_v3(co, eve->co);
 
2175
                }
 
2176
        }
 
2177
 
 
2178
#if 0
 
2179
        //TAG Mesh Objects that share this data
 
2180
        for (base = scene->base.first; base; base = base->next) {
 
2181
                if (base->object && base->object->data == me) {
 
2182
                        base->object->recalc = OB_RECALC_DATA;
 
2183
                }
 
2184
        }
 
2185
#endif
 
2186
}
 
2187
 
 
2188
 
 
2189
static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
 
2190
{
 
2191
        Object *obedit = CTX_data_edit_object(C);
 
2192
        Mesh *me = obedit->data;
 
2193
        BMEditMesh *em = me->edit_btmesh;
 
2194
 
 
2195
        shape_propagate(em, op);
 
2196
 
 
2197
        EDBM_update_generic(C, em, FALSE);
 
2198
 
 
2199
        return OPERATOR_FINISHED;
 
2200
}
 
2201
 
 
2202
 
 
2203
void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
 
2204
{
 
2205
        /* identifiers */
 
2206
        ot->name = "Shape Propagate";
 
2207
        ot->description = "Apply selected vertex locations to all other shape keys";
 
2208
        ot->idname = "MESH_OT_shape_propagate_to_all";
 
2209
 
 
2210
        /* api callbacks */
 
2211
        ot->exec = edbm_shape_propagate_to_all_exec;
 
2212
        ot->poll = ED_operator_editmesh;
 
2213
 
 
2214
        /* flags */
 
2215
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2216
}
 
2217
 
 
2218
/* BMESH_TODO this should be properly encapsulated in a bmop.  but later.*/
 
2219
static int edbm_blend_from_shape_exec(bContext *C, wmOperator *op)
 
2220
{
 
2221
        Object *obedit = CTX_data_edit_object(C);
 
2222
        Mesh *me = obedit->data;
 
2223
        BMEditMesh *em = me->edit_btmesh;
 
2224
        BMVert *eve;
 
2225
        BMIter iter;
 
2226
        float co[3], *sco;
 
2227
        float blend = RNA_float_get(op->ptr, "blend");
 
2228
        int shape = RNA_enum_get(op->ptr, "shape");
 
2229
        int add = RNA_boolean_get(op->ptr, "add");
 
2230
        int totshape;
 
2231
 
 
2232
        /* sanity check */
 
2233
        totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
 
2234
        if (totshape == 0 || shape < 0 || shape >= totshape)
 
2235
                return OPERATOR_CANCELLED;
 
2236
 
 
2237
        BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 
2238
                if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN))
 
2239
                        continue;
 
2240
 
 
2241
                sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
 
2242
                copy_v3_v3(co, sco);
 
2243
 
 
2244
 
 
2245
                if (add) {
 
2246
                        mul_v3_fl(co, blend);
 
2247
                        add_v3_v3v3(eve->co, eve->co, co);
 
2248
                }
 
2249
                else {
 
2250
                        interp_v3_v3v3(eve->co, eve->co, co, blend);
 
2251
                }
 
2252
                
 
2253
                copy_v3_v3(sco, co);
 
2254
        }
 
2255
 
 
2256
        EDBM_update_generic(C, em, TRUE);
 
2257
 
 
2258
        return OPERATOR_FINISHED;
 
2259
}
 
2260
 
 
2261
static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr),  PropertyRNA *UNUSED(prop), int *free)
6030
2262
{       
6031
 
        /* identifiers */
6032
 
        ot->name= "Subdivide";
6033
 
        ot->description= "Subdivide selected edges";
6034
 
        ot->idname= "MESH_OT_subdivide";
6035
 
 
6036
 
        /* api callbacks */
6037
 
        ot->exec= subdivide_exec;
6038
 
        ot->poll= ED_operator_editmesh;
6039
 
 
6040
 
        /* flags */
6041
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6042
 
 
6043
 
        /* properties */
6044
 
        RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
6045
 
        RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
6046
 
        RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor", 0.0f, 1000.0f);
6047
 
        RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
6048
 
}
6049
 
 
6050
 
/********************** Fill Operators *************************/
6051
 
 
6052
 
/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
6053
 
edge/face flags, with very mixed results.... */
6054
 
static void beautify_fill(EditMesh *em)
6055
 
{
6056
 
        EditVert *v1, *v2, *v3, *v4;
6057
 
        EditEdge *eed, *nexted;
6058
 
        EditEdge dia1, dia2;
6059
 
        EditFace *efa, *w;
6060
 
        // void **efaar, **efaa;
6061
 
        EVPTuple *efaar;
6062
 
        EVPtr *efaa;
6063
 
        float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
6064
 
        int totedge, ok, notbeauty=8, onedone, vindex[4];
6065
 
 
6066
 
        /* - all selected edges with two faces
6067
 
                * - find the faces: store them in edges (using datablock)
6068
 
                * - per edge: - test convex
6069
 
                *                          - test edge: flip?
6070
 
                *                          - if true: remedge,  addedge, all edges at the edge get new face pointers
6071
 
                */
6072
 
 
6073
 
        EM_selectmode_set(em);  // makes sure in selectmode 'face' the edges of selected faces are selected too
6074
 
 
6075
 
        totedge = count_selected_edges(em->edges.first);
6076
 
        if(totedge==0) return;
6077
 
 
6078
 
        /* temp block with face pointers */
6079
 
        efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
6080
 
 
6081
 
        while (notbeauty) {
6082
 
                notbeauty--;
6083
 
 
6084
 
                ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
6085
 
 
6086
 
                /* there we go */
6087
 
                onedone= 0;
6088
 
 
6089
 
                eed= em->edges.first;
6090
 
                while(eed) {
6091
 
                        nexted= eed->next;
6092
 
 
6093
 
                        /* f2 is set in collect_quadedges() */
6094
 
                        if(eed->f2==2 && eed->h==0) {
6095
 
 
6096
 
                                efaa = (EVPtr *) eed->tmp.p;
6097
 
 
6098
 
                                /* none of the faces should be treated before, nor be part of fgon */
6099
 
                                ok= 1;
6100
 
                                efa= efaa[0];
6101
 
                                if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
6102
 
                                if(efa->fgonf) ok= 0;
6103
 
                                efa= efaa[1];
6104
 
                                if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
6105
 
                                if(efa->fgonf) ok= 0;
6106
 
 
6107
 
                                if(ok) {
6108
 
                                        /* test convex */
6109
 
                                        givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
6110
 
                                        if(v1 && v2 && v3 && v4) {
6111
 
                                                if( convex(v1->co, v2->co, v3->co, v4->co) ) {
6112
 
 
6113
 
                                                        /* test edges */
6114
 
                                                        if( (v1) > (v3) ) {
6115
 
                                                                dia1.v1= v3;
6116
 
                                                                dia1.v2= v1;
6117
 
                                                        }
6118
 
                                                        else {
6119
 
                                                                dia1.v1= v1;
6120
 
                                                                dia1.v2= v3;
6121
 
                                                        }
6122
 
 
6123
 
                                                        if( (v2) > (v4) ) {
6124
 
                                                                dia2.v1= v4;
6125
 
                                                                dia2.v2= v2;
6126
 
                                                        }
6127
 
                                                        else {
6128
 
                                                                dia2.v1= v2;
6129
 
                                                                dia2.v2= v4;
6130
 
                                                        }
6131
 
 
6132
 
                                                        /* testing rule:
6133
 
                                                        * the area divided by the total edge lengths
6134
 
                                                        */
6135
 
 
6136
 
                                                        len1= len_v3v3(v1->co, v2->co);
6137
 
                                                        len2= len_v3v3(v2->co, v3->co);
6138
 
                                                        len3= len_v3v3(v3->co, v4->co);
6139
 
                                                        len4= len_v3v3(v4->co, v1->co);
6140
 
                                                        len5= len_v3v3(v1->co, v3->co);
6141
 
                                                        len6= len_v3v3(v2->co, v4->co);
6142
 
 
6143
 
                                                        opp1= area_tri_v3(v1->co, v2->co, v3->co);
6144
 
                                                        opp2= area_tri_v3(v1->co, v3->co, v4->co);
6145
 
 
6146
 
                                                        fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
6147
 
 
6148
 
                                                        opp1= area_tri_v3(v2->co, v3->co, v4->co);
6149
 
                                                        opp2= area_tri_v3(v2->co, v4->co, v1->co);
6150
 
 
6151
 
                                                        fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
6152
 
 
6153
 
                                                        ok= 0;
6154
 
                                                        if(fac1 > fac2) {
6155
 
                                                                if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
6156
 
                                                                        eed->f1= 1;
6157
 
                                                                        efa= efaa[0];
6158
 
                                                                        efa->f1= 1;
6159
 
                                                                        efa= efaa[1];
6160
 
                                                                        efa->f1= 1;
6161
 
 
6162
 
                                                                        w= EM_face_from_faces(em, efaa[0], efaa[1],
6163
 
                                                                                                                  vindex[0], vindex[1], 4+vindex[2], -1);
6164
 
                                                                        EM_select_face(w, 1);
6165
 
 
6166
 
 
6167
 
                                                                        w= EM_face_from_faces(em, efaa[0], efaa[1],
6168
 
                                                                                                                  vindex[0], 4+vindex[2], 4+vindex[3], -1);
6169
 
                                                                        EM_select_face(w, 1);
6170
 
 
6171
 
                                                                        onedone= 1;
6172
 
                                                                }
6173
 
                                                        }
6174
 
                                                        else if(fac1 < fac2) {
6175
 
                                                                if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
6176
 
                                                                        eed->f1= 1;
6177
 
                                                                        efa= efaa[0];
6178
 
                                                                        efa->f1= 1;
6179
 
                                                                        efa= efaa[1];
6180
 
                                                                        efa->f1= 1;
6181
 
 
6182
 
 
6183
 
                                                                        w= EM_face_from_faces(em, efaa[0], efaa[1],
6184
 
                                                                                                                  vindex[1], 4+vindex[2], 4+vindex[3], -1);
6185
 
                                                                        EM_select_face(w, 1);
6186
 
 
6187
 
                                                                        w= EM_face_from_faces(em, efaa[0], efaa[1],
6188
 
                                                                                                                  vindex[0], 4+vindex[1], 4+vindex[3], -1);
6189
 
                                                                        EM_select_face(w, 1);
6190
 
 
6191
 
                                                                        onedone= 1;
6192
 
                                                                }
6193
 
                                                        }
6194
 
                                                }
6195
 
                                        }
6196
 
                                }
6197
 
 
6198
 
                        }
6199
 
                        eed= nexted;
6200
 
                }
6201
 
 
6202
 
                free_tagged_edges_faces(em, em->edges.first, em->faces.first);
6203
 
 
6204
 
                if(onedone==0) break;
6205
 
 
6206
 
                EM_selectmode_set(em);  // new edges/faces were added
6207
 
        }
6208
 
 
6209
 
        MEM_freeN(efaar);
6210
 
 
6211
 
        EM_select_flush(em);
6212
 
 
6213
 
}
6214
 
 
6215
 
/* Got this from scanfill.c. You will need to juggle around the
6216
 
* callbacks for the scanfill.c code a bit for this to work. */
6217
 
static void fill_mesh(EditMesh *em)
6218
 
{
6219
 
        EditVert *eve,*v1;
6220
 
        EditEdge *eed,*e1,*nexted;
6221
 
        EditFace *efa,*nextvl, *efan;
6222
 
        short ok;
6223
 
 
6224
 
        if(em==NULL) return;
6225
 
        waitcursor(1);
6226
 
 
6227
 
        /* copy all selected vertices */
6228
 
        eve= em->verts.first;
6229
 
        while(eve) {
6230
 
                if(eve->f & SELECT) {
6231
 
                        v1= BLI_addfillvert(eve->co);
6232
 
                        eve->tmp.v= v1;
6233
 
                        v1->tmp.v= eve;
6234
 
                        v1->xs= 0;      // used for counting edges
6235
 
                }
6236
 
                eve= eve->next;
6237
 
        }
6238
 
        /* copy all selected edges */
6239
 
        eed= em->edges.first;
6240
 
        while(eed) {
6241
 
                if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
6242
 
                        e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
6243
 
                        e1->v1->xs++;
6244
 
                        e1->v2->xs++;
6245
 
                }
6246
 
                eed= eed->next;
6247
 
        }
6248
 
        /* from all selected faces: remove vertices and edges to prevent doubles */
6249
 
        /* all edges add values, faces subtract,
6250
 
                then remove edges with vertices ->xs<2 */
6251
 
        efa= em->faces.first;
6252
 
        ok= 0;
6253
 
        while(efa) {
6254
 
                nextvl= efa->next;
6255
 
                if( faceselectedAND(efa, 1) ) {
6256
 
                        efa->v1->tmp.v->xs--;
6257
 
                        efa->v2->tmp.v->xs--;
6258
 
                        efa->v3->tmp.v->xs--;
6259
 
                        if(efa->v4) efa->v4->tmp.v->xs--;
6260
 
                        ok= 1;
6261
 
 
6262
 
                }
6263
 
                efa= nextvl;
6264
 
        }
6265
 
        if(ok) {        /* there are faces selected */
6266
 
                eed= filledgebase.first;
6267
 
                while(eed) {
6268
 
                        nexted= eed->next;
6269
 
                        if(eed->v1->xs<2 || eed->v2->xs<2) {
6270
 
                                BLI_remlink(&filledgebase,eed);
6271
 
                        }
6272
 
                        eed= nexted;
6273
 
                }
6274
 
        }
6275
 
 
6276
 
        if(BLI_edgefill(em->mat_nr)) {
6277
 
                efa= fillfacebase.first;
6278
 
                while(efa) {
6279
 
                        /* normals default pointing up */
6280
 
                        efan= addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v,
6281
 
                                                          efa->v1->tmp.v, 0, NULL, NULL);
6282
 
                        if(efan) EM_select_face(efan, 1);
6283
 
                        efa= efa->next;
6284
 
                }
6285
 
        }
6286
 
 
6287
 
        BLI_end_edgefill();
6288
 
        beautify_fill(em);
6289
 
 
6290
 
        WM_cursor_wait(0);
6291
 
        EM_select_flush(em);
6292
 
 
6293
 
}
6294
 
 
6295
 
static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op))
6296
 
{
6297
 
        Object *obedit= CTX_data_edit_object(C);
6298
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6299
 
 
6300
 
        fill_mesh(em);
6301
 
 
6302
 
        BKE_mesh_end_editmesh(obedit->data, em);
6303
 
 
6304
 
        DAG_id_tag_update(obedit->data, 0);
6305
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6306
 
 
 
2263
        Object *obedit = CTX_data_edit_object(C);
 
2264
        BMEditMesh *em;
 
2265
        EnumPropertyItem *item = NULL;
 
2266
        int totitem = 0;
 
2267
 
 
2268
        if ((obedit && obedit->type == OB_MESH) &&
 
2269
            (em = BMEdit_FromObject(obedit)) &&
 
2270
            CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY))
 
2271
        {
 
2272
                EnumPropertyItem tmp = {0, "", 0, "", ""};
 
2273
                int a;
 
2274
 
 
2275
                for (a = 0; a < em->bm->vdata.totlayer; a++) {
 
2276
                        if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
 
2277
                                continue;
 
2278
 
 
2279
                        tmp.value = totitem;
 
2280
                        tmp.identifier = em->bm->vdata.layers[a].name;
 
2281
                        tmp.name = em->bm->vdata.layers[a].name;
 
2282
                        /* RNA_enum_item_add sets totitem itself! */
 
2283
                        RNA_enum_item_add(&item, &totitem, &tmp);
 
2284
                }
 
2285
        }
 
2286
 
 
2287
        RNA_enum_item_end(&item, &totitem);
 
2288
        *free = 1;
 
2289
 
 
2290
        return item;
 
2291
}
 
2292
 
 
2293
void MESH_OT_blend_from_shape(wmOperatorType *ot)
 
2294
{
 
2295
        PropertyRNA *prop;
 
2296
        static EnumPropertyItem shape_items[] = {{0, NULL, 0, NULL, NULL}};
 
2297
 
 
2298
        /* identifiers */
 
2299
        ot->name = "Blend From Shape";
 
2300
        ot->description = "Blend in shape from a shape key";
 
2301
        ot->idname = "MESH_OT_blend_from_shape";
 
2302
 
 
2303
        /* api callbacks */
 
2304
        ot->exec = edbm_blend_from_shape_exec;
 
2305
        ot->invoke = WM_operator_props_popup;
 
2306
        ot->poll = ED_operator_editmesh;
 
2307
 
 
2308
        /* flags */
 
2309
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2310
 
 
2311
        /* properties */
 
2312
        prop = RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending");
 
2313
        RNA_def_enum_funcs(prop, shape_itemf);
 
2314
        RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor", -2.0f, 2.0f);
 
2315
        RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather than blend between shapes");
 
2316
}
 
2317
 
 
2318
/* BMESH_TODO - some way to select on an arbitrary axis */
 
2319
static int edbm_select_axis_exec(bContext *C, wmOperator *op)
 
2320
{
 
2321
        Object *obedit = CTX_data_edit_object(C);
 
2322
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
2323
        BMEditSelection *ese = em->bm->selected.last;
 
2324
        int axis = RNA_enum_get(op->ptr, "axis");
 
2325
        int mode = RNA_enum_get(op->ptr, "mode"); /* -1 == aligned, 0 == neg, 1 == pos */
 
2326
 
 
2327
        if (ese == NULL || ese->htype != BM_VERT) {
 
2328
                BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
 
2329
                return OPERATOR_CANCELLED;
 
2330
        }
 
2331
        else {
 
2332
                BMVert *ev, *act_vert = (BMVert *)ese->ele;
 
2333
                BMIter iter;
 
2334
                float value = act_vert->co[axis];
 
2335
                float limit =  CTX_data_tool_settings(C)->doublimit; // XXX
 
2336
 
 
2337
                if (mode == 0)
 
2338
                        value -= limit;
 
2339
                else if (mode == 1)
 
2340
                        value += limit;
 
2341
 
 
2342
                BM_ITER_MESH (ev, &iter, em->bm, BM_VERTS_OF_MESH) {
 
2343
                        if (!BM_elem_flag_test(ev, BM_ELEM_HIDDEN)) {
 
2344
                                switch (mode) {
 
2345
                                        case -1: /* aligned */
 
2346
                                                if (fabs(ev->co[axis] - value) < limit)
 
2347
                                                        BM_vert_select_set(em->bm, ev, TRUE);
 
2348
                                                break;
 
2349
                                        case 0: /* neg */
 
2350
                                                if (ev->co[axis] > value)
 
2351
                                                        BM_vert_select_set(em->bm, ev, TRUE);
 
2352
                                                break;
 
2353
                                        case 1: /* pos */
 
2354
                                                if (ev->co[axis] < value)
 
2355
                                                        BM_vert_select_set(em->bm, ev, TRUE);
 
2356
                                                break;
 
2357
                                }
 
2358
                        }
 
2359
                }
 
2360
        }
 
2361
 
 
2362
        EDBM_selectmode_flush(em);
 
2363
        WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
 
2364
 
 
2365
        return OPERATOR_FINISHED;
 
2366
}
 
2367
 
 
2368
void MESH_OT_select_axis(wmOperatorType *ot)
 
2369
{
 
2370
        static EnumPropertyItem axis_mode_items[] = {
 
2371
                {0,  "POSITIVE", 0, "Positive Axis", ""},
 
2372
                {1,  "NEGATIVE", 0, "Negative Axis", ""},
 
2373
                {-1, "ALIGNED",  0, "Aligned Axis", ""},
 
2374
                {0, NULL, 0, NULL, NULL}};
 
2375
 
 
2376
        static EnumPropertyItem axis_items_xyz[] = {
 
2377
                {0, "X_AXIS", 0, "X Axis", ""},
 
2378
                {1, "Y_AXIS", 0, "Y Axis", ""},
 
2379
                {2, "Z_AXIS", 0, "Z Axis", ""},
 
2380
                {0, NULL, 0, NULL, NULL}};
 
2381
 
 
2382
        /* identifiers */
 
2383
        ot->name = "Select Axis";
 
2384
        ot->description = "Select all data in the mesh on a single axis";
 
2385
        ot->idname = "MESH_OT_select_axis";
 
2386
 
 
2387
        /* api callbacks */
 
2388
        ot->exec = edbm_select_axis_exec;
 
2389
        ot->poll = ED_operator_editmesh;
 
2390
 
 
2391
        /* flags */
 
2392
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2393
 
 
2394
        /* properties */
 
2395
        RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
 
2396
        RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
 
2397
}
 
2398
 
 
2399
static int edbm_solidify_exec(bContext *C, wmOperator *op)
 
2400
{
 
2401
        Object *obedit = CTX_data_edit_object(C);
 
2402
        Mesh *me = obedit->data;
 
2403
        BMEditMesh *em = me->edit_btmesh;
 
2404
        BMesh *bm = em->bm;
 
2405
        BMOperator bmop;
 
2406
 
 
2407
        float thickness = RNA_float_get(op->ptr, "thickness");
 
2408
 
 
2409
        if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
 
2410
                return OPERATOR_CANCELLED;
 
2411
        }
 
2412
 
 
2413
        /* deselect only the faces in the region to be solidified (leave wire
 
2414
         * edges and loose verts selected, as there will be no corresponding
 
2415
         * geometry selected below) */
 
2416
        BMO_slot_buffer_hflag_disable(bm, &bmop, "geom", BM_FACE, BM_ELEM_SELECT, TRUE);
 
2417
 
 
2418
        /* run the solidify operator */
 
2419
        BMO_op_exec(bm, &bmop);
 
2420
 
 
2421
        /* select the newly generated faces */
 
2422
        BMO_slot_buffer_hflag_enable(bm, &bmop, "geomout", BM_FACE, BM_ELEM_SELECT, TRUE);
 
2423
 
 
2424
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
2425
                return OPERATOR_CANCELLED;
 
2426
        }
 
2427
 
 
2428
        EDBM_update_generic(C, em, TRUE);
 
2429
 
 
2430
        return OPERATOR_FINISHED;
 
2431
}
 
2432
 
 
2433
 
 
2434
void MESH_OT_solidify(wmOperatorType *ot)
 
2435
{
 
2436
        PropertyRNA *prop;
 
2437
        /* identifiers */
 
2438
        ot->name = "Solidify";
 
2439
        ot->description = "Create a solid skin by extruding, compensating for sharp angles";
 
2440
        ot->idname = "MESH_OT_solidify";
 
2441
 
 
2442
        /* api callbacks */
 
2443
        ot->exec = edbm_solidify_exec;
 
2444
        ot->poll = ED_operator_editmesh;
 
2445
 
 
2446
        /* flags */
 
2447
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2448
 
 
2449
        prop = RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
 
2450
        RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
 
2451
}
 
2452
 
 
2453
#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
 
2454
#define TRAIL_FREEHAND 2
 
2455
#define TRAIL_MIXED    3 /* (1|2) */
 
2456
#define TRAIL_AUTO     4 
 
2457
#define TRAIL_MIDPOINTS 8
 
2458
 
 
2459
typedef struct CutCurve {
 
2460
        float x;
 
2461
        float y;
 
2462
} CutCurve;
 
2463
 
 
2464
/* ******************************************************************** */
 
2465
/* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
 
2466
 * drawn by user.
 
2467
 *
 
2468
 * Currently mapped to KKey when in MeshEdit mode.
 
2469
 * Usage:
 
2470
 * - Hit Shift K, Select Centers or Exact
 
2471
 * - Hold LMB down to draw path, hit RETKEY.
 
2472
 * - ESC cancels as expected.
 
2473
 *
 
2474
 * Contributed by Robert Wenzlaff (Det. Thorn).
 
2475
 *
 
2476
 * 2.5 Revamp:
 
2477
 *  - non modal (no menu before cutting)
 
2478
 *  - exit on mouse release
 
2479
 *  - polygon/segment drawing can become handled by WM cb later
 
2480
 *
 
2481
 * bmesh port version
 
2482
 */
 
2483
 
 
2484
#define KNIFE_EXACT     1
 
2485
#define KNIFE_MIDPOINT  2
 
2486
#define KNIFE_MULTICUT  3
 
2487
 
 
2488
static EnumPropertyItem knife_items[] = {
 
2489
        {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
 
2490
        {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
 
2491
        {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
 
2492
        {0, NULL, 0, NULL, NULL}
 
2493
};
 
2494
 
 
2495
/* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
 
2496
 
 
2497
static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode,
 
2498
                               struct GHash *gh, int *isected)
 
2499
{
 
2500
#define MAXSLOPE 100000
 
2501
        float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max;
 
2502
        float y2min, dist, lastdist = 0, xdiff2, xdiff1;
 
2503
        float m1, b1, m2, b2, x21, x22, y21, y22, xi;
 
2504
        float yi, x1min, x1max, y1max, y1min, perc = 0;
 
2505
        float  *scr;
 
2506
        float threshold = 0.0;
 
2507
        int i;
 
2508
        
 
2509
        //threshold = 0.000001; /* tolerance for vertex intersection */
 
2510
        // XXX threshold = scene->toolsettings->select_thresh / 100;
 
2511
        
 
2512
        /* Get screen coords of verts */
 
2513
        scr = BLI_ghash_lookup(gh, e->v1);
 
2514
        x21 = scr[0];
 
2515
        y21 = scr[1];
 
2516
        
 
2517
        scr = BLI_ghash_lookup(gh, e->v2);
 
2518
        x22 = scr[0];
 
2519
        y22 = scr[1];
 
2520
        
 
2521
        xdiff2 = (x22 - x21);
 
2522
        if (xdiff2) {
 
2523
                m2 = (y22 - y21) / xdiff2;
 
2524
                b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
 
2525
        }
 
2526
        else {
 
2527
                m2 = MAXSLOPE;  /* Verticle slope  */
 
2528
                b2 = x22;
 
2529
        }
 
2530
 
 
2531
        *isected = 0;
 
2532
 
 
2533
        /* check for _exact_ vertex intersection first */
 
2534
        if (mode != KNIFE_MULTICUT) {
 
2535
                for (i = 0; i < len; i++) {
 
2536
                        if (i > 0) {
 
2537
                                x11 = x12;
 
2538
                                y11 = y12;
 
2539
                        }
 
2540
                        else {
 
2541
                                x11 = c[i].x;
 
2542
                                y11 = c[i].y;
 
2543
                        }
 
2544
                        x12 = c[i].x;
 
2545
                        y12 = c[i].y;
 
2546
                        
 
2547
                        /* test e->v1 */
 
2548
                        if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
 
2549
                                perc = 0;
 
2550
                                *isected = 1;
 
2551
                                return perc;
 
2552
                        }
 
2553
                        /* test e->v2 */
 
2554
                        else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
 
2555
                                perc = 0;
 
2556
                                *isected = 2;
 
2557
                                return perc;
 
2558
                        }
 
2559
                }
 
2560
        }
 
2561
        
 
2562
        /* now check for edge intersect (may produce vertex intersection as well) */
 
2563
        for (i = 0; i < len; i++) {
 
2564
                if (i > 0) {
 
2565
                        x11 = x12;
 
2566
                        y11 = y12;
 
2567
                }
 
2568
                else {
 
2569
                        x11 = c[i].x;
 
2570
                        y11 = c[i].y;
 
2571
                }
 
2572
                x12 = c[i].x;
 
2573
                y12 = c[i].y;
 
2574
                
 
2575
                /* Perp. Distance from point to line */
 
2576
                if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2);  /* /sqrt(m2 * m2 + 1); Only looking for */
 
2577
                /* change in sign.  Skip extra math */
 
2578
                else dist = x22 - x12;
 
2579
                
 
2580
                if (i == 0) lastdist = dist;
 
2581
                
 
2582
                /* if dist changes sign, and intersect point in edge's Bound Box */
 
2583
                if ((lastdist * dist) <= 0) {
 
2584
                        xdiff1 = (x12 - x11); /* Equation of line between last 2 points */
 
2585
                        if (xdiff1) {
 
2586
                                m1 = (y12 - y11) / xdiff1;
 
2587
                                b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
 
2588
                        }
 
2589
                        else {
 
2590
                                m1 = MAXSLOPE;
 
2591
                                b1 = x12;
 
2592
                        }
 
2593
                        x2max = MAX2(x21, x22) + 0.001; /* prevent missed edges   */
 
2594
                        x2min = MIN2(x21, x22) - 0.001; /* due to round off error */
 
2595
                        y2max = MAX2(y21, y22) + 0.001;
 
2596
                        y2min = MIN2(y21, y22) - 0.001;
 
2597
                        
 
2598
                        /* Found an intersect,  calc intersect point */
 
2599
                        if (m1 == m2) { /* co-incident lines */
 
2600
                                /* cut at 50% of overlap area */
 
2601
                                x1max = MAX2(x11, x12);
 
2602
                                x1min = MIN2(x11, x12);
 
2603
                                xi = (MIN2(x2max, x1max) + MAX2(x2min, x1min)) / 2.0;
 
2604
                                
 
2605
                                y1max = MAX2(y11, y12);
 
2606
                                y1min = MIN2(y11, y12);
 
2607
                                yi = (MIN2(y2max, y1max) + MAX2(y2min, y1min)) / 2.0;
 
2608
                        }
 
2609
                        else if (m2 == MAXSLOPE) {
 
2610
                                xi = x22;
 
2611
                                yi = m1 * x22 + b1;
 
2612
                        }
 
2613
                        else if (m1 == MAXSLOPE) {
 
2614
                                xi = x12;
 
2615
                                yi = m2 * x12 + b2;
 
2616
                        }
 
2617
                        else {
 
2618
                                xi = (b1 - b2) / (m2 - m1);
 
2619
                                yi = (b1 * m2 - m1 * b2) / (m2 - m1);
 
2620
                        }
 
2621
                        
 
2622
                        /* Intersect inside bounding box of edge?*/
 
2623
                        if ((xi >= x2min) && (xi <= x2max) && (yi <= y2max) && (yi >= y2min)) {
 
2624
                                /* test for vertex intersect that may be 'close enough'*/
 
2625
                                if (mode != KNIFE_MULTICUT) {
 
2626
                                        if (xi <= (x21 + threshold) && xi >= (x21 - threshold)) {
 
2627
                                                if (yi <= (y21 + threshold) && yi >= (y21 - threshold)) {
 
2628
                                                        *isected = 1;
 
2629
                                                        perc = 0;
 
2630
                                                        break;
 
2631
                                                }
 
2632
                                        }
 
2633
                                        if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
 
2634
                                                if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
 
2635
                                                        *isected = 2;
 
2636
                                                        perc = 0;
 
2637
                                                        break;
 
2638
                                                }
 
2639
                                        }
 
2640
                                }
 
2641
                                if ((m2 <= 1.0f) && (m2 >= -1.0f)) perc = (xi - x21) / (x22 - x21);
 
2642
                                else perc = (yi - y21) / (y22 - y21);  /* lower slope more accurate */
 
2643
                                //isect = 32768.0 * (perc + 0.0000153); /* Percentage in 1 / 32768ths */
 
2644
                                
 
2645
                                break;
 
2646
                        }
 
2647
                }       
 
2648
                lastdist = dist;
 
2649
        }
 
2650
        return perc;
 
2651
 
2652
 
 
2653
#define MAX_CUTS 2048
 
2654
 
 
2655
static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
 
2656
{
 
2657
        Object *obedit = CTX_data_edit_object(C);
 
2658
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
2659
        BMesh *bm = em->bm;
 
2660
        ARegion *ar = CTX_wm_region(C);
 
2661
        BMVert *bv;
 
2662
        BMIter iter;
 
2663
        BMEdge *be;
 
2664
        BMOperator bmop;
 
2665
        CutCurve curve[MAX_CUTS];
 
2666
        struct GHash *gh;
 
2667
        float isect = 0.0f;
 
2668
        float  *scr, co[4];
 
2669
        int len = 0, isected;
 
2670
        short numcuts = 1, mode = RNA_int_get(op->ptr, "type");
 
2671
        
 
2672
        /* edit-object needed for matrix, and ar->regiondata for projections to work */
 
2673
        if (ELEM3(NULL, obedit, ar, ar->regiondata))
 
2674
                return OPERATOR_CANCELLED;
 
2675
        
 
2676
        if (bm->totvertsel < 2) {
 
2677
                //error("No edges are selected to operate on");
 
2678
                return OPERATOR_CANCELLED;
 
2679
        }
 
2680
 
 
2681
        /* get the cut curve */
 
2682
        RNA_BEGIN (op->ptr, itemptr, "path") {
 
2683
                RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
 
2684
                len++;
 
2685
                if (len >= MAX_CUTS) {
 
2686
                        break;
 
2687
                }
 
2688
        }
 
2689
        RNA_END;
 
2690
        
 
2691
        if (len < 2) {
 
2692
                return OPERATOR_CANCELLED;
 
2693
        }
 
2694
 
 
2695
        /* the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer */
 
2696
        gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife cut exec");
 
2697
        for (bv = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); bv; bv = BM_iter_step(&iter)) {
 
2698
                scr = MEM_mallocN(sizeof(float) * 2, "Vertex Screen Coordinates");
 
2699
                copy_v3_v3(co, bv->co);
 
2700
                co[3] = 1.0f;
 
2701
                mul_m4_v4(obedit->obmat, co);
 
2702
                project_float(ar, co, scr);
 
2703
                BLI_ghash_insert(gh, bv, scr);
 
2704
        }
 
2705
 
 
2706
        if (!EDBM_op_init(em, &bmop, op, "esubd")) {
 
2707
                return OPERATOR_CANCELLED;
 
2708
        }
 
2709
 
 
2710
        /* store percentage of edge cut for KNIFE_EXACT here.*/
 
2711
        for (be = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be = BM_iter_step(&iter)) {
 
2712
                if (BM_elem_flag_test(be, BM_ELEM_SELECT)) {
 
2713
                        isect = bm_edge_seg_isect(be, curve, len, mode, gh, &isected);
 
2714
                        
 
2715
                        if (isect != 0.0f) {
 
2716
                                if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
 
2717
                                        BMO_slot_map_float_insert(bm, &bmop,
 
2718
                                                                  "edgepercents",
 
2719
                                                                  be, isect);
 
2720
 
 
2721
                                }
 
2722
                                BMO_elem_flag_enable(bm, be, 1);
 
2723
                        }
 
2724
                        else {
 
2725
                                BMO_elem_flag_disable(bm, be, 1);
 
2726
                        }
 
2727
                }
 
2728
                else {
 
2729
                        BMO_elem_flag_disable(bm, be, 1);
 
2730
                }
 
2731
        }
 
2732
        
 
2733
        BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, 1);
 
2734
 
 
2735
        if (mode == KNIFE_MIDPOINT) numcuts = 1;
 
2736
        BMO_slot_int_set(&bmop, "numcuts", numcuts);
 
2737
 
 
2738
        BMO_slot_int_set(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT);
 
2739
        BMO_slot_bool_set(&bmop, "use_singleedge", FALSE);
 
2740
        BMO_slot_bool_set(&bmop, "use_gridfill", FALSE);
 
2741
 
 
2742
        BMO_slot_float_set(&bmop, "radius", 0);
 
2743
        
 
2744
        BMO_op_exec(bm, &bmop);
 
2745
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
2746
                return OPERATOR_CANCELLED;
 
2747
        }
 
2748
        
 
2749
        BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
 
2750
 
 
2751
        EDBM_update_generic(C, em, TRUE);
 
2752
 
 
2753
        return OPERATOR_FINISHED;
 
2754
}
 
2755
 
 
2756
void MESH_OT_knife_cut(wmOperatorType *ot)
 
2757
{
 
2758
        PropertyRNA *prop;
 
2759
        
 
2760
        ot->name = "Knife Cut";
 
2761
        ot->description = "Cut selected edges and faces into parts";
 
2762
        ot->idname = "MESH_OT_knife_cut";
 
2763
        
 
2764
        ot->invoke = WM_gesture_lines_invoke;
 
2765
        ot->modal = WM_gesture_lines_modal;
 
2766
        ot->exec = edbm_knife_cut_exec;
 
2767
        
 
2768
        ot->poll = EM_view3d_poll;
 
2769
        
 
2770
        /* flags */
 
2771
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
2772
        
 
2773
        RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
 
2774
        prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
 
2775
        RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
 
2776
        
 
2777
        /* internal */
 
2778
        RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
 
2779
}
 
2780
 
 
2781
static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
 
2782
{
 
2783
        Base *basenew;
 
2784
        BMIter iter;
 
2785
        BMVert *v;
 
2786
        BMEdge *e;
 
2787
        Object *obedit = editbase->object;
 
2788
        Mesh *me = obedit->data;
 
2789
        BMEditMesh *em = me->edit_btmesh;
 
2790
        BMesh *bm_new;
 
2791
        
 
2792
        if (!em)
 
2793
                return FALSE;
 
2794
                
 
2795
        bm_new = BM_mesh_create(&bm_mesh_allocsize_default);
 
2796
        CustomData_copy(&em->bm->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
 
2797
        CustomData_copy(&em->bm->edata, &bm_new->edata, CD_MASK_BMESH, CD_CALLOC, 0);
 
2798
        CustomData_copy(&em->bm->ldata, &bm_new->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
 
2799
        CustomData_copy(&em->bm->pdata, &bm_new->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
 
2800
 
 
2801
        CustomData_bmesh_init_pool(&bm_new->vdata, bm_mesh_allocsize_default.totvert, BM_VERT);
 
2802
        CustomData_bmesh_init_pool(&bm_new->edata, bm_mesh_allocsize_default.totedge, BM_EDGE);
 
2803
        CustomData_bmesh_init_pool(&bm_new->ldata, bm_mesh_allocsize_default.totloop, BM_LOOP);
 
2804
        CustomData_bmesh_init_pool(&bm_new->pdata, bm_mesh_allocsize_default.totface, BM_FACE);
 
2805
                
 
2806
        basenew = ED_object_add_duplicate(bmain, scene, editbase, USER_DUP_MESH);   /* 0 = fully linked */
 
2807
        assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
 
2808
 
 
2809
        ED_base_object_select(basenew, BA_DESELECT);
 
2810
        
 
2811
        EDBM_op_callf(em, wmop, "dupe geom=%hvef dest=%p", BM_ELEM_SELECT, bm_new);
 
2812
        EDBM_op_callf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_FACES);
 
2813
 
 
2814
        /* clean up any loose edges */
 
2815
        BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
 
2816
                if (BM_elem_flag_test(e, BM_ELEM_HIDDEN))
 
2817
                        continue;
 
2818
 
 
2819
                if (!BM_edge_is_wire(e)) {
 
2820
                        BM_edge_select_set(em->bm, e, FALSE);
 
2821
                }
 
2822
        }
 
2823
        EDBM_op_callf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES);
 
2824
 
 
2825
        /* clean up any loose verts */
 
2826
        BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
 
2827
                if (BM_elem_flag_test(v, BM_ELEM_HIDDEN))
 
2828
                        continue;
 
2829
 
 
2830
                if (BM_vert_edge_count(v) != 0) {
 
2831
                        BM_vert_select_set(em->bm, v, FALSE);
 
2832
                }
 
2833
        }
 
2834
 
 
2835
        EDBM_op_callf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS);
 
2836
 
 
2837
        BM_mesh_normals_update(bm_new, TRUE);
 
2838
 
 
2839
        BM_mesh_bm_to_me(bm_new, basenew->object->data, FALSE);
 
2840
                
 
2841
        BM_mesh_free(bm_new);
 
2842
        ((Mesh *)basenew->object->data)->edit_btmesh = NULL;
 
2843
        
 
2844
        return TRUE;
 
2845
}
 
2846
 
 
2847
static int mesh_separate_material(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
 
2848
{
 
2849
        BMFace *f_cmp, *f;
 
2850
        BMIter iter;
 
2851
        int result = FALSE;
 
2852
        Object *obedit = editbase->object;
 
2853
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
2854
        BMesh *bm = em->bm;
 
2855
 
 
2856
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
2857
 
 
2858
        while ((f_cmp = BM_iter_at_index(bm, BM_FACES_OF_MESH, NULL, 0))) {
 
2859
                const short mat_nr = f_cmp->mat_nr;
 
2860
                int tot = 0;
 
2861
 
 
2862
                BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
 
2863
                        if (f->mat_nr == mat_nr) {
 
2864
                                BM_face_select_set(bm, f, TRUE);
 
2865
                                tot++;
 
2866
                        }
 
2867
                }
 
2868
 
 
2869
                /* leave the current object with some materials */
 
2870
                if (tot == bm->totface) {
 
2871
                        break;
 
2872
                }
 
2873
 
 
2874
                /* Move selection into a separate object */
 
2875
                result |= mesh_separate_selected(bmain, scene, editbase, wmop);
 
2876
        }
 
2877
 
 
2878
        return result;
 
2879
}
 
2880
 
 
2881
static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
 
2882
{
 
2883
        int i;
 
2884
        BMVert *v;
 
2885
        BMEdge *e;
 
2886
        BMVert *v_seed;
 
2887
        BMWalker walker;
 
2888
        BMIter iter;
 
2889
        int result = FALSE;
 
2890
        Object *obedit = editbase->object;
 
2891
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
2892
        BMesh *bm = em->bm;
 
2893
        int max_iter = bm->totvert;
 
2894
 
 
2895
        /* Clear all selected vertices */
 
2896
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
2897
 
 
2898
        /* A "while (true)" loop should work here as each iteration should
 
2899
         * select and remove at least one vertex and when all vertices
 
2900
         * are selected the loop will break out. But guard against bad
 
2901
         * behavior by limiting iterations to the number of vertices in the
 
2902
         * original mesh.*/
 
2903
        for (i = 0; i < max_iter; i++) {
 
2904
                /* Get a seed vertex to start the walk */
 
2905
                v_seed = NULL;
 
2906
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
 
2907
                        v_seed = v;
 
2908
                        break;
 
2909
                }
 
2910
 
 
2911
                /* No vertices available, can't do anything */
 
2912
                if (v_seed == NULL) {
 
2913
                        break;
 
2914
                }
 
2915
 
 
2916
                /* Select the seed explicitly, in case it has no edges */
 
2917
                BM_vert_select_set(bm, v_seed, TRUE);
 
2918
 
 
2919
                /* Walk from the single vertex, selecting everything connected
 
2920
                 * to it */
 
2921
                BMW_init(&walker, bm, BMW_SHELL,
 
2922
                         BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
 
2923
                         BMW_FLAG_NOP, /* BMESH_TODO - should be BMW_FLAG_TEST_HIDDEN ? */
 
2924
                         BMW_NIL_LAY);
 
2925
 
 
2926
                e = BMW_begin(&walker, v_seed);
 
2927
                for (; e; e = BMW_step(&walker)) {
 
2928
                        BM_vert_select_set(bm, e->v1, TRUE);
 
2929
                        BM_vert_select_set(bm, e->v2, TRUE);
 
2930
                }
 
2931
                BMW_end(&walker);
 
2932
                                
 
2933
                /* Flush the selection to get edge/face selections matching
 
2934
                 * the vertex selection */
 
2935
                EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
 
2936
 
 
2937
                if (bm->totvert == bm->totvertsel) {
 
2938
                        /* Every vertex selected, nothing to separate, work is done */
 
2939
                        break;
 
2940
                }
 
2941
 
 
2942
                /* Move selection into a separate object */
 
2943
                result |= mesh_separate_selected(bmain, scene, editbase, wmop);
 
2944
        }
 
2945
 
 
2946
        return result;
 
2947
}
 
2948
 
 
2949
static int edbm_separate_exec(bContext *C, wmOperator *op)
 
2950
{
 
2951
        Main *bmain = CTX_data_main(C);
 
2952
        Scene *scene = CTX_data_scene(C);
 
2953
        Base *base = CTX_data_active_base(C);
 
2954
        int retval = 0, type = RNA_enum_get(op->ptr, "type");
 
2955
        
 
2956
        if (type == 0)
 
2957
                retval = mesh_separate_selected(bmain, scene, base, op);
 
2958
        else if (type == 1)
 
2959
                retval = mesh_separate_material(bmain, scene, base, op);
 
2960
        else if (type == 2)
 
2961
                retval = mesh_separate_loose(bmain, scene, base, op);
 
2962
 
 
2963
        if (retval) {
 
2964
                BMEditMesh *em = BMEdit_FromObject(base->object);
 
2965
                EDBM_update_generic(C, em, TRUE);
 
2966
 
 
2967
                return OPERATOR_FINISHED;
 
2968
        }
 
2969
 
 
2970
        return OPERATOR_CANCELLED;
 
2971
}
 
2972
 
 
2973
/* *************** Operator: separate parts *************/
 
2974
 
 
2975
static EnumPropertyItem prop_separate_types[] = {
 
2976
        {0, "SELECTED", 0, "Selection", ""},
 
2977
        {1, "MATERIAL", 0, "By Material", ""},
 
2978
        {2, "LOOSE", 0, "By loose parts", ""},
 
2979
        {0, NULL, 0, NULL, NULL}
 
2980
};
 
2981
 
 
2982
void MESH_OT_separate(wmOperatorType *ot)
 
2983
{
 
2984
        /* identifiers */
 
2985
        ot->name = "Separate";
 
2986
        ot->description = "Separate selected geometry into a new mesh";
 
2987
        ot->idname = "MESH_OT_separate";
 
2988
        
 
2989
        /* api callbacks */
 
2990
        ot->invoke = WM_menu_invoke;
 
2991
        ot->exec = edbm_separate_exec;
 
2992
        ot->poll = ED_operator_editmesh;
 
2993
        
 
2994
        /* flags */
 
2995
        ot->flag = OPTYPE_UNDO;
 
2996
        
 
2997
        ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
 
2998
}
 
2999
 
 
3000
 
 
3001
static int edbm_fill_exec(bContext *C, wmOperator *op)
 
3002
{
 
3003
        Object *obedit = CTX_data_edit_object(C);
 
3004
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3005
        BMOperator bmop;
 
3006
        
 
3007
        if (!EDBM_op_init(em, &bmop, op, "triangle_fill edges=%he", BM_ELEM_SELECT)) {
 
3008
                return OPERATOR_CANCELLED;
 
3009
        }
 
3010
        
 
3011
        BMO_op_exec(em->bm, &bmop);
 
3012
        
 
3013
        /* select new geometry */
 
3014
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_FACE | BM_EDGE, BM_ELEM_SELECT, TRUE);
 
3015
        
 
3016
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
3017
                return OPERATOR_CANCELLED;
 
3018
        }
 
3019
 
 
3020
        EDBM_update_generic(C, em, TRUE);
 
3021
        
6307
3022
        return OPERATOR_FINISHED;
6308
3023
 
6309
3024
}
6311
3026
void MESH_OT_fill(wmOperatorType *ot)
6312
3027
{
6313
3028
        /* identifiers */
6314
 
        ot->name= "Fill";
6315
 
        ot->description= "Create a segment, edge or face";
6316
 
        ot->idname= "MESH_OT_fill";
 
3029
        ot->name = "Fill";
 
3030
        ot->idname = "MESH_OT_fill";
 
3031
        ot->description = "Fill a selected edge loop with faces";
6317
3032
 
6318
3033
        /* api callbacks */
6319
 
        ot->exec= fill_mesh_exec;
6320
 
        ot->poll= ED_operator_editmesh;
 
3034
        ot->exec = edbm_fill_exec;
 
3035
        ot->poll = ED_operator_editmesh;
6321
3036
 
6322
3037
        /* flags */
6323
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
3038
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
6324
3039
}
6325
3040
 
6326
 
static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op))
 
3041
static int edbm_beautify_fill_exec(bContext *C, wmOperator *op)
6327
3042
{
6328
 
        Object *obedit= CTX_data_edit_object(C);
6329
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6330
 
 
6331
 
        beautify_fill(em);
6332
 
 
6333
 
        BKE_mesh_end_editmesh(obedit->data, em);
6334
 
 
6335
 
        DAG_id_tag_update(obedit->data, 0);
6336
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6337
 
 
 
3043
        Object *obedit = CTX_data_edit_object(C);
 
3044
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3045
 
 
3046
        if (!EDBM_op_callf(em, op, "beautify_fill faces=%hf", BM_ELEM_SELECT))
 
3047
                return OPERATOR_CANCELLED;
 
3048
 
 
3049
        EDBM_update_generic(C, em, TRUE);
 
3050
        
6338
3051
        return OPERATOR_FINISHED;
6339
3052
}
6340
3053
 
6341
3054
void MESH_OT_beautify_fill(wmOperatorType *ot)
6342
3055
{
6343
3056
        /* identifiers */
6344
 
        ot->name= "Beautify Fill";
6345
 
        ot->description= "Rearrange geometry on a selected surface to avoid skinny faces";
6346
 
        ot->idname= "MESH_OT_beautify_fill";
6347
 
 
6348
 
        /* api callbacks */
6349
 
        ot->exec= beautify_fill_exec;
6350
 
        ot->poll= ED_operator_editmesh;
6351
 
 
6352
 
        /* flags */
6353
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
3057
        ot->name = "Beautify Fill";
 
3058
        ot->idname = "MESH_OT_beautify_fill";
 
3059
 
 
3060
        /* api callbacks */
 
3061
        ot->exec = edbm_beautify_fill_exec;
 
3062
        ot->poll = ED_operator_editmesh;
 
3063
 
 
3064
        /* flags */
 
3065
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3066
}
 
3067
 
 
3068
/********************** Quad/Tri Operators *************************/
 
3069
 
 
3070
static int edbm_quads_convert_to_tris_exec(bContext *C, wmOperator *op)
 
3071
{
 
3072
        Object *obedit = CTX_data_edit_object(C);
 
3073
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3074
        int use_beauty = RNA_boolean_get(op->ptr, "use_beauty");
 
3075
 
 
3076
        if (!EDBM_op_callf(em, op, "triangulate faces=%hf use_beauty=%b", BM_ELEM_SELECT, use_beauty))
 
3077
                return OPERATOR_CANCELLED;
 
3078
 
 
3079
        EDBM_update_generic(C, em, TRUE);
 
3080
 
 
3081
        return OPERATOR_FINISHED;
 
3082
}
 
3083
 
 
3084
void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
 
3085
{
 
3086
        /* identifiers */
 
3087
        ot->name = "Triangulate Faces";
 
3088
        ot->idname = "MESH_OT_quads_convert_to_tris";
 
3089
        ot->description = "Triangulate selected faces";
 
3090
 
 
3091
        /* api callbacks */
 
3092
        ot->exec = edbm_quads_convert_to_tris_exec;
 
3093
        ot->poll = ED_operator_editmesh;
 
3094
 
 
3095
        /* flags */
 
3096
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3097
 
 
3098
        RNA_def_boolean(ot->srna, "use_beauty", 1, "Beauty", "Use best triangulation division (currently quads only)");
 
3099
}
 
3100
 
 
3101
static int edbm_tris_convert_to_quads_exec(bContext *C, wmOperator *op)
 
3102
{
 
3103
        Object *obedit = CTX_data_edit_object(C);
 
3104
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3105
        int dosharp, douvs, dovcols, domaterials;
 
3106
        float limit = RNA_float_get(op->ptr, "limit");
 
3107
 
 
3108
        dosharp = RNA_boolean_get(op->ptr, "sharp");
 
3109
        douvs = RNA_boolean_get(op->ptr, "uvs");
 
3110
        dovcols = RNA_boolean_get(op->ptr, "vcols");
 
3111
        domaterials = RNA_boolean_get(op->ptr, "materials");
 
3112
 
 
3113
        if (!EDBM_op_callf(em, op,
 
3114
                           "join_triangles faces=%hf limit=%f cmp_sharp=%b cmp_uvs=%b cmp_vcols=%b cmp_materials=%b",
 
3115
                           BM_ELEM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
 
3116
        {
 
3117
                return OPERATOR_CANCELLED;
 
3118
        }
 
3119
 
 
3120
        EDBM_update_generic(C, em, TRUE);
 
3121
 
 
3122
        return OPERATOR_FINISHED;
 
3123
}
 
3124
 
 
3125
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
 
3126
{
 
3127
        PropertyRNA *prop;
 
3128
 
 
3129
        /* identifiers */
 
3130
        ot->name = "Tris to Quads";
 
3131
        ot->idname = "MESH_OT_tris_convert_to_quads";
 
3132
        ot->description = "Join triangles into quads";
 
3133
 
 
3134
        /* api callbacks */
 
3135
        ot->exec = edbm_tris_convert_to_quads_exec;
 
3136
        ot->poll = ED_operator_editmesh;
 
3137
 
 
3138
        /* flags */
 
3139
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3140
 
 
3141
        prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
 
3142
                                      "Max Angle", "Angle Limit", 0.0f, DEG2RADF(180.0f));
 
3143
        RNA_def_property_float_default(prop, DEG2RADF(40.0f));
 
3144
 
 
3145
        RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
 
3146
        RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
 
3147
        RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
 
3148
        RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
 
3149
}
 
3150
 
 
3151
static int edbm_dissolve_exec(bContext *C, wmOperator *op)
 
3152
{
 
3153
        Object *obedit = CTX_data_edit_object(C);
 
3154
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3155
 
 
3156
        int use_verts = RNA_boolean_get(op->ptr, "use_verts");
 
3157
 
 
3158
        if (em->selectmode & SCE_SELECT_FACE) {
 
3159
                if (!EDBM_op_callf(em, op, "dissolve_faces faces=%hf use_verts=%b", BM_ELEM_SELECT, use_verts))
 
3160
                        return OPERATOR_CANCELLED;
 
3161
        }
 
3162
        else if (em->selectmode & SCE_SELECT_EDGE) {
 
3163
                if (!EDBM_op_callf(em, op, "dissolve_edges edges=%he use_verts=%b", BM_ELEM_SELECT, use_verts))
 
3164
                        return OPERATOR_CANCELLED;
 
3165
        }
 
3166
        else if (em->selectmode & SCE_SELECT_VERTEX) {
 
3167
                if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv", BM_ELEM_SELECT))
 
3168
                        return OPERATOR_CANCELLED;
 
3169
        }
 
3170
 
 
3171
        EDBM_update_generic(C, em, TRUE);
 
3172
 
 
3173
        return OPERATOR_FINISHED;
 
3174
}
 
3175
 
 
3176
void MESH_OT_dissolve(wmOperatorType *ot)
 
3177
{
 
3178
        /* identifiers */
 
3179
        ot->name = "Dissolve";
 
3180
        ot->description = "Dissolve geometry";
 
3181
        ot->idname = "MESH_OT_dissolve";
 
3182
 
 
3183
        /* api callbacks */
 
3184
        ot->exec = edbm_dissolve_exec;
 
3185
        ot->poll = ED_operator_editmesh;
 
3186
 
 
3187
        /* flags */
 
3188
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3189
 
 
3190
        /* TODO, move dissolve into its own operator so this doesnt confuse non-dissolve options */
 
3191
        RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts",
 
3192
                        "When dissolving faces/edges, also dissolve remaining vertices");
 
3193
}
 
3194
 
 
3195
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
 
3196
{
 
3197
        Object *obedit = CTX_data_edit_object(C);
 
3198
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3199
        float angle_limit = RNA_float_get(op->ptr, "angle_limit");
 
3200
 
 
3201
        if (!EDBM_op_callf(em, op,
 
3202
                           "dissolve_limit edges=%he verts=%hv angle_limit=%f",
 
3203
                           BM_ELEM_SELECT, BM_ELEM_SELECT, angle_limit))
 
3204
        {
 
3205
                return OPERATOR_CANCELLED;
 
3206
        }
 
3207
 
 
3208
        EDBM_update_generic(C, em, TRUE);
 
3209
 
 
3210
        return OPERATOR_FINISHED;
 
3211
}
 
3212
 
 
3213
void MESH_OT_dissolve_limited(wmOperatorType *ot)
 
3214
{
 
3215
        PropertyRNA *prop;
 
3216
 
 
3217
        /* identifiers */
 
3218
        ot->name = "Limited Dissolve";
 
3219
        ot->idname = "MESH_OT_dissolve_limited";
 
3220
        ot->description = "Dissolve selected edges and verts, limited by the angle of surrounding geometry";
 
3221
 
 
3222
        /* api callbacks */
 
3223
        ot->exec = edbm_dissolve_limited_exec;
 
3224
        ot->poll = ED_operator_editmesh;
 
3225
 
 
3226
        /* flags */
 
3227
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3228
 
 
3229
        prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f),
 
3230
                                      "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f));
 
3231
        RNA_def_property_float_default(prop, DEG2RADF(15.0f));
 
3232
}
 
3233
 
 
3234
static int edbm_split_exec(bContext *C, wmOperator *op)
 
3235
{
 
3236
        Object *ob = CTX_data_edit_object(C);
 
3237
        BMEditMesh *em = BMEdit_FromObject(ob);
 
3238
        BMOperator bmop;
 
3239
 
 
3240
        EDBM_op_init(em, &bmop, op, "split geom=%hvef use_only_faces=%b", BM_ELEM_SELECT, FALSE);
 
3241
        BMO_op_exec(em->bm, &bmop);
 
3242
        BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, FALSE);
 
3243
        BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
3244
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
3245
                return OPERATOR_CANCELLED;
 
3246
        }
 
3247
 
 
3248
        /* Geometry has changed, need to recalc normals and looptris */
 
3249
        EDBM_mesh_normals_update(em);
 
3250
 
 
3251
        EDBM_update_generic(C, em, TRUE);
 
3252
 
 
3253
        return OPERATOR_FINISHED;
 
3254
}
 
3255
 
 
3256
void MESH_OT_split(wmOperatorType *ot)
 
3257
{
 
3258
        /* identifiers */
 
3259
        ot->name = "Split";
 
3260
        ot->idname = "MESH_OT_split";
 
3261
        ot->description = "Split off selected geometry from connected unselected geometry";
 
3262
 
 
3263
        /* api callbacks */
 
3264
        ot->exec = edbm_split_exec;
 
3265
        ot->poll = ED_operator_editmesh;
 
3266
 
 
3267
        /* flags */
 
3268
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3269
}
 
3270
 
 
3271
 
 
3272
static int edbm_spin_exec(bContext *C, wmOperator *op)
 
3273
{
 
3274
        Object *obedit = CTX_data_edit_object(C);
 
3275
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3276
        BMesh *bm = em->bm;
 
3277
        BMOperator spinop;
 
3278
        float cent[3], axis[3], imat[3][3];
 
3279
        float d[3] = {0.0f, 0.0f, 0.0f};
 
3280
        int steps, dupli;
 
3281
        float degr;
 
3282
 
 
3283
        RNA_float_get_array(op->ptr, "center", cent);
 
3284
        RNA_float_get_array(op->ptr, "axis", axis);
 
3285
        steps = RNA_int_get(op->ptr, "steps");
 
3286
        degr = RNA_float_get(op->ptr, "degrees");
 
3287
        //if (ts->editbutflag & B_CLOCKWISE)
 
3288
        degr = -degr;
 
3289
        dupli = RNA_boolean_get(op->ptr, "dupli");
 
3290
 
 
3291
        /* undo object transformation */
 
3292
        copy_m3_m4(imat, obedit->imat);
 
3293
        sub_v3_v3(cent, obedit->obmat[3]);
 
3294
        mul_m3_v3(imat, cent);
 
3295
        mul_m3_v3(imat, axis);
 
3296
 
 
3297
        if (!EDBM_op_init(em, &spinop, op,
 
3298
                          "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i ang=%f do_dupli=%b",
 
3299
                          BM_ELEM_SELECT, cent, axis, d, steps, degr, dupli))
 
3300
        {
 
3301
                return OPERATOR_CANCELLED;
 
3302
        }
 
3303
        BMO_op_exec(bm, &spinop);
 
3304
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
3305
        BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
3306
        if (!EDBM_op_finish(em, &spinop, op, TRUE)) {
 
3307
                return OPERATOR_CANCELLED;
 
3308
        }
 
3309
 
 
3310
        EDBM_update_generic(C, em, TRUE);
 
3311
 
 
3312
        return OPERATOR_FINISHED;
 
3313
}
 
3314
 
 
3315
/* get center and axis, in global coords */
 
3316
static int edbm_spin_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
3317
{
 
3318
        Scene *scene = CTX_data_scene(C);
 
3319
        View3D *v3d = CTX_wm_view3d(C);
 
3320
        RegionView3D *rv3d = ED_view3d_context_rv3d(C);
 
3321
 
 
3322
        RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
 
3323
        RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
 
3324
 
 
3325
        return edbm_spin_exec(C, op);
 
3326
}
 
3327
 
 
3328
void MESH_OT_spin(wmOperatorType *ot)
 
3329
{
 
3330
        /* identifiers */
 
3331
        ot->name = "Spin";
 
3332
        ot->description = "Extrude selected vertices in a circle around the cursor in indicated viewport";
 
3333
        ot->idname = "MESH_OT_spin";
 
3334
 
 
3335
        /* api callbacks */
 
3336
        ot->invoke = edbm_spin_invoke;
 
3337
        ot->exec = edbm_spin_exec;
 
3338
        ot->poll = EM_view3d_poll;
 
3339
 
 
3340
        /* flags */
 
3341
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3342
 
 
3343
        /* props */
 
3344
        RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX);
 
3345
        RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
 
3346
        RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
 
3347
 
 
3348
        RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
 
3349
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
 
3350
 
 
3351
}
 
3352
 
 
3353
static int edbm_screw_exec(bContext *C, wmOperator *op)
 
3354
{
 
3355
        Object *obedit = CTX_data_edit_object(C);
 
3356
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3357
        BMesh *bm = em->bm;
 
3358
        BMEdge *eed;
 
3359
        BMVert *eve, *v1, *v2;
 
3360
        BMIter iter, eiter;
 
3361
        BMOperator spinop;
 
3362
        float dvec[3], nor[3], cent[3], axis[3];
 
3363
        float imat[3][3];
 
3364
        int steps, turns;
 
3365
        int valence;
 
3366
 
 
3367
 
 
3368
        turns = RNA_int_get(op->ptr, "turns");
 
3369
        steps = RNA_int_get(op->ptr, "steps");
 
3370
        RNA_float_get_array(op->ptr, "center", cent);
 
3371
        RNA_float_get_array(op->ptr, "axis", axis);
 
3372
 
 
3373
        /* undo object transformation */
 
3374
        copy_m3_m4(imat, obedit->imat);
 
3375
        sub_v3_v3(cent, obedit->obmat[3]);
 
3376
        mul_m3_v3(imat, cent);
 
3377
        mul_m3_v3(imat, axis);
 
3378
 
 
3379
 
 
3380
        /* find two vertices with valence count == 1, more or less is wrong */
 
3381
        v1 = NULL;
 
3382
        v2 = NULL;
 
3383
        for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); eve; eve = BM_iter_step(&iter)) {
 
3384
 
 
3385
                valence = 0;
 
3386
 
 
3387
                for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve); eed; eed = BM_iter_step(&eiter)) {
 
3388
 
 
3389
                        if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
 
3390
                                valence++;
 
3391
                        }
 
3392
 
 
3393
                }
 
3394
 
 
3395
                if (valence == 1) {
 
3396
                        if (v1 == NULL) {
 
3397
                                v1 = eve;
 
3398
                        }
 
3399
                        else if (v2 == NULL) {
 
3400
                                v2 = eve;
 
3401
                        }
 
3402
                        else {
 
3403
                                v1 = NULL;
 
3404
                                break;
 
3405
                        }
 
3406
                }
 
3407
        }
 
3408
 
 
3409
        if (v1 == NULL || v2 == NULL) {
 
3410
                BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too");
 
3411
                return OPERATOR_CANCELLED;
 
3412
        }
 
3413
 
 
3414
        /* calculate dvec */
 
3415
        sub_v3_v3v3(dvec, v1->co, v2->co);
 
3416
        mul_v3_fl(dvec, 1.0f / steps);
 
3417
 
 
3418
        if (dot_v3v3(nor, dvec) > 0.000f)
 
3419
                negate_v3(dvec);
 
3420
 
 
3421
        if (!EDBM_op_init(em, &spinop, op,
 
3422
                          "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%i ang=%f do_dupli=%b",
 
3423
                          BM_ELEM_SELECT, cent, axis, dvec, turns * steps, 360.0f * turns, FALSE))
 
3424
        {
 
3425
                return OPERATOR_CANCELLED;
 
3426
        }
 
3427
        BMO_op_exec(bm, &spinop);
 
3428
        EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
3429
        BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ALL, BM_ELEM_SELECT, TRUE);
 
3430
        if (!EDBM_op_finish(em, &spinop, op, TRUE)) {
 
3431
                return OPERATOR_CANCELLED;
 
3432
        }
 
3433
 
 
3434
        EDBM_update_generic(C, em, TRUE);
 
3435
 
 
3436
        return OPERATOR_FINISHED;
 
3437
}
 
3438
 
 
3439
/* get center and axis, in global coords */
 
3440
static int edbm_screw_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
 
3441
{
 
3442
        Scene *scene = CTX_data_scene(C);
 
3443
        View3D *v3d = CTX_wm_view3d(C);
 
3444
        RegionView3D *rv3d = ED_view3d_context_rv3d(C);
 
3445
 
 
3446
        RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
 
3447
        RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
 
3448
 
 
3449
        return edbm_screw_exec(C, op);
 
3450
}
 
3451
 
 
3452
void MESH_OT_screw(wmOperatorType *ot)
 
3453
{
 
3454
        /* identifiers */
 
3455
        ot->name = "Screw";
 
3456
        ot->description = "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport";
 
3457
        ot->idname = "MESH_OT_screw";
 
3458
 
 
3459
        /* api callbacks */
 
3460
        ot->invoke = edbm_screw_invoke;
 
3461
        ot->exec = edbm_screw_exec;
 
3462
        ot->poll = EM_view3d_poll;
 
3463
 
 
3464
        /* flags */
 
3465
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3466
 
 
3467
        /* props */
 
3468
        RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
 
3469
        RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
 
3470
 
 
3471
        RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX,
 
3472
                             "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
 
3473
        RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f,
 
3474
                             "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
 
3475
}
 
3476
 
 
3477
static int edbm_select_by_number_vertices_exec(bContext *C, wmOperator *op)
 
3478
{
 
3479
        Object *obedit = CTX_data_edit_object(C);
 
3480
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3481
        BMFace *efa;
 
3482
        BMIter iter;
 
3483
        int numverts = RNA_int_get(op->ptr, "number");
 
3484
        int type = RNA_enum_get(op->ptr, "type");
 
3485
 
 
3486
        for (efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
 
3487
             efa; efa = BM_iter_step(&iter)) {
 
3488
 
 
3489
                int select = 0;
 
3490
 
 
3491
                if (type == 0 && efa->len < numverts) {
 
3492
                        select = 1;
 
3493
                }
 
3494
                else if (type == 1 && efa->len == numverts) {
 
3495
                        select = 1;
 
3496
                }
 
3497
                else if (type == 2 && efa->len > numverts) {
 
3498
                        select = 1;
 
3499
                }
 
3500
                else if (type == 3 && efa->len != numverts) {
 
3501
                        select = 1;
 
3502
                }
 
3503
 
 
3504
                if (select) {
 
3505
                        BM_face_select_set(em->bm, efa, TRUE);
 
3506
                }
 
3507
        }
 
3508
 
 
3509
        EDBM_selectmode_flush(em);
 
3510
 
 
3511
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
 
3512
        return OPERATOR_FINISHED;
 
3513
}
 
3514
 
 
3515
void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
 
3516
{
 
3517
        static const EnumPropertyItem type_items[] = {
 
3518
                {0, "LESS", 0, "Less Than", ""},
 
3519
                {1, "EQUAL", 0, "Equal To", ""},
 
3520
                {2, "GREATER", 0, "Greater Than", ""},
 
3521
                {3, "NOTEQUAL", 0, "Not Equal To", ""},
 
3522
                {0, NULL, 0, NULL, NULL}};
 
3523
 
 
3524
        /* identifiers */
 
3525
        ot->name = "Select by Number of Vertices";
 
3526
        ot->description = "Select vertices or faces by vertex count";
 
3527
        ot->idname = "MESH_OT_select_by_number_vertices";
 
3528
        
 
3529
        /* api callbacks */
 
3530
        ot->exec = edbm_select_by_number_vertices_exec;
 
3531
        ot->poll = ED_operator_editmesh;
 
3532
        
 
3533
        /* flags */
 
3534
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3535
 
 
3536
        /* properties */
 
3537
        RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX);
 
3538
        RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make");
 
3539
}
 
3540
 
 
3541
static int edbm_select_loose_verts_exec(bContext *C, wmOperator *UNUSED(op))
 
3542
{
 
3543
        Object *obedit = CTX_data_edit_object(C);
 
3544
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3545
        BMVert *eve;
 
3546
        BMEdge *eed;
 
3547
        BMIter iter;
 
3548
 
 
3549
        for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
 
3550
             eve; eve = BM_iter_step(&iter)) {
 
3551
 
 
3552
                if (!eve->e) {
 
3553
                        BM_vert_select_set(em->bm, eve, TRUE);
 
3554
                }
 
3555
        }
 
3556
 
 
3557
        for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
 
3558
             eed; eed = BM_iter_step(&iter)) {
 
3559
 
 
3560
                if (!eed->l) {
 
3561
                        BM_edge_select_set(em->bm, eed, TRUE);
 
3562
                }
 
3563
        }
 
3564
 
 
3565
        EDBM_selectmode_flush(em);
 
3566
 
 
3567
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
 
3568
        return OPERATOR_FINISHED;
 
3569
}
 
3570
 
 
3571
void MESH_OT_select_loose_verts(wmOperatorType *ot)
 
3572
{
 
3573
        /* identifiers */
 
3574
        ot->name = "Select Loose Vertices/Edges";
 
3575
        ot->description = "Select vertices with no edges nor faces, and edges with no faces";
 
3576
        ot->idname = "MESH_OT_select_loose_verts";
 
3577
 
 
3578
        /* api callbacks */
 
3579
        ot->exec = edbm_select_loose_verts_exec;
 
3580
        ot->poll = ED_operator_editmesh;
 
3581
 
 
3582
        /* flags */
 
3583
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3584
}
 
3585
 
 
3586
static int edbm_select_mirror_exec(bContext *C, wmOperator *op)
 
3587
{
 
3588
        Object *obedit = CTX_data_edit_object(C);
 
3589
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3590
        int extend = RNA_boolean_get(op->ptr, "extend");
 
3591
 
 
3592
        EDBM_select_mirrored(obedit, em, extend);
 
3593
        EDBM_selectmode_flush(em);
 
3594
        WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
 
3595
 
 
3596
        return OPERATOR_FINISHED;
 
3597
}
 
3598
 
 
3599
void MESH_OT_select_mirror(wmOperatorType *ot)
 
3600
{
 
3601
        /* identifiers */
 
3602
        ot->name = "Select Mirror";
 
3603
        ot->description = "Select mesh items at mirrored locations";
 
3604
        ot->idname = "MESH_OT_select_mirror";
 
3605
 
 
3606
        /* api callbacks */
 
3607
        ot->exec = edbm_select_mirror_exec;
 
3608
        ot->poll = ED_operator_editmesh;
 
3609
 
 
3610
        /* flags */
 
3611
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3612
 
 
3613
        /* props */
 
3614
        RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
 
3615
}
 
3616
 
 
3617
/* qsort routines.  not sure how to make these
 
3618
 * work, since we aren't using linked lists for
 
3619
 * geometry anymore.  might need a sort of "swap"
 
3620
 * function for bmesh elements. */
 
3621
 
 
3622
/* TODO All this section could probably use a refresh...
 
3623
 *      face code works in object mode, does everything in one op, while vert uses several...
 
3624
 */
 
3625
 
 
3626
typedef struct xvertsort {
 
3627
        int x; /* X screen-coordinate */
 
3628
        int org_idx; /* Original index of this vertex _in the mempool_ */
 
3629
} xvertsort;
 
3630
 
 
3631
 
 
3632
static int vergxco(const void *v1, const void *v2)
 
3633
{
 
3634
        const xvertsort *x1 = v1, *x2 = v2;
 
3635
 
 
3636
        /* We move unchanged vertices (org_idx < 0) at the begining of the sorted list. */
 
3637
        if (x1->org_idx >= 0 && x2->org_idx >= 0)
 
3638
                return (x1->x > x2->x) - (x1->x < x2->x);
 
3639
        return (x2->org_idx < 0) - (x1->org_idx < 0);
 
3640
}
 
3641
 
 
3642
#if 0 /* Unused */
 
3643
struct facesort {
 
3644
        uintptr_t x;
 
3645
        struct EditFace *efa;
 
3646
};
 
3647
 
 
3648
static int vergface(const void *v1, const void *v2)
 
3649
{
 
3650
        const struct facesort *x1 = v1, *x2 = v2;
 
3651
 
 
3652
        if (x1->x > x2->x) return 1;
 
3653
        else if (x1->x < x2->x) return -1;
 
3654
        return 0;
 
3655
}
 
3656
#endif
 
3657
 
 
3658
static void xsortvert_flag__doSetX(void *userData, BMVert *UNUSED(eve), int x, int UNUSED(y), int index)
 
3659
{
 
3660
        xvertsort *sortblock = userData;
 
3661
 
 
3662
        sortblock[index].x = x;
 
3663
}
 
3664
 
 
3665
/* all verts with (flag & 'flag') are sorted */
 
3666
static void xsortvert_flag(bContext *C, int flag)
 
3667
{
 
3668
        ViewContext vc;
 
3669
        BMEditMesh *em;
 
3670
        BMVert *ve;
 
3671
        BMIter iter;
 
3672
        xvertsort *sortblock;
 
3673
        int *unchangedblock, *vmap;
 
3674
        int totvert, sorted = 0, unchanged = 0, i;
 
3675
 
 
3676
        em_setup_viewcontext(C, &vc);
 
3677
        em = vc.em;
 
3678
 
 
3679
        totvert = em->bm->totvert;
 
3680
 
 
3681
        sortblock = MEM_callocN(sizeof(xvertsort) * totvert, "xsort sorted");
 
3682
        /* Stores unchanged verts, will be reused as final old2new vert mapping... */
 
3683
        unchangedblock = MEM_callocN(sizeof(int) * totvert, "xsort unchanged");
 
3684
        BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
 
3685
                if (BM_elem_flag_test(ve, flag)) {
 
3686
                        sortblock[i].org_idx = i;
 
3687
                        sorted++;
 
3688
                }
 
3689
                else {
 
3690
                        unchangedblock[unchanged++] = i;
 
3691
                        sortblock[i].org_idx = -1;
 
3692
                }
 
3693
        }
 
3694
/*      printf("%d verts: %d to be sorted, %d unchangedā€¦\n", totvert, sorted, unchanged);*/
 
3695
        if (sorted == 0)
 
3696
                return;
 
3697
 
 
3698
        ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
 
3699
        mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
 
3700
 
 
3701
        qsort(sortblock, totvert, sizeof(xvertsort), vergxco);
 
3702
 
 
3703
        /* Convert sortblock into an array mapping old idx to new. */
 
3704
        vmap = unchangedblock;
 
3705
        unchangedblock = NULL;
 
3706
        if (unchanged) {
 
3707
                unchangedblock = MEM_mallocN(sizeof(int) * unchanged, "xsort unchanged");
 
3708
                memcpy(unchangedblock, vmap, unchanged * sizeof(int));
 
3709
        }
 
3710
        for (i = totvert; i--; ) {
 
3711
                if (i < unchanged)
 
3712
                        vmap[unchangedblock[i]] = i;
 
3713
                else
 
3714
                        vmap[sortblock[i].org_idx] = i;
 
3715
        }
 
3716
 
 
3717
        MEM_freeN(sortblock);
 
3718
        if (unchangedblock)
 
3719
                MEM_freeN(unchangedblock);
 
3720
 
 
3721
        BM_mesh_remap(em->bm, vmap, NULL, NULL);
 
3722
 
 
3723
        MEM_freeN(vmap);
 
3724
}
 
3725
 
 
3726
static int edbm_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
 
3727
{
 
3728
        xsortvert_flag(C, BM_ELEM_SELECT);
 
3729
        return OPERATOR_FINISHED;
 
3730
}
 
3731
 
 
3732
void MESH_OT_vertices_sort(wmOperatorType *ot)
 
3733
{
 
3734
        /* identifiers */
 
3735
        ot->name = "Vertex Sort";
 
3736
        ot->description = "Sort vertex order";
 
3737
        ot->idname = "MESH_OT_vertices_sort";
 
3738
 
 
3739
        /* api callbacks */
 
3740
        ot->exec = edbm_vertices_sort_exec;
 
3741
 
 
3742
        ot->poll = EM_view3d_poll; /* uses view relative X axis to sort verts */
 
3743
 
 
3744
        /* flags */
 
3745
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
6354
3746
}
6355
3747
 
6356
3748
/* ********************** SORT FACES ******************* */
6381
3773
        x1 = face_sort_floats[((int *) v1)[0]];
6382
3774
        x2 = face_sort_floats[((int *) v2)[0]];
6383
3775
        
6384
 
        if( x1 > x2 ) return 1;
6385
 
        else if( x1 < x2 ) return -1;
 
3776
        if      (x1 > x2) return  1;
 
3777
        else if (x1 < x2) return -1;
6386
3778
        return 0;
6387
3779
}
6388
3780
 
6389
 
 
6390
 
static int sort_faces_exec(bContext *C, wmOperator *op)
 
3781
static int edbm_sort_faces_exec(bContext *C, wmOperator *op)
6391
3782
{
6392
 
        RegionView3D *rv3d= ED_view3d_context_rv3d(C);
6393
 
        View3D *v3d= CTX_wm_view3d(C);
6394
 
        Object *ob= CTX_data_edit_object(C);
6395
 
        Scene *scene= CTX_data_scene(C);
 
3783
        RegionView3D *rv3d = ED_view3d_context_rv3d(C);
 
3784
        View3D *v3d = CTX_wm_view3d(C);
 
3785
        Object *ob = CTX_data_edit_object(C);
 
3786
        Scene *scene = CTX_data_scene(C);
6396
3787
        Mesh *me;
6397
3788
        CustomDataLayer *layer;
6398
 
        int i, *index;
 
3789
        int i, j, *index;
6399
3790
        int event;
6400
3791
        float reverse = 1;
6401
 
        // XXX int ctrl= 0;
 
3792
        // XXX int ctrl = 0;
6402
3793
        
6403
3794
        if (!v3d) return OPERATOR_CANCELLED;
6404
3795
 
6408
3799
         */
6409
3800
        ED_object_exit_editmode(C, EM_FREEDATA);
6410
3801
 
6411
 
        me= ob->data;
6412
 
        if(me->totface==0) {
 
3802
        me = ob->data;
 
3803
        if (me->totpoly == 0) {
6413
3804
                ED_object_enter_editmode(C, 0);
6414
3805
                return OPERATOR_FINISHED;
6415
3806
        }
6416
3807
 
6417
 
        event= RNA_enum_get(op->ptr, "type");
 
3808
        event = RNA_enum_get(op->ptr, "type");
6418
3809
 
6419
3810
        // XXX
6420
 
        //if(ctrl)
 
3811
        //if (ctrl)
6421
3812
        //      reverse = -1;
6422
3813
        
6423
3814
        /* create index list */
6424
 
        index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces");
6425
 
        for (i = 0; i < me->totface; i++) {
 
3815
        index = (int *)MEM_mallocN(sizeof(int) * me->totpoly, "sort faces");
 
3816
        for (i = 0; i < me->totpoly; i++) {
6426
3817
                index[i] = i;
6427
3818
        }
6428
3819
        
6429
 
        face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float");
 
3820
        face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totpoly, "sort faces float");
6430
3821
 
6431
3822
        /* sort index list instead of faces itself 
6432
3823
         * and apply this permutation to all face layers
6433
3824
         */
6434
3825
        if (event == 5) {
6435
3826
                /* Random */
6436
 
                for(i=0; i<me->totface; i++) {
 
3827
                for (i = 0; i < me->totpoly; i++) {
6437
3828
                        face_sort_floats[i] = BLI_frand();
6438
3829
                }
6439
 
                qsort(index, me->totface, sizeof(int), float_sort);             
6440
 
        } else {
6441
 
                MFace *mf;
 
3830
                qsort(index, me->totpoly, sizeof(int), float_sort);
 
3831
        }
 
3832
        else {
 
3833
                MPoly *mp;
 
3834
                MLoop *ml;
 
3835
                MVert *mv;
6442
3836
                float vec[3];
6443
3837
                float mat[4][4];
6444
3838
                float cur[3];
6445
3839
                
6446
3840
                if (event == 1)
6447
 
                        mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* apply the view matrix to the object matrix */
 
3841
                        mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat);  /* apply the view matrix to the object matrix */
6448
3842
                else if (event == 2) { /* sort from cursor */
6449
 
                        if( v3d && v3d->localvd ) {
6450
 
                                VECCOPY(cur, v3d->cursor);
6451
 
                        } else {
6452
 
                                VECCOPY(cur, scene->cursor);
 
3843
                        if (v3d && v3d->localvd) {
 
3844
                                copy_v3_v3(cur, v3d->cursor);
 
3845
                        }
 
3846
                        else {
 
3847
                                copy_v3_v3(cur, scene->cursor);
6453
3848
                        }
6454
3849
                        invert_m4_m4(mat, OBACT->obmat);
6455
3850
                        mul_m4_v3(mat, cur);
6456
3851
                }
6457
3852
                
6458
 
                mf= me->mface;
 
3853
                mp = me->mpoly;
6459
3854
 
6460
 
                for(i=0; i<me->totface; i++, mf++) {
6461
 
                        if (event==3) {
6462
 
                                face_sort_floats[i] = ((float)mf->mat_nr)*reverse;
6463
 
                        } else if (event==4) {
6464
 
                                /*selected first*/
6465
 
                                if (mf->flag & ME_FACE_SEL)
 
3855
                for (i = 0; i < me->totpoly; i++, mp++) {
 
3856
                        if (event == 3) {
 
3857
                                face_sort_floats[i] = ((float)mp->mat_nr) * reverse;
 
3858
                        }
 
3859
                        else if (event == 4) {
 
3860
                                /* selected first */
 
3861
                                if (mp->flag & ME_FACE_SEL)
6466
3862
                                        face_sort_floats[i] = 0.0;
6467
3863
                                else
6468
3864
                                        face_sort_floats[i] = reverse;
6469
 
                        } else {
6470
 
                                /* find the faces center */
6471
 
                                add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
6472
 
                                if (mf->v4) {
6473
 
                                        add_v3_v3(vec, (me->mvert+mf->v3)->co);
6474
 
                                        add_v3_v3(vec, (me->mvert+mf->v4)->co);
6475
 
                                        mul_v3_fl(vec, 0.25f);
6476
 
                                } else {
6477
 
                                        add_v3_v3(vec, (me->mvert+mf->v3)->co);
6478
 
                                        mul_v3_fl(vec, 1.0f/3.0f);
6479
 
                                } /* done */
 
3865
                        }
 
3866
                        else {
 
3867
                                /* find the face's center */
 
3868
                                ml = me->mloop + mp->loopstart;
 
3869
                                zero_v3(vec);
 
3870
                                for (j = 0; j < mp->totloop; j++, ml++) {
 
3871
                                        mv = me->mvert + ml->v;
 
3872
                                        add_v3_v3(vec, mv->co);
 
3873
                                }
 
3874
                                mul_v3_fl(vec, 1.0f / (float)mp->totloop);
6480
3875
                                
6481
3876
                                if (event == 1) { /* sort on view axis */
6482
3877
                                        mul_m4_v3(mat, vec);
6483
3878
                                        face_sort_floats[i] = vec[2] * reverse;
6484
 
                                } else if(event == 2) { /* distance from cursor*/
 
3879
                                }
 
3880
                                else if (event == 2) { /* distance from cursor */
6485
3881
                                        face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
6486
3882
                                }
6487
3883
                        }
6488
3884
                }
6489
 
                qsort(index, me->totface, sizeof(int), float_sort);
 
3885
                qsort(index, me->totpoly, sizeof(int), float_sort);
6490
3886
        }
6491
3887
        
6492
3888
        MEM_freeN(face_sort_floats);
6493
 
        for(i = 0; i < me->fdata.totlayer; i++) {
6494
 
                layer = &me->fdata.layers[i];
6495
 
                permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index);
 
3889
        for (i = 0; i < me->pdata.totlayer; i++) {
 
3890
                layer = &me->pdata.layers[i];
 
3891
                permutate(layer->data, me->totpoly, CustomData_sizeof(layer->type), index);
6496
3892
        }
6497
3893
 
6498
3894
        MEM_freeN(index);
6506
3902
 
6507
3903
void MESH_OT_sort_faces(wmOperatorType *ot)
6508
3904
{
6509
 
        static EnumPropertyItem type_items[]= {
 
3905
        static EnumPropertyItem type_items[] = {
6510
3906
                { 1, "VIEW_AXIS", 0, "View Axis", "" },
6511
3907
                { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" },
6512
3908
                { 3, "MATERIAL", 0, "Material", "" },
6515
3911
                { 0, NULL, 0, NULL, NULL }};
6516
3912
 
6517
3913
        /* identifiers */
6518
 
        ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t|
6519
 
        ot->description= "The faces of the active Mesh Object are sorted, based on the current view";
6520
 
        ot->idname= "MESH_OT_sort_faces";
6521
 
 
6522
 
        /* api callbacks */
6523
 
        ot->invoke= WM_menu_invoke;
6524
 
        ot->exec= sort_faces_exec;
6525
 
        ot->poll= ED_operator_editmesh;
6526
 
 
6527
 
        /* flags */
6528
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6529
 
 
6530
 
        /* properties */
6531
 
        ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
6532
 
}
6533
 
 
6534
 
/********************** Quad/Tri Operators *************************/
6535
 
 
6536
 
static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op))
6537
 
{
6538
 
        Object *obedit= CTX_data_edit_object(C);
6539
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6540
 
 
6541
 
        convert_to_triface(em,0);
6542
 
 
6543
 
        DAG_id_tag_update(obedit->data, 0);
6544
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6545
 
 
6546
 
        BKE_mesh_end_editmesh(obedit->data, em);
6547
 
        return OPERATOR_FINISHED;
6548
 
}
6549
 
 
6550
 
void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
6551
 
{
6552
 
        /* identifiers */
6553
 
        ot->name= "Quads to Tris";
6554
 
        ot->description= "Convert selected quads to triangles";
6555
 
        ot->idname= "MESH_OT_quads_convert_to_tris";
6556
 
 
6557
 
        /* api callbacks */
6558
 
        ot->exec= quads_convert_to_tris_exec;
6559
 
        ot->poll= ED_operator_editmesh;
6560
 
 
6561
 
        /* flags */
6562
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6563
 
}
6564
 
 
6565
 
static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op))
6566
 
{
6567
 
        Object *obedit= CTX_data_edit_object(C);
6568
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6569
 
 
6570
 
        join_triangles(em);
6571
 
 
6572
 
        DAG_id_tag_update(obedit->data, 0);
6573
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6574
 
 
6575
 
        BKE_mesh_end_editmesh(obedit->data, em);
6576
 
        return OPERATOR_FINISHED;
6577
 
}
6578
 
 
6579
 
void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
6580
 
{
6581
 
        /* identifiers */
6582
 
        ot->name= "Tris to Quads";
6583
 
        ot->description= "Convert selected triangles to quads";
6584
 
        ot->idname= "MESH_OT_tris_convert_to_quads";
6585
 
 
6586
 
        /* api callbacks */
6587
 
        ot->exec= tris_convert_to_quads_exec;
6588
 
        ot->poll= ED_operator_editmesh;
6589
 
 
6590
 
        /* flags */
6591
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6592
 
}
6593
 
 
6594
 
static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op))
6595
 
{
6596
 
        Object *obedit= CTX_data_edit_object(C);
6597
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6598
 
 
6599
 
        edge_flip(em);
6600
 
 
6601
 
        DAG_id_tag_update(obedit->data, 0);
6602
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6603
 
 
6604
 
        BKE_mesh_end_editmesh(obedit->data, em);
6605
 
        return OPERATOR_FINISHED;
6606
 
}
6607
 
 
6608
 
void MESH_OT_edge_flip(wmOperatorType *ot)
6609
 
{
6610
 
        /* identifiers */
6611
 
        ot->name= "Edge Flip";
6612
 
        ot->description= "Flip selected edge or adjoining faces";
6613
 
        ot->idname= "MESH_OT_edge_flip";
6614
 
 
6615
 
        /* api callbacks */
6616
 
        ot->exec= edge_flip_exec;
6617
 
        ot->poll= ED_operator_editmesh;
6618
 
 
6619
 
        /* flags */
6620
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6621
 
}
6622
 
 
6623
 
/********************** Smooth/Solid Operators *************************/
6624
 
 
6625
 
static void mesh_set_smooth_faces(EditMesh *em, short smooth)
6626
 
{
6627
 
        EditFace *efa;
6628
 
 
6629
 
        if(em==NULL) return;
6630
 
 
6631
 
        for(efa= em->faces.first; efa; efa=efa->next) {
6632
 
                if(efa->f & SELECT) {
6633
 
                        if(smooth) efa->flag |= ME_SMOOTH;
6634
 
                        else efa->flag &= ~ME_SMOOTH;
6635
 
                }
6636
 
        }
6637
 
 
6638
 
        recalc_editnormals(em);
6639
 
}
6640
 
 
6641
 
static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
6642
 
{
6643
 
        Object *obedit= CTX_data_edit_object(C);
6644
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6645
 
 
6646
 
        mesh_set_smooth_faces(em, 1);
6647
 
 
6648
 
        BKE_mesh_end_editmesh(obedit->data, em);
6649
 
 
6650
 
        DAG_id_tag_update(obedit->data, 0);
6651
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6652
 
 
6653
 
        return OPERATOR_FINISHED;
6654
 
}
6655
 
 
6656
 
void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
6657
 
{
6658
 
        /* identifiers */
6659
 
        ot->name= "Shade Smooth";
6660
 
        ot->description= "Display faces 'smooth' (using vertex normals)";
6661
 
        ot->idname= "MESH_OT_faces_shade_smooth";
6662
 
 
6663
 
        /* api callbacks */
6664
 
        ot->exec= mesh_faces_shade_smooth_exec;
6665
 
        ot->poll= ED_operator_editmesh;
6666
 
 
6667
 
        /* flags */
6668
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6669
 
}
6670
 
 
6671
 
static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
6672
 
{
6673
 
        Object *obedit= CTX_data_edit_object(C);
6674
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6675
 
 
6676
 
        mesh_set_smooth_faces(em, 0);
6677
 
 
6678
 
        DAG_id_tag_update(obedit->data, 0);
6679
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6680
 
 
6681
 
        return OPERATOR_FINISHED;
6682
 
}
6683
 
 
6684
 
void MESH_OT_faces_shade_flat(wmOperatorType *ot)
6685
 
{
6686
 
        /* identifiers */
6687
 
        ot->name= "Shade Flat";
6688
 
        ot->description= "Display faces 'flat'";
6689
 
        ot->idname= "MESH_OT_faces_shade_flat";
6690
 
 
6691
 
        /* api callbacks */
6692
 
        ot->exec= mesh_faces_shade_flat_exec;
6693
 
        ot->poll= ED_operator_editmesh;
6694
 
 
6695
 
        /* flags */
6696
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6697
 
}
6698
 
 
6699
 
/* TODO - some way to select on an arbitrary axis */
6700
 
static int select_axis_exec(bContext *C, wmOperator *op)
6701
 
{
6702
 
        Object *obedit= CTX_data_edit_object(C);
6703
 
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6704
 
 
6705
 
        int axis= RNA_enum_get(op->ptr, "axis");
6706
 
        int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
6707
 
 
6708
 
        EditSelection *ese = em->selected.last;
6709
 
 
6710
 
 
6711
 
        if (ese==NULL || ese->type != EDITVERT) {
6712
 
                BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)");
6713
 
                return OPERATOR_CANCELLED;
6714
 
        }
6715
 
        else {
6716
 
                EditVert *ev;
6717
 
                EditVert *act_vert= (EditVert*)ese->data;
6718
 
                float value= act_vert->co[axis];
6719
 
                float limit=  CTX_data_tool_settings(C)->doublimit; // XXX
6720
 
 
6721
 
                if(mode==0)                     value -= limit;
6722
 
                else if (mode==1)       value += limit;
6723
 
 
6724
 
                for(ev=em->verts.first;ev;ev=ev->next) {
6725
 
                        if(!ev->h) {
6726
 
                                switch(mode) {
6727
 
                                case -1: /* aligned */
6728
 
                                        if(fabs(ev->co[axis] - value) < limit)
6729
 
                                                ev->f |= SELECT;
6730
 
                                        break;
6731
 
                                case 0: /* neg */
6732
 
                                        if(ev->co[axis] > value)
6733
 
                                                ev->f |= SELECT;
6734
 
                                        break;
6735
 
                                case 1: /* pos */
6736
 
                                        if(ev->co[axis] < value)
6737
 
                                                ev->f |= SELECT;
6738
 
                                        break;
6739
 
                                }
6740
 
                        }
6741
 
                }
6742
 
        }
6743
 
 
6744
 
        EM_select_flush(em);
6745
 
        WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6746
 
 
6747
 
        return OPERATOR_FINISHED;
6748
 
}
6749
 
 
6750
 
void MESH_OT_select_axis(wmOperatorType *ot)
6751
 
{
6752
 
        static EnumPropertyItem axis_mode_items[] = {
6753
 
                {0,  "POSITIVE", 0, "Positive Axis", ""},
6754
 
                {1,  "NEGATIVE", 0, "Negative Axis", ""},
6755
 
                {-1, "ALIGNED",  0, "Aligned Axis", ""},
6756
 
                {0, NULL, 0, NULL, NULL}};
6757
 
        
6758
 
        static EnumPropertyItem axis_items_xyz[] = {
6759
 
                {0, "X_AXIS", 0, "X Axis", ""},
6760
 
                {1, "Y_AXIS", 0, "Y Axis", ""},
6761
 
                {2, "Z_AXIS", 0, "Z Axis", ""},
6762
 
                {0, NULL, 0, NULL, NULL}};
6763
 
 
6764
 
        /* identifiers */
6765
 
        ot->name= "Select Axis";
6766
 
        ot->description= "Select all data in the mesh on a single axis";
6767
 
        ot->idname= "MESH_OT_select_axis";
6768
 
 
6769
 
        /* api callbacks */
6770
 
        ot->exec= select_axis_exec;
6771
 
        ot->poll= ED_operator_editmesh;
6772
 
 
6773
 
        /* flags */
6774
 
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6775
 
 
6776
 
        /* properties */
6777
 
        RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
6778
 
        RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
6779
 
}
6780
 
 
 
3914
        ot->name = "Sort Faces"; // XXX (Ctrl to reverse)%t|
 
3915
        ot->description = "The faces of the active Mesh Object are sorted, based on the current view";
 
3916
        ot->idname = "MESH_OT_sort_faces";
 
3917
 
 
3918
        /* api callbacks */
 
3919
        ot->invoke = WM_menu_invoke;
 
3920
        ot->exec = edbm_sort_faces_exec;
 
3921
        ot->poll = ED_operator_editmesh;
 
3922
 
 
3923
        /* flags */
 
3924
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
3925
 
 
3926
        /* properties */
 
3927
        ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
 
3928
}
 
3929
 
 
3930
/* ******************************* Randomize verts ************************* */
 
3931
static void hashvert_flag(BMEditMesh *em, int flag, unsigned int seed)
 
3932
{
 
3933
        BMVert *ve;
 
3934
        BMIter iter;
 
3935
        char *block /* Just to mark protected vertices */, *t_blk;
 
3936
        int *randblock, *vmap, *t_idx, *r_idx;
 
3937
        int totvert, randomized = 0, /*protected = 0, */ i;
 
3938
 
 
3939
        totvert = em->bm->totvert;
 
3940
 
 
3941
        block = MEM_callocN(sizeof(char) * totvert, "randvert block");
 
3942
        randblock = MEM_callocN(sizeof(int) * totvert, "randvert randblock");
 
3943
        BM_ITER_MESH_INDEX (ve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
 
3944
                if (BM_elem_flag_test(ve, flag)) {
 
3945
                        block[i] = FALSE;
 
3946
                        randblock[randomized++] = i;
 
3947
                }
 
3948
                else {
 
3949
                        block[i] = TRUE;
 
3950
                }
 
3951
        }
 
3952
/*      protected = totvert - randomized;*/
 
3953
/*      printf("%d verts: %d to be randomized, %d protectedā€¦\n", totvert, randomized, protected);*/
 
3954
        if (randomized == 0)
 
3955
                return;
 
3956
 
 
3957
        
 
3958
        /* Randomize non-protected vertices indices, and create an array mapping old idx to new
 
3959
         *  from both blocks, keeping protected vertices at the same indices. */
 
3960
        vmap = randblock;
 
3961
        randblock = MEM_mallocN(sizeof(int) * randomized, "randvert randblock");
 
3962
        memcpy(randblock, vmap, randomized * sizeof(int));
 
3963
        BLI_array_randomize((void *)randblock, sizeof(int), randomized, seed);
 
3964
        t_blk = block + totvert - 1;
 
3965
        t_idx = vmap + totvert - 1;
 
3966
        r_idx = randblock + randomized - 1;
 
3967
        for (i = totvert; i--; t_blk--, t_idx--) {
 
3968
                if (*t_blk) /* Protected! */
 
3969
                        *t_idx = i;
 
3970
                else
 
3971
                        *t_idx = *r_idx--;
 
3972
        }
 
3973
 
 
3974
        MEM_freeN(randblock);
 
3975
        MEM_freeN(block);
 
3976
 
 
3977
        BM_mesh_remap(em->bm, vmap, NULL, NULL);
 
3978
 
 
3979
        MEM_freeN(vmap);
 
3980
}
 
3981
 
 
3982
static int edbm_vertices_randomize_exec(bContext *C, wmOperator *op)
 
3983
{
 
3984
        Object *obedit = CTX_data_edit_object(C);
 
3985
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
3986
        unsigned int seed = RNA_int_get(op->ptr, "seed");
 
3987
 
 
3988
        hashvert_flag(em, BM_ELEM_SELECT, seed);
 
3989
 
 
3990
        return OPERATOR_FINISHED;
 
3991
}
 
3992
 
 
3993
void MESH_OT_vertices_randomize(wmOperatorType *ot)
 
3994
{
 
3995
        /* identifiers */
 
3996
        ot->name = "Vertex Randomize";
 
3997
        ot->description = "Randomize vertex order";
 
3998
        ot->idname = "MESH_OT_vertices_randomize";
 
3999
 
 
4000
        /* api callbacks */
 
4001
        ot->exec = edbm_vertices_randomize_exec;
 
4002
 
 
4003
        ot->poll = ED_operator_editmesh;
 
4004
 
 
4005
        /* flags */
 
4006
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
4007
 
 
4008
        /* Properties */
 
4009
        ot->prop = RNA_def_int(ot->srna, "seed", 0, 0, INT_MAX, "Seed", "Seed for the random generator", 0, 255);
 
4010
}
 
4011
 
 
4012
/******end of qsort stuff ****/
 
4013
 
 
4014
 
 
4015
static int edbm_noise_exec(bContext *C, wmOperator *op)
 
4016
{
 
4017
        Object *obedit = CTX_data_edit_object(C);
 
4018
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
4019
        Material *ma;
 
4020
        Tex *tex;
 
4021
        BMVert *eve;
 
4022
        BMIter iter;
 
4023
        float fac = RNA_float_get(op->ptr, "factor");
 
4024
 
 
4025
        if (em == NULL) {
 
4026
                return OPERATOR_FINISHED;
 
4027
        }
 
4028
 
 
4029
        if ((ma  = give_current_material(obedit, obedit->actcol)) == NULL ||
 
4030
            (tex = give_current_material_texture(ma)) == NULL)
 
4031
        {
 
4032
                BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned");
 
4033
                return OPERATOR_FINISHED;
 
4034
        }
 
4035
 
 
4036
        if (tex->type == TEX_STUCCI) {
 
4037
                float b2, vec[3];
 
4038
                float ofs = tex->turbul / 200.0;
 
4039
                BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 
4040
                        if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 
4041
                                b2 = BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
 
4042
                                if (tex->stype) ofs *= (b2 * b2);
 
4043
                                vec[0] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0] + ofs, eve->co[1], eve->co[2]));
 
4044
                                vec[1] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1] + ofs, eve->co[2]));
 
4045
                                vec[2] = fac * (b2 - BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2] + ofs));
 
4046
                                
 
4047
                                add_v3_v3(eve->co, vec);
 
4048
                        }
 
4049
                }
 
4050
        }
 
4051
        else {
 
4052
                BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
 
4053
                        if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
 
4054
                                float tin, dum;
 
4055
                                externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
 
4056
                                eve->co[2] += fac * tin;
 
4057
                        }
 
4058
                }
 
4059
        }
 
4060
 
 
4061
        EDBM_mesh_normals_update(em);
 
4062
 
 
4063
        EDBM_update_generic(C, em, TRUE);
 
4064
 
 
4065
        return OPERATOR_FINISHED;
 
4066
}
 
4067
 
 
4068
void MESH_OT_noise(wmOperatorType *ot)
 
4069
{
 
4070
        /* identifiers */
 
4071
        ot->name = "Noise";
 
4072
        ot->description = "Use vertex coordinate as texture coordinate";
 
4073
        ot->idname = "MESH_OT_noise";
 
4074
 
 
4075
        /* api callbacks */
 
4076
        ot->exec = edbm_noise_exec;
 
4077
        ot->poll = ED_operator_editmesh;
 
4078
 
 
4079
        /* flags */
 
4080
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
4081
 
 
4082
        RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
 
4083
}
 
4084
 
 
4085
/* bevel! yay!!*/
 
4086
static int edbm_bevel_exec(bContext *C, wmOperator *op)
 
4087
{
 
4088
        Object *obedit = CTX_data_edit_object(C);
 
4089
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
4090
        BMIter iter;
 
4091
        BMEdge *eed;
 
4092
        BMOperator bmop;
 
4093
        float factor = RNA_float_get(op->ptr, "percent") /*, dfac */ /* UNUSED */, df, s;
 
4094
        int i, recursion = 1; /* RNA_int_get(op->ptr, "recursion"); */ /* temp removed, see comment below */
 
4095
        const int use_even = RNA_boolean_get(op->ptr, "use_even");
 
4096
        const int use_dist = RNA_boolean_get(op->ptr, "use_dist");
 
4097
        float *w = NULL, ftot;
 
4098
        int li;
 
4099
        
 
4100
        BM_data_layer_add(em->bm, &em->bm->edata, CD_PROP_FLT);
 
4101
        li = CustomData_number_of_layers(&em->bm->edata, CD_PROP_FLT) - 1;
 
4102
        
 
4103
        BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
 
4104
                float d = len_v3v3(eed->v1->co, eed->v2->co);
 
4105
                float *dv = CustomData_bmesh_get_n(&em->bm->edata, eed->head.data, CD_PROP_FLT, li);
 
4106
                
 
4107
                *dv = d;
 
4108
        }
 
4109
        
 
4110
        if (em == NULL) {
 
4111
                return OPERATOR_CANCELLED;
 
4112
        }
 
4113
        
 
4114
        w = MEM_mallocN(sizeof(float) * recursion, "bevel weights");
 
4115
 
 
4116
        /* ugh, stupid math depends somewhat on angles!*/
 
4117
        /* dfac = 1.0/(float)(recursion + 1); */ /* UNUSED */
 
4118
        df = 1.0;
 
4119
        for (i = 0, ftot = 0.0f; i < recursion; i++) {
 
4120
                s = powf(df, 1.25f);
 
4121
 
 
4122
                w[i] = s;
 
4123
                ftot += s;
 
4124
 
 
4125
                df *= 2.0;
 
4126
        }
 
4127
 
 
4128
        mul_vn_fl(w, recursion, 1.0f / (float)ftot);
 
4129
 
 
4130
        for (i = 0; i < recursion; i++) {
 
4131
                float fac = w[recursion - i - 1] * factor;
 
4132
 
 
4133
                if (!EDBM_op_init(em, &bmop, op,
 
4134
                                  "bevel geom=%hev percent=%f lengthlayer=%i use_lengths=%b use_even=%b use_dist=%b",
 
4135
                                  BM_ELEM_SELECT, fac, li, TRUE, use_even, use_dist))
 
4136
                {
 
4137
                        return OPERATOR_CANCELLED;
 
4138
                }
 
4139
                
 
4140
                BMO_op_exec(em->bm, &bmop);
 
4141
                if (!EDBM_op_finish(em, &bmop, op, TRUE))
 
4142
                        return OPERATOR_CANCELLED;
 
4143
        }
 
4144
        
 
4145
        BM_data_layer_free_n(em->bm, &em->bm->edata, CD_PROP_FLT, li);
 
4146
        
 
4147
        MEM_freeN(w);
 
4148
 
 
4149
        EDBM_mesh_normals_update(em);
 
4150
 
 
4151
        EDBM_update_generic(C, em, TRUE);
 
4152
 
 
4153
        return OPERATOR_FINISHED;
 
4154
}
 
4155
 
 
4156
void MESH_OT_bevel(wmOperatorType *ot)
 
4157
{
 
4158
        /* identifiers */
 
4159
        ot->name = "Bevel";
 
4160
        ot->description = "Edge Bevel";
 
4161
        ot->idname = "MESH_OT_bevel";
 
4162
 
 
4163
        /* api callbacks */
 
4164
        ot->exec = edbm_bevel_exec;
 
4165
        ot->poll = ED_operator_editmesh;
 
4166
 
 
4167
        /* flags */
 
4168
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
4169
 
 
4170
        RNA_def_float(ot->srna, "percent", 0.5f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f);
 
4171
//  XXX, disabled for 2.63 release, needs to work much better without overlap before we can give to users.
 
4172
//      RNA_def_int(ot->srna, "recursion", 1, 1, 50, "Recursion Level", "Recursion Level", 1, 8);
 
4173
 
 
4174
        RNA_def_boolean(ot->srna, "use_even", FALSE, "Even",     "Calculate evenly spaced bevel");
 
4175
        RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units");
 
4176
 
 
4177
}
 
4178
 
 
4179
static int edbm_bridge_edge_loops_exec(bContext *C, wmOperator *op)
 
4180
{
 
4181
        Object *obedit = CTX_data_edit_object(C);
 
4182
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
4183
        
 
4184
        if (!EDBM_op_callf(em, op, "bridge_loops edges=%he", BM_ELEM_SELECT))
 
4185
                return OPERATOR_CANCELLED;
 
4186
        
 
4187
        EDBM_update_generic(C, em, TRUE);
 
4188
 
 
4189
        return OPERATOR_FINISHED;
 
4190
}
 
4191
 
 
4192
void MESH_OT_bridge_edge_loops(wmOperatorType *ot)
 
4193
{
 
4194
        /* identifiers */
 
4195
        ot->name = "Bridge Two Edge Loops";
 
4196
        ot->description = "Make faces between two edge loops";
 
4197
        ot->idname = "MESH_OT_bridge_edge_loops";
 
4198
        
 
4199
        /* api callbacks */
 
4200
        ot->exec = edbm_bridge_edge_loops_exec;
 
4201
        ot->poll = ED_operator_editmesh;
 
4202
        
 
4203
        /* flags */
 
4204
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
4205
        
 
4206
        RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
 
4207
}
 
4208
 
 
4209
 
 
4210
 
 
4211
static int edbm_inset_exec(bContext *C, wmOperator *op)
 
4212
{
 
4213
        Object *obedit = CTX_data_edit_object(C);
 
4214
        BMEditMesh *em = BMEdit_FromObject(obedit);
 
4215
        BMOperator bmop;
 
4216
        const int use_boundary        = RNA_boolean_get(op->ptr, "use_boundary");
 
4217
        const int use_even_offset     = RNA_boolean_get(op->ptr, "use_even_offset");
 
4218
        const int use_relative_offset = RNA_boolean_get(op->ptr, "use_relative_offset");
 
4219
        const float thickness         = RNA_float_get(op->ptr,   "thickness");
 
4220
        const float depth             = RNA_float_get(op->ptr,   "depth");
 
4221
        const int use_outset          = RNA_boolean_get(op->ptr, "use_outset");
 
4222
        const int use_select_inset    = RNA_boolean_get(op->ptr, "use_select_inset"); /* not passed onto the BMO */
 
4223
 
 
4224
        EDBM_op_init(em, &bmop, op,
 
4225
                     "inset faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b "
 
4226
                     "thickness=%f depth=%f use_outset=%b",
 
4227
                     BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset,
 
4228
                     thickness, depth, use_outset);
 
4229
 
 
4230
        BMO_op_exec(em->bm, &bmop);
 
4231
 
 
4232
        if (use_select_inset) {
 
4233
                /* deselect original faces/verts */
 
4234
                EDBM_flag_disable_all(em, BM_ELEM_SELECT);
 
4235
                BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_FACE, BM_ELEM_SELECT, TRUE);
 
4236
        }
 
4237
        else {
 
4238
                BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE, BM_ELEM_SELECT, FALSE);
 
4239
                BMO_slot_buffer_hflag_disable(em->bm, &bmop, "faceout", BM_FACE, BM_ELEM_SELECT, FALSE);
 
4240
                /* re-select faces so the verts and edges get selected too */
 
4241
                BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, TRUE, BM_ELEM_SELECT);
 
4242
        }
 
4243
 
 
4244
        if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
 
4245
                return OPERATOR_CANCELLED;
 
4246
        }
 
4247
        else {
 
4248
                EDBM_update_generic(C, em, TRUE);
 
4249
                return OPERATOR_FINISHED;
 
4250
        }
 
4251
}
 
4252
 
 
4253
void MESH_OT_inset(wmOperatorType *ot)
 
4254
{
 
4255
        PropertyRNA *prop;
 
4256
 
 
4257
        /* identifiers */
 
4258
        ot->name = "Inset Faces";
 
4259
        ot->idname = "MESH_OT_inset";
 
4260
        ot->description = "Inset new faces into selected faces";
 
4261
 
 
4262
        /* api callbacks */
 
4263
        ot->exec = edbm_inset_exec;
 
4264
        ot->poll = ED_operator_editmesh;
 
4265
 
 
4266
        /* flags */
 
4267
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
4268
 
 
4269
        /* properties */
 
4270
        RNA_def_boolean(ot->srna, "use_boundary",        TRUE, "Boundary",  "Inset face boundaries");
 
4271
        RNA_def_boolean(ot->srna, "use_even_offset",     TRUE, "Offset Even",      "Scale the offset to give more even thickness");
 
4272
        RNA_def_boolean(ot->srna, "use_relative_offset", FALSE, "Offset Relative", "Scale the offset by surrounding geometry");
 
4273
 
 
4274
        prop = RNA_def_float(ot->srna, "thickness", 0.01f, 0.0f, FLT_MAX, "Thickness", "", 0.0f, 10.0f);
 
4275
        /* use 1 rather then 10 for max else dragging the button moves too far */
 
4276
        RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4);
 
4277
        prop = RNA_def_float(ot->srna, "depth", 0.0f, -FLT_MAX, FLT_MAX, "Depth", "", -10.0f, 10.0f);
 
4278
        RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4);
 
4279
 
 
4280
        RNA_def_boolean(ot->srna, "use_outset", FALSE, "Outset", "Outset rather than inset");
 
4281
        RNA_def_boolean(ot->srna, "use_select_inset", TRUE, "Select Outer", "Select the new inset faces");
 
4282
}