35
editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
44
#include "BLO_sys_types.h" // for intptr_t support
46
#include "DNA_meshdata_types.h"
32
#include "MEM_guardedalloc.h"
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"
52
#include "MEM_guardedalloc.h"
54
40
#include "RNA_define.h"
55
41
#include "RNA_access.h"
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"
65
#include "BLI_scanfill.h"
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"
72
#include "BKE_bmesh.h"
51
#include "BKE_object.h"
73
52
#include "BKE_report.h"
53
#include "BKE_texture.h"
55
#include "BKE_tessmesh.h"
76
57
#include "WM_api.h"
77
58
#include "WM_types.h"
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"
67
#include "RE_render_ext.h"
86
69
#include "mesh_intern.h"
89
static void waitcursor(int UNUSED(val)) {}
90
#define add_numbut(a, b, c, d, e, f, g) {}
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}};
103
/* local prototypes ---------------*/
104
static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa);
105
int EdgeLoopDelete(EditMesh *em, wmOperator *op);
107
/********* qsort routines *********/
110
typedef struct xvertsort {
115
static int vergxco(const void *v1, const void *v2)
117
const xvertsort *x1=v1, *x2=v2;
119
if( x1->x > x2->x ) return 1;
120
else if( x1->x < x2->x) return -1;
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])
75
if (dot_v3v3(nor, add) < -0.9999f) {
83
static int edbm_subdivide_exec(bContext *C, wmOperator *op)
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;
91
if (RNA_boolean_get(op->ptr, "quadtri") &&
92
RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
94
RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
97
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
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"));
104
EDBM_update_generic(C, em, TRUE);
106
return OPERATOR_FINISHED;
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}
130
static int vergface(const void *v1, const void *v2)
132
const struct facesort *x1=v1, *x2=v2;
134
if( x1->x > x2->x ) return 1;
135
else if( x1->x < x2->x) return -1;
140
/* *********************************** */
142
static void convert_to_triface(EditMesh *em, int direction)
144
EditFace *efa, *efan, *next;
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);
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);
168
BLI_remlink(&em->faces, efa);
169
free_editface(em, efa);
175
EM_fgon_flags(em); // redo flags and indices for fgons
180
int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */
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.
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;
198
/* flag 128 is cleared, count */
200
/* Normal non weld operation */
201
eve= em->verts.first;
205
if(eve->h==0 && (automerge || (eve->f & flag))) amount++;
208
if(amount==0) return 0;
210
/* allocate memory and qsort */
211
sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
212
eve= em->verts.first;
214
if(eve->h==0 && (automerge || (eve->f & flag))) {
215
sb->x= eve->co[0]+eve->co[1]+eve->co[2];
221
qsort(sortblock, amount, sizeof(xvertsort), vergxco);
224
/* test for doubles */
227
for(a=0; a<amount; a++, sb++) {
229
if( (eve->f & 128)==0 ) {
231
for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) {
232
if(sb1->x - sb->x > limit) break;
234
/* when automarge, only allow unselected->selected */
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)
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)
259
for(a=0; a<amount; a++, sb++) {
261
if( (eve->f & 128)==0 ) {
263
for(b=a+1; b<amount; b++, sb1++) {
264
/* first test: simpel dist */
265
if(sb1->x - sb->x > limit) break;
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)
282
MEM_freeN(sortblock);
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);
289
/* test edges and insert again */
290
eed= em->edges.first;
300
if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
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);
312
if(e1!=eed) free_editedge(em, eed);
318
/* first count amount of test faces */
319
efa= (struct EditFace *)em->faces.first;
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;
328
if(efa->f1==1) amount++;
332
/* test faces for double vertices, and if needed remove them */
333
efa= (struct EditFace *)em->faces.first;
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;
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;
353
if(test==1 || test==2) {
358
EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3);
362
else if(test==8 || test==16) {
367
BLI_remlink(&em->faces, efa);
368
free_editface(em, efa);
373
BLI_remlink(&em->faces, efa);
374
free_editface(em, efa);
380
/* set edge pointers */
381
efa->e1= findedgelist(em, efa->v1, efa->v2);
382
efa->e2= findedgelist(em, efa->v2, efa->v3);
384
efa->e3= findedgelist(em, efa->v3, efa->v1);
388
efa->e3= findedgelist(em, efa->v3, efa->v4);
389
efa->e4= findedgelist(em, efa->v4, efa->v1);
396
/* double faces: sort block */
397
/* count again, now all selected faces */
399
efa= em->faces.first;
402
if(faceselectedOR(efa, 1)) {
410
/* double faces: sort block */
411
vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub");
412
efa= em->faces.first;
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);
424
qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
427
for(a=0; a<amount; a++) {
429
if( (efa->f1 & 128)==0 ) {
432
for(b=a+1; b<amount; b++) {
434
/* first test: same pointer? */
435
if(vsb->x != vsb1->x) break;
437
/* second test: is test permitted? */
439
if( (efa->f1 & 128)==0 ) {
440
if( compareface(efa, vsb->efa)) efa->f1 |= 128;
449
MEM_freeN(vlsortblock);
451
/* remove double faces */
452
efa= (struct EditFace *)em->faces.first;
456
BLI_remlink(&em->faces, efa);
457
free_editface(em, efa);
463
/* remove double vertices */
465
eve= (struct EditVert *)em->verts.first;
468
if(automerge || eve->f & flag) {
471
BLI_remlink(&em->verts, eve);
472
free_editvert(em, eve);
478
return a; /* amount */
481
static int removedoublesflag_exec(bContext *C, wmOperator *op)
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;
487
int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
489
if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
490
recalc_editnormals(em);
492
DAG_id_tag_update(obedit->data, 0);
493
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
496
BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices");
498
BKE_mesh_end_editmesh(obedit->data, em);
500
return OPERATOR_FINISHED;
503
void MESH_OT_remove_doubles(wmOperatorType *ot)
118
void MESH_OT_subdivide(wmOperatorType *ot)
505
120
PropertyRNA *prop;
507
122
/* identifiers */
508
ot->name= "Remove Doubles";
509
ot->description= "Remove duplicate vertices";
510
ot->idname= "MESH_OT_remove_doubles";
513
ot->exec= removedoublesflag_exec;
514
ot->poll= ED_operator_editmesh;
517
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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);
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)
527
xvertsort *sortblock = userData;
529
sortblock[index].x = x;
532
/* all verts with (flag & 'flag') are sorted */
533
static void xsortvert_flag(bContext *C, int flag)
537
xvertsort *sortblock;
541
em_setup_viewcontext(C, &vc);
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)
547
sortblock[i].v1 = eve;
549
ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
550
mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF);
552
qsort(sortblock, amount, sizeof(xvertsort), vergxco);
554
/* make temporal listbase */
555
tbase.first= tbase.last= 0;
556
for (i=0; i<amount; i++) {
557
eve = sortblock[i].v1;
560
BLI_remlink(&vc.em->verts, eve);
561
BLI_addtail(&tbase, eve);
565
BLI_movelisttolist(&vc.em->verts, &tbase);
567
MEM_freeN(sortblock);
571
static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
573
xsortvert_flag(C, SELECT);
574
return OPERATOR_FINISHED;
577
void MESH_OT_vertices_sort(wmOperatorType *ot)
580
ot->name= "Vertex Sort";
581
ot->description= "Sort vertex order";
582
ot->idname= "MESH_OT_vertices_sort";
585
ot->exec= mesh_vertices_sort_exec;
587
ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
590
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
594
/* called from buttons */
595
static void hashvert_flag(EditMesh *em, int flag)
597
/* switch vertex order using hash table */
599
struct xvertsort *sortblock, *sb, onth, *newsort;
604
eve= em->verts.first;
607
if(eve->f & flag) amount++;
610
if(amount==0) return;
612
/* allocate memory */
613
sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
614
eve= em->verts.first;
626
for(a=0; a<amount; a++, sb++) {
627
b= (int)(amount*BLI_drand());
628
if(b>=0 && b<amount) {
629
newsort= sortblock+b;
636
/* make temporal listbase */
637
tbase.first= tbase.last= 0;
641
BLI_remlink(&em->verts, eve);
642
BLI_addtail(&tbase, eve);
646
BLI_movelisttolist(&em->verts, &tbase);
648
MEM_freeN(sortblock);
652
static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
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;
660
void MESH_OT_vertices_randomize(wmOperatorType *ot)
663
ot->name= "Vertex Randomize";
664
ot->description= "Randomize vertex order";
665
ot->idname= "MESH_OT_vertices_randomize";
668
ot->exec= mesh_vertices_randomize_exec;
670
ot->poll= ED_operator_editmesh;
673
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
123
ot->name = "Subdivide";
124
ot->description = "Subdivide selected edges";
125
ot->idname = "MESH_OT_subdivide";
128
ot->exec = edbm_subdivide_exec;
129
ot->poll = ED_operator_editmesh;
132
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
139
RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor", 0.0f, 1.0f);
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)");
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);
150
void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em)
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];
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);
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))
179
EDBM_op_init(em, &bmop, op, "extrude_face_indiv faces=%hf", hflag);
181
/* deselect original verts */
182
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
184
BMO_op_exec(em->bm, &bmop);
186
BMO_ITER (f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
187
BM_face_select_set(em->bm, f, TRUE);
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);
195
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
199
return 's'; // s is shrink/fatten
202
/* extrudes individual edges */
203
static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
207
EDBM_op_init(em, &bmop, op, "extrude_edge_only edges=%he", hflag);
209
/* deselect original verts */
210
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
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);
215
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
219
return 'n'; // n is normal grab
222
/* extrudes individual vertices */
223
static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
227
EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag);
229
/* deselect original verts */
230
BMO_slot_buffer_hflag_disable(em->bm, &bmop, "verts", BM_VERT, BM_ELEM_SELECT, TRUE);
232
BMO_op_exec(em->bm, &bmop);
233
BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_VERT, BM_ELEM_SELECT, TRUE);
235
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
239
return 'g'; // g is grab
242
static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
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);
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.
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;
264
if (mmd->flag & MOD_MIR_CLIPPING) {
266
if (mmd->mirror_ob) {
268
invert_m4_m4(imtx, mmd->mirror_ob->obmat);
269
mult_m4_m4m4(mtx, imtx, obedit->obmat);
272
for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL);
274
edge = BM_iter_step(&iter))
276
if (BM_elem_flag_test(edge, hflag) &&
277
BM_edge_is_boundary(edge) &&
278
BM_elem_flag_test(edge->l->f, hflag))
280
float co1[3], co2[3];
282
copy_v3_v3(co1, edge->v1->co);
283
copy_v3_v3(co2, edge->v2->co);
285
if (mmd->mirror_ob) {
286
mul_v3_m4v3(co1, mtx, co1);
287
mul_v3_m4v3(co2, mtx, co2);
290
if (mmd->flag & MOD_MIR_AXIS_X) {
291
if ((fabsf(co1[0]) < mmd->tolerance) &&
292
(fabsf(co2[0]) < mmd->tolerance))
294
BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
297
if (mmd->flag & MOD_MIR_AXIS_Y) {
298
if ((fabsf(co1[1]) < mmd->tolerance) &&
299
(fabsf(co2[1]) < mmd->tolerance))
301
BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
304
if (mmd->flag & MOD_MIR_AXIS_Z) {
305
if ((fabsf(co1[2]) < mmd->tolerance) &&
306
(fabsf(co2[2]) < mmd->tolerance))
308
BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL);
317
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
319
BMO_op_exec(bm, &extop);
323
BMO_ITER (ele, &siter, bm, &extop, "geomout", BM_ALL) {
324
BM_elem_select_set(bm, ele, TRUE);
326
if (ele->head.htype == BM_FACE) {
328
add_normal_aligned(nor, f->no);
334
BMO_op_finish(bm, &extop);
336
/* grab / normal constraint */
337
return is_zero_v3(nor) ? 'g' : 'n';
340
static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
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);
353
BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT);
354
BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT);
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);
362
BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT);
367
return edbm_extrude_edge(obedit, em, hflag, nor);
370
static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
372
Object *obedit = CTX_data_edit_object(C);
373
BMEditMesh *em = BMEdit_FromObject(obedit);
374
RegionView3D *rv3d = CTX_wm_region_view3d(C);
376
int steps = RNA_int_get(op->ptr, "steps");
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};
383
normalize_v3_v3(dvec, rv3d->persinv[2]);
384
mul_v3_fl(dvec, offs);
386
/* base correction */
387
copy_m3_m4(bmat, obedit->obmat);
388
invert_m3_m3(tmat, bmat);
389
mul_m3_v3(tmat, dvec);
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);
399
EDBM_mesh_normals_update(em);
401
EDBM_update_generic(C, em, TRUE);
403
return OPERATOR_FINISHED;
406
void MESH_OT_extrude_repeat(wmOperatorType *ot)
409
ot->name = "Extrude Repeat Mesh";
410
ot->description = "Extrude selected vertices, edges or faces repeatedly";
411
ot->idname = "MESH_OT_extrude_repeat";
414
ot->exec = edbm_extrude_repeat_exec;
415
ot->poll = ED_operator_editmesh_view3d;
418
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
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)
680
float nor[3]= {0.0, 0.0, 0.0};
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);
693
BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
698
/* We need to force immediate calculation here because
699
* transform may use derived objects (which are now stale).
701
* This shouldn't be necessary, derived queries should be
702
* automatically building this data if invalid. Or something.
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;
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");
443
nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
445
else if (em->selectmode & SCE_SELECT_EDGE) {
446
if (em->bm->totedgesel == 0) nr = 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");
455
nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
459
if (em->bm->totfacesel == 0) nr = 0;
460
else if (em->bm->totfacesel == 1) nr = 1;
462
nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
465
if (nr < 1) return 'g';
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);
474
if (transmode == 0) {
475
BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
479
/* We need to force immediate calculation here because
480
* transform may use derived objects (which are now stale).
482
* This shouldn't be necessary, derived queries should be
483
* automatically building this data if invalid. Or something.
485
// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
486
object_handle_update(scene, obedit);
706
488
/* individual faces? */
707
489
// BIF_TransformSetUndo("Extrude");
709
491
// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
713
495
// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
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");
725
// XXX should be a menu item
726
static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
728
Object *obedit= CTX_data_edit_object(C);
729
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
731
extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
733
BKE_mesh_end_editmesh(obedit->data, em);
735
DAG_id_tag_update(obedit->data, 0);
736
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
738
return OPERATOR_FINISHED;
741
508
/* extrude without transform */
742
static int mesh_extrude_exec(bContext *C, wmOperator *op)
744
Object *obedit= CTX_data_edit_object(C);
745
EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
747
extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
749
DAG_id_tag_update(obedit->data, 0);
750
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
752
BKE_mesh_end_editmesh(obedit->data, em);
753
return OPERATOR_FINISHED;
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}};
764
static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
766
EnumPropertyItem *item= NULL;
767
Object *obedit= CTX_data_edit_object(C);
772
if(obedit==NULL || obedit->type != OB_MESH)
773
return extrude_items;
775
em = BKE_mesh_get_editmesh(obedit->data);
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]);
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]);
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]);
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]);
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]);
814
if (em->totfacesel == 0) {}
815
else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); }
817
RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
818
RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
823
RNA_enum_item_end(&item, &totitem);
832
void MESH_OT_extrude(wmOperatorType *ot)
838
ot->description= "Extrude selected vertices, edges or faces";
839
ot->idname= "MESH_OT_extrude";
842
ot->invoke= mesh_extrude_invoke;
843
ot->exec= mesh_extrude_exec;
844
ot->poll= ED_operator_editmesh;
847
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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);
856
static int split_mesh(bContext *C, wmOperator *UNUSED(op))
858
Object *obedit= CTX_data_edit_object(C);
859
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
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);
871
DAG_id_tag_update(obedit->data, 0);
872
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
874
BKE_mesh_end_editmesh(obedit->data, em);
875
return OPERATOR_FINISHED;
878
void MESH_OT_split(wmOperatorType *ot)
882
ot->description= "Split selected geometry into separate disconnected mesh";
883
ot->idname= "MESH_OT_split";
886
ot->exec= split_mesh;
887
ot->poll= ED_operator_editmesh;
890
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
894
static int extrude_repeat_mesh_exec(bContext *C, wmOperator *op)
896
Object *obedit= CTX_data_edit_object(C);
897
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
899
int steps = RNA_int_get(op->ptr,"steps");
901
float offs = RNA_float_get(op->ptr,"offset");
903
float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
907
RNA_float_get_array(op->ptr, "direction", dvec);
913
/* base correction */
914
copy_m3_m4(bmat, obedit->obmat);
915
invert_m3_m3(tmat, bmat);
916
mul_m3_v3(tmat, dvec);
918
for(a=0; a<steps; a++) {
919
extrudeflag(obedit, em, SELECT, nor, 0);
920
translateflag(em, SELECT, dvec);
923
recalc_editnormals(em);
927
DAG_id_tag_update(obedit->data, 0);
928
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
930
BKE_mesh_end_editmesh(obedit->data, em);
931
return OPERATOR_FINISHED;
934
/* get center and axis, in global coords */
935
static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
937
RegionView3D *rv3d= ED_view3d_context_rv3d(C);
940
RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]);
942
return extrude_repeat_mesh_exec(C, op);
945
void MESH_OT_extrude_repeat(wmOperatorType *ot)
948
ot->name= "Extrude Repeat Mesh";
949
ot->description= "Extrude selected vertices, edges or faces repeatedly";
950
ot->idname= "MESH_OT_extrude_repeat";
953
ot->invoke= extrude_repeat_mesh_invoke;
954
ot->exec= extrude_repeat_mesh_exec;
955
ot->poll= ED_operator_editmesh;
958
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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);
966
/* ************************** spin operator ******************** */
969
static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli )
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];
981
RNA_float_get_array(op->ptr, "center", cent);
983
/* imat and center and size */
984
copy_m3_m4(bmat, obedit->obmat);
985
invert_m3_m3(imat,bmat);
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);
992
phi= degr*(float)M_PI/360.0f;
994
if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
996
RNA_float_get_array(op->ptr, "axis", n);
999
q[0]= (float)cos(phi);
1000
si= (float)sin(phi);
1004
quat_to_mat3( cmat,q);
1006
mul_m3_m3m3(tmat,cmat,bmat);
1007
mul_m3_m3m3(bmat,imat,tmat);
1010
if(ts->editbutflag & B_KEEPORIG)
1011
adduplicateflag(em, 1);
1013
for(a=0; a<steps; a++) {
1014
if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0);
1015
else adduplicateflag(em, SELECT);
1020
rotateflag(em, SELECT, cent, bmat);
1022
mul_m3_v3(bmat,dvec);
1023
translateflag(em, SELECT, dvec);
1028
/* no vertices or only loose ones selected, remove duplicates */
1029
eve= em->verts.first;
1032
if(eve->f & SELECT) {
1033
BLI_remlink(&em->verts,eve);
1034
free_editvert(em, eve);
1040
recalc_editnormals(em);
1044
DAG_id_tag_update(obedit->data, 0);
1047
BKE_mesh_end_editmesh(obedit->data, em);
1051
static int spin_mesh_exec(bContext *C, wmOperator *op)
1053
Object *obedit= CTX_data_edit_object(C);
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"));
1058
BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
1059
return OPERATOR_CANCELLED;
1062
DAG_id_tag_update(obedit->data, 0);
1063
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1065
return OPERATOR_FINISHED;
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)
1071
511
Scene *scene = CTX_data_scene(C);
1072
View3D *v3d = CTX_wm_view3d(C);
1073
RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1075
RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
1076
RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
1078
return spin_mesh_exec(C, op);
1081
void MESH_OT_spin(wmOperatorType *ot)
1085
ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport";
1086
ot->idname= "MESH_OT_spin";
1089
ot->invoke= spin_mesh_invoke;
1090
ot->exec= spin_mesh_exec;
1091
ot->poll= EM_view3d_poll;
1094
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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);
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);
1106
static int screw_mesh_exec(bContext *C, wmOperator *op)
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;
1112
float dvec[3], nor[3];
1115
turns= RNA_int_get(op->ptr, "turns");
1116
steps= RNA_int_get(op->ptr, "steps");
1119
for(eve= em->verts.first; eve; eve= eve->next)
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++;
1132
/* find two vertices with eve->f1==1, more or less is wrong */
1133
for(eve= em->verts.first; eve; eve= eve->next) {
1135
if(v1==NULL) v1= eve;
1136
else if(v2==NULL) v2= eve;
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;
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;
1154
VECCOPY(nor, obedit->obmat[2]);
1156
if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) {
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);
1164
BKE_mesh_end_editmesh(obedit->data, em);
512
Object *obedit = CTX_data_edit_object(C);
513
BMEditMesh *em = BMEdit_FromObject(obedit);
515
edbm_extrude_mesh(scene, obedit, em, op, NULL);
517
/* This normally happens when pushing undo but modal operators
518
* like this one don't push undo data until after modal mode is
520
EDBM_mesh_normals_update(em);
522
EDBM_update_generic(C, em, TRUE);
524
return OPERATOR_FINISHED;
527
void MESH_OT_extrude_region(wmOperatorType *ot)
530
ot->name = "Extrude Region";
531
ot->idname = "MESH_OT_extrude_region";
532
ot->description = "Extrude region of faces";
535
//ot->invoke = mesh_extrude_region_invoke;
536
ot->exec = edbm_extrude_region_exec;
537
ot->poll = ED_operator_editmesh;
540
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
542
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
545
static int edbm_extrude_verts_exec(bContext *C, wmOperator *op)
547
Object *obedit = CTX_data_edit_object(C);
548
BMEditMesh *em = BMEdit_FromObject(obedit);
551
edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor);
553
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
555
return OPERATOR_FINISHED;
558
void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
561
ot->name = "Extrude Only Vertices";
562
ot->idname = "MESH_OT_extrude_verts_indiv";
563
ot->description = "Extrude individual vertices only";
566
ot->exec = edbm_extrude_verts_exec;
567
ot->poll = ED_operator_editmesh;
570
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
572
/* to give to transform */
573
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
576
static int edbm_extrude_edges_exec(bContext *C, wmOperator *op)
578
Object *obedit = CTX_data_edit_object(C);
579
BMEditMesh *em = BMEdit_FromObject(obedit);
582
edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor);
584
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
586
return OPERATOR_FINISHED;
589
void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
592
ot->name = "Extrude Only Edges";
593
ot->idname = "MESH_OT_extrude_edges_indiv";
594
ot->description = "Extrude individual edges only";
597
ot->exec = edbm_extrude_edges_exec;
598
ot->poll = ED_operator_editmesh;
601
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
603
/* to give to transform */
604
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
607
static int edbm_extrude_faces_exec(bContext *C, wmOperator *op)
609
Object *obedit = CTX_data_edit_object(C);
610
BMEditMesh *em = BMEdit_FromObject(obedit);
613
edbm_extrude_face_indiv(em, op, BM_ELEM_SELECT, nor);
615
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
617
return OPERATOR_FINISHED;
620
void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
623
ot->name = "Extrude Individual Faces";
624
ot->idname = "MESH_OT_extrude_faces_indiv";
625
ot->description = "Extrude individual faces only";
628
ot->exec = edbm_extrude_faces_exec;
629
ot->poll = ED_operator_editmesh;
632
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
634
RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
637
/* ******************** (de)select all operator **************** */
639
static int edbm_select_all_exec(bContext *C, wmOperator *op)
641
Object *obedit = CTX_data_edit_object(C);
642
BMEditMesh *em = BMEdit_FromObject(obedit);
643
int action = RNA_enum_get(op->ptr, "action");
647
EDBM_select_toggle_all(em);
650
EDBM_flag_enable_all(em, BM_ELEM_SELECT);
653
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
656
EDBM_select_swap(em);
657
EDBM_selectmode_flush(em);
661
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
663
return OPERATOR_FINISHED;
666
void MESH_OT_select_all(wmOperatorType *ot)
669
ot->name = "(De)select All";
670
ot->idname = "MESH_OT_select_all";
671
ot->description = "(De)select all vertices, edges or faces";
674
ot->exec = edbm_select_all_exec;
675
ot->poll = ED_operator_editmesh;
678
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
680
WM_operator_properties_select_all(ot);
683
static int edbm_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op))
685
Object *obedit = CTX_data_edit_object(C);
686
BMEditMesh *em = BMEdit_FromObject(obedit);
688
if (EDBM_select_interior_faces(em)) {
689
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
1165
691
return OPERATOR_FINISHED;
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;
1174
/* get center and axis, in global coords */
1175
static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1177
Scene *scene = CTX_data_scene(C);
1178
View3D *v3d = CTX_wm_view3d(C);
1179
RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1181
RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
1182
RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
1184
return screw_mesh_exec(C, op);
1187
void MESH_OT_screw(wmOperatorType *ot)
1191
ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport";
1192
ot->idname= "MESH_OT_screw";
1195
ot->invoke= screw_mesh_invoke;
1196
ot->exec= screw_mesh_exec;
1197
ot->poll= EM_view3d_poll;
1200
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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);
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);
1210
static void erase_edges(EditMesh *em, ListBase *l)
1212
EditEdge *ed, *nexted;
1214
ed = (EditEdge *) l->first;
1217
if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
1219
free_editedge(em, ed);
1225
static void erase_faces(EditMesh *em, ListBase *l)
1227
EditFace *f, *nextf;
1229
f = (EditFace *) l->first;
1233
if( faceselectedOR(f, SELECT) ) {
1235
free_editface(em, f);
1241
static void erase_vertices(EditMesh *em, ListBase *l)
1243
EditVert *v, *nextv;
1245
v = (EditVert *) l->first;
1250
free_editvert(em, v);
1256
static void delete_mesh(EditMesh *em, wmOperator *op, int event)
1258
EditFace *efa, *nextvl;
1259
EditVert *eve,*nextve;
1260
EditEdge *eed,*nexted;
1262
/* const char *str="Erase"; */
1268
/* str= "Erase Vertices"; */
1269
erase_edges(em, &em->edges);
1270
erase_faces(em, &em->faces);
1271
erase_vertices(em, &em->verts);
1274
if(!EdgeLoopDelete(em, op))
1277
/* str= "Erase Edge Loop"; */
1280
/* str= "Erase Edges & Faces"; */
1281
efa= em->faces.first;
1284
/* delete only faces with 1 or more edges selected */
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++;
1291
BLI_remlink(&em->faces, efa);
1292
free_editface(em, efa);
1296
eed= em->edges.first;
1299
if(eed->f & SELECT) {
1301
free_editedge(em, eed);
1305
efa= em->faces.first;
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++;
1315
BLI_remlink(&em->faces, efa);
1316
free_editface(em, efa);
1322
/* str= "Erase Edges"; */
1324
efa= em->faces.first;
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++;
1334
BLI_remlink(&em->faces, efa);
1335
free_editface(em, efa);
1339
eed= em->edges.first;
1342
if(eed->f & SELECT) {
1344
free_editedge(em, eed);
1348
/* to remove loose vertices: */
1349
eed= em->edges.first;
1351
if( eed->v1->f & SELECT) eed->v1->f-=SELECT;
1352
if( eed->v2->f & SELECT) eed->v2->f-=SELECT;
1355
eve= em->verts.first;
1358
if(eve->f & SELECT) {
1359
BLI_remlink(&em->verts,eve);
1360
free_editvert(em, eve);
1367
/* str="Erase Faces"; */
1368
delfaceflag(em, SELECT);
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));
1378
/* str= "Erase Only Faces"; */
1379
efa= em->faces.first;
1382
if(efa->f & SELECT) {
1383
BLI_remlink(&em->faces, efa);
1384
free_editface(em, efa);
1390
recalc_editnormals(em);
1392
EM_fgon_flags(em); // redo flags and indices for fgons
699
void MESH_OT_select_interior_faces(wmOperatorType *ot)
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";
707
ot->exec = edbm_faces_select_interior_exec;
708
ot->poll = ED_operator_editmesh;
711
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
714
/* *************** add-click-mesh (extrude) operator ************** */
715
static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
720
float min[3], max[3];
724
em_setup_viewcontext(C, &vc);
726
use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) &&
727
(vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE));
729
INIT_MINMAX(min, max);
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);
740
const short rot_src = RNA_boolean_get(op->ptr, "rotate_source");
742
float vec[3], cent[3], mat[3][3];
743
float nor[3] = {0.0, 0.0, 0.0};
748
mval_f[0] = (float)event->mval[0];
749
mval_f[1] = (float)event->mval[1];
751
/* check for edges that are half selected, use for rotation */
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);
761
/* 2D rotate by 90d while adding.
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]);
771
nor[0] += (co2[1] - co1[1]);
772
nor[1] += -(co2[0] - co1[0]);
779
float view_vec[3], cross[3];
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 */
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);
794
mid_v3_v3v3(cent, min, max);
795
copy_v3_v3(min, cent);
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
801
sub_v3_v3(min, cent);
803
/* calculate rotation */
808
normalize_v3_v3(vec, min);
810
angle = angle_normalized_v3v3(vec, nor);
815
cross_v3_v3v3(axis, nor, vec);
817
/* halve the rotation if its applied twice */
822
axis_angle_to_mat3(mat, axis, angle);
827
EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
828
BM_ELEM_SELECT, cent, mat);
830
/* also project the source, for retopo workflow */
832
EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
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);
842
float *curs = give_cursor(vc.scene, vc.v3d);
846
copy_v3_v3(min, curs);
847
view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0);
849
invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
850
mul_m4_v3(vc.obedit->imat, min); // back in object space
852
EDBM_op_init(vc.em, &bmop, op, "makevert co=%v", min);
853
BMO_op_exec(vc.em->bm, &bmop);
855
BMO_ITER (v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
856
BM_vert_select_set(vc.em->bm, v1, TRUE);
859
if (!EDBM_op_finish(vc.em, &bmop, op, TRUE)) {
860
return OPERATOR_CANCELLED;
865
EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
867
/* This normally happens when pushing undo but modal operators
868
* like this one don't push undo data until after modal mode is
870
EDBM_mesh_normals_update(vc.em);
872
EDBM_update_generic(C, vc.em, TRUE);
874
return OPERATOR_FINISHED;
877
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
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";
885
ot->invoke = edbm_dupli_extrude_cursor_invoke;
886
ot->poll = ED_operator_editmesh;
889
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
891
RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
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}
1407
static int delete_mesh_exec(bContext *C, wmOperator *op)
904
static int edbm_delete_exec(bContext *C, wmOperator *op)
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");
1414
return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL);
1416
delete_mesh(em, op, type);
1418
DAG_id_tag_update(obedit->data, 0);
1419
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
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");
911
if (!EDBM_op_callf(em, op, "del geom=%hv context=%i", BM_ELEM_SELECT, DEL_VERTS)) /* Erase Vertices */
912
return OPERATOR_CANCELLED;
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;
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;
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;
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;
933
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
935
EDBM_update_generic(C, em, TRUE);
1422
937
return OPERATOR_FINISHED;
1425
940
void MESH_OT_delete(wmOperatorType *ot)
1427
942
/* identifiers */
1429
ot->description= "Delete selected vertices, edges or faces";
1430
ot->idname= "MESH_OT_delete";
1433
ot->invoke= WM_menu_invoke;
1434
ot->exec= delete_mesh_exec;
1436
ot->poll= ED_operator_editmesh;
1439
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1442
ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
1447
/*-------------------------------------------------------------------------------*/
1448
/*--------------------------- Edge Based Subdivide ------------------------------*/
1455
/*used by faceloop cut to select only edges valid for edge slide*/
1456
#define DOUBLEOPFILL 16
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)
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];
1467
sub_v3_v3v3(nor, edge->v1->co, edge->v2->co);
1468
len= 0.5f*normalize_v3(nor);
1470
copy_v3_v3(nor1, edge->v1->no);
1471
copy_v3_v3(nor2, edge->v2->no);
1474
fac= dot_v3v3(nor, nor1);
1475
mul_v3_v3fl(tvec, nor1, fac);
1478
fac= -dot_v3v3(nor, nor2);
1479
madd_v3_v3fl(tvec, nor2, fac);
1481
/* falloff for multi subdivide */
1482
smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc)));
1484
mul_v3_fl(tvec, smooth * len);
1486
add_v3_v3(co, tvec);
1488
else if(beauty & B_SPHERE) { /* subdivide sphere */
1490
mul_v3_fl(co, smooth);
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);
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)
1510
interp_v3_v3v3(co, edge->v1->co, edge->v2->co, percent);
1512
/* offset for smooth or sphere or fractal */
1513
alter_co(co, edge, smooth, fractal, beauty, percent);
1515
/* clip if needed by mirror modifier */
1517
if ( edge->v1->f2 & edge->v2->f2 & 1) {
1520
if ( edge->v1->f2 & edge->v2->f2 & 2) {
1523
if ( edge->v1->f2 & edge->v2->f2 & 4) {
1528
ev = addvertlist(em, co, NULL);
1530
/* vert data (vgroups, ..) */
1531
EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent);
1534
interp_v3_v3v3(ev->no, edge->v1->no, edge->v2->no, percent);
1535
normalize_v3(ev->no);
1540
static void flipvertarray(EditVert** arr, short size)
1545
for(i=0; i<size/2; i++) {
1547
arr[i] = arr[size-i-1];
1548
arr[size-i-1] = hold;
1552
static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
1554
float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
1555
float *v4 = source->v4? source->v4->co: NULL;
1558
CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
1560
target->mat_nr = source->mat_nr;
1561
target->flag = source->flag;
1562
target->h = source->h;
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);
1568
interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co);
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);
1574
static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
1576
EditEdge *cedge=NULL;
1577
EditVert *v[4], **verts;
1579
short start=0, /* end, */ /* UNUSED */ left, right, vertsize,i;
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;}
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;
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
1600
if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
1601
/* end = (start+1)%4; */ /* UNUSED */
1603
right = (start+3)%4;
1606
We should have something like this now
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
1620
We will fill this case like this or this depending on even or odd cuts
1622
|---*---*---| |---*---|
1626
------------- ---------
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;
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;
1639
facecopy(em, efa,hold);
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;
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;
1660
static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
1662
EditEdge *cedge=NULL;
1663
EditVert *v[3], **verts;
1665
short start=0, /* end, */ /* UNUSED */ op, vertsize,i;
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;}
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;
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
1684
if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
1685
/* end = (start+1)%3; */ /* UNUSED */
1689
We should have something like this now
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
1705
We will fill this case like this or this depending on even or odd cuts
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;
1726
facecopy(em, efa,hold);
1730
static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1732
EditEdge *cedge[2]={NULL, NULL};
1733
EditVert *v[4], **verts[2];
1735
short start=0, /*end,*/ left, /* right,*/ vertsize,i;
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;}
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;
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
1755
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1756
/* end = (start+1)%4; */ /* UNUSED */
1758
/* right = (start+3)%4; */ /* UNUSED */
1759
if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
1761
We should have something like this now
1773
We will fill this case like this or this depending on even or odd cuts
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;
1789
facecopy(em, efa,hold);
1793
static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1795
EditEdge *cedge[2]={NULL, NULL};
1796
EditVert *v[4], **verts[2];
1798
short start=0, start2=0, vertsize,i;
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;}
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;
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
1821
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1822
if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1824
We should have something like this now
1828
start2 0|---*---*---|
1836
We will fill this case like this or this depending on even or odd cuts
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 */
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 */
1855
hold->e1->f2 |= EDGEINNER;
1856
facecopy(em, efa,hold);
1857
//if(scene->toolsettings->editbutflag & B_AUTOFGON) {
1858
// hold->e1->h |= EM_FGON;
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);
1867
//EM_fgon_flags(em);
1871
static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1873
EditEdge *cedge[2]={NULL, NULL};
1874
EditVert *v[4], *op=NULL, **verts[2];
1876
short start=0, start2=0, /* vertsize, */ /* UNUSED */ i;
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;}
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 */
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
1899
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1900
if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1902
We should have something like this now
1906
start2 0|---*---*---|
1912
end2 3|-----------|op
1914
We will fill this case like this or this (warning horrible ascii art follows)
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);
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);
1935
static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
1937
EditEdge *cedge[2]={NULL, NULL};
1938
EditVert *v[4], *op=NULL, **verts[2],**inner;
1940
short start=0, start2=0, /* vertsize, */ /* UNUSED */ i;
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;}
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 */
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
1964
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
1965
if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
1967
We should have something like this now
1971
start2 0|---*---*---|
1977
end2 3|-----------|op
1979
We will fill this case like this or this (warning horrible ascii art follows)
1990
// Add Inner Vert(s)
1991
inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts");
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;
2000
EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
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);
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);
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);
2017
//if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2018
// hold->e1->h |= EM_FGON;
2020
// Add Fill Quads (if # cuts > 1)
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);
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);
2033
//if(scene->toolsettings->editbutflag & B_AUTOFGON) {
2034
// hold->e1->h |= EM_FGON;
2038
//EM_fgon_flags(em);
2043
static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
2045
EditEdge *cedge[2]={NULL, NULL};
2046
EditVert *v[3], **verts[2];
2048
short start=0, start2=0, vertsize,i;
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;}
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;
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
2068
if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
2069
if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
2071
We should have something like this now
2075
start2 0|---*---*---|
2083
We will fill this case like this or this depending on even or odd cuts
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);
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);
2106
static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
2108
EditEdge *cedge[3]={0};
2109
EditVert *v[4], **verts[3];
2111
short start=0, start2=0, start3=0, vertsize, i, repeats;
2118
if(!(efa->e1->f & SELECT)) {
2122
start = 1;start2 = 2;start3 = 3;
2124
if(!(efa->e2->f & SELECT)) {
2128
start = 2;start2 = 3;start3 = 0;
2130
if(!(efa->e3->f & SELECT)) {
2134
start = 3;start2 = 0;start3 = 1;
2136
if(!(efa->e4->f & SELECT)) {
2140
start = 0;start2 = 1;start3 = 2;
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;
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
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);}
2157
We should have something like this now
2161
start3 0|---*---*---|3
2167
3|-----------|0 start
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
2174
For even cuts, there is a quad in the middle and 2 quads on the bottom
2176
they are numbered here for clarity
2178
1 outer tris and bottom quads
2197
|---*---*---*---*---|
2205
*-------------------*
2209
*-------------------*
2213
*-------------------*
2217
|-------------------|
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);
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;
2243
facecopy(em, efa,hold);
2244
repeats = (numcuts / 2) -1;
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;
2252
facecopy(em, efa,hold);
2253
repeats = ((numcuts+1) / 2)-1;
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);
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);
2272
hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
2274
hold->e2->f2 |= EDGEINNER;
2275
facecopy(em, efa,hold);
2277
//EM_fgon_flags(em);
2280
static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
2282
EditVert **verts[4], ***innerverts;
2285
short /* vertsize, */ /* UNUSED */ i, j;
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);
2293
//This is the index size of the verts array
2294
/* vertsize = numcuts+2; */ /* UNUSED */
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
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);}
2305
We should have something like this now
2319
// we will fill a 2 dim array of editvert*s to make filling easier
2320
// the innervert order is shown
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");
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];
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];
2347
for(j=1;j<=numcuts;j++) {
2348
float percent= (float)j/(float)(numcuts+1);
2350
innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent);
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;
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; }
2367
facecopy(em, efa,hold);
2370
// Clean up our dynamic multi-dim array
2371
for(i=0;i<numcuts+2;i++) {
2372
MEM_freeN(innerverts[i]);
2374
MEM_freeN(innerverts);
2377
static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
2379
EditVert **verts[3], ***innerverts;
2380
short /* vertsize, */ /* UNUSED */ i, j;
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);
2389
//This is the index size of the verts array
2390
/* vertsize = numcuts+2; */ /* UNUSED */
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
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);}
2400
We should have something like this now
2413
we will fill a 2 dim array of editvert*s to make filling easier
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");
2435
//top row is e3 backwards
2436
for(i=0;i<numcuts+2;i++) {
2437
innerverts[0][i] = verts[2][(numcuts+1)-i];
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];
2445
for(j=1;j<(numcuts+1)-i;j++) {
2446
float percent= (float)j/(float)((numcuts+1)-i);
2448
innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent);
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;}
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;
2476
// Clean up our dynamic multi-dim array
2477
for(i=0;i<numcuts+2;i++) {
2478
MEM_freeN(innerverts[i]);
2480
MEM_freeN(innerverts);
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)
2489
Depending on which two vertices have been knifed through (v1 and v2), we
2490
triangulate like the patterns below.
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);
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);
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);
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);
2530
static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
2532
EditEdge *cedge=NULL;
2533
EditVert *v[4], **verts;
2535
short start=0, end, left, right /* , vertsize */ /* UNUSED */;
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;}
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 */
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
2556
if(verts[0] != v[start]) {flipvertarray(verts,3);}
2559
right = (start+3)%4;
2562
We should have something like this now
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...
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);
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);
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);
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)
2631
if (beauty & (B_PERCENTSUBD) && totpoint == 1)
2632
//percent=(float)(edge->tmp.l)/32768.0f;
2633
percent= edge->tmp.fp;
2635
percent= (float)curpoint/(float)(totpoint+1);
2637
ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent);
2638
ev->f = edge->v1->f;
2643
void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype)
2646
EditEdge *eed, *cedge, *sort[4];
2647
EditVert *eve, **templist;
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;
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 */
2662
for (; md; md=md->next) {
2663
if ((md->type==eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
2664
MirrorModifierData *mmd = (MirrorModifierData*) md;
2666
if(mmd->flag & MOD_MIR_CLIPPING) {
2667
for (eve= em->verts.first; eve; eve= eve->next) {
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;
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;
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*
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) {
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);
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);
2719
// Beauty Short Edges
2720
if(beauty & B_BEAUTY_SHORT) {
2726
} else if(hold == -1) {
2729
if(length[hold] < length[i]) {
2735
sort[hold]->f &= ~SELECT;
2736
sort[hold]->f2 |= EDGENEW;
2742
// Beauty Long Edges
2749
} else if(hold == -1) {
2752
if(length[hold] > length[i]) {
2758
sort[hold]->f &= ~SELECT;
2759
sort[hold]->f2 |= EDGENEW;
2768
gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh");
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);
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) {
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
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;
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);
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) {
2808
if(ef->e1->f & flag) {edgecount++;}
2809
if(ef->e2->f & flag) {edgecount++;}
2810
if(ef->e3->f & flag) {edgecount++;}
2813
if(ef->e4->f & flag) {edgecount++;}
2818
if(beauty & B_KNIFE && numcuts == 1){
2819
/*Test for when knifing through two opposite verts but no edges*/
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){
2828
fill_quad_doublevert(em, ef, 1, 3);
2830
else if(ef->v2->f1 && ef->v4->f1){
2832
fill_quad_doublevert(em, ef, 2, 4);
2839
if(beauty & B_KNIFE && numcuts == 1){
2840
/*Test for when knifing through an edge and one vert*/
2842
if(ef->v1->f1) touchcount++;
2843
if(ef->v2->f1) touchcount++;
2844
if(ef->v3->f1) touchcount++;
2845
if(ef->v4->f1) touchcount++;
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 )) ){
2854
fill_quad_singlevert(em, ef, gh);
2858
fill_quad_single(em, ef, gh, numcuts, seltype);
2863
fill_quad_single(em, ef, gh, numcuts, seltype);
2868
fill_quad_single(em, ef, gh, numcuts, seltype);
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);
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;
2886
case 3: ef->f1 = SELECT;
2887
fill_quad_triple(em, ef, gh, numcuts);
2889
case 4: ef->f1 = SELECT;
2890
fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty);
2896
case 1: ef->f1 = SELECT;
2897
fill_tri_single(em, ef, gh, numcuts, seltype);
2899
case 2: ef->f1 = SELECT;
2900
fill_tri_double(em, ef, gh, numcuts);
2902
case 3: ef->f1 = SELECT;
2903
fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty);
2909
// Delete Old Edges and Faces
2910
for(eed = em->edges.first;eed;eed = eed->next) {
2911
if(BLI_ghash_haskey(gh,eed)) {
2917
free_tagged_edges_faces(em, em->edges.first, em->faces.first);
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
2923
for(eed = em->edges.first;eed;eed = eed->next) {
2924
if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) {
2926
EM_select_edge(eed,0);
2929
for(eed = em->edges.first;eed;eed = eed->next) {
2930
if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) {
2932
EM_select_edge(eed,1);
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) {
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;
2944
EM_select_edge(eed,0);
2947
} else if(seltype == SUBDIV_SELECT_LOOPCUT){
2948
for(eed = em->edges.first;eed;eed = eed->next) {
2949
if(eed->f2 & DOUBLEOPFILL){
2951
EM_select_edge(eed,1);
2954
EM_select_edge(eed,0);
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;
2967
//fix hide flags for edges. First pass, hide edges of hidden faces
2968
for(ef=em->faces.first; ef; ef=ef->next){
2973
if(ef->e4) ef->e4->h |= 1;
2976
//second pass: unhide edges of visible faces adjacent to hidden faces
2977
for(ef=em->faces.first; ef; ef=ef->next){
2982
if(ef->e4) ef->e4->h &= ~1;
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)
2993
// Free the ghash and call MEM_freeN on all the value entries to return
2995
BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
2997
EM_selectmode_flush(em);
2998
for(ef=em->faces.first;ef;ef = ef->next) {
3000
if( (ef->e1->f & SELECT && ef->e2->f & SELECT) &&
3001
(ef->e3->f & SELECT && ef->e4->f & SELECT) ) {
3005
if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
3011
recalc_editnormals(em);
3014
static int count_selected_edges(EditEdge *ed)
3019
if( ed->f & SELECT ) totedge++;
3025
/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */
3026
typedef EditFace *EVPtr;
3027
typedef EVPtr EVPTuple[2];
3029
/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces)
3031
arguments: selected edge list, face list.
3032
Edges will also be tagged accordingly (see eed->f2) */
3034
static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
3036
EditEdge *e1, *e2, *e3;
3040
/* run through edges, if selected, set pointer edge-> facearray */
3044
if( eed->f & SELECT ) {
3045
eed->tmp.p = (EditVert *) (&efaa[i]);
3048
else eed->tmp.p = NULL;
3054
/* find edges pointing to 2 faces by procedure:
3056
- run through faces and their edges, increase
3057
face counter e->f1 for each face
3062
if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */
3066
if(e1->f2<3 && e1->tmp.p) {
3068
evp= (EVPtr *) e1->tmp.p;
3069
evp[(int)e1->f2] = efa;
3073
if(e2->f2<3 && e2->tmp.p) {
3075
evp= (EVPtr *) e2->tmp.p;
3076
evp[(int)e2->f2]= efa;
3080
if(e3->f2<3 && e3->tmp.p) {
3082
evp= (EVPtr *) e3->tmp.p;
3083
evp[(int)e3->f2]= efa;
3089
/* set to 3 to make sure these are not flipped or joined */
3093
if (efa->e4) efa->e4->f2= 3;
3102
/* returns vertices of two adjacent triangles forming a quad
3103
- can be righthand or lefthand
3114
#define VTEST(face, num, other) \
3115
(face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
3117
static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex)
3119
if VTEST(efa, 1, efa1) {
3125
else if VTEST(efa, 2, efa1) {
3131
else if VTEST(efa, 3, efa1) {
3138
if VTEST(efa1, 1, efa) {
3140
*v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
3142
vindex[3]= (efa1->v2 == *v2)? 2: 1;
3144
else if VTEST(efa1, 2, efa) {
3146
*v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
3148
vindex[3]= (efa1->v3 == *v2)? 0: 2;
3150
else if VTEST(efa1, 3, efa) {
3152
*v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
3154
vindex[3]= (efa1->v1 == *v2)? 1: 0;
3160
/* Helper functions for edge/quad edit features*/
3161
static void untag_edges(EditFace *f)
3166
if (f->e4) f->e4->f1 = 0;
3169
/** remove and free list of tagged edges and faces */
3170
static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
3178
BLI_remlink(&em->faces, efa);
3179
free_editface(em, efa);
3182
/* avoid deleting edges that are still in use */
3191
free_editedge(em, eed);
3198
/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
3199
static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit)
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;
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);
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);
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;
3222
measure += (normalADiff/360) + (normalBDiff/360);
3223
if(measure > limit) return measure;
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);
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;
3241
if(measure > limit) return measure;
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);
3247
if(areaA <= areaB) minarea = areaA;
3248
else minarea = areaB;
3250
if(areaA >= areaB) maxarea = areaA;
3251
else maxarea = areaB;
3253
if(!maxarea) measure += 1;
3254
else measure += (1 - (minarea / maxarea));
3259
#define T2QUV_LIMIT 0.005f
3260
#define T2QCOL_LIMIT 3
3261
static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
3263
/*Test to see if the per-face attributes for the joining edge match within limit*/
3265
unsigned int *col1, *col2;
3266
short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2];
3268
tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE);
3269
tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE);
3271
col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL);
3272
col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL);
3274
/*store indices for faceedges*/
3279
fe1[0] = eed->v1->f1;
3280
fe1[1] = eed->v2->f1;
3286
fe2[0] = eed->v1->f1;
3287
fe2[1] = eed->v2->f1;
3289
/*compare faceedges for each face attribute. Additional per face attributes can be added later*/
3291
if(flag & B_JOINTRIA_UV){
3293
if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
3294
else if(tf1->tpage != tf2->tpage); /*do nothing*/
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;
3304
if(flag & B_JOINTRIA_VCOL){
3305
if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
3307
char *f1vcol, *f2vcol;
3308
for(i = 0; i < 2; i++){
3309
f1vcol = (char *)&(col1[fe1[i]]);
3310
f2vcol = (char *)&(col2[fe2[i]]);
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;
3320
if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1;
3324
static int fplcmp(const void *v1, const void *v2)
3326
const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
3328
if( e1->crease > e2->crease) return 1;
3329
else if( e1->crease < e2->crease) return -1;
3334
/*Bitflags for edges.*/
3336
#define T2QCOMPLEX 2
3338
void join_triangles(EditMesh *em)
3340
EditVert *v1, *v2, *v3, *v4, *eve;
3341
EditEdge *eed, **edsortblock = NULL, **edb = NULL;
3343
EVPTuple *efaar = 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];
3350
/*if we take a long time on very dense meshes we want waitcursor to display*/
3353
totseledge = count_selected_edges(em->edges.first);
3354
if(totseledge==0) return;
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;
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;
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);
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 */
3382
efaa= (EVPtr *) eed->tmp.p;
3388
for(eed=em->edges.first; eed; eed=eed->next){
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){
3397
efaa[0]->f1 = 1; //mark for join
3398
efaa[1]->f1 = 1; //mark for join
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:
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
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.
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.
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*/
3424
measure = measure_facepair(v1, v2, v3, v4, limit);
3425
if(measure < limit){
3427
eed->f1 |= T2QCOMPLEX;
3428
eed->crease = measure; /*we dont mark edges for join yet*/
3436
/*Quicksort the complex edges according to their weighting*/
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){
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;
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.*/
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);
3478
/*free data and cleanup*/
3480
for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
3483
for(eed=em->edges.first; eed; eed=eed->next){
3484
if(eed->f1 & T2QDELETE) eed->f1 = 1;
3487
free_tagged_edges_faces(em, em->edges.first, em->faces.first);
3488
if(efaar) MEM_freeN(efaar);
3489
if(edsortblock) MEM_freeN(edsortblock);
3491
EM_selectmode_flush(em);
3494
/* ******************** END TRIANGLE TO QUAD ************************************* */
3496
#define FACE_MARKCLEAR(f) (f->f1 = 1)
3498
/* quick hack, basically a copy of beautify_fill */
3499
static void edge_flip(EditMesh *em)
3501
EditVert *v1, *v2, *v3, *v4;
3502
EditEdge *eed, *nexted;
3504
//void **efaar, **efaa;
3507
int totedge, ok, vindex[4];
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
3516
EM_selectmode_flush(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
3518
totedge = count_selected_edges(em->edges.first);
3519
if(totedge==0) return;
3521
/* temporary array for : edge -> face[1], face[2] */
3522
efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
3524
ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
3526
eed= em->edges.first;
3530
if(eed->f2==2) { /* points to 2 faces */
3532
efaa= (EVPtr *) eed->tmp.p;
3534
/* don't do it if flagged */
3538
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
3540
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
3544
givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
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);
3563
EM_select_face(w, 1);
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);
3569
EM_select_face(w, 1);
3571
/* tag as to-be-removed */
3572
FACE_MARKCLEAR(efaa[1]);
3573
FACE_MARKCLEAR(efaa[0]);
3576
} /* endif test convex */
3583
/* clear tagged edges and faces: */
3584
free_tagged_edges_faces(em, em->edges.first, em->faces.first);
3589
#define DIRECTION_CW 1
3590
#define DIRECTION_CCW 2
3592
static const EnumPropertyItem direction_items[]= {
944
ot->description = "Delete selected vertices, edges or faces";
945
ot->idname = "MESH_OT_delete";
948
ot->invoke = WM_menu_invoke;
949
ot->exec = edbm_delete_exec;
951
ot->poll = ED_operator_editmesh;
954
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
957
ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 0, "Type", "Method used for deleting mesh data");
960
static int edbm_collapse_edge_exec(bContext *C, wmOperator *op)
962
Object *obedit = CTX_data_edit_object(C);
963
BMEditMesh *em = BMEdit_FromObject(obedit);
965
if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
966
return OPERATOR_CANCELLED;
968
EDBM_update_generic(C, em, TRUE);
970
return OPERATOR_FINISHED;
973
void MESH_OT_edge_collapse(wmOperatorType *ot)
976
ot->name = "Edge Collapse";
977
ot->description = "Collapse selected edges";
978
ot->idname = "MESH_OT_edge_collapse";
981
ot->exec = edbm_collapse_edge_exec;
982
ot->poll = ED_operator_editmesh;
985
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
988
static int edbm_collapse_edge_loop_exec(bContext *C, wmOperator *op)
990
Object *obedit = CTX_data_edit_object(C);
991
BMEditMesh *em = BMEdit_FromObject(obedit);
993
if (!EDBM_op_callf(em, op, "dissolve_edge_loop edges=%he", BM_ELEM_SELECT))
994
return OPERATOR_CANCELLED;
996
EDBM_update_generic(C, em, TRUE);
998
return OPERATOR_FINISHED;
1001
void MESH_OT_edge_collapse_loop(wmOperatorType *ot)
1004
ot->name = "Edge Collapse Loop";
1005
ot->description = "Collapse selected edge loops";
1006
ot->idname = "MESH_OT_edge_collapse_loop";
1009
ot->exec = edbm_collapse_edge_loop_exec;
1010
ot->poll = ED_operator_editmesh;
1013
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1016
static int edbm_add_edge_face__smooth_get(BMesh *bm)
1021
unsigned int vote_on_smooth[2] = {0, 0};
1023
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1024
if (BM_elem_flag_test(e, BM_ELEM_SELECT) && e->l)
1026
vote_on_smooth[BM_elem_flag_test_bool(e->l->f, BM_ELEM_SMOOTH)]++;
1030
return (vote_on_smooth[0] < vote_on_smooth[1]);
1033
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
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 */
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))
1045
return OPERATOR_CANCELLED;
1048
BMO_op_exec(em->bm, &bmop);
1049
BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_FACE, BM_ELEM_SELECT, TRUE);
1051
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1052
return OPERATOR_CANCELLED;
1055
EDBM_update_generic(C, em, TRUE);
1057
return OPERATOR_FINISHED;
1060
void MESH_OT_edge_face_add(wmOperatorType *ot)
1063
ot->name = "Make Edge/Face";
1064
ot->description = "Add an edge or face to selected";
1065
ot->idname = "MESH_OT_edge_face_add";
1068
ot->exec = edbm_add_edge_face_exec;
1069
ot->poll = ED_operator_editmesh;
1072
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1075
/* ************************* SEAMS AND EDGES **************** */
1077
static int edbm_mark_seam(bContext *C, wmOperator *op)
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);
1086
int clear = RNA_boolean_get(op->ptr, "clear");
1088
/* auto-enable seams drawing */
1090
me->drawflag |= ME_DRAWSEAMS;
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))
1098
BM_elem_flag_disable(eed, BM_ELEM_SEAM);
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))
1105
BM_elem_flag_enable(eed, BM_ELEM_SEAM);
1109
ED_uvedit_live_unwrap(scene, obedit);
1110
EDBM_update_generic(C, em, TRUE);
1112
return OPERATOR_FINISHED;
1115
void MESH_OT_mark_seam(wmOperatorType *ot)
1118
ot->name = "Mark Seam";
1119
ot->idname = "MESH_OT_mark_seam";
1120
ot->description = "(Un)mark selected edges as a seam";
1123
ot->exec = edbm_mark_seam;
1124
ot->poll = ED_operator_editmesh;
1127
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1129
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1132
static int edbm_mark_sharp(bContext *C, wmOperator *op)
1134
Object *obedit = CTX_data_edit_object(C);
1135
Mesh *me = ((Mesh *)obedit->data);
1136
BMEditMesh *em = BMEdit_FromObject(obedit);
1140
int clear = RNA_boolean_get(op->ptr, "clear");
1142
/* auto-enable sharp edge drawing */
1144
me->drawflag |= ME_DRAWSHARP;
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))
1152
BM_elem_flag_disable(eed, BM_ELEM_SMOOTH);
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))
1160
BM_elem_flag_enable(eed, BM_ELEM_SMOOTH);
1164
EDBM_update_generic(C, em, TRUE);
1166
return OPERATOR_FINISHED;
1169
void MESH_OT_mark_sharp(wmOperatorType *ot)
1172
ot->name = "Mark Sharp";
1173
ot->idname = "MESH_OT_mark_sharp";
1174
ot->description = "(Un)mark selected edges as sharp";
1177
ot->exec = edbm_mark_sharp;
1178
ot->poll = ED_operator_editmesh;
1181
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1183
RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
1187
static int edbm_vert_connect(bContext *C, wmOperator *op)
1189
Object *obedit = CTX_data_edit_object(C);
1190
BMEditMesh *em = BMEdit_FromObject(obedit);
1195
if (!EDBM_op_init(em, &bmop, op, "connectverts verts=%hv", BM_ELEM_SELECT)) {
1196
return OPERATOR_CANCELLED;
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;
1204
EDBM_update_generic(C, em, TRUE);
1206
return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1209
void MESH_OT_vert_connect(wmOperatorType *ot)
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";
1217
ot->exec = edbm_vert_connect;
1218
ot->poll = ED_operator_editmesh;
1221
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1224
static int edbm_edge_split_exec(bContext *C, wmOperator *op)
1226
Object *obedit = CTX_data_edit_object(C);
1227
BMEditMesh *em = BMEdit_FromObject(obedit);
1232
if (!EDBM_op_init(em, &bmop, op, "edgesplit edges=%he", BM_ELEM_SELECT)) {
1233
return OPERATOR_CANCELLED;
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;
1241
EDBM_update_generic(C, em, TRUE);
1243
return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1246
void MESH_OT_edge_split(wmOperatorType *ot)
1249
ot->name = "Edge Split";
1250
ot->idname = "MESH_OT_edge_split";
1253
ot->exec = edbm_edge_split_exec;
1254
ot->poll = ED_operator_editmesh;
1257
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1260
/****************** add duplicate operator ***************/
1262
static int edbm_duplicate_exec(bContext *C, wmOperator *op)
1264
Object *ob = CTX_data_edit_object(C);
1265
BMEditMesh *em = BMEdit_FromObject(ob);
1268
EDBM_op_init(em, &bmop, op, "dupe geom=%hvef", BM_ELEM_SELECT);
1270
BMO_op_exec(em->bm, &bmop);
1271
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1273
BMO_slot_buffer_hflag_enable(em->bm, &bmop, "newout", BM_ALL, BM_ELEM_SELECT, TRUE);
1275
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1276
return OPERATOR_CANCELLED;
1279
EDBM_update_generic(C, em, TRUE);
1281
return OPERATOR_FINISHED;
1284
static int edbm_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
1287
edbm_duplicate_exec(C, op);
1290
return OPERATOR_FINISHED;
1293
void MESH_OT_duplicate(wmOperatorType *ot)
1296
ot->name = "Duplicate";
1297
ot->description = "Duplicate selected vertices, edges or faces";
1298
ot->idname = "MESH_OT_duplicate";
1301
ot->invoke = edbm_duplicate_invoke;
1302
ot->exec = edbm_duplicate_exec;
1304
ot->poll = ED_operator_editmesh;
1306
/* to give to transform */
1307
RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1310
static int edbm_flip_normals_exec(bContext *C, wmOperator *op)
1312
Object *obedit = CTX_data_edit_object(C);
1313
BMEditMesh *em = BMEdit_FromObject(obedit);
1315
if (!EDBM_op_callf(em, op, "reversefaces faces=%hf", BM_ELEM_SELECT))
1316
return OPERATOR_CANCELLED;
1318
EDBM_update_generic(C, em, TRUE);
1320
return OPERATOR_FINISHED;
1323
void MESH_OT_flip_normals(wmOperatorType *ot)
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";
1331
ot->exec = edbm_flip_normals_exec;
1332
ot->poll = ED_operator_editmesh;
1335
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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}};
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}};
3605
static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
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];
3613
/* check to make sure that the edge is only part of 2 faces */
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 */
3622
face[facecount] = efa;
3631
/* how many edges does each face have */
3632
if(face[0]->e4) fac1= 4;
3635
if(face[1]->e4) fac2= 4;
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;
3644
/* we don't want to rotate edges between faces that share more than one edge */
3646
for(i=0; i<fac1; i++)
3647
for(j=0; j<fac2; j++)
3648
if (edges[0][i] == edges[1][j])
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 */
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;
3668
if((p1+1)%fac1 == p2)
3670
if((p3+1)%fac2 == p4)
3673
for (i = 0; i < 4; i++) {
3674
p[0][i]= (p1 + i)%fac1;
3675
p[1][i]= (p3 + i)%fac2;
3678
/* create an Array of the Edges who have h set prior to rotate */
3680
for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next)
3681
if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT)))
3684
hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
3686
BKE_report(op->reports, RPT_ERROR, "Memory allocation failed");
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;
3695
/* create the 2 new faces */
3696
if(fac1 == 3 && fac2 == 3) {
3697
/* no need of reverse setup */
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);
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);
3710
verts[0][p[0][2]]->f |= SELECT;
3711
verts[1][p[1][1]]->f |= SELECT;
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]);
3722
verts[0][p[0][1]]->f |= SELECT;
3723
verts[1][p[1][2]]->f |= SELECT;
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]);
3735
verts[0][p[0][2]]->f |= SELECT;
3736
verts[1][p[1][2]]->f |= SELECT;
3740
return; /* This should never happen */
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;
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;
3759
/* resetting hidden flag */
3760
for(numhidden--; numhidden>=0; numhidden--)
3761
hiddenedges[numhidden]->h= 1;
3763
/* check for orhphan edges */
3764
for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
3768
MEM_freeN(hiddenedges);
3770
/* get rid of the old edge and faces*/
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]);
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)
3782
Object *obedit= CTX_data_edit_object(C);
3783
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
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);
1351
const int do_ccw = RNA_enum_get(op->ptr, "direction") == 1;
3789
/*clear new flag for new edges, count selected edges */
3790
for(eed= em->edges.first; eed; eed= eed->next) {
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;
3797
/* more selected edges, check faces */
3798
for(efa= em->faces.first; efa; efa= efa->next) {
3799
if(efa->f & SELECT) {
3803
if(efa->e4) efa->e4->f1++;
3807
for(eed= em->edges.first; eed; eed= eed->next) {
3808
if(eed->f1==2) edgeCount++;
3811
for(eed= em->edges.first; eed; eed= eed->next) {
3813
edge_rotate(em, op, eed,dir);
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)) {
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);
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;
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);
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;
3840
/* flush selected vertices (again) to edges/faces */
3841
EM_select_flush(em);
3843
BKE_mesh_end_editmesh(obedit->data, em);
3845
DAG_id_tag_update(obedit->data, 0);
3846
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1375
/* ok, we don't have two adjacent faces, but we do have two selected ones.
1376
* that's an error condition.*/
1378
BKE_report(op->reports, RPT_ERROR, "Could not find any selected edges that can be rotated");
1379
return OPERATOR_CANCELLED;
1382
EDBM_op_init(em, &bmop, op, "edgerotate edges=%he ccw=%b", BM_ELEM_TAG, do_ccw);
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);
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);
1394
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1395
return OPERATOR_CANCELLED;
1398
EDBM_update_generic(C, em, TRUE);
3848
1400
return OPERATOR_FINISHED;
3851
1403
void MESH_OT_edge_rotate(wmOperatorType *ot)
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";
3859
ot->exec= edge_rotate_selected;
3860
ot->poll= ED_operator_editmesh;
3863
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3866
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around");
3870
/******************* BEVEL CODE STARTS HERE ********************/
3872
/* XXX old bevel not ported yet */
3874
static void UNUSED_FUNCTION(bevel_menu)(EditMesh *em)
3877
BME_TransData_Head *td;
3879
int options, res, gbm_free = 0;
3881
// t = BIF_GetTransInfo();
3883
G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
3887
G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT;
3888
G.editBMesh->res = 1;
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");
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);
3903
BME_free_transdata(td);
3905
// if (t->state != TRANS_CONFIRM) {
3908
if (options == G.editBMesh->options) {
3909
G.editBMesh->options &= ~BME_BEVEL_RUNNING;
3914
MEM_freeN(G.editBMesh);
3920
/* *********** END BEVEL *********/
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
3926
short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2)
3928
EditFace *search=NULL;
3930
search = em->faces.first;
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))
3941
search = search->next;
3946
int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op))
3948
#if 0 //XXX won't work with new edgeslide
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;
3955
if(!EdgeSlide(em, op, 1, 1)) {
3959
/* restore uvcalc flag */
3960
// scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
3963
removedoublesflag(em, 1,0, 0.001);
3964
EM_select_flush(em);
3965
// DAG_id_tag_update(obedit->data, 0);
3972
/* -------------------- More tools ------------------ */
3974
void mesh_set_face_flags(EditMesh *em, short mode)
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,
3983
short flag = 0, change = 0;
3985
// XXX if (!EM_texFaceCheck()) {
3986
// error("not a mesh with uv/image layers");
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);
4003
if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW))
4006
/* these 2 cant both be on */
4007
if (mode) /* are we seeting*/
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;
4027
efa= em->faces.first;
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;
4041
/********************** Rip Operator *************************/
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])
4046
float vec1[2], vec2[2], mvalf[2];
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];
4053
return dist_to_line_segment_v2(mvalf, vec1, vec2);
4056
/* helper for below */
4057
static void mesh_rip_setface(EditMesh *em, EditFace *sefa)
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;
4065
sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1);
4066
sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2);
4068
sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3);
4069
sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4);
4072
sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3);
4076
/* based on mouse cursor position, it defines how is being ripped */
4077
static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
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;
4088
int *mval= event->mval;
4090
/* select flush... vertices are important */
4091
EM_selectmode_set(em);
4093
ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
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) {
4100
if(efa->v4 && faceselectedOR(efa, SELECT) ) {
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++;
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]) );
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;
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;
4131
/* duplicate vertices, new vertices get selected */
4132
for(eve = em->verts.last; eve; eve= eve->prev) {
4134
if(eve->f & SELECT) {
4135
eve->tmp.v = addvertlist(em, eve->co, eve);
4137
eve->tmp.v->f |= SELECT;
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;
4148
/* or we do the distance trick */
4150
mindist= 1000000.0f;
4151
if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
4152
dist = mesh_rip_edgedist(ar, projectMat,
4154
sefa->e1->v2->co, mval);
4160
if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
4161
dist = mesh_rip_edgedist(ar, projectMat,
4163
sefa->e2->v2->co, mval);
4169
if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
4170
dist= mesh_rip_edgedist(ar, projectMat,
4172
sefa->e3->v2->co, mval);
4178
if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
4179
dist= mesh_rip_edgedist(ar, projectMat,
4181
sefa->e4->v2->co, mval);
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;
4195
faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
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) {
4200
if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
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);
4210
eed->tmp.v = (EditVert *)newed;
4214
/* first clear edges to help finding neighbours */
4215
for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
4217
/* put new vertices & edges && flag in best face */
4218
mesh_rip_setface(em, sefa);
4220
/* starting with neighbours of best face, we loop over the seam */
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 */
4232
mesh_rip_setface(em, efa);
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) {
4247
if(efa->e4) efa->e4->f1= 1;
4250
for(eed = em->edges.last; eed; eed= seed) {
4253
if(eed->v1->tmp.v || eed->v2->tmp.v ||
4254
(eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
4256
free_editedge(em, eed);
4266
/* and remove loose selected vertices, that got duplicated accidentally */
4267
for(eve = em->verts.first; eve; eve= nextve) {
4269
if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
4270
BLI_remlink(&em->verts,eve);
4271
free_editvert(em, eve);
4275
DAG_id_tag_update(obedit->data, 0);
4276
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
4278
BKE_mesh_end_editmesh(obedit->data, em);
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);
4284
return OPERATOR_FINISHED;
4287
void MESH_OT_rip(wmOperatorType *ot)
4291
ot->description= "Rip selection from mesh (quads only)";
4292
ot->idname= "MESH_OT_rip";
4295
ot->invoke= mesh_rip_invoke;
4296
ot->poll= EM_view3d_poll;
4299
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
4301
/* to give to transform */
4302
/* XXX Transform this in a macro */
4303
Transform_Properties(ot, P_CONSTRAINT|P_MIRROR);
4307
/************************ Shape Operators *************************/
4309
static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
4311
EditVert *ev = NULL;
4312
Mesh* me = (Mesh*)obedit->data;
4314
KeyBlock* kb = NULL;
4320
BKE_report(op->reports, RPT_WARNING, "Object Has No Key");
4324
if(ky->block.first){
4325
for(ev = em->verts.first; ev ; ev = ev->next){
4327
for(kb=ky->block.first;kb;kb = kb->next){
4330
VECCOPY(data+(ev->keyindex*3),ev->co);
4335
BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
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;
4348
DAG_id_tag_update(obedit->data, 0);
4353
static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
4355
Object *obedit= CTX_data_edit_object(C);
4356
Mesh *me= obedit->data;
4357
EditMesh *em= BKE_mesh_get_editmesh(me);
4359
shape_propagate(obedit, em, op);
4361
DAG_id_tag_update(&me->id, 0);
4362
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
4364
return OPERATOR_FINISHED;
4368
void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
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";
4376
ot->exec= shape_propagate_to_all_exec;
4377
ot->poll= ED_operator_editmesh;
4380
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
4383
static int blend_from_shape_exec(bContext *C, wmOperator *op)
4385
Object *obedit= CTX_data_edit_object(C);
4386
Mesh *me= obedit->data;
4388
EditMesh *em= BKE_mesh_get_editmesh(me);
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");
4397
if(key && (kb= BLI_findlink(&key->block, shape))) {
4401
refkb= BLI_findlink(&key->block, kb->relative);
4403
refdata = refkb->data;
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);
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);
4416
madd_v3_v3fl(eve->co, co, blend);
4419
/* in blend mode, we interpolate to the shape key */
4420
interp_v3_v3v3(eve->co, eve->co, co, blend);
4429
BKE_mesh_end_editmesh(me, em);
4432
return OPERATOR_CANCELLED;
4434
DAG_id_tag_update(&me->id, 0);
4435
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
4437
return OPERATOR_FINISHED;
4440
static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
4442
Object *obedit= CTX_data_edit_object(C);
4443
Mesh *me= (obedit) ? obedit->data : NULL;
4445
KeyBlock *kb, *actkb;
4446
EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
4449
if(obedit && obedit->type == OB_MESH) {
4451
actkb= ob_get_keyblock(obedit);
4454
for(kb=key->block.first, a=0; kb; kb=kb->next, a++) {
4457
tmp.identifier= kb->name;
4459
RNA_enum_item_add(&item, &totitem, &tmp);
4465
RNA_enum_item_end(&item, &totitem);
4471
void MESH_OT_blend_from_shape(wmOperatorType *ot)
4474
static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
4477
ot->name= "Blend From Shape";
4478
ot->description= "Blend in shape from a shape key";
4479
ot->idname= "MESH_OT_blend_from_shape";
4482
ot->exec= blend_from_shape_exec;
4483
ot->invoke= WM_operator_props_popup;
4484
ot->poll= ED_operator_editmesh;
4487
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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");
4496
/************************ Merge Operator *************************/
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...*/
4503
typedef struct Collection{
4504
struct Collection *next, *prev;
4506
ListBase collectionbase;
4509
typedef struct CollectedEdge{
4510
struct CollectedEdge *next, *prev;
4514
#define MERGELIMIT 0.000001
4516
static void build_edgecollection(EditMesh *em, ListBase *allcollections)
4519
Collection *edgecollection, *newcollection;
4520
CollectedEdge *newedge;
4523
short ebalanced = 0;
4524
short collectionfound = 0;
4526
for (eed=em->edges.first; eed; eed = eed->next){
4533
for(eed=em->edges.first; eed; eed=eed->next){
4535
eed->v1->tmp.l = currtag;
4536
eed->v2->tmp.l = currtag;
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){
4544
for(eed=em->edges.first; eed; eed = eed->next){
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;
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;
4560
for(eed=em->edges.first; eed; eed=eed->next){
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");
4567
BLI_addtail(&(edgecollection->collectionbase), newedge);
4568
collectionfound = 1;
4571
else collectionfound = 0;
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;
4580
newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
4583
BLI_addtail(&(newcollection->collectionbase), newedge);
4584
BLI_addtail(allcollections, newcollection);
4591
static void freecollections(ListBase *allcollections)
4593
struct Collection *curcollection;
4595
for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next)
4596
BLI_freelistN(&(curcollection->collectionbase));
4597
BLI_freelistN(allcollections);
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.
4606
struct wUV *next, *prev;
4608
float u, v; /*cached copy of UV coordinates pointed to by nodes*/
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*/
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*/
4627
typedef struct wUVEdgeCollect{ /*used for grouping*/
4628
struct wUVEdgeCollect *next, *prev;
4633
static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
4635
wUV *curwvert, *newwvert;
4638
MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
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);
4654
newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
4655
newnode->u = &(tf->uv[tfindex][0]);
4656
newnode->v = &(tf->uv[tfindex][1]);
4658
newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert");
4659
newwvert->u = *(newnode->u);
4660
newwvert->v = *(newnode->v);
4661
newwvert->eve = eve;
4663
BLI_addtail(&(newwvert->nodes), newnode);
4664
BLI_addtail(uvverts, newwvert);
4669
static void build_weldedUVs(EditMesh *em, ListBase *uvverts)
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);
4680
static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges)
4682
wUVEdge *curwedge, *newwedge;
4683
int v1tfindex, v2tfindex, found;
4684
MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
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;
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;
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]){
4701
break; //do nothing, we don't need another welded uv edge
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;
4713
BLI_addtail(uvedges, newwedge);
4717
static void build_weldedUVEdges(EditMesh *em, ListBase *uvedges, ListBase *uvverts)
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);
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;
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;
4748
static void free_weldedUVs(ListBase *uvverts)
4751
for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes));
4752
BLI_freelistN(uvverts);
4755
static void collapse_edgeuvs(EditMesh *em)
4757
ListBase uvedges, uvverts, allcollections;
4760
wUVEdgeCollect *collectedwuve, *newcollectedwuve;
4761
Collection *wuvecollection, *newcollection;
4762
int curtag, balanced, collectionfound= 0, vcount;
4765
if (!EM_texFaceCheck(em))
4768
uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
4770
build_weldedUVs(em, &uvverts);
4771
build_weldedUVEdges(em, &uvedges, &uvverts);
4775
for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
4776
curwedge->v1->f = curtag;
4777
curwedge->v2->f = curtag;
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;
4793
for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f;
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;
4807
else collectionfound = 0;
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;
4816
newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
4817
newcollectedwuve->uved = curwedge;
4819
BLI_addtail(&(newcollection->collectionbase), newcollectedwuve);
4820
BLI_addtail(&allcollections, newcollection);
4824
for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
4826
vcount = avg[0] = avg[1] = 0;
4828
for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
4829
avg[0] += collectedwuve->uved->v1uv[0];
4830
avg[1] += collectedwuve->uved->v1uv[1];
4832
avg[0] += collectedwuve->uved->v2uv[0];
4833
avg[1] += collectedwuve->uved->v2uv[1];
4839
avg[0] /= vcount; avg[1] /= vcount;
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];
4846
for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){
4847
*(curwnode->u) = avg[0];
4848
*(curwnode->v) = avg[1];
4853
free_weldedUVs(&uvverts);
4854
BLI_freelistN(&uvedges);
4855
freecollections(&allcollections);
4858
/*End UV Edge collapse code*/
4860
static void collapseuvs(EditMesh *em, EditVert *mergevert)
4867
if (!EM_texFaceCheck(em))
4874
for(efa = em->faces.first; efa; efa=efa->next){
4875
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4877
if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) {
4878
uvav[0] += tf->uv[0][0];
4879
uvav[1] += tf->uv[0][1];
4882
if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){
4883
uvav[0] += tf->uv[1][0];
4884
uvav[1] += tf->uv[1][1];
4887
if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){
4888
uvav[0] += tf->uv[2][0];
4889
uvav[1] += tf->uv[2][1];
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];
4903
for(efa = em->faces.first; efa; efa=efa->next){
4904
tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
4907
tf->uv[0][0] = uvav[0];
4908
tf->uv[0][1] = uvav[1];
4911
tf->uv[1][0] = uvav[0];
4912
tf->uv[1][1] = uvav[1];
4915
tf->uv[2][0] = uvav[0];
4916
tf->uv[2][1] = uvav[1];
4918
if(efa->v4 && efa->v4->f1){
4919
tf->uv[3][0] = uvav[0];
4920
tf->uv[3][1] = uvav[1];
4926
static int collapseEdges(EditMesh *em)
4931
ListBase allcollections;
4932
CollectedEdge *curredge;
4933
Collection *edgecollection;
4935
int totedges, mergecount,vcount /*, groupcount*/;
4938
allcollections.first = 0;
4939
allcollections.last = 0;
4943
build_edgecollection(em, &allcollections);
4944
/*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/
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;
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];
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];
4966
avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount;
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);
4973
if (EM_texFaceCheck(em)) {
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;
4982
collapse_edgeuvs(em);
4986
freecollections(&allcollections);
4987
removedoublesflag(em, 1, 0, MERGELIMIT);
4992
static int merge_firstlast(EditMesh *em, int first, int uvmerge)
4994
EditVert *eve,*mergevert;
1406
ot->name = "Rotate Selected Edge";
1407
ot->description = "Rotate selected edge or adjoining faces";
1408
ot->idname = "MESH_OT_edge_rotate";
1411
ot->exec = edbm_edge_rotate_selected_exec;
1412
ot->poll = ED_operator_editmesh;
1415
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1418
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around");
1422
static int edbm_hide_exec(bContext *C, wmOperator *op)
1424
Object *obedit = CTX_data_edit_object(C);
1425
BMEditMesh *em = BMEdit_FromObject(obedit);
1427
EDBM_mesh_hide(em, RNA_boolean_get(op->ptr, "unselected"));
1429
EDBM_update_generic(C, em, TRUE);
1431
return OPERATOR_FINISHED;
1434
void MESH_OT_hide(wmOperatorType *ot)
1437
ot->name = "Hide Selection";
1438
ot->idname = "MESH_OT_hide";
1439
ot->description = "Hide (un)selected vertices, edges or faces";
1442
ot->exec = edbm_hide_exec;
1443
ot->poll = ED_operator_editmesh;
1446
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1449
RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1452
static int edbm_reveal_exec(bContext *C, wmOperator *UNUSED(op))
1454
Object *obedit = CTX_data_edit_object(C);
1455
BMEditMesh *em = BMEdit_FromObject(obedit);
1457
EDBM_mesh_reveal(em);
1459
EDBM_update_generic(C, em, TRUE);
1461
return OPERATOR_FINISHED;
1464
void MESH_OT_reveal(wmOperatorType *ot)
1467
ot->name = "Reveal Hidden";
1468
ot->idname = "MESH_OT_reveal";
1469
ot->description = "Reveal all hidden vertices, edges and faces";
1472
ot->exec = edbm_reveal_exec;
1473
ot->poll = ED_operator_editmesh;
1476
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1479
static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op)
1481
Object *obedit = CTX_data_edit_object(C);
1482
BMEditMesh *em = BMEdit_FromObject(obedit);
1484
/* doflip has to do with bmesh_rationalize_normals, it's an internal
1486
if (!EDBM_op_callf(em, op, "righthandfaces faces=%hf do_flip=%b", BM_ELEM_SELECT, TRUE))
1487
return OPERATOR_CANCELLED;
1489
if (RNA_boolean_get(op->ptr, "inside"))
1490
EDBM_op_callf(em, op, "reversefaces faces=%hf", BM_ELEM_SELECT);
1492
EDBM_update_generic(C, em, TRUE);
1494
return OPERATOR_FINISHED;
1497
void MESH_OT_normals_make_consistent(wmOperatorType *ot)
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";
1505
ot->exec = edbm_normals_make_consistent_exec;
1506
ot->poll = ED_operator_editmesh;
1509
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1511
RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
1516
static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
1518
Object *obedit = CTX_data_edit_object(C);
1519
BMEditMesh *em = BMEdit_FromObject(obedit);
1521
int mirrx = FALSE, mirry = FALSE, mirrz = FALSE;
1523
float clipdist = 0.0f;
1525
/* mirror before smooth */
1526
if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
1527
EDBM_verts_mirror_cache_begin(em, TRUE);
1530
/* if there is a mirror modifier with clipping, flag the verts that
1531
* are within tolerance of the plane(s) of reflection
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;
1537
if (mmd->flag & MOD_MIR_CLIPPING) {
1538
if (mmd->flag & MOD_MIR_AXIS_X)
1540
if (mmd->flag & MOD_MIR_AXIS_Y)
1542
if (mmd->flag & MOD_MIR_AXIS_Z)
1545
clipdist = mmd->tolerance;
1550
repeat = RNA_int_get(op->ptr, "repeat");
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))
1559
return OPERATOR_CANCELLED;
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);
1569
EDBM_update_generic(C, em, TRUE);
1571
return OPERATOR_FINISHED;
1574
void MESH_OT_vertices_smooth(wmOperatorType *ot)
1577
ot->name = "Smooth Vertex";
1578
ot->description = "Flatten angles of selected vertices";
1579
ot->idname = "MESH_OT_vertices_smooth";
1582
ot->exec = edbm_do_smooth_vertex_exec;
1583
ot->poll = ED_operator_editmesh;
1586
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1588
RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
1591
/********************** Smooth/Solid Operators *************************/
1593
static void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
1598
if (em == NULL) return;
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);
1607
static int edbm_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
1609
Object *obedit = CTX_data_edit_object(C);
1610
BMEditMesh *em = BMEdit_FromObject(obedit);
1612
mesh_set_smooth_faces(em, 1);
1614
EDBM_update_generic(C, em, FALSE);
1616
return OPERATOR_FINISHED;
1619
void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
1622
ot->name = "Shade Smooth";
1623
ot->description = "Display faces smooth (using vertex normals)";
1624
ot->idname = "MESH_OT_faces_shade_smooth";
1627
ot->exec = edbm_faces_shade_smooth_exec;
1628
ot->poll = ED_operator_editmesh;
1631
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1634
static int edbm_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
1636
Object *obedit = CTX_data_edit_object(C);
1637
BMEditMesh *em = BMEdit_FromObject(obedit);
1639
mesh_set_smooth_faces(em, 0);
1641
EDBM_update_generic(C, em, FALSE);
1643
return OPERATOR_FINISHED;
1646
void MESH_OT_faces_shade_flat(wmOperatorType *ot)
1649
ot->name = "Shade Flat";
1650
ot->description = "Display faces flat";
1651
ot->idname = "MESH_OT_faces_shade_flat";
1654
ot->exec = edbm_faces_shade_flat_exec;
1655
ot->poll = ED_operator_editmesh;
1658
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1662
/********************** UV/Color Operators *************************/
1664
static int edbm_rotate_uvs_exec(bContext *C, wmOperator *op)
1666
Object *ob = CTX_data_edit_object(C);
1667
BMEditMesh *em = BMEdit_FromObject(ob);
1670
/* get the direction from RNA */
1671
int dir = RNA_enum_get(op->ptr, "direction");
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);
1676
/* execute the operator */
1677
BMO_op_exec(em->bm, &bmop);
1679
/* finish the operator */
1680
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1681
return OPERATOR_CANCELLED;
1684
EDBM_update_generic(C, em, FALSE);
1687
return OPERATOR_FINISHED;
1690
static int edbm_reverse_uvs_exec(bContext *C, wmOperator *op)
1692
Object *ob = CTX_data_edit_object(C);
1693
BMEditMesh *em = BMEdit_FromObject(ob);
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);
1699
/* execute the operator */
1700
BMO_op_exec(em->bm, &bmop);
1702
/* finish the operator */
1703
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1704
return OPERATOR_CANCELLED;
1707
EDBM_update_generic(C, em, FALSE);
1710
return OPERATOR_FINISHED;
1713
static int edbm_rotate_colors_exec(bContext *C, wmOperator *op)
1715
Object *ob = CTX_data_edit_object(C);
1716
BMEditMesh *em = BMEdit_FromObject(ob);
1719
/* get the direction from RNA */
1720
int dir = RNA_enum_get(op->ptr, "direction");
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);
1725
/* execute the operator */
1726
BMO_op_exec(em->bm, &bmop);
1728
/* finish the operator */
1729
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1730
return OPERATOR_CANCELLED;
1733
/* dependencies graph and notification stuff */
1734
EDBM_update_generic(C, em, FALSE);
1737
return OPERATOR_FINISHED;
1741
static int edbm_reverse_colors_exec(bContext *C, wmOperator *op)
1743
Object *ob = CTX_data_edit_object(C);
1744
BMEditMesh *em = BMEdit_FromObject(ob);
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);
1750
/* execute the operator */
1751
BMO_op_exec(em->bm, &bmop);
1753
/* finish the operator */
1754
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
1755
return OPERATOR_CANCELLED;
1758
EDBM_update_generic(C, em, FALSE);
1761
return OPERATOR_FINISHED;
1764
void MESH_OT_uvs_rotate(wmOperatorType *ot)
1767
ot->name = "Rotate UVs";
1768
ot->idname = "MESH_OT_uvs_rotate";
1769
ot->description = "Rotate UV coordinates inside faces";
1772
ot->exec = edbm_rotate_uvs_exec;
1773
ot->poll = ED_operator_editmesh;
1776
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1779
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around");
1782
//void MESH_OT_uvs_mirror(wmOperatorType *ot)
1783
void MESH_OT_uvs_reverse(wmOperatorType *ot)
1786
ot->name = "Reverse UVs";
1787
ot->idname = "MESH_OT_uvs_reverse";
1788
ot->description = "Flip direction of UV coordinates inside faces";
1791
ot->exec = edbm_reverse_uvs_exec;
1792
ot->poll = ED_operator_editmesh;
1795
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1798
//RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
1801
void MESH_OT_colors_rotate(wmOperatorType *ot)
1804
ot->name = "Rotate Colors";
1805
ot->idname = "MESH_OT_colors_rotate";
1806
ot->description = "Rotate vertex colors inside faces";
1809
ot->exec = edbm_rotate_colors_exec;
1810
ot->poll = ED_operator_editmesh;
1813
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1816
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CCW, "Direction", "Direction to rotate edge around");
1819
void MESH_OT_colors_reverse(wmOperatorType *ot)
1822
ot->name = "Reverse Colors";
1823
ot->idname = "MESH_OT_colors_reverse";
1824
ot->description = "Flip direction of vertex colors inside faces";
1827
ot->exec = edbm_reverse_colors_exec;
1828
ot->poll = ED_operator_editmesh;
1831
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1834
//RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around");
1838
static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
1841
BMEditSelection *ese;
4997
1843
/* do sanity check in mergemenu in edit.c ?*/
4999
ese = em->selected.last;
5000
mergevert= (EditVert*)ese->data;
5003
ese = em->selected.first;
5004
mergevert = (EditVert*)ese->data;
5007
if(mergevert->f&SELECT){
5008
for (eve=em->verts.first; eve; eve=eve->next){
5010
VECCOPY(eve->co,mergevert->co);
5014
if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){
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;
5020
collapseuvs(em, mergevert);
5023
return removedoublesflag(em, 1, 0, MERGELIMIT);
1845
ese = em->bm->selected.last;
1846
mergevert = (BMVert *)ese->ele;
1849
ese = em->bm->selected.first;
1850
mergevert = (BMVert *)ese->ele;
1853
if (!BM_elem_flag_test(mergevert, BM_ELEM_SELECT))
1854
return OPERATOR_CANCELLED;
1857
if (!EDBM_op_callf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_ELEM_SELECT, mergevert))
1858
return OPERATOR_CANCELLED;
1861
if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, mergevert->co))
1862
return OPERATOR_CANCELLED;
1864
return OPERATOR_FINISHED;
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)
5029
float cent[3] = {0.0f, 0.0f, 0.0f};
1872
float *vco = NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f};
5032
for (eve=em->verts.first; eve; eve=eve->next) {
5033
if (eve->f & SELECT) {
5034
add_v3_v3(cent, eve->co);
1875
vco = give_cursor(scene, v3d);
1876
copy_v3_v3(co, vco);
1877
mul_m4_v3(ob->imat, co);
1882
BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
1883
if (!BM_elem_flag_test(v, BM_ELEM_SELECT))
1885
add_v3_v3(cent, v->co);
5042
mul_v3_fl(cent, 1.0f / (float)i);
5044
for (eve=em->verts.first; eve; eve=eve->next) {
5045
if (eve->f & SELECT) {
5046
VECCOPY(eve->co, cent);
1890
return OPERATOR_CANCELLED;
1892
fac = 1.0f / (float)i;
1893
mul_v3_fl(cent, fac);
1894
copy_v3_v3(co, cent);
1899
return OPERATOR_CANCELLED;
1902
if (!EDBM_op_callf(em, wmop, "vert_average_facedata verts=%hv", BM_ELEM_SELECT))
1903
return OPERATOR_CANCELLED;
1906
if (!EDBM_op_callf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_SELECT, co))
1907
return OPERATOR_CANCELLED;
1909
return OPERATOR_FINISHED;
5051
static void em_snap_to_cursor(EditMesh *em, bContext *C)
1912
static int edbm_merge_exec(bContext *C, wmOperator *op)
5053
1914
Scene *scene = CTX_data_scene(C);
5054
Object *ob= CTX_data_edit_object(C);
5055
1915
View3D *v3d = CTX_wm_view3d(C);
5057
float co[3], *vco, invmat[4][4];
5059
invert_m4_m4(invmat, ob->obmat);
5061
vco = give_cursor(scene, v3d);
5063
mul_m4_v3(invmat, co);
5065
for (eve=em->verts.first; eve; eve=eve->next) {
5066
if (eve->f & SELECT) {
5067
VECCOPY(eve->co, co);
5072
static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge)
5077
if(target) em_snap_to_cursor(em, C);
5078
else em_snap_to_center(em);
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;
5085
collapseuvs(em, NULL);
5088
return removedoublesflag(em, 1, 0, MERGELIMIT);
5092
static int merge_exec(bContext *C, wmOperator *op)
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");
5098
int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
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");
1920
switch (RNA_enum_get(op->ptr, "type")) {
5102
count = merge_target(C, em, 0, uvs);
1922
status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
5105
count = merge_target(C, em, 1, uvs);
1925
status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
5108
ese= (EditSelection *)em->selected.last;
5109
if(ese && ese->type == EDITVERT) {
5110
count = merge_firstlast(em, 0, uvs);
5112
BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
1928
status = merge_firstlast(em, 0, uvs, op);
5116
ese= (EditSelection *)em->selected.first;
5117
if(ese && ese->type == EDITVERT) {
5118
count = merge_firstlast(em, 1, uvs);
5121
BKE_report(op->reports, RPT_WARNING, "no last selected vertex set");
1931
status = merge_firstlast(em, 1, uvs, op);
5125
count = collapseEdges(em);
1935
if (!EDBM_op_callf(em, op, "collapse edges=%he", BM_ELEM_SELECT))
5129
if (!(totvert != em->totvert || totedge != em->totedge || totface != em->totface))
5130
1941
return OPERATOR_CANCELLED;
5132
recalc_editnormals(em);
5134
BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices");
5136
BKE_mesh_end_editmesh(obedit->data, em);
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);
5141
1945
return OPERATOR_FINISHED;
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", ""},
5226
#define PATH_SELECT_EDGE_LENGTH 0
5227
#define PATH_SELECT_TOPOLOGICAL 1
5229
static int select_vertex_path_exec(bContext *C, wmOperator *op)
2083
static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op)
5231
Object *obedit= CTX_data_edit_object(C);
5232
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5233
EditVert *eve, *s, *t;
5235
PathEdge *newpe, *currpe;
5238
int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
5239
int unbalanced, totnodes;
5241
int type= RNA_enum_get(op->ptr, "type");
5242
Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
5245
for(eve=em->verts.first; eve; eve=eve->next) {
5247
if(s == NULL) s= eve;
5248
else if(t == NULL) t= eve;
5250
/* more than two vertices are selected,
5251
show warning message and cancel operator */
5258
/*need to find out if t is actually reachable by s....*/
5262
if(s != NULL && t != NULL) {
5269
for(eed=em->edges.first; eed; eed=eed->next){
5271
if(eed->v1->f1 && !eed->v2->f1){
5276
else if(eed->v2->f1 && !eed->v1->f1){
5285
if(s->f1 && t->f1){ /* t can be reached by s */
5286
Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
5288
for(eve=em->verts.first; eve; eve=eve->next){
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]);
5297
else eve->tmp.p = NULL;
5300
for(eed=em->edges.first; eed; eed=eed->next){
5303
currpn = ((PathNode*)eed->v1->tmp.p);
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);
5313
BLI_addtail(&(currpn->edges), newpe);
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);
5325
BLI_addtail(&(currpn->edges), newpe);
5330
heap = BLI_heap_new();
5331
cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
5332
previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
5334
for(v=0; v < totnodes; v++){
5336
previous[v] = -1; /*array of indices*/
5339
pnindex = ((PathNode*)s->tmp.p)->u;
5341
BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
5343
while( !BLI_heap_empty(heap) ){
5345
pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
5346
currpn = &(Q[pnindex]);
5348
if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
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));
5363
pathvert = ((PathNode*)t->tmp.p)->u;
5364
while(pathvert != -1){
5365
for(eve=em->verts.first; eve; eve=eve->next){
5367
if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
5370
pathvert = previous[pathvert];
5373
for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
5376
MEM_freeN(previous);
5377
BLI_heap_free(heap, NULL);
5378
EM_select_flush(em);
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;
5387
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5388
BKE_mesh_end_editmesh(obedit->data, em);
2085
Object *ob = CTX_data_edit_object(C);
2086
BMEditMesh *em = BMEdit_FromObject(ob);
2088
BMEditSelection *sv, *ev;
2090
/* get the type from RNA */
2091
int type = RNA_enum_get(op->ptr, "type");
2093
sv = em->bm->selected.last;
2096
else return OPERATOR_CANCELLED;
2098
return OPERATOR_CANCELLED;
2100
if ((sv->htype != BM_VERT) || (ev->htype != BM_VERT))
2101
return OPERATOR_CANCELLED;
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);
2106
/* execute the operator */
2107
BMO_op_exec(em->bm, &bmop);
2109
/* DO NOT clear the existing selection */
2110
/* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
2112
/* select the output */
2113
BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ALL, BM_ELEM_SELECT, TRUE);
2115
/* finish the operator */
2116
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
2117
return OPERATOR_CANCELLED;
2120
EDBM_selectmode_flush(em);
2122
EDBM_update_generic(C, em, FALSE);
5390
2125
return OPERATOR_FINISHED;
5393
2128
void MESH_OT_select_vertex_path(wmOperatorType *ot)
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}
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";
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;
5410
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2146
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
5412
2148
/* properties */
5413
ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance");
5416
/********************** Region/Loop Operators *************************/
5418
static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
5420
Object *obedit= CTX_data_edit_object(C);
5421
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5426
for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
5428
for(efa=em->faces.first; efa; efa=efa->next){
5441
return OPERATOR_CANCELLED;
5443
EM_clear_flag_all(em, SELECT);
5445
for(eed=em->edges.first; eed; eed=eed->next){
5446
if(eed->f1 == 1) EM_select_edge(eed, 1);
5449
em->selectmode = SCE_SELECT_EDGE;
5450
CTX_data_tool_settings(C)->selectmode= em->selectmode;
5451
EM_selectmode_set(em);
5453
BKE_mesh_end_editmesh(obedit->data, em);
5455
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5457
return OPERATOR_FINISHED;
5460
void MESH_OT_region_to_loop(wmOperatorType *ot)
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";
5468
ot->exec= region_to_loop;
5469
ot->poll= ED_operator_editmesh;
5472
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5475
static int validate_loop(EditMesh *em, Collection *edgecollection)
5479
CollectedEdge *curredge;
5482
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5483
curredge->eed->v1->f1 = 0;
5484
curredge->eed->v2->f1 = 0;
5486
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5487
curredge->eed->v1->f1++;
5488
curredge->eed->v2->f1++;
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);
5496
for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0;
5497
for(efa=em->faces.first; efa; efa=efa->next){
5501
if(efa->e4) efa->e4->f1++;
5503
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
5504
if(curredge->eed->f1 > 2) return(0);
5509
static int loop_bisect(EditMesh *em, Collection *edgecollection)
5511
EditFace *efa, *sf1, *sf2;
5512
EditEdge *eed, *sed;
5513
CollectedEdge *curredge;
5514
int totsf1, totsf2, unbalanced,balancededges;
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;
5519
for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
5522
sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
5524
for(efa=em->faces.first; efa; efa=efa->next){
5527
if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
5530
if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa;
5534
if(sf1==NULL || sf2==NULL)
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;
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;
5555
for(efa=em->faces.first; efa; efa=efa->next){
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;
5577
for(efa=em->faces.first; efa; efa=efa->next){
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;
5595
if(totsf1 < totsf2) return(1);
5599
static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
5601
Object *obedit= CTX_data_edit_object(C);
5602
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5606
ListBase allcollections={NULL,NULL};
5607
Collection *edgecollection;
5610
build_edgecollection(em, &allcollections);
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);
5624
for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/
5625
if(efa->f&SELECT) EM_select_face(efa,1);
5628
freecollections(&allcollections);
5629
BKE_mesh_end_editmesh(obedit->data, em);
5631
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
5633
return OPERATOR_FINISHED;
5636
void MESH_OT_loop_to_region(wmOperatorType *ot)
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";
5644
ot->exec= loop_to_region;
5645
ot->poll= ED_operator_editmesh;
5648
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5651
/********************** UV/Color Operators *************************/
5653
// XXX please check if these functions do what you want them to
5654
/* texface and vertex color editmode tools for the face menu */
5656
static int mesh_rotate_uvs(bContext *C, wmOperator *op)
5658
Object *obedit= CTX_data_edit_object(C);
5659
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5665
int dir= RNA_enum_get(op->ptr, "direction");
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;
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);
5679
if (dir == DIRECTION_CCW) {
5681
tf->uv[0][0]= tf->uv[3][0];
5682
tf->uv[0][1]= tf->uv[3][1];
5684
tf->uv[3][0]= tf->uv[2][0];
5685
tf->uv[3][1]= tf->uv[2][1];
5687
tf->uv[0][0]= tf->uv[2][0];
5688
tf->uv[0][1]= tf->uv[2][1];
5691
tf->uv[2][0]= tf->uv[1][0];
5692
tf->uv[2][1]= tf->uv[1][1];
5697
tf->uv[0][0]= tf->uv[1][0];
5698
tf->uv[0][1]= tf->uv[1][1];
5700
tf->uv[1][0]= tf->uv[2][0];
5701
tf->uv[1][1]= tf->uv[2][1];
5704
tf->uv[2][0]= tf->uv[3][0];
5705
tf->uv[2][1]= tf->uv[3][1];
5719
BKE_mesh_end_editmesh(obedit->data, em);
5722
return OPERATOR_CANCELLED;
5724
DAG_id_tag_update(obedit->data, 0);
5725
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5727
return OPERATOR_FINISHED;
5730
static int mesh_mirror_uvs(bContext *C, wmOperator *op)
5732
Object *obedit= CTX_data_edit_object(C);
5733
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5739
int axis= RNA_enum_get(op->ptr, "axis");
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;
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) {
5755
tf->uv[1][0]= tf->uv[2][0];
5756
tf->uv[1][1]= tf->uv[2][1];
5764
tf->uv[3][0]= tf->uv[0][0];
5765
tf->uv[3][1]= tf->uv[0][1];
5771
tf->uv[1][0]= tf->uv[2][0];
5772
tf->uv[1][1]= tf->uv[2][1];
5782
tf->uv[0][0]= tf->uv[1][0];
5783
tf->uv[0][1]= tf->uv[1][1];
5791
tf->uv[3][0]= tf->uv[2][0];
5792
tf->uv[3][1]= tf->uv[2][1];
5798
tf->uv[0][0]= tf->uv[1][0];
5799
tf->uv[0][1]= tf->uv[1][1];
5808
BKE_mesh_end_editmesh(obedit->data, em);
5811
return OPERATOR_CANCELLED;
5813
DAG_id_tag_update(obedit->data, 0);
5814
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5816
return OPERATOR_FINISHED;
5819
static int mesh_rotate_colors(bContext *C, wmOperator *op)
5821
Object *obedit= CTX_data_edit_object(C);
5822
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5827
int dir= RNA_enum_get(op->ptr, "direction");
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;
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);
5840
if (dir == DIRECTION_CCW) {
5864
BKE_mesh_end_editmesh(obedit->data, em);
5867
return OPERATOR_CANCELLED;
5869
DAG_id_tag_update(obedit->data, 0);
5870
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5872
return OPERATOR_FINISHED;
5876
static int mesh_mirror_colors(bContext *C, wmOperator *op)
5878
Object *obedit= CTX_data_edit_object(C);
5879
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
5884
int axis= RNA_enum_get(op->ptr, "axis");
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;
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) {
5920
BKE_mesh_end_editmesh(obedit->data, em);
5923
return OPERATOR_CANCELLED;
5925
DAG_id_tag_update(obedit->data, 0);
5926
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
5928
return OPERATOR_FINISHED;
5931
void MESH_OT_uvs_rotate(wmOperatorType *ot)
5934
ot->name= "Rotate UVs";
5935
ot->description= "Rotate selected UVs";
5936
ot->idname= "MESH_OT_uvs_rotate";
5939
ot->exec= mesh_rotate_uvs;
5940
ot->poll= ED_operator_editmesh;
5943
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5946
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around");
5949
void MESH_OT_uvs_mirror(wmOperatorType *ot)
5952
ot->name= "Mirror UVs";
5953
ot->description= "Mirror selected UVs";
5954
ot->idname= "MESH_OT_uvs_mirror";
5957
ot->exec= mesh_mirror_uvs;
5958
ot->poll= ED_operator_editmesh;
5961
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5964
RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around");
5967
void MESH_OT_colors_rotate(wmOperatorType *ot)
5970
ot->name= "Rotate Colors";
5971
ot->description= "Rotate UV/image color layer";
5972
ot->idname= "MESH_OT_colors_rotate";
5975
ot->exec= mesh_rotate_colors;
5976
ot->poll= ED_operator_editmesh;
5979
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
5982
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around");
5985
void MESH_OT_colors_mirror(wmOperatorType *ot)
5988
ot->name= "Mirror Colors";
5989
ot->description= "Mirror UV/image color layer";
5990
ot->idname= "MESH_OT_colors_mirror";
5993
ot->exec= mesh_mirror_colors;
5994
ot->poll= ED_operator_editmesh;
5997
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
6000
RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around");
6003
/********************** Subdivide Operator *************************/
6005
static int subdivide_exec(bContext *C, wmOperator *op)
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");
6021
esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0);
6023
DAG_id_tag_update(obedit->data, 0);
6024
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
6026
return OPERATOR_FINISHED;
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");
2151
/********************** Rip Operator *************************/
2153
/************************ Shape Operators *************************/
2155
/* BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
2156
static void shape_propagate(BMEditMesh *em, wmOperator *op)
2161
int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2163
if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
2164
BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
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))
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);
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;
2189
static int edbm_shape_propagate_to_all_exec(bContext *C, wmOperator *op)
2191
Object *obedit = CTX_data_edit_object(C);
2192
Mesh *me = obedit->data;
2193
BMEditMesh *em = me->edit_btmesh;
2195
shape_propagate(em, op);
2197
EDBM_update_generic(C, em, FALSE);
2199
return OPERATOR_FINISHED;
2203
void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
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";
2211
ot->exec = edbm_shape_propagate_to_all_exec;
2212
ot->poll = ED_operator_editmesh;
2215
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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)
2221
Object *obedit = CTX_data_edit_object(C);
2222
Mesh *me = obedit->data;
2223
BMEditMesh *em = me->edit_btmesh;
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");
2233
totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
2234
if (totshape == 0 || shape < 0 || shape >= totshape)
2235
return OPERATOR_CANCELLED;
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))
2241
sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
2242
copy_v3_v3(co, sco);
2246
mul_v3_fl(co, blend);
2247
add_v3_v3v3(eve->co, eve->co, co);
2250
interp_v3_v3v3(eve->co, eve->co, co, blend);
2253
copy_v3_v3(sco, co);
2256
EDBM_update_generic(C, em, TRUE);
2258
return OPERATOR_FINISHED;
2261
static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
6032
ot->name= "Subdivide";
6033
ot->description= "Subdivide selected edges";
6034
ot->idname= "MESH_OT_subdivide";
6037
ot->exec= subdivide_exec;
6038
ot->poll= ED_operator_editmesh;
6041
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
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");
6050
/********************** Fill Operators *************************/
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)
6056
EditVert *v1, *v2, *v3, *v4;
6057
EditEdge *eed, *nexted;
6058
EditEdge dia1, dia2;
6060
// void **efaar, **efaa;
6063
float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
6064
int totedge, ok, notbeauty=8, onedone, vindex[4];
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
6073
EM_selectmode_set(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
6075
totedge = count_selected_edges(em->edges.first);
6076
if(totedge==0) return;
6078
/* temp block with face pointers */
6079
efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
6084
ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
6089
eed= em->edges.first;
6093
/* f2 is set in collect_quadedges() */
6094
if(eed->f2==2 && eed->h==0) {
6096
efaa = (EVPtr *) eed->tmp.p;
6098
/* none of the faces should be treated before, nor be part of fgon */
6101
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
6102
if(efa->fgonf) ok= 0;
6104
if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
6105
if(efa->fgonf) ok= 0;
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) ) {
6133
* the area divided by the total edge lengths
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);
6143
opp1= area_tri_v3(v1->co, v2->co, v3->co);
6144
opp2= area_tri_v3(v1->co, v3->co, v4->co);
6146
fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
6148
opp1= area_tri_v3(v2->co, v3->co, v4->co);
6149
opp2= area_tri_v3(v2->co, v4->co, v1->co);
6151
fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
6155
if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
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);
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);
6174
else if(fac1 < fac2) {
6175
if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
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);
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);
6202
free_tagged_edges_faces(em, em->edges.first, em->faces.first);
6204
if(onedone==0) break;
6206
EM_selectmode_set(em); // new edges/faces were added
6211
EM_select_flush(em);
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)
6220
EditEdge *eed,*e1,*nexted;
6221
EditFace *efa,*nextvl, *efan;
6224
if(em==NULL) return;
6227
/* copy all selected vertices */
6228
eve= em->verts.first;
6230
if(eve->f & SELECT) {
6231
v1= BLI_addfillvert(eve->co);
6234
v1->xs= 0; // used for counting edges
6238
/* copy all selected edges */
6239
eed= em->edges.first;
6241
if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
6242
e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
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;
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--;
6265
if(ok) { /* there are faces selected */
6266
eed= filledgebase.first;
6269
if(eed->v1->xs<2 || eed->v2->xs<2) {
6270
BLI_remlink(&filledgebase,eed);
6276
if(BLI_edgefill(em->mat_nr)) {
6277
efa= fillfacebase.first;
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);
6291
EM_select_flush(em);
6295
static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op))
6297
Object *obedit= CTX_data_edit_object(C);
6298
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
6302
BKE_mesh_end_editmesh(obedit->data, em);
6304
DAG_id_tag_update(obedit->data, 0);
6305
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2263
Object *obedit = CTX_data_edit_object(C);
2265
EnumPropertyItem *item = NULL;
2268
if ((obedit && obedit->type == OB_MESH) &&
2269
(em = BMEdit_FromObject(obedit)) &&
2270
CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY))
2272
EnumPropertyItem tmp = {0, "", 0, "", ""};
2275
for (a = 0; a < em->bm->vdata.totlayer; a++) {
2276
if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
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);
2287
RNA_enum_item_end(&item, &totitem);
2293
void MESH_OT_blend_from_shape(wmOperatorType *ot)
2296
static EnumPropertyItem shape_items[] = {{0, NULL, 0, NULL, NULL}};
2299
ot->name = "Blend From Shape";
2300
ot->description = "Blend in shape from a shape key";
2301
ot->idname = "MESH_OT_blend_from_shape";
2304
ot->exec = edbm_blend_from_shape_exec;
2305
ot->invoke = WM_operator_props_popup;
2306
ot->poll = ED_operator_editmesh;
2309
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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");
2318
/* BMESH_TODO - some way to select on an arbitrary axis */
2319
static int edbm_select_axis_exec(bContext *C, wmOperator *op)
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 */
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;
2332
BMVert *ev, *act_vert = (BMVert *)ese->ele;
2334
float value = act_vert->co[axis];
2335
float limit = CTX_data_tool_settings(C)->doublimit; // XXX
2342
BM_ITER_MESH (ev, &iter, em->bm, BM_VERTS_OF_MESH) {
2343
if (!BM_elem_flag_test(ev, BM_ELEM_HIDDEN)) {
2345
case -1: /* aligned */
2346
if (fabs(ev->co[axis] - value) < limit)
2347
BM_vert_select_set(em->bm, ev, TRUE);
2350
if (ev->co[axis] > value)
2351
BM_vert_select_set(em->bm, ev, TRUE);
2354
if (ev->co[axis] < value)
2355
BM_vert_select_set(em->bm, ev, TRUE);
2362
EDBM_selectmode_flush(em);
2363
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2365
return OPERATOR_FINISHED;
2368
void MESH_OT_select_axis(wmOperatorType *ot)
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}};
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}};
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";
2388
ot->exec = edbm_select_axis_exec;
2389
ot->poll = ED_operator_editmesh;
2392
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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");
2399
static int edbm_solidify_exec(bContext *C, wmOperator *op)
2401
Object *obedit = CTX_data_edit_object(C);
2402
Mesh *me = obedit->data;
2403
BMEditMesh *em = me->edit_btmesh;
2407
float thickness = RNA_float_get(op->ptr, "thickness");
2409
if (!EDBM_op_init(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) {
2410
return OPERATOR_CANCELLED;
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);
2418
/* run the solidify operator */
2419
BMO_op_exec(bm, &bmop);
2421
/* select the newly generated faces */
2422
BMO_slot_buffer_hflag_enable(bm, &bmop, "geomout", BM_FACE, BM_ELEM_SELECT, TRUE);
2424
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
2425
return OPERATOR_CANCELLED;
2428
EDBM_update_generic(C, em, TRUE);
2430
return OPERATOR_FINISHED;
2434
void MESH_OT_solidify(wmOperatorType *ot)
2438
ot->name = "Solidify";
2439
ot->description = "Create a solid skin by extruding, compensating for sharp angles";
2440
ot->idname = "MESH_OT_solidify";
2443
ot->exec = edbm_solidify_exec;
2444
ot->poll = ED_operator_editmesh;
2447
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
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
2459
typedef struct CutCurve {
2464
/* ******************************************************************** */
2465
/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
2468
* Currently mapped to KKey when in MeshEdit mode.
2470
* - Hit Shift K, Select Centers or Exact
2471
* - Hold LMB down to draw path, hit RETKEY.
2472
* - ESC cancels as expected.
2474
* Contributed by Robert Wenzlaff (Det. Thorn).
2477
* - non modal (no menu before cutting)
2478
* - exit on mouse release
2479
* - polygon/segment drawing can become handled by WM cb later
2481
* bmesh port version
2484
#define KNIFE_EXACT 1
2485
#define KNIFE_MIDPOINT 2
2486
#define KNIFE_MULTICUT 3
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}
2495
/* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */
2497
static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode,
2498
struct GHash *gh, int *isected)
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;
2506
float threshold = 0.0;
2509
//threshold = 0.000001; /* tolerance for vertex intersection */
2510
// XXX threshold = scene->toolsettings->select_thresh / 100;
2512
/* Get screen coords of verts */
2513
scr = BLI_ghash_lookup(gh, e->v1);
2517
scr = BLI_ghash_lookup(gh, e->v2);
2521
xdiff2 = (x22 - x21);
2523
m2 = (y22 - y21) / xdiff2;
2524
b2 = ((x22 * y21) - (x21 * y22)) / xdiff2;
2527
m2 = MAXSLOPE; /* Verticle slope */
2533
/* check for _exact_ vertex intersection first */
2534
if (mode != KNIFE_MULTICUT) {
2535
for (i = 0; i < len; i++) {
2548
if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) {
2554
else if ((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)) {
2562
/* now check for edge intersect (may produce vertex intersection as well) */
2563
for (i = 0; i < len; i++) {
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;
2580
if (i == 0) lastdist = dist;
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 */
2586
m1 = (y12 - y11) / xdiff1;
2587
b1 = ((x12 * y11) - (x11 * y12)) / xdiff1;
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;
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;
2605
y1max = MAX2(y11, y12);
2606
y1min = MIN2(y11, y12);
2607
yi = (MIN2(y2max, y1max) + MAX2(y2min, y1min)) / 2.0;
2609
else if (m2 == MAXSLOPE) {
2613
else if (m1 == MAXSLOPE) {
2618
xi = (b1 - b2) / (m2 - m1);
2619
yi = (b1 * m2 - m1 * b2) / (m2 - m1);
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)) {
2633
if (xi <= (x22 + threshold) && xi >= (x22 - threshold)) {
2634
if (yi <= (y22 + threshold) && yi >= (y22 - threshold)) {
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 */
2653
#define MAX_CUTS 2048
2655
static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
2657
Object *obedit = CTX_data_edit_object(C);
2658
BMEditMesh *em = BMEdit_FromObject(obedit);
2660
ARegion *ar = CTX_wm_region(C);
2665
CutCurve curve[MAX_CUTS];
2669
int len = 0, isected;
2670
short numcuts = 1, mode = RNA_int_get(op->ptr, "type");
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;
2676
if (bm->totvertsel < 2) {
2677
//error("No edges are selected to operate on");
2678
return OPERATOR_CANCELLED;
2681
/* get the cut curve */
2682
RNA_BEGIN (op->ptr, itemptr, "path") {
2683
RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
2685
if (len >= MAX_CUTS) {
2692
return OPERATOR_CANCELLED;
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);
2701
mul_m4_v4(obedit->obmat, co);
2702
project_float(ar, co, scr);
2703
BLI_ghash_insert(gh, bv, scr);
2706
if (!EDBM_op_init(em, &bmop, op, "esubd")) {
2707
return OPERATOR_CANCELLED;
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);
2715
if (isect != 0.0f) {
2716
if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
2717
BMO_slot_map_float_insert(bm, &bmop,
2722
BMO_elem_flag_enable(bm, be, 1);
2725
BMO_elem_flag_disable(bm, be, 1);
2729
BMO_elem_flag_disable(bm, be, 1);
2733
BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, 1);
2735
if (mode == KNIFE_MIDPOINT) numcuts = 1;
2736
BMO_slot_int_set(&bmop, "numcuts", numcuts);
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);
2742
BMO_slot_float_set(&bmop, "radius", 0);
2744
BMO_op_exec(bm, &bmop);
2745
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
2746
return OPERATOR_CANCELLED;
2749
BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
2751
EDBM_update_generic(C, em, TRUE);
2753
return OPERATOR_FINISHED;
2756
void MESH_OT_knife_cut(wmOperatorType *ot)
2760
ot->name = "Knife Cut";
2761
ot->description = "Cut selected edges and faces into parts";
2762
ot->idname = "MESH_OT_knife_cut";
2764
ot->invoke = WM_gesture_lines_invoke;
2765
ot->modal = WM_gesture_lines_modal;
2766
ot->exec = edbm_knife_cut_exec;
2768
ot->poll = EM_view3d_poll;
2771
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
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);
2778
RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
2781
static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
2787
Object *obedit = editbase->object;
2788
Mesh *me = obedit->data;
2789
BMEditMesh *em = me->edit_btmesh;
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);
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);
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 */
2809
ED_base_object_select(basenew, BA_DESELECT);
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);
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))
2819
if (!BM_edge_is_wire(e)) {
2820
BM_edge_select_set(em->bm, e, FALSE);
2823
EDBM_op_callf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES);
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))
2830
if (BM_vert_edge_count(v) != 0) {
2831
BM_vert_select_set(em->bm, v, FALSE);
2835
EDBM_op_callf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS);
2837
BM_mesh_normals_update(bm_new, TRUE);
2839
BM_mesh_bm_to_me(bm_new, basenew->object->data, FALSE);
2841
BM_mesh_free(bm_new);
2842
((Mesh *)basenew->object->data)->edit_btmesh = NULL;
2847
static int mesh_separate_material(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
2852
Object *obedit = editbase->object;
2853
BMEditMesh *em = BMEdit_FromObject(obedit);
2856
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
2858
while ((f_cmp = BM_iter_at_index(bm, BM_FACES_OF_MESH, NULL, 0))) {
2859
const short mat_nr = f_cmp->mat_nr;
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);
2869
/* leave the current object with some materials */
2870
if (tot == bm->totface) {
2874
/* Move selection into a separate object */
2875
result |= mesh_separate_selected(bmain, scene, editbase, wmop);
2881
static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
2890
Object *obedit = editbase->object;
2891
BMEditMesh *em = BMEdit_FromObject(obedit);
2893
int max_iter = bm->totvert;
2895
/* Clear all selected vertices */
2896
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
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
2903
for (i = 0; i < max_iter; i++) {
2904
/* Get a seed vertex to start the walk */
2906
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
2911
/* No vertices available, can't do anything */
2912
if (v_seed == NULL) {
2916
/* Select the seed explicitly, in case it has no edges */
2917
BM_vert_select_set(bm, v_seed, TRUE);
2919
/* Walk from the single vertex, selecting everything connected
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 ? */
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);
2933
/* Flush the selection to get edge/face selections matching
2934
* the vertex selection */
2935
EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX);
2937
if (bm->totvert == bm->totvertsel) {
2938
/* Every vertex selected, nothing to separate, work is done */
2942
/* Move selection into a separate object */
2943
result |= mesh_separate_selected(bmain, scene, editbase, wmop);
2949
static int edbm_separate_exec(bContext *C, wmOperator *op)
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");
2957
retval = mesh_separate_selected(bmain, scene, base, op);
2959
retval = mesh_separate_material(bmain, scene, base, op);
2961
retval = mesh_separate_loose(bmain, scene, base, op);
2964
BMEditMesh *em = BMEdit_FromObject(base->object);
2965
EDBM_update_generic(C, em, TRUE);
2967
return OPERATOR_FINISHED;
2970
return OPERATOR_CANCELLED;
2973
/* *************** Operator: separate parts *************/
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}
2982
void MESH_OT_separate(wmOperatorType *ot)
2985
ot->name = "Separate";
2986
ot->description = "Separate selected geometry into a new mesh";
2987
ot->idname = "MESH_OT_separate";
2990
ot->invoke = WM_menu_invoke;
2991
ot->exec = edbm_separate_exec;
2992
ot->poll = ED_operator_editmesh;
2995
ot->flag = OPTYPE_UNDO;
2997
ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
3001
static int edbm_fill_exec(bContext *C, wmOperator *op)
3003
Object *obedit = CTX_data_edit_object(C);
3004
BMEditMesh *em = BMEdit_FromObject(obedit);
3007
if (!EDBM_op_init(em, &bmop, op, "triangle_fill edges=%he", BM_ELEM_SELECT)) {
3008
return OPERATOR_CANCELLED;
3011
BMO_op_exec(em->bm, &bmop);
3013
/* select new geometry */
3014
BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_FACE | BM_EDGE, BM_ELEM_SELECT, TRUE);
3016
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
3017
return OPERATOR_CANCELLED;
3020
EDBM_update_generic(C, em, TRUE);
6307
3022
return OPERATOR_FINISHED;