diff options
Diffstat (limited to 'source/blender/editors')
116 files changed, 17131 insertions, 23502 deletions
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript index 96b05b8bccc..3e5133c1174 100644 --- a/source/blender/editors/animation/SConscript +++ b/source/blender/editors/animation/SConscript @@ -4,6 +4,6 @@ Import ('env') sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf' -incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader' +incs += ' ../../bmesh ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader' env.BlenderLib ( 'bf_editors_animation', sources, Split(incs), [], libtype=['core'], priority=[125] ) diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript index beabd912a20..e9694bab63f 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -5,6 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf ../../blenloader' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' +incs += ' ../../render/extern/include ../../bmesh' incs += ' ../../gpu ../../makesrna #/intern/opennl/extern' if env['OURPLATFORM'] == 'linux2': diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index 20352206121..52e6a0cdaa8 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -2113,7 +2113,7 @@ typedef struct UndoArmature { ListBase lb; } UndoArmature; -static void undoBones_to_editBones(void *uarmv, void *armv) +static void undoBones_to_editBones(void *uarmv, void *armv, void *UNUSED(data)) { UndoArmature *uarm= uarmv; bArmature *arm= armv; @@ -2146,7 +2146,7 @@ static void undoBones_to_editBones(void *uarmv, void *armv) } } -static void *editBones_to_undoBones(void *armv) +static void *editBones_to_undoBones(void *armv, void *UNUSED(obdata)) { bArmature *arm= armv; UndoArmature *uarm; @@ -4503,7 +4503,8 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i /* for each vertex in the mesh */ for (i=0; i < mesh->totvert; i++) { - iflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0; + /*BMESH_TODO*/ + iflip = 0; //(dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0; /* for each skinnable bone */ for (j=0; j < numbones; ++j) { @@ -4696,7 +4697,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, } /* only generated in some cases but can call anyway */ - mesh_octree_table(ob, NULL, NULL, 'e'); + //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 'e'); /* free the memory allocated */ MEM_freeN(bonelist); diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index b99605e65c1..41733bcd29a 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -43,10 +43,10 @@ #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" +#include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_memarena.h" -#include "BLI_utildefines.h" #include "BKE_DerivedMesh.h" #include "BKE_modifier.h" @@ -692,12 +692,16 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, laplacian_system_construct_end(sys); +#if 0 /*BMESH_TODO*/ if(dgroupflip) { vertsflipped = MEM_callocN(sizeof(int)*me->totvert, "vertsflipped"); for(a=0; a<me->totvert; a++) vertsflipped[a] = mesh_get_x_mirror_vert(ob, a); } - +#else + dgroupflip = 0; +#endif + /* compute weights per bone */ for(j=0; j<numsource; j++) { if(!selected[j]) @@ -1170,8 +1174,8 @@ static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec) isec->labda= 1e10; - mface= mdb->cagedm->getFaceArray(mdb->cagedm); - totface= mdb->cagedm->getNumFaces(mdb->cagedm); + mface= mdb->cagedm->getTessFaceArray(mdb->cagedm); + totface= mdb->cagedm->getNumTessFaces(mdb->cagedm); add_v3_v3v3(end, isec->start, isec->vec); @@ -1860,7 +1864,7 @@ static void harmonic_coordinates_bind(Scene *UNUSED(scene), MeshDeformModifierDa static void heat_weighting_bind(Scene *scene, DerivedMesh *dm, MeshDeformModifierData *mmd, MeshDeformBind *mdb) { LaplacianSystem *sys; - MFace *mface= dm->getFaceArray(dm), *mf; + MFace *mface= dm->getTessFaceArray(dm), *mf; int totvert= dm->getNumVerts(dm); int totface= dm->getNumFaces(dm); float solution, weight; diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index 04501243acb..0522b24ae91 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -57,6 +57,7 @@ //#include "BIF_toolbox.h" //#include "BIF_graphics.h" +#include "BKE_mesh.h" //#include "blendef.h" @@ -3383,9 +3384,12 @@ static int iteratorStopped(void *arg) ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) { + (void)C; + return NULL; +#if 0 Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); - EditMesh *em =( (Mesh*)obedit->data)->edit_mesh; + EditMesh *em =BKE_mesh_get_editmesh(((Mesh*)obedit->data)); EdgeIndex indexed_edges; VertexData *data; ReebGraph *rg = NULL; @@ -3481,7 +3485,14 @@ ReebGraph *BIF_ReebGraphMultiFromEditMesh(bContext *C) MEM_freeN(data); + /*no need to load the editmesh back into the object, just + free it (avoids ngon conversion issues too going back the + other way)*/ + free_editMesh(em); + MEM_freeN(em); + return rg; +#endif } #if 0 diff --git a/source/blender/editors/curve/SConscript b/source/blender/editors/curve/SConscript index efb56ce5466..95dd7fc6233 100644 --- a/source/blender/editors/curve/SConscript +++ b/source/blender/editors/curve/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../gpu ../../blenloader' +incs += ' ../../bmesh ../../gpu ../../blenloader' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' env.BlenderLib ( 'bf_editors_curve', sources, Split(incs), [], libtype=['core'], priority=[45] ) diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 06d88b16fa8..bfca5453bc5 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6559,12 +6559,12 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf) ListBase *editnurb; Nurb *nu; int newob= 0; - int enter_editmode; + int enter_editmode, is_aligned; unsigned int layer; float loc[3], rot[3]; float mat[4][4]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &is_aligned)) return OPERATOR_CANCELLED; if (!isSurf) { /* adding curve */ @@ -6957,7 +6957,7 @@ static void *undo_check_lastsel(void *lastsel, Nurb *nu, Nurb *newnu) return NULL; } -static void undoCurve_to_editCurve(void *ucu, void *obe) +static void undoCurve_to_editCurve(void *ucu, void *UNUSED(edata), void *obe) { Object *obedit= obe; Curve *cu= (Curve*)obedit->data; @@ -7007,10 +7007,9 @@ static void undoCurve_to_editCurve(void *ucu, void *obe) ED_curve_updateAnimPaths(obedit); } -static void *editCurve_to_undoCurve(void *obe) +static void *editCurve_to_undoCurve(void *UNUSED(edata), void *obdata) { - Object *obedit= obe; - Curve *cu= (Curve*)obedit->data; + Curve *cu= obdata; ListBase *nubase= ED_curve_editnurbs(cu); UndoCurve *undoCurve; EditNurb *editnurb= cu->editnurb, tmpEditnurb; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 649ff9e953a..76e6fe9a0c1 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1769,7 +1769,7 @@ void FONT_OT_unlink(wmOperatorType *ot) /* **************** undo for font object ************** */ -static void undoFont_to_editFont(void *strv, void *ecu) +static void undoFont_to_editFont(void *strv, void *ecu, void *UNUSED(obdata)) { Curve *cu= (Curve *)ecu; EditFont *ef= cu->editfont; @@ -1786,7 +1786,7 @@ static void undoFont_to_editFont(void *strv, void *ecu) update_string(cu); } -static void *editFont_to_undoFont(void *ecu) +static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) { Curve *cu= (Curve *)ecu; EditFont *ef= cu->editfont; diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript index dd0db90af44..0cbeb96ffdb 100644 --- a/source/blender/editors/datafiles/SConscript +++ b/source/blender/editors/datafiles/SConscript @@ -4,6 +4,6 @@ Import ('env') sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' -incs += ' #/intern/guardedalloc' +incs += ' ../../bmesh #/intern/guardedalloc' env.BlenderLib ( 'bf_editor_datafiles', sources, Split(incs), [], libtype=['core', 'player'], priority=[235, 30] ) diff --git a/source/blender/editors/gpencil/SConscript b/source/blender/editors/gpencil/SConscript index d2fd9e5fe9d..6c23e77208a 100644 --- a/source/blender/editors/gpencil/SConscript +++ b/source/blender/editors/gpencil/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../gpu ../../blenloader' +incs += ' ../../gpu ../../blenloader ../../bmesh' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' env.BlenderLib ( 'bf_editors_gpencil', sources, Split(incs), [], libtype=['core'], priority=[45] ) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index f4da734473d..b8c5b05f5e6 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -50,7 +50,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_gpencil_types.h" -#include "DNA_windowmanager_types.h" #include "UI_view2d.h" diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 8bb77ad43a0..dc30c7b5355 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -45,7 +45,6 @@ struct EditVert; struct EditEdge; struct EditFace; struct bContext; -struct wmOperator; struct wmWindowManager; struct wmKeyConfig; struct ReportList; @@ -63,130 +62,176 @@ struct MCol; struct UvVertMap; struct UvMapVert; struct CustomData; +struct BMEditMesh; +struct BMEditSelection; +struct BMesh; +struct BMVert; +struct MLoopCol; +struct BMEdge; +struct BMFace; +struct UvVertMap; +struct UvMapVert; struct Material; struct Object; struct rcti; +struct wmOperator; +struct ToolSettings; -#define EM_FGON_DRAW 1 // face flag -#define EM_FGON 2 // edge and face flag both +// edge and face flag both +#define EM_FGON 2 +// face flag +#define EM_FGON_DRAW 1 /* editbutflag */ -#define B_CLOCKWISE 1 -#define B_KEEPORIG 2 -#define B_BEAUTY 4 -#define B_SMOOTH 8 -#define B_BEAUTY_SHORT 0x10 -#define B_AUTOFGON 0x20 -#define B_KNIFE 0x80 +#define B_CLOCKWISE 1 +#define B_KEEPORIG 2 +#define B_BEAUTY 4 +#define B_SMOOTH 8 +#define B_BEAUTY_SHORT 16 +#define B_AUTOFGON 32 +#define B_KNIFE 0x80 #define B_PERCENTSUBD 0x40 //#define B_MESH_X_MIRROR 0x100 // deprecated, use mesh #define B_JOINTRIA_UV 0x200 #define B_JOINTRIA_VCOL 0X400 #define B_JOINTRIA_SHARP 0X800 #define B_JOINTRIA_MAT 0X1000 -#define B_FRACTAL 0x2000 -#define B_SPHERE 0x4000 - -/* meshtools.c */ +#define B_FRACTAL 0x2000 +#define B_SPHERE 0x4000 -intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode); -long mesh_mirrtopo_table(struct Object *ob, char mode); - -struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, struct EditVert *eve, float *co, int index); -int mesh_get_x_mirror_vert(struct Object *ob, int index); -int *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em); - -int join_mesh_exec(struct bContext *C, struct wmOperator *op); -int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); +float *bm_get_cd_float(struct CustomData *cdata, void *data, int type); -/* mesh_ops.c */ -void ED_operatortypes_mesh(void); -void ED_operatormacros_mesh(void); -void ED_keymap_mesh(struct wmKeyConfig *keyconf); +/* bmeshutils.c */ +/* + [note: I've decided to use ideasman's code for non-editmode stuff, but since + it has a big "not for editmode!" disclaimer, I'm going to keep what I have here + - joeedh] + + x-mirror editing api. usage: + + EDBM_CacheMirrorVerts(em); + ... + ... + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + mirrorv = EDBM_GetMirrorVert(em, v); + } + ... + ... + EDBM_EndMirrorCache(em); + + note: why do we only allow x axis mirror editing? + */ +void EDBM_CacheMirrorVerts(struct BMEditMesh *em); + +/*retrieves mirrored cache vert, or NULL if there isn't one. + note: calling this without ensuring the mirror cache state + is bad.*/ +struct BMVert *EDBM_GetMirrorVert(struct BMEditMesh *em, struct BMVert *v); +void EDBM_EndMirrorCache(struct BMEditMesh *em); + +void EDBM_RecalcNormals(struct BMEditMesh *em); + +void EDBM_MakeEditBMesh(struct ToolSettings *ts, struct Scene *scene, struct Object *ob); +void EDBM_FreeEditBMesh(struct BMEditMesh *tm); +void EDBM_LoadEditBMesh(struct Scene *scene, struct Object *ob); + +void EDBM_init_index_arrays(struct BMEditMesh *em, int forvert, int foredge, int forface); +void EDBM_free_index_arrays(struct BMEditMesh *em); +struct BMVert *EDBM_get_vert_for_index(struct BMEditMesh *em, int index); +struct BMEdge *EDBM_get_edge_for_index(struct BMEditMesh *em, int index); +struct BMFace *EDBM_get_face_for_index(struct BMEditMesh *em, int index); +struct BMFace *EDBM_get_actFace(struct BMEditMesh *em, int sloppy); + +int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op, + const char *selectslot, const char *fmt, ...); + +/*flushes based on the current select mode. if in vertex select mode, + verts select/deselect edges and faces, if in edge select mode, + edges select/deselect faces and vertices, and in face select mode faces select/deselect + edges and vertices.*/ +void EDBM_selectmode_flush(struct BMEditMesh *em); + +int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese); + +/*exactly the same as EDBM_selectmode_flush, but you pass in the selectmode + instead of using the current one*/ +void EDBM_select_flush(struct BMEditMesh *em, int selectmode); +void EDBM_deselect_flush(struct BMEditMesh *em); + +void EDBM_selectmode_set(struct BMEditMesh *em); +void EDBM_convertsel(struct BMEditMesh *em, short oldmode, short selectmode); +void undo_push_mesh(struct bContext *C, const char *name); -/* editmesh.c */ -void make_editMesh(struct Scene *scene, struct Object *ob); -void load_editMesh(struct Scene *scene, struct Object *ob); -void remake_editMesh(struct Scene *scene, struct Object *ob); -void free_editMesh(struct EditMesh *em); +void EDBM_editselection_center(struct BMEditMesh *em, float *center, struct BMEditSelection *ese); +void EDBM_editselection_plane(struct BMEditMesh *em, float *plane, struct BMEditSelection *ese); +void EDBM_editselection_normal(float *normal, struct BMEditSelection *ese); +int EDBM_vertColorCheck(struct BMEditMesh *em); +void EDBM_validate_selections(struct BMEditMesh *em); -void recalc_editnormals(struct EditMesh *em); +void EDBM_hide_mesh(struct BMEditMesh *em, int swap); +void EDBM_reveal_mesh(struct BMEditMesh *em); -void EM_init_index_arrays(struct EditMesh *em, int forVert, int forEdge, int forFace); -void EM_free_index_arrays(void); -struct EditVert *EM_get_vert_for_index(int index); -struct EditEdge *EM_get_edge_for_index(int index); -struct EditFace *EM_get_face_for_index(int index); -int EM_texFaceCheck(struct EditMesh *em); -int EM_vertColorCheck(struct EditMesh *em); +int EDBM_check_backbuf(unsigned int index); +int EDBM_mask_init_backbuf_border(struct ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax); +void EDBM_free_backbuf(void); +int EDBM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax); +int EDBM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads); -void undo_push_mesh(struct bContext *C, const char *name); +void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */ +void EDBM_set_actFace(struct BMEditMesh *em, struct BMFace *efa); +int EDBM_texFaceCheck(struct BMEditMesh *em); +struct MTexPoly *EDBM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, int sloppy); -/* editmesh_lib.c */ +void EDBM_free_uv_vert_map(struct UvVertMap *vmap); +struct UvMapVert *EDBM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v); +struct UvVertMap *EDBM_make_uv_vert_map(struct BMEditMesh *em, int selected, int do_face_idx_array, float *limit); +void EM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name); +void EM_free_data_layer(struct BMEditMesh *em, struct CustomData *data, int type); -struct EditFace *EM_get_actFace(struct EditMesh *em, int sloppy); -void EM_set_actFace(struct EditMesh *em, struct EditFace *efa); -float EM_face_area(struct EditFace *efa); +void EDBM_toggle_select_all(struct BMEditMesh *em); +void EDBM_set_flag_all(struct BMEditMesh *em, int flag); +void EDBM_clear_flag_all(struct BMEditMesh *em, int flag); +void EDBM_automerge(struct Scene *scene, struct Object *ob, int update); -void EM_select_edge(struct EditEdge *eed, int sel); -void EM_select_face(struct EditFace *efa, int sel); -void EM_select_face_fgon(struct EditMesh *em, struct EditFace *efa, int val); -void EM_select_swap(struct EditMesh *em); -void EM_toggle_select_all(struct EditMesh *em); -void EM_select_all(struct EditMesh *em); -void EM_deselect_all(struct EditMesh *em); -void EM_selectmode_flush(struct EditMesh *em); -void EM_deselect_flush(struct EditMesh *em); -void EM_selectmode_set(struct EditMesh *em); -void EM_select_flush(struct EditMesh *em); -void EM_convertsel(struct EditMesh *em, short oldmode, short selectmode); -void EM_validate_selections(struct EditMesh *em); -void EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit); +/* editmesh_mods.c */ +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; - /* exported to transform */ -int EM_get_actSelection(struct EditMesh *em, struct EditSelection *ese); -void EM_editselection_normal(float *normal, struct EditSelection *ese); -void EM_editselection_plane(float *plane, struct EditSelection *ese); -void EM_editselection_center(float *center, struct EditSelection *ese); +intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode); +long mesh_mirrtopo_table(struct Object *ob, char mode); -struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_face_idx_array, float *limit); -struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v); -void EM_free_uv_vert_map(struct UvVertMap *vmap); +//BMESH_TODO void EM_cache_x_mirror_vert(struct Object *ob, struct BMEditMesh *em); -void EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type, const char *name); -void EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type); +int mouse_mesh(struct bContext *C, const int mval[2], short extend); -void EM_make_hq_normals(struct EditMesh *em); -void EM_solidify(struct EditMesh *em, float dist); +struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, float *co, int index); +int mesh_get_x_mirror_vert(struct Object *ob, int index); +int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em); -int EM_deselect_nth(struct EditMesh *em, int nth); +int join_mesh_exec(struct bContext *C, struct wmOperator *op); +int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); -void EM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct EditMesh *em); +/* mesh_ops.c */ +void ED_operatortypes_mesh(void); +void ED_operatormacros_mesh(void); +void ED_keymap_mesh(struct wmKeyConfig *keyconf); -/* editmesh_mods.c */ -extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs; -void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em); -int mouse_mesh(struct bContext *C, const int mval[2], short extend); -int EM_check_backbuf(unsigned int index); -int EM_mask_init_backbuf_border(struct ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax); -void EM_free_backbuf(void); -int EM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax); -int EM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads); +/* editmesh.c */ -void EM_hide_mesh(struct EditMesh *em, int swap); -void EM_reveal_mesh(struct EditMesh *em); +void ED_spacetypes_init(void); +void ED_keymap_mesh(struct wmKeyConfig *keyconf); -void EM_select_by_material(struct EditMesh *em, int index); -void EM_deselect_by_material(struct EditMesh *em, int index); +/* bmesh_mods.c */ +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; -void EM_automerge(struct Scene *scene, struct Object *obedit, int update); +/* bmesh_tools.c (could be moved) */ +void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct BMEditMesh *em); /* editface.c */ void paintface_flush_flags(struct Object *ob); -struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy); +struct MTexPoly *EM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, struct MLoopCol **col, int sloppy); int paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], int extend); int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int select, int extend); void paintface_deselect_all_visible(struct Object *ob, int action, short flush_flags); @@ -217,13 +262,19 @@ void ED_vgroup_vert_add(struct Object *ob, struct bDeformGroup *dg, int vertnum void ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum); float ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum); -/*needed by edge slide*/ -struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *eve); -struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2); -int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve); -int editface_containsVert(struct EditFace *efa, struct EditVert *eve); -int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed); -short sharesFace(struct EditMesh *em, struct EditEdge *e1, struct EditEdge *e2); +/** + * findnearestvert + * + * dist (in/out): minimal distance to the nearest and at the end, actual distance + * sel: selection bias + * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts + * if 0, unselected vertice are given the bias + * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased + */ + +struct BMVert *EDBM_findnearestvert(struct ViewContext *vc, int *dist, short sel, short strict); +struct BMEdge *EDBM_findnearestedge(struct ViewContext *vc, int *dist); +struct BMFace *EDBM_findnearestface(struct ViewContext *vc, int *dist); /* mesh_data.c */ // void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces); @@ -241,9 +292,12 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set); int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me); +void EDBM_selectmode_to_scene(struct Scene *scene, struct Object *obedit); + +#include "../mesh/editbmesh_bvh.h" + #ifdef __cplusplus } #endif #endif /* ED_MESH_H */ - diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 28d0a9520b2..9a444c36758 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -104,8 +104,11 @@ float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob, void ED_object_add_generic_props(struct wmOperatorType *ot, int do_editmode); int ED_object_add_generic_invoke(struct bContext *C, struct wmOperator *op, struct wmEvent *event); -int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, float *loc, float *rot, int *enter_editmode, unsigned int *layer); -struct Object *ED_object_add_type(struct bContext *C, int type, float *loc, float *rot, int enter_editmode, unsigned int layer); +int ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, + float *loc, float *rot, int *enter_editmode, unsigned int *layer, int *is_view_aligned); + +struct Object *ED_object_add_type(struct bContext *C, int type, float *loc, + float *rot, int enter_editmode, unsigned int layer); void ED_object_single_users(struct Main *bmain, struct Scene *scene, int full); diff --git a/source/blender/editors/include/ED_toolmode.h b/source/blender/editors/include/ED_toolmode.h new file mode 100755 index 00000000000..733ca6c74fc --- /dev/null +++ b/source/blender/editors/include/ED_toolmode.h @@ -0,0 +1,80 @@ +#if 0 +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#ifndef ED_TOOLMODE_H +#define ED_TOOLMODE_H + +struct ID; +struct View3D; +struct ARegion; +struct bContext; +struct wmWindowManager; +struct wmKeyConfig; +struct ReportList; +struct ViewContext; +struct bDeformGroup; +struct MDeformWeight; +struct MDeformVert; +struct Scene; +struct Mesh; +struct MCol; +struct UvVertMap; +struct UvMapVert; +struct CustomData; +struct BMEditMesh; +struct BMEditSelection; +struct BMesh; +struct BMVert; +struct BMEdge; +struct BMFace; +struct UvVertMap; +struct UvMapVert; +struct Material; +struct Object; +struct rcti; +struct wmOperator; + +typedef struct ToolModeDefine { + short idtype, icon; + char *name; + void (*create)(void *args); + void (*free)(void *self); + + /*called when mode is set active*/ + void (*enter)(void *self, struct bContext *C); + void (*exit)(void *self, struct bContext *C); + + /*called on draw*/ + void (*draw)(void *self, struct bContext *C); + /*modal is option, and should be used carefully*/ + void (*modal)(struct bContext *C, struct wmOperator *op, struct wmEvent *event); + + /*keymap stuff*/ + void (*create_keymap)(struct wmKeyConfig *km); + void (*keymap_poll)(struct bContext *C); +}; +#endif diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 5e004fd8d47..5d433879882 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -40,7 +40,7 @@ struct ARegion; struct uiBlock; struct wmOperator; struct wmOperatorType; -struct EditMesh; +struct BMEditMesh; struct Mesh; /* ed_util.c */ @@ -72,8 +72,8 @@ int ED_undo_valid (const struct bContext *C, const char *undoname); void undo_editmode_push(struct bContext *C, const char *name, void * (*getdata)(struct bContext *C), void (*freedata)(void *), - void (*to_editmode)(void *, void *), - void *(*from_editmode)(void *), + void (*to_editmode)(void *, void *, void *), + void *(*from_editmode)(void *, void *), int (*validate_undo)(void *, void *)); @@ -81,7 +81,7 @@ void undo_editmode_clear (void); /* crazyspace.c */ float *crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit); -void crazyspace_set_quats_editmesh(struct EditMesh *em, float *origcos, float *mappedcos, float *quats); +void crazyspace_set_quats_editmesh(struct BMEditMesh *em, float *origcos, float *mappedcos, float *quats); void crazyspace_set_quats_mesh(struct Mesh *me, float *origcos, float *mappedcos, float *quats); int sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); void crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index f6106e62533..2ccfbd9fab1 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -40,6 +40,10 @@ struct Object; struct Scene; struct bContext; struct wmKeyConfig; +struct BMEditMesh; +struct BMLoop; +struct BMFace; +struct MTexPoly; /* uvedit_ops.c */ void ED_operatortypes_uvedit(void); @@ -52,18 +56,17 @@ int ED_uvedit_test_silent(struct Object *obedit); int ED_uvedit_test(struct Object *obedit); /* visibility and selection */ -int uvedit_edge_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); -int uvedit_face_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf); -int uvedit_face_visible_nolocal(struct Scene *scene, struct EditFace *efa); -int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct EditFace *efa, struct MTFace *tf); -int uvedit_uv_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); -void uvedit_edge_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); -void uvedit_edge_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); -void uvedit_face_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf); -void uvedit_face_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf); -void uvedit_uv_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); -void uvedit_uv_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i); +int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf); +int uvedit_face_selected(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa); +int uvedit_edge_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); +int uvedit_uv_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); +int uvedit_face_select(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa); +int uvedit_face_deselect(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa); +void uvedit_edge_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); +void uvedit_edge_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); +void uvedit_uv_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); +void uvedit_uv_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l); int ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima, float co[2], float uv[2]); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index dfe0a304748..06d1131cf1d 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -40,8 +40,11 @@ struct BezTriple; struct bglMats; struct BoundBox; struct BPoint; -struct EditEdge; -struct EditFace; +struct Nurb; +struct BezTriple; +struct BMVert; +struct BMEdge; +struct BMFace; struct EditVert; struct ImBuf; struct Main; @@ -63,7 +66,7 @@ typedef struct ViewContext { struct ARegion *ar; struct View3D *v3d; struct RegionView3D *rv3d; - struct EditMesh *em; + struct BMEditMesh *em; int mval[2]; } ViewContext; @@ -184,9 +187,9 @@ void ED_view3d_from_object(struct Object *ob, float ofs[3], float quat[4], float */ void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist); -#if 0 /* UNUSED */ +//#if 0 /* UNUSED */ void view3d_unproject(struct bglMats *mats, float out[3], const short x, const short y, const float z); -#endif +//#endif /* Depth buffer */ void ED_view3d_depth_update(struct ARegion *ar); @@ -212,12 +215,13 @@ int ED_view3d_clip_range_get(struct View3D *v3d, struct RegionView3D *rv3d, floa int ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int winxi, int winyi, struct rctf *viewplane, float *clipsta, float *clipend, float *pixsize); void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); void ED_view3d_project_float(struct ARegion *a, const float vec[3], float adr[2], float mat[4][4]); +void ED_view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]); void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, struct rctf *viewborder_r, short do_shift); /* drawobject.c iterators */ -void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts); -void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts); -void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData); +void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, int x, int y, int index), void *userData, int clipVerts); +void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts); +void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData); diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript index 5998d4d2953..54390baadb9 100644 --- a/source/blender/editors/interface/SConscript +++ b/source/blender/editors/interface/SConscript @@ -8,7 +8,7 @@ for source in env.Glob('*_api.c'): incs = '../include ../../blenlib ../../blenfont ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc ../../gpu' -incs += ' #/extern/glew/include ../../blenloader' +incs += ' #/extern/glew/include ../../blenloader ../../bmesh' incs += ' ../../python/' # python button eval defs = [] diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 02a25a2a122..aff5f69e9d5 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -21,9 +21,11 @@ set(INC ../include + ../uvedit ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../imbuf ../../makesdna ../../makesrna @@ -37,18 +39,20 @@ set(INC_SYS ) set(SRC - editface.c - editmesh.c - editmesh_add.c - editmesh_lib.c - editmesh_loop.c - editmesh_mods.c - editmesh_tools.c + meshtools.c loopcut.c - mesh_data.c mesh_ops.c - meshtools.c + editbmesh_bvh.c + editbmesh_add.c + bmeshutils.c + bmesh_selecthistory.c + bmesh_select.c + mesh_data.c + bmesh_tools.c + knifetool.c + editface.c + editbmesh_bvh.h mesh_intern.h ) diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript index 34936c025bc..dc352e07fec 100644 --- a/source/blender/editors/mesh/SConscript +++ b/source/blender/editors/mesh/SConscript @@ -7,6 +7,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../gpu ../../blenloader' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' +incs += ' ../../bmesh ../uvedit ' if env['OURPLATFORM'] == 'linux2': cflags='-pthread' diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c new file mode 100644 index 00000000000..885f9ef4553 --- /dev/null +++ b/source/blender/editors/mesh/bmesh_select.c @@ -0,0 +1,2450 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* + +BMEditMesh_mods.c, UI level access, no geometry changes + +*/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_array.h" +#include "BLI_smallhash.h" + +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" +#include "BKE_paint.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "bmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "UI_resources.h" + +#include "mesh_intern.h" + +#include "BLO_sys_types.h" // for intptr_t support + +/* ****************************** MIRROR **************** */ + +static void EDBM_select_mirrored(Object *obedit, BMEditMesh *em) +{ + if(em->selectmode & SCE_SELECT_VERTEX) { + BMVert *eve, *v1; + BMIter iter; + int i; + + i= 0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) { + v1= editbmesh_get_x_mirror_vert(obedit, em, eve, eve->co, i); + if(v1) { + BM_Select(em->bm, eve, 0); + BM_Select(em->bm, v1, 1); + } + } + i++; + } + } +} + +void EDBM_automerge(Scene *scene, Object *obedit, int update) +{ + BMEditMesh *em; + + if ((scene->toolsettings->automerge) && + (obedit && obedit->type==OB_MESH)) + { + em = ((Mesh*)obedit->data)->edit_btmesh; + if (!em) + return; + + BMO_CallOpf(em->bm, "automerge verts=%hv dist=%f", BM_SELECT, scene->toolsettings->doublimit); + if (update) { + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + } + } +} + +/* ****************************** SELECTION ROUTINES **************** */ + +unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0; /* set in drawobject.c ... for colorindices */ + +/* facilities for border select and circle select */ +static char *selbuf= NULL; + +/* opengl doesn't support concave... */ +static void draw_triangulated(int mcords[][2], short tot) +{ + ListBase lb={NULL, NULL}; + DispList *dl; + float *fp; + int a; + + /* make displist */ + dl= MEM_callocN(sizeof(DispList), "poly disp"); + dl->type= DL_POLY; + dl->parts= 1; + dl->nr= tot; + dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts"); + BLI_addtail(&lb, dl); + + for(a=0; a<tot; a++, fp+=3) { + fp[0]= (float)mcords[a][0]; + fp[1]= (float)mcords[a][1]; + } + + /* do the fill */ + filldisplist(&lb, &lb, 0); + + /* do the draw */ + dl= lb.first; /* filldisplist adds in head of list */ + if(dl->type==DL_INDEX3) { + int *index; + + a= dl->parts; + fp= dl->verts; + index= dl->index; + glBegin(GL_TRIANGLES); + while(a--) { + glVertex3fv(fp+3*index[0]); + glVertex3fv(fp+3*index[1]); + glVertex3fv(fp+3*index[2]); + index+= 3; + } + glEnd(); + } + + freedisplist(&lb); +} + + +/* reads rect, and builds selection array for quick lookup */ +/* returns if all is OK */ +int EDBM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) +{ + struct ImBuf *buf; + unsigned int *dr; + int a; + + if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(buf==NULL) return 0; + if(bm_vertoffs==0) return 0; + + dr = buf->rect; + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + + a= (xmax-xmin+1)*(ymax-ymin+1); + while(a--) { + if(*dr>0 && *dr<=bm_vertoffs) + selbuf[*dr]= 1; + dr++; + } + IMB_freeImBuf(buf); + return 1; +} + +int EDBM_check_backbuf(unsigned int index) +{ + if(selbuf==NULL) return 1; + if(index>0 && index<=bm_vertoffs) + return selbuf[index]; + return 0; +} + +void EDBM_free_backbuf(void) +{ + if(selbuf) MEM_freeN(selbuf); + selbuf= NULL; +} + +/* mcords is a polygon mask + - grab backbuffer, + - draw with black in backbuffer, + - grab again and compare + returns 'OK' +*/ +int EDBM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) +{ + unsigned int *dr, *drm; + struct ImBuf *buf, *bufmask; + int a; + + /* method in use for face selecting too */ + if(vc->obedit==NULL) { + if(paint_facesel_test(vc->obact)); + else return 0; + } + else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(buf==NULL) return 0; + if(bm_vertoffs==0) return 0; + + dr = buf->rect; + + /* draw the mask */ + glDisable(GL_DEPTH_TEST); + + glColor3ub(0, 0, 0); + + /* yah, opengl doesn't do concave... tsk! */ + ED_region_pixelspace(vc->ar); + draw_triangulated(mcords, tot); + + glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */ + for(a=0; a<tot; a++) glVertex2iv(mcords[a]); + glEnd(); + + glFinish(); /* to be sure readpixels sees mask */ + + /* grab mask */ + bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + drm = bufmask->rect; + if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */ + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + + a= (xmax-xmin+1)*(ymax-ymin+1); + while(a--) { + if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1; + dr++; drm++; + } + IMB_freeImBuf(buf); + IMB_freeImBuf(bufmask); + return 1; + +} + +/* circle shaped sample area */ +int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads) +{ + struct ImBuf *buf; + unsigned int *dr; + short xmin, ymin, xmax, ymax, xc, yc; + int radsq; + + /* method in use for face selecting too */ + if(vc->obedit==NULL) { + if(paint_facesel_test(vc->obact)); + else return 0; + } + else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; + + xmin= xs-rads; xmax= xs+rads; + ymin= ys-rads; ymax= ys+rads; + buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); + if(bm_vertoffs==0) return 0; + if(buf==NULL) return 0; + + dr = buf->rect; + + /* build selection lookup */ + selbuf= MEM_callocN(bm_vertoffs+1, "selbuf"); + radsq= rads*rads; + for(yc= -rads; yc<=rads; yc++) { + for(xc= -rads; xc<=rads; xc++, dr++) { + if(xc*xc + yc*yc < radsq) { + if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1; + } + } + } + + IMB_freeImBuf(buf); + return 1; + +} + +static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index) +{ + struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData; + + if (data->pass==0) { + if (index<=data->lastIndex) + return; + } else { + if (index>data->lastIndex) + return; + } + + if (data->dist>3) { + int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y); + if (BM_TestHFlag(eve, BM_SELECT) == data->select) { + if (data->strict == 1) + return; + else + temp += 5; + } + + if (temp<data->dist) { + data->dist = temp; + data->closest = eve; + data->closestIndex = index; + } + } +} + + + + +static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index) +{ + BMEditMesh *em= (BMEditMesh *)handle; + BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1); + + if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0; + return 1; +} +/** + * findnearestvert + * + * dist (in/out): minimal distance to the nearest and at the end, actual distance + * sel: selection bias + * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts + * if 0, unselected vertice are given the bias + * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased + */ +BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict) +{ + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){ + int distance; + unsigned int index; + BMVert *eve; + + if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); + else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); + + eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1); + + if(eve && distance < *dist) { + *dist = distance; + return eve; + } else { + return NULL; + } + + } + else { + struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data; + static int lastSelectedIndex=0; + static BMVert *lastSelected=NULL; + + if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) { + lastSelectedIndex = 0; + lastSelected = NULL; + } + + data.lastIndex = lastSelectedIndex; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.select = sel; + data.dist = *dist; + data.strict = strict; + data.closest = NULL; + data.closestIndex = 0; + + data.pass = 0; + + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); + + if (data.dist>3) { + data.pass = 1; + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); + } + + *dist = data.dist; + lastSelected = data.closest; + lastSelectedIndex = data.closestIndex; + + return data.closest; + } +} + +/* returns labda for closest distance v1 to line-piece v2-v3 */ +float labda_PdistVL2Dfl(const float v1[3], const float v2[3], const float v3[3]) +{ + float rc[2], len; + + rc[0]= v3[0]-v2[0]; + rc[1]= v3[1]-v2[1]; + len= rc[0]*rc[0]+ rc[1]*rc[1]; + if(len==0.0f) + return 0.0f; + + return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len; +} + +/* note; uses v3d, so needs active 3d window */ +static void findnearestedge__doClosest(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index)) +{ + struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData; + float v1[2], v2[2]; + int distance; + + v1[0] = x0; + v1[1] = y0; + v2[0] = x1; + v2[1] = y1; + + distance= dist_to_line_segment_v2(data->mval, v1, v2); + + if(BM_TestHFlag(eed, BM_SELECT)) distance+=5; + if(distance < data->dist) { + if(data->vc.rv3d->rflag & RV3D_CLIPPING) { + float labda= labda_PdistVL2Dfl(data->mval, v1, v2); + float vec[3]; + + vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]); + vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]); + vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]); + mul_m4_v3(data->vc.obedit->obmat, vec); + + if(ED_view3d_test_clipping(data->vc.rv3d, vec, 1)==0) { + data->dist = distance; + data->closest = eed; + } + } + else { + data->dist = distance; + data->closest = eed; + } + } +} +BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist) +{ + + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { + int distance; + unsigned int index; + BMEdge *eed; + + view3d_validate_backbuf(vc); + + index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL); + eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1); + + if (eed && distance<*dist) { + *dist = distance; + return eed; + } else { + return NULL; + } + } + else { + struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data; + + data.vc= *vc; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = *dist; + data.closest = NULL; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2); + + *dist = data.dist; + return data.closest; + } +} + +static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) +{ + struct { short mval[2]; int dist; BMFace *toFace; } *data = userData; + + if (efa==data->toFace) { + int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); + + if (temp<data->dist) + data->dist = temp; + } +} +static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index) +{ + struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData; + + if (data->pass==0) { + if (index<=data->lastIndex) + return; + } else { + if (index>data->lastIndex) + return; + } + + if (data->dist>3) { + int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); + + if (temp<data->dist) { + data->dist = temp; + data->closest = efa; + data->closestIndex = index; + } + } +} + +BMFace *EDBM_findnearestface(ViewContext *vc, int *dist) +{ + + if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { + unsigned int index; + BMFace *efa; + + view3d_validate_backbuf(vc); + + index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); + efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1); + + if (efa) { + struct { short mval[2]; int dist; BMFace *toFace; } data; + + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = 0x7FFF; /* largest short */ + data.toFace = efa; + + mesh_foreachScreenFace(vc, findnearestface__getDistance, &data); + + if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */ + *dist= data.dist; + return efa; + } + } + + return NULL; + } + else { + struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data; + static int lastSelectedIndex=0; + static BMFace *lastSelected=NULL; + + if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) { + lastSelectedIndex = 0; + lastSelected = NULL; + } + + data.lastIndex = lastSelectedIndex; + data.mval[0] = vc->mval[0]; + data.mval[1] = vc->mval[1]; + data.dist = *dist; + data.closest = NULL; + data.closestIndex = 0; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + + data.pass = 0; + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); + + if (data.dist>3) { + data.pass = 1; + ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); + mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); + } + + *dist = data.dist; + lastSelected = data.closest; + lastSelectedIndex = data.closestIndex; + + return data.closest; + } +} + +/* best distance based on screen coords. + use em->selectmode to define how to use + selected vertices and edges get disadvantage + return 1 if found one +*/ +static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa) +{ + BMEditMesh *em= vc->em; + int dist= 75; + + *eve= NULL; + *eed= NULL; + *efa= NULL; + + /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ + view3d_validate_backbuf(vc); + + if(em->selectmode & SCE_SELECT_VERTEX) + *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0); + if(em->selectmode & SCE_SELECT_FACE) + *efa= EDBM_findnearestface(vc, &dist); + + dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */ + if(em->selectmode & SCE_SELECT_EDGE) + *eed= EDBM_findnearestedge(vc, &dist); + + /* return only one of 3 pointers, for frontbuffer redraws */ + if(*eed) { + *efa= NULL; *eve= NULL; + } + else if(*efa) { + *eve= NULL; + } + + return (*eve || *eed || *efa); +} + +/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ + +static EnumPropertyItem prop_similar_types[] = { + {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""}, + {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""}, + {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, + + {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, + {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, + {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""}, + {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""}, + {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""}, + {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""}, + {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""}, + + {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, + {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""}, + {SIMFACE_AREA, "AREA", 0, "Area", ""}, + {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, + {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, + {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, + + {0, NULL, 0, NULL, NULL} +}; + +/* selects new faces/edges/verts based on the existing selection */ + +static int similar_face_select_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* get the type from RNA */ + int type = RNA_enum_get(op->ptr, "type"); + + float thresh = CTX_data_tool_settings(C)->select_thresh; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_clear_flag_all(em, BM_SELECT); + + /* select the output */ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); + + /* we succeeded */ + return OPERATOR_FINISHED; +} + +/* ***************************************************** */ + +/* EDGE GROUP */ + +/* wrap the above function but do selection flushing edge to face */ +static int similar_edge_select_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* get the type from RNA */ + int type = RNA_enum_get(op->ptr, "type"); + + float thresh = CTX_data_tool_settings(C)->select_thresh; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_clear_flag_all(em, BM_SELECT); + + /* select the output */ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL); + EDBM_selectmode_flush(em); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); + + /* we succeeded */ + return OPERATOR_FINISHED; +} + +/* ********************************* */ + +/* +VERT GROUP + mode 1: same normal + mode 2: same number of face users + mode 3: same vertex groups +*/ + + +static int similar_vert_select_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + /* get the type from RNA */ + int type = RNA_enum_get(op->ptr, "type"); + float thresh = CTX_data_tool_settings(C)->select_thresh; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "similarverts verts=%hv type=%d thresh=%f", BM_SELECT, type, thresh); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_clear_flag_all(em, BM_SELECT); + + /* select the output */ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + EDBM_selectmode_flush(em); + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); + + /* we succeeded */ + return OPERATOR_FINISHED; +} + +static int select_similar_exec(bContext *C, wmOperator *op) +{ + int type= RNA_enum_get(op->ptr, "type"); + + if(type < 100) + return similar_vert_select_exec(C, op); + else if(type < 200) + return similar_edge_select_exec(C, op); + else + return similar_face_select_exec(C, op); +} + +static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +{ + Object *obedit = CTX_data_edit_object(C); + EnumPropertyItem *item= NULL; + int a, totitem= 0; + + if(obedit && obedit->type == OB_MESH) { + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + + if(em->selectmode & SCE_SELECT_VERTEX) { + for (a=SIMVERT_NORMAL; a<SIMEDGE_LENGTH; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } else if(em->selectmode & SCE_SELECT_EDGE) { + for (a=SIMEDGE_LENGTH; a<SIMFACE_MATERIAL; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } else if(em->selectmode & SCE_SELECT_FACE) { + for (a=SIMFACE_MATERIAL; a<=SIMFACE_COPLANAR; a++) { + RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); + } + } + RNA_enum_item_end(&item, &totitem); + + *free= 1; + + return item; + } + + return NULL; +} + +void MESH_OT_select_similar(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name= "Select Similar"; + ot->idname= "MESH_OT_select_similar"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= select_similar_exec; + ot->poll= ED_operator_editmesh; + ot->description= "Select similar vertices, edges or faces by property types."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + prop= ot->prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); + RNA_def_enum_funcs(prop, select_similar_type_itemf); +} + +/* ***************************************************** */ + +/* **************** LOOP SELECTS *************** */ +/*faceloop_select, edgeloop_select, and edgering_select, are left + here for reference purposes temporarily, but have all been replaced + by uses of walker_select.*/ + +static void walker_select(BMEditMesh *em, int walkercode, void *start, int select) +{ + BMesh *bm = em->bm; + BMHeader *h; + BMWalker walker; + + BMW_Init(&walker, bm, walkercode, 0, 0); + h = BMW_Begin(&walker, start); + for (; h; h=BMW_Step(&walker)) { + BM_Select(bm, h, select); + } + BMW_End(&walker); +} + +static int loop_multiselect(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMEdge *eed; + BMEdge **edarray; + int edindex; + int looptype= RNA_boolean_get(op->ptr, "ring"); + + BMIter iter; + int totedgesel = 0; + + for(eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; eed = BMIter_Step(&iter)){ + + if(BM_TestHFlag(eed, BM_SELECT)){ + totedgesel++; + } + } + + + edarray = MEM_mallocN(sizeof(BMEdge*)*totedgesel,"edge array"); + edindex = 0; + + for(eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; eed = BMIter_Step(&iter)){ + + if(BM_TestHFlag(eed, BM_SELECT)){ + edarray[edindex] = eed; + edindex++; + } + } + + if(looptype){ + for(edindex = 0; edindex < totedgesel; edindex +=1){ + eed = edarray[edindex]; + walker_select(em, BMW_EDGERING, eed, 1); + } + EDBM_selectmode_flush(em); + } + else{ + for(edindex = 0; edindex < totedgesel; edindex +=1){ + eed = edarray[edindex]; + walker_select(em, BMW_LOOP, eed, 1); + } + EDBM_selectmode_flush(em); + } + MEM_freeN(edarray); +// if (EM_texFaceCheck()) + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_loop_multi_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Multi Select Loops"; + ot->idname= "MESH_OT_loop_multi_select"; + + /* api callbacks */ + ot->exec= loop_multiselect; + ot->poll= ED_operator_editmesh; + ot->description= "Select a loop of connected edges by connection type."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); +} + + +/* ***************** MAIN MOUSE SELECTION ************** */ + + +/* ***************** loop select (non modal) ************** */ + +static void mouse_mesh_loop(bContext *C, int mval[2], short extend, short ring) +{ + ViewContext vc; + BMEditMesh *em; + BMEdge *eed; + int select= 1; + int dist= 50; + + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + em= vc.em; + + /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */ + view3d_validate_backbuf(&vc); + + eed= EDBM_findnearestedge(&vc, &dist); + if(eed) { + if(extend==0) EDBM_clear_flag_all(em, BM_SELECT); + + if(BM_TestHFlag(em, BM_SELECT)==0) select=1; + else if(extend) select=0; + + if(em->selectmode & SCE_SELECT_FACE) { + walker_select(em, BMW_FACELOOP, eed, select); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + if(ring) + walker_select(em, BMW_EDGERING, eed, select); + else + walker_select(em, BMW_LOOP, eed, select); + } + else if(em->selectmode & SCE_SELECT_VERTEX) { + if(ring) + walker_select(em, BMW_EDGERING, eed, select); + else + walker_select(em, BMW_LOOP, eed, select); + } + + EDBM_selectmode_flush(em); +// if (EM_texFaceCheck()) + + /* sets as active, useful for other tools */ + if(select && em->selectmode & SCE_SELECT_EDGE) { + EDBM_store_selection(em, eed); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit); + } +} + +static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + + view3d_operator_needs_opengl(C); + + mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "ring")); + + /* cannot do tweaks for as long this keymap is after transform map */ + return OPERATOR_FINISHED; +} + +void MESH_OT_loop_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Loop Select"; + ot->idname= "MESH_OT_loop_select"; + + /* api callbacks */ + ot->invoke= mesh_select_loop_invoke; + ot->poll= ED_operator_editmesh; + ot->description= "Select a loop of connected edges."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); + RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", ""); +} + +/* ******************* mesh shortest path select, uses prev-selected edge ****************** */ + +/* since you want to create paths with multiple selects, it doesn't have extend option */ +static void mouse_mesh_shortest_path(bContext *UNUSED(C), int UNUSED(mval[2])) +{ +#if 0 //BMESH_TODO + ViewContext vc; + BMEditMesh *em; + BMEdge *eed; + int dist= 50; + + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + em= vc.em; + + eed= findnearestedge(&vc, &dist); + if(eed) { + Mesh *me= vc.obedit->data; + int path = 0; + + if (em->bm->selected.last) { + EditSelection *ese = em->bm->selected.last; + + if(ese && ese->type == BMEdge) { + BMEdge *eed_act; + eed_act = (BMEdge*)ese->data; + if (eed_act != eed) { + if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { + EM_remove_selection(em, eed_act, BMEdge); + path = 1; + } + } + } + } + if (path==0) { + int act = (edgetag_context_check(vc.scene, eed)==0); + edgetag_context_set(em, vc.scene, eed, act); /* switch the edge option */ + } + + EM_selectmode_flush(em); + + /* even if this is selected it may not be in the selection list */ + if(edgetag_context_check(vc.scene, eed)==0) + EDBM_remove_selection(em, eed); + else + EDBM_store_selection(em, eed); + + /* force drawmode for mesh */ + switch (CTX_data_tool_settings(C)->edge_mode) { + + case EDGE_MODE_TAG_SEAM: + me->drawflag |= ME_DRAWSEAMS; + break; + case EDGE_MODE_TAG_SHARP: + me->drawflag |= ME_DRAWSHARP; + break; + case EDGE_MODE_TAG_CREASE: + me->drawflag |= ME_DRAWCREASES; + break; + case EDGE_MODE_TAG_BEVEL: + me->drawflag |= ME_DRAWBWEIGHTS; + break; + } + + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data); + } +#endif +} + + +static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) +{ + + view3d_operator_needs_opengl(C); + + mouse_mesh_shortest_path(C, event->mval); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_shortest_path(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Shortest Path Select"; + ot->idname= "MESH_OT_select_shortest_path"; + + /* api callbacks */ + ot->invoke= mesh_shortest_path_select_invoke; + ot->poll= ED_operator_editmesh; + ot->description= "Select shortest path between two selections."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); +} + +/* ************************************************** */ +/* here actual select happens */ +/* gets called via generic mouse select operator */ +int mouse_mesh(bContext *C, const int mval[2], short extend) +{ + ViewContext vc; + BMVert *eve = NULL; + BMEdge *eed = NULL; + BMFace *efa = NULL; + + /* setup view context for argument to callbacks */ + em_setup_viewcontext(C, &vc); + vc.mval[0]= mval[0]; + vc.mval[1]= mval[1]; + + if(unified_findnearest(&vc, &eve, &eed, &efa)) { + + if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT); + + if(efa) { + /* set the last selected face */ + EDBM_set_actFace(vc.em, efa); + + if(!BM_TestHFlag(efa, BM_SELECT)) { + EDBM_store_selection(vc.em, efa); + BM_Select(vc.em->bm, efa, 1); + } + else if(extend) { + EDBM_remove_selection(vc.em, efa); + BM_Select(vc.em->bm, efa, 0); + } + } + else if(eed) { + if(!BM_TestHFlag(eed, BM_SELECT)) { + EDBM_store_selection(vc.em, eed); + BM_Select(vc.em->bm, eed, 1); + } + else if(extend) { + EDBM_remove_selection(vc.em, eed); + BM_Select(vc.em->bm, eed, 0); + } + } + else if(eve) { + if(!BM_TestHFlag(eve, BM_SELECT)) { + EDBM_store_selection(vc.em, eve); + BM_Select(vc.em->bm, eve, 1); + } + else if(extend){ + EDBM_remove_selection(vc.em, eve); + BM_Select(vc.em->bm, eve, 0); + } + } + + EDBM_selectmode_flush(vc.em); + +// if (EM_texFaceCheck()) { + + if (efa && efa->mat_nr != vc.obedit->actcol-1) { + vc.obedit->actcol= efa->mat_nr+1; + vc.em->mat_nr= efa->mat_nr; +// BIF_preview_changed(ID_MA); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit); + return 1; + } + + return 0; +} + +static void EDBM_strip_selections(BMEditMesh *em) +{ + BMEditSelection *ese, *nextese; + + if(!(em->selectmode & SCE_SELECT_VERTEX)){ + ese = em->bm->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese); + ese = nextese; + } + } + if(!(em->selectmode & SCE_SELECT_EDGE)){ + ese=em->bm->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese); + ese = nextese; + } + } + if(!(em->selectmode & SCE_SELECT_FACE)){ + ese=em->bm->selected.first; + while(ese){ + nextese = ese->next; + if(ese->type == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese); + ese = nextese; + } + } +} + +/* when switching select mode, makes sure selection is consistant for editing */ +/* also for paranoia checks to make sure edge or face mode works */ +void EDBM_selectmode_set(BMEditMesh *em) +{ + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + + em->bm->selectmode = em->selectmode; + + EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/ + + if(em->selectmode & SCE_SELECT_VERTEX) { + /*BMIter iter; + + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0); + + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/ + + EDBM_selectmode_flush(em); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + /* deselect vertices, and select again based on edge select */ + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0); + + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if (BM_TestHFlag(eed, BM_SELECT)) + BM_Select(em->bm, eed, 1); + } + + /* selects faces based on edge status */ + EDBM_selectmode_flush(em); + } + else if(em->selectmode & SCE_SELECT_FACE) { + /* deselect eges, and select again based on face select */ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0); + + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + if (BM_TestHFlag(efa, BM_SELECT)) + BM_Select(em->bm, efa, 1); + } + } +} + +void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode) +{ + BMEdge *eed; + BMFace *efa; + BMIter iter; + + /*have to find out what the selectionmode was previously*/ + if(oldmode == SCE_SELECT_VERTEX) { + if(selectmode == SCE_SELECT_EDGE) { + /*select all edges associated with every selected vertex*/ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1); + else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1); + } + } + else if(selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /*select all faces associated with every selected vertex*/ + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + BM_Select(em->bm, efa, 1); + break; + } + } + } + } + } + + if(oldmode == SCE_SELECT_EDGE){ + if(selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /*select all faces associated with every selected vertex*/ + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + BM_Select(em->bm, efa, 1); + break; + } + } + } + } + } +} + + +void EDBM_select_swap(BMEditMesh *em) /* exported for UV */ +{ + BMIter iter; + BMVert *eve; + BMEdge *eed; + BMFace *efa; + + if(em->bm->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_HIDDEN)) + continue; + BM_Select(em->bm, eve, !BM_TestHFlag(eve, BM_SELECT)); + } + } + else if(em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN)) + continue; + BM_Select(em->bm, eed, !BM_TestHFlag(eed, BM_SELECT)); + } + } + else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_TestHFlag(efa, BM_HIDDEN)) + continue; + BM_Select(em->bm, efa, !BM_TestHFlag(efa, BM_SELECT)); + } + + } +// if (EM_texFaceCheck()) +} + +static int select_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + EDBM_select_swap(em); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_inverse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Inverse"; + ot->idname= "MESH_OT_select_inverse"; + ot->description= "Select inverse of (un)selected vertices, edges or faces."; + + /* api callbacks */ + ot->exec= select_inverse_mesh_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Object *obedit= CTX_data_edit_object(C); + ViewContext vc; + BMWalker walker; + BMEditMesh *em; + BMVert *eve; + BMEdge *e, *eed; + BMFace *efa; + int sel= !RNA_boolean_get(op->ptr, "deselect"); + + /* unified_finednearest needs ogl */ + view3d_operator_needs_opengl(C); + + /* setup view context for argument to callbacks */ + em_setup_viewcontext(C, &vc); + em = vc.em; + + if(vc.em->bm->totedge==0) + return OPERATOR_CANCELLED; + + vc.mval[0]= event->mval[0]; + vc.mval[1]= event->mval[1]; + + /* return warning! */ + + /*if(limit) { + int retval= select_linked_limited_invoke(&vc, 0, sel); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + return retval; + }*/ + + if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) { + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_CANCELLED; + } + + if (efa) { + eed = bm_firstfaceloop(efa)->e; + } else if (!eed) { + if (!eve || !eve->e) + return OPERATOR_CANCELLED; + + eed = eve->e; + } + + BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0); + e = BMW_Begin(&walker, eed->v1); + for (; e; e=BMW_Step(&walker)) { + BM_Select(em->bm, e->v1, sel); + BM_Select(em->bm, e->v2, sel); + } + BMW_End(&walker); + EDBM_select_flush(em, SCE_SELECT_VERTEX); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_linked_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Linked"; + ot->idname= "MESH_OT_select_linked_pick"; + + /* api callbacks */ + ot->invoke= select_linked_pick_invoke; + ot->poll= ED_operator_editmesh; + ot->description= "select/deselect all vertices linked to the edge under the mouse cursor."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); + RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", ""); +} + + +static int select_linked_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BLI_array_declare(verts); + BMVert **verts = NULL; + BMIter iter; + BMVert *v; + BMEdge *e; + BMWalker walker; + int i, tot; + + tot = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT) && !BM_TestHFlag(v, BM_HIDDEN)) { + BLI_array_growone(verts); + verts[tot++] = v; + } + } + + BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0); + for (i=0; i<tot; i++) { + e = BMW_Begin(&walker, verts[i]); + for (; e; e=BMW_Step(&walker)) { + BM_Select(em->bm, e->v1, 1); + BM_Select(em->bm, e->v2, 1); + } + } + BMW_End(&walker); + EDBM_select_flush(em, SCE_SELECT_VERTEX); + + BLI_array_free(verts); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Linked All"; + ot->idname= "MESH_OT_select_linked"; + + /* api callbacks */ + ot->exec= select_linked_exec; + ot->poll= ED_operator_editmesh; + ot->description= "Select all vertices linked to the active mesh."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", ""); +} + +/* ******************** **************** */ + +static int select_more(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_SELECT, 0, usefaces); + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL); + + EDBM_selectmode_flush(em); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select More"; + ot->idname= "MESH_OT_select_more"; + ot->description= "Select more vertices, edges or faces connected to initial selection."; + + /* api callbacks */ + ot->exec= select_more; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int select_less(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_SELECT, 1, usefaces); + + BMO_Exec_Op(em->bm, &bmop); + BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL); + + EDBM_selectmode_flush(em); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Less"; + ot->idname= "MESH_OT_select_less"; + ot->description= "Deselect vertices, edges or faces at the boundary of each selection region."; + + /* api callbacks */ + ot->exec= select_less; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int mesh_select_nth_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); +// BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; +// int nth = RNA_int_get(op->ptr, "nth"); + +#if 0 //BMESH_TODO + if(EM_deselect_nth(em, nth) == 0) { + BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face."); + return OPERATOR_CANCELLED; + } +#else + BKE_report(op->reports, RPT_ERROR, "Unimplemented"); +#endif + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_select_nth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Nth"; + ot->description= ""; + ot->idname= "MESH_OT_select_nth"; + + /* api callbacks */ + ot->exec= mesh_select_nth_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX); +} + +#if 0 //BMESH_TODO, select nth tool +/* not that optimal!, should be nicer with bmesh */ +static void tag_face_edges(EditFace *efa) +{ + if(efa->v4) + efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1; + else + efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1; +} +static int tag_face_edges_test(EditFace *efa) +{ + if(efa->v4) + return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0; + else + return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0; +} + +void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act) +{ + EditFace *efa; + EditEdge *eed; + int ok= 1; + + if(efa_act==NULL) { + return; + } + + /* to detect loose edges, we put f2 flag on 1 */ + for(eed= em->edges.first; eed; eed= eed->next) { + eed->tmp.l= 0; + } + + for (efa= em->faces.first; efa; efa= efa->next) { + efa->tmp.l = 0; + } + + efa_act->tmp.l = 1; + + while(ok) { + ok = 0; + + for (efa= em->faces.first; efa; efa= efa->next) { + if(efa->tmp.l==1) { /* initialize */ + tag_face_edges(efa); + } + + if(efa->tmp.l) + efa->tmp.l++; + } + + for (efa= em->faces.first; efa; efa= efa->next) { + if(efa->tmp.l==0 && tag_face_edges_test(efa)) { + efa->tmp.l= 1; + ok = 1; /* keep looping */ + } + } + } + + for (efa= em->faces.first; efa; efa= efa->next) { + if(efa->tmp.l > 0 && efa->tmp.l % nth) { + EM_select_face(efa, 0); + } + } + for (efa= em->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT) { + EM_select_face(efa, 1); + } + } + + EM_nvertices_selected(em); + EM_nedges_selected(em); + EM_nfaces_selected(em); +} + +/* not that optimal!, should be nicer with bmesh */ +static void tag_edge_verts(EditEdge *eed) +{ + eed->v1->tmp.l= eed->v2->tmp.l= 1; +} +static int tag_edge_verts_test(EditEdge *eed) +{ + return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0; +} + +void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act) +{ + EditEdge *eed; + EditVert *eve; + int ok= 1; + + if(eed_act==NULL) { + return; + } + + for(eve= em->verts.first; eve; eve= eve->next) { + eve->tmp.l= 0; + } + + for (eed= em->edges.first; eed; eed= eed->next) { + eed->tmp.l = 0; + } + + eed_act->tmp.l = 1; + + while(ok) { + ok = 0; + + for (eed= em->edges.first; eed; eed= eed->next) { + if(eed->tmp.l==1) { /* initialize */ + tag_edge_verts(eed); + } + + if(eed->tmp.l) + eed->tmp.l++; + } + + for (eed= em->edges.first; eed; eed= eed->next) { + if(eed->tmp.l==0 && tag_edge_verts_test(eed)) { + eed->tmp.l= 1; + ok = 1; /* keep looping */ + } + } + } + + for (eed= em->edges.first; eed; eed= eed->next) { + if(eed->tmp.l > 0 && eed->tmp.l % nth) { + EM_select_edge(eed, 0); + } + } + for (eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + EM_select_edge(eed, 1); + } + } + + { + /* grr, should be a function */ + EditFace *efa; + for (efa= em->faces.first; efa; efa= efa->next) { + if(efa->v4) { + if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT ); + else efa->f &= ~SELECT; + } + else { + if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT ); + else efa->f &= ~SELECT; + } + } + } + + EM_nvertices_selected(em); + EM_nedges_selected(em); + EM_nfaces_selected(em); +} + +void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act) +{ + EditVert *eve; + EditEdge *eed; + int ok= 1; + + if(eve_act==NULL) { + return; + } + + for (eve= em->verts.first; eve; eve= eve->next) { + eve->tmp.l = 0; + } + + eve_act->tmp.l = 1; + + while(ok) { + ok = 0; + + for (eve= em->verts.first; eve; eve= eve->next) { + if(eve->tmp.l) + eve->tmp.l++; + } + + for (eed= em->edges.first; eed; eed= eed->next) { + if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */ + eed->v2->tmp.l= 1; + ok = 1; /* keep looping */ + } + else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */ + eed->v1->tmp.l= 1; + ok = 1; /* keep looping */ + } + } + } + + for (eve= em->verts.first; eve; eve= eve->next) { + if(eve->tmp.l > 0 && eve->tmp.l % nth) { + eve->f &= ~SELECT; + } + } + + EM_deselect_flush(em); + + EM_nvertices_selected(em); + // EM_nedges_selected(em); // flush does these + // EM_nfaces_selected(em); // flush does these +} +#endif + +static int EM_deselect_nth(BMEditMesh *em, int nth) +{ +#if 1 /*BMESH_TODO*/ + (void)em; + (void)nth; +#else + EditSelection *ese; + ese = ((EditSelection*)em->selected.last); + if(ese) { + if(ese->type == EDITVERT) { + em_deselect_nth_vert(em, nth, (EditVert*)ese->data); + return 1; + } + + if(ese->type == EDITEDGE) { + em_deselect_nth_edge(em, nth, (EditEdge*)ese->data); + return 1; + } + } + else { + EditFace *efa_act = EM_get_actFace(em, 0); + if(efa_act) { + em_deselect_nth_face(em, nth, efa_act); + return 1; + } + } + + return 0; +#endif + return 1; +} + +void em_setup_viewcontext(bContext *C, ViewContext *vc) +{ + view3d_set_viewcontext(C, vc); + + if(vc->obedit) { + Mesh *me= vc->obedit->data; + vc->em= me->edit_btmesh; + } +} + +/* poll call for mesh operators requiring a view3d context */ +int EM_view3d_poll(bContext *C) +{ + if(ED_operator_editmesh(C) && ED_operator_view3d_active(C)) + return 1; + return 0; +} + + +static int select_sharp_edges_exec(bContext *C, wmOperator *op) +{ + /* Find edges that have exactly two neighboring faces, + * check the angle between those faces, and if angle is + * small enough, select the edge + */ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMIter iter; + BMEdge *e; + BMLoop *l1, *l2; + float sharp = RNA_float_get(op->ptr, "sharpness"), angle; + + sharp = (sharp * M_PI) / 180.0; + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_HIDDEN) || !e->l) + continue; + + l1 = e->l; + l2 = l1->radial_next; + + if (l1 == l2) + continue; + + /* edge has exactly two neighboring faces, check angle */ + angle = saacos(l1->f->no[0]*l2->f->no[0]+l1->f->no[1]*l2->f->no[1]+l1->f->no[2]*l2->f->no[2]); + + if (fabs(angle) < sharp) { + BM_Select(em->bm, e, 1); + } + + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_edges_select_sharp(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Sharp Edges"; + ot->description= "Marked selected edges as sharp."; + ot->idname= "MESH_OT_edges_select_sharp"; + + /* api callbacks */ + ot->exec= select_sharp_edges_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f); +} + +static int select_linked_flat_faces_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMIter iter, liter, liter2; + BMFace *f, **stack = NULL; + BLI_array_declare(stack); + BMLoop *l, *l2; + float sharp = RNA_float_get(op->ptr, "sharpness"); + int i; + + sharp = (sharp * M_PI) / 180.0; + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_SetIndex(f, 0); + } + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_TestHFlag(f, BM_HIDDEN) || !BM_TestHFlag(f, BM_SELECT) || BM_GetIndex(f)) + continue; + + BLI_array_empty(stack); + i = 1; + + BLI_array_growone(stack); + stack[i-1] = f; + + while (i) { + f = stack[i-1]; + i--; + + BM_Select(em->bm, f, 1); + + BM_SetIndex(f, 1); + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_LOOP, l) { + float angle; + + if (BM_GetIndex(l2->f) || BM_TestHFlag(l2->f, BM_HIDDEN)) + continue; + + /* edge has exactly two neighboring faces, check angle */ + angle = saacos(f->no[0]*l2->f->no[0]+f->no[1]*l2->f->no[1]+f->no[2]*l2->f->no[2]); + + /* invalidate: edge too sharp */ + if (fabs(angle) < sharp) { + BLI_array_growone(stack); + stack[i] = l2->f; + i++; + } + } + } + } + } + + BLI_array_free(stack); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Linked Flat Faces"; + ot->description= "Select linked faces by angle."; + ot->idname= "MESH_OT_faces_select_linked_flat"; + + /* api callbacks */ + ot->exec= select_linked_flat_faces_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f); +} + +static int select_non_manifold_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMVert *v; + BMEdge *e; + BMIter iter; + + /* Selects isolated verts, and edges that do not have 2 neighboring + * faces + */ + + if(em->selectmode==SCE_SELECT_FACE) { + BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode"); + return OPERATOR_CANCELLED; + } + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Vert(em->bm, v)) + BM_Select(em->bm, v, 1); + } + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Edge_FaceCount(e) != 2) + BM_Select(em->bm, e, 1); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_non_manifold(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Non Manifold"; + ot->description= "Select all non-manifold vertices or edges."; + ot->idname= "MESH_OT_select_non_manifold"; + + /* api callbacks */ + ot->exec= select_non_manifold_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int mesh_select_random_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMVert *eve; + BMEdge *eed; + BMFace *efa; + BMIter iter; + float randfac = RNA_float_get(op->ptr, "percent")/100.0f; + + BLI_srand( BLI_rand() ); /* random seed */ + + if(!RNA_boolean_get(op->ptr, "extend")) + EDBM_clear_flag_all(em, BM_SELECT); + + if(em->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(eve, BM_HIDDEN) && BLI_frand() < randfac) + BM_Select(em->bm, eve, 1); + } + EDBM_selectmode_flush(em); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(eed, BM_HIDDEN) && BLI_frand() < randfac) + BM_Select(em->bm, eed, 1); + } + EDBM_selectmode_flush(em); + } + else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && BLI_frand() < randfac) + BM_Select(em->bm, efa, 1); + } + EDBM_selectmode_flush(em); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_random(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Random"; + ot->description= "Randomly select vertices."; + ot->idname= "MESH_OT_select_random"; + + /* api callbacks */ + ot->exec= mesh_select_random_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly.", 0.f, 100.0f); + RNA_def_boolean(ot->srna, "extend", 0, "Extend Selection", "Extend selection instead of deselecting everything first."); +} + +static int select_next_loop(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMFace *f; + BMVert *v; + BMIter iter; + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, 0); + } + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BMLoop *l; + BMIter liter; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + if (BM_TestHFlag(l->v, BM_SELECT) && !BM_TestHFlag(l->v, BM_HIDDEN)) { + BM_SetIndex(l->next->v, 1); + BM_Select(em->bm, l->v, 0); + } + } + } + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_GetIndex(v)) { + BM_Select(em->bm, v, 1); + } + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_next_loop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Next Loop"; + ot->idname= "MESH_OT_select_next_loop"; + ot->description= ""; + + /* api callbacks */ + ot->exec= select_next_loop; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +static int region_to_loop(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMFace *f; + BMEdge *e; + BMIter iter; + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + BM_SetIndex(e, 0); + } + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BMLoop *l1, *l2; + BMIter liter1, liter2; + + BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) { + int tot=0, totsel=0; + + BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) { + tot++; + totsel += BM_TestHFlag(l2->f, BM_SELECT) != 0; + } + + if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) + BM_SetIndex(l1->e, 1); + } + } + + EDBM_clear_flag_all(em, BM_SELECT); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_GetIndex(e) && !BM_TestHFlag(e, BM_HIDDEN)) + BM_Select_Edge(em->bm, e, 1); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + return OPERATOR_FINISHED; +} + +void MESH_OT_region_to_loop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Boundary Loop"; + ot->idname= "MESH_OT_region_to_loop"; + + /* api callbacks */ + ot->exec= region_to_loop; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int loop_find_region(BMEditMesh *em, BMLoop *l, int flag, + SmallHash *fhash, BMFace ***region_out) +{ + BLI_array_declare(region); + BLI_array_declare(stack); + BMFace **region = NULL, *f; + BMFace **stack = NULL; + + BLI_array_append(stack, l->f); + BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL); + + while (BLI_array_count(stack) > 0) { + BMIter liter1, liter2; + BMLoop *l1, *l2; + + f = BLI_array_pop(stack); + BLI_array_append(region, f); + + BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) { + if (BM_TestHFlag(l1->e, flag)) + continue; + + BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) { + if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f)) + continue; + + BLI_array_append(stack, l2->f); + BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL); + } + } + } + + BLI_array_free(stack); + + *region_out = region; + return BLI_array_count(region); +} + +static int verg_radial(const void *va, const void *vb) +{ + BMEdge *e1 = *((void**)va); + BMEdge *e2 = *((void**)vb); + int a, b; + + a = BM_Edge_FaceCount(e1); + b = BM_Edge_FaceCount(e2); + + if (a > b) return -1; + if (a == b) return 0; + if (a < b) return 1; + + return -1; +} + +static int loop_find_regions(BMEditMesh *em, int selbigger) +{ + SmallHash visithash; + BMIter iter; + BMEdge *e, **edges=NULL; + BLI_array_declare(edges); + BMFace *f; + int count = 0, i; + + BLI_smallhash_init(&visithash); + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_SetIndex(f, 0); + } + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) { + BLI_array_append(edges, e); + BM_SetIndex(e, 1); + } else { + BM_SetIndex(e, 0); + } + } + + /*sort edges by radial cycle length*/ + qsort(edges, BLI_array_count(edges), sizeof(void*), verg_radial); + + for (i=0; i<BLI_array_count(edges); i++) { + BMIter liter; + BMLoop *l; + BMFace **region=NULL, **r; + int c, tot=0; + + e = edges[i]; + + if (!BM_GetIndex(e)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_EDGE, e) { + if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f)) + continue; + + c = loop_find_region(em, l, BM_SELECT, &visithash, &r); + + if (!region || (selbigger ? c >= tot : c < tot)) { + tot = c; + if (region) + MEM_freeN(region); + region = r; + } + } + + if (region) { + int j; + + for (j=0; j<tot; j++) { + BM_SetIndex(region[j], 1); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) { + BM_SetIndex(l->e, 0); + } + } + + count += tot; + + MEM_freeN(region); + } + } + + BLI_array_free(edges); + BLI_smallhash_release(&visithash); + + return count; +} + +static int loop_to_region(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMIter iter; + BMFace *f; + int selbigger = RNA_boolean_get(op->ptr, "select_bigger"); + int a, b; + + /*find the set of regions with smallest number of total faces*/ + a = loop_find_regions(em, selbigger); + b = loop_find_regions(em, !selbigger); + + if ((a <= b) ^ selbigger) { + loop_find_regions(em, selbigger); + } + + EDBM_clear_flag_all(em, BM_SELECT); + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_GetIndex(f) && !BM_TestHFlag(f, BM_HIDDEN)) { + BM_Select_Face(em->bm, f, 1); + } + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + return OPERATOR_FINISHED; +} + +void MESH_OT_loop_to_region(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Loop Inner-Region"; + ot->idname= "MESH_OT_loop_to_region"; + + /* api callbacks */ + ot->exec= loop_to_region; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones"); +} diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c new file mode 100644 index 00000000000..3b7fade9c05 --- /dev/null +++ b/source/blender/editors/mesh/bmesh_selecthistory.c @@ -0,0 +1,126 @@ +/** + * $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/* ********* Selection History ************ */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_texture_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_array.h" + +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_DerivedMesh.h" +#include "BKE_customdata.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_texture.h" +#include "BKE_utildefines.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#include "RE_render_ext.h" /* externtex */ + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "bmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "mesh_intern.h" + +#include "BLO_sys_types.h" // for intptr_t support + +/*these wrap equivilent bmesh functions. I'm in two minds of it we should + just use the bm functions directly; on the one hand, there's no real + need (at the moment) to wrap them, but on the other hand having these + wrapped avoids a confusing mess of mixing BM_ and EDBM_ namespaces.*/ + +void EDBM_editselection_center(BMEditMesh *em, float *center, BMEditSelection *ese) +{ + BM_editselection_center(em->bm, center, ese); +} + +void EDBM_editselection_normal(float *normal, BMEditSelection *ese) +{ + BM_editselection_normal(normal, ese); +} + +/* Calculate a plane that is rightangles to the edge/vert/faces normal +also make the plane run allong an axis that is related to the geometry, +because this is used for the manipulators Y axis.*/ +void EDBM_editselection_plane(BMEditMesh *em, float *plane, BMEditSelection *ese) +{ + BM_editselection_plane(em->bm, plane, ese); +} + +void EDBM_remove_selection(BMEditMesh *em, void *data) +{ + BM_remove_selection(em->bm, data); +} + +void EDBM_store_selection(BMEditMesh *em, void *data) +{ + BM_store_selection(em->bm, data); +} + +void EDBM_validate_selections(BMEditMesh *em) +{ + BM_validate_selections(em->bm); +} diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c new file mode 100644 index 00000000000..bdc5e0296e9 --- /dev/null +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -0,0 +1,4891 @@ + /* $Id: bmesh_tools.c + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" +#include "BLI_array.h" +#include "BLI_smallhash.h" + +#include "BKE_material.h" +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_DerivedMesh.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" +#include "BKE_texture.h" +#include "BKE_main.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_object.h" + +#include "UI_interface.h" + +#include "RE_render_ext.h" + +#include "mesh_intern.h" +#include "bmesh.h" + +#include "editbmesh_bvh.h" + +static void add_normal_aligned(float *nor, float *add) +{ + if( INPR(nor, add) < -0.9999f) + sub_v3_v3v3(nor, nor, add); + else + add_v3_v3v3(nor, nor, add); +} + + +static int subdivide_exec(bContext *C, wmOperator *op) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int cuts= RNA_int_get(op->ptr,"number_cuts"); + float fractal= RNA_float_get(op->ptr, "fractal")/2.5; + int flag= 0; + + if(fractal != 0.0f) + flag |= B_FRACTAL; + + if (RNA_boolean_get(op->ptr, "quadtri") && + RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT) + { + RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT); + } + + BM_esubdivideflag(obedit, em->bm, BM_SELECT, + 0.0f, fractal, + ts->editbutflag|flag, + cuts, 0, RNA_enum_get(op->ptr, "quadcorner"), + RNA_boolean_get(op->ptr, "quadtri"), + 1, RNA_int_get(op->ptr, "seed")); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +/* Note, these values must match delete_mesh() event values */ +static EnumPropertyItem prop_mesh_cornervert_types[] = { + {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""}, + {SUBD_PATH, "PATH", 0, "Path", ""}, + {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""}, + {SUBD_FAN, "FAN", 0, "Fan", ""}, + {0, NULL, 0, NULL, NULL} +}; + +void MESH_OT_subdivide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Subdivide"; + ot->description= "Subdivide selected edges."; + ot->idname= "MESH_OT_subdivide"; + + /* api callbacks */ + ot->exec= subdivide_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "number_cuts", 1, 1, 50, "Number of Cuts", "", 1, INT_MAX); + + RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons"); + RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "How to subdivide quad corners (anything other then Straight Cut will prevent ngons)"); + + RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f); + RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50); +} + + +void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em) +{ + BMIter iter; + BMVert *eve; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { + float mval[2], vec[3], no_dummy[3]; + int dist_dummy; + mul_v3_m4v3(vec, obedit->obmat, eve->co); + project_float_noclip(ar, vec, mval); + if(snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) { + mul_v3_m4v3(eve->co, obedit->imat, vec); + } + } + } +} + + +/* individual face extrude */ +/* will use vertex normals for extrusion directions, so *nor is unaffected */ +static short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) +{ + BMOIter siter; + BMIter liter; + BMFace *f; + BMLoop *l; + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag); + + /*deselect original verts*/ + EDBM_clear_flag_all(em, BM_SELECT); + + BMO_Exec_Op(em->bm, &bmop); + + BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) { + BM_Select(em->bm, f, 1); + + /*set face vertex normals to face normal*/ + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + VECCOPY(l->v->no, f->no); + } + } + + if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0; + + return 's'; // s is shrink/fatten +} + +#if 0 +short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor) + EditVert *eve, *v1, *v2, *v3, *v4; + EditEdge *eed; + EditFace *efa, *nextfa; + + if(em==NULL) return 0; + + /* selected edges with 1 or more selected face become faces */ + /* selected faces each makes new faces */ + /* always remove old faces, keeps volumes manifold */ + /* select the new extrusion, deselect old */ + + /* step 1; init, count faces in edges */ + recalc_editnormals(em); + + for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag + + for(eed= em->edges.first; eed; eed= eed->next) { + eed->f2= 0; // amount of unselected faces + } + for(efa= em->faces.first; efa; efa= efa->next) { + if(efa->f & SELECT); + else { + efa->e1->f2++; + efa->e2->f2++; + efa->e3->f2++; + if(efa->e4) efa->e4->f2++; + } + } + + /* step 2: make new faces from faces */ + for(efa= em->faces.last; efa; efa= efa->prev) { + if(efa->f & SELECT) { + v1= addvertlist(em, efa->v1->co, efa->v1); + v2= addvertlist(em, efa->v2->co, efa->v2); + v3= addvertlist(em, efa->v3->co, efa->v3); + + v1->f1= v2->f1= v3->f1= 1; + VECCOPY(v1->no, efa->n); + VECCOPY(v2->no, efa->n); + VECCOPY(v3->no, efa->n); + if(efa->v4) { + v4= addvertlist(em, efa->v4->co, efa->v4); + v4->f1= 1; + VECCOPY(v4->no, efa->n); + } + else v4= NULL; + + /* side faces, clockwise */ + addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL); + addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL); + if(efa->v4) { + addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL); + addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL); + } + else { + addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL); + } + /* top face */ + addfacelist(em, v1, v2, v3, v4, efa, NULL); + } + } + + /* step 3: remove old faces */ + efa= em->faces.first; + while(efa) { + nextfa= efa->next; + if(efa->f & SELECT) { + BLI_remlink(&em->faces, efa); + free_editface(em, efa); + } + efa= nextfa; + } + + /* step 4: redo selection */ + EM_clear_flag_all(em, SELECT); + + for(eve= em->verts.first; eve; eve= eve->next) { + if(eve->f1) eve->f |= SELECT; + } + + EM_select_flush(em); + + return 'n'; +} +#endif + +/* extrudes individual edges */ +static short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) +{ + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag); + + /*deselect original verts*/ + EDBM_clear_flag_all(em, BM_SELECT); + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0; + + return 'n'; // n is normal grab +} + +#if 0 +/* nor is filled with constraint vector */ +short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor) +{ + EditVert *eve; + EditEdge *eed; + EditFace *efa; + + for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL; + for(eed= em->edges.first; eed; eed= eed->next) { + eed->tmp.f = NULL; + eed->f2= ((eed->f & flag)!=0); + } + + set_edge_directions_f2(em, 2); + + /* sample for next loop */ + for(efa= em->faces.first; efa; efa= efa->next) { + efa->e1->tmp.f = efa; + efa->e2->tmp.f = efa; + efa->e3->tmp.f = efa; + if(efa->e4) efa->e4->tmp.f = efa; + } + /* make the faces */ + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & flag) { + if(eed->v1->tmp.v == NULL) + eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1); + if(eed->v2->tmp.v == NULL) + eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2); + + if(eed->dir==1) + addfacelist(em, eed->v1, eed->v2, + eed->v2->tmp.v, eed->v1->tmp.v, + eed->tmp.f, NULL); + else + addfacelist(em, eed->v2, eed->v1, + eed->v1->tmp.v, eed->v2->tmp.v, + eed->tmp.f, NULL); + + /* for transform */ + if(eed->tmp.f) { + efa = eed->tmp.f; + if (efa->f & SELECT) add_normal_aligned(nor, efa->n); + } + } + } + normalize_v3(nor); + + /* set correct selection */ + EM_clear_flag_all(em, SELECT); + for(eve= em->verts.last; eve; eve= eve->prev) { + if(eve->tmp.v) { + eve->tmp.v->f |= flag; + } + } + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->v1->f & eed->v2->f & flag) eed->f |= flag; + } + + if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab + return 'n'; // n is for normal constraint +} +#endif + +/* extrudes individual vertices */ +static short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor)) +{ + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag); + + /*deselect original verts*/ + BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT); + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0; + + return 'g'; // g is grab +} + +static short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor) +{ + BMesh *bm = em->bm; + BMIter iter; + BMOIter siter; + BMOperator extop; + BMVert *vert; + BMEdge *edge; + BMFace *f; + ModifierData *md; + BMHeader *el; + + BMO_Init_Op(&extop, "extrudefaceregion"); + BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein", + flag, BM_VERT|BM_EDGE|BM_FACE); + + /* If a mirror modifier with clipping is on, we need to adjust some + * of the cases above to handle edges on the line of symmetry. + */ + md = obedit->modifiers.first; + for (; md; md=md->next) { + if (md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + if(mmd->flag & MOD_MIR_CLIPPING) { + float mtx[4][4]; + if (mmd->mirror_ob) { + float imtx[4][4]; + invert_m4_m4(imtx, mmd->mirror_ob->obmat); + mul_m4_m4m4(mtx, obedit->obmat, imtx); + } + + for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL); + edge; edge=BMIter_Step(&iter)) + { + if(edge->head.flag & flag) { + float co1[3], co2[3]; + + copy_v3_v3(co1, edge->v1->co); + copy_v3_v3(co2, edge->v2->co); + + if (mmd->mirror_ob) { + mul_v3_m4v3(co1, mtx, co1); + mul_v3_m4v3(co2, mtx, co2); + } + + if (mmd->flag & MOD_MIR_AXIS_X) + if ( (fabs(co1[0]) < mmd->tolerance) && + (fabs(co2[0]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Y) + if ( (fabs(co1[1]) < mmd->tolerance) && + (fabs(co2[1]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + + if (mmd->flag & MOD_MIR_AXIS_Z) + if ( (fabs(co1[2]) < mmd->tolerance) && + (fabs(co2[2]) < mmd->tolerance) ) + BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL); + } + } + } + } + } + + BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_Select(bm, vert, 0); + } + + BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) { + BM_Select(bm, edge, 0); + } + + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BM_Select(bm, f, 0); + } + + BMO_Exec_Op(bm, &extop); + + nor[0] = nor[1] = nor[2] = 0.0f; + + BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) { + BM_Select(bm, el, 1); + + if (el->type == BM_FACE) { + f = (BMFace*)el; + add_normal_aligned(nor, f->no); + }; + } + + normalize_v3(nor); + + BMO_Finish_Op(bm, &extop); + + if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab + return 'n'; // normal constraint + +} +static short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor) +{ + BMIter iter; + BMEdge *eed; + + /*ensure vert flags are consistent for edge selections*/ + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter)) { + if (BM_TestHFlag(eed, flag)) { + if (flag != BM_SELECT) { + BM_SetHFlag(eed->v1, flag); + BM_SetHFlag(eed->v2, flag); + } else { + BM_Select(em->bm, eed->v1, 1); + BM_Select(em->bm, eed->v2, 1); + } + } else { + if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) { + if (flag != BM_SELECT) + BM_SetHFlag(eed, flag); + else BM_Select(em->bm, eed, 1); + } + } + } + + return EDBM_Extrude_edge(obedit, em, flag, nor); + +} + +static int extrude_repeat_mesh(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + RegionView3D *rv3d = CTX_wm_region_view3d(C); + + int steps = RNA_int_get(op->ptr,"steps"); + + float offs = RNA_float_get(op->ptr,"offset"); + float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; + short a; + + /* dvec */ + dvec[0]= rv3d->persinv[2][0]; + dvec[1]= rv3d->persinv[2][1]; + dvec[2]= rv3d->persinv[2][2]; + normalize_v3(dvec); + dvec[0]*= offs; + dvec[1]*= offs; + dvec[2]*= offs; + + /* base correction */ + copy_m3_m4(bmat, obedit->obmat); + invert_m3_m3(tmat, bmat); + mul_m3_v3(tmat, dvec); + + for(a=0; a<steps; a++) { + EDBM_Extrude_edge(obedit, em, BM_SELECT, nor); + //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT); + BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT); + //extrudeflag(obedit, em, SELECT, nor); + //translateflag(em, SELECT, dvec); + } + + EDBM_RecalcNormals(em); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_repeat(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Repeat Mesh"; + ot->description= "Extrude selected vertices, edges or faces repeatedly."; + ot->idname= "MESH_OT_extrude_repeat"; + + /* api callbacks */ + ot->exec= extrude_repeat_mesh; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX); + RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX); +} + +/* generic extern called extruder */ +static int EDBM_Extrude_Mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin) +{ + short nr, transmode= 0; + float stacknor[3] = {0.0f, 0.0f, 0.0f}; + float *nor = norin ? norin : stacknor; + + nor[0] = nor[1] = nor[2] = 0.0f; + + if(em->selectmode & SCE_SELECT_VERTEX) { + if(em->bm->totvertsel==0) nr= 0; + else if(em->bm->totvertsel==1) nr= 4; + else if(em->bm->totedgesel==0) nr= 4; + else if(em->bm->totfacesel==0) + nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); + else if(em->bm->totfacesel==1) + nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); + } + else if(em->selectmode & SCE_SELECT_EDGE) { + if (em->bm->totedgesel==0) nr = 0; + + nr = 1; + /*else if (em->totedgesel==1) nr = 3; + else if(em->totfacesel==0) nr = 3; + else if(em->totfacesel==1) + nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3"); + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); + */ + } + else { + if (em->bm->totfacesel == 0) nr = 0; + else if (em->bm->totfacesel == 1) nr = 1; + else + nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); + } + + if(nr<1) return 'g'; + + if(nr==1 && em->selectmode & SCE_SELECT_VERTEX) + transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor); + else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor); + else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor); + else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor); + else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor); + + if(transmode==0) { + BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude"); + } + else { + + /* We need to force immediate calculation here because + * transform may use derived objects (which are now stale). + * + * This shouldn't be necessary, derived queries should be + * automatically building this data if invalid. Or something. + */ +// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); + object_handle_update(scene, obedit); + + /* individual faces? */ +// BIF_TransformSetUndo("Extrude"); + if(nr==2) { +// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); +// Transform(); + } + else { +// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); + if(transmode=='n') { + mul_m4_v3(obedit->obmat, nor); + sub_v3_v3v3(nor, nor, obedit->obmat[3]); +// BIF_setSingleAxisConstraint(nor, "along normal"); + } +// Transform(); + } + } + + return transmode; +} + +/* extrude without transform */ +static int mesh_extrude_region_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + + EDBM_Extrude_Mesh(scene, obedit, em, op, NULL); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_region(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Region"; + ot->idname= "MESH_OT_extrude_region"; + + /* api callbacks */ + //ot->invoke= mesh_extrude_region_invoke; + ot->exec= mesh_extrude_region_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +static int mesh_extrude_verts_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + float nor[3]; + + EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Only Vertices"; + ot->idname= "MESH_OT_extrude_verts_indiv"; + + /* api callbacks */ + ot->exec= mesh_extrude_verts_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* to give to transform */ + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +static int mesh_extrude_edges_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + float nor[3]; + + EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Only Edges"; + ot->idname= "MESH_OT_extrude_edges_indiv"; + + /* api callbacks */ + ot->exec= mesh_extrude_edges_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* to give to transform */ + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +static int mesh_extrude_faces_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + float nor[3]; + + EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Extrude Individual Faces"; + ot->idname= "MESH_OT_extrude_faces_indiv"; + + /* api callbacks */ + ot->exec= mesh_extrude_faces_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +/* ******************** (de)select all operator **************** */ + +void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */ +{ + if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel) + EDBM_clear_flag_all(em, SELECT); + else + EDBM_set_flag_all(em, SELECT); +} + +static int toggle_select_all_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + EDBM_toggle_select_all(em); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select/Deselect All"; + ot->idname= "MESH_OT_select_all"; + ot->description= "(de)select all vertices, edges or faces."; + + /* api callbacks */ + ot->exec= toggle_select_all_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/* *************** add-click-mesh (extrude) operator ************** */ +/* in trunk see: 'editmesh_add.c' */ +static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) +{ + ViewContext vc; + BMVert *v1; + BMIter iter; + float min[3], max[3]; + int done= 0; + short use_proj; + + em_setup_viewcontext(C, &vc); + + use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE); + + INIT_MINMAX(min, max); + + BM_ITER(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v1, BM_SELECT)) { + DO_MINMAX(v1->co, min, max); + done= 1; + } + } + + /* call extrude? */ + if(done) { + const short rot_src= RNA_boolean_get(op->ptr, "rotate_source"); + BMEdge *eed; + float vec[3], cent[3], mat[3][3]; + float nor[3]= {0.0, 0.0, 0.0}; + + /* 2D normal calc */ + float mval_f[2]; + + mval_f[0]= (float)event->mval[0]; + mval_f[1]= (float)event->mval[1]; + + /* check for edges that are half selected, use for rotation */ + done= 0; + BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_SELECT)) { + float co1[3], co2[3]; + mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); + mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); + project_float_noclip(vc.ar, co1, co1); + project_float_noclip(vc.ar, co2, co2); + + /* 2D rotate by 90d while adding. + * (x, y) = (y, -x) + * + * accumulate the screenspace normal in 2D, + * with screenspace edge length weighting the result. */ + if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) { + nor[0] += (co1[1] - co2[1]); + nor[1] += -(co1[0] - co2[0]); + } + else { + nor[0] += (co2[1] - co1[1]); + nor[1] += -(co2[0] - co1[0]); + } + } + done= 1; + } + + if(done) { + float view_vec[3], cross[3]; + + /* convert the 2D nomal into 3D */ + mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ + mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ + + /* correct the normal to be aligned on the view plane */ + copy_v3_v3(view_vec, vc.rv3d->viewinv[2]); + mul_mat3_m4_v3(vc.obedit->imat, view_vec); + cross_v3_v3v3(cross, nor, view_vec); + cross_v3_v3v3(nor, view_vec, cross); + normalize_v3(nor); + } + + /* center */ + mid_v3_v3v3(cent, min, max); + copy_v3_v3(min, cent); + + mul_m4_v3(vc.obedit->obmat, min); // view space + view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); + mul_m4_v3(vc.obedit->imat, min); // back in object space + + sub_v3_v3(min, cent); + + /* calculate rotation */ + unit_m3(mat); + if(done) { + float dot; + + copy_v3_v3(vec, min); + normalize_v3(vec); + dot= INPR(vec, nor); + + if( fabs(dot)<0.999) { + float cross[3], si, q1[4]; + + cross_v3_v3v3(cross, nor, vec); + normalize_v3(cross); + dot= 0.5f*saacos(dot); + + /* halve the rotation if its applied twice */ + if(rot_src) dot *= 0.5f; + + si= (float)sin(dot); + q1[0]= (float)cos(dot); + q1[1]= cross[0]*si; + q1[2]= cross[1]*si; + q1[3]= cross[2]*si; + quat_to_mat3( mat,q1); + } + } + + if(rot_src) { + EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3", + BM_SELECT, cent, mat); + + /* also project the source, for retopo workflow */ + if(use_proj) + EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); + } + + EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor); + EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3", + BM_SELECT, cent, mat); + EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v", + BM_SELECT, min); + } + else { + float *curs= give_cursor(vc.scene, vc.v3d); + BMOperator bmop; + BMOIter oiter; + + copy_v3_v3(min, curs); + view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0); + + invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); + mul_m4_v3(vc.obedit->imat, min); // back in object space + + EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min); + BMO_Exec_Op(vc.em->bm, &bmop); + + BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) { + BM_Select(vc.em->bm, v1, 1); + } + + if (!EDBM_FinishOp(vc.em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + } + + if(use_proj) + EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); + + WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); + DAG_id_tag_update(vc.obedit->data, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Duplicate or Extrude at 3D Cursor"; + ot->idname= "MESH_OT_dupli_extrude_cursor"; + + /* api callbacks */ + ot->invoke= dupli_extrude_cursor; + ot->description= "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor."; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape"); +} + +static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *UNUSED(scene)) +{ + BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh; + + if(event<1) return OPERATOR_CANCELLED; + + if(event==10 ) { + //"Erase Vertices"; + + if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS)) + return OPERATOR_CANCELLED; + } + else if(event==11) { + //"Edge Loop" + if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT)) + return OPERATOR_CANCELLED; + } + else if(event==7) { + //"Dissolve" + if (bem->selectmode & SCE_SELECT_FACE) { + if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT)) + return OPERATOR_CANCELLED; + } else if (bem->selectmode & SCE_SELECT_EDGE) { + if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT)) + return OPERATOR_CANCELLED; + } else if (bem->selectmode & SCE_SELECT_VERTEX) { + if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT)) + return OPERATOR_CANCELLED; + } + } + else if(event==4) { + //Edges and Faces + if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES)) + return OPERATOR_CANCELLED; + } + else if(event==1) { + //"Erase Edges" + if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES)) + return OPERATOR_CANCELLED; + } + else if(event==2) { + //"Erase Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES)) + return OPERATOR_CANCELLED; + } + else if(event==5) { + //"Erase Only Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d", + BM_SELECT, DEL_ONLYFACES)) + return OPERATOR_CANCELLED; + } + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +/* Note, these values must match delete_mesh() event values */ +static EnumPropertyItem prop_mesh_delete_types[] = { + {7, "DISSOLVE", 0, "Dissolve", ""}, + {12, "COLLAPSE", 0, "Collapse", ""}, + {10,"VERT", 0, "Vertices", ""}, + {1, "EDGE", 0, "Edges", ""}, + {2, "FACE", 0, "Faces", ""}, + {11, "EDGE_LOOP", 0, "Edge Loop", ""}, + {4, "EDGE_FACE", 0, "Edges & Faces", ""}, + {5, "ONLY_FACE", 0, "Only Faces", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int delete_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + Scene *scene = CTX_data_scene(C); + int type = RNA_enum_get(op->ptr, "type"); + + if (type != 12) { + delete_mesh(C, obedit, op, type, scene); + } else { + if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT)) + return OPERATOR_CANCELLED; + } + + + WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +void MESH_OT_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Delete"; + ot->description= "Delete selected vertices, edges or faces."; + ot->idname= "MESH_OT_delete"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= delete_mesh_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /*props */ + ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data"); +} + + +static int addedgeface_mesh_exec(bContext *C, wmOperator *op) +{ + BMOperator bmop; + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT)) + return OPERATOR_CANCELLED; + + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + + return OPERATOR_FINISHED; +} + +void MESH_OT_edge_face_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Make Edge/Face"; + ot->description= "Add an edge or face to selected."; + ot->idname= "MESH_OT_edge_face_add"; + + /* api callbacks */ + ot->exec= addedgeface_mesh_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + +} + +static EnumPropertyItem prop_mesh_edit_types[] = { + {1, "VERT", 0, "Vertices", ""}, + {2, "EDGE", 0, "Edges", ""}, + {3, "FACE", 0, "Faces", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static int mesh_selection_type_exec(bContext *C, wmOperator *op) +{ + + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int type = RNA_enum_get(op->ptr,"type"); + + switch (type) { + case 1: + em->selectmode = SCE_SELECT_VERTEX; + break; + case 2: + em->selectmode = SCE_SELECT_EDGE; + break; + case 3: + em->selectmode = SCE_SELECT_FACE; + break; + } + + EDBM_selectmode_set(em); + CTX_data_tool_settings(C)->selectmode = em->selectmode; + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; +} + +static void MESH_OT_selection_type(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Selection Mode"; + ot->description= "Set the selection mode type."; + ot->idname= "MESH_OT_selection_type"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= mesh_selection_type_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type"); + RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode"); +} + +/* ************************* SEAMS AND EDGES **************** */ + +static int editbmesh_mark_seam(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Mesh *me= ((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMEdge *eed; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + /* auto-enable seams drawing */ + if(clear==0) { + me->drawflag |= ME_DRAWSEAMS; + } + + if(clear) { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN)) + continue; + + BM_ClearHFlag(eed, BM_SEAM); + } + } + else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN)) + continue; + BM_SetHFlag(eed, BM_SEAM); + } + } + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_mark_seam(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Seam"; + ot->idname= "MESH_OT_mark_seam"; + ot->description= "(un)mark selected edges as a seam."; + + /* api callbacks */ + ot->exec= editbmesh_mark_seam; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} + +static int editbmesh_mark_sharp(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Mesh *me= ((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMEdge *eed; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + /* auto-enable sharp edge drawing */ + if(clear == 0) { + me->drawflag |= ME_DRAWSHARP; + } + + if(!clear) { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN)) + continue; + + BM_SetHFlag(eed, BM_SHARP); + } + } else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(eed, BM_SELECT) || BM_TestHFlag(eed, BM_HIDDEN)) + continue; + + BM_ClearHFlag(eed, BM_SHARP); + } + } + + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_mark_sharp(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Sharp"; + ot->idname= "MESH_OT_mark_sharp"; + ot->description= "(un)mark selected edges as sharp."; + + /* api callbacks */ + ot->exec= editbmesh_mark_sharp; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} + + +static int editbmesh_vert_connect(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMOperator bmop; + int len = 0; + + BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT); + BMO_Exec_Op(bm, &bmop); + len = BMO_GetSlot(&bmop, "edgeout")->len; + BMO_Finish_Op(bm, &bmop); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void MESH_OT_vert_connect(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Vertex Connect"; + ot->idname= "MESH_OT_vert_connect"; + + /* api callbacks */ + ot->exec= editbmesh_vert_connect; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int editbmesh_edge_split(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMOperator bmop; + int len = 0; + + BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts")); + BMO_Exec_Op(bm, &bmop); + len = BMO_GetSlot(&bmop, "outsplit")->len; + BMO_Finish_Op(bm, &bmop); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void MESH_OT_edge_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Edge Split"; + ot->idname= "MESH_OT_edge_split"; + + /* api callbacks */ + ot->exec= editbmesh_edge_split; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX); +} + +/****************** add duplicate operator ***************/ + +static int mesh_duplicate_exec(bContext *C, wmOperator *op) +{ + Object *ob= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT); + + BMO_Exec_Op(em->bm, &bmop); + EDBM_clear_flag_all(em, BM_SELECT); + + BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + WM_cursor_wait(1); + mesh_duplicate_exec(C, op); + WM_cursor_wait(0); + + return OPERATOR_FINISHED; +} + +void MESH_OT_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Duplicate"; + ot->description= "Duplicate selected vertices, edges or faces."; + ot->idname= "MESH_OT_duplicate"; + + /* api callbacks */ + ot->invoke= mesh_duplicate_invoke; + ot->exec= mesh_duplicate_exec; + + ot->poll= ED_operator_editmesh; + + /* to give to transform */ + RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); +} + +static int flip_normals(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + + if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_flip_normals(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Flip Normals"; + ot->description= "Flip the direction of selected face's vertex and face normals"; + ot->idname= "MESH_OT_flip_normals"; + + /* api callbacks */ + ot->exec= flip_normals; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +float *bm_get_cd_float(CustomData *cdata, void *data, int type) +{ + float *f = CustomData_bmesh_get(cdata, data, type); + + return f; +} + +static const EnumPropertyItem direction_items[]= { + {DIRECTION_CW, "CW", 0, "Clockwise", ""}, + {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""}, + {0, NULL, 0, NULL, NULL}}; + +/* only accepts 1 selected edge, or 2 selected faces */ +static int edge_rotate_selected(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMOperator bmop; + BMEdge *eed; + BMIter iter; + int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW. + + if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) { + BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces"); + return OPERATOR_CANCELLED; + } + + /*first see if we have two adjacent faces*/ + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_Edge_FaceCount(eed) == 2) { + if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_SELECT)) + && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_HIDDEN))) + { + break; + } + } + } + + /*ok, we don't have two adjacent faces, but we do have two selected ones. + that's an error condition.*/ + if (!eed && em->bm->totfacesel == 2) { + BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces"); + return OPERATOR_CANCELLED; + } + + if (!eed) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_SELECT) && !BM_TestHFlag(eed, BM_HIDDEN)) + break; + } + } + + /*this should never happen*/ + if (!eed) + return OPERATOR_CANCELLED; + + EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw); + BMO_Exec_Op(em->bm, &bmop); + + BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_edge_rotate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Rotate Selected Edge"; + ot->description= "Rotate selected edge or adjoining faces."; + ot->idname= "MESH_OT_edge_rotate"; + + /* api callbacks */ + ot->exec= edge_rotate_selected; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around."); +} + +/* swap is 0 or 1, if 1 it hides not selected */ +void EDBM_hide_mesh(BMEditMesh *em, int swap) +{ + BMIter iter; + BMHeader *h; + int itermode; + + if(em==NULL) return; + + if (em->selectmode & SCE_SELECT_VERTEX) + itermode = BM_VERTS_OF_MESH; + else if (em->selectmode & SCE_SELECT_EDGE) + itermode = BM_EDGES_OF_MESH; + else + itermode = BM_FACES_OF_MESH; + + BM_ITER(h, &iter, em->bm, itermode, NULL) { + if (BM_TestHFlag(h, BM_SELECT) ^ swap) + BM_Hide(em->bm, h, 1); + } + + /*original hide flushing comment (OUTDATED): + hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */ + /* - vertex hidden, always means edge is hidden too + - edge hidden, always means face is hidden too + - face hidden, only set face hide + - then only flush back down what's absolute hidden + */ + +} + +static int hide_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + + EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected")); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_hide(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Hide Selection"; + ot->idname= "MESH_OT_hide"; + + /* api callbacks */ + ot->exec= hide_mesh_exec; + ot->poll= ED_operator_editmesh; + ot->description= "Hide (un)selected vertices, edges or faces."; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected."); +} + + +void EDBM_reveal_mesh(BMEditMesh *em) +{ + BMIter iter; + BMHeader *ele; + int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))}; + + for (i=0; i<3; i++) { + BM_ITER(ele, &iter, em->bm, types[i], NULL) { + if (BM_TestHFlag(ele, BM_HIDDEN)) { + BM_Hide(em->bm, ele, 0); + + if (sels[i]) + BM_Select(em->bm, ele, 1); + } + } + } + + EDBM_selectmode_flush(em); +} + +static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + + EDBM_reveal_mesh(em); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_reveal(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Reveal Hidden"; + ot->idname= "MESH_OT_reveal"; + ot->description= "Reveal all hidden vertices, edges and faces."; + + /* api callbacks */ + ot->exec= reveal_mesh_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int normals_make_consistent_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + /*doflip has to do with bmesh_rationalize_normals, it's an internal + thing*/ + if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_SELECT, 1)) + return OPERATOR_CANCELLED; + + if (RNA_boolean_get(op->ptr, "inside")) + EDBM_CallOpf(em, op, "reversefaces faces=%hf doflip=%d", BM_SELECT, 1); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_normals_make_consistent(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Make Normals Consistent"; + ot->description= "Make face and vertex normals point either outside or inside the mesh"; + ot->idname= "MESH_OT_normals_make_consistent"; + + /* api callbacks */ + ot->exec= normals_make_consistent_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "inside", 0, "Inside", ""); +} + + + +static int do_smooth_vertex(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + ModifierData *md; + int mirrx=0, mirry=0, mirrz=0; + int i, repeat; + + /* if there is a mirror modifier with clipping, flag the verts that + * are within tolerance of the plane(s) of reflection + */ + for(md=obedit->modifiers.first; md; md=md->next) { + if(md->type==eModifierType_Mirror) { + MirrorModifierData *mmd = (MirrorModifierData*) md; + + if(mmd->flag & MOD_MIR_CLIPPING) { + if (mmd->flag & MOD_MIR_AXIS_X) + mirrx = 1; + if (mmd->flag & MOD_MIR_AXIS_Y) + mirry = 1; + if (mmd->flag & MOD_MIR_AXIS_Z) + mirrz = 1; + } + } + } + + repeat = RNA_int_get(op->ptr,"repeat"); + if (!repeat) + repeat = 1; + + for (i=0; i<repeat; i++) { + if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d", + BM_SELECT, mirrx, mirry, mirrz)) + { + return OPERATOR_CANCELLED; + } + } + + //BMESH_TODO: need to handle the x-axis editing option here properly. + //should probably make a helper function for that? I dunno. + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_vertices_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Smooth Vertex"; + ot->description= "Flatten angles of selected vertices."; + ot->idname= "MESH_OT_vertices_smooth"; + + /* api callbacks */ + ot->exec= do_smooth_vertex; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX); +} + + +static int bm_test_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + ARegion *ar = CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMBVHTree *tree = BMBVH_NewBVH(em); + BMIter iter; + BMEdge *e; + + /*hide all back edges*/ + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_TestHFlag(e, BM_SELECT)) + continue; + + if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit)) + BM_Select(em->bm, e, 0); + } + + BMBVH_FreeBVH(tree); + +#if 0 //uv island walker test + BMIter iter, liter; + BMFace *f; + BMLoop *l, *l2; + MLoopUV *luv; + BMWalker walker; + int i=0; + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + } + } + + BMW_Init(&walker, em->bm, BMW_UVISLAND, 0); + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (luv->flag & MLOOPUV_VERTSEL) { + l2 = BMW_Begin(&walker, l); + for (; l2; l2=BMW_Step(&walker)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + } + } + } + + BMW_End(&walker); +#endif + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_bm_test(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "BMesh Test Operator"; + ot->idname= "MESH_OT_bm_test"; + + /* api callbacks */ + ot->exec= bm_test_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX); +} + +/********************** Smooth/Solid Operators *************************/ + +static void mesh_set_smooth_faces(BMEditMesh *em, short smooth) +{ + BMIter iter; + BMFace *efa; + + if(em==NULL) return; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_TestHFlag(efa, BM_SELECT)) { + if (smooth) + BM_SetHFlag(efa, BM_SMOOTH); + else + BM_ClearHFlag(efa, BM_SMOOTH); + } + } +} + +static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + mesh_set_smooth_faces(em, 1); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_faces_shade_smooth(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Shade Smooth"; + ot->description= "Display faces smooth (using vertex normals)."; + ot->idname= "MESH_OT_faces_shade_smooth"; + + /* api callbacks */ + ot->exec= mesh_faces_shade_smooth_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + mesh_set_smooth_faces(em, 0); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_faces_shade_flat(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Shade Flat"; + ot->description= "Display faces flat."; + ot->idname= "MESH_OT_faces_shade_flat"; + + /* api callbacks */ + ot->exec= mesh_faces_shade_flat_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +/********************** UV/Color Operators *************************/ + + +static const EnumPropertyItem axis_items[]= { + {OPUVC_AXIS_X, "X", 0, "X", ""}, + {OPUVC_AXIS_Y, "Y", 0, "Y", ""}, + {0, NULL, 0, NULL, NULL}}; + +static int mesh_rotate_uvs(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* get the direction from RNA */ + int dir = RNA_enum_get(op->ptr, "direction"); + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); +/* DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); +*/ + /* we succeeded */ + return OPERATOR_FINISHED; +} + +static int mesh_reverse_uvs(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); +/* DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); +*/ + /* we succeeded */ + return OPERATOR_FINISHED; +} + +static int mesh_rotate_colors(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* get the direction from RNA */ + int dir = RNA_enum_get(op->ptr, "direction"); + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + + /* dependencies graph and notification stuff */ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); +/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob); +*/ + /* we succeeded */ + return OPERATOR_FINISHED; +} + + +static int mesh_reverse_colors(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); + + /* we succeeded */ + return OPERATOR_FINISHED; +#if 0 + Scene *scene= CTX_data_scene(C); + Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + + EditFace *efa; + short change = 0; + MCol tmpcol, *mcol; + int axis= RNA_enum_get(op->ptr, "axis"); + + if (!EM_vertColorCheck(em)) { + BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers"); + BKE_mesh_end_editmesh(obedit->data, em); + return OPERATOR_CANCELLED; + } + + for(efa=em->faces.first; efa; efa=efa->next) { + if (efa->f & SELECT) { + mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + if (axis == AXIS_Y) { + tmpcol= mcol[1]; + mcol[1]= mcol[2]; + mcol[2]= tmpcol; + + if(efa->v4) { + tmpcol= mcol[0]; + mcol[0]= mcol[3]; + mcol[3]= tmpcol; + } + } else { + tmpcol= mcol[0]; + mcol[0]= mcol[1]; + mcol[1]= tmpcol; + + if(efa->v4) { + tmpcol= mcol[2]; + mcol[2]= mcol[3]; + mcol[3]= tmpcol; + } + } + change = 1; + } + } + + BKE_mesh_end_editmesh(obedit->data, em); + + if(!change) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + +#endif + return OPERATOR_FINISHED; +} + +void MESH_OT_uvs_rotate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Rotate UVs"; + ot->idname= "MESH_OT_uvs_rotate"; + + /* api callbacks */ + ot->exec= mesh_rotate_uvs; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around."); +} + +//void MESH_OT_uvs_mirror(wmOperatorType *ot) +void MESH_OT_uvs_reverse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Reverse UVs"; + ot->idname= "MESH_OT_uvs_reverse"; + + /* api callbacks */ + ot->exec= mesh_reverse_uvs; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around."); +} + +void MESH_OT_colors_rotate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Rotate Colors"; + ot->idname= "MESH_OT_colors_rotate"; + + /* api callbacks */ + ot->exec= mesh_rotate_colors; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around."); +} + +void MESH_OT_colors_reverse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Reverse Colors"; + ot->idname= "MESH_OT_colors_reverse"; + + /* api callbacks */ + ot->exec= mesh_reverse_colors; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around."); +} + + +static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop) +{ + BMVert *mergevert; + BMEditSelection *ese; + + /* do sanity check in mergemenu in edit.c ?*/ + if(first == 0){ + ese = em->bm->selected.last; + mergevert= (BMVert*)ese->data; + } + else{ + ese = em->bm->selected.first; + mergevert = (BMVert*)ese->data; + } + + if (!BM_TestHFlag(mergevert, BM_SELECT)) + return OPERATOR_CANCELLED; + + if (uvmerge) { + if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert)) + return OPERATOR_CANCELLED; + } + + if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co)) + return OPERATOR_CANCELLED; + + return OPERATOR_FINISHED; +} + +static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob, + int target, int uvmerge, wmOperator *wmop) +{ + BMIter iter; + BMVert *v; + float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f}, fac; + int i; + + if (target) { + vco = give_cursor(scene, v3d); + VECCOPY(co, vco); + mul_m4_v3(ob->imat, co); + } else { + i = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(v, BM_SELECT)) + continue; + VECADD(cent, cent, v->co); + i++; + } + + if (!i) + return OPERATOR_CANCELLED; + + fac = 1.0f / (float)i; + mul_v3_fl(cent, fac); + copy_v3_v3(co, cent); + vco = co; + } + + if (!vco) + return OPERATOR_CANCELLED; + + if (uvmerge) { + if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT)) + return OPERATOR_CANCELLED; + } + + if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co)) + return OPERATOR_CANCELLED; + + return OPERATOR_FINISHED; +} + +static int merge_exec(bContext *C, wmOperator *op) +{ + Scene *scene= CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs"); + + switch(RNA_enum_get(op->ptr, "type")) { + case 3: + status = merge_target(em, scene, v3d, obedit, 0, uvs, op); + break; + case 4: + status = merge_target(em, scene, v3d, obedit, 1, uvs, op); + break; + case 1: + status = merge_firstlast(em, 0, uvs, op); + break; + case 6: + status = merge_firstlast(em, 1, uvs, op); + break; + case 5: + status = 1; + if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT)) + status = 0; + break; + } + + if(!status) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +static EnumPropertyItem merge_type_items[]= { + {6, "FIRST", 0, "At First", ""}, + {1, "LAST", 0, "At Last", ""}, + {3, "CENTER", 0, "At Center", ""}, + {4, "CURSOR", 0, "At Cursor", ""}, + {5, "COLLAPSE", 0, "Collapse", ""}, + {0, NULL, 0, NULL, NULL}}; + +static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +{ + Object *obedit; + EnumPropertyItem *item= NULL; + int totitem= 0; + + if(!C) /* needed for docs */ + return merge_type_items; + + obedit= CTX_data_edit_object(C); + if(obedit && obedit->type == OB_MESH) { + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + + if(em->selectmode & SCE_SELECT_VERTEX) { + if(em->bm->selected.first && em->bm->selected.last && + ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) { + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); + } + else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT) + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); + else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); + } + + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4); + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5); + RNA_enum_item_end(&item, &totitem); + + *free= 1; + + return item; + } + + return NULL; +} + +void MESH_OT_merge(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Merge"; + ot->idname= "MESH_OT_merge"; + + /* api callbacks */ + ot->exec= merge_exec; + ot->invoke= WM_menu_invoke; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + ot->prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use."); + RNA_def_enum_funcs(ot->prop, merge_type_itemf); + RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge."); +} + + +static int removedoublesflag_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMOperator bmop; + int count; + + EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f", + BM_SELECT, RNA_float_get(op->ptr, "mergedist")); + BMO_Exec_Op(em->bm, &bmop); + + count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout"); + + if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) { + BMO_Finish_Op(em->bm, &bmop); + return OPERATOR_CANCELLED; + } + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + /*we need a better way of reporting this, since this doesn't work + with the last operator panel correctly. + if(count) + { + sprintf(msg, "Removed %d vertices", count); + BKE_report(op->reports, RPT_INFO, msg); + } + */ + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_remove_doubles(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Remove Doubles"; + ot->idname= "MESH_OT_remove_doubles"; + + /* api callbacks */ + ot->exec= removedoublesflag_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f, + "Merge Distance", + "Minimum distance between elements to merge.", 0.00001, 10.0); +} + +/************************ Vertex Path Operator *************************/ + +typedef struct PathNode { + int u; + int visited; + ListBase edges; +} PathNode; + +typedef struct PathEdge { + struct PathEdge *next, *prev; + int v; + float w; +} PathEdge; + + + +static int select_vertex_path_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMOperator bmop; + BMEditSelection *sv, *ev; + + /* get the type from RNA */ + int type = RNA_enum_get(op->ptr, "type"); + + sv = em->bm->selected.last; + if( sv != NULL ) + ev = sv->prev; + else return OPERATOR_CANCELLED; + if( ev == NULL ) + return OPERATOR_CANCELLED; + + if( sv->type != BM_VERT || ev->type != BM_VERT ) + return OPERATOR_CANCELLED; + + /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */ + EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type); + + /* execute the operator */ + BMO_Exec_Op(em->bm, &bmop); + + /* DO NOT clear the existing selection */ + /* EDBM_clear_flag_all(em, BM_SELECT); */ + + /* select the output */ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL); + + /* finish the operator */ + if( !EDBM_FinishOp(em, &bmop, op, 1) ) + return OPERATOR_CANCELLED; + + EDBM_selectmode_flush(em); + + /* dependencies graph and notification stuff */ +/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob); +*/ + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); + + + /* we succeeded */ + return OPERATOR_FINISHED; +#if 0 + Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + EditVert *eve, *s, *t; + EditEdge *eed; + EditSelection *ese; + PathEdge *newpe, *currpe; + PathNode *currpn; + PathNode *Q; + int v, *previous, pathvert, pnindex; /*pnindex redundant?*/ + int unbalanced, totnodes; + short physical; + float *cost; + Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/ + + s = t = NULL; + + ese = ((EditSelection*)em->selected.last); + if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){ + physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0"); + + t = (EditVert*)ese->data; + s = (EditVert*)ese->prev->data; + + /*need to find out if t is actually reachable by s....*/ + for(eve=em->verts.first; eve; eve=eve->next){ + eve->f1 = 0; + } + + s->f1 = 1; + + unbalanced = 1; + totnodes = 1; + while(unbalanced){ + unbalanced = 0; + for(eed=em->edges.first; eed; eed=eed->next){ + if(!eed->h){ + if(eed->v1->f1 && !eed->v2->f1){ + eed->v2->f1 = 1; + totnodes++; + unbalanced = 1; + } + else if(eed->v2->f1 && !eed->v1->f1){ + eed->v1->f1 = 1; + totnodes++; + unbalanced = 1; + } + } + } + } + + if(s->f1 && t->f1){ /* t can be reached by s */ + Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes"); + totnodes = 0; + for(eve=em->verts.first; eve; eve=eve->next){ + if(eve->f1){ + Q[totnodes].u = totnodes; + Q[totnodes].edges.first = 0; + Q[totnodes].edges.last = 0; + Q[totnodes].visited = 0; + eve->tmp.p = &(Q[totnodes]); + totnodes++; + } + else eve->tmp.p = NULL; + } + + for(eed=em->edges.first; eed; eed=eed->next){ + if(!eed->h){ + if(eed->v1->f1){ + currpn = ((PathNode*)eed->v1->tmp.p); + + newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); + newpe->v = ((PathNode*)eed->v2->tmp.p)->u; + if(physical){ + newpe->w = len_v3v3(eed->v1->co, eed->v2->co); + } + else newpe->w = 1; + newpe->next = 0; + newpe->prev = 0; + BLI_addtail(&(currpn->edges), newpe); + } + if(eed->v2->f1){ + currpn = ((PathNode*)eed->v2->tmp.p); + newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); + newpe->v = ((PathNode*)eed->v1->tmp.p)->u; + if(physical){ + newpe->w = len_v3v3(eed->v1->co, eed->v2->co); + } + else newpe->w = 1; + newpe->next = 0; + newpe->prev = 0; + BLI_addtail(&(currpn->edges), newpe); + } + } + } + + heap = BLI_heap_new(); + cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs"); + previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices"); + + for(v=0; v < totnodes; v++){ + cost[v] = 1000000; + previous[v] = -1; /*array of indices*/ + } + + pnindex = ((PathNode*)s->tmp.p)->u; + cost[pnindex] = 0; + BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex)); + + while( !BLI_heap_empty(heap) ){ + + pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); + currpn = &(Q[pnindex]); + + if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/ + break; + + for(currpe=currpn->edges.first; currpe; currpe=currpe->next){ + if(!Q[currpe->v].visited){ + if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){ + cost[currpe->v] = cost[currpn->u] + currpe->w; + previous[currpe->v] = currpn->u; + Q[currpe->v].visited = 1; + BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v)); + } + } + } + } + + pathvert = ((PathNode*)t->tmp.p)->u; + while(pathvert != -1){ + for(eve=em->verts.first; eve; eve=eve->next){ + if(eve->f1){ + if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT; + } + } + pathvert = previous[pathvert]; + } + + for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges)); + MEM_freeN(Q); + MEM_freeN(cost); + MEM_freeN(previous); + BLI_heap_free(heap, NULL); + EM_select_flush(em); + } + } + else { + BKE_mesh_end_editmesh(obedit->data, em); + BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected"); + return OPERATOR_CANCELLED; + } + + WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); + BKE_mesh_end_editmesh(obedit->data, em); +#endif +} + +void MESH_OT_select_vertex_path(wmOperatorType *ot) +{ + static const EnumPropertyItem type_items[] = { + {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL}, + {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name= "Select Vertex Path"; + ot->idname= "MESH_OT_select_vertex_path"; + + /* api callbacks */ + ot->exec= select_vertex_path_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance."); +} +/********************** Rip Operator *************************/ + +/* helper to find edge for edge_rip */ +static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2]) +{ + float vec1[3], vec2[3], mvalf[2]; + + ED_view3d_project_float(ar, co1, vec1, mat); + ED_view3d_project_float(ar, co2, vec2, mat); + mvalf[0]= (float)mval[0]; + mvalf[1]= (float)mval[1]; + + return dist_to_line_segment_v2(mvalf, vec1, vec2); +} + +/* based on mouse cursor position, it defines how is being ripped */ +static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Object *obedit= CTX_data_edit_object(C); + ARegion *ar= CTX_wm_region(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d= CTX_wm_region_view3d(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMOperator bmop; + BMBVHTree *bvhtree; + BMOIter siter; + BMIter iter, eiter, liter; + BMLoop *l; + BMEdge *e, *e2, *closest = NULL; + BMVert *v; + int side = 0, i, singlesel = 0; + float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f}; + float dist = FLT_MAX, d; + + ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) + BM_SetIndex(e, 1); + else BM_SetIndex(e, 0); + } + + /*handle case of one vert selected. identify + closest edge around that vert to mouse cursor, + then rip two adjacent edges in the vert fan.*/ + if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) { + singlesel = 1; + + /*find selected vert*/ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT)) + break; + } + + /*this should be impossible, but sanity checks are a good thing*/ + if (!v) + return OPERATOR_CANCELLED; + + /*find closest edge to mouse cursor*/ + e2 = NULL; + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) { + d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval); + if (d < dist) { + dist = d; + e2 = e; + } + } + + if (!e2) + return OPERATOR_CANCELLED; + + /*rip two adjacent edges*/ + if (BM_Edge_FaceCount(e2) == 1) { + l = e2->l; + e = BM_OtherFaceLoop(e2, l->f, v)->e; + + BM_SetIndex(e, 1); + BM_SetHFlag(e, BM_SELECT); + } else if (BM_Edge_FaceCount(e2) == 2) { + l = e2->l; + e = BM_OtherFaceLoop(e2, l->f, v)->e; + BM_SetIndex(e, 1); + BM_SetHFlag(e, BM_SELECT); + + l = e2->l->radial_next; + e = BM_OtherFaceLoop(e2, l->f, v)->e; + BM_SetIndex(e, 1); + BM_SetHFlag(e, BM_SELECT); + } + + dist = FLT_MAX; + } else { + /*expand edge selection*/ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + e2 = NULL; + i = 0; + BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) { + if (BM_GetIndex(e)) { + e2 = e; + i++; + } + } + + if (i == 1 && e2->l) { + l = BM_OtherFaceLoop(e2, e2->l->f, v); + l = (BMLoop*)l->radial_next; + l = BM_OtherFaceLoop(l->e, l->f, v); + + if (l) + BM_Select(em->bm, l->e, 1); + } + } + } + + if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) { + return OPERATOR_CANCELLED; + } + + BMO_Exec_Op(em->bm, &bmop); + + /*build bvh tree for edge visibility tests*/ + bvhtree = BMBVH_NewBVH(em); + + for (i=0; i<2; i++) { + BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) { + float cent[3] = {0, 0, 0}, mid[4], vec[3]; + + if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l) + continue; + + /*method for calculating distance: + + for each edge: calculate face center, then made a vector + from edge midpoint to face center. offset edge midpoint + by a small amount along this vector.*/ + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) { + add_v3_v3v3(cent, cent, l->v->co); + } + mul_v3_fl(cent, 1.0f/(float)e->l->f->len); + + add_v3_v3v3(mid, e->v1->co, e->v2->co); + mul_v3_fl(mid, 0.5f); + sub_v3_v3v3(vec, cent, mid); + normalize_v3(vec); + mul_v3_fl(vec, 0.01f); + add_v3_v3v3(mid, mid, vec); + + /*yay we have our comparison point, now project it*/ + ED_view3d_project_float(ar, mid, mid, projectMat); + + vec[0] = fmval[0] - mid[0]; + vec[1] = fmval[1] - mid[1]; + d = vec[0]*vec[0] + vec[1]*vec[1]; + + if (d < dist) { + side = i; + closest = e; + dist = d; + } + } + } + + EDBM_clear_flag_all(em, BM_SELECT); + BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) + BM_SetIndex(e, 1); + else BM_SetIndex(e, 0); + } + + /*constrict edge selection again*/ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + e2 = NULL; + i = 0; + BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) { + if (BM_GetIndex(e)) { + e2 = e; + i++; + } + } + + if (i == 1) { + if (singlesel) + BM_Select(em->bm, v, 0); + else + BM_Select(em->bm, e2, 0); + } + } + + EDBM_selectmode_flush(em); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) { + BMBVH_FreeBVH(bvhtree); + return OPERATOR_CANCELLED; + } + + BMBVH_FreeBVH(bvhtree); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_rip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Rip"; + ot->idname= "MESH_OT_rip"; + + /* api callbacks */ + ot->invoke= mesh_rip_invoke; + ot->poll= EM_view3d_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* to give to transform */ + Transform_Properties(ot, P_PROPORTIONAL); + RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", ""); +} + +/************************ Shape Operators *************************/ + +/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ +static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op) +{ + BMIter iter; + BMVert *eve = NULL; + float *co; + int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY); + + if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { + BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys"); + return; + } + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN)) + continue; + + for (i=0; i<totshape; i++) { + co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i); + VECCOPY(co, eve->co); + } + } + +#if 0 + //TAG Mesh Objects that share this data + for(base = scene->base.first; base; base = base->next){ + if(base->object && base->object->data == me){ + base->object->recalc = OB_RECALC_DATA; + } + } +#endif + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); +} + + +static int shape_propagate_to_all_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Mesh *me= obedit->data; + BMEditMesh *em= me->edit_btmesh; + + shape_propagate(obedit, em, op); + + DAG_id_tag_update(&me->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); + + return OPERATOR_FINISHED; +} + + +void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Shape Propagate"; + ot->description= "Apply selected vertex locations to all other shape keys."; + ot->idname= "MESH_OT_shape_propagate_to_all"; + + /* api callbacks */ + ot->exec= shape_propagate_to_all_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/ +static int blend_from_shape_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + Mesh *me= obedit->data; + BMEditMesh *em= me->edit_btmesh; + BMVert *eve; + BMIter iter; + float co[3], *sco; + float blend= RNA_float_get(op->ptr, "blend"); + int shape= RNA_enum_get(op->ptr, "shape"); + int add= RNA_int_get(op->ptr, "add"); + int totshape; + + /*sanity check*/ + totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY); + if (totshape == 0 || shape < 0 || shape >= totshape) + return OPERATOR_CANCELLED; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN)) + continue; + + sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape); + VECCOPY(co, sco); + + + if(add) { + mul_v3_fl(co, blend); + add_v3_v3v3(eve->co, eve->co, co); + } + else + interp_v3_v3v3(eve->co, eve->co, co, blend); + + VECCOPY(sco, co); + } + + DAG_id_tag_update(&me->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); + + return OPERATOR_FINISHED; +} + +static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) +{ + Object *obedit= CTX_data_edit_object(C); + Mesh *me= (obedit) ? obedit->data : NULL; + BMEditMesh *em = me->edit_btmesh; + EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL; + int totitem= 0, a; + + if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { + for (a=0; a<em->bm->vdata.totlayer; a++) { + if (em->bm->vdata.layers[a].type != CD_SHAPEKEY) + continue; + + tmp.value= totitem; + tmp.identifier= em->bm->vdata.layers[a].name; + tmp.name= em->bm->vdata.layers[a].name; + RNA_enum_item_add(&item, &totitem, &tmp); + + totitem++; + } + } + + RNA_enum_item_end(&item, &totitem); + *free= 1; + + return item; +} + +void MESH_OT_blend_from_shape(wmOperatorType *ot) +{ + PropertyRNA *prop; + static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name= "Blend From Shape"; + ot->description= "Blend in shape from a shape key."; + ot->idname= "MESH_OT_blend_from_shape"; + + /* api callbacks */ + ot->exec= blend_from_shape_exec; + ot->invoke= WM_operator_props_popup; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending."); + RNA_def_enum_funcs(prop, shape_itemf); + RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f); + RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes."); +} + +/* TODO - some way to select on an arbitrary axis */ +static int select_axis_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMEditSelection *ese = em->bm->selected.last; + int axis= RNA_int_get(op->ptr, "axis"); + int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/ + + if(ese==NULL) + return OPERATOR_CANCELLED; + + if(ese->type==BM_VERT) { + BMVert *ev, *act_vert= (BMVert*)ese->data; + BMIter iter; + float value= act_vert->co[axis]; + float limit= CTX_data_tool_settings(C)->doublimit; // XXX + + if(mode==0) + value -= limit; + else if (mode==1) + value += limit; + + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_TestHFlag(ev, BM_HIDDEN)) { + switch(mode) { + case -1: /* aligned */ + if(fabs(ev->co[axis] - value) < limit) + BM_Select(em->bm, ev, 1); + break; + case 0: /* neg */ + if(ev->co[axis] > value) + BM_Select(em->bm, ev, 1); + break; + case 1: /* pos */ + if(ev->co[axis] < value) + BM_Select(em->bm, ev, 1); + break; + } + } + } + } + + EDBM_selectmode_flush(em); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_select_axis(wmOperatorType *ot) +{ + static EnumPropertyItem axis_mode_items[] = { + {0, "POSITIVE", 0, "Positive Axis", ""}, + {1, "NEGATIVE", 0, "Negative Axis", ""}, + {-1, "ALIGNED", 0, "Aligned Axis", ""}, + {0, NULL, 0, NULL, NULL}}; + + /* identifiers */ + ot->name= "Select Axis"; + ot->description= "Select all data in the mesh on a single axis."; + ot->idname= "MESH_OT_select_axis"; + + /* api callbacks */ + ot->exec= select_axis_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting"); + RNA_def_int(ot->srna, "axis", 0, 0, 2, "Axis", "Select the axis to compare each vertex on", 0, 2); +} + +static int solidify_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ +#if 0 + Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); + float nor[3] = {0,0,1}; + + float thickness= RNA_float_get(op->ptr, "thickness"); + + extrudeflag(obedit, em, SELECT, nor, 1); + EM_make_hq_normals(em); + EM_solidify(em, thickness); + + + /* update vertex normals too */ + recalc_editnormals(em); + + BKE_mesh_end_editmesh(obedit->data, em); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +#endif + return OPERATOR_CANCELLED; +} + + +void MESH_OT_solidify(wmOperatorType *ot) +{ + PropertyRNA *prop; + /* identifiers */ + ot->name= "Solidify"; + ot->description= "Create a solid skin by extruding, compensating for sharp angles."; + ot->idname= "MESH_OT_solidify"; + + /* api callbacks */ + ot->exec= solidify_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f); + RNA_def_property_ui_range(prop, -10, 10, 0.1, 4); +} + +#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */ +#define TRAIL_FREEHAND 2 +#define TRAIL_MIXED 3 /* (1|2) */ +#define TRAIL_AUTO 4 +#define TRAIL_MIDPOINTS 8 + +typedef struct CutCurve { + float x; + float y; +} CutCurve; + +/* ******************************************************************** */ +/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail + drawn by user. + + Currently mapped to KKey when in MeshEdit mode. + Usage: + Hit Shift K, Select Centers or Exact + Hold LMB down to draw path, hit RETKEY. + ESC cancels as expected. + + Contributed by Robert Wenzlaff (Det. Thorn). + + 2.5 revamp: + - non modal (no menu before cutting) + - exit on mouse release + - polygon/segment drawing can become handled by WM cb later + + bmesh port version +*/ + +#define KNIFE_EXACT 1 +#define KNIFE_MIDPOINT 2 +#define KNIFE_MULTICUT 3 + +static EnumPropertyItem knife_items[]= { + {KNIFE_EXACT, "EXACT", 0, "Exact", ""}, + {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""}, + {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""}, + {0, NULL, 0, NULL, NULL} +}; + +/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */ + +static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode, + struct GHash *gh, int *isected) +{ +#define MAXSLOPE 100000 + float x11, y11, x12=0, y12=0, x2max, x2min, y2max; + float y2min, dist, lastdist=0, xdiff2, xdiff1; + float m1, b1, m2, b2, x21, x22, y21, y22, xi; + float yi, x1min, x1max, y1max, y1min, perc=0; + float *scr; + float threshold = 0.0; + int i; + + //threshold = 0.000001; /*tolerance for vertex intersection*/ + // XXX threshold = scene->toolsettings->select_thresh / 100; + + /* Get screen coords of verts */ + scr = BLI_ghash_lookup(gh, e->v1); + x21=scr[0]; + y21=scr[1]; + + scr = BLI_ghash_lookup(gh, e->v2); + x22=scr[0]; + y22=scr[1]; + + xdiff2=(x22-x21); + if (xdiff2) { + m2=(y22-y21)/xdiff2; + b2= ((x22*y21)-(x21*y22))/xdiff2; + } + else { + m2=MAXSLOPE; /* Verticle slope */ + b2=x22; + } + + *isected = 0; + + /*check for *exact* vertex intersection first*/ + if(mode!=KNIFE_MULTICUT){ + for (i=0; i<len; i++){ + if (i>0){ + x11=x12; + y11=y12; + } + else { + x11=c[i].x; + y11=c[i].y; + } + x12=c[i].x; + y12=c[i].y; + + /*test e->v1*/ + if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){ + perc = 0; + *isected = 1; + return(perc); + } + /*test e->v2*/ + else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){ + perc = 0; + *isected = 2; + return(perc); + } + } + } + + /*now check for edge interesect (may produce vertex intersection as well)*/ + for (i=0; i<len; i++){ + if (i>0){ + x11=x12; + y11=y12; + } + else { + x11=c[i].x; + y11=c[i].y; + } + x12=c[i].x; + y12=c[i].y; + + /* Perp. Distance from point to line */ + if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */ + /* change in sign. Skip extra math */ + else dist=x22-x12; + + if (i==0) lastdist=dist; + + /* if dist changes sign, and intersect point in edge's Bound Box*/ + if ((lastdist*dist)<=0){ + xdiff1=(x12-x11); /* Equation of line between last 2 points */ + if (xdiff1){ + m1=(y12-y11)/xdiff1; + b1= ((x12*y11)-(x11*y12))/xdiff1; + } + else{ + m1=MAXSLOPE; + b1=x12; + } + x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */ + x2min=MIN2(x21,x22)-0.001; /* due to round off error */ + y2max=MAX2(y21,y22)+0.001; + y2min=MIN2(y21,y22)-0.001; + + /* Found an intersect, calc intersect point */ + if (m1==m2){ /* co-incident lines */ + /* cut at 50% of overlap area*/ + x1max=MAX2(x11, x12); + x1min=MIN2(x11, x12); + xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0; + + y1max=MAX2(y11, y12); + y1min=MIN2(y11, y12); + yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0; + } + else if (m2==MAXSLOPE){ + xi=x22; + yi=m1*x22+b1; + } + else if (m1==MAXSLOPE){ + xi=x12; + yi=m2*x12+b2; + } + else { + xi=(b1-b2)/(m2-m1); + yi=(b1*m2-m1*b2)/(m2-m1); + } + + /* Intersect inside bounding box of edge?*/ + if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){ + /*test for vertex intersect that may be 'close enough'*/ + if(mode!=KNIFE_MULTICUT){ + if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){ + if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){ + *isected = 1; + perc = 0; + break; + } + } + if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){ + if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){ + *isected = 2; + perc = 0; + break; + } + } + } + if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21); + else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/ + //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */ + + break; + } + } + lastdist=dist; + } + return(perc); +} + +#define MAX_CUTS 2048 + +static int knife_cut_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMesh *bm = em->bm; + ARegion *ar= CTX_wm_region(C); + BMVert *bv; + BMIter iter; + BMEdge *be; + BMOperator bmop; + CutCurve curve[MAX_CUTS]; + struct GHash *gh; + float isect=0.0; + float *scr, co[4]; + int len=0, isected, i; + short numcuts=1, mode= RNA_int_get(op->ptr, "type"); + + /* edit-object needed for matrix, and ar->regiondata for projections to work */ + if (ELEM3(NULL, obedit, ar, ar->regiondata)) + return OPERATOR_CANCELLED; + + if (bm->totvertsel < 2) { + //error("No edges are selected to operate on"); + return OPERATOR_CANCELLED;; + } + + /* get the cut curve */ + RNA_BEGIN(op->ptr, itemptr, "path") { + + RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]); + len++; + if(len>= MAX_CUTS) break; + } + RNA_END; + + if(len<2) { + return OPERATOR_CANCELLED; + } + + /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/ + gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife cut exec"); + for(bv=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);bv;bv=BMIter_Step(&iter)){ + scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates"); + VECCOPY(co, bv->co); + co[3]= 1.0; + mul_m4_v4(obedit->obmat, co); + project_float(ar, co, scr); + BLI_ghash_insert(gh, bv, scr); + } + + BMO_Init_Op(&bmop, "esubd"); + + i = 0; + /*store percentage of edge cut for KNIFE_EXACT here.*/ + for (be=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be=BMIter_Step(&iter)) { + if( BM_Selected(bm, be) ) { + isect= bm_seg_intersect(be, curve, len, mode, gh, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_Insert_MapFloat(bm, &bmop, + "edgepercents", + be, isect); + + } + BMO_SetFlag(bm, be, 1); + } else BMO_ClearFlag(bm, be, 1); + } else BMO_ClearFlag(bm, be, 1); + } + + BMO_Flag_To_Slot(bm, &bmop, "edges", 1, BM_EDGE); + + if (mode == KNIFE_MIDPOINT) numcuts = 1; + BMO_Set_Int(&bmop, "numcuts", numcuts); + + BMO_Set_Int(&bmop, "flag", B_KNIFE); + BMO_Set_Int(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT); + BMO_Set_Int(&bmop, "singleedge", 0); + BMO_Set_Int(&bmop, "gridfill", 0); + + BMO_Set_Float(&bmop, "radius", 0); + + BMO_Exec_Op(bm, &bmop); + BMO_Finish_Op(bm, &bmop); + + BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_knife_cut(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name= "Knife Cut"; + ot->description= "Cut selected edges and faces into parts."; + ot->idname= "MESH_OT_knife_cut"; + + ot->invoke= WM_gesture_lines_invoke; + ot->modal= WM_gesture_lines_modal; + ot->exec= knife_cut_exec; + + ot->poll= EM_view3d_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", ""); + prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath); + + /* internal */ + RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); +} + +static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) +{ + Base *basenew; + BMIter iter; + BMVert *v; + BMEdge *e; + Object *obedit = editbase->object; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + BMesh *bmnew; + int allocsize[] = {512, 512, 2048, 512}; + + if (!em) + return OPERATOR_CANCELLED; + + bmnew = BM_Make_Mesh(obedit, allocsize); + CustomData_copy(&em->bm->vdata, &bmnew->vdata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&em->bm->edata, &bmnew->edata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&em->bm->ldata, &bmnew->ldata, CD_MASK_BMESH, CD_CALLOC, 0); + CustomData_copy(&em->bm->pdata, &bmnew->pdata, CD_MASK_BMESH, CD_CALLOC, 0); + + CustomData_bmesh_init_pool(&bmnew->vdata, allocsize[0]); + CustomData_bmesh_init_pool(&bmnew->edata, allocsize[1]); + CustomData_bmesh_init_pool(&bmnew->ldata, allocsize[2]); + CustomData_bmesh_init_pool(&bmnew->pdata, allocsize[3]); + + basenew= ED_object_add_duplicate(bmain, scene, editbase, USER_DUP_MESH); /* 0 = fully linked */ + assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ + + ED_base_object_select(basenew, BA_DESELECT); + + EDBM_CallOpf(em, wmop, "dupe geom=%hvef dest=%p", BM_SELECT, bmnew); + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_FACES); + + /*clean up any loose edges*/ + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_HIDDEN)) + continue; + + if (BM_Edge_FaceCount(e) != 0) + BM_Select(em->bm, e, 0); /*deselect*/ + } + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_EDGES); + + /*clean up any loose verts*/ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_HIDDEN)) + continue; + + if (BM_Vert_EdgeCount(v) != 0) + BM_Select(em->bm, v, 0); /*deselect*/ + } + + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_VERTS); + + BM_Compute_Normals(bmnew); + BMO_CallOpf(bmnew, "bmesh_to_mesh mesh=%p object=%p", basenew->object->data, basenew->object); + + BM_Free_Mesh(bmnew); + ((Mesh*)basenew->object->data)->edit_btmesh = NULL; + + return 1; +} + +//BMESH_TODO +static int mesh_separate_material(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop)) +{ + return 0; +} + +//BMESH_TODO +static int mesh_separate_loose(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop)) +{ + return 0; +} + +static int mesh_separate_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene= CTX_data_scene(C); + Base *base= CTX_data_active_base(C); + int retval= 0, type= RNA_enum_get(op->ptr, "type"); + + if(type == 0) + retval= mesh_separate_selected(bmain, scene, base, op); + else if(type == 1) + retval= mesh_separate_material (bmain, scene, base, op); + else if(type == 2) + retval= mesh_separate_loose(bmain, scene, base, op); + + if(retval) { + DAG_id_tag_update(base->object->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +/* *************** Operator: separate parts *************/ + +static EnumPropertyItem prop_separate_types[] = { + {0, "SELECTED", 0, "Selection", ""}, + {1, "MATERIAL", 0, "By Material", ""}, + {2, "LOOSE", 0, "By loose parts", ""}, + {0, NULL, 0, NULL, NULL} +}; + +void MESH_OT_separate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Separate"; + ot->description= "Separate selected geometry into a new mesh."; + ot->idname= "MESH_OT_separate"; + + /* api callbacks */ + ot->invoke= WM_menu_invoke; + ot->exec= mesh_separate_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", ""); +} + + +static int fill_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMOperator bmop; + + if (!EDBM_InitOpf(em, &bmop, op, "triangle_fill edges=%he", BM_SELECT)) + return OPERATOR_CANCELLED; + + BMO_Exec_Op(em->bm, &bmop); + + /*select new geometry*/ + BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_FACE|BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, 1)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; + +} + +void MESH_OT_fill(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Fill"; + ot->idname= "MESH_OT_fill"; + + /* api callbacks */ + ot->exec= fill_mesh_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int beautify_fill_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + if (!EDBM_CallOpf(em, op, "beautify_fill faces=%hf", BM_SELECT)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_beautify_fill(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Beautify Fill"; + ot->idname= "MESH_OT_beautify_fill"; + + /* api callbacks */ + ot->exec= beautify_fill_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/********************** Quad/Tri Operators *************************/ + +static int quads_convert_to_tris_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + + if (!EDBM_CallOpf(em, op, "triangulate faces=%hf", BM_SELECT)) + return OPERATOR_CANCELLED; + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Quads to Tris"; + ot->idname= "MESH_OT_quads_convert_to_tris"; + + /* api callbacks */ + ot->exec= quads_convert_to_tris_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +static int tris_convert_to_quads_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + int dosharp, douvs, dovcols, domaterials; + float limit = RNA_float_get(op->ptr, "limit"); + + dosharp = RNA_boolean_get(op->ptr, "sharp"); + douvs = RNA_boolean_get(op->ptr, "uvs"); + dovcols = RNA_boolean_get(op->ptr, "vcols"); + domaterials = RNA_boolean_get(op->ptr, "materials"); + + if (!EDBM_CallOpf(em, op, + "join_triangles faces=%hf limit=%f compare_sharp=%i compare_uvs=%i compare_vcols=%i compare_materials=%i", + BM_SELECT, limit, dosharp, douvs, dovcols, domaterials)) + { + return OPERATOR_CANCELLED; + } + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Tris to Quads"; + ot->idname= "MESH_OT_tris_convert_to_quads"; + + /* api callbacks */ + ot->exec= tris_convert_to_quads_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "limit", 40.0f, -180.0f, 180.0f, "Max Angle", "Angle Limit in Degrees", -180, 180.0f); + + RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", ""); + RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", ""); + RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", ""); + RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", ""); + +} + +static int edge_flip_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ +#if 0 + Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + + edge_flip(em); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + BKE_mesh_end_editmesh(obedit->data, em); +#endif + return OPERATOR_FINISHED; +} + +void MESH_OT_edge_flip(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Edge Flip"; + ot->idname= "MESH_OT_edge_flip"; + + /* api callbacks */ + ot->exec= edge_flip_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +//BMESH_TODO +static int split_mesh(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ +#if 0 + Object *obedit= CTX_data_edit_object(C); + EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + + WM_cursor_wait(1); + + /* make duplicate first */ + adduplicateflag(em, SELECT); + /* old faces have flag 128 set, delete them */ + delfaceflag(em, 128); + recalc_editnormals(em); + + WM_cursor_wait(0); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + BKE_mesh_end_editmesh(obedit->data, em); +#endif + return OPERATOR_FINISHED; +} + +void MESH_OT_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Split"; + ot->idname= "MESH_OT_split"; + + /* api callbacks */ + ot->exec= split_mesh; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli) +{ + Object *obedit= CTX_data_edit_object(C); + ToolSettings *ts= CTX_data_tool_settings(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + float nor[3]= {0.0f, 0.0f, 0.0f}; + float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3]; + float cent[3], bmat[3][3], rmat[4][4]; + float phi; + short a, ok= 1; + BMOperator bmop; + + RNA_float_get_array(op->ptr, "center", cent); + + /* imat and center and size */ + copy_m3_m4(bmat, obedit->obmat); + invert_m3_m3(imat,bmat); + + cent[0]-= obedit->obmat[3][0]; + cent[1]-= obedit->obmat[3][1]; + cent[2]-= obedit->obmat[3][2]; + mul_m3_v3(imat, cent); + + phi= degr*M_PI/360.0; + phi/= steps; + if(ts->editbutflag & B_CLOCKWISE) phi= -phi; + + RNA_float_get_array(op->ptr, "axis", n); + normalize_v3(n); + + q[0]= (float)cos(phi); + si= (float)sin(phi); + q[1]= n[0]*si; + q[2]= n[1]*si; + q[3]= n[2]*si; + quat_to_mat3( cmat,q); + + mul_m3_m3m3(tmat,cmat,bmat); + mul_m3_m3m3(bmat,imat,tmat); + copy_m4_m3(rmat, bmat); + + for(a=0; a<steps; a++) { + if(dupli==0) { + EDBM_Extrude_edge(obedit, em, BM_SELECT, nor); + BMO_CallOpf(em->bm, "rotate cent=%v mat=%m4 verts=%hv", cent, rmat, BM_SELECT); + ok = 1; + } else { + EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT); + BMO_Exec_Op(em->bm, &bmop); + BMO_CallOpf(em->bm, "rotate cent=%v mat=%m4 verts=%s", cent, rmat, &bmop, "newout"); + EDBM_clear_flag_all(em, BM_SELECT); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL); + ok = EDBM_FinishOp(em, &bmop, op, 1); + } + + if(!ok) + break; + + if(dvec) { + mul_m3_v3(bmat, dvec); + BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT); + } + } + + + return ok; +} + +static int spin_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + int ok; + + ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli")); + if(ok==0) { + BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected"); + return OPERATOR_CANCELLED; + } + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +/* get center and axis, in global coords */ +static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d= ED_view3d_context_rv3d(C); + + RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); + RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]); + + return spin_mesh_exec(C, op); +} + +void MESH_OT_spin(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Spin"; + ot->idname= "MESH_OT_spin"; + + /* api callbacks */ + ot->invoke= spin_mesh_invoke; + ot->exec= spin_mesh_exec; + ot->poll= EM_view3d_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, INT_MAX); + RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates"); + RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f); + + RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); + RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); + +} + +static int screw_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMEdge *eed; + BMVert *eve, *v1, *v2; + BMIter iter, eiter; + float dvec[3], nor[3]; + int steps, turns; + int valence; + + + turns= RNA_int_get(op->ptr, "turns"); + steps= RNA_int_get(op->ptr, "steps"); + + + /* find two vertices with valence count==1, more or less is wrong */ + v1 = NULL; + v2 = NULL; + for(eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + eve; eve = BMIter_Step(&iter)){ + + valence = 0; + + for(eed = BMIter_New(&eiter, em->bm, BM_EDGES_OF_VERT, eve); + eed; eed = BMIter_Step(&eiter)){ + + if(BM_TestHFlag(eed, BM_SELECT)){ + valence++; + } + + } + + if(valence == 1){ + if(v1==NULL) v1 = eve; + else if(v2==NULL) v2= eve; + else { + v1= NULL; + break; + } + } + } + + if(v1==NULL || v2==NULL) { + BKE_report(op->reports, RPT_ERROR, "You have to select a string of connected vertices too"); + return OPERATOR_CANCELLED; + } + + /* calculate dvec */ + dvec[0]= ( v1->co[0]- v2->co[0] )/steps; + dvec[1]= ( v1->co[1]- v2->co[1] )/steps; + dvec[2]= ( v1->co[2]- v2->co[2] )/steps; + + VECCOPY(nor, obedit->obmat[2]); + + if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) { + dvec[0]= -dvec[0]; + dvec[1]= -dvec[1]; + dvec[2]= -dvec[2]; + } + + if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) { + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected"); + return OPERATOR_CANCELLED; + } + + return OPERATOR_FINISHED; +} + +/* get center and axis, in global coords */ +static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + RegionView3D *rv3d= ED_view3d_context_rv3d(C); + + RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); + RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]); + + return screw_mesh_exec(C, op); +} + +void MESH_OT_screw(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Screw"; + ot->idname= "MESH_OT_screw"; + + /* api callbacks */ + ot->invoke= screw_mesh_invoke; + ot->exec= screw_mesh_exec; + ot->poll= EM_view3d_poll; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /*props */ + RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256); + RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256); + + RNA_def_float_vector(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); + RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); +} + +static int select_by_number_vertices_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMIter iter; + int numverts= RNA_int_get(op->ptr, "number"); + int type = RNA_enum_get(op->ptr, "type"); + + for(efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + efa; efa = BMIter_Step(&iter)){ + + int select = 0; + + if(type == 0 && efa->len < numverts){ + select = 1; + }else if(type == 1 && efa->len == numverts){ + select = 1; + }else if(type == 2 && efa->len > numverts){ + select = 1; + } + + if(select){ + BM_Select(em->bm, efa, 1); + } + } + + EDBM_selectmode_flush(em); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_by_number_vertices(wmOperatorType *ot) +{ + static const EnumPropertyItem type_items[] = { + {0, "LESS", 0, "Less Than", ""}, + {1, "EQUAL", 0, "Equal To", ""}, + {2, "GREATER", 0, "Greater Than", ""}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name= "Select by Number of Vertices"; + ot->description= "Select vertices or faces by vertex count."; + ot->idname= "MESH_OT_select_by_number_vertices"; + + /* api callbacks */ + ot->exec= select_by_number_vertices_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_int(ot->srna, "number", 4, 3, INT_MAX, "Number of Vertices", "", 3, INT_MAX); + RNA_def_enum(ot->srna, "type", type_items, 1, "Type", "Type of comparison to make"); +} + +static int select_loose_verts_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMVert *eve; + BMEdge *eed; + BMIter iter; + + for(eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + eve; eve = BMIter_Step(&iter)){ + + if(!eve->e){ + BM_Select(em->bm, eve, 1); + } + } + + for(eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; eed = BMIter_Step(&iter)){ + + if(!eed->l){ + BM_Select(em->bm, eed, 1); + } + } + + EDBM_selectmode_flush(em); + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_loose_verts(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Loose Vertices/Edges"; + ot->description = "Select vertices with edges or faces and edges with no faces"; + ot->idname = "MESH_OT_select_loose_verts"; + + /* api callbacks */ + ot->exec = select_loose_verts_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; +} + +#define MIRROR_THRESH 1.0f + +static int select_mirror_exec(bContext *C, wmOperator *op) +{ + + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMBVHTree *tree = BMBVH_NewBVH(em); + BMVert *v1, *v2; + BMIter iter; + int extend= RNA_boolean_get(op->ptr, "extend"); + float mirror_co[3]; + + BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(v1, BM_SELECT) || BM_TestHFlag(v1, BM_HIDDEN)) + BM_SetIndex(v1, 0); + else BM_SetIndex(v1, 1); + } + + if (!extend) + EDBM_clear_flag_all(em, BM_SELECT); + + BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_GetIndex(v1) || BM_TestHFlag(v1, BM_HIDDEN)) + continue; + + VECCOPY(mirror_co, v1->co); + mirror_co[0] *= -1.0f; + + v2 = BMBVH_FindClosestVertTopo(tree, mirror_co, MIRROR_THRESH, v1); + if (v2 && !BM_TestHFlag(v2, BM_HIDDEN)) + BM_Select(em->bm, v2, 1); + } + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); + return OPERATOR_FINISHED; +} + +void MESH_OT_select_mirror(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Select Mirror"; + ot->description= "Select mesh items at mirrored locations."; + ot->idname= "MESH_OT_select_mirror"; + + /* api callbacks */ + ot->exec= select_mirror_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); +} + +/********* qsort routines. not sure how to make these + work, since we aren't using linked lists for + geometry anymore. might need a sortof "swap" + function for bmesh elements. *********/ + +typedef struct xvertsort { + float x; + BMVert *v1; +} xvertsort; + + +static int vergxco(const void *v1, const void *v2) +{ + const xvertsort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} + +struct facesort { + uintptr_t x; + struct EditFace *efa; +}; + +#if 0 /* UNUSED */ +static int vergface(const void *v1, const void *v2) +{ + const struct facesort *x1=v1, *x2=v2; + + if( x1->x > x2->x ) return 1; + else if( x1->x < x2->x) return -1; + return 0; +} +#endif + +// XXX is this needed? +/* called from buttons */ +#if 0 /* UNUSED */ +static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index) +{ + xvertsort *sortblock = userData; + + sortblock[index].x = x; +} +#endif + +/* all verts with (flag & 'flag') are sorted */ +static void xsortvert_flag(bContext *UNUSED(C), int UNUSED(flag)) +{ + /*BMESH_TODO*/ +#if 0 //hrm, geometry isn't in linked lists anymore. . . + ViewContext vc; + BMEditMesh *em; + BMVert *eve; + BMIter iter; + xvertsort *sortblock; + ListBase tbase; + int i, amount; + + em_setup_viewcontext(C, &vc); + em = vc.em; + + amount = em->bm->totvert; + sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort"); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) + sortblock[i].v1 = eve; + } + + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0); + + qsort(sortblock, amount, sizeof(xvertsort), vergxco); + + /* make temporal listbase */ + tbase.first= tbase.last= 0; + for (i=0; i<amount; i++) { + eve = sortblock[i].v1; + + if (eve) { + BLI_remlink(&vc.em->verts, eve); + BLI_addtail(&tbase, eve); + } + } + + BLI_movelisttolist(&vc.em->verts, &tbase); + + MEM_freeN(sortblock); +#endif + +} + +static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op)) +{ + xsortvert_flag(C, SELECT); + return OPERATOR_FINISHED; +} + +void MESH_OT_vertices_sort(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Vertex Sort"; + ot->description= "Sort vertex order"; + ot->idname= "MESH_OT_vertices_sort"; + + /* api callbacks */ + ot->exec= mesh_vertices_sort_exec; + + ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */ + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +#if 0 +/* called from buttons */ +static void hashvert_flag(EditMesh *em, int flag) +{ + /* switch vertex order using hash table */ + EditVert *eve; + struct xvertsort *sortblock, *sb, onth, *newsort; + ListBase tbase; + int amount, a, b; + + /* count */ + eve= em->verts.first; + amount= 0; + while(eve) { + if(eve->f & flag) amount++; + eve= eve->next; + } + if(amount==0) return; + + /* allocate memory */ + sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub"); + eve= em->verts.first; + while(eve) { + if(eve->f & flag) { + sb->v1= eve; + sb++; + } + eve= eve->next; + } + + BLI_srand(1); + + sb= sortblock; + for(a=0; a<amount; a++, sb++) { + b= (int)(amount*BLI_drand()); + if(b>=0 && b<amount) { + newsort= sortblock+b; + onth= *sb; + *sb= *newsort; + *newsort= onth; + } + } + + /* make temporal listbase */ + tbase.first= tbase.last= 0; + sb= sortblock; + while(amount--) { + eve= sb->v1; + BLI_remlink(&em->verts, eve); + BLI_addtail(&tbase, eve); + sb++; + } + + BLI_movelisttolist(&em->verts, &tbase); + + MEM_freeN(sortblock); + +} +#endif + +static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; +#if 1 /*BMESH TODO*/ + (void)em; +#else + hashvert_flag(em, SELECT); +#endif + return OPERATOR_FINISHED; +} + +void MESH_OT_vertices_randomize(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Vertex Randomize"; + ot->description= "Randomize vertex order"; + ot->idname= "MESH_OT_vertices_randomize"; + + /* api callbacks */ + ot->exec= mesh_vertices_randomize_exec; + + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + +/******end of qsort stuff ****/ + + +static int mesh_noise_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + Material *ma; + Tex *tex; + BMVert *eve; + BMIter iter; + float fac= RNA_float_get(op->ptr, "factor"); + + if(em==NULL) return OPERATOR_FINISHED; + + ma= give_current_material(obedit, obedit->actcol); + if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) { + BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned."); + return OPERATOR_FINISHED; + } + tex= give_current_material_texture(ma); + + if(tex->type==TEX_STUCCI) { + float b2, vec[3]; + float ofs= tex->turbul/200.0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) { + b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]); + if(tex->stype) ofs*=(b2*b2); + vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2])); + vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2])); + vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs)); + + add_v3_v3(eve->co, vec); + } + } + } + else { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) { + float tin, dum; + externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0); + eve->co[2]+= fac*tin; + } + } + } + + EDBM_RecalcNormals(em); + + DAG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_noise(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Noise"; + ot->description= "Use vertex coordinate as texture coordinate"; + ot->idname= "MESH_OT_noise"; + + /* api callbacks */ + ot->exec= mesh_noise_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f); +} + +/*bevel! yay!!*/ +static int mesh_bevel_exec(bContext *C, wmOperator *op) +{ + Object *obedit= CTX_data_edit_object(C); + BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh; + BMIter iter; + BMEdge *eed; + BMOperator bmop; + float factor= RNA_float_get(op->ptr, "percent"), fac=factor, dfac, df, s; + /*float p2 = RNA_float_get(op->ptr, "param2"); + float p3 = RNA_float_get(op->ptr, "param3"); + float p4 = RNA_float_get(op->ptr, "param4"); + float p5 = RNA_float_get(op->ptr, "param5");*/ + int i, recursion = RNA_int_get(op->ptr, "recursion"); + float *w = NULL, ftot; + int li; + BLI_array_declare(w); + + BM_add_data_layer(em->bm, &em->bm->edata, CD_PROP_FLT); + li = CustomData_number_of_layers(&em->bm->edata, CD_PROP_FLT)-1; + + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + float d = len_v3v3(eed->v1->co, eed->v2->co); + float *dv = CustomData_bmesh_get_n(&em->bm->edata, eed->head.data, CD_PROP_FLT, li); + + *dv = d; + } + + if(em==NULL) return OPERATOR_CANCELLED; + + /*ugh, stupid math depends somewhat on angles!*/ + dfac = 1.0/(float)(recursion+1); + df = 1.0; + for (i=0, ftot=0.0f; i<recursion; i++) { + s = pow(df, 1.25); + + BLI_array_append(w, s); + ftot += s; + + df *= 2.0; + } + + for (i=0; i<BLI_array_count(w); i++) { + w[i] /= ftot; + } + + fac = factor; + for (i=0; i<BLI_array_count(w); i++) { + fac = w[BLI_array_count(w)-i-1]*factor; + + if (!EDBM_InitOpf(em, &bmop, op, "bevel geom=%hev percent=%f lengthlayer=%i uselengths=%i", BM_SELECT, fac, li, 1)) + return OPERATOR_CANCELLED; + + BMO_Exec_Op(em->bm, &bmop); + BMO_Finish_Op(em->bm, &bmop); + } + + BM_free_data_layer_n(em->bm, &em->bm->edata, CD_MASK_PROP_FLT, li); + + BLI_array_free(w); + EDBM_RecalcNormals(em); + + DAG_id_tag_update(obedit->data, 0); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_bevel(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Bevel"; + ot->description= "Edge/Vertex Bevel"; + ot->idname= "MESH_OT_bevel"; + + /* api callbacks */ + ot->exec= mesh_bevel_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_float(ot->srna, "percent", 0.5f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f); + RNA_def_int(ot->srna, "recursion", 1, 1, 50, "Recursion Level", "Recursion Level", 1, 8); + //RNA_def_float(ot->srna, "param2", 1.0f, -FLT_MAX, FLT_MAX, "Parameter 2", "", -1000.0f, 1000.0f); + //RNA_def_float(ot->srna, "param3", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 3", "", -1000.0f, 1000.0f); + //RNA_def_float(ot->srna, "param4", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 4", "", -1000.0f, 1000.0f); + //RNA_def_float(ot->srna, "param5", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 5", "", -1000.0f, 1000.0f); +} + +static int mesh_export_obj_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + DerivedMesh *dm; + Scene *scene = CTX_data_scene(C); + Mesh *me; + Main *bmain = CTX_data_main(C); + MVert *mvert, *mv; + MLoop *mloop, *ml; + MPoly *mpoly, *mp; + MTexPoly *mtexpoly; + MLoopUV *luv, *mloopuv; + MLoopCol *mloopcol; + FILE *file, *matfile; + int *face_mat_group; + struct {Material *mat; MTexPoly poly; int end;} **matlists; + char str[FILE_MAX], str2[FILE_MAX]; + int i, j, c, free; + + if (ob->type != OB_MESH) { + BKE_report(op->reports, RPT_OPERATOR, "Only meshes can be exported"); + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "filepath", str); + + sprintf(str2, "%s_materials.mtl", str); + file = fopen(str, "wb"); + matfile = fopen(str2, "wb"); + + if (!file) { + BKE_report(op->reports, RPT_OPERATOR, "Could not open file"); + + if (matfile) + fclose(matfile); + return OPERATOR_CANCELLED; + } + + if (!matfile) { + BKE_report(op->reports, RPT_OPERATOR, "Could not open material file"); + + if (file) + fclose(file); + return OPERATOR_CANCELLED; + } + + me = ob->data; + if (me->edit_btmesh) { + EDBM_LoadEditBMesh(scene, ob); + } + + if (!RNA_boolean_get(op->ptr, "apply_modifiers")) { + dm = CDDM_from_mesh(me, ob); + free = 1; + } else { + dm = mesh_get_derived_final(scene, ob, CD_MASK_DERIVEDMESH); + if (!CDDM_Check(dm)) { + dm = CDDM_copy(dm, 0); + free = 1; + } else { + free = 0; + } + } + + face_mat_group = MEM_callocN(sizeof(int)*dm->numPolyData, "face_mat_group"); + + if (MAX2(ob->totcol, me->totcol)) + matlists = MEM_callocN(sizeof(*matlists)*MAX2(me->totcol, ob->totcol), "matlists"); + else matlists = NULL; + + for (i=0; i<MAX2(ob->totcol, me->totcol); i++) { + matlists[i] = MEM_callocN(sizeof(**matlists), "matlists[i]"); + matlists[i][0].end = 1; + } + + + mvert = CDDM_get_verts(dm); + mloop = CDDM_get_loops(dm); + mpoly = CDDM_get_polys(dm); + mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY); + mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV); + mloopcol = CustomData_get_layer(&dm->loopData, CD_MLOOPCOL); + + /*build material list*/ + mp = mpoly; + for (i=0; i<dm->numPolyData; i++, (mtexpoly ? mtexpoly++ : NULL), mp++) { + int found = 0; + + j = 0; + while (!matlists[mp->mat_nr][j].end) { + Material *mat = ob->matbits[mp->mat_nr] ? ob->mat[mp->mat_nr] : me->mat[mp->mat_nr]; + + if (matlists[mp->mat_nr][j].mat == mat) { + if (mtexpoly) { + if (matlists[mp->mat_nr][j].poly.tpage == mtexpoly->tpage) { + found = 1; + break; + } + } else { + found = 1; + break; + } + } + j++; + } + + if (!found) { + matlists[mp->mat_nr] = MEM_reallocN(matlists[mp->mat_nr], sizeof(**matlists)*(j+2)); + + /*add sentinal*/ + matlists[mp->mat_nr][j+1].end = 1; + matlists[mp->mat_nr][j].end = 0; + + if (ob->matbits && ob->matbits[mp->mat_nr]) { + matlists[mp->mat_nr][j].mat = ob->mat[mp->mat_nr]; + } else { + matlists[mp->mat_nr][j].mat = me->mat[mp->mat_nr]; + } + + if (mtexpoly) + matlists[mp->mat_nr][j].poly = *mtexpoly; + } + + face_mat_group[i] = j; + } + + /*write material references*/ + fprintf(file, "mtllib %s_materials.mtl\n", str); + fprintf(file, "o %s\n", (ob->id.name+2)); + + for (mv=mvert, i=0; i<dm->numVertData; i++, mv++) { + fprintf(file, "v %.8f\t%.8f\t%.8f\n", mv->co[0], mv->co[1], mv->co[2]); + fprintf(file, "vn %.5f\t%.5f\t%.5f\n", (float)mv->no[0]/65535.0f, (float)mv->no[1]/65535.0f, (float)mv->no[2]/65535.0f); + } + + /*write texture coordinates*/ + if (mloopuv) { + fprintf(file, "\n"); + for (mp=mpoly, i=0; i<dm->numPolyData; i++, mp++) { + luv = mloopuv + mp->loopstart; + for (j=0; j<mp->totloop; j++, luv++) { + fprintf(file, "vt %.8f\t%.8f\n", luv->uv[0], luv->uv[1]); + } + } + } + + fprintf(file, "\n"); + c = 0; + for (mp=mpoly, i=0; i<dm->numPolyData; i++, mp++) { + char matname[256]; + + if (mp->flag & ME_SMOOTH) { + fprintf(file, "s 1\n"); + } else { + fprintf(file, "s off\n"); + } + + if (matlists[mp->mat_nr][face_mat_group[i]].mat && matlists[mp->mat_nr][face_mat_group[i]].poly.tpage) { + sprintf(matname, "%s__%s", matlists[mp->mat_nr][face_mat_group[i]].mat->id.name+2, + matlists[mp->mat_nr][face_mat_group[i]].poly.tpage->id.name+2); + } else if (matlists[mp->mat_nr][face_mat_group[i]].mat) { + sprintf(matname, "%s", matlists[mp->mat_nr][face_mat_group[i]].mat->id.name+2); + } else if (matlists[mp->mat_nr][face_mat_group[i]].poly.tpage != NULL) { + sprintf(matname, "texture_%s", matlists[mp->mat_nr][face_mat_group[i]].poly.tpage->id.name+2); + } else { + sprintf(matname, "__null_material_%d_%d", mp->mat_nr, face_mat_group[mp->mat_nr]); + } + + fprintf(file, "usemtl %s\n", matname); + fprintf(file, "f "); + + ml = mloop + mp->loopstart; + luv = mloopuv ? mloopuv + mp->loopstart : NULL; + for (j=0; j<mp->totloop; j++, ml++, (luv ? luv++ : NULL), c++) { + if (luv) { + fprintf(file, "%d/%d ", ml->v+1, c+1); + } else { + fprintf(file, "%d ", ml->v+1); + } + } + fprintf(file, "\n"); + } + + fclose(file); + + /*write material library*/ + fprintf(matfile, "#Blender MTL File\n\n"); + for (i=0; i<MAX2(ob->totcol, me->totcol); i++) { + Material *mat; + char basedir[FILE_MAX], filename[FILE_MAX], str3[FILE_MAX]; + + j = 0; + while (!matlists[i][j].end) { + mat = matlists[i][j].mat; + + if (mat && matlists[i][j].poly.tpage) { + fprintf(matfile, "newmtl %s__%s\n", mat->id.name+2, + matlists[i][j].poly.tpage->id.name+2); + } else if (mat) { + fprintf(matfile, "newmtl %s\n", mat->id.name+2); + } else if (matlists[i][j].poly.tpage != NULL) { + fprintf(matfile, "newmtl texture_%s\n", matlists[i][j].poly.tpage->id.name+2); + } else { + fprintf(matfile, "newmtl __null_material_%d_%d\n", i, j); + } + + if (mat) { + fprintf(matfile, "Kd %.6f %.6f %.6f\n", mat->r, mat->g, mat->b); + fprintf(matfile, "Ks %.6f %.6f %.6f\n", mat->specr, mat->specg, mat->specb); + fprintf(matfile, "Ns %.6f\n", mat->spec*1000.0f); + } else { + fprintf(matfile, "Kd %.6f %.6f %.6f\n", 0.45f, 0.45f, 0.45f); + fprintf(matfile, "Ks %.6f %.6f %.6f\n", 1.0f, 0.4f, 0.1f); + fprintf(matfile, "Ns %.6f\n", 300.0f); + } + + fprintf(matfile, "illum 2\n"); + + if (matlists[i][j].poly.tpage) { + BLI_strncpy(str2, matlists[i][j].poly.tpage->name, FILE_MAX); + BLI_strncpy(basedir, bmain->name, FILE_MAX); + + BLI_splitdirstring(basedir, filename); + BLI_cleanup_file(basedir, str2); /* fix any /foo/../foo/ */ + + if (BLI_exists(str2)) { + char rel[3] = {0}; + + BLI_strncpy(str3, str2, FILE_MAX); + if (RNA_boolean_get(op->ptr, "relpaths")) { + BLI_path_rel(str3, str); + + if (str3[2] != '.' && str3[2] != '/' && str3[2] != '\\') { + rel[0] = '.'; + rel[1] = '/'; + } + } + + fprintf(matfile, "map_Ka %s%s\n", rel, (str3+2*RNA_boolean_get(op->ptr, "relpaths"))); + fprintf(matfile, "map_Kd %s%s\n", rel, (str3+2*RNA_boolean_get(op->ptr, "relpaths"))); + } + } + + fprintf(matfile, "\n"); + j++; + } + } + + fclose(matfile); + + for (i=0; i<MAX2(ob->totcol, me->totcol); i++) { + MEM_freeN(matlists[i]); + } + + if (matlists) + MEM_freeN(matlists); + + if (face_mat_group) + MEM_freeN(face_mat_group); + + if (free) { + dm->needsFree = 1; + dm->release(dm); + } + + return OPERATOR_FINISHED; +} + +static void export_obj_filesel(bContext *C, wmOperator *op, const char *path) +{ + RNA_string_set(op->ptr, "filepath", path); + WM_event_add_fileselect(C, op); +} + + +static int export_obj_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) +{ + char filename[FILE_MAX]; + + BLI_strncpy(filename, "//untitled.obj", FILE_MAX); + + if(RNA_property_is_set(op->ptr, "filepath")) + return mesh_export_obj_exec(C, op); + + export_obj_filesel(C, op, filename); + + return OPERATOR_RUNNING_MODAL; +} + + +void EXPORT_MESH_OT_wavefront(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Export Wavefront OBJ"; + ot->description= "Export Wavefront (obj)"; + ot->idname= "EXPORT_MESH_OT_wavefront"; + + /* api callbacks */ + ot->exec= mesh_export_obj_exec; + ot->invoke= export_obj_invoke; + ot->poll= ED_operator_object_active; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_filesel(ot, FOLDERFILE|TEXTFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH); + + RNA_def_boolean(ot->srna, "apply_modifiers", 0, "Apply Modifiers", "Apply Modifiers"); + RNA_def_boolean(ot->srna, "relpaths", 0, "Relative Paths", "Use relative paths for textures"); +} diff --git a/source/blender/editors/mesh/bmeshutils.c b/source/blender/editors/mesh/bmeshutils.c new file mode 100644 index 00000000000..c6a5917066a --- /dev/null +++ b/source/blender/editors/mesh/bmeshutils.c @@ -0,0 +1,903 @@ + /* $Id: bmeshutils.c + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" +#include "BLI_array.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_key.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "bmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" + +#include "UI_interface.h" + +#include "editbmesh_bvh.h" +#include "mesh_intern.h" + +void EDBM_RecalcNormals(BMEditMesh *em) +{ + BM_Compute_Normals(em->bm); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + BMIter iter; + BMHeader *ele; + int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH}; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i=0; i<3; i++) { + ele = BMIter_New(&iter, em->bm, types[i], NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (BM_TestHFlag(ele, BM_SELECT)) { + *tots[i]++; + } + } + } +} + +int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...) +{ + BMesh *bm = em->bm; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, bmop, fmt, list)) { + BKE_report(op->reports, RPT_ERROR, + "Parse error in EDBM_CallOpf"); + va_end(list); + return 0; + } + + if (!em->emcopy) + em->emcopy = BMEdit_Copy(em); + em->emcopyusers++; + + va_end(list); + + return 1; +} + + +/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/ +int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report) { + const char *errmsg; + + BMO_Finish_Op(em->bm, bmop); + + if (BMO_GetError(em->bm, &errmsg, NULL)) { + BMEditMesh *emcopy = em->emcopy; + + if (report) BKE_report(op->reports, RPT_ERROR, errmsg); + + BMEdit_Free(em); + *em = *emcopy; + + MEM_freeN(emcopy); + em->emcopyusers = 0; + em->emcopy = NULL; + return 0; + } else { + em->emcopyusers--; + if (em->emcopyusers < 0) { + printf("warning: em->emcopyusers was less then zero.\n"); + } + + if (em->emcopyusers <= 0) { + BMEdit_Free(em->emcopy); + MEM_freeN(em->emcopy); + em->emcopy = NULL; + } + } + + return 1; +} + +int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, &bmop, fmt, list)) { + BKE_report(op->reports, RPT_ERROR, + "Parse error in EDBM_CallOpf"); + va_end(list); + return 0; + } + + if (!em->emcopy) + em->emcopy = BMEdit_Copy(em); + em->emcopyusers++; + + BMO_Exec_Op(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, op, 1); +} + +int EDBM_CallAndSelectOpf(BMEditMesh *em, wmOperator *op, const char *selectslot, const char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, &bmop, fmt, list)) { + BKE_report(op->reports, RPT_ERROR, + "Parse error in EDBM_CallOpf"); + va_end(list); + return 0; + } + + if (!em->emcopy) + em->emcopy = BMEdit_Copy(em); + em->emcopyusers++; + + BMO_Exec_Op(bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, selectslot, BM_SELECT, BM_ALL); + + va_end(list); + return EDBM_FinishOp(em, &bmop, op, 1); +} + +int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_VInitOpf(bm, &bmop, fmt, list)) { + va_end(list); + return 0; + } + + if (!em->emcopy) + em->emcopy = BMEdit_Copy(em); + em->emcopyusers++; + + BMO_Exec_Op(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, NULL, 0); +} + +void EDBM_selectmode_to_scene(Scene *scene, Object *obedit) +{ + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + + if (!em) + return; + + scene->toolsettings->selectmode = em->selectmode; +} + +void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob) +{ + Mesh *me = ob->data; + BMesh *bm; + + if (!me->mpoly && me->totface) { + printf("yeek!! bmesh conversion issue! may lose lots of geometry!\n"); + + /*BMESH_TODO need to write smarter code here*/ + bm = BKE_mesh_to_bmesh(me, ob); + } else { + bm = BKE_mesh_to_bmesh(me, ob); + } + + me->edit_btmesh = BMEdit_Create(bm); + me->edit_btmesh->selectmode = ts->selectmode; + me->edit_btmesh->me = me; + me->edit_btmesh->ob = ob; +} + +void EDBM_LoadEditBMesh(Scene *scene, Object *ob) +{ + Mesh *me = ob->data; + BMesh *bm = me->edit_btmesh->bm; + + BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob); +} + +void EDBM_FreeEditBMesh(BMEditMesh *tm) +{ + BMEdit_Free(tm); +} + +void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface) +{ + EDBM_free_index_arrays(tm); + + if (forvert) { + BMIter iter; + BMVert *ele; + int i=0; + + tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index"); + + ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->vert_index[i++] = ele; + } + } + + if (foredge) { + BMIter iter; + BMEdge *ele; + int i=0; + + tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index"); + + ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->edge_index[i++] = ele; + } + } + + if (forface) { + BMIter iter; + BMFace *ele; + int i=0; + + tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index"); + + ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + tm->face_index[i++] = ele; + } + } +} + +void EDBM_free_index_arrays(BMEditMesh *tm) +{ + if (tm->vert_index) { + MEM_freeN(tm->vert_index); + tm->vert_index = NULL; + } + + if (tm->edge_index) { + MEM_freeN(tm->edge_index); + tm->edge_index = NULL; + } + + if (tm->face_index) { + MEM_freeN(tm->face_index); + tm->face_index = NULL; + } +} + +BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index) +{ + return tm->vert_index && index < tm->bm->totvert ?tm->vert_index[index]:NULL; +} + +BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index) +{ + return tm->edge_index && index < tm->bm->totedge ?tm->edge_index[index]:NULL; +} + +BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index) +{ + return (tm->face_index && index<tm->bm->totface && index>=0) ? tm->face_index[index] : NULL; +} + +/* this replaces the active flag used in uv/face mode */ +void EDBM_set_actFace(BMEditMesh *em, BMFace *efa) +{ + em->bm->act_face = efa; +} + +BMFace *EDBM_get_actFace(BMEditMesh *em, int sloppy) +{ + if (em->bm->act_face) { + return em->bm->act_face; + } else if (sloppy) { + BMFace *efa= NULL; + BMEditSelection *ese; + + ese = em->bm->selected.last; + for (; ese; ese=ese->prev){ + if(ese->type == BM_FACE) { + efa = (BMFace *)ese->data; + + if (BM_TestHFlag(efa, BM_HIDDEN)) efa= NULL; + else break; + } + } + if (efa==NULL) { + BMIter iter; + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter)) { + if (BM_TestHFlag(efa, BM_SELECT)) + break; + } + } + return efa; /* can still be null */ + } + return NULL; + +} + +void EDBM_select_flush(BMEditMesh *em, int selectmode) +{ + em->bm->selectmode = selectmode; + BM_SelectMode_Flush(em->bm); + em->bm->selectmode = em->selectmode; +} + +/*BMESH_TODO*/ +void EDBM_deselect_flush(BMEditMesh *UNUSED(em)) +{ +} + + +void EDBM_selectmode_flush(BMEditMesh *em) +{ + em->bm->selectmode = em->selectmode; + BM_SelectMode_Flush(em->bm); +} + +/*EDBM_select_[more/less] are api functions, I think the uv editor + uses them? though the select more/less ops themselves do not.*/ +static void EDBM_select_more(BMEditMesh *em) +{ + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + BMO_InitOpf(em->bm, &bmop, + "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_SELECT, 0, usefaces); + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL); + BMO_Finish_Op(em->bm, &bmop); + + EDBM_selectmode_flush(em); +} + +static void EDBM_select_less(BMEditMesh *em) +{ + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + BMO_InitOpf(em->bm, &bmop, + "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_SELECT, 0, usefaces); + BMO_Exec_Op(em->bm, &bmop); + BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL); + BMO_Finish_Op(em->bm, &bmop); + + EDBM_selectmode_flush(em); +} + +int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese) +{ + BMEditSelection *ese_last = em->bm->selected.last; + BMFace *efa = EDBM_get_actFace(em, 0); + + ese->next = ese->prev = NULL; + + if (ese_last) { + if (ese_last->type == BM_FACE) { /* if there is an active face, use it over the last selected face */ + if (efa) { + ese->data = (void *)efa; + } else { + ese->data = ese_last->data; + } + ese->type = BM_FACE; + } else { + ese->data = ese_last->data; + ese->type = ese_last->type; + } + } else if (efa) { /* no */ + ese->data = (void *)efa; + ese->type = BM_FACE; + } else { + ese->data = NULL; + return 0; + } + return 1; +} + +void EDBM_clear_flag_all(BMEditMesh *em, int flag) +{ + BMIter iter; + BMHeader *ele; + int i, type; + + if (flag & BM_SELECT) + BM_clear_selection_history(em->bm); + + for (i=0; i<3; i++) { + switch (i) { + case 0: + type = BM_VERTS_OF_MESH; + break; + case 1: + type = BM_EDGES_OF_MESH; + break; + case 2: + type = BM_FACES_OF_MESH; + break; + } + + BM_ITER(ele, &iter, em->bm, type, NULL) { + if (flag & BM_SELECT) BM_Select(em->bm, ele, 0); + BM_ClearHFlag(ele, flag); + } + } +} + +void EDBM_set_flag_all(BMEditMesh *em, int flag) +{ + BMIter iter; + BMHeader *ele; + int i, type; + + for (i=0; i<3; i++) { + switch (i) { + case 0: + type = BM_VERTS_OF_MESH; + break; + case 1: + type = BM_EDGES_OF_MESH; + break; + case 2: + type = BM_FACES_OF_MESH; + break; + } + + ele = BMIter_New(&iter, em->bm, type, NULL); + for ( ; ele; ele=BMIter_Step(&iter)) { + if (flag & BM_SELECT) BM_Select(em->bm, ele, 1); + BM_SetHFlag(ele, flag); + } + } +} + +/**************-------------- Undo ------------*****************/ + +/* for callbacks */ + +static void *getEditMesh(bContext *C) +{ + Object *obedit= CTX_data_edit_object(C); + if(obedit && obedit->type==OB_MESH) { + Mesh *me= obedit->data; + return me->edit_btmesh; + } + return NULL; +} + +typedef struct undomesh { + Mesh me; + int selectmode; + char obname[64]; +} undomesh; + +/*undo simply makes copies of a bmesh*/ +static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +{ + BMEditMesh *em = emv; + Mesh *obme = obdata; + + undomesh *me = MEM_callocN(sizeof(undomesh), "undo Mesh"); + strcpy(me->obname, em->bm->ob->id.name+2); + + /*make sure shape keys work*/ + me->me.key = obme->key ? copy_key_nolib(obme->key) : NULL; + + /*we recalc the tesselation here, to avoid seeding calls to + BMEdit_RecalcTesselation throughout the code.*/ + BMEdit_RecalcTesselation(em); + + BMO_CallOpf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", me, 1); + me->selectmode = em->selectmode; + + return me; +} + +static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata)) +{ + BMEditMesh *em = emv, *em2; + Object *ob; + undomesh *me = umv; + BMesh *bm; + int allocsize[4] = {512, 512, 2048, 512}; + + ob = (Object*)find_id("OB", me->obname); + ob->shapenr = em->bm->shapenr; + + BMEdit_Free(em); + + bm = BM_Make_Mesh(ob, allocsize); + BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 0); + + em2 = BMEdit_Create(bm); + *em = *em2; + + em->selectmode = me->selectmode; + + MEM_freeN(em2); +} + + +static void free_undo(void *umv) +{ + if (((Mesh*)umv)->key) + { + free_key(((Mesh*)umv)->key); + MEM_freeN(((Mesh*)umv)->key); + } + + free_mesh(umv, 0); + MEM_freeN(umv); +} + +/* and this is all the undo system needs to know */ +void undo_push_mesh(bContext *C, const char *name) +{ + undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL); +} + +/*write comment here*/ +UvVertMap *EDBM_make_uv_vert_map(BMEditMesh *em, int selected, int do_face_idx_array, float *limit) +{ + BMVert *ev; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + /* vars from original func */ + UvVertMap *vmap; + UvMapVert *buf; + MTexPoly *tf; + MLoopUV *luv; + unsigned int a; + int totverts, i, totuv; + + if (do_face_idx_array) + EDBM_init_index_arrays(em, 0, 0, 1); + + /* we need the vert */ + totverts=0; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(ev, totverts); + totverts++; + } + + totuv = 0; + + /* generate UvMapVert array */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) + totuv += efa->len; + } + + if(totuv==0) { + if (do_face_idx_array) + EDBM_free_index_arrays(em); + return NULL; + } + vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap"); + if (!vmap) { + if (do_face_idx_array) + EDBM_free_index_arrays(em); + return NULL; + } + + vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*"); + buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert"); + + if (!vmap->vert || !vmap->buf) { + free_uv_vert_map(vmap); + if (do_face_idx_array) + EDBM_free_index_arrays(em); + return NULL; + } + + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) { + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + buf->tfindex= i; + buf->f= a; + buf->separate = 0; + + buf->next= vmap->vert[BM_GetIndex(l->v)]; + vmap->vert[BM_GetIndex(l->v)]= buf; + + buf++; + i++; + } + } + + a++; + } + + /* sort individual uvs for each vert */ + a = 0; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + UvMapVert *newvlist= NULL, *vlist=vmap->vert[a]; + UvMapVert *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while(vlist) { + v= vlist; + vlist= vlist->next; + v->next= newvlist; + newvlist= v; + + efa = EDBM_get_face_for_index(em, v->f); + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, v->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + uv = luv->uv; + + lastv= NULL; + iterv= vlist; + + while(iterv) { + next= iterv->next; + efa = EDBM_get_face_for_index(em, iterv->f); + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + uv2 = luv->uv; + + sub_v2_v2v2(uvdiff, uv2, uv); + + if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) { + if(lastv) lastv->next= next; + else vlist= next; + iterv->next= newvlist; + newvlist= iterv; + } + else + lastv=iterv; + + iterv= next; + } + + newvlist->separate = 1; + } + + vmap->vert[a]= newvlist; + a++; + } + + if (do_face_idx_array) + EDBM_free_index_arrays(em); + + return vmap; +} + + +UvMapVert *EDBM_get_uv_map_vert(UvVertMap *vmap, unsigned int v) +{ + return vmap->vert[v]; +} + +void EDBM_free_uv_vert_map(UvVertMap *vmap) +{ + if (vmap) { + if (vmap->vert) MEM_freeN(vmap->vert); + if (vmap->buf) MEM_freeN(vmap->buf); + MEM_freeN(vmap); + } +} + + +/* last_sel, use em->act_face otherwise get the last selected face in the editselections + * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */ +MTexPoly *EDBM_get_active_mtexpoly(BMEditMesh *em, BMFace **act_efa, int sloppy) +{ + BMFace *efa = NULL; + + if(!EDBM_texFaceCheck(em)) + return NULL; + + efa = EDBM_get_actFace(em, sloppy); + + if (efa) { + if (act_efa) *act_efa = efa; + return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + } + + if (act_efa) *act_efa= NULL; + return NULL; +} + +/* can we edit UV's for this mesh?*/ +int EDBM_texFaceCheck(BMEditMesh *em) +{ + /* some of these checks could be a touch overkill */ + return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) && + CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV); +} + +int EDBM_vertColorCheck(BMEditMesh *em) +{ + /* some of these checks could be a touch overkill */ + return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); +} + + +void EDBM_CacheMirrorVerts(BMEditMesh *em) +{ + BMBVHTree *tree = BMBVH_NewBVH(em); + BMIter iter; + BMVert *v; + float invmat[4][4]; + int li, i; + + if (!em->vert_index) { + EDBM_init_index_arrays(em, 1, 0, 0); + em->mirr_free_arrays = 1; + } + + if (!CustomData_get_layer_named(&em->bm->vdata, CD_PROP_INT, (char*)"__mirror_index")) { + BM_add_data_layer_named(em->bm, &em->bm->vdata, CD_PROP_INT, (char*)"__mirror_index"); + } + + li = CustomData_get_named_layer_index(&em->bm->vdata, CD_PROP_INT, "__mirror_index"); + em->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY; + + /*multiply verts by object matrix, temporarily*/ + + i = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, i); + i++; + + if (em->ob) + mul_m4_v3(em->ob->obmat, v->co); + } + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BMVert *mirr; + int *idx = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, li); + float co[3] = {-v->co[0], v->co[1], v->co[2]}; + + //temporary for testing, check for selection + if (!BM_TestHFlag(v, BM_SELECT)) + continue; + + mirr = BMBVH_FindClosestVertTopo(tree, co, BM_SEARCH_MAXDIST, v); + if (mirr && mirr != v) { + *idx = BM_GetIndex(mirr); + idx = CustomData_bmesh_get_layer_n(&em->bm->vdata,mirr->head.data, li); + *idx = BM_GetIndex(v); + } else *idx = -1; + } + + /*unmultiply by object matrix*/ + if (em->ob) { + i = 0; + invert_m4_m4(invmat, em->ob->obmat); + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, i); + i++; + + mul_m4_v3(invmat, v->co); + } + + BMBVH_FreeBVH(tree); + } +} + +BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v) +{ + int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); + + if (mirr && *mirr >=0 && *mirr < em->bm->totvert) { + if (!em->vert_index) { + printf("err: should only be called between " + "EDBM_CacheMirrorVerts and EDBM_EndMirrorCache"); + return NULL; + } + + return em->vert_index[*mirr]; + } + + return NULL; +} + +void EDBM_EndMirrorCache(BMEditMesh *em) +{ + if (em->mirr_free_arrays) { + MEM_freeN(em->vert_index); + em->vert_index = NULL; + } +} diff --git a/source/blender/editors/mesh/editbmesh_add.c b/source/blender/editors/mesh/editbmesh_add.c new file mode 100644 index 00000000000..b9a936d65b5 --- /dev/null +++ b/source/blender/editors/mesh/editbmesh_add.c @@ -0,0 +1,620 @@ + /* $Id: bmesh_tools.c + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2004 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" +#include "BLI_array.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_object.h" + +#include "UI_interface.h" + +#include "mesh_intern.h" +#include "bmesh.h" + +#include "editbmesh_bvh.h" + + +/* uses context to figure out transform for primitive */ +/* returns standard diameter */ +static float new_primitive_matrix(bContext *C, float *loc, float *rot, float primmat[][4]) +{ + Object *obedit= CTX_data_edit_object(C); + View3D *v3d =CTX_wm_view3d(C); + float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; + + unit_m4(primmat); + + eul_to_mat3(rmat, rot); + invert_m3(rmat); + + /* inverse transform for initial rotation and object */ + copy_m3_m4(mat, obedit->obmat); + mul_m3_m3m3(cmat, rmat, mat); + invert_m3_m3(imat, cmat); + copy_m4_m3(primmat, imat); + + /* center */ + VECCOPY(primmat[3], loc); + VECSUB(primmat[3], primmat[3], obedit->obmat[3]); + invert_m3_m3(imat, mat); + mul_m3_v3(imat, primmat[3]); + + if(v3d) return v3d->grid; + return 1.0f; +} + +/* ********* add primitive operators ************* */ + +static void make_prim_init(bContext *C, float *dia, float mat[][4], + int *state, float *loc, float *rot, unsigned int layer) +{ + Object *obedit= CTX_data_edit_object(C); + + *state = 0; + if(obedit==NULL || obedit->type!=OB_MESH) { + obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer); + + /* create editmode */ + ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ + *state = 1; + } + else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + + *dia *= new_primitive_matrix(C, loc, rot, mat); +} + +static void make_prim_finish(bContext *C, int *state, int enter_editmode) +{ + Object *obedit = CTX_data_edit_object(C); + + EDBM_selectmode_flush(((Mesh*)obedit->data)->edit_btmesh); + + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + /* userdef */ + if (*state && !enter_editmode) { + ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */ + } + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit); + +} +static int add_primitive_plane_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_grid xsegments=%i ysegments=%i size=%f mat=%m4", 1, 1, sqrt(2.0), mat)) + return OPERATOR_CANCELLED; + + /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */ + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_plane_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Plane"; + ot->description= "Construct a filled planar mesh with 4 vertices."; + ot->idname= "MESH_OT_primitive_plane_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_plane_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_cube_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit= CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_cube mat=%m4 size=%f", mat, 2.0f)) + return OPERATOR_CANCELLED; + + /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */ + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_cube_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Cube"; + ot->description= "Construct a cube mesh."; + ot->idname= "MESH_OT_primitive_cube_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_cube_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + ED_object_add_generic_props(ot, TRUE); +} + +static const EnumPropertyItem fill_type_items[]= { + {0, "NOTHING", 0, "Nothing", "Don't fill at all"}, + {1, "NGON", 0, "Ngon", "Use ngons"}, + {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"}, + {0, NULL, 0, NULL, NULL}}; + +static int add_primitive_circle_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state, cap_end, cap_tri; + unsigned int layer; + + cap_end = RNA_enum_get(op->ptr, "fill_type"); + cap_tri = cap_end==2; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_circle segments=%i diameter=%f cap_ends=%i cap_tris=%i mat=%m4", + RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), + cap_end, cap_tri, mat)) + return OPERATOR_CANCELLED; + + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_circle_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Circle"; + ot->description= "Construct a circle mesh."; + ot->idname= "MESH_OT_primitive_circle_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_circle_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500); + RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); + RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", ""); + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state, cap_end, cap_tri; + unsigned int layer; + + cap_end = RNA_enum_get(op->ptr, "end_fill_type"); + cap_tri = cap_end==2; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i cap_tris=%i depth=%f mat=%m4", + RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"), + RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat)) + return OPERATOR_CANCELLED; + + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Tube"; + ot->description= "Construct a tube mesh."; + ot->idname= "MESH_OT_primitive_cylinder_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_cylinder_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500); + RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); + RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); + RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", ""); + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_cone_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state, cap_end, cap_tri; + unsigned int layer; + + cap_end = RNA_enum_get(op->ptr, "end_fill_type"); + cap_tri = cap_end==2; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i cap_tris=%i depth=%f mat=%m4", + RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"), + RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat)) + return OPERATOR_CANCELLED; + + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_cone_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Cone"; + ot->description= "Construct a conic mesh (ends filled)."; + ot->idname= "MESH_OT_primitive_cone_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_cone_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500); + RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00); + RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00); + RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); + RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", ""); + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_grid_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_grid xsegments=%i ysegments=%i size=%f mat=%m4", + RNA_int_get(op->ptr, "x_subdivisions"), + RNA_int_get(op->ptr, "y_subdivisions"), + RNA_float_get(op->ptr, "size"), mat)) + { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, &state, enter_editmode); + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_grid_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Grid"; + ot->description= "Construct a grid mesh."; + ot->idname= "MESH_OT_primitive_grid_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_grid_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000); + RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000); + RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX); + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_monkey_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state, view_aligned; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &view_aligned); + if (!view_aligned) + rot[0] += M_PI/2.0f; + + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_monkey mat=%m4", mat)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, &state, enter_editmode); + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_monkey_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Monkey"; + ot->description= "Construct a Suzanne mesh."; + ot->idname= "MESH_OT_primitive_monkey_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_monkey_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + ED_object_add_generic_props(ot, TRUE); +} + + +static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_uvsphere segments=%i revolutions=%i diameter=%f mat=%m4", + RNA_int_get(op->ptr, "rings"), RNA_int_get(op->ptr, "segments"), + RNA_float_get(op->ptr,"size"), mat)) + return OPERATOR_CANCELLED; + + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add UV Sphere"; + ot->description= "Construct a UV sphere mesh."; + ot->idname= "MESH_OT_primitive_uv_sphere_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_uvsphere_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500); + RNA_def_int(ot->srna, "rings", 24, INT_MIN, INT_MAX, "Rings", "", 3, 500); + RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00); + + ED_object_add_generic_props(ot, TRUE); +} + +static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; + float loc[3], rot[3], mat[4][4], dia; + int enter_editmode; + int state; + unsigned int layer; + + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; + + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_icosphere subdivisions=%i diameter=%f mat=%m4", + RNA_int_get(op->ptr, "subdivisions"), + RNA_float_get(op->ptr, "size"), mat)) { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, &state, enter_editmode); + + return OPERATOR_FINISHED; +} + +void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Add Ico Sphere"; + ot->description= "Construct an Icosphere mesh."; + ot->idname= "MESH_OT_primitive_ico_sphere_add"; + + /* api callbacks */ + ot->invoke= ED_object_add_generic_invoke; + ot->exec= add_primitive_icosphere_exec; + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + /* props */ + RNA_def_int(ot->srna, "subdivisions", 2, 0, 6, "Subdivisions", "", 0, 8); + RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00); + + ED_object_add_generic_props(ot, TRUE); +} diff --git a/source/blender/editors/mesh/editbmesh_bvh.c b/source/blender/editors/mesh/editbmesh_bvh.c new file mode 100644 index 00000000000..fcefeb6ce6b --- /dev/null +++ b/source/blender/editors/mesh/editbmesh_bvh.c @@ -0,0 +1,724 @@ + /* $Id: + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2010 by Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ +#define IN_EDITMESHBVH + +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <math.h> +#include <float.h> + +#include "MEM_guardedalloc.h" +#include "PIL_time.h" + +#include "BLO_sys_types.h" // for intptr_t support + +#include "DNA_mesh_types.h" +#include "DNA_material_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" +#include "DNA_key_types.h" + +#include "RNA_types.h" +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_editVert.h" +#include "BLI_rand.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_heap.h" +#include "BLI_array.h" +#include "BLI_kdopbvh.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_depsgraph.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_util.h" +#include "ED_screen.h" +#include "ED_transform.h" + +#include "UI_interface.h" + +#include "mesh_intern.h" +#include "bmesh.h" + +#include "editbmesh_bvh.h" + +typedef struct BMBVHTree { + BMEditMesh *em; + BMesh *bm; + BVHTree *tree; + float epsilon; + float maxdist; //for nearest point search + + /*stuff for topological vert search*/ + BMVert *v, *curv; + GHash *gh; + float curw, curd; + float co[3]; + int curtag; +} BMBVHTree; + +BMBVHTree *BMBVH_NewBVH(BMEditMesh *em) +{ + BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree"); + float cos[3][3]; + int i; + + BMEdit_RecalcTesselation(em); + + tree->em = em; + tree->bm = em->bm; + tree->epsilon = FLT_EPSILON*2.0f; + + tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8); + + for (i=0; i<em->tottri; i++) { + VECCOPY(cos[0], em->looptris[i][0]->v->co); + VECCOPY(cos[1], em->looptris[i][1]->v->co); + VECCOPY(cos[2], em->looptris[i][2]->v->co); + + BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3); + } + + BLI_bvhtree_balance(tree->tree); + + return tree; +} + +void BMBVH_FreeBVH(BMBVHTree *tree) +{ + BLI_bvhtree_free(tree->tree); + MEM_freeN(tree); +} + +/*taken from bvhutils.c*/ +static float ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), float *v0, + float *v1, float *v2, float *uv, float UNUSED(e)) +{ + float dist; +#if 0 + float vv1[3], vv2[3], vv3[3], cent[3]; + + /*expand triangle by an epsilon. this is probably a really stupid + way of doing it, but I'm too tired to do better work.*/ + VECCOPY(vv1, v0); + VECCOPY(vv2, v1); + VECCOPY(vv3, v2); + + add_v3_v3v3(cent, vv1, vv2); + add_v3_v3v3(cent, cent, vv3); + mul_v3_fl(cent, 1.0f/3.0f); + + sub_v3_v3v3(vv1, vv1, cent); + sub_v3_v3v3(vv2, vv2, cent); + sub_v3_v3v3(vv3, vv3, cent); + + mul_v3_fl(vv1, 1.0f + e); + mul_v3_fl(vv2, 1.0f + e); + mul_v3_fl(vv3, 1.0f + e); + + add_v3_v3v3(vv1, vv1, cent); + add_v3_v3v3(vv2, vv2, cent); + add_v3_v3v3(vv3, vv3, cent); + + if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, vv1, vv2, vv3, &dist, uv)) + return dist; +#else + if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv)) + return dist; +#endif + + return FLT_MAX; +} + +static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit) +{ + BMBVHTree *tree = userdata; + BMLoop **ls = tree->em->looptris[index]; + float dist, uv[2]; + + if (!ls[0] || !ls[1] || !ls[2]) + return; + + dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co, + ls[2]->v->co, uv, tree->epsilon); + if (dist < hit->dist) { + hit->dist = dist; + hit->index = index; + + VECCOPY(hit->no, ls[0]->v->no); + + copy_v3_v3(hit->co, ray->direction); + normalize_v3(hit->co); + mul_v3_fl(hit->co, dist); + add_v3_v3(hit->co, ray->origin); + } +} + +BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout) +{ + BVHTreeRayHit hit; + + hit.dist = FLT_MAX; + hit.index = -1; + + BLI_bvhtree_ray_cast(tree->tree, co, dir, 0.0f, &hit, raycallback, tree); + if (hit.dist != FLT_MAX && hit.index != -1) { + if (hitout) { + VECCOPY(hitout, hit.co); + } + + return tree->em->looptris[hit.index][0]->f; + } + + return NULL; +} + +BVHTree *BMBVH_BVHTree(BMBVHTree *tree) +{ + return tree->tree; +} + +static void vertsearchcallback(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *hit) +{ + BMBVHTree *tree = userdata; + BMLoop **ls = tree->em->looptris[index]; + float dist, maxdist, v[3]; + int i; + + maxdist = tree->maxdist; + + for (i=0; i<3; i++) { + sub_v3_v3v3(v, hit->co, ls[i]->v->co); + + dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); + if (dist < hit->dist && dist < maxdist) { + VECCOPY(hit->co, ls[i]->v->co); + VECCOPY(hit->no, ls[i]->v->no); + hit->dist = dist; + } + } +} + +BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist) +{ + BVHTreeNearest hit; + + VECCOPY(hit.co, co); + hit.dist = maxdist*5; + hit.index = -1; + + tree->maxdist = maxdist; + + BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback, tree); + if (hit.dist != FLT_MAX && hit.index != -1) { + BMLoop **ls = tree->em->looptris[hit.index]; + float dist, curdist = tree->maxdist, v[3]; + int cur=0, i; + + maxdist = tree->maxdist; + + for (i=0; i<3; i++) { + sub_v3_v3v3(v, hit.co, ls[i]->v->co); + + dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]); + if (dist < curdist) { + cur = i; + curdist = dist; + } + } + + return ls[i]->v; + } + + return NULL; +} + +typedef struct walklist { + BMVert *v; + int valence; + int depth; + float w, r; + int totwalked; + + /*state data*/ + BMVert *lastv; + BMLoop *curl, *firstl; + BMEdge *cure; +} walklist; + + +static short winding(float *v1, float *v2, float *v3) +/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */ +{ + double inp; + + //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]); + inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]); + + if(inp<0.0) return 0; + else if(inp==0) { + if(v1[0]==v3[0] && v1[1]==v3[1]) return 0; + if(v2[0]==v3[0] && v2[1]==v3[1]) return 0; + } + return 1; +} + +static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2) +{ + BMIter iter1, iter2; + BMEdge *e1, *e2, *cure1 = NULL, *cure2 = NULL; + BMLoop *l1, *l2; + BMVert *lastv1, *lastv2; + GHash *gh; + walklist *stack1=NULL, *stack2=NULL; + BLI_array_declare(stack1); + BLI_array_declare(stack2); + float vec1[3], vec2[3], minangle=FLT_MAX, w; + int lvl=1; + static int maxlevel = 3; + + /*ok. see how similar v is to v2, based on topological similaritys in the local + topological neighborhood*/ + + /*step 1: find two edges, one that contains v and one that contains v2, with the + smallest angle between the two edges*/ + + BM_ITER(e1, &iter1, bm, BM_EDGES_OF_VERT, v1) { + BM_ITER(e2, &iter2, bm, BM_EDGES_OF_VERT, v2) { + float angle; + + if (e1->v1 == e2->v1 || e1->v2 == e2->v2 || e1->v1 == e2->v2 || e1->v2 == e2->v1) + continue; + + sub_v3_v3v3(vec1, BM_OtherEdgeVert(e1, v1)->co, v1->co); + sub_v3_v3v3(vec2, BM_OtherEdgeVert(e2, v2)->co, v2->co); + + angle = fabs(angle_v3v3(vec1, vec2)); + + if (angle < minangle) { + minangle = angle; + cure1 = e1; + cure2 = e2; + } + } + } + + if (!cure1 || !cure1->l || !cure2->l) { + /*just return 1.0 in this case*/ + return 1.0f; + } + + /*assumtions + + we assume a 2-manifold mesh here. if at any time this isn't the case, + e.g. a hole or an edge with more then 2 faces around it, we um ignore + that edge I guess, and try to make the algorithm go around as necassary.*/ + + l1 = cure1->l; + l2 = cure2->l; + + lastv1 = l1->v == v1 ? ((BMLoop*)l1->next)->v : ((BMLoop*)l1->prev)->v; + lastv2 = l2->v == v2 ? ((BMLoop*)l2->next)->v : ((BMLoop*)l2->prev)->v; + + /*we can only provide meaningful comparisons if v1 and v2 have the same valence*/ + if (BM_Vert_EdgeCount(v1) != BM_Vert_EdgeCount(v2)) + return 1.0f; /*full mismatch*/ + + gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh"); + +#define SPUSH(s, d, vt, lv, e)\ + if (BLI_array_count(s) <= lvl) BLI_array_growone(s);\ + memset((s+lvl), 0, sizeof(*s));\ + s[lvl].depth = d;\ + s[lvl].v = vt;\ + s[lvl].cure = e;\ + s[lvl].lastv = lv;\ + s[lvl].valence = BM_Vert_EdgeCount(vt);\ + + lvl = 0; + + SPUSH(stack1, 0, v1, lastv1, cure1); + SPUSH(stack2, 0, v2, lastv2, cure2); + + BLI_srand( BLI_rand() ); /* random seed */ + + lvl = 1; + while (lvl) { + int term = 0; + walklist *s1 = stack1 + lvl - 1, *s2 = stack2 + lvl - 1; + + /*pop from the stack*/ + lvl--; + + if (s1->curl && s1->curl->e == s1->cure) + term = 1; + if (s2->curl && s2->curl->e == s2->cure) + term = 1; + + /*find next case to do*/ + if (!s1->curl) + s1->curl = s1->cure->l; + if (!s2->curl) { + float no1[3], no2[3], angle; + int wind1, wind2; + + s2->curl = s2->cure->l; + + /*find which of two possible faces to use*/ + l1 = BM_OtherFaceLoop(s1->curl->e, s1->curl->f, s1->lastv); + l2 = BM_OtherFaceLoop(s2->curl->e, s2->curl->f, s2->lastv); + + if (l1->v == s2->lastv) { + l1 = (BMLoop*) l1->next; + if (l1->v == s2->v) + l1 = (BMLoop*) l1->prev->prev; + } else if (l1->v == s2->v) { + l1 = (BMLoop*) l1->next; + if (l1->v == s2->lastv) + l1 = (BMLoop*) l1->prev->prev; + } + + if (l2->v == s2->lastv) { + l2 = (BMLoop*) l2->next; + if (l2->v == s2->v) + l2 = (BMLoop*) l2->prev->prev; + } else if (l2->v == s2->v) { + l2 = (BMLoop*) l2->next; + if (l2->v == s2->lastv) + l2 = (BMLoop*) l2->prev->prev; + } + + wind1 = winding(s1->v->co, s1->lastv->co, l1->v->co); + + wind2 = winding(s2->v->co, s2->lastv->co, l2->v->co); + + /*if angle between the two adjacent faces is greater then 90 degrees, + we need to flip wind2*/ + l1 = l2; + l2 = s2->curl->radial_next; + l2 = BM_OtherFaceLoop(l2->e, l2->f, s2->lastv); + + if (l2->v == s2->lastv) { + l2 = (BMLoop*) l2->next; + if (l2->v == s2->v) + l2 = (BMLoop*) l2->prev->prev; + } else if (l2->v == s2->v) { + l2 = (BMLoop*) l2->next; + if (l2->v == s2->lastv) + l2 = (BMLoop*) l2->prev->prev; + } + + normal_tri_v3(no1, s2->v->co, s2->lastv->co, l1->v->co); + normal_tri_v3(no2, s2->v->co, s2->lastv->co, l2->v->co); + + /*enforce identical winding as no1*/ + mul_v3_fl(no2, -1.0); + + angle = angle_v3v3(no1, no2); + if (angle > M_PI/2 - FLT_EPSILON*2) + wind2 = !wind2; + + if (wind1 == wind2) + s2->curl = s2->curl->radial_next; + } + + /*handle termination cases of having already looped through all child + nodes, or the valence mismatching between v1 and v2, or we hit max + recursion depth*/ + term |= s1->valence != s2->valence || lvl+1 > maxlevel; + term |= s1->curl->radial_next == (BMLoop*)l1; + term |= s2->curl->radial_next == (BMLoop*)l2; + + if (!term) { + lastv1 = s1->v; + lastv2 = s2->v; + v1 = BM_OtherEdgeVert(s1->curl->e, lastv1); + v2 = BM_OtherEdgeVert(s2->curl->e, lastv2); + + e1 = s1->curl->e; + e2 = s2->curl->e; + + if (!BLI_ghash_haskey(gh, v1) && !BLI_ghash_haskey(gh, v2)) { + /*repush the current stack item*/ + lvl++; + + //if (maxlevel % 2 == 0) { + BLI_ghash_insert(gh, v1, NULL); + BLI_ghash_insert(gh, v2, NULL); + //} + + /*now push the child node*/ + SPUSH(stack1, lvl, v1, lastv1, e1); + SPUSH(stack2, lvl, v2, lastv2, e2); + + lvl++; + + s1 = stack1 + lvl - 2; + s2 = stack2 + lvl - 2; + } + + s1->curl = s1->curl->v == s1->v ? (BMLoop*) s1->curl->prev : (BMLoop*) s1->curl->next; + s2->curl = s2->curl->v == s2->v ? (BMLoop*) s2->curl->prev : (BMLoop*) s2->curl->next; + + s1->curl = (BMLoop*) s1->curl->radial_next; + s2->curl = (BMLoop*) s2->curl->radial_next; + } + +#define WADD(stack, s)\ + if (lvl) {/*silly attempt to make this non-commutative: randomize\ + how much this particular weight adds to the total*/\ + stack[lvl-1].r += r;\ + s->w *= r;\ + stack[lvl-1].totwalked++;\ + stack[lvl-1].w += s->w;\ + } + + /*if no next case to do, update parent weight*/ + if (term) { + float r = 0.8f + BLI_frand()*0.2f - FLT_EPSILON; + + if (s1->totwalked) { + s1->w /= s1->r; + } else + s1->w = s1->valence == s2->valence ? 1.0f : 0.0f; + + WADD(stack1, s1); + + if (s2->totwalked) { + s2->w /= s2->r; + } else + s2->w = s1->valence == s2->valence ? 1.0f : 0.0f; + + WADD(stack2, s2); + + /*apply additional penalty to weight mismatch*/ + if (s2->w != s1->w) + s2->w *= 0.8f; + } + } + + w = (stack1[0].w + stack2[0].w)*0.5f; + + BLI_array_free(stack1); + BLI_array_free(stack2); + + BLI_ghash_free(gh, NULL, NULL); + + return 1.0f - w; +} + +static void vertsearchcallback_topo(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *UNUSED(hit)) +{ + BMBVHTree *tree = userdata; + BMLoop **ls = tree->em->looptris[index]; + int i; + float maxdist, vec[3], w; + + maxdist = tree->maxdist; + + for (i=0; i<3; i++) { + float dis; + + if (BLI_ghash_haskey(tree->gh, ls[i]->v)) + continue; + + sub_v3_v3v3(vec, tree->co, ls[i]->v->co); + dis = dot_v3v3(vec, vec); + + w = topo_compare(tree->em->bm, tree->v, ls[i]->v); + tree->curtag++; + + if (w < tree->curw-FLT_EPSILON*4) { + tree->curw = w; + tree->curv = ls[i]->v; + + sub_v3_v3v3(vec, tree->co, ls[i]->v->co); + tree->curd = dot_v3v3(vec, vec); + + /*we deliberately check for equality using (smallest possible float)*4 + comparison factor, to always prefer distance in cases of verts really + close to each other*/ + } else if (fabs(tree->curw - w) < FLT_EPSILON*4) { + /*if w is equal to hitex->curw, sort by distance*/ + sub_v3_v3v3(vec, tree->co, ls[i]->v->co); + dis = dot_v3v3(vec, vec); + + if (dis < tree->curd) { + tree->curd = dis; + tree->curv = ls[i]->v; + } + } + + BLI_ghash_insert(tree->gh, ls[i]->v, NULL); + } +} + +BMVert *BMBVH_FindClosestVertTopo(BMBVHTree *tree, float *co, float maxdist, BMVert *sourcev) +{ + BVHTreeNearest hit; + + memset(&hit, 0, sizeof(hit)); + + VECCOPY(hit.co, co); + VECCOPY(tree->co, co); + hit.index = -1; + hit.dist = maxdist; + + tree->curw = FLT_MAX; + tree->curd = FLT_MAX; + tree->curv = NULL; + tree->curtag = 1; + + tree->gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh"); + + tree->maxdist = maxdist; + tree->v = sourcev; + + BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback_topo, tree); + + BLI_ghash_free(tree->gh, NULL, NULL); + tree->gh = NULL; + + return tree->curv; +} + + +#if 0 //BMESH_TODO: not implemented yet +int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) +{ + +} +#endif + +static BMFace *edge_ray_cast(BMBVHTree *tree, float *co, float *dir, float *hitout, BMEdge *e) +{ + BMFace *f = BMBVH_RayCast(tree, co, dir, hitout); + + if (f && BM_Edge_In_Face(f, e)) + return NULL; + + return f; +} + +static void scale_point(float *c1, float *p, float s) +{ + sub_v3_v3(c1, p); + mul_v3_fl(c1, s); + add_v3_v3(c1, p); +} + + +int BMBVH_EdgeVisible(BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v3d, Object *obedit) +{ + BMFace *f; + float co1[3], co2[3], co3[3], dir1[4], dir2[4], dir3[4]; + float origin[3], invmat[4][4]; + float epsilon = 0.01f; + float mval_f[2], end[3]; + + if (!ar) { + printf("error in BMBVH_EdgeVisible!\n"); + return 0; + } + + mval_f[0] = ar->winx/2.0; + mval_f[1] = ar->winy/2.0; + ED_view3d_win_to_segment_clip(ar, v3d, mval_f, origin, end); + + invert_m4_m4(invmat, obedit->obmat); + mul_m4_v3(invmat, origin); + + VECCOPY(co1, e->v1->co); + add_v3_v3v3(co2, e->v1->co, e->v2->co); + mul_v3_fl(co2, 0.5f); + VECCOPY(co3, e->v2->co); + + scale_point(co1, co2, 0.99); + scale_point(co3, co2, 0.99); + + /*ok, idea is to generate rays going from the camera origin to the + three points on the edge (v1, mid, v2)*/ + sub_v3_v3v3(dir1, origin, co1); + sub_v3_v3v3(dir2, origin, co2); + sub_v3_v3v3(dir3, origin, co3); + + normalize_v3(dir1); + normalize_v3(dir2); + normalize_v3(dir3); + + mul_v3_fl(dir1, epsilon); + mul_v3_fl(dir2, epsilon); + mul_v3_fl(dir3, epsilon); + + /*offset coordinates slightly along view vectors, to avoid + hitting the faces that own the edge.*/ + add_v3_v3v3(co1, co1, dir1); + add_v3_v3v3(co2, co2, dir2); + add_v3_v3v3(co3, co3, dir3); + + normalize_v3(dir1); + normalize_v3(dir2); + normalize_v3(dir3); + + /*do three samplings: left, middle, right*/ + f = edge_ray_cast(tree, co1, dir1, NULL, e); + if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) + return 1; + else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) + return 1; + else if (!f) + return 1; + + return 0; +} diff --git a/source/blender/editors/mesh/editbmesh_bvh.h b/source/blender/editors/mesh/editbmesh_bvh.h new file mode 100644 index 00000000000..c8decd24f38 --- /dev/null +++ b/source/blender/editors/mesh/editbmesh_bvh.h @@ -0,0 +1,31 @@ +#ifndef _EDITBMESH_BVH +#define _EDITBMESH_BVH + +struct BMEditMesh; +struct BMFace; +struct BMEdge; +struct BMVert; +struct RegionView3D; +struct BMBVHTree; +struct BVHTree; + +#ifndef IN_EDITMESHBVH +typedef struct BMBVHTree BMBVHTree; +#endif + +struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em); +void BMBVH_FreeBVH(struct BMBVHTree *tree); +struct BVHTree *BMBVH_BVHTree(struct BMBVHTree *tree); + +struct BMFace *BMBVH_RayCast(struct BMBVHTree *tree, float *co, float *dir, float *hitout); + +int BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, + struct ARegion *ar, struct View3D *v3d, struct Object *obedit); + +#define BM_SEARCH_MAXDIST 0.4f + +/*find a vert closest to co in a sphere of radius maxdist*/ +struct BMVert *BMBVH_FindClosestVert(struct BMBVHTree *tree, float *co, float maxdist); +struct BMVert *BMBVH_FindClosestVertTopo(struct BMBVHTree *tree, float *co, + float maxdist, struct BMVert *sourcev); +#endif /* _EDITBMESH_H */ diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index ab62c88deaa..91e45dbc688 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. @@ -36,6 +36,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_heap.h" @@ -54,6 +55,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BIF_gl.h" @@ -73,40 +75,47 @@ void paintface_flush_flags(Object *ob) { Mesh *me= get_mesh(ob); DerivedMesh *dm= ob->derivedFinal; - MFace *faces, *mf, *mf_orig; - int *index_array = NULL; + MPoly *mf_orig, *mp; + int *index = NULL; int totface; int i; if(me==NULL || dm==NULL) return; - index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); - - if(!index_array) - return; - - faces = dm->getFaceArray(dm); totface = dm->getNumFaces(dm); - - mf= faces; - - for (i= 0; i<totface; i++, mf++) { /* loop over derived mesh faces */ - mf_orig= me->mface + index_array[i]; - mf->flag= mf_orig->flag; + index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + mp = dm->getPolyArray(dm); + for (i=0; i<dm->numPolyData; i++, index++, mp++) { + if (!index) + break; + + mf_orig = me->mpoly + *index; + mp->flag = mf_orig->flag; } } /* returns 0 if not found, otherwise 1 */ -static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], unsigned int *index, short rect) +static int facesel_face_pick(struct bContext *C, Mesh *me, Object *ob, const int mval[2], unsigned int *index, short rect) { + Scene *scene = CTX_data_scene(C); ViewContext vc; view3d_set_viewcontext(C, &vc); - if (!me || me->totface==0) + if (!me || me->totpoly==0) return 0; -// XXX if (v3d->flag & V3D_INVALID_BACKBUF) { + /*we can't assume mfaces have a correct origindex layer that indices to mpolys. + so instead we have to regenerate the tesselation faces altogether. + + the final 0, 0 paramters causes it to use the index of each mpoly, instead + of reading from the origindex layer.*/ + me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, + me->mvert, me->totface, me->totloop, me->totpoly, 0, 0); + mesh_update_customdata_pointers(me); + makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0); + + // XXX if (v3d->flag & V3D_INVALID_BACKBUF) { // XXX drawview.c! check_backbuf(); // XXX persp(PERSP_VIEW); // XXX } @@ -123,7 +132,7 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un *index = view3d_sample_backbuf(&vc, mval[0], mval[1]); } - if ((*index)<=0 || (*index)>(unsigned int)me->totface) + if ((*index)<=0 || (*index)>(unsigned int)me->totpoly) return 0; (*index)--; @@ -133,41 +142,35 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un /* last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */ -MTFace *EM_get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy) +static MTexPoly *EDBM_get_active_mtface(BMEditMesh *em, BMFace **act_efa, int sloppy) { - EditFace *efa = NULL; + BMFace *efa = NULL; - if(!EM_texFaceCheck(em)) + if(!EDBM_texFaceCheck(em)) return NULL; - efa = EM_get_actFace(em, sloppy); + efa = EDBM_get_actFace(em, sloppy); if (efa) { - if (mcol) { - if (CustomData_has_layer(&em->fdata, CD_MCOL)) - *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - else - *mcol = NULL; - } if (act_efa) *act_efa = efa; - return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); } + if (act_efa) *act_efa= NULL; - if(mcol) *mcol = NULL; return NULL; } void paintface_hide(Object *ob, const int unselected) { Mesh *me; - MFace *mface; + MPoly *mface; int a; me= get_mesh(ob); - if(me==NULL || me->totface==0) return; + if(me==NULL || me->totpoly==0) return; - mface= me->mface; - a= me->totface; + mface= me->mpoly; + a= me->totpoly; while(a--) { if((mface->flag & ME_HIDE) == 0) { if(unselected) { @@ -189,14 +192,14 @@ void paintface_hide(Object *ob, const int unselected) void paintface_reveal(Object *ob) { Mesh *me; - MFace *mface; + MPoly *mface; int a; me= get_mesh(ob); - if(me==NULL || me->totface==0) return; + if(me==NULL || me->totpoly==0) return; - mface= me->mface; - a= me->totface; + mface= me->mpoly; + a= me->totpoly; while(a--) { if(mface->flag & ME_HIDE) { mface->flag |= ME_FACE_SEL; @@ -210,30 +213,30 @@ void paintface_reveal(Object *ob) /* Set tface seams based on edge data, uses hash table to find seam edges. */ -static void hash_add_face(EdgeHash *ehash, MFace *mf) +static void hash_add_face(EdgeHash *ehash, MPoly *mf, MLoop *mloop) { - BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL); - BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL); - if(mf->v4) { - BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL); - BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL); - } - else - BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL); + MLoop *ml, *ml2; + int i; + + for (i=0, ml=mloop; i<mf->totloop; i++, ml++) { + ml2 = mloop + (i+1) % mf->totloop; + BLI_edgehash_insert(ehash, ml->v, ml2->v, NULL); + } } static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index) { - MFace *mf; - int a, doit=1, mark=0; - char *linkflag; EdgeHash *ehash, *seamhash; + MPoly *mf; + MLoop *ml; MEdge *med; + char *linkflag; + int a, b, doit=1, mark=0; ehash= BLI_edgehash_new(); seamhash = BLI_edgehash_new(); - linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv"); + linkflag= MEM_callocN(sizeof(char)*me->totpoly, "linkflaguv"); for(med=me->medge, a=0; a < me->totedge; a++, med++) if(med->flag & ME_SEAM) @@ -241,17 +244,17 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind if (mode==0 || mode==1) { /* only put face under cursor in array */ - mf= ((MFace*)me->mface) + index; - hash_add_face(ehash, mf); + mf= ((MPoly*)me->mpoly) + index; + hash_add_face(ehash, mf, me->mloop + mf->loopstart); linkflag[index]= 1; } else { /* fill array by selection */ - mf= me->mface; - for(a=0; a<me->totface; a++, mf++) { + mf= me->mpoly; + for(a=0; a<me->totpoly; a++, mf++) { if(mf->flag & ME_HIDE); else if(mf->flag & ME_FACE_SEL) { - hash_add_face(ehash, mf); + hash_add_face(ehash, mf, me->mloop + mf->loopstart); linkflag[a]= 1; } } @@ -261,35 +264,26 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind doit= 0; /* expand selection */ - mf= me->mface; - for(a=0; a<me->totface; a++, mf++) { + mf= me->mpoly; + for(a=0; a<me->totpoly; a++, mf++) { if(mf->flag & ME_HIDE) continue; if(!linkflag[a]) { + MLoop *mnextl; mark= 0; - if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2)) - if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2)) - mark= 1; - if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3)) - if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3)) - mark= 1; - if(mf->v4) { - if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4)) - if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4)) - mark= 1; - if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1)) - if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1)) - mark= 1; + ml = me->mloop + mf->loopstart; + for (b=0; b<mf->totloop; b++, ml++) { + mnextl = b < mf->totloop-1 ? ml - 1 : me->mloop + mf->loopstart; + if (!BLI_edgehash_haskey(seamhash, ml->v, mnextl->v)) + if (!BLI_edgehash_haskey(ehash, ml->v, mnextl->v)) + mark = 1; } - else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1)) - if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1)) - mark = 1; if(mark) { linkflag[a]= 1; - hash_add_face(ehash, mf); + hash_add_face(ehash, mf, me->mloop + mf->loopstart); doit= 1; } } @@ -301,24 +295,24 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind BLI_edgehash_free(seamhash, NULL); if(mode==0 || mode==2) { - for(a=0, mf=me->mface; a<me->totface; a++, mf++) + for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) if(linkflag[a]) mf->flag |= ME_FACE_SEL; else mf->flag &= ~ME_FACE_SEL; } else if(mode==1) { - for(a=0, mf=me->mface; a<me->totface; a++, mf++) + for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) if(linkflag[a] && (mf->flag & ME_FACE_SEL)) break; - if (a<me->totface) { - for(a=0, mf=me->mface; a<me->totface; a++, mf++) + if (a<me->totpoly) { + for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) if(linkflag[a]) mf->flag &= ~ME_FACE_SEL; } else { - for(a=0, mf=me->mface; a<me->totface; a++, mf++) + for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) if(linkflag[a]) mf->flag |= ME_FACE_SEL; } @@ -333,7 +327,7 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2] unsigned int index=0; me = get_mesh(ob); - if(me==NULL || me->totface==0) return; + if(me==NULL || me->totpoly==0) return; if (mode==0 || mode==1) { // XXX - Causes glitches, not sure why @@ -349,31 +343,30 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2] } /* note: caller needs to run paintface_flush_flags(ob) after this */ -void paintface_deselect_all_visible(Object *ob, int action, short flush_flags) +void paintface_deselect_all_visible(Object *ob, int action, short UNUSED(flush_flags)) { Mesh *me; - MFace *mface; + MPoly *mface; int a; me= get_mesh(ob); if(me==NULL) return; if(action == SEL_INVERT) { - mface= me->mface; - a= me->totface; + mface= me->mpoly; + a= me->totpoly; while(a--) { if((mface->flag & ME_HIDE) == 0) { mface->flag ^= ME_FACE_SEL; } mface++; } - } - else { + } else { if (action == SEL_TOGGLE) { action = SEL_SELECT; - mface= me->mface; - a= me->totface; + mface= me->mpoly; + a= me->totpoly; while(a--) { if((mface->flag & ME_HIDE) == 0 && mface->flag & ME_FACE_SEL) { action = SEL_DESELECT; @@ -382,55 +375,65 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags) mface++; } } - - mface= me->mface; - a= me->totface; - while(a--) { - if((mface->flag & ME_HIDE) == 0) { - switch (action) { - case SEL_SELECT: - mface->flag |= ME_FACE_SEL; - break; - case SEL_DESELECT: - mface->flag &= ~ME_FACE_SEL; - break; - case SEL_INVERT: - mface->flag ^= ME_FACE_SEL; - break; - } - } - mface++; - } } - if(flush_flags) { - paintface_flush_flags(ob); + //BMESH_TODO object_facesel_flush_dm(ob); +// XXX notifier! object_tface_flags_changed(OBACT, 0); +} + +static void selectswap_tface(Scene *scene) +{ + Mesh *me; + MPoly *mface; + int a; + + me= get_mesh(OBACT); + if(me==0) return; + + mface= me->mpoly; + a= me->totpoly; + while(a--) { + if(mface->flag & ME_HIDE); + else { + if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL; + else mface->flag |= ME_FACE_SEL; + } } } int paintface_minmax(Object *ob, float *min, float *max) { - Mesh *me= get_mesh(ob); - MFace *mf; + Mesh *me; + MPoly *mf; + MTexPoly *tf; + MLoop *ml; MVert *mv; - int a, ok=0; - float vec[3]; + int a, b, ok=0; + float vec[3], bmat[3][3]; - if(me==NULL) - return ok; + me= get_mesh(ob); + if(!me || !me->mtpoly) return ok; + + copy_m3_m4(bmat, ob->obmat); mv= me->mvert; - mf= me->mface; - for (a=me->totface; a>0; a--, mf++) { - if ((mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL)) == 0) { - int i= mf->v4 ? 3:2; - do { - mul_v3_m4v3(vec, ob->obmat, (mv + (*(&mf->v1 + i)))->co); - DO_MINMAX(vec, min, max); - } while (i--); - ok= 1; + mf= me->mpoly; + tf= me->mtpoly; + for (a=me->totpoly; a>0; a--, mf++, tf++) { + if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL)) + continue; + + ml = me->mloop + mf->totloop; + for (b=0; b<mf->totloop; b++, ml++) { + VECCOPY(vec, (mv+ml->v)->co); + mul_m3_v3(bmat, vec); + add_v3_v3v3(vec, vec, ob->obmat[3]); + DO_MINMAX(vec, min, max); } + + ok= 1; } + return ok; } @@ -438,12 +441,12 @@ int paintface_minmax(Object *ob, float *min, float *max) #define ME_SEAM_DONE 2 /* reuse this flag */ -static float edgetag_cut_cost(int e1, int e2, int vert) +static float edgetag_cut_cost(BMEditMesh *em, int e1, int e2, int vert) { - EditVert *v = EM_get_vert_for_index(vert); - EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2); - EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l ); - EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l ); + BMVert *v = EDBM_get_vert_for_index(em, vert); + BMEdge *eed1 = EDBM_get_edge_for_index(em, e1), *eed2 = EDBM_get_edge_for_index(em, e2); + BMVert *v1 = EDBM_get_vert_for_index(em, (BM_GetIndex(eed1->v1) == vert)? BM_GetIndex(eed1->v2): vert ); + BMVert *v2 = EDBM_get_vert_for_index(em, (BM_GetIndex(eed2->v1) == vert)? BM_GetIndex(eed2->v2): vert ); float cost, d1[3], d2[3]; cost = len_v3v3(v1->co, v->co); @@ -457,19 +460,20 @@ static float edgetag_cut_cost(int e1, int e2, int vert) return cost; } -static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost) +static void edgetag_add_adjacent(BMEditMesh *em, Heap *heap, int mednum, int vertnum, + int *nedges, int *edges, int *prevedge, float *cost) { int startadj, endadj = nedges[vertnum+1]; for (startadj = nedges[vertnum]; startadj < endadj; startadj++) { int adjnum = edges[startadj]; - EditEdge *eedadj = EM_get_edge_for_index(adjnum); + BMEdge *eedadj = EDBM_get_edge_for_index(em, adjnum); float newcost; - if (eedadj->f2 & ME_SEAM_DONE) + if (eedadj->head.flags[0].f & ME_SEAM_DONE) continue; - newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum); + newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum); if (cost[adjnum] > newcost) { cost[adjnum] = newcost; @@ -479,72 +483,94 @@ static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedge } } -void edgetag_context_set(Scene *scene, EditEdge *eed, int val) +void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val) { switch (scene->toolsettings->edge_mode) { case EDGE_MODE_SELECT: - EM_select_edge(eed, val); + BM_Select(em->bm, eed, val); break; case EDGE_MODE_TAG_SEAM: - if (val) {eed->seam = 255;} - else {eed->seam = 0;} + if (val) {BM_SetHFlag(eed, BM_SEAM);} + else {BM_ClearHFlag(eed, BM_SEAM);} break; case EDGE_MODE_TAG_SHARP: - if (val) {eed->sharp = 1;} - else {eed->sharp = 0;} + if (val) {BM_SetHFlag(eed, BM_SEAM);} + else {BM_ClearHFlag(eed, BM_SEAM);} break; - case EDGE_MODE_TAG_CREASE: - if (val) {eed->crease = 1.0f;} - else {eed->crease = 0.0f;} + case EDGE_MODE_TAG_CREASE: + { + float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE); + + if (val) {*crease = 1.0f;} + else {*crease = 0.0f;} break; + } case EDGE_MODE_TAG_BEVEL: - if (val) {eed->bweight = 1.0f;} - else {eed->bweight = 0.0f;} + { + float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT); + + if (val) {*bweight = 1.0f;} + else {*bweight = 0.0f;} break; + } } } -int edgetag_context_check(Scene *scene, EditEdge *eed) +static float bm_cdata_get_single_float(BMesh *UNUSED(bm), CustomData *cdata, void *element, int type) +{ + BMHeader *ele = element; + float *f; + + if (!CustomData_has_layer(cdata, type)) + return 0.0f; + + f = CustomData_bmesh_get(cdata, ele->data, type); + + return *f; +} + +int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed) { switch (scene->toolsettings->edge_mode) { case EDGE_MODE_SELECT: - return (eed->f & SELECT) ? 1 : 0; + return BM_TestHFlag(eed, BM_SELECT) ? 1 : 0; case EDGE_MODE_TAG_SEAM: - return eed->seam ? 1 : 0; + return BM_TestHFlag(eed, BM_SEAM); case EDGE_MODE_TAG_SHARP: - return eed->sharp ? 1 : 0; + return BM_TestHFlag(eed, BM_SHARP); case EDGE_MODE_TAG_CREASE: - return eed->crease ? 1 : 0; + return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_CREASE) ? 1 : 0; case EDGE_MODE_TAG_BEVEL: - return eed->bweight ? 1 : 0; + return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_BWEIGHT) ? 1 : 0; } return 0; } -int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target) +int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target) { - EditEdge *eed; - EditVert *ev; - + BMEdge *eed; + BMVert *ev; + BMIter iter; Heap *heap; float *cost; int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0; /* we need the vert */ - for (ev= em->verts.first, totvert=0; ev; ev= ev->next) { - ev->tmp.l = totvert; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(ev, totvert); totvert++; } - for (eed= em->edges.first; eed; eed = eed->next) { - eed->f2 = 0; - if (eed->h) { - eed->f2 |= ME_SEAM_DONE; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + eed->head.flags[0].f = 0; + if (BM_TestHFlag(eed, BM_SELECT)) { + eed->head.flags[0].f |= ME_SEAM_DONE; } - eed->tmp.l = totedge; + + BM_SetIndex(eed, totedge); totedge++; } @@ -555,9 +581,9 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost"); /* count edges, compute adjacent edges offsets and fill adjacent edges */ - for (eed= em->edges.first; eed; eed = eed->next) { - nedges[eed->v1->tmp.l+1]++; - nedges[eed->v2->tmp.l+1]++; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + nedges[BM_GetIndex(eed->v1)+1]++; + nedges[BM_GetIndex(eed->v2)+1]++; } for (a=1; a<totvert; a++) { @@ -567,107 +593,108 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge } nedges[0] = nedges[1] = 0; - for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) { - edges[nedges[eed->v1->tmp.l+1]++] = a; - edges[nedges[eed->v2->tmp.l+1]++] = a; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + edges[nedges[BM_GetIndex(eed->v1)+1]++] = a; + edges[nedges[BM_GetIndex(eed->v2)+1]++] = a; cost[a] = 1e20f; prevedge[a] = -1; + a++; } /* regular dijkstra shortest path, but over edges instead of vertices */ heap = BLI_heap_new(); - BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l)); - cost[source->tmp.l] = 0.0f; - - EM_init_index_arrays(em, 1, 1, 0); + BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_GetIndex(source))); + cost[BM_GetIndex(source)] = 0.0f; + EDBM_init_index_arrays(em, 1, 1, 0); while (!BLI_heap_empty(heap)) { mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); - eed = EM_get_edge_for_index( mednum ); + eed = EDBM_get_edge_for_index(em, mednum); - if (mednum == target->tmp.l) + if (mednum == BM_GetIndex(target)) break; - if (eed->f2 & ME_SEAM_DONE) + if (eed->head.flags[0].f & ME_SEAM_DONE) continue; - eed->f2 |= ME_SEAM_DONE; + eed->head.flags[0].f |= ME_SEAM_DONE; - edgetag_add_adjacent(heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost); - edgetag_add_adjacent(heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost); + edgetag_add_adjacent(em, heap, mednum, BM_GetIndex(eed->v1), nedges, edges, prevedge, cost); + edgetag_add_adjacent(em, heap, mednum, BM_GetIndex(eed->v2), nedges, edges, prevedge, cost); } - MEM_freeN(nedges); MEM_freeN(edges); MEM_freeN(cost); BLI_heap_free(heap, NULL); - for (eed= em->edges.first; eed; eed = eed->next) { - eed->f2 &= ~ME_SEAM_DONE; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + eed->head.flags[0].f &= ~ME_SEAM_DONE; } - if (mednum != target->tmp.l) { + if (mednum != BM_GetIndex(target)) { MEM_freeN(prevedge); - EM_free_index_arrays(); + EDBM_free_index_arrays(em); return 0; } /* follow path back to source and mark as seam */ - if (mednum == target->tmp.l) { + if (mednum == BM_GetIndex(target)) { short allseams = 1; - mednum = target->tmp.l; + mednum = BM_GetIndex(target); do { - eed = EM_get_edge_for_index( mednum ); - if (!edgetag_context_check(scene, eed)) { + eed = EDBM_get_edge_for_index(em, mednum); + if (!edgetag_context_check(scene, em, eed)) { allseams = 0; break; } mednum = prevedge[mednum]; - } while (mednum != source->tmp.l); + } while (mednum != BM_GetIndex(source)); - mednum = target->tmp.l; + mednum = BM_GetIndex(target); do { - eed = EM_get_edge_for_index( mednum ); + eed = EDBM_get_edge_for_index(em, mednum); if (allseams) - edgetag_context_set(scene, eed, 0); + edgetag_context_set(em, scene, eed, 0); else - edgetag_context_set(scene, eed, 1); + edgetag_context_set(em, scene, eed, 1); mednum = prevedge[mednum]; } while (mednum != -1); } MEM_freeN(prevedge); - EM_free_index_arrays(); + EDBM_free_index_arrays(em); return 1; } /* *************************************** */ #if 0 -static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf) +static void seam_edgehash_insert_face(EdgeHash *ehash, MPoly *mf, MLoop *loopstart) { - BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL); - BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL); - if (mf->v4) { - BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL); - BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL); - } - else - BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL); + MLoop *ml1, *ml2; + int a; + + for (a=0; a<mf->totloop; a++) { + ml1 = loopstart + a; + ml2 = loopstart + (a+1) % mf->totloop; + + BLI_edgehash_insert(ehash, ml1->v, ml2->v, NULL); + } } void seam_mark_clear_tface(Scene *scene, short mode) { Mesh *me; - MFace *mf; + MPoly *mf; + MLoop *ml1, *ml2; MEdge *med; - int a; + int a, b; me= get_mesh(OBACT); - if(me==0 || me->totface==0) return; + if(me==0 || me->totpoly==0) return; if (mode == 0) mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2"); @@ -678,9 +705,9 @@ void seam_mark_clear_tface(Scene *scene, short mode) if (mode == 2) { EdgeHash *ehash = BLI_edgehash_new(); - for (a=0, mf=me->mface; a<me->totface; a++, mf++) + for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL)) - seam_edgehash_insert_face(ehash, mf); + seam_edgehash_insert_face(ehash, mf, me->mloop + mf->loopstart); for (a=0, med=me->medge; a<me->totedge; a++, med++) if (BLI_edgehash_haskey(ehash, med->v1, med->v2)) @@ -693,11 +720,11 @@ void seam_mark_clear_tface(Scene *scene, short mode) EdgeHash *ehash1 = BLI_edgehash_new(); EdgeHash *ehash2 = BLI_edgehash_new(); - for (a=0, mf=me->mface; a<me->totface; a++, mf++) { + for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) { if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL)) - seam_edgehash_insert_face(ehash1, mf); + seam_edgehash_insert_face(ehash1, mf, me->mloop + mf->loopstart); else - seam_edgehash_insert_face(ehash2, mf); + seam_edgehash_insert_face(ehash2, mf, me->mloop + mf->loopstart); } for (a=0, med=me->medge; a<me->totedge; a++, med++) @@ -719,21 +746,24 @@ void seam_mark_clear_tface(Scene *scene, short mode) int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], int extend) { Mesh *me; - MFace *mface, *msel; + MPoly *mface, *msel; unsigned int a, index; /* Get the face under the cursor */ me = get_mesh(ob); - if (!facesel_face_pick(C, me, mval, &index, 1)) + if (!facesel_face_pick(C, me, ob, mval, &index, 1)) return 0; - msel= (((MFace*)me->mface)+index); + if (index >= me->totpoly || index < 0) + return 0; + + msel= me->mpoly + index; if (msel->flag & ME_HIDE) return 0; /* clear flags */ - mface = me->mface; - a = me->totface; + mface = me->mpoly; + a = me->totpoly; if (!extend) { while (a--) { mface->flag &= ~ME_FACE_SEL; @@ -761,25 +791,36 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], in int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) { + Object *ob = vc->obact; Mesh *me; - MFace *mface; + MPoly *mface; struct ImBuf *ibuf; unsigned int *rt; - int a, index; char *selar; + int a, index; int sx= rect->xmax-rect->xmin+1; int sy= rect->ymax-rect->ymin+1; - - me= get_mesh(vc->obact); + + me= get_mesh(ob); + if(me==0) return 0; + if(me->totpoly==0) return 0; if(me==NULL || me->totface==0 || sx*sy <= 0) return OPERATOR_CANCELLED; - selar= MEM_callocN(me->totface+1, "selar"); + selar= MEM_callocN(me->totpoly+1, "selar"); if (extend == 0 && select) paintface_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE); + if (extend == 0 && select) { + mface= me->mpoly; + for(a=1; a<=me->totpoly; a++, mface++) { + if((mface->flag & ME_HIDE) == 0) + mface->flag &= ~ME_FACE_SEL; + } + } + view3d_validate_backbuf(vc); ibuf = IMB_allocImBuf(sx,sy,32,IB_rect); @@ -796,8 +837,8 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) rt++; } - mface= me->mface; - for(a=1; a<=me->totface; a++, mface++) { + mface= me->mpoly; + for(a=1; a<=me->totpoly; a++, mface++) { if(selar[a]) { if(mface->flag & ME_HIDE); else { diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c deleted file mode 100644 index ec08bfccda3..00000000000 --- a/source/blender/editors/mesh/editmesh.c +++ /dev/null @@ -1,1961 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * Contributor(s): Blender Foundation, full recode 2002-2008 - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh.c - * \ingroup edmesh - */ - - - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_scene_types.h" -#include "DNA_object_types.h" -#include "DNA_key_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_editVert.h" -#include "BLI_dynstr.h" -#include "BLI_rand.h" -#include "BLI_utildefines.h" - -#include "BKE_DerivedMesh.h" -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_global.h" -#include "BKE_key.h" -#include "BKE_main.h" -#include "BKE_material.h" -#include "BKE_mesh.h" -#include "BKE_paint.h" -#include "BKE_report.h" -#include "BKE_multires.h" - -#include "ED_mesh.h" -#include "ED_object.h" -#include "ED_screen.h" -#include "ED_util.h" -#include "ED_view3d.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -/* own include */ -#include "mesh_intern.h" - -/* -editmesh.c: - - add/alloc/free data - - hashtables - - enter/exit editmode -*/ - -/* XXX */ -static void BIF_undo_push(const char *UNUSED(arg)) {} -static void error(const char *UNUSED(arg)) {} - - -/* ***************** HASH ********************* */ - - -#define EDHASHSIZE (512*512) -#define EDHASH(a, b) (a % EDHASHSIZE) - - -/* ************ ADD / REMOVE / FIND ****************** */ - -static void *calloc_em(EditMesh *UNUSED(em), size_t size, size_t nr) -{ - return calloc(size, nr); -} - -/* used to bypass normal calloc with fast one */ -static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em; -static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em; -static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em; - -EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example) -{ - EditVert *eve; - static int hashnr= 0; - - eve= callocvert(em, sizeof(EditVert), 1); - BLI_addtail(&em->verts, eve); - em->totvert++; - - if(vec) VECCOPY(eve->co, vec); - - eve->hash= hashnr++; - if( hashnr>=EDHASHSIZE) hashnr= 0; - - /* new verts get keyindex of -1 since they did not - * have a pre-editmode vertex order - */ - eve->keyindex = -1; - - if(example) { - CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data); - eve->bweight = example->bweight; - } - else { - CustomData_em_set_default(&em->vdata, &eve->data); - } - - return eve; -} - -void free_editvert (EditMesh *em, EditVert *eve) -{ - - EM_remove_selection(em, eve, EDITVERT); - CustomData_em_free_block(&em->vdata, &eve->data); - if(eve->fast==0) - free(eve); - - em->totvert--; -} - - -EditEdge *findedgelist(EditMesh *em, EditVert *v1, EditVert *v2) -{ - EditVert *v3; - struct HashEdge *he; - - /* swap ? */ - if( v1 > v2) { - v3= v2; - v2= v1; - v1= v3; - } - - if(em->hashedgetab==NULL) - em->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab"); - - he= em->hashedgetab + EDHASH(v1->hash, v2->hash); - - while(he) { - - if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed; - - he= he->next; - } - return 0; -} - -static void insert_hashedge(EditMesh *em, EditEdge *eed) -{ - /* assuming that eed is not in the list yet, and that a find has been done before */ - - struct HashEdge *first, *he; - - first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash); - - if( first->eed==0 ) { - first->eed= eed; - } - else { - he= &eed->hash; - he->eed= eed; - he->next= first->next; - first->next= he; - } -} - -static void remove_hashedge(EditMesh *em, EditEdge *eed) -{ - /* assuming eed is in the list */ - - struct HashEdge *first, *he, *prev=NULL; - - he=first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash); - - while(he) { - if(he->eed == eed) { - /* remove from list */ - if(he==first) { - if(first->next) { - he= first->next; - first->eed= he->eed; - first->next= he->next; - } - else he->eed= 0; - } - else { - prev->next= he->next; - } - return; - } - prev= he; - he= he->next; - } -} - -EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *example) -{ - EditVert *v3; - EditEdge *eed; - int swap= 0; - - if(v1==v2) return NULL; - if(v1==NULL || v2==NULL) return NULL; - - /* swap ? */ - if(v1>v2) { - v3= v2; - v2= v1; - v1= v3; - swap= 1; - } - - /* find in hashlist */ - eed= findedgelist(em, v1, v2); - - if(eed==NULL) { - - eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1); - eed->v1= v1; - eed->v2= v2; - BLI_addtail(&em->edges, eed); - eed->dir= swap; - insert_hashedge(em, eed); - em->totedge++; - - /* copy edge data: - rule is to do this with addedgelist call, before addfacelist */ - if(example) { - eed->crease= example->crease; - eed->bweight= example->bweight; - eed->sharp = example->sharp; - eed->seam = example->seam; - eed->h |= (example->h & EM_FGON); - } - } - - return eed; -} - -void remedge(EditMesh *em, EditEdge *eed) -{ - BLI_remlink(&em->edges, eed); - remove_hashedge(em, eed); - - em->totedge--; -} - -void free_editedge(EditMesh *em, EditEdge *eed) -{ - EM_remove_selection(em, eed, EDITEDGE); - if(eed->fast==0){ - free(eed); - } -} - -void free_editface(EditMesh *em, EditFace *efa) -{ - EM_remove_selection(em, efa, EDITFACE); - - if (em->act_face==efa) { - EM_set_actFace(em, em->faces.first == efa ? NULL : em->faces.first); - } - - CustomData_em_free_block(&em->fdata, &efa->data); - if(efa->fast==0) - free(efa); - - em->totface--; -} - -void free_vertlist(EditMesh *em, ListBase *edve) -{ - EditVert *eve, *next; - - if (!edve) return; - - eve= edve->first; - while(eve) { - next= eve->next; - free_editvert(em, eve); - eve= next; - } - edve->first= edve->last= NULL; - em->totvert= em->totvertsel= 0; -} - -void free_edgelist(EditMesh *em, ListBase *lb) -{ - EditEdge *eed, *next; - - eed= lb->first; - while(eed) { - next= eed->next; - free_editedge(em, eed); - eed= next; - } - lb->first= lb->last= NULL; - em->totedge= em->totedgesel= 0; -} - -void free_facelist(EditMesh *em, ListBase *lb) -{ - EditFace *efa, *next; - - efa= lb->first; - while(efa) { - next= efa->next; - free_editface(em, efa); - efa= next; - } - lb->first= lb->last= NULL; - em->totface= em->totfacesel= 0; -} - -EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges) -{ - EditFace *efa; - EditEdge *e1, *e2=0, *e3=0, *e4=0; - - /* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */ - if(v1==v4 || v2==v4 || v3==v4) v4= NULL; - - /* add face to list and do the edges */ - if(exampleEdges) { - e1= addedgelist(em, v1, v2, exampleEdges->e1); - e2= addedgelist(em, v2, v3, exampleEdges->e2); - if(v4) e3= addedgelist(em, v3, v4, exampleEdges->e3); - else e3= addedgelist(em, v3, v1, exampleEdges->e3); - if(v4) e4= addedgelist(em, v4, v1, exampleEdges->e4); - } - else { - e1= addedgelist(em, v1, v2, NULL); - e2= addedgelist(em, v2, v3, NULL); - if(v4) e3= addedgelist(em, v3, v4, NULL); - else e3= addedgelist(em, v3, v1, NULL); - if(v4) e4= addedgelist(em, v4, v1, NULL); - } - - if(v1==v2 || v2==v3 || v1==v3) return NULL; - if(e2==0) return NULL; - - efa= (EditFace *)callocface(em, sizeof(EditFace), 1); - efa->v1= v1; - efa->v2= v2; - efa->v3= v3; - efa->v4= v4; - - efa->e1= e1; - efa->e2= e2; - efa->e3= e3; - efa->e4= e4; - - if(example) { - efa->mat_nr= example->mat_nr; - efa->flag= example->flag; - CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data); - CustomData_em_validate_data(&em->fdata, efa->data, efa->v4 ? 4 : 3); - } - else { - efa->mat_nr= em->mat_nr; - - CustomData_em_set_default(&em->fdata, &efa->data); - } - - BLI_addtail(&em->faces, efa); - em->totface++; - - if(efa->v4) { - normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - } - else { - normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co); - cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co); - } - - return efa; -} - -/* ************************ end add/new/find ************ */ - -/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */ - -/* some nice utility functions */ - -EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve) -{ - if (eve==eed->v1) { - return eed->v2; - } else if (eve==eed->v2) { - return eed->v1; - } else { - return NULL; - } -} - -EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2) -{ - if (eed->v1==eed2->v1 || eed->v1==eed2->v2) { - return eed->v1; - } else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) { - return eed->v2; - } else { - return NULL; - } -} - -int editedge_containsVert(EditEdge *eed, EditVert *eve) -{ - return (eed->v1==eve || eed->v2==eve); -} - -int editface_containsVert(EditFace *efa, EditVert *eve) -{ - return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve)); -} - -int editface_containsEdge(EditFace *efa, EditEdge *eed) -{ - return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed)); -} - - -/* ************************ stuct EditMesh manipulation ***************************** */ - -/* fake callocs for fastmalloc below */ -static void *calloc_fastvert(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr)) -{ - EditVert *eve= em->curvert++; - eve->fast= 1; - return eve; -} -static void *calloc_fastedge(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr)) -{ - EditEdge *eed= em->curedge++; - eed->fast= 1; - return eed; -} -static void *calloc_fastface(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr)) -{ - EditFace *efa= em->curface++; - efa->fast= 1; - return efa; -} - -/* allocate 1 chunk for all vertices, edges, faces. These get tagged to - prevent it from being freed -*/ -static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface) -{ - if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts"); - else em->allverts= NULL; - em->curvert= em->allverts; - - if(totedge==0) totedge= 4*totface; // max possible - - if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges"); - else em->alledges= NULL; - em->curedge= em->alledges; - - if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces"); - else em->allfaces= NULL; - em->curface= em->allfaces; - - callocvert= calloc_fastvert; - callocedge= calloc_fastedge; - callocface= calloc_fastface; -} - -static void end_editmesh_fastmalloc(void) -{ - callocvert= calloc_em; - callocedge= calloc_em; - callocface= calloc_em; -} - -/* do not free editmesh itself here */ -void free_editMesh(EditMesh *em) -{ - if(em==NULL) return; - - if(em->verts.first) free_vertlist(em, &em->verts); - if(em->edges.first) free_edgelist(em, &em->edges); - if(em->faces.first) free_facelist(em, &em->faces); - if(em->selected.first) BLI_freelistN(&(em->selected)); - - CustomData_free(&em->vdata, 0); - CustomData_free(&em->fdata, 0); - - if(em->derivedFinal) { - if (em->derivedFinal!=em->derivedCage) { - em->derivedFinal->needsFree= 1; - em->derivedFinal->release(em->derivedFinal); - } - em->derivedFinal= NULL; - } - if(em->derivedCage) { - em->derivedCage->needsFree= 1; - em->derivedCage->release(em->derivedCage); - em->derivedCage= NULL; - } - - /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */ -#if 0 - if(em->hashedgetab) { - HashEdge *he, *hen; - int a, used=0, max=0, nr; - he= em->hashedgetab; - for(a=0; a<EDHASHSIZE; a++, he++) { - if(he->eed) used++; - hen= he->next; - nr= 0; - while(hen) { - nr++; - hen= hen->next; - } - if(max<nr) max= nr; - } - printf("hastab used %d max %d\n", used, max); - } -#endif - if(em->hashedgetab) MEM_freeN(em->hashedgetab); - em->hashedgetab= NULL; - - if(em->allverts) MEM_freeN(em->allverts); - if(em->alledges) MEM_freeN(em->alledges); - if(em->allfaces) MEM_freeN(em->allfaces); - - em->allverts= em->curvert= NULL; - em->alledges= em->curedge= NULL; - em->allfaces= em->curface= NULL; - - mesh_octree_table(NULL, NULL, NULL, 'e'); - mesh_mirrtopo_table(NULL, 'e'); - - em->totvert= em->totedge= em->totface= 0; - -// XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data); - em->retopo_paint_data= NULL; - em->act_face = NULL; -} - -static void editMesh_set_hash(EditMesh *em) -{ - EditEdge *eed; - - if(em->hashedgetab) MEM_freeN(em->hashedgetab); - em->hashedgetab= NULL; - - for(eed=em->edges.first; eed; eed= eed->next) { - if( findedgelist(em, eed->v1, eed->v2)==NULL ) - insert_hashedge(em, eed); - } - -} - - -/* ************************ IN & OUT EDITMODE ***************************** */ - - -static void edge_normal_compare(EditEdge *eed, EditFace *efa1) -{ - EditFace *efa2; - float cent1[3], cent2[3]; - float inp; - - efa2 = eed->tmp.f; - if(efa1==efa2) return; - - inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2]; - if(inp<0.999f && inp >-0.999f) eed->f2= 1; - - if(efa1->v4) cent_quad_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co); - else cent_tri_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co); - if(efa2->v4) cent_quad_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co); - else cent_tri_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co); - - sub_v3_v3v3(cent1, cent2, cent1); - normalize_v3(cent1); - inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2]; - - if(inp < -0.001f) eed->f1= 1; -} - -#if 0 -typedef struct { - EditEdge *eed; - float noLen,no[3]; - int adjCount; -} EdgeDrawFlagInfo; - -static int edgeDrawFlagInfo_cmp(const void *av, const void *bv) -{ - const EdgeDrawFlagInfo *a = av; - const EdgeDrawFlagInfo *b = bv; - - if (a->noLen<b->noLen) return -1; - else if (a->noLen>b->noLen) return 1; - else return 0; -} -#endif - -static void edge_drawflags(Mesh *me, EditMesh *em) -{ - EditVert *eve; - EditEdge *eed, *e1, *e2, *e3, *e4; - EditFace *efa; - - /* - count number of times edges are used in faces: 0 en 1 time means draw edge - * - edges more than 1 time used: in *tmp.f is pointer to first face - * - check all faces, when normal differs to much: draw (flag becomes 1) - */ - - /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old - game engine (2.04) - */ - - recalc_editnormals(em); - - /* init */ - eve= em->verts.first; - while(eve) { - eve->f1= 1; /* during test it's set at zero */ - eve= eve->next; - } - eed= em->edges.first; - while(eed) { - eed->f2= eed->f1= 0; - eed->tmp.f = 0; - eed= eed->next; - } - - efa= em->faces.first; - while(efa) { - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - e4= efa->e4; - if(e1->f2<4) e1->f2+= 1; - if(e2->f2<4) e2->f2+= 1; - if(e3->f2<4) e3->f2+= 1; - if(e4 && e4->f2<4) e4->f2+= 1; - - if(e1->tmp.f == 0) e1->tmp.f = (void *) efa; - if(e2->tmp.f == 0) e2->tmp.f = (void *) efa; - if(e3->tmp.f ==0) e3->tmp.f = (void *) efa; - if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa; - - efa= efa->next; - } - - if(me->drawflag & ME_ALLEDGES) { - efa= em->faces.first; - while(efa) { - if(efa->e1->f2>=2) efa->e1->f2= 1; - if(efa->e2->f2>=2) efa->e2->f2= 1; - if(efa->e3->f2>=2) efa->e3->f2= 1; - if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1; - - efa= efa->next; - } - } - else { - - /* handle single-edges for 'test cylinder flag' (old engine) */ - - eed= em->edges.first; - while(eed) { - if(eed->f2==1) eed->f1= 1; - eed= eed->next; - } - - /* all faces, all edges with flag==2: compare normal */ - efa= em->faces.first; - while(efa) { - if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa); - else efa->e1->f2= 1; - if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa); - else efa->e2->f2= 1; - if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa); - else efa->e3->f2= 1; - if(efa->e4) { - if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa); - else efa->e4->f2= 1; - } - efa= efa->next; - } - - /* sphere collision flag */ - - eed= em->edges.first; - while(eed) { - if(eed->f1!=1) { - eed->v1->f1= eed->v2->f1= 0; - } - eed= eed->next; - } - - } -} - -/* turns Mesh into editmesh */ -void make_editMesh(Scene *scene, Object *ob) -{ - Mesh *me= ob->data; - MFace *mface; - MVert *mvert; - MSelect *mselect; - KeyBlock *actkey; - EditMesh *em; - EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4; - EditFace *efa, *efa_last_sel= NULL; - EditEdge *eed; - EditSelection *ese; - float *co, (*keyco)[3]= NULL; - int tot, a, eekadoodle= 0; - const short is_paint_sel= paint_facesel_test(ob); - - if(me->edit_mesh==NULL) - me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh"); - else - /* because of reload */ - free_editMesh(me->edit_mesh); - - em= me->edit_mesh; - - em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced - em->act_face = NULL; - em->totvert= tot= me->totvert; - em->totedge= me->totedge; - em->totface= me->totface; - - if(tot==0) { - return; - } - - if(ob->actcol > 0) - em->mat_nr= ob->actcol-1; - - /* initialize fastmalloc for editmesh */ - init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface); - - actkey = ob_get_keyblock(ob); - if(actkey) { - /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */ - undo_editmode_clear(); - keyco= actkey->data; - em->shapenr= ob->shapenr; - } - - /* make editverts */ - CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - mvert= me->mvert; - - evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist"); - for(a=0; a<tot; a++, mvert++) { - - co= mvert->co; - - /* edit the shape key coordinate if available */ - if(keyco && a < actkey->totelem) - co= keyco[a]; - - eve= addvertlist(em, co, NULL); - evlist[a]= eve; - - /* face select sets selection in next loop */ - if(!is_paint_sel) - eve->f |= (mvert->flag & 1); - - if (mvert->flag & ME_HIDE) eve->h= 1; - normal_short_to_float_v3(eve->no, mvert->no); - - eve->bweight= ((float)mvert->bweight)/255.0f; - - /* lets overwrite the keyindex of the editvert - * with the order it used to be in before - * editmode - */ - eve->keyindex = a; - - CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data); - } - - if(actkey && actkey->totelem!=me->totvert); - else { - MEdge *medge= me->medge; - - CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); - /* make edges */ - for(a=0; a<me->totedge; a++, medge++) { - eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL); - /* eed can be zero when v1 and v2 are identical, dxf import does this... */ - if(eed) { - eed->crease= ((float)medge->crease)/255.0f; - eed->bweight= ((float)medge->bweight)/255.0f; - - if(medge->flag & ME_SEAM) eed->seam= 1; - if(medge->flag & ME_SHARP) eed->sharp = 1; - if(medge->flag & SELECT) eed->f |= SELECT; - if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! - if(medge->flag & ME_HIDE) eed->h |= 1; - if(em->selectmode==SCE_SELECT_EDGE) - EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ... - CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data); - } - } - - CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - - /* make faces */ - mface= me->mface; - - for(a=0; a<me->totface; a++, mface++) { - eve1= evlist[mface->v1]; - eve2= evlist[mface->v2]; - if(!mface->v3) eekadoodle= 1; - eve3= evlist[mface->v3]; - if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL; - - efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL); - - if(efa) { - CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data); - - efa->mat_nr= mface->mat_nr; - efa->flag= mface->flag & ~ME_HIDE; - - /* select and hide face flag */ - if(mface->flag & ME_HIDE) { - efa->h= 1; - } else { - if (a==me->act_face) { - EM_set_actFace(em, efa); - } - - /* dont allow hidden and selected */ - if(mface->flag & ME_FACE_SEL) { - efa->f |= SELECT; - - if(is_paint_sel) { - EM_select_face(efa, 1); /* flush down */ - } - - efa_last_sel= efa; - } - } - } - } - } - - if(EM_get_actFace(em, 0)==NULL && efa_last_sel) { - EM_set_actFace(em, efa_last_sel); - } - - if(eekadoodle) - error("This Mesh has old style edgecodes, please put it in the bugtracker!"); - - MEM_freeN(evlist); - - end_editmesh_fastmalloc(); // resets global function pointers - - if(me->mselect){ - //restore editselections - EM_init_index_arrays(em, 1,1,1); - mselect = me->mselect; - - for(a=0; a<me->totselect; a++, mselect++){ - /*check if recorded selection is still valid, if so copy into editmesh*/ - if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){ - ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); - ese->type = mselect->type; - if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else - if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else - if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index); - BLI_addtail(&(em->selected),ese); - } - } - EM_free_index_arrays(); - } - /* this creates coherent selections. also needed for older files */ - EM_selectmode_set(em); - /* paranoia check to enforce hide rules */ - EM_hide_reset(em); - /* sets helper flags which arent saved */ - EM_fgon_flags(em); - - if (EM_get_actFace(em, 0)==NULL) { - EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */ - } -} - -/* makes Mesh out of editmesh */ -void load_editMesh(Scene *scene, Object *obedit) -{ - Mesh *me= obedit->data; - MVert *mvert, *oldverts; - MEdge *medge; - MFace *mface; - MSelect *mselect; - EditMesh *em= me->edit_mesh; - EditVert *eve; - EditFace *efa, *efa_act; - EditEdge *eed; - EditSelection *ese; - float *fp, *newkey, *oldkey; - int i, a, ototvert; - - /* this one also tests of edges are not in faces: */ - /* eed->f2==0: not in face, f2==1: draw it */ - /* eed->f1 : flag for dynaface (cylindertest, old engine) */ - /* eve->f1 : flag for dynaface (sphere test, old engine) */ - /* eve->f2 : being used in vertexnormals */ - edge_drawflags(me, em); - - EM_stats_update(em); - - /* new Vertex block */ - if(em->totvert==0) mvert= NULL; - else mvert= MEM_callocN(em->totvert*sizeof(MVert), "loadeditMesh vert"); - - /* new Edge block */ - if(em->totedge==0) medge= NULL; - else medge= MEM_callocN(em->totedge*sizeof(MEdge), "loadeditMesh edge"); - - /* new Face block */ - if(em->totface==0) mface= NULL; - else mface= MEM_callocN(em->totface*sizeof(MFace), "loadeditMesh face"); - - /* lets save the old verts just in case we are actually working on - * a key ... we now do processing of the keys at the end */ - oldverts= me->mvert; - ototvert= me->totvert; - - /* don't free this yet */ - CustomData_set_layer(&me->vdata, CD_MVERT, NULL); - - /* free custom data */ - CustomData_free(&me->vdata, me->totvert); - CustomData_free(&me->edata, me->totedge); - CustomData_free(&me->fdata, me->totface); - - /* add new custom data */ - me->totvert= em->totvert; - me->totedge= em->totedge; - me->totface= em->totface; - - CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert); - CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge); - CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface); - - CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge); - CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface); - mesh_update_customdata_pointers(me); - - /* the vertices, use ->tmp.l as counter */ - eve= em->verts.first; - a= 0; - - while(eve) { - VECCOPY(mvert->co, eve->co); - - /* vertex normal */ - normal_float_to_short_v3(mvert->no, eve->no); - - /* note: it used to remove me->dvert when it was not in use, cancelled - that... annoying when you have a fresh vgroup */ - CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a); - - eve->tmp.l = a++; /* counter */ - - mvert->flag= 0; - mvert->flag |= (eve->f & SELECT); - if (eve->h) mvert->flag |= ME_HIDE; - - mvert->bweight= (char)(255.0f*eve->bweight); - - eve= eve->next; - mvert++; - } - - /* the edges */ - a= 0; - eed= em->edges.first; - while(eed) { - medge->v1= (unsigned int) eed->v1->tmp.l; - medge->v2= (unsigned int) eed->v2->tmp.l; - - medge->flag= (eed->f & SELECT) | ME_EDGERENDER; - if(eed->f2<2) medge->flag |= ME_EDGEDRAW; - if(eed->f2==0) medge->flag |= ME_LOOSEEDGE; - if(eed->sharp) medge->flag |= ME_SHARP; - if(eed->seam) medge->flag |= ME_SEAM; - if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes - if(eed->h & 1) medge->flag |= ME_HIDE; - - medge->crease= (char)(255.0f*eed->crease); - medge->bweight= (char)(255.0f*eed->bweight); - CustomData_from_em_block(&em->edata, &me->edata, eed->data, a); - - eed->tmp.l = a++; - - medge++; - eed= eed->next; - } - - /* the faces */ - a = 0; - efa= em->faces.first; - efa_act= EM_get_actFace(em, 0); - i = 0; - me->act_face = -1; - while(efa) { - mface= &((MFace *) me->mface)[i]; - - mface->v1= (unsigned int) efa->v1->tmp.l; - mface->v2= (unsigned int) efa->v2->tmp.l; - mface->v3= (unsigned int) efa->v3->tmp.l; - if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l; - - mface->mat_nr= efa->mat_nr; - - mface->flag= efa->flag; - /* bit 0 of flag is already taken for smooth... */ - - if(efa->h) { - mface->flag |= ME_HIDE; - mface->flag &= ~ME_FACE_SEL; - } else { - if(efa->f & 1) mface->flag |= ME_FACE_SEL; - else mface->flag &= ~ME_FACE_SEL; - } - - /* watch: efa->e1->f2==0 means loose edge */ - - if(efa->e1->f2==1) { - efa->e1->f2= 2; - } - if(efa->e2->f2==1) { - efa->e2->f2= 2; - } - if(efa->e3->f2==1) { - efa->e3->f2= 2; - } - if(efa->e4 && efa->e4->f2==1) { - efa->e4->f2= 2; - } - - CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i); - - /* no index '0' at location 3 or 4 */ - test_index_face(mface, &me->fdata, i, efa->v4?4:3); - - if (efa_act == efa) - me->act_face = a; - - efa->tmp.l = a++; - i++; - efa= efa->next; - } - - /* patch hook indices and vertex parents */ - { - Object *ob; - ModifierData *md; - EditVert **vertMap = NULL; - int j; - - for (ob=G.main->object.first; ob; ob=ob->id.next) { - if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) { - - /* duplicate code from below, make it function later...? */ - if (!vertMap) { - vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap"); - - for (eve=em->verts.first; eve; eve=eve->next) { - if (eve->keyindex!=-1) - vertMap[eve->keyindex] = eve; - } - } - if(ob->par1 < ototvert) { - eve = vertMap[ob->par1]; - if(eve) ob->par1= eve->tmp.l; - } - if(ob->par2 < ototvert) { - eve = vertMap[ob->par2]; - if(eve) ob->par2= eve->tmp.l; - } - if(ob->par3 < ototvert) { - eve = vertMap[ob->par3]; - if(eve) ob->par3= eve->tmp.l; - } - - } - if (ob->data==me) { - for (md=ob->modifiers.first; md; md=md->next) { - if (md->type==eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData*) md; - - if (!vertMap) { - vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap"); - - for (eve=em->verts.first; eve; eve=eve->next) { - if (eve->keyindex!=-1) - vertMap[eve->keyindex] = eve; - } - } - - for (i=j=0; i<hmd->totindex; i++) { - if(hmd->indexar[i] < ototvert) { - eve = vertMap[hmd->indexar[i]]; - - if (eve) { - hmd->indexar[j++] = eve->tmp.l; - } - } - else j++; - } - - hmd->totindex = j; - } - } - } - } - - if (vertMap) MEM_freeN(vertMap); - } - - /* are there keys? */ - if(me->key) { - KeyBlock *currkey; - KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1); - - float (*ofs)[3] = NULL; - - /* editing the base key should update others */ - if(me->key->type==KEY_RELATIVE && oldverts) { - int act_is_basis = 0; - /* find if this key is a basis for any others */ - for(currkey = me->key->block.first; currkey; currkey= currkey->next) { - if(em->shapenr-1 == currkey->relative) { - act_is_basis = 1; - break; - } - } - - if(act_is_basis) { /* active key is a base */ - float (*fp)[3]= actkey->data; - i=0; - ofs= MEM_callocN(sizeof(float) * 3 * em->totvert, "currkey->data"); - eve= em->verts.first; - mvert = me->mvert; - while(eve) { - if(eve->keyindex>=0) - VECSUB(ofs[i], mvert->co, fp[eve->keyindex]); - - eve= eve->next; - i++; - mvert++; - } - } - } - - - /* Lets reorder the key data so that things line up roughly - * with the way things were before editmode */ - currkey = me->key->block.first; - while(currkey) { - int apply_offset = (ofs && (currkey != actkey) && (em->shapenr-1 == currkey->relative)); - - fp= newkey= MEM_callocN(me->key->elemsize*em->totvert, "currkey->data"); - oldkey = currkey->data; - - eve= em->verts.first; - - i = 0; - mvert = me->mvert; - while(eve) { - if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex - if(currkey == actkey) { - if(actkey == me->key->refkey) { - VECCOPY(fp, mvert->co); - } - else { - VECCOPY(fp, mvert->co); - if(oldverts) { - VECCOPY(mvert->co, oldverts[eve->keyindex].co); - } - } - } - else { - if(oldkey) { - VECCOPY(fp, oldkey + 3 * eve->keyindex); - } - } - } - else { - VECCOPY(fp, mvert->co); - } - - /* propagate edited basis offsets to other shapes */ - if(apply_offset) { - VECADD(fp, fp, ofs[i]); - } - - fp+= 3; - ++i; - ++mvert; - eve= eve->next; - } - currkey->totelem= em->totvert; - if(currkey->data) MEM_freeN(currkey->data); - currkey->data = newkey; - - currkey= currkey->next; - } - - if(ofs) MEM_freeN(ofs); - } - - if(oldverts) MEM_freeN(oldverts); - - i = 0; - for(ese=em->selected.first; ese; ese=ese->next) i++; - me->totselect = i; - if(i==0) mselect= NULL; - else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections"); - - if(me->mselect) MEM_freeN(me->mselect); - me->mselect= mselect; - - for(ese=em->selected.first; ese; ese=ese->next){ - mselect->type = ese->type; - if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l; - else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l; - else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l; - mselect++; - } - - /* to be sure: clear ->tmp.l pointers */ - eve= em->verts.first; - while(eve) { - eve->tmp.l = 0; - eve= eve->next; - } - - eed= em->edges.first; - while(eed) { - eed->tmp.l = 0; - eed= eed->next; - } - - efa= em->faces.first; - while(efa) { - efa->tmp.l = 0; - efa= efa->next; - } - - /* remake softbody of all users */ - if(me->id.us>1) { - Base *base; - for(base= scene->base.first; base; base= base->next) - if(base->object->data==me) - base->object->recalc |= OB_RECALC_DATA; - } - - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); - - /* topology could be changed, ensure mdisps are ok */ - multires_topology_changed(scene, obedit); -} - -void remake_editMesh(Scene *scene, Object *ob) -{ - make_editMesh(scene, ob); - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - BIF_undo_push("Undo all changes"); -} - -/* *************** Operator: separate parts *************/ - -static EnumPropertyItem prop_separate_types[] = { - {0, "SELECTED", 0, "Selection", ""}, - {1, "MATERIAL", 0, "By Material", ""}, - {2, "LOOSE", 0, "By loose parts", ""}, - {0, NULL, 0, NULL, NULL} -}; - -/* return 1: success */ -static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase) -{ - EditMesh *em, *emnew; - EditVert *eve, *v1; - EditEdge *eed, *e1; - EditFace *efa, *f1; - Object *obedit; - Mesh *me, *menew; - Base *basenew; - - if(editbase==NULL) return 0; - - obedit= editbase->object; - me= obedit->data; - em= BKE_mesh_get_editmesh(me); - if(me->key) { - BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys."); - BKE_mesh_end_editmesh(me, em); - return 0; - } - - if(em->selected.first) - BLI_freelistN(&(em->selected)); /* clear the selection order */ - - EM_selectmode_set(em); // enforce full consistent selection flags - - EM_stats_update(em); - - if(em->totvertsel==0) { - BKE_mesh_end_editmesh(me, em); - return 0; - } - - /* we are going to work as follows: - * 1. add a linked duplicate object: this will be the new one, we remember old pointer - * 2. give new object empty mesh and put in editmode - * 3: do a split if needed on current editmesh. - * 4. copy over: all NOT selected verts, edges, faces - * 5. call load_editMesh() on the new object - */ - - /* 1 */ - basenew= ED_object_add_duplicate(bmain, scene, editbase, 0); /* 0 = fully linked */ - ED_base_object_select(basenew, BA_DESELECT); - - /* 2 */ - basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */ - assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ - me->id.us--; - make_editMesh(scene, basenew->object); - emnew= menew->edit_mesh; - CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); - CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0); - CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); - - /* 3 */ - /* SPLIT: first make duplicate */ - adduplicateflag(em, SELECT); - /* SPLIT: old faces have 3x flag 128 set, delete these ones */ - delfaceflag(em, 128); - /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */ - EM_selectmode_set(em); - - /* 4 */ - /* move over: everything that is selected */ - for(eve= em->verts.first; eve; eve= v1) { - v1= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts, eve); - BLI_addtail(&emnew->verts, eve); - } - } - - for(eed= em->edges.first; eed; eed= e1) { - e1= eed->next; - if(eed->f & SELECT) { - BLI_remlink(&em->edges, eed); - BLI_addtail(&emnew->edges, eed); - } - } - - for(efa= em->faces.first; efa; efa= f1) { - f1= efa->next; - if (efa == em->act_face && (efa->f & SELECT)) { - EM_set_actFace(em, NULL); - } - - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - BLI_addtail(&emnew->faces, efa); - } - } - - /* 5 */ - load_editMesh(scene, basenew->object); - free_editMesh(emnew); - MEM_freeN(menew->edit_mesh); - menew->edit_mesh= NULL; - - /* copy settings */ - menew->texflag= me->texflag; - menew->drawflag= me->drawflag; - menew->flag= me->flag; - menew->editflag= me->editflag; - menew->smoothresh= me->smoothresh; - - /* hashedges are invalid now, make new! */ - editMesh_set_hash(em); - - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA); - - BKE_mesh_end_editmesh(me, em); - - return 1; -} - -/* return 1: success */ -static int mesh_separate_material(wmOperator *op, Main *bmain, Scene *scene, Base *editbase) -{ - Mesh *me= editbase->object->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - unsigned char curr_mat; - - for (curr_mat = 1; curr_mat < editbase->object->totcol; ++curr_mat) { - /* clear selection, we're going to use that to select material group */ - EM_clear_flag_all(em, SELECT); - /* select the material */ - EM_select_by_material(em, curr_mat); - /* and now separate */ - if(0==mesh_separate_selected(op, bmain, scene, editbase)) { - BKE_mesh_end_editmesh(me, em); - return 0; - } - } - - BKE_mesh_end_editmesh(me, em); - return 1; -} - -/* return 1: success */ -static int mesh_separate_loose(wmOperator *op, Main *bmain, Scene *scene, Base *editbase) -{ - Mesh *me; - EditMesh *em; - int doit= 1; - - me= editbase->object->data; - em= BKE_mesh_get_editmesh(me); - - if(me->key) { - error("Can't separate with vertex keys"); - BKE_mesh_end_editmesh(me, em); - return 0; - } - - EM_clear_flag_all(em, SELECT); - - while(doit) { - /* Select a random vert to start with */ - EditVert *eve; - int tot; - - /* check if all verts that are visible have been done */ - for(eve=em->verts.first; eve; eve= eve->next) - if(!eve->h) break; - if(eve==NULL) break; /* only hidden verts left, quit early */ - - /* first non hidden vert */ - eve->f |= SELECT; - - selectconnected_mesh_all(em); - - /* don't separate the very last part */ - for(eve=em->verts.first; eve; eve= eve->next) - if((eve->f & SELECT)==0) break; - if(eve==NULL) break; - - tot= BLI_countlist(&em->verts); - - /* and now separate */ - doit= mesh_separate_selected(op, bmain, scene, editbase); - - /* with hidden verts this can happen */ - if(tot == BLI_countlist(&em->verts)) - break; - } - - BKE_mesh_end_editmesh(me, em); - return 1; -} - - -static int mesh_separate_exec(bContext *C, wmOperator *op) -{ - Main *bmain= CTX_data_main(C); - Scene *scene= CTX_data_scene(C); - Base *base= CTX_data_active_base(C); - int retval= 0, type= RNA_enum_get(op->ptr, "type"); - - if(type == 0) - retval= mesh_separate_selected(op, bmain, scene, base); - else if(type == 1) - retval= mesh_separate_material(op, bmain, scene, base); - else if(type == 2) - retval= mesh_separate_loose(op, bmain, scene, base); - - if(retval) { - WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data); - - // XXX: new object was created, but selection wasn't actually changed - // need this for outliner update without adding new ND. nazgul. - WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; -} - -void MESH_OT_separate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Separate"; - ot->description= "Separate selected geometry into a new mesh"; - ot->idname= "MESH_OT_separate"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= mesh_separate_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - ot->prop= RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", ""); -} - - -/* ******************************************** */ - -/* *************** UNDO ***************************** */ -/* new mesh undo, based on pushing editmesh data itself */ -/* reuses same code as for global and curve undo... unify that (ton) */ - -/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */ - -/* a compressed version of editmesh data */ - -typedef struct EditVertC -{ - float no[3]; - float co[3]; - unsigned char f, h; - short bweight; - int keyindex; -} EditVertC; - -typedef struct EditEdgeC -{ - int v1, v2; - unsigned char f, h, seam, sharp, pad; - short crease, bweight, fgoni; -} EditEdgeC; - -typedef struct EditFaceC -{ - int v1, v2, v3, v4; - unsigned char flag, f, h, fgonf, pad1; - short mat_nr; -} EditFaceC; - -typedef struct EditSelectionC{ - short type; - int index; -}EditSelectionC; - -typedef struct UndoMesh { - EditVertC *verts; - EditEdgeC *edges; - EditFaceC *faces; - EditSelectionC *selected; - int totvert, totedge, totface, totsel; - int selectmode, shapenr; - char retopo_mode; - CustomData vdata, edata, fdata; -} UndoMesh; - -/* for callbacks */ - -static void free_undoMesh(void *umv) -{ - UndoMesh *um= umv; - - if(um->verts) MEM_freeN(um->verts); - if(um->edges) MEM_freeN(um->edges); - if(um->faces) MEM_freeN(um->faces); - if(um->selected) MEM_freeN(um->selected); -// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data); - CustomData_free(&um->vdata, um->totvert); - CustomData_free(&um->edata, um->totedge); - CustomData_free(&um->fdata, um->totface); - MEM_freeN(um); -} - -static void *editMesh_to_undoMesh(void *emv) -{ - EditMesh *em= (EditMesh *)emv; - UndoMesh *um; - EditVert *eve; - EditEdge *eed; - EditFace *efa; - EditSelection *ese; - EditVertC *evec=NULL; - EditEdgeC *eedc=NULL; - EditFaceC *efac=NULL; - EditSelectionC *esec=NULL; - int a; - - um= MEM_callocN(sizeof(UndoMesh), "undomesh"); - - um->selectmode = em->selectmode; - um->shapenr = em->shapenr; - - for(eve=em->verts.first; eve; eve= eve->next) um->totvert++; - for(eed=em->edges.first; eed; eed= eed->next) um->totedge++; - for(efa=em->faces.first; efa; efa= efa->next) um->totface++; - for(ese=em->selected.first; ese; ese=ese->next) um->totsel++; - /* malloc blocks */ - - if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC"); - if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC"); - if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC"); - if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections"); - - if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert); - if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge); - if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface); - - /* now copy vertices */ - a = 0; - for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) { - VECCOPY(evec->co, eve->co); - VECCOPY(evec->no, eve->no); - - evec->f= eve->f; - evec->h= eve->h; - evec->keyindex= eve->keyindex; - eve->tmp.l = a; /*store index*/ - evec->bweight= (short)(eve->bweight*255.0f); - - CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a); - } - - /* copy edges */ - a = 0; - for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) { - eedc->v1= (int)eed->v1->tmp.l; - eedc->v2= (int)eed->v2->tmp.l; - eedc->f= eed->f; - eedc->h= eed->h; - eedc->seam= eed->seam; - eedc->sharp= eed->sharp; - eedc->crease= (short)(eed->crease*255.0f); - eedc->bweight= (short)(eed->bweight*255.0f); - eedc->fgoni= eed->fgoni; - eed->tmp.l = a; /*store index*/ - CustomData_from_em_block(&em->edata, &um->edata, eed->data, a); - - } - - /* copy faces */ - a = 0; - for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) { - efac->v1= (int)efa->v1->tmp.l; - efac->v2= (int)efa->v2->tmp.l; - efac->v3= (int)efa->v3->tmp.l; - if(efa->v4) efac->v4= (int)efa->v4->tmp.l; - else efac->v4= -1; - - efac->mat_nr= efa->mat_nr; - efac->flag= efa->flag; - efac->f= efa->f; - efac->h= efa->h; - efac->fgonf= efa->fgonf; - - efa->tmp.l = a; /*store index*/ - - CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a); - } - - a = 0; - for(ese=em->selected.first; ese; ese=ese->next, esec++){ - esec->type = ese->type; - if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l; - else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l; - else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l; - } - -// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data); -// um->retopo_mode= scene->toolsettings->retopo_mode; - - return um; -} - -static void undoMesh_to_editMesh(void *umv, void *emv) -{ - EditMesh *em= (EditMesh *)emv; - UndoMesh *um= (UndoMesh *)umv; - EditVert *eve, **evar=NULL; - EditEdge *eed; - EditFace *efa; - EditSelection *ese; - EditVertC *evec; - EditEdgeC *eedc; - EditFaceC *efac; - EditSelectionC *esec; - int a=0; - - free_editMesh(em); - - /* malloc blocks */ - memset(em, 0, sizeof(EditMesh)); - - em->selectmode = um->selectmode; - em->shapenr = um->shapenr; - - init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface); - - CustomData_free(&em->vdata, 0); - CustomData_free(&em->edata, 0); - CustomData_free(&em->fdata, 0); - - CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0); - CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0); - - /* now copy vertices */ - - if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar"); - for(a=0, evec= um->verts; a<um->totvert; a++, evec++) { - eve= addvertlist(em, evec->co, NULL); - evar[a]= eve; - - VECCOPY(eve->no, evec->no); - eve->f= evec->f; - eve->h= evec->h; - eve->keyindex= evec->keyindex; - eve->bweight= ((float)evec->bweight)/255.0f; - - CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data); - } - - /* copy edges */ - for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) { - eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL); - - eed->f= eedc->f; - eed->h= eedc->h; - eed->seam= eedc->seam; - eed->sharp= eedc->sharp; - eed->fgoni= eedc->fgoni; - eed->crease= ((float)eedc->crease)/255.0f; - eed->bweight= ((float)eedc->bweight)/255.0f; - CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data); - } - - /* copy faces */ - for(a=0, efac= um->faces; a<um->totface; a++, efac++) { - if(efac->v4 != -1) - efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL); - else - efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL); - - efa->mat_nr= efac->mat_nr; - efa->flag= efac->flag; - efa->f= efac->f; - efa->h= efac->h; - efa->fgonf= efac->fgonf; - - CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data); - } - - end_editmesh_fastmalloc(); - if(evar) MEM_freeN(evar); - - em->totvert = um->totvert; - em->totedge = um->totedge; - em->totface = um->totface; - /*restore stored editselections*/ - if(um->totsel){ - EM_init_index_arrays(em, 1,1,1); - for(a=0, esec= um->selected; a<um->totsel; a++, esec++){ - ese = MEM_callocN(sizeof(EditSelection), "Edit Selection"); - ese->type = esec->type; - if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else - if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else - if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index); - BLI_addtail(&(em->selected),ese); - } - EM_free_index_arrays(); - } - - /* restore total selections */ - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); - -// XXX retopo_free_paint(); -// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data); -// scene->toolsettings->retopo_mode= um->retopo_mode; -// if(scene->toolsettings->retopo_mode) { -// XXX if(G.vd->depths) G.vd->depths->damaged= 1; -// retopo_queue_updates(G.vd); -// retopo_paint_view_update(G.vd); -// } - -} - -static void *getEditMesh(bContext *C) -{ - Object *obedit= CTX_data_edit_object(C); - if(obedit && obedit->type==OB_MESH) { - Mesh *me= obedit->data; - return me->edit_mesh; - } - return NULL; -} - -/* and this is all the undo system needs to know */ -void undo_push_mesh(bContext *C, const char *name) -{ - undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL); -} - - - -/* *************** END UNDO *************/ - -static EditVert **g_em_vert_array = NULL; -static EditEdge **g_em_edge_array = NULL; -static EditFace **g_em_face_array = NULL; - -void EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - int i; - - if (forVert) { - em->totvert= BLI_countlist(&em->verts); - - if(em->totvert) { - g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*em->totvert, "em_v_arr"); - - for (i=0,eve=em->verts.first; eve; i++,eve=eve->next) - g_em_vert_array[i] = eve; - } - } - - if (forEdge) { - em->totedge= BLI_countlist(&em->edges); - - if(em->totedge) { - g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*em->totedge, "em_e_arr"); - - for (i=0,eed=em->edges.first; eed; i++,eed=eed->next) - g_em_edge_array[i] = eed; - } - } - - if (forFace) { - em->totface= BLI_countlist(&em->faces); - - if(em->totface) { - g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*em->totface, "em_f_arr"); - - for (i=0,efa=em->faces.first; efa; i++,efa=efa->next) - g_em_face_array[i] = efa; - } - } -} - -void EM_free_index_arrays(void) -{ - if (g_em_vert_array) MEM_freeN(g_em_vert_array); - if (g_em_edge_array) MEM_freeN(g_em_edge_array); - if (g_em_face_array) MEM_freeN(g_em_face_array); - g_em_vert_array = NULL; - g_em_edge_array = NULL; - g_em_face_array = NULL; -} - -EditVert *EM_get_vert_for_index(int index) -{ - return g_em_vert_array?g_em_vert_array[index]:NULL; -} - -EditEdge *EM_get_edge_for_index(int index) -{ - return g_em_edge_array?g_em_edge_array[index]:NULL; -} - -EditFace *EM_get_face_for_index(int index) -{ - return g_em_face_array?g_em_face_array[index]:NULL; -} - -/* can we edit UV's for this mesh?*/ -int EM_texFaceCheck(EditMesh *em) -{ - /* some of these checks could be a touch overkill */ - if ( (em) && - (em->faces.first) && - (CustomData_has_layer(&em->fdata, CD_MTFACE))) - return 1; - return 0; -} - -/* can we edit colors for this mesh?*/ -int EM_vertColorCheck(EditMesh *em) -{ - /* some of these checks could be a touch overkill */ - if ( (em) && - (em->faces.first) && - (CustomData_has_layer(&em->fdata, CD_MCOL))) - return 1; - return 0; -} - - -void em_setup_viewcontext(bContext *C, ViewContext *vc) -{ - view3d_set_viewcontext(C, vc); - - if(vc->obedit) { - Mesh *me= vc->obedit->data; - vc->em= me->edit_mesh; - } -} diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c deleted file mode 100644 index fa3619883f4..00000000000 --- a/source/blender/editors/mesh/editmesh_add.c +++ /dev/null @@ -1,1772 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 by Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_add.c - * \ingroup edmesh - */ - - - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_meshdata_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "RNA_define.h" -#include "RNA_access.h" -#include "RNA_enum_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_editVert.h" -#include "BLI_utildefines.h" - -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_library.h" -#include "BKE_mesh.h" -#include "BKE_report.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_mesh.h" -#include "ED_screen.h" -#include "ED_transform.h" -#include "ED_view3d.h" -#include "ED_object.h" - -#include "mesh_intern.h" - -/* bpymenu removed XXX */ - -/* XXX */ -#define add_numbut(a, b, c, d, e, f, g) {} -/* XXX */ - -static float icovert[12][3] = { - {0.0f,0.0f,-200.0f}, - {144.72f, -105.144f,-89.443f}, - {-55.277f, -170.128,-89.443f}, - {-178.885f,0.0f,-89.443f}, - {-55.277f,170.128f,-89.443f}, - {144.72f,105.144f,-89.443f}, - {55.277f,-170.128f,89.443f}, - {-144.72f,-105.144f,89.443f}, - {-144.72f,105.144f,89.443f}, - {55.277f,170.128f,89.443f}, - {178.885f,0.0f,89.443f}, - {0.0f,0.0f,200.0f} -}; -static short icoface[20][3] = { - {2,0,1}, - {1,0,5}, - {3,0,2}, - {4,0,3}, - {5,0,4}, - {1,5,10}, - {2,1,6}, - {3,2,7}, - {4,3,8}, - {5,4,9}, - {6,1,10}, - {7,2,6}, - {8,3,7}, - {9,4,8}, - {10,5,9}, - {6,10,11}, - {7,6,11}, - {8,7,11}, - {9,8,11}, - {10,9,11} -}; - -/* *************** add-click-mesh (extrude) operator ************** */ - -static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event) -{ - ViewContext vc; - EditVert *eve; - float min[3], max[3]; - int done= 0; - short use_proj; - - em_setup_viewcontext(C, &vc); - - use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE); - - invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); - - INIT_MINMAX(min, max); - - for(eve= vc.em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - DO_MINMAX(eve->co, min, max); - done= 1; - } - } - - /* call extrude? */ - if(done) { - const short rot_src= RNA_boolean_get(op->ptr, "rotate_source"); - EditEdge *eed; - float vec[3], cent[3], mat[3][3]; - float nor[3]= {0.0, 0.0, 0.0}; - - /* 2D normal calc */ - float mval_f[2]; - - mval_f[0]= (float)event->mval[0]; - mval_f[1]= (float)event->mval[1]; - - done= 0; - - /* calculate the normal for selected edges */ - for(eed= vc.em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - float co1[3], co2[3]; - mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); - mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); - project_float_noclip(vc.ar, co1, co1); - project_float_noclip(vc.ar, co2, co2); - - /* 2D rotate by 90d while adding. - * (x, y) = (y, -x) - * - * accumulate the screenspace normal in 2D, - * with screenspace edge length weighting the result. */ - if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) { - nor[0] += (co1[1] - co2[1]); - nor[1] += -(co1[0] - co2[0]); - } - else { - nor[0] += (co2[1] - co1[1]); - nor[1] += -(co2[0] - co1[0]); - } - done= 1; - } - } - - if(done) { - float view_vec[3], cross[3]; - - /* convert the 2D nomal into 3D */ - mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ - mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ - - /* correct the normal to be aligned on the view plane */ - copy_v3_v3(view_vec, vc.rv3d->viewinv[2]); - mul_mat3_m4_v3(vc.obedit->imat, view_vec); - cross_v3_v3v3(cross, nor, view_vec); - cross_v3_v3v3(nor, view_vec, cross); - normalize_v3(nor); - } - - /* center */ - mid_v3_v3v3(cent, min, max); - copy_v3_v3(min, cent); - - mul_m4_v3(vc.obedit->obmat, min); // view space - view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); - mul_m4_v3(vc.obedit->imat, min); // back in object space - - sub_v3_v3(min, cent); - - /* calculate rotation */ - unit_m3(mat); - if(done) { - float dot; - - copy_v3_v3(vec, min); - normalize_v3(vec); - dot= INPR(vec, nor); - - if( fabs(dot)<0.999) { - float cross[3], si, q1[4]; - - cross_v3_v3v3(cross, nor, vec); - normalize_v3(cross); - dot= 0.5f*saacos(dot); - - /* halve the rotation if its applied twice */ - if(rot_src) dot *= 0.5f; - - si= (float)sin(dot); - q1[0]= (float)cos(dot); - q1[1]= cross[0]*si; - q1[2]= cross[1]*si; - q1[3]= cross[2]*si; - quat_to_mat3( mat,q1); - } - } - - if(rot_src) { - rotateflag(vc.em, SELECT, cent, mat); - /* also project the source, for retopo workflow */ - if(use_proj) - EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); - } - - extrudeflag(vc.obedit, vc.em, SELECT, nor, 0); - rotateflag(vc.em, SELECT, cent, mat); - translateflag(vc.em, SELECT, min); - - recalc_editnormals(vc.em); - } - else if(vc.em->selectmode & SCE_SELECT_VERTEX) { - - float imat[4][4]; - const float *curs= give_cursor(vc.scene, vc.v3d); - - copy_v3_v3(min, curs); - view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE); - - eve= addvertlist(vc.em, 0, NULL); - - invert_m4_m4(imat, vc.obedit->obmat); - mul_v3_m4v3(eve->co, imat, min); - - eve->f= SELECT; - } - - if(use_proj) - EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); - - WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); - DAG_id_tag_update(vc.obedit->data, 0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Duplicate or Extrude at 3D Cursor"; - ot->description= "Duplicate and extrude selected vertices, edges or faces towards 3D Cursor"; - ot->idname= "MESH_OT_dupli_extrude_cursor"; - - /* api callbacks */ - ot->invoke= dupli_extrude_cursor; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape"); -} - - -/* ********************** */ - -/* selected faces get hidden edges */ -static int make_fgon(EditMesh *em, wmOperator *op, int make) -{ - EditFace *efa; - EditEdge *eed; - EditVert *eve; - float *nor=NULL; // reference - int done=0; - - if(make==0) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - efa->fgonf= 0; - efa->e1->h &= ~EM_FGON; - efa->e2->h &= ~EM_FGON; - efa->e3->h &= ~EM_FGON; - if(efa->e4) efa->e4->h &= ~EM_FGON; - done= 1; - } - } - EM_fgon_flags(em); // redo flags and indices for fgons - - return done; - } - - /* tagging edges. rule is: - - edge used by exactly 2 selected faces - - no vertices allowed with only tagged edges (return) - - face normals are allowed to difffer - - */ - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; // amount of selected - eed->f2= 0; // amount of unselected - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - if(nor==NULL) nor= efa->n; - if(efa->e1->f1 < 3) efa->e1->f1++; - if(efa->e2->f1 < 3) efa->e2->f1++; - if(efa->e3->f1 < 3) efa->e3->f1++; - if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++; - } - else { - if(efa->e1->f2 < 3) efa->e1->f2++; - if(efa->e2->f2 < 3) efa->e2->f2++; - if(efa->e3->f2 < 3) efa->e3->f2++; - if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++; - } - } - // now eed->f1 becomes tagged edge - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1==2 && eed->f2==0) eed->f1= 1; - else eed->f1= 0; - } - - // no vertices allowed with only tagged edges - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1) { - eed->v1->f1 |= 1; - eed->v2->f1 |= 1; - } - else { - eed->v1->f1 |= 2; - eed->v2->f1 |= 2; - } - } - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1==1) break; - } - if(eve) { - BKE_report(op->reports, RPT_WARNING, "Cannot make a polygon with interior vertices"); - return 0; - } - - // check for faces - if(nor==NULL) { - BKE_report(op->reports, RPT_WARNING, "No faces were selected to make FGon"); - return 0; - } - - // and there we go - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1) { - eed->h |= EM_FGON; - done= 1; - } - } - - if(done) - EM_fgon_flags(em); // redo flags and indices for fgons - return done; -} - -static int make_fgon_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - if( make_fgon(em, op, 1) ) { - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; - } - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; -} - -void MESH_OT_fgon_make(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Make F-gon"; - ot->description= "Make fgon from selected faces"; - ot->idname= "MESH_OT_fgon_make"; - - /* api callbacks */ - ot->exec= make_fgon_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int clear_fgon_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - if( make_fgon(em, op, 0) ) { - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; - } - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; -} - -void MESH_OT_fgon_clear(struct wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Clear F-gon"; - ot->description= "Clear fgon from selected face"; - ot->idname= "MESH_OT_fgon_clear"; - - /* api callbacks */ - ot->exec= clear_fgon_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/* precondition; 4 vertices selected, check for 4 edges and create face */ -static EditFace *addface_from_edges(EditMesh *em) -{ - EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL}; - EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL; - int a; - - /* find the 4 edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - if( (eed->f & SELECT) || (eed->v1->f & eed->v2->f & SELECT) ) { - if(eedar[0]==NULL) eedar[0]= eed; - else if(eedar[1]==NULL) eedar[1]= eed; - else if(eedar[2]==NULL) eedar[2]= eed; - else eedar[3]= eed; - - } - } - - - if(eedar[3]) { - /* first 2 points */ - v1= eedar[0]->v1; - v2= eedar[0]->v2; - - /* find the 2 edges connected to first edge */ - for(a=1; a<4; a++) { - if( eedar[a]->v1 == v2) v3= eedar[a]->v2; - else if(eedar[a]->v2 == v2) v3= eedar[a]->v1; - else if( eedar[a]->v1 == v1) v4= eedar[a]->v2; - else if(eedar[a]->v2 == v1) v4= eedar[a]->v1; - } - - /* verify if last edge exists */ - if(v3 && v4) { - for(a=1; a<4; a++) { - if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break; - if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break; - } - if(a!=4) { - return addfacelist(em, v1, v2, v3, v4, NULL, NULL); - } - } - } - return NULL; -} - -/* ******************************* */ - -/* this also allows to prevent triangles being made in quads */ -static int compareface_overlaps(EditFace *vl1, EditFace *vl2) -{ - EditVert *v1, *v2, *v3, *v4; - int equal= 0; - - v1= vl2->v1; - v2= vl2->v2; - v3= vl2->v3; - v4= vl2->v4; - - if(vl1==vl2) return 0; - - if(v4==NULL && vl1->v4==NULL) { - if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++; - if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++; - if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++; - } - else { - if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++; - if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++; - if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++; - if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++; - } - - if(v4 && vl1->v4) { - if(equal==4) return 1; - } - else - if(equal>=3) return 1; - - return 0; -} - -/* checks for existence, and for tria overlapping inside quad */ -static EditFace *exist_face_overlaps(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4) -{ - EditFace *efa, efatest; - - efatest.v1= v1; - efatest.v2= v2; - efatest.v3= v3; - efatest.v4= v4; - - efa= em->faces.first; - while(efa) { - if(compareface_overlaps(&efatest, efa)) return efa; - efa= efa->next; - } - return NULL; -} - -/* will be new face smooth or solid? depends on smoothness of face neighbours - * of new face, if function return 1, then new face will be smooth, when functio - * will return zero, then new face will be solid */ -static void fix_new_face(EditMesh *em, EditFace *eface) -{ - struct EditFace *efa; - struct EditEdge *eed=NULL; - struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4; - struct EditVert *ev1=NULL, *ev2=NULL; - short smooth=0; /* "total smoothnes" of faces in neighbourhood */ - short coef; /* "weight" of smoothness */ - short count=0; /* number of edges with same direction as eface */ - short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */ - - efa = em->faces.first; - - while(efa) { - - if(efa==eface) { - efa = efa->next; - continue; - } - - coef = 0; - ev1 = ev2 = NULL; - eed = NULL; - - if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) { - ev1 = v1; - coef++; - } - if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) { - if(ev1) ev2 = v2; - else ev1 = v2; - coef++; - } - if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) { - if(coef<2) { - if(ev1) ev2 = v3; - else ev1 = v3; - } - coef++; - } - if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) { - if(ev1 && coef<2) ev2 = v4; - coef++; - } - - /* "democracy" of smoothness */ - if(efa->flag & ME_SMOOTH) - smooth += coef; - else - smooth -= coef; - - /* try to find edge using vertexes ev1 and ev2 */ - if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(em, ev1, ev2); - - /* has bordering edge of efa same direction as edge of eface ? */ - if(eed) { - if(eed->v1==v1) vi00 = 1; - else if(eed->v1==v2) vi00 = 2; - else if(eed->v1==v3) vi00 = 3; - else if(v4 && eed->v1==v4) vi00 = 4; - - if(eed->v2==v1) vi01 = 1; - else if(eed->v2==v2) vi01 = 2; - else if(eed->v2==v3) vi01 = 3; - else if(v4 && eed->v2==v4) vi01 = 4; - - if(v4) { - if(vi01==1 && vi00==4) vi00 = 0; - if(vi01==4 && vi00==1) vi01 = 0; - } - else { - if(vi01==1 && vi00==3) vi00 = 0; - if(vi01==3 && vi00==1) vi01 = 0; - } - - if(eed->v1==efa->v1) vi10 = 1; - else if(eed->v1==efa->v2) vi10 = 2; - else if(eed->v1==efa->v3) vi10 = 3; - else if(efa->v4 && eed->v1==efa->v4) vi10 = 4; - - if(eed->v2==efa->v1) vi11 = 1; - else if(eed->v2==efa->v2) vi11 = 2; - else if(eed->v2==efa->v3) vi11 = 3; - else if(efa->v4 && eed->v2==efa->v4) vi11 = 4; - - if(efa->v4) { - if(vi11==1 && vi10==4) vi10 = 0; - if(vi11==4 && vi10==1) vi11 = 0; - } - else { - if(vi11==1 && vi10==3) vi10 = 0; - if(vi11==3 && vi10==1) vi11 = 0; - } - - if(((vi00>vi01) && (vi10>vi11)) || - ((vi00<vi01) && (vi10<vi11))) - count++; - else - count--; - } - - efa = efa->next; - } - - /* set up smoothness according voting of face in neighbourhood */ - if(smooth >= 0) - eface->flag |= ME_SMOOTH; - else - eface->flag &= ~ME_SMOOTH; - - /* flip face, when too much "face normals" in neighbourhood is different */ - if(count > 0) { - flipface(em, eface); - } -} - -/* only adds quads or trias when there's edges already */ -static void addfaces_from_edgenet(EditMesh *em) -{ - EditVert *eve1, *eve2, *eve3, *eve4; - - for(eve1= em->verts.first; eve1; eve1= eve1->next) { - for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) { - if(findedgelist(em, eve1,eve2)) { - for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) { - if((eve2!=eve3 && (eve3->f & 1) && findedgelist(em, eve1,eve3))) { - EditEdge *sh_edge= NULL; - EditVert *sh_vert= NULL; - - sh_edge= findedgelist(em, eve2,eve3); - - if(sh_edge) { /* Add a triangle */ - if(!exist_face_overlaps(em, eve1,eve2,eve3,NULL)) - fix_new_face(em, addfacelist(em, eve1,eve2,eve3,NULL,NULL,NULL)); - } - else { /* Check for a shared vertex */ - for(eve4= em->verts.first; eve4; eve4= eve4->next) { - if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) && - !findedgelist(em, eve1,eve4) && findedgelist(em, eve2,eve4) && - findedgelist(em, eve3,eve4)) { - sh_vert= eve4; - break; - } - } - - if(sh_vert) { - if(sh_vert) { - if(!exist_face_overlaps(em, eve1,eve2,eve4,eve3)) - fix_new_face(em, addfacelist(em, eve1,eve2,eve4,eve3,NULL,NULL)); - } - } - } - } - } - } - } - } - - EM_select_flush(em); - -// XXX DAG_id_tag_update(obedit->data, 0); -} - -static void addedgeface_mesh(EditMesh *em, wmOperator *op) -{ - EditVert *eve, *neweve[4]; - EditEdge *eed; - EditFace *efa; - short amount=0; - - /* how many selected ? */ - if(em->selectmode & SCE_SELECT_EDGE) { - /* in edge mode finding selected vertices means flushing down edge codes... */ - /* can't make face with only edge selection info... */ - EM_selectmode_set(em); - } - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - amount++; - if(amount>4) break; - neweve[amount-1]= eve; - } - } - - if(amount==2) { - eed= addedgelist(em, neweve[0], neweve[1], NULL); - EM_select_edge(eed, 1); - - // XXX DAG_id_tag_update(obedit->data, 0); - return; - } - else if(amount > 4) { - addfaces_from_edgenet(em); - return; - } - else if(amount<2) { - BKE_report(op->reports, RPT_WARNING, "More vertices are needed to make an edge/face"); - return; - } - - efa= NULL; // check later - - if(amount==3) { - - if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) { - efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL); - EM_select_face(efa, 1); - } - else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); - } - else if(amount==4) { - /* this test survives when theres 2 triangles */ - if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) { - int tria= 0; - - /* remove trias if they exist, 4 cases.... */ - if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++; - if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++; - if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++; - if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++; - - if(tria==2) join_triangles(em); - else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) { - /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */ - EditEdge *eedcheck; - int count; - count = 0; - for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) { - if(eedcheck->f & SELECT) { - count++; - } - } - - if(count++ > 4){ - addfaces_from_edgenet(em); - return; - } else { - /* if 4 edges exist, we just create the face, convex or not */ - efa= addface_from_edges(em); - if(efa==NULL) { - - /* the order of vertices can be anything, 6 cases to check */ - if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) { - efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) { - efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) { - efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) { - efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) { - efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL); - } - else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) { - efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL); - } - else BKE_report(op->reports, RPT_WARNING, "cannot find nice quad from concave set of vertices"); - - } - } - } - else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); - } - else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face"); - } - - if(efa) { - EM_select_face(efa, 1); - - fix_new_face(em, efa); - - recalc_editnormals(em); - } - } - -static int addedgeface_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - addedgeface_mesh(em, op); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_edge_face_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Make Edge/Face"; - ot->description= "Add an edge or face to selected"; - ot->idname= "MESH_OT_edge_face_add"; - - /* api callbacks */ - ot->exec= addedgeface_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - -} - - - -/* ************************ primitives ******************* */ - -// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker -// this hack is only used so that scons+mingw + split-sources hack works - // ------------------------------- start copied code -/* these are not the monkeys you are looking for */ -static int monkeyo= 4; -static int monkeynv= 271; -static int monkeynf= 250; -static signed char monkeyv[271][3]= { -{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92}, -{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83}, -{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102}, -{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92}, -{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74}, -{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99}, -{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105}, -{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100}, -{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100}, -{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73}, -{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45}, -{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68}, -{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68}, -{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80}, -{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96}, -{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90}, -{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85}, -{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94}, -{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96}, -{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95}, -{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84}, -{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109}, -{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88}, -{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82}, -{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96}, -{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96}, -{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100}, -{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104}, -{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71}, -{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88}, -{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84}, -{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81}, -{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99}, -{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87}, -{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100}, -{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97}, -{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86}, -{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96}, -{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79}, -{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59}, -{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37}, -{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59}, -{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7}, -{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9}, -{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52}, -{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51}, -{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55}, -{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34}, -{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30}, -{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7}, -{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57}, -{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26}, -{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16}, -{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54}, -{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52}, -{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28}, -{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57}, -{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27}, -{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35}, -{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24}, -{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41}, -{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41}, -{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62}, -{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42}, -{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48}, -{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62}, -{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63}, -{-26,-16,-42},{-17,49,-49}, -}; - -static signed char monkeyf[250][4]= { -{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4}, -{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6}, -{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8}, -{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12}, -{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12}, -{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4}, -{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4}, -{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23}, -{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15}, -{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, -{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, -{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44}, -{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19}, -{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38}, -{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39}, -{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42}, -{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16}, -{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32}, -{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35}, -{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21}, -{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11}, -{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38}, -{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39}, -{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34}, -{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34}, -{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36}, -{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27}, -{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42}, -{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34}, -{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26}, -{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35}, -{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35}, -{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58}, -{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52}, -{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49}, -{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24}, -{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100}, -{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24}, -{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110}, -{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48}, -{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43}, -{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6}, -{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30}, -{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5}, -{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13}, -{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30}, -{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31}, -{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35}, -{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27}, -{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23}, -{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35}, -{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4}, -{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35}, -{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33}, -{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35}, -{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36}, -{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39}, -{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17}, -{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19}, -{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30}, -{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30}, -{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66}, -{-68,-67,24,-33}, -}; - // ------------------------------- end copied code - - -#define PRIM_PLANE 0 -#define PRIM_CUBE 1 -#define PRIM_CIRCLE 4 -#define PRIM_CYLINDER 5 -#define PRIM_CONE 7 -#define PRIM_GRID 10 -#define PRIM_UVSPHERE 11 -#define PRIM_ICOSPHERE 12 -#define PRIM_MONKEY 13 - -static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg, - int subdiv, float dia, float depth, int ext, int fill) -{ - /* - * type - for the type of shape - * dia - the radius for cone,sphere cylinder etc. - * depth - - * ext - extrude - * fill - end capping, and option to fill in circle - * cent[3] - center of the data. - * */ - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown; - float phi, phid, vec[3]; - float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0}; - short a, b; - - EM_clear_flag_all(em, SELECT); - - phid= 2.0f*(float)M_PI/tot; - phi= .25f*(float)M_PI; - - switch(type) { - case PRIM_GRID: /* grid */ - /* clear flags */ - eve= em->verts.first; - while(eve) { - eve->f= 0; - eve= eve->next; - } - - /* one segment first: the X axis */ - phi = (2*dia)/(float)(tot-1); - phid = (2*dia)/(float)(seg-1); - for(a=tot-1;a>=0;a--) { - vec[0] = (phi*a) - dia; - vec[1]= - dia; - vec[2]= 0.0f; - eve= addvertlist(em, vec, NULL); - eve->f= 1+2+4; - if(a < tot -1) addedgelist(em, eve->prev, eve, NULL); - } - /* extrude and translate */ - vec[0]= vec[2]= 0.0; - vec[1]= phid; - - for(a=0;a<seg-1;a++) { - extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused - translateflag(em, 2, vec); - } - - /* and now do imat */ - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - mul_m4_v3(mat,eve->co); - } - eve= eve->next; - } - recalc_editnormals(em); - break; - - case PRIM_UVSPHERE: /* UVsphere */ - - /* clear all flags */ - eve= em->verts.first; - while(eve) { - eve->f= 0; - eve= eve->next; - } - - /* one segment first */ - phi= 0; - phid/=2; - for(a=0; a<=tot; a++) { - vec[0]= dia*sinf(phi); - vec[1]= 0.0; - vec[2]= dia*cosf(phi); - eve= addvertlist(em, vec, NULL); - eve->f= 1+2+4; - if(a==0) v1= eve; - else addedgelist(em, eve, eve->prev, NULL); - phi+= phid; - } - - /* extrude and rotate */ - phi= M_PI/seg; - q[0]= cos(phi); - q[3]= sin(phi); - q[1]=q[2]= 0; - quat_to_mat3( cmat,q); - - for(a=0; a<seg; a++) { - extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused - rotateflag(em, 2, v1->co, cmat); - } - - removedoublesflag(em, 4, 0, 0.0001); - - /* and now do imat */ - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - mul_m4_v3(mat,eve->co); - } - eve= eve->next; - } - recalc_editnormals(em); - break; - case PRIM_ICOSPHERE: /* Icosphere */ - { - EditVert *eva[12]; - EditEdge *eed; - - /* clear all flags */ - eve= em->verts.first; - while(eve) { - eve->f= 0; - eve= eve->next; - } - dia/=200; - for(a=0;a<12;a++) { - vec[0]= dia*icovert[a][0]; - vec[1]= dia*icovert[a][1]; - vec[2]= dia*icovert[a][2]; - eva[a]= addvertlist(em, vec, NULL); - eva[a]->f= 1+2; - } - for(a=0;a<20;a++) { - EditFace *evtemp; - v1= eva[ icoface[a][0] ]; - v2= eva[ icoface[a][1] ]; - v3= eva[ icoface[a][2] ]; - evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL); - evtemp->e1->f = 1+2; - evtemp->e2->f = 1+2; - evtemp->e3->f = 1+2; - } - - dia*=200; - for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0); - /* and now do imat */ - eve= em->verts.first; - while(eve) { - if(eve->f & 2) { - mul_m4_v3(mat,eve->co); - } - eve= eve->next; - } - - // Clear the flag 2 from the edges - for(eed=em->edges.first;eed;eed=eed->next){ - if(eed->f & 2){ - eed->f &= !2; - } - } - } - break; - case PRIM_MONKEY: /* Monkey */ - { - //extern int monkeyo, monkeynv, monkeynf; - //extern signed char monkeyf[][4]; - //extern signed char monkeyv[][3]; - EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv"); - int i; - - for (i=0; i<monkeynv; i++) { - float v[3]; - v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0; - tv[i]= addvertlist(em, v, NULL); - tv[i]->f |= SELECT; - tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL); - tv[monkeynv+i]->f |= SELECT; - } - for (i=0; i<monkeynf; i++) { - addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); - addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL); - } - - MEM_freeN(tv); - - /* and now do imat */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - mul_m4_v3(mat,eve->co); - } - } - recalc_editnormals(em); - } - break; - default: /* all types except grid, sphere... */ - if(type==PRIM_CONE); - else if(ext==0) - depth= 0.0f; - - /* first vertex at 0° for circular objects */ - if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) ) - phi = 0.0f; - - vtop= vdown= v1= v2= 0; - for(b=0; b<=ext; b++) { - for(a=0; a<tot; a++) { - - vec[0]= dia*sinf(phi); - vec[1]= dia*cosf(phi); - vec[2]= b?depth:-depth; - - mul_m4_v3(mat, vec); - eve= addvertlist(em, vec, NULL); - eve->f= SELECT; - if(a==0) { - if(b==0) v1= eve; - else v2= eve; - } - phi+=phid; - } - } - - /* center vertices */ - /* type PRIM_CONE can only have 1 one side filled - * if the cone has no capping, dont add vtop */ - if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) { - vec[0]= vec[1]= 0.0f; - vec[2]= type==PRIM_CONE ? depth : -depth; - mul_m4_v3(mat, vec); - vdown= addvertlist(em, vec, NULL); - if((ext || type==PRIM_CONE) && fill) { - vec[0]= vec[1]= 0.0f; - vec[2]= type==PRIM_CONE ? -depth : depth; - mul_m4_v3(mat,vec); - vtop= addvertlist(em, vec, NULL); - } - } else { - vdown= v1; - vtop= v2; - } - if(vtop) vtop->f= SELECT; - if(vdown) vdown->f= SELECT; - - /* top and bottom face */ - if(fill || type==PRIM_CONE) { - if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) { - v3= v1->next->next; - if(ext) v4= v2->next->next; - - addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL); - if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL); - - } - else { - v3= v1; - v4= v2; - for(a=1; a<tot; a++) { - addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL); - v3= v3->next; - if(ext && fill) { - addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL); - v4= v4->next; - } - } - if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) { - addfacelist(em, vdown, v3, v1, 0, NULL, NULL); - if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL); - } - } - } - else if(type==PRIM_CIRCLE) { /* we need edges for a circle */ - v3= v1; - for(a=1;a<tot;a++) { - addedgelist(em, v3, v3->next, NULL); - v3= v3->next; - } - addedgelist(em, v3, v1, NULL); - } - /* side faces */ - if(ext) { - v3= v1; - v4= v2; - for(a=1; a<tot; a++) { - addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL); - v3= v3->next; - v4= v4->next; - } - addfacelist(em, v3, v1, v2, v4, NULL, NULL); - } - else if(fill && type==PRIM_CONE) { - /* add the bottom flat area of the cone - * if capping is disabled dont bother */ - v3= v1; - for(a=1; a<tot; a++) { - addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL); - v3= v3->next; - } - addfacelist(em, vtop, v1, v3, 0, NULL, NULL); - } - } - - EM_stats_update(em); - /* simple selection flush OK, based on fact it's a single model */ - EM_select_flush(em); /* flushes vertex -> edge -> face selection */ - - if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY)) - EM_recalc_normal_direction(em, FALSE, TRUE); /* otherwise monkey has eyes in wrong direction */ - - BKE_mesh_end_editmesh(obedit->data, em); -} - -/* ********* add primitive operators ************* */ - -static const char *get_mesh_defname(int type) -{ - switch (type) { - case PRIM_PLANE: return "Plane"; - case PRIM_CUBE: return "Cube"; - case PRIM_CIRCLE: return "Circle"; - case PRIM_CYLINDER: return "Cylinder"; - case PRIM_CONE: return "Cone"; - case PRIM_GRID: return "Grid"; - case PRIM_UVSPHERE: return "Sphere"; - case PRIM_ICOSPHERE: return "Icosphere"; - case PRIM_MONKEY: return "Monkey"; - default: - return "Mesh"; - } -} - -static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmode, unsigned int layer, - int type, int tot, int seg, - int subdiv, float dia, float depth, int ext, int fill) -{ - Object *obedit= CTX_data_edit_object(C); - int newob = 0; - float mat[4][4]; - float scale; - - if(obedit==NULL || obedit->type!=OB_MESH) { - obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer); - - rename_id((ID *)obedit, get_mesh_defname(type)); - rename_id((ID *)obedit->data, get_mesh_defname(type)); - - /* create editmode */ - ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - newob = 1; - } - else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - - scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); - - dia *= scale; - depth *= scale * 0.5f; - - make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - - /* userdef */ - if (newob && !enter_editmode) { - ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */ - } - WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit); -} - -static int add_primitive_plane_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */ - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_PLANE, 4, 0, 0, sqrt(2.0f), 0.0f, 0, 1); - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_plane_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Plane"; - ot->description= "Construct a filled planar mesh with 4 vertices"; - ot->idname= "MESH_OT_primitive_plane_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_plane_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_cube_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */ - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_CUBE, 4, 0, 0, sqrt(2.0f), 2.0f, 1, 1); - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_cube_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Cube"; - ot->description= "Construct a cube mesh"; - ot->idname= "MESH_OT_primitive_cube_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_cube_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_circle_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_CIRCLE, RNA_int_get(op->ptr, "vertices"), 0, 0, - RNA_float_get(op->ptr,"radius"), 0.0f, 0, - RNA_boolean_get(op->ptr, "fill")); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_circle_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Circle"; - ot->description= "Construct a circle mesh"; - ot->idname= "MESH_OT_primitive_circle_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_circle_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500); - RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); - RNA_def_boolean(ot->srna, "fill", 0, "Fill", ""); - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_cylinder_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_CYLINDER, RNA_int_get(op->ptr, "vertices"), 0, 0, - RNA_float_get(op->ptr,"radius"), - RNA_float_get(op->ptr, "depth"), 1, - RNA_boolean_get(op->ptr, "cap_ends")); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Cylinder"; - ot->description= "Construct a cylinder mesh"; - ot->idname= "MESH_OT_primitive_cylinder_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_cylinder_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500); - RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); - RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); - RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", ""); - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_cone_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_CONE, RNA_int_get(op->ptr, "vertices"), 0, 0, - RNA_float_get(op->ptr,"radius"), RNA_float_get(op->ptr, "depth"), - 0, RNA_boolean_get(op->ptr, "cap_end")); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_cone_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Cone"; - ot->description= "Construct a conic mesh (ends filled)"; - ot->idname= "MESH_OT_primitive_cone_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_cone_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500); - RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); - RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); - RNA_def_boolean(ot->srna, "cap_end", 1, "Cap End", ""); - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_grid_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_GRID, RNA_int_get(op->ptr, "x_subdivisions"), - RNA_int_get(op->ptr, "y_subdivisions"), 0, - RNA_float_get(op->ptr,"size"), 0.0f, 0, 1); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_grid_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Grid"; - ot->description= "Construct a grid mesh"; - ot->idname= "MESH_OT_primitive_grid_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_grid_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000); - RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000); - RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX); - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_monkey_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_monkey_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Monkey"; - ot->description= "Construct a Suzanne mesh"; - ot->idname= "MESH_OT_primitive_monkey_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_monkey_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_UVSPHERE, RNA_int_get(op->ptr, "ring_count"), - RNA_int_get(op->ptr, "segments"), 0, - RNA_float_get(op->ptr,"size"), 0.0f, 0, 0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add UV Sphere"; - ot->description= "Construct a UV sphere mesh"; - ot->idname= "MESH_OT_primitive_uv_sphere_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_uvsphere_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500); - RNA_def_int(ot->srna, "ring_count", 16, INT_MIN, INT_MAX, "Rings", "", 3, 500); - RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00); - - ED_object_add_generic_props(ot, TRUE); -} - -static int add_primitive_icosphere_exec(bContext *C, wmOperator *op) -{ - int enter_editmode; - unsigned int layer; - float loc[3], rot[3]; - - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; - - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_ICOSPHERE, 0, 0, RNA_int_get(op->ptr, "subdivisions"), - RNA_float_get(op->ptr,"size"), 0.0f, 0, 0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Ico Sphere"; - ot->description= "Construct an Icosphere mesh"; - ot->idname= "MESH_OT_primitive_ico_sphere_add"; - - /* api callbacks */ - ot->invoke= ED_object_add_generic_invoke; - ot->exec= add_primitive_icosphere_exec; - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "subdivisions", 2, 0, INT_MAX, "Subdivisions", "", 0, 8); - RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00); - - ED_object_add_generic_props(ot, TRUE); -} - -/****************** add duplicate operator ***************/ - -static int mesh_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(ob->data); - - adduplicateflag(em, SELECT); - - BKE_mesh_end_editmesh(ob->data, em); - - DAG_id_tag_update(ob->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - WM_cursor_wait(1); - mesh_duplicate_exec(C, op); - WM_cursor_wait(0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_duplicate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Duplicate Mesh"; - ot->description= "Duplicate selected vertices, edges or faces"; - ot->idname= "MESH_OT_duplicate"; - - /* api callbacks */ - ot->invoke= mesh_duplicate_invoke; - ot->exec= mesh_duplicate_exec; - - ot->poll= ED_operator_editmesh; - - /* to give to transform */ - RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", ""); -} - diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c deleted file mode 100644 index b7ed6ec14ca..00000000000 --- a/source/blender/editors/mesh/editmesh_lib.c +++ /dev/null @@ -1,2848 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 by Blender Foundation - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_lib.c - * \ingroup edmesh - */ - - -/* - -editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data - -*/ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_editVert.h" -#include "BLI_edgehash.h" -#include "BLI_utildefines.h" - -#include "BKE_customdata.h" -#include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_mesh.h" - - -#include "ED_mesh.h" -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_transform.h" - -#include "mesh_intern.h" - -/* Helpers for EM_set_flag_all_selectmode */ -#define SET_EVE_FLAG(eve, flag) \ - if (eve->h==0) { \ - if (flag & SELECT && !(eve->f & SELECT)) { \ - ++selvert; \ - } \ - eve->f |= flag; \ - } - -#define SET_EED_FLAG(eed, flag) \ - if (eed->h==0) { \ - if (flag & SELECT && !(eed->f & SELECT)) { \ - ++seledge; \ - } \ - eed->f |= flag; \ - SET_EVE_FLAG(eed->v1, flag); \ - SET_EVE_FLAG(eed->v2, flag); \ - } - - -/* ****************** stats *************** */ - -int EM_nfaces_selected(EditMesh *em) -{ - EditFace *efa; - int count= 0; - - for (efa= em->faces.first; efa; efa= efa->next) - if (efa->f & SELECT) - count++; - - em->totfacesel= count; - - return count; -} - -int EM_nedges_selected(EditMesh *em) -{ - EditEdge *eed; - int count= 0; - - for (eed= em->edges.first; eed; eed= eed->next) - if(eed->f & SELECT) - count++; - - em->totedgesel= count; - - return count; -} - -int EM_nvertices_selected(EditMesh *em) -{ - EditVert *eve; - int count= 0; - - for (eve= em->verts.first; eve; eve= eve->next) - if (eve->f & SELECT) - count++; - - em->totvertsel= count; - - return count; -} - -void EM_stats_update(EditMesh *em) -{ - - em->totvert= BLI_countlist(&em->verts); - em->totedge= BLI_countlist(&em->edges); - em->totface= BLI_countlist(&em->faces); - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -/* ************************************** */ - -/* this replaces the active flag used in uv/face mode */ -void EM_set_actFace(EditMesh *em, EditFace *efa) -{ - em->act_face = efa; -} - -EditFace *EM_get_actFace(EditMesh *em, int sloppy) -{ - if (em->act_face) { - return em->act_face; - } else if (sloppy) { - EditFace *efa= NULL; - EditSelection *ese; - - ese = em->selected.last; - for (; ese; ese=ese->prev){ - if(ese->type == EDITFACE) { - efa = (EditFace *)ese->data; - - if (efa->h) efa= NULL; - else break; - } - } - if (efa==NULL) { - for (efa= em->faces.first; efa; efa= efa->next) { - if (efa->f & SELECT) - break; - } - } - return efa; /* can still be null */ - } - return NULL; -} - -int EM_get_actSelection(EditMesh *em, EditSelection *ese) -{ - EditSelection *ese_last = em->selected.last; - EditFace *efa = EM_get_actFace(em, 0); - - ese->next = ese->prev = NULL; - - if (ese_last) { - if (ese_last->type == EDITFACE) { /* if there is an active face, use it over the last selected face */ - if (efa) { - ese->data = (void *)efa; - } else { - ese->data = ese_last->data; - } - ese->type = EDITFACE; - } else { - ese->data = ese_last->data; - ese->type = ese_last->type; - } - } else if (efa) { /* no */ - ese->data = (void *)efa; - ese->type = EDITFACE; - } else { - ese->data = NULL; - return 0; - } - return 1; -} - -/* ********* Selection History ************ */ -static int EM_check_selection(EditMesh *em, void *data) -{ - EditSelection *ese; - - for(ese = em->selected.first; ese; ese = ese->next){ - if(ese->data == data) return 1; - } - - return 0; -} - -void EM_remove_selection(EditMesh *em, void *data, int UNUSED(type)) -{ - EditSelection *ese; - for(ese=em->selected.first; ese; ese = ese->next){ - if(ese->data == data){ - BLI_freelinkN(&(em->selected),ese); - break; - } - } -} - -void EM_store_selection(EditMesh *em, void *data, int type) -{ - EditSelection *ese; - if(!EM_check_selection(em, data)){ - ese = (EditSelection*) MEM_callocN( sizeof(EditSelection), "Edit Selection"); - ese->type = type; - ese->data = data; - BLI_addtail(&(em->selected),ese); - } -} - -void EM_validate_selections(EditMesh *em) -{ - EditSelection *ese, *nextese; - - ese = em->selected.first; - - while(ese){ - nextese = ese->next; - if(ese->type == EDITVERT && !(((EditVert*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese); - else if(ese->type == EDITEDGE && !(((EditEdge*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese); - else if(ese->type == EDITFACE && !(((EditFace*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese); - ese = nextese; - } -} - -static void EM_strip_selections(EditMesh *em) -{ - EditSelection *ese, *nextese; - if(!(em->selectmode & SCE_SELECT_VERTEX)){ - ese = em->selected.first; - while(ese){ - nextese = ese->next; - if(ese->type == EDITVERT) BLI_freelinkN(&(em->selected),ese); - ese = nextese; - } - } - if(!(em->selectmode & SCE_SELECT_EDGE)){ - ese=em->selected.first; - while(ese){ - nextese = ese->next; - if(ese->type == EDITEDGE) BLI_freelinkN(&(em->selected), ese); - ese = nextese; - } - } - if(!(em->selectmode & SCE_SELECT_FACE)){ - ese=em->selected.first; - while(ese){ - nextese = ese->next; - if(ese->type == EDITFACE) BLI_freelinkN(&(em->selected), ese); - ese = nextese; - } - } -} - -/* generic way to get data from an EditSelection type -These functions were written to be used by the Modifier widget when in Rotate about active mode, -but can be used anywhere. -EM_editselection_center -EM_editselection_normal -EM_editselection_plane -*/ -void EM_editselection_center(float *center, EditSelection *ese) -{ - if (ese->type==EDITVERT) { - EditVert *eve= ese->data; - copy_v3_v3(center, eve->co); - } else if (ese->type==EDITEDGE) { - EditEdge *eed= ese->data; - add_v3_v3v3(center, eed->v1->co, eed->v2->co); - mul_v3_fl(center, 0.5); - } else if (ese->type==EDITFACE) { - EditFace *efa= ese->data; - copy_v3_v3(center, efa->cent); - } -} - -void EM_editselection_normal(float *normal, EditSelection *ese) -{ - if (ese->type==EDITVERT) { - EditVert *eve= ese->data; - copy_v3_v3(normal, eve->no); - } else if (ese->type==EDITEDGE) { - EditEdge *eed= ese->data; - float plane[3]; /* need a plane to correct the normal */ - float vec[3]; /* temp vec storage */ - - add_v3_v3v3(normal, eed->v1->no, eed->v2->no); - sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); - - /* the 2 vertex normals will be close but not at rightangles to the edge - for rotate about edge we want them to be at right angles, so we need to - do some extra colculation to correct the vert normals, - we need the plane for this */ - cross_v3_v3v3(vec, normal, plane); - cross_v3_v3v3(normal, plane, vec); - normalize_v3(normal); - - } else if (ese->type==EDITFACE) { - EditFace *efa= ese->data; - copy_v3_v3(normal, efa->n); - } -} - -/* Calculate a plane that is rightangles to the edge/vert/faces normal -also make the plane run allong an axis that is related to the geometry, -because this is used for the manipulators Y axis.*/ -void EM_editselection_plane(float *plane, EditSelection *ese) -{ - if (ese->type==EDITVERT) { - EditVert *eve= ese->data; - float vec[3]={0,0,0}; - - if (ese->prev) { /*use previously selected data to make a usefull vertex plane */ - EM_editselection_center(vec, ese->prev); - sub_v3_v3v3(plane, vec, eve->co); - } else { - /* make a fake plane thats at rightangles to the normal - we cant make a crossvec from a vec thats the same as the vec - unlikely but possible, so make sure if the normal is (0,0,1) - that vec isnt the same or in the same direction even.*/ - if (eve->no[0]<0.5f) vec[0]=1; - else if (eve->no[1]<0.5f) vec[1]=1; - else vec[2]=1; - cross_v3_v3v3(plane, eve->no, vec); - } - } else if (ese->type==EDITEDGE) { - EditEdge *eed= ese->data; - - /*the plane is simple, it runs allong the edge - however selecting different edges can swap the direction of the y axis. - this makes it less likely for the y axis of the manipulator - (running along the edge).. to flip less often. - at least its more predictable */ - if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */ - sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); - else - sub_v3_v3v3(plane, eed->v1->co, eed->v2->co); - - } else if (ese->type==EDITFACE) { - EditFace *efa= ese->data; - float vec[3]; - if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/ - float vecA[3], vecB[3]; - sub_v3_v3v3(vecA, efa->v4->co, efa->v3->co); - sub_v3_v3v3(vecB, efa->v1->co, efa->v2->co); - add_v3_v3v3(plane, vecA, vecB); - - sub_v3_v3v3(vecA, efa->v1->co, efa->v4->co); - sub_v3_v3v3(vecB, efa->v2->co, efa->v3->co); - add_v3_v3v3(vec, vecA, vecB); - /*use the biggest edge length*/ - if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) - copy_v3_v3(plane, vec); - } else { - /*start with v1-2 */ - sub_v3_v3v3(plane, efa->v1->co, efa->v2->co); - - /*test the edge between v2-3, use if longer */ - sub_v3_v3v3(vec, efa->v2->co, efa->v3->co); - if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) - copy_v3_v3(plane, vec); - - /*test the edge between v1-3, use if longer */ - sub_v3_v3v3(vec, efa->v3->co, efa->v1->co); - if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2]) - copy_v3_v3(plane, vec); - } - } - normalize_v3(plane); -} - - - -void EM_select_face(EditFace *efa, int sel) -{ - if(sel) { - efa->f |= SELECT; - efa->e1->f |= SELECT; - efa->e2->f |= SELECT; - efa->e3->f |= SELECT; - if(efa->e4) efa->e4->f |= SELECT; - efa->v1->f |= SELECT; - efa->v2->f |= SELECT; - efa->v3->f |= SELECT; - if(efa->v4) efa->v4->f |= SELECT; - } - else { - efa->f &= ~SELECT; - efa->e1->f &= ~SELECT; - efa->e2->f &= ~SELECT; - efa->e3->f &= ~SELECT; - if(efa->e4) efa->e4->f &= ~SELECT; - efa->v1->f &= ~SELECT; - efa->v2->f &= ~SELECT; - efa->v3->f &= ~SELECT; - if(efa->v4) efa->v4->f &= ~SELECT; - } -} - -void EM_select_edge(EditEdge *eed, int sel) -{ - if(sel) { - eed->f |= SELECT; - eed->v1->f |= SELECT; - eed->v2->f |= SELECT; - } - else { - eed->f &= ~SELECT; - eed->v1->f &= ~SELECT; - eed->v2->f &= ~SELECT; - } -} - -void EM_select_face_fgon(EditMesh *em, EditFace *efa, int val) -{ - short index=0; - - if(efa->fgonf==0) EM_select_face(efa, val); - else { - if(efa->e1->fgoni) index= efa->e1->fgoni; - if(efa->e2->fgoni) index= efa->e2->fgoni; - if(efa->e3->fgoni) index= efa->e3->fgoni; - if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni; - - if((index==0) && (G.f & G_DEBUG))printf("wrong fgon select\n"); - - // select all ngon faces with index - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->fgonf) { - if(efa->e1->fgoni==index || efa->e2->fgoni==index || - efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) { - EM_select_face(efa, val); - } - } - } - } -} - - -/* only vertices */ -int faceselectedOR(EditFace *efa, int flag) -{ - if ((efa->v1->f | efa->v2->f | efa->v3->f | (efa->v4?efa->v4->f:0))&flag) { - return 1; - } else { - return 0; - } -} - -// replace with (efa->f & SELECT) -int faceselectedAND(EditFace *efa, int flag) -{ - if ((efa->v1->f & efa->v2->f & efa->v3->f & (efa->v4?efa->v4->f:flag))&flag) { - return 1; - } else { - return 0; - } -} - -void EM_clear_flag_all(EditMesh *em, int flag) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - for (eve= em->verts.first; eve; eve= eve->next) eve->f &= ~flag; - for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~flag; - for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~flag; - - if(flag & SELECT) { - BLI_freelistN(&(em->selected)); - em->totvertsel= em->totedgesel= em->totfacesel= 0; - } -} - -void EM_set_flag_all(EditMesh *em, int flag) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag; - for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag; - for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag; - - if(flag & SELECT) { - em->totvertsel= em->totvert; - em->totedgesel= em->totedge; - em->totfacesel= em->totface; - } -} - -void EM_set_flag_all_selectmode(EditMesh *em, int flag) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - int selvert= 0, seledge= 0, selface= 0; - - if (em->selectmode & SCE_SELECT_VERTEX) { - /* If vertex select mode enabled all the data could be affected */ - for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag; - for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag; - for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag; - - if (flag & SELECT) { - selvert= em->totvert; - seledge= em->totedge; - selface= em->totface; - } - } else if (em->selectmode & SCE_SELECT_EDGE) { - /* If edge select mode is enabled we should affect on all edges, faces and */ - /* vertices, connected to them */ - - for (eed= em->edges.first; eed; eed= eed->next) { - SET_EED_FLAG(eed, flag) - } - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - efa->f |= flag; - - if (flag & SELECT) { - ++selface; - } - } - } - } else if (em->selectmode & SCE_SELECT_FACE) { - /* No vertex and edge select mode, only face selection */ - /* In face select mode only edges and vertices belongs to faces should be affected */ - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - efa->f |= flag; - SET_EED_FLAG(efa->e1, flag); - SET_EED_FLAG(efa->e2, flag); - SET_EED_FLAG(efa->e3, flag); - - if (efa->e4) { - SET_EED_FLAG(efa->e4, flag); - } - - if (flag & SELECT) { - ++selface; - } - } - } - } - - if(flag & SELECT) { - em->totvertsel= selvert; - em->totedgesel= seledge; - em->totfacesel= selface; - } - } -/* flush for changes in vertices only */ -void EM_deselect_flush(EditMesh *em) -{ - EditEdge *eed; - EditFace *efa; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->f & eed->v2->f & SELECT); - else eed->f &= ~SELECT; - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4) { - if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ); - else efa->f &= ~SELECT; - } - else { - if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ); - else efa->f &= ~SELECT; - } - } - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - - -/* flush selection to edges & faces */ - -/* this only based on coherent selected vertices, for example when adding new - objects. call clear_flag_all() before you select vertices to be sure it ends OK! - -*/ - -void EM_select_flush(EditMesh *em) -{ - EditEdge *eed; - EditFace *efa; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT; - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4) { - if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ) efa->f |= SELECT; - } - else { - if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ) efa->f |= SELECT; - } - } - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -/* when vertices or edges can be selected, also make fgon consistent */ -static void check_fgons_selection(EditMesh *em) -{ - EditFace *efa, *efan; - EditEdge *eed; - ListBase *lbar; - int sel, desel, index, totfgon= 0; - - /* count amount of fgons */ - for(eed= em->edges.first; eed; eed= eed->next) - if(eed->fgoni>totfgon) totfgon= eed->fgoni; - - if(totfgon==0) return; - - lbar= MEM_callocN((totfgon+1)*sizeof(ListBase), "listbase array"); - - /* put all fgons in lbar */ - for(efa= em->faces.first; efa; efa= efan) { - efan= efa->next; - index= efa->e1->fgoni; - if(index==0) index= efa->e2->fgoni; - if(index==0) index= efa->e3->fgoni; - if(index==0 && efa->e4) index= efa->e4->fgoni; - if(index) { - BLI_remlink(&em->faces, efa); - BLI_addtail(&lbar[index], efa); - } - } - - /* now check the fgons */ - for(index=1; index<=totfgon; index++) { - /* we count on vertices/faces/edges being set OK, so we only have to set ngon itself */ - sel= desel= 0; - for(efa= lbar[index].first; efa; efa= efa->next) { - if(efa->e1->fgoni==0) { - if(efa->e1->f & SELECT) sel++; - else desel++; - } - if(efa->e2->fgoni==0) { - if(efa->e2->f & SELECT) sel++; - else desel++; - } - if(efa->e3->fgoni==0) { - if(efa->e3->f & SELECT) sel++; - else desel++; - } - if(efa->e4 && efa->e4->fgoni==0) { - if(efa->e4->f & SELECT) sel++; - else desel++; - } - - if(sel && desel) break; - } - - if(sel && desel) sel= 0; - else if(sel) sel= 1; - else sel= 0; - - /* select/deselect and put back */ - for(efa= lbar[index].first; efa; efa= efa->next) { - if(sel) efa->f |= SELECT; - else efa->f &= ~SELECT; - } - BLI_movelisttolist(&em->faces, &lbar[index]); - } - - MEM_freeN(lbar); -} - - -/* flush to edges & faces */ - -/* based on select mode it selects edges/faces - assumed is that verts/edges/faces were properly selected themselves - with the calls above -*/ - -void EM_selectmode_flush(EditMesh *em) -{ - EditEdge *eed; - EditFace *efa; - - // flush to edges & faces - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT; - else eed->f &= ~SELECT; - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4) { - if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT) efa->f |= SELECT; - else efa->f &= ~SELECT; - } - else { - if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT) efa->f |= SELECT; - else efa->f &= ~SELECT; - } - } - } - // flush to faces - else if(em->selectmode & SCE_SELECT_EDGE) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4) { - if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT) efa->f |= SELECT; - else efa->f &= ~SELECT; - } - else { - if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT) efa->f |= SELECT; - else efa->f &= ~SELECT; - } - } - } - // make sure selected faces have selected edges too, for extrude (hack?) - else if(em->selectmode & SCE_SELECT_FACE) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) EM_select_face(efa, 1); - } - } - - if(!(em->selectmode & SCE_SELECT_FACE)) - check_fgons_selection(em); - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -void EM_convertsel(EditMesh *em, short oldmode, short selectmode) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - /*clear flags*/ - for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0; - for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0; - for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0; - - /*have to find out what the selectionmode was previously*/ - if(oldmode == SCE_SELECT_VERTEX) { - if(selectmode == SCE_SELECT_EDGE){ - /*select all edges associated with every selected vertex*/ - for(eed= em->edges.first; eed; eed= eed->next){ - if(eed->v1->f&SELECT) eed->f1 = 1; - else if(eed->v2->f&SELECT) eed->f1 = 1; - } - - for(eed= em->edges.first; eed; eed= eed->next){ - if(eed->f1 == 1) EM_select_edge(eed,1); - } - } - else if(selectmode == SCE_SELECT_FACE){ - /*select all faces associated with every selected vertex*/ - for(efa= em->faces.first; efa; efa= efa->next){ - if(efa->v1->f&SELECT) efa->f1 = 1; - else if(efa->v2->f&SELECT) efa->f1 = 1; - else if(efa->v3->f&SELECT) efa->f1 = 1; - else{ - if(efa->v4){ - if(efa->v4->f&SELECT) efa->f1 =1; - } - } - } - for(efa= em->faces.first; efa; efa= efa->next){ - if(efa->f1 == 1) EM_select_face(efa,1); - } - } - } - - if(oldmode == SCE_SELECT_EDGE){ - if(selectmode == SCE_SELECT_FACE){ - for(efa= em->faces.first; efa; efa= efa->next){ - if(efa->e1->f&SELECT) efa->f1 = 1; - else if(efa->e2->f&SELECT) efa->f1 = 1; - else if(efa->e3->f&SELECT) efa->f1 = 1; - else if(efa->e4){ - if(efa->e4->f&SELECT) efa->f1 = 1; - } - } - for(efa= em->faces.first; efa; efa= efa->next){ - if(efa->f1 == 1) EM_select_face(efa,1); - } - } - } - - check_fgons_selection(em); - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -void EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit) -{ - scene->toolsettings->selectmode= get_mesh(obedit)->edit_mesh->selectmode; -} - -/* when switching select mode, makes sure selection is consistent for editing */ -/* also for paranoia checks to make sure edge or face mode works */ -void EM_selectmode_set(EditMesh *em) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - EM_strip_selections(em); /*strip EditSelections from em->selected that are not relevant to new mode*/ - - if(em->selectmode & SCE_SELECT_VERTEX) { - /* vertices -> edges -> faces */ - for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~SELECT; - for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~SELECT; - - EM_select_flush(em); - } - else if(em->selectmode & SCE_SELECT_EDGE) { - /* deselect vertices, and select again based on edge select */ - for(eve= em->verts.first; eve; eve= eve->next) eve->f &= ~SELECT; - for(eed= em->edges.first; eed; eed= eed->next) - if(eed->f & SELECT) EM_select_edge(eed, 1); - /* selects faces based on edge status */ - EM_selectmode_flush(em); - } - else if(em->selectmode & SCE_SELECT_FACE) { - /* deselect eges, and select again based on face select */ - for(eed= em->edges.first; eed; eed= eed->next) EM_select_edge(eed, 0); - - for(efa= em->faces.first; efa; efa= efa->next) - if(efa->f & SELECT) EM_select_face(efa, 1); - } - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -/* paranoia check, actually only for entering editmode. rule: -- vertex hidden, always means edge is hidden too -- edge hidden, always means face is hidden too -- face hidden, dont change anything -*/ -void EM_hide_reset(EditMesh *em) -{ - EditEdge *eed; - EditFace *efa; - - for(eed= em->edges.first; eed; eed= eed->next) - if(eed->v1->h || eed->v2->h) eed->h |= 1; - - for(efa= em->faces.first; efa; efa= efa->next) - if((efa->e1->h & 1) || (efa->e2->h & 1) || (efa->e3->h & 1) || (efa->e4 && (efa->e4->h & 1))) - efa->h= 1; - -} - -void EM_data_interp_from_verts(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *eve, float fac) -{ - void *src[2]; - float w[2]; - - if (v1->data && v2->data) { - src[0]= v1->data; - src[1]= v2->data; - w[0] = 1.0f-fac; - w[1] = fac; - - CustomData_em_interp(&em->vdata, src, w, NULL, 2, eve->data); - } -} - -void EM_data_interp_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4) -{ - float w[2][4][4]; - void *src[2]; - int count = (efa2)? 2: 1; - - if (efa1->data) { - /* set weights for copying from corners directly to other corners */ - memset(w, 0, sizeof(w)); - - w[i1/4][0][i1%4]= 1.0f; - w[i2/4][1][i2%4]= 1.0f; - w[i3/4][2][i3%4]= 1.0f; - if (i4 != -1) - w[i4/4][3][i4%4]= 1.0f; - - src[0]= efa1->data; - src[1]= (efa2)? efa2->data: NULL; - - CustomData_em_interp(&em->fdata, src, NULL, (float*)w, count, efan->data); - } -} - -EditFace *EM_face_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, int i1, int i2, int i3, int i4) -{ - EditFace *efan; - EditVert **v[2]; - - v[0]= &efa1->v1; - v[1]= (efa2)? &efa2->v1: NULL; - - efan= addfacelist(em, v[i1/4][i1%4], v[i2/4][i2%4], v[i3/4][i3%4], - (i4 == -1)? 0: v[i4/4][i4%4], efa1, NULL); - - EM_data_interp_from_faces(em, efa1, efa2, efan, i1, i2, i3, i4); - - return efan; -} - -static void update_data_blocks(EditMesh *em, CustomData *olddata, CustomData *data) -{ - EditFace *efa; - EditVert *eve; - void *block; - - if (data == &em->vdata) { - for(eve= em->verts.first; eve; eve= eve->next) { - block = NULL; - CustomData_em_set_default(data, &block); - CustomData_em_copy_data(olddata, data, eve->data, &block); - CustomData_em_free_block(olddata, &eve->data); - eve->data= block; - } - } - else if (data == &em->fdata) { - for(efa= em->faces.first; efa; efa= efa->next) { - block = NULL; - CustomData_em_set_default(data, &block); - CustomData_em_copy_data(olddata, data, efa->data, &block); - CustomData_em_free_block(olddata, &efa->data); - efa->data= block; - } - } -} - -void EM_add_data_layer(EditMesh *em, CustomData *data, int type, const char *name) -{ - CustomData olddata; - - olddata= *data; - olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL; - CustomData_add_layer_named(data, type, CD_CALLOC, NULL, 0, name); - - update_data_blocks(em, &olddata, data); - if (olddata.layers) MEM_freeN(olddata.layers); -} - -void EM_free_data_layer(EditMesh *em, CustomData *data, int type) -{ - CustomData olddata; - - olddata= *data; - olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL; - CustomData_free_layer_active(data, type, 0); - - update_data_blocks(em, &olddata, data); - if (olddata.layers) MEM_freeN(olddata.layers); -} - -/* ******** EXTRUDE ********* */ - -static void add_normal_aligned(float *nor, float *add) -{ - if( INPR(nor, add) < -0.9999f) - sub_v3_v3(nor, add); - else - add_v3_v3(nor, add); -} - -static void set_edge_directions_f2(EditMesh *em, int val) -{ - EditFace *efa; - int do_all= 1; - - /* edge directions are used for extrude, to detect direction of edges that make new faces */ - /* we have set 'f2' flags in edges that need to get a direction set (e.g. get new face) */ - /* the val argument differs... so we need it as arg */ - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - do_all= 0; - if(efa->e1->f2<val) { - if(efa->e1->v1 == efa->v1) efa->e1->dir= 0; - else efa->e1->dir= 1; - } - if(efa->e2->f2<val) { - if(efa->e2->v1 == efa->v2) efa->e2->dir= 0; - else efa->e2->dir= 1; - } - if(efa->e3->f2<val) { - if(efa->e3->v1 == efa->v3) efa->e3->dir= 0; - else efa->e3->dir= 1; - } - if(efa->e4 && efa->e4->f2<val) { - if(efa->e4->v1 == efa->v4) efa->e4->dir= 0; - else efa->e4->dir= 1; - } - } - } - /* ok, no faces done... then we at least set it for exterior edges */ - if(do_all) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e1->v1 == efa->v1) efa->e1->dir= 0; - else efa->e1->dir= 1; - if(efa->e2->v1 == efa->v2) efa->e2->dir= 0; - else efa->e2->dir= 1; - if(efa->e3->v1 == efa->v3) efa->e3->dir= 0; - else efa->e3->dir= 1; - if(efa->e4) { - if(efa->e4->v1 == efa->v4) efa->e4->dir= 0; - else efa->e4->dir= 1; - } - } - } -} - -/* individual face extrude */ -/* will use vertex normals for extrusion directions, so *nor is unaffected */ -short extrudeflag_face_indiv(EditMesh *em, short UNUSED(flag), float *UNUSED(nor)) -{ - EditVert *eve, *v1, *v2, *v3, *v4; - EditEdge *eed; - EditFace *efa, *nextfa; - - if(em==NULL) return 0; - - /* selected edges with 1 or more selected face become faces */ - /* selected faces each makes new faces */ - /* always remove old faces, keeps volumes manifold */ - /* select the new extrusion, deselect old */ - - /* step 1; init, count faces in edges */ - recalc_editnormals(em); - - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f2= 0; // amount of unselected faces - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT); - else { - efa->e1->f2++; - efa->e2->f2++; - efa->e3->f2++; - if(efa->e4) efa->e4->f2++; - } - } - - /* step 2: make new faces from faces */ - for(efa= em->faces.last; efa; efa= efa->prev) { - if(efa->f & SELECT) { - v1= addvertlist(em, efa->v1->co, efa->v1); - v2= addvertlist(em, efa->v2->co, efa->v2); - v3= addvertlist(em, efa->v3->co, efa->v3); - - v1->f1= v2->f1= v3->f1= 1; - VECCOPY(v1->no, efa->n); - VECCOPY(v2->no, efa->n); - VECCOPY(v3->no, efa->n); - if(efa->v4) { - v4= addvertlist(em, efa->v4->co, efa->v4); - v4->f1= 1; - VECCOPY(v4->no, efa->n); - } - else v4= NULL; - - /* side faces, clockwise */ - addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL); - addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL); - if(efa->v4) { - addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL); - addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL); - } - else { - addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL); - } - /* top face */ - addfacelist(em, v1, v2, v3, v4, efa, NULL); - } - } - - /* step 3: remove old faces */ - efa= em->faces.first; - while(efa) { - nextfa= efa->next; - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextfa; - } - - /* step 4: redo selection */ - EM_clear_flag_all(em, SELECT); - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1) eve->f |= SELECT; - } - - EM_select_flush(em); - - return 'n'; -} - - -/* extrudes individual edges */ -/* nor is filled with constraint vector */ -short extrudeflag_edges_indiv(EditMesh *em, short flag, float *nor) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL; - for(eed= em->edges.first; eed; eed= eed->next) { - eed->tmp.f = NULL; - eed->f2= ((eed->f & flag)!=0); - } - - set_edge_directions_f2(em, 2); - - /* sample for next loop */ - for(efa= em->faces.first; efa; efa= efa->next) { - efa->e1->tmp.f = efa; - efa->e2->tmp.f = efa; - efa->e3->tmp.f = efa; - if(efa->e4) efa->e4->tmp.f = efa; - } - /* make the faces */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & flag) { - if(eed->v1->tmp.v == NULL) - eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1); - if(eed->v2->tmp.v == NULL) - eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2); - - if(eed->dir==1) - addfacelist(em, eed->v1, eed->v2, - eed->v2->tmp.v, eed->v1->tmp.v, - eed->tmp.f, NULL); - else - addfacelist(em, eed->v2, eed->v1, - eed->v1->tmp.v, eed->v2->tmp.v, - eed->tmp.f, NULL); - - /* for transform */ - if(eed->tmp.f) { - efa = eed->tmp.f; - if (efa->f & SELECT) add_normal_aligned(nor, efa->n); - } - } - } - normalize_v3(nor); - - /* set correct selection */ - EM_clear_flag_all(em, SELECT); - for(eve= em->verts.last; eve; eve= eve->prev) { - if(eve->tmp.v) { - eve->tmp.v->f |= flag; - } - } - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->f & eed->v2->f & flag) eed->f |= flag; - } - - if(is_zero_v3(nor)) return 'g'; // g is grab - return 'n'; // n is for normal constraint -} - -/* extrudes individual vertices */ -short extrudeflag_verts_indiv(EditMesh *em, short flag, float *UNUSED(nor)) -{ - EditVert *eve; - - /* make the edges */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & flag) { - eve->tmp.v = addvertlist(em, eve->co, eve); - addedgelist(em, eve, eve->tmp.v, NULL); - } - else eve->tmp.v = NULL; - } - - /* set correct selection */ - EM_clear_flag_all(em, SELECT); - - for(eve= em->verts.last; eve; eve= eve->prev) - if (eve->tmp.v) - eve->tmp.v->f |= flag; - - return 'g'; // g is grab -} - - -/* this is actually a recode of extrudeflag(), using proper edge/face select */ -/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */ -static short extrudeflag_edge(Object *obedit, EditMesh *em, short UNUSED(flag), float *nor, int all) -{ - /* all select edges/faces: extrude */ - /* old select is cleared, in new ones it is set */ - EditVert *eve, *nextve; - EditEdge *eed, *nexted; - EditFace *efa, *nextfa, *efan; - short del_old= 0; - ModifierData *md; - - if(em==NULL) return 0; - - md = obedit->modifiers.first; - - /* selected edges with 0 or 1 selected face become faces */ - /* selected faces generate new faces */ - - /* if *one* selected face has edge with unselected face; remove old selected faces */ - - /* if selected edge is not used anymore; remove */ - /* if selected vertex is not used anymore: remove */ - - /* select the new extrusion, deselect old */ - - - /* step 1; init, count faces in edges */ - recalc_editnormals(em); - - for(eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.v = NULL; - eve->f1= 0; - } - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; // amount of unselected faces - eed->f2= 0; // amount of selected faces - if(eed->f & SELECT) { - eed->v1->f1= 1; // we call this 'selected vertex' now - eed->v2->f1= 1; - } - eed->tmp.f = NULL; // here we tuck face pointer, as sample - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - efa->e1->f2++; - efa->e2->f2++; - efa->e3->f2++; - if(efa->e4) efa->e4->f2++; - - // sample for next loop - efa->e1->tmp.f = efa; - efa->e2->tmp.f = efa; - efa->e3->tmp.f = efa; - if(efa->e4) efa->e4->tmp.f = efa; - } - else { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - /* If a mirror modifier with clipping is on, we need to adjust some - * of the cases above to handle edges on the line of symmetry. - */ - for (; md; md=md->next) { - if (md->type==eModifierType_Mirror) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - float mtx[4][4]; - if (mmd->mirror_ob) { - float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, obedit->obmat, imtx); - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2 == 1) { - float co1[3], co2[3]; - - copy_v3_v3(co1, eed->v1->co); - copy_v3_v3(co2, eed->v2->co); - - if (mmd->mirror_ob) { - mul_m4_v3(mtx, co1); - mul_m4_v3(mtx, co2); - } - - if (mmd->flag & MOD_MIR_AXIS_X) - if ( (fabsf(co1[0]) < mmd->tolerance) && - (fabsf(co2[0]) < mmd->tolerance) ) - ++eed->f2; - - if (mmd->flag & MOD_MIR_AXIS_Y) - if ( (fabsf(co1[1]) < mmd->tolerance) && - (fabsf(co2[1]) < mmd->tolerance) ) - ++eed->f2; - - if (mmd->flag & MOD_MIR_AXIS_Z) - if ( (fabsf(co1[2]) < mmd->tolerance) && - (fabsf(co2[2]) < mmd->tolerance) ) - ++eed->f2; - } - } - } - } - } - - set_edge_directions_f2(em, 2); - - /* step 1.5: if *one* selected face has edge with unselected face; remove old selected faces */ - if(all == 0) { - for(efa= em->faces.last; efa; efa= efa->prev) { - if(efa->f & SELECT) { - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1 || (efa->e4 && efa->e4->f1)) { - del_old= 1; - break; - } - } - } - } - - /* step 2: make new faces from edges */ - for(eed= em->edges.last; eed; eed= eed->prev) { - if(eed->f & SELECT) { - if(eed->f2<2) { - if(eed->v1->tmp.v == NULL) - eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1); - if(eed->v2->tmp.v == NULL) - eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2); - - /* if del_old, the preferred normal direction is exact - * opposite as for keep old faces - */ - if(eed->dir!=del_old) - addfacelist(em, eed->v1, eed->v2, - eed->v2->tmp.v, eed->v1->tmp.v, - eed->tmp.f, NULL); - else - addfacelist(em, eed->v2, eed->v1, - eed->v1->tmp.v, eed->v2->tmp.v, - eed->tmp.f, NULL); - } - } - } - - /* step 3: make new faces from faces */ - for(efa= em->faces.last; efa; efa= efa->prev) { - if(efa->f & SELECT) { - if (efa->v1->tmp.v == NULL) - efa->v1->tmp.v = addvertlist(em, efa->v1->co, efa->v1); - if (efa->v2->tmp.v ==NULL) - efa->v2->tmp.v = addvertlist(em, efa->v2->co, efa->v2); - if (efa->v3->tmp.v ==NULL) - efa->v3->tmp.v = addvertlist(em, efa->v3->co, efa->v3); - if (efa->v4 && (efa->v4->tmp.v == NULL)) - efa->v4->tmp.v = addvertlist(em, efa->v4->co, efa->v4); - - if(efa->v4) - efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v, - efa->v3->tmp.v, efa->v4->tmp.v, efa, efa); - else - efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v, - efa->v3->tmp.v, NULL, efa, efa); - - /* keep old faces means flipping normal, reverse vertex order gives bad UV's & VCols etc - [#25260] */ - if(del_old==0) { - flipface(em, efan); - } - - if (em->act_face == efa) { - em->act_face = efan; - } - - /* for transform */ - add_normal_aligned(nor, efa->n); - } - } - - if(del_old) { - - /* step 4: remove old faces, if del_old */ - efa= em->faces.first; - while(efa) { - nextfa= efa->next; - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextfa; - } - - - /* step 5: remove selected unused edges */ - /* start tagging again */ - for(eed= em->edges.first; eed; eed= eed->next) eed->f1=0; - for(efa= em->faces.first; efa; efa= efa->next) { - efa->e1->f1= 1; - efa->e2->f1= 1; - efa->e3->f1= 1; - if(efa->e4) efa->e4->f1= 1; - } - /* remove */ - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - if(eed->f1==0) { - remedge(em, eed); - free_editedge(em, eed); - } - } - eed= nexted; - } - - /* step 6: remove selected unused vertices */ - for(eed= em->edges.first; eed; eed= eed->next) - eed->v1->f1= eed->v2->f1= 0; - - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f1) { - // hack... but we need it for step 7, redoing selection - if(eve->tmp.v) eve->tmp.v->tmp.v= eve->tmp.v; - - BLI_remlink(&em->verts, eve); - free_editvert(em, eve); - } - eve= nextve; - } - } - - normalize_v3(nor); // translation normal grab - - /* step 7: redo selection */ - EM_clear_flag_all(em, SELECT); - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->tmp.v) { - eve->tmp.v->f |= SELECT; - } - } - - EM_select_flush(em); - - if(is_zero_v3(nor)) return 'g'; // grab - return 'n'; // normal constraint -} - -short extrudeflag_vert(Object *obedit, EditMesh *em, short flag, float *nor, int all) -{ - /* all verts/edges/faces with (f & 'flag'): extrude */ - /* from old verts, 'flag' is cleared, in new ones it is set */ - EditVert *eve, *v1, *v2, *v3, *v4, *nextve; - EditEdge *eed, *e1, *e2, *e3, *e4, *nexted; - EditFace *efa, *efa2, *nextvl; - short sel=0, del_old= 0, is_face_sel=0; - ModifierData *md; - - if(em==NULL) return 0; - - md = obedit->modifiers.first; - - /* clear vert flag f1, we use this to detect a loose selected vertice */ - eve= em->verts.first; - while(eve) { - if(eve->f & flag) eve->f1= 1; - else eve->f1= 0; - eve= eve->next; - } - /* clear edges counter flag, if selected we set it at 1 */ - eed= em->edges.first; - while(eed) { - if( (eed->v1->f & flag) && (eed->v2->f & flag) ) { - eed->f2= 1; - eed->v1->f1= 0; - eed->v2->f1= 0; - } - else eed->f2= 0; - - eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */ - eed->tmp.f = NULL; /* used as sample */ - - eed= eed->next; - } - - /* we set a flag in all selected faces, and increase the associated edge counters */ - - efa= em->faces.first; - while(efa) { - efa->f1= 0; - - if(faceselectedAND(efa, flag)) { - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - e4= efa->e4; - - if(e1->f2 < 3) e1->f2++; - if(e2->f2 < 3) e2->f2++; - if(e3->f2 < 3) e3->f2++; - if(e4 && e4->f2 < 3) e4->f2++; - - efa->f1= 1; - is_face_sel= 1; // for del_old - } - else if(faceselectedOR(efa, flag)) { - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - e4= efa->e4; - - if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2; - if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2; - if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2; - if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2; - } - - // sample for next loop - efa->e1->tmp.f = efa; - efa->e2->tmp.f = efa; - efa->e3->tmp.f = efa; - if(efa->e4) efa->e4->tmp.f = efa; - - efa= efa->next; - } - - set_edge_directions_f2(em, 3); - - /* the current state now is: - eve->f1==1: loose selected vertex - - eed->f2==0 : edge is not selected, no extrude - eed->f2==1 : edge selected, is not part of a face, extrude - eed->f2==2 : edge selected, is part of 1 face, extrude - eed->f2==3 : edge selected, is part of more faces, no extrude - - eed->f1==0: new edge - eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove - eed->f1==2: edge selected, part of a partially selected face - - efa->f1==1 : duplicate this face - */ - - /* If a mirror modifier with clipping is on, we need to adjust some - * of the cases above to handle edges on the line of symmetry. - */ - for (; md; md=md->next) { - if (md->type==eModifierType_Mirror) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - float mtx[4][4]; - if (mmd->mirror_ob) { - float imtx[4][4]; - invert_m4_m4(imtx, mmd->mirror_ob->obmat); - mul_m4_m4m4(mtx, obedit->obmat, imtx); - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2 == 2) { - float co1[3], co2[3]; - - copy_v3_v3(co1, eed->v1->co); - copy_v3_v3(co2, eed->v2->co); - - if (mmd->mirror_ob) { - mul_m4_v3(mtx, co1); - mul_m4_v3(mtx, co2); - } - - if (mmd->flag & MOD_MIR_AXIS_X) - if ( (fabsf(co1[0]) < mmd->tolerance) && - (fabsf(co2[0]) < mmd->tolerance) ) - ++eed->f2; - - if (mmd->flag & MOD_MIR_AXIS_Y) - if ( (fabsf(co1[1]) < mmd->tolerance) && - (fabsf(co2[1]) < mmd->tolerance) ) - ++eed->f2; - if (mmd->flag & MOD_MIR_AXIS_Z) - if ( (fabsf(co1[2]) < mmd->tolerance) && - (fabsf(co2[2]) < mmd->tolerance) ) - ++eed->f2; - } - } - } - } - } - - /* copy all selected vertices, */ - /* write pointer to new vert in old struct at eve->tmp.v */ - eve= em->verts.last; - while(eve) { - eve->f &= ~128; /* clear, for later test for loose verts */ - if(eve->f & flag) { - sel= 1; - v1= addvertlist(em, 0, NULL); - - VECCOPY(v1->co, eve->co); - VECCOPY(v1->no, eve->no); - v1->f= eve->f; - eve->f &= ~flag; - eve->tmp.v = v1; - } - else eve->tmp.v = NULL; - eve= eve->prev; - } - - if(sel==0) return 0; - - /* all edges with eed->f2==1 or eed->f2==2 become faces */ - - /* if del_old==1 then extrude is in partial geometry, to keep it manifold. - verts with f1==0 and (eve->f & 128)==0) are removed - edges with eed->f2>2 are removed - faces with efa->f1 are removed - if del_old==0 the extrude creates a volume. - */ - - /* find if we delete old faces */ - if(is_face_sel && all==0) { - for(eed= em->edges.first; eed; eed= eed->next) { - if( (eed->f2==1 || eed->f2==2) ) { - if(eed->f1==2) { - del_old= 1; - break; - } - } - } - } - - eed= em->edges.last; - while(eed) { - nexted= eed->prev; - if( eed->f2<3) { - eed->v1->f |= 128; /* = no loose vert! */ - eed->v2->f |= 128; - } - if( (eed->f2==1 || eed->f2==2) ) { - - /* if del_old, the preferred normal direction is exact opposite as for keep old faces */ - if(eed->dir != del_old) - efa2 = addfacelist(em, eed->v1, eed->v2, - eed->v2->tmp.v, eed->v1->tmp.v, - eed->tmp.f, NULL); - else - efa2 = addfacelist(em, eed->v2, eed->v1, - eed->v1->tmp.v, eed->v2->tmp.v, - eed->tmp.f, NULL); - - /* Needs smarter adaption of existing creases. - * If addedgelist is used, make sure seams are set to 0 on these - * new edges, since we do not want to add any seams on extrusion. - */ - efa2->e1->crease= eed->crease; - efa2->e2->crease= eed->crease; - efa2->e3->crease= eed->crease; - if(efa2->e4) efa2->e4->crease= eed->crease; - } - - eed= nexted; - } - - /* duplicate faces, if necessary remove old ones */ - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f1 & 1) { - - v1 = efa->v1->tmp.v; - v2 = efa->v2->tmp.v; - v3 = efa->v3->tmp.v; - if(efa->v4) - v4 = efa->v4->tmp.v; - else - v4= NULL; - - /* hmm .. not sure about edges here */ - if(del_old==0) // if we keep old, we flip normal - efa2= addfacelist(em, v3, v2, v1, v4, efa, efa); - else - efa2= addfacelist(em, v1, v2, v3, v4, efa, efa); - - /* for transform */ - add_normal_aligned(nor, efa->n); - - if(del_old) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - } - efa= nextvl; - } - /* delete edges after copying edges above! */ - if(del_old) { - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f2==3 && eed->f1==1) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } - } - - normalize_v3(nor); // for grab - - /* for all vertices with eve->tmp.v!=0 - if eve->f1==1: make edge - if flag!=128 : if del_old==1: remove - */ - eve= em->verts.last; - while(eve) { - nextve= eve->prev; - if(eve->tmp.v) { - if(eve->f1==1) addedgelist(em, eve, eve->tmp.v, NULL); - else if( (eve->f & 128)==0) { - if(del_old) { - BLI_remlink(&em->verts,eve); - free_editvert(em, eve); - eve= NULL; - } - } - } - if(eve) { - eve->f &= ~128; - } - eve= nextve; - } - // since its vertex select mode now, it also deselects higher order - EM_selectmode_flush(em); - - if(is_zero_v3(nor)) return 'g'; // g is grab, for correct undo print - return 'n'; -} - -/* generic extrude */ -short extrudeflag(Object *obedit, EditMesh *em, short flag, float *nor, int all) -{ - if(em->selectmode & SCE_SELECT_VERTEX) - return extrudeflag_vert(obedit, em, flag, nor, all); - else - return extrudeflag_edge(obedit, em, flag, nor, all); - -} - -void rotateflag(EditMesh *em, short flag, float *cent, float rotmat[][3]) -{ - /* all verts with (flag & 'flag') rotate */ - EditVert *eve; - - eve= em->verts.first; - while(eve) { - if(eve->f & flag) { - eve->co[0]-=cent[0]; - eve->co[1]-=cent[1]; - eve->co[2]-=cent[2]; - mul_m3_v3(rotmat,eve->co); - eve->co[0]+=cent[0]; - eve->co[1]+=cent[1]; - eve->co[2]+=cent[2]; - } - eve= eve->next; - } -} - -void translateflag(EditMesh *em, short flag, float *vec) -{ - /* all verts with (flag & 'flag') translate */ - EditVert *eve; - - eve= em->verts.first; - while(eve) { - if(eve->f & flag) { - eve->co[0]+=vec[0]; - eve->co[1]+=vec[1]; - eve->co[2]+=vec[2]; - } - eve= eve->next; - } -} - -/* helper call for below */ -static EditVert *adduplicate_vertex(EditMesh *em, EditVert *eve, int flag) -{ - /* FIXME: copy deformation weight from eve ok here? */ - EditVert *v1= addvertlist(em, eve->co, eve); - - v1->f= eve->f; - eve->f &= ~flag; - eve->f|= 128; - - eve->tmp.v = v1; - - return v1; -} - -/* old selection has flag 128 set, and flag 'flag' cleared -new selection has flag 'flag' set */ -void adduplicateflag(EditMesh *em, int flag) -{ - EditVert *eve, *v1, *v2, *v3, *v4; - EditEdge *eed, *newed; - EditFace *efa, *newfa, *act_efa = EM_get_actFace(em, 0); - - EM_clear_flag_all(em, 128); - EM_selectmode_set(em); // paranoia check, selection now is consistent - - /* vertices first */ - for(eve= em->verts.last; eve; eve= eve->prev) { - - if(eve->f & flag) - adduplicate_vertex(em, eve, flag); - else - eve->tmp.v = NULL; - } - - /* copy edges, note that vertex selection can be independent of edge */ - for(eed= em->edges.last; eed; eed= eed->prev) { - if( eed->f & flag ) { - v1 = eed->v1->tmp.v; - if(v1==NULL) v1= adduplicate_vertex(em, eed->v1, flag); - v2 = eed->v2->tmp.v; - if(v2==NULL) v2= adduplicate_vertex(em, eed->v2, flag); - - newed= addedgelist(em, v1, v2, eed); - - newed->f= eed->f; - eed->f &= ~flag; - eed->f |= 128; - } - } - - /* then duplicate faces, again create new vertices if needed */ - for(efa= em->faces.last; efa; efa= efa->prev) { - if(efa->f & flag) { - v1 = efa->v1->tmp.v; - if(v1==NULL) v1= adduplicate_vertex(em, efa->v1, flag); - v2 = efa->v2->tmp.v; - if(v2==NULL) v2= adduplicate_vertex(em, efa->v2, flag); - v3 = efa->v3->tmp.v; - if(v3==NULL) v3= adduplicate_vertex(em, efa->v3, flag); - if(efa->v4) { - v4 = efa->v4->tmp.v; - if(v4==NULL) v4= adduplicate_vertex(em, efa->v4, flag); - } - else v4= NULL; - - newfa= addfacelist(em, v1, v2, v3, v4, efa, efa); - - if (efa==act_efa) { - EM_set_actFace(em, newfa); - } - - newfa->f= efa->f; - efa->f &= ~flag; - efa->f |= 128; - } - } - - EM_fgon_flags(em); // redo flags and indices for fgons -} - -void delfaceflag(EditMesh *em, int flag) -{ - /* delete all faces with 'flag', including loose edges and loose vertices */ - /* this is maybe a bit weird, but this function is used for 'split' and 'separate' */ - /* in remaining vertices/edges 'flag' is cleared */ - EditVert *eve,*nextve; - EditEdge *eed, *nexted; - EditFace *efa,*nextvl; - - /* to detect loose edges, we put f2 flag on 1 */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & flag) eed->f2= 1; - else eed->f2= 0; - } - - /* delete faces */ - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f & flag) { - - efa->e1->f2= 1; - efa->e2->f2= 1; - efa->e3->f2= 1; - if(efa->e4) { - efa->e4->f2= 1; - } - - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - - /* all remaining faces: make sure we keep the edges */ - for(efa= em->faces.first; efa; efa= efa->next) { - efa->e1->f2= 0; - efa->e2->f2= 0; - efa->e3->f2= 0; - if(efa->e4) { - efa->e4->f2= 0; - } - } - - /* remove tagged edges, and clear remaining ones */ - eed= em->edges.first; - while(eed) { - nexted= eed->next; - - if(eed->f2==1) { - remedge(em, eed); - free_editedge(em, eed); - } - else { - eed->f &= ~flag; - eed->v1->f &= ~flag; - eed->v2->f &= ~flag; - } - eed= nexted; - } - - /* vertices with 'flag' now are the loose ones, and will be removed */ - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f & flag) { - BLI_remlink(&em->verts, eve); - free_editvert(em, eve); - } - eve= nextve; - } - -} - -/* ********************* */ -#if 0 -static int check_vnormal_flip(float *n, float *vnorm) -{ - float inp; - - inp= n[0]*vnorm[0]+n[1]*vnorm[1]+n[2]*vnorm[2]; - - /* angles 90 degrees: dont flip */ - if(inp> -0.000001) return 0; - - return 1; -} -#endif - - - -/* does face centers too */ -void recalc_editnormals(EditMesh *em) -{ - EditFace *efa; - EditVert *eve; - - for(eve= em->verts.first; eve; eve=eve->next) - zero_v3(eve->no); - - for(efa= em->faces.first; efa; efa=efa->next) { - float *n4= (efa->v4)? efa->v4->no: NULL; - float *c4= (efa->v4)? efa->v4->co: NULL; - - if(efa->v4) { - normal_quad_v3(efa->n, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - } - else { - normal_tri_v3(efa->n, efa->v1->co, efa->v2->co, efa->v3->co); - cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co); - } - - accumulate_vertex_normals(efa->v1->no, efa->v2->no, efa->v3->no, n4, - efa->n, efa->v1->co, efa->v2->co, efa->v3->co, c4); - } - - /* following Mesh convention; we use vertex coordinate itself for normal in this case */ - for(eve= em->verts.first; eve; eve=eve->next) { - if(normalize_v3(eve->no) == 0.0f) { - copy_v3_v3(eve->no, eve->co); - normalize_v3(eve->no); - } - } -} - -int compareface(EditFace *vl1, EditFace *vl2) -{ - EditVert *v1, *v2, *v3, *v4; - - if(vl1->v4 && vl2->v4) { - v1= vl2->v1; - v2= vl2->v2; - v3= vl2->v3; - v4= vl2->v4; - - if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) { - if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) { - if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) { - if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) { - return 1; - } - } - } - } - } - else if(vl1->v4==0 && vl2->v4==0) { - v1= vl2->v1; - v2= vl2->v2; - v3= vl2->v3; - - if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) { - if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) { - if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) { - return 1; - } - } - } - } - - return 0; -} - -/* checks for existence, not tria overlapping inside quad */ -EditFace *exist_face(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4) -{ - EditFace *efa, efatest; - - efatest.v1= v1; - efatest.v2= v2; - efatest.v3= v3; - efatest.v4= v4; - - efa= em->faces.first; - while(efa) { - if(compareface(&efatest, efa)) return efa; - efa= efa->next; - } - return NULL; -} - -/* evaluate if entire quad is a proper convex quad */ -int convex(float *v1, float *v2, float *v3, float *v4) -{ - float nor[3], nor1[3], nor2[3], vec[4][2]; - - /* define projection, do both trias apart, quad is undefined! */ - normal_tri_v3( nor1,v1, v2, v3); - normal_tri_v3( nor2,v1, v3, v4); - nor[0]= ABS(nor1[0]) + ABS(nor2[0]); - nor[1]= ABS(nor1[1]) + ABS(nor2[1]); - nor[2]= ABS(nor1[2]) + ABS(nor2[2]); - - if(nor[2] >= nor[0] && nor[2] >= nor[1]) { - vec[0][0]= v1[0]; vec[0][1]= v1[1]; - vec[1][0]= v2[0]; vec[1][1]= v2[1]; - vec[2][0]= v3[0]; vec[2][1]= v3[1]; - vec[3][0]= v4[0]; vec[3][1]= v4[1]; - } - else if(nor[1] >= nor[0] && nor[1]>= nor[2]) { - vec[0][0]= v1[0]; vec[0][1]= v1[2]; - vec[1][0]= v2[0]; vec[1][1]= v2[2]; - vec[2][0]= v3[0]; vec[2][1]= v3[2]; - vec[3][0]= v4[0]; vec[3][1]= v4[2]; - } - else { - vec[0][0]= v1[1]; vec[0][1]= v1[2]; - vec[1][0]= v2[1]; vec[1][1]= v2[2]; - vec[2][0]= v3[1]; vec[2][1]= v3[2]; - vec[3][0]= v4[1]; vec[3][1]= v4[2]; - } - - /* linetests, the 2 diagonals have to instersect to be convex */ - if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1; - return 0; -} - - -/* ********************* Fake Polgon support (FGon) ***************** */ - - -/* results in: - - faces having ->fgonf flag set (also for draw) - - edges having ->fgoni index set (for select) -*/ - -float EM_face_area(EditFace *efa) -{ - if(efa->v4) return area_quad_v3(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - else return area_tri_v3(efa->v1->co, efa->v2->co, efa->v3->co); -} - -float EM_face_perimeter(EditFace *efa) -{ - if(efa->v4) return - len_v3v3(efa->v1->co, efa->v2->co)+ - len_v3v3(efa->v2->co, efa->v3->co)+ - len_v3v3(efa->v3->co, efa->v4->co)+ - len_v3v3(efa->v4->co, efa->v1->co); - - else return - len_v3v3(efa->v1->co, efa->v2->co)+ - len_v3v3(efa->v2->co, efa->v3->co)+ - len_v3v3(efa->v3->co, efa->v1->co); -} - -void EM_fgon_flags(EditMesh *em) -{ - EditFace *efa, *efan, *efamax; - EditEdge *eed; - ListBase listb={NULL, NULL}; - float size, maxsize; - short done, curindex= 1; - - // for each face with fgon edge AND not fgon flag set - for(eed= em->edges.first; eed; eed= eed->next) eed->fgoni= 0; // index - for(efa= em->faces.first; efa; efa= efa->next) efa->fgonf= 0; // flag - - // for speed & simplicity, put fgon face candidates in new listbase - efa= em->faces.first; - while(efa) { - efan= efa->next; - if( (efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) || - (efa->e3->h & EM_FGON) || (efa->e4 && (efa->e4->h & EM_FGON)) ) { - BLI_remlink(&em->faces, efa); - BLI_addtail(&listb, efa); - } - efa= efan; - } - - // find an undone face with fgon edge - for(efa= listb.first; efa; efa= efa->next) { - if(efa->fgonf==0) { - - // init this face - efa->fgonf= EM_FGON; - if(efa->e1->h & EM_FGON) efa->e1->fgoni= curindex; - if(efa->e2->h & EM_FGON) efa->e2->fgoni= curindex; - if(efa->e3->h & EM_FGON) efa->e3->fgoni= curindex; - if(efa->e4 && (efa->e4->h & EM_FGON)) efa->e4->fgoni= curindex; - - // we search for largest face, to give facedot drawing rights - maxsize= EM_face_area(efa); - efamax= efa; - - // now flush curendex over edges and set faceflags - done= 1; - while(done==1) { - done= 0; - - for(efan= listb.first; efan; efan= efan->next) { - if(efan->fgonf==0) { - // if one if its edges has index set, do other too - if( (efan->e1->fgoni==curindex) || (efan->e2->fgoni==curindex) || - (efan->e3->fgoni==curindex) || (efan->e4 && (efan->e4->fgoni==curindex)) ) { - - efan->fgonf= EM_FGON; - if(efan->e1->h & EM_FGON) efan->e1->fgoni= curindex; - if(efan->e2->h & EM_FGON) efan->e2->fgoni= curindex; - if(efan->e3->h & EM_FGON) efan->e3->fgoni= curindex; - if(efan->e4 && (efan->e4->h & EM_FGON)) efan->e4->fgoni= curindex; - - size= EM_face_area(efan); - if(size>maxsize) { - efamax= efan; - maxsize= size; - } - done= 1; - } - } - } - } - - efamax->fgonf |= EM_FGON_DRAW; - curindex++; - - } - } - - // put fgon face candidates back in listbase - efa= listb.first; - while(efa) { - efan= efa->next; - BLI_remlink(&listb, efa); - BLI_addtail(&em->faces, efa); - efa= efan; - } - - // remove fgon flags when edge not in fgon (anymore) - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->fgoni==0) eed->h &= ~EM_FGON; - } - -} - -/* editmesh vertmap, copied from intern.mesh.c - * if do_face_idx_array is 0 it means we need to run it as well as freeing - * */ - -UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array, float *limit) -{ - EditVert *ev; - EditFace *efa; - int totverts; - - /* vars from original func */ - UvVertMap *vmap; - UvMapVert *buf; - MTFace *tf; - unsigned int a; - int i, totuv, nverts; - - if (do_face_idx_array) - EM_init_index_arrays(em, 0, 0, 1); - - /* we need the vert */ - for (ev= em->verts.first, totverts=0; ev; ev= ev->next, totverts++) { - ev->tmp.l = totverts; - } - - totuv = 0; - - /* generate UvMapVert array */ - for (efa= em->faces.first; efa; efa= efa->next) - if(!selected || ((!efa->h) && (efa->f & SELECT))) - totuv += (efa->v4)? 4: 3; - - if(totuv==0) { - if (do_face_idx_array) - EM_free_index_arrays(); - return NULL; - } - vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap"); - if (!vmap) { - if (do_face_idx_array) - EM_free_index_arrays(); - return NULL; - } - - vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*"); - buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert"); - - if (!vmap->vert || !vmap->buf) { - free_uv_vert_map(vmap); - if (do_face_idx_array) - EM_free_index_arrays(); - return NULL; - } - - for (a=0, efa= em->faces.first; efa; a++, efa= efa->next) { - if(!selected || ((!efa->h) && (efa->f & SELECT))) { - nverts= (efa->v4)? 4: 3; - - for(i=0; i<nverts; i++) { - buf->tfindex= i; - buf->f= a; - buf->separate = 0; - - buf->next= vmap->vert[(*(&efa->v1 + i))->tmp.l]; - vmap->vert[(*(&efa->v1 + i))->tmp.l]= buf; - - buf++; - } - } - } - - /* sort individual uvs for each vert */ - for(a=0, ev=em->verts.first; ev; a++, ev= ev->next) { - UvMapVert *newvlist= NULL, *vlist=vmap->vert[a]; - UvMapVert *iterv, *v, *lastv, *next; - float *uv, *uv2, uvdiff[2]; - - while(vlist) { - v= vlist; - vlist= vlist->next; - v->next= newvlist; - newvlist= v; - - efa = EM_get_face_for_index(v->f); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uv = tf->uv[v->tfindex]; - - lastv= NULL; - iterv= vlist; - - while(iterv) { - next= iterv->next; - efa = EM_get_face_for_index(iterv->f); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uv2 = tf->uv[iterv->tfindex]; - - sub_v2_v2v2(uvdiff, uv2, uv); - - if(fabsf(uv[0]-uv2[0]) < limit[0] && fabsf(uv[1]-uv2[1]) < limit[1]) { - if(lastv) lastv->next= next; - else vlist= next; - iterv->next= newvlist; - newvlist= iterv; - } - else - lastv=iterv; - - iterv= next; - } - - newvlist->separate = 1; - } - - vmap->vert[a]= newvlist; - } - - if (do_face_idx_array) - EM_free_index_arrays(); - - return vmap; -} - -UvMapVert *EM_get_uv_map_vert(UvVertMap *vmap, unsigned int v) -{ - return vmap->vert[v]; -} - -void EM_free_uv_vert_map(UvVertMap *vmap) -{ - if (vmap) { - if (vmap->vert) MEM_freeN(vmap->vert); - if (vmap->buf) MEM_freeN(vmap->buf); - MEM_freeN(vmap); - } -} - -/* poll call for mesh operators requiring a view3d context */ -int EM_view3d_poll(bContext *C) -{ - if(ED_operator_editmesh(C) && ED_operator_view3d_active(C)) - return 1; - return 0; -} - -/* higher quality normals */ - -/* NormalCalc */ -/* NormalCalc modifier: calculates higher quality normals -*/ - -/* each edge uses this to */ -typedef struct EdgeFaceRef { - int f1; /* init as -1 */ - int f2; -} EdgeFaceRef; - -void EM_make_hq_normals(EditMesh *em) -{ - EditFace *efa; - EditVert *eve; - int i; - - EdgeHash *edge_hash = BLI_edgehash_new(); - EdgeHashIterator *edge_iter; - int edge_ref_count = 0; - int ed_v1, ed_v2; /* use when getting the key */ - EdgeFaceRef *edge_ref_array = MEM_callocN(em->totedge * sizeof(EdgeFaceRef), "Edge Connectivity"); - EdgeFaceRef *edge_ref; - float edge_normal[3]; - - EM_init_index_arrays(em, 1, 1, 1); - - for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) { - zero_v3(eve->no); - eve->tmp.l= i; - } - - /* This function adds an edge hash if its not there, and adds the face index */ -#define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \ - edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, EDV1, EDV2); \ - if (!edge_ref) { \ - edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \ - edge_ref->f1=i; \ - edge_ref->f2=-1; \ - BLI_edgehash_insert(edge_hash, EDV1, EDV2, edge_ref); \ - } else { \ - edge_ref->f2=i; \ - } - - - efa= em->faces.first; - for(i = 0; i < em->totface; i++, efa= efa->next) { - if(efa->v4) { - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l); - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l); - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v4->tmp.l); - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v4->tmp.l, efa->v1->tmp.l); - } else { - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l); - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l); - NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v1->tmp.l); - } - } - -#undef NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE - - - for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) { - /* Get the edge vert indices, and edge value (the face indices that use it)*/ - BLI_edgehashIterator_getKey(edge_iter, (int*)&ed_v1, (int*)&ed_v2); - edge_ref = BLI_edgehashIterator_getValue(edge_iter); - - if (edge_ref->f2 != -1) { - EditFace *ef1= EM_get_face_for_index(edge_ref->f1), *ef2= EM_get_face_for_index(edge_ref->f2); - float angle= angle_normalized_v3v3(ef1->n, ef2->n); - if(angle > 0.0f) { - /* We have 2 faces using this edge, calculate the edges normal - * using the angle between the 2 faces as a weighting */ - add_v3_v3v3(edge_normal, ef1->n, ef2->n); - normalize_v3(edge_normal); - mul_v3_fl(edge_normal, angle); - } - else { - /* cant do anything useful here! - Set the face index for a vert incase it gets a zero normal */ - EM_get_vert_for_index(ed_v1)->tmp.l= - EM_get_vert_for_index(ed_v2)->tmp.l= -(edge_ref->f1 + 1); - continue; - } - } else { - /* only one face attached to that edge */ - /* an edge without another attached- the weight on this is - * undefined, M_PI/2 is 90d in radians and that seems good enough */ - VECCOPY(edge_normal, EM_get_face_for_index(edge_ref->f1)->n) - mul_v3_fl(edge_normal, M_PI/2); - } - add_v3_v3(EM_get_vert_for_index(ed_v1)->no, edge_normal ); - add_v3_v3(EM_get_vert_for_index(ed_v2)->no, edge_normal ); - - - } - BLI_edgehashIterator_free(edge_iter); - BLI_edgehash_free(edge_hash, NULL); - MEM_freeN(edge_ref_array); - - /* normalize vertex normals and assign */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(normalize_v3(eve->no) == 0.0f && eve->tmp.l < 0) { - /* exceptional case, totally flat */ - efa= EM_get_face_for_index(-(eve->tmp.l) - 1); - VECCOPY(eve->no, efa->n); - } - } - - EM_free_index_arrays(); -} - -void EM_solidify(EditMesh *em, float dist) -{ - EditFace *efa; - EditVert *eve; - float *vert_angles= MEM_callocN(sizeof(float) * em->totvert * 2, "EM_solidify"); /* 2 in 1 */ - float *vert_accum= vert_angles + em->totvert; - float face_angles[4]; - int i, j; - - for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) { - eve->tmp.l= i; - } - - efa= em->faces.first; - for(i = 0; i < em->totface; i++, efa= efa->next) { - - if(!(efa->f & SELECT)) - continue; - - if(efa->v4) { - angle_quad_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - j= 3; - } - else { - angle_tri_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co); - j= 2; - } - - for(; j>=0; j--) { - eve= *(&efa->v1 + j); - vert_accum[eve->tmp.l] += face_angles[j]; - vert_angles[eve->tmp.l]+= shell_angle_to_dist(angle_normalized_v3v3(eve->no, efa->n)) * face_angles[j]; - } - } - - for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) { - if(vert_accum[i]) { /* zero if unselected */ - madd_v3_v3fl(eve->co, eve->no, dist * vert_angles[i] / vert_accum[i]); - } - } - - MEM_freeN(vert_angles); -} - -/* not that optimal!, should be nicer with bmesh */ -static void tag_face_edges(EditFace *efa) -{ - if(efa->v4) - efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1; - else - efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1; -} -static int tag_face_edges_test(EditFace *efa) -{ - if(efa->v4) - return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0; - else - return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0; -} - -static void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act) -{ - EditFace *efa; - EditEdge *eed; - int ok= 1; - - if(efa_act==NULL) { - return; - } - - /* to detect loose edges, we put f2 flag on 1 */ - for(eed= em->edges.first; eed; eed= eed->next) { - eed->tmp.l= 0; - } - - for (efa= em->faces.first; efa; efa= efa->next) { - efa->tmp.l = 0; - } - - efa_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - if(efa->tmp.l==1) { /* initialize */ - tag_face_edges(efa); - } - - if(efa->tmp.l) { - efa->tmp.l++; - } - } - } - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - if(efa->tmp.l==0 && tag_face_edges_test(efa)) { - efa->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - } - - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l > 0 && efa->tmp.l % nth) { - EM_select_face(efa, 0); - } - } - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - EM_select_face(efa, 1); - } - } - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -/* not that optimal!, should be nicer with bmesh */ -static void tag_edge_verts(EditEdge *eed) -{ - eed->v1->tmp.l= eed->v2->tmp.l= 1; -} -static int tag_edge_verts_test(EditEdge *eed) -{ - return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0; -} - -static void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act) -{ - EditEdge *eed; - EditVert *eve; - int ok= 1; - - if(eed_act==NULL) { - return; - } - - for(eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.l= 0; - } - - for (eed= em->edges.first; eed; eed= eed->next) { - eed->tmp.l = 0; - } - - eed_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - if(eed->tmp.l==1) { /* initialize */ - tag_edge_verts(eed); - } - - if(eed->tmp.l) { - eed->tmp.l++; - } - } - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - if(eed->tmp.l==0 && tag_edge_verts_test(eed)) { - eed->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->tmp.l > 0 && eed->tmp.l % nth) { - EM_select_edge(eed, 0); - } - } - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - EM_select_edge(eed, 1); - } - } - - { - /* grr, should be a function */ - EditFace *efa; - for (efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4) { - if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT ); - else efa->f &= ~SELECT; - } - else { - if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT ); - else efa->f &= ~SELECT; - } - } - } - - EM_nvertices_selected(em); - EM_nedges_selected(em); - EM_nfaces_selected(em); -} - -static void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act) -{ - EditVert *eve; - EditEdge *eed; - int ok= 1; - - if(eve_act==NULL) { - return; - } - - for (eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.l = 0; - } - - eve_act->tmp.l = 1; - - while(ok) { - ok = 0; - - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - if(eve->tmp.l) - eve->tmp.l++; - } - } - - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */ - eed->v2->tmp.l= 1; - ok = 1; /* keep looping */ - } - else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */ - eed->v1->tmp.l= 1; - ok = 1; /* keep looping */ - } - } - } - } - - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->tmp.l > 0 && eve->tmp.l % nth) { - eve->f &= ~SELECT; - } - } - - EM_deselect_flush(em); - - EM_nvertices_selected(em); - // EM_nedges_selected(em); // flush does these - // EM_nfaces_selected(em); // flush does these -} - -static void deselect_nth_active(EditMesh *em, EditVert **eve_p, EditEdge **eed_p, EditFace **efa_p) -{ - EditSelection *ese; - - *eve_p= NULL; - *eed_p= NULL; - *efa_p= NULL; - - ese= (EditSelection*)em->selected.last; - - if(ese) { - switch(ese->type) { - case EDITVERT: - *eve_p= (EditVert *)ese->data; - return; - case EDITEDGE: - *eed_p= (EditEdge *)ese->data; - return; - case EDITFACE: - *efa_p= (EditFace *)ese->data; - return; - } - } - - if(em->selectmode & SCE_SELECT_VERTEX) { - EditVert *eve; - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - *eve_p= eve; - return; - } - } - } - - if(em->selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for (eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - *eed_p= eed; - return; - } - } - } - - if(em->selectmode & SCE_SELECT_FACE) { - EditFace *efa= EM_get_actFace(em, 1); - if(efa) { - *efa_p= efa; - return; - } - } -} - -int EM_deselect_nth(EditMesh *em, int nth) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - deselect_nth_active(em, &eve, &eed, &efa); - - if(eve) - em_deselect_nth_vert(em, nth, eve); - else if (eed) - em_deselect_nth_edge(em, nth, eed); - else if (efa) - em_deselect_nth_face(em, nth, efa); - else - return 0; - - return 1; -} - -void EM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, EditMesh *em) -{ - EditVert *eve; - for(eve= em->verts.first;eve; eve=eve->next) { - if(eve->f & SELECT) { - float mval[2], vec[3], no_dummy[3]; - int dist_dummy; - mul_v3_m4v3(vec, obedit->obmat, eve->co); - project_float_noclip(ar, vec, mval); - if(snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) { - mul_v3_m4v3(eve->co, obedit->imat, vec); - } - } - } -} diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c deleted file mode 100644 index acbe5ef2144..00000000000 --- a/source/blender/editors/mesh/editmesh_loop.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 by Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_loop.c - * \ingroup edmesh - */ - - -/* - -editmesh_loop: tools with own drawing subloops, select, knife, subdiv - -*/ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - - -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" -#include "BLI_editVert.h" -#include "BLI_ghash.h" - -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_mesh.h" -#include "BKE_array_mallocn.h" - -#include "PIL_time.h" - -#include "BIF_gl.h" - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_mesh.h" -#include "ED_view3d.h" - -#include "mesh_intern.h" - -/* **** XXX ******** */ -static void error(const char *UNUSED(arg)) {} -/* **** XXX ******** */ - -#if 0 /* UNUSED 2.5 */ -static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines) -{ - EditEdge *eed; - EditFace *efa; - EditVert *v[2][2]; - float co[2][3]; - int looking= 1,i; - - /* in eed->f1 we put the valence (amount of faces in edge) */ - /* in eed->f2 we put tagged flag as correct loop */ - /* in efa->f1 we put tagged flag as correct to select */ - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; - } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - // tag startedge OK - startedge->f2= 1; - - while(looking) { - looking= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad - if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok - - // if edge tagged, select opposing edge and mark face ok - if(efa->e1->f2) { - efa->e3->f2= 1; - efa->f1= 1; - looking= 1; - } - else if(efa->e2->f2) { - efa->e4->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e3->f2) { - efa->e1->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e4->f2) { - efa->e2->f2= 1; - efa->f1= 1; - looking= 1; - } - } - } - } - } - - if(previewlines > 0 && select == 0){ -// XXX persp(PERSP_VIEW); -// XXX glPushMatrix(); -// XXX mymultmatrix(obedit->obmat); - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4 == NULL) { continue; } - if(efa->h == 0){ - if(efa->e1->f2 == 1){ - if(efa->e1->h == 1 || efa->e3->h == 1 ) - continue; - - v[0][0] = efa->v1; - v[0][1] = efa->v2; - v[1][0] = efa->v4; - v[1][1] = efa->v3; - } else if(efa->e2->f2 == 1){ - if(efa->e2->h == 1 || efa->e4->h == 1) - continue; - v[0][0] = efa->v2; - v[0][1] = efa->v3; - v[1][0] = efa->v1; - v[1][1] = efa->v4; - } else { continue; } - - for(i=1;i<=previewlines;i++){ - co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; - co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; - co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; - - co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; - co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; - co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; - glColor3ub(255, 0, 255); - glBegin(GL_LINES); - glVertex3f(co[0][0],co[0][1],co[0][2]); - glVertex3f(co[1][0],co[1][1],co[1][2]); - glEnd(); - } - } - } - glPopMatrix(); - } else { - - /* (de)select the edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2) EM_select_edge(eed, select); - } - } -} - -static void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts) -{ - ViewContext vc; // XXX - EditEdge *nearest=NULL, *eed; - float fac; - int keys = 0, holdnum=0, selectmode, dist; - int mvalo[2] = {0, 0}, mval[2] = {0, 0}; - short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0; - short hasHidden = 0; - char msg[128]; - - selectmode = em->selectmode; - - if(em->selectmode & SCE_SELECT_FACE){ - em->selectmode = SCE_SELECT_EDGE; - EM_selectmode_set(em); - } - - - BIF_undo_push("Loopcut Begin"); - while(choosing && !cancel){ -// XXX getmouseco_areawin(mval); - if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) { - mvalo[0] = mval[0]; - mvalo[1] = mval[1]; - dist= 50; - nearest = findnearestedge(&vc, &dist); // returns actual distance in dist -// scrarea_do_windraw(curarea); // after findnearestedge, backbuf! - - BLI_snprintf(msg, sizeof(msg),"Number of Cuts: %d (S)mooth: %s", numcuts, smooth ? "on":"off"); - -// headerprint(msg); - /* Need to figure preview */ - if(nearest){ - edgering_sel(em, nearest, 0, numcuts); - } -// XXX screen_swapbuffers(); - - /* backbuffer refresh for non-apples (no aux) */ -#ifndef __APPLE__ -// XXX if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) { -// backdrawview3d(0); -// } -#endif - } - else PIL_sleep_ms(10); // idle - - - while(qtest()) - { - val=0; -// XXX event= extern_qread(&val); - if(val && (event == MOUSEX || event == MOUSEY)){ ; } - else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER))) - { - if(event == MIDDLEMOUSE){ - cuthalf = 1; - } - if (nearest==NULL) - cancel = 1; - choosing=0; - mvalo[0] = -1; - } - else if(val && (event==ESCKEY || event==RIGHTMOUSE )) - { - choosing=0; - cancel = 1; - mvalo[0] = -1; - } - else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE)) - { - numcuts++; - mvalo[0] = -1; - } - else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE)) - { - if(numcuts > 1){ - numcuts--; - mvalo[0] = -1; - } - } - else if(val && event==SKEY) - { - if(smooth){smooth=0;} - else { smooth=1; } - mvalo[0] = -1; - } - - else if(val){ - holdnum = -1; - switch(event){ - case PAD9: - case NINEKEY: - holdnum = 9; break; - case PAD8: - case EIGHTKEY: - holdnum = 8;break; - case PAD7: - case SEVENKEY: - holdnum = 7;break; - case PAD6: - case SIXKEY: - holdnum = 6;break; - case PAD5: - case FIVEKEY: - holdnum = 5;break; - case PAD4: - case FOURKEY: - holdnum = 4;break; - case PAD3: - case THREEKEY: - holdnum = 3; break; - case PAD2: - case TWOKEY: - holdnum = 2;break; - case PAD1: - case ONEKEY: - holdnum = 1; break; - case PAD0: - case ZEROKEY: - holdnum = 0;break; - case BACKSPACEKEY: - holdnum = -2;break; - } - if(holdnum >= 0 && numcuts*10 < 130){ - if(keys == 0){ // first level numeric entry - if(holdnum > 0){ - numcuts = holdnum; - keys++; - } - } else if(keys > 0){//highrt level numeric entry - numcuts *= 10; - numcuts += holdnum; - keys++; - } - } else if (holdnum == -2){// backspace - if (keys > 1){ - numcuts /= 10; - keys--; - } else { - numcuts=1; - keys = 0; - } - } - mvalo[0] = -1; - break; - } // End Numeric Entry - } //End while(qtest()) - } // End Choosing - - if(cancel){ - return; - } - /* clean selection */ - for(eed=em->edges.first; eed; eed = eed->next){ - EM_select_edge(eed,0); - } - /* select edge ring */ - edgering_sel(em, nearest, 1, 0); - - /* now cut the loops */ - if(smooth){ - fac= 1.0f; -// XXX if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return; - fac= 0.292f*fac; - esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts, SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT); - } else { - esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT); - } - /* if this was a single cut, enter edgeslide mode */ - if(numcuts == 1 && hasHidden == 0){ - if(cuthalf) - EdgeSlide(em, op, 1,0.0); - else { - if(EdgeSlide(em, op, 0,0.0) == -1){ - BIF_undo(); - } - } - } - - if(em->selectmode != selectmode){ - em->selectmode = selectmode; - EM_selectmode_set(em); - } - -// DAG_id_tag_update(obedit->data, 0); - return; -} -#endif - -/* *************** LOOP SELECT ************* */ -#if 0 -static short edgeFaces(EditMesh *em, EditEdge *e) -{ - EditFace *search=NULL; - short count = 0; - - search = em->faces.first; - while(search){ - if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e)) - count++; - search = search->next; - } - return count; -} -#endif - - - -/* ***************** TRAIL ************************ - -Read a trail of mouse coords and return them as an array of CutCurve structs -len returns number of mouse coords read before commiting with RETKEY -It is up to the caller to free the block when done with it, - -XXX Is only used here, so local inside this file (ton) - */ - -#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */ -#define TRAIL_FREEHAND 2 -#define TRAIL_MIXED 3 /* (1|2) */ -#define TRAIL_AUTO 4 -#define TRAIL_MIDPOINTS 8 - -typedef struct CutCurve { - float x; - float y; -} CutCurve; - - -/* ******************************************************************** */ -/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail - drawn by user. - - Currently mapped to KKey when in MeshEdit mode. - Usage: - Hit Shift K, Select Centers or Exact - Hold LMB down to draw path, hit RETKEY. - ESC cancels as expected. - - Contributed by Robert Wenzlaff (Det. Thorn). - - 2.5 revamp: - - non modal (no menu before cutting) - - exit on mouse release - - polygon/segment drawing can become handled by WM cb later - -*/ - -#define KNIFE_EXACT 1 -#define KNIFE_MIDPOINT 2 -#define KNIFE_MULTICUT 3 - -static EnumPropertyItem knife_items[]= { - {KNIFE_EXACT, "EXACT", 0, "Exact", ""}, - {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""}, - {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""}, - {0, NULL, 0, NULL, NULL} -}; - -/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */ - -static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh) -{ -#define MAXSLOPE 100000 - float x11, y11, x12=0, y12=0, x2max, x2min, y2max; - float y2min, dist, lastdist=0, xdiff2, xdiff1; - float m1, b1, m2, b2, x21, x22, y21, y22, xi; - float yi, x1min, x1max, y1max, y1min, perc=0; - float *scr; - float threshold; - int i; - - threshold = 0.000001; /*tolerance for vertex intersection*/ - // XXX threshold = scene->toolsettings->select_thresh / 100; - - /* Get screen coords of verts */ - scr = BLI_ghash_lookup(gh, e->v1); - x21=scr[0]; - y21=scr[1]; - - scr = BLI_ghash_lookup(gh, e->v2); - x22=scr[0]; - y22=scr[1]; - - xdiff2=(x22-x21); - if (xdiff2) { - m2=(y22-y21)/xdiff2; - b2= ((x22*y21)-(x21*y22))/xdiff2; - } - else { - m2=MAXSLOPE; /* Verticle slope */ - b2=x22; - } - - /*check for *exact* vertex intersection first*/ - if(mode!=KNIFE_MULTICUT){ - for (i=0; i<len; i++){ - if (i>0){ - x11=x12; - y11=y12; - } - else { - x11=c[i].x; - y11=c[i].y; - } - x12=c[i].x; - y12=c[i].y; - - /*test e->v1*/ - if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){ - e->v1->f1 = 1; - perc = 0; - return(perc); - } - /*test e->v2*/ - else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){ - e->v2->f1 = 1; - perc = 0; - return(perc); - } - } - } - - /*now check for edge interesect (may produce vertex intersection as well)*/ - for (i=0; i<len; i++){ - if (i>0){ - x11=x12; - y11=y12; - } - else { - x11=c[i].x; - y11=c[i].y; - } - x12=c[i].x; - y12=c[i].y; - - /* Perp. Distance from point to line */ - if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */ - /* change in sign. Skip extra math */ - else dist=x22-x12; - - if (i==0) lastdist=dist; - - /* if dist changes sign, and intersect point in edge's Bound Box*/ - if ((lastdist*dist)<=0){ - xdiff1=(x12-x11); /* Equation of line between last 2 points */ - if (xdiff1){ - m1=(y12-y11)/xdiff1; - b1= ((x12*y11)-(x11*y12))/xdiff1; - } - else{ - m1=MAXSLOPE; - b1=x12; - } - x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */ - x2min=MIN2(x21,x22)-0.001; /* due to round off error */ - y2max=MAX2(y21,y22)+0.001; - y2min=MIN2(y21,y22)-0.001; - - /* Found an intersect, calc intersect point */ - if (m1==m2){ /* co-incident lines */ - /* cut at 50% of overlap area*/ - x1max=MAX2(x11, x12); - x1min=MIN2(x11, x12); - xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0; - - y1max=MAX2(y11, y12); - y1min=MIN2(y11, y12); - yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0; - } - else if (m2==MAXSLOPE){ - xi=x22; - yi=m1*x22+b1; - } - else if (m1==MAXSLOPE){ - xi=x12; - yi=m2*x12+b2; - } - else { - xi=(b1-b2)/(m2-m1); - yi=(b1*m2-m1*b2)/(m2-m1); - } - - /* Intersect inside bounding box of edge?*/ - if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){ - /*test for vertex intersect that may be 'close enough'*/ - if(mode!=KNIFE_MULTICUT){ - if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){ - if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){ - e->v1->f1 = 1; - perc = 0; - break; - } - } - if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){ - if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){ - e->v2->f1 = 1; - perc = 0; - break; - } - } - } - if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21); - else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/ - //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */ - - break; - } - } - lastdist=dist; - } - return(perc); -} - -/* for multicut */ -#define MAX_CUTS 256 - -/* for amount of edges */ -#define MAX_CUT_EDGES 1024 - -static int knife_cut_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - ARegion *ar= CTX_wm_region(C); - EditEdge *eed; - EditVert *eve; - CutCurve curve[MAX_CUT_EDGES]; - struct GHash *gh; - float isect=0.0; - float *scr, co[4]; - int len=0; - short numcuts= RNA_int_get(op->ptr, "num_cuts"); - short mode= RNA_enum_get(op->ptr, "type"); -// int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern"); - - /* edit-object needed for matrix, and ar->regiondata for projections to work */ - if (ELEM3(NULL, obedit, ar, ar->regiondata)) - return OPERATOR_CANCELLED; - - if (EM_nvertices_selected(em) < 2) { - error("No edges are selected to operate on"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - /* get the cut curve */ - RNA_BEGIN(op->ptr, itemptr, "path") { - - RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]); - len++; - if(len>= MAX_CUT_EDGES) break; - } - RNA_END; - - if(len<2) { - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - /*store percentage of edge cut for KNIFE_EXACT here.*/ - for(eed=em->edges.first; eed; eed= eed->next) - eed->tmp.fp = 0.0; - - /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/ - gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife_cut_exec gh"); - for(eve=em->verts.first; eve; eve=eve->next){ - scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates"); - VECCOPY(co, eve->co); - co[3]= 1.0; - mul_m4_v4(obedit->obmat, co); - project_float(ar, co, scr); - BLI_ghash_insert(gh, eve, scr); - eve->f1 = 0; /*store vertex intersection flag here*/ - - } - - eed= em->edges.first; - while(eed) { - if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet - isect= seg_intersect(eed, curve, len, mode, gh); - if (isect!=0.0f) eed->f2= 1; - else eed->f2=0; - eed->tmp.fp= isect; - } - else { - eed->f2=0; - eed->f1=0; - } - eed= eed->next; - } - - if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER); - else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER); - else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER); - - eed=em->edges.first; - while(eed){ - eed->f2=0; - eed->f1=0; - eed=eed->next; - } - - BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - - -void MESH_OT_knife_cut(wmOperatorType *ot) -{ - PropertyRNA *prop; - - ot->name= "Knife Cut"; - ot->description= "Cut selected edges and faces into parts"; - ot->idname= "MESH_OT_knife_cut"; - - ot->invoke= WM_gesture_lines_invoke; - ot->modal= WM_gesture_lines_modal; - ot->exec= knife_cut_exec; - ot->cancel= WM_gesture_lines_cancel; - - ot->poll= EM_view3d_poll; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", ""); - prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath); - RNA_def_int(ot->srna, "num_cuts", 1, 1, MAX_CUTS, "Number of Cuts", "Only for Multi-Cut", 1, MAX_CUTS); - // doesn't work atm.. 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"); - - /* internal */ - RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); -} - -/* ******************************************************* */ - diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c deleted file mode 100644 index 9497370a4fa..00000000000 --- a/source/blender/editors/mesh/editmesh_mods.c +++ /dev/null @@ -1,4500 +0,0 @@ -/* - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_mods.c - * \ingroup edmesh - */ - - -/* - -editmesh_mods.c, UI level access, no geometry changes - -*/ - -#include <stdlib.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_material_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_editVert.h" -#include "BLI_rand.h" -#include "BLI_utildefines.h" - -#include "BKE_context.h" -#include "BKE_displist.h" -#include "BKE_depsgraph.h" -#include "BKE_mesh.h" -#include "BKE_material.h" -#include "BKE_paint.h" -#include "BKE_report.h" -#include "BKE_texture.h" - -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - -#include "RE_render_ext.h" /* externtex */ - -#include "WM_api.h" -#include "WM_types.h" - - -#include "RNA_access.h" -#include "RNA_define.h" - -#include "ED_mesh.h" -#include "ED_screen.h" -#include "ED_view3d.h" -#include "ED_uvedit.h" - -#include "BIF_gl.h" - -#include "mesh_intern.h" - -#include "BLO_sys_types.h" // for intptr_t support - -/* XXX */ -static void waitcursor(int UNUSED(val)) {} -static int pupmenu(const char *UNUSED(arg)) {return 0;} - -/* ****************************** MIRROR **************** */ - -void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em) -{ - EditVert *eve, *eve_mirror; - int index= 0; - - for(eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.v= NULL; - } - - for(eve= em->verts.first; eve; eve= eve->next, index++) { - if(eve->tmp.v==NULL) { - eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); - if(eve_mirror) { - eve->tmp.v= eve_mirror; - eve_mirror->tmp.v = eve; - } - } - } -} - -static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend) -{ - - EditVert *eve; - - EM_cache_x_mirror_vert(obedit, em); - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT && eve->tmp.v && (eve->tmp.v != eve->tmp.v->tmp.v)) { - eve->tmp.v->f |= SELECT; - - if(extend==FALSE) - eve->f &= ~SELECT; - - /* remove the interference */ - eve->tmp.v->tmp.v= NULL; - eve->tmp.v= NULL; - } - } -} - -void EM_automerge(Scene *scene, Object *obedit, int update) -{ - Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */ - int len; - - if ((scene->toolsettings->automerge) && - (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT)) - ) { - EditMesh *em= me->edit_mesh; - int totvert= em->totvert, totedge= em->totedge, totface= em->totface; - - len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit); - if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) { - if (update) { - DAG_id_tag_update(&me->id, 0); - } - } - } -} - -/* ****************************** SELECTION ROUTINES **************** */ - -unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */ - -/* facilities for border select and circle select */ -static char *selbuf= NULL; - -/* opengl doesn't support concave... */ -static void draw_triangulated(int mcords[][2], short tot) -{ - ListBase lb={NULL, NULL}; - DispList *dl; - float *fp; - int a; - - /* make displist */ - dl= MEM_callocN(sizeof(DispList), "poly disp"); - dl->type= DL_POLY; - dl->parts= 1; - dl->nr= tot; - dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts"); - BLI_addtail(&lb, dl); - - for(a=0; a<tot; a++, fp+=3) { - fp[0]= (float)mcords[a][0]; - fp[1]= (float)mcords[a][1]; - } - - /* do the fill */ - filldisplist(&lb, &lb, 0); - - /* do the draw */ - dl= lb.first; /* filldisplist adds in head of list */ - if(dl->type==DL_INDEX3) { - int *index; - - a= dl->parts; - fp= dl->verts; - index= dl->index; - glBegin(GL_TRIANGLES); - while(a--) { - glVertex3fv(fp+3*index[0]); - glVertex3fv(fp+3*index[1]); - glVertex3fv(fp+3*index[2]); - index+= 3; - } - glEnd(); - } - - freedisplist(&lb); -} - - -/* reads rect, and builds selection array for quick lookup */ -/* returns if all is OK */ -int EM_init_backbuf_border(ViewContext *vc, short xmin, short ymin, short xmax, short ymax) -{ - struct ImBuf *buf; - unsigned int *dr; - int a; - - if(vc->obedit==NULL || vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; - - buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); - if(buf==NULL) return 0; - if(em_vertoffs==0) return 0; - - dr = buf->rect; - - /* build selection lookup */ - selbuf= MEM_callocN(em_vertoffs+1, "selbuf"); - - a= (xmax-xmin+1)*(ymax-ymin+1); - while(a--) { - if(*dr>0 && *dr<=em_vertoffs) - selbuf[*dr]= 1; - dr++; - } - IMB_freeImBuf(buf); - return 1; -} - -int EM_check_backbuf(unsigned int index) -{ - if(selbuf==NULL) return 1; - if(index>0 && index<=em_vertoffs) - return selbuf[index]; - return 0; -} - -void EM_free_backbuf(void) -{ - if(selbuf) MEM_freeN(selbuf); - selbuf= NULL; -} - -/* mcords is a polygon mask - - grab backbuffer, - - draw with black in backbuffer, - - grab again and compare - returns 'OK' -*/ -int EM_mask_init_backbuf_border(ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax) -{ - unsigned int *dr, *drm; - struct ImBuf *buf, *bufmask; - int a; - GLboolean is_cull; - - /* method in use for face selecting too */ - if(vc->obedit==NULL) { - if(paint_facesel_test(vc->obact)); - else return 0; - } - else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; - - buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); - if(buf==NULL) return 0; - if(em_vertoffs==0) return 0; - - dr = buf->rect; - - /* draw the mask */ - glDisable(GL_DEPTH_TEST); - - glColor3ub(0, 0, 0); - - /* some opengl drivers have problems with draw direction */ - glGetBooleanv(GL_CULL_FACE, &is_cull); - if(is_cull) glDisable(GL_CULL_FACE); - - /* yah, opengl doesn't do concave... tsk! */ - ED_region_pixelspace(vc->ar); - draw_triangulated(mcords, tot); - - glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */ - for(a=0; a<tot; a++) glVertex2iv(mcords[a]); - glEnd(); - - glFinish(); /* to be sure readpixels sees mask */ - - /* grab mask */ - bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); - drm = bufmask->rect; - if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */ - - /* build selection lookup */ - selbuf= MEM_callocN(em_vertoffs+1, "selbuf"); - - a= (xmax-xmin+1)*(ymax-ymin+1); - while(a--) { - if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1; - dr++; drm++; - } - IMB_freeImBuf(buf); - IMB_freeImBuf(bufmask); - - if(is_cull) glEnable(GL_CULL_FACE); - - return 1; - -} - -/* circle shaped sample area */ -int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads) -{ - struct ImBuf *buf; - unsigned int *dr; - short xmin, ymin, xmax, ymax, xc, yc; - int radsq; - - /* method in use for face selecting too */ - if(vc->obedit==NULL) { - if(paint_facesel_test(vc->obact)); - else return 0; - } - else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0; - - xmin= xs-rads; xmax= xs+rads; - ymin= ys-rads; ymax= ys+rads; - buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax); - if(em_vertoffs==0) return 0; - if(buf==NULL) return 0; - - dr = buf->rect; - - /* build selection lookup */ - selbuf= MEM_callocN(em_vertoffs+1, "selbuf"); - radsq= rads*rads; - for(yc= -rads; yc<=rads; yc++) { - for(xc= -rads; xc<=rads; xc++, dr++) { - if(xc*xc + yc*yc < radsq) { - if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1; - } - } - } - - IMB_freeImBuf(buf); - return 1; - -} - -static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index) -{ - struct { int mval[2]; short pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData; - - if (data->pass==0) { - if (index<=data->lastIndex) - return; - } else { - if (index>data->lastIndex) - return; - } - - if (data->dist>3) { - int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y); - if ((eve->f&1) == data->select) { - if (data->strict == 1) - return; - else - temp += 5; - } - - if (temp<data->dist) { - data->dist = temp; - data->closest = eve; - data->closestIndex = index; - } - } -} - - - - -static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index) -{ - EditMesh *em= (EditMesh *)handle; - EditVert *eve = BLI_findlink(&em->verts, index-1); - - if(eve && (eve->f & SELECT)) return 0; - return 1; -} -/** - * findnearestvert - * - * dist (in/out): minimal distance to the nearest and at the end, actual distance - * sel: selection bias - * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts - * if 0, unselected vertice are given the bias - * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased - */ -EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict) -{ - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){ - int distance; - unsigned int index; - EditVert *eve; - - if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); - else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); - - eve = BLI_findlink(&vc->em->verts, index-1); - - if(eve && distance < *dist) { - *dist = distance; - return eve; - } else { - return NULL; - } - - } - else { - struct { int mval[2]; short pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data; - static int lastSelectedIndex=0; - static EditVert *lastSelected=NULL; - - if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) { - lastSelectedIndex = 0; - lastSelected = NULL; - } - - data.lastIndex = lastSelectedIndex; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.select = sel; - data.dist = *dist; - data.strict = strict; - data.closest = NULL; - data.closestIndex = 0; - - data.pass = 0; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); - - if (data.dist>3) { - data.pass = 1; - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1); - } - - *dist = data.dist; - lastSelected = data.closest; - lastSelectedIndex = data.closestIndex; - - return data.closest; - } -} - -/* returns labda for closest distance v1 to line-piece v2-v3 */ -static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3) -{ - float rc[2], len; - - rc[0]= v3[0]-v2[0]; - rc[1]= v3[1]-v2[1]; - len= rc[0]*rc[0]+ rc[1]*rc[1]; - if(len==0.0f) - return 0.0f; - - return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len; -} - -/* note; uses v3d, so needs active 3d window */ -static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index)) -{ - struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData; - float v1[2], v2[2]; - int distance; - - ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */ - - v1[0] = x0; - v1[1] = y0; - v2[0] = x1; - v2[1] = y1; - - distance= dist_to_line_segment_v2(data->mval, v1, v2); - - - if(eed->f & SELECT) distance+=5; - if(distance < data->dist) { - if(data->vc.rv3d->rflag & RV3D_CLIPPING) { - float labda= labda_PdistVL2Dfl(data->mval, v1, v2); - float vec[3]; - - vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]); - vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]); - vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]); - - if(ED_view3d_test_clipping(data->vc.rv3d, vec, 1)==0) { - data->dist = distance; - data->closest = eed; - } - } - else { - data->dist = distance; - data->closest = eed; - } - } -} -EditEdge *findnearestedge(ViewContext *vc, int *dist) -{ - - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { - int distance; - unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL); - EditEdge *eed = BLI_findlink(&vc->em->edges, index-1); - - if (eed && distance<*dist) { - *dist = distance; - return eed; - } else { - return NULL; - } - } - else { - struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data; - - data.vc= *vc; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = *dist; - data.closest = NULL; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2); - - *dist = data.dist; - return data.closest; - } -} - -static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) -{ - struct { int mval[2]; int dist; EditFace *toFace; } *data = userData; - - if (efa==data->toFace) { - int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); - - if (temp<data->dist) - data->dist = temp; - } -} -static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index) -{ - struct { int mval[2]; short pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData; - - if (data->pass==0) { - if (index<=data->lastIndex) - return; - } else { - if (index>data->lastIndex) - return; - } - - if (data->dist>3) { - int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y); - - if (temp<data->dist) { - data->dist = temp; - data->closest = efa; - data->closestIndex = index; - } - } -} -static EditFace *findnearestface(ViewContext *vc, int *dist) -{ - - if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) { - unsigned int index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]); - EditFace *efa = BLI_findlink(&vc->em->faces, index-1); - - if (efa) { - struct { int mval[2]; int dist; EditFace *toFace; } data; - - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = 0x7FFF; /* largest short */ - data.toFace = efa; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__getDistance, &data); - - if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */ - *dist= data.dist; - return efa; - } - } - - return NULL; - } - else { - struct { int mval[2]; short pass; int dist, lastIndex, closestIndex; EditFace *closest; } data; - static int lastSelectedIndex=0; - static EditFace *lastSelected=NULL; - - if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) { - lastSelectedIndex = 0; - lastSelected = NULL; - } - - data.lastIndex = lastSelectedIndex; - data.mval[0] = vc->mval[0]; - data.mval[1] = vc->mval[1]; - data.dist = *dist; - data.closest = NULL; - data.closestIndex = 0; - - data.pass = 0; - - ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); - - if (data.dist>3) { - data.pass = 1; - mesh_foreachScreenFace(vc, findnearestface__doClosest, &data); - } - - *dist = data.dist; - lastSelected = data.closest; - lastSelectedIndex = data.closestIndex; - - return data.closest; - } -} - -/* best distance based on screen coords. - use em->selectmode to define how to use - selected vertices and edges get disadvantage - return 1 if found one -*/ -static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa) -{ - EditMesh *em= vc->em; - int dist= 75; - - *eve= NULL; - *eed= NULL; - *efa= NULL; - - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - view3d_validate_backbuf(vc); - - if(em->selectmode & SCE_SELECT_VERTEX) - *eve= findnearestvert(vc, &dist, SELECT, 0); - if(em->selectmode & SCE_SELECT_FACE) - *efa= findnearestface(vc, &dist); - - dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */ - if(em->selectmode & SCE_SELECT_EDGE) - *eed= findnearestedge(vc, &dist); - - /* return only one of 3 pointers, for frontbuffer redraws */ - if(*eed) { - *efa= NULL; *eve= NULL; - } - else if(*efa) { - *eve= NULL; - } - - return (*eve || *eed || *efa); -} - - -/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */ - -/* selects new faces/edges/verts based on the existing selection */ - -/* VERT GROUP */ - -#define SIMVERT_NORMAL 0 -#define SIMVERT_FACE 1 -#define SIMVERT_VGROUP 2 -#define SIMVERT_TOT 3 - -/* EDGE GROUP */ - -#define SIMEDGE_LENGTH 101 -#define SIMEDGE_DIR 102 -#define SIMEDGE_FACE 103 -#define SIMEDGE_FACE_ANGLE 104 -#define SIMEDGE_CREASE 105 -#define SIMEDGE_SEAM 106 -#define SIMEDGE_SHARP 107 -#define SIMEDGE_TOT 108 - -/* FACE GROUP */ - -#define SIMFACE_MATERIAL 201 -#define SIMFACE_IMAGE 202 -#define SIMFACE_AREA 203 -#define SIMFACE_PERIMETER 204 -#define SIMFACE_NORMAL 205 -#define SIMFACE_COPLANAR 206 -#define SIMFACE_TOT 207 - -static EnumPropertyItem prop_similar_types[] = { - {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""}, - {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""}, - {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""}, - {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""}, - {SIMEDGE_DIR, "DIR", 0, "Direction", ""}, - {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""}, - {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""}, - {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""}, - {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""}, - {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""}, - {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""}, - {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""}, - {SIMFACE_AREA, "AREA", 0, "Area", ""}, - {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""}, - {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""}, - {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""}, - {0, NULL, 0, NULL, NULL} -}; - - -/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes -*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */ -#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5f) <= b)) - -static int similar_face_select__internal(EditMesh *em, int mode, float thresh) -{ - EditFace *efa, *base_efa=NULL; - unsigned int selcount=0; /*count how many new faces we select*/ - - /*deselcount, count how many deselected faces are left, so we can bail out early - also means that if there are no deselected faces, we can avoid a lot of looping */ - unsigned int deselcount=0; - short ok=0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if (!efa->h) { - if (efa->f & SELECT) { - efa->f1=1; - ok=1; - } else { - efa->f1=0; - deselcount++; /* a deselected face we may select later */ - } - } - } - - if (!ok || !deselcount) /* no data selected OR no more data to select */ - return 0; - - if (mode==SIMFACE_AREA) { - for(efa= em->faces.first; efa; efa= efa->next) { - efa->tmp.fp= EM_face_area(efa); - } - } else if (mode==SIMFACE_PERIMETER) { - for(efa= em->faces.first; efa; efa= efa->next) { - efa->tmp.fp= EM_face_perimeter(efa); - } - } - - for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) { - if (base_efa->f1) { /* This was one of the faces originaly selected */ - if (mode==SIMFACE_MATERIAL) { /* same material */ - for(efa= em->faces.first; efa; efa= efa->next) { - if ( - !(efa->f & SELECT) && - !efa->h && - base_efa->mat_nr == efa->mat_nr - ) { - EM_select_face(efa, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMFACE_IMAGE) { /* same image */ - MTFace *tf, *base_tf; - - base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data, - CD_MTFACE); - - if(!base_tf) - return selcount; - - for(efa= em->faces.first; efa; efa= efa->next) { - if (!(efa->f & SELECT) && !efa->h) { - tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data, - CD_MTFACE); - - if(base_tf->tpage == tf->tpage) { - EM_select_face(efa, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } - } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */ - for(efa= em->faces.first; efa; efa= efa->next) { - if ( - (!(efa->f & SELECT) && !efa->h) && - SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp) - ) { - EM_select_face(efa, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMFACE_NORMAL) { - float angle; - for(efa= em->faces.first; efa; efa= efa->next) { - if (!(efa->f & SELECT) && !efa->h) { - angle= RAD2DEGF(angle_v2v2(base_efa->n, efa->n)); - if (angle/180.0f<=thresh) { - EM_select_face(efa, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } - } else if (mode==SIMFACE_COPLANAR) { /* same planer */ - float angle, base_dot, dot; - base_dot= dot_v3v3(base_efa->cent, base_efa->n); - for(efa= em->faces.first; efa; efa= efa->next) { - if (!(efa->f & SELECT) && !efa->h) { - angle= RAD2DEGF(angle_v2v2(base_efa->n, efa->n)); - if (angle/180.0f<=thresh) { - dot=dot_v3v3(efa->cent, base_efa->n); - if (fabsf(base_dot-dot) <= thresh) { - EM_select_face(efa, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } - } - } - } - } /* end base_efa loop */ - return selcount; -} - -static int similar_face_select_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - - int selcount = similar_face_select__internal(em, RNA_enum_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold")); - - if (selcount) { - /* here was an edge-mode only select flush case, has to be generalized */ - EM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(me, em); - return OPERATOR_FINISHED; - } - - BKE_mesh_end_editmesh(me, em); - return OPERATOR_CANCELLED; -} - -/* ***************************************************** */ - -static int similar_edge_select__internal(EditMesh *em, int mode, float thresh) -{ - EditEdge *eed, *base_eed=NULL; - unsigned int selcount=0; /* count how many new edges we select*/ - - /*count how many visible selected edges there are, - so we can return when there are none left */ - unsigned int deselcount=0; - - short ok=0; - - for(eed= em->edges.first; eed; eed= eed->next) { - if (!eed->h) { - if (eed->f & SELECT) { - eed->f1=1; - ok=1; - } else { - eed->f1=0; - deselcount++; - } - /* set all eed->tmp.l to 0 we use it later. - for counting face users*/ - eed->tmp.l=0; - eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */ - } - } - - if (!ok || !deselcount) /* no data selected OR no more data to select*/ - return 0; - - if (mode==SIMEDGE_LENGTH) { /*store length*/ - for(eed= em->edges.first; eed; eed= eed->next) { - if (!eed->h) /* dont calc data for hidden edges*/ - eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co); - } - } else if (mode==SIMEDGE_FACE) { /*store face users*/ - EditFace *efa; - /* cound how many faces each edge uses use tmp->l */ - for(efa= em->faces.first; efa; efa= efa->next) { - efa->e1->tmp.l++; - efa->e2->tmp.l++; - efa->e3->tmp.l++; - if (efa->e4) efa->e4->tmp.l++; - } - } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */ - EditFace *efa; - int j; - /* cound how many faces each edge uses use tmp.l */ - for(efa= em->faces.first; efa; efa= efa->next) { - /* here we use the edges temp data to assign a face - if a face has already been assigned (eed->f2==1) - we calculate the angle between the current face and - the edges previously found face. - store the angle in eed->tmp.fp (loosing the face eed->tmp.f) - but tagging eed->f2==2, so we know not to look at it again. - This only works for edges that connect to 2 faces. but its good enough - */ - - /* se we can loop through face edges*/ - j=0; - eed= efa->e1; - while (j<4) { - if (j==1) eed= efa->e2; - else if (j==2) eed= efa->e3; - else if (j==3) { - eed= efa->e4; - if (!eed) - break; - } /* done looping */ - - if (!eed->h) { /* dont calc data for hidden edges*/ - if (eed->f2==2) - break; - else if (eed->f2==0) /* first access, assign the face */ - eed->tmp.f= efa; - else if (eed->f2==1) /* second, we assign the angle*/ - eed->tmp.fp= RAD2DEGF(angle_v2v2(eed->tmp.f->n, efa->n))/180; - eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/ - } - j++; - } - } - } - - for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) { - if (base_eed->f1) { - if (mode==SIMEDGE_LENGTH) { /* same length */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp) - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMEDGE_DIR) { /* same direction */ - float base_dir[3], dir[3], angle; - sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co); - for(eed= em->edges.first; eed; eed= eed->next) { - if (!(eed->f & SELECT) && !eed->h) { - sub_v3_v3v3(dir, eed->v1->co, eed->v2->co); - angle= RAD2DEGF(angle_v2v2(base_dir, dir)); - - if (angle>90.0f) /* use the smallest angle between the edges */ - angle= fabsf(angle-180.0f); - - if (angle / 90.0f<=thresh) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } - } else if (mode==SIMEDGE_FACE) { /* face users */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - base_eed->tmp.l==eed->tmp.l - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - eed->f2==2 && - (fabsf(base_eed->tmp.fp-eed->tmp.fp)<=thresh) - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMEDGE_CREASE) { /* edge crease */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - (fabsf(base_eed->crease-eed->crease) <= thresh) - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMEDGE_SEAM) { /* edge seam */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - (eed->seam == base_eed->seam) - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } else if (mode==SIMEDGE_SHARP) { /* edge sharp */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - (eed->sharp == base_eed->sharp) - ) { - EM_select_edge(eed, 1); - selcount++; - deselcount--; - if (!deselcount) /*have we selected all posible faces?, if so return*/ - return selcount; - } - } - } - } - } - return selcount; -} -/* wrap the above function but do selection flushing edge to face */ -static int similar_edge_select_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - - int selcount = similar_edge_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold")); - - if (selcount) { - /* here was an edge-mode only select flush case, has to be generalized */ - EM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(me, em); - return OPERATOR_FINISHED; - } - - BKE_mesh_end_editmesh(me, em); - return OPERATOR_CANCELLED; -} - -/* ********************************* */ - -static int similar_vert_select_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - EditVert *eve, *base_eve=NULL; - unsigned int selcount=0; /* count how many new edges we select*/ - - /*count how many visible selected edges there are, - so we can return when there are none left */ - unsigned int deselcount=0; - int mode= RNA_enum_get(op->ptr, "type"); - float thresh = RNA_float_get(op->ptr, "threshold"); - - short ok=0; - - for(eve= em->verts.first; eve; eve= eve->next) { - if (!eve->h) { - if (eve->f & SELECT) { - eve->f1=1; - ok=1; - } else { - eve->f1=0; - deselcount++; - } - /* set all eve->tmp.l to 0 we use them later.*/ - eve->tmp.l=0; - } - - } - - if (!ok || !deselcount) { /* no data selected OR no more data to select*/ - BKE_mesh_end_editmesh(me, em); - return 0; - } - - if(mode == SIMVERT_FACE) { - /* store face users */ - EditFace *efa; - - /* count how many faces each edge uses use tmp->l */ - for(efa= em->faces.first; efa; efa= efa->next) { - efa->v1->tmp.l++; - efa->v2->tmp.l++; - efa->v3->tmp.l++; - if (efa->v4) efa->v4->tmp.l++; - } - } - - - for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) { - if (base_eve->f1) { - - if(mode == SIMVERT_NORMAL) { - float angle; - for(eve= em->verts.first; eve; eve= eve->next) { - if (!(eve->f & SELECT) && !eve->h) { - angle= RAD2DEGF(angle_v2v2(base_eve->no, eve->no)); - if (angle/180.0f<=thresh) { - eve->f |= SELECT; - selcount++; - deselcount--; - if (!deselcount) {/*have we selected all posible faces?, if so return*/ - BKE_mesh_end_editmesh(me, em); - return selcount; - } - } - } - } - } - else if(mode == SIMVERT_FACE) { - for(eve= em->verts.first; eve; eve= eve->next) { - if ( - !(eve->f & SELECT) && - !eve->h && - base_eve->tmp.l==eve->tmp.l - ) { - eve->f |= SELECT; - selcount++; - deselcount--; - if (!deselcount) {/*have we selected all posible faces?, if so return*/ - BKE_mesh_end_editmesh(me, em); - return selcount; - } - } - } - } - else if(mode == SIMVERT_VGROUP) { - MDeformVert *dvert, *base_dvert; - short i, j; /* weight index */ - - base_dvert= CustomData_em_get(&em->vdata, base_eve->data, - CD_MDEFORMVERT); - - if (!base_dvert || base_dvert->totweight == 0) { - BKE_mesh_end_editmesh(me, em); - return selcount; - } - - for(eve= em->verts.first; eve; eve= eve->next) { - dvert= CustomData_em_get(&em->vdata, eve->data, - CD_MDEFORMVERT); - - if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) { - /* do the extra check for selection in the following if, so were not - checking verts that may be already selected */ - for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) { - for (j=0; dvert->totweight >j; j++) { - if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) { - eve->f |= SELECT; - selcount++; - deselcount--; - if (!deselcount) { /*have we selected all posible faces?, if so return*/ - BKE_mesh_end_editmesh(me, em); - return selcount; - } - break; - } - } - } - } - } - } - } - } /* end basevert loop */ - - if(selcount) { - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(me, em); - return OPERATOR_FINISHED; - } - - BKE_mesh_end_editmesh(me, em); - return OPERATOR_CANCELLED; -} - -static int select_similar_exec(bContext *C, wmOperator *op) -{ - int type= RNA_enum_get(op->ptr, "type"); - - if(type < 100) - return similar_vert_select_exec(C, op); - else if(type < 200) - return similar_edge_select_exec(C, op); - else - return similar_face_select_exec(C, op); -} - -static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) -{ - Object *obedit= CTX_data_edit_object(C); - EnumPropertyItem *item= NULL; - int a, totitem= 0; - - if (C == NULL) { - return prop_similar_types; - } - - if(obedit && obedit->type == OB_MESH) { - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - - if(em->selectmode & SCE_SELECT_VERTEX) { - for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++) - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - else if(em->selectmode & SCE_SELECT_EDGE) { - for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++) - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - else if(em->selectmode & SCE_SELECT_FACE) { - for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++) - RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a); - } - } - - RNA_enum_item_end(&item, &totitem); - *free= 1; - - return item; -} - -void MESH_OT_select_similar(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name= "Select Similar"; - ot->description= "Select similar vertices, edges or faces by property types"; - ot->idname= "MESH_OT_select_similar"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= select_similar_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", ""); - RNA_def_enum_funcs(prop, select_similar_type_itemf); - ot->prop= prop; - RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 100.f); -} - -/* ******************************************* */ - - -int mesh_layers_menu_charlen(CustomData *data, int type) -{ - int i, len = 0; - /* see if there is a duplicate */ - for(i=0; i<data->totlayer; i++) { - if((&data->layers[i])->type == type) { - /* we could count the chars here but we'll just assumeme each - * is 32 chars with some room for the menu text - 40 should be fine */ - len+=40; - } - } - return len; -} - -/* this function adds menu text into an existing string. - * this string's size should be allocated with mesh_layers_menu_charlen */ -void mesh_layers_menu_concat(CustomData *data, int type, char *str) -{ - int i, count = 0; - char *str_pt = str; - CustomDataLayer *layer; - - /* see if there is a duplicate */ - for(i=0; i<data->totlayer; i++) { - layer = &data->layers[i]; - if(layer->type == type) { - str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count); - count++; - } - } -} - -int mesh_layers_menu(CustomData *data, int type) { - int ret; - char *str_pt, *str; - - str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu"); - str[0] = '\0'; - - str_pt += sprintf(str_pt, "Layers%%t|"); - - mesh_layers_menu_concat(data, type, str_pt); - - ret = pupmenu(str); - MEM_freeN(str); - return ret; -} - -static void EM_mesh_copy_edge(EditMesh *em, short type) -{ - EditSelection *ese; - short change=0; - - EditEdge *eed, *eed_act; - float vec[3], vec_mid[3], eed_len, eed_len_act; - - if (!em) return; - - ese = em->selected.last; - if (!ese) return; - - eed_act = (EditEdge*)ese->data; - - switch (type) { - case 1: /* copy crease */ - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) { - eed->crease = eed_act->crease; - change = 1; - } - } - break; - case 2: /* copy bevel weight */ - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) { - eed->bweight = eed_act->bweight; - change = 1; - } - } - break; - - case 3: /* copy length */ - eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co); - for(eed=em->edges.first; eed; eed=eed->next) { - if (eed->f & SELECT && eed != eed_act) { - - eed_len = len_v3v3(eed->v1->co, eed->v2->co); - - if (eed_len == eed_len_act) continue; - /* if this edge is zero length we cont do anything with it*/ - if (eed_len == 0.0f) continue; - if (eed_len_act == 0.0f) { - add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co); - mul_v3_fl(vec_mid, 0.5); - VECCOPY(eed->v1->co, vec_mid); - VECCOPY(eed->v2->co, vec_mid); - } else { - /* copy the edge length */ - add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co); - mul_v3_fl(vec_mid, 0.5); - - /* SCALE 1 */ - sub_v3_v3v3(vec, eed->v1->co, vec_mid); - mul_v3_fl(vec, eed_len_act/eed_len); - add_v3_v3v3(eed->v1->co, vec, vec_mid); - - /* SCALE 2 */ - sub_v3_v3v3(vec, eed->v2->co, vec_mid); - mul_v3_fl(vec, eed_len_act/eed_len); - add_v3_v3v3(eed->v2->co, vec, vec_mid); - } - change = 1; - } - } - - if (change) - recalc_editnormals(em); - - break; - } - - if (change) { -// DAG_id_tag_update(obedit->data, 0); - - } -} - -static void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type) -{ - short change=0; - - EditFace *efa, *efa_act; - MTFace *tf, *tf_act = NULL; - MCol *mcol, *mcol_act = NULL; - if (!em) return; - efa_act = EM_get_actFace(em, 0); - - if (!efa_act) return; - - tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE); - mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL); - - switch (type) { - case 1: /* copy material */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) { - efa->mat_nr = efa_act->mat_nr; - change = 1; - } - } - break; - case 2: /* copy image */ - if (!tf_act) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - return; - } - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (tf_act->tpage) { - tf->tpage = tf_act->tpage; - tf->mode |= TF_TEX; - } else { - tf->tpage = NULL; - tf->mode &= ~TF_TEX; - } - tf->tile= tf_act->tile; - change = 1; - } - } - break; - - case 3: /* copy UV's */ - if (!tf_act) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - return; - } - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, tf_act->uv, sizeof(tf->uv)); - change = 1; - } - } - break; - case 4: /* mode's */ - if (!tf_act) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - return; - } - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->mode= tf_act->mode; - change = 1; - } - } - break; - case 5: /* copy transp's */ - if (!tf_act) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - return; - } - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->transp= tf_act->transp; - change = 1; - } - } - break; - - case 6: /* copy vcols's */ - if (!mcol_act) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers."); - return; - } else { - /* guess the 4th color if needs be */ - float val =- 1; - - if (!efa_act->v4) { - /* guess the othe vale, we may need to use it - * - * Modifying the 4th value of the mcol is ok here since its not seen - * on a triangle - * */ - val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->r = (char)val; - - val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->g = (char)val; - - val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255); - (mcol_act+3)->b = (char)val; - } - - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT && efa != efa_act) { - /* TODO - make copy from tri to quad guess the 4th vert */ - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - memcpy(mcol, mcol_act, sizeof(MCol)*4); - change = 1; - } - } - } - break; - } - - if (change) { -// DAG_id_tag_update(obedit->data, 0); - - } -} - - -void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type) -{ - short change=0; - - EditFace *efa; - MTFace *tf, *tf_from; - MCol *mcol, *mcol_from; - - if (!em) return; - - switch(type) { - case 7: - case 8: - case 9: - if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) { - BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple uv/image layers"); - return; - } else { - int layer_orig_idx, layer_idx; - - layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE); - if (layer_idx<0) return; - - /* warning, have not updated mesh pointers however this is not needed since we swicth back */ - layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE); - if (layer_idx==layer_orig_idx) - return; - - /* get the tfaces */ - CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx); - /* store the tfaces in our temp */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - } - } - CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx); - } - break; - - case 10: /* select vcol layers - make sure this stays in sync with above code */ - if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) { - BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple color layers"); - return; - } else { - int layer_orig_idx, layer_idx; - - layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL); - if (layer_idx<0) return; - - /* warning, have not updated mesh pointers however this is not needed since we swicth back */ - layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL); - if (layer_idx==layer_orig_idx) - return; - - /* get the tfaces */ - CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx); - /* store the tfaces in our temp */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - } - } - CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx); - - } - break; - } - - /* layer copy only - sanity checks done above */ - switch (type) { - case 7: /* copy UV's only */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, tf_from->uv, sizeof(tf->uv)); - change = 1; - } - } - break; - case 8: /* copy image settings only */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (tf_from->tpage) { - tf->tpage = tf_from->tpage; - tf->mode |= TF_TEX; - } else { - tf->tpage = NULL; - tf->mode &= ~TF_TEX; - } - tf->tile= tf_from->tile; - change = 1; - } - } - break; - case 9: /* copy all tface info */ - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv)); - tf->tpage = tf_from->tpage; - tf->mode = tf_from->mode; - tf->transp = tf_from->transp; - change = 1; - } - } - break; - case 10: - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol_from = (MCol *)efa->tmp.p; - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - memcpy(mcol, mcol_from, sizeof(MCol)*4); - change = 1; - } - } - break; - } - - if (change) { -// DAG_id_tag_update(obedit->data, 0); - - } -} - - -/* ctrl+c in mesh editmode */ -static void mesh_copy_menu(EditMesh *em, wmOperator *op) -{ - EditSelection *ese; - int ret; - if (!em) return; - - ese = em->selected.last; - - /* Faces can have a NULL ese, so dont return on a NULL ese here */ - - if(ese && ese->type == EDITVERT) { - /* EditVert *ev, *ev_act = (EditVert*)ese->data; - ret= pupmenu(""); */ - } else if(ese && ese->type == EDITEDGE) { - ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3"); - if (ret<1) return; - - EM_mesh_copy_edge(em, ret); - - } else if(ese==NULL || ese->type == EDITFACE) { - ret= pupmenu( - "Copy Face Selected%t|" - "Active Material%x1|Active Image%x2|Active UV Coords%x3|" - "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|" - - "TexFace UVs from layer%x7|" - "TexFace Images from layer%x8|" - "TexFace All from layer%x9|" - "Vertex Colors from layer%x10"); - if (ret<1) return; - - if (ret<=6) { - EM_mesh_copy_face(em, op, ret); - } else { - EM_mesh_copy_face_layer(em, op, ret); - } - } -} - -/* **************** LOOP SELECTS *************** */ - -/* selects quads in loop direction of indicated edge */ -/* only flush over edges with valence <= 2 */ -void faceloop_select(EditMesh *em, EditEdge *startedge, int select) -{ - EditEdge *eed; - EditFace *efa; - int looking= 1; - - /* in eed->f1 we put the valence (amount of faces in edge) */ - /* in eed->f2 we put tagged flag as correct loop */ - /* in efa->f1 we put tagged flag as correct to select */ - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; - } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - /* tag startedge OK*/ - startedge->f2= 1; - - while(looking) { - looking= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */ - if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */ - - /* if edge tagged, select opposing edge and mark face ok */ - if(efa->e1->f2) { - efa->e3->f2= 1; - efa->f1= 1; - looking= 1; - } - else if(efa->e2->f2) { - efa->e4->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e3->f2) { - efa->e1->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e4->f2) { - efa->e2->f2= 1; - efa->f1= 1; - looking= 1; - } - } - } - } - } - - /* (de)select the faces */ - if(select!=2) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f1) EM_select_face(efa, select); - } - } -} - - -/* helper for edgeloop_select, checks for eed->f2 tag in faces */ -static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed) -{ - EditFace *efa; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */ - if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */ - return 0; - } - } - } - } - return 1; -} - -static void ensure_ed_vert_sel(EditMesh *em) -{ - EditEdge *eed; - - /* EM_selectmode_flush() doesnt take into account that deselected edges - * may be still connected to selected edges [#26885] */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->v1->f |= SELECT; - eed->v2->f |= SELECT; - } - } -} - -/* selects or deselects edges that: -- if edges has 2 faces: - - has vertices with valence of 4 - - not shares face with previous edge -- if edge has 1 face: - - has vertices with valence 4 - - not shares face with previous edge - - but also only 1 face -- if edge no face: - - has vertices with valence 2 -*/ -static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - int looking= 1; - - /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */ - /* in eed->f2 and efa->f1 we put tagged flag as correct loop */ - for(eve= em->verts.first; eve; eve= eve->next) { - eve->f1= 0; - eve->f2= 0; - } - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; - if((eed->h & 1)==0) { /* fgon edges add to valence too */ - eed->v1->f1++; eed->v2->f1++; - } - } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - /* looped edges & vertices get tagged f2 */ - starteed->f2= 1; - if(starteed->v1->f1<5) starteed->v1->f2= 1; - if(starteed->v2->f1<5) starteed->v2->f2= 1; - /* sorry, first edge isnt even ok */ - if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0; - - while(looking) { - looking= 0; - - /* find correct valence edges which are not tagged yet, but connect to tagged one */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */ - if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */ - /* new edge is not allowed to be in face with tagged edge */ - if(edge_not_in_tagged_face(em, eed)) { - if(eed->f1==starteed->f1) { /* same amount of faces */ - looking= 1; - eed->f2= 1; - if(eed->v2->f1<5) eed->v2->f2= 1; - if(eed->v1->f1<5) eed->v1->f2= 1; - } - } - } - } - } - } - /* and we do the select */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2) EM_select_edge(eed, select); - } - - if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */ - ensure_ed_vert_sel(em); - } -} - -/* - Almostly exactly the same code as faceloop select -*/ -static void edgering_select(EditMesh *em, EditEdge *startedge, int select) -{ - EditEdge *eed; - EditFace *efa; - int looking= 1; - - /* in eed->f1 we put the valence (amount of faces in edge) */ - /* in eed->f2 we put tagged flag as correct loop */ - /* in efa->f1 we put tagged flag as correct to select */ - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; - } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - /* tag startedge OK */ - startedge->f2= 1; - - while(looking) { - looking= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */ - if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */ - - /* if edge tagged, select opposing edge and mark face ok */ - if(efa->e1->f2) { - efa->e3->f2= 1; - efa->f1= 1; - looking= 1; - } - else if(efa->e2->f2) { - efa->e4->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e3->f2) { - efa->e1->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e4->f2) { - efa->e2->f2= 1; - efa->f1= 1; - looking= 1; - } - } - } - } - } - - /* (de)select the edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2) EM_select_edge(eed, select); - } - - if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */ - ensure_ed_vert_sel(em); - } -} - -static int loop_multiselect(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditEdge *eed; - EditEdge **edarray; - int edindex, edfirstcount; - int looptype= RNA_boolean_get(op->ptr, "ring"); - - /* sets em->totedgesel */ - EM_nedges_selected(em); - - edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array"); - edindex = 0; - edfirstcount = em->totedgesel; - - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f&SELECT){ - edarray[edindex] = eed; - edindex += 1; - } - } - - if(looptype){ - for(edindex = 0; edindex < edfirstcount; edindex +=1){ - eed = edarray[edindex]; - edgering_select(em, eed,SELECT); - } - EM_selectmode_flush(em); - } - else{ - for(edindex = 0; edindex < edfirstcount; edindex +=1){ - eed = edarray[edindex]; - edgeloop_select(em, eed,SELECT); - } - EM_selectmode_flush(em); - } - MEM_freeN(edarray); -// if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_loop_multi_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Multi Select Loops"; - ot->description= "Select a loop of connected edges by connection type"; - ot->idname= "MESH_OT_loop_multi_select"; - - /* api callbacks */ - ot->exec= loop_multiselect; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "ring", 0, "Ring", ""); -} - - -/* ***************** MAIN MOUSE SELECTION ************** */ - - -/* ***************** loop select (non modal) ************** */ - -static void mouse_mesh_loop(bContext *C, const int mval[2], short extend, short ring) -{ - ViewContext vc; - EditMesh *em; - EditEdge *eed; - int select= 1; - int dist= 50; - - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - em= vc.em; - - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - view3d_validate_backbuf(&vc); - - eed= findnearestedge(&vc, &dist); - if(eed) { - if(extend==0) EM_clear_flag_all(em, SELECT); - - if((eed->f & SELECT)==0) select=1; - else if(extend) select=0; - - if(em->selectmode & SCE_SELECT_FACE) { - faceloop_select(em, eed, select); - } - else if(em->selectmode & SCE_SELECT_EDGE) { - if(ring) - edgering_select(em, eed, select); - else - edgeloop_select(em, eed, select); - } - else if(em->selectmode & SCE_SELECT_VERTEX) { - if(ring) - edgering_select(em, eed, select); - else - edgeloop_select(em, eed, select); - } - - EM_selectmode_flush(em); -// if (EM_texFaceCheck()) - - /* sets as active, useful for other tools */ - if(select) { - if(em->selectmode & SCE_SELECT_VERTEX) - EM_store_selection(em, eed->v1, EDITVERT); - if(em->selectmode & SCE_SELECT_EDGE) - EM_store_selection(em, eed, EDITEDGE); - } - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data); - } -} - -static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - - view3d_operator_needs_opengl(C); - - mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"), - RNA_boolean_get(op->ptr, "ring")); - - /* cannot do tweaks for as long this keymap is after transform map */ - return OPERATOR_FINISHED; -} - -void MESH_OT_loop_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Loop Select"; - ot->description= "Select a loop of connected edges"; - ot->idname= "MESH_OT_loop_select"; - - /* api callbacks */ - ot->invoke= mesh_select_loop_invoke; - ot->poll= ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); - RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", ""); -} - -/* ******************* mesh shortest path select, uses prev-selected edge ****************** */ - -/* since you want to create paths with multiple selects, it doesn't have extend option */ -static void mouse_mesh_shortest_path(bContext *C, const int mval[2]) -{ - ViewContext vc; - EditMesh *em; - EditEdge *eed, *eed_act= NULL; - int dist= 50; - - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - em= vc.em; - - /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */ - view3d_validate_backbuf(&vc); - - eed= findnearestedge(&vc, &dist); - if(eed) { - Mesh *me= vc.obedit->data; - int path = 0; - - if (em->selected.last) { - EditSelection *ese = em->selected.last; - - if(ese && ese->type == EDITEDGE) { - eed_act = (EditEdge*)ese->data; - if (eed_act != eed) { - if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */ - EM_remove_selection(em, eed_act, EDITEDGE); - path = 1; - } - } - } - } - if (path==0) { - int act = (edgetag_context_check(vc.scene, eed)==0); - edgetag_context_set(vc.scene, eed, act); /* switch the edge option */ - } - - /* even if this is selected it may not be in the selection list */ - if(edgetag_context_check(vc.scene, eed)==0) { - EM_remove_selection(em, eed, EDITEDGE); - } - else { - /* other modes need to keep the last edge tagged */ - if(eed_act) { - if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) { - /* for non-select modes, always de-select the previous active edge */ - EM_select_edge(eed_act, 0); - } - } - - /* set the new edge active */ - EM_select_edge(eed, 1); - EM_store_selection(em, eed, EDITEDGE); - } - - EM_selectmode_flush(em); - - /* force drawmode for mesh */ - switch (vc.scene->toolsettings->edge_mode) { - - case EDGE_MODE_TAG_SEAM: - me->drawflag |= ME_DRAWSEAMS; - break; - case EDGE_MODE_TAG_SHARP: - me->drawflag |= ME_DRAWSHARP; - break; - case EDGE_MODE_TAG_CREASE: - me->drawflag |= ME_DRAWCREASES; - break; - case EDGE_MODE_TAG_BEVEL: - me->drawflag |= ME_DRAWBWEIGHTS; - break; - } - - /* live unwrap while tagging */ - if( (vc.scene->toolsettings->edge_mode_live_unwrap) && - (vc.scene->toolsettings->edge_mode == EDGE_MODE_TAG_SEAM) && - (CustomData_has_layer(&em->fdata, CD_MTFACE)) - ) { - ED_unwrap_lscm(vc.scene, vc.obedit, FALSE); /* unwrap all not just sel */ - } - - DAG_id_tag_update(vc.obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data); - } -} - - -static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event) -{ - - view3d_operator_needs_opengl(C); - - mouse_mesh_shortest_path(C, event->mval); - - return OPERATOR_FINISHED; -} - -static int mesh_shortest_path_select_poll(bContext *C) -{ - if(ED_operator_editmesh_region_view3d(C)) { - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - return (em->selectmode & SCE_SELECT_EDGE); - } - return 0; -} - -void MESH_OT_select_shortest_path(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Shortest Path Select"; - ot->description= "Select shortest path between two selections"; - ot->idname= "MESH_OT_select_shortest_path"; - - /* api callbacks */ - ot->invoke= mesh_shortest_path_select_invoke; - ot->poll= mesh_shortest_path_select_poll; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); -} - - -/* ************************************************** */ - - -/* here actual select happens */ -/* gets called via generic mouse select operator */ -int mouse_mesh(bContext *C, const int mval[2], short extend) -{ - ViewContext vc; - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - /* setup view context for argument to callbacks */ - em_setup_viewcontext(C, &vc); - vc.mval[0]= mval[0]; - vc.mval[1]= mval[1]; - - if(unified_findnearest(&vc, &eve, &eed, &efa)) { - - if(extend==0) EM_clear_flag_all(vc.em, SELECT); - - if(efa) { - /* set the last selected face */ - EM_set_actFace(vc.em, efa); - - if( (efa->f & SELECT)==0 ) { - EM_store_selection(vc.em, efa, EDITFACE); - EM_select_face_fgon(vc.em, efa, 1); - } - else if(extend) { - EM_remove_selection(vc.em, efa, EDITFACE); - EM_select_face_fgon(vc.em, efa, 0); - } - } - else if(eed) { - if((eed->f & SELECT)==0) { - EM_store_selection(vc.em, eed, EDITEDGE); - EM_select_edge(eed, 1); - } - else if(extend) { - EM_remove_selection(vc.em, eed, EDITEDGE); - EM_select_edge(eed, 0); - } - } - else if(eve) { - if((eve->f & SELECT)==0) { - eve->f |= SELECT; - EM_store_selection(vc.em, eve, EDITVERT); - } - else if(extend){ - EM_remove_selection(vc.em, eve, EDITVERT); - eve->f &= ~SELECT; - } - } - - EM_selectmode_flush(vc.em); - -// if (EM_texFaceCheck()) { - - if (efa && efa->mat_nr != vc.obedit->actcol-1) { - vc.obedit->actcol= efa->mat_nr+1; - vc.em->mat_nr= efa->mat_nr; - WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, NULL); - } - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data); - - return 1; - } - - return 0; -} - -/* *********** select linked ************* */ - -/* for use with selectconnected_delimit_mesh only! */ -#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0)) -#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4)) - -#define face_tag(efa)\ -if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\ -else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1; - -/* all - 1) use all faces for extending the selection 2) only use the mouse face -* sel - 1) select 0) deselect -* */ - -/* legacy warning, this function combines too much :) */ -static int select_linked_limited_invoke(ViewContext *vc, short all, short sel) -{ - EditMesh *em= vc->em; - EditFace *efa; - EditEdge *eed; - EditVert *eve; - short done=1, change=0; - - if(em->faces.first==0) return OPERATOR_CANCELLED; - - /* flag all edges+faces as off*/ - for(eed= em->edges.first; eed; eed= eed->next) - eed->tmp.l=0; - - for(efa= em->faces.first; efa; efa= efa->next) { - efa->tmp.l = 0; - } - - if (all) { - // XXX verts? - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) - eed->tmp.l= 1; - } - for(efa= em->faces.first; efa; efa= efa->next) { - - if (efa->f & SELECT) { - face_tag(efa); - } else { - efa->tmp.l = 0; - } - } - } - else { - if( unified_findnearest(vc, &eve, &eed, &efa) ) { - - if(efa) { - efa->tmp.l = 1; - face_tag(efa); - } - else if(eed) - eed->tmp.l= 1; - else { - for(eed= em->edges.first; eed; eed= eed->next) - if(eed->v1==eve || eed->v2==eve) - break; - eed->tmp.l= 1; - } - } - else - return OPERATOR_FINISHED; - } - - while(done==1) { - done= 0; - /* simple algo - select all faces that have a selected edge - * this intern selects the edge, repeat until nothing is left to do */ - for(efa= em->faces.first; efa; efa= efa->next) { - if ((efa->tmp.l == 0) && (!efa->h)) { - if (is_face_tag(efa)) { - face_tag(efa); - done= 1; - } - } - } - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if (efa->tmp.l) { - if (sel) { - if (!(efa->f & SELECT)) { - EM_select_face(efa, 1); - change = 1; - } - } else { - if (efa->f & SELECT) { - EM_select_face(efa, 0); - change = 1; - } - } - } - } - - if (!change) - return OPERATOR_CANCELLED; - - if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundaries */ - for(efa= em->faces.first; efa; efa= efa->next) - if (efa->f & SELECT) - EM_select_face(efa, 1); - - // if (EM_texFaceCheck()) - - return OPERATOR_FINISHED; -} - -#undef is_edge_delimit_ok -#undef is_face_tag -#undef face_tag - -static void linked_limit_default(bContext *C, wmOperator *op) { - if(!RNA_property_is_set(op->ptr, "limit")) { - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - if(em->selectmode == SCE_SELECT_FACE) - RNA_boolean_set(op->ptr, "limit", TRUE); - } -} - -static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - Object *obedit= CTX_data_edit_object(C); - ViewContext vc; - EditVert *eve, *v1, *v2; - EditEdge *eed; - EditFace *efa; - short done=1, toggle=0; - int sel= !RNA_boolean_get(op->ptr, "deselect"); - int limit; - - linked_limit_default(C, op); - - limit = RNA_boolean_get(op->ptr, "limit"); - - /* unified_finednearest needs ogl */ - view3d_operator_needs_opengl(C); - - /* setup view context for argument to callbacks */ - em_setup_viewcontext(C, &vc); - - if(vc.em->edges.first==0) return OPERATOR_CANCELLED; - - vc.mval[0]= event->mval[0]; - vc.mval[1]= event->mval[1]; - - /* return warning! */ - if(limit) { - int retval= select_linked_limited_invoke(&vc, 0, sel); - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - return retval; - } - - if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) { - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - return OPERATOR_CANCELLED; - } - - /* clear test flags */ - for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0; - - /* start vertex/face/edge */ - if(eve) eve->f1= 1; - else if(eed) eed->v1->f1= eed->v2->f1= 1; - else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1; - - /* set flag f1 if affected */ - while(done==1) { - done= 0; - toggle++; - - if(toggle & 1) eed= vc.em->edges.first; - else eed= vc.em->edges.last; - - while(eed) { - v1= eed->v1; - v2= eed->v2; - - if(eed->h==0) { - if(v1->f1 && v2->f1==0) { - v2->f1= 1; - done= 1; - } - else if(v1->f1==0 && v2->f1) { - v1->f1= 1; - done= 1; - } - } - - if(toggle & 1) eed= eed->next; - else eed= eed->prev; - } - } - - /* now use vertex f1 flag to select/deselect */ - for(eed= vc.em->edges.first; eed; eed= eed->next) { - if(eed->v1->f1 && eed->v2->f1) - EM_select_edge(eed, sel); - } - for(efa= vc.em->faces.first; efa; efa= efa->next) { - if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) - EM_select_face(efa, sel); - } - /* no flush needed, connected geometry is done */ - -// if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_linked_pick(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Linked"; - ot->description= "(un)select all vertices linked to the active mesh"; - ot->idname= "MESH_OT_select_linked_pick"; - - /* api callbacks */ - ot->invoke= select_linked_pick_invoke; - ot->poll= ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", ""); - RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)"); -} - - -/* ************************* */ - -void selectconnected_mesh_all(EditMesh *em) -{ - EditVert *v1,*v2; - EditEdge *eed; - short done=1, toggle=0; - - if(em->edges.first==0) return; - - while(done==1) { - done= 0; - - toggle++; - if(toggle & 1) eed= em->edges.first; - else eed= em->edges.last; - - while(eed) { - v1= eed->v1; - v2= eed->v2; - if(eed->h==0) { - if(v1->f & SELECT) { - if( (v2->f & SELECT)==0 ) { - v2->f |= SELECT; - done= 1; - } - } - else if(v2->f & SELECT) { - if( (v1->f & SELECT)==0 ) { - v1->f |= SELECT; - done= 1; - } - } - } - if(toggle & 1) eed= eed->next; - else eed= eed->prev; - } - } - - /* now use vertex select flag to select rest */ - EM_select_flush(em); - - // if (EM_texFaceCheck()) -} - -static int select_linked_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - - if( RNA_boolean_get(op->ptr, "limit") ) { - ViewContext vc; - em_setup_viewcontext(C, &vc); - select_linked_limited_invoke(&vc, 1, 1); - } - else - selectconnected_mesh_all(em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - linked_limit_default(C, op); - return select_linked_exec(C, op); -} - -void MESH_OT_select_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Linked All"; - ot->description= "Select all vertices linked to the active mesh"; - ot->idname= "MESH_OT_select_linked"; - - /* api callbacks */ - ot->exec= select_linked_exec; - ot->invoke= select_linked_invoke; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)"); -} - - -/* ************************* */ - -/* swap is 0 or 1, if 1 it hides not selected */ -void EM_hide_mesh(EditMesh *em, int swap) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - int a; - - if(em==NULL) return; - - /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */ - /* - vertex hidden, always means edge is hidden too - - edge hidden, always means face is hidden too - - face hidden, only set face hide - - then only flush back down what's absolute hidden - */ - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if((eve->f & SELECT)!=swap) { - eve->f &= ~SELECT; - eve->h= 1; - } - } - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->h || eed->v2->h) { - eed->h |= 1; - eed->f &= ~SELECT; - } - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) { - efa->h= 1; - efa->f &= ~SELECT; - } - } - } - else if(em->selectmode & SCE_SELECT_EDGE) { - - for(eed= em->edges.first; eed; eed= eed->next) { - if((eed->f & SELECT)!=swap) { - eed->h |= 1; - EM_select_edge(eed, 0); - } - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) { - efa->h= 1; - efa->f &= ~SELECT; - } - } - } - else { - - for(efa= em->faces.first; efa; efa= efa->next) { - if((efa->f & SELECT)!=swap) { - efa->h= 1; - EM_select_face(efa, 0); - } - } - } - - /* flush down, only whats 100% hidden */ - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0; - - if(em->selectmode & SCE_SELECT_FACE) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h) a= 1; else a= 2; - efa->e1->f1 |= a; - efa->e2->f1 |= a; - efa->e3->f1 |= a; - if(efa->e4) efa->e4->f1 |= a; - /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */ - if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) { - EM_select_face(efa, 1); - } - } - } - - if(em->selectmode >= SCE_SELECT_EDGE) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1==1) eed->h |= 1; - if(eed->h & 1) a= 1; else a= 2; - eed->v1->f1 |= a; - eed->v2->f1 |= a; - } - } - - if(em->selectmode >= SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1==1) eve->h= 1; - } - } - - em->totedgesel= em->totfacesel= em->totvertsel= 0; -// if(EM_texFaceCheck()) - - // DAG_id_tag_update(obedit->data, 0); -} - -static int hide_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected")); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_hide(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Hide Selection"; - ot->description= "Hide (un)selected vertices, edges or faces"; - ot->idname= "MESH_OT_hide"; - - /* api callbacks */ - ot->exec= hide_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected."); -} - -void EM_reveal_mesh(EditMesh *em) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - if(em==NULL) return; - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h) { - eve->h= 0; - eve->f |= SELECT; - } - } - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h & 1) { - eed->h &= ~1; - if(em->selectmode & SCE_SELECT_VERTEX); - else EM_select_edge(eed, 1); - } - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h) { - efa->h= 0; - if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)); - else EM_select_face(efa, 1); - } - } - - EM_fgon_flags(em); /* redo flags and indices for fgons */ - EM_selectmode_flush(em); - -// if (EM_texFaceCheck()) -// DAG_id_tag_update(obedit->data, 0); -} - -static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - EM_reveal_mesh(em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_reveal(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Reveal Hidden"; - ot->description= "Reveal all hidden vertices, edges and faces"; - ot->idname= "MESH_OT_reveal"; - - /* api callbacks */ - ot->exec= reveal_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int select_by_number_vertices_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditFace *efa; - int numverts= RNA_enum_get(op->ptr, "type"); - - /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring - * faces - */ - - /* for loose vertices/edges, we first select all, loop below will deselect */ - if(numverts==5) { - EM_set_flag_all(em, SELECT); - } - else if(em->selectmode!=SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode"); - return OPERATOR_CANCELLED; - } - - for(efa= em->faces.first; efa; efa= efa->next) { - if (efa->e4) { - EM_select_face(efa, (numverts==4) ); - } - else { - EM_select_face(efa, (numverts==3) ); - } - } - - EM_selectmode_flush(em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_by_number_vertices(wmOperatorType *ot) -{ - static const EnumPropertyItem type_items[]= { - {3, "TRIANGLES", 0, "Triangles", NULL}, - {4, "QUADS", 0, "Quads", NULL}, - {5, "OTHER", 0, "Other", NULL}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name= "Select by Number of Vertices"; - ot->description= "Select vertices or faces by vertex count"; - ot->idname= "MESH_OT_select_by_number_vertices"; - - /* api callbacks */ - ot->exec= select_by_number_vertices_exec; - ot->invoke= WM_menu_invoke; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select."); -} - - -static int select_mirror_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - int extend= RNA_boolean_get(op->ptr, "extend"); - - EM_select_mirrored(obedit, em, extend); - EM_selectmode_flush(em); - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_mirror(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Mirror"; - ot->description= "Select mesh items at mirrored locations"; - ot->idname= "MESH_OT_select_mirror"; - - /* api callbacks */ - ot->exec= select_mirror_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection"); -} - -static int select_sharp_edges_exec(bContext *C, wmOperator *op) -{ - /* Find edges that have exactly two neighboring faces, - * check the angle between those faces, and if angle is - * small enough, select the edge - */ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditEdge *eed; - EditFace *efa; - EditFace **efa1; - EditFace **efa2; - intptr_t edgecount = 0, i = 0; - float sharpness, fsharpness; - - /* 'standard' behaviour - check if selected, then apply relevant selection */ - - if(em->selectmode==SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - sharpness= RNA_float_get(op->ptr, "sharpness"); - fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f; - - /* count edges, use tmp.l */ - eed= em->edges.first; - while(eed) { - edgecount++; - eed->tmp.l = i; - eed= eed->next; - ++i; - } - - /* for each edge, we want a pointer to two adjacent faces */ - efa1 = MEM_callocN(edgecount*sizeof(EditFace *), - "pairs of edit face pointers"); - efa2 = MEM_callocN(edgecount*sizeof(EditFace *), - "pairs of edit face pointers"); - -#define face_table_edge(eed) { \ - i = eed->tmp.l; \ - if (i != -1) { \ - if (efa1[i]) { \ - if (efa2[i]) { \ - /* invalidate, edge has more than two neighbors */ \ - eed->tmp.l = -1; \ - } \ - else { \ - efa2[i] = efa; \ - } \ - } \ - else { \ - efa1[i] = efa; \ - } \ - } \ - } - - /* find the adjacent faces of each edge, we want only two */ - efa= em->faces.first; - while(efa) { - face_table_edge(efa->e1); - face_table_edge(efa->e2); - face_table_edge(efa->e3); - if (efa->e4) { - face_table_edge(efa->e4); - } - efa= efa->next; - } - -#undef face_table_edge - - eed = em->edges.first; - while(eed) { - i = eed->tmp.l; - if (i != -1) { - /* edge has two or less neighboring faces */ - if ( (efa1[i]) && (efa2[i]) ) { - /* edge has exactly two neighboring faces, check angle */ - float angle; - angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] + - efa1[i]->n[1]*efa2[i]->n[1] + - efa1[i]->n[2]*efa2[i]->n[2]); - if (fabsf(angle) >= fsharpness) - EM_select_edge(eed, 1); - } - } - - eed= eed->next; - } - - MEM_freeN(efa1); - MEM_freeN(efa2); - -// if (EM_texFaceCheck()) - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); //TODO is this needed ? - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_edges_select_sharp(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Sharp Edges"; - ot->description= "Marked selected edges as sharp"; - ot->idname= "MESH_OT_edges_select_sharp"; - - /* api callbacks */ - ot->exec= select_sharp_edges_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f); -} - - -static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness) -{ - /* Find faces that are linked to selected faces that are - * relatively flat (angle between faces is higher than - * specified angle) - */ - EditEdge *eed; - EditFace *efa; - EditFace **efa1; - EditFace **efa2; - intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0; - float fsharpness; - - if(em->selectmode!=SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode"); - return; - } - - fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f; - - i=0; - /* count edges, use tmp.l */ - eed= em->edges.first; - while(eed) { - edgecount++; - eed->tmp.l = i; - eed= eed->next; - ++i; - } - - /* for each edge, we want a pointer to two adjacent faces */ - efa1 = MEM_callocN(edgecount*sizeof(EditFace *), - "pairs of edit face pointers"); - efa2 = MEM_callocN(edgecount*sizeof(EditFace *), - "pairs of edit face pointers"); - -#define face_table_edge(eed) { \ - i = eed->tmp.l; \ - if (i != -1) { \ - if (efa1[i]) { \ - if (efa2[i]) { \ - /* invalidate, edge has more than two neighbors */ \ - eed->tmp.l = -1; \ - } \ - else { \ - efa2[i] = efa; \ - } \ - } \ - else { \ - efa1[i] = efa; \ - } \ - } \ - } - - /* find the adjacent faces of each edge, we want only two */ - efa= em->faces.first; - while(efa) { - face_table_edge(efa->e1); - face_table_edge(efa->e2); - face_table_edge(efa->e3); - if (efa->e4) { - face_table_edge(efa->e4); - } - - /* while were at it, count the selected faces */ - if (efa->f & SELECT) ++faceselcount; - - efa= efa->next; - } - -#undef face_table_edge - - eed= em->edges.first; - while(eed) { - i = eed->tmp.l; - if (i != -1) { - /* edge has two or less neighboring faces */ - if ( (efa1[i]) && (efa2[i]) ) { - /* edge has exactly two neighboring faces, check angle */ - float angle; - angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] + - efa1[i]->n[1]*efa2[i]->n[1] + - efa1[i]->n[2]*efa2[i]->n[2]); - /* invalidate: edge too sharp */ - if (fabsf(angle) >= fsharpness) - eed->tmp.l = -1; - } - else { - /* invalidate: less than two neighbors */ - eed->tmp.l = -1; - } - } - - eed= eed->next; - } - -#define select_flat_neighbor(eed) { \ - i = eed->tmp.l; \ - if (i!=-1) { \ - if (! (efa1[i]->f & SELECT) ) { \ - EM_select_face(efa1[i], 1); \ - ++faceselcount; \ - } \ - if (! (efa2[i]->f & SELECT) ) { \ - EM_select_face(efa2[i], 1); \ - ++faceselcount; \ - } \ - } \ - } - - while (faceselcount != faceselcountold) { - faceselcountold = faceselcount; - - efa= em->faces.first; - while(efa) { - if (efa->f & SELECT) { - select_flat_neighbor(efa->e1); - select_flat_neighbor(efa->e2); - select_flat_neighbor(efa->e3); - if (efa->e4) { - select_flat_neighbor(efa->e4); - } - } - efa= efa->next; - } - } - -#undef select_flat_neighbor - - MEM_freeN(efa1); - MEM_freeN(efa2); - -// if (EM_texFaceCheck()) - -} - -static int select_linked_flat_faces_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness")); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_faces_select_linked_flat(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Linked Flat Faces"; - ot->description= "Select linked faces by angle"; - ot->idname= "MESH_OT_faces_select_linked_flat"; - - /* api callbacks */ - ot->exec= select_linked_flat_faces_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_float(ot->srna, "sharpness", 135.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f); -} - -static void select_non_manifold(EditMesh *em, wmOperator *op ) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - /* Selects isolated verts, and edges that do not have 2 neighboring - * faces - */ - - if(em->selectmode==SCE_SELECT_FACE) { - BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode"); - return; - } - - eve= em->verts.first; - while(eve) { - /* this will count how many edges are connected - * to this vert */ - eve->f1= 0; - eve= eve->next; - } - - eed= em->edges.first; - while(eed) { - /* this will count how many faces are connected to - * this edge */ - eed->f1= 0; - /* increase edge count for verts */ - ++eed->v1->f1; - ++eed->v2->f1; - eed= eed->next; - } - - efa= em->faces.first; - while(efa) { - /* increase face count for edges */ - ++efa->e1->f1; - ++efa->e2->f1; - ++efa->e3->f1; - if (efa->e4) - ++efa->e4->f1; - efa= efa->next; - } - - /* select verts that are attached to an edge that does not - * have 2 neighboring faces */ - eed= em->edges.first; - while(eed) { - if (eed->h==0 && eed->f1 != 2) { - EM_select_edge(eed, 1); - } - eed= eed->next; - } - - /* select isolated verts */ - if(em->selectmode & SCE_SELECT_VERTEX) { - eve= em->verts.first; - while(eve) { - if (eve->f1 == 0) { - if (!eve->h) eve->f |= SELECT; - } - eve= eve->next; - } - } - -// if (EM_texFaceCheck()) - -} - -static int select_non_manifold_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - select_non_manifold(em, op); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_non_manifold(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Non Manifold"; - ot->description= "Select all non-manifold vertices or edges"; - ot->idname= "MESH_OT_select_non_manifold"; - - /* api callbacks */ - ot->exec= select_non_manifold_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -void EM_select_swap(EditMesh *em) /* exported for UV */ -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - if(em->selectmode & SCE_SELECT_VERTEX) { - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - if(eve->f & SELECT) eve->f &= ~SELECT; - else eve->f|= SELECT; - } - } - } - else if(em->selectmode & SCE_SELECT_EDGE) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - EM_select_edge(eed, !(eed->f & SELECT)); - } - } - } - else { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - EM_select_face(efa, !(efa->f & SELECT)); - } - } - } - - EM_selectmode_flush(em); - -// if (EM_texFaceCheck()) - -} - -static int select_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - EM_select_swap(em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_inverse(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Inverse"; - ot->description= "Select inverse of (un)selected vertices, edges or faces"; - ot->idname= "MESH_OT_select_inverse"; - - /* api callbacks */ - ot->exec= select_inverse_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/* ******************** (de)select all operator **************** */ - -void EM_toggle_select_all(EditMesh *em) /* exported for UV */ -{ - if(EM_nvertices_selected(em)) - EM_clear_flag_all(em, SELECT); - else - EM_set_flag_all_selectmode(em, SELECT); -} - -void EM_select_all(EditMesh *em) -{ - EM_set_flag_all_selectmode(em, SELECT); -} - -void EM_deselect_all(EditMesh *em) -{ - EM_clear_flag_all(em, SELECT); -} - -static int select_all_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - int action = RNA_enum_get(op->ptr, "action"); - - switch (action) { - case SEL_TOGGLE: - EM_toggle_select_all(em); - break; - case SEL_SELECT: - EM_select_all(em); - break; - case SEL_DESELECT: - EM_deselect_all(em); - break; - case SEL_INVERT: - EM_select_swap(em); - break; - } - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select or Deselect All"; - ot->description= "Change selection of all vertices, edges or faces"; - ot->idname= "MESH_OT_select_all"; - - /* api callbacks */ - ot->exec= select_all_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - WM_operator_properties_select_all(ot); -} - -/* ******************** **************** */ - -void EM_select_more(EditMesh *em) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) eve->f1= 1; - else eve->f1 = 0; - } - - /* set f1 flags in vertices to select 'more' */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - if (eed->v1->f & SELECT) - eed->v2->f1 = 1; - if (eed->v2->f & SELECT) - eed->v1->f1 = 1; - } - } - - /* new selected edges, but not in facemode */ - if(em->selectmode <= SCE_SELECT_EDGE) { - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1); - } - } - } - /* new selected faces */ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1)) - EM_select_face(efa, 1); - } - } -} - -static int select_more(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ; - - EM_select_more(em); - -// if (EM_texFaceCheck(em)) - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_more(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select More"; - ot->description= "Select more vertices, edges or faces connected to initial selection"; - ot->idname= "MESH_OT_select_more"; - - /* api callbacks */ - ot->exec= select_more; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static void EM_select_less(EditMesh *em) -{ - EditEdge *eed; - EditFace *efa; - - if(em->selectmode <= SCE_SELECT_EDGE) { - /* eed->f1 == 1: edge with a selected and deselected vert */ - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - if(eed->h==0) { - - if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) - eed->f1= 1; - if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) ) - eed->f1= 1; - } - } - - /* deselect edges with flag set */ - for(eed= em->edges.first; eed; eed= eed->next) { - if (eed->h==0 && eed->f1 == 1) { - EM_select_edge(eed, 0); - } - } - EM_deselect_flush(em); - - } - else { - /* deselect faces with 1 or more deselect edges */ - /* eed->f1 == mixed selection edge */ - for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - if(efa->f & SELECT) { - efa->e1->f1 |= 1; - efa->e2->f1 |= 1; - efa->e3->f1 |= 1; - if(efa->e4) efa->e4->f1 |= 1; - } - else { - efa->e1->f1 |= 2; - efa->e2->f1 |= 2; - efa->e3->f1 |= 2; - if(efa->e4) efa->e4->f1 |= 2; - } - } - } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) { - EM_select_face(efa, 0); - } - } - } - EM_selectmode_flush(em); - - } -} - -static int select_less(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - EM_select_less(em); - -// if (EM_texFaceCheck(em)) - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_less(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Less"; - ot->description= "Select less vertices, edges or faces connected to initial selection"; - ot->idname= "MESH_OT_select_less"; - - /* api callbacks */ - ot->exec= select_less; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static void selectrandom_mesh(EditMesh *em, float randfac) /* randomly selects a user-set % of vertices/edges/faces */ -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - - BLI_srand( BLI_rand() ); /* random seed */ - - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - if (BLI_frand() < randfac) - eve->f |= SELECT; - } - } - EM_selectmode_flush(em); - } - else if(em->selectmode & SCE_SELECT_EDGE) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - if (BLI_frand() < randfac) - EM_select_edge(eed, 1); - } - } - EM_selectmode_flush(em); - } - else { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0) { - if (BLI_frand() < randfac) - EM_select_face(efa, 1); - } - } - - EM_selectmode_flush(em); - } -// if (EM_texFaceCheck()) -} - -static int mesh_select_random_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - if(!RNA_boolean_get(op->ptr, "extend")) - EM_deselect_all(em); - - selectrandom_mesh(em, RNA_float_get(op->ptr, "percent")/100.0f); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_select_random(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Random"; - ot->description= "Randomly select vertices"; - ot->idname= "MESH_OT_select_random"; - - /* api callbacks */ - ot->exec= mesh_select_random_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly.", 0.f, 100.0f); - RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first."); -} - -void EM_select_by_material(EditMesh *em, int index) -{ - EditFace *efa; - - for (efa=em->faces.first; efa; efa= efa->next) { - if (efa->mat_nr==index) { - EM_select_face(efa, 1); - } - } - - EM_selectmode_flush(em); -} - -void EM_deselect_by_material(EditMesh *em, int index) -{ - EditFace *efa; - - for (efa=em->faces.first; efa; efa= efa->next) { - if (efa->mat_nr==index) { - EM_select_face(efa, 0); - } - } - - EM_selectmode_flush(em); -} - -/* ************************* SEAMS AND EDGES **************** */ - -static int editmesh_mark_seam(bContext *C, wmOperator *op) -{ - Scene *scene= CTX_data_scene(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - Mesh *me= ((Mesh *)obedit->data); - EditEdge *eed; - int clear = RNA_boolean_get(op->ptr, "clear"); - - /* auto-enable seams drawing */ - if(clear==0) { - me->drawflag |= ME_DRAWSEAMS; - } - - if(clear) { - eed= em->edges.first; - while(eed) { - if((eed->h==0) && (eed->f & SELECT)) { - eed->seam = 0; - } - eed= eed->next; - } - } - else { - eed= em->edges.first; - while(eed) { - if((eed->h==0) && (eed->f & SELECT)) { - eed->seam = 1; - } - eed= eed->next; - } - } - - /* live unwrap while tagging */ - if( (scene->toolsettings->edge_mode_live_unwrap) && - (CustomData_has_layer(&em->fdata, CD_MTFACE)) - ) { - ED_unwrap_lscm(scene, obedit, FALSE); /* unwrap all not just sel */ - } - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_mark_seam(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Seam"; - ot->description= "(un)mark selected edges as a seam"; - ot->idname= "MESH_OT_mark_seam"; - - /* api callbacks */ - ot->exec= editmesh_mark_seam; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); -} - -static int editmesh_mark_sharp(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - Mesh *me= ((Mesh *)obedit->data); - int clear = RNA_boolean_get(op->ptr, "clear"); - EditEdge *eed; - - /* auto-enable sharp edge drawing */ - if(clear == 0) { - me->drawflag |= ME_DRAWSHARP; - } - - if(!clear) { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->sharp = 1; - eed = eed->next; - } - } else { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->sharp = 0; - eed = eed->next; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_mark_sharp(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Sharp"; - ot->description= "(un)mark selected edges as sharp"; - ot->idname= "MESH_OT_mark_sharp"; - - /* api callbacks */ - ot->exec= editmesh_mark_sharp; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); -} - -/* **************** NORMALS ************** */ - -void EM_recalc_normal_direction(EditMesh *em, int inside, int select) /* makes faces righthand turning */ -{ - EditEdge *eed, *ed1, *ed2, *ed3, *ed4; - EditFace *efa, *startvl; - float maxx, nor[3], cent[3]; - int totsel, found, foundone, direct, turn, tria_nr; - - /* based at a select-connected to witness loose objects */ - - /* count per edge the amount of faces */ - - /* find the ultimate left, front, upper face (not manhattan dist!!) */ - /* also evaluate both triangle cases in quad, since these can be non-flat */ - - /* put normal to the outside, and set the first direction flags in edges */ - - /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */ - /* this is in fact the 'select connected' */ - - /* in case (selected) faces were not done: start over with 'find the ultimate ...' */ - - waitcursor(1); - - eed= em->edges.first; - while(eed) { - eed->f2= 0; /* edge direction */ - eed->f1= 0; /* counter */ - eed= eed->next; - } - - /* count faces and edges */ - totsel= 0; - efa= em->faces.first; - while(efa) { - if(select==0 || (efa->f & SELECT) ) { - efa->f1= 1; - totsel++; - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->v4) efa->e4->f1++; - } - else efa->f1= 0; - - efa= efa->next; - } - - while(totsel>0) { - /* from the outside to the inside */ - - efa= em->faces.first; - startvl= NULL; - maxx= -1.0e10; - tria_nr= 0; - - while(efa) { - if(efa->f1) { - cent_tri_v3(cent, efa->v1->co, efa->v2->co, efa->v3->co); - cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2]; - - if(cent[0]>maxx) { - maxx= cent[0]; - startvl= efa; - tria_nr= 0; - } - if(efa->v4) { - cent_tri_v3(cent, efa->v1->co, efa->v3->co, efa->v4->co); - cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2]; - - if(cent[0]>maxx) { - maxx= cent[0]; - startvl= efa; - tria_nr= 1; - } - } - } - efa= efa->next; - } - - if (startvl==NULL) - startvl= em->faces.first; - - /* set first face correct: calc normal */ - - if(tria_nr==1) { - normal_tri_v3( nor,startvl->v1->co, startvl->v3->co, startvl->v4->co); - cent_tri_v3(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co); - } else { - normal_tri_v3( nor,startvl->v1->co, startvl->v2->co, startvl->v3->co); - cent_tri_v3(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co); - } - /* first normal is oriented this way or the other */ - if(inside) { - if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0f) flipface(em, startvl); - } - else { - if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0f) flipface(em, startvl); - } - - eed= startvl->e1; - if(eed->v1==startvl->v1) eed->f2= 1; - else eed->f2= 2; - - eed= startvl->e2; - if(eed->v1==startvl->v2) eed->f2= 1; - else eed->f2= 2; - - eed= startvl->e3; - if(eed->v1==startvl->v3) eed->f2= 1; - else eed->f2= 2; - - eed= startvl->e4; - if(eed) { - if(eed->v1==startvl->v4) eed->f2= 1; - else eed->f2= 2; - } - - startvl->f1= 0; - totsel--; - - /* test normals */ - found= 1; - direct= 1; - while(found) { - found= 0; - if(direct) efa= em->faces.first; - else efa= em->faces.last; - while(efa) { - if(efa->f1) { - turn= 0; - foundone= 0; - - ed1= efa->e1; - ed2= efa->e2; - ed3= efa->e3; - ed4= efa->e4; - - if(ed1->f2) { - if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1; - if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1; - foundone= 1; - } - else if(ed2->f2) { - if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1; - if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1; - foundone= 1; - } - else if(ed3->f2) { - if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1; - if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1; - foundone= 1; - } - else if(ed4 && ed4->f2) { - if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1; - if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1; - foundone= 1; - } - - if(foundone) { - found= 1; - totsel--; - efa->f1= 0; - - if(turn) { - if(ed1->v1==efa->v1) ed1->f2= 2; - else ed1->f2= 1; - if(ed2->v1==efa->v2) ed2->f2= 2; - else ed2->f2= 1; - if(ed3->v1==efa->v3) ed3->f2= 2; - else ed3->f2= 1; - if(ed4) { - if(ed4->v1==efa->v4) ed4->f2= 2; - else ed4->f2= 1; - } - - flipface(em, efa); - - } - else { - if(ed1->v1== efa->v1) ed1->f2= 1; - else ed1->f2= 2; - if(ed2->v1==efa->v2) ed2->f2= 1; - else ed2->f2= 2; - if(ed3->v1==efa->v3) ed3->f2= 1; - else ed3->f2= 2; - if(ed4) { - if(ed4->v1==efa->v4) ed4->f2= 1; - else ed4->f2= 2; - } - } - } - } - if(direct) efa= efa->next; - else efa= efa->prev; - } - direct= 1-direct; - } - } - - recalc_editnormals(em); - -// DAG_id_tag_update(obedit->data, 0); - - waitcursor(0); -} - - -static int normals_make_consistent_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - - /* 'standard' behaviour - check if selected, then apply relevant selection */ - - // XXX need other args - EM_recalc_normal_direction(em, RNA_boolean_get(op->ptr, "inside"), 1); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); //TODO is this needed ? - - return OPERATOR_FINISHED; -} - -void MESH_OT_normals_make_consistent(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Make Normals Consistent"; - ot->description= "Flip all selected vertex and face normals in a consistent direction"; - ot->idname= "MESH_OT_normals_make_consistent"; - - /* api callbacks */ - ot->exec= normals_make_consistent_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "inside", 0, "Inside", ""); -} - -/* **************** VERTEX DEFORMS *************** */ - -static int smooth_vertex(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditVert *eve, *eve_mir = NULL; - EditEdge *eed; - float *adror, *adr, fac; - float fvec[3]; - int teller=0; - ModifierData *md; - int index; - - /* count */ - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) teller++; - eve= eve->next; - } - if(teller==0) { - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth"); - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - eve->tmp.p = (void*)adr; - eve->f1= 0; - eve->f2= 0; - adr+= 3; - } - eve= eve->next; - } - - /* if there is a mirror modifier with clipping, flag the verts that - * are within tolerance of the plane(s) of reflection - */ - for(md=obedit->modifiers.first; md; md=md->next) { - if(md->type==eModifierType_Mirror) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - - switch(mmd->axis){ - case 0: - if (fabsf(eve->co[0]) < mmd->tolerance) - eve->f2 |= 1; - break; - case 1: - if (fabsf(eve->co[1]) < mmd->tolerance) - eve->f2 |= 2; - break; - case 2: - if (fabsf(eve->co[2]) < mmd->tolerance) - eve->f2 |= 4; - break; - } - } - } - } - } - } - - eed= em->edges.first; - while(eed) { - if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) { - mid_v3_v3v3(fvec, eed->v1->co, eed->v2->co); - - if((eed->v1->f & SELECT) && eed->v1->f1<255) { - eed->v1->f1++; - add_v3_v3(eed->v1->tmp.p, fvec); - } - if((eed->v2->f & SELECT) && eed->v2->f1<255) { - eed->v2->f1++; - add_v3_v3(eed->v2->tmp.p, fvec); - } - } - eed= eed->next; - } - - index= 0; - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - if(eve->f1) { - - int xaxis= RNA_boolean_get(op->ptr, "xaxis"); - int yaxis= RNA_boolean_get(op->ptr, "yaxis"); - int zaxis= RNA_boolean_get(op->ptr, "zaxis"); - - if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { - eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve, eve->co, index); - } - - adr = eve->tmp.p; - fac= 0.5f/(float)eve->f1; - - if(xaxis) - eve->co[0]= 0.5f*eve->co[0]+fac*adr[0]; - if(yaxis) - eve->co[1]= 0.5f*eve->co[1]+fac*adr[1]; - if(zaxis) - eve->co[2]= 0.5f*eve->co[2]+fac*adr[2]; - - - /* clip if needed by mirror modifier */ - if (eve->f2) { - if (eve->f2 & 1) { - eve->co[0]= 0.0f; - } - if (eve->f2 & 2) { - eve->co[1]= 0.0f; - } - if (eve->f2 & 4) { - eve->co[2]= 0.0f; - } - } - - if (eve_mir) { - eve_mir->co[0]=-eve->co[0]; - eve_mir->co[1]= eve->co[1]; - eve_mir->co[2]= eve->co[2]; - } - - } - eve->tmp.p= NULL; - } - index++; - eve= eve->next; - } - MEM_freeN(adror); - - recalc_editnormals(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -static int smooth_vertex_exec(bContext *C, wmOperator *op) -{ - int repeat = RNA_int_get(op->ptr, "repeat"); - int i; - - if (!repeat) repeat = 1; - - for (i=0; i<repeat; i++) { - smooth_vertex(C, op); - } - - return OPERATOR_FINISHED; -} - -void MESH_OT_vertices_smooth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Smooth Vertex"; - ot->description= "Flatten angles of selected vertices"; - ot->idname= "MESH_OT_vertices_smooth"; - - /* api callbacks */ - ot->exec= smooth_vertex_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Smooth Iterations", "", 1, INT_MAX); - RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis."); - RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis."); - RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis."); -} - -static int mesh_noise_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - Material *ma; - Tex *tex; - EditVert *eve; - float fac= RNA_float_get(op->ptr, "factor"); - - if(em==NULL) return OPERATOR_FINISHED; - - ma= give_current_material(obedit, obedit->actcol); - if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned."); - return OPERATOR_FINISHED; - } - tex= give_current_material_texture(ma); - - - if(tex->type==TEX_STUCCI) { - float b2, vec[3]; - float ofs= tex->turbul/200.0f; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]); - if(tex->stype) ofs*=(b2*b2); - vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2])); - vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2])); - vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs)); - - add_v3_v3(eve->co, vec); - } - } - } - else { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - float tin, dum; - externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0); - eve->co[2]+= fac*tin; - } - } - } - - recalc_editnormals(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_noise(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Noise"; - ot->description= "Use vertex coordinate as texture coordinate"; - ot->idname= "MESH_OT_noise"; - - /* api callbacks */ - ot->exec= mesh_noise_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f); -} - -void flipface(EditMesh *em, EditFace *efa) -{ - if(efa->v4) { - SWAP(EditVert *, efa->v2, efa->v4); - SWAP(EditEdge *, efa->e1, efa->e4); - SWAP(EditEdge *, efa->e2, efa->e3); - EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1); - } - else { - SWAP(EditVert *, efa->v2, efa->v3); - SWAP(EditEdge *, efa->e1, efa->e3); - efa->e2->dir= 1-efa->e2->dir; - EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3); - } - - if(efa->v4) normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co); - else normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co); -} - - -static int flip_normals(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - EditFace *efa; - - efa= em->faces.first; - while(efa) { - if( efa->f & SELECT ){ - flipface(em, efa); - } - efa= efa->next; - } - - /* update vertex normals too */ - recalc_editnormals(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_flip_normals(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Flip Normals"; - ot->description= "Toggle the direction of selected face's vertex and face normals"; - ot->idname= "MESH_OT_flip_normals"; - - /* api callbacks */ - ot->exec= flip_normals; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - - -static int solidify_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - float nor[3] = {0,0,1}; - - float thickness= RNA_float_get(op->ptr, "thickness"); - - extrudeflag(obedit, em, SELECT, nor, 1); - EM_make_hq_normals(em); - EM_solidify(em, thickness); - - - /* update vertex normals too */ - recalc_editnormals(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - - -void MESH_OT_solidify(wmOperatorType *ot) -{ - PropertyRNA *prop; - /* identifiers */ - ot->name= "Solidify"; - ot->description= "Create a solid skin by extruding, compensating for sharp angles"; - ot->idname= "MESH_OT_solidify"; - - /* api callbacks */ - ot->exec= solidify_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "Thickness", "", -10.0f, 10.0f); - RNA_def_property_ui_range(prop, -10, 10, 0.1, 4); -} - -static int mesh_select_nth_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - int nth = RNA_int_get(op->ptr, "nth"); - - EM_deselect_nth(em, nth); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - - -void MESH_OT_select_nth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Select Nth"; - ot->description= ""; - ot->idname= "MESH_OT_select_nth"; - - /* api callbacks */ - ot->exec= mesh_select_nth_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX); -} - diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c deleted file mode 100644 index bfae101d38e..00000000000 --- a/source/blender/editors/mesh/editmesh_tools.c +++ /dev/null @@ -1,7606 +0,0 @@ - /* $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2004 by Blender Foundation. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): Johnny Matthews, Geoffrey Bantle. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -/** \file blender/editors/mesh/editmesh_tools.c - * \ingroup edmesh - */ - - -/* - -editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c - -*/ - -#include <stdlib.h> -#include <string.h> -#include <math.h> -#include <float.h> - -#include "BLO_sys_types.h" // for intptr_t support - -#include "DNA_meshdata_types.h" -#include "DNA_modifier_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_key_types.h" - -#include "MEM_guardedalloc.h" - -#include "RNA_define.h" -#include "RNA_access.h" - -#include "BLI_blenlib.h" -#include "BLI_math.h" -#include "BLI_utildefines.h" -#include "BLI_editVert.h" -#include "BLI_rand.h" -#include "BLI_ghash.h" -#include "BLI_linklist.h" -#include "BLI_heap.h" -#include "BLI_scanfill.h" - -#include "BKE_context.h" -#include "BKE_depsgraph.h" -#include "BKE_global.h" -#include "BKE_key.h" -#include "BKE_mesh.h" -#include "BKE_bmesh.h" -#include "BKE_report.h" - - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_mesh.h" -#include "ED_screen.h" -#include "ED_transform.h" -#include "ED_view3d.h" -#include "ED_object.h" - - -#include "mesh_intern.h" - -/* XXX */ -static void waitcursor(int UNUSED(val)) {} -#define add_numbut(a, b, c, d, e, f, g) {} - -/* XXX */ - -/* RNA corner cut enum property - used in multiple files for tools - * that need this property for esubdivideflag() */ -EnumPropertyItem corner_type_items[] = { - {SUBDIV_CORNER_PATH, "PATH", 0, "Path", ""}, - {SUBDIV_CORNER_INNERVERT, "INNER_VERTEX", 0, "Inner Vertex", ""}, - {SUBDIV_CORNER_FAN, "FAN", 0, "Fan", ""}, - {0, NULL, 0, NULL, NULL}}; - - -/* local prototypes ---------------*/ -static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa); -int EdgeLoopDelete(EditMesh *em, wmOperator *op); - -/********* qsort routines *********/ - - -typedef struct xvertsort { - float x; - EditVert *v1; -} xvertsort; - -static int vergxco(const void *v1, const void *v2) -{ - const xvertsort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - -struct facesort { - uintptr_t x; - struct EditFace *efa; -}; - - -static int vergface(const void *v1, const void *v2) -{ - const struct facesort *x1=v1, *x2=v2; - - if( x1->x > x2->x ) return 1; - else if( x1->x < x2->x) return -1; - return 0; -} - - -/* *********************************** */ - -static void convert_to_triface(EditMesh *em, int direction) -{ - EditFace *efa, *efan, *next; - float fac; - - efa= em->faces.last; - while(efa) { - next= efa->prev; - if(efa->v4) { - if(efa->f & SELECT) { - /* choose shortest diagonal for split */ - fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co); - /* this makes sure exact squares get split different in both cases */ - if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) { - efan= EM_face_from_faces(em, efa, NULL, 0, 1, 2, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - efan= EM_face_from_faces(em, efa, NULL, 0, 2, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - } - else { - efan= EM_face_from_faces(em, efa, NULL, 0, 1, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1); - if(efa->f & SELECT) EM_select_face(efan, 1); - } - - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - } - efa= next; - } - - EM_fgon_flags(em); // redo flags and indices for fgons - - -} - -int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */ -{ - /* - flag - Test with vert->flags - automerge - Alternative operation, merge unselected into selected. - Used for "Auto Weld" mode. warning. - limit - Quick manhattan distance between verts. - */ - - /* all verts with (flag & 'flag') are being evaluated */ - EditVert *eve, *v1, *nextve; - EditEdge *eed, *e1, *nexted; - EditFace *efa, *nextvl; - xvertsort *sortblock, *sb, *sb1; - struct facesort *vlsortblock, *vsb, *vsb1; - int a, b, test, amount; - - - /* flag 128 is cleared, count */ - - /* Normal non weld operation */ - eve= em->verts.first; - amount= 0; - while(eve) { - eve->f &= ~128; - if(eve->h==0 && (automerge || (eve->f & flag))) amount++; - eve= eve->next; - } - if(amount==0) return 0; - - /* allocate memory and qsort */ - sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub"); - eve= em->verts.first; - while(eve) { - if(eve->h==0 && (automerge || (eve->f & flag))) { - sb->x= eve->co[0]+eve->co[1]+eve->co[2]; - sb->v1= eve; - sb++; - } - eve= eve->next; - } - qsort(sortblock, amount, sizeof(xvertsort), vergxco); - - - /* test for doubles */ - sb= sortblock; - if (automerge) { - for(a=0; a<amount; a++, sb++) { - eve= sb->v1; - if( (eve->f & 128)==0 ) { - sb1= sb+1; - for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) { - if(sb1->x - sb->x > limit) break; - - /* when automarge, only allow unselected->selected */ - v1= sb1->v1; - if( (v1->f & 128)==0 ) { - if ((eve->f & flag)==0 && (v1->f & flag)==1) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { /* unique bit */ - eve->f|= 128; - eve->tmp.v = v1; - } - } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { /* unique bit */ - v1->f|= 128; - v1->tmp.v = eve; - } - } - } - } - } - } - } else { - for(a=0; a<amount; a++, sb++) { - eve= sb->v1; - if( (eve->f & 128)==0 ) { - sb1= sb+1; - for(b=a+1; b<amount; b++, sb1++) { - /* first test: simpel dist */ - if(sb1->x - sb->x > limit) break; - v1= sb1->v1; - - /* second test: is vertex allowed */ - if( (v1->f & 128)==0 ) { - if( (float)fabs(v1->co[0]-eve->co[0])<=limit && - (float)fabs(v1->co[1]-eve->co[1])<=limit && - (float)fabs(v1->co[2]-eve->co[2])<=limit) - { - v1->f|= 128; - v1->tmp.v = eve; - } - } - } - } - } - } - MEM_freeN(sortblock); - - if (!automerge) - for(eve = em->verts.first; eve; eve=eve->next) - if((eve->f & flag) && (eve->f & 128)) - EM_data_interp_from_verts(em, eve, eve->tmp.v, eve->tmp.v, 0.5f); - - /* test edges and insert again */ - eed= em->edges.first; - while(eed) { - eed->f2= 0; - eed= eed->next; - } - eed= em->edges.last; - while(eed) { - nexted= eed->prev; - - if(eed->f2==0) { - if( (eed->v1->f & 128) || (eed->v2->f & 128) ) { - remedge(em, eed); - - if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v; - if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v; - e1= addedgelist(em, eed->v1, eed->v2, eed); - - if(e1) { - e1->f2= 1; - if(eed->f & SELECT) - e1->f |= SELECT; - } - if(e1!=eed) free_editedge(em, eed); - } - } - eed= nexted; - } - - /* first count amount of test faces */ - efa= (struct EditFace *)em->faces.first; - amount= 0; - while(efa) { - efa->f1= 0; - if(efa->v1->f & 128) efa->f1= 1; - else if(efa->v2->f & 128) efa->f1= 1; - else if(efa->v3->f & 128) efa->f1= 1; - else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1; - - if(efa->f1==1) amount++; - efa= efa->next; - } - - /* test faces for double vertices, and if needed remove them */ - efa= (struct EditFace *)em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f1==1) { - - if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v; - if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v; - if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v; - if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v; - - test= 0; - if(efa->v1==efa->v2) test+=1; - if(efa->v2==efa->v3) test+=2; - if(efa->v3==efa->v1) test+=4; - if(efa->v4==efa->v1) test+=8; - if(efa->v3==efa->v4) test+=16; - if(efa->v2==efa->v4) test+=32; - - if(test) { - if(efa->v4) { - if(test==1 || test==2) { - efa->v2= efa->v3; - efa->v3= efa->v4; - efa->v4= 0; - - EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3); - - test= 0; - } - else if(test==8 || test==16) { - efa->v4= 0; - test= 0; - } - else { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - amount--; - } - } - else { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - amount--; - } - } - - if(test==0) { - /* set edge pointers */ - efa->e1= findedgelist(em, efa->v1, efa->v2); - efa->e2= findedgelist(em, efa->v2, efa->v3); - if(efa->v4==0) { - efa->e3= findedgelist(em, efa->v3, efa->v1); - efa->e4= 0; - } - else { - efa->e3= findedgelist(em, efa->v3, efa->v4); - efa->e4= findedgelist(em, efa->v4, efa->v1); - } - } - } - efa= nextvl; - } - - /* double faces: sort block */ - /* count again, now all selected faces */ - amount= 0; - efa= em->faces.first; - while(efa) { - efa->f1= 0; - if(faceselectedOR(efa, 1)) { - efa->f1= 1; - amount++; - } - efa= efa->next; - } - - if(amount) { - /* double faces: sort block */ - vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub"); - efa= em->faces.first; - while(efa) { - if(efa->f1 & 1) { - if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4); - else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3); - - vsb->efa= efa; - vsb++; - } - efa= efa->next; - } - - qsort(vlsortblock, amount, sizeof(struct facesort), vergface); - - vsb= vlsortblock; - for(a=0; a<amount; a++) { - efa= vsb->efa; - if( (efa->f1 & 128)==0 ) { - vsb1= vsb+1; - - for(b=a+1; b<amount; b++) { - - /* first test: same pointer? */ - if(vsb->x != vsb1->x) break; - - /* second test: is test permitted? */ - efa= vsb1->efa; - if( (efa->f1 & 128)==0 ) { - if( compareface(efa, vsb->efa)) efa->f1 |= 128; - - } - vsb1++; - } - } - vsb++; - } - - MEM_freeN(vlsortblock); - - /* remove double faces */ - efa= (struct EditFace *)em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f1 & 128) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - } - - /* remove double vertices */ - a= 0; - eve= (struct EditVert *)em->verts.first; - while(eve) { - nextve= eve->next; - if(automerge || eve->f & flag) { - if(eve->f & 128) { - a++; - BLI_remlink(&em->verts, eve); - free_editvert(em, eve); - } - } - eve= nextve; - } - - return a; /* amount */ -} - -static int removedoublesflag_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); - int totvert= em->totvert, totedge= em->totedge, totface= em->totface; - - int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit")); - - if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) { - recalc_editnormals(em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - } - - BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices"); - - BKE_mesh_end_editmesh(obedit->data, em); - - return OPERATOR_FINISHED; -} - -void MESH_OT_remove_doubles(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name= "Remove Doubles"; - ot->description= "Remove duplicate vertices"; - ot->idname= "MESH_OT_remove_doubles"; - - /* api callbacks */ - ot->exec= removedoublesflag_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f); - RNA_def_property_ui_range(prop, 0.000001f, 50.0f, 0.001, 5); -} - -// XXX is this needed? -/* called from buttons */ -static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index) -{ - xvertsort *sortblock = userData; - - sortblock[index].x = x; -} - -/* all verts with (flag & 'flag') are sorted */ -static void xsortvert_flag(bContext *C, int flag) -{ - ViewContext vc; - EditVert *eve; - xvertsort *sortblock; - ListBase tbase; - int i, amount; - - em_setup_viewcontext(C, &vc); - - amount = BLI_countlist(&vc.em->verts); - sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort"); - for (i=0,eve= vc.em->verts.first; eve; i++,eve=eve->next) - if(eve->f & flag) - sortblock[i].v1 = eve; - - ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0); - - qsort(sortblock, amount, sizeof(xvertsort), vergxco); - - /* make temporal listbase */ - tbase.first= tbase.last= 0; - for (i=0; i<amount; i++) { - eve = sortblock[i].v1; - - if (eve) { - BLI_remlink(&vc.em->verts, eve); - BLI_addtail(&tbase, eve); - } - } - - BLI_movelisttolist(&vc.em->verts, &tbase); - - MEM_freeN(sortblock); - -} - -static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op)) -{ - xsortvert_flag(C, SELECT); - return OPERATOR_FINISHED; -} - -void MESH_OT_vertices_sort(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Vertex Sort"; - ot->description= "Sort vertex order"; - ot->idname= "MESH_OT_vertices_sort"; - - /* api callbacks */ - ot->exec= mesh_vertices_sort_exec; - - ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */ - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - - -/* called from buttons */ -static void hashvert_flag(EditMesh *em, int flag) -{ - /* switch vertex order using hash table */ - EditVert *eve; - struct xvertsort *sortblock, *sb, onth, *newsort; - ListBase tbase; - int amount, a, b; - - /* count */ - eve= em->verts.first; - amount= 0; - while(eve) { - if(eve->f & flag) amount++; - eve= eve->next; - } - if(amount==0) return; - - /* allocate memory */ - sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub"); - eve= em->verts.first; - while(eve) { - if(eve->f & flag) { - sb->v1= eve; - sb++; - } - eve= eve->next; - } - - BLI_srand(1); - - sb= sortblock; - for(a=0; a<amount; a++, sb++) { - b= (int)(amount*BLI_drand()); - if(b>=0 && b<amount) { - newsort= sortblock+b; - onth= *sb; - *sb= *newsort; - *newsort= onth; - } - } - - /* make temporal listbase */ - tbase.first= tbase.last= 0; - sb= sortblock; - while(amount--) { - eve= sb->v1; - BLI_remlink(&em->verts, eve); - BLI_addtail(&tbase, eve); - sb++; - } - - BLI_movelisttolist(&em->verts, &tbase); - - MEM_freeN(sortblock); - -} - -static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - hashvert_flag(em, SELECT); - return OPERATOR_FINISHED; -} - -void MESH_OT_vertices_randomize(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Vertex Randomize"; - ot->description= "Randomize vertex order"; - ot->idname= "MESH_OT_vertices_randomize"; - - /* api callbacks */ - ot->exec= mesh_vertices_randomize_exec; - - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - - -/* generic extern called extruder */ -static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type) -{ - float nor[3]= {0.0, 0.0, 0.0}; - short transmode= 0; - - if(type<1) return; - - if(type==1) transmode= extrudeflag(obedit, em, SELECT, nor, 0); - else if(type==4) transmode= extrudeflag_verts_indiv(em, SELECT, nor); - else if(type==3) transmode= extrudeflag_edges_indiv(em, SELECT, nor); - else transmode= extrudeflag_face_indiv(em, SELECT, nor); - - EM_stats_update(em); - - if(transmode==0) { - BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude"); - } - else { - EM_fgon_flags(em); - - /* We need to force immediate calculation here because - * transform may use derived objects (which are now stale). - * - * This shouldn't be necessary, derived queries should be - * automatically building this data if invalid. Or something. - */ - DAG_id_tag_update(obedit->data, 0); - - /* individual faces? */ -// BIF_TransformSetUndo("Extrude"); - if(type==2) { -// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR); -// Transform(); - } - else { -// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR); - if(transmode=='n') { - mul_m4_v3(obedit->obmat, nor); - sub_v3_v3(nor, obedit->obmat[3]); -// BIF_setSingleAxisConstraint(nor, "along normal"); - } -// Transform(); - } - } - -} - -// XXX should be a menu item -static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type")); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -/* extrude without transform */ -static int mesh_extrude_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - - extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type")); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -static EnumPropertyItem extrude_items[] = { - {1, "REGION", 0, "Region", ""}, - {2, "FACES", 0, "Individual Faces", ""}, - {3, "EDGES", 0, "Only Edges", ""}, - {4, "VERTS", 0, "Only Vertices", ""}, - {0, NULL, 0, NULL, NULL}}; - - -static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) -{ - EnumPropertyItem *item= NULL; - Object *obedit= CTX_data_edit_object(C); - EditMesh *em; - - int totitem= 0; - - if(obedit==NULL || obedit->type != OB_MESH) - return extrude_items; - - em = BKE_mesh_get_editmesh(obedit->data); - - EM_stats_update(em); - - if(em->selectmode & SCE_SELECT_VERTEX) { - if(em->totvertsel==0) {} - else if(em->totvertsel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); } - else if(em->totedgesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); } - else if(em->totfacesel==0) { - RNA_enum_item_add(&item, &totitem, &extrude_items[2]); - RNA_enum_item_add(&item, &totitem, &extrude_items[3]); - } - else if(em->totfacesel==1) { - RNA_enum_item_add(&item, &totitem, &extrude_items[0]); - RNA_enum_item_add(&item, &totitem, &extrude_items[2]); - RNA_enum_item_add(&item, &totitem, &extrude_items[3]); - } - else { - RNA_enum_item_add(&item, &totitem, &extrude_items[0]); - RNA_enum_item_add(&item, &totitem, &extrude_items[1]); - RNA_enum_item_add(&item, &totitem, &extrude_items[2]); - RNA_enum_item_add(&item, &totitem, &extrude_items[3]); - } - } - else if(em->selectmode & SCE_SELECT_EDGE) { - if (em->totedgesel==0) {} - else if (em->totedgesel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); } - else if(em->totfacesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); } - else if(em->totfacesel==1) { - RNA_enum_item_add(&item, &totitem, &extrude_items[0]); - RNA_enum_item_add(&item, &totitem, &extrude_items[2]); - } - else { - RNA_enum_item_add(&item, &totitem, &extrude_items[0]); - RNA_enum_item_add(&item, &totitem, &extrude_items[1]); - RNA_enum_item_add(&item, &totitem, &extrude_items[2]); - } - } - else { - if (em->totfacesel == 0) {} - else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); } - else { - RNA_enum_item_add(&item, &totitem, &extrude_items[0]); - RNA_enum_item_add(&item, &totitem, &extrude_items[1]); - } - } - - if(item) { - RNA_enum_item_end(&item, &totitem); - *free= 1; - return item; - } - else { - return NULL; - } -} - -void MESH_OT_extrude(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name= "Extrude"; - ot->description= "Extrude selected vertices, edges or faces"; - ot->idname= "MESH_OT_extrude"; - - /* api callbacks */ - ot->invoke= mesh_extrude_invoke; - ot->exec= mesh_extrude_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_enum_funcs(prop, mesh_extrude_itemf); - ot->prop= prop; -} - -static int split_mesh(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - WM_cursor_wait(1); - - /* make duplicate first */ - adduplicateflag(em, SELECT); - /* old faces have flag 128 set, delete them */ - delfaceflag(em, 128); - recalc_editnormals(em); - - WM_cursor_wait(0); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_split(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Split"; - ot->description= "Split selected geometry into separate disconnected mesh"; - ot->idname= "MESH_OT_split"; - - /* api callbacks */ - ot->exec= split_mesh; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - - -static int extrude_repeat_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - int steps = RNA_int_get(op->ptr,"steps"); - - float offs = RNA_float_get(op->ptr,"offset"); - - float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0}; - short a; - - /* dvec */ - RNA_float_get_array(op->ptr, "direction", dvec); - normalize_v3(dvec); - dvec[0]*= offs; - dvec[1]*= offs; - dvec[2]*= offs; - - /* base correction */ - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(tmat, bmat); - mul_m3_v3(tmat, dvec); - - for(a=0; a<steps; a++) { - extrudeflag(obedit, em, SELECT, nor, 0); - translateflag(em, SELECT, dvec); - } - - recalc_editnormals(em); - - EM_fgon_flags(em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -/* get center and axis, in global coords */ -static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - RegionView3D *rv3d= ED_view3d_context_rv3d(C); - - if(rv3d) - RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]); - - return extrude_repeat_mesh_exec(C, op); -} - -void MESH_OT_extrude_repeat(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Extrude Repeat Mesh"; - ot->description= "Extrude selected vertices, edges or faces repeatedly"; - ot->idname= "MESH_OT_extrude_repeat"; - - /* api callbacks */ - ot->invoke= extrude_repeat_mesh_invoke; - ot->exec= extrude_repeat_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, 100.0f); - RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, 180); - RNA_def_float_vector(ot->srna, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "Direction of extrude", -FLT_MAX, FLT_MAX); -} - -/* ************************** spin operator ******************** */ - - -static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli ) -{ - Object *obedit= CTX_data_edit_object(C); - ToolSettings *ts= CTX_data_tool_settings(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditVert *eve,*nextve; - float nor[3]= {0.0f, 0.0f, 0.0f}; - float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3]; - float cent[3], bmat[3][3]; - float phi; - short a, ok= 1; - - RNA_float_get_array(op->ptr, "center", cent); - - /* imat and center and size */ - copy_m3_m4(bmat, obedit->obmat); - invert_m3_m3(imat,bmat); - - cent[0]-= obedit->obmat[3][0]; - cent[1]-= obedit->obmat[3][1]; - cent[2]-= obedit->obmat[3][2]; - mul_m3_v3(imat, cent); - - phi= degr*(float)M_PI/360.0f; - phi/= steps; - if(ts->editbutflag & B_CLOCKWISE) phi= -phi; - - RNA_float_get_array(op->ptr, "axis", n); - normalize_v3(n); - - q[0]= (float)cos(phi); - si= (float)sin(phi); - q[1]= n[0]*si; - q[2]= n[1]*si; - q[3]= n[2]*si; - quat_to_mat3( cmat,q); - - mul_m3_m3m3(tmat,cmat,bmat); - mul_m3_m3m3(bmat,imat,tmat); - - if(dupli==0) - if(ts->editbutflag & B_KEEPORIG) - adduplicateflag(em, 1); - - for(a=0; a<steps; a++) { - if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0); - else adduplicateflag(em, SELECT); - - if(ok==0) - break; - - rotateflag(em, SELECT, cent, bmat); - if(dvec) { - mul_m3_v3(bmat,dvec); - translateflag(em, SELECT, dvec); - } - } - - if(ok==0) { - /* no vertices or only loose ones selected, remove duplicates */ - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts,eve); - free_editvert(em, eve); - } - eve= nextve; - } - } - else { - recalc_editnormals(em); - - EM_fgon_flags(em); - - DAG_id_tag_update(obedit->data, 0); - } - - BKE_mesh_end_editmesh(obedit->data, em); - return ok; -} - -static int spin_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - int ok; - - ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli")); - if(ok==0) { - BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected"); - return OPERATOR_CANCELLED; - } - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -/* get center and axis, in global coords */ -static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d= ED_view3d_context_rv3d(C); - - RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); - RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]); - - return spin_mesh_exec(C, op); -} - -void MESH_OT_spin(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Spin"; - ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport"; - ot->idname= "MESH_OT_spin"; - - /* api callbacks */ - ot->invoke= spin_mesh_invoke; - ot->exec= spin_mesh_exec; - ot->poll= EM_view3d_poll; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128); - RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates"); - RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f); - - RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); - RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); - -} - -static int screw_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditVert *eve,*v1=0,*v2=0; - EditEdge *eed; - float dvec[3], nor[3]; - int steps, turns; - - turns= RNA_int_get(op->ptr, "turns"); - steps= RNA_int_get(op->ptr, "steps"); - - /* clear flags */ - for(eve= em->verts.first; eve; eve= eve->next) - eve->f1= 0; - - /* edges set flags in verts */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->v1->f & SELECT) { - if(eed->v2->f & SELECT) { - /* watch: f1 is a byte */ - if(eed->v1->f1<2) eed->v1->f1++; - if(eed->v2->f1<2) eed->v2->f1++; - } - } - } - /* find two vertices with eve->f1==1, more or less is wrong */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1==1) { - if(v1==NULL) v1= eve; - else if(v2==NULL) v2= eve; - else { - v1= NULL; - break; - } - } - } - if(v1==NULL || v2==NULL) { - BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - /* calculate dvec */ - dvec[0]= ( v1->co[0]- v2->co[0] )/steps; - dvec[1]= ( v1->co[1]- v2->co[1] )/steps; - dvec[2]= ( v1->co[2]- v2->co[2] )/steps; - - VECCOPY(nor, obedit->obmat[2]); - - if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) { - negate_v3(dvec); - } - - if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) { - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; - } - else { - BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } -} - -/* get center and axis, in global coords */ -static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event)) -{ - Scene *scene = CTX_data_scene(C); - View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d= ED_view3d_context_rv3d(C); - - RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d)); - RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]); - - return screw_mesh_exec(C, op); -} - -void MESH_OT_screw(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Screw"; - ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport"; - ot->idname= "MESH_OT_screw"; - - /* api callbacks */ - ot->invoke= screw_mesh_invoke; - ot->exec= screw_mesh_exec; - ot->poll= EM_view3d_poll; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /*props */ - RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256); - RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256); - - RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX); - RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX); -} - -static void erase_edges(EditMesh *em, ListBase *l) -{ - EditEdge *ed, *nexted; - - ed = (EditEdge *) l->first; - while(ed) { - nexted= ed->next; - if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) { - remedge(em, ed); - free_editedge(em, ed); - } - ed= nexted; - } -} - -static void erase_faces(EditMesh *em, ListBase *l) -{ - EditFace *f, *nextf; - - f = (EditFace *) l->first; - - while(f) { - nextf= f->next; - if( faceselectedOR(f, SELECT) ) { - BLI_remlink(l, f); - free_editface(em, f); - } - f = nextf; - } -} - -static void erase_vertices(EditMesh *em, ListBase *l) -{ - EditVert *v, *nextv; - - v = (EditVert *) l->first; - while(v) { - nextv= v->next; - if(v->f & 1) { - BLI_remlink(l, v); - free_editvert(em, v); - } - v = nextv; - } -} - -static void delete_mesh(EditMesh *em, wmOperator *op, int event) -{ - EditFace *efa, *nextvl; - EditVert *eve,*nextve; - EditEdge *eed,*nexted; - int count; - /* const char *str="Erase"; */ - - - if(event<1) return; - - if(event==10 ) { - /* str= "Erase Vertices"; */ - erase_edges(em, &em->edges); - erase_faces(em, &em->faces); - erase_vertices(em, &em->verts); - } - else if(event==6) { - if(!EdgeLoopDelete(em, op)) - return; - - /* str= "Erase Edge Loop"; */ - } - else if(event==4) { - /* str= "Erase Edges & Faces"; */ - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - /* delete only faces with 1 or more edges selected */ - count= 0; - if(efa->e1->f & SELECT) count++; - if(efa->e2->f & SELECT) count++; - if(efa->e3->f & SELECT) count++; - if(efa->e4 && (efa->e4->f & SELECT)) count++; - if(count) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->v1->f & SELECT) event++; - if( efa->v2->f & SELECT) event++; - if( efa->v3->f & SELECT) event++; - if(efa->v4 && (efa->v4->f & SELECT)) event++; - - if(event>1) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - } - else if(event==1) { - /* str= "Erase Edges"; */ - // faces first - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - event=0; - if( efa->e1->f & SELECT) event++; - if( efa->e2->f & SELECT) event++; - if( efa->e3->f & SELECT) event++; - if(efa->e4 && (efa->e4->f & SELECT)) event++; - - if(event) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - eed= em->edges.first; - while(eed) { - nexted= eed->next; - if(eed->f & SELECT) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } - /* to remove loose vertices: */ - eed= em->edges.first; - while(eed) { - if( eed->v1->f & SELECT) eed->v1->f-=SELECT; - if( eed->v2->f & SELECT) eed->v2->f-=SELECT; - eed= eed->next; - } - eve= em->verts.first; - while(eve) { - nextve= eve->next; - if(eve->f & SELECT) { - BLI_remlink(&em->verts,eve); - free_editvert(em, eve); - } - eve= nextve; - } - - } - else if(event==2) { - /* str="Erase Faces"; */ - delfaceflag(em, SELECT); - } - else if(event==3) { - /* str= "Erase All"; */ - if(em->verts.first) free_vertlist(em, &em->verts); - if(em->edges.first) free_edgelist(em, &em->edges); - if(em->faces.first) free_facelist(em, &em->faces); - if(em->selected.first) BLI_freelistN(&(em->selected)); - } - else if(event==5) { - /* str= "Erase Only Faces"; */ - efa= em->faces.first; - while(efa) { - nextvl= efa->next; - if(efa->f & SELECT) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - efa= nextvl; - } - } - - EM_fgon_flags(em); // redo flags and indices for fgons -} - -/* Note, these values must match delete_mesh() event values */ -static EnumPropertyItem prop_mesh_delete_types[] = { - {10,"VERT", 0, "Vertices", ""}, - {1, "EDGE", 0, "Edges", ""}, - {2, "FACE", 0, "Faces", ""}, - {3, "ALL", 0, "All", ""}, - {4, "EDGE_FACE",0, "Edges & Faces", ""}, - {5, "ONLY_FACE",0, "Only Faces", ""}, - {6, "EDGE_LOOP",0, "Edge Loop", ""}, - {0, NULL, 0, NULL, NULL} -}; - -static int delete_mesh_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - int type= RNA_enum_get(op->ptr, "type"); - - if(type==6) - return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL); - - delete_mesh(em, op, type); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_delete(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Delete"; - ot->description= "Delete selected vertices, edges or faces"; - ot->idname= "MESH_OT_delete"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= delete_mesh_exec; - - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /*props */ - ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data"); -} - - -/*GB*/ -/*-------------------------------------------------------------------------------*/ -/*--------------------------- Edge Based Subdivide ------------------------------*/ - -#define EDGENEW 2 -#define FACENEW 2 -#define EDGEINNER 4 -#define EDGEOLD 8 - -/*used by faceloop cut to select only edges valid for edge slide*/ -#define DOUBLEOPFILL 16 - -/* calculates offset for co, based on fractal, sphere or smooth settings */ -static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int beauty, float perc) -{ - float vec1[3], fac; - - if(beauty & B_SMOOTH) { - /* we calculate an offset vector vec1[], to be added to *co */ - float len, fac, nor[3], nor1[3], nor2[3]; - - sub_v3_v3v3(nor, edge->v1->co, edge->v2->co); - len= 0.5f*normalize_v3(nor); - - VECCOPY(nor1, edge->v1->no); - VECCOPY(nor2, edge->v2->no); - - /* cosine angle */ - fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ; - - vec1[0]= fac*nor1[0]; - vec1[1]= fac*nor1[1]; - vec1[2]= fac*nor1[2]; - - /* cosine angle */ - fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ; - - vec1[0]+= fac*nor2[0]; - vec1[1]+= fac*nor2[1]; - vec1[2]+= fac*nor2[2]; - - /* falloff for multi subdivide */ - smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc))); - - vec1[0]*= smooth*len; - vec1[1]*= smooth*len; - vec1[2]*= smooth*len; - - co[0] += vec1[0]; - co[1] += vec1[1]; - co[2] += vec1[2]; - } - else if(beauty & B_SPHERE) { /* subdivide sphere */ - normalize_v3(co); - co[0]*= smooth; - co[1]*= smooth; - co[2]*= smooth; - } - - if(beauty & B_FRACTAL) { - fac= fractal*len_v3v3(edge->v1->co, edge->v2->co); - vec1[0]= fac*(float)(0.5-BLI_drand()); - vec1[1]= fac*(float)(0.5-BLI_drand()); - vec1[2]= fac*(float)(0.5-BLI_drand()); - add_v3_v3(co, vec1); - } -} - -/* assumes in the edge is the correct interpolated vertices already */ -/* percent defines the interpolation, smooth, fractal and beauty are for special options */ -/* results in new vertex with correct coordinate, vertex normal and weight group info */ -static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smooth, float fractal, int beauty, float percent) -{ - EditVert *ev; - float co[3]; - - co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0]; - co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1]; - co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2]; - - /* offset for smooth or sphere or fractal */ - alter_co(co, edge, smooth, fractal, beauty, percent); - - /* clip if needed by mirror modifier */ - if (edge->v1->f2) { - if ( edge->v1->f2 & edge->v2->f2 & 1) { - co[0]= 0.0f; - } - if ( edge->v1->f2 & edge->v2->f2 & 2) { - co[1]= 0.0f; - } - if ( edge->v1->f2 & edge->v2->f2 & 4) { - co[2]= 0.0f; - } - } - - ev = addvertlist(em, co, NULL); - - /* vert data (vgroups, ..) */ - EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent); - - /* normal */ - ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0]; - ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1]; - ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2]; - normalize_v3(ev->no); - - return ev; -} - -static void flipvertarray(EditVert** arr, short size) -{ - EditVert *hold; - int i; - - for(i=0; i<size/2; i++) { - hold = arr[i]; - arr[i] = arr[size-i-1]; - arr[size-i-1] = hold; - } -} - -static void facecopy(EditMesh *em, EditFace *source, EditFace *target) -{ - float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co; - float *v4 = source->v4? source->v4->co: NULL; - float w[4][4]; - - CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data); - - target->mat_nr = source->mat_nr; - target->flag = source->flag; - target->h = source->h; - - interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co); - interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co); - interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co); - if (target->v4) - interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co); - - CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3); - CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data); -} - -static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype) -{ - EditEdge *cedge=NULL; - EditVert *v[4], **verts; - EditFace *hold; - short start=0, end, left, right, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} - end = (start+1)%4; - left = (start+2)%4; - right = (start+3)%4; - - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - | | - | | - | | - ------------- - left right - - where start,end,left, right are indexes of EditFace->v1, etc (stored in v) - and 0,1,2... are the indexes of the new verts stored in verts - - We will fill this case like this or this depending on even or odd cuts - - |---*---*---| |---*---| - | / \ | | / \ | - | / \ | | / \ | - |/ \| |/ \| - ------------- --------- - */ - - // Make center face - if(vertsize % 2 == 0) { - hold = addfacelist(em, verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e4->f2 |= EDGEINNER; - }else{ - hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL); - hold->e1->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - } - facecopy(em, efa,hold); - - // Make side faces - for(i=0;i<(vertsize-1)/2;i++) { - hold = addfacelist(em, verts[i],verts[i+1],v[right],NULL,NULL,NULL); - facecopy(em, efa,hold); - if(i+1 != (vertsize-1)/2) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e2->f2 |= EDGEINNER; - } - } - hold = addfacelist(em, verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL); - facecopy(em, efa,hold); - if(i+1 != (vertsize-1)/2) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e3->f2 |= EDGEINNER; - } - } - } -} - -static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype) -{ - EditEdge *cedge=NULL; - EditVert *v[3], **verts; - EditFace *hold; - short start=0, end, op, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);} - end = (start+1)%3; - op = (start+2)%3; - - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - \ | - \ | - \ | - \ | - \ | - \ | - |op - - where start,end,op are indexes of EditFace->v1, etc (stored in v) - and 0,1,2... are the indexes of the new verts stored in verts - - We will fill this case like this or this depending on even or odd cuts - - 3 2 1 0 - |---*---*---| - \ \ \ | - \ \ \ | - \ \ \ | - \ \ \| - \ \\| - \ | - |op - */ - - // Make side faces - for(i=0;i<(vertsize-1);i++) { - hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL); - if(i+1 != vertsize-1) { - if(seltype == SUBDIV_SELECT_INNER) { - hold->e2->f2 |= EDGEINNER; - } - } - facecopy(em, efa,hold); - } -} - -static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], **verts[2]; - EditFace *hold; - short start=0, /*end,*/ left, /* right,*/ vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;} - else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - /* end = (start+1)%4; */ /* UNUSED */ - left = (start+2)%4; - /* right = (start+3)%4; */ /* UNUSED */ - if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - |---*---*---| - | | - | | - | | - |---*---*---| - 0 1 2 3 - left right - - We will fill this case like this or this depending on even or odd cuts - - |---*---*---| - | | | | - | | | | - | | | | - |---*---*---| - */ - - // Make side faces - for(i=0;i<vertsize-1;i++) { - hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL); - if(i < vertsize-2) { - hold->e2->f2 |= EDGEINNER; - hold->e2->f2 |= DOUBLEOPFILL; - } - facecopy(em, efa,hold); - } -} - -static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - int ctrl= 0; // XXX - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------| - - We will fill this case like this or this depending on even or odd cuts - |---*---*---| - | / / / | - * / / | - | / / | - * / | - | / | - |-----------| - */ - - // Make outside tris - hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - /* when ctrl is depressed, only want verts on the cutline selected */ - if (ctrl) - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - hold = addfacelist(em, verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL); - /* when ctrl is depressed, only want verts on the cutline selected */ - if (ctrl) - hold->e1->f2 |= EDGEINNER; - facecopy(em, efa,hold); - //if(scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - // Make side faces - - for(i=0;i<numcuts;i++) { - hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - } - //EM_fgon_flags(em); - -} - -static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], *op=NULL, **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} - - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------|op - - We will fill this case like this or this (warning horrible ascii art follows) - |---*---*---| - | \ \ \ | - *---\ \ \ | - | \ \ \ \| - *---- \ \ \ | - | --- \\\| - |-----------| - */ - - for(i=0;i<=numcuts;i++) { - hold = addfacelist(em, op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL); - hold->e1->f2 |= EDGEINNER; - facecopy(em, efa,hold); - - hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - } -} - -static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[4], *op=NULL, **verts[2],**inner; - EditFace *hold; - short start=0, start2=0, vertsize,i; - float co[3]; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;} - if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;} - if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;} - - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | | - 1* | - | | - 2* | - | | - end2 3|-----------|op - - We will fill this case like this or this (warning horrible ascii art follows) - |---*-----*---| - | * / | - * \ / | - | * | - | / \ | - * \ | - | \ | - |-------------| - */ - - // Add Inner Vert(s) - inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts"); - - for(i=0;i<numcuts;i++) { - co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ; - co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ; - co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ; - inner[i] = addvertlist(em, co, NULL); - inner[i]->f2 |= EDGEINNER; - - EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f); - } - - // Add Corner Quad - hold = addfacelist(em, verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - // Add Bottom Quads - hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - - hold = addfacelist(em, op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - - //if(scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - // Add Fill Quads (if # cuts > 1) - - for(i=0;i<numcuts-1;i++) { - hold = addfacelist(em, inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL); - hold->e1->f2 |= EDGEINNER; - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - - hold = addfacelist(em, inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - hold->e4->f2 |= EDGEINNER; - facecopy(em, efa,hold); - - //if(scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e1->h |= EM_FGON; - //} - } - - //EM_fgon_flags(em); - - MEM_freeN(inner); -} - -static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[2]={NULL, NULL}; - EditVert *v[3], **verts[2]; - EditFace *hold; - short start=0, start2=0, vertsize,i; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - - if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;} - if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;} - if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;} - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - /* - We should have something like this now - - end start - 3 2 1 0 - start2 0|---*---*---| - | / - 1* / - | / - 2* / - | / - end2 3| - - We will fill this case like this or this depending on even or odd cuts - |---*---*---| - | / / / - * / / - | / / - * / - | / - | - */ - - // Make outside tri - hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - // Make side faces - - for(i=0;i<numcuts;i++) { - hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - } -} - -static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts) -{ - EditEdge *cedge[3]={0}; - EditVert *v[4], **verts[3]; - EditFace *hold; - short start=0, start2=0, start3=0, vertsize, i, repeats; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(!(efa->e1->f & SELECT)) { - cedge[0] = efa->e2; - cedge[1] = efa->e3; - cedge[2] = efa->e4; - start = 1;start2 = 2;start3 = 3; - } - if(!(efa->e2->f & SELECT)) { - cedge[0] = efa->e3; - cedge[1] = efa->e4; - cedge[2] = efa->e1; - start = 2;start2 = 3;start3 = 0; - } - if(!(efa->e3->f & SELECT)) { - cedge[0] = efa->e4; - cedge[1] = efa->e1; - cedge[2] = efa->e2; - start = 3;start2 = 0;start3 = 1; - } - if(!(efa->e4->f & SELECT)) { - cedge[0] = efa->e1; - cedge[1] = efa->e2; - cedge[2] = efa->e3; - start = 0;start2 = 1;start3 = 2; - } - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, cedge[0]); - verts[1] = BLI_ghash_lookup(gh, cedge[1]); - verts[2] = BLI_ghash_lookup(gh, cedge[2]); - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);} - /* - We should have something like this now - - start2 - 3 2 1 0 - start3 0|---*---*---|3 - | | - 1* *2 - | | - 2* *1 - | | - 3|-----------|0 start - - We will fill this case like this or this depending on even or odd cuts - there are a couple of differences. For odd cuts, there is a tri in the - middle as well as 1 quad at the bottom (not including the extra quads - for odd cuts > 1 - - For even cuts, there is a quad in the middle and 2 quads on the bottom - - they are numbered here for clarity - - 1 outer tris and bottom quads - 2 inner tri or quad - 3 repeating quads - - |---*---*---*---| - |1/ / \ \ 1| - |/ 3 / \ 3 \| - * / 2 \ * - | / \ | - |/ \ | - *---------------* - | 3 | - | | - *---------------* - | | - | 1 | - | | - |---------------| - - |---*---*---*---*---| - | 1/ / \ \ 1| - | / / \ \ | - |/ 3 / \ 3 \| - * / \ * - | / \ | - | / 2 \ | - |/ \| - *-------------------* - | | - | 3 | - | | - *-------------------* - | | - | 1 | - | | - *-------------------* - | | - | 1 | - | | - |-------------------| - - */ - - // Make outside tris - hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL); - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa,hold); - // Make bottom quad - hold = addfacelist(em, verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - //If it is even cuts, add the 2nd lower quad - if(numcuts % 2 == 0) { - hold = addfacelist(em, verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - // Also Make inner quad - hold = addfacelist(em, verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL); - hold->e3->f2 |= EDGEINNER; - //if(scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e3->h |= EM_FGON; - //} - facecopy(em, efa,hold); - repeats = (numcuts / 2) -1; - } else { - // Make inner tri - hold = addfacelist(em, verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL); - hold->e2->f2 |= EDGEINNER; - //if(scene->toolsettings->editbutflag & B_AUTOFGON) { - // hold->e2->h |= EM_FGON; - //} - facecopy(em, efa,hold); - repeats = ((numcuts+1) / 2)-1; - } - - // cuts for 1 and 2 do not have the repeating quads - if(numcuts < 3) {repeats = 0;} - for(i=0;i<repeats;i++) { - //Make side repeating Quads - hold = addfacelist(em, verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL); - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - hold = addfacelist(em, verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL); - hold->e4->f2 |= EDGEINNER; - facecopy(em, efa,hold); - } - // Do repeating bottom quads - for(i=0;i<repeats;i++) { - if(numcuts % 2 == 1) { - hold = addfacelist(em, verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL); - } else { - hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL); - } - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa,hold); - } - //EM_fgon_flags(em); -} - -static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty) -{ - EditVert **verts[4], ***innerverts; - EditFace *hold; - EditEdge temp; - short vertsize, i, j; - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, efa->e1); - verts[1] = BLI_ghash_lookup(gh, efa->e2); - verts[2] = BLI_ghash_lookup(gh, efa->e3); - verts[3] = BLI_ghash_lookup(gh, efa->e4); - - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);} - if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);} - /* - We should have something like this now - 1 - - 3 2 1 0 - 0|---*---*---|0 - | | - 1* *1 - 2 | | 4 - 2* *2 - | | - 3|---*---*---|3 - 3 2 1 0 - - 3 - // we will fill a 2 dim array of editvert*s to make filling easier - // the innervert order is shown - - 0 0---1---2---3 - | | | | - 1 0---1---2---3 - | | | | - 2 0---1---2---3 - | | | | - 3 0---1---2---3 - - */ - innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array"); - for(i=0;i<numcuts+2;i++) { - innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array"); - } - - // first row is e1 last row is e3 - for(i=0;i<numcuts+2;i++) { - innerverts[0][i] = verts[0][(numcuts+1)-i]; - innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i]; - } - - for(i=1;i<=numcuts;i++) { - /* we create a fake edge for the next loop */ - temp.v2 = innerverts[i][0] = verts[1][i]; - temp.v1 = innerverts[i][numcuts+1] = verts[3][i]; - - for(j=1;j<=numcuts;j++) { - float percent= (float)j/(float)(numcuts+1); - - innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent); - } - } - // Fill with faces - for(i=0;i<numcuts+1;i++) { - for(j=0;j<numcuts+1;j++) { - hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL); - hold->e1->f2 = EDGENEW; - hold->e2->f2 = EDGENEW; - hold->e3->f2 = EDGENEW; - hold->e4->f2 = EDGENEW; - - if(i != 0) { hold->e1->f2 |= EDGEINNER; } - if(j != 0) { hold->e2->f2 |= EDGEINNER; } - if(i != numcuts) { hold->e3->f2 |= EDGEINNER; } - if(j != numcuts) { hold->e4->f2 |= EDGEINNER; } - - facecopy(em, efa,hold); - } - } - // Clean up our dynamic multi-dim array - for(i=0;i<numcuts+2;i++) { - MEM_freeN(innerverts[i]); - } - MEM_freeN(innerverts); -} - -static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty) -{ - EditVert **verts[3], ***innerverts; - short vertsize, i, j; - EditFace *hold; - EditEdge temp; - - // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1] - verts[0] = BLI_ghash_lookup(gh, efa->e1); - verts[1] = BLI_ghash_lookup(gh, efa->e2); - verts[2] = BLI_ghash_lookup(gh, efa->e3); - - //This is the index size of the verts array - vertsize = numcuts+2; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);} - if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);} - if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);} - /* - We should have something like this now - 3 - - 3 2 1 0 - 0|---*---*---|3 - | / - 1 1* *2 - | / - 2* *1 2 - | / - 3|/ - 0 - - we will fill a 2 dim array of editvert*s to make filling easier - - 3 - - 0 0---1---2---3---4 - | / | / |/ | / - 1 0---1----2---3 - 1 | / | / | / - 2 0----1---2 2 - | / | / - |/ |/ - 3 0---1 - | / - |/ - 4 0 - - */ - - innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array"); - for(i=0;i<numcuts+2;i++) { - innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array"); - } - //top row is e3 backwards - for(i=0;i<numcuts+2;i++) { - innerverts[0][i] = verts[2][(numcuts+1)-i]; - } - - for(i=1;i<=numcuts+1;i++) { - //fake edge, first vert is from e1, last is from e2 - temp.v1= innerverts[i][0] = verts[0][i]; - temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i]; - - for(j=1;j<(numcuts+1)-i;j++) { - float percent= (float)j/(float)((numcuts+1)-i); - - innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent); - } - } - - // Now fill the verts with happy little tris :) - for(i=0;i<=numcuts+1;i++) { - for(j=0;j<(numcuts+1)-i;j++) { - //We always do the first tri - hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - if(i != 0) { hold->e1->f2 |= EDGEINNER; } - if(j != 0) { hold->e2->f2 |= EDGEINNER; } - if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;} - - facecopy(em, efa,hold); - //if there are more to come, we do the 2nd - if(j+1 <= numcuts-i) { - hold = addfacelist(em, innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL); - facecopy(em, efa,hold); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - } - } - } - - // Clean up our dynamic multi-dim array - for(i=0;i<numcuts+2;i++) { - MEM_freeN(innerverts[i]); - } - MEM_freeN(innerverts); -} - -//Next two fill types are for knife exact only and are provided to allow for knifing through vertices -//This means there is no multicut! -static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2) -{ - EditFace *hold; - /* - Depending on which two vertices have been knifed through (v1 and v2), we - triangulate like the patterns below. - X-------| |-------X - | \ | | / | - | \ | | / | - | \ | | / | - --------X X-------- - */ - - if(v1 == 1 && v2 == 3){ - hold= addfacelist(em, efa->v1, efa->v2, efa->v3, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa, hold); - - hold= addfacelist(em, efa->v1, efa->v3, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(em, efa, hold); - } - else{ - hold= addfacelist(em, efa->v1, efa->v2, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e2->f2 |= EDGEINNER; - facecopy(em, efa, hold); - - hold= addfacelist(em, efa->v2, efa->v3, efa->v4, 0, efa, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa, hold); - } -} - -static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh) -{ - EditEdge *cedge=NULL; - EditVert *v[4], **verts; - EditFace *hold; - short start=0, end, left, right, vertsize; - - v[0] = efa->v1; - v[1] = efa->v2; - v[2] = efa->v3; - v[3] = efa->v4; - - if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;} - else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;} - else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;} - else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;} - - // Point verts to the array of new verts for cedge - verts = BLI_ghash_lookup(gh, cedge); - //This is the index size of the verts array - vertsize = 3; - - // Is the original v1 the same as the first vert on the selected edge? - // if not, the edge is running the opposite direction in this face so flip - // the array to the correct direction - - if(verts[0] != v[start]) {flipvertarray(verts,3);} - end = (start+1)%4; - left = (start+2)%4; - right = (start+3)%4; - -/* - We should have something like this now - - end start - 2 1 0 - |-----*-----| - | | - | | - | | - ------------- - left right - - where start,end,left, right are indexes of EditFace->v1, etc (stored in v) - and 0,1,2 are the indexes of the new verts stored in verts. We fill like - this, depending on whether its vertex 'left' or vertex 'right' thats - been knifed through... - - |---*---| |---*---| - | / | | \ | - | / | | \ | - |/ | | \| - X-------- --------X -*/ - - if(v[left]->f1){ - //triangle is composed of cutvert, end and left - hold = addfacelist(em, verts[1],v[end],v[left],NULL, NULL,NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e3->f2 |= EDGEINNER; - facecopy(em, efa, hold); - - //quad is composed of cutvert, left, right and start - hold = addfacelist(em, verts[1],v[left],v[right],v[start], NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e4->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(em, efa, hold); - } - else if(v[right]->f1){ - //triangle is composed of cutvert, right and start - hold = addfacelist(em, verts[1],v[right],v[start], NULL, NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e1->f2 |= EDGEINNER; - facecopy(em, efa, hold); - //quad is composed of cutvert, end, left, right - hold = addfacelist(em, verts[1],v[end], v[left], v[right], NULL, NULL); - hold->e1->f2 |= EDGENEW; - hold->e2->f2 |= EDGENEW; - hold->e3->f2 |= EDGENEW; - hold->e4->f2 |= EDGENEW; - hold->e4->f2 |= EDGEINNER; - facecopy(em, efa, hold); - } - -} - -// This function takes an example edge, the current point to create and -// the total # of points to create, then creates the point and return the -// editvert pointer to it. -static EditVert *subdivideedgenum(EditMesh *em, EditEdge *edge, int curpoint, int totpoint, float smooth, float fractal, int beauty) -{ - EditVert *ev; - float percent; - - if (beauty & (B_PERCENTSUBD) && totpoint == 1) - //percent=(float)(edge->tmp.l)/32768.0f; - percent= edge->tmp.fp; - else - percent= (float)curpoint/(float)(totpoint+1); - - ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent); - ev->f = edge->v1->f; - - return ev; -} - -void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype) -{ - EditFace *ef; - EditEdge *eed, *cedge, *sort[4]; - EditVert *eve, **templist; - struct GHash *gh; - float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3]; - int i, j, edgecount, touchcount, facetype,hold; - ModifierData *md= obedit->modifiers.first; - int ctrl= 0; // XXX - - //Set faces f1 to 0 cause we need it later - for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0; - for(eve=em->verts.first; eve; eve=eve->next) { - if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */ - eve->f1 = 0; - eve->f2 = 0; - } - - for (; md; md=md->next) { - if (md->type==eModifierType_Mirror) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - for (eve= em->verts.first; eve; eve= eve->next) { - eve->f2= 0; - switch(mmd->axis){ - case 0: - if (fabsf(eve->co[0]) < mmd->tolerance) - eve->f2 |= 1; - break; - case 1: - if (fabsf(eve->co[1]) < mmd->tolerance) - eve->f2 |= 2; - break; - case 2: - if (fabsf(eve->co[2]) < mmd->tolerance) - eve->f2 |= 4; - break; - } - } - } - } - } - - //Flush vertex flags upward to the edges - for(eed = em->edges.first;eed;eed = eed->next) { - //if(eed->f & flag && eed->v1->f == eed->v2->f) { - // eed->f |= eed->v1->f; - // } - eed->f2 = 0; - if(eed->f & flag) { - eed->f2 |= EDGEOLD; - } - } - - // We store an array of verts for each edge that is subdivided, - // we put this array as a value in a ghash which is keyed by the EditEdge* - - // Now for beauty subdivide deselect edges based on length - if(beauty & B_BEAUTY) { - for(ef = em->faces.first;ef;ef = ef->next) { - if(!ef->v4) { - continue; - } - if(ef->f & SELECT) { - VECCOPY(v1mat, ef->v1->co); - VECCOPY(v2mat, ef->v2->co); - VECCOPY(v3mat, ef->v3->co); - VECCOPY(v4mat, ef->v4->co); - mul_mat3_m4_v3(obedit->obmat, v1mat); - mul_mat3_m4_v3(obedit->obmat, v2mat); - mul_mat3_m4_v3(obedit->obmat, v3mat); - mul_mat3_m4_v3(obedit->obmat, v4mat); - - length[0] = len_v3v3(v1mat, v2mat); - length[1] = len_v3v3(v2mat, v3mat); - length[2] = len_v3v3(v3mat, v4mat); - length[3] = len_v3v3(v4mat, v1mat); - sort[0] = ef->e1; - sort[1] = ef->e2; - sort[2] = ef->e3; - sort[3] = ef->e4; - - - // Beauty Short Edges - if(beauty & B_BEAUTY_SHORT) { - for(j=0;j<2;j++) { - hold = -1; - for(i=0;i<4;i++) { - if(length[i] < 0) { - continue; - } else if(hold == -1) { - hold = i; - } else { - if(length[hold] < length[i]) { - hold = i; - } - } - } - if (hold > -1) { - sort[hold]->f &= ~SELECT; - sort[hold]->f2 |= EDGENEW; - length[hold] = -1; - } - } - } - - // Beauty Long Edges - else { - for(j=0;j<2;j++) { - hold = -1; - for(i=0;i<4;i++) { - if(length[i] < 0) { - continue; - } else if(hold == -1) { - hold = i; - } else { - if(length[hold] > length[i]) { - hold = i; - } - } - } - if (hold > -1) { - sort[hold]->f &= ~SELECT; - sort[hold]->f2 |= EDGENEW; - length[hold] = -1; - } - } - } - } - } - } - - gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh"); - - // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut - if(beauty & B_KNIFE) { - for(eed= em->edges.first;eed;eed=eed->next) { - if( eed->tmp.fp == 0 ) { - EM_select_edge(eed,0); - } - } - } - // So for each edge, if it is selected, we allocate an array of size cuts+2 - // so we can have a place for the v1, the new verts and v2 - for(eed=em->edges.first;eed;eed = eed->next) { - if(eed->f & flag) { - templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist"); - templist[0] = eed->v1; - for(i=0;i<numcuts;i++) { - // This function creates the new vert and returns it back - // to the array - templist[i+1] = subdivideedgenum(em, eed, i+1, numcuts, smooth, fractal, beauty); - //while we are here, we can copy edge info from the original edge - cedge = addedgelist(em, templist[i],templist[i+1],eed); - // Also set the edge f2 to EDGENEW so that we can use this info later - cedge->f2 = EDGENEW; - } - templist[i+1] = eed->v2; - //Do the last edge too - cedge = addedgelist(em, templist[i],templist[i+1],eed); - cedge->f2 = EDGENEW; - // Now that the edge is subdivided, we can put its verts in the ghash - BLI_ghash_insert(gh, eed, templist); - } - } - -// DAG_id_tag_update(obedit->data, 0); - // Now for each face in the mesh we need to figure out How many edges were cut - // and which filling method to use for that face - for(ef = em->faces.first;ef;ef = ef->next) { - edgecount = 0; - facetype = 3; - if(ef->e1->f & flag) {edgecount++;} - if(ef->e2->f & flag) {edgecount++;} - if(ef->e3->f & flag) {edgecount++;} - if(ef->v4) { - facetype = 4; - if(ef->e4->f & flag) {edgecount++;} - } - if(facetype == 4) { - switch(edgecount) { - case 0: - if(beauty & B_KNIFE && numcuts == 1){ - /*Test for when knifing through two opposite verts but no edges*/ - touchcount = 0; - if(ef->v1->f1) touchcount++; - if(ef->v2->f1) touchcount++; - if(ef->v3->f1) touchcount++; - if(ef->v4->f1) touchcount++; - if(touchcount == 2){ - if(ef->v1->f1 && ef->v3->f1){ - ef->f1 = SELECT; - fill_quad_doublevert(em, ef, 1, 3); - } - else if(ef->v2->f1 && ef->v4->f1){ - ef->f1 = SELECT; - fill_quad_doublevert(em, ef, 2, 4); - } - } - } - break; - - case 1: - if(beauty & B_KNIFE && numcuts == 1){ - /*Test for when knifing through an edge and one vert*/ - touchcount = 0; - if(ef->v1->f1) touchcount++; - if(ef->v2->f1) touchcount++; - if(ef->v3->f1) touchcount++; - if(ef->v4->f1) touchcount++; - - if(touchcount == 1){ - if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) || - (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) || - (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) || - (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){ - - ef->f1 = SELECT; - fill_quad_singlevert(em, ef, gh); - } - else{ - ef->f1 = SELECT; - fill_quad_single(em, ef, gh, numcuts, seltype); - } - } - else{ - ef->f1 = SELECT; - fill_quad_single(em, ef, gh, numcuts, seltype); - } - } - else{ - ef->f1 = SELECT; - fill_quad_single(em, ef, gh, numcuts, seltype); - } - break; - case 2: ef->f1 = SELECT; - // if there are 2, we check if edge 1 and 3 are either both on or off that way - // we can tell if the selected pair is Adjacent or Opposite of each other - if((ef->e1->f & flag && ef->e3->f & flag) || - (ef->e2->f & flag && ef->e4->f & flag)) { - fill_quad_double_op(em, ef, gh, numcuts); - }else{ - switch(corner_pattern) { - case 0: fill_quad_double_adj_path(em, ef, gh, numcuts); break; - case 1: fill_quad_double_adj_inner(em, ef, gh, numcuts); break; - case 2: fill_quad_double_adj_fan(em, ef, gh, numcuts); break; - } - - } - break; - case 3: ef->f1 = SELECT; - fill_quad_triple(em, ef, gh, numcuts); - break; - case 4: ef->f1 = SELECT; - fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty); - break; - } - } else { - switch(edgecount) { - case 0: break; - case 1: ef->f1 = SELECT; - fill_tri_single(em, ef, gh, numcuts, seltype); - break; - case 2: ef->f1 = SELECT; - fill_tri_double(em, ef, gh, numcuts); - break; - case 3: ef->f1 = SELECT; - fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty); - break; - } - } - } - - // Delete Old Edges and Faces - for(eed = em->edges.first;eed;eed = eed->next) { - if(BLI_ghash_haskey(gh,eed)) { - eed->f1 = SELECT; - } else { - eed->f1 = 0; - } - } - free_tagged_edges_faces(em, em->edges.first, em->faces.first); - - if(seltype == SUBDIV_SELECT_ORIG && !ctrl) { - /* bugfix: vertex could get flagged as "not-selected" - // solution: clear flags before, not at the same time as setting SELECT flag -dg - */ - for(eed = em->edges.first;eed;eed = eed->next) { - if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) { - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) { - eed->f |= flag; - EM_select_edge(eed,1); - } - } - } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) { - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & EDGEINNER) { - eed->f |= flag; - EM_select_edge(eed,1); - if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT; - if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT; - }else{ - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - } else if(seltype == SUBDIV_SELECT_LOOPCUT){ - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f2 & DOUBLEOPFILL){ - eed->f |= flag; - EM_select_edge(eed,1); - }else{ - eed->f &= !flag; - EM_select_edge(eed,0); - } - } - } - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eed = em->edges.first;eed;eed = eed->next) { - if(eed->f & SELECT) { - eed->v1->f |= SELECT; - eed->v2->f |= SELECT; - } - } - } - - //fix hide flags for edges. First pass, hide edges of hidden faces - for(ef=em->faces.first; ef; ef=ef->next){ - if(ef->h){ - ef->e1->h |= 1; - ef->e2->h |= 1; - ef->e3->h |= 1; - if(ef->e4) ef->e4->h |= 1; - } - } - //second pass: unhide edges of visible faces adjacent to hidden faces - for(ef=em->faces.first; ef; ef=ef->next){ - if(ef->h == 0){ - ef->e1->h &= ~1; - ef->e2->h &= ~1; - ef->e3->h &= ~1; - if(ef->e4) ef->e4->h &= ~1; - } - } - - //third pass: unhide edges that have both verts visible - //(these were missed if all faces were hidden, bug #21976) - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->v1->h == 0 && eed->v2->h == 0) - eed->h &= ~1; - } - - // Free the ghash and call MEM_freeN on all the value entries to return - // that memory - BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); - - EM_selectmode_flush(em); - for(ef=em->faces.first;ef;ef = ef->next) { - if(ef->e4) { - if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && - (ef->e3->f & SELECT && ef->e4->f & SELECT) ) { - ef->f |= SELECT; - } - } else { - if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) { - ef->f |= SELECT; - } - } - } - - recalc_editnormals(em); -} - -static int count_selected_edges(EditEdge *ed) -{ - int totedge = 0; - while(ed) { - ed->tmp.p = 0; - if( ed->f & SELECT ) totedge++; - ed= ed->next; - } - return totedge; -} - -/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */ -typedef EditFace *EVPtr; -typedef EVPtr EVPTuple[2]; - -/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces) - sharing one edge. - arguments: selected edge list, face list. - Edges will also be tagged accordingly (see eed->f2) */ - -static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa) -{ - EditEdge *e1, *e2, *e3; - EVPtr *evp; - int i = 0; - - /* run through edges, if selected, set pointer edge-> facearray */ - while(eed) { - eed->f2= 0; - eed->f1= 0; - if( eed->f & SELECT ) { - eed->tmp.p = (EditVert *) (&efaa[i]); - i++; - } - else eed->tmp.p = NULL; - - eed= eed->next; - } - - - /* find edges pointing to 2 faces by procedure: - - - run through faces and their edges, increase - face counter e->f1 for each face - */ - - while(efa) { - efa->f1= 0; - if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */ - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - if(e1->f2<3 && e1->tmp.p) { - if(e1->f2<2) { - evp= (EVPtr *) e1->tmp.p; - evp[(int)e1->f2] = efa; - } - e1->f2+= 1; - } - if(e2->f2<3 && e2->tmp.p) { - if(e2->f2<2) { - evp= (EVPtr *) e2->tmp.p; - evp[(int)e2->f2]= efa; - } - e2->f2+= 1; - } - if(e3->f2<3 && e3->tmp.p) { - if(e3->f2<2) { - evp= (EVPtr *) e3->tmp.p; - evp[(int)e3->f2]= efa; - } - e3->f2+= 1; - } - } - else { - /* set to 3 to make sure these are not flipped or joined */ - efa->e1->f2= 3; - efa->e2->f2= 3; - efa->e3->f2= 3; - if (efa->e4) efa->e4->f2= 3; - } - - efa= efa->next; - } - return i; -} - - -/* returns vertices of two adjacent triangles forming a quad - - can be righthand or lefthand - - 4-----3 - |\ | - | \ 2 | <- efa1 - | \ | - efa-> | 1 \ | - | \| - 1-----2 - -*/ -#define VTEST(face, num, other) \ - (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3) - -static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex) -{ - if VTEST(efa, 1, efa1) { - *v1= efa->v1; - *v2= efa->v2; - vindex[0]= 0; - vindex[1]= 1; - } - else if VTEST(efa, 2, efa1) { - *v1= efa->v2; - *v2= efa->v3; - vindex[0]= 1; - vindex[1]= 2; - } - else if VTEST(efa, 3, efa1) { - *v1= efa->v3; - *v2= efa->v1; - vindex[0]= 2; - vindex[1]= 0; - } - - if VTEST(efa1, 1, efa) { - *v3= efa1->v1; - *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2; - vindex[2]= 0; - vindex[3]= (efa1->v2 == *v2)? 2: 1; - } - else if VTEST(efa1, 2, efa) { - *v3= efa1->v2; - *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3; - vindex[2]= 1; - vindex[3]= (efa1->v3 == *v2)? 0: 2; - } - else if VTEST(efa1, 3, efa) { - *v3= efa1->v3; - *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1; - vindex[2]= 2; - vindex[3]= (efa1->v1 == *v2)? 1: 0; - } - else - *v3= *v4= NULL; -} - -/* Helper functions for edge/quad edit features*/ -static void untag_edges(EditFace *f) -{ - f->e1->f1 = 0; - f->e2->f1 = 0; - f->e3->f1 = 0; - if (f->e4) f->e4->f1 = 0; -} - -/** remove and free list of tagged edges and faces */ -static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa) -{ - EditEdge *nexted; - EditFace *nextvl; - - while(efa) { - nextvl= efa->next; - if(efa->f1) { - BLI_remlink(&em->faces, efa); - free_editface(em, efa); - } - else - /* avoid deleting edges that are still in use */ - untag_edges(efa); - efa= nextvl; - } - - while(eed) { - nexted= eed->next; - if(eed->f1) { - remedge(em, eed); - free_editedge(em, eed); - } - eed= nexted; - } -} - - -/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */ -static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit) -{ - - /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/ - /*Note: this is more complicated than it needs to be and should be cleaned up...*/ - float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff, - edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff, - minarea, maxarea, areaA, areaB; - - /*First Test: Normal difference*/ - normal_tri_v3( noA1,v1->co, v2->co, v3->co); - normal_tri_v3( noA2,v1->co, v3->co, v4->co); - - if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0; - else normalADiff = RAD2DEGF(angle_v2v2(noA1, noA2)); - //if(!normalADiff) normalADiff = 179; - normal_tri_v3( noB1,v2->co, v3->co, v4->co); - normal_tri_v3( noB2,v4->co, v1->co, v2->co); - - if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0; - else normalBDiff = RAD2DEGF(angle_v2v2(noB1, noB2)); - //if(!normalBDiff) normalBDiff = 179; - - measure += (normalADiff/360) + (normalBDiff/360); - if(measure > limit) return measure; - - /*Second test: Colinearity*/ - sub_v3_v3v3(edgeVec1, v1->co, v2->co); - sub_v3_v3v3(edgeVec2, v2->co, v3->co); - sub_v3_v3v3(edgeVec3, v3->co, v4->co); - sub_v3_v3v3(edgeVec4, v4->co, v1->co); - - diff = 0.0; - - diff = ( - fabsf(RAD2DEGF(angle_v2v2(edgeVec1, edgeVec2)) - 90) + - fabsf(RAD2DEGF(angle_v2v2(edgeVec2, edgeVec3)) - 90) + - fabsf(RAD2DEGF(angle_v2v2(edgeVec3, edgeVec4)) - 90) + - fabsf(RAD2DEGF(angle_v2v2(edgeVec4, edgeVec1)) - 90)) / 360; - if(!diff) return 0.0; - - measure += diff; - if(measure > limit) return measure; - - /*Third test: Concavity*/ - areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co); - areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co); - - if(areaA <= areaB) minarea = areaA; - else minarea = areaB; - - if(areaA >= areaB) maxarea = areaA; - else maxarea = areaB; - - if(!maxarea) measure += 1; - else measure += (1 - (minarea / maxarea)); - - return measure; -} - -#define T2QUV_LIMIT 0.005f -#define T2QCOL_LIMIT 3 -static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed) -{ - /*Test to see if the per-face attributes for the joining edge match within limit*/ - MTFace *tf1, *tf2; - unsigned int *col1, *col2; - short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2]; - - tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE); - tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE); - - col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL); - col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL); - - /*store indices for faceedges*/ - f1->v1->f1 = 0; - f1->v2->f1 = 1; - f1->v3->f1 = 2; - - fe1[0] = eed->v1->f1; - fe1[1] = eed->v2->f1; - - f2->v1->f1 = 0; - f2->v2->f1 = 1; - f2->v3->f1 = 2; - - fe2[0] = eed->v1->f1; - fe2[1] = eed->v2->f1; - - /*compare faceedges for each face attribute. Additional per face attributes can be added later*/ - /*do UVs*/ - if(flag & B_JOINTRIA_UV){ - - if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV; - else if(tf1->tpage != tf2->tpage); /*do nothing*/ - else{ - for(i = 0; i < 2; i++){ - 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] && - 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; - } - } - } - - /*do VCOLs*/ - if(flag & B_JOINTRIA_VCOL){ - if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL; - else{ - char *f1vcol, *f2vcol; - for(i = 0; i < 2; i++){ - f1vcol = (char *)&(col1[fe1[i]]); - f2vcol = (char *)&(col2[fe2[i]]); - - /*compare f1vcol with f2vcol*/ - if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] && - f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] && - f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL; - } - } - } - - if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1; - return 0; -} - -static int fplcmp(const void *v1, const void *v2) -{ - const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2); - - if( e1->crease > e2->crease) return 1; - else if( e1->crease < e2->crease) return -1; - - return 0; -} - -/*Bitflags for edges.*/ -#define T2QDELETE 1 -#define T2QCOMPLEX 2 -#define T2QJOIN 4 -void join_triangles(EditMesh *em) -{ - EditVert *v1, *v2, *v3, *v4, *eve; - EditEdge *eed, **edsortblock = NULL, **edb = NULL; - EditFace *efa; - EVPTuple *efaar = NULL; - EVPtr *efaa = NULL; - float *creases = NULL; - float measure; /*Used to set tolerance*/ - float limit = 0.8f; // XXX scene->toolsettings->jointrilimit; - int i, ok, totedge=0, totseledge=0, complexedges, vindex[4]; - - /*if we take a long time on very dense meshes we want waitcursor to display*/ - waitcursor(1); - - totseledge = count_selected_edges(em->edges.first); - if(totseledge==0) return; - - /*abusing crease value to store weights for edge pairs. Nasty*/ - for(eed=em->edges.first; eed; eed=eed->next) totedge++; - if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array"); - for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){ - creases[i] = eed->crease; - eed->crease = 0.0; - } - - /*clear temp flags*/ - for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0; - for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0; - for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0; - - /*For every selected 2 manifold edge, create pointers to its two faces.*/ - efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad"); - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - complexedges = 0; - - if(ok){ - - - /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/ - for(eed=em->edges.first; eed; eed=eed->next){ - /* eed->f2 is 2 only if this edge is part of exactly two - triangles, and both are selected, and it has EVPTuple assigned */ - if(eed->f2 == 2){ - efaa= (EVPtr *) eed->tmp.p; - efaa[0]->tmp.l++; - efaa[1]->tmp.l++; - } - } - - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f2 == 2){ - efaa= (EVPtr *) eed->tmp.p; - v1 = v2 = v3 = v4 = NULL; - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if(v1 && v2 && v3 && v4){ - /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/ - if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){ - eed->f1 |= T2QJOIN; - efaa[0]->f1 = 1; //mark for join - efaa[1]->f1 = 1; //mark for join - } - else{ - - /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved. - Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria: - - 1: the two faces do not share the same material - 2: the edge joining the two faces is marked as sharp. - 3: the two faces UV's do not make a good match - 4: the two faces Vertex colors do not make a good match - - If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function. - This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user - the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the - same faces in the current pair later. - - This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of - the python scripts bundled with Blender releases. - */ - -// XXX if(scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/ -// else if(scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/ -// else if(((scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) && - compareFaceAttribs(em, efaa[0], efaa[1], eed); // XXX == 0); /*do nothing*/ -// else{ - measure = measure_facepair(v1, v2, v3, v4, limit); - if(measure < limit){ - complexedges++; - eed->f1 |= T2QCOMPLEX; - eed->crease = measure; /*we dont mark edges for join yet*/ - } -// } - } - } - } - } - - /*Quicksort the complex edges according to their weighting*/ - if(complexedges){ - edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array"); - for(eed = em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QCOMPLEX){ - *edb = eed; - edb++; - } - } - qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp); - /*now go through and mark the edges who get the highest weighting*/ - for(edb=edsortblock, i=0; i < complexedges; edb++, i++){ - efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/ - if( !efaa[0]->f1 && !efaa[1]->f1){ - efaa[0]->f1 = 1; //mark for join - efaa[1]->f1 = 1; //mark for join - (*edb)->f1 |= T2QJOIN; - } - } - } - - /*finally go through all edges marked for join (simple and complex) and create new faces*/ - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QJOIN){ - efaa= (EVPtr *)eed->tmp.p; - v1 = v2 = v3 = v4 = NULL; - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/ - /*flag for delete*/ - eed->f1 |= T2QDELETE; - /*create new quad and select*/ - efa = EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]); - EM_select_face(efa,1); - } - else{ - efaa[0]->f1 = 0; - efaa[1]->f1 = 0; - } - } - } - } - - /*free data and cleanup*/ - if(creases){ - for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i]; - MEM_freeN(creases); - } - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f1 & T2QDELETE) eed->f1 = 1; - else eed->f1 = 0; - } - free_tagged_edges_faces(em, em->edges.first, em->faces.first); - if(efaar) MEM_freeN(efaar); - if(edsortblock) MEM_freeN(edsortblock); - - EM_selectmode_flush(em); - -} -/* ******************** END TRIANGLE TO QUAD ************************************* */ - -#define FACE_MARKCLEAR(f) (f->f1 = 1) - -/* quick hack, basically a copy of beautify_fill */ -static void edge_flip(EditMesh *em) -{ - EditVert *v1, *v2, *v3, *v4; - EditEdge *eed, *nexted; - EditFace *efa, *w; - //void **efaar, **efaa; - EVPTuple *efaar; - EVPtr *efaa; - int totedge, ok, vindex[4]; - - /* - all selected edges with two faces - * - find the faces: store them in edges (using datablock) - * - per edge: - test convex - * - test edge: flip? - - if true: remedge, addedge, all edges at the edge get new face pointers - */ - - EM_selectmode_flush(em); // makes sure in selectmode 'face' the edges of selected faces are selected too - - totedge = count_selected_edges(em->edges.first); - if(totedge==0) return; - - /* temporary array for : edge -> face[1], face[2] */ - efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip"); - - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - - eed= em->edges.first; - while(eed) { - nexted= eed->next; - - if(eed->f2==2) { /* points to 2 faces */ - - efaa= (EVPtr *) eed->tmp.p; - - /* don't do it if flagged */ - - ok= 1; - efa= efaa[0]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - efa= efaa[1]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - - if(ok) { - /* test convex */ - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - -/* - 4-----3 4-----3 - |\ | | /| - | \ 1 | | 1 / | - | \ | -> | / | - | 0 \ | | / 0 | - | \| |/ | - 1-----2 1-----2 -*/ - /* make new faces */ - if (v1 && v2 && v3) { - if( convex(v1->co, v2->co, v3->co, v4->co) ) { - if(exist_face(em, v1, v2, v3, v4)==0) { - /* outch this may break seams */ - w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], - vindex[1], 4+vindex[2], -1); - - EM_select_face(w, 1); - - /* outch this may break seams */ - w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], - 4+vindex[2], 4+vindex[3], -1); - - EM_select_face(w, 1); - } - /* tag as to-be-removed */ - FACE_MARKCLEAR(efaa[1]); - FACE_MARKCLEAR(efaa[0]); - eed->f1 = 1; - - } /* endif test convex */ - } - } - } - eed= nexted; - } - - /* clear tagged edges and faces: */ - free_tagged_edges_faces(em, em->edges.first, em->faces.first); - - MEM_freeN(efaar); -} - -#define DIRECTION_CW 1 -#define DIRECTION_CCW 2 - -static const EnumPropertyItem direction_items[]= { - {DIRECTION_CW, "CW", 0, "Clockwise", ""}, - {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""}, - {0, NULL, 0, NULL, NULL}}; - -#define AXIS_X 1 -#define AXIS_Y 2 - -static const EnumPropertyItem axis_items_xy[]= { - {AXIS_X, "X", 0, "X", ""}, - {AXIS_Y, "Y", 0, "Y", ""}, - {0, NULL, 0, NULL, NULL}}; - -static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir) -{ - EditVert **verts[2]; - EditFace *face[2], *efa, *newFace[2]; - EditEdge **edges[2], **hiddenedges, *srchedge; - int facecount, p1, p2, p3, p4, fac1, fac2, i, j; - int numhidden, numshared, p[2][4]; - - /* check to make sure that the edge is only part of 2 faces */ - facecount = 0; - for(efa = em->faces.first;efa;efa = efa->next) { - if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) { - if(facecount >= 2) { - /* more than two faces with this edge */ - return; - } - else { - face[facecount] = efa; - facecount++; - } - } - } - - if(facecount < 2) - return; - - /* how many edges does each face have */ - if(face[0]->e4) fac1= 4; - else fac1= 3; - - if(face[1]->e4) fac2= 4; - else fac2= 3; - - /* make a handy array for verts and edges */ - verts[0]= &face[0]->v1; - edges[0]= &face[0]->e1; - verts[1]= &face[1]->v1; - edges[1]= &face[1]->e1; - - /* we don't want to rotate edges between faces that share more than one edge */ - numshared= 0; - for(i=0; i<fac1; i++) - for(j=0; j<fac2; j++) - if (edges[0][i] == edges[1][j]) - numshared++; - - if(numshared > 1) - return; - - /* we want to construct an array of vertex indicis in both faces, starting at - the last vertex of the edge being rotated. - - first we find the two vertices that lie on the rotating edge - - then we make sure they are ordered according to the face vertex order - - and then we construct the array */ - p1= p2= p3= p4= 0; - - for(i=0; i<4; i++) { - if(eed->v1 == verts[0][i]) p1 = i; - if(eed->v2 == verts[0][i]) p2 = i; - if(eed->v1 == verts[1][i]) p3 = i; - if(eed->v2 == verts[1][i]) p4 = i; - } - - if((p1+1)%fac1 == p2) - SWAP(int, p1, p2); - if((p3+1)%fac2 == p4) - SWAP(int, p3, p4); - - for (i = 0; i < 4; i++) { - p[0][i]= (p1 + i)%fac1; - p[1][i]= (p3 + i)%fac2; - } - - /* create an Array of the Edges who have h set prior to rotate */ - numhidden = 0; - for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next) - if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT))) - numhidden++; - - hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts"); - if(!hiddenedges) { - BKE_report(op->reports, RPT_ERROR, "Memory allocation failed"); - return; - } - - numhidden = 0; - for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) - if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT)) - hiddenedges[numhidden++] = srchedge; - - /* create the 2 new faces */ - if(fac1 == 3 && fac2 == 3) { - /* no need of reverse setup */ - - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); - } - else if(fac1 == 4 && fac2 == 3) { - if(dir == DIRECTION_CCW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1); - } else if (dir == DIRECTION_CW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]); - newFace[1]= EM_face_from_faces(em, face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1); - - verts[0][p[0][2]]->f |= SELECT; - verts[1][p[1][1]]->f |= SELECT; - } - } - else if(fac1 == 3 && fac2 == 4) { - if(dir == DIRECTION_CCW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == DIRECTION_CW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]); - - verts[0][p[0][1]]->f |= SELECT; - verts[1][p[1][2]]->f |= SELECT; - } - - } - else if(fac1 == 4 && fac2 == 4) { - if(dir == DIRECTION_CCW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == DIRECTION_CW) { - newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]); - newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]); - - verts[0][p[0][2]]->f |= SELECT; - verts[1][p[1][2]]->f |= SELECT; - } - } - else - return; /* This should never happen */ - - if(dir == DIRECTION_CCW || (fac1 == 3 && fac2 == 3)) { - verts[0][p[0][1]]->f |= SELECT; - verts[1][p[1][1]]->f |= SELECT; - } - - /* copy old edge's flags to new center edge*/ - for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) { - if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) { - srchedge->f = eed->f; - srchedge->h = eed->h; - srchedge->dir = eed->dir; - srchedge->seam = eed->seam; - srchedge->crease = eed->crease; - srchedge->bweight = eed->bweight; - } - } - - /* resetting hidden flag */ - for(numhidden--; numhidden>=0; numhidden--) - hiddenedges[numhidden]->h= 1; - - /* check for orhphan edges */ - for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next) - srchedge->f1= -1; - - /* cleanup */ - MEM_freeN(hiddenedges); - - /* get rid of the old edge and faces*/ - remedge(em, eed); - free_editedge(em, eed); - BLI_remlink(&em->faces, face[0]); - free_editface(em, face[0]); - BLI_remlink(&em->faces, face[1]); - free_editface(em, face[1]); -} - -/* only accepts 1 selected edge, or 2 selected faces */ -static int edge_rotate_selected(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditEdge *eed; - EditFace *efa; - int dir = RNA_enum_get(op->ptr, "direction"); // dir == 2 when clockwise and ==1 for counter CW. - short edgeCount = 0; - - /*clear new flag for new edges, count selected edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2 &= ~2; - if(eed->f & SELECT) edgeCount++; - } - - if(edgeCount>1) { - /* more selected edges, check faces */ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - edgeCount= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1==2) edgeCount++; - } - if(edgeCount==1) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f1==2) { - edge_rotate(em, op, eed,dir); - break; - } - } - } - else - { - BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - } - else if(edgeCount==1) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - EM_select_edge(eed, 0); - edge_rotate(em, op, eed,dir); - break; - } - } - } - else { - BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - /* flush selected vertices (again) to edges/faces */ - EM_select_flush(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_edge_rotate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Rotate Selected Edge"; - ot->description= "Rotate selected edge or adjoining faces"; - ot->idname= "MESH_OT_edge_rotate"; - - /* api callbacks */ - ot->exec= edge_rotate_selected; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around."); -} - - -/******************* BEVEL CODE STARTS HERE ********************/ - - /* XXX old bevel not ported yet */ - -static void bevel_menu(EditMesh *em) -{ - BME_Mesh *bm; - BME_TransData_Head *td; -// TransInfo *t; - int options, res, gbm_free = 0; - -// t = BIF_GetTransInfo(); - if (!G.editBMesh) { - G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh"); - gbm_free = 1; - } - - G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT; - G.editBMesh->res = 1; - - while(G.editBMesh->options & BME_BEVEL_RUNNING) { - options = G.editBMesh->options; - res = G.editBMesh->res; - bm = BME_editmesh_to_bmesh(em); -// BIF_undo_push("Pre-Bevel"); - free_editMesh(em); - BME_bevel(bm,0.1f,res,options,0,0,&td); - BME_bmesh_to_editmesh(bm, td, em); - EM_selectmode_flush(em); - G.editBMesh->bm = bm; - G.editBMesh->td = td; -// initTransform(TFM_BEVEL,CTX_BMESH); -// Transform(); - BME_free_transdata(td); - BME_free_mesh(bm); -// if (t->state != TRANS_CONFIRM) { -// BIF_undo(); -// } - if (options == G.editBMesh->options) { - G.editBMesh->options &= ~BME_BEVEL_RUNNING; - } - } - - if (gbm_free) { - MEM_freeN(G.editBMesh); - G.editBMesh = NULL; - } -} - - -/* *********** END BEVEL *********/ - -/* this utility function checks to see if 2 edit edges share a face, -returns 1 if they do -returns 0 if they do not, or if the function is passed the same edge 2 times -*/ -short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2) -{ - EditFace *search=NULL; - - search = em->faces.first; - if (e1 == e2){ - return 0 ; - } - while(search){ - if( - ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) && - ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2)) - ) { - return 1; - } - search = search->next; - } - return 0; -} - -#if 0 - -typedef struct SlideUv { - float origuv[2]; - float *uv_up, *uv_down; - //float *fuv[4]; - LinkNode *fuv_list; -} SlideUv; - -typedef struct SlideVert { - EditEdge *up,*down; - EditVert origvert; -} SlideVert; - -int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc) -{ - return 0; -/* XXX REFACTOR - #if 0'd for now, otherwise can't make 64bit windows builds on 64bit machine */ -useless: - goto useless // because it doesn't do anything right now - -// NumInput num; XXX - Mesh *me= NULL; // XXX - EditFace *efa; - EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; - EditVert *ev, *nearest; - LinkNode *edgelist = NULL, *vertlist=NULL, *look; - GHash *vertgh; - - SlideVert *tempsv; - float perc = 0, percp = 0,vertdist; // XXX, projectMat[4][4]; - float shiftlabda= 0.0f,len = 0.0f; - int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0; - int wasshift = 0; - - /* UV correction vars */ - GHash **uvarray= NULL; - int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); - int uvlay_idx; - SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; - float uv_tmp[2]; - LinkNode *fuv_link; - - short event, draw=1; - int mval[2], mvalo[2]; - char str[128]; - float labda = 0.0f; - -// initNumInput(&num); - -// view3d_get_object_project_mat(curarea, obedit, projectMat); - - mvalo[0] = -1; mvalo[1] = -1; - numsel =0; - - // Get number of selected edges and clear some flags - for(eed=em->edges.first;eed;eed=eed->next) { - eed->f1 = 0; - eed->f2 = 0; - if(eed->f & SELECT) numsel++; - } - - for(ev=em->verts.first;ev;ev=ev->next) { - ev->f1 = 0; - } - - //Make sure each edge only has 2 faces - // make sure loop doesn't cross face - for(efa=em->faces.first;efa;efa=efa->next) { - int ct = 0; - if(efa->e1->f & SELECT) { - ct++; - efa->e1->f1++; - if(efa->e1->f1 > 2) { - BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - return 0; - } - } - if(efa->e2->f & SELECT) { - ct++; - efa->e2->f1++; - if(efa->e2->f1 > 2) { - BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - return 0; - } - } - if(efa->e3->f & SELECT) { - ct++; - efa->e3->f1++; - if(efa->e3->f1 > 2) { - BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - return 0; - } - } - if(efa->e4 && efa->e4->f & SELECT) { - ct++; - efa->e4->f1++; - if(efa->e4->f1 > 2) { - BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - return 0; - } - } - // Make sure loop is not 2 edges of same face - if(ct > 1) { - BKE_report(op->reports, RPT_ERROR, "Loop crosses itself"); - return 0; - } - } - // Get # of selected verts - for(ev=em->verts.first;ev;ev=ev->next) { - if(ev->f & SELECT) vertsel++; - } - - // Test for multiple segments - if(vertsel > numsel+1) { - BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop"); - return 0; - } - - // Get the edgeloop in order - mark f1 with SELECT once added - for(eed=em->edges.first;eed;eed=eed->next) { - if((eed->f & SELECT) && !(eed->f1 & SELECT)) { - // If this is the first edge added, just put it in - if(!edgelist) { - BLI_linklist_prepend(&edgelist,eed); - numadded++; - first = eed; - last = eed; - eed->f1 = SELECT; - } else { - if(editedge_getSharedVert(eed, last)) { - BLI_linklist_append(&edgelist,eed); - eed->f1 = SELECT; - numadded++; - last = eed; - } else if(editedge_getSharedVert(eed, first)) { - BLI_linklist_prepend(&edgelist,eed); - eed->f1 = SELECT; - numadded++; - first = eed; - } - } - } - if(eed->next == NULL && numadded != numsel) { - eed=em->edges.first; - timesthrough++; - } - - // It looks like there was an unexpected case - Hopefully should not happen - if(timesthrough >= numsel*2) { - BLI_linklist_free(edgelist,NULL); - BKE_report(op->reports, RPT_ERROR, "Could not order loop"); - return 0; - } - } - - // Put the verts in order in a linklist - look = edgelist; - while(look) { - eed = look->link; - if(!vertlist) { - if(look->next) { - temp = look->next->link; - - //This is the first entry takes care of extra vert - if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } else { - BLI_linklist_append(&vertlist,eed->v2); - eed->v2->f1 = 1; - } - } else { - //This is the case that we only have 1 edge - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } - } - // for all the entries - if(eed->v1->f1 != 1) { - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } else if(eed->v2->f1 != 1) { - BLI_linklist_append(&vertlist,eed->v2); - eed->v2->f1 = 1; - } - look = look->next; - } - - // populate the SlideVerts - - vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlide gh"); - look = vertlist; - while(look) { - i=0; - j=0; - ev = look->link; - tempsv = (struct SlideVert*)MEM_mallocN(sizeof(struct SlideVert),"SlideVert"); - tempsv->up = NULL; - tempsv->down = NULL; - tempsv->origvert.co[0] = ev->co[0]; - tempsv->origvert.co[1] = ev->co[1]; - tempsv->origvert.co[2] = ev->co[2]; - tempsv->origvert.no[0] = ev->no[0]; - tempsv->origvert.no[1] = ev->no[1]; - tempsv->origvert.no[2] = ev->no[2]; - // i is total edges that vert is on - // j is total selected edges that vert is on - - for(eed=em->edges.first;eed;eed=eed->next) { - if(eed->v1 == ev || eed->v2 == ev) { - i++; - if(eed->f & SELECT) { - j++; - } - } - } - // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges - if(i == 4 && j == 2) { - for(eed=em->edges.first;eed;eed=eed->next) { - if(editedge_containsVert(eed, ev)) { - if(!(eed->f & SELECT)) { - if(!tempsv->up) { - tempsv->up = eed; - } else if (!(tempsv->down)) { - tempsv->down = eed; - } - } - } - } - } - // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected - if(i >= 3 && j == 1) { - for(eed=em->edges.first;eed;eed=eed->next) { - if(editedge_containsVert(eed, ev) && eed->f & SELECT) { - for(efa = em->faces.first;efa;efa=efa->next) { - if(editface_containsEdge(efa, eed)) { - if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e1; - } else if (!(tempsv->down)) { - tempsv->down = efa->e1; - } - } - if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e2; - } else if (!(tempsv->down)) { - tempsv->down = efa->e2; - } - } - if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e3; - } else if (!(tempsv->down)) { - tempsv->down = efa->e3; - } - } - if(efa->e4) { - if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e4; - } else if (!(tempsv->down)) { - tempsv->down = efa->e4; - } - } - } - - } - } - } - } - } - if(i > 4 && j == 2) { - BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(vertlist,NULL); - BLI_linklist_free(edgelist,NULL); - return 0; - } - BLI_ghash_insert(vertgh,ev,tempsv); - - look = look->next; - } - - // make sure the UPs nad DOWNs are 'faceloops' - // Also find the nearest slidevert to the cursor -// XXX getmouseco_areawin(mval); - look = vertlist; - nearest = NULL; - vertdist = -1; - while(look) { - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); - - if(!tempsv->up || !tempsv->down) { - BKE_report(op->reports, RPT_ERROR, "Missing rails"); - BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(vertlist,NULL); - BLI_linklist_free(edgelist,NULL); - return 0; - } - - if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { - if(!(tempsv->up->f & SELECT)) { - tempsv->up->f |= SELECT; - tempsv->up->f2 |= 16; - } else { - tempsv->up->f2 |= ~16; - } - if(!(tempsv->down->f & SELECT)) { - tempsv->down->f |= SELECT; - tempsv->down->f2 |= 16; - } else { - tempsv->down->f2 |= ~16; - } - } - - if(look->next != NULL) { - SlideVert *sv; - - sv = BLI_ghash_lookup(vertgh,(EditVert*)look->next->link); - - if(sv) { - float tempdist, co[2]; - - if(!sharesFace(em, tempsv->up,sv->up)) { - EditEdge *swap; - swap = sv->up; - sv->up = sv->down; - sv->down = swap; - } - -// view3d_project_float(curarea, tempsv->origvert.co, co, projectMat); - - tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2)); - - if(vertdist < 0) { - vertdist = tempdist; - nearest = (EditVert*)look->link; - } else if ( tempdist < vertdist ) { - vertdist = tempdist; - nearest = (EditVert*)look->link; - } - } - } - - - - look = look->next; - } - - - if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { - int maxnum = 0; - uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); - suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(SlideUv), "SlideUVs"); /* uvLayers * verts */ - suv = NULL; - - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - - uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlideUV gh"); - - for(ev=em->verts.first;ev;ev=ev->next) { - ev->tmp.l = 0; - } - look = vertlist; - while(look) { - float *uv_new; - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); - - ev = look->link; - suv = NULL; - for(efa = em->faces.first;efa;efa=efa->next) { - if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ - int k=-1; /* face corner */ - - /* Is this vert in the faces corner? */ - if (efa->v1==ev) k=0; - else if (efa->v2==ev) k=1; - else if (efa->v3==ev) k=2; - else if (efa->v4 && efa->v4==ev) k=3; - - if (k != -1) { - MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); - EditVert *ev_up, *ev_down; - - uv_new = tf->uv[k]; - - if (ev->tmp.l) { - if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) { - ev->tmp.l = -1; /* Tag as invalid */ - BLI_linklist_free(suv->fuv_list,NULL); - suv->fuv_list = NULL; - BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); - suv = NULL; - break; - } - } else { - ev->tmp.l = 1; - suv = suv_last; - - suv->fuv_list = NULL; - suv->uv_up = suv->uv_down = NULL; - suv->origuv[0] = uv_new[0]; - suv->origuv[1] = uv_new[1]; - - BLI_linklist_prepend(&suv->fuv_list, uv_new); - BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); - - suv_last++; /* advance to next slide UV */ - maxnum++; - } - - /* Now get the uvs along the up or down edge if we can */ - if (suv) { - if (!suv->uv_up) { - ev_up = editedge_getOtherVert(tempsv->up,ev); - if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; - else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; - else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; - else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; - } - if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ - ev_down = editedge_getOtherVert(tempsv->down,ev); - if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; - else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; - else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; - else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; - } - - /* Copy the pointers to the face UV's */ - BLI_linklist_prepend(&suv->fuv_list, uv_new); - } - } - } - } - look = look->next; - } - } /* end uv layer loop */ - } /* end uvlay_tot */ - - - - // we should have enough info now to slide - - len = 0.0f; - - percp = -1; - while(draw) { - /* For the % calculation */ - int mval[2]; - float rc[2]; - float v2[2], v3[2]; - EditVert *centerVert, *upVert, *downVert; - -// XXX getmouseco_areawin(mval); - - if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) { - PIL_sleep_ms(10); - } else { - char *p = str; - int ctrl= 0, shift= 0; // XXX - - mvalo[0] = mval[0]; - mvalo[1] = mval[1]; - - - tempsv = BLI_ghash_lookup(vertgh,nearest); - - centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); - upVert = editedge_getOtherVert(tempsv->up, centerVert); - downVert = editedge_getOtherVert(tempsv->down, centerVert); - -// view3d_project_float(curarea, upVert->co, v2, projectMat); -// view3d_project_float(curarea, downVert->co, v3, projectMat); - - /* Determine the % on which the loop should be cut */ - - rc[0]= v3[0]-v2[0]; - rc[1]= v3[1]-v2[1]; - len= rc[0]*rc[0]+ rc[1]*rc[1]; - if (len==0) {len = 0.0001;} - - if (shift) { - wasshift = 0; - labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len; - } - else { - if (wasshift==0) { - wasshift = 1; - shiftlabda = labda; - } - labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda; - } - - - if(labda<=0.0) labda=0.0; - else if(labda>=1.0)labda=1.0; - - perc=((1-labda)*2)-1; - - if(shift == 0 && ctrl==0) { - perc *= 100; - perc = floor(perc); - perc /= 100; - } else if (ctrl) { - perc *= 10; - perc = floor(perc); - perc /= 10; - } - - if(prop == 0) { - len = len_v3v3(upVert->co,downVert->co)*((perc+1)/2); - if(flip == 1) { - len = len_v3v3(upVert->co,downVert->co) - len; - } - } - - if (0) // XXX hasNumInput(&num)) - { -// XXX applyNumInput(&num, &perc); - - if (prop) - { - perc = MIN2(perc, 1); - perc = MAX2(perc, -1); - } - else - { - len = MIN2(perc, len_v3v3(upVert->co,downVert->co)); - len = MAX2(len, 0); - } - } - - //Adjust Edgeloop - if(immediate) { - perc = imperc; - } - percp = perc; - if(prop) { - look = vertlist; - while(look) { - EditVert *tempev; - ev = look->link; - tempsv = BLI_ghash_lookup(vertgh,ev); - - tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); - interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); - - if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - - look = look->next; - } - } - else { - //Non prop code - look = vertlist; - while(look) { - float newlen; - ev = look->link; - tempsv = BLI_ghash_lookup(vertgh,ev); - newlen = (len / len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co)); - if(newlen > 1.0) {newlen = 1.0;} - if(newlen < 0.0) {newlen = 0.0;} - if(flip == 0) { - interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); - if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - /* dont do anything if no UVs */ - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - } else{ - interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); - - if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - /* dont do anything if no UVs */ - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - } - look = look->next; - } - - } - - // Highlight the Control Edges -// scrarea_do_windraw(curarea); -// persp(PERSP_VIEW); -// glPushMatrix(); -// mymultmatrix(obedit->obmat); - - glColor3ub(0, 255, 0); - glBegin(GL_LINES); - glVertex3fv(upVert->co); - glVertex3fv(downVert->co); - glEnd(); - - if(prop == 0) { - // draw start edge for non-prop - glPointSize(5); - glBegin(GL_POINTS); - glColor3ub(255,0,255); - if(flip) { - glVertex3fv(upVert->co); - } else { - glVertex3fv(downVert->co); - } - glEnd(); - } - - - glPopMatrix(); - - if(prop) { - p += sprintf(str, "(P)ercentage: "); - } else { - p += sprintf(str, "Non (P)rop Length: "); - } - - if (0) // XXX hasNumInput(&num)) - { - char num_str[20]; - - // XX outputNumInput(&num, num_str); - p += sprintf(p, "%s", num_str); - } - else - { - if (prop) - { - p += sprintf(p, "%f", perc); - } - else - { - p += sprintf(p, "%f", len); - } - } - - - if (prop == 0) { - p += sprintf(p, ", Press (F) to flip control side"); - } - -// headerprint(str); -// screen_swapbuffers(); - } - if(!immediate) { - while(qtest()) { - short val=0; - event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle - - /* val==0 on key-release event */ - if (val) { - if(ELEM(event, ESCKEY, RIGHTMOUSE)) { - prop = 1; // Go back to prop mode - imperc = 0; // This is the % that gets set for immediate - immediate = 1; //Run through eval code 1 more time - cancel = 1; // Return -1 - mvalo[0] = -1; - } else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) { - draw = 0; // End looping now - } else if(event==MIDDLEMOUSE) { - perc = 0; - immediate = 1; - } else if(event==PKEY) { -// XXX initNumInput(&num); /* reset num input */ - if (prop) { - prop = 0; -// XXX num.flag |= NUM_NO_NEGATIVE; - } - else { - prop = 1; - } - mvalo[0] = -1; - } else if(event==FKEY) { - (flip == 1) ? (flip = 0):(flip = 1); - mvalo[0] = -1; - } else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges - look = vertlist; - while(look) { - if(nearest == (EditVert*)look->link) { - if(look->next == NULL) { - nearest = (EditVert*)vertlist->link; - } else { - nearest = (EditVert*)look->next->link; - } - mvalo[0] = -1; - break; - } - look = look->next; - } - } else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges - look = vertlist; - while(look) { - if(look->next) { - if(look->next->link == nearest) { - nearest = (EditVert*)look->link; - mvalo[0] = -1; - break; - } - } else { - if((EditVert*)vertlist->link == nearest) { - nearest = look->link; - mvalo[0] = -1; - break; - } - } - look = look->next; - } - } - -// XXX if (handleNumInput(&num, event)) - { - mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */ - } - } - - } - } else { - draw = 0; - } -// DAG_id_tag_update(obedit->data, 0); - } - - - if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { - look = vertlist; - while(look) { - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); - if(tempsv != NULL) { - tempsv->up->f &= !SELECT; - tempsv->down->f &= !SELECT; - } - look = look->next; - } - } - -// force_draw(0); - - if(!immediate) - EM_automerge(0); -// DAG_id_tag_update(obedit->data, 0); -// scrarea_queue_winredraw(curarea); - - //BLI_ghash_free(edgesgh, freeGHash, NULL); - BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(vertlist,NULL); - BLI_linklist_free(edgelist,NULL); - - if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - BLI_ghash_free(uvarray[uvlay_idx], NULL, NULL); - } - MEM_freeN(uvarray); - MEM_freeN(slideuvs); - - suv = suv_last-1; - while (suv >= slideuvs) { - if (suv->fuv_list) { - BLI_linklist_free(suv->fuv_list,NULL); - } - suv--; - } - } - - if(cancel == 1) { - return -1; - } - - return 1; -} -#endif // END OF XXX - -int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op)) -{ -#if 0 //XXX won't work with new edgeslide - - /* temporal flag setting so we keep UVs when deleting edge loops, - * this is a bit of a hack but it works how you would want in almost all cases */ - // short uvcalc_flag_orig = 0; // XXX scene->toolsettings->uvcalc_flag; - // scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT; - - if(!EdgeSlide(em, op, 1, 1)) { - return 0; - } - - /* restore uvcalc flag */ - // scene->toolsettings->uvcalc_flag = uvcalc_flag_orig; - - EM_select_more(em); - removedoublesflag(em, 1,0, 0.001); - EM_select_flush(em); - // DAG_id_tag_update(obedit->data, 0); - return 1; -#endif - return 0; -} - - -/* -------------------- More tools ------------------ */ -#if 0 -void mesh_set_face_flags(EditMesh *em, short mode) -{ - EditFace *efa; - MTFace *tface; - short m_tex=0, m_shared=0, - m_light=0, m_invis=0, m_collision=0, - m_twoside=0, m_obcolor=0, m_halo=0, - m_billboard=0, m_shadow=0, m_text=0, - m_sort=0; - short flag = 0, change = 0; - -// XXX if (!EM_texFaceCheck()) { -// error("not a mesh with uv/image layers"); -// return; -// } - - add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL); - add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL); - add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL); - add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL); - add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL); - add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL); - add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL); - add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL); - add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL); - add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL); - add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL); - add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL); - - if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW)) - return; - - /* these 2 cant both be on */ - if (mode) /* are we seeting*/ - if (m_halo) - m_billboard = 0; - - if (m_tex) flag |= TF_TEX; - if (m_shared) flag |= TF_SHAREDCOL; - if (m_light) flag |= TF_LIGHT; - if (m_invis) flag |= TF_INVISIBLE; - if (m_collision) flag |= TF_DYNAMIC; - if (m_twoside) flag |= TF_TWOSIDE; - if (m_obcolor) flag |= TF_OBCOL; - if (m_halo) flag |= TF_BILLBOARD; - if (m_billboard) flag |= TF_BILLBOARD2; - if (m_shadow) flag |= TF_SHADOW; - if (m_text) flag |= TF_BMFONT; - if (m_sort) flag |= TF_ALPHASORT; - - if (flag==0) - return; - - efa= em->faces.first; - while(efa) { - if(efa->f & SELECT) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (mode) tface->mode |= flag; - else tface->mode &= ~flag; - change = 1; - } - efa= efa->next; - } - -} -#endif - -/********************** Rip Operator *************************/ - -/* helper to find edge for edge_rip */ -static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const int mval[2]) -{ - float vec1[3], vec2[3], mvalf[2]; - - ED_view3d_project_float(ar, co1, vec1, mat); - ED_view3d_project_float(ar, co2, vec2, mat); - mvalf[0]= (float)mval[0]; - mvalf[1]= (float)mval[1]; - - return dist_to_line_segment_v2(mvalf, vec1, vec2); -} - -/* helper for below */ -static void mesh_rip_setface(EditMesh *em, EditFace *sefa) -{ - /* put new vertices & edges in best face */ - if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v; - if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v; - if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v; - if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v; - - sefa->e1= addedgelist(em, sefa->v1, sefa->v2, sefa->e1); - sefa->e2= addedgelist(em, sefa->v2, sefa->v3, sefa->e2); - if(sefa->v4) { - sefa->e3= addedgelist(em, sefa->v3, sefa->v4, sefa->e3); - sefa->e4= addedgelist(em, sefa->v4, sefa->v1, sefa->e4); - } - else - sefa->e3= addedgelist(em, sefa->v3, sefa->v1, sefa->e3); - -} - -/* based on mouse cursor position, it defines how is being ripped */ -static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - ARegion *ar= CTX_wm_region(C); - RegionView3D *rv3d= ar->regiondata; - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditVert *eve, *nextve; - EditEdge *eed, *seed= NULL; - EditFace *efa, *sefa= NULL; - float projectMat[4][4], vec[3], dist, mindist; - short doit= 1; - int *mval= event->mval; - - /* select flush... vertices are important */ - EM_selectmode_set(em); - - ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); - - /* find best face, exclude triangles and break on face select or faces with 2 edges select */ - mindist= 1000000.0f; - for(efa= em->faces.first; efa; efa=efa->next) { - if( efa->f & 1) - break; - if(efa->v4 && faceselectedOR(efa, SELECT) ) { - int totsel=0; - - if(efa->e1->f & SELECT) totsel++; - if(efa->e2->f & SELECT) totsel++; - if(efa->e3->f & SELECT) totsel++; - if(efa->e4->f & SELECT) totsel++; - - if(totsel>1) - break; - ED_view3d_project_float(ar, efa->cent, vec, projectMat); - dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) ); - if(dist<mindist) { - mindist= dist; - sefa= efa; - } - } - } - - if(efa) { - BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - if(sefa==NULL) { - BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - - /* duplicate vertices, new vertices get selected */ - for(eve = em->verts.last; eve; eve= eve->prev) { - eve->tmp.v = NULL; - if(eve->f & SELECT) { - eve->tmp.v = addvertlist(em, eve->co, eve); - eve->f &= ~SELECT; - eve->tmp.v->f |= SELECT; - } - } - - /* find the best candidate edge */ - /* or one of sefa edges is selected... */ - if(sefa->e1->f & SELECT) seed= sefa->e2; - if(sefa->e2->f & SELECT) seed= sefa->e1; - if(sefa->e3->f & SELECT) seed= sefa->e2; - if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3; - - /* or we do the distance trick */ - if(seed==NULL) { - mindist= 1000000.0f; - if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) { - dist = mesh_rip_edgedist(ar, projectMat, - sefa->e1->v1->co, - sefa->e1->v2->co, mval); - if(dist<mindist) { - seed= sefa->e1; - mindist= dist; - } - } - if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) { - dist = mesh_rip_edgedist(ar, projectMat, - sefa->e2->v1->co, - sefa->e2->v2->co, mval); - if(dist<mindist) { - seed= sefa->e2; - mindist= dist; - } - } - if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) { - dist= mesh_rip_edgedist(ar, projectMat, - sefa->e3->v1->co, - sefa->e3->v2->co, mval); - if(dist<mindist) { - seed= sefa->e3; - mindist= dist; - } - } - if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) { - dist= mesh_rip_edgedist(ar, projectMat, - sefa->e4->v1->co, - sefa->e4->v2->co, mval); - if(dist<mindist) { - seed= sefa->e4; - mindist= dist; - } - } - } - - if(seed==NULL) { // never happens? - BKE_report(op->reports, RPT_WARNING, "No proper edge found to start"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1 - - /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */ - for(eed = em->edges.last; eed; eed= eed->prev) { - eed->tmp.v = NULL; - if((eed->v1->tmp.v) || (eed->v2->tmp.v)) { - EditEdge *newed; - - newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1, - eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed); - if(eed->f & SELECT) { - EM_select_edge(eed, 0); - EM_remove_selection(em, eed, EDITEDGE); - EM_select_edge(newed, 1); - } - eed->tmp.v = (EditVert *)newed; - } - } - - /* first clear edges to help finding neighbours */ - for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; - - /* put new vertices & edges && flag in best face */ - mesh_rip_setface(em, sefa); - - /* starting with neighbours of best face, we loop over the seam */ - sefa->f1= 2; - doit= 1; - while(doit) { - doit= 0; - - for(efa= em->faces.first; efa; efa=efa->next) { - /* new vert in face */ - if (efa->v1->tmp.v || efa->v2->tmp.v || - efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) { - /* face is tagged with loop */ - if(efa->f1==1) { - mesh_rip_setface(em, efa); - efa->f1= 2; - doit= 1; - } - } - } - } - - /* remove loose edges, that were part of a ripped face */ - for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0; - for(efa= em->faces.first; efa; efa=efa->next) { - efa->e1->f1= 1; - efa->e2->f1= 1; - efa->e3->f1= 1; - if(efa->e4) efa->e4->f1= 1; - } - - for(eed = em->edges.last; eed; eed= seed) { - seed= eed->prev; - if(eed->f1==0) { - if(eed->v1->tmp.v || eed->v2->tmp.v || - (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) { - remedge(em, eed); - free_editedge(em, eed); - eed= NULL; - } - } - if(eed) { - eed->v1->f1= 1; - eed->v2->f1= 1; - } - } - - /* and remove loose selected vertices, that got duplicated accidentally */ - for(eve = em->verts.first; eve; eve= nextve) { - nextve= eve->next; - if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) { - BLI_remlink(&em->verts,eve); - free_editvert(em, eve); - } - } - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - -// RNA_enum_set(op->ptr, "proportional", 0); -// RNA_boolean_set(op->ptr, "mirror", 0); -// WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr); - - return OPERATOR_FINISHED; -} - -void MESH_OT_rip(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Rip"; - ot->description= "Rip selection from mesh (quads only)"; - ot->idname= "MESH_OT_rip"; - - /* api callbacks */ - ot->invoke= mesh_rip_invoke; - ot->poll= EM_view3d_poll; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* to give to transform */ - /* XXX Transform this in a macro */ - Transform_Properties(ot, P_CONSTRAINT|P_MIRROR); -} - - -/************************ Shape Operators *************************/ - -static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op) -{ - EditVert *ev = NULL; - Mesh* me = (Mesh*)obedit->data; - Key* ky = NULL; - KeyBlock* kb = NULL; - - - if(me->key){ - ky = me->key; - } else { - BKE_report(op->reports, RPT_WARNING, "Object Has No Key"); - return; - } - - if(ky->block.first){ - for(ev = em->verts.first; ev ; ev = ev->next){ - if(ev->f & SELECT){ - for(kb=ky->block.first;kb;kb = kb->next){ - float *data; - data = kb->data; - VECCOPY(data+(ev->keyindex*3),ev->co); - } - } - } - } else { - BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes"); - return; - } - -#if 0 - //TAG Mesh Objects that share this data - for(base = scene->base.first; base; base = base->next){ - if(base->object && base->object->data == me){ - base->object->recalc = OB_RECALC_DATA; - } - } -#endif - - DAG_id_tag_update(obedit->data, 0); - return; -} - - -static int shape_propagate_to_all_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - - shape_propagate(obedit, em, op); - - DAG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); - - return OPERATOR_FINISHED; -} - - -void MESH_OT_shape_propagate_to_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Shape Propagate"; - ot->description= "Apply selected vertex locations to all other shape keys"; - ot->idname= "MESH_OT_shape_propagate_to_all"; - - /* api callbacks */ - ot->exec= shape_propagate_to_all_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int blend_from_shape_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= obedit->data; - Key *key= me->key; - EditMesh *em= BKE_mesh_get_editmesh(me); - EditVert *eve; - KeyBlock *kb, *refkb= NULL; - float *data, *refdata= NULL, co[3]; - float blend= RNA_float_get(op->ptr, "blend"); - int shape= RNA_enum_get(op->ptr, "shape"); - int add= RNA_boolean_get(op->ptr, "add"); - int blended= 0; - - if(key && (kb= BLI_findlink(&key->block, shape))) { - data= kb->data; - - if(add) { - refkb= BLI_findlink(&key->block, kb->relative); - if(refkb) - refdata = refkb->data; - } - - for(eve=em->verts.first; eve; eve=eve->next){ - if(eve->f & SELECT) { - if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) { - copy_v3_v3(co, data + eve->keyindex*3); - - if(add) { - /* in add mode, we add relative shape key offset */ - if(refdata && eve->keyindex < refkb->totelem) - sub_v3_v3v3(co, co, refdata + eve->keyindex*3); - - madd_v3_v3fl(eve->co, co, blend); - } - else { - /* in blend mode, we interpolate to the shape key */ - interp_v3_v3v3(eve->co, eve->co, co, blend); - } - - blended= 1; - } - } - } - } - - BKE_mesh_end_editmesh(me, em); - - if(!blended) - return OPERATOR_CANCELLED; - - DAG_id_tag_update(&me->id, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); - - return OPERATOR_FINISHED; -} - -static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) -{ - Object *obedit= CTX_data_edit_object(C); - Mesh *me= (obedit) ? obedit->data : NULL; - Key *key; - KeyBlock *kb, *actkb; - EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL; - int totitem= 0, a; - - if(obedit && obedit->type == OB_MESH) { - key= me->key; - actkb= ob_get_keyblock(obedit); - - if(key && actkb) { - for(kb=key->block.first, a=0; kb; kb=kb->next, a++) { - if(kb != actkb) { - tmp.value= a; - tmp.identifier= kb->name; - tmp.name= kb->name; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - } - } - - RNA_enum_item_end(&item, &totitem); - *free= 1; - - return item; -} - -void MESH_OT_blend_from_shape(wmOperatorType *ot) -{ - PropertyRNA *prop; - static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name= "Blend From Shape"; - ot->description= "Blend in shape from a shape key"; - ot->idname= "MESH_OT_blend_from_shape"; - - /* api callbacks */ - ot->exec= blend_from_shape_exec; - ot->invoke= WM_operator_props_popup; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending."); - RNA_def_enum_funcs(prop, shape_itemf); - RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f); - RNA_def_boolean(ot->srna, "add", 0, "Add", "Add rather than blend between shapes."); -} - -/************************ Merge Operator *************************/ - -/* Collection Routines|Currently used by the improved merge code*/ -/* buildEdge_collection() creates a list of lists*/ -/* these lists are filled with edges that are topologically connected.*/ -/* This whole tool needs to be redone, its rather poorly implemented...*/ - -typedef struct Collection{ - struct Collection *next, *prev; - int index; - ListBase collectionbase; -} Collection; - -typedef struct CollectedEdge{ - struct CollectedEdge *next, *prev; - EditEdge *eed; -} CollectedEdge; - -#define MERGELIMIT 0.000001 - -static void build_edgecollection(EditMesh *em, ListBase *allcollections) -{ - EditEdge *eed; - Collection *edgecollection, *newcollection; - CollectedEdge *newedge; - - int currtag = 1; - short ebalanced = 0; - short collectionfound = 0; - - for (eed=em->edges.first; eed; eed = eed->next){ - eed->tmp.l = 0; - eed->v1->tmp.l = 0; - eed->v2->tmp.l = 0; - } - - /*1st pass*/ - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f&SELECT){ - eed->v1->tmp.l = currtag; - eed->v2->tmp.l = currtag; - currtag +=1; - } - } - - /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */ - while(ebalanced == 0){ - ebalanced = 1; - for(eed=em->edges.first; eed; eed = eed->next){ - if(eed->f&SELECT){ - if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{ - if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l; - else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l; - ebalanced = 0; - } - } - } - } - - /*3rd pass, set all the edge flags (unnessecary?)*/ - for(eed=em->edges.first; eed; eed = eed->next){ - if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l; - } - - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f&SELECT){ - if(allcollections->first){ - for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){ - if(edgecollection->index == eed->tmp.l){ - newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); - newedge->eed = eed; - BLI_addtail(&(edgecollection->collectionbase), newedge); - collectionfound = 1; - break; - } - else collectionfound = 0; - } - } - if(allcollections->first == NULL || collectionfound == 0){ - newcollection = MEM_mallocN(sizeof(Collection), "element collection"); - newcollection->index = eed->tmp.l; - newcollection->collectionbase.first = 0; - newcollection->collectionbase.last = 0; - - newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge"); - newedge->eed = eed; - - BLI_addtail(&(newcollection->collectionbase), newedge); - BLI_addtail(allcollections, newcollection); - } - } - - } -} - -static void freecollections(ListBase *allcollections) -{ - struct Collection *curcollection; - - for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next) - BLI_freelistN(&(curcollection->collectionbase)); - BLI_freelistN(allcollections); -} - -/*Begin UV Edge Collapse Code - Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail - 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. - The welded UV edges can then be sorted and collapsed. -*/ -typedef struct wUV{ - struct wUV *next, *prev; - ListBase nodes; - float u, v; /*cached copy of UV coordinates pointed to by nodes*/ - EditVert *eve; - int f; -} wUV; - -typedef struct wUVNode{ - struct wUVNode *next, *prev; - float *u; /*pointer to original tface data*/ - float *v; /*pointer to original tface data*/ -} wUVNode; - -typedef struct wUVEdge{ - struct wUVEdge *next, *prev; - float v1uv[2], v2uv[2]; /*nasty.*/ - struct wUV *v1, *v2; /*oriented same as editedge*/ - EditEdge *eed; - int f; -} wUVEdge; - -typedef struct wUVEdgeCollect{ /*used for grouping*/ - struct wUVEdgeCollect *next, *prev; - wUVEdge *uved; - int id; -} wUVEdgeCollect; - -static void append_weldedUV(EditMesh *em, EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts) -{ - wUV *curwvert, *newwvert; - wUVNode *newnode; - int found; - MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - found = 0; - - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){ - newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); - newnode->u = &(tf->uv[tfindex][0]); - newnode->v = &(tf->uv[tfindex][1]); - BLI_addtail(&(curwvert->nodes), newnode); - found = 1; - break; - } - } - - if(!found){ - newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node"); - newnode->u = &(tf->uv[tfindex][0]); - newnode->v = &(tf->uv[tfindex][1]); - - newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert"); - newwvert->u = *(newnode->u); - newwvert->v = *(newnode->v); - newwvert->eve = eve; - - BLI_addtail(&(newwvert->nodes), newnode); - BLI_addtail(uvverts, newwvert); - - } -} - -static void build_weldedUVs(EditMesh *em, ListBase *uvverts) -{ - EditFace *efa; - for(efa=em->faces.first; efa; efa=efa->next){ - if(efa->v1->f1) append_weldedUV(em, efa, efa->v1, 0, uvverts); - if(efa->v2->f1) append_weldedUV(em, efa, efa->v2, 1, uvverts); - if(efa->v3->f1) append_weldedUV(em, efa, efa->v3, 2, uvverts); - if(efa->v4 && efa->v4->f1) append_weldedUV(em, efa, efa->v4, 3, uvverts); - } -} - -static void append_weldedUVEdge(EditMesh *em, EditFace *efa, EditEdge *eed, ListBase *uvedges) -{ - wUVEdge *curwedge, *newwedge; - int v1tfindex, v2tfindex, found; - MTFace *tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - found = 0; - - if(eed->v1 == efa->v1) v1tfindex = 0; - else if(eed->v1 == efa->v2) v1tfindex = 1; - else if(eed->v1 == efa->v3) v1tfindex = 2; - else /* if(eed->v1 == efa->v4) */ v1tfindex = 3; - - if(eed->v2 == efa->v1) v2tfindex = 0; - else if(eed->v2 == efa->v2) v2tfindex = 1; - else if(eed->v2 == efa->v3) v2tfindex = 2; - else /* if(eed->v2 == efa->v4) */ v2tfindex = 3; - - for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ - 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]){ - found = 1; - break; //do nothing, we don't need another welded uv edge - } - } - - if(!found){ - newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge"); - newwedge->v1uv[0] = tf->uv[v1tfindex][0]; - newwedge->v1uv[1] = tf->uv[v1tfindex][1]; - newwedge->v2uv[0] = tf->uv[v2tfindex][0]; - newwedge->v2uv[1] = tf->uv[v2tfindex][1]; - newwedge->eed = eed; - - BLI_addtail(uvedges, newwedge); - } -} - -static void build_weldedUVEdges(EditMesh *em, ListBase *uvedges, ListBase *uvverts) -{ - wUV *curwvert; - wUVEdge *curwedge; - EditFace *efa; - - for(efa=em->faces.first; efa; efa=efa->next){ - if(efa->e1->f1) append_weldedUVEdge(em, efa, efa->e1, uvedges); - if(efa->e2->f1) append_weldedUVEdge(em, efa, efa->e2, uvedges); - if(efa->e3->f1) append_weldedUVEdge(em, efa, efa->e3, uvedges); - if(efa->e4 && efa->e4->f1) append_weldedUVEdge(em, efa, efa->e4, uvedges); - } - - - //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers - for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){ - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){ - curwedge->v1 = curwvert; - break; - } - } - for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){ - if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){ - curwedge->v2 = curwvert; - break; - } - } - } -} - -static void free_weldedUVs(ListBase *uvverts) -{ - wUV *curwvert; - for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes)); - BLI_freelistN(uvverts); -} - -static void collapse_edgeuvs(EditMesh *em) -{ - ListBase uvedges, uvverts, allcollections; - wUVEdge *curwedge; - wUVNode *curwnode; - wUVEdgeCollect *collectedwuve, *newcollectedwuve; - Collection *wuvecollection, *newcollection; - int curtag, balanced, collectionfound= 0, vcount; - float avg[2]; - - if (!EM_texFaceCheck(em)) - return; - - uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL; - - build_weldedUVs(em, &uvverts); - build_weldedUVEdges(em, &uvedges, &uvverts); - - curtag = 0; - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - curwedge->v1->f = curtag; - curwedge->v2->f = curtag; - curtag +=1; - } - - balanced = 0; - while(!balanced){ - balanced = 1; - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - if(curwedge->v1->f != curwedge->v2->f){ - if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f; - else curwedge->v2->f = curwedge->v1->f; - balanced = 0; - } - } - } - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f; - - - for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){ - if(allcollections.first){ - for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ - if(wuvecollection->index == curwedge->f){ - newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); - newcollectedwuve->uved = curwedge; - BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve); - collectionfound = 1; - break; - } - - else collectionfound = 0; - } - } - if(allcollections.first == NULL || collectionfound == 0){ - newcollection = MEM_callocN(sizeof(Collection), "element collection"); - newcollection->index = curwedge->f; - newcollection->collectionbase.first = 0; - newcollection->collectionbase.last = 0; - - newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge"); - newcollectedwuve->uved = curwedge; - - BLI_addtail(&(newcollection->collectionbase), newcollectedwuve); - BLI_addtail(&allcollections, newcollection); - } - } - - for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){ - - vcount = avg[0] = avg[1] = 0; - - for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ - avg[0] += collectedwuve->uved->v1uv[0]; - avg[1] += collectedwuve->uved->v1uv[1]; - - avg[0] += collectedwuve->uved->v2uv[0]; - avg[1] += collectedwuve->uved->v2uv[1]; - - vcount +=2; - - } - - avg[0] /= vcount; avg[1] /= vcount; - - for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){ - for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){ - *(curwnode->u) = avg[0]; - *(curwnode->v) = avg[1]; - } - for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){ - *(curwnode->u) = avg[0]; - *(curwnode->v) = avg[1]; - } - } - } - - free_weldedUVs(&uvverts); - BLI_freelistN(&uvedges); - freecollections(&allcollections); -} - -/*End UV Edge collapse code*/ - -static void collapseuvs(EditMesh *em, EditVert *mergevert) -{ - EditFace *efa; - MTFace *tf; - int uvcount; - float uvav[2]; - - if (!EM_texFaceCheck(em)) - return; - - uvcount = 0; - uvav[0] = 0; - uvav[1] = 0; - - for(efa = em->faces.first; efa; efa=efa->next){ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(efa->v1->f1 && ELEM(mergevert, NULL, efa->v1)) { - uvav[0] += tf->uv[0][0]; - uvav[1] += tf->uv[0][1]; - uvcount += 1; - } - if(efa->v2->f1 && ELEM(mergevert, NULL, efa->v2)){ - uvav[0] += tf->uv[1][0]; - uvav[1] += tf->uv[1][1]; - uvcount += 1; - } - if(efa->v3->f1 && ELEM(mergevert, NULL, efa->v3)){ - uvav[0] += tf->uv[2][0]; - uvav[1] += tf->uv[2][1]; - uvcount += 1; - } - if(efa->v4 && efa->v4->f1 && ELEM(mergevert, NULL, efa->v4)){ - uvav[0] += tf->uv[3][0]; - uvav[1] += tf->uv[3][1]; - uvcount += 1; - } - } - - if(uvcount > 0) { - uvav[0] /= uvcount; - uvav[1] /= uvcount; - - for(efa = em->faces.first; efa; efa=efa->next){ - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(efa->v1->f1){ - tf->uv[0][0] = uvav[0]; - tf->uv[0][1] = uvav[1]; - } - if(efa->v2->f1){ - tf->uv[1][0] = uvav[0]; - tf->uv[1][1] = uvav[1]; - } - if(efa->v3->f1){ - tf->uv[2][0] = uvav[0]; - tf->uv[2][1] = uvav[1]; - } - if(efa->v4 && efa->v4->f1){ - tf->uv[3][0] = uvav[0]; - tf->uv[3][1] = uvav[1]; - } - } - } -} - -static int collapseEdges(EditMesh *em) -{ - EditVert *eve; - EditEdge *eed; - - ListBase allcollections; - CollectedEdge *curredge; - Collection *edgecollection; - - int totedges, mergecount,vcount /*, groupcount*/; - float avgcount[3]; - - allcollections.first = 0; - allcollections.last = 0; - - mergecount = 0; - - build_edgecollection(em, &allcollections); - /*groupcount = BLI_countlist(&allcollections);*/ /*UNUSED*/ - - - for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){ - totedges = BLI_countlist(&(edgecollection->collectionbase)); - mergecount += totedges; - avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0; - - vcount = 0; - - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0]; - avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1]; - avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2]; - - avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0]; - avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1]; - avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2]; - - vcount +=2; - } - - avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount; - - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount); - VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount); - } - - if (EM_texFaceCheck(em)) { - /*uv collapse*/ - for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0; - for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){ - curredge->eed->v1->f1 = 1; - curredge->eed->v2->f1 = 1; - curredge->eed->f1 = 1; - } - collapse_edgeuvs(em); - } - - } - freecollections(&allcollections); - removedoublesflag(em, 1, 0, MERGELIMIT); - - return mergecount; -} - -static int merge_firstlast(EditMesh *em, int first, int uvmerge) -{ - EditVert *eve,*mergevert; - EditSelection *ese; - - /* do sanity check in mergemenu in edit.c ?*/ - if(first == 0){ - ese = em->selected.last; - mergevert= (EditVert*)ese->data; - } - else{ - ese = em->selected.first; - mergevert = (EditVert*)ese->data; - } - - if(mergevert->f&SELECT){ - for (eve=em->verts.first; eve; eve=eve->next){ - if (eve->f&SELECT) - VECCOPY(eve->co,mergevert->co); - } - } - - if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){ - - for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eve=em->verts.first; eve; eve=eve->next){ - if(eve->f&SELECT) eve->f1 = 1; - } - collapseuvs(em, mergevert); - } - - return removedoublesflag(em, 1, 0, MERGELIMIT); -} - -static void em_snap_to_center(EditMesh *em) -{ - EditVert *eve; - float cent[3] = {0.0f, 0.0f, 0.0f}; - int i=0; - - for (eve=em->verts.first; eve; eve=eve->next) { - if (eve->f & SELECT) { - add_v3_v3(cent, eve->co); - i++; - } - } - - if (!i) - return; - - mul_v3_fl(cent, 1.0f / (float)i); - - for (eve=em->verts.first; eve; eve=eve->next) { - if (eve->f & SELECT) { - VECCOPY(eve->co, cent); - } - } -} - -static void em_snap_to_cursor(EditMesh *em, bContext *C) -{ - Scene *scene = CTX_data_scene(C); - Object *ob= CTX_data_edit_object(C); - View3D *v3d = CTX_wm_view3d(C); - EditVert *eve; - float co[3], *vco, invmat[4][4]; - - invert_m4_m4(invmat, ob->obmat); - - vco = give_cursor(scene, v3d); - VECCOPY(co, vco); - mul_m4_v3(invmat, co); - - for (eve=em->verts.first; eve; eve=eve->next) { - if (eve->f & SELECT) { - VECCOPY(eve->co, co); - } - } -} - -static int merge_target(bContext *C, EditMesh *em, int target, int uvmerge) -{ - EditVert *eve; - - // XXX not working - if(target) em_snap_to_cursor(em, C); - else em_snap_to_center(em); - - if(uvmerge && CustomData_has_layer(&em->fdata, CD_MTFACE)){ - for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = 0; - for(eve=em->verts.first; eve; eve=eve->next){ - if(eve->f&SELECT) eve->f1 = 1; - } - collapseuvs(em, NULL); - } - - return removedoublesflag(em, 1, 0, MERGELIMIT); -} -#undef MERGELIMIT - -static int merge_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - int count= 0, uvs= RNA_boolean_get(op->ptr, "uvs"); - EditSelection *ese; - int totvert= em->totvert, totedge= em->totedge, totface= em->totface; - - switch(RNA_enum_get(op->ptr, "type")) { - case 3: - count = merge_target(C, em, 0, uvs); - break; - case 4: - count = merge_target(C, em, 1, uvs); - break; - case 1: - ese= (EditSelection *)em->selected.last; - if(ese && ese->type == EDITVERT) { - count = merge_firstlast(em, 0, uvs); - } else { - BKE_report(op->reports, RPT_WARNING, "no last selected vertex set"); - } - break; - case 6: - ese= (EditSelection *)em->selected.first; - if(ese && ese->type == EDITVERT) { - count = merge_firstlast(em, 1, uvs); - } - else { - BKE_report(op->reports, RPT_WARNING, "no last selected vertex set"); - } - break; - case 5: - count = collapseEdges(em); - break; - } - - if (!(totvert != em->totvert || totedge != em->totedge || totface != em->totface)) - return OPERATOR_CANCELLED; - - recalc_editnormals(em); - - BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices"); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -static EnumPropertyItem merge_type_items[]= { - {6, "FIRST", 0, "At First", ""}, - {1, "LAST", 0, "At Last", ""}, - {3, "CENTER", 0, "At Center", ""}, - {4, "CURSOR", 0, "At Cursor", ""}, - {5, "COLLAPSE", 0, "Collapse", ""}, - {0, NULL, 0, NULL, NULL}}; - -static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) -{ - Object *obedit= CTX_data_edit_object(C); - EnumPropertyItem *item= NULL; - int totitem= 0; - - if (C==NULL) { - return merge_type_items; - } - - if(obedit && obedit->type == OB_MESH) { - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - - if(em->selectmode & SCE_SELECT_VERTEX) { - if(em->selected.first && em->selected.last && - ((EditSelection*)em->selected.first)->type == EDITVERT && ((EditSelection*)em->selected.last)->type == EDITVERT) { - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); - } - else if(em->selected.first && ((EditSelection*)em->selected.first)->type == EDITVERT) - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); - else if(em->selected.last && ((EditSelection*)em->selected.last)->type == EDITVERT) - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6); - } - - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4); - RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5); - } - - RNA_enum_item_end(&item, &totitem); - *free= 1; - - return item; -} - -void MESH_OT_merge(wmOperatorType *ot) -{ - PropertyRNA *prop; - - /* identifiers */ - ot->name= "Merge"; - ot->description= "Merge selected vertices"; - ot->idname= "MESH_OT_merge"; - - /* api callbacks */ - ot->exec= merge_exec; - ot->invoke= WM_menu_invoke; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use."); - RNA_def_enum_funcs(prop, merge_type_itemf); - ot->prop= prop; - RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge."); -} - -/************************ Vertex Path Operator *************************/ - -typedef struct PathNode { - int u; - int visited; - ListBase edges; -} PathNode; - -typedef struct PathEdge { - struct PathEdge *next, *prev; - int v; - float w; -} PathEdge; - -#define PATH_SELECT_EDGE_LENGTH 0 -#define PATH_SELECT_TOPOLOGICAL 1 - -static int select_vertex_path_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditVert *eve, *s, *t; - EditEdge *eed; - PathEdge *newpe, *currpe; - PathNode *currpn; - PathNode *Q; - int v, *previous, pathvert, pnindex; /*pnindex redundant?*/ - int unbalanced, totnodes; - float *cost; - int type= RNA_enum_get(op->ptr, "type"); - Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/ - - s = t = NULL; - for(eve=em->verts.first; eve; eve=eve->next) { - if(eve->f&SELECT) { - if(s == NULL) s= eve; - else if(t == NULL) t= eve; - else { - /* more than two vertices are selected, - show warning message and cancel operator */ - s = t = NULL; - break; - } - - } - - /*need to find out if t is actually reachable by s....*/ - eve->f1 = 0; - } - - if(s != NULL && t != NULL) { - s->f1 = 1; - - unbalanced = 1; - totnodes = 1; - while(unbalanced){ - unbalanced = 0; - for(eed=em->edges.first; eed; eed=eed->next){ - if(!eed->h){ - if(eed->v1->f1 && !eed->v2->f1){ - eed->v2->f1 = 1; - totnodes++; - unbalanced = 1; - } - else if(eed->v2->f1 && !eed->v1->f1){ - eed->v1->f1 = 1; - totnodes++; - unbalanced = 1; - } - } - } - } - - if(s->f1 && t->f1){ /* t can be reached by s */ - Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes"); - totnodes = 0; - for(eve=em->verts.first; eve; eve=eve->next){ - if(eve->f1){ - Q[totnodes].u = totnodes; - Q[totnodes].edges.first = 0; - Q[totnodes].edges.last = 0; - Q[totnodes].visited = 0; - eve->tmp.p = &(Q[totnodes]); - totnodes++; - } - else eve->tmp.p = NULL; - } - - for(eed=em->edges.first; eed; eed=eed->next){ - if(!eed->h){ - if(eed->v1->f1){ - currpn = ((PathNode*)eed->v1->tmp.p); - - newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); - newpe->v = ((PathNode*)eed->v2->tmp.p)->u; - if (type == PATH_SELECT_EDGE_LENGTH) { - newpe->w = len_v3v3(eed->v1->co, eed->v2->co); - } - else newpe->w = 1; - newpe->next = 0; - newpe->prev = 0; - BLI_addtail(&(currpn->edges), newpe); - } - if(eed->v2->f1){ - currpn = ((PathNode*)eed->v2->tmp.p); - newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge"); - newpe->v = ((PathNode*)eed->v1->tmp.p)->u; - if (type == PATH_SELECT_EDGE_LENGTH) { - newpe->w = len_v3v3(eed->v1->co, eed->v2->co); - } - else newpe->w = 1; - newpe->next = 0; - newpe->prev = 0; - BLI_addtail(&(currpn->edges), newpe); - } - } - } - - heap = BLI_heap_new(); - cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs"); - previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices"); - - for(v=0; v < totnodes; v++){ - cost[v] = 1000000; - previous[v] = -1; /*array of indices*/ - } - - pnindex = ((PathNode*)s->tmp.p)->u; - cost[pnindex] = 0; - BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex)); - - while( !BLI_heap_empty(heap) ){ - - pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); - currpn = &(Q[pnindex]); - - if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/ - break; - - for(currpe=currpn->edges.first; currpe; currpe=currpe->next){ - if(!Q[currpe->v].visited){ - if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){ - cost[currpe->v] = cost[currpn->u] + currpe->w; - previous[currpe->v] = currpn->u; - Q[currpe->v].visited = 1; - BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v)); - } - } - } - } - - pathvert = ((PathNode*)t->tmp.p)->u; - while(pathvert != -1){ - for(eve=em->verts.first; eve; eve=eve->next){ - if(eve->f1){ - if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT; - } - } - pathvert = previous[pathvert]; - } - - for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges)); - MEM_freeN(Q); - MEM_freeN(cost); - MEM_freeN(previous); - BLI_heap_free(heap, NULL); - EM_select_flush(em); - } - } - else { - BKE_mesh_end_editmesh(obedit->data, em); - BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected"); - return OPERATOR_CANCELLED; - } - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_vertex_path(wmOperatorType *ot) -{ - static const EnumPropertyItem type_items[] = { - {PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL}, - {PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name= "Select Vertex Path"; - ot->description= "Select shortest path between two vertices by distance type"; - ot->idname= "MESH_OT_select_vertex_path"; - - /* api callbacks */ - ot->exec= select_vertex_path_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance."); -} - -/********************** Region/Loop Operators *************************/ - -static int region_to_loop(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditEdge *eed; - EditFace *efa; - int selected= 0; - - for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0; - - for(efa=em->faces.first; efa; efa=efa->next){ - if(efa->f&SELECT){ - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) - efa->e4->f1++; - - selected= 1; - } - } - - if(!selected) - return OPERATOR_CANCELLED; - - EM_clear_flag_all(em, SELECT); - - for(eed=em->edges.first; eed; eed=eed->next){ - if(eed->f1 == 1) EM_select_edge(eed, 1); - } - - em->selectmode = SCE_SELECT_EDGE; - CTX_data_tool_settings(C)->selectmode= em->selectmode; - EM_selectmode_set(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_region_to_loop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Region to Loop"; - ot->description= "Select a region as a loop of connected edges"; - ot->idname= "MESH_OT_region_to_loop"; - - /* api callbacks */ - ot->exec= region_to_loop; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int validate_loop(EditMesh *em, Collection *edgecollection) -{ - EditEdge *eed; - EditFace *efa; - CollectedEdge *curredge; - - /*1st test*/ - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - curredge->eed->v1->f1 = 0; - curredge->eed->v2->f1 = 0; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - curredge->eed->v1->f1++; - curredge->eed->v2->f1++; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - if(curredge->eed->v1->f1 > 2) return(0); else - if(curredge->eed->v2->f1 > 2) return(0); - } - - /*2nd test*/ - for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0; - for(efa=em->faces.first; efa; efa=efa->next){ - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){ - if(curredge->eed->f1 > 2) return(0); - } - return(1); -} - -static int loop_bisect(EditMesh *em, Collection *edgecollection){ - - EditFace *efa, *sf1, *sf2; - EditEdge *eed, *sed; - CollectedEdge *curredge; - int totsf1, totsf2, unbalanced,balancededges; - - for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0; - for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = 0; - - for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1; - - sf1 = sf2 = NULL; - sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed; - - for(efa=em->faces.first; efa; efa=efa->next){ - if(sf2) break; - else if(sf1){ - if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa; - } - else{ - if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa; - } - } - - if(sf1==NULL || sf2==NULL) - return(-1); - - if(!(sf1->e1->f1)) sf1->e1->f2 = 1; - if(!(sf1->e2->f1)) sf1->e2->f2 = 1; - if(!(sf1->e3->f1)) sf1->e3->f2 = 1; - if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1; - sf1->f1 = 1; - totsf1 = 1; - - if(!(sf2->e1->f1)) sf2->e1->f2 = 2; - if(!(sf2->e2->f1)) sf2->e2->f2 = 2; - if(!(sf2->e3->f1)) sf2->e3->f2 = 2; - if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2; - sf2->f1 = 2; - totsf2 = 1; - - /*do sf1*/ - unbalanced = 1; - while(unbalanced){ - unbalanced = 0; - for(efa=em->faces.first; efa; efa=efa->next){ - balancededges = 0; - if(efa->f1 == 0){ - if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){ - balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1; - balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1; - balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1; - if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1; - if(balancededges){ - unbalanced = 1; - efa->f1 = 1; - totsf1++; - } - } - } - } - } - - /*do sf2*/ - unbalanced = 1; - while(unbalanced){ - unbalanced = 0; - for(efa=em->faces.first; efa; efa=efa->next){ - balancededges = 0; - if(efa->f1 == 0){ - if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){ - balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2; - balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2; - balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2; - if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2; - if(balancededges){ - unbalanced = 1; - efa->f1 = 2; - totsf2++; - } - } - } - } - } - - if(totsf1 < totsf2) return(1); - else return(2); -} - -static int loop_to_region(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - - EditFace *efa; - ListBase allcollections={NULL,NULL}; - Collection *edgecollection; - int testflag; - - build_edgecollection(em, &allcollections); - - for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){ - if(validate_loop(em, edgecollection)){ - testflag = loop_bisect(em, edgecollection); - for(efa=em->faces.first; efa; efa=efa->next){ - if(efa->f1 == testflag){ - if(efa->f&SELECT) EM_select_face(efa, 0); - else EM_select_face(efa,1); - } - } - } - } - - for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/ - if(efa->f&SELECT) EM_select_face(efa,1); - } - - freecollections(&allcollections); - BKE_mesh_end_editmesh(obedit->data, em); - - WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_loop_to_region(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Loop to Region"; - ot->description= "Select a loop of connected edges as a region"; - ot->idname= "MESH_OT_loop_to_region"; - - /* api callbacks */ - ot->exec= loop_to_region; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/********************** UV/Color Operators *************************/ - -// XXX please check if these functions do what you want them to -/* texface and vertex color editmode tools for the face menu */ - -static int mesh_rotate_uvs(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - EditFace *efa; - short change = 0; - MTFace *tf; - float u1, v1; - int dir= RNA_enum_get(op->ptr, "direction"); - - if (!EM_texFaceCheck(em)) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - u1= tf->uv[0][0]; - v1= tf->uv[0][1]; - - if (dir == DIRECTION_CCW) { - if(efa->v4) { - tf->uv[0][0]= tf->uv[3][0]; - tf->uv[0][1]= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[2][0]; - tf->uv[3][1]= tf->uv[2][1]; - } else { - tf->uv[0][0]= tf->uv[2][0]; - tf->uv[0][1]= tf->uv[2][1]; - } - - tf->uv[2][0]= tf->uv[1][0]; - tf->uv[2][1]= tf->uv[1][1]; - - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - } else { - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - - if(efa->v4) { - tf->uv[2][0]= tf->uv[3][0]; - tf->uv[2][1]= tf->uv[3][1]; - - tf->uv[3][0]= u1; - tf->uv[3][1]= v1; - } - else { - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - } - change = 1; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - if(!change) - return OPERATOR_CANCELLED; - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -static int mesh_mirror_uvs(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - EditFace *efa; - short change = 0; - MTFace *tf; - float u1, v1; - int axis= RNA_enum_get(op->ptr, "axis"); - - if (!EM_texFaceCheck(em)) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers."); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (axis == AXIS_Y) { - u1= tf->uv[1][0]; - v1= tf->uv[1][1]; - if(efa->v4) { - - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - - u1= tf->uv[3][0]; - v1= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[0][0]; - tf->uv[3][1]= tf->uv[0][1]; - - tf->uv[0][0]= u1; - tf->uv[0][1]= v1; - } - else { - tf->uv[1][0]= tf->uv[2][0]; - tf->uv[1][1]= tf->uv[2][1]; - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - - } else { - u1= tf->uv[0][0]; - v1= tf->uv[0][1]; - if(efa->v4) { - - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - - u1= tf->uv[3][0]; - v1= tf->uv[3][1]; - - tf->uv[3][0]= tf->uv[2][0]; - tf->uv[3][1]= tf->uv[2][1]; - - tf->uv[2][0]= u1; - tf->uv[2][1]= v1; - } - else { - tf->uv[0][0]= tf->uv[1][0]; - tf->uv[0][1]= tf->uv[1][1]; - tf->uv[1][0]= u1; - tf->uv[1][1]= v1; - } - } - change = 1; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - if(!change) - return OPERATOR_CANCELLED; - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -static int mesh_rotate_colors(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - EditFace *efa; - short change = 0; - MCol tmpcol, *mcol; - int dir= RNA_enum_get(op->ptr, "direction"); - - if (!EM_vertColorCheck(em)) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers."); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - tmpcol= mcol[0]; - - if (dir == DIRECTION_CCW) { - if(efa->v4) { - mcol[0]= mcol[3]; - mcol[3]= mcol[2]; - } else { - mcol[0]= mcol[2]; - } - mcol[2]= mcol[1]; - mcol[1]= tmpcol; - } else { - mcol[0]= mcol[1]; - mcol[1]= mcol[2]; - - if(efa->v4) { - mcol[2]= mcol[3]; - mcol[3]= tmpcol; - } - else - mcol[2]= tmpcol; - } - change = 1; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - if(!change) - return OPERATOR_CANCELLED; - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - - -static int mesh_mirror_colors(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - EditFace *efa; - short change = 0; - MCol tmpcol, *mcol; - int axis= RNA_enum_get(op->ptr, "axis"); - - if (!EM_vertColorCheck(em)) { - BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers"); - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_CANCELLED; - } - - for(efa=em->faces.first; efa; efa=efa->next) { - if (efa->f & SELECT) { - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); - if (axis == AXIS_Y) { - tmpcol= mcol[1]; - mcol[1]= mcol[2]; - mcol[2]= tmpcol; - - if(efa->v4) { - tmpcol= mcol[0]; - mcol[0]= mcol[3]; - mcol[3]= tmpcol; - } - } else { - tmpcol= mcol[0]; - mcol[0]= mcol[1]; - mcol[1]= tmpcol; - - if(efa->v4) { - tmpcol= mcol[2]; - mcol[2]= mcol[3]; - mcol[3]= tmpcol; - } - } - change = 1; - } - } - - BKE_mesh_end_editmesh(obedit->data, em); - - if(!change) - return OPERATOR_CANCELLED; - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_uvs_rotate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Rotate UVs"; - ot->description= "Rotate selected UVs"; - ot->idname= "MESH_OT_uvs_rotate"; - - /* api callbacks */ - ot->exec= mesh_rotate_uvs; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around."); -} - -void MESH_OT_uvs_mirror(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mirror UVs"; - ot->description= "Mirror selected UVs"; - ot->idname= "MESH_OT_uvs_mirror"; - - /* api callbacks */ - ot->exec= mesh_mirror_uvs; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around."); -} - -void MESH_OT_colors_rotate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Rotate Colors"; - ot->description= "Rotate UV/image color layer"; - ot->idname= "MESH_OT_colors_rotate"; - - /* api callbacks */ - ot->exec= mesh_rotate_colors; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around."); -} - -void MESH_OT_colors_mirror(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mirror Colors"; - ot->description= "Mirror UV/image color layer"; - ot->idname= "MESH_OT_colors_mirror"; - - /* api callbacks */ - ot->exec= mesh_mirror_colors; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* props */ - RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around."); -} - -/********************** Subdivide Operator *************************/ - -static int subdivide_exec(bContext *C, wmOperator *op) -{ - ToolSettings *ts= CTX_data_tool_settings(C); - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - int cuts= RNA_int_get(op->ptr,"number_cuts"); - float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness"); - float fractal= RNA_float_get(op->ptr, "fractal")/100; - int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern"); - int flag= 0; - - if(smooth != 0.0f) - flag |= B_SMOOTH; - if(fractal != 0.0f) - flag |= B_FRACTAL; - - esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_subdivide(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Subdivide"; - ot->description= "Subdivide selected edges"; - ot->idname= "MESH_OT_subdivide"; - - /* api callbacks */ - ot->exec= subdivide_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10); - RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor.", 0.0f, 1.0f); - RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f); - 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"); -} - -/********************** Fill Operators *************************/ - -/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the -edge/face flags, with very mixed results.... */ -static void beautify_fill(EditMesh *em) -{ - EditVert *v1, *v2, *v3, *v4; - EditEdge *eed, *nexted; - EditEdge dia1, dia2; - EditFace *efa, *w; - // void **efaar, **efaa; - EVPTuple *efaar; - EVPtr *efaa; - float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2; - int totedge, ok, notbeauty=8, onedone, vindex[4]; - - /* - all selected edges with two faces - * - find the faces: store them in edges (using datablock) - * - per edge: - test convex - * - test edge: flip? - * - if true: remedge, addedge, all edges at the edge get new face pointers - */ - - EM_selectmode_set(em); // makes sure in selectmode 'face' the edges of selected faces are selected too - - totedge = count_selected_edges(em->edges.first); - if(totedge==0) return; - - /* temp block with face pointers */ - efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill"); - - while (notbeauty) { - notbeauty--; - - ok = collect_quadedges(efaar, em->edges.first, em->faces.first); - - /* there we go */ - onedone= 0; - - eed= em->edges.first; - while(eed) { - nexted= eed->next; - - /* f2 is set in collect_quadedges() */ - if(eed->f2==2 && eed->h==0) { - - efaa = (EVPtr *) eed->tmp.p; - - /* none of the faces should be treated before, nor be part of fgon */ - ok= 1; - efa= efaa[0]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - if(efa->fgonf) ok= 0; - efa= efaa[1]; - if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0; - if(efa->fgonf) ok= 0; - - if(ok) { - /* test convex */ - givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex); - if(v1 && v2 && v3 && v4) { - if( convex(v1->co, v2->co, v3->co, v4->co) ) { - - /* test edges */ - if( (v1) > (v3) ) { - dia1.v1= v3; - dia1.v2= v1; - } - else { - dia1.v1= v1; - dia1.v2= v3; - } - - if( (v2) > (v4) ) { - dia2.v1= v4; - dia2.v2= v2; - } - else { - dia2.v1= v2; - dia2.v2= v4; - } - - /* testing rule: - * the area divided by the total edge lengths - */ - - len1= len_v3v3(v1->co, v2->co); - len2= len_v3v3(v2->co, v3->co); - len3= len_v3v3(v3->co, v4->co); - len4= len_v3v3(v4->co, v1->co); - len5= len_v3v3(v1->co, v3->co); - len6= len_v3v3(v2->co, v4->co); - - opp1= area_tri_v3(v1->co, v2->co, v3->co); - opp2= area_tri_v3(v1->co, v3->co, v4->co); - - fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5); - - opp1= area_tri_v3(v2->co, v3->co, v4->co); - opp2= area_tri_v3(v2->co, v4->co, v1->co); - - fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6); - - ok= 0; - if(fac1 > fac2) { - if(dia2.v1==eed->v1 && dia2.v2==eed->v2) { - eed->f1= 1; - efa= efaa[0]; - efa->f1= 1; - efa= efaa[1]; - efa->f1= 1; - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[0], vindex[1], 4+vindex[2], -1); - w->f |= SELECT; - - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[0], 4+vindex[2], 4+vindex[3], -1); - w->f |= SELECT; - - onedone= 1; - } - } - else if(fac1 < fac2) { - if(dia1.v1==eed->v1 && dia1.v2==eed->v2) { - eed->f1= 1; - efa= efaa[0]; - efa->f1= 1; - efa= efaa[1]; - efa->f1= 1; - - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[1], 4+vindex[2], 4+vindex[3], -1); - w->f |= SELECT; - - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[0], 4+vindex[1], 4+vindex[3], -1); - w->f |= SELECT; - - onedone= 1; - } - } - } - } - } - - } - eed= nexted; - } - - free_tagged_edges_faces(em, em->edges.first, em->faces.first); - - if(onedone==0) break; - - EM_selectmode_set(em); // new edges/faces were added - } - - MEM_freeN(efaar); - - EM_select_flush(em); - -} - -/* Got this from scanfill.c. You will need to juggle around the -* callbacks for the scanfill.c code a bit for this to work. */ -static void fill_mesh(EditMesh *em) -{ - EditVert *eve,*v1; - EditEdge *eed,*e1,*nexted; - EditFace *efa,*nextvl, *efan; - short ok; - - if(em==NULL) return; - waitcursor(1); - - /* copy all selected vertices */ - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { - v1= BLI_addfillvert(eve->co); - eve->tmp.v= v1; - v1->tmp.v= eve; - v1->xs= 0; // used for counting edges - } - eve= eve->next; - } - /* copy all selected edges */ - eed= em->edges.first; - while(eed) { - if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) { - e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v); - e1->v1->xs++; - e1->v2->xs++; - } - eed= eed->next; - } - /* from all selected faces: remove vertices and edges to prevent doubles */ - /* all edges add values, faces subtract, - then remove edges with vertices ->xs<2 */ - efa= em->faces.first; - ok= 0; - while(efa) { - nextvl= efa->next; - if( faceselectedAND(efa, 1) ) { - efa->v1->tmp.v->xs--; - efa->v2->tmp.v->xs--; - efa->v3->tmp.v->xs--; - if(efa->v4) efa->v4->tmp.v->xs--; - ok= 1; - - } - efa= nextvl; - } - if(ok) { /* there are faces selected */ - eed= filledgebase.first; - while(eed) { - nexted= eed->next; - if(eed->v1->xs<2 || eed->v2->xs<2) { - BLI_remlink(&filledgebase,eed); - } - eed= nexted; - } - } - - if(BLI_edgefill(em->mat_nr)) { - efa= fillfacebase.first; - while(efa) { - /* normals default pointing up */ - efan= addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v, - efa->v1->tmp.v, 0, NULL, NULL); - if(efan) EM_select_face(efan, 1); - efa= efa->next; - } - } - - BLI_end_edgefill(); - beautify_fill(em); - - WM_cursor_wait(0); - EM_select_flush(em); - -} - -static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - fill_mesh(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; - -} - -void MESH_OT_fill(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Fill"; - ot->description= "Create a segment, edge or face"; - ot->idname= "MESH_OT_fill"; - - /* api callbacks */ - ot->exec= fill_mesh_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - beautify_fill(em); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_beautify_fill(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Beautify Fill"; - ot->description= "Rearrange geometry on a selected surface to avoid skinny faces"; - ot->idname= "MESH_OT_beautify_fill"; - - /* api callbacks */ - ot->exec= beautify_fill_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/* ********************** SORT FACES ******************* */ - -static void permutate(void *list, int num, int size, int *index) -{ - void *buf; - int len; - int i; - - len = num * size; - - buf = MEM_mallocN(len, "permutate"); - memcpy(buf, list, len); - - for (i = 0; i < num; i++) { - memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size); - } - MEM_freeN(buf); -} - -/* sort faces on view axis */ -static float *face_sort_floats; -static int float_sort(const void *v1, const void *v2) -{ - float x1, x2; - - x1 = face_sort_floats[((int *) v1)[0]]; - x2 = face_sort_floats[((int *) v2)[0]]; - - if( x1 > x2 ) return 1; - else if( x1 < x2 ) return -1; - return 0; -} - - -static int sort_faces_exec(bContext *C, wmOperator *op) -{ - RegionView3D *rv3d= ED_view3d_context_rv3d(C); - View3D *v3d= CTX_wm_view3d(C); - Object *ob= CTX_data_edit_object(C); - Scene *scene= CTX_data_scene(C); - Mesh *me; - CustomDataLayer *layer; - int i, *index; - int event; - float reverse = 1; - // XXX int ctrl= 0; - - if (!v3d) return OPERATOR_CANCELLED; - - /* This operator work in Object Mode, not in edit mode. - * After talk with Campbell we agree that there is no point to port this to EditMesh right now. - * so for now, we just exit_editmode and enter_editmode at the end of this function. - */ - ED_object_exit_editmode(C, EM_FREEDATA); - - me= ob->data; - if(me->totface==0) { - ED_object_enter_editmode(C, 0); - return OPERATOR_FINISHED; - } - - event= RNA_enum_get(op->ptr, "type"); - - // XXX - //if(ctrl) - // reverse = -1; - - /* create index list */ - index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces"); - for (i = 0; i < me->totface; i++) { - index[i] = i; - } - - face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float"); - - /* sort index list instead of faces itself - * and apply this permutation to all face layers - */ - if (event == 5) { - /* Random */ - for(i=0; i<me->totface; i++) { - face_sort_floats[i] = BLI_frand(); - } - qsort(index, me->totface, sizeof(int), float_sort); - } else { - MFace *mf; - float vec[3]; - float mat[4][4]; - float cur[3]; - - if (event == 1) - mul_m4_m4m4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */ - else if (event == 2) { /* sort from cursor */ - if( v3d && v3d->localvd ) { - VECCOPY(cur, v3d->cursor); - } else { - VECCOPY(cur, scene->cursor); - } - invert_m4_m4(mat, OBACT->obmat); - mul_m4_v3(mat, cur); - } - - mf= me->mface; - - for(i=0; i<me->totface; i++, mf++) { - if (event==3) { - face_sort_floats[i] = ((float)mf->mat_nr)*reverse; - } else if (event==4) { - /*selected first*/ - if (mf->flag & ME_FACE_SEL) - face_sort_floats[i] = 0.0; - else - face_sort_floats[i] = reverse; - } else { - /* find the faces center */ - add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co); - if (mf->v4) { - add_v3_v3(vec, (me->mvert+mf->v3)->co); - add_v3_v3(vec, (me->mvert+mf->v4)->co); - mul_v3_fl(vec, 0.25f); - } else { - add_v3_v3(vec, (me->mvert+mf->v3)->co); - mul_v3_fl(vec, 1.0f/3.0f); - } /* done */ - - if (event == 1) { /* sort on view axis */ - mul_m4_v3(mat, vec); - face_sort_floats[i] = vec[2] * reverse; - } else if(event == 2) { /* distance from cursor*/ - face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */ - } - } - } - qsort(index, me->totface, sizeof(int), float_sort); - } - - MEM_freeN(face_sort_floats); - for(i = 0; i < me->fdata.totlayer; i++) { - layer = &me->fdata.layers[i]; - permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index); - } - - MEM_freeN(index); - DAG_id_tag_update(ob->data, 0); - - /* Return to editmode. */ - ED_object_enter_editmode(C, 0); - - return OPERATOR_FINISHED; -} - -void MESH_OT_sort_faces(wmOperatorType *ot) -{ - static EnumPropertyItem type_items[]= { - { 1, "VIEW_AXIS", 0, "View Axis", "" }, - { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" }, - { 3, "MATERIAL", 0, "Material", "" }, - { 4, "SELECTED", 0, "Selected", "" }, - { 5, "RANDOMIZE", 0, "Randomize", "" }, - { 0, NULL, 0, NULL, NULL }}; - - /* identifiers */ - ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t| - ot->description= "The faces of the active Mesh Object are sorted, based on the current view."; - ot->idname= "MESH_OT_sort_faces"; - - /* api callbacks */ - ot->invoke= WM_menu_invoke; - ot->exec= sort_faces_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); -} - -/********************** Quad/Tri Operators *************************/ - -static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - convert_to_triface(em,0); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_quads_convert_to_tris(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Quads to Tris"; - ot->description= "Convert selected quads to triangles"; - ot->idname= "MESH_OT_quads_convert_to_tris"; - - /* api callbacks */ - ot->exec= quads_convert_to_tris_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - join_triangles(em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Tris to Quads"; - ot->description= "Convert selected triangles to quads"; - ot->idname= "MESH_OT_tris_convert_to_quads"; - - /* api callbacks */ - ot->exec= tris_convert_to_quads_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - edge_flip(em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); - return OPERATOR_FINISHED; -} - -void MESH_OT_edge_flip(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Edge Flip"; - ot->description= "Flip selected edge or adjoining faces"; - ot->idname= "MESH_OT_edge_flip"; - - /* api callbacks */ - ot->exec= edge_flip_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/********************** Smooth/Solid Operators *************************/ - -static void mesh_set_smooth_faces(EditMesh *em, short smooth) -{ - EditFace *efa; - - if(em==NULL) return; - - for(efa= em->faces.first; efa; efa=efa->next) { - if(efa->f & SELECT) { - if(smooth) efa->flag |= ME_SMOOTH; - else efa->flag &= ~ME_SMOOTH; - } - } - - recalc_editnormals(em); -} - -static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - mesh_set_smooth_faces(em, 1); - - BKE_mesh_end_editmesh(obedit->data, em); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_faces_shade_smooth(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Shade Smooth"; - ot->description= "Display faces 'smooth' (using vertex normals)"; - ot->idname= "MESH_OT_faces_shade_smooth"; - - /* api callbacks */ - ot->exec= mesh_faces_shade_smooth_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - mesh_set_smooth_faces(em, 0); - - DAG_id_tag_update(obedit->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_faces_shade_flat(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Shade Flat"; - ot->description= "Display faces 'flat'"; - ot->idname= "MESH_OT_faces_shade_flat"; - - /* api callbacks */ - ot->exec= mesh_faces_shade_flat_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; -} - -/* TODO - some way to select on an arbitrary axis */ -static int select_axis_exec(bContext *C, wmOperator *op) -{ - Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - - int axis= RNA_enum_get(op->ptr, "axis"); - int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/ - - EditSelection *ese = em->selected.last; - - - if(ese==NULL) - return OPERATOR_CANCELLED; - - if(ese->type==EDITVERT) { - EditVert *ev; - EditVert *act_vert= (EditVert*)ese->data; - float value= act_vert->co[axis]; - float limit= CTX_data_tool_settings(C)->doublimit; // XXX - - if(mode==0) value -= limit; - else if (mode==1) value += limit; - - for(ev=em->verts.first;ev;ev=ev->next) { - if(!ev->h) { - switch(mode) { - case -1: /* aligned */ - if(fabs(ev->co[axis] - value) < limit) - ev->f |= SELECT; - break; - case 0: /* neg */ - if(ev->co[axis] > value) - ev->f |= SELECT; - break; - case 1: /* pos */ - if(ev->co[axis] < value) - ev->f |= SELECT; - break; - } - } - } - } - - EM_select_flush(em); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - return OPERATOR_FINISHED; -} - -void MESH_OT_select_axis(wmOperatorType *ot) -{ - static EnumPropertyItem axis_mode_items[] = { - {0, "POSITIVE", 0, "Positive Axis", ""}, - {1, "NEGATIVE", 0, "Negative Axis", ""}, - {-1, "ALIGNED", 0, "Aligned Axis", ""}, - {0, NULL, 0, NULL, NULL}}; - - static EnumPropertyItem axis_items_xyz[] = { - {0, "X_AXIS", 0, "X Axis", ""}, - {1, "Y_AXIS", 0, "Y Axis", ""}, - {2, "Z_AXIS", 0, "Z Axis", ""}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name= "Select Axis"; - ot->description= "Select all data in the mesh on a single axis"; - ot->idname= "MESH_OT_select_axis"; - - /* api callbacks */ - ot->exec= select_axis_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - /* properties */ - RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting"); - RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on"); -} - diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c new file mode 100755 index 00000000000..be36cb4a69b --- /dev/null +++ b/source/blender/editors/mesh/knifetool.c @@ -0,0 +1,1934 @@ +/** + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Joseph Eagar, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +#include "DNA_ID.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" +#include "DNA_object_types.h" + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "BLI_utildefines.h" +#include "BLI_blenlib.h" +#include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_editVert.h" +#include "BLI_array.h" +#include "BLI_ghash.h" +#include "BLI_memarena.h" +#include "BLI_mempool.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_kdopbvh.h" +#include "BLI_smallhash.h" +#include "BLI_scanfill.h" + +#include "BKE_blender.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" +#include "BKE_scene.h" +#include "BKE_mesh.h" +#include "BKE_tessmesh.h" +#include "BKE_depsgraph.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" /* for paint cursor */ + +#include "IMB_imbuf_types.h" + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" +#include "ED_mesh.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "mesh_intern.h" +#include "editbmesh_bvh.h" + +/* this code here is kindof messy. . .I might need to eventually rework it - joeedh*/ + +#define MAXGROUP 30 +#define KMAXDIST 25 /*max mouse distance from edge before not detecting it*/ + +/* knifetool operator */ +typedef struct KnifeVert { + BMVert *v; /*non-NULL if this is an original vert*/ + ListBase edges; + + float co[3], sco[3]; /*sco is screen coordinates*/ + short flag, draw, isface, inspace; +} KnifeVert; + +typedef struct Ref { + struct Ref *next, *prev; + void *ref; +} Ref; + +typedef struct KnifeEdge { + KnifeVert *v1, *v2; + BMFace *basef; /*face to restrict face fill to*/ + ListBase faces; + int draw; + + BMEdge *e, *oe; /*non-NULL if this is an original edge*/ +} KnifeEdge; + +typedef struct BMEdgeHit { + KnifeEdge *kfe; + float hit[3]; + float realhit[3]; /*used in midpoint mode*/ + float schit[3]; + float l; /*lambda along line*/ + KnifeVert *v; //set if snapped to a vert + BMFace *f; +} BMEdgeHit; + +/* struct for properties used while drawing */ +typedef struct knifetool_opdata { + ARegion *ar; /* region that knifetool was activated in */ + void *draw_handle; /* for drawing preview loop */ + ViewContext vc; + bContext *C; + + Object *ob; + BMEditMesh *em; + + MemArena *arena; + + GHash *origvertmap; + GHash *origedgemap; + + GHash *kedgefacemap; + + BMBVHTree *bmbvh; + + BLI_mempool *kverts; + BLI_mempool *kedges; + + float vthresh; + float ethresh; + + float vertco[3]; + float prevco[3]; + + /*used for drag-cutting*/ + BMEdgeHit *linehits; + int totlinehit; + + /*if curedge is NULL, attach to curvert; + if curvert is NULL, attach to curbmface, + otherwise create null vert*/ + KnifeEdge *curedge, *prevedge; + KnifeVert *curvert, *prevvert; + BMFace *curbmface, *prevbmface; + + int totkedge, totkvert, cutnr; + + BLI_mempool *refs; + + float projmat[4][4]; + int is_ortho; + float clipsta, clipend; + + enum { + MODE_IDLE, + MODE_DRAGGING, + MODE_CONNECT, + MODE_PANNING, + } mode; + + int snap_midpoints, prevmode, extend; + int ignore_edge_snapping, ignore_vert_snapping; + + int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh*/ +} knifetool_opdata; + +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f); + +static void knife_project_v3(knifetool_opdata *kcd, float co[3], float sco[3]) +{ + if (kcd->is_ortho) { + mul_v3_m4v3(sco, kcd->projmat, co); + + sco[0] = (float)(kcd->ar->winx/2.0f)+(kcd->ar->winx/2.0f)*sco[0]; + sco[1] = (float)(kcd->ar->winy/2.0f)+(kcd->ar->winy/2.0f)*sco[1]; + } + else { + ED_view3d_project_float(kcd->ar, co, sco, kcd->projmat); + } +} + +static KnifeEdge *new_knife_edge(knifetool_opdata *kcd) +{ + kcd->totkedge++; + return BLI_mempool_calloc(kcd->kedges); +} + +static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co) +{ + KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); + + kcd->totkvert++; + + copy_v3_v3(kfv->co, co); + copy_v3_v3(kfv->sco, co); + + knife_project_v3(kcd, kfv->co, kfv->sco); + + return kfv; +} + +/*get a KnifeVert wrapper for an existing BMVert*/ +static KnifeVert *get_bm_knife_vert(knifetool_opdata *kcd, BMVert *v) +{ + KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v); + + if (!kfv) { + kfv = new_knife_vert(kcd, v->co); + kfv->v = v; + BLI_ghash_insert(kcd->origvertmap, v, kfv); + } + + return kfv; +} + +/*get a KnifeEdge wrapper for an existing BMEdge*/ +static KnifeEdge *get_bm_knife_edge(knifetool_opdata *kcd, BMEdge *e) +{ + KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e); + if (!kfe) { + Ref *ref; + BMIter iter; + BMFace *f; + + kfe = new_knife_edge(kcd); + kfe->e = e; + kfe->v1 = get_bm_knife_vert(kcd, e->v1); + kfe->v2 = get_bm_knife_vert(kcd, e->v2); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v2->edges, ref); + + BLI_ghash_insert(kcd->origedgemap, e, kfe); + + BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) { + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = f; + BLI_addtail(&kfe->faces, ref); + + /*ensures the kedges lst for this f is initialized, + it automatically adds kfe by itself*/ + knife_get_face_kedges(kcd, f); + } + } + + return kfe; +} + +static void knife_start_cut(knifetool_opdata *kcd) +{ + kcd->prevedge = kcd->curedge; + kcd->prevvert = kcd->curvert; + kcd->prevbmface = kcd->curbmface; + kcd->cutnr++; + kcd->prev_is_space = kcd->is_space; + kcd->is_space = 0; + + copy_v3_v3(kcd->prevco, kcd->vertco); +} + +static Ref *find_ref(ListBase *lb, void *ref) +{ + Ref *ref1; + + for (ref1=lb->first; ref1; ref1=ref1->next) { + if (ref1->ref == ref) + return ref1; + } + + return NULL; +} + +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f) +{ + ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f); + + if (!lst) { + BMIter iter; + BMEdge *e; + + lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); + lst->first = lst->last = NULL; + + BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) { + Ref *ref = BLI_mempool_calloc(kcd->refs); + ref->ref = get_bm_knife_edge(kcd, e); + BLI_addtail(lst, ref); + } + + BLI_ghash_insert(kcd->kedgefacemap, f, lst); + } + + return lst; +} + +/*finds the proper face to restrict face fill to*/ +static void knife_find_basef(knifetool_opdata *kcd, KnifeEdge *kfe) +{ + if (!kfe->basef) { + Ref *r1, *r2, *r3, *r4; + + if (kfe->v1->isface || kfe->v2->isface) { + if (kfe->v2->isface) + kfe->basef = kcd->curbmface; + else + kfe->basef = kcd->prevbmface; + } else { + for (r1=kfe->v1->edges.first; r1 && !kfe->basef; r1=r1->next) { + KnifeEdge *ke1 = r1->ref; + for (r2=ke1->faces.first; r2 && !kfe->basef; r2=r2->next) { + for (r3=kfe->v2->edges.first; r3 && !kfe->basef; r3=r3->next) { + KnifeEdge *ke2 = r3->ref; + + for (r4=ke2->faces.first; r4 && !kfe->basef; r4=r4->next) { + if (r2->ref == r4->ref) { + kfe->basef = r2->ref; + } + } + } + } + } + } + /*ok, at this point kfe->basef should be set if any valid possibility + exists*/ + } +} + +static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out) +{ + KnifeEdge *newkfe = new_knife_edge(kcd); + ListBase *lst; + Ref *ref; + + newkfe->v1 = kfe->v1; + newkfe->v2 = new_knife_vert(kcd, co); + newkfe->v2->draw = 1; + newkfe->basef = kfe->basef; + + ref = find_ref(&kfe->v1->edges, kfe); + BLI_remlink(&kfe->v1->edges, ref); + + kfe->v1 = newkfe->v2; + BLI_addtail(&kfe->v1->edges, ref); + + for (ref=kfe->faces.first; ref; ref=ref->next) { + Ref *ref2 = BLI_mempool_calloc(kcd->refs); + + /*add kedge ref to bm faces*/ + lst = knife_get_face_kedges(kcd, ref->ref); + ref2->ref = newkfe; + BLI_addtail(lst, ref2); + + ref2 = BLI_mempool_calloc(kcd->refs); + ref2->ref = ref->ref; + BLI_addtail(&newkfe->faces, ref2); + } + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = newkfe; + BLI_addtail(&newkfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = newkfe; + BLI_addtail(&newkfe->v2->edges, ref); + + newkfe->draw = kfe->draw; + newkfe->e = kfe->e; + + *newkfe_out = newkfe; + + return newkfe->v2; +} + +static void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f) +{ + ListBase *lst = knife_get_face_kedges(kcd, f); + Ref *ref = BLI_mempool_calloc(kcd->refs); + + ref->ref = kfe; + BLI_addtail(lst, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = f; + BLI_addtail(&kfe->faces, ref); +} + +#if 0 +static void knife_copy_edge_facelist(knifetool_opdata *kcd, KnifeEdge *dest, KnifeEdge *source) +{ + Ref *ref, *ref2; + + for (ref2 = source->faces.first; ref2; ref2=ref2->next) { + ListBase *lst = knife_get_face_kedges(kcd, ref2->ref); + + /*add new edge to face knife edge list*/ + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = dest; + BLI_addtail(lst, ref); + + /*add face to new edge's face list*/ + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = ref2->ref; + BLI_addtail(&dest->faces, ref); + } +} +#endif + +static void knife_add_single_cut(knifetool_opdata *kcd) +{ + KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL; + Ref *ref; + + if (kcd->prevvert && kcd->prevvert == kcd->curvert) + return; + if (kcd->prevedge && kcd->prevedge == kcd->curedge) + return; + + kfe->draw = 1; + + if (kcd->prevvert) { + kfe->v1 = kcd->prevvert; + } else if (kcd->prevedge) { + kfe->v1 = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe2); + } else { + kfe->v1 = new_knife_vert(kcd, kcd->prevco); + kfe->v1->draw = kfe->draw = !kcd->prev_is_space; + kfe->v1->inspace = kcd->prev_is_space; + kfe->draw = !kcd->prev_is_space; + kfe->v1->isface = 1; + } + + if (kcd->curvert) { + kfe->v2 = kcd->curvert; + } else if (kcd->curedge) { + kfe->v2 = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3); + + kcd->curvert = kfe->v2; + } else { + kfe->v2 = new_knife_vert(kcd, kcd->vertco); + kfe->v2->draw = !kcd->is_space; + kfe->v2->isface = 1; + kfe->v2->inspace = kcd->is_space; + + if (kcd->is_space) + kfe->draw = 0; + + kcd->curvert = kfe->v2; + } + + knife_find_basef(kcd, kfe); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v1->edges, ref); + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = kfe; + BLI_addtail(&kfe->v2->edges, ref); + + if (kfe->basef && !find_ref(&kfe->faces, kfe->basef)) + knife_edge_append_face(kcd, kfe, kfe->basef); + + /*sanity check to make sure we're in the right edge/face lists*/ + if (kcd->curbmface) { + if (!find_ref(&kfe->faces, kcd->curbmface)) { + knife_edge_append_face(kcd, kfe, kcd->curbmface); + } + + if (kcd->prevbmface && kcd->prevbmface != kcd->curbmface) { + if (!find_ref(&kfe->faces, kcd->prevbmface)) { + knife_edge_append_face(kcd, kfe, kcd->prevbmface); + } + } + } + + /*set up for next cut*/ + kcd->prevbmface = kcd->curbmface; + kcd->prevvert = kcd->curvert; + kcd->prevedge = kcd->curedge; + copy_v3_v3(kcd->prevco, kcd->vertco); + kcd->prev_is_space = kcd->is_space; +} + +static int verge_linehit(const void *vlh1, const void *vlh2) +{ + const BMEdgeHit *lh1=vlh1, *lh2=vlh2; + + if (lh1->l < lh2->l) return -1; + else if (lh1->l > lh2->l) return 1; + else return 0; +} + +static void knife_add_cut(knifetool_opdata *kcd) +{ + /*BMEditMesh *em = kcd->em;*/ /*UNUSED*/ + knifetool_opdata oldkcd = *kcd; + + if (kcd->linehits) { + BMEdgeHit *lh, *lastlh, *firstlh; + int i; + + qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); + + lh = kcd->linehits; + lastlh = firstlh = NULL; + for (i=0; i<kcd->totlinehit; i++, (lastlh=lh), lh++) { + BMFace *f = lastlh ? lastlh->f : lh->f; + + if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) { + if (!firstlh) + firstlh = lastlh; + continue; + } else if (lastlh && firstlh) { + if (firstlh->v || lastlh->v) { + KnifeVert *kfv = firstlh->v ? firstlh->v : lastlh->v; + + kcd->prevvert = kfv; + copy_v3_v3(kcd->prevco, firstlh->hit); + kcd->prevedge = NULL; + kcd->prevbmface = f; + } + lastlh = firstlh = NULL; + } + + if (len_v3v3(kcd->prevco, lh->realhit) < FLT_EPSILON*80) + continue; + if (len_v3v3(kcd->vertco, lh->realhit) < FLT_EPSILON*80) + continue; + + if (kcd->prev_is_space || kcd->is_space) { + kcd->prev_is_space = kcd->is_space = 0; + copy_v3_v3(kcd->prevco, lh->hit); + kcd->prevedge = lh->kfe; + kcd->curbmface = lh->f; + continue; + } + + kcd->is_space = 0; + kcd->curedge = lh->kfe; + kcd->curbmface = lh->f; + kcd->curvert = lh->v; + copy_v3_v3(kcd->vertco, lh->hit); + + knife_add_single_cut(kcd); + } + + kcd->curbmface = oldkcd.curbmface; + kcd->curvert = oldkcd.curvert; + kcd->curedge = oldkcd.curedge; + kcd->is_space = oldkcd.is_space; + copy_v3_v3(kcd->vertco, oldkcd.vertco); + + knife_add_single_cut(kcd); + + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } else { + knife_add_single_cut(kcd); + } +} + +static void knife_finish_cut(knifetool_opdata *UNUSED(kcd)) +{ + +} + +/* modal loop selection drawing callback */ +static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + knifetool_opdata *kcd = arg; + + glDisable(GL_DEPTH_TEST); + + glPolygonOffset(1.0f, 1.0f); + + glPushMatrix(); + glMultMatrixf(kcd->ob->obmat); + + if (kcd->mode == MODE_DRAGGING) { + glColor3f(0.1, 0.1, 0.1); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->prevco); + glVertex3fv(kcd->vertco); + glEnd(); + + glLineWidth(1.0); + } + + if (kcd->curedge) { + glColor3f(0.5, 0.3, 0.15); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->curedge->v1->co); + glVertex3fv(kcd->curedge->v2->co); + glEnd(); + + glLineWidth(1.0); + } else if (kcd->curvert) { + glColor3f(0.8, 0.2, 0.1); + glPointSize(11); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertco); + glEnd(); + } + + if (kcd->curbmface) { + glColor3f(0.1, 0.8, 0.05); + glPointSize(9); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertco); + glEnd(); + } + + if (kcd->totlinehit > 0) { + BMEdgeHit *lh; + int i; + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + /*draw any snapped verts first*/ + glColor4f(0.8, 0.2, 0.1, 0.4); + glPointSize(11); + glBegin(GL_POINTS); + lh = kcd->linehits; + for (i=0; i<kcd->totlinehit; i++, lh++) { + float sv1[3], sv2[3]; + + knife_project_v3(kcd, lh->kfe->v1->co, sv1); + knife_project_v3(kcd, lh->kfe->v2->co, sv2); + knife_project_v3(kcd, lh->hit, lh->schit); + + if (len_v2v2(lh->schit, sv1) < kcd->vthresh/4) { + copy_v3_v3(lh->hit, lh->kfe->v1->co); + glVertex3fv(lh->hit); + lh->v = lh->kfe->v1; + } else if (len_v2v2(lh->schit, sv2) < kcd->vthresh/4) { + copy_v3_v3(lh->hit, lh->kfe->v2->co); + glVertex3fv(lh->hit); + lh->v = lh->kfe->v2; + } + } + glEnd(); + + /*now draw the rest*/ + glColor4f(0.1, 0.8, 0.05, 0.4); + glPointSize(7); + glBegin(GL_POINTS); + lh = kcd->linehits; + for (i=0; i<kcd->totlinehit; i++, lh++) { + glVertex3fv(lh->hit); + } + glEnd(); + glDisable(GL_BLEND); + } + + if (kcd->totkedge > 0) { + BLI_mempool_iter iter; + KnifeEdge *kfe; + + glLineWidth(1.0); + glBegin(GL_LINES); + + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + if (!kfe->draw) + continue; + + glColor3f(0.2, 0.2, 0.2); + + glVertex3fv(kfe->v1->co); + glVertex3fv(kfe->v2->co); + } + + glEnd(); + glLineWidth(1.0); + } + + if (kcd->totkvert > 0) { + BLI_mempool_iter iter; + KnifeVert *kfv; + + glPointSize(5.0); + + glBegin(GL_POINTS); + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) { + if (!kfv->draw) + continue; + + glColor3f(0.6, 0.1, 0.2); + + glVertex3fv(kfv->co); + } + + glEnd(); + } + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); +} + +static void _print_smhash(SmallHash *hash) +{ + int i, linecol=79, c=0; + + printf("{"); + for (i=0; i<hash->size; i++) { + if (hash->table[i].val == CELL_UNUSED) { + printf("--u-"); + } else if (hash->table[i].val == CELL_FREE) { + printf("--f-"); + } else { + printf("%2x", (unsigned int)hash->table[i].key); + } + + if (i != hash->size-1) + printf(", "); + + c += 6; + + if (c >= linecol) { + printf("\n "); + c = 0; + } + } + + fflush(stdout); +} + +static int kfe_vert_in_edge(KnifeEdge *e, KnifeVert *v) { + return e->v1 == v || e->v2 == v; +} + +static int point_on_line(float p[3], float v1[3], float v2[3]) +{ + float d = dist_to_line_segment_v3(p, v1, v2); + if (d < 0.01) { + d = len_v3v3(v1, v2); + if (d == 0.0) + return 0; + + d = len_v3v3(p, v1) / d; + + if (d >= -FLT_EPSILON*10 || d <= 1.0+FLT_EPSILON*10) + return 1; + } + + return 0; +} + +static BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3], + float v2[3], float v3[3], SmallHash *ehash, bglMats *mats, int *count) +{ + BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree); + BMEdgeHit *edges = NULL; + BLI_array_declare(edges); + BVHTreeOverlap *results, *result; + BMLoop **ls; + float cos[9], uv[3], lambda; + unsigned int tot=0; + int i, j; + + copy_v3_v3(cos, v1); + copy_v3_v3(cos+3, v2); + copy_v3_v3(cos+6, v3); + + BLI_bvhtree_insert(tree2, 0, cos, 3); + BLI_bvhtree_balance(tree2); + + result = results = BLI_bvhtree_overlap(tree, tree2, &tot); + + for (i=0; i<tot; i++, result++) { + float p[3]; + + ls = (BMLoop**)kcd->em->looptris[result->indexA]; + + for (j=0; j<3; j++) { + BMLoop *l1 = ls[j]; + BMFace *hitf; + ListBase *lst = knife_get_face_kedges(kcd, l1->f); + Ref *ref, *ref2; + + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + + if (kfe == kcd->curedge || kfe== kcd->prevedge) + continue; + + if (isect_line_tri_v3(kfe->v1->co, kfe->v2->co, v1, v2, v3, &lambda, uv)) { + float no[3], view[3], sp[3]; + + sub_v3_v3v3(p, kfe->v2->co, kfe->v1->co); + mul_v3_fl(p, lambda); + add_v3_v3(p, kfe->v1->co); + + if (kcd->curedge && point_on_line(p, kcd->curedge->v1->co, kcd->curedge->v2->co)) + continue; + if (kcd->prevedge && point_on_line(p, kcd->prevedge->v1->co, kcd->prevedge->v2->co)) + continue; + if (kcd->curvert && len_v3v3(kcd->curvert->co, p) < FLT_EPSILON*50) + continue; + if (kcd->prevvert && len_v3v3(kcd->prevvert->co, p) < FLT_EPSILON*50) + continue; + if (len_v3v3(kcd->prevco, p) < FLT_EPSILON*50 || len_v3v3(kcd->vertco, p) < FLT_EPSILON*50) + continue; + + knife_project_v3(kcd, p, sp); + view3d_unproject(mats, view, sp[0], sp[1], 0.0f); + mul_m4_v3(kcd->ob->imat, view); + + sub_v3_v3v3(view, p, view); + normalize_v3(view);; + + copy_v3_v3(no, view); + mul_v3_fl(no, -0.0003); + + /*go backwards toward view a bit*/ + add_v3_v3(p, no); + + hitf = BMBVH_RayCast(bmtree, p, no, NULL); + for (ref2=kfe->faces.first; ref2; ref2=ref2->next) { + if (ref2->ref == hitf) + hitf = NULL; + } + + if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) { + BMEdgeHit hit; + + if (len_v3v3(p, kcd->vertco) < FLT_EPSILON*50 || len_v3v3(p, kcd->prevco) < FLT_EPSILON*50) + continue; + + hit.kfe = kfe; + hit.v = NULL; + + knife_find_basef(kcd, kfe); + hit.f = kfe->basef; + + copy_v3_v3(hit.realhit, p); + + if (kcd->snap_midpoints) { + add_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co); + mul_v3_fl(hit.hit, 0.5f); + } else { + copy_v3_v3(hit.hit, p); + } + knife_project_v3(kcd, hit.hit, hit.schit); + + BLI_array_append(edges, hit); + BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL); + } + } + } + } + } + + if (results) + MEM_freeN(results); + + BLI_bvhtree_free(tree2); + *count = BLI_array_count(edges); + + return edges; +} + +static void knife_bgl_get_mats(knifetool_opdata *UNUSED(kcd), bglMats *mats) +{ + bgl_get_mats(mats); + //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat); + //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat); +} + +/*finds (visible) edges that intersects the current screen drag line*/ +static void knife_find_line_hits(knifetool_opdata *kcd) +{ + bglMats mats; + BMEdgeHit *e1, *e2; + SmallHash hash, *ehash = &hash; + float vec[3], v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3]; + int i, c1, c2; + + knife_bgl_get_mats(kcd, &mats); + + if (kcd->linehits) { + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + } + + copy_v3_v3(v1, kcd->prevco); + copy_v3_v3(v2, kcd->vertco); + + /*project screen line's 3d coordinates back into 2d*/ + knife_project_v3(kcd, v1, s1); + knife_project_v3(kcd, v2, s2); + + if (len_v2v2(s1, s2) < 1) + return; + + /*unproject screen line*/ + ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s1, v1, v3); + ED_view3d_win_to_segment_clip(kcd->ar, kcd->vc.v3d, s2, v2, v4); + + /*view3d_unproject(&mats, v1, s1[0], s1[1], 0.0f); + view3d_unproject(&mats, v2, s2[0], s2[1], 0.0f); + view3d_unproject(&mats, v3, s1[0], s1[1], 1.0f-FLT_EPSILON); + view3d_unproject(&mats, v4, s2[0], s2[1], 1.0f-FLT_EPSILON);*/ + + mul_m4_v3(kcd->ob->imat, v1); + mul_m4_v3(kcd->ob->imat, v2); + mul_m4_v3(kcd->ob->imat, v3); + mul_m4_v3(kcd->ob->imat, v4); + + sub_v3_v3v3(vec, v2, v1); + normalize_v3(vec); + mul_v3_fl(vec, 0.01); + add_v3_v3(v1, vec); + add_v3_v3(v3, vec); + + sub_v3_v3v3(vec, v4, v2); + normalize_v3(vec); + mul_v3_fl(vec, 0.01); + add_v3_v3(v4, vec); + add_v3_v3(v2, vec); + + sub_v3_v3v3(view, v4, v1); + normalize_v3(view); + + BLI_smallhash_init(ehash); + + /*test two triangles of sceen line's plane*/ + e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1); + e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, ehash, &mats, &c2); + if (c1 && c2) { + e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2)); + memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2); + MEM_freeN(e2); + } else if (c2) { + e1 = e2; + } + + kcd->linehits = e1; + kcd->totlinehit = c1+c2; + + /*find position along screen line, used for sorting*/ + for (i=0; i<kcd->totlinehit; i++) { + BMEdgeHit *lh = e1+i; + + lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1); + } + + BLI_smallhash_release(ehash); +} + +static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3], int *is_space) +{ + BMFace *f; + bglMats mats; + float origin[3], ray[3]; + float mval[2], imat[3][3]; + int dist = KMAXDIST; + + knife_bgl_get_mats(kcd, &mats); + + mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1]; + + /*unproject to find view ray*/ + view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f); + + sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]); + normalize_v3(ray); + + /*transform into object space*/ + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + copy_m3_m4(imat, kcd->ob->obmat); + invert_m3(imat); + + mul_m4_v3(kcd->ob->imat, origin); + mul_m3_v3(imat, ray); + + copy_v3_v3(co, origin); + add_v3_v3(co, ray); + + f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co); + + if (is_space) + *is_space = !f; + + if (!f) { + /*try to use backbuffer selection method if ray casting failed*/ + f = EDBM_findnearestface(&kcd->vc, &dist); + + /*cheat for now; just put in the origin instead + of a true coordinate on the face*/ + copy_v3_v3(co, origin); + add_v3_v3(co, ray); + } + + return f; +} + +/*find the 2d screen space density of vertices within a radius. used to scale snapping + distance for picking edges/verts.*/ +static int knife_sample_screen_density(knifetool_opdata *kcd, float radius) +{ + BMFace *f; + int is_space; + float co[3], sco[3]; + + f = knife_find_closest_face(kcd, co, &is_space); + + if (f && !is_space) { + ListBase *lst; + Ref *ref; + float dis; + int c = 0; + + knife_project_v3(kcd, co, sco); + + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + int i; + + for (i=0; i<2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + + knife_project_v3(kcd, kfv->co, kfv->sco); + + dis = len_v2v2(kfv->sco, sco); + if (dis < radius) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float vec[3]; + + copy_v3_v3(vec, kfv->co); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(ED_view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + c++; + } + } else { + c++; + } + } + } + } + + return c; + } + + return 0; +} + +/*returns snapping distance for edges/verts, scaled by the density of the + surrounding mesh (in screen space)*/ +static float knife_snap_size(knifetool_opdata *kcd, float maxsize) +{ + float density = (float)knife_sample_screen_density(kcd, maxsize*2.0f); + + density = MAX2(density, 1); + + return MIN2(maxsize / (density*0.5f), maxsize); +} + +/*p is closest point on edge to the mouse cursor*/ +static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space) +{ + BMFace *f; + float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh); + + if (kcd->ignore_vert_snapping) + maxdist *= 0.5; + + f = knife_find_closest_face(kcd, co, NULL); + *is_space = !f; + + /*set p to co, in case we don't find anything, means a face cut*/ + copy_v3_v3(p, co); + kcd->curbmface = f; + + if (f) { + KnifeEdge *cure = NULL; + ListBase *lst; + Ref *ref; + float dis, curdis=FLT_MAX; + + knife_project_v3(kcd, co, sco); + + /*look through all edges associated with this face*/ + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + + /*project edge vertices into screen space*/ + knife_project_v3(kcd, kfe->v1->co, kfe->v1->sco); + knife_project_v3(kcd, kfe->v2->co, kfe->v2->sco); + + dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco); + if (dis < curdis && dis < maxdist) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float labda= labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco); + float vec[3]; + + vec[0]= kfe->v1->co[0] + labda*(kfe->v2->co[0] - kfe->v1->co[0]); + vec[1]= kfe->v1->co[1] + labda*(kfe->v2->co[1] - kfe->v1->co[1]); + vec[2]= kfe->v1->co[2] + labda*(kfe->v2->co[2] - kfe->v1->co[2]); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(ED_view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + cure = kfe; + curdis = dis; + } + } else { + cure = kfe; + curdis = dis; + } + } + } + + if (fptr) + *fptr = f; + + if (cure && p) { + float d; + + if (!kcd->ignore_edge_snapping || !(cure->e)) { + + closest_to_line_segment_v3(p, sco, cure->v1->sco, cure->v2->sco); + sub_v3_v3(p, cure->v1->sco); + + if (kcd->snap_midpoints) { + d = 0.5f; + } else { + d = len_v3v3(cure->v1->sco, cure->v2->sco); + if (d != 0.0) { + d = len_v3(p) / d; + } + } + + interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d); + } else { + return NULL; + } + } + + return cure; + } + + if (fptr) + *fptr = NULL; + + return NULL; +} + +/*find a vertex near the mouse cursor, if it exists*/ +static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space) +{ + BMFace *f; + float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh); + + if (kcd->ignore_vert_snapping) + maxdist *= 0.5; + + f = knife_find_closest_face(kcd, co, is_space); + + /*set p to co, in case we don't find anything, means a face cut*/ + copy_v3_v3(p, co); + kcd->curbmface = f; + + if (f) { + ListBase *lst; + Ref *ref; + KnifeVert *curv = NULL; + float dis, curdis=FLT_MAX; + + knife_project_v3(kcd, co, sco); + + lst = knife_get_face_kedges(kcd, f); + for (ref=lst->first; ref; ref=ref->next) { + KnifeEdge *kfe = ref->ref; + int i; + + for (i=0; i<2; i++) { + KnifeVert *kfv = i ? kfe->v2 : kfe->v1; + + knife_project_v3(kcd, kfv->co, kfv->sco); + + dis = len_v2v2(kfv->sco, sco); + if (dis < curdis && dis < maxdist) { + if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + float vec[3]; + + copy_v3_v3(vec, kfv->co); + mul_m4_v3(kcd->vc.obedit->obmat, vec); + + if(ED_view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) { + curv = kfv; + curdis = dis; + } + } else { + curv = kfv; + curdis = dis; + } + } + } + } + + if (!kcd->ignore_vert_snapping || !(curv && curv->v)) { + if (fptr) + *fptr = f; + + if (curv && p) { + copy_v3_v3(p, curv->co); + } + + return curv; + } else { + if (fptr) + *fptr = f; + + return NULL; + } + } + + if (fptr) + *fptr = NULL; + + return NULL; +} + +/*update active knife edge/vert pointers*/ +static int knife_update_active(knifetool_opdata *kcd) +{ + kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL; + + kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space); + if (!kcd->curvert) { + kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space); + } + + if (kcd->mode == MODE_DRAGGING) { + knife_find_line_hits(kcd); + } + return 1; +} + +#define MARK 4 +#define DEL 8 +#define VERT_ON_EDGE 16 +#define VERT_ORIG 32 +#define FACE_FLIP 64 +#define BOUNDARY 128 +#define FACE_NEW 256 + +typedef struct facenet_entry { + struct facenet_entry *next, *prev; + KnifeEdge *kfe; +} facenet_entry; + +static void rnd_offset_co(float co[3], float scale) +{ + int i; + + for (i=0; i<3; i++) { + co[i] += (BLI_drand()-0.5)*scale; + } +} + +static void remerge_faces(knifetool_opdata *kcd) +{ + BMesh *bm = kcd->em->bm; + SmallHash svisit, *visit=&svisit; + BMIter iter; + BMFace *f; + BMFace **stack = NULL; + BLI_array_declare(stack); + BMFace **faces = NULL; + BLI_array_declare(faces); + BMOperator bmop; + int idx; + + BMO_InitOpf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY); + + BMO_Exec_Op(bm, &bmop); + BMO_Flag_Buffer(bm, &bmop, "geomout", FACE_NEW, BM_FACE); + + BMO_Finish_Op(bm, &bmop); + + BLI_smallhash_init(visit); + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BMIter eiter; + BMEdge *e; + BMFace *f2; + + if (!BMO_TestFlag(bm, f, FACE_NEW)) + continue; + + if (BLI_smallhash_haskey(visit, (intptr_t)f)) + continue; + + BLI_array_empty(stack); + BLI_array_empty(faces); + BLI_array_append(stack, f); + BLI_smallhash_insert(visit, (intptr_t)f, NULL); + + do { + f2 = BLI_array_pop(stack); + + BLI_array_append(faces, f2); + + BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f2) { + BMIter fiter; + BMFace *f3; + + if (BMO_TestFlag(bm, e, BOUNDARY)) + continue; + + BM_ITER(f3, &fiter, bm, BM_FACES_OF_EDGE, e) { + if (!BMO_TestFlag(bm, f3, FACE_NEW)) + continue; + if (BLI_smallhash_haskey(visit, (intptr_t)f3)) + continue; + + BLI_smallhash_insert(visit, (intptr_t)f3, NULL); + BLI_array_append(stack, f3); + } + } + } while (BLI_array_count(stack) > 0); + + if (BLI_array_count(faces) > 0) { + idx = BM_GetIndex(faces[0]); + + f2 = BM_Join_Faces(bm, faces, BLI_array_count(faces)); + if (f2) { + BMO_SetFlag(bm, f2, FACE_NEW); + BM_SetIndex(f2, idx); + } + } + } +} + +/*use edgenet to fill faces. this is a bit annoying and convoluted.*/ +static void knifenet_fill_faces(knifetool_opdata *kcd) +{ + BMesh *bm = kcd->em->bm; + BMIter bmiter; + BLI_mempool_iter iter; + BMFace *f; + BMEdge *e; + KnifeVert *kfv; + KnifeEdge *kfe; + facenet_entry *entry; + ListBase *face_nets = MEM_callocN(sizeof(ListBase)*bm->totface, "face_nets"); + BMFace **faces = MEM_callocN(sizeof(BMFace*)*bm->totface, "faces knife"); + MemArena *arena = BLI_memarena_new(1<<16, "knifenet_fill_faces"); + SmallHash shash, *hash = &shash; + /* SmallHash shash2, *visited = &shash2; */ /*UNUSED*/ + int i, j, k=0, totface=bm->totface; + + BMO_push(bm, NULL); + bmesh_begin_edit(bm, BMOP_UNTAN_MULTIRES); + + i = 0; + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BM_SetIndex(f, i); + faces[i] = f; + i++; + } + + BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) { + BMO_SetFlag(bm, e, BOUNDARY); + } + + /*turn knife verts into real verts, as necassary*/ + BLI_mempool_iternew(kcd->kverts, &iter); + for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) { + if (!kfv->v) { + kfv->v = BM_Make_Vert(bm, kfv->co, NULL); + kfv->flag = 1; + BMO_SetFlag(bm, kfv->v, DEL); + } else { + kfv->flag = 0; + BMO_SetFlag(bm, kfv->v, VERT_ORIG); + } + + BMO_SetFlag(bm, kfv->v, MARK); + } + + /*we want to only do changed faces. first, go over new edges and add to + face net lists.*/ + i=0; j=0; k=0; + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + Ref *ref; + if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace) + continue; + + i++; + + if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) { + kfe->oe = kfe->e; + continue; + } + + j++; + + if (kfe->e) { + kfe->oe = kfe->e; + + BMO_SetFlag(bm, kfe->e, DEL); + BMO_ClearFlag(bm, kfe->e, BOUNDARY); + kfe->e = NULL; + } + + kfe->e = BM_Make_Edge(bm, kfe->v1->v, kfe->v2->v, NULL, 1); + BMO_SetFlag(bm, kfe->e, BOUNDARY); + + for (ref=kfe->faces.first; ref; ref=ref->next) { + f = ref->ref; + + entry = BLI_memarena_alloc(arena, sizeof(*entry)); + entry->kfe = kfe; + BLI_addtail(face_nets+BM_GetIndex(f), entry); + } + } + + /*go over original edges, and add to faces with new geometry*/ + BLI_mempool_iternew(kcd->kedges, &iter); + for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) { + Ref *ref; + + if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace) + continue; + if (!(kfe->oe && kfe->v1->v == kfe->oe->v1 && kfe->v2->v == kfe->oe->v2)) + continue; + + k++; + + BMO_SetFlag(bm, kfe->e, BOUNDARY); + kfe->oe = kfe->e; + + for (ref=kfe->faces.first; ref; ref=ref->next) { + f = ref->ref; + + if (face_nets[BM_GetIndex(f)].first) { + entry = BLI_memarena_alloc(arena, sizeof(*entry)); + entry->kfe = kfe; + BLI_addtail(face_nets+BM_GetIndex(f), entry); + } + } + } + + for (i=0; i<totface; i++) { + EditFace *efa; + EditVert *eve, *lasteve; + int j; + float rndscale = FLT_EPSILON*25; + + f = faces[i]; + BLI_smallhash_init(hash); + + if (face_nets[i].first) + BMO_SetFlag(bm, f, DEL); + + BLI_begin_edgefill(); + + for (entry=face_nets[i].first; entry; entry=entry->next) { + if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) { + eve = BLI_addfillvert(entry->kfe->v1->v->co); + eve->xs = 0; + rnd_offset_co(eve->co, rndscale); + eve->tmp.p = entry->kfe->v1->v; + BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, eve); + } + + if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) { + eve = BLI_addfillvert(entry->kfe->v2->v->co); + eve->xs = 0; + rnd_offset_co(eve->co, rndscale); + eve->tmp.p = entry->kfe->v2->v; + BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, eve); + } + } + + for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) { + lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1); + eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2); + + eve->xs++; + lasteve->xs++; + } + + for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) { + lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1); + eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2); + + if (eve->xs > 1 && lasteve->xs > 1) { + BLI_addfilledge(lasteve, eve); + + BMO_ClearFlag(bm, entry->kfe->e->v1, DEL); + BMO_ClearFlag(bm, entry->kfe->e->v2, DEL); + } else { + if (lasteve->xs < 2) + BLI_remlink(&fillvertbase, lasteve); + if (eve->xs < 2) + BLI_remlink(&fillvertbase, eve); + } + } + + BLI_edgefill(0); + + for (efa=fillfacebase.first; efa; efa=efa->next) { + BMVert *v1=efa->v3->tmp.p, *v2=efa->v2->tmp.p, *v3=efa->v1->tmp.p; + BMFace *f2; + BMLoop *l; + BMVert *verts[3] = {v1, v2, v3}; + + if (v1 == v2 || v2 == v3 || v1 == v3) + continue; + if (BM_Face_Exists(bm, verts, 3, &f2)) + continue; + + f2 = BM_Make_QuadTri(bm, v1, v2, v3, NULL, NULL, 0); + BMO_SetFlag(bm, f2, FACE_NEW); + + l = bm_firstfaceloop(f2); + do { + BMO_ClearFlag(bm, l->e, DEL); + l = l->next; + } while (l != bm_firstfaceloop(f2)); + + BMO_ClearFlag(bm, f2, DEL); + BM_SetIndex(f2, i); + + BM_Face_UpdateNormal(bm, f2); + if (dot_v3v3(f->no, f2->no) < 0.0) { + BM_flip_normal(bm, f2); + } + } + + BLI_end_edgefill(); + BLI_smallhash_release(hash); + } + + /* interpolate customdata */ + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BMLoop *l1; + BMFace *f2; + BMIter liter1; + + if (!BMO_TestFlag(bm, f, FACE_NEW)) + continue; + + f2 = faces[BM_GetIndex(f)]; + if (BM_GetIndex(f) < 0 || BM_GetIndex(f) >= totface) { + printf("eek!!\n"); + } + + BM_Copy_Attributes(bm, bm, f2, f); + + BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) { + BM_loop_interp_from_face(bm, l1, f2, 1, 1); + } + } + + /*merge triangles back into faces*/ + remerge_faces(kcd); + + /*delete left over faces*/ + BMO_CallOpf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES); + BMO_CallOpf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES); + BMO_CallOpf(bm, "del geom=%fv context=%i", DEL, DEL_VERTS); + + if (face_nets) + MEM_freeN(face_nets); + if (faces) + MEM_freeN(faces); + BLI_memarena_free(arena); + BLI_smallhash_release(hash); + + BMO_ClearStack(bm); /*remerge_faces sometimes raises errors, so make sure to clear them*/ + + bmesh_end_edit(bm, BMOP_UNTAN_MULTIRES); + BMO_pop(bm); +} + +/*called on tool confirmation*/ +static void knifetool_finish(bContext *C, wmOperator *op) +{ + knifetool_opdata *kcd= op->customdata; + + knifenet_fill_faces(kcd); + + DAG_id_tag_update(kcd->ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, kcd->ob->data); +} + +/*copied from paint_image.c*/ +static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend) +{ + int orth= ED_view3d_clip_range_get(v3d, rv3d, clipsta, clipend); + + if (orth) { /* only needed for ortho */ + float fac = 2.0f / ((*clipend) - (*clipsta)); + *clipsta *= fac; + *clipend *= fac; + } + + return orth; +} + +static void knife_recalc_projmat(knifetool_opdata *kcd) +{ + ARegion *ar = CTX_wm_region(kcd->C); + + if (!ar) + return; + + invert_m4_m4(kcd->ob->imat, kcd->ob->obmat); + ED_view3d_ob_project_mat_get(ar->regiondata, kcd->ob, kcd->projmat); + //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->viewmat, kcd->vc.rv3d->winmat); + + kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d, + &kcd->clipsta, &kcd->clipend); +} + +/* called when modal loop selection is done... */ +static void knifetool_exit (bContext *UNUSED(C), wmOperator *op) +{ + knifetool_opdata *kcd= op->customdata; + + if (!kcd) + return; + + /* deactivate the extra drawing stuff in 3D-View */ + ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle); + + /* free the custom data */ + BLI_mempool_destroy(kcd->refs); + BLI_mempool_destroy(kcd->kverts); + BLI_mempool_destroy(kcd->kedges); + + BLI_ghash_free(kcd->origedgemap, NULL, NULL); + BLI_ghash_free(kcd->origvertmap, NULL, NULL); + BLI_ghash_free(kcd->kedgefacemap, NULL, NULL); + + BMBVH_FreeBVH(kcd->bmbvh); + BLI_memarena_free(kcd->arena); + + /* tag for redraw */ + ED_region_tag_redraw(kcd->ar); + + /* destroy kcd itself */ + MEM_freeN(kcd); + op->customdata= NULL; +} + +/* called when modal loop selection gets set up... */ +static int knifetool_init (bContext *C, wmOperator *op, int UNUSED(do_cut)) +{ + knifetool_opdata *kcd; + + /* alloc new customdata */ + kcd= op->customdata= MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data"); + + /* assign the drawing handle for drawing preview line... */ + kcd->ar= CTX_wm_region(C); + kcd->C = C; + kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW); + em_setup_viewcontext(C, &kcd->vc); + + kcd->ob = CTX_data_edit_object(C); + kcd->em= ((Mesh *)kcd->ob->data)->edit_btmesh; + kcd->bmbvh = BMBVH_NewBVH(kcd->em); + kcd->arena = BLI_memarena_new(1<<15, "knife"); + kcd->vthresh = KMAXDIST-1; + kcd->ethresh = KMAXDIST; + + kcd->extend = 1; + + knife_recalc_projmat(kcd); + + ED_region_tag_redraw(kcd->ar); + + kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0, 0); + kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, 0, 1); + kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, 0, 1); + + kcd->origedgemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origedgemap"); + kcd->origvertmap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap"); + kcd->kedgefacemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap"); + + return 1; +} + +static int knifetool_cancel (bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + knifetool_exit(C, op); + return OPERATOR_CANCELLED; +} + +static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt) +{ + knifetool_opdata *kcd; + + view3d_operator_needs_opengl(C); + + if (!knifetool_init(C, op, 0)) + return OPERATOR_CANCELLED; + + /* add a modal handler for this operator - handles loop selection */ + WM_event_add_modal_handler(C, op); + + kcd = op->customdata; + kcd->vc.mval[0] = evt->mval[0]; + kcd->vc.mval[1] = evt->mval[1]; + + return OPERATOR_RUNNING_MODAL; +} + +enum { + KNF_MODAL_CANCEL=1, + KNF_MODAL_CONFIRM, + KNF_MODAL_MIDPOINT_ON, + KNF_MODAL_MIDPOINT_OFF, + KNF_MODAL_NEW_CUT, + KNF_MODEL_IGNORE_SNAP_ON, + KNF_MODEL_IGNORE_SNAP_OFF, + KNF_MODAL_ADD_CUT, +}; + +wmKeyMap* knifetool_modal_keymap(wmKeyConfig *keyconf) +{ + static EnumPropertyItem modal_items[] = { + {KNF_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {KNF_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {KNF_MODAL_MIDPOINT_ON, "SNAP_MIDPOINTS_ON", 0, "Snap To Midpoints On", ""}, + {KNF_MODAL_MIDPOINT_OFF, "SNAP_MIDPOINTS_OFF", 0, "Snap To Midpoints Off", ""}, + {KNF_MODEL_IGNORE_SNAP_ON, "IGNORE_SNAP_ON", 0, "Ignore Snapping On", ""}, + {KNF_MODEL_IGNORE_SNAP_OFF, "IGNORE_SNAP_OFF", 0, "Ignore Snapping Off", ""}, + {KNF_MODAL_NEW_CUT, "NEW_CUT", 0, "End Current Cut", ""}, + {KNF_MODAL_ADD_CUT, "ADD_CUT", 0, "Add Cut", ""}, + + {0, NULL, 0, NULL, NULL}}; + + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Knife Tool Modal Map"); + + /* this function is called for each spacetype, only needs to add map once */ + if(keymap) return NULL; + + keymap= WM_modalkeymap_add(keyconf, "Knife Tool Modal Map", modal_items); + + /* items for modal map */ + WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_ADD_CUT); + WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KNF_MODAL_CONFIRM); + WM_modalkeymap_add_item(keymap, EKEY, KM_PRESS, 0, 0, KNF_MODAL_NEW_CUT); + + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON); + WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF); + WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, KNF_MODAL_MIDPOINT_ON); + WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, KNF_MODAL_MIDPOINT_OFF); + + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON); + WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF); + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_PRESS, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_ON); + WM_modalkeymap_add_item(keymap, RIGHTSHIFTKEY, KM_RELEASE, KM_ANY, 0, KNF_MODEL_IGNORE_SNAP_OFF); + + WM_modalkeymap_assign(keymap, "MESH_OT_knifetool"); + + return keymap; +} + +static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event) +{ + Object *obedit; + knifetool_opdata *kcd= op->customdata; + + if (!C) { + return OPERATOR_FINISHED; + } + + obedit = CTX_data_edit_object(C); + if (!obedit || obedit->type != OB_MESH || ((Mesh*)obedit->data)->edit_btmesh != kcd->em) { + knifetool_exit(C, op); + return OPERATOR_FINISHED; + } + + view3d_operator_needs_opengl(C); + + if (kcd->mode == MODE_PANNING) + kcd->mode = kcd->prevmode; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case KNF_MODAL_CANCEL: + /* finish */ + ED_region_tag_redraw(kcd->ar); + + knifetool_exit(C, op); + + return OPERATOR_CANCELLED; + case KNF_MODAL_CONFIRM: + /* finish */ + ED_region_tag_redraw(kcd->ar); + + knifetool_finish(C, op); + knifetool_exit(C, op); + + return OPERATOR_FINISHED; + case KNF_MODAL_MIDPOINT_ON: + ED_region_tag_redraw(kcd->ar); + kcd->snap_midpoints = 1; + break; + case KNF_MODAL_MIDPOINT_OFF: + ED_region_tag_redraw(kcd->ar); + kcd->snap_midpoints = 0; + break; + case KNF_MODEL_IGNORE_SNAP_ON: + ED_region_tag_redraw(kcd->ar); + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 1; + break; + case KNF_MODEL_IGNORE_SNAP_OFF: + ED_region_tag_redraw(kcd->ar); + kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = 0; + break; + case KNF_MODAL_NEW_CUT: + ED_region_tag_redraw(kcd->ar); + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + break; + case KNF_MODAL_ADD_CUT: + knife_recalc_projmat(kcd); + + if (kcd->mode == MODE_DRAGGING) { + knife_add_cut(kcd); + if (!kcd->extend) { + knife_finish_cut(kcd); + kcd->mode = MODE_IDLE; + } + } else if (kcd->mode != MODE_PANNING) { + knife_start_cut(kcd); + kcd->mode = MODE_DRAGGING; + } + + ED_region_tag_redraw(kcd->ar); + break; + } + } else { /*non-modal-mapped events*/ + switch (event->type) { + case WHEELUPMOUSE: + case WHEELDOWNMOUSE: + return OPERATOR_PASS_THROUGH; + case MIDDLEMOUSE: + if (event->val != KM_RELEASE) { + if (kcd->mode != MODE_PANNING) + kcd->prevmode = kcd->mode; + kcd->mode = MODE_PANNING; + } else { + kcd->mode = kcd->prevmode; + } + + ED_region_tag_redraw(kcd->ar); + return OPERATOR_PASS_THROUGH; + + case MOUSEMOVE: /* mouse moved somewhere to select another loop */ + if (kcd->mode != MODE_PANNING) { + knife_recalc_projmat(kcd); + kcd->vc.mval[0] = event->mval[0]; + kcd->vc.mval[1] = event->mval[1]; + + if (knife_update_active(kcd)) + ED_region_tag_redraw(kcd->ar); + } + + break; + } + } + + /* keep going until the user confirms */ + return OPERATOR_RUNNING_MODAL; +} + +void MESH_OT_knifetool (wmOperatorType *ot) +{ + /* description */ + ot->name= "Knife Topology Tool"; + ot->idname= "MESH_OT_knifetool"; + ot->description= "Cut new topology"; + + /* callbacks */ + ot->invoke= knifetool_invoke; + ot->modal= knifetool_modal; + ot->cancel= knifetool_cancel; + ot->poll= ED_operator_editmesh_view3d; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING; +} diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index 0ec356a88ae..3b7d21199ea 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -15,7 +15,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2007 Blender Foundation. * All rights reserved. @@ -32,6 +32,8 @@ #include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> #include <string.h> #include <ctype.h> #include <stdio.h> @@ -41,7 +43,6 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" -#include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -50,7 +51,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ #include "BLI_editVert.h" -#include "BLI_math.h" +#include "BLI_array.h" #include "BLI_utildefines.h" #include "BKE_blender.h" @@ -61,6 +62,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_array_mallocn.h" +#include "BKE_tessmesh.h" +#include "BKE_depsgraph.h" #include "BIF_gl.h" #include "BIF_glutil.h" /* for paint cursor */ @@ -95,8 +98,8 @@ typedef struct tringselOpData { ViewContext vc; Object *ob; - EditMesh *em; - EditEdge *eed; + BMEditMesh *em; + BMEdge *eed; int extend; int do_cut; @@ -130,17 +133,62 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) } } +/*given two opposite edges in a face, finds the ordering of their vertices so + that cut preview lines won't cross each other*/ +static void edgering_find_order(BMEditMesh *em, BMEdge *lasteed, BMEdge *eed, + BMVert *lastv1, BMVert *v[2][2]) +{ + BMIter liter; + BMLoop *l, *l2; + int rev; + + l = eed->l; + + /*find correct order for v[1]*/ + if (!(BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_LOOP, l) { + if (BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed)) + break; + } + } + + /*this should never happen*/ + if (!l) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + v[1][0] = lasteed->v1; + v[1][1] = lasteed->v2; + return; + } + + l2 = BM_OtherFaceLoop(l->e, l->f, eed->v1); + rev = (l2 == (BMLoop*)l->prev); + while (l2->v != lasteed->v1 && l2->v != lasteed->v2) { + l2 = rev ? (BMLoop*)l2->prev : (BMLoop*)l2->next; + } + + if (l2->v == lastv1) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + } else { + v[0][0] = eed->v2; + v[0][1] = eed->v1; + } +} + static void edgering_sel(tringselOpData *lcd, int previewlines, int select) { - EditMesh *em = lcd->em; - EditEdge *startedge = lcd->eed; - EditEdge *eed; - EditFace *efa; - EditVert *v[2][2]; + BMEditMesh *em = lcd->em; + BMEdge *startedge = lcd->eed; + BMEdge *eed, *lasteed; + BMVert *v[2][2], *lastv1; + BMWalker walker; float (*edges)[2][3] = NULL; - V_DYNDECLARE(edges); + BLI_array_declare(edges); float co[2][3]; - int looking=1, i, tot=0; + int i, tot=0; + + memset(v, 0, sizeof(v)); if (!startedge) return; @@ -152,110 +200,81 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select) } if (!lcd->extend) { - EM_clear_flag_all(lcd->em, SELECT); + EDBM_clear_flag_all(lcd->em, BM_SELECT); } - /* in eed->f1 we put the valence (amount of faces in edge) */ - /* in eed->f2 we put tagged flag as correct loop */ - /* in efa->f1 we put tagged flag as correct to select */ + if (select) { + BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0); + eed = BMW_Begin(&walker, startedge); + for (; eed; eed=BMW_Step(&walker)) { + BM_Select(em->bm, eed, 1); + } + BMW_End(&walker); - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; + return; } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - // tag startedge OK - startedge->f2= 1; - - while(looking) { - looking= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad - if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok - - // if edge tagged, select opposing edge and mark face ok - if(efa->e1->f2) { - efa->e3->f2= 1; - efa->f1= 1; - looking= 1; - } - else if(efa->e2->f2) { - efa->e4->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e3->f2) { - efa->e1->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e4->f2) { - efa->e2->f2= 1; - efa->f1= 1; - looking= 1; - } - } + BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0); + eed = startedge = BMW_Begin(&walker, startedge); + lastv1 = NULL; + for (lasteed=NULL; eed; eed=BMW_Step(&walker)) { + if (lasteed) { + if (lastv1) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; + } else { + v[1][0] = lasteed->v1; + v[1][1] = lasteed->v2; + lastv1 = lasteed->v1; + } + + edgering_find_order(em, lasteed, eed, lastv1, v); + lastv1 = v[0][0]; + + for(i=1;i<=previewlines;i++){ + co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; + co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; + co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; + + co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; + co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; + co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; + + BLI_array_growone(edges); + VECCOPY(edges[tot][0], co[0]); + VECCOPY(edges[tot][1], co[1]); + tot++; } } + lasteed = eed; } - if(previewlines > 0 && !select){ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4 == NULL) { continue; } - if(efa->h == 0){ - if(efa->e1->f2 == 1){ - if(efa->e1->h == 1 || efa->e3->h == 1 ) - continue; - - v[0][0] = efa->v1; - v[0][1] = efa->v2; - v[1][0] = efa->v4; - v[1][1] = efa->v3; - } else if(efa->e2->f2 == 1){ - if(efa->e2->h == 1 || efa->e4->h == 1) - continue; - v[0][0] = efa->v2; - v[0][1] = efa->v3; - v[1][0] = efa->v1; - v[1][1] = efa->v4; - } else { continue; } - - for(i=1;i<=previewlines;i++){ - co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; - co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; - co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; - - co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; - co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; - co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; - - V_GROW(edges); - VECCOPY(edges[tot][0], co[0]); - VECCOPY(edges[tot][1], co[1]); - tot++; - } - } - } - } else { - select = (startedge->f & SELECT) == 0; + if (BM_Edge_Share_Faces(lasteed, startedge)) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; + + edgering_find_order(em, lasteed, startedge, lastv1, v); + + for(i=1;i<=previewlines;i++){ + if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) + continue; + + co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; + co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; + co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; - /* select the edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2) EM_select_edge(eed, select); + co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; + co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; + co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; + + BLI_array_growone(edges); + VECCOPY(edges[tot][0], co[0]); + VECCOPY(edges[tot][1], co[1]); + tot++; } } + BMW_End(&walker); lcd->edges = edges; lcd->totedge = tot; } @@ -265,7 +284,8 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts) if (lcd->eed) { edgering_sel(lcd, cuts, 0); } else if(lcd->edges) { - MEM_freeN(lcd->edges); + if (lcd->edges) + MEM_freeN(lcd->edges); lcd->edges = NULL; lcd->totedge = 0; } @@ -274,17 +294,18 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts) static void ringsel_finish(bContext *C, wmOperator *op) { tringselOpData *lcd= op->customdata; - int cuts= (lcd->do_cut)? RNA_int_get(op->ptr,"number_cuts"): 0; + int cuts= RNA_int_get(op->ptr, "number_cuts"); if (lcd->eed) { - EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data); - + BMEditMesh *em = lcd->em; + edgering_sel(lcd, cuts, 1); if (lcd->do_cut) { - - esubdivideflag(lcd->ob, em, SELECT, 0.0f, 0.0f, 0, cuts, 0, SUBDIV_SELECT_LOOPCUT); - + BM_esubdivideflag(lcd->ob, em->bm, BM_SELECT, 0.0f, + 0.0f, 0, cuts, SUBDIV_SELECT_LOOPCUT, + SUBD_PATH, 0, 0, 0); + /* force edge slide to edge select mode in in face select mode */ if (em->selectmode & SCE_SELECT_FACE) { if (em->selectmode == SCE_SELECT_FACE) @@ -292,33 +313,35 @@ static void ringsel_finish(bContext *C, wmOperator *op) else em->selectmode &= ~SCE_SELECT_FACE; CTX_data_tool_settings(C)->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); + + WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C)); WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C)); } - + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT|ND_DATA, lcd->ob->data); DAG_id_tag_update(lcd->ob->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, lcd->ob->data); } else { /* sets as active, useful for other tools */ if(em->selectmode & SCE_SELECT_VERTEX) - EM_store_selection(em, lcd->eed->v1, EDITVERT); + EDBM_selectmode_flush(em); if(em->selectmode & SCE_SELECT_EDGE) - EM_store_selection(em, lcd->eed, EDITEDGE); + EDBM_selectmode_flush(em); - EM_selectmode_flush(lcd->em); + EDBM_selectmode_flush(lcd->em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, lcd->ob->data); } } } /* called when modal loop selection is done... */ -static void ringsel_exit(wmOperator *op) +static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) { tringselOpData *lcd= op->customdata; - + /* deactivate the extra drawing stuff in 3D-View */ ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); @@ -344,7 +367,7 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut) lcd->ar= CTX_wm_region(C); lcd->draw_handle= ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW); lcd->ob = CTX_data_edit_object(C); - lcd->em= BKE_mesh_get_editmesh((Mesh *)lcd->ob->data); + lcd->em= ((Mesh *)lcd->ob->data)->edit_btmesh; lcd->extend = do_cut ? 0 : RNA_boolean_get(op->ptr, "extend"); lcd->do_cut = do_cut; em_setup_viewcontext(C, &lcd->vc); @@ -354,17 +377,17 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut) return 1; } -static int ringcut_cancel (bContext *UNUSED(C), wmOperator *op) +static int ringcut_cancel (bContext *C, wmOperator *op) { /* this is just a wrapper around exit() */ - ringsel_exit(op); + ringsel_exit(C, op); return OPERATOR_CANCELLED; } static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) { tringselOpData *lcd; - EditEdge *edge; + BMEdge *edge; int dist = 75; view3d_operator_needs_opengl(C); @@ -375,7 +398,7 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) lcd = op->customdata; if (lcd->em->selectmode == SCE_SELECT_FACE) { - ringsel_exit(op); + ringsel_exit(C, op); WM_operator_name_call(C, "MESH_OT_loop_select", WM_OP_INVOKE_REGION_WIN, NULL); return OPERATOR_CANCELLED; } @@ -383,17 +406,13 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) lcd->vc.mval[0] = evt->mval[0]; lcd->vc.mval[1] = evt->mval[1]; - edge = findnearestedge(&lcd->vc, &dist); - if(!edge) { - ringsel_exit(op); - return OPERATOR_CANCELLED; - } + edge = EDBM_findnearestedge(&lcd->vc, &dist); lcd->eed = edge; + ringsel_find_edge(lcd, 1); - ringsel_finish(C, op); - ringsel_exit(op); + ringsel_exit(C, op); return OPERATOR_FINISHED; } @@ -402,7 +421,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) { Object *obedit= CTX_data_edit_object(C); tringselOpData *lcd; - EditEdge *edge; + BMEdge *edge; int dist = 75; if(modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit)) @@ -420,7 +439,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) lcd->vc.mval[0] = evt->mval[0]; lcd->vc.mval[1] = evt->mval[1]; - edge = findnearestedge(&lcd->vc, &dist); + edge = EDBM_findnearestedge(&lcd->vc, &dist); if (edge != lcd->eed) { lcd->eed = edge; ringsel_find_edge(lcd, 1); @@ -430,22 +449,23 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_RUNNING_MODAL; } -static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) +static int loopcut_modal (bContext *C, wmOperator *op, wmEvent *event) { int cuts= RNA_int_get(op->ptr,"number_cuts"); tringselOpData *lcd= op->customdata; view3d_operator_needs_opengl(C); - switch (event->type) { + case RETKEY: case LEFTMOUSE: /* confirm */ // XXX hardcoded if (event->val == KM_PRESS) { /* finish */ ED_region_tag_redraw(lcd->ar); ringsel_finish(C, op); - ringsel_exit(op); + ringsel_exit(C, op); + ED_area_headerprint(CTX_wm_area(C), NULL); return OPERATOR_FINISHED; @@ -454,6 +474,11 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) ED_region_tag_redraw(lcd->ar); break; case RIGHTMOUSE: /* abort */ // XXX hardcoded + ED_region_tag_redraw(lcd->ar); + ringsel_exit(C, op); + ED_area_headerprint(CTX_wm_area(C), NULL); + + return OPERATOR_FINISHED; case ESCKEY: if (event->val == KM_RELEASE) { /* cancel */ @@ -465,33 +490,35 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) ED_region_tag_redraw(lcd->ar); break; - case WHEELUPMOUSE: /* change number of cuts */ case PAGEUPKEY: - if (event->val == KM_PRESS) { - cuts++; - RNA_int_set(op->ptr, "number_cuts",cuts); - ringsel_find_edge(lcd, cuts); - - ED_region_tag_redraw(lcd->ar); - } + case WHEELUPMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + + cuts++; + RNA_int_set(op->ptr,"number_cuts",cuts); + ringsel_find_edge(lcd, cuts); + + ED_region_tag_redraw(lcd->ar); break; - case WHEELDOWNMOUSE: /* change number of cuts */ case PAGEDOWNKEY: - if (event->val == KM_PRESS) { - cuts=MAX2(cuts-1,1); - RNA_int_set(op->ptr,"number_cuts",cuts); - ringsel_find_edge(lcd, cuts); - - ED_region_tag_redraw(lcd->ar); - } + case WHEELDOWNMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + + cuts=MAX2(cuts-1,1); + RNA_int_set(op->ptr,"number_cuts",cuts); + ringsel_find_edge(lcd, cuts); + + ED_region_tag_redraw(lcd->ar); break; case MOUSEMOVE: { /* mouse moved somewhere to select another loop */ int dist = 75; - EditEdge *edge; + BMEdge *edge; lcd->vc.mval[0] = event->mval[0]; lcd->vc.mval[1] = event->mval[1]; - edge = findnearestedge(&lcd->vc, &dist); + edge = EDBM_findnearestedge(&lcd->vc, &dist); if (edge != lcd->eed) { lcd->eed = edge; @@ -529,11 +556,11 @@ void MESH_OT_loopcut (wmOperatorType *ot) /* description */ ot->name= "Loop Cut"; ot->idname= "MESH_OT_loopcut"; - ot->description= "Add a new loop between existing loops"; + ot->description= "Add a new loop between existing loops."; /* callbacks */ ot->invoke= ringcut_invoke; - ot->modal= ringcut_modal; + ot->modal= loopcut_modal; ot->cancel= ringcut_cancel; ot->poll= ED_operator_editmesh_region_view3d; diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index c4a302d4d18..c4df9801400 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -43,6 +43,7 @@ #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_editVert.h" #include "BLI_edgehash.h" @@ -56,6 +57,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "RNA_access.h" #include "RNA_define.h" @@ -72,15 +74,27 @@ #include "mesh_intern.h" +#define GET_CD_DATA(me, data) (me->edit_btmesh ? &me->edit_btmesh->bm->data : &me->data) + static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer) { Mesh *me = ob->data; - CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; + CustomData *data; void *actlayerdata, *rndlayerdata, *clonelayerdata, *stencillayerdata, *layerdata=layer->data; int type= layer->type; - int index= CustomData_get_layer_index(data, type); - int i, actindex, rndindex, cloneindex, stencilindex; + int index; + int i, actindex, rndindex, cloneindex, stencilindex, tot; + if (layer->type == CD_MLOOPCOL || layer->type == CD_MLOOPUV) { + data = (me->edit_btmesh)? &me->edit_btmesh->bm->ldata: &me->ldata; + tot = me->totloop; + } else { + data = (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata; + tot = me->totpoly; + } + + index = CustomData_get_layer_index(data, type); + /* ok, deleting a non-active layer needs to preserve the active layer indices. to do this, we store a pointer to the .data member of both layer and the active layer, (to detect if we're deleting the active layer or not), then use the active @@ -94,15 +108,15 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la stencillayerdata = data->layers[CustomData_get_stencil_layer_index(data, type)].data; CustomData_set_layer_active(data, type, layer - &data->layers[index]); - if(me->edit_mesh) { - EM_free_data_layer(me->edit_mesh, data, type); + if(me->edit_btmesh) { + BM_free_data_layer(me->edit_btmesh->bm, data, type); } else { - CustomData_free_layer_active(data, type, me->totface); + CustomData_free_layer_active(data, type, tot); mesh_update_customdata_pointers(me); } - if(!CustomData_has_layer(data, type) && (type == CD_MCOL && (ob->mode & OB_MODE_VERTEX_PAINT))) + if(!CustomData_has_layer(data, type) && (type == CD_MLOOPCOL && (ob->mode & OB_MODE_VERTEX_PAINT))) ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT); /* reconstruct active layer */ @@ -163,8 +177,13 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la } } -static void copy_editface_active_customdata(EditMesh *em, int type, int index) +static void copy_editface_active_customdata(BMEditMesh *em, int type, int index) { +#if 1 /*BMESH_TODO*/ + (void)em; + (void)type; + (void)index; +#else EditFace *efa; int n= CustomData_get_active_layer(&em->fdata, type); @@ -172,41 +191,56 @@ static void copy_editface_active_customdata(EditMesh *em, int type, int index) void *data= CustomData_em_get_n(&em->fdata, efa->data, type, n); CustomData_em_set_n(&em->fdata, efa->data, type, index, data); } +#endif } int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_set) { - EditMesh *em; + BMEditMesh *em; int layernum; - if(me->edit_mesh) { - em= me->edit_mesh; + if(me->edit_btmesh) { + em= me->edit_btmesh; - layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE); + layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); if(layernum >= MAX_MTFACE) return 0; - EM_add_data_layer(em, &em->fdata, CD_MTFACE, name); + BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY); + CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum); + CustomData_set_layer_name(&em->bm->pdata, CD_MTEXPOLY, layernum, name); if(layernum) /* copy data from active UV */ copy_editface_active_customdata(em, CD_MTFACE, layernum); if(active_set || layernum==0) - CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum); + CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum); + + BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV); + CustomData_set_layer_name(&em->bm->ldata, CD_MLOOPUV, layernum, name); + + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum); + if(active_set || layernum==0) + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum); } else { - layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE); + layernum= CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); if(layernum >= MAX_MTFACE) return 0; - if(me->mtface) - CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name); - else - CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name); - - if(active_set || layernum==0) - CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum); - + if(me->mtpoly) { + CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly, name); + CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name); + } else { + CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, name); + CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name); + } + + if(active_set || layernum==0) { + CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum); + CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum); + } + mesh_update_customdata_pointers(me); } @@ -218,17 +252,22 @@ int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_s int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me) { - CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; - CustomDataLayer *cdl; + CustomData *pdata = GET_CD_DATA(me, pdata), *ldata = GET_CD_DATA(me, ldata); + CustomDataLayer *cdlp, *cdlu; int index; - index= CustomData_get_active_layer_index(data, CD_MTFACE); - cdl= (index == -1) ? NULL: &data->layers[index]; + index= CustomData_get_active_layer_index(pdata, CD_MTEXPOLY); + cdlp= (index == -1)? NULL: &pdata->layers[index]; - if(!cdl) + index= CustomData_get_active_layer_index(ldata, CD_MLOOPUV); + cdlu= (index == -1)? NULL: &ldata->layers[index]; + + if (!cdlp || !cdlu) return 0; - delete_customdata_layer(C, ob, cdl); + delete_customdata_layer(C, ob, cdlp); + delete_customdata_layer(C, ob, cdlu); + DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); @@ -237,39 +276,42 @@ int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me) int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *me, const char *name, int active_set) { - EditMesh *em; - MCol *mcol; + BMEditMesh *em; + MLoopCol *mcol; int layernum; - if(me->edit_mesh) { - em= me->edit_mesh; + if(me->edit_btmesh) { + em= me->edit_btmesh; - layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL); + layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); if(layernum >= MAX_MCOL) return 0; - EM_add_data_layer(em, &em->fdata, CD_MCOL, name); + BM_add_data_layer(em->bm, &em->bm->pdata, CD_MLOOPCOL); + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); + if(layernum) /* copy data from active vertex color layer */ copy_editface_active_customdata(em, CD_MCOL, layernum); if(active_set || layernum==0) - CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum); + CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum); + } else { - layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL); - if(layernum >= MAX_MCOL) + layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL); + if(layernum >= CD_MLOOPCOL) return 0; - mcol= me->mcol; + mcol= me->mloopcol; - if(me->mcol) - CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name); + if(me->mloopcol) + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name); else - CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name); + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); if(active_set || layernum==0) - CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum); + CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum); mesh_update_customdata_pointers(me); } @@ -282,12 +324,11 @@ int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mes int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me) { - CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; CustomDataLayer *cdl; int index; - index= CustomData_get_active_layer_index(data, CD_MCOL); - cdl= (index == -1)? NULL: &data->layers[index]; + index= CustomData_get_active_layer_index(&me->ldata, CD_MLOOPCOL); + cdl= (index == -1)? NULL: &me->ldata.layers[index]; if(!cdl) return 0; @@ -368,25 +409,25 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_CANCELLED; } - /* turn mesh in editmode */ - /* BKE_mesh_get/end_editmesh: ED_uvedit_assign_image also calls this */ + /* put mesh in editmode */ obedit= base->object; me= obedit->data; - if(me->edit_mesh==NULL) { - make_editMesh(scene, obedit); + if(me->edit_btmesh==NULL) { + EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit); exitmode= 1; } - if(me->edit_mesh==NULL) + + if(me->edit_btmesh==NULL) return OPERATOR_CANCELLED; ED_uvedit_assign_image(scene, obedit, ima, NULL); if(exitmode) { - load_editMesh(scene, obedit); - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + EDBM_LoadEditBMesh(scene, obedit); + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; } /* dummie drop support; ensure view shows a result :) */ @@ -572,7 +613,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges) if(calc_edges || (mesh->totface && mesh->totedge == 0)) BKE_mesh_calc_edges(mesh, calc_edges); - mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL); + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL); DAG_id_tag_update(&mesh->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh); @@ -608,15 +649,15 @@ static void mesh_add_verts(Mesh *mesh, int len) mesh->totvert= totvert; } -void ED_mesh_transform(Mesh *me, float *mat) +void ED_mesh_transform(Mesh *mesh, float *mat) { int i; - MVert *mvert= me->mvert; + MVert *mvert= mesh->mvert; - for(i= 0; i < me->totvert; i++, mvert++) + for(i= 0; i < mesh->totvert; i++, mvert++) mul_m4_v3((float (*)[4])mat, mvert->co); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL); } static void mesh_add_edges(Mesh *mesh, int len) @@ -682,7 +723,7 @@ static void mesh_add_faces(Mesh *mesh, int len) /* void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode."); return; } @@ -698,19 +739,18 @@ void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't add faces in edit mode."); return; } - mesh_add_faces(mesh, count); } void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't add edges in edit mode."); - return; + return; } mesh_add_edges(mesh, count); @@ -718,7 +758,7 @@ void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count) void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't add vertices in edit mode."); return; } @@ -726,7 +766,7 @@ void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count) mesh_add_verts(mesh, count); } -void ED_mesh_calc_normals(Mesh *me) +void ED_mesh_calc_normals(Mesh *mesh) { - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL); } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 4d620424b0a..3b33afa8b49 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -37,15 +37,72 @@ #ifndef MESH_INTERN_H #define MESH_INTERN_H +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + +#include "BKE_tessmesh.h" + +#include "BLI_editVert.h" + +#include "RNA_types.h" + struct bContext; struct wmOperatorType; +struct ViewContext; +struct BMEditMesh; +struct BMesh; +struct BMEdge; +struct BMFace; struct wmOperator; +struct wmKeyMap; +struct wmKeyConfig; + +/* ******************** bmeshutils.c */ + +/* +ok: the EDBM module is for editmode bmesh stuff. in contrast, the + BMEdit module is for code shared with blenkernel that concerns + the BMEditMesh structure. +*/ + +/*calls a bmesh op, reporting errors to the user, etc*/ +int EDBM_CallOpf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...); + +/*calls a bmesh op, reporting errors to the user, etc. + + selects an output slot specified by selslot*/ +//int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op, char *selslot, char *fmt, ...); +//moved to ED_mesh.h + +/*same as above, but doesn't report errors.*/ +int EDBM_CallOpfSilent(struct BMEditMesh *em, const char *fmt, ...); + +/*these next two functions are the split version of EDBM_CallOpf, so you can + do stuff with a bmesh operator, after initializing it but before executing + it. + + execute the operator with BM_Exec_Op*/ +int EDBM_InitOpf(struct BMEditMesh *em, struct BMOperator *bmop, + struct wmOperator *op, const char *fmt, ...); +/*cleans up after a bmesh operator*/ +int EDBM_FinishOp(struct BMEditMesh *em, struct BMOperator *bmop, + struct wmOperator *op, int report); + +void EDBM_clear_flag_all(struct BMEditMesh *em, int flag); +void EDBM_store_selection(struct BMEditMesh *em, void *data); +void EDBM_validate_selections(struct BMEditMesh *em); +void EDBM_remove_selection(struct BMEditMesh *em, void *data); +void EDBM_stats_update(struct BMEditMesh *em); + +/* TODO, move to math_geometry.c */ +float labda_PdistVL2Dfl(const float v1[3], const float v2[3], const float v3[3]); /* ******************** editface.c */ -int edgetag_context_check(Scene *scene, EditEdge *eed); -void edgetag_context_set(Scene *scene, EditEdge *eed, int val); -int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target); +int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed); +void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val); +int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target); /* ******************* editmesh.c */ @@ -53,6 +110,10 @@ extern void free_editvert(EditMesh *em, EditVert *eve); extern void free_editedge(EditMesh *em, EditEdge *eed); extern void free_editface(EditMesh *em, EditFace *efa); +/*frees dst mesh, then copies the contents of + *src (the struct) to dst. */ +void set_editMesh(EditMesh *dst, EditMesh *src); + extern void free_vertlist(EditMesh *em, ListBase *edve); extern void free_edgelist(EditMesh *em, ListBase *lb); extern void free_facelist(EditMesh *em, ListBase *lb); @@ -64,7 +125,7 @@ extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct Ed extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges); extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2); -void em_setup_viewcontext(struct bContext *C, ViewContext *vc); +void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); void MESH_OT_separate(struct wmOperatorType *ot); @@ -136,13 +197,16 @@ extern struct EditFace *EM_face_from_faces(EditMesh *em, struct EditFace *efa1, extern int EM_view3d_poll(struct bContext *C); -/* ******************* editmesh_loop.c */ +struct wmKeyMap* knifetool_modal_keymap(struct wmKeyConfig *keyconf); + +/* ******************* knifetool.c */ void MESH_OT_knife_cut(struct wmOperatorType *ot); -/* ******************* editmesh_mods.c */ +/* ******************* bmesh_select.c */ void MESH_OT_loop_select(struct wmOperatorType *ot); void MESH_OT_select_all(struct wmOperatorType *ot); +void MESH_OT_bmesh_test(struct wmOperatorType *ot); void MESH_OT_select_more(struct wmOperatorType *ot); void MESH_OT_select_less(struct wmOperatorType *ot); void MESH_OT_select_inverse(struct wmOperatorType *ot); @@ -152,6 +216,7 @@ void MESH_OT_select_linked_pick(struct wmOperatorType *ot); void MESH_OT_hide(struct wmOperatorType *ot); void MESH_OT_reveal(struct wmOperatorType *ot); void MESH_OT_select_by_number_vertices(struct wmOperatorType *ot); +void MESH_OT_select_loose_verts(struct wmOperatorType *ot); void MESH_OT_select_mirror(struct wmOperatorType *ot); void MESH_OT_normals_make_consistent(struct wmOperatorType *ot); void MESH_OT_faces_select_linked_flat(struct wmOperatorType *ot); @@ -164,32 +229,12 @@ void MESH_OT_mark_seam(struct wmOperatorType *ot); void MESH_OT_mark_sharp(struct wmOperatorType *ot); void MESH_OT_vertices_smooth(struct wmOperatorType *ot); void MESH_OT_noise(struct wmOperatorType *ot); +void EXPORT_MESH_OT_wavefront(struct wmOperatorType *ot); void MESH_OT_flip_normals(struct wmOperatorType *ot); void MESH_OT_solidify(struct wmOperatorType *ot); void MESH_OT_select_nth(struct wmOperatorType *ot); - - -extern EditEdge *findnearestedge(ViewContext *vc, int *dist); -void editmesh_select_by_material(EditMesh *em, int index); -void EM_recalc_normal_direction(EditMesh *em, int inside, int select); /* makes faces righthand turning */ -void EM_select_more(EditMesh *em); -void selectconnected_mesh_all(EditMesh *em); -void faceloop_select(EditMesh *em, EditEdge *startedge, int select); - -/** - * findnearestvert - * - * dist (in/out): minimal distance to the nearest and at the end, actual distance - * sel: selection bias - * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts - * if 0, unselected vertice are given the bias - * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased - */ -extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict); - - -/* ******************* editmesh_tools.c */ - +void MESH_OT_select_next_loop(struct wmOperatorType *ot); + #define SUBDIV_SELECT_ORIG 0 #define SUBDIV_SELECT_INNER 1 #define SUBDIV_SELECT_INNER_SEL 2 @@ -232,9 +277,12 @@ void MESH_OT_region_to_loop(struct wmOperatorType *ot); void MESH_OT_select_axis(struct wmOperatorType *ot); void MESH_OT_uvs_rotate(struct wmOperatorType *ot); -void MESH_OT_uvs_mirror(struct wmOperatorType *ot); +//void MESH_OT_uvs_mirror(struct wmOperatorType *ot); +void MESH_OT_uvs_reverse(struct wmOperatorType *ot); void MESH_OT_colors_rotate(struct wmOperatorType *ot); -void MESH_OT_colors_mirror(struct wmOperatorType *ot); +//void MESH_OT_colors_mirror(struct wmOperatorType *ot); + +void MESH_OT_colors_reverse(struct wmOperatorType *ot); void MESH_OT_delete(struct wmOperatorType *ot); void MESH_OT_rip(struct wmOperatorType *ot); @@ -253,8 +301,20 @@ void MESH_OT_sticky_add(struct wmOperatorType *ot); void MESH_OT_sticky_remove(struct wmOperatorType *ot); void MESH_OT_drop_named_image(struct wmOperatorType *ot); +/* ************* bmesh_tools.c ***********/ +void MESH_OT_vert_connect(struct wmOperatorType *ot); +void MESH_OT_edge_split(struct wmOperatorType *ot); +void MESH_OT_extrude_region(struct wmOperatorType *ot); +void MESH_OT_extrude_verts_indiv(struct wmOperatorType *ot); +void MESH_OT_extrude_edges_indiv(struct wmOperatorType *ot); +void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot); +void MESH_OT_bm_test(struct wmOperatorType *ot); + void MESH_OT_edgering_select(struct wmOperatorType *ot); void MESH_OT_loopcut(struct wmOperatorType *ot); +void MESH_OT_knifetool(struct wmOperatorType *ot); +void MESH_OT_bevel(struct wmOperatorType *ot); + #endif // MESH_INTERN_H diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 282eeef906f..82d925c4ff3 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -59,6 +59,7 @@ /**************************** registration **********************************/ +void EXPORT_MESH_OT_wavefront(wmOperatorType *ot); void ED_operatortypes_mesh(void) { WM_operatortype_append(MESH_OT_select_all); @@ -72,6 +73,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_hide); WM_operatortype_append(MESH_OT_reveal); WM_operatortype_append(MESH_OT_select_by_number_vertices); + WM_operatortype_append(MESH_OT_select_loose_verts); WM_operatortype_append(MESH_OT_select_mirror); WM_operatortype_append(MESH_OT_normals_make_consistent); WM_operatortype_append(MESH_OT_merge); @@ -87,16 +89,18 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_primitive_monkey_add); WM_operatortype_append(MESH_OT_primitive_uv_sphere_add); WM_operatortype_append(MESH_OT_primitive_ico_sphere_add); - WM_operatortype_append(MESH_OT_fgon_clear); - WM_operatortype_append(MESH_OT_fgon_make); WM_operatortype_append(MESH_OT_duplicate); WM_operatortype_append(MESH_OT_remove_doubles); WM_operatortype_append(MESH_OT_vertices_sort); WM_operatortype_append(MESH_OT_vertices_randomize); - WM_operatortype_append(MESH_OT_extrude); WM_operatortype_append(MESH_OT_spin); WM_operatortype_append(MESH_OT_screw); - + + WM_operatortype_append(MESH_OT_extrude_region); + WM_operatortype_append(MESH_OT_extrude_faces_indiv); + WM_operatortype_append(MESH_OT_extrude_edges_indiv); + WM_operatortype_append(MESH_OT_extrude_verts_indiv); + WM_operatortype_append(MESH_OT_split); WM_operatortype_append(MESH_OT_extrude_repeat); WM_operatortype_append(MESH_OT_edge_rotate); @@ -106,9 +110,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_select_axis); WM_operatortype_append(MESH_OT_uvs_rotate); - WM_operatortype_append(MESH_OT_uvs_mirror); WM_operatortype_append(MESH_OT_colors_rotate); - WM_operatortype_append(MESH_OT_colors_mirror); WM_operatortype_append(MESH_OT_fill); WM_operatortype_append(MESH_OT_beautify_fill); @@ -117,7 +119,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_edge_flip); WM_operatortype_append(MESH_OT_faces_shade_smooth); WM_operatortype_append(MESH_OT_faces_shade_flat); - WM_operatortype_append(MESH_OT_sort_faces); + //WM_operatortype_append(MESH_OT_sort_faces); WM_operatortype_append(MESH_OT_delete); @@ -133,7 +135,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_vertices_smooth); WM_operatortype_append(MESH_OT_noise); WM_operatortype_append(MESH_OT_flip_normals); - WM_operatortype_append(MESH_OT_knife_cut); + //WM_operatortype_append(MESH_OT_knife_cut); WM_operatortype_append(MESH_OT_rip); WM_operatortype_append(MESH_OT_blend_from_shape); WM_operatortype_append(MESH_OT_shape_propagate_to_all); @@ -151,6 +153,14 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_solidify); WM_operatortype_append(MESH_OT_select_nth); + WM_operatortype_append(MESH_OT_vert_connect); + WM_operatortype_append(MESH_OT_knifetool); + + WM_operatortype_append(MESH_OT_bevel); + + WM_operatortype_append(MESH_OT_select_next_loop); + + WM_operatortype_append(EXPORT_MESH_OT_wavefront); } #if 0 /* UNUSED, remove? */ @@ -158,7 +168,7 @@ static int ED_operator_editmesh_face_select(bContext *C) { Object *obedit= CTX_data_edit_object(C); if(obedit && obedit->type==OB_MESH) { - EditMesh *em = ((Mesh *)obedit->data)->edit_mesh; + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; if (em && em->selectmode & SCE_SELECT_FACE) { return 1; } @@ -194,31 +204,28 @@ void ED_operatormacros_mesh(void) ot= WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move", OPTYPE_UNDO|OPTYPE_REGISTER); ot->description = "Extrude region and move result"; - otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude"); - RNA_enum_set(otmacro->ptr, "type", 1); + otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); RNA_enum_set(otmacro->ptr, "proportional", 0); RNA_boolean_set(otmacro->ptr, "mirror", 0); ot= WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", OPTYPE_UNDO|OPTYPE_REGISTER); ot->description = "Extrude faces and move result"; - otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude"); - RNA_enum_set(otmacro->ptr, "type", 2); + otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv"); otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten"); RNA_enum_set(otmacro->ptr, "proportional", 0); RNA_boolean_set(otmacro->ptr, "mirror", 0); ot= WM_operatortype_append_macro("MESH_OT_extrude_edges_move", "Extrude Only Edges and Move", OPTYPE_UNDO|OPTYPE_REGISTER); ot->description = "Extrude edges and move result"; - otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude"); - RNA_enum_set(otmacro->ptr, "type", 3); + otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv"); otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); RNA_enum_set(otmacro->ptr, "proportional", 0); RNA_boolean_set(otmacro->ptr, "mirror", 0); ot= WM_operatortype_append_macro("MESH_OT_extrude_vertices_move", "Extrude Only Vertices and Move", OPTYPE_UNDO|OPTYPE_REGISTER); ot->description = "Extrude vertices and move result"; - otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude"); + otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv"); RNA_enum_set(otmacro->ptr, "type", 4); otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); RNA_enum_set(otmacro->ptr, "proportional", 0); @@ -284,6 +291,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_fill", FKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "MESH_OT_beautify_fill", FKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); + WM_keymap_add_item(keymap, "MESH_OT_quads_convert_to_tris", TKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "MESH_OT_tris_convert_to_quads", JKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "MESH_OT_edge_flip", FKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0); @@ -301,7 +309,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_menu(keymap, "INFO_MT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "MESH_OT_vert_connect", YKEY, KM_PRESS, 0, 0); /* use KM_CLICK because same key is used for tweaks */ WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0); @@ -310,8 +318,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "MESH_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "MESH_OT_delete", DELKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, 0, KKEY); - RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/); + WM_keymap_add_item(keymap, "MESH_OT_knifetool", KKEY, KM_PRESS, 0, 0); + //RNA_enum_set(WM_keymap_add_item(keymap, "MESH_OT_knife_cut", LEFTMOUSE, KM_PRESS, KM_SHIFT, KKEY)->ptr, "type", 2/*KNIFE_MIDPOINT*/); WM_keymap_add_item(keymap, "OBJECT_OT_vertex_parent_set", PKEY, KM_PRESS, KM_CTRL, 0); @@ -331,5 +339,6 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) } ED_object_generic_keymap(keyconf, keymap, 3); + knifetool_modal_keymap(keyconf); } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 763e82b8b53..aa38950884b 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -68,6 +68,7 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "BKE_multires.h" #include "BLO_sys_types.h" // for intptr_t support @@ -81,14 +82,14 @@ /* own include */ #include "mesh_intern.h" - +#include "uvedit_intern.h" /* * ********************** no editmode!!! *********** */ /*********************** JOIN ***************************/ /* join selected meshes into the active mesh, context sensitive -return 0 if no join is made (error) and 1 of the join is done */ +return 0 if no join is made (error) and 1 if the join is done */ int join_mesh_exec(bContext *C, wmOperator *op) { @@ -100,15 +101,17 @@ int join_mesh_exec(bContext *C, wmOperator *op) MVert *mvert, *mv; MEdge *medge = NULL; MFace *mface = NULL; + MPoly *mpoly = NULL; + MLoop *mloop = NULL; Key *key, *nkey=NULL; KeyBlock *kb, *okb, *kbn; float imat[4][4], cmat[4][4], *fp1, *fp2, curpos; int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0; - int vertofs, *matmap=NULL; - int i, j, index, haskey=0, edgeofs, faceofs; + int totloop=0, totpoly=0, vertofs, *matmap=NULL; + int i, j, index, haskey=0, edgeofs, faceofs, loopofs, polyofs; bDeformGroup *dg, *odg; MDeformVert *dvert; - CustomData vdata, edata, fdata; + CustomData vdata, edata, fdata, ldata, pdata; if(scene->obedit) { BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode"); @@ -129,6 +132,8 @@ int join_mesh_exec(bContext *C, wmOperator *op) totvert+= me->totvert; totedge+= me->totedge; totface+= me->totface; + totloop+= me->totloop; + totpoly+= me->totpoly; totmat+= base->object->totcol; if(base->object == ob) @@ -282,14 +287,20 @@ int join_mesh_exec(bContext *C, wmOperator *op) memset(&vdata, 0, sizeof(vdata)); memset(&edata, 0, sizeof(edata)); memset(&fdata, 0, sizeof(fdata)); + memset(&ldata, 0, sizeof(ldata)); + memset(&pdata, 0, sizeof(pdata)); mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge); mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface); + mloop= CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); + mpoly= CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); vertofs= 0; edgeofs= 0; faceofs= 0; + loopofs= 0; + polyofs= 0; /* inverse transform for all selected meshes in this object */ invert_m4_m4(imat, ob->obmat); @@ -413,9 +424,6 @@ int join_mesh_exec(bContext *C, wmOperator *op) } } - if(base->object!=ob) - multiresModifier_prepare_join(scene, base->object, ob); - CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface); CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface); @@ -442,14 +450,51 @@ int join_mesh_exec(bContext *C, wmOperator *op) medge->v1+= vertofs; medge->v2+= vertofs; } + } + + if (me->totloop) { + if(base->object!=ob) + multiresModifier_prepare_join(scene, base->object, ob); - edgeofs += me->totedge; + CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop); + CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop); + + for(a=0; a<me->totloop; a++, mloop++) { + mloop->v += vertofs; + mloop->e += edgeofs; + } } - /* vertofs is used to help newly added verts be reattached to their edge/face - * (cannot be set earlier, or else reattaching goes wrong) + if(me->totpoly) { + /* make mapping for materials */ + for(a=1; a<=base->object->totcol; a++) { + ma= give_current_material(base->object, a); + + for(b=0; b<totcol; b++) { + if(ma == matar[b]) { + matmap[a-1]= b; + break; + } + } + } + + CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly); + CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly); + + for(a=0; a<me->totpoly; a++, mpoly++) { + mpoly->loopstart += loopofs; + mpoly->mat_nr= matmap ? matmap[(int)mpoly->mat_nr] : 0; + } + + polyofs += me->totpoly; + } + + /* these are used for relinking (cannot be set earlier, + * or else reattaching goes wrong) */ vertofs += me->totvert; + edgeofs += me->totedge; + loopofs += me->totloop; /* free base, now that data is merged */ if(base->object != ob) @@ -464,14 +509,20 @@ int join_mesh_exec(bContext *C, wmOperator *op) CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); me->totvert= totvert; me->totedge= totedge; me->totface= totface; + me->totloop= totloop; + me->totpoly= totpoly; me->vdata= vdata; me->edata= edata; me->fdata= fdata; + me->ldata= ldata; + me->pdata= pdata; mesh_update_customdata_pointers(me); @@ -530,11 +581,11 @@ int join_mesh_exec(bContext *C, wmOperator *op) ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO); #else /* toggle editmode using lower level functions so this can be called from python */ - make_editMesh(scene, ob); - load_editMesh(scene, ob); - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + EDBM_MakeEditBMesh(scene->toolsettings, scene, ob); + EDBM_LoadEditBMesh(scene, ob); + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA); #endif WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene); @@ -761,7 +812,7 @@ static struct { /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) +intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, float *co, char mode) { MocNode **bt; @@ -787,10 +838,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) * we are using the undeformed coordinates*/ INIT_MINMAX(min, max); - if(em && me->edit_mesh==em) { - EditVert *eve; + if(em && me->edit_btmesh==em) { + BMIter iter; + BMVert *eve; - for(eve= em->verts.first; eve; eve= eve->next) + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) DO_MINMAX(eve->co, min, max) } else { @@ -822,10 +874,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode) MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table"); - if(em && me->edit_mesh==em) { - EditVert *eve; + if(em && me->edit_btmesh==em) { + BMVert *eve; + BMIter iter; - for(eve= em->verts.first; eve; eve= eve->next) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve)); } } @@ -887,27 +940,23 @@ long mesh_mirrtopo_table(Object *ob, char mode) Mesh *me= ob->data; if( (mesh_topo_lookup==NULL) || (mesh_topo_lookup_mode != ob->mode) || - (me->edit_mesh && me->edit_mesh->totvert != mesh_topo_lookup_tot) || - (me->edit_mesh==NULL && me->totvert != mesh_topo_lookup_tot) + (me->edit_btmesh && me->edit_btmesh->bm->totvert != mesh_topo_lookup_tot) || + (me->edit_btmesh==NULL && me->totvert != mesh_topo_lookup_tot) ) { mesh_mirrtopo_table(ob, 's'); } } else if(mode=='s') { /* start table */ Mesh *me= ob->data; MEdge *medge; - EditMesh *em= me->edit_mesh; - void **eve_tmp_back= NULL; /* some of the callers are using eve->tmp so restore after */ - - - /* editmode*/ - EditEdge *eed; - - int a, last, totvert; - int totUnique= -1, totUniqueOld= -1; - + BMEditMesh *em= me->edit_btmesh; + BMEdge *eed; + BMIter iter; MIRRHASH_TYPE *MirrTopoHash = NULL; MIRRHASH_TYPE *MirrTopoHash_Prev = NULL; MirrTopoPair *MirrTopoPairs; + int a, last, totvert; + int totUnique= -1, totUniqueOld= -1; + mesh_topo_lookup_mode= ob->mode; /* reallocate if needed */ @@ -917,12 +966,12 @@ long mesh_mirrtopo_table(Object *ob, char mode) } if(em) { - EditVert *eve; + BMVert *eve; + totvert= 0; - eve_tmp_back= MEM_callocN( em->totvert * sizeof(void *), "TopoMirr" ); - for(eve= em->verts.first; eve; eve= eve->next) { - eve_tmp_back[totvert]= eve->tmp.p; - eve->tmp.l = totvert++; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(eve, totvert); + totvert++; } } else { @@ -933,9 +982,9 @@ long mesh_mirrtopo_table(Object *ob, char mode) /* Initialize the vert-edge-user counts used to detect unique topology */ if(em) { - for(eed=em->edges.first; eed; eed= eed->next) { - MirrTopoHash[eed->v1->tmp.l]++; - MirrTopoHash[eed->v2->tmp.l]++; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + MirrTopoHash[BM_GetIndex(eed->v1)]++; + MirrTopoHash[BM_GetIndex(eed->v2)]++; } } else { for(a=0, medge=me->medge; a<me->totedge; a++, medge++) { @@ -951,9 +1000,9 @@ long mesh_mirrtopo_table(Object *ob, char mode) /* use the number of edges per vert to give verts unique topology IDs */ if(em) { - for(eed=em->edges.first; eed; eed= eed->next) { - MirrTopoHash[eed->v1->tmp.l] += MirrTopoHash_Prev[eed->v2->tmp.l]; - MirrTopoHash[eed->v2->tmp.l] += MirrTopoHash_Prev[eed->v1->tmp.l]; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + MirrTopoHash[BM_GetIndex(eed->v1)] += MirrTopoHash_Prev[BM_GetIndex(eed->v2)]; + MirrTopoHash[BM_GetIndex(eed->v2)] += MirrTopoHash_Prev[BM_GetIndex(eed->v1)]; } } else { for(a=0, medge=me->medge; a<me->totedge; a++, medge++) { @@ -985,19 +1034,6 @@ long mesh_mirrtopo_table(Object *ob, char mode) memcpy(MirrTopoHash_Prev, MirrTopoHash, sizeof(MIRRHASH_TYPE) * totvert); } - /* restore eve->tmp.* */ - if(eve_tmp_back) { - EditVert *eve; - totvert= 0; - for(eve= em->verts.first; eve; eve= eve->next) { - eve->tmp.p= eve_tmp_back[totvert++]; - } - - MEM_freeN(eve_tmp_back); - eve_tmp_back= NULL; - } - - /* Hash/Index pairs are needed for sorting to find index pairs */ MirrTopoPairs= MEM_callocN( sizeof(MirrTopoPair) * totvert, "MirrTopoPairs"); @@ -1005,7 +1041,7 @@ long mesh_mirrtopo_table(Object *ob, char mode) mesh_topo_lookup = MEM_mallocN( totvert * sizeof(long), "mesh_topo_lookup" ); if(em) { - EM_init_index_arrays(em,1,0,0); + EDBM_init_index_arrays(em,1,0,0); } @@ -1029,8 +1065,8 @@ long mesh_mirrtopo_table(Object *ob, char mode) if ((a==totvert) || (MirrTopoPairs[a-1].hash != MirrTopoPairs[a].hash)) { if (a-last==2) { if(em) { - mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-2].vIndex); - mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-1].vIndex); + mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-2].vIndex); + mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-1].vIndex); } else { mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = MirrTopoPairs[a-2].vIndex; mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = MirrTopoPairs[a-1].vIndex; @@ -1040,7 +1076,7 @@ long mesh_mirrtopo_table(Object *ob, char mode) } } if(em) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } MEM_freeN( MirrTopoPairs ); @@ -1090,9 +1126,10 @@ int mesh_get_x_mirror_vert(Object *ob, int index) } else { return mesh_get_x_mirror_vert_spacial(ob, index); } + return 0; } -static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, float *co) +static BMVert *editbmesh_get_x_mirror_vert_spacial(Object *ob, BMEditMesh *em, float *co) { float vec[3]; intptr_t poinval; @@ -1110,20 +1147,28 @@ static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, fl poinval= mesh_octree_table(ob, em, vec, 'u'); if(poinval != -1) - return (EditVert *)(poinval); + return (BMVert *)(poinval); return NULL; } -static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em, EditVert *eve, int index) +static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *em, BMVert *eve, int index) { long poinval; if (mesh_mirrtopo_table(ob, 'u')==-1) return NULL; if (index == -1) { - index = BLI_findindex(&em->verts, eve); - - if (index == -1) { + BMIter iter; + BMVert *v; + + index = 0; + BM_ITER(v, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (v == eve) + break; + index++; + } + + if (index == em->bm->totvert) { return NULL; } } @@ -1131,22 +1176,23 @@ static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em poinval= mesh_topo_lookup[ index ]; if(poinval != -1) - return (EditVert *)(poinval); + return (BMVert *)(poinval); return NULL; } -EditVert *editmesh_get_x_mirror_vert(Object *ob, struct EditMesh *em, EditVert *eve, float *co, int index) +BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *eve, float *co, int index) { + //BMESH_TODO use this flag, ME_EDIT_MIRROR_TOPO, at appropriate places if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) { - return editmesh_get_x_mirror_vert_topo(ob, em, eve, index); + return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index); } else { - return editmesh_get_x_mirror_vert_spacial(ob, em, co); + return editbmesh_get_x_mirror_vert_spacial(ob, em, co); } } -#if 0 -float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_cent) + +static float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent) { float vec[2]; float cent_vec[2]; @@ -1174,26 +1220,29 @@ float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_ /* TODO - Optimize */ { - EditFace *efa; - int i, len; - for(efa=em->faces.first; efa; efa=efa->next) { - MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uv_center(tf->uv, cent, (void *)efa->v4); - + BMIter iter; + BMFace *efa; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + poly_uv_center(em, efa, cent); + if ( (fabs(cent[0] - cent_vec[0]) < 0.001) && (fabs(cent[1] - cent_vec[1]) < 0.001) ) { - len = efa->v4 ? 4 : 3; - for (i=0; i<len; i++) { - if ( (fabs(tf->uv[i][0] - vec[0]) < 0.001) && (fabs(tf->uv[i][1] - vec[1]) < 0.001) ) { - return tf->uv[i]; - } + BMIter liter; + BMLoop *l; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if ( (fabs(luv->uv[0] - vec[0]) < 0.001) && (fabs(luv->uv[1] - vec[1]) < 0.001) ) { + return luv->uv; + } } } } + } return NULL; } -#endif static unsigned int mirror_facehash(const void *ptr) { @@ -1241,7 +1290,7 @@ static int mirror_facecmp(const void *a, const void *b) return (mirror_facerotation((MFace*)a, (MFace*)b) == -1); } -int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em) +int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em) { Mesh *me= ob->data; MVert *mv, *mvert= me->mvert; diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index b007e30422d..4ffa2b76704 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -556,7 +556,7 @@ static void freeMetaElemlist(ListBase *lb) } -static void undoMball_to_editMball(void *lbu, void *lbe) +static void undoMball_to_editMball(void *lbu, void *lbe, void *UNUSED(obe)) { ListBase *lb= lbu; ListBase *editelems= lbe; @@ -574,7 +574,7 @@ static void undoMball_to_editMball(void *lbu, void *lbe) } -static void *editMball_to_undoMball(void *lbe) +static void *editMball_to_undoMball(void *lbe, void *UNUSED(obe)) { ListBase *editelems= lbe; ListBase *lb; diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index 14b40d55f11..58496a914cb 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../gpu ../../ikplugin ../../imbuf diff --git a/source/blender/editors/object/SConscript b/source/blender/editors/object/SConscript index 660643fbb0f..5db12f32d8b 100644 --- a/source/blender/editors/object/SConscript +++ b/source/blender/editors/object/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc ../../blenloader' -incs += ' ../../makesrna ../../python ../../ikplugin' +incs += ' ../../makesrna ../../python ../../ikplugin ../../bmesh' incs += ' ../../render/extern/include ../../gpu' # for object_bake.c defs = [] diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 7ca172c6945..c758954b235 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -229,7 +229,8 @@ int ED_object_add_generic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(ev return op->type->exec(C, op); } -int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, float *rot, int *enter_editmode, unsigned int *layer) +int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, + float *rot, int *enter_editmode, unsigned int *layer, int *is_view_aligned) { View3D *v3d = CTX_wm_view3d(C); int a, layer_values[20]; @@ -275,7 +276,9 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, floa else RNA_float_get_array(op->ptr, "rotation", rot); - + if (is_view_aligned) + *is_view_aligned = view_align; + RNA_float_get_array(op->ptr, "location", loc); if(*layer == 0) { @@ -288,7 +291,8 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, floa /* for object add primitive operators */ /* do not call undo push in this function (users of this function have to) */ -Object *ED_object_add_type(bContext *C, int type, float *loc, float *rot, int enter_editmode, unsigned int layer) +Object *ED_object_add_type(bContext *C, int type, float *loc, float *rot, + int enter_editmode, unsigned int layer) { Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); @@ -325,7 +329,7 @@ static int object_add_exec(bContext *C, wmOperator *op) unsigned int layer; float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; ED_object_add_type(C, RNA_enum_get(op->ptr, "type"), loc, rot, enter_editmode, layer); @@ -382,7 +386,7 @@ static Object *effector_add_type(bContext *C, wmOperator *op, int type) object_add_generic_invoke_options(C, op); - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return NULL; if(type==PFIELD_GUIDE) { @@ -462,7 +466,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op) object_add_generic_invoke_options(C, op); - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; ob= ED_object_add_type(C, OB_CAMERA, loc, rot, FALSE, layer); @@ -516,7 +520,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op) object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; if(obedit==NULL || obedit->type!=OB_MBALL) { @@ -585,7 +589,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; if(obedit && obedit->type==OB_FONT) @@ -626,7 +630,7 @@ static int object_armature_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; object_add_generic_invoke_options(C, op); // XXX these props don't get set right when only exec() is called - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; if ((obedit==NULL) || (obedit->type != OB_ARMATURE)) { @@ -692,7 +696,7 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; object_add_generic_invoke_options(C, op); - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; ob= ED_object_add_type(C, OB_LAMP, loc, rot, FALSE, layer); @@ -741,7 +745,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op) float loc[3], rot[3]; object_add_generic_invoke_options(C, op); - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL)) return OPERATOR_CANCELLED; if(group) { @@ -1173,7 +1177,7 @@ static int convert_exec(bContext *C, wmOperator *op) dm= mesh_get_derived_final(scene, newob, CD_MASK_MESH); /* dm= mesh_create_derived_no_deform(ob1, NULL); this was called original (instead of get_derived). man o man why! (ton) */ - DM_to_mesh(dm, newob->data); + DM_to_mesh(dm, newob->data, newob); dm->release(dm); object_free_modifiers(newob); /* after derivedmesh calls! */ diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index bdd911d68ee..b22536cc368 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -360,6 +360,16 @@ static int multiresbake_test_break(MultiresBakeRender *bkr) static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData passKnownData, MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData) { +#if 1 // BMESH_TODO + (void)bkr; + (void)ima; + (void)passKnownData; + (void)initBakeData; + (void)applyBakeData; + (void)freeBakeData; + + printf("BMESH_TODO" AT "\n"); +#else DerivedMesh *dm= bkr->lores_dm; ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); const int lvl= bkr->lvl; @@ -442,6 +452,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData if(freeBakeData) freeBakeData(data.bake_data); } +#endif // BMESH_TODO } static void interp_bilinear_quad_data(float data[4][3], float u, float v, float res[3]) @@ -504,6 +515,16 @@ static void interp_bilinear_grid(DMGridData *grid, int grid_size, float crn_x, f static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, const int lvl, const int face_index, const float u, const float v, float co[3], float n[3]) { +#if 1 // BMESH_TODO + (void)lodm; + (void)hidm; + (void)lvl; + (void)face_index; + (void)u; + (void)v; + (void)co; + (void)n; +#else MFace mface; DMGridData **grid_data; float crn_x, crn_y; @@ -546,6 +567,7 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, const int lvl, if(co != NULL) interp_bilinear_grid(grid_data[g_index + S], grid_size, crn_x, crn_y, 1, co); +#endif } /* mode = 0: interpolate normals, @@ -675,6 +697,16 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const int face_index, const int lvl, const float st[2], float UNUSED(tangmat[3][3]), const int x, const int y) { +#if 1 // BMESH_TODO + (void)lores_dm; + (void)hires_dm; + (void)bake_data; + (void)face_index; + (void)lvl; + (void)st; + (void)x; + (void)y; +#else MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; Image *ima= mtface[face_index].tpage; @@ -734,6 +766,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, char *rrgb= (char*)ibuf->rect + pixel*4; rrgb[3]= 255; } +#endif // BMESH_TODO } /* MultiresBake callback for normals' baking @@ -745,6 +778,16 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const int face_index, const int lvl, const float st[2], float tangmat[3][3], const int x, const int y) { +#if 1 // BMESH_TODO + (void)lores_dm; + (void)hires_dm; + (void)face_index; + (void)lvl; + (void)st; + (void)tangmat; + (void)y; + (void)x; +#else MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE); MFace mface; Image *ima= mtface[face_index].tpage; @@ -790,6 +833,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, rrgb[2]= FTOCHAR(vec[2]); rrgb[3]= 255; } +#endif } static void count_images(MultiresBakeRender *bkr) @@ -971,7 +1015,7 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l if(*lvl==0) { DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob); - dm= CDDM_copy(tmp_dm); + dm= CDDM_copy(tmp_dm, 0); tmp_dm->release(tmp_dm); } else { MultiresModifierData tmp_mmd= *mmd; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 29a740affc5..c6f82f5b7b0 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -81,6 +81,7 @@ #include "BKE_sca.h" #include "BKE_softbody.h" #include "BKE_modifier.h" +#include "BKE_tessmesh.h" #include "ED_armature.h" #include "ED_curve.h" @@ -321,22 +322,24 @@ void ED_object_exit_editmode(bContext *C, int flag) // if(retopo_mesh_paint_check()) // retopo_end_okee(); - if(me->edit_mesh->totvert>MESH_MAX_VERTS) { + if(me->edit_btmesh->bm->totvert>MESH_MAX_VERTS) { error("Too many vertices"); return; } - load_editMesh(scene, obedit); + + EDBM_LoadEditBMesh(scene, obedit); if(freedata) { - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; } - +#if 0 //BMESH_TODO if(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) { mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); } +#endif } else if (obedit->type==OB_ARMATURE) { ED_armature_from_edit(obedit); @@ -376,7 +379,7 @@ void ED_object_exit_editmode(bContext *C, int flag) } BLI_freelistN(&pidlist); - BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_OUTDATED); + BKE_ptcache_object_reset(scene, obedit, PTCACHE_RESET_DEPSGRAPH); /* also flush ob recalc, doesn't take much overhead, but used for particles */ DAG_id_tag_update(&obedit->id, OB_RECALC_OB|OB_RECALC_DATA); @@ -445,7 +448,7 @@ void ED_object_enter_editmode(bContext *C, int flag) ok= 1; scene->obedit= ob; // context sees this - make_editMesh(scene, ob); + EDBM_MakeEditBMesh(CTX_data_tool_settings(C), scene, ob); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene); } @@ -1929,11 +1932,16 @@ static int object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *o { ObjectMode mode = RNA_enum_get(op->ptr, "mode"); - if(ob) { - if(mode == OB_MODE_OBJECT) - return 1; + if(mode == OB_MODE_OBJECT) + return 1; + if(ob) { switch(ob->type) { + case OB_EMPTY: + case OB_LAMP: + case OB_CAMERA: + return 0; + case OB_MESH: if(mode & (OB_MODE_EDIT|OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT|OB_MODE_PARTICLE_EDIT)) return 1; @@ -1942,14 +1950,14 @@ static int object_mode_set_compat(bContext *UNUSED(C), wmOperator *op, Object *o case OB_SURF: case OB_FONT: case OB_MBALL: - if(mode & (OB_MODE_EDIT)) + if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT)) return 1; return 0; case OB_LATTICE: - if(mode & (OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT)) + if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_WEIGHT_PAINT)) return 1; case OB_ARMATURE: - if(mode & (OB_MODE_EDIT|OB_MODE_POSE)) + if(mode & (OB_MODE_OBJECT|OB_MODE_EDIT|OB_MODE_POSE)) return 1; } } @@ -1965,7 +1973,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) int toggle = RNA_boolean_get(op->ptr, "toggle"); if(!ob || !object_mode_set_compat(C, op, ob)) - return OPERATOR_PASS_THROUGH; + return OPERATOR_CANCELLED; /* Exit current mode if it's not the mode we're setting */ if(ob->mode != OB_MODE_OBJECT && ob->mode != mode) @@ -2006,7 +2014,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) /* flags */ ot->flag= 0; /* no register/undo here, leave it to operators being called */ - prop= RNA_def_enum(ot->srna, "mode", object_mode_items, OB_MODE_OBJECT, "Mode", ""); + prop= RNA_def_enum(ot->srna, "mode", object_mode_items, 0, "Mode", ""); RNA_def_enum_funcs(prop, object_mode_set_itemsf); RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index bb32869469a..01fab0813d4 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -57,6 +57,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_deform.h" +#include "BKE_tessmesh.h" #include "RNA_define.h" #include "RNA_access.h" @@ -73,13 +74,14 @@ #include "object_intern.h" -static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float *cent) +static int return_editmesh_indexar(BMEditMesh *em, int *tot, int **indexar, float *cent) { - EditVert *eve; + BMVert *eve; + BMIter iter; int *index, nr, totvert=0; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) totvert++; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) totvert++; } if(totvert==0) return 0; @@ -88,8 +90,8 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float nr= 0; zero_v3(cent); - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { *index= nr; index++; add_v3_v3(cent, eve->co); } @@ -101,7 +103,7 @@ static int return_editmesh_indexar(EditMesh *em, int *tot, int **indexar, float return totvert; } -static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, float *cent) +static int return_editmesh_vgroup(Object *obedit, BMEditMesh *em, char *name, float *cent) { zero_v3(cent); @@ -110,11 +112,12 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa int totvert=0; MDeformVert *dvert; - EditVert *eve; + BMVert *eve; + BMIter iter; /* find the vertices */ - for(eve= em->verts.first; eve; eve= eve->next) { - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) { if(defvert_find_weight(dvert, defgrp_index) > 0.0f) { @@ -134,25 +137,27 @@ static int return_editmesh_vgroup(Object *obedit, EditMesh *em, char *name, floa return 0; } -static void select_editmesh_hook(Object *ob, HookModifierData *hmd) +static void select_editbmesh_hook(Object *ob, HookModifierData *hmd) { Mesh *me= ob->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - EditVert *eve; + BMEditMesh *em= me->edit_btmesh; + BMVert *eve; + BMIter iter; int index=0, nr=0; if (hmd->indexar == NULL) return; - for(eve= em->verts.first; eve; eve= eve->next, nr++) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { if(nr==hmd->indexar[index]) { - eve->f |= SELECT; + BM_Select(em->bm, eve, 1); if(index < hmd->totindex-1) index++; } + + nr++; } - EM_select_flush(em); - BKE_mesh_end_editmesh(me, em); + EDBM_selectmode_flush(em); } static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent) @@ -302,15 +307,13 @@ static int object_hook_index_array(Object *obedit, int *tot, int **indexar, char case OB_MESH: { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; /* check selected vertices first */ if( return_editmesh_indexar(em, tot, indexar, cent_r)) { - BKE_mesh_end_editmesh(me, em); return 1; } else { int ret = return_editmesh_vgroup(obedit, em, name, cent_r); - BKE_mesh_end_editmesh(me, em); return ret; } } @@ -379,7 +382,7 @@ static void object_hook_select(Object *ob, HookModifierData *hmd) if (hmd->indexar == NULL) return; - if(ob->type==OB_MESH) select_editmesh_hook(ob, hmd); + if(ob->type==OB_MESH) select_editbmesh_hook(ob, hmd); else if(ob->type==OB_LATTICE) select_editlattice_hook(ob, hmd); else if(ob->type==OB_CURVE) select_editcurve_hook(ob, hmd); else if(ob->type==OB_SURF) select_editcurve_hook(ob, hmd); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 801880f0f32..6dacb7707af 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -160,6 +160,7 @@ void OBJECT_OT_multires_external_save(struct wmOperatorType *ot); void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot); void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot); void OBJECT_OT_explode_refresh(struct wmOperatorType *ot); +void OBJECT_OT_test_multires(struct wmOperatorType *ot); /* object_constraint.c */ void OBJECT_OT_constraint_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c index 14ce223db5e..af1d76fd3d0 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -367,7 +367,7 @@ typedef struct UndoLattice { int pntsu, pntsv, pntsw; } UndoLattice; -static void undoLatt_to_editLatt(void *data, void *edata) +static void undoLatt_to_editLatt(void *data, void *edata, void *UNUSED(obdata)) { UndoLattice *ult= (UndoLattice*)data; EditLatt *editlatt= (EditLatt *)edata; @@ -376,7 +376,7 @@ static void undoLatt_to_editLatt(void *data, void *edata) memcpy(editlatt->latt->def, ult->def, a*sizeof(BPoint)); } -static void *editLatt_to_undoLatt(void *edata) +static void *editLatt_to_undoLatt(void *edata, void *UNUSED(obdata)) { UndoLattice *ult= MEM_callocN(sizeof(UndoLattice), "UndoLattice"); EditLatt *editlatt= (EditLatt *)edata; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 2ac9161ffa3..e9702af070c 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -67,6 +67,7 @@ #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_softbody.h" +#include "BKE_tessmesh.h" #include "RNA_access.h" #include "RNA_define.h" @@ -216,15 +217,15 @@ int ED_object_modifier_remove(ReportList *reports, Main *bmain, Scene *scene, Ob } if(ok) { - if(me->edit_mesh) { - EditMesh *em= me->edit_mesh; + if(me->edit_btmesh) { + BMEditMesh *em= me->edit_btmesh; /* CustomData_external_remove is used here only to mark layer as non-external for further free-ing, so zero element count looks safer than em->totface */ - CustomData_external_remove(&em->fdata, &me->id, CD_MDISPS, 0); - EM_free_data_layer(em, &em->fdata, CD_MDISPS); + CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0); + BM_free_data_layer(em->bm, &em->bm->ldata, CD_MDISPS); } else { - CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); - CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface); + CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); + CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop); } } } @@ -408,6 +409,17 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M return 0; } + /* + It should be ridiculously easy to extract the original verts that we want + and form the shape data. We can probably use the CD KEYINDEX layer (or + whatever I ended up calling it, too tired to check now), though this would + by necassity have to make some potentially ugly assumptions about the order + of the mesh data :-/ you can probably assume in 99% of cases that the first + element of a given index is the original, and any subsequent duplicates are + copies/interpolates, but that's an assumption that would need to be tested + and then predominantly stated in comments in a half dozen headers. + */ + if (ob->type==OB_MESH) { DerivedMesh *dm; Mesh *me= ob->data; @@ -420,7 +432,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M } mesh_pmv_off(me); - dm = mesh_create_derived_for_modifier(scene, ob, md); + dm = mesh_create_derived_for_modifier(scene, ob, md, 0); if (!dm) { BKE_report(reports, RPT_ERROR, "Modifier is disabled or returned error, skipping apply"); return 0; @@ -480,19 +492,19 @@ static int modifier_apply_obdata(ReportList *reports, Scene *scene, Object *ob, return 0; } } else { - dm = mesh_create_derived_for_modifier(scene, ob, md); + dm = mesh_create_derived_for_modifier(scene, ob, md, 1); if (!dm) { BKE_report(reports, RPT_ERROR, "Modifier returned error, skipping apply"); return 0; } - DM_to_mesh(dm, me); + DM_to_mesh(dm, me, ob); dm->release(dm); if(md->type == eModifierType_Multires) { - CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); - CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface); + CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); + CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop); } } } @@ -1114,6 +1126,66 @@ void OBJECT_OT_multires_reshape(wmOperatorType *ot) edit_modifier_properties(ot); } +static int multires_test_exec(bContext *C, wmOperator *op) +{ + Object *ob= ED_object_active_context(C); + Mesh *me = ob->data; + MPoly *mp; + MDisps *mdisps; + int i, x = RNA_int_get(op->ptr, "x"), y = RNA_int_get(op->ptr, "y"); + + if (ob->type != OB_MESH || !me) + return OPERATOR_CANCELLED; + + mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + if (!mdisps) + return OPERATOR_CANCELLED; + + mp = me->mpoly; + for (i=0; i<me->totpoly; i++, mp++) { + MLoop *ml; + int j; + + ml = me->mloop + mp->loopstart; + for (j=0; j<mp->totloop; j++, ml++) { + MLoop *ml2 = me->mloop + mp->loopstart + (j+mp->totloop-1)%mp->totloop; + MLoop *ml3 = me->mloop + mp->loopstart + (j+1)%mp->totloop; + + if ((me->mvert[ml->v].flag&SELECT) && (me->mvert[ml2->v].flag&SELECT) && (me->mvert[ml3->v].flag&SELECT)) { + MDisps *md = mdisps + mp->loopstart + j; + int res = sqrt(md->totdisp); + + if (x >= res) x = res-1; + if (y >= res) y = res-1; + + md->disps[y*res + x][2] += 1.0; + } + } + } + + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob); + + return OPERATOR_FINISHED; +} + +void OBJECT_OT_test_multires(wmOperatorType *ot) +{ + ot->name= "Multires Object Mode Test"; + ot->description= ""; + ot->idname= "OBJECT_OT_test_multires"; + + ot->poll= multires_poll; + ot->exec= multires_test_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + RNA_def_int(ot->srna, "x", 0, 0, 100, "x", "x", 0, 100); + RNA_def_int(ot->srna, "y", 0, 0, 100, "y", "y", 0, 100); +} + + + /****************** multires save external operator *********************/ static int multires_external_save_exec(bContext *C, wmOperator *op) @@ -1126,7 +1198,7 @@ static int multires_external_save_exec(bContext *C, wmOperator *op) if(!me) return OPERATOR_CANCELLED; - if(CustomData_external_test(&me->fdata, CD_MDISPS)) + if(CustomData_external_test(&me->ldata, CD_MDISPS)) return OPERATOR_CANCELLED; RNA_string_get(op->ptr, "filepath", path); @@ -1134,8 +1206,8 @@ static int multires_external_save_exec(bContext *C, wmOperator *op) if(relative) BLI_path_rel(path, G.main->name); - CustomData_external_add(&me->fdata, &me->id, CD_MDISPS, me->totface, path); - CustomData_external_write(&me->fdata, &me->id, CD_MASK_MESH, me->totface, 0); + CustomData_external_add(&me->ldata, &me->id, CD_MDISPS, me->totloop, path); + CustomData_external_write(&me->ldata, &me->id, CD_MASK_MESH, me->totloop, 0); return OPERATOR_FINISHED; } @@ -1155,7 +1227,7 @@ static int multires_external_save_invoke(bContext *C, wmOperator *op, wmEvent *U if (!mmd) return OPERATOR_CANCELLED; - if(CustomData_external_test(&me->fdata, CD_MDISPS)) + if(CustomData_external_test(&me->ldata, CD_MDISPS)) return OPERATOR_CANCELLED; if(!RNA_property_is_set(op->ptr, "relative_path")) @@ -1199,11 +1271,11 @@ static int multires_external_pack_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_active_context(C); Mesh *me= ob->data; - if(!CustomData_external_test(&me->fdata, CD_MDISPS)) + if(!CustomData_external_test(&me->ldata, CD_MDISPS)) return OPERATOR_CANCELLED; // XXX don't remove.. - CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface); + CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); return OPERATOR_FINISHED; } @@ -1403,4 +1475,3 @@ void OBJECT_OT_explode_refresh(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; edit_modifier_properties(ot); } - diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index ff9b13379a2..addc8f31aa5 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -211,6 +211,9 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_bake_image); WM_operatortype_append(OBJECT_OT_drop_named_material); + + WM_operatortype_append(OBJECT_OT_test_multires); + } void ED_operatormacros_object(void) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index f21241b6e7a..0272a04618f 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -76,6 +76,7 @@ #include "BKE_sca.h" #include "BKE_scene.h" #include "BKE_texture.h" +#include "BKE_tessmesh.h" #include "WM_api.h" #include "WM_types.h" @@ -108,7 +109,8 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) Main *bmain= CTX_data_main(C); Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditVert *eve; + BMVert *eve; + BMIter iter; Curve *cu; Nurb *nu; BezTriple *bezt; @@ -120,22 +122,17 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; - eve= em->verts.first; - while(eve) { - if(eve->f & 1) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { if(v1==0) v1= nr; else if(v2==0) v2= nr; else if(v3==0) v3= nr; else if(v4==0) v4= nr; else break; } - nr++; - eve= eve->next; } - - BKE_mesh_end_editmesh(me, em); } else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) { ListBase *editnurb= curve_get_editcurve(obedit); @@ -1134,6 +1131,8 @@ static int move_to_layer_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, scene); WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, scene); + WM_event_add_notifier(C, NC_SCENE|ND_LAYER_CONTENT, scene); + DAG_scene_sort(bmain, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index fd2e7fd7c99..a7b73b21865 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -189,10 +189,10 @@ static int object_shape_key_mirror(bContext *C, Object *ob) Mesh *me= ob->data; MVert *mv; - mesh_octree_table(ob, NULL, NULL, 's'); + //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 's'); for(i1=0, mv=me->mvert; i1<me->totvert; i1++, mv++) { - i2= mesh_get_x_mirror_vert(ob, i1); + i2= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, i1); if(i2==i1) { fp1= ((float *)kb->data) + i1*3; fp1[0] = -fp1[0]; @@ -215,7 +215,7 @@ static int object_shape_key_mirror(bContext *C, Object *ob) } } - mesh_octree_table(ob, NULL, NULL, 'e'); + //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 'e'); } else if (ob->type == OB_LATTICE) { Lattice *lt= ob->data; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index f7c6ff99bde..fcf049023a7 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -53,6 +53,7 @@ #include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "BKE_multires.h" #include "BKE_armature.h" @@ -492,7 +493,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo } /* update normals */ - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else if (ob->type==OB_ARMATURE) { ED_armature_apply_transform(ob, mat); @@ -669,37 +670,37 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; - - if(around==V3D_CENTROID) { - int total= 0; - for(eve= em->verts.first; eve; eve= eve->next) { - total++; - add_v3_v3(cent, eve->co); - } - if(total) { - mul_v3_fl(cent, 1.0f/(float)total); + BMEditMesh *em = me->edit_btmesh; + BMVert *eve; + BMIter iter; + int total = 0; + + if(centermode == ORIGIN_TO_CURSOR) { + copy_v3_v3(cent, cursor); + invert_m4_m4(obedit->imat, obedit->obmat); + mul_m4_v3(obedit->imat, cent); + } else { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(around==V3D_CENTROID) { + total++; + add_v3_v3(cent, eve->co); + mul_v3_fl(cent, 1.0f/(float)total); + } + else { + DO_MINMAX(eve->co, min, max); + mid_v3_v3v3(cent, min, max); + } } } - else { - for(eve= em->verts.first; eve; eve= eve->next) { - DO_MINMAX(eve->co, min, max); - } - mid_v3_v3v3(cent, min, max); + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + sub_v3_v3(eve->co, cent); } - if(!is_zero_v3(cent)) { - for(eve= em->verts.first; eve; eve= eve->next) { - sub_v3_v3(eve->co, cent); - } - - recalc_editnormals(em); - tot_change++; - DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - } - BKE_mesh_end_editmesh(me, em); - } + EDBM_RecalcNormals(em); + tot_change++; + DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); + } } /* reset flags */ diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 52ba9460818..92fab159875 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -43,6 +43,7 @@ #include "DNA_curve_types.h" #include "DNA_lattice_types.h" #include "DNA_meshdata_types.h" +#include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_object_force.h" @@ -50,7 +51,7 @@ #include "DNA_particle_types.h" #include "BLI_blenlib.h" -#include "BLI_editVert.h" +#include "BLI_cellalloc.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -59,6 +60,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BKE_report.h" #include "RNA_access.h" @@ -89,7 +91,7 @@ static Lattice *vgroup_edit_lattice(Object *ob) int ED_vgroup_object_is_edit_mode(Object *ob) { if(ob->type == OB_MESH) - return (((Mesh*)ob->data)->edit_mesh != NULL); + return (((Mesh*)ob->data)->edit_btmesh != NULL); else if(ob->type == OB_LATTICE) return (((Lattice*)ob->data)->editlatt != NULL); @@ -169,23 +171,25 @@ static int ED_vgroup_give_parray(ID *id, MDeformVert ***dvert_arr, int *dvert_to { Mesh *me = (Mesh *)id; - if(me->edit_mesh) { - EditMesh *em = me->edit_mesh; - EditVert *eve; + if(me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; int i; - if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) { + if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) { return 0; } - i= BLI_countlist(&em->verts); + i = em->bm->totvert; *dvert_arr= MEM_mallocN(sizeof(void*)*i, "vgroup parray from me"); *dvert_tot = i; i = 0; - for (eve=em->verts.first; eve; eve=eve->next, i++) { - (*dvert_arr)[i] = CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + (*dvert_arr)[i] = CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + i++; } return 1; @@ -312,12 +316,12 @@ int ED_vgroup_copy_array(Object *ob, Object *ob_from) for(i=0; i<dvert_tot; i++, dvf++, dv++) { if((*dv)->dw) - MEM_freeN((*dv)->dw); + BLI_cellalloc_free((*dv)->dw); *(*dv)= *(*dvf); if((*dv)->dw) - (*dv)->dw= MEM_dupallocN((*dv)->dw); + (*dv)->dw= BLI_cellalloc_dupalloc((*dv)->dw); } MEM_freeN(dvert_array); @@ -371,13 +375,13 @@ static void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum) * deform weight, and reshuffle the others */ if(dvert->totweight) { - newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), + newdw = BLI_cellalloc_malloc(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight"); if(dvert->dw){ memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i); memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i)); - MEM_freeN(dvert->dw); + BLI_cellalloc_free(dvert->dw); } dvert->dw=newdw; } @@ -385,7 +389,7 @@ static void ED_vgroup_nr_vert_remove(Object *ob, int def_nr, int vertnum) * left then just remove the deform weight */ else { - MEM_freeN(dvert->dw); + BLI_cellalloc_free(dvert->dw); dvert->dw = NULL; break; } @@ -467,11 +471,11 @@ static void ED_vgroup_nr_vert_add(Object *ob, int def_nr, int vertnum, float wei /* if we are doing an additive assignment, then * we need to create the deform weight */ - newdw = MEM_callocN(sizeof(MDeformWeight)*(dv->totweight+1), + newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight"); if(dv->dw){ memcpy(newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight); - MEM_freeN(dv->dw); + BLI_cellalloc_free(dv->dw); } dv->dw=newdw; @@ -526,7 +530,7 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) static float get_vert_def_nr(Object *ob, int def_nr, int vertnum) { MDeformVert *dvert= NULL; - EditVert *eve; + BMVert *eve; Mesh *me; int i; @@ -534,12 +538,12 @@ static float get_vert_def_nr(Object *ob, int def_nr, int vertnum) if(ob->type==OB_MESH) { me= ob->data; - if(me->edit_mesh) { - eve= BLI_findlink(&me->edit_mesh->verts, vertnum); + if(me->edit_btmesh) { + eve= BMIter_AtIndex(me->edit_btmesh->bm, BM_VERTS_OF_MESH, NULL, vertnum); if(!eve) { return 0.0f; } - dvert= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT); + dvert= CustomData_bmesh_get(&me->edit_btmesh->bm->vdata, eve->head.data, CD_MDEFORMVERT); vertnum= 0; } else { @@ -594,34 +598,32 @@ void ED_vgroup_select_by_name(Object *ob, const char *name) /* only in editmode */ static void vgroup_select_verts(Object *ob, int select) { - EditVert *eve; + BMVert *eve; MDeformVert *dvert; int i; if(ob->type == OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMIter iter; - for(eve=em->verts.first; eve; eve=eve->next){ - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert && dvert->totweight){ for(i=0; i<dvert->totweight; i++){ if(dvert->dw[i].def_nr == (ob->actdef-1)){ - if(!eve->h) { - if(select) eve->f |= SELECT; - else eve->f &= ~SELECT; + if (!BM_TestHFlag(eve, BM_HIDDEN)) { + BM_Select(em->bm, eve, select); + break; } - break; } } } } /* this has to be called, because this function operates on vertices only */ - if(select) EM_select_flush(em); // vertices to edges/faces - else EM_deselect_flush(em); - - BKE_mesh_end_editmesh(me, em); + if(select) EDBM_selectmode_flush(em); // vertices to edges/faces + else EDBM_deselect_flush(em); } else if(ob->type == OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); @@ -888,12 +890,12 @@ static void vgroup_invert(Object *ob, int auto_assign, int auto_remove) static void vgroup_blend(Object *ob) { + BMEditMesh *em= ((Mesh *)ob->data)->edit_btmesh; bDeformGroup *dg; MDeformWeight *dw; MDeformVert *dvert_array=NULL, *dvert; int i, def_nr, dvert_tot=0; - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data)); // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot); if(em==NULL) @@ -902,46 +904,47 @@ static void vgroup_blend(Object *ob) dg = BLI_findlink(&ob->defbase, (ob->actdef-1)); if(dg) { - int sel1, sel2; - int i1, i2; - - EditEdge *eed; - EditVert *eve; + BMEdge *eed; + BMVert *eve; + BMIter iter; float *vg_weights; float *vg_users; + int sel1, sel2; + int i1, i2; def_nr= ob->actdef-1; i= 0; - for(eve= em->verts.first; eve; eve= eve->next) - eve->tmp.l= i++; - + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(eve, i); + i++; + } dvert_tot= i; vg_weights= MEM_callocN(sizeof(float)*dvert_tot, "vgroup_blend_f"); vg_users= MEM_callocN(sizeof(int)*dvert_tot, "vgroup_blend_i"); - for(eed= em->edges.first; eed; eed= eed->next) { - sel1= eed->v1->f & SELECT; - sel2= eed->v2->f & SELECT; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + sel1= BM_TestHFlag(eed->v1, BM_SELECT); + sel2= BM_TestHFlag(eed->v2, BM_SELECT); if(sel1 != sel2) { /* i1 is always the selected one */ if(sel1==TRUE && sel2==FALSE) { - i1= eed->v1->tmp.l; - i2= eed->v2->tmp.l; + i1= BM_GetIndex(eed->v1); + i2= BM_GetIndex(eed->v2); eve= eed->v2; } else { - i2= eed->v1->tmp.l; - i1= eed->v2->tmp.l; + i2= BM_GetIndex(eed->v1); + i1= BM_GetIndex(eed->v2); eve= eed->v1; } vg_users[i1]++; /* TODO, we may want object mode blending */ - if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + if(em) dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); else dvert= dvert_array+i2; dw= defvert_find_index(dvert, def_nr); @@ -953,10 +956,10 @@ static void vgroup_blend(Object *ob) } i= 0; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT && vg_users[i] > 0) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT) && vg_users[i] > 0) { /* TODO, we may want object mode blending */ - if(em) dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + if(em) dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); else dvert= dvert_array+i; dw= defvert_verify_index(dvert, def_nr); @@ -1067,7 +1070,10 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v { #define VGROUP_MIRR_OP dvert_mirror_op(dvert, dvert_mirr, sel, sel_mirr, flip_map, mirror_weights, flip_vgroups) +#if 0 EditVert *eve, *eve_mirr; +#endif + MDeformVert *dvert, *dvert_mirr; short sel, sel_mirr; int *flip_map; @@ -1079,6 +1085,11 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v /* only the active group */ if(ob->type == OB_MESH) { +#if 1 //BMESH_TODO + (void)dvert; + (void)dvert_mirr; + (void)flip_map; +#else Mesh *me= ob->data; EditMesh *em = BKE_mesh_get_editmesh(me); @@ -1109,6 +1120,7 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v } BKE_mesh_end_editmesh(me, em); +#endif // BMESH_TODO } else if (ob->type == OB_LATTICE) { Lattice *lt= ob->data; @@ -1257,7 +1269,7 @@ static void vgroup_delete_object_mode(Object *ob, bDeformGroup *dg) /* removes from active defgroup, if allverts==0 only selected vertices */ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGroup *dg) { - EditVert *eve; + BMVert *eve; MDeformVert *dvert; MDeformWeight *newdw; bDeformGroup *eg; @@ -1265,29 +1277,30 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr if(ob->type == OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMIter iter; - for(eve=em->verts.first; eve; eve=eve->next){ - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); - if(dvert && dvert->dw && ((eve->f & SELECT) || allverts)){ + if(dvert && dvert->dw && (BM_TestHFlag(eve, BM_SELECT) || allverts)){ for(i=0; i<dvert->totweight; i++){ /* Find group */ eg = BLI_findlink(&ob->defbase, dvert->dw[i].def_nr); if(eg == dg){ dvert->totweight--; - if(dvert->totweight){ - newdw = MEM_mallocN(sizeof(MDeformWeight)*(dvert->totweight), "deformWeight"); + if (dvert->totweight){ + newdw = BLI_cellalloc_malloc (sizeof(MDeformWeight)*(dvert->totweight), "deformWeight"); if(dvert->dw){ memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*i); memcpy(newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i)); - MEM_freeN(dvert->dw); + BLI_cellalloc_free(dvert->dw); } dvert->dw=newdw; } else{ - MEM_freeN(dvert->dw); + BLI_cellalloc_free (dvert->dw); dvert->dw=NULL; break; } @@ -1295,7 +1308,6 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr } } } - BKE_mesh_end_editmesh(me, em); } else if(ob->type == OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); @@ -1325,19 +1337,19 @@ static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg) /* Make sure that any verts with higher indices are adjusted accordingly */ if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; MDeformVert *dvert; - for(eve=em->verts.first; eve; eve=eve->next){ - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) for(i=0; i<dvert->totweight; i++) if(dvert->dw[i].def_nr > dg_index) dvert->dw[i].def_nr--; } - BKE_mesh_end_editmesh(me, em); } else if(ob->type==OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); @@ -1377,7 +1389,7 @@ static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg) else if(ob->type==OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); if(lt->dvert) { - MEM_freeN(lt->dvert); + BLI_cellalloc_free(lt->dvert); lt->dvert= NULL; } } @@ -1387,7 +1399,7 @@ static void vgroup_delete_edit_mode(Object *ob, bDeformGroup *dg) static int vgroup_object_in_edit_mode(Object *ob) { if(ob->type == OB_MESH) - return (((Mesh*)ob->data)->edit_mesh != NULL); + return (((Mesh*)ob->data)->edit_btmesh != NULL); else if(ob->type == OB_LATTICE) return (((Lattice*)ob->data)->editlatt != NULL); @@ -1417,7 +1429,7 @@ static void vgroup_delete_all(Object *ob) else if(ob->type==OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); if(lt->dvert) { - MEM_freeN(lt->dvert); + BLI_cellalloc_free(lt->dvert); lt->dvert= NULL; } } @@ -1432,7 +1444,7 @@ static void vgroup_delete_all(Object *ob) /* only in editmode */ static void vgroup_assign_verts(Object *ob, float weight) { - EditVert *eve; + BMVert *eve; bDeformGroup *dg, *eg; MDeformWeight *newdw; MDeformVert *dvert; @@ -1444,16 +1456,17 @@ static void vgroup_assign_verts(Object *ob, float weight) if(ob->type == OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMIter iter; - if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) - EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL); + if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) + BM_add_data_layer(em->bm, &em->bm->vdata, CD_MDEFORMVERT); /* Go through the list of editverts and assign them */ - for(eve=em->verts.first; eve; eve=eve->next){ - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); - if(dvert && (eve->f & SELECT)){ + if(dvert && BM_TestHFlag(eve, BM_SELECT)) { /* See if this vert already has a reference to this group */ /* If so: Change its weight */ done=0; @@ -1468,10 +1481,10 @@ static void vgroup_assign_verts(Object *ob, float weight) } /* If not: Add the group and set its weight */ if(!done){ - newdw = MEM_callocN(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight"); + newdw = BLI_cellalloc_calloc(sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight"); if(dvert->dw){ memcpy(newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight); - MEM_freeN(dvert->dw); + BLI_cellalloc_free(dvert->dw); } dvert->dw=newdw; @@ -1483,7 +1496,6 @@ static void vgroup_assign_verts(Object *ob, float weight) } } } - BKE_mesh_end_editmesh(me, em); } else if(ob->type == OB_LATTICE) { Lattice *lt= vgroup_edit_lattice(ob); @@ -2143,11 +2155,12 @@ static int vgroup_do_remap(Object *ob, char *name_array, wmOperator *op) if(ob->mode == OB_MODE_EDIT) { if(ob->type==OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(ob->data); - EditVert *eve; + BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh; + BMIter iter; + BMVert *eve; - for(eve=em->verts.first; eve; eve=eve->next){ - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert && dvert->totweight){ defvert_remap(dvert, sort_map); } diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript index 274819c918c..dad0e25ca5e 100644 --- a/source/blender/editors/physics/SConscript +++ b/source/blender/editors/physics/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../gpu ../../blenloader' +incs += ' ../../gpu ../../blenloader ../../bmesh' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' defs = '' diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index b8cdc18e739..48963d9f5db 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1058,7 +1058,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys) BLI_kdtree_free(edit->emitter_field); - totface=dm->getNumFaces(dm); + totface=dm->getNumTessFaces(dm); /*totvert=dm->getNumVerts(dm);*/ /*UNSUED*/ edit->emitter_cosnos=MEM_callocN(totface*6*sizeof(float),"emitter cosnos"); @@ -1069,7 +1069,7 @@ static void recalc_emitter_field(Object *ob, ParticleSystem *psys) nor=vec+3; for(i=0; i<totface; i++, vec+=6, nor+=6) { - MFace *mface=dm->getFaceData(dm,i,CD_MFACE); + MFace *mface=dm->getTessFaceData(dm,i,CD_MFACE); MVert *mvert; mvert=dm->getVertData(dm,mface->v1,CD_MVERT); @@ -2594,7 +2594,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) PTCacheEditPoint *newpoint, *new_points; POINT_P; KEY_K; HairKey *hkey; - int *mirrorfaces; + int *mirrorfaces = NULL; int rotation, totpart, newtotpart; if(psys->flag & PSYS_GLOBAL_HAIR) @@ -2604,7 +2604,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) if(!psmd->dm) return; - mirrorfaces= mesh_get_x_mirror_faces(ob, NULL); + //BMESH_TODO mirrorfaces= mesh_get_x_mirror_faces(ob, NULL); if(!edit->mirror_cache) PE_update_mirror_cache(ob, psys); @@ -2625,7 +2625,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) } } - if((point->flag & PEP_TAG) && mirrorfaces[pa->num*2] != -1) + if((point->flag & PEP_TAG) && mirrorfaces && mirrorfaces[pa->num*2] != -1) newtotpart++; } @@ -2662,7 +2662,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) if(point->flag & PEP_HIDE) continue; - if(!(point->flag & PEP_TAG) || mirrorfaces[pa->num*2] == -1) + if(!(point->flag & PEP_TAG) || (mirrorfaces && mirrorfaces[pa->num*2] == -1)) continue; /* duplicate */ @@ -2672,7 +2672,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) if(point->keys) newpoint->keys= MEM_dupallocN(point->keys); /* rotate weights according to vertex index rotation */ - rotation= mirrorfaces[pa->num*2+1]; + rotation= mirrorfaces ? mirrorfaces[pa->num*2+1] : 0; newpa->fuv[0]= pa->fuv[2]; newpa->fuv[1]= pa->fuv[1]; newpa->fuv[2]= pa->fuv[0]; @@ -2684,7 +2684,7 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) SHIFT3(float, newpa->fuv[0], newpa->fuv[1], newpa->fuv[2]) /* assign face inddex */ - newpa->num= mirrorfaces[pa->num*2]; + newpa->num= mirrorfaces ? mirrorfaces[pa->num*2] : 0; newpa->num_dmcache= psys_particle_dm_face_lookup(ob,psmd->dm,newpa->num,newpa->fuv, NULL); /* update edit key pointers */ @@ -2706,7 +2706,8 @@ static void PE_mirror_x(Scene *scene, Object *ob, int tagged) point->flag &= ~PEP_TAG; } - MEM_freeN(mirrorfaces); + if (mirrorfaces) + MEM_freeN(mirrorfaces); } static int mirror_exec(bContext *C, wmOperator *UNUSED(op)) @@ -3106,8 +3107,8 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, floa VECCOPY(p_max,pa_minmax+3); } - totface=dm->getNumFaces(dm); - mface=dm->getFaceDataArray(dm,CD_MFACE); + totface=dm->getNumTessFaces(dm); + mface=dm->getTessFaceDataArray(dm,CD_MFACE); mvert=dm->getVertDataArray(dm,CD_MVERT); /* lets intersect the faces */ diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 8ec95e9b107..d0deec70b51 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -646,7 +646,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) if(psmd->dm->deformedOnly) /* we don't want to mess up psmd->dm when converting to global coordinates below */ - dm= CDDM_copy(psmd->dm); + dm= CDDM_copy(psmd->dm, 0); else dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); @@ -672,7 +672,7 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) continue; } - mface = CDDM_get_face(dm,nearest.index); + mface = CDDM_get_tessface(dm,nearest.index); copy_v3_v3(v[0], CDDM_get_vert(dm,mface->v1)->co); copy_v3_v3(v[1], CDDM_get_vert(dm,mface->v2)->co); diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index cf6c4290ee0..74abde1094a 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ../../blenloader ../../gpu ../../imbuf + ../../bmesh ../../makesdna ../../makesrna ../../render/extern/include diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript index 2b9737557cd..bd6dcf73546 100644 --- a/source/blender/editors/render/SConscript +++ b/source/blender/editors/render/SConscript @@ -7,7 +7,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../gpu' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' -incs += ' ../../blenloader' +incs += ' ../../blenloader ../../bmesh' if env['OURPLATFORM'] == 'linux2': cflags='-pthread' diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index fdd53d27b02..ea4a4f43ca3 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -65,6 +65,7 @@ #include "BKE_scene.h" #include "BKE_texture.h" #include "BKE_world.h" +#include "BKE_tessmesh.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -163,13 +164,15 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) if(ob && ob->actcol>0) { if(ob->type == OB_MESH) { - EditMesh *em= ((Mesh*)ob->data)->edit_mesh; - EditFace *efa; + BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh; + BMFace *efa; + BMIter iter; if(em) { - for(efa= em->faces.first; efa; efa=efa->next) - if(efa->f & SELECT) + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_TestHFlag(efa, BM_SELECT)) efa->mat_nr= ob->actcol-1; + } } } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { @@ -222,14 +225,15 @@ static int material_slot_de_select(bContext *C, int select) return OPERATOR_CANCELLED; if(ob->type == OB_MESH) { - EditMesh *em= ((Mesh*)ob->data)->edit_mesh; - +/*BMESH_TODO + BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh; if(em) { if(select) EM_select_by_material(em, ob->actcol-1); else EM_deselect_by_material(em, ob->actcol-1); } +*/ } else if ELEM(ob->type, OB_CURVE, OB_SURF) { ListBase *nurbs= ED_curve_editnurbs((Curve*)ob->data); diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 4282110901b..aa347961dcb 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../imbuf ../../makesdna ../../makesrna diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript index 61f3429521d..6370c9d3153 100644 --- a/source/blender/editors/screen/SConscript +++ b/source/blender/editors/screen/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../blenfont ../../makesdna ../../imbuf' incs += ' ../../blenloader ../../windowmanager ../../makesrna ../../gpu' -incs += ' ../../render/extern/include' +incs += ' ../../render/extern/include ../../bmesh' incs += ' #/intern/guardedalloc #/extern/glew/include' defs = '' diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 68326edfb11..3268f6293a7 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -55,6 +55,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "BKE_sound.h" #include "WM_api.h" @@ -314,7 +315,7 @@ int ED_operator_editmesh(bContext *C) { Object *obedit= CTX_data_edit_object(C); if(obedit && obedit->type==OB_MESH) - return NULL != ((Mesh *)obedit->data)->edit_mesh; + return NULL != ((Mesh *)obedit->data)->edit_btmesh; return 0; } @@ -361,24 +362,21 @@ int ED_operator_uvedit(bContext *C) { SpaceImage *sima= CTX_wm_space_image(C); Object *obedit= CTX_data_edit_object(C); + return ED_space_image_show_uvedit(sima, obedit); } int ED_operator_uvmap(bContext *C) { Object *obedit= CTX_data_edit_object(C); - EditMesh *em= NULL; + BMEditMesh *em= NULL; if(obedit && obedit->type==OB_MESH) - em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + em= ((Mesh *)obedit->data)->edit_btmesh; - if(em && (em->faces.first)) { - BKE_mesh_end_editmesh(obedit->data, em); + if(em && (em->bm->totface)) return 1; - } - if(obedit) - BKE_mesh_end_editmesh(obedit->data, em); return 0; } @@ -2949,7 +2947,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode) ScreenAnimData *sad= wt->customdata; sad->ar= CTX_wm_region(C); - } + } } return OPERATOR_FINISHED; diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript index 90b56ded2cd..829a2760d1a 100644 --- a/source/blender/editors/sculpt_paint/SConscript +++ b/source/blender/editors/sculpt_paint/SConscript @@ -8,7 +8,7 @@ defs = [] incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include' -incs += ' ../../gpu ../../makesrna ../../blenloader' +incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh' if env['OURPLATFORM'] == 'linux2': cflags='-pthread' diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index c9a6aa87cd0..e1188f5f77b 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -2868,11 +2868,11 @@ static void project_paint_begin(ProjPaintState *ps) } ps->dm_mvert = ps->dm->getVertArray(ps->dm); - ps->dm_mface = ps->dm->getFaceArray(ps->dm); - ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE); + ps->dm_mface = ps->dm->getTessFaceArray(ps->dm); + ps->dm_mtface= ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE); ps->dm_totvert = ps->dm->getNumVerts(ps->dm); - ps->dm_totface = ps->dm->getNumFaces(ps->dm); + ps->dm_totface = ps->dm->getNumTessFaces(ps->dm); /* use clone mtface? */ @@ -2905,15 +2905,18 @@ static void project_paint_begin(ProjPaintState *ps) } /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */ - if(ps->dm->type != DM_TYPE_CDDM) { + // this seems like a bad check, since some constructive modifiers use cddm? - joeedh + if(1) { //ps->dm->type != DM_TYPE_CDDM) { ps->dm_mvert= MEM_dupallocN(ps->dm_mvert); ps->dm_mface= MEM_dupallocN(ps->dm_mface); /* looks like these are ok for now.*/ - /* + ps->dm_mtface= MEM_dupallocN(ps->dm_mtface); - ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); - ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); - */ + if (ps->dm_mtface_clone) + ps->dm_mtface_clone= MEM_dupallocN(ps->dm_mtface_clone); + if (ps->dm_mtface_stencil) + ps->dm_mtface_stencil= MEM_dupallocN(ps->dm_mtface_stencil); + } ps->viewDir[0] = 0.0f; @@ -3390,7 +3393,8 @@ static void project_paint_end(ProjPaintState *ps) } /* copy for subsurf/multires, so throw away */ - if(ps->dm->type != DM_TYPE_CDDM) { + // this seems like a bad check, since some constructive modifiers use cddm? - joeedh + if(1) { //ps->dm->type != DM_TYPE_CDDM) { if(ps->dm_mvert) MEM_freeN(ps->dm_mvert); if(ps->dm_mface) MEM_freeN(ps->dm_mface); /* looks like these dont need copying */ @@ -4698,9 +4702,29 @@ static int texture_paint_init(bContext *C, wmOperator *op) pop->orig_brush_size= brush_size(brush); if(pop->mode != PAINT_MODE_2D) { + Mesh *me; + pop->s.ob = OBACT; + if (!pop->ps.ob) + pop->ps.ob = pop->s.ob; + pop->s.me = get_mesh(pop->s.ob); if (!pop->s.me) return 0; + + me = pop->s.me; + + /*recalc mesh tesselation so the face origindex values point + to the tesselation faces themselves, instead of polys*/ + me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, + &me->pdata, me->mvert, me->totface, me->totloop, me->totpoly, 0, 1); + mesh_update_customdata_pointers(me); + + /*force customdata update*/ + makeDerivedMesh(scene, pop->ps.ob, NULL, CD_MASK_BAREMESH, 0); + + /* Dont allow brush size below 2 */ + if (pop->ps.brush && pop->ps.brush->size<=1) + pop->ps.brush->size = 2; } else { pop->s.image = pop->s.sima->image; diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 09f5c32bea0..4f2cd0160d1 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -151,9 +151,9 @@ static void imapaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, fl void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2]) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); - const int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX); - MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf; - int numfaces = dm->getNumFaces(dm), a, findex; + const int *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + MTFace *tface = dm->getTessFaceDataArray(dm, CD_MTFACE), *tf; + int numfaces = dm->getNumTessFaces(dm), a, findex; float p[2], w[3], absw, minabsw; MFace mf; MVert mv[4]; @@ -166,7 +166,7 @@ void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const in findex= index ? index[a]: a; if(findex == faceindex) { - dm->getFace(dm, a, &mf); + dm->getTessFace(dm, a, &mf); dm->getVert(dm, mf.v1, &mv[0]); dm->getVert(dm, mf.v2, &mv[1]); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 3da19ba7346..d1f2f7617ca 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -45,6 +45,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -198,7 +199,7 @@ unsigned int vpaint_get_current_col(VPaint *vp) return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f); } -static void do_shared_vertexcol(Mesh *me) +static void do_shared_vertex_tesscol(Mesh *me) { /* if no mcol: do not do */ /* if tface: only the involved faces, otherwise all */ @@ -264,19 +265,78 @@ static void do_shared_vertexcol(Mesh *me) MEM_freeN(scolmain); } +void do_shared_vertexcol(Mesh *me) +{ + MLoop *ml = me->mloop; + MLoopCol *lcol = me->mloopcol; + MTexPoly *mtp = me->mtpoly; + MPoly *mp = me->mpoly; + float (*scol)[5]; + int i; + + /* if no mloopcol: do not do */ + /* if mtexpoly: only the involved faces, otherwise all */ + + if(me->mloopcol==0 || me->totvert==0 || me->totpoly==0) return; + + scol = MEM_callocN(sizeof(float)*me->totvert*5, "scol"); + + for (i=0; i<me->totloop; i++, ml++, lcol++) { + if (i >= mp->loopstart + mp->totloop) { + mp++; + if (mtp) mtp++; + } + + if (mtp && !(mtp->mode & TF_SHAREDCOL)) + continue; + + scol[ml->v][0] += lcol->r; + scol[ml->v][1] += lcol->g; + scol[ml->v][2] += lcol->b; + scol[ml->v][3] += lcol->a; + scol[ml->v][4] += 1.0; + } + + for (i=0; i<me->totvert; i++) { + if (!scol[i][4]) continue; + + scol[i][0] /= scol[i][4]; + scol[i][1] /= scol[i][4]; + scol[i][2] /= scol[i][4]; + scol[i][3] /= scol[i][4]; + } + + ml = me->mloop; + lcol = me->mloopcol; + for (i=0; i<me->totloop; i++, ml++, lcol++) { + if (!scol[ml->v][4]) continue; + + lcol->r = scol[ml->v][0]; + lcol->g = scol[ml->v][1]; + lcol->b = scol[ml->v][2]; + lcol->a = scol[ml->v][3]; + } + + MEM_freeN(scol); + + do_shared_vertex_tesscol(me); +} + static void make_vertexcol(Object *ob) /* single ob */ { Mesh *me; if(!ob || ob->id.lib) return; me= get_mesh(ob); if(me==NULL) return; - if(me->edit_mesh) return; + if(me->edit_btmesh) return; /* copies from shadedisplist to mcol */ - if(!me->mcol) { - CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface); - mesh_update_customdata_pointers(me); - } + if(!me->mcol) + CustomData_add_layer(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface); + if (!me->mloopcol) + CustomData_add_layer(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop); + + mesh_update_customdata_pointers(me); //if(shade) // shadeMeshMCol(scene, ob, me); @@ -325,7 +385,7 @@ static void wpaint_mirror_vgroup_ensure(Object *ob, int *vgroup_mirror) *vgroup_mirror= -1; } -static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot) +static void copy_vpaint_prev(VPaint *vp, unsigned int *lcol, int tot) { if(vp->vpaint_prev) { MEM_freeN(vp->vpaint_prev); @@ -333,10 +393,10 @@ static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot) } vp->tot= tot; - if(mcol==NULL || tot==0) return; + if(lcol==NULL || tot==0) return; - vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev"); - memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot); + vp->vpaint_prev= MEM_mallocN(sizeof(int)*tot, "vpaint_prev"); + memcpy(vp->vpaint_prev, lcol, sizeof(int)*tot); } @@ -359,9 +419,11 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) void vpaint_fill(Object *ob, unsigned int paintcol) { Mesh *me; - MFace *mf; + MFace *mf; + MPoly *mp; + MLoopCol *lcol; unsigned int *mcol; - int i, selected; + int i, j, selected; me= get_mesh(ob); if(me==NULL || me->totface==0) return; @@ -381,6 +443,18 @@ void vpaint_fill(Object *ob, unsigned int paintcol) mcol[3] = paintcol; } } + + mp = me->mpoly; + lcol = me->mloopcol; + for (i=0; i<me->totpoly; i++, mp++) { + if (!(!selected || mp->flag & ME_FACE_SEL)) + continue; + + lcol = me->mloopcol + mp->loopstart; + for (j=0; j<mp->totloop; j++, lcol++) { + *(int*)lcol = paintcol; + } + } DAG_id_tag_update(&me->id, 0); } @@ -445,7 +519,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight) dw->weight= paintweight; if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ - int j= mesh_get_x_mirror_vert(ob, faceverts[i]); + int j= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, faceverts[i]); if(j>=0) { /* copy, not paint again */ if(vgroup_mirror != -1) { @@ -876,6 +950,7 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float /* sets wp->weight to the closest weight value to vertex */ /* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */ +#if 0// BMESH_TODO static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) { ViewContext vc; @@ -942,6 +1017,7 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_CANCELLED; } } +#endif void PAINT_OT_weight_sample(wmOperatorType *ot) { @@ -950,7 +1026,9 @@ void PAINT_OT_weight_sample(wmOperatorType *ot) ot->idname= "PAINT_OT_weight_sample"; /* api callbacks */ +#if 0 // BMESH_TODO ot->invoke= weight_sample_invoke; +#endif ot->poll= weight_paint_mode_poll; /* flags */ @@ -958,6 +1036,7 @@ void PAINT_OT_weight_sample(wmOperatorType *ot) } /* samples cursor location, and gives menu with vertex groups to activate */ +#if 0 // BMESH_TODO static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free) { if (C) { @@ -1024,6 +1103,7 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA return DummyRNA_NULL_items; } +#endif static int weight_sample_group_exec(bContext *C, wmOperator *op) { @@ -1057,7 +1137,9 @@ void PAINT_OT_weight_sample_group(wmOperatorType *ot) /* keyingset to use (dynamic enum) */ prop= RNA_def_enum(ot->srna, "group", DummyRNA_DEFAULT_items, 0, "Keying Set", "The Keying Set to use"); +#if 0 // BMESH_TODO RNA_def_enum_funcs(prop, weight_paint_sample_enum_itemf); +#endif ot->prop= prop; } @@ -1120,7 +1202,7 @@ static void do_weight_paint_vertex(VPaint *wp, Object *ob, int index, do_weight_paint_auto_normalize(me->dvert+index, vgroup, validmap); if(me->editflag & ME_EDIT_MIRROR_X) { /* x mirror painting */ - int j= mesh_get_x_mirror_vert(ob, index); + int j= -1; //BMESH_TODO mesh_get_x_mirror_vert(ob, index); if(j>=0) { /* copy, not paint again */ if(vgroup_mirror != -1) @@ -1168,7 +1250,7 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ paint_init(&wp->paint, PAINT_CURSOR_WEIGHT_PAINT); paint_cursor_start(C, weight_paint_poll); - mesh_octree_table(ob, NULL, NULL, 's'); + //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 's'); /* verify if active weight group is also active bone */ par= modifiers_isDeformedByArmature(ob); @@ -1180,8 +1262,8 @@ static int set_wpaint(bContext *C, wmOperator *UNUSED(op)) /* toggle */ } } else { - mesh_octree_table(NULL, NULL, NULL, 'e'); - mesh_mirrtopo_table(NULL, 'e'); + //BMESH_TODO mesh_octree_table(NULL, NULL, NULL, 'e'); + //BMESH_TODO mesh_mirrtopo_table(NULL, 'e'); } WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene); @@ -1303,6 +1385,13 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED me= get_mesh(ob); if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; + /*we can't assume mfaces have a correct origindex layer that indices to mpolys. + so instead we have to regenerate the tesselation faces altogether.*/ + me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, + me->mvert, me->totface, me->totloop, me->totpoly, 1, 0); + mesh_update_customdata_pointers(me); + makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0); + /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { ED_vgroup_data_create(&me->id); @@ -1427,22 +1516,22 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P if(wp->flag & VP_COLINDEX) { for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1); - if(mface->mat_nr!=ob->actcol-1) { + if(mpoly->mat_nr!=ob->actcol-1) { indexar[index]= 0; } } } } - if((me->editflag & ME_EDIT_PAINT_MASK) && me->mface) { + if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) { for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= ((MFace *)me->mface) + (indexar[index]-1); + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1); - if((mface->flag & ME_FACE_SEL)==0) { + if((mpoly->flag & ME_FACE_SEL)==0) { indexar[index]= 0; } } @@ -1458,13 +1547,14 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P paintweight= ts->vgroup_weight; for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= me->mface + (indexar[index]-1); - - (me->dvert+mface->v1)->flag= 1; - (me->dvert+mface->v2)->flag= 1; - (me->dvert+mface->v3)->flag= 1; - if(mface->v4) (me->dvert+mface->v4)->flag= 1; + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= me->mpoly + (indexar[index]-1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; + + for (i=0; i<mpoly->totloop; i++, ml++) { + (me->dvert+ml->v)->flag = 1; + } if(brush->vertexpaint_tool==VP_BLUR) { MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); @@ -1474,15 +1564,13 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P else dw_func= defvert_verify_index; - dw= dw_func(me->dvert+mface->v1, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - dw= dw_func(me->dvert+mface->v2, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - dw= dw_func(me->dvert+mface->v3, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} - if(mface->v4) { - dw= dw_func(me->dvert+mface->v4, ob->actdef-1); - if(dw) {paintweight+= dw->weight; totw++;} + ml = me->mloop + mpoly->loopstart; + for (i=0; i<mpoly->totloop; i++, ml++) { + dw = dw_func(me->dvert+ml->v, ob->actdef-1); + if (dw) { + paintweight += dw->weight; + totw++; + } } } } @@ -1492,49 +1580,20 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P paintweight/= (float)totw; for(index=0; index<totindex; index++) { - - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mface= me->mface + (indexar[index]-1); - - if((me->dvert+mface->v1)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v1, mval, pressure); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v1, - alpha, paintweight, flip, wpd->vgroup_mirror, - wpd->vgroup_validmap); - } - (me->dvert+mface->v1)->flag= 0; - } - - if((me->dvert+mface->v2)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v2, mval, pressure); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v2, - alpha, paintweight, flip, wpd->vgroup_mirror, - wpd->vgroup_validmap); - } - (me->dvert+mface->v2)->flag= 0; - } - - if((me->dvert+mface->v3)->flag) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v3, mval, pressure); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v3, - alpha, paintweight, flip, wpd->vgroup_mirror, - wpd->vgroup_validmap); - } - (me->dvert+mface->v3)->flag= 0; - } - - if((me->dvert+mface->v4)->flag) { - if(mface->v4) { - alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*mface->v4, mval, pressure); - if(alpha) { - do_weight_paint_vertex(wp, ob, mface->v4, - alpha, paintweight, flip, wpd->vgroup_mirror, + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= me->mpoly + (indexar[index]-1); + MLoop *ml=me->mloop+mpoly->loopstart; + int i; + + for (i=0; i<mpoly->totloop; i++, ml++) { + if ((me->dvert+ml->v)->flag) { + alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*ml->v, mval, pressure); + if(alpha != 0.0f) { + do_weight_paint_vertex(wp, ob, ml->v, + alpha, paintweight, flip, wpd->vgroup_mirror, wpd->vgroup_validmap); } - (me->dvert+mface->v4)->flag= 0; + (me->dvert+ml->v)->flag= 0; } } } @@ -1668,7 +1727,7 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */ return OPERATOR_PASS_THROUGH; } - if(me && me->mcol==NULL) make_vertexcol(ob); + if(me && me->mloopcol==NULL) make_vertexcol(ob); /* toggle: end vpaint */ if(ob->mode & OB_MODE_VERTEX_PAINT) { @@ -1736,14 +1795,60 @@ For future: */ +typedef struct polyfacemap_e { + struct polyfacemap_e *next, *prev; + int facenr; +} polyfacemap_e; + typedef struct VPaintData { ViewContext vc; unsigned int paintcol; int *indexar; float *vertexcosnos; float vpimat[3][3]; + + /*mpoly -> mface mapping*/ + MemArena *arena; + ListBase *polyfacemap; } VPaintData; +static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me, + Object *ob, Scene *scene) +{ + MFace *mf; + polyfacemap_e *e; + int *origIndex; + int i; + + vd->arena = BLI_memarena_new(1<<13, "vpaint tmp"); + BLI_memarena_use_calloc(vd->arena); + + vd->polyfacemap = BLI_memarena_alloc(vd->arena, sizeof(ListBase)*me->totpoly); + + /*we can't assume mfaces have a correct origindex layer that indices to mpolys. + so instead we have to regenerate the tesselation faces altogether.*/ + me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata, + me->mvert, me->totface, me->totloop, me->totpoly, 1, 0); + mesh_update_customdata_pointers(me); + makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0); + + origIndex = CustomData_get_layer(&me->fdata, CD_ORIGINDEX); + mf = me->mface; + + if (!origIndex) + return; + + for (i=0; i<me->totface; i++, mf++, origIndex++) { + if (*origIndex == ORIGINDEX_NONE) + continue; + + e = BLI_memarena_alloc(vd->arena, sizeof(polyfacemap_e)); + e->facenr = i; + + BLI_addtail(&vd->polyfacemap[*origIndex], e); + } +} + static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event)) { ToolSettings *ts= CTX_data_tool_settings(C); @@ -1751,15 +1856,19 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent VPaint *vp= ts->vpaint; struct VPaintData *vpd; Object *ob= CTX_data_active_object(C); + Scene *scene = CTX_data_scene(C); Mesh *me; float mat[4][4], imat[4][4]; /* context checks could be a poll() */ me= get_mesh(ob); - if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH; + if(me==NULL || me->totpoly==0) + return OPERATOR_PASS_THROUGH; - if(me->mcol==NULL) make_vertexcol(ob); - if(me->mcol==NULL) return OPERATOR_CANCELLED; + if(me->mloopcol==NULL) + make_vertexcol(ob); + if(me->mloopcol==NULL) + return OPERATOR_CANCELLED; /* make mode data storage */ vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData"); @@ -1769,9 +1878,10 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob); vpd->indexar= get_indexarray(me); vpd->paintcol= vpaint_get_current_col(vp); + vpaint_build_poly_facemap(vpd, me, ob, scene); /* for filtering */ - copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface); + copy_vpaint_prev(vp, (unsigned int *)me->mloopcol, me->totloop); /* some old cruft to sort out later */ mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat); @@ -1781,6 +1891,7 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent return 1; } +#if 0 static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, const float mval[2], float pressure, int UNUSED(flip)) { ViewContext *vc = &vpd->vc; @@ -1814,6 +1925,7 @@ static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0f)); } } +#endif static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { @@ -1823,6 +1935,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P Brush *brush = paint_brush(&vp->paint); ViewContext *vc= &vpd->vc; Object *ob= vc->obact; + polyfacemap_e *e; Mesh *me= ob->data; float mat[4][4]; int *indexar= vpd->indexar; @@ -1844,7 +1957,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P /* which faces are involved */ if(vp->flag & VP_AREA) { - totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush)); + totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size(brush)); } else { indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); @@ -1854,19 +1967,114 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(vc->rv3d->persmat, mat); - for(index=0; index<totindex; index++) { - if(indexar[index] && indexar[index]<=me->totface) - vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip); + if(vp->flag & VP_COLINDEX) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1); + + if(mpoly->mat_nr!=ob->actcol-1) { + indexar[index]= 0; + } + } + } } + + if((me->editflag & ME_EDIT_PAINT_MASK) && me->mpoly) { + for(index=0; index<totindex; index++) { + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1); + if((mpoly->flag & ME_FACE_SEL)==0) + indexar[index]= 0; + } + } + } + swap_m4m4(vc->rv3d->persmat, mat); /* was disabled because it is slow, but necessary for blur */ if(brush->vertexpaint_tool == VP_BLUR) do_shared_vertexcol(me); - ED_region_tag_redraw(vc->ar); + for(index=0; index<totindex; index++) { + + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= ((MPoly *)me->mpoly) + (indexar[index]-1); + MFace *mf; + MCol *mc; + MLoop *ml; + MLoopCol *mlc; + unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart; + unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart; + float alpha; + int i, j; + + if(brush->vertexpaint_tool==VP_BLUR) { + unsigned int blend[5] = {0}; + char *col; + + for (j=0; j<mpoly->totloop; j += 2) { + col = (char*)(lcol + j); + blend[0] += col[0]; + blend[1] += col[1]; + blend[2] += col[2]; + blend[3] += col[3]; + } + + blend[0] /= mpoly->totloop; + blend[1] /= mpoly->totloop; + blend[2] /= mpoly->totloop; + blend[3] /= mpoly->totloop; + col = (char*)(blend + 4); + col[0] = blend[0]; + col[1] = blend[1]; + col[2] = blend[2]; + col[3] = blend[3]; + + vpd->paintcol = *((unsigned int*)col); + } + + ml = me->mloop + mpoly->loopstart; + for (i=0; i<mpoly->totloop; i++, ml++) { + alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, + vpd->vertexcosnos+6*ml->v, mval, pressure); + if(alpha > 0.0f) vpaint_blend(vp, lcol+i, lcolorig+i, vpd->paintcol, (int)(alpha*255.0f)); + } + + #ifdef CPYCOL + #undef CPYCOL + #endif + #define CPYCOL(c, l) (c)->a = (l)->a, (c)->r = (l)->r, (c)->g = (l)->g, (c)->b = (l)->b + + /*update vertex colors for tesselations incrementally, + rather then regenerating the tesselation altogether.*/ + for (e=vpd->polyfacemap[(indexar[index]-1)].first; e; e=e->next) { + mf = me->mface + e->facenr; + mc = me->mcol + e->facenr*4; + + ml = me->mloop + mpoly->loopstart; + mlc = me->mloopcol + mpoly->loopstart; + for (j=0; j<mpoly->totloop; j++, ml++, mlc++) { + if (ml->v == mf->v1) + CPYCOL(mc, mlc); + else if (ml->v == mf->v2) + CPYCOL(mc+1, mlc); + else if (ml->v == mf->v3) + CPYCOL(mc+2, mlc); + else if (mf->v4 && ml->v == mf->v4) + CPYCOL(mc+3, mlc); + + } + } + #undef CPYCOL + } + } + + swap_m4m4(vc->rv3d->persmat, mat); + do_shared_vertexcol(me); + + ED_region_tag_redraw(vc->ar); DAG_id_tag_update(ob->data, 0); } @@ -1881,7 +2089,8 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) /* frees prev buffer */ copy_vpaint_prev(ts->vpaint, NULL, 0); - + BLI_memarena_free(vpd->arena); + MEM_freeN(vpd); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index be985342ea8..691170bd80a 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -135,7 +135,7 @@ struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob) Mesh *me= (Mesh*)ob->data; ModifierData *md; - if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) { + if(!CustomData_get_layer(&me->ldata, CD_MDISPS)) { /* multires can't work without displacement layer */ return NULL; } @@ -231,6 +231,8 @@ typedef struct StrokeCache { float mouse[2]; float bstrength; float tex_mouse[2]; + + rctf prect; /* The rest is temporary storage that isn't saved as a property */ @@ -277,10 +279,20 @@ typedef struct StrokeCache { static int sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d, Object *ob, rcti *rect) { + StrokeCache *cache = ob->sculpt->cache; PBVH *pbvh= ob->sculpt->pbvh; float bb_min[3], bb_max[3], pmat[4][4]; int i, j, k; +/* if (G.rt == 1) { + rect->xmin = cache->prect.xmin; + rect->xmax = cache->prect.xmax; + rect->ymin = cache->prect.ymin; + rect->ymax = cache->prect.ymax; + + return rect->xmin < rect->xmax && rect->ymin < rect->ymax;; + } +*/ ED_view3d_ob_project_mat_get(rv3d, ob, pmat); if(!pbvh) @@ -335,6 +347,7 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar, PBVH *pbvh= ob->sculpt->pbvh; BoundBox bb; bglMats mats; + StrokeCache *cache = ob->sculpt->cache; rcti rect; memset(&bb, 0, sizeof(BoundBox)); @@ -363,6 +376,13 @@ void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar, /* clear redraw flag from nodes */ if(pbvh) BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL); + + /*clear prect*/ + cache->prect.xmin = FLT_MAX; + cache->prect.xmax = -FLT_MAX; + cache->prect.ymin = FLT_MAX; + cache->prect.ymax = -FLT_MAX; + } /************************ Brush Testing *******************/ @@ -1394,7 +1414,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode proxy= BLI_pbvh_node_add_proxy(ss->pbvh, nodes[n])->co; sculpt_brush_test_init(ss, &test); - + BLI_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) { if(sculpt_brush_test(&test, vd.co)) { const float fade = bstrength*tex_strength(ss, brush, vd.co, test.dist)*frontface(brush, an, vd.no, vd.fno); @@ -2220,10 +2240,11 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod { SculptSession *ss = ob->sculpt; Brush *brush = paint_brush(&sd->paint); + rctf mr; + float xrad, yrad; float bstrength = ss->cache->bstrength; const float radius = ss->cache->radius; - float an[3]; float fc[3]; float offset = get_offset(sd, ss); @@ -2320,7 +2341,7 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) for (a= 0; a < me->totvert; a++, mvert++) VECCOPY(mvert->co, vertCos[a]); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } /* apply new coords on active key block */ @@ -2553,7 +2574,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob) /* Modifiers could depend on mesh normals, so we should update them/ Note, then if sculpting happens on locked key, normals should be re-calculated after applying coords from keyblock on base mesh */ - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else if (ss->kb) sculpt_update_keyblock(ob); } @@ -2718,7 +2739,7 @@ void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_ if(mmd) { ss->multires = mmd; ss->totvert = dm->getNumVerts(dm); - ss->totface = dm->getNumFaces(dm); + ss->totface = dm->getNumTessFaces(dm); ss->mvert= NULL; ss->mface= NULL; ss->face_normals= NULL; @@ -2869,6 +2890,11 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio int mode; ss->cache = cache; + + cache->prect.xmin = FLT_MAX; + cache->prect.xmax = -FLT_MAX; + cache->prect.ymin = FLT_MAX; + cache->prect.ymax = -FLT_MAX; /* Set scaling adjustment */ ss->cache->scale[0] = 1.0f / ob->size[0]; @@ -3363,13 +3389,18 @@ static void sculpt_flush_update(bContext *C) ARegion *ar = CTX_wm_region(C); MultiresModifierData *mmd = ss->multires; - if(mmd) - multires_mark_as_modified(ob); + if (!ss->cache) { + if(mmd) + multires_mark_as_modified(ob); + } + if(ob->derivedFinal) /* VBO no longer valid */ GPU_drawobject_free(ob->derivedFinal); - if(ss->modifiers_active) { + if (!ss->cache) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + + if(ss->modifiers_active) { ED_region_tag_redraw(ar); } else { @@ -3491,6 +3522,7 @@ static void sculpt_stroke_done(bContext *C, struct PaintStroke *UNUSED(stroke)) sculpt_cache_free(ss->cache); ss->cache = NULL; + sculpt_flush_update(C); sculpt_undo_push_end(); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index c4ea5c9478c..ca1737fdf87 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -196,8 +196,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb) tag_update= ((Mesh*)ob->data)->id.us > 1; if(ss->modifiers_active) { - Mesh *me= ob->data; - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + Mesh *mesh= ob->data; + mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL); sculpt_free_deformMats(ss); tag_update|= 1; diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index 4cbb290be76..bb9b85c5f30 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_api/SConscript b/source/blender/editors/space_api/SConscript index d6a763a78ff..6bf901cf8ad 100644 --- a/source/blender/editors/space_api/SConscript +++ b/source/blender/editors/space_api/SConscript @@ -4,7 +4,7 @@ Import ('env') sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../blenloader ../../makesdna' -incs += ' ../../windowmanager ../../python ../../makesrna' +incs += ' ../../windowmanager ../../python ../../makesrna ../../bmesh' incs += ' #/intern/guardedalloc #/extern/glew/include' defs = '' diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 4f8cb8a57b2..05edf2b167d 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -41,6 +41,8 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "bmesh.h" + #include "UI_interface.h" #include "UI_view2d.h" diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript index a4270f1f59a..2f90f1dbf31 100644 --- a/source/blender/editors/space_buttons/SConscript +++ b/source/blender/editors/space_buttons/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../makesrna ../../render/extern/include ../../blenloader' +incs += ' ../../bmesh ../../makesrna ../../render/extern/include ../../blenloader' defs = [] diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 0d4408faf49..d811f018618 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenlib ../../blenloader ../../imbuf + ../../bmesh ../../makesdna ../../makesrna ../../render/extern/include diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript index 27696e35701..cdd2133d0f5 100644 --- a/source/blender/editors/space_image/SConscript +++ b/source/blender/editors/space_image/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../render/extern/include ../../makesrna ../../blenloader' +incs += ' ../../bmesh ../../render/extern/include ../../makesrna ../../blenloader' defs = [] diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 2e9544f5d20..c74dc950df8 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -276,12 +276,11 @@ int ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit) return 0; if(obedit && obedit->type == OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + struct BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; int ret; - ret = EM_texFaceCheck(em); + ret = EDBM_texFaceCheck(em); - BKE_mesh_end_editmesh(obedit->data, em); return ret; } @@ -295,12 +294,11 @@ int ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit) if(ED_space_image_show_paint(sima)) if(obedit && obedit->type == OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + struct BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; int ret; - ret = EM_texFaceCheck(em); + ret = EDBM_texFaceCheck(em); - BKE_mesh_end_editmesh(obedit->data, em); return ret; } @@ -583,13 +581,13 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa)) if(ima && (ima->source==IMA_SRC_VIEWER || sima->pin)); else if(obedit && obedit->type == OB_MESH) { Mesh *me= (Mesh*)obedit->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - MTFace *tf; + struct BMEditMesh *em= me->edit_btmesh; + MTexPoly *tf; - if(em && EM_texFaceCheck(em)) { + if(em && EDBM_texFaceCheck(em)) { sima->image= NULL; - tf = EM_get_active_mtface(em, NULL, NULL, 1); /* partially selected face is ok */ + tf = EDBM_get_active_mtexpoly(em, NULL, 1); /* partially selected face is ok */ if(tf && (tf->mode & TF_TEX)) { /* don't need to check for pin here, see above */ @@ -599,8 +597,6 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa)) else sima->curtile= tf->tile; } } - - BKE_mesh_end_editmesh(obedit->data, em); } } diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index 22347df93a3..1930fb6bcc8 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenlib ../../blenloader ../../imbuf + ../../bmesh ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript index 697ee4319b8..746edadccc2 100644 --- a/source/blender/editors/space_info/SConscript +++ b/source/blender/editors/space_info/SConscript @@ -4,7 +4,7 @@ Import ('env') sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf ../../blenfont' -incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader' +incs += ' ../../bmesh ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../blenloader' defs = [] diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 0abfd4b71a1..0a384018c8a 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -47,6 +47,7 @@ #include "BKE_key.h" #include "BKE_mesh.h" #include "BKE_particle.h" +#include "BKE_tessmesh.h" #include "ED_info.h" #include "ED_armature.h" @@ -140,26 +141,16 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) static void stats_object_edit(Object *obedit, SceneStats *stats) { if(obedit->type==OB_MESH) { - /* Mesh Edit */ - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - EditVert *eve; - EditEdge *eed; - EditFace *efa; + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + + stats->totvert = em->bm->totvert; + stats->totvertsel = em->bm->totvertsel; - for(eve= em->verts.first; eve; eve=eve->next) { - stats->totvert++; - if(eve->f & SELECT) stats->totvertsel++; - } - for(eed= em->edges.first; eed; eed=eed->next) { - stats->totedge++; - if(eed->f & SELECT) stats->totedgesel++; - } - for(efa= em->faces.first; efa; efa=efa->next) { - stats->totface++; - if(efa->f & SELECT) stats->totfacesel++; - } + stats->totedge = em->bm->totedge; + stats->totedgesel = em->bm->totedgesel; - EM_validate_selections(em); + stats->totface = em->bm->totface; + stats->totfacesel = em->bm->totfacesel; } else if(obedit->type==OB_ARMATURE){ /* Armature Edit */ diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript index 634d4b777d9..6a5556e3e51 100644 --- a/source/blender/editors/space_node/SConscript +++ b/source/blender/editors/space_node/SConscript @@ -14,7 +14,7 @@ if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): if env['CC'] == 'gcc': #cf.append('-Werror') pass - + if env['OURPLATFORM'] == 'linux2': cflags='-pthread' incs += ' ../../../extern/binreloc/include' diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt index c6e936606c8..53b23cc7c53 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript index 84ba8d1fe86..53bd7828b63 100644 --- a/source/blender/editors/space_view3d/SConscript +++ b/source/blender/editors/space_view3d/SConscript @@ -7,7 +7,7 @@ defs = [ 'GLEW_STATIC' ] incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include ../../blenloader' -incs += ' ../../gpu ../../makesrna ../../blenfont' +incs += ' ../../gpu ../../makesrna ../../blenfont ../../bmesh' incs += ' #/intern/smoke/extern' incs += ' #source/gameengine/BlenderRoutines' diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index f070bae4e54..351be1ca4c9 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -35,6 +35,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_edgehash.h" @@ -47,6 +48,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" #include "DNA_object_types.h" #include "BKE_DerivedMesh.h" @@ -55,6 +57,7 @@ #include "BKE_material.h" #include "BKE_paint.h" #include "BKE_property.h" +#include "BKE_tessmesh.h" #include "BIF_gl.h" @@ -409,9 +412,10 @@ static void draw_textured_end(void) glPopMatrix(); } -static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr) +static int draw_tface__set_draw_legacy(MTFace *tface, int has_vcol, int matnr) { - if (tface && (tface->mode&TF_INVISIBLE)) return 0; + if (tface && (tface->mode&TF_INVISIBLE)) + return 0; if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) { glColor3ub(0xFF, 0x00, 0xFF); @@ -419,7 +423,7 @@ static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr) } else if (tface && tface->mode&TF_OBCOL) { glColor3ubv(Gtexdraw.obcol); return 2; /* Don't set color */ - } else if (!mcol) { + } else if (!has_vcol) { if (tface) glColor3f(1.0, 1.0, 1.0); else { Material *ma= give_current_material(Gtexdraw.ob, matnr+1); @@ -437,7 +441,7 @@ static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr) return 1; /* Set color from mcol */ } } -static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr) +static int draw_tface__set_draw(MTFace *tface, int has_vcol, int matnr) { if (tface && (tface->mode&TF_INVISIBLE)) return 0; @@ -445,7 +449,7 @@ static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr) return 2; /* Don't set color */ } else if (tface && tface->mode&TF_OBCOL) { return 2; /* Don't set color */ - } else if (!mcol) { + } else if (!has_vcol) { return 1; /* Don't set color */ } else { return 1; /* Set color from mcol */ @@ -454,15 +458,15 @@ static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr) static void add_tface_color_layer(DerivedMesh *dm) { MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE); - MFace *mface = DM_get_face_data_layer(dm, CD_MFACE); + MFace *mface = dm->getTessFaceArray(dm); MCol *finalCol; int i,j; - MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL); + MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL); if(!mcol) - mcol = dm->getFaceDataArray(dm, CD_MCOL); + mcol = dm->getTessFaceDataArray(dm, CD_MCOL); - finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumFaces(dm),"add_tface_color_layer"); - for(i=0;i<dm->getNumFaces(dm);i++) { + finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumTessFaces(dm),"add_tface_color_layer"); + for(i=0;i<dm->getNumTessFaces(dm);i++) { if (tface && (tface->mode&TF_INVISIBLE)) { if( mcol ) memcpy(&finalCol[i*4],&mcol[i*4],sizeof(MCol)*4); @@ -528,30 +532,53 @@ static void add_tface_color_layer(DerivedMesh *dm) static int draw_tface_mapped__set_draw(void *userData, int index) { Mesh *me = (Mesh*)userData; - MTFace *tface = (me->mtface)? &me->mtface[index]: NULL; - MFace *mface = &me->mface[index]; - MCol *mcol = (me->mcol)? &me->mcol[index]: NULL; - const int matnr = mface->mat_nr; - if (mface->flag & ME_HIDE) return 0; - return draw_tface__set_draw(tface, mcol, matnr); + MTexPoly *tpoly = (me->mtpoly)? &me->mtpoly[index]: NULL; + MPoly *mpoly = (me->mpoly)? &me->mpoly[index]: NULL; + MTFace mtf; + int matnr = me->mpoly[index].mat_nr; + + if (mpoly && mpoly->flag&ME_HIDE) return 0; + + memset(&mtf, 0, sizeof(mtf)); + if (tpoly) { + mtf.flag = tpoly->flag; + mtf.tpage = tpoly->tpage; + mtf.transp = tpoly->transp; + mtf.mode = tpoly->mode; + mtf.tile = tpoly->tile; + mtf.unwrap = tpoly->unwrap; + } + + return draw_tface__set_draw(&mtf, CustomData_has_layer(&me->ldata, CD_MLOOPCOL), matnr); } static int draw_em_tf_mapped__set_draw(void *userData, int index) { - EditMesh *em = userData; - EditFace *efa= EM_get_face_for_index(index); - MTFace *tface; - MCol *mcol; - int matnr; + BMEditMesh *em = userData; + BMFace *efa= EDBM_get_face_for_index(em, index); + MTexPoly *tpoly; + MTFace mtf; + int matnr, has_vcol; - if (efa->h) + if (efa==NULL || BM_TestHFlag(efa, BM_HIDDEN)) return 0; - tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL); + tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + has_vcol = CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); matnr = efa->mat_nr; - return draw_tface__set_draw_legacy(tface, mcol, matnr); + memset(&mtf, 0, sizeof(mtf)); + + if (tpoly) { + mtf.flag = tpoly->flag; + mtf.tpage = tpoly->tpage; + mtf.transp = tpoly->transp; + mtf.mode = tpoly->mode; + mtf.tile = tpoly->tile; + mtf.unwrap = tpoly->unwrap; + } + + return draw_tface__set_draw_legacy(&mtf, has_vcol, matnr); } static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r) @@ -667,7 +694,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o glColor4f(1.0f,1.0f,1.0f,1.0f); if(ob->mode & OB_MODE_EDIT) { - dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh); + dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_btmesh); } else if(faceselect) { if(ob->mode & OB_MODE_WEIGHT_PAINT) dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index e314d249e6d..b308368e72b 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -48,6 +48,7 @@ #include "DNA_world_types.h" #include "DNA_armature_types.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_editVert.h" @@ -75,6 +76,8 @@ #include "BKE_pointcache.h" #include "BKE_unit.h" +#include "BKE_tessmesh.h" + #include "smoke_API.h" #include "IMB_imbuf.h" @@ -226,7 +229,7 @@ static int check_material_alpha(Base *base, Mesh *me, int glsl) if(G.f & G_PICKSEL) return 0; - if(me->edit_mesh) + if(me->edit_btmesh) return 0; return (glsl || (base->object->dtx & OB_DRAWTRANSP)); @@ -1621,16 +1624,21 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) * use the object matrix in the useual way */ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) { - struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; - EditVert *eve = EM_get_vert_for_index(index); + struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { short s[2]= {IS_CLIPPED, 0}; + float co2[3]; + + VECCOPY(co2, co); + + mul_m4_v3(data->vc.obedit->obmat, co2); if (data->clipVerts) { view3d_project_short_clip(data->vc.ar, co, s, 1); } else { - view3d_project_short_noclip(data->vc.ar, co, s); + project_short_noclip(data->vc.ar, co2, s); } if (s[0]!=IS_CLIPPED) @@ -1638,39 +1646,46 @@ static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co } } -void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts) +void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts) { - struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; + EDBM_init_index_arrays(vc->em, 1, 0, 0); if(clipVerts) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 1, 0, 0); dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co) { - struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData; - EditEdge *eed = EM_get_edge_for_index(index); + struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData; + BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index); short s[2][2]; + float v1_co[3], v2_co[3]; + + VECCOPY(v1_co, v0co); + VECCOPY(v2_co, v1co); + + mul_m4_v3(data->vc.obedit->obmat, v1_co); + mul_m4_v3(data->vc.obedit->obmat, v2_co); - if (eed->h==0) { + if (!BM_TestHFlag(eed, BM_HIDDEN)) { if (data->clipVerts==1) { view3d_project_short_clip(data->vc.ar, v0co, s[0], 1); view3d_project_short_clip(data->vc.ar, v1co, s[1], 1); } else { - view3d_project_short_noclip(data->vc.ar, v0co, s[0]); - view3d_project_short_noclip(data->vc.ar, v1co, s[1]); + project_short_noclip(data->vc.ar, v1_co, s[0]); + project_short_noclip(data->vc.ar, v2_co, s[1]); if (data->clipVerts==2) { if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy)) @@ -1683,54 +1698,57 @@ static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0 } } -void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) +void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts) { - struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; data.clipVerts = clipVerts; + EDBM_init_index_arrays(vc->em, 0, 1, 0); if(clipVerts) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 0, 1, 0); dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no)) { - struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData; - EditFace *efa = EM_get_face_for_index(index); + struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData; + float cent2[3]; + BMFace *efa = EDBM_get_face_for_index(data->vc.em, index); short s[2]; - if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { - view3d_project_short_clip(data->vc.ar, cent, s, 1); + VECCOPY(cent2, cent); + if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) { + mul_m4_v3(data->vc.obedit->obmat, cent2); + project_short(data->vc.ar, cent2, s); data->func(data->userData, efa, s[0], s[1], index); } } -void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData) +void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData) { - struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data; + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; data.userData = userData; + EDBM_init_index_arrays(vc->em, 0, 0, 1); //if(clipVerts) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 0, 0, 1); dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data); - EM_free_index_arrays(); + EDBM_free_index_arrays(vc->em); dm->release(dm); } @@ -1797,46 +1815,53 @@ void nurbs_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, Nurb static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no) { - ToolSettings *ts= ((Scene *)userData)->toolsettings; - EditFace *efa = EM_get_face_for_index(index); + Scene *scene= ((void **)userData)[0]; + BMEditMesh *em = ((void **)userData)[1]; + BMFace *efa = EDBM_get_face_for_index(em, index); + ToolSettings *ts= scene->toolsettings; - if (efa->h==0 && efa->fgonf!=EM_FGON) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { glVertex3fv(cent); glVertex3f( cent[0] + no[0]*ts->normalsize, cent[1] + no[1]*ts->normalsize, cent[2] + no[2]*ts->normalsize); } } -static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) +static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { + void *ptrs[2] = {scene, em}; + glBegin(GL_LINES); - dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene); + dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs); glEnd(); } static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no)) { - EditFace *efa = EM_get_face_for_index(index); - int sel = *((int*) userData); - - if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) { + BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index); + int sel = *(((int **)userData)[1]); + + if (efa && !BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) { bglVertex3fv(cent); } } -static void draw_dm_face_centers(DerivedMesh *dm, int sel) +static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel) { + void *ptrs[2] = {em, &sel}; + bglBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel); + dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs); bglEnd(); } static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) { - Scene *scene= (Scene *)userData; + Scene *scene= ((void **)userData)[0]; ToolSettings *ts= scene->toolsettings; - EditVert *eve = EM_get_vert_for_index(index); + BMEditMesh *em = ((void **)userData)[1]; + BMVert *eve = EDBM_get_vert_for_index(em, index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { glVertex3fv(co); if (no_f) { @@ -1850,20 +1875,22 @@ static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, } } } -static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm) +static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { + void *ptrs[2] = {scene, em}; + glBegin(GL_LINES); - dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene); + dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs); glEnd(); } - /* Draw verts with color set based on selection */ +/* Draw verts with color set based on selection */ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) { - struct { int sel; EditVert *eve_act; } * data = userData; - EditVert *eve = EM_get_vert_for_index(index); + struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData; + BMVert *eve = EDBM_get_vert_for_index(data->em, index); - if (eve->h==0 && (eve->f&SELECT)==data->sel) { + if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) { /* draw active larger - need to stop/start point drawing for this :/ */ if (eve==data->eve_act) { float size = UI_GetThemeValuef(TH_VERTEX_SIZE); @@ -1885,11 +1912,16 @@ static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float * } } -static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) +static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act) { - struct { int sel; EditVert *eve_act; } data; + struct { BMEditMesh *em; int sel; BMVert *eve_act; } data; data.sel = sel; data.eve_act = eve_act; + data.em = em; + + bglBegin(GL_POINTS); + dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); + bglEnd(); bglBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); @@ -1899,16 +1931,18 @@ static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act) /* Draw edges with color set based on selection */ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed; //unsigned char **cols = userData, *col; - struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData; + struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData; unsigned char *col; - if (eed->h==0) { + eed = EDBM_get_edge_for_index(data->em, index); + + if (!BM_TestHFlag(eed, BM_HIDDEN)) { if (eed==data->eed_act) { glColor4ubv(data->actCol); } else { - if (eed->f&SELECT) { + if (BM_TestHFlag(eed, BM_SELECT)) { col = data->selCol; } else { col = data->baseCol; @@ -1923,38 +1957,40 @@ static int draw_dm_edges_sel__setDrawOptions(void *userData, int index) return 0; } } -static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act) +static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, + unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act) { - struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data; + struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data; data.baseCol = baseCol; data.selCol = selCol; data.actCol = actCol; + data.em = em; data.eed_act = eed_act; dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data); } /* Draw edges */ -static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_edges__setDrawOptions(void *userData, int index) { - return EM_get_edge_for_index(index)->h==0; + return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN); } -static void draw_dm_edges(DerivedMesh *dm) +static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em); } /* Draw edges with color interpolated based on selection */ -static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index) { - return EM_get_edge_for_index(index)->h==0; + return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_HIDDEN); } static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[0], index); unsigned char **cols = userData; - unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0]; - unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0]; + unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?2:1]; + unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?2:1]; glColor4ub( col0[0] + (col1[0]-col0[0])*t, col0[1] + (col1[1]-col0[1])*t, @@ -1962,36 +1998,36 @@ static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int i col0[3] + (col1[3]-col0[3])*t); } -static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) +static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol) { - unsigned char *cols[2]; - cols[0]= baseCol; - cols[1]= selCol; + void *cols[3] = {em, baseCol, selCol}; + dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols); } /* Draw only seam edges */ -static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_edges_seams__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - return (eed->h==0 && eed->seam); + return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SEAM); } -static void draw_dm_edges_seams(DerivedMesh *dm) + +static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em); } /* Draw only sharp edges */ -static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEdge *eed = EDBM_get_edge_for_index(userData, index); - return (eed->h==0 && eed->sharp); + return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP); } -static void draw_dm_edges_sharp(DerivedMesh *dm) +static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em); } @@ -1999,18 +2035,24 @@ static void draw_dm_edges_sharp(DerivedMesh *dm) * return 2 for the active face so it renders with stipple enabled */ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r)) { - struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData; - EditFace *efa = EM_get_face_for_index(index); + struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData; + BMFace *efa = EDBM_get_face_for_index(data->em, index); unsigned char *col; - if (efa->h==0) { + if (!efa) + return 0; + + if (!BM_TestHFlag(efa, BM_HIDDEN)) { if (efa == data->efa_act) { glColor4ubv(data->cols[2]); + return 2; /* stipple */ } else { - col = data->cols[(efa->f&SELECT)?1:0]; + col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0]; if (col[3]==0) return 0; + glColor4ubv(col); + return 1; } } @@ -2018,68 +2060,87 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNU } /* also draws the active face */ -static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) +static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, + unsigned char *selCol, unsigned char *actCol, BMFace *efa_act, Mesh *me) { - struct { unsigned char *cols[3]; EditFace *efa_act; } data; + struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data; + data.cols[0] = baseCol; + data.em = em; data.cols[1] = selCol; data.cols[2] = actCol; data.efa_act = efa_act; + data.me = me; dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material); } -static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_creases__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); - - if (eed->h==0 && eed->crease != 0.0f) { - UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease); + BMEditMesh *em = userData; + BMEdge *eed = EDBM_get_edge_for_index(userData, index); + float *crease = eed ? bm_get_cd_float(&em->bm->edata, eed->head.data, CD_CREASE) : NULL; + + if (!crease) + return 0; + + if (!BM_TestHFlag(eed, BM_HIDDEN) && *crease!=0.0f) { + UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease); return 1; } else { return 0; } } -static void draw_dm_creases(DerivedMesh *dm) +static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm) { glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em); glLineWidth(1.0); } -static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_bweights__setDrawOptions(void *userData, int index) { - EditEdge *eed = EM_get_edge_for_index(index); + BMEditMesh *em = userData; + BMEdge *eed = EDBM_get_edge_for_index(userData, index); + float *bweight = bm_get_cd_float(&em->bm->edata, eed->head.data, CD_BWEIGHT); - if (eed->h==0 && eed->bweight != 0.0f) { - UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight); + if (!bweight) + return 0; + + if (!BM_TestHFlag(eed, BM_HIDDEN) && *bweight!=0.0f) { + UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight); return 1; } else { return 0; } } -static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) +static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) { - EditVert *eve = EM_get_vert_for_index(index); - - if (eve->h==0 && eve->bweight != 0.0f) { - UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight); + BMEditMesh *em = userData; + BMVert *eve = EDBM_get_vert_for_index(userData, index); + float *bweight = bm_get_cd_float(&em->bm->vdata, eve->head.data, CD_BWEIGHT); + + if (!bweight) + return; + + if (!BM_TestHFlag(eve, BM_HIDDEN) && *bweight!=0.0f) { + UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight); bglVertex3fv(co); } } -static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) +static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { ToolSettings *ts= scene->toolsettings; if (ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2); bglBegin(GL_POINTS); - dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL); + dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em); bglEnd(); } else { glLineWidth(3.0); - dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em); glLineWidth(1.0); } } @@ -2093,7 +2154,8 @@ static void draw_dm_bweights(Scene *scene, DerivedMesh *dm) /* EditMesh drawing routines*/ -static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, DerivedMesh *cageDM, EditVert *eve_act) +static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, + BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act) { ToolSettings *ts= scene->toolsettings; int sel; @@ -2130,13 +2192,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, Deriv if(ts->selectmode & SCE_SELECT_VERTEX) { glPointSize(size); glColor4ubv(col); - draw_dm_verts(cageDM, sel, eve_act); + draw_dm_verts(em, cageDM, sel, eve_act); } if(check_ob_drawface_dot(scene, v3d, obedit->dt)) { glPointSize(fsize); glColor4ubv(fcol); - draw_dm_face_centers(cageDM, sel); + draw_dm_face_centers(em, cageDM, sel); } if (pass==0) { @@ -2150,7 +2212,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, Deriv glPointSize(1.0); } -static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act) +static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, + Mesh *me, DerivedMesh *cageDM, short sel_only, + BMEdge *eed_act) { ToolSettings *ts= scene->toolsettings; int pass; @@ -2183,21 +2247,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh } if(ts->selectmode == SCE_SELECT_FACE) { - draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) { if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) { glShadeModel(GL_SMOOTH); - draw_dm_edges_sel_interp(cageDM, wireCol, selCol); + draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol); glShadeModel(GL_FLAT); } else { - draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act); + draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act); } } else { if (!sel_only) { glColor4ubv(wireCol); - draw_dm_edges(cageDM); + draw_dm_edges(em, cageDM); } } @@ -2208,13 +2272,11 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh } } -static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit) +static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, + Object *ob, BMEditMesh *em, UnitSettings *unit) { Mesh *me= ob->data; - EditEdge *eed; - EditFace *efa; - float v1[3], v2[3], v3[3], v4[3], vmid[3]; - float fvec[3]; + float v1[3], v2[3], v3[3], vmid[3], fvec[3]; char val[32]; /* Stores the measurement display text here */ const char *conv_float; /* Use a float conversion matching the grid size */ unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */ @@ -2224,6 +2286,9 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E const int do_global= v3d->flag & V3D_GLOBAL_STATS; const int do_moving= G.moving; + BMIter iter; + int i; + /* make the precision of the pronted value proportionate to the gridsize */ if (grid < 0.01f) conv_float= "%.6g"; @@ -2238,11 +2303,16 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f); if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { + BMEdge *eed; + UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col); - for(eed= em->edges.first; eed; eed= eed->next) { - /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */ - if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) { + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for(; eed; eed=BMIter_Step(&iter)) { + /* draw selected edges, or edges next to selected verts while draging */ + if(BM_TestHFlag(eed, BM_SELECT) || + (do_moving && (BM_TestHFlag(eed->v1, BM_SELECT) || BM_TestHFlag(eed->v2, BM_SELECT) ))) { + copy_v3_v3(v1, eed->v1->co); copy_v3_v3(v2, eed->v2->co); @@ -2263,109 +2333,108 @@ static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, E } if(me->drawflag & ME_DRAWEXTRA_FACEAREA) { -// XXX extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now? + /* would be nice to use BM_face_area, but that is for 2d faces + so instead add up tessalation triangle areas */ + BMFace *f; + int n; + +#define DRAW_EM_MEASURE_STATS_FACEAREA(void)\ + if (BM_TestHFlag(f, BM_SELECT)) {\ + mul_v3_fl(vmid, 1.0/n);\ + if(unit->system)\ + bUnit_AsString(val, sizeof(val), area*unit->scale_length,\ + 3, unit->system, B_UNIT_LENGTH, do_split, FALSE);\ + else\ + sprintf(val, conv_float, area);\ + view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);\ + } + UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col); - for(efa= em->faces.first; efa; efa= efa->next) { - if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) { - copy_v3_v3(v1, efa->v1->co); - copy_v3_v3(v2, efa->v2->co); - copy_v3_v3(v3, efa->v3->co); - if (efa->v4) { - copy_v3_v3(v4, efa->v4->co); - } - if(do_global) { - mul_mat3_m4_v3(ob->obmat, v1); - mul_mat3_m4_v3(ob->obmat, v2); - mul_mat3_m4_v3(ob->obmat, v3); - if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4); - } - - if (efa->v4) - area= area_quad_v3(v1, v2, v3, v4); - else - area = area_tri_v3(v1, v2, v3); - - if(unit->system) - bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA - else - sprintf(val, conv_float, area); - - view3d_cached_text_draw_add(efa->cent, val, 0, V3D_CACHE_TEXT_ASCII, col); + f = NULL; + area = 0.0; + zero_v3(vmid); + n = 0; + for(i = 0; i < em->tottri; i++) { + BMLoop **l = em->looptris[i]; + if(f && l[0]->f != f) { + DRAW_EM_MEASURE_STATS_FACEAREA(); + zero_v3(vmid); + area = 0.0; + n = 0; } - } - } - if(me->drawflag & ME_DRAWEXTRA_FACEANG) { - EditEdge *e1, *e2, *e3, *e4; - UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col); - for(efa= em->faces.first; efa; efa= efa->next) { - copy_v3_v3(v1, efa->v1->co); - copy_v3_v3(v2, efa->v2->co); - copy_v3_v3(v3, efa->v3->co); - if(efa->v4) { - copy_v3_v3(v4, efa->v4->co); - } - else { - copy_v3_v3(v4, v3); - } + f = l[0]->f; + copy_v3_v3(v1, l[0]->v->co); + copy_v3_v3(v2, l[1]->v->co); + copy_v3_v3(v3, l[2]->v->co); if(do_global) { mul_mat3_m4_v3(ob->obmat, v1); mul_mat3_m4_v3(ob->obmat, v2); mul_mat3_m4_v3(ob->obmat, v3); - mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */ } - - e1= efa->e1; - e2= efa->e2; - e3= efa->e3; - if(efa->e4) e4= efa->e4; else e4= e3; - - /* Calculate the angles */ - - if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) { - /* Vec 1 */ - sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2))); - interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f); - view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col); - } - if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) { - /* Vec 2 */ - sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3))); - interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f); - view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col); - } - if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) { - /* Vec 3 */ - if(efa->v4) - sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4))); - else - sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1))); - interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f); - view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col); - } - /* Vec 4 */ - if(efa->v4) { - if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) { - sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1))); - interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f); + area += area_tri_v3(v1, v2, v3); + add_v3_v3(vmid, v1); + add_v3_v3(vmid, v2); + add_v3_v3(vmid, v3); + n += 3; + } + + if(f){ + DRAW_EM_MEASURE_STATS_FACEAREA(); + } +#undef DRAW_EM_MEASURE_STATS_FACEAREA + } + + if(me->drawflag & ME_DRAWEXTRA_FACEANG) { + BMFace *efa; + + UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col); + + + for(efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + efa; efa=BMIter_Step(&iter)) { + BMIter liter; + BMLoop *loop; + + BM_Compute_Face_Center(em->bm, efa, vmid); + + for(loop = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + loop; loop = BMIter_Step(&liter)) { + + float v1[3], v2[3], v3[3]; + + copy_v3_v3(v1, loop->prev->v->co); + copy_v3_v3(v2, loop->v->co); + copy_v3_v3(v3, loop->next->v->co); + + if(do_global){ + mul_mat3_m4_v3(ob->obmat, v1); + mul_mat3_m4_v3(ob->obmat, v2); + mul_mat3_m4_v3(ob->obmat, v3); + } + + if(BM_TestHFlag(efa, BM_SELECT) || + (do_moving && BM_TestHFlag(loop->v, BM_SELECT))){ + sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3))); + interp_v3_v3v3(fvec, vmid, v2, 0.8f); view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col); } } } } - + if(v3d->zbuf) { glEnable(GL_DEPTH_TEST); bglPolygonOffset(rv3d->dist, 0.0f); } } -static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r)) +static int draw_em_fancy__setFaceOpts(void *userData, int index, int *UNUSED(drawSmooth_r)) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(userData, index); - if (efa->h==0) { + if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) { GPU_enable_material(efa->mat_nr+1, NULL); return 1; } @@ -2373,33 +2442,35 @@ static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UN return 0; } -static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index) +static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(userData, index); - return (efa->h==0); + return !BM_TestHFlag(efa, BM_HIDDEN); } -static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) +static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, + BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) + { Mesh *me = ob->data; - EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */ - EditEdge *eed_act = NULL; - EditVert *eve_act = NULL; + BMFace *efa_act = EDBM_get_actFace(em, 0); /* annoying but active faces is stored differently */ + BMEdge *eed_act = NULL; + BMVert *eve_act = NULL; - if (em->selected.last) { - EditSelection *ese = em->selected.last; + if (em->bm->selected.last) { + BMEditSelection *ese = em->bm->selected.last; /* face is handeled above */ /*if (ese->type == EDITFACE ) { efa_act = (EditFace *)ese->data; } else */ if ( ese->type == EDITEDGE ) { - eed_act = (EditEdge *)ese->data; + eed_act = (BMEdge *)ese->data; } else if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + eve_act = (BMVert *)ese->data; } } - EM_init_index_arrays(em, 1, 1, 1); + EDBM_init_index_arrays(em, 1, 1, 1); if(dt>OB_WIRE) { if(CHECK_OB_DRAWTEXTURE(v3d, dt)) { @@ -2407,7 +2478,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material, - draw_em_fancy__setGLSLFaceOpts, NULL); + draw_em_fancy__setGLSLFaceOpts, em); GPU_disable_material(); glFrontFace(GL_CCW); @@ -2422,8 +2493,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); - - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, NULL, 0, GPU_enable_material); + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, me->edit_btmesh, 0, GPU_enable_material); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); @@ -2457,7 +2527,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object if CHECK_OB_DRAWTEXTURE(v3d, dt) col1[3] = 0; - draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -2472,7 +2542,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object glEnable(GL_BLEND); glDepthMask(0); // disable write in zbuffer, needed for nice transp - draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -2484,14 +2554,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object /* we are drawing textures and 'ME_DRAWEDGES' is disabled, dont draw any edges */ /* only draw selected edges otherwise there is no way of telling if a face is selected */ - draw_em_fancy_edges(scene, v3d, me, cageDM, 1, eed_act); + draw_em_fancy_edges(em, scene, v3d, me, cageDM, 1, eed_act); } else { if(me->drawflag & ME_DRAWSEAMS) { UI_ThemeColor(TH_EDGE_SEAM); glLineWidth(2); - draw_dm_edges_seams(cageDM); + draw_dm_edges_seams(em, cageDM); glColor3ub(0,0,0); glLineWidth(1); @@ -2501,33 +2571,33 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object UI_ThemeColor(TH_EDGE_SHARP); glLineWidth(2); - draw_dm_edges_sharp(cageDM); + draw_dm_edges_sharp(em, cageDM); glColor3ub(0,0,0); glLineWidth(1); } - if(me->drawflag & ME_DRAWCREASES) { - draw_dm_creases(cageDM); + if(me->drawflag & ME_DRAWCREASES && CustomData_has_layer(&em->bm->edata, CD_CREASE)) { + draw_dm_creases(em, cageDM); } if(me->drawflag & ME_DRAWBWEIGHTS) { - draw_dm_bweights(scene, cageDM); + draw_dm_bweights(em, scene, cageDM); } - - draw_em_fancy_edges(scene, v3d, me, cageDM, 0, eed_act); + + draw_em_fancy_edges(em, scene, v3d, me, cageDM, 0, eed_act); } if(em) { // XXX retopo_matrix_update(v3d); - draw_em_fancy_verts(scene, v3d, ob, cageDM, eve_act); + draw_em_fancy_verts(scene, v3d, ob, em, cageDM, eve_act); if(me->drawflag & ME_DRAWNORMALS) { UI_ThemeColor(TH_NORMAL); - draw_dm_face_normals(scene, cageDM); + draw_dm_face_normals(em, scene, cageDM); } if(me->drawflag & ME_DRAW_VNORMALS) { UI_ThemeColor(TH_VNORMAL); - draw_dm_vert_normals(scene, cageDM); + draw_dm_vert_normals(em, scene, cageDM); } if(me->drawflag & (ME_DRAWEXTRA_EDGELEN|ME_DRAWEXTRA_FACEAREA|ME_DRAWEXTRA_FACEANG) && !((v3d->flag2 & V3D_RENDER_OVERRIDE))) @@ -2540,7 +2610,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object GPU_disable_material(); } - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } /* Mesh drawing routines */ @@ -2595,7 +2665,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* totvert = dm->getNumVerts(dm); */ /*UNUSED*/ totedge = dm->getNumEdges(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumTessFaces(dm); /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */ if(dt!=OB_SHADED) @@ -2817,7 +2887,7 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D Object *ob= base->object; Object *obedit= scene->obedit; Mesh *me= ob->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; int do_alpha_pass= 0, drawlinked= 0, retval= 0, glsl, check_alpha; if(obedit && ob!=obedit && ob->data==obedit->data) { @@ -2830,9 +2900,9 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D DerivedMesh *finalDM, *cageDM; if (obedit!=ob) - finalDM = cageDM = editmesh_get_derived_base(ob, em); + finalDM = cageDM = editbmesh_get_derived_base(ob, em); else - cageDM = editmesh_get_derived_cage_and_final(scene, ob, em, &finalDM, + cageDM = editbmesh_get_derived_cage_and_final(scene, ob, em, &finalDM, scene->customdata_mask); if(dt>OB_WIRE) { @@ -6360,44 +6430,51 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) { - int offset = (intptr_t) userData; - EditVert *eve = EM_get_vert_for_index(index); + void **ptrs = userData; + int offset = (intptr_t) ptrs[0]; + BMVert *eve = EDBM_get_vert_for_index(ptrs[1], index); - if (eve->h==0) { + if (!BM_TestHFlag(eve, BM_HIDDEN)) { WM_set_framebuffer_index_color(offset+index); bglVertex3fv(co); } } -static void bbs_mesh_verts(DerivedMesh *dm, int offset) +static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) { + void *ptrs[2] = {(void*)(intptr_t) offset, em}; + glPointSize( UI_GetThemeValuef(TH_VERTEX_SIZE) ); bglBegin(GL_POINTS); - dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(intptr_t) offset); + dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, ptrs); bglEnd(); glPointSize(1.0); } static int bbs_mesh_wire__setDrawOptions(void *userData, int index) { - int offset = (intptr_t) userData; - EditEdge *eed = EM_get_edge_for_index(index); + void **ptrs = userData; + int offset = (intptr_t) ptrs[0]; + BMEdge *eed = EDBM_get_edge_for_index(ptrs[1], index); - if (eed->h==0) { + if (!BM_TestHFlag(eed, BM_HIDDEN)) { WM_set_framebuffer_index_color(offset+index); return 1; } else { return 0; } } -static void bbs_mesh_wire(DerivedMesh *dm, int offset) +static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) { - dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(intptr_t) offset); + void *ptrs[2] = {(void*)(intptr_t) offset, em}; + dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, ptrs); } static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r)) { - if (EM_get_face_for_index(index)->h==0) { - if (userData) { + BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index); + + if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) { + if (((void**)userData)[1]) { WM_set_framebuffer_index_color(index+1); } return 1; @@ -6406,11 +6483,11 @@ static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *U } } -static void bbs_mesh_solid__drawCenter(void *UNUSED(userData), int index, float *cent, float *UNUSED(no)) +static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *UNUSED(no)) { - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(((void**)userData)[0], index); - if (efa->h==0 && efa->fgonf!=EM_FGON) { + if (!BM_TestHFlag(efa, BM_HIDDEN)) { WM_set_framebuffer_index_color(index+1); bglVertex3fv(cent); @@ -6418,23 +6495,26 @@ static void bbs_mesh_solid__drawCenter(void *UNUSED(userData), int index, float } /* two options, facecolors or black */ -static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh *dm, int facecol) +static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, + Object *ob, DerivedMesh *dm, int facecol) { + void *ptrs[2] = {em, NULL}; //second one being null means to draw black cpack(0); if (facecol) { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0, GPU_enable_material); + ptrs[1] = (void*)(intptr_t) 1; + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material); if(check_ob_drawface_dot(scene, v3d, ob->dt)) { glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE)); bglBegin(GL_POINTS); - dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL); + dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, ptrs); bglEnd(); } } else { - dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0, GPU_enable_material); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material); } } @@ -6483,36 +6563,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec { if(ob->mode & OB_MODE_EDIT) { Mesh *me= ob->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; - DerivedMesh *dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); + DerivedMesh *dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); - EM_init_index_arrays(em, 1, 1, 1); + EDBM_init_index_arrays(em, 1, 1, 1); - bbs_mesh_solid_EM(scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE); + bbs_mesh_solid_EM(em, scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE); if(ts->selectmode & SCE_SELECT_FACE) - em_solidoffs = 1+em->totface; + bm_solidoffs = 1+em->bm->totface; else - em_solidoffs= 1; + bm_solidoffs= 1; bglPolygonOffset(rv3d->dist, 1.0); // we draw edges always, for loop (select) tools - bbs_mesh_wire(dm, em_solidoffs); - em_wireoffs= em_solidoffs + em->totedge; + bbs_mesh_wire(em, dm, bm_solidoffs); + bm_wireoffs= bm_solidoffs + em->bm->totedge; // we draw verts if vert select mode or if in transform (for snap). if(ts->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT) { - bbs_mesh_verts(dm, em_wireoffs); - em_vertoffs= em_wireoffs + em->totvert; + bbs_mesh_verts(em, dm, bm_wireoffs); + bm_vertoffs= bm_wireoffs + em->bm->totvert; } - else em_vertoffs= em_wireoffs; + else bm_vertoffs= bm_wireoffs; bglPolygonOffset(rv3d->dist, 0.0); dm->release(dm); - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } else bbs_mesh_solid(scene, ob); } @@ -6538,7 +6618,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r int glsl; if(ob->mode & OB_MODE_EDIT) - edm= editmesh_get_derived_base(ob, me->edit_mesh); + edm= editbmesh_get_derived_base(ob, me->edit_btmesh); else dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index acdbcb0d06d..805887e3805 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -40,6 +40,7 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_editVert.h" diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 6833dec2e43..d9fcb45881c 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -479,6 +479,7 @@ static int view3d_ima_bg_drop_poll(bContext *C, wmDrag *drag, wmEvent *event) if( ED_view3d_give_base_under_cursor(C, event->mval) ) { return 0; } + return view3d_ima_drop_poll(C, drag, event); } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 6e03866153f..64a3e473975 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -60,6 +60,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "BKE_deform.h" #include "WM_api.h" @@ -153,31 +154,32 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve, *evedef=NULL; - EditEdge *eed; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve, *evedef=NULL; + BMEdge *eed; + BMIter iter; - eve= em->verts.first; - while(eve) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { evedef= eve; tot++; add_v3_v3(median, eve->co); } - eve= eve->next; } - eed= em->edges.first; - while(eed) { - if((eed->f & SELECT)) { + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { + float *f = bm_get_cd_float(&bm->edata, eed->head.data, CD_CREASE); + totedge++; - median[3]+= eed->crease; + median[3]+= f ? *f : 0.0f; } - eed= eed->next; } /* check for defgroups */ if(evedef) - dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT); + dvert= CustomData_bmesh_get(&em->bm->vdata, evedef->head.data, CD_MDEFORMVERT); if(tot==1 && dvert && dvert->totweight) { bDeformGroup *dg; int i, max=1, init=1; @@ -201,8 +203,6 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float tfp->defweightp= &dvert->dw[0].weight; } } - - BKE_mesh_end_editmesh(me, em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { Curve *cu= ob->data; @@ -387,31 +387,34 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; + BMVert *eve; + BMIter iter; - /* allow for some rounding error becasue of matrix transform */ if(len_v3(median) > 0.000001f) { - EditVert *eve; - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { add_v3_v3(eve->co, median); } } - - recalc_editnormals(em); + + EDBM_RecalcNormals(em); } - + if(median[3] != 0.0f) { - EditEdge *eed; + BMEdge *eed; const float fixed_crease= (ve_median[3] <= 0.0f ? 0.0f : (ve_median[3] >= 1.0f ? 1.0f : FLT_MAX)); if(fixed_crease != FLT_MAX) { /* simple case */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->crease= fixed_crease; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { + float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE); + if (!crease) break; + + *crease= fixed_crease; } } } @@ -428,10 +431,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* scale down */ const float sca= median_new / median_orig; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->crease *= sca; - CLAMP(eed->crease, 0.0f, 1.0f); + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT) && !BM_TestHFlag(eed, BM_HIDDEN)) { + float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE); + + if (!crease) break; + + *crease *= sca; + CLAMP(*crease, 0.0f, 1.0f); } } } @@ -439,17 +446,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* scale up */ const float sca= (1.0f - median_new) / (1.0f - median_orig); - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->crease = 1.0f - ((1.0f - eed->crease) * sca); - CLAMP(eed->crease, 0.0f, 1.0f); + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT) && !BM_TestHFlag(eed, BM_HIDDEN)) { + float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE); + if (!crease) break; + + *crease = 1.0f - ((1.0f - *crease) * sca); + CLAMP(*crease, 0.0f, 1.0f); } } } } } - - BKE_mesh_end_editmesh(me, em); + + EDBM_RecalcNormals(em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { Curve *cu= ob->data; @@ -526,37 +536,35 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float #define B_VGRP_PNL_EDIT_SINGLE 8 /* or greater */ #define B_VGRP_PNL_COPY_SINGLE 16384 /* or greater */ -static void act_vert_def(Object *ob, EditVert **eve, MDeformVert **dvert) +static void act_vert_def(Object *ob, BMVert **eve, MDeformVert **dvert) { if(ob && ob->mode & OB_MODE_EDIT && ob->type==OB_MESH && ob->defbase.first) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditSelection *ese = ((EditSelection*)em->selected.last); + BMEditMesh *em = me->edit_btmesh; + BMEditSelection *ese = ((BMEditSelection*)em->bm->selected.last); - if(ese && ese->type == EDITVERT) { - *eve= (EditVert*)ese->data; - *dvert= CustomData_em_get(&em->vdata, (*eve)->data, CD_MDEFORMVERT); + if(ese && ese->type == BM_VERT) { + *eve= (BMVert*)ese->data; + *dvert= CustomData_bmesh_get(&em->bm->vdata, (*eve)->head.data, CD_MDEFORMVERT); return; } - - BKE_mesh_end_editmesh(me, em); } *eve= NULL; *dvert= NULL; } -static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int index) +static void editvert_mirror_update(Object *ob, BMVert *eve, int def_nr, int index) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve_mirr; + BMEditMesh *em = me->edit_btmesh; + BMVert *eve_mirr; - eve_mirr= editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); + eve_mirr= editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index); if(eve_mirr && eve_mirr != eve) { - MDeformVert *dvert_src= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); - MDeformVert *dvert_dst= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT); + MDeformVert *dvert_src= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + MDeformVert *dvert_dst= CustomData_bmesh_get(&em->bm->vdata, eve_mirr->head.data, CD_MDEFORMVERT); if(dvert_dst) { if(def_nr == -1) { /* all vgroups, add groups where neded */ @@ -578,7 +586,7 @@ static void editvert_mirror_update(Object *ob, EditVert *eve, int def_nr, int in static void vgroup_adjust_active(Object *ob, int def_nr) { - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dvert_act; act_vert_def(ob, &eve_act, &dvert_act); @@ -591,7 +599,7 @@ static void vgroup_adjust_active(Object *ob, int def_nr) static void vgroup_copy_active_to_sel(Object *ob) { - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dvert_act; act_vert_def(ob, &eve_act, &dvert_act); @@ -601,14 +609,15 @@ static void vgroup_copy_active_to_sel(Object *ob) } else { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; MDeformVert *dvert; int index= 0; - for(eve= em->verts.first; eve; eve= eve->next, index++) { - if(eve->f & SELECT && eve != eve_act) { - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT) && eve != eve_act) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) { defvert_copy(dvert, dvert_act); @@ -617,13 +626,15 @@ static void vgroup_copy_active_to_sel(Object *ob) } } + + index++; } } } static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) { - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dvert_act; act_vert_def(ob, &eve_act, &dvert_act); @@ -633,8 +644,9 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) } else { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; MDeformVert *dvert; MDeformWeight *dw; float act_weight = -1.0f; @@ -650,10 +662,11 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) if(act_weight < -0.5f) return; - - for(eve= em->verts.first; eve; eve= eve->next, index++) { - if(eve->f & SELECT && eve != eve_act) { - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (index=0; eve; eve=BMIter_Step(&iter), index++) { + if(BM_TestHFlag(eve, BM_SELECT) && eve != eve_act) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) { for(i=0, dw=dvert->dw; i < dvert->totweight; i++, dw++) { if(def_nr == dw->def_nr) { @@ -677,7 +690,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, int def_nr) static void vgroup_normalize_active(Object *ob) { - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dvert_act; act_vert_def(ob, &eve_act, &dvert_act); @@ -725,7 +738,7 @@ static int view3d_panel_vgroup_poll(const bContext *C, PanelType *UNUSED(pt)) { Scene *scene= CTX_data_scene(C); Object *ob= OBACT; - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dvert_act; act_vert_def(ob, &eve_act, &dvert_act); @@ -740,7 +753,7 @@ static void view3d_panel_vgroup(const bContext *C, Panel *pa) Scene *scene= CTX_data_scene(C); Object *ob= OBACT; - EditVert *eve; + BMVert *eve; MDeformVert *dvert; act_vert_def(ob, &eve, &dvert); diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 75c8d5cae73..1df85192389 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -55,6 +55,7 @@ #include "BKE_modifier.h" #include "BKE_paint.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "ED_mesh.h" #include "ED_util.h" @@ -325,12 +326,12 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) ScrArea *sa= CTX_wm_area(C); View3D *v3d= sa->spacedata.first; Object *obedit = CTX_data_edit_object(C); - EditMesh *em= NULL; + BMEditMesh *em= NULL; int ctrl= win->eventstate->ctrl, shift= win->eventstate->shift; PointerRNA props_ptr; if(obedit && obedit->type==OB_MESH) { - em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + em= ((Mesh *)obedit->data)->edit_btmesh; } /* watch it: if sa->win does not exist, check that when calling direct drawing routines */ @@ -351,7 +352,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) if(shift==0 || em->selectmode==0) em->selectmode= SCE_SELECT_VERTEX; ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); ED_undo_push(C, "Selectmode Set: Vertex"); } @@ -360,12 +361,12 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) if(em) { if(shift==0 || em->selectmode==0){ if( (em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX){ - if(ctrl) EM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE); + if(ctrl) EDBM_convertsel(em, SCE_SELECT_VERTEX,SCE_SELECT_EDGE); } em->selectmode = SCE_SELECT_EDGE; } ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); ED_undo_push(C, "Selectmode Set: Edge"); } @@ -373,14 +374,13 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) case B_SEL_FACE: if(em) { if( shift==0 || em->selectmode==0){ - if( ((em->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((em->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){ - if(ctrl) - EM_convertsel(em, (em->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE); + if( ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){ + if(ctrl) EDBM_convertsel(em, (ts->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE); } em->selectmode = SCE_SELECT_FACE; } ts->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); ED_undo_push(C, "Selectmode Set: Face"); } @@ -413,9 +413,6 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event) default: break; } - - if(obedit && obedit->type==OB_MESH) - BKE_mesh_end_editmesh(obedit->data, em); } /* Returns the icon associated with an object mode */ @@ -440,7 +437,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL); if(obedit && (obedit->type == OB_MESH)) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; uiLayout *row; row= uiLayoutRow(layout, 1); @@ -448,8 +445,6 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C) uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode"); uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode"); uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode"); - - BKE_mesh_end_editmesh(obedit->data, em); } } @@ -478,11 +473,17 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiBlockSetEmboss(block, UI_EMBOSS); /* mode */ - if(ob) + if(ob) { + /*sanity point checkpoint, put here to avoid seeding + this same code in 10 different other places.*/ + if (!ob->mode) + ob->mode = OB_MODE_OBJECT; + v3d->modeselect = ob->mode; - else + } else { v3d->modeselect = OB_MODE_OBJECT; - + } + uiBlockBeginAlign(block); uiDefIconTextButS(block, MENU, B_MODESELECT, object_mode_icon(v3d->modeselect), view3d_modeselect_pup(scene) , 0,0,126 * dpi_fac, UI_UNIT_Y, &(v3d->modeselect), 0, 0, 0, 0, "Mode"); @@ -551,4 +552,3 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiTemplateEditModeSelection(layout, C); } - diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 9290e1fc631..32fc7f12359 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: view3d_select.c 35106 2011-02-23 10:52:22Z jesterking $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -57,7 +57,7 @@ #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_armature.h" - +#include "BKE_tessmesh.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -156,57 +156,63 @@ void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglM /* local prototypes */ -static void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select) +static void EDBM_backbuf_checkAndSelectVerts(BMEditMesh *em, int select) { - EditVert *eve; - int index= em_wireoffs; + BMVert *eve; + BMIter iter; + int index= bm_wireoffs; - for(eve= em->verts.first; eve; eve= eve->next, index++) { - if(eve->h==0) { - if(EM_check_backbuf(index)) { - eve->f = select?(eve->f|1):(eve->f&~1); + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_Select_Vert(em->bm, eve, select); } } } } -static void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select) +static void EDBM_backbuf_checkAndSelectEdges(BMEditMesh *em, int select) { - EditEdge *eed; - int index= em_solidoffs; + BMEdge *eed; + BMIter iter; + int index= bm_solidoffs; - for(eed= em->edges.first; eed; eed= eed->next, index++) { - if(eed->h==0) { - if(EM_check_backbuf(index)) { - EM_select_edge(eed, select); + eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(eed, BM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_Select_Edge(em->bm, eed, select); } } } } -static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select) +static void EDBM_backbuf_checkAndSelectFaces(BMEditMesh *em, int select) { - EditFace *efa; + BMFace *efa; + BMIter iter; int index= 1; - for(efa= em->faces.first; efa; efa= efa->next, index++) { - if(efa->h==0) { - if(EM_check_backbuf(index)) { - EM_select_face_fgon(em, efa, select); + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BMIter_Step(&iter), index++) { + if(!BM_TestHFlag(efa, BM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_Select_Face(em->bm, efa, select); } } } } -static void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select) +static void EDBM_backbuf_checkAndSelectTFaces(Mesh *me, int select) { - MFace *mface = me->mface; + MPoly *mpoly = me->mpoly; int a; - if (mface) { - for(a=1; a<=me->totface; a++, mface++) { - if(EM_check_backbuf(a)) { - mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL); + if (mpoly) { + for(a=1; a<=me->totpoly; a++, mpoly++) { + if(EDBM_check_backbuf(a)) { + mpoly->flag = select?(mpoly->flag|ME_FACE_SEL):(mpoly->flag&~ME_FACE_SEL); } } } @@ -426,39 +432,39 @@ static void lasso_select_boundbox(rcti *rect, int mcords[][2], short moves) } } -static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) +static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index)) { struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select(data->vc.em->bm, eve, data->select); } } -static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) +static void do_lasso_select_mesh__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) { struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; - if (EM_check_backbuf(em_solidoffs+index)) { + if (EDBM_check_backbuf(bm_solidoffs+index)) { if (data->pass==0) { if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) && lasso_inside(data->mcords, data->moves, x0, y0) && lasso_inside(data->mcords, data->moves, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select(data->vc.em->bm, eed, data->select); data->done = 1; } } else { if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select(data->vc.em->bm, eed, data->select); } } } } -static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) +static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) { struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { - EM_select_face_fgon(data->vc.em, efa, data->select); + BM_Select(data->vc.em->bm, efa, data->select); } } @@ -472,7 +478,7 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, lasso_select_boundbox(&rect, mcords, moves); /* set editmesh */ - vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; + vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh; data.vc= *vc; data.rect = ▭ @@ -483,17 +489,17 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, data.pass = 0; if (extend == 0 && select) - EM_deselect_all(vc->em); + EDBM_clear_flag_all(vc->em, BM_SELECT); /* for non zbuf projections, dont change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); glLoadMatrixf(vc->rv3d->viewmat); - bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + bbsel= EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); if(ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - EM_backbuf_checkAndSelectVerts(vc->em, select); + EDBM_backbuf_checkAndSelectVerts(vc->em, select); } else { mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1); @@ -512,15 +518,15 @@ static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, if(ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - EM_backbuf_checkAndSelectFaces(vc->em, select); + EDBM_backbuf_checkAndSelectFaces(vc->em, select); } else { mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data); } } - EM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_free_backbuf(); + EDBM_selectmode_flush(vc->em); } #if 0 @@ -739,14 +745,14 @@ static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short mo if(extend==0 && select) paintface_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */ - em_vertoffs= me->totface+1; /* max index array */ + bm_vertoffs= me->totpoly+1; /* max index array */ lasso_select_boundbox(&rect, mcords, moves); - EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - EM_backbuf_checkAndSelectTFaces(me, select); + EDBM_backbuf_checkAndSelectTFaces(me, select); - EM_free_backbuf(); + EDBM_free_backbuf(); paintface_flush_flags(ob); } @@ -1438,37 +1444,37 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int ex return OPERATOR_FINISHED; } -static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) +static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index)) { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select(data->vc.em->bm, eve, data->select); } } -static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) +static void do_mesh_box_select__doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index) { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; - if(EM_check_backbuf(em_solidoffs+index)) { + if(EDBM_check_backbuf(bm_solidoffs+index)) { if (data->pass==0) { if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select(data->vc.em->bm, eed, data->select); data->done = 1; } } else { if (edge_inside_rect(data->rect, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select(data->vc.em->bm, eed, data->select); } } } } -static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) +static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) { struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - EM_select_face_fgon(data->vc.em, efa, data->select); + BM_Select(data->vc.em->bm, efa, data->select); } } static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend) @@ -1484,17 +1490,17 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten data.done = 0; if (extend == 0 && select) - EM_deselect_all(vc->em); + EDBM_clear_flag_all(vc->em, BM_SELECT); /* for non zbuf projections, dont change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); glLoadMatrixf(vc->rv3d->viewmat); - bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); + bbsel= EDBM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); if(ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - EM_backbuf_checkAndSelectVerts(vc->em, select); + EDBM_backbuf_checkAndSelectVerts(vc->em, select); } else { mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1); } @@ -1513,15 +1519,15 @@ static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int exten if(ts->selectmode & SCE_SELECT_FACE) { if(bbsel) { - EM_backbuf_checkAndSelectFaces(vc->em, select); + EDBM_backbuf_checkAndSelectFaces(vc->em, select); } else { mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data); } } - EM_free_backbuf(); + EDBM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_selectmode_flush(vc->em); return OPERATOR_FINISHED; } @@ -1755,7 +1761,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) if(vc.obedit) { switch(vc.obedit->type) { case OB_MESH: - vc.em= ((Mesh *)vc.obedit->data)->edit_mesh; + vc.em= ((Mesh *)vc.obedit->data)->edit_btmesh; ret= do_mesh_box_select(&vc, &rect, select, extend); // if (EM_texFaceCheck()) if(ret & OPERATOR_FINISHED) { @@ -1896,32 +1902,32 @@ void VIEW3D_OT_select(wmOperatorType *ot) /* -------------------- circle select --------------------------------------------- */ -static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) +static void mesh_circle_doSelectVert(void *userData, BMVert *eve, int x, int y, int UNUSED(index)) { struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; int mx = x - data->mval[0], my = y - data->mval[1]; float r = sqrt(mx*mx + my*my); if (r<=data->radius) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_Select(data->vc->em->bm, eve, data->select); } } -static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index)) +static void mesh_circle_doSelectEdge(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index)) { struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) { - EM_select_edge(eed, data->select); + BM_Select(data->vc->em->bm, eed, data->select); } } -static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) +static void mesh_circle_doSelectFace(void *userData, BMFace *efa, int x, int y, int UNUSED(index)) { struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; int mx = x - data->mval[0], my = y - data->mval[1]; float r = sqrt(mx*mx + my*my); if (r<=data->radius) { - EM_select_face_fgon(data->vc->em, efa, data->select); + BM_Select(data->vc->em->bm, efa, data->select); } } @@ -1931,10 +1937,10 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f int bbsel; struct {ViewContext *vc; short select; int mval[2]; float radius; } data; - bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); + bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ - vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; + vc->em= ((Mesh *)vc->obedit->data)->edit_btmesh; data.vc = vc; data.select = select; @@ -1944,7 +1950,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f if(ts->selectmode & SCE_SELECT_VERTEX) { if(bbsel) { - EM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE); + EDBM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE); } else { mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1); } @@ -1952,7 +1958,7 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f if(ts->selectmode & SCE_SELECT_EDGE) { if (bbsel) { - EM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE); + EDBM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE); } else { mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0); } @@ -1960,14 +1966,14 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f if(ts->selectmode & SCE_SELECT_FACE) { if(bbsel) { - EM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE); + EDBM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE); } else { mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data); } } - EM_free_backbuf(); - EM_selectmode_flush(vc->em); + EDBM_free_backbuf(); + EDBM_selectmode_flush(vc->em); } static void paint_facesel_circle_select(ViewContext *vc, int select, const int mval[2], float rad) @@ -1977,11 +1983,11 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m int bbsel; if (me) { - em_vertoffs= me->totface+1; /* max index array */ + bm_vertoffs= me->totpoly+1; /* max index array */ - bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); - EM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE); - EM_free_backbuf(); + bbsel= EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); + EDBM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE); + EDBM_free_backbuf(); } } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index b4d2fc22143..ad10c703b80 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -1,5 +1,5 @@ /* - * $Id$ + * $Id: view3d_snap.c 35106 2011-02-23 10:52:22Z jesterking $ * * ***** BEGIN GPL LICENSE BLOCK ***** * @@ -57,6 +57,8 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_tessmesh.h" +#include "BKE_DerivedMesh.h" #include "WM_api.h" #include "WM_types.h" @@ -79,10 +81,11 @@ extern float originmat[3][3]; /* XXX object.c */ typedef struct TransVert { float *loc; - float oldloc[3], fac; + float oldloc[3], maploc[3], fac; float *val, oldval; int flag; float *nor; + int f1; } TransVert; static TransVert *transvmain=NULL; @@ -98,7 +101,7 @@ static void special_transvert_update(Object *obedit) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - recalc_editnormals(me->edit_mesh); // does face centers too + BM_Compute_Normals(me->edit_btmesh->bm); // does face centers too } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu= obedit->data; @@ -189,6 +192,19 @@ static void special_transvert_update(Object *obedit) } } +static void set_mapped_co(void *vuserdata, int index, float *co, float *UNUSED(no), short *UNUSED(no_s)) +{ + void ** userdata = vuserdata; + BMEditMesh *em = userdata[0]; + TransVert *tv = userdata[1]; + BMVert *eve = EDBM_get_vert_for_index(em, index); + + if (BM_GetIndex(eve) != -1 && !tv[BM_GetIndex(eve)].f1) { + copy_v3_v3(tv[BM_GetIndex(eve)].maploc, co); + tv[BM_GetIndex(eve)].f1 = 1; + } +} + /* copied from editobject.c, needs to be replaced with new transform code still */ /* mode flags: */ #define TM_ALL_JOINTS 1 /* all joints (for bones only) */ @@ -200,7 +216,7 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) BPoint *bp; TransVert *tv=NULL; MetaElem *ml; - EditVert *eve; + BMVert *eve; EditBone *ebo; float total, center[3], centroid[3]; int a; @@ -212,52 +228,87 @@ static void make_trans_verts(Object *obedit, float *min, float *max, int mode) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em= me->edit_mesh; + BMEditMesh *em= me->edit_btmesh; + BMesh *bm = em->bm; + BMIter iter; + void *userdata[2] = {em, NULL}; + /*int proptrans= 0; */ /*UNUSED*/ // transform now requires awareness for select mode, so we tag the f1 flags in verts tottrans= 0; - if(em->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0 && (eve->f & SELECT)) { - eve->f1= SELECT; + if(em->bm->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) { + BM_SetIndex(eve, 1); tottrans++; } - else eve->f1= 0; + else BM_SetIndex(eve, 0); } } - else if(em->selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT; + else if(em->bm->selectmode & SCE_SELECT_EDGE) { + BMEdge *eed; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) + BM_SetIndex(eve, 0); + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT)) + BM_SetIndex(eed->v1, 1), BM_SetIndex(eed->v2, 1); } - for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) + if(BM_GetIndex(eve)) tottrans++; } else { - EditFace *efa; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && (efa->f & SELECT)) { - efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; - if(efa->v4) efa->v4->f1= SELECT; + BMFace *efa; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) + BM_SetIndex(eve, 0); + + BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) { + if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) { + BMIter liter; + BMLoop *l; + + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) { + BM_SetIndex(l->v, 1); + } } } - for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) + if(BM_GetIndex(eve)) tottrans++; } /* and now make transverts */ if(tottrans) { tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts"); - - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f1) { + + a = 0; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_GetIndex(eve)) { + BM_SetIndex(eve, a); VECCOPY(tv->oldloc, eve->co); tv->loc= eve->co; if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f) tv->nor= eve->no; // note this is a hackish signal (ton) - tv->flag= eve->f1 & SELECT; + tv->flag= BM_GetIndex(eve) & SELECT; tv++; - } + a++; + } else BM_SetIndex(eve, -1); + } + + userdata[1] = transvmain; + } + + if (transvmain && em->derivedCage) { + EDBM_init_index_arrays(em, 1, 0, 0); + em->derivedCage->foreachMappedVert(em->derivedCage, set_mapped_co, userdata); + EDBM_free_index_arrays(em); + } else if (transvmain) { + tv = transvmain; + for (a=0; a<tottrans; a++, tv++) { + copy_v3_v3(tv->maploc, tv->loc); } } } @@ -866,10 +917,10 @@ static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op)) if (obedit->type == OB_MESH) { /* check active */ Mesh *me= obedit->data; - EditSelection ese; + BMEditSelection ese; - if (EM_get_actSelection(me->edit_mesh, &ese)) { - EM_editselection_center(curs, &ese); + if (EDBM_get_actSelection(me->edit_btmesh, &ese)) { + EDBM_editselection_center(me->edit_btmesh, curs, &ese); } mul_m4_v3(obedit->obmat, curs); @@ -954,7 +1005,7 @@ int minmax_verts(Object *obedit, float *min, float *max) tv= transvmain; for(a=0; a<tottrans; a++, tv++) { - VECCOPY(vec, tv->loc); + VECCOPY(vec, tv->maploc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); add_v3_v3(centroid, vec); @@ -966,4 +1017,3 @@ int minmax_verts(Object *obedit, float *min, float *max) return 1; } - diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c index 2e96800bf3b..f06b4678d70 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -264,3 +264,4 @@ void VIEW3D_OT_toolshelf(wmOperatorType *ot) /* flags */ ot->flag= 0; } + diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index eeaf87757ce..7b1ef9634a2 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -698,7 +698,6 @@ void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][ mul_m4_m4m4(pmat, vmat, rv3d->winmat); } -#if 0 /* Uses window coordinates (x,y) and depth component z to find a point in modelspace */ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z) @@ -711,13 +710,13 @@ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, out[1] = uy; out[2] = uz; } -#endif -/* use above call to get projecting mat */ +/* use view3d_get_object_project_mat to get projecting mat */ void ED_view3d_project_float(ARegion *ar, const float vec[3], float adr[2], float mat[4][4]) { float vec4[4]; + VECCOPY(vec4, vec); adr[0]= IS_CLIPPED; copy_v3_v3(vec4, vec); vec4[3]= 1.0; @@ -732,6 +731,26 @@ void ED_view3d_project_float(ARegion *ar, const float vec[3], float adr[2], floa } } +/* use view3d_get_object_project_mat to get projecting mat */ +void ED_view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4]) +{ + float vec4[4]; + + VECCOPY(vec4, vec); + adr[0]= IS_CLIPPED; + vec4[3]= 1.0; + + mul_m4_v4(mat, vec4); + + if( vec4[3]>FLT_EPSILON ) { + adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3]; + adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3]; + adr[2] = vec4[2]/vec4[3]; + } else { + adr[0] = adr[1] = adr[2] = 0.0f; + } +} + int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb) { /* return 1: draw */ @@ -1793,7 +1812,7 @@ static int game_engine_exec(bContext *C, wmOperator *op) if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */ rctf cam_framef; - ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE); + ED_view3d_calc_camera_border(startscene, ar, rv3d, CTX_wm_view3d(C), &cam_framef, FALSE); cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin; cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin; cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin; diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index 283b09f42e4..c0a1a6a29f4 100644 --- a/source/blender/editors/transform/CMakeLists.txt +++ b/source/blender/editors/transform/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript index edc2156a07b..eba73b080f0 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -6,6 +6,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' incs += ' ../../render/extern/include' -incs += ' ../../gpu ../../makesrna ../../blenloader' +incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh' env.BlenderLib ( 'bf_editors_transform', sources, Split(incs), [], libtype=['core'], priority=[40] ) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d3a30991aa6..fa1fcb6c150 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -84,6 +84,8 @@ #include "BLI_editVert.h" #include "BLI_ghash.h" #include "BLI_linklist.h" +#include "BLI_smallhash.h" +#include "BLI_array.h" #include "UI_resources.h" @@ -93,6 +95,8 @@ #include "transform.h" +#include <stdio.h> + void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg); int doEdgeSlide(TransInfo *t, float perc); @@ -3484,7 +3488,8 @@ static void applyTranslation(TransInfo *t, float vec[3]) { protectedTransBits(td->protectflag, tvec); - add_v3_v3v3(td->loc, td->iloc, tvec); + if (td->loc) + add_v3_v3v3(td->loc, td->iloc, tvec); constraintTransLim(t, td); } @@ -4290,508 +4295,456 @@ int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2])) } /* ******************** Edge Slide *************** */ +static BMEdge *get_other_edge(BMesh *bm, BMVert *v, BMEdge *e) +{ + BMIter iter; + BMEdge *e2; + + BM_ITER(e2, &iter, bm, BM_EDGES_OF_VERT, v) { + if (BM_TestHFlag(e2, BM_SELECT) && e2 != e) + return e2; + } + + return NULL; +} + +static BMLoop *get_next_loop(BMesh *UNUSED(bm), BMVert *v, BMLoop *l, + BMEdge *olde, BMEdge *nexte, float vec[3]) +{ + BMLoop *firstl; + float a[3] = {0.0f, 0.0f, 0.0f}, n[3] = {0.0f, 0.0f, 0.0f}; + int i=0; + + firstl = l; + do { + l = BM_OtherFaceLoop(l->e, l->f, v); + if (l->radial_next == l) + return NULL; + + if (l->e == nexte) { + if (i) { + mul_v3_fl(a, 1.0f / (float)i); + } else { + float f1[3], f2[3], f3[3]; + + sub_v3_v3v3(f1, BM_OtherEdgeVert(olde, v)->co, v->co); + sub_v3_v3v3(f2, BM_OtherEdgeVert(nexte, v)->co, v->co); + + cross_v3_v3v3(f3, f1, l->f->no); + cross_v3_v3v3(a, f2, l->f->no); + mul_v3_fl(a, -1.0f); + + add_v3_v3(a, f3); + mul_v3_fl(a, 0.5f); + } + + VECCOPY(vec, a); + return l; + } else { + sub_v3_v3v3(n, BM_OtherEdgeVert(l->e, v)->co, v->co); + add_v3_v3v3(a, a, n); + i += 1; + } + + if (BM_OtherFaceLoop(l->e, l->f, v)->e == nexte) { + if (i) + mul_v3_fl(a, 1.0f / (float)i); + + VECCOPY(vec, a); + return BM_OtherFaceLoop(l->e, l->f, v); + } + + l = l->radial_next; + } while (l != firstl); + + if (i) + mul_v3_fl(a, 1.0f / (float)i); + + VECCOPY(vec, a); + + return NULL; +} static int createSlideVerts(TransInfo *t) { Mesh *me = t->obedit->data; - EditMesh *em = me->edit_mesh; - EditFace *efa; - EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL; - EditVert *ev, *nearest = NULL; - LinkNode *edgelist = NULL, *vertlist=NULL, *look; - GHash *vertgh; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + BMIter iter, iter2; + BMEdge *e, *e1, *ee, *le; + BMVert *v, *v2, *first; + BMLoop *l, *l1, *l2; TransDataSlideVert *tempsv; - float vertdist; // XXX, projectMat[4][4]; - int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0; - /* UV correction vars */ - GHash **uvarray= NULL; + BMBVHTree *btree = BMBVH_NewBVH(em); + SmallHash table; SlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); - int uvlay_idx; - TransDataSlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL; - RegionView3D *v3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */ + View3D *v3d = t->sa ? t->sa->spacedata.first : NULL; + RegionView3D *rv3d = t->ar ? t->ar->regiondata : NULL; /* background mode support */ + ARegion *ar = t->ar; float projectMat[4][4]; - float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f}; - float vec[3]; - float totvec=0.0; + float start[3] = {0.0f, 0.0f, 0.0f}, dir[3], end[3] = {0.0f, 0.0f, 0.0f}; + float vec[3], vec2[3], lastvec[3], size, dis=0.0, z; + int numsel, i, j; if (!v3d) { /*ok, let's try to survive this*/ unit_m4(projectMat); } else { - ED_view3d_ob_project_mat_get(v3d, t->obedit, projectMat); + ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat); } - numsel =0; - - // Get number of selected edges and clear some flags - for(eed=em->edges.first;eed;eed=eed->next) { - eed->f1 = 0; - eed->f2 = 0; - if(eed->f & SELECT) numsel++; - } - - for(ev=em->verts.first;ev;ev=ev->next) { - ev->f1 = 0; - } + BLI_smallhash_init(&sld->vhash); + BLI_smallhash_init(&sld->origfaces); + BLI_smallhash_init(&table); + + /*ensure valid selection*/ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT)) { + numsel = 0; + BM_ITER(e, &iter2, em->bm, BM_EDGES_OF_VERT, v) { + if (BM_TestHFlag(e, BM_SELECT)) { + /*BMESH_TODO: this is probably very evil, + set v->e to a selected edge*/ + v->e = e; - //Make sure each edge only has 2 faces - // make sure loop doesn't cross face - for(efa=em->faces.first;efa;efa=efa->next) { - int ct = 0; - if(efa->e1->f & SELECT) { - ct++; - efa->e1->f1++; - if(efa->e1->f1 > 2) { - //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - MEM_freeN(sld); - return 0; - } - } - if(efa->e2->f & SELECT) { - ct++; - efa->e2->f1++; - if(efa->e2->f1 > 2) { - //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - MEM_freeN(sld); - return 0; - } - } - if(efa->e3->f & SELECT) { - ct++; - efa->e3->f1++; - if(efa->e3->f1 > 2) { - //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - MEM_freeN(sld); - return 0; + numsel++; + } } - } - if(efa->e4 && efa->e4->f & SELECT) { - ct++; - efa->e4->f1++; - if(efa->e4->f1 > 2) { - //BKE_report(op->reports, RPT_ERROR, "3+ face edge"); - MEM_freeN(sld); - return 0; + + if (numsel > 2) { + return 0; //invalid edge selection } } - // Make sure loop is not 2 edges of same face - if(ct > 1) { - //BKE_report(op->reports, RPT_ERROR, "Loop crosses itself"); - MEM_freeN(sld); - return 0; + } + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) { + if (BM_Edge_FaceCount(e) > 2 || BM_Edge_FaceCount(e) == 0) + return 0; //can't handle more then 2 faces around an edge } } - // Get # of selected verts - for(ev=em->verts.first;ev;ev=ev->next) { - if(ev->f & SELECT) vertsel++; + j = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT)) { + BM_SetIndex(v, 1); + BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j)); + j += 1; + } else BM_SetIndex(v, 0); } - // Test for multiple segments - if(vertsel > numsel+1) { - //BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop"); - MEM_freeN(sld); + if (!j) return 0; - } - // Get the edgeloop in order - mark f1 with SELECT once added - for(eed=em->edges.first;eed;eed=eed->next) { - if((eed->f & SELECT) && !(eed->f1 & SELECT)) { - // If this is the first edge added, just put it in - if(!edgelist) { - BLI_linklist_prepend(&edgelist,eed); - numadded++; - first = eed; - last = eed; - eed->f1 = SELECT; - } else { - if(editedge_getSharedVert(eed, last)) { - BLI_linklist_append(&edgelist,eed); - eed->f1 = SELECT; - numadded++; - last = eed; - } else if(editedge_getSharedVert(eed, first)) { - BLI_linklist_prepend(&edgelist,eed); - eed->f1 = SELECT; - numadded++; - first = eed; - } - } - } - if(eed->next == NULL && numadded != numsel) { - eed=em->edges.first; - timesthrough++; - } + tempsv = MEM_callocN(sizeof(TransDataSlideVert)*j, "tempsv"); + + j = 0; + while (1) { + v = NULL; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_GetIndex(v)) + break; - // It looks like there was an unexpected case - Hopefully should not happen - if(timesthrough >= numsel*2) { - BLI_linklist_free(edgelist,NULL); - //BKE_report(op->reports, RPT_ERROR, "Could not order loop"); - MEM_freeN(sld); - return 0; } - } - // Put the verts in order in a linklist - look = edgelist; - while(look) { - eed = look->link; - if(!vertlist) { - if(look->next) { - temp = look->next->link; + if (!v) + break; - //This is the first entry takes care of extra vert - if(eed->v1 != temp->v1 && eed->v1 != temp->v2) { - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } else { - BLI_linklist_append(&vertlist,eed->v2); - eed->v2->f1 = 1; - } - } else { - //This is the case that we only have 1 edge - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } - } - // for all the entries - if(eed->v1->f1 != 1) { - BLI_linklist_append(&vertlist,eed->v1); - eed->v1->f1 = 1; - } else if(eed->v2->f1 != 1) { - BLI_linklist_append(&vertlist,eed->v2); - eed->v2->f1 = 1; - } - look = look->next; - } - - // populate the SlideVerts - - vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts gh"); - look = vertlist; - while(look) { - i=0; - j=0; - ev = look->link; - tempsv = (struct TransDataSlideVert*)MEM_mallocN(sizeof(struct TransDataSlideVert),"SlideVert"); - tempsv->up = NULL; - tempsv->down = NULL; - tempsv->origvert.co[0] = ev->co[0]; - tempsv->origvert.co[1] = ev->co[1]; - tempsv->origvert.co[2] = ev->co[2]; - tempsv->origvert.no[0] = ev->no[0]; - tempsv->origvert.no[1] = ev->no[1]; - tempsv->origvert.no[2] = ev->no[2]; - // i is total edges that vert is on - // j is total selected edges that vert is on - - for(eed=em->edges.first;eed;eed=eed->next) { - if(eed->v1 == ev || eed->v2 == ev) { - i++; - if(eed->f & SELECT) { - j++; - } - } - } - // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges - if(i == 4 && j == 2) { - for(eed=em->edges.first;eed;eed=eed->next) { - if(editedge_containsVert(eed, ev)) { - if(!(eed->f & SELECT)) { - if(!tempsv->up) { - tempsv->up = eed; - } else if (!(tempsv->down)) { - tempsv->down = eed; - } - } - } - } - } - // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected - if(i >= 3 && j == 1) { - for(eed=em->edges.first;eed;eed=eed->next) { - if(editedge_containsVert(eed, ev) && eed->f & SELECT) { - for(efa = em->faces.first;efa;efa=efa->next) { - if(editface_containsEdge(efa, eed)) { - if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e1; - } else if (!(tempsv->down)) { - tempsv->down = efa->e1; - } - } - if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e2; - } else if (!(tempsv->down)) { - tempsv->down = efa->e2; - } - } - if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e3; - } else if (!(tempsv->down)) { - tempsv->down = efa->e3; - } - } - if(efa->e4) { - if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) { - if(!tempsv->up) { - tempsv->up = efa->e4; - } else if (!(tempsv->down)) { - tempsv->down = efa->e4; - } - } - } + if (!v->e) + continue; + + first = v; - } - } - } + /*walk along the edge loop*/ + e = v->e; + + /*first, rewind*/ + numsel = 0; + do { + e = get_other_edge(bm, v, e); + if (!e) { + e = v->e; + break; } - } - if(i > 4 && j == 2) { - BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(vertlist,NULL); - BLI_linklist_free(edgelist,NULL); - return 0; - } - BLI_ghash_insert(vertgh,ev,tempsv); - look = look->next; - } + numsel += 1; - // make sure the UPs and DOWNs are 'faceloops' - // Also find the nearest slidevert to the cursor + if (!BM_GetIndex(BM_OtherEdgeVert(e, v))) + break; - look = vertlist; - nearest = NULL; - vertdist = -1; - while(look) { - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + v = BM_OtherEdgeVert(e, v); + } while (e != first->e); - if(!tempsv->up || !tempsv->down) { - //BKE_report(op->reports, RPT_ERROR, "Missing rails"); - BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(vertlist,NULL); - BLI_linklist_free(edgelist,NULL); - return 0; - } + BM_SetIndex(v, 0); - if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { - if(!(tempsv->up->f & SELECT)) { - tempsv->up->f |= SELECT; - tempsv->up->f2 |= 16; - } else { - tempsv->up->f2 |= ~16; - } - if(!(tempsv->down->f & SELECT)) { - tempsv->down->f |= SELECT; - tempsv->down->f2 |= 16; - } else { - tempsv->down->f2 |= ~16; - } - } + l1 = l2 = l = NULL; + l1 = e->l; + l2 = e->l->radial_next; - if(look->next != NULL) { - TransDataSlideVert *sv; - - ev = (EditVert*)look->next->link; - sv = BLI_ghash_lookup(vertgh, ev); + l = BM_OtherFaceLoop(l1->e, l1->f, v); + sub_v3_v3v3(vec, BM_OtherEdgeVert(l->e, v)->co, v->co); - if(sv) { - float co[3], co2[3], tvec[3]; + if (l2 != l1) { + l = BM_OtherFaceLoop(l2->e, l2->f, v); + sub_v3_v3v3(vec2, BM_OtherEdgeVert(l->e, v)->co, v->co); + } else { + l2 = NULL; + } - ev = (EditVert*)look->link; + /*iterate over the loop*/ + first = v; + j = 0; + do { + TransDataSlideVert *sv = tempsv + j; - if(!sharesFace(em, tempsv->up,sv->up)) { - EditEdge *swap; - swap = sv->up; - sv->up = sv->down; - sv->down = swap; - } - - if (v3d) { - ED_view3d_project_float(t->ar, tempsv->up->v1->co, co, projectMat); - ED_view3d_project_float(t->ar, tempsv->up->v2->co, co2, projectMat); - } + sv->v = v; + sv->origvert = *v; + VECCOPY(sv->upvec, vec); + if (l2) + VECCOPY(sv->downvec, vec2); - if (ev == tempsv->up->v1) { - sub_v3_v3v3(tvec, co, co2); - } else { - sub_v3_v3v3(tvec, co2, co); - } + l = BM_OtherFaceLoop(l1->e, l1->f, v); + sv->up = BM_OtherEdgeVert(l->e, v); - add_v3_v3(start, tvec); + if (l2) { + l = BM_OtherFaceLoop(l2->e, l2->f, v); + sv->down = BM_OtherEdgeVert(l->e, v); + } - if (v3d) { - ED_view3d_project_float(t->ar, tempsv->down->v1->co, co, projectMat); - ED_view3d_project_float(t->ar, tempsv->down->v2->co, co2, projectMat); - } + v2=v, v = BM_OtherEdgeVert(e, v); - if (ev == tempsv->down->v1) { - sub_v3_v3v3(tvec, co2, co); - } else { - sub_v3_v3v3(tvec, co, co2); - } + e1 = e; + e = get_other_edge(bm, v, e); + if (!e) { + //v2=v, v = BM_OtherEdgeVert(l1->e, v); - add_v3_v3(end, tvec); + sv = tempsv + j + 1; + sv->v = v; + sv->origvert = *v; + + l = BM_OtherFaceLoop(l1->e, l1->f, v); + sv->up = BM_OtherEdgeVert(l->e, v); + sub_v3_v3v3(sv->upvec, BM_OtherEdgeVert(l->e, v)->co, v->co); + + if (l2) { + l = BM_OtherFaceLoop(l2->e, l2->f, v); + sv->down = BM_OtherEdgeVert(l->e, v); + sub_v3_v3v3(sv->downvec, BM_OtherEdgeVert(l->e, v)->co, v->co); + } - totvec += 1.0f; - nearest = (EditVert*)look->link; + BM_SetIndex(v, 0); + BM_SetIndex(v2, 0); + + j += 2; + break; } - } + l1 = get_next_loop(bm, v, l1, e1, e, vec); + l2 = l2 ? get_next_loop(bm, v, l2, e1, e, vec2) : NULL; + j += 1; - look = look->next; + BM_SetIndex(v, 0); + BM_SetIndex(v2, 0); + } while (e != first->e && l1); } - add_v3_v3(start, end); - mul_v3_fl(start, 0.5f*(1.0f/totvec)); - VECCOPY(vec, start); - start[0] = t->mval[0]; - start[1] = t->mval[1]; - add_v3_v3v3(end, start, vec); + //EDBM_clear_flag_all(em, BM_SELECT); + sld->sv = tempsv; + sld->totsv = j; + + /*find mouse vector*/ + dis = z = -1.0f; + size = 50.0; + zero_v3(lastvec); zero_v3(dir); + ee = le = NULL; + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(e, BM_SELECT)) { + BMIter iter2; + BMEdge *e2; + float vec1[3], dis2, mval[2] = {t->mval[0], t->mval[1]}, d; + + /*search cross edges for visible edge to the mouse cursor, + then use the shared vertex to calculate screen vector*/ + dis2 = -1.0f; + for (i=0; i<2; i++) { + v = i?e->v1:e->v2; + BM_ITER(e2, &iter2, em->bm, BM_EDGES_OF_VERT, v) { + if (BM_TestHFlag(e2, BM_SELECT)) + continue; + + if (!BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) + continue; + + j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v)); + + if (tempsv[j].down) { + ED_view3d_project_float_v3(ar, tempsv[j].down->co, vec1, projectMat); + } else { + add_v3_v3v3(vec1, v->co, tempsv[j].downvec); + ED_view3d_project_float_v3(ar, vec1, vec1, projectMat); + } + + if (tempsv[j].up) { + ED_view3d_project_float_v3(ar, tempsv[j].up->co, vec2, projectMat); + } else { + add_v3_v3v3(vec1, v->co, tempsv[j].upvec); + ED_view3d_project_float_v3(ar, vec2, vec2, projectMat); + } - /* Ensure minimum screen distance, when looking top down on edge loops */ -#define EDGE_SLIDE_MIN 30 - if (len_squared_v2v2(start, end) < (EDGE_SLIDE_MIN * EDGE_SLIDE_MIN)) { - if(ABS(start[0]-end[0]) + ABS(start[1]-end[1]) < 4.0f) { - /* even more exceptional case, points are ontop of eachother */ - end[0]= start[0]; - end[1]= start[1] + EDGE_SLIDE_MIN; - } - else { - sub_v2_v2(end, start); - normalize_v2(end); - mul_v2_fl(end, EDGE_SLIDE_MIN); - add_v2_v2(end, start); + d = dist_to_line_segment_v2(mval, vec1, vec2); + if (dis2 == -1.0f || d < dis2) { + dis2 = d; + ee = e2; + size = len_v3v3(vec1, vec2); + sub_v3_v3v3(dir, vec1, vec2); + } + } + } } } -#undef EDGE_SLIDE_MIN + + em->bm->ob = t->obedit; + bmesh_begin_edit(em->bm, BMOP_UNTAN_MULTIRES); + /*create copies of faces for customdata projection*/ + tempsv = sld->sv; + for (i=0; i<sld->totsv; i++, tempsv++) { + BMIter fiter, liter; + BMFace *f; + BMLoop *l; + + BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) { + + if (!BLI_smallhash_haskey(&sld->origfaces, (uintptr_t)f)) { + BMFace *copyf = BM_Copy_Face(em->bm, f, 1, 1); + + BM_Select(em->bm, copyf, 0); + BM_SetHFlag(copyf, BM_HIDDEN); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, copyf) { + BM_Select(em->bm, l->v, 0); + BM_SetHFlag(l->v, BM_HIDDEN); + BM_Select(em->bm, l->e, 0); + BM_SetHFlag(l->e, BM_HIDDEN); + } - sld->start[0] = (int) start[0]; - sld->start[1] = (int) start[1]; - sld->end[0] = (int) end[0]; - sld->end[1] = (int) end[1]; - - if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) { - int maxnum = 0; + BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf); + } + } - uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array"); - sld->totuv = uvlay_tot; - suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(TransDataSlideUv), "SlideUVs"); /* uvLayers * verts */ - suv = NULL; + BLI_smallhash_insert(&sld->vhash, (uintptr_t)tempsv->v, tempsv); + } + + sld->em = em; + + /*zero out start*/ + zero_v3(start); + + /*dir holds a vector along edge loop*/ + copy_v3_v3(end, dir); + mul_v3_fl(end, 0.5); + + sld->start[0] = t->mval[0] + start[0]; + sld->start[1] = t->mval[1] + start[1]; - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { + sld->end[0] = t->mval[0] + end[0]; + sld->end[1] = t->mval[1] + end[1]; + + sld->perc = 0.0f; + + t->customData = sld; + + BLI_smallhash_release(&table); + BMBVH_FreeBVH(btree); + + return 1; +} - uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts2 gh"); +void projectSVData(TransInfo *t, int final) +{ + SlideData *sld = t->customData; + TransDataSlideVert *tempsv; + BMEditMesh *em = sld->em; + SmallHash visit; + int i; + + if (!em) + return; + + BLI_smallhash_init(&visit); + + for (i=0, tempsv=sld->sv; i<sld->totsv; i++, tempsv++) { + BMIter fiter; + BMFace *f; + + BM_ITER(f, &fiter, em->bm, BM_FACES_OF_VERT, tempsv->v) { + BMIter liter2; + BMFace *copyf, *copyf2; + BMLoop *l2; + int sel, do_vdata; + + if (BLI_smallhash_haskey(&visit, (uintptr_t)f)) + continue; + + BLI_smallhash_insert(&visit, (uintptr_t)f, NULL); + + /*the face attributes of the copied face will get + copied over, so its necessary to save the selection state*/ + sel = BM_TestHFlag(f, BM_SELECT); + + copyf2 = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)f); + + /*project onto copied projection face*/ + BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_FACE, f) { + copyf = copyf2; + do_vdata = l2->v==tempsv->v; + + if (BM_TestHFlag(l2->e, BM_SELECT) || BM_TestHFlag(l2->prev->e, BM_SELECT)) { + BMLoop *l3 = l2; + + do_vdata = 1; + + if (!BM_TestHFlag(l2->e, BM_SELECT)) + l3 = l3->prev; + + if (sld->perc < 0.0 && BM_Vert_In_Face(l3->radial_next->f, tempsv->down)) { + copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f); + } else if (sld->perc > 0.0 && BM_Vert_In_Face(l3->radial_next->f, tempsv->up)) { + copyf = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l3->radial_next->f); + } + } + + BM_loop_interp_from_face(em->bm, l2, copyf, do_vdata, 0); - for(ev=em->verts.first;ev;ev=ev->next) { - ev->tmp.l = 0; - } - look = vertlist; - while(look) { - float *uv_new; - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); - - ev = look->link; - suv = NULL; - for(efa = em->faces.first;efa;efa=efa->next) { - if (ev->tmp.l != -1) { /* test for self, in this case its invalid */ - int k=-1; /* face corner */ - - /* Is this vert in the faces corner? */ - if (efa->v1==ev) k=0; - else if (efa->v2==ev) k=1; - else if (efa->v3==ev) k=2; - else if (efa->v4 && efa->v4==ev) k=3; - - if (k != -1) { - MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx); - EditVert *ev_up, *ev_down; - - uv_new = tf->uv[k]; - - if (ev->tmp.l) { - if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001f || fabs(suv->origuv[1]-uv_new[1]) > 0.0001f) { - ev->tmp.l = -1; /* Tag as invalid */ - BLI_linklist_free(suv->fuv_list,NULL); - suv->fuv_list = NULL; - BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL); - suv = NULL; - break; - } - } else { - ev->tmp.l = 1; - suv = suv_last; - - suv->fuv_list = NULL; - suv->uv_up = suv->uv_down = NULL; - suv->origuv[0] = uv_new[0]; - suv->origuv[1] = uv_new[1]; - - BLI_linklist_prepend(&suv->fuv_list, uv_new); - BLI_ghash_insert(uvarray[uvlay_idx],ev,suv); - - suv_last++; /* advance to next slide UV */ - maxnum++; - } - - /* Now get the uvs along the up or down edge if we can */ - if (suv) { - if (!suv->uv_up) { - ev_up = editedge_getOtherVert(tempsv->up,ev); - if (efa->v1==ev_up) suv->uv_up = tf->uv[0]; - else if (efa->v2==ev_up) suv->uv_up = tf->uv[1]; - else if (efa->v3==ev_up) suv->uv_up = tf->uv[2]; - else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3]; - } - if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */ - ev_down = editedge_getOtherVert(tempsv->down,ev); - if (efa->v1==ev_down) suv->uv_down = tf->uv[0]; - else if (efa->v2==ev_down) suv->uv_down = tf->uv[1]; - else if (efa->v3==ev_down) suv->uv_down = tf->uv[2]; - else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3]; - } - - /* Copy the pointers to the face UV's */ - BLI_linklist_prepend(&suv->fuv_list, uv_new); - } - } + if (final) { + BM_loop_interp_multires(em->bm, l2, copyf); + if (copyf2 != copyf) { + BM_loop_interp_multires(em->bm, l2, copyf2); } } - look = look->next; } - } /* end uv layer loop */ - } /* end uvlay_tot */ - - sld->uvhash = uvarray; - sld->slideuv = slideuvs; - sld->vhash = vertgh; - sld->nearest = nearest; - sld->vertlist = vertlist; - sld->edgelist = edgelist; - sld->suv_last = suv_last; - sld->uvlay_tot = uvlay_tot; - - // we should have enough info now to slide - - t->customData = sld; - - return 1; + + /*make sure face-attributes are correct (e.g. MTexPoly)*/ + BM_Copy_Attributes(em->bm, em->bm, copyf2, f); + + /*restore selection, and undo hidden flag*/ + BM_ClearHFlag(f, BM_HIDDEN); + if (sel) + BM_Select(em->bm, f, sel); + } + } + + BLI_smallhash_release(&visit); } void freeSlideVerts(TransInfo *t) { - TransDataSlideUv *suv; SlideData *sld = t->customData; - Mesh *me = t->obedit->data; - int uvlay_idx; - + SmallHashIter hiter; + BMFace *copyf; + +#if 0 /*BMESH_TODO*/ if(me->drawflag & ME_DRAWEXTRA_EDGELEN) { TransDataSlideVert *tempsv; LinkNode *look = sld->vertlist; @@ -4805,31 +4758,38 @@ void freeSlideVerts(TransInfo *t) look = look->next; } } - - //BLI_ghash_free(edgesgh, freeGHash, NULL); - BLI_ghash_free(sld->vhash, NULL, (GHashValFreeFP)MEM_freeN); - BLI_linklist_free(sld->vertlist, NULL); - BLI_linklist_free(sld->edgelist, NULL); - - if (sld->uvlay_tot) { - for (uvlay_idx=0; uvlay_idx<sld->uvlay_tot; uvlay_idx++) { - BLI_ghash_free(sld->uvhash[uvlay_idx], NULL, NULL); - } - - suv = sld->suv_last-1; - while (suv >= sld->slideuv) { - if (suv->fuv_list) { - BLI_linklist_free(suv->fuv_list,NULL); - } - suv--; - } - - MEM_freeN(sld->slideuv); - MEM_freeN(sld->uvhash); +#endif + + if (!sld) + return; + + /*handle multires reprojection, done + on transform completion since it's + really slow -joeedh*/ + if (t->state != TRANS_CANCEL) { + projectSVData(t, 1); + } else { + sld->perc = 0.0; + projectSVData(t, 0); } + + copyf = BLI_smallhash_iternew(&sld->origfaces, &hiter, NULL); + for (; copyf; copyf=BLI_smallhash_iternext(&hiter, NULL)) { + BM_Kill_Face_Verts(sld->em->bm, copyf); + } + + sld->em->bm->ob = t->obedit; + bmesh_end_edit(sld->em->bm, BMOP_UNTAN_MULTIRES); + BLI_smallhash_release(&sld->vhash); + BLI_smallhash_release(&sld->origfaces); + + MEM_freeN(sld->sv); MEM_freeN(sld); + t->customData = NULL; + + recalcData(t); } void initEdgeSlide(TransInfo *t) @@ -4868,111 +4828,28 @@ void initEdgeSlide(TransInfo *t) int doEdgeSlide(TransInfo *t, float perc) { - Mesh *me= t->obedit->data; - EditMesh *em = me->edit_mesh; SlideData *sld = t->customData; - EditVert *ev, *nearest = sld->nearest; - EditVert *centerVert, *upVert, *downVert; - LinkNode *vertlist=sld->vertlist, *look; - GHash *vertgh = sld->vhash; - TransDataSlideVert *tempsv; - float len; - int prop=1, flip=0; - /* UV correction vars */ - GHash **uvarray= sld->uvhash; - int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE); - int uvlay_idx; - TransDataSlideUv *suv; - float uv_tmp[2]; - LinkNode *fuv_link; - - tempsv = BLI_ghash_lookup(vertgh,nearest); - - centerVert = editedge_getSharedVert(tempsv->up, tempsv->down); - upVert = editedge_getOtherVert(tempsv->up, centerVert); - downVert = editedge_getOtherVert(tempsv->down, centerVert); - - len = MIN2(perc, len_v3v3(upVert->co,downVert->co)); - len = MAX2(len, 0); - - //Adjust Edgeloop - if(prop) { - look = vertlist; - while(look) { - EditVert *tempev; - ev = look->link; - tempsv = BLI_ghash_lookup(vertgh,ev); - - tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev); - interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc)); - - if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } + TransDataSlideVert *svlist = sld->sv, *sv; + float vec[3]; + int i; - look = look->next; - } - } - else { - //Non prop code - look = vertlist; - while(look) { - float newlen, edgelen; - ev = look->link; - tempsv = BLI_ghash_lookup(vertgh,ev); - edgelen = len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co); - newlen = (edgelen != 0.0f)? (len / edgelen): 0.0f; - if(newlen > 1.0f) {newlen = 1.0;} - if(newlen < 0.0f) {newlen = 0.0;} - if(flip == 0) { - interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen)); - if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - /* dont do anything if no UVs */ - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - } else{ - interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen)); - - if (uvlay_tot) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) { - /* dont do anything if no UVs */ - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { - suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev ); - if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) { - interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen)); - fuv_link = suv->fuv_list; - while (fuv_link) { - VECCOPY2D(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - } - look = look->next; - } + sld->perc = perc; + sv = svlist; + for (i=0; i<sld->totsv; i++, sv++) { + if (perc > 0.0f) { + VECCOPY(vec, sv->upvec); + mul_v3_fl(vec, perc); + add_v3_v3v3(sv->v->co, sv->origvert.co, vec); + } else { + VECCOPY(vec, sv->downvec); + mul_v3_fl(vec, -perc); + add_v3_v3v3(sv->v->co, sv->origvert.co, vec); + } } - + + projectSVData(t, 0); + return 1; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index d8e750acb88..b5541feb9aa 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -41,6 +41,8 @@ #include "DNA_listBase.h" #include "BLI_editVert.h" +#include "BLI_smallhash.h" +#include "BKE_tessmesh.h" /* ************************** Types ***************************** */ @@ -66,6 +68,7 @@ struct wmEvent; struct wmTimer; struct ARegion; struct ReportList; +struct SmallHash; typedef struct NDofInput { int flag; @@ -200,25 +203,34 @@ struct LinkNode; struct EditEdge; struct EditVert; struct GHash; -typedef struct TransDataSlideUv { - float origuv[2]; - float *uv_up, *uv_down; - //float *fuv[4]; - struct LinkNode *fuv_list; -} TransDataSlideUv; typedef struct TransDataSlideVert { - struct EditEdge *up, *down; - struct EditVert origvert; + struct BMVert vup, vdown; + struct BMVert origvert; + + struct BMVert *up, *down; + struct BMVert *v; + + float upvec[3], downvec[3]; } TransDataSlideVert; typedef struct SlideData { + TransDataSlideVert *sv; + int totsv; + + struct SmallHash vhash; + struct SmallHash origfaces; + + /* TransDataSlideUv *slideuv, *suv_last; int totuv, uvlay_tot; struct GHash *vhash, **uvhash; struct EditVert *nearest; struct LinkNode *edgelist, *vertlist; + */ int start[2], end[2]; + struct BMEditMesh *em; + float perc; } SlideData; typedef struct TransData { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 16bfc75c979..1618de5290a 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -74,6 +74,7 @@ #include "BKE_sequencer.h" #include "BKE_pointcache.h" #include "BKE_bmesh.h" +#include "BKE_tessmesh.h" #include "BKE_scene.h" #include "BKE_report.h" @@ -97,13 +98,16 @@ #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" +#include "BLI_array.h" #include "BLI_utildefines.h" +#include "BLI_smallhash.h" #include "RNA_access.h" extern ListBase editelems; #include "transform.h" +#include "bmesh.h" #include "BLO_sys_types.h" // for intptr_t support @@ -289,18 +293,20 @@ static void createTransTexspace(TransInfo *t) /* ********************* edge (for crease) ***** */ static void createTransEdge(TransInfo *t) { - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; + BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; TransData *td = NULL; - EditEdge *eed; + BMEdge *eed; + BMIter iter; float mtx[3][3], smtx[3][3]; int count=0, countsel=0; int propmode = t->flag & T_PROP_EDIT; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - if (eed->f & SELECT) countsel++; - if (propmode) count++; - } + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_TestHFlag(eed, BM_HIDDEN)) + continue; + + if (BM_TestHFlag(eed, BM_SELECT)) countsel++; + if (propmode) count++; } if (countsel == 0) @@ -318,14 +324,17 @@ static void createTransEdge(TransInfo *t) { copy_m3_m4(mtx, t->obedit->obmat); invert_m3_m3(smtx, mtx); - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT || propmode)) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(!BM_TestHFlag(eed, BM_HIDDEN) && (BM_TestHFlag(eed, BM_SELECT) || propmode)) { + float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT); + float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE); + /* need to set center for center calculations */ add_v3_v3v3(td->center, eed->v1->co, eed->v2->co); mul_v3_fl(td->center, 0.5f); td->loc= NULL; - if (eed->f & SELECT) + if (BM_TestHFlag(eed, BM_SELECT)) td->flag= TD_SELECTED; else td->flag= 0; @@ -336,12 +345,12 @@ static void createTransEdge(TransInfo *t) { td->ext = NULL; if (t->mode == TFM_BWEIGHT) { - td->val = &(eed->bweight); - td->ival = eed->bweight; + td->val = bweight; + td->ival = bweight ? *bweight : 1.0f; } else { - td->val = &(eed->crease); - td->ival = eed->crease; + td->val = crease; + td->ival = crease ? *crease : 0.0f; } td++; @@ -1809,113 +1818,144 @@ void flushTransParticles(TransInfo *t) /* proportional distance based on connectivity */ #define THRESHOLD 0.0001f -static int connectivity_edge(float mtx[][3], EditVert *v1, EditVert *v2) +/*I did this wrong, it should be a breadth-first search + but instead it's a depth-first search, fudged + to report shortest distances. I have no idea how fast + or slow this is.*/ +static void editmesh_set_connectivity_distance(BMEditMesh *em, float mtx[][3], float *dists) { - float edge_vec[3]; - float edge_len; - int done = 0; - - /* note: hidden verts are not being checked for, this assumes - * flushing of hidden faces & edges is working right */ - - if (v1->f2 + v2->f2 == 4) - return 0; + BMVert **queue = NULL; + float *dqueue = NULL; + int *tots = MEM_callocN(sizeof(int)*em->bm->totvert, "tots editmesh_set_connectivity_distance"); + BLI_array_declare(queue); + BLI_array_declare(dqueue); + SmallHash svisit, *visit=&svisit; + BMVert *v; + BMIter viter; + int i, start; - sub_v3_v3v3(edge_vec, v1->co, v2->co); - mul_m3_v3(mtx, edge_vec); - - edge_len = len_v3(edge_vec); - - if (v1->f2) { - if (v2->f2) { - if (v2->tmp.fp + edge_len + THRESHOLD < v1->tmp.fp) { - v1->tmp.fp = v2->tmp.fp + edge_len; - done = 1; - } else if (v1->tmp.fp + edge_len + THRESHOLD < v2->tmp.fp) { - v2->tmp.fp = v1->tmp.fp + edge_len; - done = 1; - } - } - else { - v2->f2 = 1; - v2->tmp.fp = v1->tmp.fp + edge_len; - done = 1; - } - } - else if (v2->f2) { - v1->f2 = 1; - v1->tmp.fp = v2->tmp.fp + edge_len; - done = 1; + i = 0; + BM_ITER(v, &viter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, i); + dists[i] = FLT_MAX; + i++; } + + BLI_smallhash_init(visit); - return done; -} - -static void editmesh_set_connectivity_distance(EditMesh *em, float mtx[][3]) -{ - EditVert *eve; - EditEdge *eed; - EditFace *efa; - int done= 1; - - /* f2 flag is used for 'selection' */ - /* tmp.l is offset on scratch array */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - eve->tmp.fp = 0; - - if(eve->f & SELECT) { - eve->f2= 2; - } - else { - eve->f2 = 0; - } - } + BM_ITER(v, &viter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(v, BM_SELECT)==0 || BM_TestHFlag(v, BM_HIDDEN)) + continue; + + + BLI_smallhash_insert(visit, (uintptr_t)v, NULL); + BLI_array_append(queue, v); + BLI_array_append(dqueue, 0.0f); + dists[BM_GetIndex(v)] = 0.0f; } + + start = 0; + while (start < BLI_array_count(queue)) { + BMIter eiter; + BMEdge *e; + BMVert *v3, *v2; + float d, vec[3]; + + v2 = queue[start]; + d = dqueue[start]; + + BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v2) { + float d2; + v3 = BM_OtherEdgeVert(e, v2); + + if (BM_TestHFlag(v3, BM_SELECT) || BM_TestHFlag(v3, BM_HIDDEN)) + continue; + + sub_v3_v3v3(vec, v2->co, v3->co); + mul_m3_v3(mtx, vec); + + d2 = d + len_v3(vec); + + if (dists[BM_GetIndex(v3)] != FLT_MAX) + dists[BM_GetIndex(v3)] = MIN2(d2, dists[BM_GetIndex(v3)]); + else + dists[BM_GetIndex(v3)] = d2; + + tots[BM_GetIndex(v3)] = 1; - - /* Floodfill routine */ - /* - At worst this is n*n of complexity where n is number of edges - Best case would be n if the list is ordered perfectly. - Estimate is n log n in average (so not too bad) - */ - while(done) { - done= 0; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - done |= connectivity_edge(mtx, eed->v1, eed->v2); - } + if (BLI_smallhash_haskey(visit, (uintptr_t)v3)) + continue; + + BLI_smallhash_insert(visit, (uintptr_t)v3, NULL); + + BLI_array_append(queue, v3); + BLI_array_append(dqueue, d2); } + + start++; + } - /* do internal edges for quads */ - for(efa= em->faces.first; efa; efa= efa->next) { - if (efa->v4 && efa->h==0) { - done |= connectivity_edge(mtx, efa->v1, efa->v3); - done |= connectivity_edge(mtx, efa->v2, efa->v4); - } - } + BLI_smallhash_release(visit); + + for (i=0; i<em->bm->totvert; i++) { + if (tots[i]) + dists[i] /= (float)tots[i]; } + + BLI_array_free(queue); + BLI_array_free(dqueue); + MEM_freeN(tots); } /* loop-in-a-loop I know, but we need it! (ton) */ -static void get_face_center(float *cent, EditMesh *em, EditVert *eve) + static void get_face_center(float *centout, BMesh *bm, BMVert *eve) + { - EditFace *efa; + BMFace *efa; + BMLoop *l; + BMIter iter; + float cent[3] = {0.0, 0.0, 0.0}; - for(efa= em->faces.first; efa; efa= efa->next) - if(efa->f & SELECT) - if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve) - break; - if(efa) { - VECCOPY(cent, efa->cent); + efa = BMIter_New(&iter, bm, BM_FACES_OF_VERT, eve); + if (efa) { + l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa); + for ( ; l; l=BMIter_Step(&iter)) { + VECADD(cent, cent, l->v->co); + } + + mul_v3_fl(cent, 1.0f / (float)efa->len); } + + if (cent[0] == 0.0f && cent[1] == 0.0f && cent[2] == 0.0f) cent[2] = 1.0f; + copy_v3_v3(centout, cent); } +#define VertsToTransData(t, td, em, eve, bweight) \ + td->flag = 0;\ + td->loc = eve->co;\ + VECCOPY(td->center, td->loc);\ + if(t->around==V3D_LOCAL && (em->selectmode & SCE_SELECT_FACE))\ + get_face_center(td->center, em, eve);\ + VECCOPY(td->iloc, td->loc);\ + VECCOPY(td->axismtx[2], eve->no);\ + td->axismtx[0][0] =\ + td->axismtx[0][1] =\ + td->axismtx[0][2] =\ + td->axismtx[1][0] =\ + td->axismtx[1][1] =\ + td->axismtx[1][2] = 0.0f;\ + td->ext = NULL;\ + td->val = NULL;\ + td->extra = NULL;\ + if (t->mode == TFM_BWEIGHT) {\ + td->val = bweight;\ + td->ival = bweight ? *(bweight) : 1.0f;\ + } + +#if 0 //way to overwrite what data is edited with transform //static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key) -static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert *eve) +inline void VertsToTransData(TransInfo *t, TransData *td, BMesh *em, BMVert *eve) { td->flag = 0; //if(key) @@ -1945,50 +1985,99 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert td->ival = eve->bweight; } } +#endif -#if 0 -static void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) { - BME_Vert *v; - BME_TransData *vtd; - TransData *tob; - int i; +/* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */ - tob = t->data = MEM_callocN(td->len*sizeof(TransData), "TransObData(Bevel tool)"); +static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) +{ + float *vec = userData; - for (i=0,v=bm->verts.first;v;v=v->next) { - if ( (vtd = BME_get_transdata(td,v)) ) { - tob->loc = vtd->loc; - tob->val = &vtd->factor; - VECCOPY(tob->iloc,vtd->co); - VECCOPY(tob->center,vtd->org); - VECCOPY(tob->axismtx[0],vtd->vec); - tob->axismtx[1][0] = vtd->max ? *vtd->max : 0; - tob++; - i++; - } + vec+= 3*index; + VECCOPY(vec, co); +} + +static int modifiers_disable_subsurf_temporary(Object *ob) +{ + ModifierData *md; + int disabled = 0; + + for(md=ob->modifiers.first; md; md=md->next) + if(md->type==eModifierType_Subsurf) + if(md->mode & eModifierMode_OnCage) { + md->mode ^= eModifierMode_DisableTemporary; + disabled= 1; + } + + return disabled; +} + +/* disable subsurf temporal, get mapped cos, and enable it */ +static float *get_crazy_mapped_editverts(TransInfo *t) +{ + Mesh *me= t->obedit->data; + DerivedMesh *dm; + float *vertexcos; + + /* disable subsurf temporal, get mapped cos, and enable it */ + if(modifiers_disable_subsurf_temporary(t->obedit)) { + /* need to make new derivemesh */ + makeDerivedMesh(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH, 0); } - /* since td is a memarena, it can hold more transdata than actual elements - * (i.e. we can't depend on td->len to determine the number of actual elements) */ - t->total = i; + + /* now get the cage */ + dm= editbmesh_get_derived_cage(t->scene, t->obedit, me->edit_btmesh, CD_MASK_BAREMESH); + + vertexcos= MEM_mallocN(3*sizeof(float)*me->edit_btmesh->bm->totvert, "vertexcos map"); + dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos); + + dm->release(dm); + + /* set back the flag, no new cage needs to be built, transform does it */ + modifiers_disable_subsurf_temporary(t->obedit); + + return vertexcos; } -#endif + +#define TAN_MAKE_VEC(a, b, c) a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2]) +static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3) +{ + float vecu[3], vecv[3]; + float q1[4], q2[4]; + + TAN_MAKE_VEC(vecu, v1, v2); + TAN_MAKE_VEC(vecv, v1, v3); + tri_to_quat( q1,v1, vecu, vecv); + + TAN_MAKE_VEC(vecu, def1, def2); + TAN_MAKE_VEC(vecv, def1, def3); + tri_to_quat( q2,def1, vecu, vecv); + + sub_qt_qtqt(quat, q2, q1); +} +#undef TAN_MAKE_VEC static void createTransEditVerts(bContext *C, TransInfo *t) { ToolSettings *ts = CTX_data_tool_settings(C); TransData *tob = NULL; - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; - EditVert *eve; - EditVert *eve_act = NULL; + BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve; + BMIter iter; + BMVert *eve_act = NULL; float *mappedcos = NULL, *quats= NULL; float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; - int count=0, countsel=0, a, totleft; - int propmode = t->flag & T_PROP_EDIT; + float *dists=NULL; + int count=0, countsel=0, a, totleft, *selstate = NULL; + BLI_array_declare(selstate); + int propmode = t->flag & (T_PROP_EDIT|T_PROP_CONNECTED); int mirror = 0; short selectmode = ts->selectmode; if (t->flag & T_MIRROR) { + EDBM_CacheMirrorVerts(em); mirror = 1; } @@ -1999,36 +2088,56 @@ static void createTransEditVerts(bContext *C, TransInfo *t) // transform now requires awareness for select mode, so we tag the f1 flags in verts if(selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0 && (eve->f & SELECT)) - eve->f1= SELECT; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)) + BM_SetIndex(eve, SELECT); else - eve->f1= 0; + BM_SetIndex(eve, 0); } } else if(selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT)) - eed->v1->f1= eed->v2->f1= SELECT; + BMEdge *eed; + + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) BM_SetIndex(eve, 0); + + eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); + for( ; eed; eed=BMIter_Step(&iter)) { + if(!BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SELECT)) + BM_SetIndex(eed->v1, SELECT), BM_SetIndex(eed->v2, SELECT); } } else { - EditFace *efa; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && (efa->f & SELECT)) { - efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; - if(efa->v4) efa->v4->f1= SELECT; + BMFace *efa; + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BMIter_Step(&iter)) BM_SetIndex(eve, 0); + + efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL); + for( ; efa; efa=BMIter_Step(&iter)) { + if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) { + BMIter liter; + BMLoop *l; + + l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BMIter_Step(&liter)) { + BM_SetIndex(l->v, SELECT); + } } } } - /* now we can count */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - if(eve->f1) countsel++; + /* now we can count. we store selection state in selstate, since + get_crazy_mapped_editverts messes up the index state of the + verts*/ + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BMIter_Step(&iter), a++) { + BLI_array_growone(selstate); + + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + if(BM_GetIndex(eve)) { + selstate[a] = 1; + countsel++; + } if(propmode) count++; } } @@ -2037,15 +2146,21 @@ static void createTransEditVerts(bContext *C, TransInfo *t) if (countsel==0) return; /* check active */ - if (em->selected.last) { - EditSelection *ese = em->selected.last; + if (em->bm->selected.last) { + BMEditSelection *ese = em->bm->selected.last; if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + eve_act = (BMVert *)ese->data; } } - if(propmode) t->total = count; + if(propmode) { + t->total = count; + + /* allocating scratch arrays */ + if (propmode & T_PROP_CONNECTED) + dists = MEM_mallocN(em->bm->totvert * sizeof(float), "scratch nears"); + } else t->total = countsel; tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)"); @@ -2053,14 +2168,15 @@ static void createTransEditVerts(bContext *C, TransInfo *t) copy_m3_m4(mtx, t->obedit->obmat); invert_m3_m3(smtx, mtx); - if(propmode) editmesh_set_connectivity_distance(em, mtx); + if(propmode & T_PROP_CONNECTED) + editmesh_set_connectivity_distance(em, mtx, dists); /* detect CrazySpace [tm] */ if(modifiers_getCageIndex(t->scene, t->obedit, NULL, 1)>=0) { if(modifiers_isCorrectableDeformed(t->obedit)) { /* check if we can use deform matrices for modifier from the start up to stack, they are more accurate than quats */ - totleft= editmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos); + totleft= editbmesh_get_first_deform_matrices(t->scene, t->obedit, em, &defmats, &defcos); /* if we still have more modifiers, also do crazyspace correction with quats, relative to the coordinates after @@ -2080,8 +2196,9 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* find out which half we do */ if(mirror) { - for (eve=em->verts.first; eve; eve=eve->next) { - if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) { + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BMIter_Step(&iter), a++) { + if(!BM_TestHFlag(eve, BM_HIDDEN) && selstate[a] && eve->co[0]!=0.0f) { if(eve->co[0]<0.0f) { t->mirror = -1; @@ -2092,34 +2209,36 @@ static void createTransEditVerts(bContext *C, TransInfo *t) } } - for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) { - if(eve->h==0) { - if(propmode || eve->f1) { - VertsToTransData(t, tob, em, eve); + eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BMIter_Step(&iter), a++) { + if(!BM_TestHFlag(eve, BM_HIDDEN)) { + if(propmode || selstate[a]) { + float *bweight = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_BWEIGHT); + + VertsToTransData(t, tob, bm, eve, bweight); /* selected */ - if(eve->f1) tob->flag |= TD_SELECTED; + if(selstate[a]) tob->flag |= TD_SELECTED; /* active */ if(eve == eve_act) tob->flag |= TD_ACTIVE; if(propmode) { - if (eve->f2) { - tob->dist= eve->tmp.fp; - } - else { + if (propmode & T_PROP_CONNECTED) { + tob->dist = dists[a]; + } else { tob->flag |= TD_NOTCONNECTED; tob->dist = MAXFLOAT; } } /* CrazySpace */ - if(defmats || (quats && eve->tmp.p)) { - float mat[3][3], imat[3][3], qmat[3][3]; + if(defmats || (quats && BM_GetIndex(eve) != -1)) { + float mat[3][3], qmat[3][3], imat[3][3]; /* use both or either quat and defmat correction */ - if(quats && eve->tmp.f) { - quat_to_mat3( qmat,eve->tmp.p); + if(quats && BM_GetIndex(eve) != -1) { + quat_to_mat3(qmat, quats + 4*BM_GetIndex(eve)); if(defmats) mul_serie_m3(mat, mtx, qmat, defmats[a], @@ -2141,9 +2260,11 @@ static void createTransEditVerts(bContext *C, TransInfo *t) } /* Mirror? */ + + //BMESH_TODO if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { - EditVert *vmir= editmesh_get_x_mirror_vert(t->obedit, em, eve, tob->iloc, a); /* initializes octree on first call */ - if(vmir != eve) { + BMVert *vmir= EDBM_GetMirrorVert(em, eve); //t->obedit, em, eve, tob->iloc, a); + if(vmir && vmir != eve) { tob->extra = vmir; } } @@ -2169,6 +2290,16 @@ static void createTransEditVerts(bContext *C, TransInfo *t) MEM_freeN(quats); if(defmats) MEM_freeN(defmats); + if (dists) + MEM_freeN(dists); + + BLI_array_free(selstate); + + if (t->flag & T_MIRROR) + { + EDBM_EndMirrorCache(em); + mirror = 1; + } } /* *** NODE EDITOR *** */ @@ -2324,30 +2455,33 @@ static void createTransUVs(bContext *C, TransInfo *t) Scene *scene = t->scene; TransData *td = NULL; TransData2D *td2d = NULL; - MTFace *tf; + MTexPoly *tf; + MLoopUV *luv; + BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; int count=0, countsel=0; int propmode = t->flag & T_PROP_EDIT; - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; - EditFace *efa; - if(!ED_space_image_show_uvedit(sima, t->obedit)) return; /* count */ - for (efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(uvedit_face_visible(scene, ima, efa, tf)) { - efa->tmp.p = tf; + if(!uvedit_face_visible(scene, ima, efa, tf)) { + BM_SetIndex(efa, 0); + continue; + } + + BM_SetIndex(efa, 1); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) + countsel++; - if (uvedit_uv_selected(scene, efa, tf, 0)) countsel++; - if (uvedit_uv_selected(scene, efa, tf, 1)) countsel++; - if (uvedit_uv_selected(scene, efa, tf, 2)) countsel++; - if (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) countsel++; if(propmode) - count += (efa->v4)? 4: 3; - } else { - efa->tmp.p = NULL; + count++; } } @@ -2366,20 +2500,17 @@ static void createTransUVs(bContext *C, TransInfo *t) td= t->data; td2d= t->data2d; - for (efa= em->faces.first; efa; efa= efa->next) { - if ((tf=(MTFace *)efa->tmp.p)) { - if (propmode) { - UVsToTransData(sima, td++, td2d++, tf->uv[0], uvedit_uv_selected(scene, efa, tf, 0)); - UVsToTransData(sima, td++, td2d++, tf->uv[1], uvedit_uv_selected(scene, efa, tf, 1)); - UVsToTransData(sima, td++, td2d++, tf->uv[2], uvedit_uv_selected(scene, efa, tf, 2)); - if(efa->v4) - UVsToTransData(sima, td++, td2d++, tf->uv[3], uvedit_uv_selected(scene, efa, tf, 3)); - } else { - if(uvedit_uv_selected(scene, efa, tf, 0)) UVsToTransData(sima, td++, td2d++, tf->uv[0], 1); - if(uvedit_uv_selected(scene, efa, tf, 1)) UVsToTransData(sima, td++, td2d++, tf->uv[1], 1); - if(uvedit_uv_selected(scene, efa, tf, 2)) UVsToTransData(sima, td++, td2d++, tf->uv[2], 1); - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) UVsToTransData(sima, td++, td2d++, tf->uv[3], 1); - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (!propmode && !uvedit_uv_selected(em, scene, l)) + continue; + + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + UVsToTransData(sima, td++, td2d++, luv->uv, uvedit_uv_selected(em, scene, l)); } } @@ -2401,6 +2532,8 @@ void flushTransUVs(TransInfo *t) /* flush to 2d vector from internally used 3d vector */ for(a=0, td= t->data2d; a<t->total; a++, td++) { + if (!td->loc2d) continue; + td->loc2d[0]= td->loc[0]*invx; td->loc2d[1]= td->loc[1]*invy; @@ -4728,7 +4861,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) if (t->spacetype==SPACE_VIEW3D) { if (t->obedit) { if (cancelled==0) { - EM_automerge(t->scene, t->obedit, 1); + EDBM_automerge(t->scene, t->obedit, 1); } } } @@ -4958,9 +5091,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) else if (t->obedit) { if (t->obedit->type == OB_MESH) { - EditMesh *em = ((Mesh *)t->obedit->data)->edit_mesh; + // BMEditMesh *em = ((Mesh *)t->obedit->data)->edit_btmesh; /* table needs to be created for each edit command, since vertices can move etc */ - mesh_octree_table(t->obedit, em, NULL, 'e'); + // BMESH_TODO mesh_octree_table(t->obedit, em, NULL, 'e'); } } else if ((t->flag & T_POSE) && (t->poseobj)) { diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 20a26d8c58d..ef96e92222a 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -72,6 +72,7 @@ #include "BKE_mesh.h" #include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "ED_anim_api.h" #include "ED_armature.h" @@ -232,10 +233,10 @@ static void clipMirrorModifier(TransInfo *t, Object *ob) } /* assumes obedit set to mesh object */ -static void editmesh_apply_to_mirror(TransInfo *t) +static void editbmesh_apply_to_mirror(TransInfo *t) { TransData *td = t->data; - EditVert *eve; + BMVert *eve; int i; for(i = 0 ; i < t->total; i++, td++) { @@ -672,7 +673,7 @@ void recalcData(TransInfo *t) if(la->editlatt->latt->flag & LT_OUTSIDE) outside_lattice(la->editlatt->latt); } else if (t->obedit->type == OB_MESH) { - EditMesh *em = ((Mesh*)t->obedit->data)->edit_mesh; + BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh; /* mirror modifier clipping? */ if(t->state != TRANS_CANCEL) { /* apply clipping after so we never project past the clip plane [#25423] */ @@ -680,11 +681,12 @@ void recalcData(TransInfo *t) clipMirrorModifier(t, t->obedit); } if((t->options & CTX_NO_MIRROR) == 0 && (t->flag & T_MIRROR)) - editmesh_apply_to_mirror(t); + editbmesh_apply_to_mirror(t); DAG_id_tag_update(t->obedit->data, 0); /* sets recalc flags */ - recalc_editnormals(em); + EDBM_RecalcNormals(em); + BMEdit_RecalcTesselation(em); } else if(t->obedit->type==OB_ARMATURE) { /* no recalc flag, does pose */ bArmature *arm= t->obedit->data; @@ -1444,13 +1446,13 @@ void calculateCenter(TransInfo *t) /* EDIT MODE ACTIVE EDITMODE ELEMENT */ if (t->obedit && t->obedit->type == OB_MESH) { - EditSelection ese; - EditMesh *em = BKE_mesh_get_editmesh(t->obedit->data); + BMEditSelection ese; + BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh; - if (EM_get_actSelection(em, &ese)) { - EM_editselection_center(t->center, &ese); - calculateCenter2D(t); - break; + if (EDBM_get_actSelection(em, &ese)) { + EDBM_editselection_center(em, t->center, &ese); + calculateCenter2D(t); + break; } } /* END EDIT MODE ACTIVE ELEMENT */ diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index d62227a122d..218e90af717 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -61,6 +61,7 @@ #include "BKE_mesh.h" #include "BKE_particle.h" #include "BKE_pointcache.h" +#include "BKE_tessmesh.h" #include "BLI_math.h" #include "BLI_editVert.h" @@ -299,17 +300,29 @@ int calc_manipulator_stats(const bContext *C) if((ob->lay & v3d->lay)==0) return 0; if(obedit->type==OB_MESH) { - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); - EditVert *eve; - EditSelection ese; + BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMVert *eve; + BMEditSelection ese; + BMIter iter; float vec[3]= {0,0,0}; /* USE LAST SELECTE WITH ACTIVE */ - if (v3d->around==V3D_ACTIVE && EM_get_actSelection(em, &ese)) { - EM_editselection_center(vec, &ese); + if (v3d->around==V3D_ACTIVE && EDBM_get_actSelection(em, &ese)) { + EDBM_editselection_center(em, vec, &ese); calc_tw_center(scene, vec); totsel= 1; } else { +#if 1 /* OLD CODE */ + /* do vertices for center, and if still no normal found, use vertex normals */ + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_TestHFlag(eve, BM_SELECT)) { + totsel++; + calc_tw_center(scene, eve->co); + } + } + +#else // BMESH_TODO /* do vertices/edges/faces for center depending on selection mode. note we can't use just vertex selection flag because it is not flush down on changes */ @@ -369,6 +382,7 @@ int calc_manipulator_stats(const bContext *C) } } } +#endif } } /* end editmesh */ else if (obedit->type==OB_ARMATURE){ diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 2d539055db3..495ce8663cb 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -42,6 +42,7 @@ #include "BKE_armature.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BKE_report.h" #include "BLI_math.h" @@ -570,56 +571,56 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], if(ob->type==OB_MESH) { Mesh *me= ob->data; - EditMesh *em = me->edit_mesh; - EditVert *eve; - EditSelection ese; + BMEditMesh *em = me->edit_btmesh; + BMVert *eve; + BMEditSelection ese; float vec[3]= {0,0,0}; /* USE LAST SELECTED WITH ACTIVE */ - if (activeOnly && EM_get_actSelection(em, &ese)) + if (activeOnly && EDBM_get_actSelection(em, &ese)) { - EM_editselection_normal(normal, &ese); - EM_editselection_plane(plane, &ese); + EDBM_editselection_normal(normal, &ese); + EDBM_editselection_plane(em, plane, &ese); switch (ese.type) { - case EDITVERT: + case BM_VERT: result = ORIENTATION_VERT; break; - case EDITEDGE: + case BM_EDGE: result = ORIENTATION_EDGE; break; - case EDITFACE: + case BM_FACE: result = ORIENTATION_FACE; break; } } else { - if (em->totfacesel >= 1) + if (em->bm->totfacesel >= 1) { - EditFace *efa; - - for(efa= em->faces.first; efa; efa= efa->next) - { - if(efa->f & SELECT) - { - VECADD(normal, normal, efa->n); - sub_v3_v3v3(vec, efa->v2->co, efa->v1->co); + BMFace *efa; + BMIter iter; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_TestHFlag(efa, BM_SELECT)) { + VECADD(normal, normal, efa->no); + sub_v3_v3v3(vec, ((BMLoopList*)efa->loops.first)->first->v->co, + (((BMLoopList*)efa->loops.first)->first->next)->v->co); VECADD(plane, plane, vec); } } result = ORIENTATION_FACE; } - else if (em->totvertsel == 3) + else if (em->bm->totvertsel == 3) { - EditVert *v1 = NULL, *v2 = NULL, *v3 = NULL; + BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL; + BMIter iter; float cotangent[3]; - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -638,12 +639,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } /* if there's an edge available, use that for the tangent */ - if (em->totedgesel >= 1) + if (em->bm->totedgesel >= 1) { - EditEdge *eed = NULL; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { + BMEdge *eed = NULL; + BMIter iter; + + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); break; } @@ -652,12 +654,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], result = ORIENTATION_FACE; } - else if (em->totedgesel == 1) + else if (em->bm->totedgesel == 1) { - EditEdge *eed; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { + BMEdge *eed = NULL; + BMIter iter; + + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SELECT)) { /* use average vert normals as plane and edge vector as normal */ VECCOPY(plane, eed->v1->no); VECADD(plane, plane, eed->v2->no); @@ -667,13 +670,13 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } result = ORIENTATION_EDGE; } - else if (em->totvertsel == 2) + else if (em->bm->totvertsel == 2) { - EditVert *v1 = NULL, *v2 = NULL; - - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BMVert *v1 = NULL, *v2 = NULL; + BMIter iter; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -689,24 +692,25 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], } result = ORIENTATION_EDGE; } - else if (em->totvertsel == 1) + else if (em->bm->totvertsel == 1) { - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BMIter iter; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { VECCOPY(normal, eve->no); break; } } result = ORIENTATION_VERT; } - else if (em->totvertsel > 3) + else if (em->bm->totvertsel > 3) { - normal[0] = normal[1] = normal[2] = 0; - - for (eve = em->verts.first; eve; eve = eve->next) - { - if ( eve->f & SELECT ) { + BMIter iter; + normal[0] = normal[1] = normal[2] = 0.0f; + + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_TestHFlag(eve, BM_SELECT)) { add_v3_v3(normal, eve->no); } } @@ -896,6 +900,14 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3], VECCOPY(normal, ob->obmat[2]); VECCOPY(plane, ob->obmat[1]); } + else { + normal[0] = 0.0f; + normal[1] = 0.0f; + normal[2] = 1.0f; + plane[0] = 1.0f; + plane[1] = 0.0f; + plane[2] = 0.0f; + } result = ORIENTATION_NORMAL; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index d9d9b0f9102..46aaed5897a 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -70,6 +70,8 @@ #include "BKE_object.h" #include "BKE_anim.h" /* for duplis */ #include "BKE_context.h" +#include "BKE_tessmesh.h" +#include "BKE_mesh.h" #include "ED_armature.h" #include "ED_image.h" @@ -1280,11 +1282,14 @@ static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm return retval; } -static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, EditMesh *em, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth) +static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, + DerivedMesh *dm, BMEditMesh *em, float obmat[][4], + float ray_start[3], float ray_normal[3], float mval[2], + float *loc, float *no, int *dist, float *depth) { int retval = 0; int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); if (totvert > 0) { float imat[4][4]; @@ -1352,19 +1357,19 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh #else MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); + MFace *faces = dm->getTessFaceArray(dm); int *index_array = NULL; int index = 0; int i; if (em != NULL) { - index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 0, 0, 1); + index_array = dm->getTessFaceDataArray(dm, CD_ORIGINDEX); + EDBM_init_index_arrays(em, 0, 0, 1); } for( i = 0; i < totface; i++) { - EditFace *efa = NULL; + BMFace *efa = NULL; MFace *f = faces + i; test = 1; /* reset for every face */ @@ -1386,11 +1391,22 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh } else { - efa = EM_get_face_for_index(index); + efa = EDBM_get_face_for_index(em, index); - if (efa && (efa->h || (efa->v1->f & SELECT) || (efa->v2->f & SELECT) || (efa->v3->f & SELECT) || (efa->v4 && efa->v4->f & SELECT))) + if (efa && BM_TestHFlag(efa, BM_HIDDEN)) { test = 0; + } else if (efa) { + BMIter iter; + BMLoop *l; + + l = BMIter_New(&iter, em->bm, BM_LOOPS_OF_FACE, efa); + for ( ; l; l=BMIter_Step(&iter)) { + if (BM_TestHFlag(l->v, BM_SELECT)) { + test = 0; + break; + } + } } } } @@ -1418,7 +1434,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } #endif break; @@ -1433,11 +1449,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh if (em != NULL) { index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 1, 0, 0); + EDBM_init_index_arrays(em, 1, 0, 0); } for( i = 0; i < totvert; i++) { - EditVert *eve = NULL; + BMVert *eve = NULL; MVert *v = verts + i; test = 1; /* reset for every vert */ @@ -1459,9 +1475,9 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh } else { - eve = EM_get_vert_for_index(index); + eve = EDBM_get_vert_for_index(em, index); - if (eve && (eve->h || (eve->f & SELECT))) + if (eve && (BM_TestHFlag(eve, BM_HIDDEN) || BM_TestHFlag(eve, BM_SELECT))) { test = 0; } @@ -1477,7 +1493,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } break; } @@ -1493,11 +1509,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh if (em != NULL) { index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX); - EM_init_index_arrays(em, 0, 1, 0); + EDBM_init_index_arrays(em, 0, 1, 0); } for( i = 0; i < totedge; i++) { - EditEdge *eed = NULL; + BMEdge *eed = NULL; MEdge *e = edges + i; test = 1; /* reset for every vert */ @@ -1519,9 +1535,11 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh } else { - eed = EM_get_edge_for_index(index); + eed = EDBM_get_edge_for_index(em, index); - if (eed && (eed->h || (eed->v1->f & SELECT) || (eed->v2->f & SELECT))) + if (eed && (BM_TestHFlag(eed, BM_HIDDEN) || + BM_TestHFlag(eed->v1, BM_SELECT) || + BM_TestHFlag(eed->v2, BM_SELECT))) { test = 0; } @@ -1537,7 +1555,7 @@ static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh if (em != NULL) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } break; } @@ -1554,14 +1572,14 @@ static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, flo int retval = 0; if (ob->type == OB_MESH) { - EditMesh *em; + BMEditMesh *em; DerivedMesh *dm; if (editobject) { - em = ((Mesh *)ob->data)->edit_mesh; - /* dm = editmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */ - dm = editmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */ + em = ((Mesh *)ob->data)->edit_btmesh; + /* dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */ + dm = editbmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */ } else { @@ -1708,7 +1726,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float { int retval = 0; int totvert = dm->getNumVerts(dm); - int totface = dm->getNumFaces(dm); + int totface = dm->getNumTessFaces(dm); if (totvert > 0) { float imat[4][4]; @@ -1738,7 +1756,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float if (test == 1) { MVert *verts = dm->getVertArray(dm); - MFace *faces = dm->getFaceArray(dm); + MFace *faces = dm->getTessFaceArray(dm); int i; for( i = 0; i < totface; i++) { @@ -1834,6 +1852,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L Object *dob = dupli_ob->ob; if (dob->type == OB_MESH) { +#if 0 //BMESH_TODO EditMesh *em; DerivedMesh *dm = NULL; int val; @@ -1855,6 +1874,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L retval = retval || val; dm->release(dm); +#endif } } @@ -1862,7 +1882,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L } if (ob->type == OB_MESH) { - EditMesh *em; + BMEditMesh *em; DerivedMesh *dm = NULL; int val; @@ -1874,8 +1894,8 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L } else { - em = ((Mesh *)ob->data)->edit_mesh; - dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); + em = ((Mesh *)ob->data)->edit_btmesh; + dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH); val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels); } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 72f13c14f5d..e39e3e87399 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript index a694b211ca4..2d5ee84333b 100644 --- a/source/blender/editors/util/SConscript +++ b/source/blender/editors/util/SConscript @@ -5,7 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../makesrna' +incs += ' ../../makesrna ../../bmesh' incs += ' ../../blenloader' env.BlenderLib ( 'bf_editors_util', sources, Split(incs), [], libtype=['core'], priority=[130] ) diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c index 9560924941d..6d524a59b40 100644 --- a/source/blender/editors/util/crazyspace.c +++ b/source/blender/editors/util/crazyspace.c @@ -43,6 +43,7 @@ #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -108,18 +109,18 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit) Mesh *me= obedit->data; DerivedMesh *dm; float *vertexcos; - int nverts= me->edit_mesh->totvert; + int nverts= me->edit_btmesh->bm->totvert; short *flags; MappedUserData userData; /* disable subsurf temporal, get mapped cos, and enable it */ if(modifiers_disable_subsurf_temporary(obedit)) { /* need to make new derivemesh */ - makeDerivedMesh(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH); + makeDerivedMesh(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH, 0); } /* now get the cage */ - dm= editmesh_get_derived_cage(scene, obedit, me->edit_mesh, CD_MASK_BAREMESH); + dm= editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH); vertexcos= MEM_callocN(3*sizeof(float)*nverts, "vertexcos map"); flags= MEM_callocN(sizeof(short)*nverts, "vertexcos flags"); @@ -138,10 +139,62 @@ float *crazyspace_get_mapped_editverts(Scene *scene, Object *obedit) return vertexcos; } -void crazyspace_set_quats_editmesh(EditMesh *em, float *origcos, float *mappedcos, float *quats) +void crazyspace_set_quats_editmesh(BMEditMesh *em, float *origcos, float *mappedcos, float *quats) { - EditVert *eve, *prev; - EditFace *efa; + BMVert *v; + BMIter iter, liter; + BMLoop *l; + float *v1, *v2, *v3, *co1, *co2, *co3; + int *vert_table = MEM_callocN(sizeof(int)*em->bm->totvert, "vert_table"); + int index = 0; + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, index); + index++; + } + + index = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_TestHFlag(v, BM_SELECT) || BM_TestHFlag(v, BM_HIDDEN)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, v) { + BMLoop *l2 = BM_OtherFaceLoop(l->e, l->f, v); + + /* retrieve mapped coordinates */ + v1= mappedcos + 3*BM_GetIndex(l->v); + v2= mappedcos + 3*BM_GetIndex(BM_OtherEdgeVert(l2->e, l->v)); + v3= mappedcos + 3*BM_GetIndex(BM_OtherEdgeVert(l->e, l->v)); + + co1= (origcos)? origcos + 3*BM_GetIndex(l->v) : l->v->co; + co2= (origcos)? origcos + 3*BM_GetIndex(BM_OtherEdgeVert(l2->e, l->v)) : BM_OtherEdgeVert(l2->e, l->v)->co; + co3= (origcos)? origcos + 3*BM_GetIndex(BM_OtherEdgeVert(l->e, l->v)) : BM_OtherEdgeVert(l->e, l->v)->co; + + set_crazy_vertex_quat(quats, v1, v2, v3, co1, co2, co3); + quats+= 4; + + vert_table[BM_GetIndex(l->v)] = index+1; + + index++; + break; /*just do one corner*/ + } + } + + index = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (vert_table[index] != 0) + BM_SetIndex(v, vert_table[index]-1); + else + BM_SetIndex(v, -1); + + index++; + } + + MEM_freeN(vert_table); +#if 0 + BMEditVert *eve, *prev; + BMEditFace *efa; + BMIter iter; float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4; intptr_t index= 0; @@ -206,7 +259,7 @@ void crazyspace_set_quats_editmesh(EditMesh *em, float *origcos, float *mappedco /* restore abused prev pointer */ for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next) eve->prev= prev; - +#endif } void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats) @@ -269,7 +322,8 @@ void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float } } -int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, float (**deformmats)[3][3], float (**deformcos)[3]) +int editbmesh_get_first_deform_matrices(Scene *scene, Object *ob, BMEditMesh *em, + float (**deformmats)[3][3], float (**deformcos)[3]) { ModifierData *md; DerivedMesh *dm; @@ -288,13 +342,13 @@ int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, f for(i = 0; md && i <= cageIndex; i++, md = md->next) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if(!editmesh_modifier_is_enabled(scene, md, dm)) + if(!editbmesh_modifier_is_enabled(scene, md, dm)) continue; if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { if(!defmats) { - dm= editmesh_get_derived(em, NULL); - deformedVerts= editmesh_get_vertex_cos(em, &numVerts); + dm= getEditDerivedBMesh(em, ob, NULL); + deformedVerts= editbmesh_get_vertex_cos(em, &numVerts); defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats"); for(a=0; a<numVerts; a++) @@ -309,7 +363,7 @@ int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, f } for(; md && i <= cageIndex; md = md->next, i++) - if(editmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md)) + if(editbmesh_modifier_is_enabled(scene, md, dm) && modifier_isCorrectableDeformed(md)) numleft++; if(dm) diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 3dd7514429e..d22751dc9aa 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -109,10 +109,10 @@ void ED_editors_exit(bContext *C) if(ob) { if(ob->type==OB_MESH) { Mesh *me= ob->data; - if(me->edit_mesh) { - free_editMesh(me->edit_mesh); - MEM_freeN(me->edit_mesh); - me->edit_mesh= NULL; + if(me->edit_btmesh) { + EDBM_FreeEditBMesh(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + me->edit_btmesh= NULL; } } else if(ob->type==OB_ARMATURE) { @@ -123,8 +123,8 @@ void ED_editors_exit(bContext *C) } /* global in meshtools... */ - mesh_octree_table(NULL, NULL, NULL, 'e'); - mesh_mirrtopo_table(NULL, 'e'); + //BMESH_TODO mesh_octree_table(NULL, NULL, NULL, 'e'); + //BMESH_TODO mesh_mirrtopo_table(NULL, 'e'); } diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index bcbc134d06d..f2ab43c281b 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -98,8 +98,8 @@ typedef struct UndoElem { char name[MAXUNDONAME]; void * (*getdata)(bContext *C); void (*freedata)(void *); - void (*to_editmode)(void *, void *); - void * (*from_editmode)(void *); + void (*to_editmode)(void *, void *, void *); + void * (*from_editmode)(void *, void *); int (*validate_undo)(void *, void *); } UndoElem; @@ -109,10 +109,10 @@ static UndoElem *curundo= NULL; /* ********************* xtern api calls ************* */ -static void undo_restore(UndoElem *undo, void *editdata) +static void undo_restore(UndoElem *undo, void *editdata, void *obdata) { if(undo) { - undo->to_editmode(undo->undodata, editdata); + undo->to_editmode(undo->undodata, editdata, obdata); } } @@ -120,8 +120,8 @@ static void undo_restore(UndoElem *undo, void *editdata) void undo_editmode_push(bContext *C, const char *name, void * (*getdata)(bContext *C), void (*freedata)(void *), - void (*to_editmode)(void *, void *), - void *(*from_editmode)(void *), + void (*to_editmode)(void *, void *, void *), + void *(*from_editmode)(void *, void *), int (*validate_undo)(void *, void *)) { UndoElem *uel; @@ -170,7 +170,7 @@ void undo_editmode_push(bContext *C, const char *name, /* copy */ memused= MEM_get_memory_in_use(); editdata= getdata(C); - curundo->undodata= curundo->from_editmode(editdata); + curundo->undodata= curundo->from_editmode(editdata, obedit->data); curundo->undosize= MEM_get_memory_in_use() - memused; curundo->ob= obedit; curundo->id= obedit->id; @@ -250,7 +250,7 @@ void undo_editmode_step(bContext *C, int step) undo_clean_stack(C); if(step==0) { - undo_restore(curundo, curundo->getdata(C)); + undo_restore(curundo, curundo->getdata(C), obedit->data); } else if(step==1) { @@ -258,7 +258,7 @@ void undo_editmode_step(bContext *C, int step) else { if(G.f & G_DEBUG) printf("undo %s\n", curundo->name); curundo= curundo->prev; - undo_restore(curundo, curundo->getdata(C)); + undo_restore(curundo, curundo->getdata(C), obedit->data); } } else { @@ -266,7 +266,7 @@ void undo_editmode_step(bContext *C, int step) if(curundo==NULL || curundo->next==NULL) error("No more steps to redo"); else { - undo_restore(curundo->next, curundo->getdata(C)); + undo_restore(curundo->next, curundo->getdata(C), obedit->data); curundo= curundo->next; if(G.f & G_DEBUG) printf("redo %s\n", curundo->name); } @@ -274,7 +274,7 @@ void undo_editmode_step(bContext *C, int step) /* special case for editmesh, mode must be copied back to the scene */ if(obedit->type == OB_MESH) { - EM_selectmode_to_scene(CTX_data_scene(C), obedit); + EDBM_selectmode_to_scene(CTX_data_scene(C), obedit); } DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index 552e1b60154..1fe2e014a75 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -24,6 +24,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../makesdna ../../makesrna ../../windowmanager diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript index 2523de005d0..d236b18a8fd 100644 --- a/source/blender/editors/uvedit/SConscript +++ b/source/blender/editors/uvedit/SConscript @@ -5,6 +5,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' -incs += ' ../../makesrna #/intern/opennl/extern ../../gpu ../../blenloader' +incs += ' ../../bmesh ../../makesrna #/intern/opennl/extern ../../gpu ../../blenloader' env.BlenderLib ( 'bf_editors_uvedit', sources, Split(incs), [], libtype=['core'], priority=[45] ) diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c index 5380f514a73..2a69a7d6abc 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -49,6 +49,7 @@ #include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "ED_image.h" #include "ED_uvedit.h" @@ -63,32 +64,20 @@ /* UV Utilities */ -static int uvedit_center(Scene *scene, EditMesh *em, Image *ima, float center[2]) +static int uvedit_center(Scene *scene, BMEditMesh *em, Image *UNUSED(ima), float center[2]) { - EditFace *efa; - MTFace *tf; - int tot= 0; - + BMFace *f; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + int tot = 0.0; + zero_v2(center); - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) { - add_v2_v2(center, tf->uv[0]); - tot++; - } - if(uvedit_uv_selected(scene, efa, tf, 1)) { - add_v2_v2(center, tf->uv[1]); - tot++; - } - if(uvedit_uv_selected(scene, efa, tf, 2)) { - add_v2_v2(center, tf->uv[2]); - tot++; - } - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) { - add_v2_v2(center, tf->uv[3]); + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (uvedit_uv_selected(em, scene, l)) { + add_v2_v2(center, luv->uv); tot++; } } @@ -102,23 +91,19 @@ static int uvedit_center(Scene *scene, EditMesh *em, Image *ima, float center[2] return tot; } -static void uvedit_translate(Scene *scene, EditMesh *em, Image *ima, float delta[2]) +static void uvedit_translate(Scene *scene, BMEditMesh *em, Image *UNUSED(ima), float delta[2]) { - EditFace *efa; - MTFace *tf; - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) - add_v2_v2(tf->uv[0], delta); - if(uvedit_uv_selected(scene, efa, tf, 1)) - add_v2_v2(tf->uv[1], delta); - if(uvedit_uv_selected(scene, efa, tf, 2)) - add_v2_v2(tf->uv[2], delta); - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) - add_v2_v2(tf->uv[3], delta); + BMFace *f; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (uvedit_uv_selected(em, scene, l)) { + add_v2_v2(luv->uv, delta); + } } } } @@ -133,13 +118,13 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); Image *ima= sima->image; + BMEditMesh *em; float center[2]; int imx, imy, step, digits; - EditMesh *em; ED_space_image_size(sima, &imx, &imy); - em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + em= ((Mesh *)obedit->data)->edit_btmesh; if(uvedit_center(scene, em, ima, center)) { copy_v2_v2(uvedit_old_center, center); @@ -163,8 +148,6 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block) uiDefButF(block, NUM, B_UVEDIT_VERTEX, "Y:", 165, 10, 145, 19, &uvedit_old_center[1], -10*imy, 10.0*imy, step, digits, ""); uiBlockEndAlign(block); } - - BKE_mesh_end_editmesh(obedit->data, em); } static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) @@ -173,14 +156,14 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); Image *ima= sima->image; - EditMesh *em; + BMEditMesh *em; float center[2], delta[2]; int imx, imy; if(event != B_UVEDIT_VERTEX) return; - em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + em= ((Mesh *)obedit->data)->edit_btmesh; ED_space_image_size(sima, &imx, &imy); uvedit_center(scene, em, ima, center); @@ -196,8 +179,6 @@ static void do_uvedit_vertex(bContext *C, void *UNUSED(arg), int event) uvedit_translate(scene, em, ima, delta); - BKE_mesh_end_editmesh(obedit->data, em); - WM_event_add_notifier(C, NC_IMAGE, sima->image); } diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 453bea0969b..beb65875ea2 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -33,7 +33,11 @@ #include <float.h> #include <math.h> #include <stdlib.h> +#include <string.h> +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -46,7 +50,9 @@ #include "BKE_DerivedMesh.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" +#include "BLI_array.h" #include "BIF_gl.h" #include "BIF_glutil.h" @@ -123,34 +129,33 @@ static int draw_uvs_face_check(Scene *scene) static void draw_uvs_shadow(Object *obedit) { - EditMesh *em; - EditFace *efa; - MTFace *tf; + BMEditMesh *em; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; - em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + em= ((Mesh*)obedit->data)->edit_btmesh; /* draws the grey mesh when painting */ glColor3ub(112, 112, 112); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { glBegin(GL_LINE_LOOP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + glVertex2fv(luv->uv); + } glEnd(); } - - BKE_mesh_end_editmesh(obedit->data, em); } static int draw_uvs_dm_shadow(DerivedMesh *dm) { /* draw shadow mesh - this is the mesh with the modifier applied */ - if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->faceData, CD_MTFACE)) { + if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) { glColor3ub(112, 112, 112); dm->drawUVEdges(dm); return 1; @@ -159,13 +164,19 @@ static int draw_uvs_dm_shadow(DerivedMesh *dm) return 0; } -static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFace *activetf) +static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf) { - EditFace *efa; - MTFace *tf; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; Image *ima= sima->image; - float aspx, aspy, col[4], tf_uv[4][2]; - + BLI_array_declare(tf_uv); + BLI_array_declare(tf_uvorig); + float aspx, aspy, col[4], (*tf_uv)[2] = NULL, (*tf_uvorig)[2] = NULL; + int i; + ED_space_image_uv_aspect(sima, &aspx, &aspy); switch(sima->dt_uvstretch) { @@ -173,21 +184,37 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac { float totarea=0.0f, totuvarea=0.0f, areadiff, uvarea, area; - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uv_copy_aspect(tf->uv, tf_uv, aspx, aspy); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + BLI_array_empty(tf_uv); + BLI_array_empty(tf_uvorig); + + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + BLI_array_growone(tf_uv); + BLI_array_growone(tf_uvorig); + + tf_uvorig[i][0] = luv->uv[0]; + tf_uvorig[i][1] = luv->uv[1]; - totarea += EM_face_area(efa); + i++; + } + + poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len); + + totarea += BM_face_area(efa); //totuvarea += tf_area(tf, efa->v4!=0); - totuvarea += uv_area(tf_uv, efa->v4 != NULL); + totuvarea += poly_uv_area(tf_uv, efa->len); if(uvedit_face_visible(scene, ima, efa, tf)) { - efa->tmp.p = tf; + BM_SetIndex(efa, 1); } else { if(tf == activetf) activetf= NULL; - efa->tmp.p = NULL; + BM_SetIndex(efa, 0); } } @@ -195,24 +222,41 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac col[0] = 1.0; col[1] = col[2] = 0.0; glColor3fv(col); - for(efa= em->faces.first; efa; efa= efa->next) { - if((tf=(MTFace *)efa->tmp.p)) { - glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_GetIndex(efa)) { + glBegin(GL_POLYGON); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); } } } else { - for(efa= em->faces.first; efa; efa= efa->next) { - if((tf=(MTFace *)efa->tmp.p)) { - area = EM_face_area(efa) / totarea; - uv_copy_aspect(tf->uv, tf_uv, aspx, aspy); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_GetIndex(efa)) { + area = BM_face_area(efa) / totarea; + + BLI_array_empty(tf_uv); + BLI_array_empty(tf_uvorig); + + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + BLI_array_growone(tf_uv); + BLI_array_growone(tf_uvorig); + + tf_uvorig[i][0] = luv->uv[0]; + tf_uvorig[i][1] = luv->uv[1]; + + i++; + } + + poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len); + //uvarea = tf_area(tf, efa->v4!=0) / totuvarea; - uvarea = uv_area(tf_uv, efa->v4 != NULL) / totuvarea; + uvarea = poly_uv_area(tf_uv, efa->len) / totuvarea; if(area < FLT_EPSILON || uvarea < FLT_EPSILON) areadiff = 1.0f; @@ -224,11 +268,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac weight_to_rgb(areadiff, col, col+1, col+2); glColor3fv(col); - glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + glBegin(GL_POLYGON); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); } } @@ -237,6 +281,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac } case SI_UVDT_STRETCH_ANGLE: { +#if 0 //BMESH_TODO float uvang1,uvang2,uvang3,uvang4; float ang1,ang2,ang3,ang4; float av1[3], av2[3], av3[3], av4[3]; /* use for 2d and 3d angle vectors */ @@ -247,7 +292,7 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac glShadeModel(GL_SMOOTH); for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf= CustomData_em_get(&em->fdata, efa->head.data, CD_MTFACE); if(uvedit_face_visible(scene, ima, efa, tf)) { efa->tmp.p = tf; @@ -378,11 +423,13 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac glShadeModel(GL_FLAT); break; + +#endif } } } -static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf) +static void draw_uvs_other(Scene *scene, Object *obedit, MTexPoly *activetf) { Base *base; Image *curimage; @@ -402,17 +449,19 @@ static void draw_uvs_other(Scene *scene, Object *obedit, MTFace *activetf) Mesh *me= ob->data; if(me->mtface) { - MFace *mface= me->mface; - MTFace *tface= me->mtface; - int a; + MPoly *mface= me->mpoly; + MTexPoly *tface= me->mtpoly; + MLoopUV *mloopuv; + int a, b; - for(a=me->totface; a>0; a--, tface++, mface++) { + for(a=me->totpoly; a>0; a--, tface++, mface++) { if(tface->tpage == curimage) { glBegin(GL_LINE_LOOP); - glVertex2fv(tface->uv[0]); - glVertex2fv(tface->uv[1]); - glVertex2fv(tface->uv[2]); - if(mface->v4) glVertex2fv(tface->uv[3]); + + mloopuv = me->mloopuv + mface->loopstart; + for (b=0; b<mface->totloop; b++, mloopuv++) { + glVertex2fv(mloopuv->uv); + } glEnd(); } } @@ -426,18 +475,22 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) { ToolSettings *ts; Mesh *me= obedit->data; - EditMesh *em; - EditFace *efa, *efa_act; - MTFace *tf, *activetf = NULL; + BMEditMesh *em; + BMFace *efa, *efa_act, *activef; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf, *activetf = NULL; + MLoopUV *luv; DerivedMesh *finaldm, *cagedm; unsigned char col1[4], col2[4]; float pointsize; int drawfaces, interpedges; + int i; Image *ima= sima->image; - em= BKE_mesh_get_editmesh(me); - activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */ - + em= me->edit_btmesh; + activetf= EDBM_get_active_mtexpoly(em, &efa_act, 0); /* will be set to NULL if hidden */ + activef = EDBM_get_actFace(em, 0); ts= scene->toolsettings; drawfaces= draw_uvs_face_check(scene); @@ -456,7 +509,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) /* first try existing derivedmesh */ if(!draw_uvs_dm_shadow(em->derivedFinal)) { /* create one if it does not exist */ - cagedm = editmesh_get_derived_cage_and_final(scene, obedit, em, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE); + cagedm = editbmesh_get_derived_cage_and_final(scene, obedit, me->edit_btmesh, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE); /* when sync selection is enabled, all faces are drawn (except for hidden) * so if cage is the same as the final, theres no point in drawing this */ @@ -481,45 +534,46 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(uvedit_face_visible(scene, ima, efa, tf)) { - efa->tmp.p = tf; - if(tf==activetf) continue; /* important the temp pointer is set above */ + BM_SetIndex(efa, 1); + if(tf==activetf) continue; /* important the temp boolean is set above */ - if(uvedit_face_selected(scene, efa, tf)) + if(uvedit_face_selected(scene, em, efa)) glColor4ubv((GLubyte *)col2); else glColor4ubv((GLubyte *)col1); - - glBegin(efa->v4?GL_QUADS:GL_TRIANGLES); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + + glBegin(GL_POLYGON); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); } else { if(tf == activetf) activetf= NULL; - efa->tmp.p = NULL; + BM_SetIndex(efa, 0); } } glDisable(GL_BLEND); } else { /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */ - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(uvedit_face_visible(scene, ima, efa, tf)) { - efa->tmp.p = tf; + BM_SetIndex(efa, 1); } else { if(tf == activetf) activetf= NULL; - efa->tmp.p = NULL; + BM_SetIndex(efa, 0); } } @@ -527,7 +581,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) /* 3. draw active face stippled */ - if(activetf) { + if(activef) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); UI_ThemeColor4(TH_EDITMESH_ACTIVE); @@ -535,11 +589,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glEnable(GL_POLYGON_STIPPLE); glPolygonStipple(stipple_quarttone); - glBegin(efa_act->v4? GL_QUADS: GL_TRIANGLES); - glVertex2fv(activetf->uv[0]); - glVertex2fv(activetf->uv[1]); - glVertex2fv(activetf->uv[2]); - if(efa_act->v4) glVertex2fv(activetf->uv[3]); + glBegin(GL_POLYGON); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, activef) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); glDisable(GL_POLYGON_STIPPLE); @@ -556,39 +610,38 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) switch(sima->dt_uv) { case SI_UVDT_DASH: - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(tf) { cpack(0x111111); glBegin(GL_LINE_LOOP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); - + setlinestyle(2); cpack(0x909090); - glBegin(GL_LINE_STRIP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glEnd(); - - glBegin(GL_LINE_STRIP); - glVertex2fv(tf->uv[0]); - if(efa->v4) glVertex2fv(tf->uv[3]); - else glVertex2fv(tf->uv[2]); - glEnd(); - - glBegin(GL_LINE_STRIP); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); + glBegin(GL_LINE_LOOP); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + } glEnd(); + /*glBegin(GL_LINE_STRIP); + luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->next->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + glEnd();*/ + setlinestyle(0); } } @@ -598,34 +651,32 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if(sima->dt_uv==SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f); else glColor3f(0.0f, 0.0f, 0.0f); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; - if(tf) { - glBegin(GL_LINE_LOOP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); - glEnd(); + glBegin(GL_LINE_LOOP); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); } + glEnd(); } break; case SI_UVDT_OUTLINE: glLineWidth(3); cpack(0x0); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - if(tf) { - glBegin(GL_LINE_LOOP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); - glEnd(); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + glBegin(GL_LINE_LOOP); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); } + glEnd(); } glLineWidth(1); @@ -639,83 +690,60 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) if(interpedges) { glShadeModel(GL_SMOOTH); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; - if(tf) { - glBegin(GL_LINE_LOOP); - sel = (uvedit_uv_selected(scene, efa, tf, 0)? 1 : 0); - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[0]); - - sel = uvedit_uv_selected(scene, efa, tf, 1)? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[1]); - - sel = uvedit_uv_selected(scene, efa, tf, 2)? 1 : 0; + glBegin(GL_LINE_LOOP); + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + sel = (uvedit_uv_selected(em, scene, l)? 1 : 0); if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[2]); - - if(efa->v4) { - sel = uvedit_uv_selected(scene, efa, tf, 3)? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[3]); - } - - glEnd(); + + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + luv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + i += 1; } + glEnd(); } glShadeModel(GL_FLAT); } else { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; - if(tf) { - glBegin(GL_LINES); - sel = (uvedit_edge_selected(scene, efa, tf, 0)? 1 : 0); - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - - sel = uvedit_edge_selected(scene, efa, tf, 1)? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - - sel = uvedit_edge_selected(scene, efa, tf, 2)? 1 : 0; + glBegin(GL_LINE_LOOP); + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + sel = (uvedit_edge_selected(em, scene, l)? 1 : 0); if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[2]); - - if(efa->v4) { - glVertex2fv(tf->uv[3]); - - sel = uvedit_edge_selected(scene, efa, tf, 3)? 1 : 0; - if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; } - glVertex2fv(tf->uv[3]); - } - - glVertex2fv(tf->uv[0]); - - glEnd(); + + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + luv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); + i += 1; } + glEnd(); } } } else { /* no nice edges */ - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - if(tf) { - glBegin(GL_LINE_LOOP); - glVertex2fv(tf->uv[0]); - glVertex2fv(tf->uv[1]); - glVertex2fv(tf->uv[2]); - if(efa->v4) glVertex2fv(tf->uv[3]); - glEnd(); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + glBegin(GL_LINE_LOOP); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); } + glEnd(); } } @@ -739,11 +767,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) UI_ThemeColor(TH_WIRE); bglBegin(GL_POINTS); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; - if(tf && !uvedit_face_selected(scene, efa, tf)) { - uv_center(tf->uv, cent, efa->v4 != NULL); + if(!uvedit_face_selected(scene, em, efa)) { + poly_uv_center(em, efa, cent); bglVertex2fv(cent); } } @@ -753,11 +782,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) UI_ThemeColor(TH_FACE_DOT); bglBegin(GL_POINTS); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; - if(tf && uvedit_face_selected(scene, efa, tf)) { - uv_center(tf->uv, cent, efa->v4 != NULL); + if(uvedit_face_selected(scene, em, efa)) { + poly_uv_center(em, efa, cent); bglVertex2fv(cent); } } @@ -773,18 +803,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glPointSize(pointsize); bglBegin(GL_POINTS); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - if(tf) { - if(!uvedit_uv_selected(scene, efa, tf, 0)) - bglVertex2fv(tf->uv[0]); - if(!uvedit_uv_selected(scene, efa, tf, 1)) - bglVertex2fv(tf->uv[1]); - if(!uvedit_uv_selected(scene, efa, tf, 2)) - bglVertex2fv(tf->uv[2]); - if(efa->v4 && !uvedit_uv_selected(scene, efa, tf, 3)) - bglVertex2fv(tf->uv[3]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if(!uvedit_uv_selected(em, scene, l)) + bglVertex2fv(luv->uv); } } bglEnd(); @@ -795,18 +821,15 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) cpack(0xFF); bglBegin(GL_POINTS); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - if(tf) { - if(tf->unwrap & TF_PIN1) - bglVertex2fv(tf->uv[0]); - if(tf->unwrap & TF_PIN2) - bglVertex2fv(tf->uv[1]); - if(tf->unwrap & TF_PIN3) - bglVertex2fv(tf->uv[2]); - if(efa->v4 && (tf->unwrap & TF_PIN4)) - bglVertex2fv(tf->uv[3]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if(luv->flag & MLOOPUV_PINNED) + bglVertex2fv(luv->uv); } } bglEnd(); @@ -816,25 +839,21 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glPointSize(pointsize); bglBegin(GL_POINTS); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - if(tf) { - if(uvedit_uv_selected(scene, efa, tf, 0)) - bglVertex2fv(tf->uv[0]); - if(uvedit_uv_selected(scene, efa, tf, 1)) - bglVertex2fv(tf->uv[1]); - if(uvedit_uv_selected(scene, efa, tf, 2)) - bglVertex2fv(tf->uv[2]); - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) - bglVertex2fv(tf->uv[3]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if(uvedit_uv_selected(em, scene, l)) + bglVertex2fv(luv->uv); } } bglEnd(); } glPointSize(1.0); - BKE_mesh_end_editmesh(obedit->data, em); } void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit) diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 58626ccbf64..34dd0108f46 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -35,23 +35,33 @@ #define ED_UVEDIT_INTERN_H struct SpaceImage; -struct EditFace; -struct MTFace; +struct MTexPoly; struct Scene; struct Image; struct Object; struct wmOperatorType; +struct BMEditMesh; +struct BMFace; +struct BMLoop; +struct BMEdge; +struct BMVert; /* id can be from 0 to 3 */ #define TF_PIN_MASK(id) (TF_PIN1 << id) #define TF_SEL_MASK(id) (TF_SEL1 << id) +/* visibility and selection */ +int uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa); /* geometric utilities */ void uv_center(float uv[][2], float cent[2], int quad); float uv_area(float uv[][2], int quad); void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy); +float poly_uv_area(float uv[][2], int len); +void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len); +void poly_uv_center(struct BMEditMesh *em, struct BMFace *f, float cent[2]); + /* operators */ void UV_OT_average_islands_scale(struct wmOperatorType *ot); void UV_OT_cube_project(struct wmOperatorType *ot); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index c09f8cff02d..c95d4d0636a 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -35,16 +35,20 @@ #include <stdlib.h> #include <string.h> #include <math.h> +#include <string.h> #include "MEM_guardedalloc.h" #include "DNA_object_types.h" #include "DNA_meshdata_types.h" +#include "DNA_image_types.h" +#include "DNA_space_types.h" #include "DNA_scene_types.h" #include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_editVert.h" +#include "BLI_array.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -54,6 +58,7 @@ #include "BKE_library.h" #include "BKE_mesh.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "ED_image.h" #include "ED_mesh.h" @@ -72,19 +77,23 @@ #include "uvedit_intern.h" +#define EFA_F1_FLAG 2 + /************************* state testing ************************/ int ED_uvedit_test(Object *obedit) { - EditMesh *em; + BMEditMesh *em; int ret; - if(!obedit || obedit->type != OB_MESH) + if (!obedit) + return 0; + + if(obedit->type != OB_MESH) return 0; - em = BKE_mesh_get_editmesh(obedit->data); - ret = EM_texFaceCheck(em); - BKE_mesh_end_editmesh(obedit->data, em); + em = ((Mesh*)obedit->data)->edit_btmesh; + ret = EDBM_texFaceCheck(em); return ret; } @@ -93,9 +102,10 @@ int ED_uvedit_test(Object *obedit) void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma) { - EditMesh *em; - EditFace *efa; - MTFace *tf; + BMEditMesh *em; + BMFace *efa; + BMIter iter; + MTexPoly *tf; int update= 0; /* skip assigning these procedural images... */ @@ -106,21 +116,21 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre if(!obedit || (obedit->type != OB_MESH)) return; - em= BKE_mesh_get_editmesh(((Mesh*)obedit->data)); - if(!em || !em->faces.first) { - BKE_mesh_end_editmesh(obedit->data, em); + em= ((Mesh*)obedit->data)->edit_btmesh; + if(!em || !em->bm->totface) { return; } /* ensure we have a uv layer */ - if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) { - EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL); + if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) { + BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY); + BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV); update= 1; } /* now assign to all visible faces */ - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); if(uvedit_face_visible(scene, previma, efa, tf)) { if(ima) { @@ -142,17 +152,16 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre /* and update depdency graph */ if(update) DAG_id_tag_update(obedit->data, 0); - - BKE_mesh_end_editmesh(obedit->data, em); } /* dotile - 1, set the tile flag (from the space image) * 2, set the tile index for the faces. */ static int uvedit_set_tile(Object *obedit, Image *ima, int curtile) { - EditMesh *em; - EditFace *efa; - MTFace *tf; + BMEditMesh *em; + BMFace *efa; + BMIter iter; + MTexPoly *tf; /* verify if we have something to do */ if(!ima || !ED_uvedit_test(obedit)) @@ -165,17 +174,16 @@ static int uvedit_set_tile(Object *obedit, Image *ima, int curtile) if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE) return 0; - em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + em= ((Mesh*)obedit->data)->edit_btmesh; - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(efa->h==0 && efa->f & SELECT) + if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)) tf->tile= curtile; /* set tile index */ } DAG_id_tag_update(obedit->data, 0); - BKE_mesh_end_editmesh(obedit->data, em); return 1; } @@ -186,13 +194,7 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist { int width, height; - if(sima) { - ED_space_image_size(sima, &width, &height); - } - else { - width= 256; - height= 256; - } + ED_space_image_size(sima, &width, &height); dist[0]= pixeldist/width; dist[1]= pixeldist/height; @@ -200,18 +202,17 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist /*************** visibility and selection utilities **************/ -int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa) +int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) - return (efa->h==0); + return (BM_TestHFlag(efa, BM_HIDDEN)==0); else - return (efa->h==0 && (efa->f & SELECT)); + return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT)); } -int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf) -{ +int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SHOW_SAME_IMAGE) @@ -220,131 +221,195 @@ int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf) return uvedit_face_visible_nolocal(scene, efa); } -int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf) +int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) - return (efa->f & SELECT); - else - return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4)); + return (BM_TestHFlag(efa, BM_SELECT)); + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (!(luv->flag & MLOOPUV_VERTSEL)) + return 0; + } + + return 1; + } } -void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf) +int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) - EM_select_face(efa, 1); - else - tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + BM_Select(em->bm, efa, 1); + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + + return 1; + } + + return 0; } -void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf) +int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) - EM_select_face(efa, 0); - else - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + BM_Select(em->bm, efa, 0); + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + return 1; + } + + return 0; } -int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i) +int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; - int nvert= (efa->v4)? 4: 3; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - return (efa->f & SELECT); - else if(ts->selectmode & SCE_SELECT_EDGE) - return (*(&efa->e1 + i))->f & SELECT; - else - return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT)); + return BM_TestHFlag(l->f, BM_SELECT); + else if(ts->selectmode == SCE_SELECT_EDGE) { + return BM_TestHFlag(l->e, BM_SELECT); + } else + return BM_TestHFlag(l->v, BM_SELECT) && + BM_TestHFlag(((BMLoop*)l->next)->v, BM_SELECT); + } + else { + MLoopUV *luv1, *luv2; + + luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + + return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); } - else - return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert)); } -void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i) +void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l) + { ToolSettings *ts= scene->toolsettings; - int nvert= (efa->v4)? 4: 3; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - EM_select_face(efa, 1); + BM_Select(em->bm, l->f, 1); else if(ts->selectmode & SCE_SELECT_EDGE) - EM_select_edge((*(&efa->e1 + i)), 1); + BM_Select(em->bm, l->e, 1); else { - (efa->v1 + i)->f |= SELECT; - (efa->v1 + (i+1)%nvert)->f |= SELECT; + BM_Select(em->bm, l->e->v1, 1); + BM_Select(em->bm, l->e->v2, 1); } } - else - tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert); + else { + MLoopUV *luv1, *luv2; + + luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + + luv1->flag |= MLOOPUV_VERTSEL; + luv2->flag |= MLOOPUV_VERTSEL; + } } -void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i) +void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l) + { ToolSettings *ts= scene->toolsettings; - int nvert= (efa->v4)? 4: 3; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - EM_select_face(efa, 0); + BM_Select(em->bm, l->f, 0); else if(ts->selectmode & SCE_SELECT_EDGE) - EM_select_edge((*(&efa->e1 + i)), 0); + BM_Select(em->bm, l->e, 0); else { - (efa->v1 + i)->f &= ~SELECT; - (efa->v1 + (i+1)%nvert)->f &= ~SELECT; + BM_Select(em->bm, l->e->v1, 0); + BM_Select(em->bm, l->e->v2, 0); } } - else - tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert)); + else { + MLoopUV *luv1, *luv2; + + luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + + luv1->flag &= ~MLOOPUV_VERTSEL; + luv2->flag &= ~MLOOPUV_VERTSEL; + } } -int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i) +int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - return (efa->f & SELECT); + return BM_TestHFlag(l->f, BM_SELECT); else - return (*(&efa->v1 + i))->f & SELECT; + return BM_TestHFlag(l->v, BM_SELECT); + } + else { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + return luv->flag & MLOOPUV_VERTSEL; } - else - return tf->flag & TF_SEL_MASK(i); } -void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i) +void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - EM_select_face(efa, 1); + BM_Select(em->bm, l->f, 1); else - (*(&efa->v1 + i))->f |= SELECT; + BM_Select(em->bm, l->v, 1); + } + else { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->flag |= MLOOPUV_VERTSEL; } - else - tf->flag |= TF_SEL_MASK(i); } -void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i) +void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l) { ToolSettings *ts= scene->toolsettings; if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode & SCE_SELECT_FACE) - EM_select_face(efa, 0); + BM_Select(em->bm, l->f, 0); else - (*(&efa->v1 + i))->f &= ~SELECT; + BM_Select(em->bm, l->v, 0); + } + else { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->flag &= ~MLOOPUV_VERTSEL; } - else - tf->flag &= ~TF_SEL_MASK(i); } /*********************** live unwrap utilities ***********************/ @@ -359,6 +424,24 @@ static void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *ob } /*********************** geometric utilities ***********************/ +void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2]) +{ + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + cent[0] = cent[1] = 0.0f; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + cent[0] += luv->uv[0]; + cent[1] += luv->uv[1]; + } + + cent[0] /= (float) f->len; + cent[1] /= (float) f->len; +} + void uv_center(float uv[][2], float cent[2], int quad) { @@ -380,6 +463,28 @@ float uv_area(float uv[][2], int quad) return area_tri_v2(uv[0], uv[1], uv[2]); } +float poly_uv_area(float uv[][2], int len) +{ + //BMESH_TODO: make this not suck + //maybe use scanfill? I dunno. + + if(len >= 4) + return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); + else + return area_tri_v2(uv[0], uv[1], uv[2]); + + return 1.0; +} + +void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len) +{ + int i; + for (i=0; i<len; i++) { + uv[i][0] = uv_orig[i][0]*aspx; + uv[i][1] = uv_orig[i][1]*aspy; + } +} + void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy) { uv[0][0] = uv_orig[0][0]*aspx; @@ -397,56 +502,66 @@ void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy) int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; int sel; INIT_MINMAX2(min, max); sel= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); sel = 1; } - if(uvedit_uv_selected(scene, efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); sel = 1; } - if(uvedit_uv_selected(scene, efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); sel = 1; } - if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); sel = 1; } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + DO_MINMAX2(luv->uv, min, max); + sel = 1; + } } } - - BKE_mesh_end_editmesh(obedit->data, em); + return sel; } static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3]) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; unsigned int sel= 0; zero_v3(co); - - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) { add_v3_v3(co, tf->uv[0]); sel++; } - if(uvedit_uv_selected(scene, efa, tf, 1)) { add_v3_v3(co, tf->uv[1]); sel++; } - if(uvedit_uv_selected(scene, efa, tf, 2)) { add_v3_v3(co, tf->uv[2]); sel++; } - if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3))) { add_v3_v3(co, tf->uv[3]); sel++; } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (uvedit_uv_selected(em, scene, l)) { + add_v2_v2(co, luv->uv); + sel++; + } } } mul_v3_fl(co, 1.0f/(float)sel); - BKE_mesh_end_editmesh(obedit->data, em); return (sel != 0); } static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); float min[2], max[2]; int change= 0; @@ -466,108 +581,147 @@ static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, } if(change) { - BKE_mesh_end_editmesh(obedit->data, em); return 1; } - BKE_mesh_end_editmesh(obedit->data, em); return 0; } /************************** find nearest ****************************/ typedef struct NearestHit { - EditFace *efa; - MTFace *tf; - - int vert, uv; - int edge, vert2; + BMFace *efa; + MTexPoly *tf; + BMLoop *l, *nextl; + MLoopUV *luv, *nextluv; + int lindex; //index of loop within face + int vert1, vert2; //index in mesh of edge vertices } NearestHit; -static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit) +static void find_nearest_uv_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit) { - MTFace *tf; - EditFace *efa; - EditVert *eve; + MTexPoly *tf; + BMFace *efa; + BMLoop *l; + BMVert *eve; + BMIter iter, liter; + MLoopUV *luv, *nextluv; float mindist, dist; - int i, nverts; + int i; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); - for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) - eve->tmp.l = i; + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) { + BM_SetIndex(eve, i); + } - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - - for(i=0; i<nverts; i++) { - dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); - if(dist < mindist) { - hit->tf= tf; - hit->efa= efa; - hit->edge= i; - mindist= dist; + dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv); - hit->vert= (*(&efa->v1 + i))->tmp.l; - hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l; - } + if(dist < mindist) { + hit->tf= tf; + hit->efa= efa; + + hit->l = l; + hit->nextl = (BMLoop*)l->next; + hit->luv = luv; + hit->nextluv = nextluv; + hit->lindex = i; + hit->vert1 = BM_GetIndex(hit->l->v); + hit->vert2 = BM_GetIndex(((BMLoop*)hit->l->next)->v); + + mindist = dist; } + + i++; } } } -static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit) +static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit) { - MTFace *tf; - EditFace *efa; + MTexPoly *tf; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; float mindist, dist, cent[2]; - int i, nverts; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - cent[0]= cent[1]= 0.0f; + /*this will fill in hit.vert1 and hit.vert2*/ + find_nearest_uv_edge(scene, ima, em, co, hit); + hit->l = hit->nextl = NULL; + hit->luv = hit->nextluv = NULL; - for(i=0; i<nverts; i++) { - cent[0] += tf->uv[i][0]; - cent[1] += tf->uv[i][1]; - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + cent[0]= cent[1]= 0.0f; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - cent[0] /= nverts; - cent[1] /= nverts; - dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]); + cent[0] += luv->uv[0]; + cent[1] += luv->uv[1]; + } - if(dist < mindist) { - hit->tf= tf; - hit->efa= efa; - mindist= dist; - } + cent[0] /= efa->len; + cent[1] /= efa->len; + dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]); + + if(dist < mindist) { + hit->tf= tf; + hit->efa= efa; + mindist= dist; } } } -static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2]) +static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id, + float co[2], float uv[2]) { - float m[3], v1[3], v2[3], c1, c2; - int id1, id2; + BMLoop *l; + MLoopUV *luv; + BMIter iter; + float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3; + int id1, id2, i; - id1= (id+nverts-1)%nverts; - id2= (id+nverts+1)%nverts; + id1= (id+efa->len-1)%efa->len; + id2= (id+efa->len+1)%efa->len; m[0]= co[0]-uv[0]; m[1]= co[1]-uv[1]; - sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]); - sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]); + + i = 0; + BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (i == id1) + uv1 = luv->uv; + else if (i == id) + uv2 = luv->uv; + else if (i == id2) + uv3 = luv->uv; + + i++; + } + + sub_v3_v3v3(v1, uv1, uv); + sub_v3_v3v3(v2, uv3, uv); /* m and v2 on same side of v-v1? */ c1= v1[0]*m[1] - v1[1]*m[0]; @@ -583,86 +737,103 @@ static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float return (c1*c2 >= 0.0f); } -static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit) +static void find_nearest_uv_vert(Scene *scene, Image *ima, BMEditMesh *em, + float co[2], float penalty[2], NearestHit *hit) { - EditFace *efa; - EditVert *eve; - MTFace *tf; + BMFace *efa; + BMVert *eve; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float mindist, dist; - int i, nverts; + int i; + + /*this will fill in hit.vert1 and hit.vert2*/ + find_nearest_uv_edge(scene, ima, em, co, hit); + hit->l = hit->nextl = NULL; + hit->luv = hit->nextluv = NULL; mindist= 1e10f; memset(hit, 0, sizeof(*hit)); - for(i=0, eve=em->verts.first; eve; eve=eve->next, i++) - eve->tmp.l = i; - - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; + eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (i=0; eve; eve=BMIter_Step(&iter), i++) { + BM_SetIndex(eve, i); + } - for(i=0; i<nverts; i++) { - if(penalty && uvedit_uv_selected(scene, efa, tf, i)) - dist= fabsf(co[0]-tf->uv[i][0])+penalty[0] + fabsf(co[1]-tf->uv[i][1]) + penalty[1]; - else - dist= fabsf(co[0]-tf->uv[i][0]) + fabsf(co[1]-tf->uv[i][1]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - if(dist<=mindist) { - if(dist==mindist) - if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i])) - continue; + if(penalty && uvedit_uv_selected(em, scene, l)) + dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1]; + else + dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]); - mindist= dist; + if(dist<=mindist) { + if(dist==mindist) + if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) { + i++; + continue; + } - hit->uv= i; - hit->tf= tf; - hit->efa= efa; + mindist= dist; - hit->vert= (*(&efa->v1 + i))->tmp.l; - } + hit->l = l; + hit->nextl = (BMLoop*)l->next; + hit->luv = luv; + hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV); + hit->tf= tf; + hit->efa= efa; + hit->lindex = i; + hit->vert1 = BM_GetIndex(hit->l->v); } + + i++; } } } int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2]) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float mindist, dist; - int i, nverts, found= 0; + int found= 0; mindist= 1e10f; uv[0]= co[0]; uv[1]= co[1]; - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - - for(i=0; i<nverts; i++) { - if(uvedit_uv_selected(scene, efa, tf, i)) - continue; - - dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]); - if(dist<=mindist) { - mindist= dist; + if(dist<=mindist) { + mindist= dist; - uv[0]= tf->uv[i][0]; - uv[1]= tf->uv[i][1]; - found= 1; - } + uv[0]= luv->uv[0]; + uv[1]= luv->uv[1]; + found= 1; } } } - BKE_mesh_end_editmesh(obedit->data, em); return found; } @@ -684,26 +855,28 @@ static void uv_vertex_loop_flag(UvMapVert *first) first->flag= 1; } -static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a) +static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a) { UvMapVert *iterv, *first; - - first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l); + BMLoop *l; + + l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a); + first= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v)); for(iterv=first; iterv; iterv=iterv->next) { if(iterv->separate) first= iterv; - if(iterv->f == efa->tmp.l) + if(iterv->f == BM_GetIndex(efa)) return first; } return NULL; } -static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) +static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface) { UvMapVert *iterv1, *iterv2; - EditFace *efa; + BMFace *efa; int tot = 0; /* count number of faces this edge has */ @@ -717,8 +890,8 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) if(iterv1->f == iterv2->f) { /* if face already tagged, don't do this edge */ - efa= EM_get_face_for_index(iterv1->f); - if(efa->f1) + efa= EDBM_get_face_for_index(em, iterv1->f); + if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG)) return 0; tot++; @@ -742,8 +915,8 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) break; if(iterv1->f == iterv2->f) { - efa= EM_get_face_for_index(iterv1->f); - efa->f1= 1; + efa= EDBM_get_face_for_index(em, iterv1->f); + BMO_SetFlag(em->bm, efa, EFA_F1_FLAG); break; } } @@ -752,41 +925,47 @@ static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface) return 1; } -static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend) +static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend) { - EditVert *eve; - EditFace *efa; - MTFace *tf; + BMVert *eve; + BMFace *efa; + BMIter iter, liter; + BMLoop *l; + MTexPoly *tf; UvVertMap *vmap; UvMapVert *iterv1, *iterv2; int a, count, looking, nverts, starttotf, select; /* setup */ - EM_init_index_arrays(em, 0, 0, 1); - vmap= EM_make_uv_vert_map(em, 0, 0, limit); + EDBM_init_index_arrays(em, 0, 0, 1); + vmap= EDBM_make_uv_vert_map(em, 0, 0, limit); - for(count=0, eve=em->verts.first; eve; count++, eve= eve->next) - eve->tmp.l = count; + count = 0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(eve, count); + count++; + } - for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) { + count = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { if(!extend) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uvedit_face_deselect(scene, efa, tf); + uvedit_face_deselect(scene, em, efa); } - - efa->tmp.l= count; - efa->f1= 0; + + BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG); + BM_SetIndex(efa, count); + count++; } - + /* set flags for first face and verts */ - nverts= (hit->efa->v4)? 4: 3; - iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge); - iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts); + nverts= hit->efa->len; + iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex); + iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts); uv_vertex_loop_flag(iterv1); uv_vertex_loop_flag(iterv2); starttotf= 0; - uv_edge_tag_faces(iterv1, iterv2, &starttotf); + uv_edge_tag_faces(em, iterv1, iterv2, &starttotf); /* sorry, first edge isnt even ok */ if(iterv1->flag==0 && iterv2->flag==0) looking= 0; @@ -797,21 +976,25 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h looking= 0; /* find correct valence edges which are not tagged yet, but connect to tagged one */ - for(efa= em->faces.first; efa; efa=efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) { - nverts= (efa->v4)? 4: 3; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) { + nverts= efa->len; for(a=0; a<nverts; a++) { /* check face not hidden and not tagged */ iterv1= uv_vertex_map_get(vmap, efa, a); iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts); + + if (!iterv1 || !iterv2) + continue; /* check if vertex is tagged and has right valence */ if(iterv1->flag || iterv2->flag) { - if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) { + if(uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) { looking= 1; - efa->f1= 1; + BMO_SetFlag(em->bm, efa, EFA_F1_FLAG); uv_vertex_loop_flag(iterv1); uv_vertex_loop_flag(iterv2); @@ -824,16 +1007,14 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h } /* do the actual select/deselect */ - nverts= (hit->efa->v4)? 4: 3; - iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge); - iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts); + nverts= hit->efa->len; + iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex); + iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts); iterv1->flag= 1; iterv2->flag= 1; if(extend) { - tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE); - - if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge)) + if(uvedit_uv_selected(em, scene, hit->l) && uvedit_uv_selected(em, scene, hit->l)) select= 0; else select= 1; @@ -841,83 +1022,109 @@ static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *h else select= 1; - for(efa= em->faces.first; efa; efa=efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - nverts= (efa->v4)? 4: 3; - for(a=0; a<nverts; a++) { + a = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { iterv1= uv_vertex_map_get(vmap, efa, a); if(iterv1->flag) { - if(select) uvedit_uv_select(scene, efa, tf, a); - else uvedit_uv_deselect(scene, efa, tf, a); + if(select) uvedit_uv_select(em, scene, l); + else uvedit_uv_deselect(em, scene, l); } + + a++; } } /* cleanup */ - EM_free_uv_vert_map(vmap); - EM_free_index_arrays(); + EDBM_free_uv_vert_map(vmap); + EDBM_free_index_arrays(em); return (select)? 1: -1; } /*********************** linked select ***********************/ -static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend) +static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend) { - EditFace *efa; - MTFace *tf; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; UvVertMap *vmap; UvMapVert *vlist, *iterv, *startv; int i, nverts, stacksize= 0, *stack; unsigned int a; char *flag; - EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */ - vmap= EM_make_uv_vert_map(em, 1, 0, limit); + EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */ + vmap= EDBM_make_uv_vert_map(em, 1, 1, limit); + if(vmap == NULL) return; - stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack"); - flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag"); + stack= MEM_mallocN(sizeof(*stack)*(em->bm->totface+1), "UvLinkStack"); + flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag"); if(!hit) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(uvedit_face_visible(scene, ima, efa, tf)) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - if(tf->flag & select_flag) { - stack[stacksize]= a; - stacksize++; - flag[a]= 1; + if(uvedit_face_visible(scene, ima, efa, tf)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (luv->flag & MLOOPUV_VERTSEL) { + stack[stacksize]= a; + stacksize++; + flag[a]= 1; + + break; + } } } } + a++; } else { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { if(efa == hit->efa) { stack[stacksize]= a; stacksize++; flag[a]= 1; break; } + + a++; } } while(stacksize > 0) { + int j; + stacksize--; a= stack[stacksize]; + + j = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(j==a) + break; + + j++; + } - efa = EM_get_face_for_index(a); + nverts= efa->len; - nverts= efa->v4? 4: 3; + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { - for(i=0; i<nverts; i++) { /* make_uv_vert_map_EM sets verts tmp.l to the indices */ - vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l); + vlist= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v)); startv= vlist; @@ -937,50 +1144,86 @@ static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2] stacksize++; } } + + i++; } } - if(!extend) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(flag[a]) - tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - else - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + if(!extend) { + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (flag[a]) + luv->flag |= MLOOPUV_VERTSEL; + else + luv->flag &= ~MLOOPUV_VERTSEL; + } + a++; } } else { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if((tf->flag & select_flag)) + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!flag[a]) { + a++; + continue; + } + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (luv->flag & MLOOPUV_VERTSEL) break; } + + if (l) + break; + + a++; } if(efa) { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!flag[a]) { + a++; + continue; } + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->flag &= ~MLOOPUV_VERTSEL; + } + + a++; } } else { - for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) { - if(flag[a]) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + a = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!flag[a]) { + a++; + continue; + } + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->flag |= MLOOPUV_VERTSEL; } + + a++; } } } MEM_freeN(stack); MEM_freeN(flag); - EM_free_uv_vert_map(vmap); - EM_free_index_arrays(); + EDBM_free_uv_vert_map(vmap); + EDBM_free_index_arrays(em); } /* ******************** align operator **************** */ @@ -991,32 +1234,34 @@ static void weld_align_uv(bContext *C, int tool) Scene *scene; Object *obedit; Image *ima; - EditMesh *em; - EditFace *efa; - MTFace *tf; + BMEditMesh *em; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float cent[2], min[2], max[2]; scene= CTX_data_scene(C); obedit= CTX_data_edit_object(C); - em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + em= ((Mesh*)obedit->data)->edit_btmesh; ima= CTX_data_edit_image(C); sima= CTX_wm_space_image(C); INIT_MINMAX2(min, max); if(tool == 'a') { - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) - DO_MINMAX2(tf->uv[0], min, max) - if(uvedit_uv_selected(scene, efa, tf, 1)) - DO_MINMAX2(tf->uv[1], min, max) - if(uvedit_uv_selected(scene, efa, tf, 2)) - DO_MINMAX2(tf->uv[2], min, max) - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) - DO_MINMAX2(tf->uv[3], min, max) + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + DO_MINMAX2(luv->uv, min, max) + } } } @@ -1026,33 +1271,33 @@ static void weld_align_uv(bContext *C, int tool) uvedit_center(scene, ima, obedit, cent, 0); if(tool == 'x' || tool == 'w') { - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) - tf->uv[0][0]= cent[0]; - if(uvedit_uv_selected(scene, efa, tf, 1)) - tf->uv[1][0]= cent[0]; - if(uvedit_uv_selected(scene, efa, tf, 2)) - tf->uv[2][0]= cent[0]; - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) - tf->uv[3][0]= cent[0]; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->uv[0] = cent[0]; + } + } } } if(tool == 'y' || tool == 'w') { - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) - tf->uv[0][1]= cent[1]; - if(uvedit_uv_selected(scene, efa, tf, 1)) - tf->uv[1][1]= cent[1]; - if(uvedit_uv_selected(scene, efa, tf, 2)) - tf->uv[2][1]= cent[1]; - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) - tf->uv[3][1]= cent[1]; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->uv[1] = cent[1]; + } + } } } @@ -1060,8 +1305,6 @@ static void weld_align_uv(bContext *C, int tool) uvedit_live_unwrap_update(sima, scene, obedit); DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - - BKE_mesh_end_editmesh(obedit->data, em); } static int align_exec(bContext *C, wmOperator *op) @@ -1125,40 +1368,43 @@ typedef struct UVVertAverage { static int stitch_exec(bContext *C, wmOperator *op) { - SpaceImage *sima; Scene *scene; Object *obedit; - EditMesh *em; - EditFace *efa; - EditVert *eve; + BMEditMesh *em; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + BMVert *eve; Image *ima; - MTFace *tf; + SpaceImage *sima= CTX_wm_space_image(C); + MTexPoly *tf; + MLoopUV *luv; scene= CTX_data_scene(C); obedit= CTX_data_edit_object(C); - em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + em= ((Mesh*)obedit->data)->edit_btmesh; ima= CTX_data_edit_image(C); sima= CTX_wm_space_image(C); if(RNA_boolean_get(op->ptr, "use_limit")) { UvVertMap *vmap; UvMapVert *vlist, *iterv; - float newuv[2], limit[2]; + float newuv[2], limit[2], pixels; int a, vtot; - limit[0]= RNA_float_get(op->ptr, "limit"); - limit[1]= limit[0]; + pixels= RNA_float_get(op->ptr, "limit"); + uvedit_pixel_to_float(sima, limit, pixels); - EM_init_index_arrays(em, 0, 0, 1); - vmap= EM_make_uv_vert_map(em, 1, 0, limit); + EDBM_init_index_arrays(em, 0, 0, 1); + vmap= EDBM_make_uv_vert_map(em, 1, 0, limit); if(vmap == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } - - for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) { - vlist= EM_get_uv_map_vert(vmap, a); + + a = 0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + vlist= EDBM_get_uv_map_vert(vmap, a); while(vlist) { newuv[0]= 0; newuv[1]= 0; @@ -1168,12 +1414,15 @@ static int stitch_exec(bContext *C, wmOperator *op) if((iterv != vlist) && iterv->separate) break; - efa = EM_get_face_for_index(iterv->f); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + efa = EDBM_get_face_for_index(em, iterv->f); + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) { - newuv[0] += tf->uv[iterv->tfindex][0]; - newuv[1] += tf->uv[iterv->tfindex][1]; + l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + newuv[0] += luv->uv[0]; + newuv[1] += luv->uv[1]; vtot++; } } @@ -1185,95 +1434,72 @@ static int stitch_exec(bContext *C, wmOperator *op) if((iterv != vlist) && iterv->separate) break; - efa = EM_get_face_for_index(iterv->f); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + efa = EDBM_get_face_for_index(em, iterv->f); + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) { - tf->uv[iterv->tfindex][0]= newuv[0]; - tf->uv[iterv->tfindex][1]= newuv[1]; + luv->uv[0] = newuv[0]; + luv->uv[1] = newuv[1]; + vtot++; } } } vlist= iterv; } + + a++; } - EM_free_uv_vert_map(vmap); - EM_free_index_arrays(); + EDBM_free_uv_vert_map(vmap); + EDBM_free_index_arrays(em); } else { UVVertAverage *uv_average, *uvav; int count; // index and count verts - for(count=0, eve=em->verts.first; eve; count++, eve= eve->next) - eve->tmp.l = count; + count=0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(eve, count); + count++; + } uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch"); // gather uv averages per vert - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) { - uvav = uv_average + efa->v1->tmp.l; - uvav->count++; - uvav->uv[0] += tf->uv[0][0]; - uvav->uv[1] += tf->uv[0][1]; - } - - if(uvedit_uv_selected(scene, efa, tf, 1)) { - uvav = uv_average + efa->v2->tmp.l; - uvav->count++; - uvav->uv[0] += tf->uv[1][0]; - uvav->uv[1] += tf->uv[1][1]; - } - - if(uvedit_uv_selected(scene, efa, tf, 2)) { - uvav = uv_average + efa->v3->tmp.l; - uvav->count++; - uvav->uv[0] += tf->uv[2][0]; - uvav->uv[1] += tf->uv[2][1]; - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if(uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + uvav = uv_average + BM_GetIndex(l->v); - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) { - uvav = uv_average + efa->v4->tmp.l; uvav->count++; - uvav->uv[0] += tf->uv[3][0]; - uvav->uv[1] += tf->uv[3][1]; + uvav->uv[0] += luv->uv[0]; + uvav->uv[1] += luv->uv[1]; } } } // apply uv welding - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(uvedit_uv_selected(scene, efa, tf, 0)) { - uvav = uv_average + efa->v1->tmp.l; - tf->uv[0][0] = uvav->uv[0]/uvav->count; - tf->uv[0][1] = uvav->uv[1]/uvav->count; - } - - if(uvedit_uv_selected(scene, efa, tf, 1)) { - uvav = uv_average + efa->v2->tmp.l; - tf->uv[1][0] = uvav->uv[0]/uvav->count; - tf->uv[1][1] = uvav->uv[1]/uvav->count; - } - - if(uvedit_uv_selected(scene, efa, tf, 2)) { - uvav = uv_average + efa->v3->tmp.l; - tf->uv[2][0] = uvav->uv[0]/uvav->count; - tf->uv[2][1] = uvav->uv[1]/uvav->count; - } - - if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) { - uvav = uv_average + efa->v4->tmp.l; - tf->uv[3][0] = uvav->uv[0]/uvav->count; - tf->uv[3][1] = uvav->uv[1]/uvav->count; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if(uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + uvav = uv_average + BM_GetIndex(l->v); + luv->uv[0] = uvav->uv[0]/uvav->count; + luv->uv[1] = uvav->uv[1]/uvav->count; } } } @@ -1285,7 +1511,6 @@ static int stitch_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1303,7 +1528,7 @@ static void UV_OT_stitch(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance."); - RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX); + RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX); } /* ******************** (de)select all operator **************** */ @@ -1313,44 +1538,51 @@ static int select_all_exec(bContext *C, wmOperator *op) Scene *scene; ToolSettings *ts; Object *obedit; - EditMesh *em; - EditFace *efa; + BMEditMesh *em; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; Image *ima; - MTFace *tf; + MTexPoly *tf; + MLoopUV *luv; int action = RNA_enum_get(op->ptr, "action"); scene= CTX_data_scene(C); ts= CTX_data_tool_settings(C); obedit= CTX_data_edit_object(C); - em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + em= ((Mesh*)obedit->data)->edit_btmesh; ima= CTX_data_edit_image(C); if(ts->uv_flag & UV_SYNC_SELECTION) { + switch (action) { case SEL_TOGGLE: - EM_toggle_select_all(em); + EDBM_toggle_select_all(((Mesh*)obedit->data)->edit_btmesh); break; case SEL_SELECT: - EM_select_all(em); + EDBM_set_flag_all(em, BM_SELECT); break; case SEL_DESELECT: - EM_deselect_all(em); + EDBM_clear_flag_all(em, BM_SELECT); break; case SEL_INVERT: - EM_select_swap(em); + EDBM_select_swap(em); break; } } else { - if (action == SEL_TOGGLE) { action = SEL_SELECT; - for(efa= em->faces.first; efa; efa= efa->next) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(tf->flag & select_flag) { + if (luv->flag & MLOOPUV_VERTSEL) { action = SEL_DESELECT; break; } @@ -1358,21 +1590,25 @@ static int select_all_exec(bContext *C, wmOperator *op) } } - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); - if(uvedit_face_visible(scene, ima, efa, tf)) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); switch (action) { case SEL_SELECT: - tf->flag |= select_flag; + luv->flag |= MLOOPUV_VERTSEL; break; case SEL_DESELECT: - tf->flag &= ~select_flag; + luv->flag &= ~MLOOPUV_VERTSEL; break; case SEL_INVERT: - tf->flag ^= select_flag; + luv->flag ^= MLOOPUV_VERTSEL; break; } } @@ -1381,7 +1617,6 @@ static int select_all_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1402,7 +1637,7 @@ static void UV_OT_select_all(wmOperatorType *ot) /* ******************** mouse select operator **************** */ -static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky) +static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen) { int i; @@ -1411,7 +1646,7 @@ static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], floa if(sticky == SI_STICKY_DISABLE) return 0; - for(i=0; i<4; i++) { + for(i=0; i<hitlen; i++) { if(hitv[i] == v) { if(sticky == SI_STICKY_LOC) { if(fabsf(hituv[i][0]-uv[0]) < limit[0] && fabsf(hituv[i][1]-uv[1]) < limit[1]) @@ -1432,13 +1667,19 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) ToolSettings *ts= CTX_data_tool_settings(C); Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; NearestHit hit; - int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert; - int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ - float limit[2], *hituv[4], penalty[2]; + int a, i, select = 1, selectmode, sticky, sync, *hitv=NULL, nvert; + BLI_array_declare(hitv); + int flush = 0, hitlen=0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + float limit[2], **hituv = NULL; + BLI_array_declare(hituv); + float penalty[2]; /* notice 'limit' is the same no matter the zoom level, since this is like * remove doubles and could annoying if it joined points when zoomed out. @@ -1465,7 +1706,7 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) else { sync= 0; selectmode= ts->uv_selectmode; - sticky= (sima)? sima->sticky: 1; + sticky= sima->sticky; } /* find nearest element */ @@ -1473,76 +1714,88 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) /* find edge */ find_nearest_uv_edge(scene, ima, em, co, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } + + hitlen = 0; } else if(selectmode == UV_SELECT_VERTEX) { /* find vertex */ find_nearest_uv_vert(scene, ima, em, co, penalty, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } /* mark 1 vertex as being hit */ - for(i=0; i<4; i++) + for(i=0; i<hit.efa->len; i++) { + BLI_array_growone(hitv); + BLI_array_growone(hituv); hitv[i]= 0xFFFFFFFF; + } - hitv[hit.uv]= hit.vert; - hituv[hit.uv]= hit.tf->uv[hit.uv]; + hitv[hit.lindex]= hit.vert1; + hituv[hit.lindex]= hit.luv->uv; + + hitlen = hit.efa->len; } else if(selectmode == UV_SELECT_EDGE) { /* find edge */ find_nearest_uv_edge(scene, ima, em, co, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } /* mark 2 edge vertices as being hit */ - for(i=0; i<4; i++) + for(i=0; i<hit.efa->len; i++) { + BLI_array_growone(hitv); + BLI_array_growone(hituv); hitv[i]= 0xFFFFFFFF; + } + + nvert= hit.efa->len; - nvert= (hit.efa->v4)? 4: 3; + hitv[hit.lindex]= hit.vert1; + hitv[(hit.lindex+1)%nvert]= hit.vert2; + hituv[hit.lindex]= hit.luv->uv; + hituv[(hit.lindex+1)%nvert]= hit.nextluv->uv; - hitv[hit.edge]= hit.vert; - hitv[(hit.edge+1)%nvert]= hit.vert2; - hituv[hit.edge]= hit.tf->uv[hit.edge]; - hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert]; + hitlen = hit.efa->len; } else if(selectmode == UV_SELECT_FACE) { /* find face */ find_nearest_uv_face(scene, ima, em, co, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } /* make active */ - EM_set_actFace(em, hit.efa); + EDBM_set_actFace(em, hit.efa); /* mark all face vertices as being hit */ - for(i=0; i<4; i++) - hituv[i]= hit.tf->uv[i]; + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, hit.efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - hitv[0]= hit.efa->v1->tmp.l; - hitv[1]= hit.efa->v2->tmp.l; - hitv[2]= hit.efa->v3->tmp.l; + BLI_array_growone(hitv); + BLI_array_growone(hituv); + hituv[i]= luv->uv; + hitv[i] = BM_GetIndex(l->v); + i++; + } - if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l; - else hitv[3]= 0xFFFFFFFF; + hitlen = hit.efa->len; } else if(selectmode == UV_SELECT_ISLAND) { find_nearest_uv_vert(scene, ima, em, co, NULL, &hit); if(hit.efa==NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } + + hitlen = 0; } else { - BKE_mesh_end_editmesh(obedit->data, em); + hitlen = 0; return OPERATOR_CANCELLED; } @@ -1556,36 +1809,36 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) else if(extend) { if(selectmode == UV_SELECT_VERTEX) { /* (de)select uv vertex */ - if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) { - uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv); + if(uvedit_uv_selected(em, scene, hit.l)) { + uvedit_uv_deselect(em, scene, hit.l); select= 0; } else { - uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv); + uvedit_uv_select(em, scene, hit.l); select= 1; } flush = 1; } else if(selectmode == UV_SELECT_EDGE) { /* (de)select edge */ - if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) { - uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge); + if(uvedit_edge_selected(em, scene, hit.l)) { + uvedit_edge_deselect(em, scene, hit.l); select= 0; } else { - uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge); + uvedit_edge_select(em, scene, hit.l); select= 1; } flush = 1; } else if(selectmode == UV_SELECT_FACE) { /* (de)select face */ - if(uvedit_face_selected(scene, hit.efa, hit.tf)) { - uvedit_face_deselect(scene, hit.efa, hit.tf); + if(uvedit_face_selected(scene, em, hit.efa)) { + uvedit_face_deselect(scene, em, hit.efa); select= 0; } else { - uvedit_face_select(scene, hit.efa, hit.tf); + uvedit_face_select(scene, em, hit.efa); select= 1; } flush = -1; @@ -1593,109 +1846,99 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) /* (de)select sticky uv nodes */ if(sticky != SI_STICKY_DISABLE) { - EditVert *ev; - - for(a=0, ev=em->verts.first; ev; ev = ev->next, a++) - ev->tmp.l = a; + BMVert *ev; + a = 0; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(ev, a); + a++; + } + /* deselect */ if(select==0) { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) - uvedit_uv_deselect(scene, efa, tf, 0); - if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) - uvedit_uv_deselect(scene, efa, tf, 1); - if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) - uvedit_uv_deselect(scene, efa, tf, 2); - if(efa->v4) - if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) - uvedit_uv_deselect(scene, efa, tf, 3); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_deselect(em, scene, l); } } flush = -1; } /* select */ else { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tf)) { - if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) - uvedit_uv_select(scene, efa, tf, 0); - if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) - uvedit_uv_select(scene, efa, tf, 1); - if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) - uvedit_uv_select(scene, efa, tf, 2); - if(efa->v4) - if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) - uvedit_uv_select(scene, efa, tf, 3); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_select(em, scene, l); } } - + flush = 1; } } } else { /* deselect all */ - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uvedit_face_deselect(scene, efa, tf); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + uvedit_face_deselect(scene, em, efa); } if(selectmode == UV_SELECT_VERTEX) { /* select vertex */ - uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv); + uvedit_uv_select(em, scene, hit.l); flush= 1; } else if(selectmode == UV_SELECT_EDGE) { /* select edge */ - uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge); + uvedit_edge_select(em, scene, hit.l); flush= 1; } else if(selectmode == UV_SELECT_FACE) { /* select face */ - uvedit_face_select(scene, hit.efa, hit.tf); + uvedit_face_select(scene, em, hit.efa); } /* select sticky uvs */ if(sticky != SI_STICKY_DISABLE) { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tf)) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { if(sticky == SI_STICKY_DISABLE) continue; + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky)) - uvedit_uv_select(scene, efa, tf, 0); - if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky)) - uvedit_uv_select(scene, efa, tf, 1); - if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky)) - uvedit_uv_select(scene, efa, tf, 2); - if(efa->v4) - if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky)) - uvedit_uv_select(scene, efa, tf, 3); + if(sticky_select(limit, hitv, BM_GetIndex(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_select(em, scene, l); flush= 1; } } } } - + if(sync) { /* flush for mesh selection */ if(ts->selectmode != SCE_SELECT_FACE) { - if(flush==1) EM_select_flush(em); - else if(flush==-1) EM_deselect_flush(em); + if(flush==1) EDBM_select_flush(em, ts->selectmode); + //else if(flush==-1) EDBM_deselect_flush(em); <-- I think this takes care of itself. . . } } - + DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED; } @@ -1796,7 +2039,7 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i ToolSettings *ts= CTX_data_tool_settings(C); Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; float limit[2]; int extend; @@ -1804,7 +2047,6 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i if(ts->uv_flag & UV_SYNC_SELECTION) { BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled."); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -1835,7 +2077,6 @@ static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, i DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1900,31 +2141,45 @@ static int unlink_selection_exec(bContext *C, wmOperator *op) ToolSettings *ts= CTX_data_tool_settings(C); Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; if(ts->uv_flag & UV_SYNC_SELECTION) { BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled."); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int desel = 0; + + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; - if(uvedit_face_visible(scene, ima, efa, tf)) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - if(~tf->flag & select_flag) - tf->flag &= ~select_flag; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (!(luv->flag & MLOOPUV_VERTSEL)) { + desel = 1; + break; + } + } + if (desel) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag &= ~MLOOPUV_VERTSEL; + } } } DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1959,78 +2214,77 @@ static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Obje * selection (so for sticky modes, vertex or location based). */ ToolSettings *ts= CTX_data_tool_settings(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; - int nverts, i; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) { /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MTFace UV's that use a touched vert. */ - EditVert *eve; + * in the loop and select all MLoopUV's that use a touched vert. */ + BMVert *eve; - for(eve= em->verts.first; eve; eve= eve->next) - eve->tmp.l = 0; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) + BM_SetIndex(eve, 0); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l) { - if(efa->v4) - efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1; - else - efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_GetIndex(efa)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + BM_SetIndex(l->v, 1); + } } } /* now select tagged verts */ - for(efa= em->faces.first; efa; efa= efa->next) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - nverts= efa->v4? 4: 3; - for(i=0; i<nverts; i++) { - if((*(&efa->v1 + i))->tmp.l) { - if(select) - uvedit_uv_select(scene, efa, tf, i); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_GetIndex(l->v)) { + if (select) + uvedit_uv_select(em, scene, l); else - uvedit_uv_deselect(scene, efa, tf, i); + uvedit_uv_deselect(em, scene, l); } } } } else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) { - EditFace *efa_vlist; - MTFace *tf_vlist; + BMFace *efa_vlist; + MTexPoly *tf_vlist; UvMapVert *start_vlist=NULL, *vlist_iter; struct UvVertMap *vmap; float limit[2]; unsigned int efa_index; - //EditVert *eve; /* removed vert counting for now */ + //BMVert *eve; /* removed vert counting for now */ //int a; uvedit_pixel_to_float(sima, limit, 0.05); - EM_init_index_arrays(em, 0, 0, 1); - vmap= EM_make_uv_vert_map(em, 0, 0, limit); + EDBM_init_index_arrays(em, 0, 0, 1); + vmap= EDBM_make_uv_vert_map(em, 0, 0, limit); /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */ /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) eve->tmp.l = a; */ if(vmap == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); return; } - for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) { - if(efa->tmp.l) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - nverts= efa->v4? 4: 3; - - for(i=0; i<nverts; i++) { + efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for (efa_index=0; efa; efa=BMIter_Step(&iter), efa_index++) { + if(BM_GetIndex(efa)) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { if(select) - uvedit_uv_select(scene, efa, tf, i); + uvedit_uv_select(em, scene, l); else - uvedit_uv_deselect(scene, efa, tf, i); + uvedit_uv_deselect(em, scene, l); - vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l); + vlist_iter= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v)); while (vlist_iter) { if(vlist_iter->separate) @@ -2049,35 +2303,33 @@ static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Obje break; if(efa_index != vlist_iter->f) { - efa_vlist = EM_get_face_for_index(vlist_iter->f); - tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE); + efa_vlist = EDBM_get_face_for_index(em, vlist_iter->f); + tf_vlist = CustomData_bmesh_get(&em->bm->pdata, efa_vlist->head.data, CD_MTEXPOLY); if(select) - uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex); + uvedit_uv_select(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex)); else - uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex); + uvedit_uv_deselect(em, scene, BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex)); } vlist_iter = vlist_iter->next; } } } } - EM_free_index_arrays(); - EM_free_uv_vert_map(vmap); + EDBM_free_index_arrays(em); + EDBM_free_uv_vert_map(vmap); } else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->tmp.l) { - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_GetIndex(efa)) { if(select) - uvedit_face_select(scene, efa, tf); + uvedit_face_select(scene, em, efa); else - uvedit_face_deselect(scene, efa, tf); + uvedit_face_deselect(scene, em, efa); } } } - BKE_mesh_end_editmesh(obedit->data, em); } static int border_select_exec(bContext *C, wmOperator *op) @@ -2088,9 +2340,12 @@ static int border_select_exec(bContext *C, wmOperator *op) Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); ARegion *ar= CTX_wm_region(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tface; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; rcti rect; rctf rectf; int change, pinned, select, faces; @@ -2120,14 +2375,16 @@ static int border_select_exec(bContext *C, wmOperator *op) change= 0; - for(efa= em->faces.first; efa; efa= efa->next) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { /* assume not touched */ - efa->tmp.l = 0; - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tface)) { - uv_center(tface->uv, cent, efa->v4 != NULL); + BM_SetIndex(efa, 0); + + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(uvedit_face_visible(scene, ima, efa, tf)) { + poly_uv_center(em, efa, cent); if(BLI_in_rctf(&rectf, cent[0], cent[1])) { - efa->tmp.l = change = 1; + BM_SetIndex(efa, 1); + change = 1; } } } @@ -2139,51 +2396,26 @@ static int border_select_exec(bContext *C, wmOperator *op) else { /* other selection modes */ change= 1; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tf)) + continue; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - for(efa= em->faces.first; efa; efa= efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tface)) { if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) { + /* UV_SYNC_SELECTION - can't do pinned selection */ - if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) { - if(select) uvedit_uv_select(scene, efa, tface, 0); - else uvedit_uv_deselect(scene, efa, tface, 0); - } - if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) { - if(select) uvedit_uv_select(scene, efa, tface, 1); - else uvedit_uv_deselect(scene, efa, tface, 1); - } - if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) { - if(select) uvedit_uv_select(scene, efa, tface, 2); - else uvedit_uv_deselect(scene, efa, tface, 2); - } - if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) { - if(select) uvedit_uv_select(scene, efa, tface, 3); - else uvedit_uv_deselect(scene, efa, tface, 3); - } - } - else if(pinned) { - if((tface->unwrap & TF_PIN1) && - BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) { - - if(select) uvedit_uv_select(scene, efa, tface, 0); - else uvedit_uv_deselect(scene, efa, tface, 0); - } - if((tface->unwrap & TF_PIN2) && - BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) { - - if(select) uvedit_uv_select(scene, efa, tface, 1); - else uvedit_uv_deselect(scene, efa, tface, 1); - } - if((tface->unwrap & TF_PIN3) && - BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) { - - if(select) uvedit_uv_select(scene, efa, tface, 2); - else uvedit_uv_deselect(scene, efa, tface, 2); + if(BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) { + if(select) uvedit_uv_select(em, scene, l); + else uvedit_uv_deselect(em, scene, l); } - if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) { - if(select) uvedit_uv_select(scene, efa, tface, 3); - else uvedit_uv_deselect(scene, efa, tface, 3); + } else if(pinned) { + if ((luv->flag & MLOOPUV_PINNED) && + BLI_in_rctf(&rectf, luv->uv[0], luv->uv[1])) { + if(select) uvedit_uv_select(em, scene, l); + else uvedit_uv_deselect(em, scene, l); } } } @@ -2192,20 +2424,20 @@ static int border_select_exec(bContext *C, wmOperator *op) if(change) { /* make sure newly selected vert selection is updated*/ +#if 0 //ok, I think the BM_Select API handles all of this? if(ts->uv_flag & UV_SYNC_SELECTION) { if(ts->selectmode != SCE_SELECT_FACE) { if(select) EM_select_flush(em); else EM_deselect_flush(em); } } +#endif WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } - - BKE_mesh_end_editmesh(obedit->data, em); + return OPERATOR_CANCELLED; } @@ -2234,20 +2466,22 @@ static void UV_OT_select_border(wmOperatorType *ot) /* ******************** circle select operator **************** */ -static void select_uv_inside_ellipse(Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index) +static void select_uv_inside_ellipse(BMEditMesh *em, SpaceImage *UNUSED(sima), Scene *scene, int select, + float *offset, float *ell, BMLoop *l, MLoopUV *luv) { /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ float x, y, r2, *uv; - uv= tface->uv[index]; + + uv= luv->uv; x= (uv[0] - offset[0])*ell[0]; y= (uv[1] - offset[1])*ell[1]; r2 = x*x + y*y; if(r2 < 1.0f) { - if(select) uvedit_uv_select(scene, efa, tface, select_index); - else uvedit_uv_deselect(scene, efa, tface, select_index); + if(select) uvedit_uv_select(em, scene, l); + else uvedit_uv_deselect(em, scene, l); } } @@ -2256,10 +2490,12 @@ static int circle_select_exec(bContext *C, wmOperator *op) SpaceImage *sima= CTX_wm_space_image(C); Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; ARegion *ar= CTX_wm_region(C); - EditFace *efa; - MTFace *tface; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; int x, y, radius, width, height, select; float zoomx, zoomy, offset[2], ellipse[2]; int gesture_mode= RNA_int_get(op->ptr, "gesture_mode"); @@ -2281,21 +2517,19 @@ static int circle_select_exec(bContext *C, wmOperator *op) UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]); /* do selection */ - for(efa= em->faces.first; efa; efa= efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - select_uv_inside_ellipse(scene, select, efa, tface, 0, offset, ellipse, 0); - select_uv_inside_ellipse(scene, select, efa, tface, 1, offset, ellipse, 1); - select_uv_inside_ellipse(scene, select, efa, tface, 2, offset, ellipse, 2); - if(efa->v4) - select_uv_inside_ellipse(scene, select, efa, tface, 3, offset, ellipse, 3); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + select_uv_inside_ellipse(em, sima, scene, select, offset, ellipse, l, luv); + } } +#if 0 //I think the BM_Select api stuff handles all this as necassary? if(select) EM_select_flush(em); else EM_deselect_flush(em); - +#endif WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -2395,97 +2629,88 @@ static void UV_OT_snap_cursor(wmOperatorType *ot) static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tface; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tface; + MLoopUV *luv; short change= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tface)) { - if(uvedit_uv_selected(scene, efa, tface, 0)) VECCOPY2D(tface->uv[0], sima->cursor); - if(uvedit_uv_selected(scene, efa, tface, 1)) VECCOPY2D(tface->uv[1], sima->cursor); - if(uvedit_uv_selected(scene, efa, tface, 2)) VECCOPY2D(tface->uv[2], sima->cursor); - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3)) VECCOPY2D(tface->uv[3], sima->cursor); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; - change= 1; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if(uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + VECCOPY2D(luv->uv, sima->cursor); + change= 1; + } } } - BKE_mesh_end_editmesh(obedit->data, em); return change; } static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - EditVert *eve; - MTFace *tface; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + BMVert *eve; + MTexPoly *tface; + MLoopUV *luv; short change = 0; int count = 0; float *coords; short *usercount, users; /* set all verts to -1 : an unused index*/ - for(eve= em->verts.first; eve; eve= eve->next) - eve->tmp.l=-1; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) + BM_SetIndex(eve, -1); /* index every vert that has a selected UV using it, but only once so as to * get unique indices and to count how much to malloc */ - for(efa= em->faces.first; efa; efa= efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tface)) { - if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1) efa->v1->tmp.l= count++; - if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1) efa->v2->tmp.l= count++; - if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1) efa->v3->tmp.l= count++; - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1) efa->v4->tmp.l= count++; - - change = 1; - - /* optional speedup */ - efa->tmp.p = tface; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) { + BM_SetIndex(efa, 0); + continue; + } else { + BM_SetIndex(efa, 1); + } + + change = 1; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l) && BM_GetIndex(l->v) == -1) { + BM_SetIndex(l->v, count); + count++; + } } - else - efa->tmp.p = NULL; } coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords"); usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts"); /* add all UV coords from visible, unselected UV coords as well as counting them to average later */ - for(efa= em->faces.first; efa; efa= efa->next) { - if((tface=(MTFace *)efa->tmp.p)) { - /* is this an unselected UV we can snap to? */ - if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) { - coords[efa->v1->tmp.l*2] += tface->uv[0][0]; - coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1]; - usercount[efa->v1->tmp.l]++; - change = 1; - } - if(efa->v2->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 1))) { - coords[efa->v2->tmp.l*2] += tface->uv[1][0]; - coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1]; - usercount[efa->v2->tmp.l]++; - change = 1; - } - if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) { - coords[efa->v3->tmp.l*2] += tface->uv[2][0]; - coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1]; - usercount[efa->v3->tmp.l]++; - change = 1; - } - - if(efa->v4) { - if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) { - coords[efa->v4->tmp.l*2] += tface->uv[3][0]; - coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1]; - usercount[efa->v4->tmp.l]++; - change = 1; - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_GetIndex(l->v) >= 0 && + (!uvedit_uv_selected(em, scene, l))) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + coords[BM_GetIndex(l->v)*2] += luv->uv[0]; + coords[BM_GetIndex(l->v)*2+1] += luv->uv[1]; + change = 1; } } } @@ -2494,46 +2719,24 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe if(!change) { MEM_freeN(coords); MEM_freeN(usercount); - BKE_mesh_end_editmesh(obedit->data, em); return change; } /* copy the averaged unselected UVs back to the selected UVs */ - for(efa= em->faces.first; efa; efa= efa->next) { - if((tface=(MTFace *)efa->tmp.p)) { - - if( uvedit_uv_selected(scene, efa, tface, 0) && - efa->v1->tmp.l >= 0 && - (users = usercount[efa->v1->tmp.l]) - ) { - tface->uv[0][0] = coords[efa->v1->tmp.l*2] / users; - tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1] / users; - } - - if( uvedit_uv_selected(scene, efa, tface, 1) && - efa->v2->tmp.l >= 0 && - (users = usercount[efa->v2->tmp.l]) - ) { - tface->uv[1][0] = coords[efa->v2->tmp.l*2] / users; - tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1] / users; - } - - if( uvedit_uv_selected(scene, efa, tface, 2) && - efa->v3->tmp.l >= 0 && - (users = usercount[efa->v3->tmp.l]) - ) { - tface->uv[2][0] = coords[efa->v3->tmp.l*2] / users; - tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1] / users; - } - - if(efa->v4) { - if( uvedit_uv_selected(scene, efa, tface, 3) && - efa->v4->tmp.l >= 0 && - (users = usercount[efa->v4->tmp.l]) - ) { - tface->uv[3][0] = coords[efa->v4->tmp.l*2] / users; - tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1] / users; - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_GetIndex(efa)) + continue; + + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l) && BM_GetIndex(l->v) >= 0 + && (users = usercount[BM_GetIndex(l->v)])) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->uv[0] = coords[BM_GetIndex(l->v)*2]; + luv->uv[1] = coords[BM_GetIndex(l->v)*2+1]; } } } @@ -2541,43 +2744,41 @@ static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obe MEM_freeN(coords); MEM_freeN(usercount); - BKE_mesh_end_editmesh(obedit->data, em); return change; } static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - Image *ima; - EditFace *efa; - MTFace *tface; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + Image *ima= sima->image; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tface; + MLoopUV *luv; int width= 0, height= 0; float w, h; short change = 0; - if(!sima) - return 0; - - ima= sima->image; - ED_space_image_size(sima, &width, &height); w = (float)width; h = (float)height; - for(efa= em->faces.first; efa; efa= efa->next) { - tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(uvedit_face_visible(scene, ima, efa, tface)) { - if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h); - if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h); - if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h); - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; - change = 1; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + snap_uv_to_pixel(luv->uv, w, h); + } } + + change = 1; } - BKE_mesh_end_editmesh(obedit->data, em); return change; } @@ -2640,35 +2841,34 @@ static int pin_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tface; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tface; + MLoopUV *luv; int clear= RNA_boolean_get(op->ptr, "clear"); - for(efa= em->faces.first; efa; efa= efa->next) { - tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; - if(uvedit_face_visible(scene, ima, efa, tface)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if(!clear) { - if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1; - if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2; - if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3; - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4; - } - else { - if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1; - if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2; - if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3; - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4; + if (uvedit_uv_selected(em, scene, l)) + luv->flag |= MLOOPUV_PINNED; + } else { + if (uvedit_uv_selected(em, scene, l)) + luv->flag &= ~MLOOPUV_PINNED; } } } WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -2695,26 +2895,28 @@ static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); Image *ima= CTX_data_edit_image(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tface; - - for(efa= em->faces.first; efa; efa= efa->next) { - tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(uvedit_face_visible(scene, ima, efa, tface)) { - if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0); - if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1); - if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2); - if(efa->v4) { - if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3); - } + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tface; + MLoopUV *luv; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tface= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if(!uvedit_face_visible(scene, ima, efa, tface)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (luv->flag & MLOOPUV_PINNED) + uvedit_uv_select(em, scene, l); } } WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -2738,122 +2940,75 @@ static int hide_exec(bContext *C, wmOperator *op) SpaceImage *sima= CTX_wm_space_image(C); ToolSettings *ts= CTX_data_tool_settings(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + Scene *scene = CTX_data_scene(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; int swap= RNA_boolean_get(op->ptr, "unselected"); int facemode= sima ? sima->flag & SI_SELACTFACE : 0; if(ts->uv_flag & UV_SYNC_SELECTION) { - EM_hide_mesh(em, swap); + EDBM_hide_mesh(em, swap); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } - if(swap) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if(facemode) { - /* Pretend face mode */ - if(( (efa->v4==NULL && - ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || - ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) == 0) { - - if(em->selectmode == SCE_SELECT_FACE) { - efa->f &= ~SELECT; - /* must re-select after */ - efa->e1->f &= ~SELECT; - efa->e2->f &= ~SELECT; - efa->e3->f &= ~SELECT; - if(efa->e4) efa->e4->f &= ~SELECT; - } - else - EM_select_face(efa, 0); - } - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - else if(em->selectmode == SCE_SELECT_FACE) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - if((tf->flag & select_flag)==0) { - EM_select_face(efa, 0); - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } - } - else { - /* EM_deselect_flush will deselect the face */ - if((tf->flag & TF_SEL1)==0) efa->v1->f &= ~SELECT; - if((tf->flag & TF_SEL2)==0) efa->v2->f &= ~SELECT; - if((tf->flag & TF_SEL3)==0) efa->v3->f &= ~SELECT; - if((efa->v4) && (tf->flag & TF_SEL4)==0) efa->v4->f &= ~SELECT; - - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int hide = 0; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + if (luv->flag & MLOOPUV_VERTSEL) { + hide = 1; + break; } } - } - else { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(facemode) { - if( (efa->v4==NULL && - ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) == (TF_SEL1|TF_SEL2|TF_SEL3) ) || - ( tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) == (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) ) { - - if(em->selectmode == SCE_SELECT_FACE) { - efa->f &= ~SELECT; - /* must re-select after */ - efa->e1->f &= ~SELECT; - efa->e2->f &= ~SELECT; - efa->e3->f &= ~SELECT; - if(efa->e4) efa->e4->f &= ~SELECT; - } - else - EM_select_face(efa, 0); - } - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + if (swap) + hide = !hide; + + if (hide) { + if (facemode) { + /*check that every UV is selected*/ + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (!(luv->flag & MLOOPUV_VERTSEL)) + break; } - else if(em->selectmode == SCE_SELECT_FACE) { - const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3); - if(tf->flag & select_flag) - EM_select_face(efa, 0); - - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + + if (!luv) { + BM_Select(em->bm, efa, 0); + uvedit_face_deselect(scene, em, efa); } - else { - /* EM_deselect_flush will deselect the face */ - if(tf->flag & TF_SEL1) efa->v1->f &= ~SELECT; - if(tf->flag & TF_SEL2) efa->v2->f &= ~SELECT; - if(tf->flag & TF_SEL3) efa->v3->f &= ~SELECT; - if((efa->v4) && tf->flag & TF_SEL4) efa->v4->f &= ~SELECT; - - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); + } else if(em->selectmode == SCE_SELECT_FACE) { + /*check if a UV is selected*/ + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (luv->flag & MLOOPUV_VERTSEL) { + BM_Select(em->bm, efa, 0); + } + luv->flag &= ~MLOOPUV_VERTSEL; + } + } else { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + if (luv->flag & MLOOPUV_VERTSEL) { + BM_Select(em->bm, l->v, 0); + luv->flag &= ~MLOOPUV_VERTSEL; + } } } } } - /*deselects too many but ok for now*/ - if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)) - EM_deselect_flush(em); - if(em->selectmode==SCE_SELECT_FACE) { - /* de-selected all edges from faces that were de-selected. - * now make sure all faces that are selected also have selected edges */ - for(efa= em->faces.first; efa; efa= efa->next) - if(efa->f & SELECT) - EM_select_face(efa, 1); - } - - EM_validate_selections(em); + EDBM_validate_selections(em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -2880,114 +3035,102 @@ static int reveal_exec(bContext *C, wmOperator *UNUSED(op)) SpaceImage *sima= CTX_wm_space_image(C); ToolSettings *ts= CTX_data_tool_settings(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + /*Scene *scene = CTX_data_scene(C);*/ /*UNUSED*/ + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMVert *v; + BMIter iter, liter; + MLoopUV *luv; int facemode= sima ? sima->flag & SI_SELACTFACE : 0; int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(v, BM_TestHFlag(v, BM_SELECT)); + } + /* call the mesh function if we are in mesh sync sel */ if(ts->uv_flag & UV_SYNC_SELECTION) { - EM_reveal_mesh(em); + EDBM_reveal_mesh(em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } - if(facemode) { if(em->selectmode == SCE_SELECT_FACE) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(!(efa->h) && !(efa->f & SELECT)) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - EM_select_face(efa, 1); - tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && !BM_TestHFlag(efa, BM_SELECT)) { + BM_Select(em->bm, efa, 1); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } } } } else { /* enable adjacent faces to have disconnected UV selections if sticky is disabled */ if(!stickymode) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(!(efa->h) && !(efa->f & SELECT)) { - /* All verts must be unselected for the face to be selected in the UV view */ - if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==NULL || (efa->v4->f&SELECT)==0)) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4; - /* Cant use EM_select_face here because it unselects the verts - * and we cant tell if the face was totally unselected or not */ - /*EM_select_face(efa, 1); - * - * See Loop with EM_select_face() below... */ - efa->f |= SELECT; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && !BM_TestHFlag(efa, BM_SELECT)) { + int totsel=0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + totsel += BM_TestHFlag(l->v, BM_SELECT); + } + + if (!totsel) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + + BM_Select(em->bm, efa, 1); } } } - } - else { - for(efa= em->faces.first; efa; efa= efa->next) { - if(!(efa->h) && !(efa->f & SELECT)) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;} - if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;} - if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;} - if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;} - - efa->f |= SELECT; + } else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && !BM_TestHFlag(efa, BM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_TestHFlag(l->v, BM_SELECT)==0) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + } + + BM_Select(em->bm, efa, 1); } } } - - /* Select all edges and verts now */ - for(efa= em->faces.first; efa; efa= efa->next) - /* we only selected the face flags, and didnt changes edges or verts, fix this now */ - if(!(efa->h) && (efa->f & SELECT)) - EM_select_face(efa, 1); - - EM_select_flush(em); } - } - else if(em->selectmode == SCE_SELECT_FACE) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(!(efa->h) && !(efa->f & SELECT)) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - efa->f |= SELECT; - tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4; + } else if(em->selectmode == SCE_SELECT_FACE) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && !BM_TestHFlag(efa, BM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + + BM_Select(em->bm, efa, 1); } } - - /* Select all edges and verts now */ - for(efa= em->faces.first; efa; efa= efa->next) - /* we only selected the face flags, and didnt changes edges or verts, fix this now */ - if(!(efa->h) && (efa->f & SELECT)) - EM_select_face(efa, 1); - } - else { - for(efa= em->faces.first; efa; efa= efa->next) { - if(!(efa->h) && !(efa->f & SELECT)) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if((efa->v1->f & SELECT)==0) {tf->flag |= TF_SEL1;} - if((efa->v2->f & SELECT)==0) {tf->flag |= TF_SEL2;} - if((efa->v3->f & SELECT)==0) {tf->flag |= TF_SEL3;} - if((efa->v4 && (efa->v4->f & SELECT)==0)) {tf->flag |= TF_SEL4;} - - efa->f |= SELECT; + } else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_HIDDEN) && !BM_TestHFlag(efa, BM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_TestHFlag(l->v, BM_SELECT)==0) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + } + + BM_Select(em->bm, efa, 1); } } - - /* Select all edges and verts now */ - for(efa= em->faces.first; efa; efa= efa->next) - /* we only selected the face flags, and didnt changes edges or verts, fix this now */ - if(!(efa->h) && (efa->f & SELECT)) - EM_select_face(efa, 1); } - + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index dd7c336c98e..83b9752f838 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -731,8 +731,10 @@ static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys) return NULL; } -static PBool p_face_exists(PHandle *handle, PHashKey *vkeys, int i1, int i2, int i3) +int p_face_exists(ParamHandle *phandle, ParamKey *pvkeys, int i1, int i2, int i3) { + PHandle *handle = (PHandle*)phandle; + PHashKey *vkeys = (PHashKey*)pvkeys; PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]); PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index e8dac7346ac..df2fbfa193e 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -33,6 +33,8 @@ ParamHandle *param_construct_begin(void); void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy); +int p_face_exists(ParamHandle *handle, ParamKey *vkeys, int i1, int i2, int i3); + void param_face_add(ParamHandle *handle, ParamKey key, int nverts, diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index ae6836446fa..b1558a98ff6 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -43,17 +43,27 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "BLI_utildefines.h" #include "BLI_math.h" #include "BLI_edgehash.h" #include "BLI_editVert.h" #include "BLI_uvproject.h" #include "BLI_utildefines.h" +#include "BLI_rand.h" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_image.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" + +#include "BLI_math.h" +#include "BLI_edgehash.h" +#include "BLI_editVert.h" +#include "BLI_scanfill.h" +#include "BLI_array.h" +#include "BLI_uvproject.h" #include "PIL_time.h" @@ -75,9 +85,9 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMIter iter; Image *ima; bScreen *sc; ScrArea *sa; @@ -85,15 +95,15 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) SpaceImage *sima; if(ED_uvedit_test(obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return 1; } - if(em && em->faces.first) - EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL); - + if(em && em->bm->totface && !CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) { + BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY); + BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV); + } + if(!ED_uvedit_test(obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return 0; } @@ -123,19 +133,18 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) ED_uvedit_assign_image(scene, obedit, ima, NULL); /* select new UV's */ - for(efa=em->faces.first; efa; efa=efa->next) { - tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uvedit_face_select(scene, efa, tf); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + uvedit_face_select(scene, em, efa); } - BKE_mesh_end_editmesh(obedit->data, em); return 1; } /****************** Parametrizer Conversion ***************/ -static int uvedit_have_selection(Scene *scene, EditMesh *em, short implicit) +static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit) { +#if 0 // BMESH_TODO EditFace *efa; MTFace *tf; @@ -167,25 +176,35 @@ static int uvedit_have_selection(Scene *scene, EditMesh *em, short implicit) } return 0; +#else + (void)scene; + (void)em; + (void)implicit; + return 0; +#endif } -static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel, short correct_aspect) +static ParamHandle *construct_param_handle(Scene *scene, BMEditMesh *em, + short implicit, short fill, short sel, + short correct_aspect) { ParamHandle *handle; - EditFace *efa; - EditEdge *eed; - EditVert *ev; - MTFace *tf; + BMFace *efa; + BMLoop *l; + BMEdge *eed; + BMVert *ev; + BMIter iter, liter; + MTexPoly *tf; int a; handle = param_construct_begin(); if(correct_aspect) { - efa = EM_get_actFace(em, 1); + efa = EDBM_get_actFace(em, 1); if(efa) { + MTexPoly *tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); float aspx, aspy; - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); ED_image_uv_aspect(tf->tpage, &aspx, &aspy); @@ -195,75 +214,119 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp } /* we need the vert indices */ - for(ev= em->verts.first, a=0; ev; ev= ev->next, a++) - ev->tmp.l = a; + a = 0; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_SetIndex(ev, a); + a++; + } - for(efa= em->faces.first; efa; efa= efa->next) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + EditVert *v, *lastv, *firstv; + EditFace *sefa; ParamKey key, vkeys[4]; ParamBool pin[4], select[4]; + BMLoop *ls[3]; + MLoopUV *luvs[3]; float *co[4]; float *uv[4]; - int nverts; + int lsel; if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - if(efa->h) + if(BM_TestHFlag(efa, BM_HIDDEN)) { + continue; + } + } + else { + if((BM_TestHFlag(efa, BM_HIDDEN)) || (sel && BM_TestHFlag(efa, BM_SELECT)==0)) continue; } - else if((efa->h) || (sel && (efa->f & SELECT)==0)) + + tf= (MTexPoly *)CustomData_em_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + lsel = 0; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l)) { + lsel = 1; + break; + } + } + + if (implicit && !lsel) continue; - tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + key = (ParamKey)efa; + + /*scanfill time!*/ + BLI_begin_edgefill(); - if(implicit && - !( uvedit_uv_selected(scene, efa, tf, 0) || - uvedit_uv_selected(scene, efa, tf, 1) || - uvedit_uv_selected(scene, efa, tf, 2) || - (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) ) - ) { - continue; + firstv = lastv = NULL; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + int i; + + v = BLI_addfillvert(l->v->co); + + /*add small random offset*/ + for (i=0; i<3; i++) { + v->co[i] += (BLI_drand()-0.5f)*FLT_EPSILON*50; + } + + v->tmp.p = l; + + if (lastv) { + BLI_addfilledge(lastv, v); + } + + lastv = v; + if (!firstv) + firstv = v; } - key = (ParamKey)efa; - vkeys[0] = (ParamKey)efa->v1->tmp.l; - vkeys[1] = (ParamKey)efa->v2->tmp.l; - vkeys[2] = (ParamKey)efa->v3->tmp.l; - - co[0] = efa->v1->co; - co[1] = efa->v2->co; - co[2] = efa->v3->co; - - uv[0] = tf->uv[0]; - uv[1] = tf->uv[1]; - uv[2] = tf->uv[2]; - - pin[0] = ((tf->unwrap & TF_PIN1) != 0); - pin[1] = ((tf->unwrap & TF_PIN2) != 0); - pin[2] = ((tf->unwrap & TF_PIN3) != 0); - - select[0] = ((uvedit_uv_selected(scene, efa, tf, 0)) != 0); - select[1] = ((uvedit_uv_selected(scene, efa, tf, 1)) != 0); - select[2] = ((uvedit_uv_selected(scene, efa, tf, 2)) != 0); - - if(efa->v4) { - vkeys[3] = (ParamKey)efa->v4->tmp.l; - co[3] = efa->v4->co; - uv[3] = tf->uv[3]; - pin[3] = ((tf->unwrap & TF_PIN4) != 0); - select[3] = (uvedit_uv_selected(scene, efa, tf, 3) != 0); - nverts = 4; + BLI_addfilledge(firstv, v); + + /*mode 2 enables faster handling of tri/quads*/ + BLI_edgefill(2); + for (sefa = fillfacebase.first; sefa; sefa=sefa->next) { + ls[0] = sefa->v1->tmp.p; + ls[1] = sefa->v2->tmp.p; + ls[2] = sefa->v3->tmp.p; + + luvs[0] = CustomData_bmesh_get(&em->bm->ldata, ls[0]->head.data, CD_MLOOPUV); + luvs[1] = CustomData_bmesh_get(&em->bm->ldata, ls[1]->head.data, CD_MLOOPUV); + luvs[2] = CustomData_bmesh_get(&em->bm->ldata, ls[2]->head.data, CD_MLOOPUV); + + vkeys[0] = (ParamKey)BM_GetIndex(ls[0]->v); + vkeys[1] = (ParamKey)BM_GetIndex(ls[1]->v); + vkeys[2] = (ParamKey)BM_GetIndex(ls[2]->v); + + co[0] = ls[0]->v->co; + co[1] = ls[1]->v->co; + co[2] = ls[2]->v->co; + + uv[0] = luvs[0]->uv; + uv[1] = luvs[1]->uv; + uv[2] = luvs[2]->uv; + + pin[0] = (luvs[0]->flag & MLOOPUV_PINNED) != 0; + pin[1] = (luvs[1]->flag & MLOOPUV_PINNED) != 0; + pin[2] = (luvs[2]->flag & MLOOPUV_PINNED) != 0; + + select[0] = uvedit_uv_selected(em, scene, ls[0]) != 0; + select[1] = uvedit_uv_selected(em, scene, ls[1]) != 0; + select[2] = uvedit_uv_selected(em, scene, ls[2]) != 0; + + if (!p_face_exists(handle,vkeys,0,1,2)) + param_face_add(handle, key, 3, vkeys, co, uv, pin, select); } - else - nverts = 3; - param_face_add(handle, key, nverts, vkeys, co, uv, pin, select); + BLI_end_edgefill(); } if(!implicit) { - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->seam) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if(BM_TestHFlag(eed, BM_SEAM)) { ParamKey vkeys[2]; - vkeys[0] = (ParamKey)eed->v1->tmp.l; - vkeys[1] = (ParamKey)eed->v2->tmp.l; + vkeys[0] = (ParamKey)BM_GetIndex(eed->v1); + vkeys[1] = (ParamKey)BM_GetIndex(eed->v2); param_edge_set_seam(handle, vkeys); } } @@ -279,7 +342,7 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp typedef struct MinStretch { Scene *scene; Object *obedit; - EditMesh *em; + BMEditMesh *em; ParamHandle *handle; float blend; double lasttime; @@ -291,13 +354,12 @@ static int minimize_stretch_init(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; MinStretch *ms; int fill_holes= RNA_boolean_get(op->ptr, "fill_holes"); short implicit= 1; if(!uvedit_have_selection(scene, em, implicit)) { - BKE_mesh_end_editmesh(obedit->data, em); return 0; } @@ -489,12 +551,11 @@ static int pack_islands_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; ParamHandle *handle; short implicit= 1; if(!uvedit_have_selection(scene, em, implicit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -513,7 +574,6 @@ static int pack_islands_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -538,12 +598,11 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; ParamHandle *handle; short implicit= 1; if(!uvedit_have_selection(scene, em, implicit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -555,7 +614,6 @@ static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op)) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -577,19 +635,17 @@ static ParamHandle *liveHandle = NULL; void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; short abf = scene->toolsettings->unwrapper == 0; short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; if(!ED_uvedit_test(obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return; } liveHandle = construct_param_handle(scene, em, 0, fillholes, 1, 1); param_lscm_begin(liveHandle, PARAM_TRUE, abf); - BKE_mesh_end_editmesh(obedit->data, em); } void ED_uvedit_live_unwrap_re_solve(void) @@ -620,9 +676,12 @@ void ED_uvedit_live_unwrap_end(short cancel) #define POLAR_ZX 0 #define POLAR_ZY 1 -static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em) +static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, + Object *ob, BMEditMesh *em) { - EditFace *efa; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; float min[3], max[3], *cursx; int around= (v3d)? v3d->around: V3D_CENTER; @@ -632,13 +691,12 @@ static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Ob case V3D_CENTER: /* bounding box center */ min[0]= min[1]= min[2]= 1e20f; max[0]= max[1]= max[2]= -1e20f; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - DO_MINMAX(efa->v1->co, min, max); - DO_MINMAX(efa->v2->co, min, max); - DO_MINMAX(efa->v3->co, min, max); - if(efa->v4) DO_MINMAX(efa->v4->co, min, max); + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_TestHFlag(efa, BM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + DO_MINMAX(l->v->co, min, max); + } } } mid_v3_v3v3(result, min, max); @@ -712,7 +770,7 @@ static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float /* context checks are messy here, making it work in both 3d view and uv editor */ Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; View3D *v3d= CTX_wm_view3d(C); RegionView3D *rv3d= CTX_wm_region_view3d(C); /* common operator properties */ @@ -739,7 +797,6 @@ static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float else uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius); - BKE_mesh_end_editmesh(obedit->data, em); } static void uv_transform_properties(wmOperatorType *ot, int radius) @@ -762,14 +819,17 @@ static void uv_transform_properties(wmOperatorType *ot, int radius) RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "Radius of the sphere or cylinder.", 0.0001f, 100.0f); } -static void correct_uv_aspect(EditMesh *em) +static void correct_uv_aspect(BMEditMesh *em) { - EditFace *efa= EM_get_actFace(em, 1); - MTFace *tf; + BMFace *efa= EDBM_get_actFace(em, 1); + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float scale, aspx= 1.0f, aspy=1.0f; if(efa) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); ED_image_uv_aspect(tf->tpage, &aspx, &aspy); } @@ -779,30 +839,28 @@ static void correct_uv_aspect(EditMesh *em) if(aspx > aspy) { scale= aspy/aspx; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - tf->uv[0][0]= ((tf->uv[0][0]-0.5f)*scale)+0.5f; - tf->uv[1][0]= ((tf->uv[1][0]-0.5f)*scale)+0.5f; - tf->uv[2][0]= ((tf->uv[2][0]-0.5f)*scale)+0.5f; - if(efa->v4) - tf->uv[3][0]= ((tf->uv[3][0]-0.5f)*scale)+0.5f; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if (!BM_TestHFlag(efa, BM_SELECT) || BM_TestHFlag(efa, BM_HIDDEN)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->uv[0] = ((luv->uv[0]-0.5)*scale)+0.5; } } } else { scale= aspx/aspy; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - tf->uv[0][1]= ((tf->uv[0][1]-0.5f)*scale)+0.5f; - tf->uv[1][1]= ((tf->uv[1][1]-0.5f)*scale)+0.5f; - tf->uv[2][1]= ((tf->uv[2][1]-0.5f)*scale)+0.5f; - if(efa->v4) - tf->uv[3][1]= ((tf->uv[3][1]-0.5f)*scale)+0.5f; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if (!BM_TestHFlag(efa, BM_SELECT)||BM_TestHFlag(efa, BM_HIDDEN)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->uv[1] = ((luv->uv[1]-0.5)*scale)+0.5; } } } @@ -817,12 +875,13 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot) RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", "Scale UV coordinates to bounds after unwrapping."); } -static void uv_map_clip_correct(EditMesh *em, wmOperator *op) +static void uv_map_clip_correct(BMEditMesh *em, wmOperator *op) { - EditFace *efa; - MTFace *tf; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; float dx, dy, min[2], max[2]; - int b, nverts; int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect"); int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds"); int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds"); @@ -834,16 +893,13 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op) if(scale_to_bounds) { INIT_MINMAX2(min, max); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - DO_MINMAX2(tf->uv[0], min, max); - DO_MINMAX2(tf->uv[1], min, max); - DO_MINMAX2(tf->uv[2], min, max); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; - if(efa->v4) - DO_MINMAX2(tf->uv[3], min, max); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + DO_MINMAX2(luv->uv, min, max); } } @@ -856,31 +912,28 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op) if(dy > 0.0f) dy= 1.0f/dy; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - nverts= (efa->v4)? 4: 3; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; - for(b=0; b<nverts; b++) { - tf->uv[b][0]= (tf->uv[b][0]-min[0])*dx; - tf->uv[b][1]= (tf->uv[b][1]-min[1])*dy; - } + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->uv[0] = (luv->uv[0]-min[0])*dx; + luv->uv[1] = (luv->uv[1]-min[1])*dy; } } } else if(clip_to_bounds) { /* clipping and wrapping */ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - nverts= (efa->v4)? 4: 3; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; - for(b=0; b<nverts; b++) { - CLAMP(tf->uv[b][0], 0.0f, 1.0f); - CLAMP(tf->uv[b][1], 0.0f, 1.0f); - } + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + CLAMP(luv->uv[0], 0.0f, 1.0f); + CLAMP(luv->uv[1], 0.0f, 1.0f); } } } @@ -891,7 +944,7 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op) /* assumes UV layer is checked, doesn't run update funcs */ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) { - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; ParamHandle *handle; const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; @@ -909,26 +962,21 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) param_flush(handle); param_delete(handle); - - BKE_mesh_end_editmesh(obedit->data, em); } static int unwrap_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; int method = RNA_enum_get(op->ptr, "method"); int fill_holes = RNA_boolean_get(op->ptr, "fill_holes"); int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); short implicit= 0; if(!uvedit_have_selection(scene, em, implicit)) { - BKE_mesh_end_editmesh(obedit->data, em); return 0; } - - BKE_mesh_end_editmesh(obedit->data, em); /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { @@ -982,17 +1030,18 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); Camera *camera= NULL; - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - ARegion *ar= CTX_wm_region(C); + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + ARegion *ar = CTX_wm_region(C); View3D *v3d= CTX_wm_view3d(C); - RegionView3D *rv3d= ar->regiondata; - EditFace *efa; - MTFace *tf; + RegionView3D *rv3d= CTX_wm_region_view3d(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; float rotmat[4][4]; /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -1002,17 +1051,15 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) } if(RNA_boolean_get(op->ptr, "orthographic")) { - uv_map_rotation_matrix(rotmat, ar->regiondata, obedit, 90.0f, 0.0f, 1.0f); + uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - project_from_view_ortho(tf->uv[0], efa->v1->co, rotmat); - project_from_view_ortho(tf->uv[1], efa->v2->co, rotmat); - project_from_view_ortho(tf->uv[2], efa->v3->co, rotmat); - if(efa->v4) - project_from_view_ortho(tf->uv[3], efa->v4->co, rotmat); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + project_from_view_ortho(luv->uv, l->v->co, rotmat); } } } @@ -1020,15 +1067,13 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) struct UvCameraInfo *uci= project_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch); if(uci) { - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - project_from_camera(tf->uv[0], efa->v1->co, uci); - project_from_camera(tf->uv[1], efa->v2->co, uci); - project_from_camera(tf->uv[2], efa->v3->co, uci); - if(efa->v4) - project_from_camera(tf->uv[3], efa->v4->co, uci); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + project_from_camera(luv->uv, l->v->co, uci); } } @@ -1038,15 +1083,13 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) else { copy_m4_m4(rotmat, obedit->obmat); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; - project_from_view(tf->uv[0], efa->v1->co, rv3d->persmat, rotmat, ar->winx, ar->winy); - project_from_view(tf->uv[1], efa->v2->co, rv3d->persmat, rotmat, ar->winx, ar->winy); - project_from_view(tf->uv[2], efa->v3->co, rv3d->persmat, rotmat, ar->winx, ar->winy); - if(efa->v4) - project_from_view(tf->uv[3], efa->v4->co, rv3d->persmat, rotmat, ar->winx, ar->winy); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + project_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy); } } } @@ -1056,7 +1099,6 @@ static int uv_from_view_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1092,38 +1134,74 @@ static int reset_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + BLI_array_declare(uvs); + float **uvs = NULL; + int i; /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; + + BLI_array_empty(uvs); + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + BLI_array_growone(uvs); - tf->uv[0][0]= 0.0f; - tf->uv[0][1]= 0.0f; - - tf->uv[1][0]= 1.0f; - tf->uv[1][1]= 0.0f; + uvs[i++] = luv->uv; + } + + if (i == 3) { + uvs[0][0] = 0.0; + uvs[0][1] = 0.0; - tf->uv[2][0]= 1.0f; - tf->uv[2][1]= 1.0f; + uvs[1][0] = 1.0; + uvs[1][1] = 0.0; + + uvs[2][0] = 1.0; + uvs[2][1] = 1.0; + } else if (i == 4) { + uvs[0][0] = 0.0; + uvs[0][1] = 0.0; - tf->uv[3][0]= 0.0f; - tf->uv[3][1]= 1.0f; + uvs[1][0] = 1.0; + uvs[1][1] = 0.0; + + uvs[2][0] = 1.0; + uvs[2][1] = 1.0; + + uvs[3][0] = 0.0; + uvs[3][1] = 1.0; + /*make sure we ignore 2-sided faces*/ + } else if (i > 2) { + float fac = 0.0f, dfac = 1.0f / (float)efa->len; + + dfac *= M_PI*2; + + for (i=0; i<efa->len; i++) { + uvs[i][0] = sin(fac); + uvs[i][1] = cos(fac); + + fac += dfac; + } } } DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); + + BLI_array_free(uvs); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1155,55 +1233,71 @@ static void uv_sphere_project(float target[2], float source[3], float center[3], target[0] -= 1.0f; } -static void uv_map_mirror(EditFace *efa, MTFace *tf) +static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf)) { + BMLoop *l; + BMIter liter; + MLoopUV *luv; + BLI_array_declare(uvs); + float **uvs = NULL; float dx; - int nverts, i, mi; + int i, mi; - nverts= (efa->v4)? 4: 3; + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + BLI_array_growone(uvs); + + uvs[i] = luv->uv; + i++; + } mi = 0; - for(i=1; i<nverts; i++) - if(tf->uv[i][0] > tf->uv[mi][0]) + for(i=1; i<efa->len; i++) + if(uvs[i][0] > uvs[mi][0]) mi = i; - for(i=0; i<nverts; i++) { + for(i=0; i<efa->len; i++) { if(i != mi) { - dx = tf->uv[mi][0] - tf->uv[i][0]; - if(dx > 0.5f) tf->uv[i][0] += 1.0f; + dx = uvs[mi][0] - uvs[i][0]; + if(dx > 0.5f) uvs[i][0] += 1.0f; } } + + BLI_array_free(uvs); } static int sphere_project_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float center[3], rotmat[4][4]; /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } uv_map_transform(C, op, center, rotmat); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; - uv_sphere_project(tf->uv[0], efa->v1->co, center, rotmat); - uv_sphere_project(tf->uv[1], efa->v2->co, center, rotmat); - uv_sphere_project(tf->uv[2], efa->v3->co, center, rotmat); - if(efa->v4) - uv_sphere_project(tf->uv[3], efa->v4->co, center, rotmat); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - uv_map_mirror(efa, tf); + uv_sphere_project(luv->uv, l->v->co, center, rotmat); } + + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + uv_map_mirror(em, efa, tf); } uv_map_clip_correct(em, op); @@ -1211,7 +1305,6 @@ static int sphere_project_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1251,31 +1344,33 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float center[3], rotmat[4][4]; /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } uv_map_transform(C, op, center, rotmat); - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - uv_cylinder_project(tf->uv[0], efa->v1->co, center, rotmat); - uv_cylinder_project(tf->uv[1], efa->v2->co, center, rotmat); - uv_cylinder_project(tf->uv[2], efa->v3->co, center, rotmat); - if(efa->v4) - uv_cylinder_project(tf->uv[3], efa->v4->co, center, rotmat); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); - uv_map_mirror(efa, tf); + uv_cylinder_project(luv->uv, l->v->co, center, rotmat); } + + uv_map_mirror(em, efa, tf); } uv_map_clip_correct(em, op); @@ -1283,7 +1378,6 @@ static int cylinder_project_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1309,15 +1403,17 @@ static int cube_project_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); - EditFace *efa; - MTFace *tf; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MTexPoly *tf; + MLoopUV *luv; float no[3], cube_size, *loc, dx, dy; int cox, coy; /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_CANCELLED; } @@ -1327,41 +1423,40 @@ static int cube_project_exec(bContext *C, wmOperator *op) /* choose x,y,z axis for projection depending on the largest normal * component, but clusters all together around the center of map. */ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->f & SELECT) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - normal_tri_v3( no,efa->v1->co, efa->v2->co, efa->v3->co); - - no[0]= fabs(no[0]); - no[1]= fabs(no[1]); - no[2]= fabs(no[2]); - - cox=0; coy= 1; - if(no[2]>=no[0] && no[2]>=no[1]); - else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2; - else { cox= 1; coy= 2; } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int first=1; + + tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + if (!BM_TestHFlag(efa, BM_SELECT)) + continue; + + VECCOPY(no, efa->no); + + no[0]= fabs(no[0]); + no[1]= fabs(no[1]); + no[2]= fabs(no[2]); + + cox=0; coy= 1; + if(no[2]>=no[0] && no[2]>=no[1]); + else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2; + else { cox= 1; coy= 2; } + + dx = dy = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + + luv->uv[0] = 0.5f+0.5f*cube_size*(loc[cox] + l->v->co[cox]); + luv->uv[1] = 0.5f+0.5f*cube_size*(loc[coy] + l->v->co[coy]); - tf->uv[0][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v1->co[cox]); - tf->uv[0][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v1->co[coy]); - dx = floor(tf->uv[0][0]); - dy = floor(tf->uv[0][1]); - tf->uv[0][0] -= dx; - tf->uv[0][1] -= dy; - tf->uv[1][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v2->co[cox]); - tf->uv[1][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v2->co[coy]); - tf->uv[1][0] -= dx; - tf->uv[1][1] -= dy; - tf->uv[2][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v3->co[cox]); - tf->uv[2][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v3->co[coy]); - tf->uv[2][0] -= dx; - tf->uv[2][1] -= dy; - - if(efa->v4) { - tf->uv[3][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v4->co[cox]); - tf->uv[3][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v4->co[coy]); - tf->uv[3][0] -= dx; - tf->uv[3][1] -= dy; + if (first) { + dx = floor(luv->uv[0]); + dy = floor(luv->uv[1]); + first = 0; } + + + luv->uv[0] -= dx; + luv->uv[1] -= dy; } } @@ -1370,7 +1465,6 @@ static int cube_project_exec(bContext *C, wmOperator *op) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } |