diff options
author | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-02-21 05:40:04 +0400 |
---|---|---|
committer | Tamito Kajiyama <rd6t-kjym@asahi-net.or.jp> | 2012-02-21 05:40:04 +0400 |
commit | 69289c978eace478bf992517473960d540895815 (patch) | |
tree | 493d2c9bec32f761468b082fbbb015c748b71685 /source/blender/editors | |
parent | 5f093d6a5867a365900158fcca71296852787aac (diff) | |
parent | be674afdadaa1ab966147755e224e8bbda6807db (diff) |
Merged changes in the trunk up to revision 44266 (including BMesh).
Freestyle edge/face marks were ported to BMesh.
Conflicts resolved:
source/blender/editors/mesh/editface.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_meshdata_types.h
source/blender/blenkernel/intern/editderivedmesh.c
Diffstat (limited to 'source/blender/editors')
119 files changed, 17965 insertions, 23296 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 ded82b3dfb7..b85a13ced85 100644 --- a/source/blender/editors/armature/SConscript +++ b/source/blender/editors/armature/SConscript @@ -5,6 +5,7 @@ sources = env.Glob('*.c') incs = '../include ../../blenfont ../../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'] == 'linux': diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index e8c9a2cf4da..e16063b50c6 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -2126,7 +2126,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; @@ -2159,7 +2159,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; diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 005f5f6da95..bb493d3fec4 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -41,14 +41,15 @@ #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 "BLI_string.h" #include "BKE_DerivedMesh.h" #include "BKE_modifier.h" +#include "BKE_mesh.h" #ifdef RIGID_DEFORM @@ -651,10 +652,12 @@ static float heat_limit_weight(float weight) void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, const char **err_str) { LaplacianSystem *sys; - MFace *mface; + MPoly *mp; + MLoop *ml; + MFace *mf; float solution, weight; int *vertsflipped = NULL, *mask= NULL; - int a, totface, j, bbone, firstsegment, lastsegment; + int a, tottri, j, bbone, firstsegment, lastsegment; MVert *mvert = me->mvert; int use_vert_sel= FALSE; @@ -669,33 +672,34 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, mask= MEM_callocN(sizeof(int)*me->totvert, "heat_bone_weighting mask"); } - for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) { - totface++; - if(mface->v4) totface++; - + for(a = 0, mp=me->mpoly; a < me->totpoly; mp++, a++) { /* (added selectedVerts content for vertex mask, they used to just equal 1) */ if(use_vert_sel) { - mask[mface->v1]= (mvert[mface->v1].flag & SELECT) != 0; - mask[mface->v2]= (mvert[mface->v2].flag & SELECT) != 0; - mask[mface->v3]= (mvert[mface->v3].flag & SELECT) != 0; - if(mface->v4) { - mask[mface->v4]= (mvert[mface->v4].flag & SELECT) != 0; + for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { + if (use_vert_sel) { + mask[ml->v] = (mvert[ml->v].flag & SELECT) != 0; + } } } else if (use_face_sel) { - if (mface->flag & ME_FACE_SEL) { - mask[mface->v1]= 1; - mask[mface->v2]= 1; - mask[mface->v3]= 1; - if(mface->v4) { - mask[mface->v4]= 1; + if (mp->flag & ME_FACE_SEL) { + for (j = 0, ml = me->mloop + mp->loopstart; j < mp->totloop; j++, ml++) { + mask[ml->v] = 1; } } } } + /* bone heat needs triangulated faces */ + BKE_mesh_tessface_ensure(me); + + for(tottri = 0, a = 0, mf = me->mface; a < me->totface; mf++, a++) { + tottri++; + if(mf->v4) tottri++; + } + /* create laplacian */ - sys = laplacian_system_construct_begin(me->totvert, totface, 1); + sys = laplacian_system_construct_begin(me->totvert, tottri, 1); sys->heat.mface= me->mface; sys->heat.totface= me->totface; @@ -715,7 +719,7 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource, for(a=0; a<me->totvert; a++) vertsflipped[a] = mesh_get_x_mirror_vert(ob, a); } - + /* compute weights per bone */ for(j=0; j<numsource; j++) { if(!selected[j]) @@ -1188,8 +1192,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); @@ -1879,9 +1883,9 @@ 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); + int totface= dm->getNumTessFaces(dm); float solution, weight; int a, tottri, j, thrownerror = 0; diff --git a/source/blender/editors/armature/reeb.c b/source/blender/editors/armature/reeb.c index bcdda8e9eb1..cb0857d41e6 100644 --- a/source/blender/editors/armature/reeb.c +++ b/source/blender/editors/armature/reeb.c @@ -52,6 +52,7 @@ //#include "BIF_toolbox.h" //#include "BIF_graphics.h" +#include "BKE_mesh.h" //#include "blendef.h" @@ -3377,9 +3378,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; @@ -3475,7 +3479,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 5c762ca61cc..495c8a8f842 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -6461,12 +6461,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 */ @@ -6861,10 +6861,9 @@ 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 *cu_v) { - Object *obedit= obe; - Curve *cu= (Curve*)obedit->data; + Curve *cu= cu_v; UndoCurve *undoCurve= ucu; ListBase *undobase= &undoCurve->nubase; ListBase *editbase= curve_editnurbs(cu); @@ -6907,14 +6906,15 @@ static void undoCurve_to_editCurve(void *ucu, void *obe) cu->lastsel= lastsel; cu->actnu= undoCurve->actnu; - + /* BMESH_TODO */ +#if 0 ED_curve_updateAnimPaths(obedit); +#endif } -static void *editCurve_to_undoCurve(void *obe) +static void *editCurve_to_undoCurve(void *UNUSED(edata), void *cu_v) { - Object *obedit= obe; - Curve *cu= (Curve*)obedit->data; + Curve *cu= cu_v; ListBase *nubase= 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 493fc6e277b..efde93b4ad7 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -1739,7 +1739,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; @@ -1756,7 +1756,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/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 6e289fb5a2a..12524a9fd2e 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -61,6 +61,16 @@ 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 ToolSettings; struct Material; struct Object; struct rcti; @@ -85,111 +95,148 @@ struct rcti; #define B_FRACTAL 0x2000 #define B_SPHERE 0x4000 -/* meshtools.c */ - -intptr_t mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode); -int 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); +intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode); +int mesh_mirrtopo_table(struct Object *ob, char mode); -int join_mesh_exec(struct bContext *C, struct wmOperator *op); -int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); +/* bmeshutils.c */ -/* mesh_ops.c */ -void ED_operatortypes_mesh(void); -void ED_operatormacros_mesh(void); -void ED_keymap_mesh(struct wmKeyConfig *keyconf); +/* + [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, const short use_select); /* note, replaces EM_cache_x_mirror_vert in trunk */ + +/*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_ClearMirrorVert(struct BMEditMesh *em, struct BMVert *v); +void EDBM_EndMirrorCache(struct BMEditMesh *em); +void EDBM_ApplyMirrorCache(struct BMEditMesh *em, const int sel_from, const int sel_to); + +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); + +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_select_more(struct BMEditMesh *em); +void EDBM_select_less(struct BMEditMesh *em); + +int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese); + +void EDBM_selectmode_flush_ex(struct BMEditMesh *em, int selectmode); +void EDBM_selectmode_flush(struct BMEditMesh *em); + +void EDBM_deselect_flush(struct BMEditMesh *em); +void EDBM_select_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); +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); -/* 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_hide_mesh(struct BMEditMesh *em, int swap); +void EDBM_reveal_mesh(struct BMEditMesh *em); -void recalc_editnormals(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 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); +void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select); -void undo_push_mesh(struct bContext *C, const char *name); +int EDBM_select_interior_faces(struct BMEditMesh *em); -void paintvert_flush_flags(struct Object *ob); -void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags); +struct UvElementMap *EDBM_make_uv_element_map(struct BMEditMesh *em, int selected, int doIslands); +void EDBM_free_uv_element_map(struct UvElementMap *vmap); -/* editmesh_lib.c */ +void EDBM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name); +void EDBM_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_select_swap(struct BMEditMesh *em); /* exported for UV */ -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); +int EDBM_texFaceCheck(struct BMEditMesh *em); +struct MTexPoly *EDBM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, int sloppy); - /* 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); +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 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); +void EDBM_toggle_select_all(struct BMEditMesh *em); +void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag); +void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); +void EDBM_select_mirrored(struct Object *obedit, struct BMEditMesh *em, int extend); +void EDBM_automerge(struct Scene *scene, struct Object *ob, int update); -struct UvElementMap *EM_make_uv_element_map(struct EditMesh *em, int selected, int doIslands); -void EM_free_uv_element_map(struct UvElementMap *vmap); +/* editmesh_mods.c */ +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs; -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); @@ -199,6 +246,9 @@ int paintface_minmax(struct Object *ob, float *min, float *max); void paintface_hide(struct Object *ob, const int unselected); void paintface_reveal(struct Object *ob); +void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags); +void paintvert_flush_flags(struct Object *ob); + /* object_vgroup.c */ #define WEIGHT_REPLACE 1 @@ -221,18 +271,26 @@ 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); +void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count); +void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count); void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int count); @@ -246,10 +304,16 @@ void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges); int ED_mesh_uv_texture_add(struct bContext *C, struct Mesh *me, const char *name, int active_set); int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh *me); +int ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me); 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); int ED_mesh_color_remove_named(struct bContext *C, struct Object *ob, struct Mesh *me, const char *name); +void EDBM_selectmode_to_scene(struct bContext *C); +void EDBM_ClearMesh(struct BMEditMesh *em); + +#include "../mesh/editmesh_bvh.h" + /* mirrtopo */ typedef struct MirrTopoStore_t { @@ -264,9 +328,18 @@ void ED_mesh_mirrtopo_init(struct Mesh *me, const int ob_mode, MirrTopoStore_t * const short skip_em_vert_array_init); void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); +#define SUBDIV_SELECT_ORIG 0 +#define SUBDIV_SELECT_INNER 1 +#define SUBDIV_SELECT_INNER_SEL 2 +#define SUBDIV_SELECT_LOOPCUT 3 + +/* edge subdivide corner cut types */ +#define SUBDIV_CORNER_PATH 0 +#define SUBDIV_CORNER_INNERVERT 1 +#define SUBDIV_CORNER_FAN 2 + #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 c808e63d320..3e78a5649e5 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -127,8 +127,8 @@ 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); +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); diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index d082f3449fa..9bde252e776 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -38,7 +38,7 @@ struct ARegion; struct uiBlock; struct wmOperator; struct wmOperatorType; -struct EditMesh; +struct BMEditMesh; struct Mesh; /* ed_util.c */ @@ -70,8 +70,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 *)); @@ -79,7 +79,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 4d8bceb044f..6c74eea3a5e 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -42,6 +42,10 @@ struct SpaceImage; struct bContext; struct bNode; struct wmKeyConfig; +struct BMEditMesh; +struct BMLoop; +struct BMFace; +struct MTexPoly; /* uvedit_ops.c */ void ED_operatortypes_uvedit(void); @@ -57,18 +61,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 63c03cd2963..2d4e267ba80 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -38,8 +38,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; @@ -190,9 +193,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); @@ -219,12 +222,13 @@ int ED_view3d_viewplane_get(struct View3D *v3d, struct RegionView3D *rv3d, int w void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]); void ED_view3d_project_float(const struct ARegion *a, const float vec[3], float adr[2], 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 no_shift); +void ED_view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]); void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, float size_r[2]); /* drawobject.c iterators */ -void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, eV3DClipTest 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, eV3DClipTest 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, eV3DClipTest 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, eV3DClipTest 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 ec5ae99755d..2d6d5cd235e 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/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index ce0362759dc..3e7049b5b1e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2124,7 +2124,7 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe name= (namebuf)? namebuf: ""; /* hardcoded types */ - if(itemptr->type == &RNA_MeshTextureFaceLayer || itemptr->type == &RNA_MeshColorLayer) { + if(itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) { uiItemL(sub, name, icon); uiBlockSetEmboss(block, UI_EMBOSSN); uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render", 0, 0, 0, 0, 0, NULL); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 7849b71307b..9d2229b52f4 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -20,9 +20,11 @@ set(INC ../include + ../uvedit ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../imbuf ../../makesdna ../../makesrna @@ -36,18 +38,20 @@ set(INC_SYS ) set(SRC + bmesh_select.c + bmesh_selecthistory.c + bmesh_tools.c + bmesh_utils.c editface.c - editmesh.c editmesh_add.c - editmesh_lib.c - editmesh_loop.c - editmesh_mods.c - editmesh_tools.c + editmesh_bvh.c + knifetool.c loopcut.c mesh_data.c mesh_ops.c meshtools.c + editmesh_bvh.h mesh_intern.h ) diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript index 6546a44adeb..8142faf67a1 100644 --- a/source/blender/editors/mesh/SConscript +++ b/source/blender/editors/mesh/SConscript @@ -9,6 +9,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'] == 'linux': 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..89bccf8f00e --- /dev/null +++ b/source/blender/editors/mesh/bmesh_select.c @@ -0,0 +1,2767 @@ +/* + * ***** 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 ***** + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_array.h" +#include "BLI_smallhash.h" +#include "BLI_heap.h" + +#include "BKE_context.h" +#include "BKE_displist.h" +#include "BKE_depsgraph.h" +#include "BKE_report.h" +#include "BKE_paint.h" +#include "BKE_tessmesh.h" + +#include "IMB_imbuf_types.h" +#include "IMB_imbuf.h" + +#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 "BIF_gl.h" + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_mesh_types.h" + +#include "mesh_intern.h" + + +/* ****************************** MIRROR **************** */ + +void EDBM_select_mirrored(Object *UNUSED(obedit), BMEditMesh *em, int extend) +{ + BMVert *v1, *v2; + BMIter iter; + + BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(v1, BM_ELEM_SELECT) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN)) { + BM_elem_flag_disable(v1, BM_ELEM_TAG); + } + else { + BM_elem_flag_enable(v1, BM_ELEM_TAG); + } + } + + EDBM_CacheMirrorVerts(em, TRUE); + + if (!extend) + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(v1, BM_ELEM_TAG) || BM_elem_flag_test(v1, BM_ELEM_HIDDEN)) + continue; + + v2 = EDBM_GetMirrorVert(em, v1); + if (v2 && !BM_elem_flag_test(v2, BM_ELEM_HIDDEN)) { + BM_elem_select_set(em->bm, v2, TRUE); + } + } + + EDBM_EndMirrorCache(em); +} + +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_op_callf(em->bm, "automerge verts=%hv dist=%f", BM_ELEM_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 if (paint_vertsel_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 if (paint_vertsel_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_elem_flag_test(eve, BM_ELEM_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 = BM_vert_at_index(em->bm, index - 1); + + if (eve && BM_elem_flag_test(eve, BM_ELEM_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 = BM_vert_at_index(vc->em->bm, 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 && BM_vert_at_index(vc->em->bm, 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, V3D_CLIP_TEST_RV3D_CLIPPING); + + if (data.dist > 3) { + data.pass = 1; + mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING); + } + + *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_elem_flag_test(eed, BM_ELEM_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 = BM_edge_at_index(vc->em->bm, 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 = BM_face_at_index(vc->em->bm, 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 && BM_face_at_index(vc->em->bm, 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_ELEM_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", ""}, + {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""}, + + {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", ""}, + {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""}, + + {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_ELEM_SELECT, type, thresh); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + /* select the output */ + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ELEM_SELECT, BM_ALL); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_ELEM_SELECT, type, thresh); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + /* select the output */ + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ELEM_SELECT, BM_ALL); + EDBM_selectmode_flush(em); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_ELEM_SELECT, type, thresh); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* clear the existing selection */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + /* select the output */ + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_ALL); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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); + + if (obedit && obedit->type == OB_MESH) { + EnumPropertyItem *item = NULL; + int a, totitem = 0; + 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_FREESTYLE; 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 *************** */ + +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, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + h = BMW_begin(&walker, start); + for ( ; h; h = BMW_step(&walker)) { + if (!select) { + BM_select_history_remove(bm, h); + } + BM_elem_select_set(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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; eed = BM_iter_step(&iter)) { + + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + totedgesel++; + } + } + + + edarray = MEM_mallocN(sizeof(BMEdge *)*totedgesel,"edge array"); + edindex = 0; + + for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; + eed = BM_iter_step(&iter)) + { + + if (BM_elem_flag_test(eed, BM_ELEM_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 = TRUE; + 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_flag_disable_all(em, BM_ELEM_SELECT); + } + + if (BM_elem_flag_test(eed, BM_ELEM_SELECT) == 0) { + select = TRUE; + } + else if (extend) { + select = FALSE; + } + + 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) { + if (em->selectmode & SCE_SELECT_VERTEX) { + /* TODO: would be nice if the edge vertex chosen here + * was the one closer to the selection pointer, instead + * of arbitrarily selecting the first one */ + EDBM_store_selection(em, eed->v1); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + EDBM_store_selection(em, eed); + } + /* TODO: would be nice if the nearest face that + * belongs to the selected edge could be set to + * active here in face select mode */ + } + + 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"; + ot->description = "Select a loop"; + + /* api callbacks */ + ot->invoke = mesh_select_loop_invoke; + ot->poll = ED_operator_editmesh_region_view3d; + 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", "Extend the selection"); + RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "Select ring"); +} + +void MESH_OT_edgering_select (wmOperatorType *ot) +{ + /* description */ + ot->name = "Edge Ring Select"; + ot->idname = "MESH_OT_edgering_select"; + ot->description = "Select an edge ring"; + + /* callbacks */ + ot->invoke = mesh_select_loop_invoke; + ot->poll = ED_operator_editmesh_region_view3d; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); + RNA_def_boolean(ot->srna, "ring", 1, "Select Ring", "Select ring"); +} + +/* ******************* edgetag_shortest_path and helpers ****************** */ + +static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BMVert *v) +{ + BMVert *v1 = (e1->v1 == v) ? e1->v2 : e1->v1; + BMVert *v2 = (e2->v1 == v) ? e2->v2 : e2->v1; + float cost, d1[3], d2[3]; + + /* The cost is based on the simple sum of the length of the two edgees... */ + sub_v3_v3v3(d1, v->co, v1->co); + sub_v3_v3v3(d2, v2->co, v->co); + cost = len_v3(d1); + cost += len_v3(d2); + + /*.but is biased to give higher values to sharp turns, so that it will take + * paths with fewer "turns" when selecting between equal-weighted paths between + * the two edges */ + cost = cost + 0.5f * cost * (2.0f - sqrt(fabs(dot_v3v3(d1, d2)))); + + return cost; +} + +static void edgetag_add_adjacent(BMEditMesh *em, SmallHash *visithash, Heap *heap, int mednum, int vertnum, + int *nedges, int *edges, int *prevedge, float *cost) +{ + BMEdge *e1 = EDBM_get_edge_for_index(em, mednum); + BMVert *v = EDBM_get_vert_for_index(em, vertnum); + int startadj, endadj = nedges[vertnum + 1]; + + for (startadj = nedges[vertnum]; startadj < endadj; startadj++) { + int adjnum = edges[startadj]; + BMEdge *e2 = EDBM_get_edge_for_index(em, adjnum); + float newcost; + float cutcost; + + if (BLI_smallhash_haskey(visithash, (uintptr_t)e2)) + continue; + + cutcost = edgetag_cut_cost(em, e1, e2, v); + newcost = cost[mednum] + cutcost; + + if (cost[adjnum] > newcost) { + cost[adjnum] = newcost; + prevedge[adjnum] = mednum; + BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum)); + } + } +} + +static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val) +{ + + switch (scene->toolsettings->edge_mode) { + case EDGE_MODE_SELECT: + BM_elem_select_set(em->bm, e, val); + break; + case EDGE_MODE_TAG_SEAM: + if (val) {BM_elem_flag_enable(e, BM_ELEM_SEAM);} + else {BM_elem_flag_disable(e, BM_ELEM_SEAM);} + break; + case EDGE_MODE_TAG_SHARP: + if (val) {BM_elem_flag_enable(e, BM_ELEM_SEAM);} + else {BM_elem_flag_disable(e, BM_ELEM_SEAM);} + break; + case EDGE_MODE_TAG_FREESTYLE: + if (val) {BM_elem_flag_enable(e, BM_ELEM_FREESTYLE);} + else {BM_elem_flag_disable(e, BM_ELEM_FREESTYLE);} + break; + case EDGE_MODE_TAG_CREASE: + { + float *crease = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_CREASE); + + if (val) {*crease = 1.0f;} + else {*crease = 0.0f;} + break; + } + case EDGE_MODE_TAG_BEVEL: + { + float *bweight = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_BWEIGHT); + + if (val) {*bweight = 1.0f;} + else {*bweight = 0.0f;} + break; + } + } +} + +static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e) +{ + switch (scene->toolsettings->edge_mode) { + case EDGE_MODE_SELECT: + return BM_elem_flag_test(e, BM_ELEM_SELECT) ? 1 : 0; + case EDGE_MODE_TAG_SEAM: + return BM_elem_flag_test(e, BM_ELEM_SEAM); + case EDGE_MODE_TAG_SHARP: + return !BM_elem_flag_test(e, BM_ELEM_SMOOTH); + case EDGE_MODE_TAG_FREESTYLE: + return !BM_elem_flag_test(e, BM_ELEM_FREESTYLE); + case EDGE_MODE_TAG_CREASE: + return BM_elem_float_data_get(&em->bm->edata, e, CD_CREASE) ? 1 : 0; + case EDGE_MODE_TAG_BEVEL: + return BM_elem_float_data_get(&em->bm->edata, e, CD_BWEIGHT) ? 1 : 0; + } + return 0; +} + +static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target) +{ + BMEdge *e; + BMIter iter; + Heap *heap; + SmallHash visithash; + float *cost; + int i, totvert = 0, totedge = 0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0; + int targetnum; + + BLI_smallhash_init(&visithash); + + /* note, would pass BM_EDGE except we are looping over all edges anyway */ + BM_mesh_elem_index_ensure(em->bm, BM_VERT /* | BM_EDGE */); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + e->oflags[0].f = 0; /* XXX, whats this for, BMESH_TODO, double check if this is needed */ + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL); + } + + BM_elem_index_set(e, totedge); /* set_inline */ + totedge++; + } + em->bm->elem_index_dirty &= ~BM_EDGE; + + /* alloc */ + totvert = em->bm->totvert; + nedges = MEM_callocN(sizeof(*nedges) * totvert + 1, "SeamPathNEdges"); + edges = MEM_mallocN(sizeof(*edges) * totedge * 2, "SeamPathEdges"); + prevedge = MEM_mallocN(sizeof(*prevedge) * totedge, "SeamPathPrevious"); + cost = MEM_mallocN(sizeof(*cost) * totedge, "SeamPathCost"); + + /* count edges, compute adjacent edges offsets and fill adjacent */ + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + nedges[BM_elem_index_get(e->v1) + 1]++; + nedges[BM_elem_index_get(e->v2) + 1]++; + } + + for (i = 1; i < totvert; i++) { + int newswap = nedges[i + 1]; + nedges[i + 1] = nedgeswap + nedges[i]; + nedgeswap = newswap; + } + nedges[0] = nedges[1] = 0; + + i = 0; + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + edges[nedges[BM_elem_index_get(e->v1) + 1]++] = i; + edges[nedges[BM_elem_index_get(e->v2) + 1]++] = i; + + cost[i] = 1e20f; + prevedge[i] = -1; + i++; + } + + /* + * Arrays are now filled as follows: + * + * nedges[n] = sum of the # of edges incident to all vertices numbered 0 thru n - 1 + * edges[edges[n]..edges[n - 1]] = the indices of of the edges incident to vertex n + * + * As the search continues, prevedge[n] will be the previous edge on the shortest + * path found so far to edge n. The visitedhash will of course contain entries + * for edges that have been visited, cost[n] will contain the length of the shortest + * path to edge n found so far, Finally, heap is a priority heap which is built on the + * the same data as the cost arry, but inverted: it is a worklist of edges prioritized + * by the shortest path found so far to the edge. + */ + +#if 0 /* UNUSED */ /* this block does nothing, not sure why its here? - campbell */ + for (i = 0; i < totvert; i++) { + int start = nedges[i], end = nedges[i + 1], cur; + for (cur = start; cur < end; cur++) { + BMEdge *e = EDBM_get_edge_for_index(em, edges[cur]); + } + } +#endif + + /* regular dijkstra shortest path, but over edges instead of vertices */ + heap = BLI_heap_new(); + BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_elem_index_get(source))); + cost[BM_elem_index_get(source)] = 0.0f; + EDBM_init_index_arrays(em, 1, 1, 0); + targetnum = BM_elem_index_get(target); + + while (!BLI_heap_empty(heap)) { + mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); + e = EDBM_get_edge_for_index(em, mednum); + + if (mednum == targetnum) + break; + + if (BLI_smallhash_haskey(&visithash, (uintptr_t)e)) + continue; + + BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL); + + edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v1), nedges, edges, prevedge, cost); + edgetag_add_adjacent(em, &visithash, heap, mednum, BM_elem_index_get(e->v2), nedges, edges, prevedge, cost); + } + + if (mednum == targetnum) { + short allseams = 1; + + /* Check whether the path is already completely tagged. + * if it is, the tags will be cleared instead of set. */ + mednum = targetnum; + do { + e = EDBM_get_edge_for_index(em, mednum); + if (!edgetag_context_check(scene, em, e)) { + allseams = 0; + break; + } + mednum = prevedge[mednum]; + } while (mednum != BM_elem_index_get(source)); + + /* Follow path back and source and add or remove tags */ + mednum = targetnum; + do { + e = EDBM_get_edge_for_index(em, mednum); + if (allseams) + edgetag_context_set(em, scene, e, 0); + else + edgetag_context_set(em, scene, e, 1); + mednum = prevedge[mednum]; + } while (mednum != -1); + } + + EDBM_free_index_arrays(em); + MEM_freeN(nedges); + MEM_freeN(edges); + MEM_freeN(prevedge); + MEM_freeN(cost); + BLI_heap_free(heap, NULL); + BLI_smallhash_release(&visithash); + + return 1; +} + +/* ******************* 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, int mval[2]) +{ + Object *ob = CTX_data_edit_object(C); + ViewContext vc; + BMEditMesh *em; + BMEdge *e; + int dist = 50; + + em_setup_viewcontext(C, &vc); + vc.mval[0] = mval[0]; + vc.mval[1] = mval[1]; + em = vc.em; + + e = EDBM_findnearestedge(&vc, &dist); + if (e) { + Mesh *me = vc.obedit->data; + int path = 0; + + if (em->bm->selected.last) { + BMEditSelection *ese = em->bm->selected.last; + + if (ese && ese->htype == BM_EDGE) { + BMEdge *e_act; + e_act = (BMEdge *)ese->data; + if (e_act != e) { + if (edgetag_shortest_path(vc.scene, em, e_act, e)) { + EDBM_remove_selection(em, e_act); + path = 1; + } + } + } + } + if (path == 0) { + int act = (edgetag_context_check(vc.scene, em, e) == 0); + edgetag_context_set(em, vc.scene, e, act); /* switch the edge option */ + } + + EDBM_selectmode_flush(em); + + /* even if this is selected it may not be in the selection list */ + if (edgetag_context_check(vc.scene, em, e) == 0) + EDBM_remove_selection(em, e); + else + EDBM_store_selection(em, e); + + /* 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; + case EDGE_MODE_TAG_FREESTYLE: + me->drawflag |= ME_DRAW_FREESTYLE_EDGE; + break; + } + + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->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; +} + +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_flag_disable_all(vc.em, BM_ELEM_SELECT); + + if (efa) { + /* set the last selected face */ + BM_active_face_set(vc.em->bm, efa); + + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + EDBM_store_selection(vc.em, efa); + BM_elem_select_set(vc.em->bm, efa, TRUE); + } + else if (extend) { + EDBM_remove_selection(vc.em, efa); + BM_elem_select_set(vc.em->bm, efa, FALSE); + } + } + else if (eed) { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + EDBM_store_selection(vc.em, eed); + BM_elem_select_set(vc.em->bm, eed, TRUE); + } + else if (extend) { + EDBM_remove_selection(vc.em, eed); + BM_elem_select_set(vc.em->bm, eed, FALSE); + } + } + else if (eve) { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + EDBM_store_selection(vc.em, eve); + BM_elem_select_set(vc.em->bm, eve, TRUE); + } + else if (extend) { + EDBM_remove_selection(vc.em, eve); + BM_elem_select_set(vc.em->bm, eve, FALSE); + } + } + + 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->htype == 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->htype == 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->htype == 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) { + EDBM_select_flush(em); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + /* deselect vertices, and select again based on edge select */ + eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve = BM_iter_step(&iter)) BM_elem_select_set(em->bm, eve, FALSE); + + eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed = BM_iter_step(&iter)) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_elem_select_set(em->bm, eed, TRUE); + } + } + + /* 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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed = BM_iter_step(&iter)) BM_elem_select_set(em->bm, eed, FALSE); + + efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa = BM_iter_step(&iter)) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_elem_select_set(em->bm, efa, TRUE); + } + } + } +} + +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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed = BM_iter_step(&iter)) { + if ( (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) + { + BM_elem_select_set(em->bm, eed, TRUE); + } + } + } + else if (selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /* select all faces associated with every selected vertex */ + efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa = BM_iter_step(&iter)) { + l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l = BM_iter_step(&liter)) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) { + BM_elem_select_set(em->bm, efa, TRUE); + break; + } + } + } + } + } + + if (oldmode == SCE_SELECT_EDGE) { + if (selectmode == SCE_SELECT_FACE) { + BMIter liter; + BMLoop *l; + + /* select all faces associated with every selected vertex */ + efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa = BM_iter_step(&iter)) { + l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + for (; l; l = BM_iter_step(&liter)) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) { + BM_elem_select_set(em->bm, efa, TRUE); + break; + } + } + } + } + } +} + + +void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select) +{ + BMIter iter; + BMFace *efa; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + if (efa->mat_nr == index) { + BM_elem_select_set(em->bm, efa, select); + } + } +} + + +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_elem_flag_test(eve, BM_ELEM_HIDDEN)) + continue; + BM_elem_select_set(em->bm, eve, !BM_elem_flag_test(eve, BM_ELEM_SELECT)); + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + BM_elem_select_set(em->bm, eed, !BM_elem_flag_test(eed, BM_ELEM_SELECT)); + } + } + else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + BM_elem_select_set(em->bm, efa, !BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } + + } +// if (EM_texFaceCheck()) +} + +int EDBM_select_interior_faces(struct BMEditMesh *em) +{ + BMesh *bm = em->bm; + BMIter iter; + BMIter eiter; + BMFace *efa; + BMEdge *eed; + int ok; + int change = FALSE; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + continue; + + + ok = TRUE; + BM_ITER(eed, &eiter, bm, BM_EDGES_OF_FACE, efa) { + if (BM_edge_face_count(eed) < 3) { + ok = FALSE; + break; + } + } + + if (ok) { + BM_elem_select_set(bm, efa, TRUE); + change = TRUE; + } + } + + return change; +} + +static void linked_limit_default(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "limit")) { + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + if (em->selectmode == SCE_SELECT_FACE) + RNA_boolean_set(op->ptr, "limit", TRUE); + else + RNA_boolean_set(op->ptr, "limit", FALSE); + } +} + +static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + Object *obedit = CTX_data_edit_object(C); + ViewContext vc; + BMesh *bm; + BMWalker walker; + BMEditMesh *em; + BMVert *eve; + BMEdge *e, *eed; + BMFace *efa; + 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); + em = vc.em; + + if (em->bm->totedge == 0) + return OPERATOR_CANCELLED; + + bm = em->bm; + + vc.mval[0] = event->mval[0]; + vc.mval[1] = event->mval[1]; + + /* return warning! */ + + if (unified_findnearest(&vc, &eve, &eed, &efa) == 0) { + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_CANCELLED; + } + + if (em->selectmode == SCE_SELECT_FACE) { + BMIter iter; + + if (efa == NULL) + return OPERATOR_CANCELLED; + + if (limit) { + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(e, BM_ELEM_SEAM)) BMO_elem_flag_enable(bm, e, BM_ELEM_SELECT); + else BMO_elem_flag_disable(bm, e, BM_ELEM_SELECT); /* is this needed ? */ + } + } + + /* walk */ + BMW_init(&walker, bm, BMW_ISLAND, + BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + + e = BMW_begin(&walker, efa); + for (; efa; efa = BMW_step(&walker)) { + BM_elem_select_set(bm, efa, sel); + } + BMW_end(&walker); + } + else { + if (efa) { + eed = BM_FACE_FIRST_LOOP(efa)->e; + } + else if (!eed) { + if (!eve || !eve->e) + return OPERATOR_CANCELLED; + + eed = eve->e; + } + + BMW_init(&walker, bm, BMW_SHELL, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + + e = BMW_begin(&walker, eed->v1); + for ( ; e; e = BMW_step(&walker)) { + BM_elem_select_set(bm, e, sel); + } + BMW_end(&walker); + } + + 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 *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMIter iter; + BMVert *v; + BMEdge *e; + BMWalker walker; + + int limit; + + linked_limit_default(C, op); + + limit = RNA_boolean_get(op->ptr, "limit"); + + if (em->selectmode == SCE_SELECT_FACE) { + BMFace *efa; + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + } + } + + if (limit) { + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(e, BM_ELEM_SEAM)) BMO_elem_flag_enable(bm, e, BM_ELEM_SELECT); + else BMO_elem_flag_disable(bm, e, BM_ELEM_SELECT); /* is this needed ? */ + } + } + + BMW_init(&walker, bm, BMW_ISLAND, + BMW_MASK_NOP, limit ? BM_ELEM_SELECT : BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + e = BMW_begin(&walker, efa); + for (; efa; efa = BMW_step(&walker)) { + BM_elem_select_set(bm, efa, TRUE); + } + } + } + BMW_end(&walker); + } + else { + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(v, BM_ELEM_TAG); + } + } + + BMW_init(&walker, em->bm, BMW_SHELL, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + e = BMW_begin(&walker, v); + for (; e; e = BMW_step(&walker)) { + BM_elem_select_set(em->bm, e->v1, TRUE); + BM_elem_select_set(em->bm, e->v2, TRUE); + } + } + } + BMW_end(&walker); + } + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + + 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 *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh; + + EDBM_select_more(em); + + 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 *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = (((Mesh *)obedit->data))->edit_btmesh; + + EDBM_select_less(em); + + 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; +} + +/* Walk all reachable elements of the same type as h_act in breadth-first + order, starting from h_act. Deselects elements if the depth when they + are reached is not a multiple of "nth". */ +static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h_act) +{ + BMHeader *h; + BMesh *bm = em->bm; + BMWalker walker; + BMIter iter; + int walktype = 0, itertype = 0, flushtype = 0; + short mask_vert = 0, mask_edge = 0, mask_loop = 0, mask_face = 0; + + /* No active element from which to start - nothing to do */ + if (h_act == NULL) { + return; + } + + /* Determine which type of iter, walker, and select flush to use + * based on type of the elements being deselected */ + switch (h_act->htype) { + case BM_VERT: + itertype = BM_VERTS_OF_MESH; + walktype = BMW_CONNECTED_VERTEX; + flushtype = SCE_SELECT_VERTEX; + mask_vert = BM_ELEM_SELECT; + break; + case BM_EDGE: + itertype = BM_EDGES_OF_MESH; + walktype = BMW_SHELL; + flushtype = SCE_SELECT_EDGE; + mask_edge = BM_ELEM_SELECT; + break; + case BM_FACE: + itertype = BM_FACES_OF_MESH; + walktype = BMW_ISLAND; + flushtype = SCE_SELECT_FACE; + mask_face = BM_ELEM_SELECT; + break; + } + + /* Walker restrictions uses BMO flags, not header flags, + * so transfer BM_ELEM_SELECT from HFlags onto a BMO flag layer. */ + BMO_push(bm, NULL); + BM_ITER(h, &iter, bm, itertype, NULL) { + if (BM_elem_flag_test(h, BM_ELEM_SELECT)) { + BMO_elem_flag_enable(bm, (BMElemF *)h, BM_ELEM_SELECT); + } + } + + /* Walk over selected elements starting at active */ + BMW_init(&walker, bm, walktype, + mask_vert, mask_edge, mask_loop, mask_face, + BMW_NIL_LAY); + + BLI_assert(walker.order == BMW_BREADTH_FIRST); + for (h = BMW_begin(&walker, h_act); h != NULL; h = BMW_step(&walker)) { + /* Deselect elements that aren't at "nth" depth from active */ + if ((offset + BMW_current_depth(&walker)) % nth) { + BM_elem_select_set(bm, h, FALSE); + } + } + BMW_end(&walker); + + BMO_pop(bm); + + /* Flush selection up */ + EDBM_selectmode_flush_ex(em, flushtype); +} + +static void deselect_nth_active(BMEditMesh *em, BMVert **v_p, BMEdge **e_p, BMFace **f_p) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + BMIter iter; + BMEditSelection *ese; + + *v_p = NULL; + *e_p = NULL; + *f_p = NULL; + + EDBM_selectmode_flush(em); + ese = (BMEditSelection *)em->bm->selected.last; + + if (ese) { + switch(ese->htype) { + case BM_VERT: + *v_p = (BMVert *)ese->data; + return; + case BM_EDGE: + *e_p = (BMEdge *)ese->data; + return; + case BM_FACE: + *f_p = (BMFace *)ese->data; + return; + } + } + + if (em->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + *v_p = v; + return; + } + } + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + *e_p = e; + return; + } + } + } + else if (em->selectmode & SCE_SELECT_FACE) { + f = BM_active_face_get(em->bm, TRUE); + if (f) { + *f_p = f; + return; + } + } +} + +static int EM_deselect_nth(BMEditMesh *em, int nth, int offset) +{ + BMVert *v; + BMEdge *e; + BMFace *f; + + deselect_nth_active(em, &v, &e, &f); + + if (v) { + walker_deselect_nth(em, nth, offset, &v->head); + return 1; + } + else if (e) { + walker_deselect_nth(em, nth, offset, &e->head); + return 1; + } + else if (f) { + walker_deselect_nth(em, nth, offset, &f->head); + return 1; + } + + return 0; +} + +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"); + int offset = RNA_int_get(op->ptr, "offset"); + + offset = MIN2(nth, offset); + + if (EM_deselect_nth(em, nth, offset) == 0) { + BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face"); + 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_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); + RNA_def_int(ot->srna, "offset", 0, 0, 100, "Offset", "", 0, INT_MAX); +} + +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 = DEG2RADF(sharp); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) || !e->l) + continue; + + l1 = e->l; + l2 = l1->radial_next; + + if (l1 == l2) + continue; + + /* edge has exactly two neighboring faces, check angle */ + angle = angle_normalized_v3v3(l1->f->no, l2->f->no); + + if (fabsf(angle) > sharp) { + BM_elem_select_set(em->bm, e, TRUE); + } + + } + + 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_elem_flag_disable(f, BM_ELEM_TAG); + } + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(f, BM_ELEM_HIDDEN) || !BM_elem_flag_test(f, BM_ELEM_SELECT) || BM_elem_flag_test(f, BM_ELEM_TAG)) + continue; + + BLI_array_empty(stack); + i = 1; + + BLI_array_growone(stack); + stack[i - 1] = f; + + while (i) { + f = stack[i - 1]; + i--; + + BM_elem_select_set(em->bm, f, TRUE); + + BM_elem_flag_enable(f, BM_ELEM_TAG); + + 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_elem_flag_test(l2->f, BM_ELEM_TAG) || BM_elem_flag_test(l2->f, BM_ELEM_HIDDEN)) + continue; + + /* edge has exactly two neighboring faces, check angle */ + angle = angle_normalized_v3v3(f->no, l2->f->no); + + /* invalidate: edge too sharp */ + if (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_elem_flag_test(em->bm, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(em->bm, v)) { + BM_elem_select_set(em->bm, v, TRUE); + } + } + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(em->bm, BM_ELEM_HIDDEN) && BM_edge_face_count(e) != 2) { + BM_elem_select_set(em->bm, e, TRUE); + } + } + + 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_flag_disable_all(em, BM_ELEM_SELECT); + + if (em->selectmode & SCE_SELECT_VERTEX) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + BM_elem_select_set(em->bm, eve, TRUE); + } + } + EDBM_selectmode_flush(em); + } + else if (em->selectmode & SCE_SELECT_EDGE) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + BM_elem_select_set(em->bm, eed, TRUE); + } + } + EDBM_selectmode_flush(em); + } + else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BLI_frand() < randfac) { + BM_elem_select_set(em->bm, efa, TRUE); + } + } + 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_elem_flag_disable(v, BM_ELEM_TAG); + } + + 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_elem_flag_test(l->v, BM_ELEM_SELECT) && !BM_elem_flag_test(l->v, BM_ELEM_HIDDEN)) { + BM_elem_flag_enable(l->next->v, BM_ELEM_TAG); + BM_elem_select_set(em->bm, l->v, FALSE); + } + } + } + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_TAG)) { + BM_elem_select_set(em->bm, v, TRUE); + } + } + + 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; + ViewContext vc; + + em_setup_viewcontext(C, &vc); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + + 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_elem_flag_test(l2->f, BM_ELEM_SELECT) != 0; + } + + if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1)) + BM_elem_flag_enable(l1->e, BM_ELEM_TAG); + } + } + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_TAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + BM_edge_select_set(em->bm, e, TRUE); + } + + /* If in face-only select mode, switch to edge select mode so that + an edge-only selection is not inconsistent state */ + if (em->selectmode == SCE_SELECT_FACE) { + em->selectmode = SCE_SELECT_EDGE; + EDBM_selectmode_set(em); + EDBM_selectmode_to_scene(C); + } + + 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_elem_flag_test(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_face_count(e1); + b = BM_edge_face_count(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_elem_flag_disable(f, BM_ELEM_TAG); + } + + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BLI_array_append(edges, e); + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + } + + /* 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_elem_flag_test(e, BM_ELEM_TAG)) + 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_ELEM_SELECT, &visithash, &r); + + if (!region || (selbigger ? c >= tot : c < tot)) { + /* this region is the best seen so far */ + tot = c; + if (region) { + /* free the previous best */ + MEM_freeN(region); + } + /* track the current region as the new best */ + region = r; + } + else { + /* this region is not as good as best so far, just free it */ + MEM_freeN(r); + } + } + + if (region) { + int j; + + for (j = 0; j < tot; j++) { + BM_elem_flag_enable(region[j], BM_ELEM_TAG); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) { + BM_elem_flag_disable(l->e, BM_ELEM_TAG); + } + } + + 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_flag_disable_all(em, BM_ELEM_SELECT); + + BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(f, BM_ELEM_TAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + BM_face_select_set(em->bm, f, TRUE); + } + } + + 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..a242356f1ab --- /dev/null +++ b/source/blender/editors/mesh/bmesh_selecthistory.c @@ -0,0 +1,69 @@ +/* + * ***** 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 ***** + */ + +/* ********* Selection History ************ */ + +#include "BKE_tessmesh.h" + + +/* 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 along 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_select_history_remove(em->bm, data); +} + +void EDBM_store_selection(BMEditMesh *em, void *data) +{ + BM_select_history_store(em->bm, data); +} + +void EDBM_validate_selections(BMEditMesh *em) +{ + BM_select_history_validate(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..b403aaca5dc --- /dev/null +++ b/source/blender/editors/mesh/bmesh_tools.c @@ -0,0 +1,4690 @@ +/* + * ***** 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): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "RNA_define.h" +#include "RNA_access.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" +#include "BLI_rand.h" + +#include "BKE_material.h" +#include "BKE_context.h" +#include "BKE_cdderivedmesh.h" +#include "BKE_depsgraph.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_texture.h" +#include "BKE_main.h" +#include "BKE_tessmesh.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" +#include "ED_screen.h" +#include "ED_transform.h" +#include "ED_object.h" + +#include "RE_render_ext.h" + +#include "mesh_intern.h" + + +static void add_normal_aligned(float nor[3], const float add[3]) +{ + if (dot_v3v3(nor, add) < -0.9999f) + sub_v3_v3(nor, add); + else + sub_v3_v3(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 smooth = 0.292f * RNA_float_get(op->ptr, "smoothness"); + float fractal = RNA_float_get(op->ptr, "fractal")/2.5; + int flag = 0; + + if (smooth != 0.0f) + flag |= B_SMOOTH; + 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_mesh_esubdivideflag(obedit, em->bm, BM_ELEM_SELECT, + smooth, 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, INT_MAX, "Number of Cuts", "", 1, 10); + /* BMESH_TODO, this currently does nothing, just add to stop UI from erroring out! */ + RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor (BMESH TODO)", 0.0f, 1.0f); + + 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.0f, 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_elem_flag_test(eve, BM_ELEM_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, const char hflag, float *UNUSED(nor)) +{ + BMOIter siter; + BMIter liter; + BMFace *f; + BMLoop *l; + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", hflag); + + /* deselect original verts */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_op_exec(em->bm, &bmop); + + BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) { + BM_elem_select_set(em->bm, f, TRUE); + + /* set face vertex normals to face normal */ + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + copy_v3_v3(l->v->no, f->no); + } + } + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return 0; + } + + return 's'; // s is shrink/fatten +} + +/* extrudes individual edges */ +static short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) +{ + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", hflag); + + /* deselect original verts */ + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_VERT|BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return 0; + } + + return 'n'; // n is normal grab +} + +/* extrudes individual vertices */ +static short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor)) +{ + BMOperator bmop; + + EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag); + + /* deselect original verts */ + BMO_slot_buffer_hflag_disable(em->bm, &bmop, "verts", BM_ELEM_SELECT, BM_VERT); + + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_VERT); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return 0; + } + + return 'g'; // g is grab +} + +static short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3]) +{ + BMesh *bm = em->bm; + BMIter iter; + BMOIter siter; + BMOperator extop; + BMEdge *edge; + BMFace *f; + ModifierData *md; + BMHeader *el; + + BMO_op_init(bm, &extop, "extrudefaceregion"); + BMO_slot_from_hflag(bm, &extop, "edgefacein", + hflag, 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) && (md->mode & eModifierMode_Realtime)) { + 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); + mult_m4_m4m4(mtx, imtx, obedit->obmat); + } + + for (edge = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); + edge; + edge = BM_iter_step(&iter)) + { + if (BM_elem_flag_test(edge, hflag)) { + 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_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL); + } + } + if (mmd->flag & MOD_MIR_AXIS_Y) { + if ( (fabs(co1[1]) < mmd->tolerance) && + (fabs(co2[1]) < mmd->tolerance) ) + { + BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL); + } + } + if (mmd->flag & MOD_MIR_AXIS_Z) { + if ( (fabs(co1[2]) < mmd->tolerance) && + (fabs(co2[2]) < mmd->tolerance) ) + { + BMO_slot_map_ptr_insert(bm, &extop, "exclude", edge, NULL); + } + } + } + } + } + } + } + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_op_exec(bm, &extop); + + nor[0] = nor[1] = nor[2] = 0.0f; + + BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) { + BM_elem_select_set(bm, el, TRUE); + + if (el->htype == BM_FACE) { + f = (BMFace *)el; + add_normal_aligned(nor, f->no); + }; + } + + normalize_v3(nor); + + BMO_op_finish(bm, &extop); + + if (nor[0] == 0.0f && nor[1] == 0.0f && nor[2] == 0.0f) return 'g'; // grab + return 'n'; // normal constraint + +} +static short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float *nor) +{ + BMIter iter; + BMEdge *eed; + + /* ensure vert flags are consistent for edge selections */ + eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed = BM_iter_step(&iter)) { + if (BM_elem_flag_test(eed, hflag)) { + if (hflag & BM_ELEM_SELECT) { + BM_elem_select_set(em->bm, eed->v1, TRUE); + BM_elem_select_set(em->bm, eed->v2, TRUE); + } + + BM_elem_flag_enable(eed->v1, hflag & ~BM_ELEM_SELECT); + BM_elem_flag_enable(eed->v2, hflag & ~BM_ELEM_SELECT); + } + else { + if (BM_elem_flag_test(eed->v1, hflag) && BM_elem_flag_test(eed->v2, hflag)) { + if (hflag & BM_ELEM_SELECT) { + BM_elem_select_set(em->bm, eed, TRUE); + } + + BM_elem_flag_enable(eed, hflag & ~BM_ELEM_SELECT); + } + } + } + + return EDBM_Extrude_edge(obedit, em, hflag, 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 */ + normalize_v3_v3(dvec, rv3d->persinv[2]); + mul_v3_fl(dvec, 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_ELEM_SELECT, nor); + //BMO_op_callf(em->bm, "extrudefaceregion edgefacein=%hef", BM_ELEM_SELECT); + BMO_op_callf(em->bm, "translate vec=%v verts=%hv", (float *)dvec, BM_ELEM_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, BM_ELEM_SELECT, nor); + else if (nr == 1) transmode = EDBM_Extrude_edge(obedit, em, BM_ELEM_SELECT, nor); + else if (nr == 4) transmode = EDBM_Extrude_verts_indiv(em, op, BM_ELEM_SELECT, nor); + else if (nr == 3) transmode = EDBM_Extrude_edges_indiv(em, op, BM_ELEM_SELECT, nor); + else transmode = EDBM_Extrude_face_indiv(em, op, BM_ELEM_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); + + /* This normally happens when pushing undo but modal operators + * like this one don't push undo data until after modal mode is + * done.*/ + EDBM_RecalcNormals(em); + BMEdit_RecalcTesselation(em); + + 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_ELEM_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_ELEM_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_ELEM_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_flag_disable_all(em, BM_ELEM_SELECT); + else + EDBM_flag_enable_all(em, BM_ELEM_SELECT); +} + +static int mesh_select_all_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + int action = RNA_enum_get(op->ptr, "action"); + + switch (action) { + case SEL_TOGGLE: + EDBM_toggle_select_all(em); + break; + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + break; + } + + 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 = mesh_select_all_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + + WM_operator_properties_select_all(ot); +} + +static int mesh_faces_select_interior_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + + if (EDBM_select_interior_faces(em)) { + WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit); + + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } + +} + +void MESH_OT_select_interior_faces(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Interior Faces"; + ot->idname = "MESH_OT_select_interior_faces"; + ot->description = "Select faces where all edges have more than 2 face users"; + + /* api callbacks */ + ot->exec = mesh_faces_select_interior_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_elem_flag_test(v1, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_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 = dot_v3v3(vec, nor); + + if (fabsf(dot) < 0.999f) { + 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 = sinf(dot); + q1[0] = cosf(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_ELEM_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, BM_ELEM_SELECT, nor); + EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3", + BM_ELEM_SELECT, cent, mat); + EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v", + BM_ELEM_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_op_exec(vc.em->bm, &bmop); + + BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) { + BM_elem_select_set(vc.em->bm, v1, TRUE); + } + + if (!EDBM_FinishOp(vc.em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + } + + if (use_proj) + EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); + + /* This normally happens when pushing undo but modal operators + * like this one don't push undo data until after modal mode is + * done. */ + EDBM_RecalcNormals(vc.em); + BMEdit_RecalcTesselation(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_ELEM_SELECT, DEL_VERTS)) + return OPERATOR_CANCELLED; + } + else if (event == 11) { + //"Edge Loop" + if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_ELEM_SELECT)) + return OPERATOR_CANCELLED; + } + else if (event == 7) { + int use_verts = RNA_boolean_get(op->ptr, "use_verts"); + //"Dissolve" + if (bem->selectmode & SCE_SELECT_FACE) { + if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf use_verts=%i", BM_ELEM_SELECT, use_verts)) + return OPERATOR_CANCELLED; + } + else if (bem->selectmode & SCE_SELECT_EDGE) { + if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he use_verts=%i", BM_ELEM_SELECT, use_verts)) + return OPERATOR_CANCELLED; + } + else if (bem->selectmode & SCE_SELECT_VERTEX) { + if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv", BM_ELEM_SELECT)) + return OPERATOR_CANCELLED; + } + } + else if (event == 4) { + //Edges and Faces + if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_ELEM_SELECT, DEL_EDGESFACES)) + return OPERATOR_CANCELLED; + } + else if (event == 1) { + //"Erase Edges" + if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_ELEM_SELECT, DEL_EDGES)) + return OPERATOR_CANCELLED; + } + else if (event == 2) { + //"Erase Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_ELEM_SELECT, DEL_FACES)) + return OPERATOR_CANCELLED; + } + else if (event == 5) { + //"Erase Only Faces"; + if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d", + BM_ELEM_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) { + if (delete_mesh(C, obedit, op, type, scene) == OPERATOR_CANCELLED) + return OPERATOR_CANCELLED; + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + } + else { + if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_ELEM_SELECT)) + return OPERATOR_CANCELLED; + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); + } + + 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"); + + /* TODO, move dissolve into its own operator so this doesnt confuse non-dissolve options */ + RNA_def_boolean(ot->srna, "use_verts", 0, "Dissolve Verts", + "When dissolving faaces/edges, also dissolve remaining vertices"); +} + + +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_ELEM_SELECT)) + return OPERATOR_CANCELLED; + + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "faceout", BM_ELEM_SELECT, BM_FACE); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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; +} + +/* ************************* 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_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + + BM_elem_flag_disable(eed, BM_ELEM_SEAM); + } + } + else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + BM_elem_flag_enable(eed, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + + BM_elem_flag_disable(eed, BM_ELEM_SMOOTH); + } + } + else { + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT) || BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + continue; + + BM_elem_flag_enable(eed, BM_ELEM_SMOOTH); + } + } + + + 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 *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMOperator bmop; + int len = 0; + + if (!EDBM_InitOpf(em, &bmop, op, "connectverts verts=%hv", BM_ELEM_SELECT)) { + return OPERATOR_CANCELLED; + } + BMO_op_exec(bm, &bmop); + len = BMO_slot_get(&bmop, "edgeout")->len; + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + 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; + + if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he numcuts=%d", + BM_ELEM_SELECT, RNA_int_get(op->ptr,"number_cuts"))) { + return OPERATOR_CANCELLED; + } + BMO_op_exec(bm, &bmop); + len = BMO_slot_get(&bmop, "outsplit")->len; + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + 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_ELEM_SELECT); + + BMO_op_exec(em->bm, &bmop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "newout", BM_ELEM_SELECT, BM_ALL); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_ELEM_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; +} + +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; + const int do_ccw = RNA_enum_get(op->ptr, "direction") == 1; + int do_deselect = FALSE; /* do we deselect */ + + 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_face_count(eed) == 2) { + if ((BM_elem_flag_test(eed->l->f, BM_ELEM_SELECT) && BM_elem_flag_test(eed->l->radial_next->f, BM_ELEM_SELECT)) + && !(BM_elem_flag_test(eed->l->f, BM_ELEM_HIDDEN) || BM_elem_flag_test(eed->l->radial_next->f, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + /* de-select the edge before */ + do_deselect = TRUE; + break; + } + } + } + + /* this should never happen */ + if (!eed) + return OPERATOR_CANCELLED; + + EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, do_ccw); + + /* avoid adding to the selection if we start off with only a selected edge, + * we could also just deselect the single edge easily but use the BMO api + * since it seems this is more 'correct' */ + if (do_deselect) BMO_slot_buffer_hflag_disable(em->bm, &bmop, "edges", BM_ELEM_SELECT, BM_EDGE); + + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "edgeout", BM_ELEM_SELECT, BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_elem_flag_test(h, BM_ELEM_SELECT) ^ swap) + BM_elem_hide_set(em->bm, h, TRUE); + } + + EDBM_selectmode_flush(em); + + /* 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) +{ + const char iter_types[3] = {BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH}; + + int sels[3] = {(em->selectmode & SCE_SELECT_VERTEX), + (em->selectmode & SCE_SELECT_EDGE), + (em->selectmode & SCE_SELECT_FACE), + }; + + BMIter iter; + BMHeader *ele; + int i; + + /* Use index field to remember what was hidden before all is revealed. */ + for (i = 0; i < 3; i++) { + BM_ITER(ele, &iter, em->bm, iter_types[i], NULL) { + if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) { + BM_elem_flag_enable(ele, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(ele, BM_ELEM_TAG); + } + } + } + + /* Reveal everything */ + EDBM_flag_disable_all(em, BM_ELEM_HIDDEN); + + /* Select relevant just-revealed elements */ + for (i = 0; i < 3; i++) { + if (!sels[i]) { + continue; + } + + BM_ITER(ele, &iter, em->bm, iter_types[i], NULL) { + if (BM_elem_flag_test(ele, BM_ELEM_TAG)) { + BM_elem_select_set(em->bm, ele, TRUE); + } + } + } + + 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_ELEM_SELECT, 1)) + return OPERATOR_CANCELLED; + + if (RNA_boolean_get(op->ptr, "inside")) + EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_ELEM_SELECT); + + 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; + float clipdist = 0.0f; + + /* mirror before smooth */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_CacheMirrorVerts(em, TRUE); + } + + /* 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 && (md->mode & eModifierMode_Realtime)) { + 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; + + clipdist = mmd->tolerance; + } + } + } + + 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 clipdist=%f", + BM_ELEM_SELECT, mirrx, mirry, mirrz, clipdist)) + { + return OPERATOR_CANCELLED; + } + } + + /* apply mirror */ + if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) { + EDBM_ApplyMirrorCache(em, BM_ELEM_SELECT, 0); + EDBM_EndMirrorCache(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_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, 0, NULL, NULL); + BMIter iter; + BMEdge *e; + + /* hide all back edges */ + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) + continue; + + if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit)) + BM_elem_select_set(em->bm, e, FALSE); + } + + 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, BMW_NIL_LAY); + + 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_elem_flag_test(efa, BM_ELEM_SELECT)) { + if (smooth) + BM_elem_flag_enable(efa, BM_ELEM_SMOOTH); + else + BM_elem_flag_disable(efa, BM_ELEM_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_ELEM_SELECT, dir); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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); + + /* 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_ELEM_SELECT); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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); + + /* 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_ELEM_SELECT, dir); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_ELEM_SELECT); + + /* execute the operator */ + BMO_op_exec(em->bm, &bmop); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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; +} + +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_CCW, "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_elem_flag_test(mergevert, BM_ELEM_SELECT)) + return OPERATOR_CANCELLED; + + if (uvmerge) { + if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_ELEM_SELECT, mergevert)) + return OPERATOR_CANCELLED; + } + + if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_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}; + + if (target) { + vco = give_cursor(scene, v3d); + copy_v3_v3(co, vco); + mul_m4_v3(ob->imat, co); + } + else { + float fac; + int i = 0; + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) + continue; + add_v3_v3(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_ELEM_SELECT)) + return OPERATOR_CANCELLED; + } + + if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_ELEM_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_ELEM_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)->htype == BM_VERT && + ((BMEditSelection *)em->bm->selected.last)->htype == 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)->htype == BM_VERT) { + RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1); + } + else if (em->bm->selected.last && ((BMEditSelection *)em->bm->selected.last)->htype == 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_ELEM_SELECT, RNA_float_get(op->ptr, "mergedist")); + BMO_op_exec(em->bm, &bmop); + + count = BMO_slot_map_count(em->bm, &bmop, "targetmapout"); + + if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) { + BMO_op_finish(em->bm, &bmop); + return OPERATOR_CANCELLED; + } + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s", count, (count==1)?"ex":"ices"); + + + 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->htype != BM_VERT) || (ev->htype != 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_op_exec(em->bm, &bmop); + + /* DO NOT clear the existing selection */ + /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */ + + /* select the output */ + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "vertout", BM_ELEM_SELECT, BM_ALL); + + /* finish the operator */ + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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; +} + +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; + BMesh *bm = em->bm; + BMOperator bmop; + BMBVHTree *bvhtree; + BMOIter siter; + BMIter iter, eiter, liter; + BMLoop *l; + BMEdge *e, *e2, *closest = NULL; + BMVert *v, *ripvert = NULL; + int side = 0, i, singlesel = 0; + float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; + 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_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + } + + /* 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 (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) { + singlesel = 1; + + /* find selected vert */ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) + break; + } + + /* this should be impossible, but sanity checks are a good thing */ + if (!v) + return OPERATOR_CANCELLED; + + if (!v->e || !v->e->l) { + BKE_report(op->reports, RPT_ERROR, "Selected vertex has no faces"); + return OPERATOR_CANCELLED; + } + + /* find closest edge to mouse cursor */ + e2 = NULL; + BM_ITER(e, &iter, 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_face_count(e2) == 1 || BM_vert_face_count(v) == 2) { + l = e2->l; + ripvert = BM_vert_rip(bm, l->f, v); + + BLI_assert(ripvert); + if (!ripvert) { + return OPERATOR_CANCELLED; + } + } + else if (BM_edge_face_count(e2) == 2) { + l = e2->l; + e = BM_face_other_loop(e2, l->f, v)->e; + BM_elem_flag_enable(e, BM_ELEM_TAG); + BM_elem_select_set(bm, e, TRUE); + + l = e2->l->radial_next; + e = BM_face_other_loop(e2, l->f, v)->e; + BM_elem_flag_enable(e, BM_ELEM_TAG); + BM_elem_select_set(bm, e, TRUE); + } + + dist = FLT_MAX; + } + else { + /* expand edge selection */ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + e2 = NULL; + i = 0; + BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + e2 = e; + i++; + } + } + + if (i == 1 && e2->l) { + l = BM_face_other_loop(e2, e2->l->f, v); + l = l->radial_next; + l = BM_face_other_loop(l->e, l->f, v); + + if (l) { + BM_elem_select_set(bm, l->e, TRUE); + } + } + } + } + + if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_ELEM_SELECT)) { + return OPERATOR_CANCELLED; + } + + BMO_op_exec(bm, &bmop); + + /* build bvh tree for edge visibility tests */ + bvhtree = BMBVH_NewBVH(em, 0, NULL, NULL); + + for (i = 0; i < 2; i++) { + BMO_ITER(e, &siter, bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) { + float cent[3] = {0, 0, 0}, mid[3], 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, bm, BM_LOOPS_OF_FACE, e->l->f) { + add_v3_v3(cent, l->v->co); + } + mul_v3_fl(cent, 1.0f/(float)e->l->f->len); + + mid_v3_v3v3(mid, e->v1->co, e->v2->co); + 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); + + d = len_squared_v2v2(fmval, mid); + + if (d < dist) { + side = i; + closest = e; + dist = d; + } + } + } + + BMBVH_FreeBVH(bvhtree); + + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(bm, &bmop, side?"edgeout2":"edgeout1", BM_ELEM_SELECT, BM_EDGE); + + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { + BM_elem_flag_enable(e, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(e, BM_ELEM_TAG); + } + } + + /* constrict edge selection again */ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + e2 = NULL; + i = 0; + BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + e2 = e; + i++; + } + } + + if (i == 1) { + if (singlesel) + BM_elem_select_set(bm, v, FALSE); + else + BM_elem_select_set(bm, e2, FALSE); + } + } + + if (ripvert) { + BM_elem_select_set(bm, ripvert, TRUE); + } + + EDBM_selectmode_flush(em); + + BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0)); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + if (bm->totvertsel == 0) { + 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_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_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) + continue; + + for (i = 0; i < totshape; i++) { + co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i); + copy_v3_v3(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_boolean_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_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) + continue; + + sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape); + copy_v3_v3(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); + + copy_v3_v3(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) ? me->edit_btmesh : NULL; + EnumPropertyItem *item = NULL; + int totitem = 0; + + if (obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) { + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int a; + + 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"); +} + +/* BMESH_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_enum_get(op->ptr, "axis"); + int mode = RNA_enum_get(op->ptr, "mode"); /* -1 == aligned, 0 == neg, 1 == pos */ + + if (ese == NULL || ese->htype != BM_VERT) { + BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); + return OPERATOR_CANCELLED; + } + else { + 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_elem_flag_test(ev, BM_ELEM_HIDDEN)) { + switch(mode) { + case -1: /* aligned */ + if (fabs(ev->co[axis] - value) < limit) + BM_elem_select_set(em->bm, ev, TRUE); + break; + case 0: /* neg */ + if (ev->co[axis] > value) + BM_elem_select_set(em->bm, ev, TRUE); + break; + case 1: /* pos */ + if (ev->co[axis] < value) + BM_elem_select_set(em->bm, ev, TRUE); + 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}}; + + 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"); +} + +static int solidify_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + BMOperator bmop; + + float thickness = RNA_float_get(op->ptr, "thickness"); + + if (!EDBM_InitOpf(em, &bmop, op, "solidify geom=%hf thickness=%f", BM_ELEM_SELECT, thickness)) { + return OPERATOR_CANCELLED; + } + + /* deselect only the faces in the region to be solidified (leave wire + edges and loose verts selected, as there will be no corresponding + geometry selected below) */ + BMO_slot_buffer_hflag_disable(bm, &bmop, "geom", BM_ELEM_SELECT, BM_FACE); + + /* run the solidify operator */ + BMO_op_exec(bm, &bmop); + + /* select the newly generated faces */ + BMO_slot_buffer_hflag_enable(bm, &bmop, "geomout", BM_ELEM_SELECT, BM_FACE); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_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_edge_seg_isect(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.0f) && (m2 >= -1.0f)) 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.0f; + float *scr, co[4]; + int len = 0, isected; + 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); bv; bv = BM_iter_step(&iter)) { + scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates"); + copy_v3_v3(co, bv->co); + co[3] = 1.0f; + mul_m4_v4(obedit->obmat, co); + project_float(ar, co, scr); + BLI_ghash_insert(gh, bv, scr); + } + + if (!EDBM_InitOpf(em, &bmop, op, "esubd")) { + return OPERATOR_CANCELLED; + } + + /* store percentage of edge cut for KNIFE_EXACT here.*/ + for (be = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be = BM_iter_step(&iter)) { + if (BM_elem_flag_test(be, BM_ELEM_SELECT)) { + isect = bm_edge_seg_isect(be, curve, len, mode, gh, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_slot_map_float_insert(bm, &bmop, + "edgepercents", + be, isect); + + } + BMO_elem_flag_enable(bm, be, 1); + } + else { + BMO_elem_flag_disable(bm, be, 1); + } + } + else { + BMO_elem_flag_disable(bm, be, 1); + } + } + + BMO_slot_from_flag(bm, &bmop, "edges", 1, BM_EDGE); + + if (mode == KNIFE_MIDPOINT) numcuts = 1; + BMO_slot_int_set(&bmop, "numcuts", numcuts); + + BMO_slot_int_set(&bmop, "flag", B_KNIFE); + BMO_slot_int_set(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT); + BMO_slot_int_set(&bmop, "singleedge", 0); + BMO_slot_int_set(&bmop, "gridfill", 0); + + BMO_slot_float_set(&bmop, "radius", 0); + + BMO_op_exec(bm, &bmop); + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + 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; + + if (!em) + return OPERATOR_CANCELLED; + + bmnew = BM_mesh_create(obedit, bm_mesh_allocsize_default); + 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, bm_mesh_allocsize_default[0]); + CustomData_bmesh_init_pool(&bmnew->edata, bm_mesh_allocsize_default[1]); + CustomData_bmesh_init_pool(&bmnew->ldata, bm_mesh_allocsize_default[2]); + CustomData_bmesh_init_pool(&bmnew->pdata, bm_mesh_allocsize_default[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_ELEM_SELECT, bmnew); + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_FACES); + + /* clean up any loose edges */ + BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + continue; + + if (BM_edge_face_count(e) != 0) { + BM_elem_select_set(em->bm, e, FALSE); + } + } + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_EDGES); + + /* clean up any loose verts */ + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + continue; + + if (BM_vert_edge_count(v) != 0) { + BM_elem_select_set(em->bm, v, FALSE); + } + } + + EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_ELEM_SELECT, DEL_VERTS); + + BM_mesh_normals_update(bmnew); + BMO_op_callf(bmnew, "bmesh_to_mesh mesh=%p object=%p", basenew->object->data, basenew->object); + + BM_mesh_free(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; +} + +static int mesh_separate_loose(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop) +{ + int i; + BMVert *v; + BMEdge *e; + BMVert *v_seed; + BMWalker walker; + BMIter iter; + int result = 0; + Object *obedit = editbase->object; + Mesh *me = obedit->data; + BMEditMesh *em = me->edit_btmesh; + BMesh *bm = em->bm; + int max_iter = bm->totvert; + + /* Clear all selected vertices */ + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + BM_elem_select_set(bm, v, FALSE); + } + + /* Flush the selection to clear edge/face selections to match + * selected vertices */ + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + + /* A "while (true)" loop should work here as each iteration should + * select and remove at least one vertex and when all vertices + * are selected the loop will break out. But guard against bad + * behavior by limiting iterations to the number of vertices in the + * original mesh.*/ + for (i = 0; i < max_iter; i++) { + /* Get a seed vertex to start the walk */ + v_seed = NULL; + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + v_seed = v; + break; + } + + /* No vertices available, can't do anything */ + if (v_seed == NULL) { + break; + } + + /* Select the seed explicitly, in case it has no edges */ + BM_elem_select_set(bm, v_seed, TRUE); + + /* Walk from the single vertex, selecting everything connected + * to it */ + BMW_init(&walker, bm, BMW_SHELL, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + + e = BMW_begin(&walker, v_seed); + for (; e; e = BMW_step(&walker)) { + BM_elem_select_set(bm, e->v1, TRUE); + BM_elem_select_set(bm, e->v2, TRUE); + } + BMW_end(&walker); + + /* Flush the selection to get edge/face selections matching + * the vertex selection */ + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); + + if (bm->totvert == bm->totvertsel) { + /* Every vertex selected, nothing to separate, work is done */ + break; + } + + /* Move selection into a separate object */ + result |= mesh_separate_selected(bmain, scene, editbase, wmop); + } + + return result; +} + +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_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_ELEM_SELECT)) + return OPERATOR_CANCELLED; + + BMO_op_exec(em->bm, &bmop); + + /* select new geometry */ + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_FACE|BM_EDGE); + + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + 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_ELEM_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_ELEM_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_ELEM_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) +{ + PropertyRNA *prop; + + /* 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; + + prop = RNA_def_float_rotation(ot->srna, "limit", 0, NULL, 0.0f, DEG2RADF(180.0f), + "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(40.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 dissolve_limited_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + float angle_limit = RNA_float_get(op->ptr, "angle_limit"); + + if (!EDBM_CallOpf(em, op, + "dissolvelimit edges=%he verts=%hv angle_limit=%f", + BM_ELEM_SELECT, BM_ELEM_SELECT, angle_limit)) + { + 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_dissolve_limited(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Limited Dissolve"; + ot->idname = "MESH_OT_dissolve_limited"; + ot->description = "Dissolve selected edges and verts, limited by the angle of surrounding geometry"; + + /* api callbacks */ + ot->exec = dissolve_limited_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + + prop = RNA_def_float_rotation(ot->srna, "angle_limit", 0, NULL, 0.0f, DEG2RADF(180.0f), + "Max Angle", "Angle Limit in Degrees", 0.0f, DEG2RADF(180.0f)); + RNA_def_property_float_default(prop, DEG2RADF(15.0f)); +} + +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; +} + +static int split_mesh_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, "split geom=%hvef", BM_ELEM_SELECT); + BMO_op_exec(em->bm, &bmop); + BM_mesh_elem_flag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL); + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) { + return OPERATOR_CANCELLED; + } + + /* Geometry has changed, need to recalc normals and looptris */ + BMEdit_RecalcTesselation(em); + EDBM_RecalcNormals(em); + + DAG_id_tag_update(ob->data, OB_RECALC_DATA); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +void MESH_OT_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Split"; + ot->idname = "MESH_OT_split"; + + /* api callbacks */ + ot->exec = split_mesh_exec; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; +} + + +static int spin_mesh_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + ToolSettings *ts = CTX_data_tool_settings(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; + BMOperator spinop; + float cent[3], axis[3], imat[3][3]; + float d[3] = {0.0f, 0.0f, 0.0f}; + int steps, dupli; + float degr; + + RNA_float_get_array(op->ptr, "center", cent); + RNA_float_get_array(op->ptr, "axis", axis); + steps = RNA_int_get(op->ptr, "steps"); + degr = RNA_float_get(op->ptr, "degrees"); + if (ts->editbutflag & B_CLOCKWISE) degr = -degr; + dupli = RNA_boolean_get(op->ptr, "dupli"); + + /* undo object transformation */ + copy_m3_m4(imat, obedit->imat); + sub_v3_v3(cent, obedit->obmat[3]); + mul_m3_v3(imat, cent); + mul_m3_v3(imat, axis); + + if (!EDBM_InitOpf(em, &spinop, op, + "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%d ang=%f dupli=%d", + BM_ELEM_SELECT, cent, axis, d, steps, degr, dupli)) { + return OPERATOR_CANCELLED; + } + BMO_op_exec(bm, &spinop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ELEM_SELECT, BM_ALL); + if (!EDBM_FinishOp(em, &spinop, op, TRUE)) { + 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; + BMesh *bm = em->bm; + BMEdge *eed; + BMVert *eve, *v1, *v2; + BMIter iter, eiter; + BMOperator spinop; + float dvec[3], nor[3], cent[3], axis[3]; + float imat[3][3]; + int steps, turns; + int valence; + + + turns = RNA_int_get(op->ptr, "turns"); + steps = RNA_int_get(op->ptr, "steps"); + RNA_float_get_array(op->ptr, "center", cent); + RNA_float_get_array(op->ptr, "axis", axis); + + /* undo object transformation */ + copy_m3_m4(imat, obedit->imat); + sub_v3_v3(cent, obedit->obmat[3]); + mul_m3_v3(imat, cent); + mul_m3_v3(imat, axis); + + + /* find two vertices with valence count == 1, more or less is wrong */ + v1 = NULL; + v2 = NULL; + for (eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + eve; eve = BM_iter_step(&iter)) { + + valence = 0; + + for (eed = BM_iter_new(&eiter, em->bm, BM_EDGES_OF_VERT, eve); + eed; eed = BM_iter_step(&eiter)) { + + if (BM_elem_flag_test(eed, BM_ELEM_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 */ + sub_v3_v3v3(dvec, v1->co, v2->co); + mul_v3_fl(dvec, 1.0f / steps); + + if (dot_v3v3(nor, dvec) > 0.000f) + negate_v3(dvec); + + if (!EDBM_InitOpf(em, &spinop, op, + "spin geom=%hvef cent=%v axis=%v dvec=%v steps=%d ang=%f dupli=0", + BM_ELEM_SELECT, cent, axis, dvec, turns * steps, 360.0f * turns)) + { + return OPERATOR_CANCELLED; + } + BMO_op_exec(bm, &spinop); + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + BMO_slot_buffer_hflag_enable(bm, &spinop, "lastout", BM_ELEM_SELECT, BM_ALL); + if (!EDBM_FinishOp(em, &spinop, op, TRUE)) { + 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 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 = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + efa; efa = BM_iter_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_elem_select_set(em->bm, efa, TRUE); + } + } + + 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 = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + eve; eve = BM_iter_step(&iter)) { + + if (!eve->e) { + BM_elem_select_set(em->bm, eve, TRUE); + } + } + + for (eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + eed; eed = BM_iter_step(&iter)) { + + if (!eed->l) { + BM_elem_select_set(em->bm, eed, TRUE); + } + } + + 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; +} + +static int select_mirror_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + int extend = RNA_boolean_get(op->ptr, "extend"); + + EDBM_select_mirrored(obedit, em, extend); + EDBM_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"); +} + +#if 0 /* UNUSED */ +/********* 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; +}; + +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_elem_flag_test(eve, BM_ELEM_SELECT)) + sortblock[i].v1 = eve; + } + + ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); + mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, V3D_CLIP_TEST_OFF); + + 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; +} + +/* ********************** 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, j, *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->totpoly == 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->totpoly, "sort faces"); + for (i = 0; i < me->totpoly; i++) { + index[i] = i; + } + + face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totpoly, "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->totpoly; i++) { + face_sort_floats[i] = BLI_frand(); + } + qsort(index, me->totpoly, sizeof(int), float_sort); + } + else { + MPoly *mp; + MLoop *ml; + MVert *mv; + float vec[3]; + float mat[4][4]; + float cur[3]; + + if (event == 1) + mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* apply the view matrix to the object matrix */ + else if (event == 2) { /* sort from cursor */ + if (v3d && v3d->localvd) { + copy_v3_v3(cur, v3d->cursor); + } + else { + copy_v3_v3(cur, scene->cursor); + } + invert_m4_m4(mat, OBACT->obmat); + mul_m4_v3(mat, cur); + } + + mp = me->mpoly; + + for (i = 0; i < me->totpoly; i++, mp++) { + if (event == 3) { + face_sort_floats[i] = ((float)mp->mat_nr)*reverse; + } + else if (event == 4) { + /* selected first */ + if (mp->flag & ME_FACE_SEL) + face_sort_floats[i] = 0.0; + else + face_sort_floats[i] = reverse; + } + else { + /* find the face's center */ + ml = me->mloop + mp->loopstart; + zero_v3(vec); + for (j = 0; j < mp->totloop; j++, ml++) { + mv = me->mvert + ml->v; + add_v3_v3(vec, mv->co); + } + mul_v3_fl(vec, 1.0f / (float)mp->totloop); + + 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->totpoly, sizeof(int), float_sort); + } + + MEM_freeN(face_sort_floats); + for (i = 0; i < me->pdata.totlayer; i++) { + layer = &me->pdata.layers[i]; + permutate(layer->data, me->totpoly, 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", ""); +} + +#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_elem_flag_test(eve, BM_ELEM_SELECT) && !BM_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eve, BM_ELEM_SELECT) && !BM_elem_flag_test(eve, BM_ELEM_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 */ /* UNUSED */, df, s; + int i, recursion = RNA_int_get(op->ptr, "recursion"); + const int use_even = RNA_boolean_get(op->ptr, "use_even"); + const int use_dist = RNA_boolean_get(op->ptr, "use_dist"); + float *w = NULL, ftot; + int li; + + BM_data_layer_add(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; + } + + w = MEM_mallocN(sizeof(float) * recursion, "bevel weights"); + + /* ugh, stupid math depends somewhat on angles!*/ + /* dfac = 1.0/(float)(recursion + 1); */ /* UNUSED */ + df = 1.0; + for (i = 0, ftot = 0.0f; i < recursion; i++) { + s = powf(df, 1.25f); + + w[i] = s; + ftot += s; + + df *= 2.0; + } + + mul_vn_fl(w, recursion, 1.0f / (float)ftot); + + fac = factor; + for (i = 0; i < recursion; i++) { + fac = w[recursion - i - 1] * factor; + + if (!EDBM_InitOpf(em, &bmop, op, + "bevel geom=%hev percent=%f lengthlayer=%i use_lengths=%i use_even=%i use_dist=%i", + BM_ELEM_SELECT, fac, li, 1, use_even, use_dist)) + { + return OPERATOR_CANCELLED; + } + + BMO_op_exec(em->bm, &bmop); + if (!EDBM_FinishOp(em, &bmop, op, TRUE)) + return OPERATOR_CANCELLED; + } + + BM_data_layer_free_n(em->bm, &em->bm->edata, CD_MASK_PROP_FLT, li); + + MEM_freeN(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_boolean(ot->srna, "use_even", FALSE, "Even", "Calculate evenly spaced bevel"); + RNA_def_boolean(ot->srna, "use_dist", FALSE, "Distance", "Interpret the percent in blender units"); + +} + +static int bridge_edge_loops(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + + if (!EDBM_CallOpf(em, op, "bridge_loops edges=%he", BM_ELEM_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_bridge_edge_loops(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Bridge edge loops"; + ot->description = "Make faces between two edge loops"; + ot->idname = "MESH_OT_bridge_edge_loops"; + + /* api callbacks */ + ot->exec = bridge_edge_loops; + ot->poll = ED_operator_editmesh; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "inside", 0, "Inside", ""); +} + +static int mark_freestyle_edge(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Mesh *me = ((Mesh *)obedit->data); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMEdge *eed; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + if (em == NULL) return OPERATOR_FINISHED; + + /* auto-enable seams drawing */ + if (clear == 0) { + me->drawflag |= ME_DRAW_FREESTYLE_EDGE; + } + + if (clear) { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + BM_elem_flag_disable(eed, BM_ELEM_FREESTYLE); + } + } + else { + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) + BM_elem_flag_enable(eed, BM_ELEM_FREESTYLE); + } + } + + 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_freestyle_edge(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Freestyle Edge"; + ot->description= "(un)mark selected edges as Freestyle feature edges"; + ot->idname= "MESH_OT_mark_freestyle_edge"; + + /* api callbacks */ + ot->exec= mark_freestyle_edge; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} + +static int mark_freestyle_face_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + Mesh *me = ((Mesh *)obedit->data); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMFace *efa; + BMIter iter; + int clear = RNA_boolean_get(op->ptr, "clear"); + + if (em == NULL) return OPERATOR_FINISHED; + + /* auto-enable Freestyle face mark drawing */ + if(!clear) { + me->drawflag |= ME_DRAW_FREESTYLE_FACE; + } + + if(clear) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + BM_elem_flag_disable(efa, BM_ELEM_FREESTYLE); + } + } else { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) + BM_elem_flag_enable(efa, BM_ELEM_FREESTYLE); + } + } + printf("%s\n", clear ? "clear" : "set"); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + printf("face %s\n", (BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)) ? "enabled" : "disabled"); + } + printf("\n"); + + 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_freestyle_face(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mark Freestyle Face"; + ot->description= "(un)mark selected faces for exclusion from Freestyle feature edge detection"; + ot->idname= "MESH_OT_mark_freestyle_face"; + + /* api callbacks */ + ot->exec= mark_freestyle_face_exec; + ot->poll= ED_operator_editmesh; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); +} diff --git a/source/blender/editors/mesh/bmesh_utils.c b/source/blender/editors/mesh/bmesh_utils.c new file mode 100644 index 00000000000..f124823b106 --- /dev/null +++ b/source/blender/editors/mesh/bmesh_utils.c @@ -0,0 +1,1139 @@ +/* + * ***** 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): Joseph Eagar + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BLI_blenlib.h" +#include "BLI_math.h" + +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_key.h" +#include "BKE_mesh.h" +#include "BKE_bmesh.h" +#include "BKE_report.h" +#include "BKE_tessmesh.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_mesh.h" +#include "ED_util.h" + +void EDBM_RecalcNormals(BMEditMesh *em) +{ + BM_mesh_normals_update(em->bm); +} + +void EDBM_ClearMesh(BMEditMesh *em) +{ + /* clear bmesh */ + BM_mesh_clear(em->bm); + + /* free derived meshes */ + if (em->derivedCage) { + em->derivedCage->needsFree = 1; + em->derivedCage->release(em->derivedCage); + } + if (em->derivedFinal && em->derivedFinal != em->derivedCage) { + em->derivedFinal->needsFree = 1; + em->derivedFinal->release(em->derivedFinal); + } + + em->derivedCage = em->derivedFinal = NULL; + + /* free tesselation data */ + em->tottri = 0; + if (em->looptris) + MEM_freeN(em->looptris); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + const char iter_types[3] = {BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH}; + + BMIter iter; + BMHeader *ele; + 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 = BM_iter_new(&iter, em->bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_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_op_vinitf(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, const int report) +{ + const char *errmsg; + + BMO_op_finish(em->bm, bmop); + + if (BMO_error_get(em->bm, &errmsg, NULL)) { + BMEditMesh *emcopy = em->emcopy; + + if (report) BKE_report(op->reports, RPT_ERROR, errmsg); + + BMEdit_Free(em); + *em = *emcopy; + BMEdit_RecalcTesselation(em); + + 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_op_vinitf(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_op_exec(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, op, TRUE); +} + +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_op_vinitf(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_op_exec(bm, &bmop); + + BM_mesh_elem_flag_disable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, BM_ELEM_SELECT); + + BMO_slot_buffer_hflag_enable(em->bm, &bmop, selectslot, BM_ELEM_SELECT, BM_ALL); + + va_end(list); + return EDBM_FinishOp(em, &bmop, op, TRUE); +} + +int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...) +{ + BMesh *bm = em->bm; + BMOperator bmop; + va_list list; + + va_start(list, fmt); + + if (!BMO_op_vinitf(bm, &bmop, fmt, list)) { + va_end(list); + return 0; + } + + if (!em->emcopy) + em->emcopy = BMEdit_Copy(em); + em->emcopyusers++; + + BMO_op_exec(bm, &bmop); + + va_end(list); + return EDBM_FinishOp(em, &bmop, NULL, FALSE); +} + +void EDBM_selectmode_to_scene(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + + if (!em) + return; + + scene->toolsettings->selectmode = em->selectmode; + + /* Request redraw of header buttons (to show new select mode) */ + WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, scene); +} + +void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob) +{ + Mesh *me = ob->data; + BMesh *bm; + + if (!me->mpoly && me->totface) { + fprintf(stderr, "%s: bmesh conversion issue! may lose lots of geometry! (bmesh internal error)\n", __func__); + + /* BMESH_TODO need to write smarter code here */ + bm = BKE_mesh_to_bmesh(me, ob); + } + else { + bm = BKE_mesh_to_bmesh(me, ob); + } + + if (me->edit_btmesh) { + /* this happens when switching shape keys */ + BMEdit_Free(me->edit_btmesh); + MEM_freeN(me->edit_btmesh); + } + + /* currently executing operators re-tesselates, so we can avoid doing here + * but at some point it may need to be added back. */ +#if 0 + me->edit_btmesh = BMEdit_Create(bm, TRUE); +#else + me->edit_btmesh = BMEdit_Create(bm, FALSE); +#endif + + me->edit_btmesh->selectmode = me->edit_btmesh->bm->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_op_callf(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 = BM_iter_new(&iter, tm->bm, BM_VERTS_OF_MESH, NULL); + for ( ; ele; ele = BM_iter_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 = BM_iter_new(&iter, tm->bm, BM_EDGES_OF_MESH, NULL); + for ( ; ele; ele = BM_iter_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 = BM_iter_new(&iter, tm->bm, BM_FACES_OF_MESH, NULL); + for ( ; ele; ele = BM_iter_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; +} + +void EDBM_selectmode_flush_ex(BMEditMesh *em, int selectmode) +{ + em->bm->selectmode = selectmode; + BM_mesh_select_mode_flush(em->bm); + em->bm->selectmode = em->selectmode; +} + +void EDBM_selectmode_flush(BMEditMesh *em) +{ + EDBM_selectmode_flush_ex(em, em->selectmode); +} + +void EDBM_deselect_flush(BMEditMesh *em) +{ + /* function below doesnt use. just do this to keep the values in sync */ + em->bm->selectmode = em->selectmode; + BM_mesh_deselect_flush(em->bm); +} + + +void EDBM_select_flush(BMEditMesh *em) +{ + /* function below doesnt use. just do this to keep the values in sync */ + em->bm->selectmode = em->selectmode; + BM_mesh_select_flush(em->bm); +} + +void EDBM_select_more(BMEditMesh *em) +{ + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + BMO_op_initf(em->bm, &bmop, + "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_ELEM_SELECT, 0, usefaces); + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL); + BMO_op_finish(em->bm, &bmop); + + EDBM_selectmode_flush(em); +} + +void EDBM_select_less(BMEditMesh *em) +{ + BMOperator bmop; + int usefaces = em->selectmode > SCE_SELECT_EDGE; + + BMO_op_initf(em->bm, &bmop, + "regionextend geom=%hvef constrict=%d usefaces=%d", + BM_ELEM_SELECT, 0, usefaces); + BMO_op_exec(em->bm, &bmop); + BMO_slot_buffer_hflag_enable(em->bm, &bmop, "geomout", BM_ELEM_SELECT, BM_ALL); + BMO_op_finish(em->bm, &bmop); + + EDBM_selectmode_flush(em); +} + +int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese) +{ + BMEditSelection *ese_last = em->bm->selected.last; + BMFace *efa = BM_active_face_get(em->bm, FALSE); + + ese->next = ese->prev = NULL; + + if (ese_last) { + if (ese_last->htype == 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->htype = BM_FACE; + } + else { + ese->data = ese_last->data; + ese->htype = ese_last->htype; + } + } + else if (efa) { /* no */ + ese->data = (void *)efa; + ese->htype = BM_FACE; + } + else { + ese->data = NULL; + return 0; + } + return 1; +} + +void EDBM_flag_disable_all(BMEditMesh *em, const char hflag) +{ + BM_mesh_elem_flag_disable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, hflag); +} + +void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) +{ + BM_mesh_elem_flag_enable_all(em->bm, BM_VERT|BM_EDGE|BM_FACE, hflag); +} + +/**************-------------- 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[MAX_ID_NAME - 2]; +} undomesh; + +/* undo simply makes copies of a bmesh */ +static void *editbtMesh_to_undoMesh(void *emv, void *obdata) +{ + BMEditMesh *em = emv; + Mesh *obme = obdata; + + undomesh *um = MEM_callocN(sizeof(undomesh), "undo Mesh"); + BLI_strncpy(um->obname, em->bm->ob->id.name + 2, sizeof(um->obname)); + + /* make sure shape keys work */ + um->me.key = obme->key ? copy_key_nolib(obme->key) : NULL; + +#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND + + /* we recalc the tesselation here, to avoid seeding calls to + * BMEdit_RecalcTesselation throughout the code. */ + BMEdit_RecalcTesselation(em); + +#endif + + BMO_op_callf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", &um->me, 1); + um->selectmode = em->selectmode; + + return um; +} + +static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata)) +{ + BMEditMesh *em = emv, *em2; + Object *ob; + undomesh *um = umv; + BMesh *bm; + + ob = (Object *)find_id("OB", um->obname); + ob->shapenr = em->bm->shapenr; + + BMEdit_Free(em); + + bm = BM_mesh_create(ob, bm_mesh_allocsize_default); + BMO_op_callf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", &um->me, ob, 0); + + em2 = BMEdit_Create(bm, TRUE); + *em = *em2; + + em->selectmode = um->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; */ /* UNUSED */ + MLoopUV *luv; + unsigned int a; + int totverts, i, totuv; + + if (do_face_idx_array) + EDBM_init_index_arrays(em, 0, 0, 1); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + totverts = em->bm->totvert; + totuv = 0; + + /* generate UvMapVert array */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_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_pt"); + 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_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_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_elem_index_get(l->v)]; + vmap->vert[BM_elem_index_get(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); */ /* UNUSED */ + + l = BM_iter_at_index(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); */ /* UNUSED */ + + l = BM_iter_at_index(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(uvdiff[0]) < limit[0] && fabs(uvdiff[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]; +} + +/* from editmesh_lib.c in trunk */ + + +/* A specialized vert map used by stitch operator */ +UvElementMap *EDBM_make_uv_element_map(BMEditMesh *em, int selected, int do_islands) +{ + BMVert *ev; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + /* vars from original func */ + UvElementMap *element_map; + UvElement *buf; + UvElement *islandbuf; + /* island number for faces */ + int *island_number; + + MLoopUV *luv; + int totverts, i, totuv, j, nislands = 0, islandbufsize = 0; + + unsigned int *map; + BMFace **stack; + int stacksize = 0; + + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + + totverts = em->bm->totvert; + totuv = 0; + + island_number = MEM_mallocN(sizeof(*stack)*em->bm->totface, "uv_island_number_face"); + if (!island_number) { + return NULL; + } + + /* generate UvElement array */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT))) + totuv += efa->len; + } + + if (totuv == 0) { + MEM_freeN(island_number); + return NULL; + } + element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap"); + if (!element_map) { + MEM_freeN(island_number); + return NULL; + } + element_map->totalUVs = totuv; + element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts, "UvElementVerts"); + buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv, "UvElement"); + + if (!element_map->vert || !element_map->buf) { + EDBM_free_uv_element_map(element_map); + MEM_freeN(island_number); + return NULL; + } + + j = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + island_number[j++] = INVALID_ISLAND; + if (!selected || ((!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) && BM_elem_flag_test(efa, BM_ELEM_SELECT))) { + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + buf->tfindex = i; + buf->face = efa; + buf->separate = 0; + buf->island = INVALID_ISLAND; + + buf->next = element_map->vert[BM_elem_index_get(l->v)]; + element_map->vert[BM_elem_index_get(l->v)] = buf; + + buf++; + i++; + } + } + } + + /* sort individual uvs for each vert */ + i = 0; + BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + UvElement *newvlist = NULL, *vlist = element_map->vert[i]; + UvElement *iterv, *v, *lastv, *next; + float *uv, *uv2, uvdiff[2]; + + while (vlist) { + v = vlist; + vlist = vlist->next; + v->next = newvlist; + newvlist = v; + + efa = v->face; + /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ + + l = BM_iter_at_index(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 = iterv->face; + /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ + + l = BM_iter_at_index(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 (fabsf(uvdiff[0]) < STD_UV_CONNECT_LIMIT && fabsf(uvdiff[1]) < STD_UV_CONNECT_LIMIT) { + if (lastv) lastv->next = next; + else vlist = next; + iterv->next = newvlist; + newvlist = iterv; + } + else { + lastv = iterv; + } + + iterv = next; + } + + newvlist->separate = 1; + } + + element_map->vert[i] = newvlist; + i++; + } + + if (do_islands) { + /* map holds the map from current vmap->buf to the new, sorted map */ + map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap"); + stack = MEM_mallocN(sizeof(*stack)*em->bm->totface, "uv_island_face_stack"); + islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer"); + + /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */ + for (i = 0; i < totuv; i++) { + if (element_map->buf[i].island == INVALID_ISLAND) { + element_map->buf[i].island = nislands; + stack[0] = element_map->buf[i].face; + island_number[BM_elem_index_get(stack[0])] = nislands; + stacksize = 1; + + while (stacksize > 0) { + efa = stack[--stacksize]; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)]; + + for (element = initelement; element; element = element->next) { + if (element->separate) + initelement = element; + + if (element->face == efa) { + /* found the uv corresponding to our face and vertex. Now fill it to the buffer */ + element->island = nislands; + map[element - element_map->buf] = islandbufsize; + islandbuf[islandbufsize].tfindex = element->tfindex; + islandbuf[islandbufsize].face = element->face; + islandbuf[islandbufsize].separate = element->separate; + islandbuf[islandbufsize].island = nislands; + islandbufsize++; + + for (element = initelement; element; element = element->next) { + if (element->separate && element != initelement) + break; + + if (island_number[BM_elem_index_get(element->face)] == INVALID_ISLAND) { + stack[stacksize++] = element->face; + island_number[BM_elem_index_get(element->face)] = nislands; + } + } + break; + } + } + } + } + + nislands++; + } + } + + /* remap */ + for (i = 0; i < em->bm->totvert; i++) { + /* important since we may do selection only. Some of these may be NULL */ + if (element_map->vert[i]) + element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]]; + } + + element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices)*nislands,"UvElementMap_island_indices"); + if (!element_map->islandIndices) { + MEM_freeN(islandbuf); + MEM_freeN(stack); + MEM_freeN(map); + EDBM_free_uv_element_map(element_map); + MEM_freeN(island_number); + } + + j = 0; + for (i = 0; i < totuv; i++) { + UvElement *element = element_map->buf[i].next; + if (element == NULL) + islandbuf[map[i]].next = NULL; + else + islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]]; + + if (islandbuf[i].island != j) { + j++; + element_map->islandIndices[j] = i; + } + } + + MEM_freeN(element_map->buf); + + element_map->buf = islandbuf; + element_map->totalIslands = nislands; + MEM_freeN(stack); + MEM_freeN(map); + } + MEM_freeN(island_number); + + return element_map; +} + + +UvMapVert *EM_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); + } +} + +void EDBM_free_uv_element_map(UvElementMap *element_map) +{ + if (element_map) { + if (element_map->vert) MEM_freeN(element_map->vert); + if (element_map->buf) MEM_freeN(element_map->buf); + if (element_map->islandIndices) MEM_freeN(element_map->islandIndices); + MEM_freeN(element_map); + } +} + +/* 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 = BM_active_face_get(em->bm, 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); +} + +static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) +{ + intptr_t eve_i = index_lookup[index]; + return (eve_i == -1) ? NULL : (BMVert *)eve_i; +} + +/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a + * preference */ +#define BM_SEARCH_MAXDIST_MIRR 0.00002f +#define BM_CD_LAYER_ID "__mirror_index" +void EDBM_CacheMirrorVerts(BMEditMesh *em, const short use_select) +{ + Mesh *me = em->me; + BMesh *bm = em->bm; + BMIter iter; + BMVert *v; + int li, topo = 0; + + /* one or the other is used depending if topo is enabled */ + BMBVHTree *tree = NULL; + MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1}; + + if (me && (me->editflag & ME_EDIT_MIRROR_TOPO)) { + topo = 1; + } + + if (!em->vert_index) { + EDBM_init_index_arrays(em, 1, 0, 0); + em->mirr_free_arrays = 1; + } + + if (!CustomData_get_layer_named(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID)) { + BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID); + } + + li = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID); + + bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY; + + BM_mesh_elem_index_ensure(bm, BM_VERT); + + if (topo) { + ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, TRUE); + } + else { + tree = BMBVH_NewBVH(em, 0, NULL, NULL); + } + + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + + /* temporary for testing, check for selection */ + if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) { + /* do nothing */ + } + else { + BMVert *mirr; + int *idx = CustomData_bmesh_get_layer_n(&bm->vdata, v->head.data, li); + + if (topo) { + mirr = cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, BM_elem_index_get(v)); + } + else { + float co[3] = {-v->co[0], v->co[1], v->co[2]}; + mirr = BMBVH_FindClosestVert(tree, co, BM_SEARCH_MAXDIST_MIRR); + } + + if (mirr && mirr != v) { + *idx = BM_elem_index_get(mirr); + idx = CustomData_bmesh_get_layer_n(&bm->vdata, mirr->head.data, li); + *idx = BM_elem_index_get(v); + } + else { + *idx = -1; + } + } + + } + + + if (topo) { + ED_mesh_mirrtopo_free(&mesh_topo_store); + } + else { + BMBVH_FreeBVH(tree); + } + + em->mirror_cdlayer = li; +} + +BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v) +{ + int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); + + BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ + + 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_ClearMirrorVert(BMEditMesh *em, BMVert *v) +{ + int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer); + + BLI_assert(em->mirror_cdlayer != -1); /* invalid use */ + + if (mirr) { + *mirr = -1; + } +} + +void EDBM_EndMirrorCache(BMEditMesh *em) +{ + if (em->mirr_free_arrays) { + MEM_freeN(em->vert_index); + em->vert_index = NULL; + } + + em->mirror_cdlayer = -1; +} + +void EDBM_ApplyMirrorCache(BMEditMesh *em, const int sel_from, const int sel_to) +{ + BMIter iter; + BMVert *v; + + BLI_assert(em->vert_index != NULL); + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) { + BMVert *mirr = EDBM_GetMirrorVert(em, v); + if (mirr) { + if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) { + copy_v3_v3(mirr->co, v->co); + mirr->co[0] *= -1.0f; + } + } + } + } +} diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 9107b30d928..bec1403a8dd 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -34,12 +34,11 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_heap.h" #include "BLI_edgehash.h" #include "BLI_editVert.h" -#include "BLI_utildefines.h" #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -52,6 +51,7 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BIF_gl.h" @@ -69,42 +69,75 @@ * use in object mode when selecting faces (while painting) */ void paintface_flush_flags(Object *ob) { - Mesh *me= get_mesh(ob); - DerivedMesh *dm= ob->derivedFinal; - MFace *faces, *mf, *mf_orig; + Mesh *me = get_mesh(ob); + DerivedMesh *dm = ob->derivedFinal; + MPoly *polys, *mp_orig; + MFace *faces; int *index_array = NULL; - int totface; + int totface, totpoly; int i; if(me==NULL || dm==NULL) return; - index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX); + /* + * Try to push updated mesh poly flags to three other data sets: + * - Mesh polys => Mesh tess faces + * - Mesh polys => Final derived polys + * - Final derived polys => Final derived tessfaces + */ - 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; + if ((index_array = CustomData_get_layer(&me->fdata, CD_POLYINDEX))) { + faces = me->mface; + totface = me->totface; + + /* loop over tessfaces */ + for (i= 0; i<totface; i++) { + /* Copy flags onto the original tessface from its original poly */ + mp_orig = me->mpoly + index_array[i]; + faces[i].flag = mp_orig->flag; + } + } + + if ((index_array = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX))) { + polys = dm->getPolyArray(dm); + totpoly = dm->getNumPolys(dm); + + /* loop over final derived polys */ + for (i= 0; i<totpoly; i++) { + /* Copy flags onto the final derived poly from the original mesh poly */ + mp_orig = me->mpoly + index_array[i]; + polys[i].flag = mp_orig->flag; + } + } + + if ((index_array = CustomData_get_layer(&dm->faceData, CD_POLYINDEX))) { + polys = dm->getPolyArray(dm); + faces = dm->getTessFaceArray(dm);; + totface = dm->getNumTessFaces(dm); + + /* loop over tessfaces */ + for (i= 0; i<totface; i++) { + /* Copy flags onto the final tessface from its final poly */ + mp_orig = polys + index_array[i]; + faces[i].flag = mp_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) { + 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 } @@ -114,14 +147,14 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un on an edge in the backbuf, we can still select a face */ int dist; - *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totface+1, &dist,0,NULL, NULL); + *index = view3d_sample_backbuf_rect(&vc, mval, 3, 1, me->totpoly+1, &dist,0,NULL, NULL); } else { /* sample only on the exact position */ *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)--; @@ -129,43 +162,17 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const int mval[2], un return 1; } -/* 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) -{ - EditFace *efa = NULL; - - if(!EM_texFaceCheck(em)) - return NULL; - - efa = EM_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); - } - 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) { @@ -187,14 +194,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; @@ -208,30 +215,29 @@ 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 *mp, 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); + MLoop *ml; + int i; + + for (i=0, ml=mloop; i<mp->totloop; i++, ml++) { + BLI_edgehash_insert(ehash, ml->v, ME_POLY_LOOP_NEXT(mloop, mp, i)->v, NULL); } - else - BLI_edgehash_insert(ehash, mf->v3, mf->v1, 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) @@ -239,17 +245,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; } } @@ -259,35 +265,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; } } @@ -299,24 +296,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; } @@ -331,7 +328,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,15 +346,15 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, int UNUSED(mval[2] void paintface_deselect_all_visible(Object *ob, int action, short 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; @@ -369,8 +366,8 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags) 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; @@ -380,8 +377,8 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags) } } - mface= me->mface; - a= me->totface; + mface= me->mpoly; + a= me->totpoly; while(a--) { if((mface->flag & ME_HIDE) == 0) { switch (action) { @@ -407,270 +404,65 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags) int paintface_minmax(Object *ob, float *min, float *max) { - Mesh *me= get_mesh(ob); - MFace *mf; - MVert *mv; - int a, ok=0; - float vec[3]; - - if(me==NULL) - return ok; - - 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; - } - } - return ok; -} - -/* ******************** edge loop shortest path ********************* */ - -#define ME_SEAM_DONE 2 /* reuse this flag */ - -static float edgetag_cut_cost(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 ); - float cost, d1[3], d2[3]; - - cost = len_v3v3(v1->co, v->co); - cost += len_v3v3(v->co, v2->co); - - sub_v3_v3v3(d1, v->co, v1->co); - sub_v3_v3v3(d2, v2->co, v->co); - - cost = cost + 0.5f*cost*(2.0f - fabsf(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2])); - - return cost; -} - -static void edgetag_add_adjacent(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); - float newcost; - - if (eedadj->f2 & ME_SEAM_DONE) - continue; - - newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum); - - if (cost[adjnum] > newcost) { - cost[adjnum] = newcost; - prevedge[adjnum] = mednum; - BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum)); - } - } -} - -void edgetag_context_set(Scene *scene, EditEdge *eed, int val) -{ - - switch (scene->toolsettings->edge_mode) { - case EDGE_MODE_SELECT: - EM_select_edge(eed, val); - break; - case EDGE_MODE_TAG_SEAM: - if (val) {eed->seam = 255;} - else {eed->seam = 0;} - break; - case EDGE_MODE_TAG_SHARP: - if (val) {eed->sharp = 1;} - else {eed->sharp = 0;} - break; - case EDGE_MODE_TAG_CREASE: - if (val) {eed->crease = 1.0f;} - else {eed->crease = 0.0f;} - break; - case EDGE_MODE_TAG_BEVEL: - if (val) {eed->bweight = 1.0f;} - else {eed->bweight = 0.0f;} - break; - case EDGE_MODE_TAG_FREESTYLE: - if (val) {eed->freestyle = 1;} - else {eed->freestyle = 0;} - break; - } -} - -int edgetag_context_check(Scene *scene, EditEdge *eed) -{ - switch (scene->toolsettings->edge_mode) { - case EDGE_MODE_SELECT: - return (eed->f & SELECT) ? 1 : 0; - case EDGE_MODE_TAG_SEAM: - return eed->seam ? 1 : 0; - case EDGE_MODE_TAG_SHARP: - return eed->sharp ? 1 : 0; - case EDGE_MODE_TAG_CREASE: - return eed->crease ? 1 : 0; - case EDGE_MODE_TAG_BEVEL: - return eed->bweight ? 1 : 0; - case EDGE_MODE_TAG_FREESTYLE: - return eed->freestyle ? 1 : 0; - } - return 0; -} - + Mesh *me; + MPoly *mf; + MTexPoly *tf; + MLoop *ml; + MVert *mvert; + int a, b, ok=0; + float vec[3], bmat[3][3]; -int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target) -{ - EditEdge *eed; - EditVert *ev; + me= get_mesh(ob); + if(!me || !me->mtpoly) return ok; - Heap *heap; - float *cost; - int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0; - + copy_m3_m4(bmat, ob->obmat); - /* we need the vert */ - for (ev= em->verts.first, totvert=0; ev; ev= ev->next) { - ev->tmp.l = totvert; - totvert++; - } - - for (eed= em->edges.first; eed; eed = eed->next) { - eed->f2 = 0; - if (eed->h) { - eed->f2 |= ME_SEAM_DONE; - } - eed->tmp.l = totedge; - totedge++; - } - - /* alloc */ - nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges"); - edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges"); - prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious"); - 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]++; - } - - for (a=1; a<totvert; a++) { - int newswap = nedges[a+1]; - nedges[a+1] = nedgeswap + nedges[a]; - nedgeswap = newswap; - } - 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; - - cost[a] = 1e20f; - prevedge[a] = -1; - } - - /* 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); - - - while (!BLI_heap_empty(heap)) { - mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap)); - eed = EM_get_edge_for_index( mednum ); - - if (mednum == target->tmp.l) - break; - - if (eed->f2 & ME_SEAM_DONE) + mvert= me->mvert; + 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; - eed->f2 |= 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); - } - - - 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; - } - - if (mednum != target->tmp.l) { - MEM_freeN(prevedge); - EM_free_index_arrays(); - return 0; - } - - /* follow path back to source and mark as seam */ - if (mednum == target->tmp.l) { - short allseams = 1; + ml = me->mloop + mf->totloop; + for (b=0; b<mf->totloop; b++, ml++) { + copy_v3_v3(vec, (mvert[ml->v].co)); + mul_m3_v3(bmat, vec); + add_v3_v3v3(vec, vec, ob->obmat[3]); + DO_MINMAX(vec, min, max); + } - mednum = target->tmp.l; - do { - eed = EM_get_edge_for_index( mednum ); - if (!edgetag_context_check(scene, eed)) { - allseams = 0; - break; - } - mednum = prevedge[mednum]; - } while (mednum != source->tmp.l); - - mednum = target->tmp.l; - do { - eed = EM_get_edge_for_index( mednum ); - if (allseams) - edgetag_context_set(scene, eed, 0); - else - edgetag_context_set(scene, eed, 1); - mednum = prevedge[mednum]; - } while (mednum != -1); + ok= 1; } - MEM_freeN(prevedge); - EM_free_index_arrays(); - return 1; + return ok; } /* *************************************** */ #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); + 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); } - else - BLI_edgehash_insert(ehash, mf->v3, mf->v1, 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"); @@ -681,9 +473,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)) @@ -696,11 +488,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++) @@ -722,21 +514,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; @@ -764,25 +559,34 @@ 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(ob); - me= get_mesh(vc->obact); - - if(me==NULL || me->totface==0 || sx*sy <= 0) + if(me==NULL || me->totpoly==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); @@ -794,13 +598,13 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) while(a--) { if(*rt) { index= WM_framebuffer_to_index(*rt); - if(index<=me->totface) selar[index]= 1; + if(index<=me->totpoly) selar[index]= 1; } 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 { @@ -823,6 +627,104 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend) } +/* (similar to void paintface_flush_flags(Object *ob)) + * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, + * use in object mode when selecting vertices (while painting) */ +void paintvert_flush_flags(Object *ob) +{ + Mesh *me= get_mesh(ob); + DerivedMesh *dm= ob->derivedFinal; + MVert *dm_mvert, *dm_mv; + int *index_array = NULL; + int totvert; + int i; + + if(me==NULL || dm==NULL) + return; + + index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); + + dm_mvert = dm->getVertArray(dm); + totvert = dm->getNumVerts(dm); + + dm_mv= dm_mvert; + + if(index_array) { + int orig_index; + for (i= 0; i<totvert; i++, dm_mv++) { + orig_index= index_array[i]; + if(orig_index != ORIGINDEX_NONE) { + dm_mv->flag= me->mvert[index_array[i]].flag; + } + } + } + else { + for (i= 0; i<totvert; i++, dm_mv++) { + dm_mv->flag= me->mvert[i].flag; + } + } +} +/* note: if the caller passes FALSE to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */ +void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags) +{ + Mesh *me; + MVert *mvert; + int a; + + me= get_mesh(ob); + if(me==NULL) return; + + if(action == SEL_INVERT) { + mvert= me->mvert; + a= me->totvert; + while(a--) { + if((mvert->flag & ME_HIDE) == 0) { + mvert->flag ^= SELECT; + } + mvert++; + } + } + else { + if (action == SEL_TOGGLE) { + action = SEL_SELECT; + + mvert= me->mvert; + a= me->totvert; + while(a--) { + if((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) { + action = SEL_DESELECT; + break; + } + mvert++; + } + } + + mvert= me->mvert; + a= me->totvert; + while(a--) { + if((mvert->flag & ME_HIDE) == 0) { + switch (action) { + case SEL_SELECT: + mvert->flag |= SELECT; + break; + case SEL_DESELECT: + mvert->flag &= ~SELECT; + break; + case SEL_INVERT: + mvert->flag ^= SELECT; + break; + } + } + mvert++; + } + } + + if(flush_flags) { + paintvert_flush_flags(ob); + } +} + + /* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ /* note, this is not the best place for the function to be but moved * here to for the purpose of syncing with bmesh */ @@ -853,9 +755,9 @@ int ED_mesh_mirrtopo_recalc_check(Mesh *me, const int ob_mode, MirrTopoStore_t * int totvert; int totedge; - if (me->edit_mesh) { - totvert = me->edit_mesh->totvert; - totedge = me->edit_mesh->totedge; + if (me->edit_btmesh) { + totvert = me->edit_btmesh->bm->totvert; + totedge = me->edit_btmesh->bm->totedge; } else { totvert = me->totvert; @@ -879,11 +781,11 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to const short skip_em_vert_array_init) { MEdge *medge; - EditMesh *em = me->edit_mesh; - void **eve_tmp_back = NULL; /* some of the callers are using eve->tmp so restore after */ + BMEditMesh *em = me->edit_btmesh; /* editmode*/ - EditEdge *eed; + BMEdge *eed; + BMIter iter; int a, last; int totvert, totedge; @@ -901,13 +803,9 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to mesh_topo_store->prev_ob_mode = ob_mode; if(em) { - EditVert *eve; - totvert = 0; - eve_tmp_back = MEM_mallocN(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_mesh_elem_index_ensure(em->bm, BM_VERT); + + totvert = em->bm->totvert; } else { totvert = me->totvert; @@ -917,11 +815,11 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to /* Initialize the vert-edge-user counts used to detect unique topology */ if(em) { - totedge = 0; + totedge = me->edit_btmesh->bm->totedge; - for(eed=em->edges.first; eed; eed = eed->next, totedge++) { - topo_hash[eed->v1->tmp.l]++; - topo_hash[eed->v2->tmp.l]++; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + topo_hash[BM_elem_index_get(eed->v1)]++; + topo_hash[BM_elem_index_get(eed->v2)]++; } } else { @@ -940,9 +838,9 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to /* use the number of edges per vert to give verts unique topology IDs */ if(em) { - for(eed=em->edges.first; eed; eed = eed->next) { - topo_hash[eed->v1->tmp.l] += topo_hash_prev[eed->v2->tmp.l]; - topo_hash[eed->v2->tmp.l] += topo_hash_prev[eed->v1->tmp.l]; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + topo_hash[BM_elem_index_get(eed->v1)] += topo_hash_prev[BM_elem_index_get(eed->v2)]; + topo_hash[BM_elem_index_get(eed->v2)] += topo_hash_prev[BM_elem_index_get(eed->v1)]; } } else { @@ -976,19 +874,6 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * 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 */ topo_pairs = MEM_callocN( sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); @@ -997,7 +882,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to if(em) { if (skip_em_vert_array_init == FALSE) { - EM_init_index_arrays(em, 1, 0, 0); + EDBM_init_index_arrays(em,1, 0, 0); } } @@ -1018,12 +903,12 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, * but you cant ever access the last 'a' index of MirrTopoPairs */ for(a=2; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].vIndex ); */ + /* printf("I %d %ld %d\n", (a-last), MirrTopoPairs[a ].hash, MirrTopoPairs[a ].v_index ); */ if ((a==totvert) || (topo_pairs[a-1].hash != topo_pairs[a].hash)) { if (a-last==2) { if(em) { - index_lookup[topo_pairs[a-1].v_index] = (intptr_t)EM_get_vert_for_index(topo_pairs[a-2].v_index); - index_lookup[topo_pairs[a-2].v_index] = (intptr_t)EM_get_vert_for_index(topo_pairs[a-1].v_index); + index_lookup[topo_pairs[a-1].v_index] = (intptr_t)EDBM_get_vert_for_index(em, topo_pairs[a-2].v_index); + index_lookup[topo_pairs[a-2].v_index] = (intptr_t)EDBM_get_vert_for_index(em, topo_pairs[a-1].v_index); } else { index_lookup[topo_pairs[a-1].v_index] = topo_pairs[a-2].v_index; @@ -1035,7 +920,7 @@ void ED_mesh_mirrtopo_init(Mesh *me, const int ob_mode, MirrTopoStore_t *mesh_to } if(em) { if (skip_em_vert_array_init == FALSE) { - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } } diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c deleted file mode 100644 index 26645b66c7f..00000000000 --- a/source/blender/editors/mesh/editmesh.c +++ /dev/null @@ -1,2074 +0,0 @@ -/* - * ***** 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->freestyle = example->freestyle; - 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; - - 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_face_sel= paint_facesel_test(ob); - const short is_paint_vert_sel= is_paint_face_sel ? FALSE : paint_vertsel_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_face_sel) - eve->f |= (mvert->flag & SELECT); - - 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) { - int is_sel; - if (is_paint_vert_sel) { - /* when from vertex select, flush flags to edges, - * allow selection, code below handles editmode selection conversion */ - is_sel= (eed->v1->f & SELECT) && (eed->v2->f & SELECT); - } - else { - is_sel= (medge->flag & SELECT); - } - - 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 & ME_FREESTYLE_EDGE) eed->freestyle = 1; - if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines! - if(medge->flag & ME_HIDE) eed->h |= 1; - if(is_sel) eed->f |= SELECT; - 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 { - int is_sel; - - if (!is_paint_vert_sel) { - is_sel= (mface->flag & ME_FACE_SEL); - } - else { - /* when from vertex select, flush flags to edges, - * allow selection, code below handles editmode selection conversion */ - is_sel= ( (efa->v1->f & SELECT) && - (efa->v2->f & SELECT) && - (efa->v3->f & SELECT) && - (efa->v4 == NULL || efa->v4->f & SELECT) - ); - } - - if (a==me->act_face) { - EM_set_actFace(em, efa); - } - - /* dont allow hidden and selected */ - if(is_sel) { - efa->f |= SELECT; - - if(is_paint_face_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->freestyle) medge->flag |= ME_FREESTYLE_EDGE; - 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==obedit && 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) { - sub_v3_v3v3(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(em->totfacesel > 0) { - mesh_separate_selected(op, bmain, scene, editbase); - } - } - - 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_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, freestyle; - 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; - 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); - 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++) { - copy_v3_v3(evec->co, eve->co); - copy_v3_v3(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->freestyle= eed->freestyle; - 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; - } - - 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; - - copy_v3_v3(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->freestyle= eedc->freestyle; - 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); -} - -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; - } -} - - -/* (similar to void paintface_flush_flags(Object *ob)) - * copy the vertex flags, most importantly selection from the mesh to the final derived mesh, - * use in object mode when selecting vertices (while painting) */ -void paintvert_flush_flags(Object *ob) -{ - Mesh *me= get_mesh(ob); - DerivedMesh *dm= ob->derivedFinal; - MVert *dm_mvert, *dm_mv; - int *index_array = NULL; - int totvert; - int i; - - if(me==NULL || dm==NULL) - return; - - index_array = dm->getVertDataArray(dm, CD_ORIGINDEX); - - dm_mvert = dm->getVertArray(dm); - totvert = dm->getNumVerts(dm); - - dm_mv= dm_mvert; - - if(index_array) { - int orig_index; - for (i= 0; i<totvert; i++, dm_mv++) { - orig_index= index_array[i]; - if(orig_index != ORIGINDEX_NONE) { - dm_mv->flag= me->mvert[index_array[i]].flag; - } - } - } - else { - for (i= 0; i<totvert; i++, dm_mv++) { - dm_mv->flag= me->mvert[i].flag; - } - } -} -/* note: if the caller passes FALSE to flush_flags, then they will need to run paintvert_flush_flags(ob) themselves */ -void paintvert_deselect_all_visible(Object *ob, int action, short flush_flags) -{ - Mesh *me; - MVert *mvert; - int a; - - me= get_mesh(ob); - if(me==NULL) return; - - if(action == SEL_INVERT) { - mvert= me->mvert; - a= me->totvert; - while(a--) { - if((mvert->flag & ME_HIDE) == 0) { - mvert->flag ^= SELECT; - } - mvert++; - } - } - else { - if (action == SEL_TOGGLE) { - action = SEL_SELECT; - - mvert= me->mvert; - a= me->totvert; - while(a--) { - if((mvert->flag & ME_HIDE) == 0 && mvert->flag & SELECT) { - action = SEL_DESELECT; - break; - } - mvert++; - } - } - - mvert= me->mvert; - a= me->totvert; - while(a--) { - if((mvert->flag & ME_HIDE) == 0) { - switch (action) { - case SEL_SELECT: - mvert->flag |= SELECT; - break; - case SEL_DESELECT: - mvert->flag &= ~SELECT; - break; - case SEL_INVERT: - mvert->flag ^= SELECT; - break; - } - } - mvert++; - } - } - - if(flush_flags) { - paintvert_flush_flags(ob); - } -} diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index 043e02ab1d0..ea9dc73ee94 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -20,7 +20,7 @@ * * The Original Code is: all of this file. * - * Contributor(s): none yet. + * Contributor(s): Joseph Eagar * * ***** END GPL LICENSE BLOCK ***** */ @@ -29,1370 +29,99 @@ * \ingroup edmesh */ - - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_meshdata_types.h" +#include "DNA_mesh_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 "BKE_tessmesh.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= dot_v3v3(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) +/* 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); - 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; + View3D *v3d =CTX_wm_view3d(C); + float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - -} + unit_m4(primmat); - - -/* ************************ 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; - float len, len2, vec2[3]; - - 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); - } - - /* length of one segment on meridian */ - len= 2*dia*sinf(phid / 2.0f); - - /* length of one segment in shortest parallen */ - vec[0]= dia*sinf(phid); - vec[1]= 0.0; - vec[2]= dia*cosf(phid); - - mul_v3_m3v3(vec2, cmat, vec); - len2= len_v3v3(vec, vec2); - - /* use shortest segment length divided by 3 as merge threshold */ - removedoublesflag(em, 4, 0, MIN2(len, len2) / 3.0f); - - /* 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); - } - } + eul_to_mat3(rmat, rot); + invert_m3(rmat); - 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 */ + /* 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); - 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 */ + /* center */ + copy_v3_v3(primmat[3], loc); + sub_v3_v3(primmat[3], obedit->obmat[3]); + invert_m3_m3(imat, mat); + mul_m3_v3(imat, primmat[3]); - BKE_mesh_end_editmesh(obedit->data, em); + return v3d ? v3d->grid : 1.0f; } /* ********* 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) +static void make_prim_init(bContext *C, const char *idname, + float *dia, float mat[][4], + int *state, float *loc, float *rot, unsigned int layer) { Object *obedit= CTX_data_edit_object(C); - int newob = 0; - float mat[4][4]; - float scale; + *state = 0; 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)); - + rename_id((ID *)obedit, idname); + rename_id((ID *)obedit->data, idname); + /* create editmode */ ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */ - newob = 1; + *state = 1; } else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); - scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat); + *dia *= new_primitive_matrix(C, loc, rot, mat); +} + +static void make_prim_finish(bContext *C, int *state, int enter_editmode) +{ + Object *obedit; + Mesh *me; + BMEditMesh *em; - dia *= scale; - depth *= scale * 0.5f; + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; - make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill); + /* Primitive has all verts selected, use vert select flush + * to push this up to edges & faces. */ + EDBM_selectmode_flush_ex(em, SCE_SELECT_VERTEX); - DAG_id_tag_update(obedit->data, 0); + DAG_id_tag_update(obedit->data, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - /* userdef */ - if (newob && !enter_editmode) { + 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); @@ -1400,16 +129,27 @@ static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmod 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 = 1.0f; int enter_editmode; + int state; unsigned int layer; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, "Plane", &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, dia, mat)) 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); + make_prim_finish(C, &state, enter_editmode); + return OPERATOR_FINISHED; } @@ -1433,16 +173,27 @@ void MESH_OT_primitive_plane_add(wmOperatorType *ot) 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, "Cube", &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: M_SQRT2 - plane (diameter of 1.41 makes it unit size) */ + make_prim_finish(C, &state, enter_editmode); - /* 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; } @@ -1464,21 +215,41 @@ void MESH_OT_primitive_cube_add(wmOperatorType *ot) 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + 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, "Circle", &dia, mat, &state, loc, rot, layer); - 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")); + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; - return OPERATOR_FINISHED; + 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) @@ -1502,26 +273,39 @@ void MESH_OT_primitive_circle_add(wmOperatorType *ot) RNA_def_int(ot->srna, "vertices", 32, 3, INT_MAX, "Vertices", "", 3, 500); prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); RNA_def_property_subtype(prop, PROP_DISTANCE); - RNA_def_boolean(ot->srna, "fill", 0, "Fill", ""); + 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + 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, "Cylinder", &dia, mat, &state, loc, rot, layer); - 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")); + 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; } @@ -1548,26 +332,40 @@ void MESH_OT_primitive_cylinder_add(wmOperatorType *ot) RNA_def_property_subtype(prop, PROP_DISTANCE); prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); RNA_def_property_subtype(prop, PROP_DISTANCE); - RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", ""); + 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + 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, "Cone", &dia, mat, &state, loc, rot, layer); - 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")); + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; - return OPERATOR_FINISHED; + 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) @@ -1589,29 +387,44 @@ void MESH_OT_primitive_cone_add(wmOperatorType *ot) /* props */ RNA_def_int(ot->srna, "vertices", 32, 2, INT_MAX, "Vertices", "", 2, 500); - prop = RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00); + prop = RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00); + RNA_def_property_subtype(prop, PROP_DISTANCE); + prop = RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00); RNA_def_property_subtype(prop, PROP_DISTANCE); prop = RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00); RNA_def_property_subtype(prop, PROP_DISTANCE); - RNA_def_boolean(ot->srna, "cap_end", 1, "Cap End", ""); + 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 = 1.0f; int enter_editmode; + int state; 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; + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, "Grid", &dia, mat, &state, loc, rot, layer); - 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); + 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") * dia, mat)) + { + return OPERATOR_CANCELLED; + } + + make_prim_finish(C, &state, enter_editmode); return OPERATOR_FINISHED; } @@ -1643,16 +456,29 @@ void MESH_OT_primitive_grid_add(wmOperatorType *ot) 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + 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, "Monkey", &dia, mat, &state, loc, rot, layer); - make_prim_ext(C, loc, rot, enter_editmode, layer, - PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0); + 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; } @@ -1676,17 +502,28 @@ void MESH_OT_primitive_monkey_add(wmOperatorType *ot) 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, "Sphere", &dia, mat, &state, loc, rot, layer); + + obedit = CTX_data_edit_object(C); + me = obedit->data; + em = me->edit_btmesh; - 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); + if (!EDBM_CallAndSelectOpf(em, op, "vertout", + "create_uvsphere segments=%i revolutions=%i diameter=%f mat=%m4", + RNA_int_get(op->ptr, "ring_count"), 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; } @@ -1719,16 +556,29 @@ void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot) 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; - float loc[3], rot[3]; - if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer)) - return OPERATOR_CANCELLED; + ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL); + make_prim_init(C, "Icosphere", &dia, mat, &state, loc, rot, layer); - 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); + 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; } @@ -1757,47 +607,3 @@ void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot) 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_bvh.c b/source/blender/editors/mesh/editmesh_bvh.c new file mode 100644 index 00000000000..cc1f89e2c8b --- /dev/null +++ b/source/blender/editors/mesh/editmesh_bvh.c @@ -0,0 +1,418 @@ +/* + * ***** 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) 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 "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_view3d_types.h" + + +#include "BLI_math.h" +#include "BLI_smallhash.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_tessmesh.h" + +#include "ED_mesh.h" +#include "ED_view3d.h" + + +typedef struct BMBVHTree { + BMEditMesh *em; + BMesh *bm; + BVHTree *tree; + float epsilon; + float maxdist; //for nearest point search + float uv[2]; + + /*stuff for topological vert search*/ + BMVert *v, *curv; + GHash *gh; + float curw, curd; + float co[3], (*cagecos)[3], (*cos)[3]; + int curtag, flag; + + Object *ob; + Scene *scene; +} BMBVHTree; + +static void cage_mapped_verts_callback(void *userData, int index, float *co, + float *UNUSED(no_f), short *UNUSED(no_s)) +{ + void **data = userData; + BMEditMesh *em = data[0]; + float (*cagecos)[3] = data[1]; + SmallHash *hash = data[2]; + + if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) { + BLI_smallhash_insert(hash, index, NULL); + copy_v3_v3(cagecos[index], co); + } +} + +BMBVHTree *BMBVH_NewBVH(BMEditMesh *em, int flag, Scene *scene, Object *obedit) +{ + BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree"); + DerivedMesh *cage, *final; + SmallHash shash; + float cos[3][3], (*cagecos)[3] = NULL; + int i; + + /*when initializing cage verts, we only want the first cage coordinate for each vertex, + so that e.g. mirror or array use original vertex coordiantes and not mirrored or duplicate*/ + BLI_smallhash_init(&shash); + + BMEdit_RecalcTesselation(em); + + tree->ob = obedit; + tree->scene = scene; + tree->em = em; + tree->bm = em->bm; + tree->epsilon = FLT_EPSILON*2.0f; + tree->flag = flag; + + tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8); + + if (flag & BMBVH_USE_CAGE) { + BMIter iter; + BMVert *v; + void *data[3]; + + tree->cos = MEM_callocN(sizeof(float)*3*em->bm->totvert, "bmbvh cos"); + BM_ITER_INDEX(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL, i) { + BM_elem_index_set(v, i); /* set_inline */ + copy_v3_v3(tree->cos[i], v->co); + } + em->bm->elem_index_dirty &= ~BM_VERT; + + + cage = editbmesh_get_derived_cage_and_final(scene, obedit, em, &final, CD_MASK_DERIVEDMESH); + cagecos = MEM_callocN(sizeof(float)*3*em->bm->totvert, "bmbvh cagecos"); + + data[0] = em; + data[1] = cagecos; + data[2] = &shash; + + cage->foreachMappedVert(cage, cage_mapped_verts_callback, data); + } + + tree->cagecos = cagecos; + + for (i=0; i<em->tottri; i++) { + if (flag & BMBVH_USE_CAGE) { + copy_v3_v3(cos[0], cagecos[BM_elem_index_get(em->looptris[i][0]->v)]); + copy_v3_v3(cos[1], cagecos[BM_elem_index_get(em->looptris[i][1]->v)]); + copy_v3_v3(cos[2], cagecos[BM_elem_index_get(em->looptris[i][2]->v)]); + } else { + copy_v3_v3(cos[0], em->looptris[i][0]->v->co); + copy_v3_v3(cos[1], em->looptris[i][1]->v->co); + copy_v3_v3(cos[2], em->looptris[i][2]->v->co); + } + + BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3); + } + + BLI_bvhtree_balance(tree->tree); + BLI_smallhash_release(&shash); + + return tree; +} + +void BMBVH_FreeBVH(BMBVHTree *tree) +{ + BLI_bvhtree_free(tree->tree); + + if (tree->cagecos) + MEM_freeN(tree->cagecos); + if (tree->cos) + MEM_freeN(tree->cos); + + 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(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv)) + return dist; + + 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; + + copy_v3_v3(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); + + copy_v2_v2(tree->uv, uv); + } +} + +BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout, float *cagehit) +{ + BVHTreeRayHit hit; + + hit.dist = FLT_MAX; + hit.index = -1; + + tree->uv[0] = tree->uv[1] = 0.0f; + + BLI_bvhtree_ray_cast(tree->tree, co, dir, 0.0f, &hit, raycallback, tree); + if (hit.dist != FLT_MAX && hit.index != -1) { + if (hitout) { + if (tree->flag & BMBVH_RETURN_ORIG) { + BMVert *v1, *v2, *v3; + float co[3]; + int i; + + v1 = tree->em->looptris[hit.index][0]->v; + v2 = tree->em->looptris[hit.index][1]->v; + v3 = tree->em->looptris[hit.index][2]->v; + + for (i=0; i<3; i++) { + co[i] = v1->co[i] + (v2->co[i] - v1->co[i])*tree->uv[0] + (v3->co[i]-v1->co[i])*tree->uv[1]; + } + copy_v3_v3(hitout, co); + } else { + copy_v3_v3(hitout, hit.co); + } + + if (cagehit) + copy_v3_v3(cagehit, 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) { + copy_v3_v3(hit->co, ls[i]->v->co); + copy_v3_v3(hit->no, ls[i]->v->no); + hit->dist = dist; + hit->index = index; + } + } +} + +BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist) +{ + BVHTreeNearest hit; + + copy_v3_v3(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[cur]->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; + +/* UNUSED */ +#if 0 +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; +} +#endif + +#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, NULL); + + 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); + + copy_v3_v3(co1, e->v1->co); + add_v3_v3v3(co2, e->v1->co, e->v2->co); + mul_v3_fl(co2, 0.5f); + copy_v3_v3(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/editmesh_bvh.h b/source/blender/editors/mesh/editmesh_bvh.h new file mode 100644 index 00000000000..c8baa804205 --- /dev/null +++ b/source/blender/editors/mesh/editmesh_bvh.h @@ -0,0 +1,67 @@ +/* + * ***** 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. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/editmesh_bvh.h + * \ingroup edmesh + */ + +#ifndef __EDITBMESH_BVH_H__ +#define __EDITBMESH_BVH_H__ + +struct BMEditMesh; +struct BMFace; +struct BMEdge; +struct BMVert; +struct RegionView3D; +struct BMBVHTree; +struct BVHTree; +struct Scene; +struct Object; + +#ifndef IN_EDITMESHBVH +typedef struct BMBVHTree BMBVHTree; +#endif + +struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em, int flag, struct Scene *scene, struct Object *obedit); +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, float *cagehit); + +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); + +/*BMBVH_NewBVH flag parameter*/ +#define BMBVH_USE_CAGE 1 /*project geometry onto modifier cage */ +#define BMBVH_RETURN_ORIG 2 /*use with BMBVH_USE_CAGE, returns hits in relation to original geometry*/ + +#endif /* __EDITBMESH_BVH_H__ */ diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c deleted file mode 100644 index 2895f5c34e6..00000000000 --- a/source/blender/editors/mesh/editmesh_lib.c +++ /dev/null @@ -1,3070 +0,0 @@ -/* - * ***** 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 along 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 useful 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 along 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(dot_v3v3(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; - copy_v3_v3(v1->no, efa->n); - copy_v3_v3(v2->no, efa->n); - copy_v3_v3(v3->no, efa->n); - if(efa->v4) { - v4= addvertlist(em, efa->v4->co, efa->v4); - v4->f1= 1; - copy_v3_v3(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); - - /* step 5; update normals after extrude */ - recalc_editnormals(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; - } - - /* update normals after extrude */ - recalc_editnormals(em); - - 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) && (md->mode & eModifierMode_Realtime)) { - 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); - mult_m4_m4m4(mtx, imtx, obedit->obmat); - } - - 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); - - /* step 8; update normals after extrude */ - recalc_editnormals(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) && (md->mode & eModifierMode_Realtime)) { - 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); - mult_m4_m4m4(mtx, imtx, obedit->obmat); - } - - 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); - - copy_v3_v3(v1->co, eve->co); - copy_v3_v3(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; - - 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]; - - 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; -} - -/* A specialized vert map used by stitch operator */ -UvElementMap *EM_make_uv_element_map(EditMesh *em, int selected, int do_islands) -{ - EditVert *ev; - EditFace *efa; - - /* vars from original func */ - UvElementMap *vmap; - UvElement *buf; - UvElement *islandbuf; - MTFace *tf; - unsigned int a; - int i,j, totuv, nverts, nislands = 0, islandbufsize = 0; - unsigned int *map; - /* for uv island creation */ - EditFace **stack; - int stacksize = 0; - - /* we need the vert */ - for(ev = em->verts.first, i = 0; ev; ev = ev->next, i++) - ev->tmp.l = i; - - totuv = 0; - - for(efa = em->faces.first; efa; efa = efa->next) - if(!selected || ((!efa->h) && (efa->f & SELECT))) - totuv += (efa->v4)? 4: 3; - - if(totuv == 0) - return NULL; - - vmap = (UvElementMap *)MEM_callocN(sizeof(*vmap), "UvVertElementMap"); - if(!vmap) - return NULL; - - vmap->vert = (UvElement**)MEM_callocN(sizeof(*vmap->vert)*em->totvert, "UvElementVerts"); - buf = vmap->buf = (UvElement*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvElement"); - - if(!vmap->vert || !vmap->buf) { - EM_free_uv_element_map(vmap); - return NULL; - } - - vmap->totalUVs = totuv; - - for(efa = em->faces.first; efa; 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->face = efa; - buf->separate = 0; - buf->island = INVALID_ISLAND; - - buf->next = vmap->vert[(*(&efa->v1 + i))->tmp.l]; - vmap->vert[(*(&efa->v1 + i))->tmp.l] = buf; - - buf++; - } - } - - efa->tmp.l = INVALID_ISLAND; - } - - /* sort individual uvs for each vert */ - for(a = 0, ev = em->verts.first; ev; a++, ev = ev->next) { - UvElement *newvlist = NULL, *vlist = vmap->vert[a]; - UvElement *iterv, *v, *lastv, *next; - float *uv, *uv2; - - while(vlist) { - v= vlist; - vlist= vlist->next; - v->next= newvlist; - newvlist= v; - - efa = v->face; - 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 = iterv->face; - tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - uv2 = tf->uv[iterv->tfindex]; - - if(fabsf(uv[0]-uv2[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-uv2[1]) < STD_UV_CONNECT_LIMIT) { - 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_islands) { - /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */ - - /* map holds the map from current vmap->buf to the new, sorted map*/ - map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap"); - stack = MEM_mallocN(sizeof(*stack)*em->totface, "uv_island_face_stack"); - islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer"); - - for(i = 0; i < totuv; i++) { - if(vmap->buf[i].island == INVALID_ISLAND) { - vmap->buf[i].island = nislands; - stack[0] = vmap->buf[i].face; - stack[0]->tmp.l = nislands; - stacksize=1; - - while(stacksize > 0) { - efa = stack[--stacksize]; - nverts = efa->v4? 4 : 3; - - for(j = 0; j < nverts; j++) { - UvElement *element, *initelement = vmap->vert[(*(&efa->v1 + j))->tmp.l]; - - for(element = initelement; element; element = element->next) { - if(element->separate) - initelement = element; - - if(element->face == efa) { - /* found the uv corresponding to our face and vertex. Now fill it to the buffer */ - element->island = nislands; - map[element - vmap->buf] = islandbufsize; - islandbuf[islandbufsize].tfindex = element->tfindex; - islandbuf[islandbufsize].face = element->face; - islandbuf[islandbufsize].separate = element->separate; - islandbuf[islandbufsize].island = nislands; - islandbufsize++; - - for(element = initelement; element; element = element->next) { - if(element->separate && element != initelement) - break; - - if(element->face->tmp.l == INVALID_ISLAND) { - stack[stacksize++] = element->face; - element->face->tmp.l = nislands; - } - } - break; - } - } - } - } - - nislands++; - } - } - - /* remap */ - for(i = 0; i < em->totvert; i++) { - /* important since we may do selection only. Some of these may be NULL */ - if(vmap->vert[i]) - vmap->vert[i] = &islandbuf[map[vmap->vert[i] - vmap->buf]]; - } - - vmap->islandIndices = MEM_callocN(sizeof(*vmap->islandIndices)*nislands,"UvVertMap2_island_indices"); - if(!vmap->islandIndices) { - MEM_freeN(islandbuf); - MEM_freeN(stack); - MEM_freeN(map); - EM_free_uv_element_map(vmap); - } - - j = 0; - for(i = 0; i < totuv; i++) { - UvElement *element = vmap->buf[i].next; - if(element == NULL) - islandbuf[map[i]].next = NULL; - else - islandbuf[map[i]].next = &islandbuf[map[element - vmap->buf]]; - - if(islandbuf[i].island != j) { - j++; - vmap->islandIndices[j] = i; - } - } - - MEM_freeN(vmap->buf); - - vmap->buf = islandbuf; - vmap->totalIslands = nislands; - MEM_freeN(stack); - MEM_freeN(map); - } - - 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); - } -} - -void EM_free_uv_element_map(UvElementMap *vmap) -{ - if (vmap) { - if (vmap->vert) MEM_freeN(vmap->vert); - if (vmap->buf) MEM_freeN(vmap->buf); - if (vmap->islandIndices) MEM_freeN(vmap->islandIndices); - 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; - unsigned 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); \ - { \ - const unsigned int mf_v1 = EDV1; \ - const unsigned int mf_v2 = EDV2; \ - edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, mf_v1, mf_v2); \ - 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, mf_v1, mf_v2, 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, &ed_v1, &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 */ - copy_v3_v3(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); - copy_v3_v3(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 01695331542..00000000000 --- a/source/blender/editors/mesh/editmesh_loop.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * ***** 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 "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 ******** */ - -/* ***************** 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.001f; /* prevent missed edges */ - x2min=MIN2(x21,x22)-0.001f; /* due to round off error */ - y2max=MAX2(y21,y22)+0.001f; - y2min=MIN2(y21,y22)-0.001f; - - /* 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.0f; - - y1max=MAX2(y11, y12); - y1min=MIN2(y11, y12); - yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0f; - } - 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.0f) && (m2 >= -1.0f)) 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_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - ED_view3d_operator_properties_viewmat_set(C, op); - - return WM_gesture_lines_invoke(C, op, event); -} - -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)); - 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 winx, winy; - float persmat[4][4]; -// 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 (obedit == NULL) - 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; - } - - ED_view3d_operator_properties_viewmat_get(op, &winx, &winy, persmat); - - /*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); - apply_project_float(persmat, winx, winy, 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= knife_cut_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 */ - prop = RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_HIDDEN); - - ED_view3d_operator_properties_viewmat(ot); -} - -/* ******************************************************* */ - diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c deleted file mode 100644 index d7ec83e64e3..00000000000 --- a/source/blender/editors/mesh/editmesh_mods.c +++ /dev/null @@ -1,4527 +0,0 @@ -/* - * ***** 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; */ /* UNUSED */ - - 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 = */ /* UNUSED */ 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 if(paint_vertsel_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 if (paint_vertsel_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, V3D_CLIP_TEST_RV3D_CLIPPING); - - if (data.dist>3) { - data.pass = 1; - mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, V3D_CLIP_TEST_RV3D_CLIPPING); - } - - *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, V3D_CLIP_TEST_REGION); - - *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 -#define SIMEDGE_FREESTYLE 109 - -/* 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", ""}, - {SIMEDGE_FREESTYLE, "FREESTYLE", 0, "Freestyle Edge Mark", ""}, - {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_v3v3(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_v3v3(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; -} - -/* ***************************************************** */ - -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_v3v3(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_v3v3(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; - } - } - } else if (mode==SIMEDGE_FREESTYLE) { /* Freestyle edge mark */ - for(eed= em->edges.first; eed; eed= eed->next) { - if ( - !(eed->f & SELECT) && - !eed->h && - (eed->freestyle == base_eed->freestyle) - ) { - 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_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; -} - -/* ********************************* */ - -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 OPERATOR_CANCELLED; - } - - 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_v3v3(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 OPERATOR_FINISHED; - } - } - } - } - } - 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 OPERATOR_FINISHED; - } - } - } - } - 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 OPERATOR_FINISHED; - } - - 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 OPERATOR_FINISHED; - } - 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; -} - -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; - } else { - tf->tpage = NULL; - } - 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; - } else { - tf->tpage = NULL; - } - 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 UNUSED_FUNCTION(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; - case EDGE_MODE_TAG_FREESTYLE: - me->drawflag |= ME_DRAW_FREESTYLE_EDGE; - 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_struct_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); - else - RNA_boolean_set(op->ptr, "limit", FALSE); - } -} - -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()) - -} - -/* ******************** (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 editmesh_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= editmesh_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", ""); -} - -static int editmesh_mark_freestyle_edge(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 Freestyle edge mark drawing */ - if(!clear) { - me->drawflag |= ME_DRAW_FREESTYLE_EDGE; - } - - if(!clear) { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->freestyle = 1; - eed = eed->next; - } - } else { - eed= em->edges.first; - while(eed) { - if(!eed->h && (eed->f & SELECT)) eed->freestyle = 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_freestyle_edge(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Freestyle Edge"; - ot->description= "(un)mark selected edges as Freestyle feature edges"; - ot->idname= "MESH_OT_mark_freestyle_edge"; - - /* api callbacks */ - ot->exec= editmesh_mark_freestyle_edge; - 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) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - for (eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - - if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1; - if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2; - if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4; - - } - } - } - } - } - - 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 48b96eaf927..00000000000 --- a/source/blender/editors/mesh/editmesh_tools.c +++ /dev/null @@ -1,6832 +0,0 @@ -/* - * ***** 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, V3D_CLIP_TEST_OFF); - - 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; - } - } - - recalc_editnormals(em); - - 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 tvec[3], fac; - - if(beauty & B_SMOOTH) { - /* we calculate an offset vector tvec[], to be added to *co */ - float len, nor[3], nor1[3], nor2[3]; - - sub_v3_v3v3(nor, edge->v1->co, edge->v2->co); - len= 0.5f*normalize_v3(nor); - - copy_v3_v3(nor1, edge->v1->no); - copy_v3_v3(nor2, edge->v2->no); - - /* cosine angle */ - fac= dot_v3v3(nor, nor1); - mul_v3_v3fl(tvec, nor1, fac); - - /* cosine angle */ - fac= -dot_v3v3(nor, nor2); - madd_v3_v3fl(tvec, nor2, fac); - - /* falloff for multi subdivide */ - smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc))); - - mul_v3_fl(tvec, smooth * len); - - add_v3_v3(co, tvec); - } - else if(beauty & B_SPHERE) { /* subdivide sphere */ - normalize_v3(co); - mul_v3_fl(co, smooth); - } - - if(beauty & B_FRACTAL) { - fac= fractal*len_v3v3(edge->v1->co, edge->v2->co); - tvec[0]= fac*(float)(0.5-BLI_drand()); - tvec[1]= fac*(float)(0.5-BLI_drand()); - tvec[2]= fac*(float)(0.5-BLI_drand()); - add_v3_v3(co, tvec); - } -} - -/* 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]; - - interp_v3_v3v3(co, edge->v1->co, edge->v2->co, percent); - - /* 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 */ - interp_v3_v3v3(ev->no, edge->v1->no, edge->v2->no, percent); - 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, */ /* UNUSED */ 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; */ /* UNUSED */ - 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, */ /* UNUSED */ 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; */ /* UNUSED */ - 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, */ /* UNUSED */ 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; */ /* UNUSED */ - - // 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, */ /* UNUSED */ 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; */ /* UNUSED */ - - // 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, */ /* UNUSED */ 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; */ /* UNUSED */ - - // 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, */ /* UNUSED */ 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; */ /* UNUSED */ - - // 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 */ /* UNUSED */; - - 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; */ /* UNUSED */ - - // 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) && (md->mode & eModifierMode_Realtime)) { - MirrorModifierData *mmd = (MirrorModifierData*) md; - - if(mmd->flag & MOD_MIR_CLIPPING) { - for (eve= em->verts.first; eve; eve= eve->next) { - eve->f2= 0; - - if (mmd->flag & MOD_MIR_AXIS_X && fabsf(eve->co[0]) < mmd->tolerance) eve->f2 |= 1; - if (mmd->flag & MOD_MIR_AXIS_Y && fabsf(eve->co[1]) < mmd->tolerance) eve->f2 |= 2; - if (mmd->flag & MOD_MIR_AXIS_Z && fabsf(eve->co[2]) < mmd->tolerance) eve->f2 |= 4; - - } - } - } - } - - //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_v3v3(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_v3v3(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_v3v3(edgeVec1, edgeVec2)) - 90) + - fabsf(RAD2DEGF(angle_v3v3(edgeVec2, edgeVec3)) - 90) + - fabsf(RAD2DEGF(angle_v3v3(edgeVec3, edgeVec4)) - 90) + - fabsf(RAD2DEGF(angle_v3v3(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] */ /* UNUSED */; - 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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]); - /* newFace[1]= */ /* UNUSED */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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1); - /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == DIRECTION_CW) { - /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1); - /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]); - - 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]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]); - /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]); - } else if (dir == DIRECTION_CW) { - /* newFace[0]= */ /* UNUSED */EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]); - /* newFace[1]= */ /* UNUSED */EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]); - - 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->freestyle = eed->freestyle; - 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 UNUSED_FUNCTION(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; -} - -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[2], vec2[2], 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", FALSE); -// 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); - EM_select_face(w, 1); - - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[0], 4+vindex[2], 4+vindex[3], -1); - EM_select_face(w, 1); - - 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); - EM_select_face(w, 1); - - w= EM_face_from_faces(em, efaa[0], efaa[1], - vindex[0], 4+vindex[1], 4+vindex[3], -1); - EM_select_face(w, 1); - - 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) - mult_m4_m4m4(mat, rv3d->viewmat, OBACT->obmat); /* 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 || ese->type != EDITVERT) { - BKE_report(op->reports, RPT_WARNING, "This operator requires an active vertex (last selected)"); - return OPERATOR_CANCELLED; - } - else { - 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"); -} - -/********************** Freestyle Face Mark Operator *************************/ - -static int mesh_mark_freestyle_face_exec(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"); - EditFace *efa; - - /* auto-enable Freestyle face mark drawing */ - if(!clear) { - me->drawflag |= ME_DRAW_FREESTYLE_FACE; - } - - if(!clear) { - for(efa= em->faces.first; efa; efa=efa->next) { - if(efa->f & SELECT) - efa->flag |= ME_FREESTYLE_FACE; - } - } else { - for(efa= em->faces.first; efa; efa=efa->next) { - if(efa->f & SELECT) - efa->flag &= ~ME_FREESTYLE_FACE; - } - } - - 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_freestyle_face(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Mark Freestyle Face"; - ot->description= "(un)mark selected faces for exclusion from Freestyle feature edge detection"; - ot->idname= "MESH_OT_mark_freestyle_face"; - - /* api callbacks */ - ot->exec= mesh_mark_freestyle_face_exec; - ot->poll= ED_operator_editmesh; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "clear", 0, "Clear", ""); -} diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c new file mode 100755 index 00000000000..8e56a357487 --- /dev/null +++ b/source/blender/editors/mesh/knifetool.c @@ -0,0 +1,2314 @@ +/* + * ***** 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) 2007 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Joseph Eagar, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#define _USE_MATH_DEFINES + + +#include "MEM_guardedalloc.h" + + +#include "BLI_blenlib.h" +#include "BLI_array.h" +#include "BLI_math.h" +#include "BLI_rand.h" +#include "BLI_smallhash.h" +#include "BLI_scanfill.h" + +#include "BKE_DerivedMesh.h" +#include "BKE_context.h" +#include "BKE_depsgraph.h" + +#include "BIF_gl.h" +#include "BIF_glutil.h" /* for paint cursor */ + + +#include "ED_screen.h" +#include "ED_space_api.h" +#include "ED_view3d.h" +#include "ED_mesh.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DNA_scene_types.h" +#include "DNA_object_types.h" +#include "BKE_tessmesh.h" +#include "BLI_editVert.h" + +#include "mesh_intern.h" + +/* this code here is kindof messy. . .I might need to eventually rework it - joeedh */ + +#define MAXGROUP 30 +#define KMAXDIST 10 /* 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], cageco[3], sco[3]; /* sco is screen coordinates for cageco */ + 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], cagehit[3]; + float realhit[3]; /* used in midpoint mode */ + float schit[3]; + float l; /* lambda along cut line */ + float perc; /* lambda along hit 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], vertcage[3]; + float prevco[3], prevcage[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; + int cut_through; + 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 prevmval[2]; + + enum { + ANGLE_FREE, + ANGLE_0, + ANGLE_45, + ANGLE_90, + ANGLE_135 + } angle_snapping; + + int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh */ + float (*cagecos)[3]; +} knifetool_opdata; + +static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f); + +static void knife_input_ray_cast(knifetool_opdata *kcd, const int mval_i[2], + float r_origin[3], float r_ray[3]); + +static void knife_project_v3(knifetool_opdata *kcd, const float co[3], float sco[3]) +{ + ED_view3d_project_float(kcd->ar, co, sco, kcd->projmat); +} + +static ListBase *knife_empty_list(knifetool_opdata *kcd) { + ListBase *lst; + + lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase)); + lst->first = lst->last = NULL; + return lst; +} + +static void knife_append_list(knifetool_opdata *kcd, ListBase *lst, void *elem) { + Ref *ref; + + ref = BLI_mempool_calloc(kcd->refs); + ref->ref = elem; + BLI_addtail(lst, ref); +} + +static KnifeEdge *new_knife_edge(knifetool_opdata *kcd) +{ + kcd->totkedge++; + return BLI_mempool_calloc(kcd->kedges); +} + +static void knife_add_to_vert_edges(knifetool_opdata *kcd, KnifeEdge* kfe) +{ + knife_append_list(kcd, &kfe->v1->edges, kfe); + knife_append_list(kcd, &kfe->v2->edges, kfe); +} + +static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co, float *cageco) +{ + KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts); + + kcd->totkvert++; + + copy_v3_v3(kfv->co, co); + copy_v3_v3(kfv->cageco, cageco); + 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, kcd->cagecos[BM_elem_index_get(v)]); + 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) { + 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); + + knife_add_to_vert_edges(kcd, kfe); + + BLI_ghash_insert(kcd->origedgemap, e, kfe); + + BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) { + knife_append_list(kcd, &kfe->faces, f); + + /* 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; + kcd->prevmval[0] = kcd->vc.mval[0]; + kcd->prevmval[1] = kcd->vc.mval[1]; + + copy_v3_v3(kcd->prevco, kcd->vertco); + copy_v3_v3(kcd->prevcage, kcd->vertcage); + + if (kcd->prevvert == NULL && kcd->prevedge == NULL && is_zero_v3(kcd->prevcage)) { + /* Make prevcage a point on the view ray to mouse closest to a point on model: choose vertex 0 */ + float origin[3], ray[3], co[3]; + BMVert *v0; + + knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray); + add_v3_v3v3(co, origin, ray); + v0 = BM_vert_at_index(kcd->em->bm, 0); + if (v0) { + closest_to_line_v3(kcd->prevcage, v0->co, co, origin); + copy_v3_v3(kcd->prevco, kcd->prevcage); + copy_v3_v3(kcd->vertcage, kcd->prevcage); + copy_v3_v3(kcd->vertco, kcd->prevco); + } + } +} + +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 = knife_empty_list(kcd); + + BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) { + knife_append_list(kcd, lst, get_bm_knife_edge(kcd, e)); + } + + 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 void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f) +{ + knife_append_list(kcd, knife_get_face_kedges(kcd, f), kfe); + knife_append_list(kcd, &kfe->faces, f); +} + +static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out) +{ + KnifeEdge *newkfe = new_knife_edge(kcd); + Ref *ref; + float perc, cageco[3]; + + perc = len_v3v3(co, kfe->v1->co) / len_v3v3(kfe->v1->co, kfe->v2->co); + interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc); + + newkfe->v1 = kfe->v1; + newkfe->v2 = new_knife_vert(kcd, co, cageco); + 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) + knife_edge_append_face(kcd, newkfe, ref->ref); + + knife_add_to_vert_edges(kcd, newkfe); + + newkfe->draw = kfe->draw; + newkfe->e = kfe->e; + + *newkfe_out = newkfe; + + return newkfe->v2; +} + +static void knife_add_single_cut(knifetool_opdata *kcd) +{ + KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL; + + 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, 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, 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); + + knife_add_to_vert_edges(kcd, kfe); + + 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); + copy_v3_v3(kcd->prevcage, kcd->vertcage); + kcd->prev_is_space = kcd->is_space; + kcd->prevmval[0] = kcd->vc.mval[0]; + kcd->prevmval[1] = kcd->vc.mval[1]; +} + +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_single_cut_through(knifetool_opdata *kcd, + KnifeVert *v1, KnifeVert *v2, BMFace *f) +{ + KnifeEdge *kfenew; + + kfenew = new_knife_edge(kcd); + kfenew->draw = 1; + kfenew->basef = f; + kfenew->v1 = v1; + kfenew->v2 = v2; + kfenew->draw = 1; + + knife_add_to_vert_edges(kcd, kfenew); + + if (!find_ref(&kfenew->faces, f)) + knife_edge_append_face(kcd, kfenew, f); +} + +static void knife_get_vert_faces(knifetool_opdata *kcd, KnifeVert* kfv, BMFace *facef, ListBase *lst) +{ + BMIter bmiter; + BMFace *f; + + if (kfv->isface && facef) { + knife_append_list(kcd, lst, facef); + } + else if (kfv->v) { + BMesh *bm = kcd->em->bm; + BM_ITER(f, &bmiter, bm, BM_FACES_OF_VERT, kfv->v) { + knife_append_list(kcd, lst, f); + } + } +} + +static void knife_get_edge_faces(knifetool_opdata *kcd, KnifeEdge* kfe, ListBase *lst) +{ + BMIter bmiter; + BMFace *f; + + if (kfe->e) { + BMesh *bm = kcd->em->bm; + BM_ITER(f, &bmiter, bm, BM_FACES_OF_EDGE, kfe->e) { + knife_append_list(kcd, lst, f); + } + } +} + +/* BMESH_TODO: add more functionality to cut-through: + * - cutting "in face" (e.g., holes) should cut in all faces, not just visible one + * - perhaps improve O(n^2) algorithm used here */ +static void knife_cut_through(knifetool_opdata *kcd) +{ + BMEdgeHit *lh, *lh2; + BMFace *f; + KnifeEdge *kfe, *kfe2, *kfe3; + KnifeVert *v1, *v2, *firstv = NULL, *lastv = NULL; + ListBase firstfaces = {NULL, NULL}, lastfaces = { NULL, NULL}; + Ref *r, *r2; + KnifeEdge **splitkfe; + int i, j, found; + + if (!kcd->totlinehit) { + /* if no linehits then no interesting back face stuff to do */ + knife_add_single_cut(kcd); + return; + } + + qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit); + splitkfe = MEM_callocN(kcd->totlinehit * sizeof(KnifeEdge *), "knife_cut_through"); + + if (kcd->prevvert) { + if (kcd->prevvert == kcd->curvert) + return; + firstv = kcd->prevvert; + knife_get_vert_faces(kcd, firstv, kcd->prevbmface, &firstfaces); + } + else if (kcd->prevedge) { + if (kcd->prevedge == kcd->curedge) + return; + firstv = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe3); + knife_get_edge_faces(kcd, kcd->prevedge, &firstfaces); + } + + if (kcd->curvert) { + lastv = kcd->curvert; + knife_get_vert_faces(kcd, lastv, kcd->curbmface, &lastfaces); + } + else if (kcd->curedge) { + lastv = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3); + knife_get_edge_faces(kcd, kcd->curedge, &lastfaces); + } + + if (firstv) { + /* For each face incident to firstv, + * find the first following linehit (if any) sharing that face and connect */ + for (r = firstfaces.first; r; r = r->next ) { + f = r->ref; + found = 0; + for (j = 0, lh2 = kcd->linehits; j < kcd->totlinehit; j++, lh2++) { + kfe2 = lh2->kfe; + for (r2 = kfe2->faces.first; r2; r2 = r2->next) { + if (r2->ref == f) { + v2 = splitkfe[j] ? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); + knife_add_single_cut_through(kcd, firstv, v2, f); + found = 1; + break; + } + } + } + if (!found && lastv) { + for (r2 = lastfaces.first; r2; r2 = r2->next) { + if (r2->ref == f) { + knife_add_single_cut_through(kcd, firstv, lastv, f); + break; + } + } + } + } + } + + for (i = 0, lh = kcd->linehits; i < kcd->totlinehit; i++, lh++) { + kfe = lh->kfe; + + /* For each face attached to edge for this linehit, + * find the first following linehit (if any) sharing that face and connect */ + for (r = kfe->faces.first; r; r = r->next) { + f = r->ref; + found = 0; + for (j = i + 1, lh2 = lh + 1; j < kcd->totlinehit; j++, lh2++) { + kfe2 = lh2->kfe; + for (r2 = kfe2->faces.first; r2; r2 = r2->next) { + if (r2->ref == f) { + v1 = splitkfe[i]? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); + v2 = splitkfe[j]? kfe2->v1 : knife_split_edge(kcd, kfe2, lh2->hit, &splitkfe[j]); + knife_add_single_cut_through(kcd, v1, v2, f); + found = 1; + break; + } + } + } + if (!found && lastv) { + for (r2 = lastfaces.first; r2; r2 = r2->next) { + if (r2->ref == f) { + v1 = splitkfe[i]? kfe->v1 : knife_split_edge(kcd, kfe, lh->hit, &splitkfe[i]); + knife_add_single_cut_through(kcd, v1, lastv, f); + break; + } + } + } + } + } + + MEM_freeN(splitkfe); + MEM_freeN(kcd->linehits); + kcd->linehits = NULL; + kcd->totlinehit = 0; + + /* set up for next cut */ + kcd->prevbmface = kcd->curbmface; + kcd->prevvert = kcd->curvert; + kcd->prevedge = kcd->curedge; + copy_v3_v3(kcd->prevco, kcd->vertco); + copy_v3_v3(kcd->prevcage, kcd->vertcage); + kcd->prev_is_space = kcd->is_space; + kcd->prevmval[0] = kcd->vc.mval[0]; + kcd->prevmval[1] = kcd->vc.mval[1]; +} + +static void knife_add_cut(knifetool_opdata *kcd) +{ + /* BMEditMesh *em = kcd->em;*/ /* UNUSED */ + knifetool_opdata oldkcd = *kcd; + + if (kcd->cut_through) { + knife_cut_through(kcd); + } + else 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); + copy_v3_v3(kcd->prevcage, firstlh->cagehit); + kcd->prevedge = NULL; + kcd->prevbmface = f; + } + lastlh = firstlh = NULL; + } + + if (len_v3v3(kcd->prevcage, lh->realhit) < FLT_EPSILON * 80) + continue; + if (len_v3v3(kcd->vertcage, 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); + copy_v3_v3(kcd->prevcage, lh->cagehit); + 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); + copy_v3_v3(kcd->vertcage, lh->cagehit); + + 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); + copy_v3_v3(kcd->vertcage, oldkcd.vertcage); + + 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)) +{ + +} + +static void knifetool_draw_angle_snapping(knifetool_opdata *kcd) +{ + bglMats mats; + double u[3], u1[2], u2[2], v1[3], v2[3], dx, dy; + double wminx, wminy, wmaxx, wmaxy; + + /* make u the window coords of prevcage */ + view3d_get_transformation(kcd->ar, kcd->vc.rv3d, kcd->ob, &mats); + gluProject(kcd->prevcage[0], kcd->prevcage[1], kcd->prevcage[2], + mats.modelview, mats.projection, mats.viewport, + &u[0], &u[1], &u[2]); + + /* make u1, u2 the points on window going through u at snap angle */ + wminx = kcd->ar->winrct.xmin; + wmaxx = kcd->ar->winrct.xmin + kcd->ar->winx; + wminy = kcd->ar->winrct.ymin; + wmaxy = kcd->ar->winrct.ymin + kcd->ar->winy; + + switch (kcd->angle_snapping) { + case ANGLE_0: + u1[0] = wminx; + u2[0] = wmaxx; + u1[1] = u2[1] = u[1]; + break; + case ANGLE_90: + u1[0] = u2[0] = u[0]; + u1[1] = wminy; + u2[1] = wmaxy; + break; + case ANGLE_45: + /* clip against left or bottom */ + dx = u[0] - wminx; + dy = u[1] - wminy; + if (dy > dx) { + u1[0] = wminx; + u1[1] = u[1] - dx; + } + else { + u1[0] = u[0] - dy; + u1[1] = wminy; + } + /* clip against right or top */ + dx = wmaxx - u[0]; + dy = wmaxy - u[1]; + if (dy > dx) { + u2[0] = wmaxx; + u2[1] = u[1] + dx; + } + else { + u2[0] = u[0] + dy; + u2[1] = wmaxy; + } + break; + case ANGLE_135: + /* clip against right or bottom */ + dx = wmaxx - u[0]; + dy = u[1] - wminy; + if (dy > dx) { + u1[0] = wmaxx; + u1[1] = u[1] - dx; + } + else { + u1[0] = u[0] + dy; + u1[1] = wminy; + } + /* clip against left or top */ + dx = u[0] - wminx; + dy = wmaxy - u[1]; + if (dy > dx) { + u2[0] = wminx; + u2[1] = u[1] + dx; + } + else { + u2[0] = u[0] - dy; + u2[1] = wmaxy; + } + break; + default: + return; + } + + /* unproject u1 and u2 back into object space */ + gluUnProject(u1[0], u1[1], 0.0, + mats.modelview, mats.projection, mats.viewport, + &v1[0], &v1[1], &v1[2]); + gluUnProject(u2[0], u2[1], 0.0, + mats.modelview, mats.projection, mats.viewport, + &v2[0], &v2[1], &v2[2]); + + glColor3f(0.6, 0.6, 0.6); + glLineWidth(2.0); + glBegin(GL_LINES); + glVertex3dv(v1); + glVertex3dv(v2); + glEnd(); +} + +/* 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) { + if (kcd->angle_snapping != ANGLE_FREE) + knifetool_draw_angle_snapping(kcd); + + glColor3f(0.1, 0.1, 0.1); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->prevcage); + glVertex3fv(kcd->vertcage); + glEnd(); + + glLineWidth(1.0); + } + + if (kcd->curedge) { + glColor3f(0.5, 0.3, 0.15); + glLineWidth(2.0); + + glBegin(GL_LINES); + glVertex3fv(kcd->curedge->v1->cageco); + glVertex3fv(kcd->curedge->v2->cageco); + glEnd(); + + glLineWidth(1.0); + } + else if (kcd->curvert) { + glColor3f(0.8, 0.2, 0.1); + glPointSize(11); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertcage); + glEnd(); + } + + if (kcd->curbmface) { + glColor3f(0.1, 0.8, 0.05); + glPointSize(9); + + glBegin(GL_POINTS); + glVertex3fv(kcd->vertcage); + 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->cageco, sv1); + knife_project_v3(kcd, lh->kfe->v2->cageco, sv2); + knife_project_v3(kcd, lh->cagehit, lh->schit); + + if (len_v2v2(lh->schit, sv1) < kcd->vthresh / 4.0f) { + copy_v3_v3(lh->cagehit, lh->kfe->v1->cageco); + glVertex3fv(lh->cagehit); + lh->v = lh->kfe->v1; + } + else if (len_v2v2(lh->schit, sv2) < kcd->vthresh / 4.0f) { + copy_v3_v3(lh->cagehit, lh->kfe->v2->cageco); + glVertex3fv(lh->cagehit); + 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->cagehit); + } + 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->cageco); + glVertex3fv(kfe->v2->cageco); + } + + 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->cageco); + } + + glEnd(); + } + + glPopMatrix(); + glEnable(GL_DEPTH_TEST); +} + +/* do we need to keep these functions? - campbell */ + +static int UNUSED_FUNCTION(kfe_vert_in_edge)(KnifeEdge *e, KnifeVert *v) +{ + return e->v1 == v || e->v2 == v; +} + +static int UNUSED_FUNCTION(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 float len_v3_tri_side_max(const float v1[3], const float v2[3], const float v3[3]) +{ + const float s1 = len_v3v3(v1, v2); + const float s2 = len_v3v3(v2, v3); + const float s3 = len_v3v3(v3, v1); + + return MAX3(s1, s2, s3); +} + +static BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, + const float v1[3], const float v2[3], const 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; + + /* for comparing distances, error of intersection depends on triangle scale. + * need to scale down before squaring for accurate comparison */ + const float depsilon = 50 * FLT_EPSILON * len_v3_tri_side_max(v1, v2, v3); + const float depsilon_squared = depsilon * depsilon; + + copy_v3_v3(cos + 0, 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; + + 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->cageco, kfe->v2->cageco, v1, v2, v3, &lambda, uv)) { + float no[3], view[3], sp[3]; + + interp_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco, lambda); + + if (kcd->curvert && len_squared_v3v3(kcd->curvert->cageco, p) < depsilon_squared) + continue; + if (kcd->prevvert && len_squared_v3v3(kcd->prevvert->cageco, p) < depsilon_squared) + continue; + if ( len_squared_v3v3(kcd->prevcage, p) < depsilon_squared || + len_squared_v3v3(kcd->vertcage, p) < depsilon_squared) + { + continue; + } + + knife_project_v3(kcd, p, sp); + view3d_unproject(mats, view, sp[0], sp[1], 0.0f); + mul_m4_v3(kcd->ob->imat, view); + + if (kcd->cut_through) { + hitf = FALSE; + } + else { + /* check if this point is visible in the viewport */ + sub_v3_v3(view, p); + normalize_v3(view); + + copy_v3_v3(no, view); + mul_v3_fl(no, 0.003); + + /* go towards view a bit */ + add_v3_v3(p, no); + + /* ray cast */ + hitf = BMBVH_RayCast(bmtree, p, no, NULL, NULL); + } + + /* ok, if visible add the new point */ + if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) { + BMEdgeHit hit; + + if ( len_squared_v3v3(p, kcd->vertco) < depsilon_squared || + len_squared_v3v3(p, kcd->prevco) < depsilon_squared) + { + continue; + } + + hit.kfe = kfe; + hit.v = NULL; + + knife_find_basef(kcd, kfe); + hit.f = kfe->basef; + hit.perc = len_v3v3(p, kfe->v1->cageco) / len_v3v3(kfe->v1->cageco, kfe->v2->cageco); + copy_v3_v3(hit.cagehit, p); + + interp_v3_v3v3(p, kfe->v1->co, kfe->v2->co, hit.perc); + copy_v3_v3(hit.realhit, p); + + /* BMESH_TODO: should also snap to vertices */ + if (kcd->snap_midpoints) { + float perc = hit.perc; + + /* select the closest from the edge endpoints or the midpoint */ + if (perc < 0.25f) { + perc = 0.0f; + } + else if (perc < 0.75f) { + perc = 0.5f; + } + else { + perc = 1.0f; + } + + interp_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co, perc); + interp_v3_v3v3(hit.cagehit, kfe->v1->cageco, kfe->v2->cageco, perc); + } + else { + copy_v3_v3(hit.hit, p); + } + knife_project_v3(kcd, hit.cagehit, 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 (or all, if cutting through) 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 v1[3], v2[3], v3[3], v4[4], s1[3], s2[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->prevcage); + copy_v3_v3(v2, kcd->vertcage); + + /* 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); + + 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); + + 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, v2, 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 void knife_input_ray_cast(knifetool_opdata *kcd, const int mval_i[2], + float r_origin[3], float r_ray[3]) +{ + bglMats mats; + float mval[2], imat[3][3]; + + knife_bgl_get_mats(kcd, &mats); + + mval[0] = (float)mval_i[0]; + mval[1] = (float)mval_i[1]; + + /* unproject to find view ray */ + view3d_unproject(&mats, r_origin, mval[0], mval[1], 0.0f); + + if (kcd->is_ortho) { + negate_v3_v3(r_ray, kcd->vc.rv3d->viewinv[2]); + } + else { + sub_v3_v3v3(r_ray, r_origin, kcd->vc.rv3d->viewinv[3]); + } + normalize_v3(r_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, r_origin); + mul_m3_v3(imat, r_ray); +} + + +static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3], float cageco[3], int *is_space) +{ + BMFace *f; + int dist = KMAXDIST; + float origin[3]; + float ray[3]; + + /* unproject to find view ray */ + knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray); + add_v3_v3v3(co, origin, ray); + + f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co, cageco); + + 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. + * This just puts a point 1.0f infront of the view. */ + add_v3_v3v3(co, origin, 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], cageco[3], sco[3]; + + f = knife_find_closest_face(kcd, co, cageco, &is_space); + + if (f && !is_space) { + ListBase *lst; + Ref *ref; + float dis; + int c = 0; + + knife_project_v3(kcd, cageco, 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->cageco, 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->cageco); + 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], float cagep[3], BMFace **fptr, int *is_space) +{ + BMFace *f; + float co[3], cageco[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, cageco, NULL); + *is_space = !f; + + /* set p to co, in case we don't find anything, means a face cut */ + copy_v3_v3(p, co); + copy_v3_v3(cagep, cageco); + + kcd->curbmface = f; + + if (f) { + KnifeEdge *cure = NULL; + ListBase *lst; + Ref *ref; + float dis, curdis = FLT_MAX; + + knife_project_v3(kcd, cageco, 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->cageco, kfe->v1->sco); + knife_project_v3(kcd, kfe->v2->cageco, 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->cageco[0] + labda*(kfe->v2->cageco[0] - kfe->v1->cageco[0]); + vec[1] = kfe->v1->cageco[1] + labda*(kfe->v2->cageco[1] - kfe->v1->cageco[1]); + vec[2] = kfe->v1->cageco[2] + labda*(kfe->v2->cageco[2] - kfe->v1->cageco[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) { + if (!kcd->ignore_edge_snapping || !(cure->e)) { + if (kcd->snap_midpoints) { + mid_v3_v3v3(p, cure->v1->co, cure->v2->co); + mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco); + } + else { + float d; + + closest_to_line_segment_v3(cagep, cageco, cure->v1->cageco, cure->v2->cageco); + d = len_v3v3(cagep, cure->v1->cageco) / len_v3v3(cure->v1->cageco, cure->v2->cageco); + 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], float cagep[3], BMFace **fptr, int *is_space) +{ + BMFace *f; + float co[3], cageco[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, cageco, is_space); + + /* set p to co, in case we don't find anything, means a face cut */ + copy_v3_v3(p, co); + copy_v3_v3(cagep, p); + kcd->curbmface = f; + + if (f) { + ListBase *lst; + Ref *ref; + KnifeVert *curv = NULL; + float dis, curdis = FLT_MAX; + + knife_project_v3(kcd, cageco, 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->cageco, 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->cageco); + 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); + copy_v3_v3(cagep, curv->cageco); + } + + return curv; + } + else { + if (fptr) + *fptr = f; + + return NULL; + } + } + + if (fptr) + *fptr = NULL; + + return NULL; +} + +static void knife_snap_angle(knifetool_opdata *kcd) +{ + int dx, dy; + float w, abs_tan; + + dx = kcd->vc.mval[0] - kcd->prevmval[0]; + dy = kcd->vc.mval[1] - kcd->prevmval[1]; + if (dx == 0 || dy == 0) + return; + + w = (float)dy / (float)dx; + abs_tan = fabsf(w); + if (abs_tan <= 0.4142f) { /* tan(22.5 degrees) = 0.4142 */ + kcd->angle_snapping = ANGLE_0; + kcd->vc.mval[1] = kcd->prevmval[1]; + } + else if (abs_tan < 2.4142f) { /* tan(67.5 degrees) = 2.4142 */ + if (w > 0) { + kcd->angle_snapping = ANGLE_45; + kcd->vc.mval[1] = kcd->prevmval[1] + dx; + } + else { + kcd->angle_snapping = ANGLE_135; + kcd->vc.mval[1] = kcd->prevmval[1] - dx; + } + } + else { + kcd->angle_snapping = ANGLE_90; + kcd->vc.mval[0] = kcd->prevmval[0]; + } +} + +/* update active knife edge/vert pointers */ +static int knife_update_active(knifetool_opdata *kcd) +{ + if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) + knife_snap_angle(kcd); + + kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL; + + kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, kcd->vertcage, &kcd->curbmface, &kcd->is_space); + if (!kcd->curvert) { + kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, kcd->vertcage, &kcd->curbmface, &kcd->is_space); + } + + /* if no hits are found this would normally default to (0,0,0) so instead + * get a point at the mouse ray closest to the previous point. + * Note that drawing lines in `free-space` isn't properly supported + * but theres no guarantee (0,0,0) has any geometry either - campell */ + if (kcd->curvert == NULL && kcd->curedge == NULL) { + float origin[3], ray[3], co[3]; + + knife_input_ray_cast(kcd, kcd->vc.mval, origin, ray); + add_v3_v3v3(co, origin, ray); + + closest_to_line_v3(kcd->vertcage, kcd->prevcage, co, origin); + } + + 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_op_initf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY); + + BMO_op_exec(bm, &bmop); + BMO_slot_buffer_flag_enable(bm, &bmop, "geomout", FACE_NEW, BM_FACE); + + BMO_op_finish(bm, &bmop); + + BLI_smallhash_init(visit); + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + BMIter eiter; + BMEdge *e; + BMFace *f2; + + if (!BMO_elem_flag_test(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_elem_flag_test(bm, e, BOUNDARY)) + continue; + + BM_ITER(f3, &fiter, bm, BM_FACES_OF_EDGE, e) { + if (!BMO_elem_flag_test(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_elem_index_get(faces[0]); + + f2 = BM_faces_join(bm, faces, BLI_array_count(faces)); + if (f2) { + BMO_elem_flag_enable(bm, f2, FACE_NEW); + BM_elem_index_set(f2, idx); /* set_dirty! */ /* BMESH_TODO, check if this is valid or not */ + } + } + } + /* BMESH_TODO, check if the code above validates the indicies */ + /* bm->elem_index_dirty &= ~BM_FACE; */ + bm->elem_index_dirty |= BM_FACE; + + BLI_smallhash_release(visit); + + BLI_array_free(stack); + BLI_array_free(faces); +} + +/* 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; + int i, j, k = 0, totface = bm->totface; + + BMO_push(bm, NULL); + bmesh_begin_edit(bm, BMO_OP_FLAG_UNTAN_MULTIRES); + + /* BMESH_TODO this should be valid now, leaving here until we can ensure this - campbell */ + i = 0; + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BM_elem_index_set(f, i); /* set_inline */ + faces[i] = f; + i++; + } + bm->elem_index_dirty &= ~BM_FACE; + + BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) { + BMO_elem_flag_enable(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) { + /* shouldn't we be at least copying the normal? - if not some comment here should explain why - campbell */ + kfv->v = BM_vert_create(bm, kfv->co, NULL); + kfv->flag = 1; + BMO_elem_flag_enable(bm, kfv->v, DEL); + } + else { + kfv->flag = 0; + BMO_elem_flag_enable(bm, kfv->v, VERT_ORIG); + } + + BMO_elem_flag_enable(bm, kfv->v, MARK); + } + + /* we want to only do changed faces. first, go over new edges and add to + * face net lists.*/ + i = j = 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_elem_flag_enable(bm, kfe->e, DEL); + BMO_elem_flag_disable(bm, kfe->e, BOUNDARY); + kfe->e = NULL; + } + + kfe->e = BM_edge_create(bm, kfe->v1->v, kfe->v2->v, NULL, TRUE); + BMO_elem_flag_enable(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_elem_index_get(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_elem_flag_enable(bm, kfe->e, BOUNDARY); + kfe->oe = kfe->e; + + for (ref = kfe->faces.first; ref; ref = ref->next) { + f = ref->ref; + + if (face_nets[BM_elem_index_get(f)].first) { + entry = BLI_memarena_alloc(arena, sizeof(*entry)); + entry->kfe = kfe; + BLI_addtail(face_nets + BM_elem_index_get(f), entry); + } + } + } + + for (i = 0; i < totface; i++) { + SmallHash *hash = &shash; + 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_elem_flag_enable(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) { + EditEdge *eed; + eed = BLI_addfilledge(lasteve, eve); + if (entry->kfe->oe) + eed->f = FILLBOUNDARY; /* mark as original boundary edge */ + + BMO_elem_flag_disable(bm, entry->kfe->e->v1, DEL); + BMO_elem_flag_disable(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_iter; + 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_face_create_quad_tri(bm, + v1, v2, v3, NULL, + NULL, FALSE); + + BMO_elem_flag_enable(bm, f2, FACE_NEW); + + l_iter = BM_FACE_FIRST_LOOP(f2); + do { + BMO_elem_flag_disable(bm, l_iter->e, DEL); + } while ((l_iter = l_iter->next) != BM_FACE_FIRST_LOOP(f2)); + + BMO_elem_flag_disable(bm, f2, DEL); + BM_elem_index_set(f2, i); /* set_dirty! */ /* note, not 100% sure this is dirty? need to check */ + + BM_face_normal_update(bm, f2); + if (dot_v3v3(f->no, f2->no) < 0.0f) { + BM_face_normal_flip(bm, f2); + } + } + + BLI_end_edgefill(); + BLI_smallhash_release(hash); + } + bm->elem_index_dirty |= BM_FACE; + + /* interpolate customdata */ + BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) { + BMLoop *l1; + BMFace *f2; + BMIter liter1; + + if (!BMO_elem_flag_test(bm, f, FACE_NEW)) + continue; + + f2 = faces[BM_elem_index_get(f)]; + if (BM_elem_index_get(f) < 0 || BM_elem_index_get(f) >= totface) { + fprintf(stderr, "%s: face index out of range! (bmesh internal error)\n", __func__); + } + + BM_elem_attrs_copy(bm, bm, f2, f); + + BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) { + BM_loop_interp_from_face(bm, l1, f2, TRUE, TRUE); + } + } + + /* merge triangles back into faces */ + remerge_faces(kcd); + + /* delete left over faces */ + BMO_op_callf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES); + BMO_op_callf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES); + BMO_op_callf(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); + + BMO_error_clear(bm); /* remerge_faces sometimes raises errors, so make sure to clear them */ + + bmesh_end_edit(bm, BMO_OP_FLAG_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); + //mult_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat); + + 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); + + if (kcd->cagecos) + MEM_freeN(kcd->cagecos); + + /* destroy kcd itself */ + MEM_freeN(kcd); + op->customdata = NULL; +} + +static void cage_mapped_verts_callback(void *userData, int index, float *co, + float *UNUSED(no_f), short *UNUSED(no_s)) +{ + void **data = userData; + BMEditMesh *em = data[0]; + float (*cagecos)[3] = data[1]; + SmallHash *hash = data[2]; + + if (index >= 0 && index < em->bm->totvert && !BLI_smallhash_haskey(hash, index)) { + BLI_smallhash_insert(hash, index, NULL); + copy_v3_v3(cagecos[index], co); + } +} + +/* called when modal loop selection gets set up... */ +static int knifetool_init(bContext *C, wmOperator *op, int UNUSED(do_cut)) +{ + knifetool_opdata *kcd; + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + DerivedMesh *cage, *final; + SmallHash shash; + void *data[3]; + + /* alloc new customdata */ + kcd = op->customdata = MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data"); + + /* assign the drawing handle for drawing preview line... */ + kcd->ob = obedit; + 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->em = ((Mesh *)kcd->ob->data)->edit_btmesh; + + BM_mesh_elem_index_ensure(kcd->em->bm, BM_VERT); + + cage = editbmesh_get_derived_cage_and_final(scene, obedit, kcd->em, &final, CD_MASK_DERIVEDMESH); + kcd->cagecos = MEM_callocN(sizeof(float) * 3 * kcd->em->bm->totvert, "knife cagecos"); + data[0] = kcd->em; + data[1] = kcd->cagecos; + data[2] = &shash; + + BLI_smallhash_init(&shash); + cage->foreachMappedVert(cage, cage_mapped_verts_callback, data); + BLI_smallhash_release(&shash); + + kcd->bmbvh = BMBVH_NewBVH(kcd->em, BMBVH_USE_CAGE|BMBVH_RETURN_ORIG, scene, obedit); + 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, FALSE, FALSE); + kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, FALSE, TRUE); + kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, FALSE, TRUE); + + 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"); + + /* cut all the way through the mesh if use_occlude_geometry button not pushed */ + kcd->cut_through = !(kcd->vc.v3d->flag & V3D_ZBUF_SELECT); + + 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, + KNF_MODAL_ANGLE_SNAP_TOGGLE +}; + +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_ANGLE_SNAP_TOGGLE, "ANGLE_SNAP_TOGGLE", 0, "Toggle Angle Snapping", ""}, + {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_add_item(keymap, CKEY, KM_PRESS, 0, 0, KNF_MODAL_ANGLE_SNAP_TOGGLE); + + 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: + kcd->snap_midpoints = 1; + + knife_recalc_projmat(kcd); + knife_update_active(kcd); + ED_region_tag_redraw(kcd->ar); + break; + case KNF_MODAL_MIDPOINT_OFF: + kcd->snap_midpoints = 0; + + knife_recalc_projmat(kcd); + knife_update_active(kcd); + ED_region_tag_redraw(kcd->ar); + 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_ANGLE_SNAP_TOGGLE: + kcd->angle_snapping = !kcd->angle_snapping; + 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 c317eabd48a..59861d674f2 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -30,6 +30,8 @@ #include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> #include <string.h> #include <ctype.h> #include <stdio.h> @@ -39,7 +41,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" @@ -47,9 +48,9 @@ #include "BLI_array.h" #include "BLI_blenlib.h" +#include "BLI_math.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ #include "BLI_editVert.h" -#include "BLI_math.h" #include "BLI_utildefines.h" #include "BKE_blender.h" @@ -59,6 +60,8 @@ #include "BKE_modifier.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_tessmesh.h" +#include "BKE_depsgraph.h" #include "BIF_gl.h" #include "BIF_glutil.h" /* for paint cursor */ @@ -94,8 +97,8 @@ typedef struct tringselOpData { ViewContext vc; Object *ob; - EditMesh *em; - EditEdge *eed; + BMEditMesh *em; + BMEdge *eed; NumInput num; int extend; @@ -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_face_other_loop(l->e, l->f, eed->v1); + rev = (l2 == l->prev); + while (l2->v != lasteed->v1 && l2->v != lasteed->v2) { + l2 = rev ? l2->prev : 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; 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,87 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select) } if (!lcd->extend) { - EM_clear_flag_all(lcd->em, SELECT); + EDBM_flag_disable_all(lcd->em, BM_ELEM_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 */ - - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; - } + if (select) { + BMW_init(&walker, em->bm, BMW_EDGERING, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); - 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++; + eed = BMW_begin(&walker, startedge); + for (; eed; eed=BMW_step(&walker)) { + BM_elem_select_set(em->bm, eed, TRUE); } + BMW_end(&walker); + + return; } - - // 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, + BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP, + BMW_NIL_LAY); + + 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); + copy_v3_v3(edges[tot][0], co[0]); + copy_v3_v3(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]; - - BLI_array_growone(edges); - copy_v3_v3(edges[tot][0], co[0]); - copy_v3_v3(edges[tot][1], co[1]); - tot++; - } - } - } - } else { - select = (startedge->f & SELECT) == 0; + if (lasteed != startedge && 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); + copy_v3_v3(edges[tot][0], co[0]); + copy_v3_v3(edges[tot][1], co[1]); + tot++; } } + BMW_end(&walker); lcd->edges = edges; lcd->totedge = tot; } @@ -265,7 +290,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 +300,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_mesh_esubdivideflag(lcd->ob, em->bm, BM_ELEM_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,30 +319,32 @@ 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_store_selection(em, lcd->eed->v1); /* low priority TODO, get vertrex close to mouse */ if(em->selectmode & SCE_SELECT_EDGE) - EM_store_selection(em, lcd->eed, EDITEDGE); + EDBM_store_selection(em, lcd->eed); - 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; @@ -344,7 +373,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; @@ -359,13 +388,16 @@ 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; } +/* for bmesh this tool is in bmesh_select.c */ +#if 0 + static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) { tringselOpData *lcd; @@ -411,11 +443,13 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_FINISHED; } +#endif + 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)) @@ -433,7 +467,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); @@ -443,22 +477,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; @@ -467,6 +502,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 */ @@ -478,35 +518,37 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) ED_region_tag_redraw(lcd->ar); break; - case WHEELUPMOUSE: /* change number of cuts */ case PADPLUSKEY: 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 PADMINUS: 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; @@ -539,6 +581,9 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } +/* for bmesh this tool is in bmesh_select.c */ +#if 0 + void MESH_OT_edgering_select (wmOperatorType *ot) { /* description */ @@ -556,6 +601,8 @@ void MESH_OT_edgering_select (wmOperatorType *ot) RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); } +#endif + void MESH_OT_loopcut (wmOperatorType *ot) { /* description */ @@ -565,7 +612,7 @@ void MESH_OT_loopcut (wmOperatorType *ot) /* 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 09ae5e08d60..0d7d6ca8108 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -41,6 +41,8 @@ #include "DNA_scene_types.h" #include "DNA_view3d_types.h" +#include "BLI_utildefines.h" +#include "BLI_array.h" #include "BLI_math.h" #include "BLI_editVert.h" #include "BLI_edgehash.h" @@ -55,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" @@ -71,19 +74,31 @@ #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 layer data pointer to find where the active layer has ended up. + this is necassary because the deletion functions only support deleting the active layer. */ @@ -93,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_data_layer_free(me->edit_btmesh->bm, data, type); } else { - CustomData_free_layer_active(data, type, me->totface); - mesh_update_customdata_pointers(me); + CustomData_free_layer_active(data, type, tot); + mesh_update_customdata_pointers(me, TRUE); } - 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 */ @@ -162,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); @@ -171,44 +191,174 @@ 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_loop_reset(struct bContext *C, struct Mesh *me) +{ + BMEditMesh *em= me->edit_btmesh; + MLoopUV *luv; + BLI_array_declare(polylengths); + int *polylengths = NULL; + BLI_array_declare(uvs); + float **uvs = NULL; + float **fuvs = NULL; + int i, j; + + if (em) { + /* Collect BMesh UVs */ + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + BLI_assert(CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)); + + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + 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); + BLI_array_append(uvs, luv->uv); + i++; + } + + BLI_array_append(polylengths, efa->len); + } + } + else { + /* Collect Mesh UVs */ + + MPoly *mp; + + BLI_assert(CustomData_has_layer(&me->ldata, CD_MLOOPUV)); + + for (j = 0; j < me->totpoly; j++) { + mp = &me->mpoly[j]; + + for (i = 0; i < mp->totloop; i++) { + luv = &me->mloopuv[mp->loopstart + i]; + BLI_array_append(uvs, luv->uv); + } + + BLI_array_append(polylengths, mp->totloop); + } + } + + fuvs = uvs; + for (j = 0; j < BLI_array_count(polylengths); j++) { + int len = polylengths[j]; + + if (len == 3) { + fuvs[0][0] = 0.0; + fuvs[0][1] = 0.0; + + fuvs[1][0] = 1.0; + fuvs[1][1] = 0.0; + + fuvs[2][0] = 1.0; + fuvs[2][1] = 1.0; + } else if (len == 4) { + fuvs[0][0] = 0.0; + fuvs[0][1] = 0.0; + + fuvs[1][0] = 1.0; + fuvs[1][1] = 0.0; + + fuvs[2][0] = 1.0; + fuvs[2][1] = 1.0; + + fuvs[3][0] = 0.0; + fuvs[3][1] = 1.0; + /*make sure we ignore 2-sided faces*/ + } else if (len > 2) { + float fac = 0.0f, dfac = 1.0f / (float)len; + + dfac *= M_PI*2; + + for (i = 0; i < len; i++) { + fuvs[i][0] = 0.5f * sin(fac) + 0.5f; + fuvs[i][1] = 0.5f * cos(fac) + 0.5f; + + fac += dfac; + } + } + + fuvs += len; + } + + /* BMESH_TODO: Copy poly UVs onto CD_MTFACE layer for tesselated faces */ + + BLI_array_free(uvs); + BLI_array_free(polylengths); + + DAG_id_tag_update(&me->id, 0); + WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); + + return 1; } 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); - if(layernum >= MAX_MTFACE) + layernum = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY); + if (layernum >= MAX_MTFACE) return -1; - EM_add_data_layer(em, &em->fdata, CD_MTFACE, name); + BM_data_layer_add(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 data from active UV */ + if (layernum) copy_editface_active_customdata(em, CD_MTFACE, layernum); - if(active_set || layernum==0) - CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum); + if (active_set || layernum == 0) { + CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum); + } + + BM_data_layer_add(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); - if(layernum >= MAX_MTFACE) + layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY); + if (layernum >= MAX_MTFACE) return -1; - if(me->mtface) + 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); CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name); - else + } 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); CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name); + } + + if (active_set || layernum == 0) { + CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum); + CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum); - if(active_set || layernum==0) CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum); + } - mesh_update_customdata_pointers(me); + mesh_update_customdata_pointers(me, TRUE); } + ED_mesh_uv_loop_reset(C, me); + DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); @@ -217,17 +367,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); @@ -236,38 +391,50 @@ 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; + 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_MCOL); - if(layernum >= MAX_MCOL) + layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL); + if (layernum >= MAX_MCOL) { return -1; + } - EM_add_data_layer(em, &em->fdata, CD_MCOL, name); + BM_data_layer_add(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 data from active vertex color layer */ + if (layernum) { copy_editface_active_customdata(em, CD_MCOL, layernum); + } - if(active_set || layernum==0) - CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum); + if (active_set || layernum == 0) { + 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 -1; + } - if(me->mcol) - CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name); - else + if(me->mloopcol) { + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name); + CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mloopcol, me->totface, name); + } + else { + CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name); CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name); + } - if(active_set || layernum==0) + if(active_set || layernum==0) { + CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum); CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum); + } - mesh_update_customdata_pointers(me); + mesh_update_customdata_pointers(me, TRUE); } DAG_id_tag_update(&me->id, 0); @@ -278,12 +445,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; @@ -297,12 +463,11 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me) int ED_mesh_color_remove_named(bContext *C, Object *ob, Mesh *me, const char *name) { - CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata; CustomDataLayer *cdl; int index; - index= CustomData_get_named_layer_index(data, CD_MCOL, name); - cdl= (index == -1)? NULL: &data->layers[index]; + index= CustomData_get_named_layer_index(&me->ldata, CD_MLOOPCOL, name); + cdl= (index == -1)? NULL: &me->ldata.layers[index]; if(!cdl) return 0; @@ -384,25 +549,24 @@ 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(bmain, 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; /* load_editMesh free's pointers used by CustomData layers which might be used by DerivedMesh too, * so signal to re-create DerivedMesh here (sergey) */ @@ -589,10 +753,35 @@ void MESH_OT_sticky_remove(wmOperatorType *ot) void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges) { - if(calc_edges || (mesh->totface && mesh->totedge == 0)) + int *polyindex = NULL; + float (*face_nors)[3]; + + if(mesh->totface > 0 && mesh->totpoly == 0) + convert_mfaces_to_mpolys(mesh); + + if(calc_edges || (mesh->totpoly && mesh->totedge == 0)) BKE_mesh_calc_edges(mesh, calc_edges); - mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL); + /* TODO, make this optional, we dont always want this! */ + BKE_mesh_tessface_calc(mesh); + + polyindex = CustomData_get_layer(&mesh->fdata, CD_POLYINDEX); + /* add a normals layer for tesselated faces, a tessface normal will + contain the normal of the poly the face was tesselated from. */ + face_nors = CustomData_add_layer(&mesh->fdata, CD_NORMAL, CD_CALLOC, NULL, mesh->totface); + + mesh_calc_normals_mapping( + mesh->mvert, + mesh->totvert, + mesh->mloop, + mesh->mpoly, + mesh->totloop, + mesh->totpoly, + NULL /* polyNors_r */, + mesh->mface, + mesh->totface, + polyindex, + face_nors); DAG_id_tag_update(&mesh->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh); @@ -616,7 +805,7 @@ static void mesh_add_verts(Mesh *mesh, int len) CustomData_free(&mesh->vdata, mesh->totvert); mesh->vdata= vdata; - mesh_update_customdata_pointers(mesh); + mesh_update_customdata_pointers(mesh, FALSE); /* scan the input list and insert the new vertices */ @@ -636,7 +825,7 @@ void ED_mesh_transform(Mesh *me, float *mat) for(i= 0; i < me->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_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } static void mesh_add_edges(Mesh *mesh, int len) @@ -659,7 +848,7 @@ static void mesh_add_edges(Mesh *mesh, int len) CustomData_free(&mesh->edata, mesh->totedge); mesh->edata= edata; - mesh_update_customdata_pointers(mesh); + mesh_update_customdata_pointers(mesh, FALSE); /* new edges dont change tessellation */ /* set default flags */ medge= &mesh->medge[mesh->totedge]; @@ -689,7 +878,7 @@ static void mesh_add_faces(Mesh *mesh, int len) CustomData_free(&mesh->fdata, mesh->totface); mesh->fdata= fdata; - mesh_update_customdata_pointers(mesh); + mesh_update_customdata_pointers(mesh, TRUE); /* set default flags */ mface= &mesh->mface[mesh->totface]; @@ -699,6 +888,60 @@ static void mesh_add_faces(Mesh *mesh, int len) mesh->totface= totface; } +static void mesh_add_loops(Mesh *mesh, int len) +{ + CustomData ldata; + int totloop; + + if(len == 0) + return; + + totloop= mesh->totloop + len; /* new face count */ + + /* update customdata */ + CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop); + CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); + + if(!CustomData_has_layer(&ldata, CD_MLOOP)) + CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop); + + CustomData_free(&mesh->ldata, mesh->totloop); + mesh->ldata= ldata; + mesh_update_customdata_pointers(mesh, TRUE); + + mesh->totloop= totloop; +} + +static void mesh_add_polys(Mesh *mesh, int len) +{ + CustomData pdata; + MPoly *mpoly; + int i, totpoly; + + if(len == 0) + return; + + totpoly= mesh->totpoly + len; /* new face count */ + + /* update customdata */ + CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly); + CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); + + if(!CustomData_has_layer(&pdata, CD_MPOLY)) + CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly); + + CustomData_free(&mesh->pdata, mesh->totpoly); + mesh->pdata= pdata; + mesh_update_customdata_pointers(mesh, TRUE); + + /* set default flags */ + mpoly= &mesh->mpoly[mesh->totpoly]; + for(i=0; i<len; i++, mpoly++) + mpoly->flag= ME_FACE_SEL; + + mesh->totpoly= totpoly; +} + static void mesh_remove_verts(Mesh *mesh, int len) { int totvert; @@ -742,7 +985,7 @@ static void mesh_remove_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; } @@ -758,7 +1001,7 @@ 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; } @@ -768,9 +1011,9 @@ void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int 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); @@ -778,7 +1021,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; } @@ -788,7 +1031,7 @@ void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count) void ED_mesh_faces_remove(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't remove faces in edit mode"); return; } @@ -802,7 +1045,7 @@ void ED_mesh_faces_remove(Mesh *mesh, ReportList *reports, int count) void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't remove edges in edit mode"); return; } @@ -816,7 +1059,7 @@ void ED_mesh_edges_remove(Mesh *mesh, ReportList *reports, int count) void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count) { - if(mesh->edit_mesh) { + if(mesh->edit_btmesh) { BKE_report(reports, RPT_ERROR, "Can't remove vertices in edit mode"); return; } @@ -828,7 +1071,27 @@ void ED_mesh_vertices_remove(Mesh *mesh, ReportList *reports, int count) mesh_remove_verts(mesh, count); } -void ED_mesh_calc_normals(Mesh *me) +void ED_mesh_loops_add(Mesh *mesh, ReportList *reports, int count) +{ + if(mesh->edit_btmesh) { + BKE_report(reports, RPT_ERROR, "Can't add loops in edit mode."); + return; + } + + mesh_add_loops(mesh, count); +} + +void ED_mesh_polys_add(Mesh *mesh, ReportList *reports, int count) +{ + if(mesh->edit_btmesh) { + BKE_report(reports, RPT_ERROR, "Can't add polys in edit mode."); + return; + } + + mesh_add_polys(mesh, count); +} + +void ED_mesh_calc_normals(Mesh *mesh) { - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals_mapping(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 88fecae3c32..16c1da06383 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -37,14 +37,60 @@ struct bContext; struct wmOperatorType; -struct wmOperator; struct ViewContext; +struct BMEditMesh; +struct BMesh; +struct BMEdge; +struct BMFace; +struct BMOperator; +struct wmOperator; +struct wmKeyMap; +struct wmKeyConfig; +struct EnumPropertyItem; + +/* ******************** 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, const int report); + +void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); +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); +#if 0 /* REMOVE AFTER BMESH MERGE */ /* ******************* editmesh.c */ @@ -52,6 +98,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); @@ -63,6 +113,8 @@ 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); +#endif + void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); void MESH_OT_separate(struct wmOperatorType *ot); @@ -85,6 +137,8 @@ void MESH_OT_duplicate(struct wmOperatorType *ot); void MESH_OT_fgon_make(struct wmOperatorType *ot); void MESH_OT_fgon_clear(struct wmOperatorType *ot); +#if 0 /* REMOVE AFTER BMESH MERGE */ + /* ******************* editmesh_lib.c */ void EM_stats_update(EditMesh *em); @@ -133,15 +187,21 @@ extern int convex(float *v1, float *v2, float *v3, float *v4); extern struct EditFace *EM_face_from_faces(EditMesh *em, struct EditFace *efa1, struct EditFace *efa2, int i1, int i2, int i3, int i4); +#endif + 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_select_interior_faces(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_non_manifold(struct wmOperatorType *ot); @@ -150,6 +210,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); @@ -163,49 +224,23 @@ void MESH_OT_mark_sharp(struct wmOperatorType *ot); void MESH_OT_mark_freestyle_edge(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); +void MESH_OT_select_next_loop(struct wmOperatorType *ot); +extern struct EnumPropertyItem *corner_type_items; -extern EditEdge *findnearestedge(struct 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(struct ViewContext *vc, int *dist, short sel, short strict); - - -/* ******************* editmesh_tools.c */ - -#define SUBDIV_SELECT_ORIG 0 -#define SUBDIV_SELECT_INNER 1 -#define SUBDIV_SELECT_INNER_SEL 2 -#define SUBDIV_SELECT_LOOPCUT 3 - -/* edge subdivide corner cut types */ -#define SUBDIV_CORNER_PATH 0 -#define SUBDIV_CORNER_INNERVERT 1 -#define SUBDIV_CORNER_FAN 2 - -extern EnumPropertyItem corner_type_items[]; +#if 0 /* REMOVE AFTER BMESH MERGE */ void join_triangles(EditMesh *em); int removedoublesflag(EditMesh *em, short flag, short automerge, float limit); /* return amount */ void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beautify, int numcuts, int corner_pattern, int seltype); int EdgeSlide(EditMesh *em, struct wmOperator *op, short immediate, float imperc); +#endif + void MESH_OT_merge(struct wmOperatorType *ot); void MESH_OT_subdivide(struct wmOperatorType *ot); void MESH_OT_remove_doubles(struct wmOperatorType *ot); @@ -219,6 +254,7 @@ void MESH_OT_fill(struct wmOperatorType *ot); void MESH_OT_beautify_fill(struct wmOperatorType *ot); void MESH_OT_quads_convert_to_tris(struct wmOperatorType *ot); void MESH_OT_tris_convert_to_quads(struct wmOperatorType *ot); +void MESH_OT_dissolve_limited(struct wmOperatorType *ot); void MESH_OT_edge_flip(struct wmOperatorType *ot); void MESH_OT_faces_shade_smooth(struct wmOperatorType *ot); void MESH_OT_faces_shade_flat(struct wmOperatorType *ot); @@ -231,9 +267,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,9 +292,23 @@ 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); + +void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot); + /* ******************* mesh_navmesh.c */ void MESH_OT_navmesh_make(struct wmOperatorType *ot); void MESH_OT_navmesh_face_copy(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 973659cbb35..99947cb9ae2 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -46,6 +46,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_cdderivedmesh.h" #include "BKE_report.h" +#include "BKE_tessmesh.h" #include "BLI_editVert.h" #include "BLI_listbase.h" @@ -90,11 +91,11 @@ static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float BLI_linklist_append(&dms, (void*)dm); nverts+= dm->getNumVerts(dm); - nfaces= dm->getNumFaces(dm); + nfaces= dm->getNumTessFaces(dm); ntris+= nfaces; /* resolve quad faces */ - mface= dm->getFaceArray(dm); + mface= dm->getTessFaceArray(dm); for(i= 0; i<nfaces; i++) { MFace* mf= &mface[i]; if(mf->v4) @@ -129,8 +130,8 @@ static void createVertsTrisData(bContext *C, LinkNode* obs, int *nverts_r, float } /* create tris */ - curnfaces= dm->getNumFaces(dm); - mface= dm->getFaceArray(dm); + curnfaces= dm->getNumTessFaces(dm); + mface= dm->getTessFaceArray(dm); for(i= 0; i<curnfaces; i++) { MFace* mf= &mface[i]; @@ -292,7 +293,7 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, struct recast_polyMeshDetail *dmesh, Base* base) { float co[3], rot[3]; - EditMesh *em; + BMEditMesh *em; int i,j, k; unsigned short* v; int face[3]; @@ -320,14 +321,11 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, } ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); - em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)); + em= (((Mesh *)obedit->data))->edit_btmesh; if(!createob) { /* clear */ - 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)); + EDBM_ClearMesh(em); } /* create verts for polygon mesh */ @@ -341,12 +339,12 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, co[1]= bmin[1] + v[1]*ch; co[2]= bmin[2] + v[2]*cs; SWAP(float, co[1], co[2]); - addvertlist(em, co, NULL); + BM_vert_create(em->bm, co, NULL); } /* create custom data layer to save polygon idx */ - CustomData_add_layer_named(&em->fdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData"); - + CustomData_add_layer_named(&em->bm->pdata, CD_RECAST, CD_CALLOC, NULL, 0, "createRepresentation recastData"); + /* create verts and faces for detailed mesh */ meshes= recast_polyMeshDetailGetMeshes(dmesh, &nmeshes); polys= recast_polyMeshGetPolys(pmesh, NULL, &nvp); @@ -354,7 +352,7 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, tris= recast_polyMeshDetailGetTris(dmesh, NULL); for(i= 0; i<nmeshes; i++) { - int uniquevbase= em->totvert; + int uniquevbase= em->bm->totvert; unsigned int vbase= meshes[4*i+0]; unsigned short ndv= meshes[4*i+1]; unsigned short tribase= meshes[4*i+2]; @@ -371,39 +369,40 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, for(j= nv; j<ndv; j++) { copy_v3_v3(co, &dverts[3*(vbase + j)]); SWAP(float, co[1], co[2]); - addvertlist(em, co, NULL); + BM_vert_create(em->bm, co, NULL); } - EM_init_index_arrays(em, 1, 0, 0); + EDBM_init_index_arrays(em, 1, 0, 0); /* create faces */ for(j= 0; j<trinum; j++) { unsigned char* tri= &tris[4*(tribase+j)]; - EditFace* newFace; + BMFace* newFace; int* polygonIdx; for(k= 0; k<3; k++) { if(tri[k]<nv) - face[k]= p[tri[k]]; /* shared vertex */ + face[k] = p[tri[k]]; /* shared vertex */ else - face[k]= uniquevbase+tri[k]-nv; /* unique vertex */ + face[k] = uniquevbase+tri[k]-nv; /* unique vertex */ } - newFace= addfacelist(em, EM_get_vert_for_index(face[0]), EM_get_vert_for_index(face[2]), - EM_get_vert_for_index(face[1]), NULL, NULL, NULL); + newFace= BM_face_create_quad_tri(em->bm, + EDBM_get_vert_for_index(em, face[0]), + EDBM_get_vert_for_index(em, face[2]), + EDBM_get_vert_for_index(em, face[1]), NULL, + NULL, FALSE); /* set navigation polygon idx to the custom layer */ - polygonIdx= (int*)CustomData_em_get(&em->fdata, newFace->data, CD_RECAST); + polygonIdx= (int*)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST); *polygonIdx= i+1; /* add 1 to avoid zero idx */ } - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } recast_destroyPolyMesh(pmesh); recast_destroyPolyMeshDetail(dmesh); - BKE_mesh_end_editmesh((Mesh*)obedit->data, em); - DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); @@ -485,22 +484,23 @@ void MESH_OT_navmesh_make(wmOperatorType *ot) static int navmesh_face_copy_exec(bContext *C, wmOperator *op) { Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; /* do work here */ - EditFace *efa_act= EM_get_actFace(em, 0); + BMFace *efa_act= BM_active_face_get(em->bm, FALSE); if(efa_act) { - if(CustomData_has_layer(&em->fdata, CD_RECAST)) { - EditFace *efa; - int targetPolyIdx= *(int*)CustomData_em_get(&em->fdata, efa_act->data, CD_RECAST); + if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) { + BMFace *efa; + BMIter iter; + int targetPolyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, efa_act->head.data, CD_RECAST); targetPolyIdx= targetPolyIdx>=0? targetPolyIdx : -targetPolyIdx; if(targetPolyIdx > 0) { /* set target poly idx to other selected faces */ - for (efa= (EditFace *)em->faces.first; efa; efa= efa->next) { - if((efa->f & SELECT) && efa != efa_act) { - int* recastDataBlock= (int*)CustomData_em_get(&em->fdata, efa->data, CD_RECAST); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_elem_flag_test(efa, BM_ELEM_SELECT) && efa != efa_act) { + int* recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_RECAST); *recastDataBlock= targetPolyIdx; } } @@ -514,8 +514,6 @@ static int navmesh_face_copy_exec(bContext *C, wmOperator *op) DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh((Mesh*)obedit->data, em); - return OPERATOR_FINISHED; } @@ -539,19 +537,20 @@ static int compare(const void * a, const void * b) return ( *(int*)a - *(int*)b ); } -static int findFreeNavPolyIndex(EditMesh* em) +static int findFreeNavPolyIndex(BMEditMesh* em) { /* construct vector of indices */ - int numfaces= em->totface; + int numfaces= em->bm->totface; int* indices= MEM_callocN(sizeof(int)*numfaces, "findFreeNavPolyIndex(indices)"); - EditFace* ef= (EditFace*)em->faces.last; - int i, idx= 0, freeIdx= 1; + BMFace* ef; + BMIter iter; + int i, idx= em->bm->totface-1, freeIdx= 1; - while(ef) { - int polyIdx= *(int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST); + /*XXX this originally went last to first, but that isn't possible anymore*/ + BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int polyIdx= *(int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST); indices[idx]= polyIdx; - idx++; - ef= ef->prev; + idx--; } qsort(indices, numfaces, sizeof(int), compare); @@ -573,21 +572,22 @@ static int findFreeNavPolyIndex(EditMesh* em) static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op)) { Object *obedit= CTX_data_edit_object(C); - EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data); - EditFace *ef; - - if(CustomData_has_layer(&em->fdata, CD_RECAST)) { + BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh; + BMFace *ef; + BMIter iter; + + if(CustomData_has_layer(&em->bm->pdata, CD_RECAST)) { int targetPolyIdx= findFreeNavPolyIndex(em); if(targetPolyIdx>0) { /* set target poly idx to selected faces */ - ef= (EditFace*)em->faces.last; - while(ef) { - if(ef->f & SELECT) { - int *recastDataBlock= (int*)CustomData_em_get(&em->fdata, ef->data, CD_RECAST); + /*XXX this originally went last to first, but that isn't possible anymore*/ + + BM_ITER(ef, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if(BM_elem_flag_test(ef, BM_ELEM_SELECT)) { + int *recastDataBlock= (int*)CustomData_bmesh_get(&em->bm->pdata, ef->head.data, CD_RECAST); *recastDataBlock= targetPolyIdx; } - ef= ef->prev; } } } @@ -595,7 +595,6 @@ static int navmesh_face_add_exec(bContext *C, wmOperator *UNUSED(op)) DAG_id_tag_update((ID*)obedit->data, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh((Mesh*)obedit->data, em); return OPERATOR_FINISHED; } @@ -619,7 +618,7 @@ static int navmesh_obmode_data_poll(bContext *C) Object *ob = ED_object_active_context(C); if (ob && (ob->mode == OB_MODE_OBJECT) && (ob->type == OB_MESH)) { Mesh *me= ob->data; - return CustomData_has_layer(&me->fdata, CD_RECAST); + return CustomData_has_layer(&me->pdata, CD_RECAST); } return FALSE; } @@ -638,7 +637,7 @@ static int navmesh_reset_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_active_context(C); Mesh *me= ob->data; - CustomData_free_layers(&me->fdata, CD_RECAST, me->totface); + CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly); BKE_mesh_ensure_navmesh(me); @@ -668,7 +667,7 @@ static int navmesh_clear_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = ED_object_active_context(C); Mesh *me= ob->data; - CustomData_free_layers(&me->fdata, CD_RECAST, me->totface); + CustomData_free_layers(&me->pdata, CD_RECAST, me->totpoly); DAG_id_tag_update(&me->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_GEOM|ND_DATA, &me->id); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index e6268d80c21..90f125cf75a 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -60,6 +60,7 @@ void ED_operatortypes_mesh(void) { WM_operatortype_append(MESH_OT_select_all); + WM_operatortype_append(MESH_OT_select_interior_faces); WM_operatortype_append(MESH_OT_select_more); WM_operatortype_append(MESH_OT_select_less); WM_operatortype_append(MESH_OT_select_non_manifold); @@ -69,6 +70,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); @@ -84,16 +86,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); @@ -103,14 +107,15 @@ 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_uvs_reverse); WM_operatortype_append(MESH_OT_colors_rotate); - WM_operatortype_append(MESH_OT_colors_mirror); + WM_operatortype_append(MESH_OT_colors_reverse); WM_operatortype_append(MESH_OT_fill); WM_operatortype_append(MESH_OT_beautify_fill); WM_operatortype_append(MESH_OT_quads_convert_to_tris); WM_operatortype_append(MESH_OT_tris_convert_to_quads); + WM_operatortype_append(MESH_OT_dissolve_limited); WM_operatortype_append(MESH_OT_edge_flip); WM_operatortype_append(MESH_OT_faces_shade_smooth); WM_operatortype_append(MESH_OT_faces_shade_flat); @@ -132,7 +137,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); @@ -150,6 +155,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(MESH_OT_bridge_edge_loops); #ifdef WITH_GAMEENGINE WM_operatortype_append(MESH_OT_navmesh_make); @@ -165,7 +178,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; } @@ -201,32 +214,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", FALSE); 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", FALSE); 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", FALSE); 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"); - RNA_enum_set(otmacro->ptr, "type", 4); + otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv"); otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); RNA_enum_set(otmacro->ptr, "proportional", 0); RNA_boolean_set(otmacro->ptr, "mirror", FALSE); @@ -321,6 +330,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf) 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", JKEY, KM_PRESS, 0, 0); /* use KM_CLICK because same key is used for tweaks */ kmi = WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0); @@ -331,8 +341,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); @@ -352,5 +362,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 b94b60fc279..1b5011402fc 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -66,6 +66,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 @@ -79,14 +80,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) { @@ -97,16 +98,17 @@ int join_mesh_exec(bContext *C, wmOperator *op) Mesh *me; 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 a, b, totcol, totmat=0, totedge=0, totvert=0, ok=0; + int totloop=0, totpoly=0, vertofs, *matmap=NULL; + int i, j, index, haskey=0, edgeofs, 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"); @@ -126,7 +128,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) @@ -280,14 +283,18 @@ 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); @@ -398,7 +405,30 @@ int join_mesh_exec(bContext *C, wmOperator *op) mvert+= me->totvert; } - if(me->totface) { + if(me->totedge) { + CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); + CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); + + for(a=0; a<me->totedge; a++, medge++) { + medge->v1+= vertofs; + medge->v2+= vertofs; + } + } + + if (me->totloop) { + if(base->object!=ob) + multiresModifier_prepare_join(scene, base->object, ob); + + 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; + } + } + + if(me->totpoly) { /* make mapping for materials */ for(a=1; a<=base->object->totcol; a++) { ma= give_current_material(base->object, a); @@ -411,43 +441,23 @@ 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); - - for(a=0; a<me->totface; a++, mface++) { - mface->v1+= vertofs; - mface->v2+= vertofs; - mface->v3+= vertofs; - if(mface->v4) mface->v4+= vertofs; - - if (matmap) - mface->mat_nr= matmap[(int)mface->mat_nr]; - else - mface->mat_nr= 0; - } - - faceofs += me->totface; - } - - if(me->totedge) { - CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge); - CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge); + 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->totedge; a++, medge++) { - medge->v1+= vertofs; - medge->v2+= vertofs; + for(a=0; a<me->totpoly; a++, mpoly++) { + mpoly->loopstart += loopofs; + mpoly->mat_nr= matmap ? matmap[(int)mpoly->mat_nr] : 0; } - edgeofs += me->totedge; + polyofs += me->totpoly; } - - /* vertofs is used to help newly added verts be reattached to their edge/face - * (cannot be set earlier, or else reattaching goes wrong) + + /* 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) @@ -461,17 +471,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); + mesh_update_customdata_pointers(me, TRUE); /* BMESH_TODO, check if this arg can be failse, non urgent - campbell */ /* old material array */ for(a=1; a<=ob->totcol; a++) { @@ -527,11 +540,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); @@ -738,7 +751,7 @@ static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co) return (*bt)->index[a]-1; } else { - EditVert *eve= (EditVert *)((*bt)->index[a]); + BMVert *eve= (BMVert *)((*bt)->index[a]); if(compare_v3v3(eve->co, co, MOC_THRESH)) return (*bt)->index[a]; } @@ -758,7 +771,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; @@ -784,10 +797,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 { @@ -819,10 +833,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)); } } @@ -898,9 +913,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; @@ -918,20 +934,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) { intptr_t 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_VERTS_OF_MESH, NULL) { + if (v == eve) + break; + index++; + } + + if (index == em->bm->totvert) { return NULL; } } @@ -939,22 +963,23 @@ static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em poinval= mesh_topo_store.index_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) { if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) { - return editmesh_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_topo(ob, em, eve, index); + } + else { + 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]; @@ -982,25 +1007,30 @@ 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) @@ -1049,7 +1079,8 @@ 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) +/* BMESH_TODO, convert to MPoly (functions above also) */ +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 c8adfbda708..da8009ecc22 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -516,7 +516,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; @@ -534,7 +534,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 e7232524a21..05c042a4182 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -23,6 +23,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 d4739236ba1..883d0ca20ae 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 incs += ' #extern/recastnavigation' diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index dce2179db24..1b289732302 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -250,7 +250,7 @@ int ED_object_add_generic_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(ev } int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, - float *rot, int *enter_editmode, unsigned int *layer) + float *rot, int *enter_editmode, unsigned int *layer, int *is_view_aligned) { View3D *v3d = CTX_wm_view3d(C); int a, layer_values[20]; @@ -298,7 +298,9 @@ int ED_object_add_generic_get_opts(bContext *C, wmOperator *op, float *loc, 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) { @@ -352,7 +354,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); @@ -409,7 +411,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) { @@ -489,7 +491,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); @@ -543,7 +545,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) { @@ -612,7 +614,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) @@ -653,7 +655,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)) { @@ -721,7 +723,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); @@ -777,7 +779,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) { @@ -809,7 +811,7 @@ static int object_speaker_add_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); 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_SPEAKER, loc, rot, FALSE, layer); @@ -1368,7 +1370,9 @@ 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); + + /* re-tesselation is called by DM_to_mesh */ 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 d325b49c211..5f3a7cfe93b 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -367,16 +367,16 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData DerivedMesh *dm= bkr->lores_dm; ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); const int lvl= bkr->lvl; - const int tot_face= dm->getNumFaces(dm); + const int tot_face= dm->getNumTessFaces(dm); MVert *mvert= dm->getVertArray(dm); - MFace *mface= dm->getFaceArray(dm); - MTFace *mtface= dm->getFaceDataArray(dm, CD_MTFACE); + MFace *mface= dm->getTessFaceArray(dm); + MTFace *mtface= dm->getTessFaceDataArray(dm, CD_MTFACE); float *pvtangent= NULL; if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1) DM_add_tangent_layer(dm); - pvtangent= DM_get_face_data_layer(dm, CD_TANGENT); + pvtangent= DM_get_tessface_data_layer(dm, CD_TANGENT); if(tot_face > 0) { /* sanity check */ int f= 0; @@ -387,7 +387,7 @@ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData data.mvert= mvert; data.mtface= mtface; data.pvtangent= pvtangent; - data.precomputed_normals= dm->getFaceDataArray(dm, CD_NORMAL); /* don't strictly need this */ + data.precomputed_normals= dm->getTessFaceDataArray(dm, CD_NORMAL); /* don't strictly need this */ data.w= ibuf->x; data.h= ibuf->y; data.lores_dm= dm; @@ -514,7 +514,7 @@ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm, const int *orig int grid_size, S, face_side; int *grid_offset, g_index; - lodm->getFace(lodm, face_index, &mface); + lodm->getTessFace(lodm, face_index, &mface); grid_size= hidm->getGridSize(hidm); grid_data= hidm->getGridData(hidm); @@ -619,7 +619,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) height_data->ssdm= subsurf_make_derived_from_derived(bkr->lores_dm, &smd, 0, NULL, 0, 0, 0); } - height_data->origindex= lodm->getFaceDataArray(lodm, CD_ORIGINDEX); + height_data->origindex= lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX); return (void*)height_data; } @@ -631,7 +631,7 @@ static void *init_normal_data(MultiresBakeRender *bkr, Image *UNUSED(ima)) normal_data= MEM_callocN(sizeof(MNormalBakeData), "MultiresBake normalData"); - normal_data->origindex= lodm->getFaceDataArray(lodm, CD_ORIGINDEX); + normal_data->origindex= lodm->getTessFaceDataArray(lodm, CD_ORIGINDEX); return (void*)normal_data; } @@ -709,7 +709,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, int pixel= ibuf->x*y + x; float vec[3], p0[3], p1[3], n[3], len; - lores_dm->getFace(lores_dm, face_index, &mface); + lores_dm->getTessFace(lores_dm, face_index, &mface); st0= mtface[face_index].uv[0]; st1= mtface[face_index].uv[1]; @@ -729,7 +729,7 @@ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, if(height_data->ssdm) { get_ccgdm_data(lores_dm, height_data->ssdm, height_data->origindex, 0, face_index, uv[0], uv[1], p0, n); } else { - lores_dm->getFace(lores_dm, face_index, &mface); + lores_dm->getTessFace(lores_dm, face_index, &mface); if(mface.v4) { interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0); @@ -776,7 +776,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, int pixel= ibuf->x*y + x; float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5}; - lores_dm->getFace(lores_dm, face_index, &mface); + lores_dm->getTessFace(lores_dm, face_index, &mface); st0= mtface[face_index].uv[0]; st1= mtface[face_index].uv[1]; @@ -822,7 +822,7 @@ static void count_images(MultiresBakeRender *bkr) bkr->image.first= bkr->image.last= NULL; bkr->tot_image= 0; - totface= dm->getNumFaces(dm); + totface= dm->getNumTessFaces(dm); for(a= 0; a<totface; a++) mtface[a].tpage->id.flag&= ~LIB_DOIT; @@ -949,6 +949,7 @@ static int multiresbake_check(bContext *C, wmOperator *op) ok= 0; } else { + /* BMESH_TODO - use MPoly rather then tessface */ a= me->totface; while (ok && a--) { Image *ima= me->mtface[a].tpage; @@ -995,7 +996,9 @@ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *l *lvl= mmd->lvl; if(*lvl==0) { - return NULL; + DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob); + dm= CDDM_copy(tmp_dm); + tmp_dm->release(tmp_dm); } else { MultiresModifierData tmp_mmd= *mmd; DerivedMesh *cddm= CDDM_from_mesh(me, ob); @@ -1157,7 +1160,7 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa DerivedMesh *dm= data->lores_dm; MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE); - clear_images(mtface, dm->getNumFaces(dm)); + clear_images(mtface, dm->getNumTessFaces(dm)); } } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 1286ac850f6..a28b5c4feaa 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -79,6 +79,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,18 +322,18 @@ void ED_object_exit_editmode(bContext *C, int flag) // if(EM_texFaceCheck()) - 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(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) { mesh_octree_table(NULL, NULL, NULL, 'e'); mesh_mirrtopo_table(NULL, 'e'); @@ -442,7 +443,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); } @@ -1004,7 +1005,10 @@ static void UNUSED_FUNCTION(copy_attr_menu)(Main *bmain, Scene *scene, View3D *v * view3d_edit_object_copyattrmenu() and in toolbox.c */ - strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l"); + strcpy(str, + "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|" + "Time Offset%x5|Dupli%x6|Object Color%x31|%l|Mass%x7|Damping%x8|All Physical Attributes%x11|Properties%x9|" + "Logic Bricks%x10|Protected Transform%x29|%l"); strcat (str, "|Object Constraints%x22"); strcat (str, "|NLA Strips%x26"); diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index de991f28e4a..2083c51efa9 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -55,6 +55,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" @@ -71,13 +72,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_elem_flag_test(eve, BM_ELEM_SELECT)) totvert++; } if(totvert==0) return 0; @@ -86,8 +88,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_elem_flag_test(eve, BM_ELEM_SELECT)) { *index= nr; index++; add_v3_v3(cent, eve->co); } @@ -99,7 +101,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); @@ -108,11 +110,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) { @@ -132,25 +135,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_elem_select_set(em->bm, eve, TRUE); if(index < hmd->totindex-1) index++; } + + nr++; } - EM_select_flush(em); - BKE_mesh_end_editmesh(me, em); + EDBM_select_flush(em); } static int return_editlattice_indexar(Lattice *editlatt, int *tot, int **indexar, float *cent) @@ -300,20 +305,19 @@ static int object_hook_index_array(Scene *scene, Object *obedit, int *tot, int * case OB_MESH: { Mesh *me= obedit->data; - EditMesh *em; - load_editMesh(scene, obedit); - make_editMesh(scene, obedit); + BMEditMesh *em; - em = BKE_mesh_get_editmesh(me); + EDBM_LoadEditBMesh(scene, obedit); + EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit); + + 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; } } @@ -382,7 +386,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); @@ -742,6 +746,7 @@ void OBJECT_OT_hook_recenter(wmOperatorType *ot) static int object_hook_assign_exec(bContext *C, wmOperator *op) { + Scene *scene= CTX_data_scene(C); PointerRNA ptr= CTX_data_pointer_get_type(C, "modifier", &RNA_HookModifier); int num= RNA_enum_get(op->ptr, "modifier"); Object *ob=NULL; @@ -765,7 +770,7 @@ static int object_hook_assign_exec(bContext *C, wmOperator *op) /* assign functionality */ - if(!object_hook_index_array(CTX_data_scene(C), ob, &tot, &indexar, name, cent)) { + if(!object_hook_index_array(scene, ob, &tot, &indexar, name, cent)) { BKE_report(op->reports, RPT_WARNING, "Requires selected vertices or active vertex group"); return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 73c5c50f448..526706b566d 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -159,6 +159,7 @@ 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_ocean_bake(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 cac167ad84f..9f3bc9bbf37 100644 --- a/source/blender/editors/object/object_lattice.c +++ b/source/blender/editors/object/object_lattice.c @@ -366,7 +366,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; @@ -375,7 +375,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 ed5899d81a8..e8a09732313 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -68,6 +68,7 @@ #include "BKE_ocean.h" #include "BKE_particle.h" #include "BKE_softbody.h" +#include "BKE_tessmesh.h" #include "RNA_access.h" #include "RNA_define.h" @@ -214,15 +215,15 @@ static int object_modifier_remove(Object *ob, ModifierData *md, int *sort_depsgr } 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_data_layer_free(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); } } } @@ -446,6 +447,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; @@ -457,7 +469,7 @@ static int modifier_apply_shape(ReportList *reports, Scene *scene, Object *ob, M return 0; } - 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; @@ -515,19 +527,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); } } } @@ -1165,6 +1177,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 *ml_prev = ME_POLY_LOOP_PREV(me->mloop, mp, j); + MLoop *ml_next = ME_POLY_LOOP_NEXT(me->mloop, mp, j); + + if ((me->mvert[ml->v].flag&SELECT) && (me->mvert[ml_prev->v].flag&SELECT) && (me->mvert[ml_next->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) @@ -1177,7 +1249,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); @@ -1185,8 +1257,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; } @@ -1206,7 +1278,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_struct_property_is_set(op->ptr, "filepath")) @@ -1247,11 +1319,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; } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 09ae6365363..542b75e1f19 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -214,8 +214,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 37461377506..f64f25391f9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -79,6 +79,7 @@ #include "BKE_scene.h" #include "BKE_speaker.h" #include "BKE_texture.h" +#include "BKE_tessmesh.h" #include "WM_api.h" #include "WM_types.h" @@ -94,9 +95,9 @@ #include "ED_curve.h" #include "ED_keyframing.h" #include "ED_object.h" +#include "ED_mesh.h" #include "ED_screen.h" #include "ED_view3d.h" -#include "ED_mesh.h" #include "object_intern.h" @@ -112,7 +113,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; @@ -124,20 +126,19 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) if(obedit->type==OB_MESH) { Mesh *me= obedit->data; - EditMesh *em; + BMEditMesh *em; - load_editMesh(scene, obedit); - make_editMesh(scene, obedit); + EDBM_LoadEditBMesh(scene, obedit); + EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit); - em= BKE_mesh_get_editmesh(me); + em= me->edit_btmesh; /* derivedMesh might be needed for solving parenting, so re-create it here */ - makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH); + makeDerivedMesh(scene, obedit, em, CD_MASK_BAREMESH, 0); - eve= em->verts.first; - while(eve) { - if(eve->f & 1) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { if(v1==0) v1= nr; else if(v2==0) v2= nr; else if(v3==0) v3= nr; @@ -145,10 +146,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op) else break; } nr++; - eve= eve->next; } - - BKE_mesh_end_editmesh(me, em); } else if(ELEM(obedit->type, OB_SURF, OB_CURVE)) { ListBase *editnurb= object_editcurve_get(obedit); diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index e57574af839..68c017adecd 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -51,6 +51,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" @@ -479,7 +480,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_mapping(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); @@ -656,37 +657,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 7fe98a604ec..78d90bb39d2 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -41,6 +41,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" @@ -49,7 +50,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" -#include "BLI_editVert.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -58,6 +58,7 @@ #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "BKE_report.h" #include "BKE_DerivedMesh.h" @@ -90,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); @@ -187,31 +188,33 @@ 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; - if (use_vert_sel) { - for (eve=em->verts.first; eve; eve=eve->next, i++) { - (*dvert_arr)[i] = (eve->f & SELECT) ? - CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT) : NULL; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + (*dvert_arr)[i] = BM_elem_flag_test(eve, BM_ELEM_SELECT) ? + CustomData_em_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT) : NULL; + i++; } } else { - 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++; } } @@ -511,19 +514,19 @@ void ED_vgroup_vert_remove(Object *ob, bDeformGroup *dg, int vertnum) static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) { MDeformVert *dv= NULL; - EditVert *eve; + BMVert *eve; Mesh *me; /* get the deform vertices corresponding to the 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= BM_vert_at_index(me->edit_btmesh->bm, vertnum); if(!eve) { return 0.0f; } - dv= CustomData_em_get(&me->edit_mesh->vdata, eve->data, CD_MDEFORMVERT); + dv= CustomData_bmesh_get(&me->edit_btmesh->bm->vdata, eve->head.data, CD_MDEFORMVERT); } else { if(vertnum >= me->totvert) { @@ -584,24 +587,23 @@ static void vgroup_select_verts(Object *ob, int select) if(ob->type == OB_MESH) { Mesh *me= ob->data; - if (me->edit_mesh) { - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; - for (eve=em->verts.first; eve; eve=eve->next) { - if (!eve->h) { - dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if (defvert_find_index(dv, def_nr)) { - if (select) eve->f |= SELECT; - else eve->f &= ~SELECT; + BM_elem_select_set(em->bm, eve, select); } } } - /* 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); + /* this has to be called, because this function operates on vertices only */ + if(select) EDBM_select_flush(em); // vertices to edges/faces + else EDBM_deselect_flush(em); } else { if (me->dvert) { @@ -776,6 +778,8 @@ static int tryToAddVerts(int *verts, int length, int a, int b) return added; } +/* BMESH_TODO - use MPoly's */ + /* This finds all of the vertices connected to vert by an edge and returns an array of indices of size count @@ -1284,51 +1288,51 @@ static void vgroup_blend(Object *ob) int i, dvert_tot=0; const int def_nr= ob->actdef-1; - EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)ob->data)); + BMEditMesh *em= ((Mesh *)ob->data)->edit_btmesh; // ED_vgroup_give_array(ob->data, &dvert_array, &dvert_tot); if (em==NULL) return; if (BLI_findlink(&ob->defbase, def_nr)) { - int sel1, sel2; + BMEdge *eed; + BMVert *eve; + BMIter iter; + int i1, i2; - EditEdge *eed; - EditVert *eve; float *vg_weights; float *vg_users; + int sel1, sel2; - i= 0; - for(eve= em->verts.first; eve; eve= eve->next) - eve->tmp.l= i++; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - dvert_tot= i; + dvert_tot= em->bm->totvert; 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_elem_flag_test(eed->v1, BM_ELEM_SELECT); + sel2= BM_elem_flag_test(eed->v2, BM_ELEM_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_elem_index_get(eed->v1); + i2= BM_elem_index_get(eed->v2); eve= eed->v2; } else { - i2= eed->v1->tmp.l; - i1= eed->v2->tmp.l; + i2= BM_elem_index_get(eed->v1); + i1= BM_elem_index_get(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); @@ -1340,10 +1344,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_elem_flag_test(eve, BM_ELEM_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); @@ -1511,7 +1515,7 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v all_vgroups, def_nr \ ) - EditVert *eve, *eve_mirr; + BMVert *eve, *eve_mirr; MDeformVert *dvert, *dvert_mirr; short sel, sel_mirr; int *flip_map, flip_map_len; @@ -1543,33 +1547,37 @@ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_v /* only the active group */ if(ob->type == OB_MESH) { Mesh *me= ob->data; - EditMesh *em = BKE_mesh_get_editmesh(me); + BMEditMesh *em = me->edit_btmesh; if (em) { - if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) { + BMIter iter; + + if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) { goto cleanup; } - EM_cache_x_mirror_vert(ob, em); + EDBM_CacheMirrorVerts(em, FALSE); /* Go through the list of editverts and assign them */ - for(eve=em->verts.first; eve; eve=eve->next){ - if((eve_mirr=eve->tmp.v)) { - sel= eve->f & SELECT; - sel_mirr= eve_mirr->f & SELECT; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if((eve_mirr= EDBM_GetMirrorVert(em, eve))) { + sel= BM_elem_flag_test(eve, BM_ELEM_SELECT); + sel_mirr= BM_elem_flag_test(eve_mirr, BM_ELEM_SELECT); if((sel || sel_mirr) && (eve != eve_mirr)) { - dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); - dvert_mirr= CustomData_em_get(&em->vdata, eve_mirr->data, CD_MDEFORMVERT); + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + dvert_mirr= CustomData_bmesh_get(&em->bm->vdata, eve_mirr->head.data, CD_MDEFORMVERT); if(dvert && dvert_mirr) { VGROUP_MIRR_OP; } } - eve->tmp.v= eve_mirr->tmp.v= NULL; + /* don't use these again */ + EDBM_ClearMirrorVert(em, eve); + EDBM_ClearMirrorVert(em, eve_mirr); } } - BKE_mesh_end_editmesh(me, em); + EDBM_EndMirrorCache(em); } else { /* object mode / weight paint */ @@ -1771,19 +1779,19 @@ static void vgroup_active_remove_verts(Object *ob, const int allverts, bDeformGr if(ob->type == OB_MESH) { Mesh *me= ob->data; - if (me->edit_mesh) { - EditVert *eve; - EditMesh *em = BKE_mesh_get_editmesh(me); + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMVert *eve; + BMIter iter; - for (eve=em->verts.first; eve; eve=eve->next) { - dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); - if (dv && dv->dw && (allverts || (eve->f & SELECT))) { + if(dv && dv->dw && (allverts || BM_elem_flag_test(eve, BM_ELEM_SELECT))) { MDeformWeight *dw = defvert_find_index(dv, def_nr); defvert_remove_group(dv, dw); /* dw can be NULL */ } } - BKE_mesh_end_editmesh(me, em); } else { MVert *mv; @@ -1841,19 +1849,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); @@ -1903,7 +1911,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); @@ -1915,7 +1923,7 @@ static int vgroup_object_in_wpaint_vert_select(Object *ob) if (ob->type == OB_MESH) { Mesh *me = ob->data; return ( (ob->mode & OB_MODE_WEIGHT_PAINT) && - (me->edit_mesh == NULL) && + (me->edit_btmesh == NULL) && (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) ); } @@ -1968,25 +1976,26 @@ static void vgroup_assign_verts(Object *ob, const float weight) if(ob->type == OB_MESH) { Mesh *me= ob->data; - if (me->edit_mesh) { - EditMesh *em = BKE_mesh_get_editmesh(me); - EditVert *eve; - if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) - EM_add_data_layer(em, &em->vdata, CD_MDEFORMVERT, NULL); + if (me->edit_btmesh) { + BMEditMesh *em = me->edit_btmesh; + BMIter iter; + BMVert *eve; + + if(!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) + BM_data_layer_add(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) { - if (eve->f & SELECT) { + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { MDeformWeight *dw; - dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); /* can be NULL */ + dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); /* can be NULL */ dw= defvert_verify_index(dv, def_nr); if (dw) { dw->weight= weight; } } } - BKE_mesh_end_editmesh(me, em); } else { MVert *mv; @@ -2795,11 +2804,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, defbase_tot); } diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript index 188416eb04c..a478b2afb1c 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 dbf03e34c32..5648bc69099 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1064,7 +1064,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"); @@ -1075,7 +1075,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); @@ -2563,7 +2563,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) @@ -3067,6 +3067,8 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, return 0; } + /* BMESH_ONLY, deform dm may not have tessface */ + DM_ensure_tessface(dm); if(pa_minmax==0){ @@ -3079,8 +3081,8 @@ static int particle_intersect_dm(Scene *scene, Object *ob, DerivedMesh *dm, copy_v3_v3(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 */ @@ -3472,7 +3474,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr) view3d_operator_needs_opengl(C); selected= (short)count_selected_keys(scene, edit); - dmax = MAX2(fabs(dx), fabs(dy)); + dmax = maxf(fabsf(dx), fabsf(dy)); tot_steps = dmax/(0.2f * brush->size) + 1; dx /= (float)tot_steps; diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index b26661da4a2..da3f7e1f7c1 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -649,6 +649,10 @@ static void connect_hair(Scene *scene, Object *ob, ParticleSystem *psys) else dm= mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); + /* BMESH_ONLY, deform dm may not have tessface */ + DM_ensure_tessface(dm); + + numverts = dm->getNumVerts (dm); /* convert to global coordinates */ @@ -671,7 +675,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 db3f03c5d91..c9be7d0e5e0 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -26,6 +26,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 e7e883f9ef6..e496e4b4373 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 ../../freestyle' incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern' -incs += ' ../../blenloader' +incs += ' ../../blenloader ../../bmesh' if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index f31777857b1..5e0f4629e11 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -63,6 +63,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" @@ -168,13 +169,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_elem_flag_test(efa, BM_ELEM_SELECT)) efa->mat_nr= ob->actcol-1; + } } } else if(ELEM(ob->type, OB_CURVE, OB_SURF)) { @@ -227,13 +230,10 @@ 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; + 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); + EDBM_deselect_by_material(em, ob->actcol-1, select); } } else if ELEM(ob->type, OB_CURVE, OB_SURF) { diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 3614052684c..79a805cfa6e 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -24,6 +24,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 1381c820224..ade26a0b80f 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 2c652df93a0..22bac3a6699 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; } @@ -367,18 +368,15 @@ int ED_operator_uvedit(bContext *C) 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; } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 9fa91af7aec..8a6a236d10f 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -23,6 +23,7 @@ set(INC ../../blenkernel ../../blenlib ../../blenloader + ../../bmesh ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript index dd82e01240b..8669ea6c695 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 ../uvedit' +incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh ../uvedit' if env['OURPLATFORM'] == 'linux': cflags='-pthread' diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index b8b36954e22..681ab3a1492 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -84,6 +84,8 @@ #include "BKE_global.h" #include "BKE_deform.h" +#include "BKE_tessmesh.h" + #include "BIF_gl.h" #include "BIF_glutil.h" @@ -2977,11 +2979,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? */ @@ -4647,7 +4649,7 @@ static int image_paint_poll(bContext *C) static int uv_sculpt_brush_poll(bContext *C) { - EditMesh *em; + BMEditMesh *em; int ret; Object *obedit = CTX_data_edit_object(C); SpaceImage *sima= CTX_wm_space_image(C); @@ -4657,9 +4659,8 @@ static int uv_sculpt_brush_poll(bContext *C) if(!uv_sculpt_brush(C) || !obedit || 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); if(ret && sima) { ARegion *ar= CTX_wm_region(C); diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 0705ea29985..70293765813 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -250,9 +250,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]; @@ -265,7 +265,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 941e885c143..4ce304a62c4 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -43,6 +43,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_memarena.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -85,15 +86,45 @@ #include "paint_intern.h" -/* polling - retrieve whether cursor should be set or operator should be done */ +/* check if we can do partial updayes and have them draw realtime + * (without rebuilding the 'derivedFinal') */ +static int vertex_paint_use_fast_update_check(Object *ob) +{ + DerivedMesh *dm = ob->derivedFinal; + + if (dm) { + Mesh *me = get_mesh(ob); + if (me && me->mcol) { + return (me->mcol == CustomData_get_layer(&dm->faceData, CD_MCOL)); + } + } + + return FALSE; +} + +/* if the polygons from the mesh and the 'derivedFinal' match + * we can assume that no modifiers are applied and that its worth adding tesselated faces + * so 'vertex_paint_use_fast_update_check()' returns TRUE */ +static int vertex_paint_use_tessface_check(Object *ob) +{ + DerivedMesh *dm = ob->derivedFinal; + + if (dm) { + Mesh *me = get_mesh(ob); + return (me->mpoly == CustomData_get_layer(&dm->faceData, CD_MPOLY)); + } + + return FALSE; +} +/* polling - retrieve whether cursor should be set or operator should be done */ /* Returns true if vertex paint mode is active */ int vertex_paint_mode_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totface; + return ob && ob->mode == OB_MODE_VERTEX_PAINT && ((Mesh *)ob->data)->totpoly; } int vertex_paint_poll(bContext *C) @@ -114,7 +145,7 @@ int weight_paint_mode_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totface; + return ob && ob->mode == OB_MODE_WEIGHT_PAINT && ((Mesh *)ob->data)->totpoly; } int weight_paint_poll(bContext *C) @@ -150,7 +181,7 @@ static VPaint *new_vpaint(int wpaint) static int *get_indexarray(Mesh *me) { - return MEM_mallocN(sizeof(int)*(me->totface+1), "vertexpaint"); + return MEM_mallocN(sizeof(int)*(me->totpoly+1), "vertexpaint"); } @@ -188,7 +219,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 */ @@ -254,25 +285,109 @@ static void do_shared_vertexcol(Mesh *me) MEM_freeN(scolmain); } +void do_shared_vertexcol(Mesh *me, int do_tessface) +{ + MLoop *ml = me->mloop; + MLoopCol *lcol = me->mloopcol; + MTexPoly *mtp = me->mtpoly; + MPoly *mp = me->mpoly; + float (*scol)[5]; + int i, has_shared = 0; + + /* 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)) && (me->editflag & ME_EDIT_PAINT_MASK)!=0) + 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; + has_shared = 1; + } + + if (has_shared) { + 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); + + if (has_shared && do_tessface) { + 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->mloopcol) { + 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, TRUE); + } + + if (vertex_paint_use_tessface_check(ob)) { + /* assume if these exist, that they are up to date & valid */ + if (!me->mcol || !me->mface) { + /* should always be true */ + if (me->mcol) { + memset(me->mcol, 255, 4*sizeof(MCol)*me->totface); + } + + /* create tessfaces because they will be used for drawing & fast updates*/ + BKE_mesh_tessface_calc(me); /* does own call to update pointers */ + } + } + else { + if (me->totface) { + /* this wont be used, theres no need to keep it */ + BKE_mesh_tessface_clear(me); + } } //if(shade) // shadeMeshMCol(scene, ob, me); //else - - memset(me->mcol, 255, 4*sizeof(MCol)*me->totface); DAG_id_tag_update(&me->id, 0); @@ -314,7 +429,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) return -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); @@ -322,10 +437,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); } @@ -348,30 +463,34 @@ static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount) void vpaint_fill(Object *ob, unsigned int paintcol) { Mesh *me; - MFace *mf; - unsigned int *mcol; - int i, selected; + MPoly *mp; + MLoopCol *lcol; + int i, j, selected; me= get_mesh(ob); - if(me==NULL || me->totface==0) return; + if(me==NULL || me->totpoly==0) return; - if(!me->mcol) make_vertexcol(ob); - if(!me->mcol) return; /* possible we can't make mcol's */ + if(!me->mloopcol) make_vertexcol(ob); + if(!me->mloopcol) return; /* possible we can't make mcol's */ selected= (me->editflag & ME_EDIT_PAINT_MASK); - mf = me->mface; - mcol = (unsigned int*)me->mcol; - for (i = 0; i < me->totface; i++, mf++, mcol+=4) { - if (!selected || mf->flag & ME_FACE_SEL) { - mcol[0] = paintcol; - mcol[1] = paintcol; - mcol[2] = 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; } } + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + DAG_id_tag_update(&me->id, 0); } @@ -380,7 +499,7 @@ void vpaint_fill(Object *ob, unsigned int paintcol) void wpaint_fill(VPaint *wp, Object *ob, float paintweight) { Mesh *me= ob->data; - MFace *mf; + MPoly *mf; MDeformWeight *dw, *dw_prev; int vgroup_active, vgroup_mirror= -1; unsigned int index; @@ -388,7 +507,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight) /* mutually exclusive, could be made into a */ const short paint_selmode= ME_EDIT_PAINT_SEL_MODE(me); - if(me->totface==0 || me->dvert==NULL || !me->mface) return; + if(me->totpoly==0 || me->dvert==NULL || !me->mpoly) return; vgroup_active = ob->actdef - 1; @@ -399,15 +518,15 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight) copy_wpaint_prev(wp, me->dvert, me->totvert); - for(index=0, mf= me->mface; index < me->totface; index++, mf++) { - unsigned int fidx= mf->v4 ? 3:2; + for(index=0, mf= me->mpoly; index < me->totpoly; index++, mf++) { + unsigned int fidx= mf->totloop - 1; if ((paint_selmode == SCE_SELECT_FACE) && !(mf->flag & ME_FACE_SEL)) { continue; } do { - unsigned int vidx= *(&mf->v1 + fidx); + unsigned int vidx= me->mloop[mf->loopstart + fidx].v; if(!me->dvert[vidx].flag) { if((paint_selmode == SCE_SELECT_VERTEX) && !(me->mvert[vidx].flag & SELECT)) { @@ -455,7 +574,7 @@ void wpaint_fill(VPaint *wp, Object *ob, float paintweight) } /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator - + void vpaint_dogamma(Scene *scene) { VPaint *vp= scene->toolsettings->vpaint; @@ -473,12 +592,12 @@ void vpaint_dogamma(Scene *scene) igam= 1.0/vp->gamma; for(a=0; a<256; a++) { - + fac= ((float)a)/255.0; fac= vp->mul*pow( fac, igam); - + temp= 255.9*fac; - + if(temp<=0) gamtab[a]= 0; else if(temp>=255) gamtab[a]= 255; else gamtab[a]= temp; @@ -487,11 +606,11 @@ void vpaint_dogamma(Scene *scene) a= 4*me->totface; cp= (unsigned char *)me->mcol; while(a--) { - + cp[1]= gamtab[ cp[1] ]; cp[2]= gamtab[ cp[2] ]; cp[3]= gamtab[ cp[3] ]; - + cp+= 4; } } @@ -911,14 +1030,14 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) index= view3d_sample_backbuf(&vc, event->mval[0], event->mval[1]); - if(index && index<=me->totface) { + if(index && index<=me->totpoly) { DerivedMesh *dm= mesh_get_derived_final(vc.scene, vc.obact, CD_MASK_BAREMESH); if(dm->getVertCo==NULL) { BKE_report(op->reports, RPT_WARNING, "The modifier used does not support deformed locations"); } else { - MFace *mf= ((MFace *)me->mface) + index-1; + MPoly *mf= ((MPoly *)me->mpoly) + index-1; const int vgroup_active= vc.obact->actdef - 1; ToolSettings *ts= vc.scene->toolsettings; float mval_f[2]; @@ -929,10 +1048,10 @@ static int weight_sample_invoke(bContext *C, wmOperator *op, wmEvent *event) mval_f[0]= (float)event->mval[0]; mval_f[1]= (float)event->mval[1]; - fidx= mf->v4 ? 3:2; + fidx= mf->totloop - 1; do { float co[3], sco[3], len; - const int v_idx= (*(&mf->v1 + fidx)); + const int v_idx= me->mloop[mf->loopstart + fidx].v; dm->getVertCo(dm, v_idx, co); project_float_noclip(vc.ar, co, sco); len= len_squared_v2v2(mval_f, sco); @@ -995,16 +1114,16 @@ static EnumPropertyItem *weight_paint_sample_enum_itemf(bContext *C, PointerRNA index= view3d_sample_backbuf(&vc, win->eventstate->x - vc.ar->winrct.xmin, win->eventstate->y - vc.ar->winrct.ymin); - if(index && index<=me->totface) { + if(index && index<=me->totpoly) { const int defbase_tot= BLI_countlist(&vc.obact->defbase); if(defbase_tot) { - MFace *mf= ((MFace *)me->mface) + index-1; - unsigned int fidx= mf->v4 ? 3:2; + MPoly *mf= ((MPoly *)me->mpoly) + index-1; + unsigned int fidx= mf->totloop - 1; int *groups= MEM_callocN(defbase_tot*sizeof(int), "groups"); int found= FALSE; do { - MDeformVert *dvert= me->dvert + (*(&mf->v1 + fidx)); + MDeformVert *dvert= me->dvert + me->mloop[mf->loopstart + fidx].v; int i= dvert->totweight; MDeformWeight *dw; for(dw= dvert->dw; i > 0; dw++, i--) { @@ -2031,7 +2150,7 @@ 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; + if(me==NULL || me->totpoly==0) return OPERATOR_PASS_THROUGH; /* if nothing was added yet, we make dverts and a vertex deform group */ if (!me->dvert) { @@ -2194,7 +2313,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P if(wp->flag & VP_AREA) { /* Ugly hack, to avoid drawing vertex index when getting the face index buffer - campbell */ me->editflag &= ~ME_EDIT_VERT_SEL; - totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size_pressure); + totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); me->editflag |= use_vert_sel ? ME_EDIT_VERT_SEL : 0; } else { @@ -2205,22 +2324,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; } } @@ -2236,42 +2355,40 @@ 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); + if(indexar[index] && indexar[index]<=me->totpoly) { + MPoly *mpoly= me->mpoly + (indexar[index]-1); + MLoop *ml = me->mloop + mpoly->loopstart; + int i; if(use_vert_sel) { - me->dvert[mface->v1].flag = (me->mvert[mface->v1].flag & SELECT); - me->dvert[mface->v2].flag = (me->mvert[mface->v2].flag & SELECT); - me->dvert[mface->v3].flag = (me->mvert[mface->v3].flag & SELECT); - if(mface->v4) me->dvert[mface->v4].flag = (me->mvert[mface->v4].flag & SELECT); + for (i=0; i<mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = (me->mvert[ml->v].flag & SELECT); + } } else { - 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; + for (i=0; i<mpoly->totloop; i++, ml++) { + me->dvert[ml->v].flag = 1; + } } if (brush->vertexpaint_tool == PAINT_BLEND_BLUR) { MDeformWeight *dw, *(*dw_func)(MDeformVert *, const int); - unsigned int fidx= mface->v4 ? 3:2; if(wp->flag & VP_ONLYVGROUP) dw_func= (MDeformWeight *(*)(MDeformVert *, const int))defvert_find_index; else dw_func= defvert_verify_index; - - do { - unsigned int vidx= *(&mface->v1 + fidx); + + ml = me->mloop + mpoly->loopstart; + for (i=0; i<mpoly->totloop; i++, ml++) { + unsigned int vidx= ml->v; const float fac = calc_vp_strength_dl(wp, vc, wpd->vertexcosnos+6*vidx, mval, brush_size_pressure); if (fac > 0.0f) { dw = dw_func(&me->dvert[vidx], wpi.vgroup_active); paintweight += dw ? (dw->weight * fac) : 0.0f; totw += fac; } - - } while (fidx--); - + } } } } @@ -2281,14 +2398,16 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } for(index=0; index<totindex; index++) { - - if(indexar[index] && indexar[index]<=me->totface) { - MFace *mf= me->mface + (indexar[index]-1); - unsigned int fidx= mf->v4 ? 3:2; - do { - unsigned int vidx= *(&mf->v1 + fidx); - if(me->dvert[vidx].flag) { + 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++) { + unsigned int vidx= ml->v; + + if (me->dvert[vidx].flag) { alpha= calc_vp_alpha_dl(wp, vc, wpd->wpimat, wpd->vertexcosnos+6*vidx, mval, brush_size_pressure, brush_alpha_pressure); if(alpha) { @@ -2296,7 +2415,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } me->dvert[vidx].flag= 0; } - } while (fidx--); + } } } @@ -2436,7 +2555,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) { @@ -2504,14 +2623,56 @@ 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]; + + /* modify 'me->mcol' directly, since the derived mesh is drawing from this array, + * otherwise we need to refresh the modifier stack */ + int use_fast_update; + + /*mpoly -> mface mapping*/ + MemArena *polyfacemap_arena; + ListBase *polyfacemap; } VPaintData; +static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me) +{ + MFace *mf; + polyfacemap_e *e; + int *origIndex; + int i; + + vd->polyfacemap_arena = BLI_memarena_new(1<<13, "vpaint tmp"); + BLI_memarena_use_calloc(vd->polyfacemap_arena); + + vd->polyfacemap = BLI_memarena_alloc(vd->polyfacemap_arena, sizeof(ListBase)*me->totpoly); + + origIndex = CustomData_get_layer(&me->fdata, CD_POLYINDEX); + 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->polyfacemap_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); @@ -2524,10 +2685,13 @@ static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent /* 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"); @@ -2537,9 +2701,20 @@ 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); - + + + /* are we painting onto a modified mesh?, + * if not we can skip face map trickyness */ + if (vertex_paint_use_fast_update_check(ob)) { + vpaint_build_poly_facemap(vpd, me); + vpd->use_fast_update = TRUE; + } + else { + vpd->use_fast_update = FALSE; + } + /* 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 */ mult_m4_m4m4(mat, vpd->vc.rv3d->viewmat, ob->obmat); @@ -2549,6 +2724,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, const unsigned int index, const float mval[2], const float brush_size_pressure, const float brush_alpha_pressure, @@ -2591,6 +2767,100 @@ static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, } } } +#endif + +/* BMESH version of vpaint_paint_face (commented above) */ + +static void vpaint_paint_poly(VPaint *vp, VPaintData *vpd, Object *ob, + const unsigned int index, const float mval[2], + const float brush_size_pressure, const float brush_alpha_pressure, + int UNUSED(flip) + ) +{ + ViewContext *vc = &vpd->vc; + Brush *brush = paint_brush(&vp->paint); + Mesh *me = get_mesh(ob); + MPoly *mpoly= &me->mpoly[index]; + MFace *mf; + MCol *mc; + MLoop *ml; + MLoopCol *mlc; + polyfacemap_e *e; + unsigned int *lcol = ((unsigned int*)me->mloopcol) + mpoly->loopstart; + unsigned int *lcolorig = ((unsigned int*)vp->vpaint_prev) + mpoly->loopstart; + float alpha; + int i, j; + + int brush_alpha_pressure_i = (int)(brush_alpha_pressure*255.0f); + + if(brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + unsigned int blend[4] = {0}; + unsigned int tcol; + 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 *)&tcol; + 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, + brush_size_pressure, brush_alpha_pressure); + if(alpha > 0.0f) { + const int alpha_i = (int)(alpha*255.0f); + lcol[i] = vpaint_blend(vp, lcol[i], lcolorig[i], vpd->paintcol, alpha_i, brush_alpha_pressure_i); + } + } + + if (vpd->use_fast_update) { + +#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[index].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 + } + +} static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr) { @@ -2613,7 +2883,9 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P RNA_float_get_array(itemptr, "mouse", mval); flip = RNA_boolean_get(itemptr, "pen_flip"); - + + (void)flip; /* BMESH_TODO */ + view3d_operator_needs_opengl(C); /* load projection matrix */ @@ -2625,7 +2897,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_pressure); + totindex= sample_backbuf_area(vc, indexar, me->totpoly, mval[0], mval[1], brush_size_pressure); } else { indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]); @@ -2633,23 +2905,55 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P else totindex= 0; } - 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, brush_size_pressure, brush_alpha_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 == PAINT_BLEND_BLUR) - do_shared_vertexcol(me); + for(index=0; index<totindex; index++) { + + if(indexar[index] && indexar[index]<=me->totpoly) { + vpaint_paint_poly(vp, vpd, ob, indexar[index]-1, mval, brush_size_pressure, brush_alpha_pressure, flip); + } + } + + swap_m4m4(vc->rv3d->persmat, mat); + + /* was disabled because it is slow, but necessary for blur */ + if(brush->vertexpaint_tool == PAINT_BLEND_BLUR) { + int do_tessface = vpd->use_fast_update; + do_shared_vertexcol(me, do_tessface); + } + ED_region_tag_redraw(vc->ar); - - DAG_id_tag_update(ob->data, 0); + + if (vpd->use_fast_update == FALSE) { + /* recalculate modifier stack to get new colors, slow, + * avoid this if we can! */ + DAG_id_tag_update(ob->data, 0); + } } static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) @@ -2663,7 +2967,11 @@ static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke) /* frees prev buffer */ copy_vpaint_prev(ts->vpaint, NULL, 0); - + + if (vpd->polyfacemap_arena) { + BLI_memarena_free(vpd->polyfacemap_arena); + } + MEM_freeN(vpd); } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index d05582512ae..2bff8476ea9 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -107,7 +107,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; } @@ -904,10 +904,11 @@ static void calc_sculpt_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **n polygon.) */ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned vert) { - int i, skip= -1, total=0; - IndexNode *node= ss->fmap[vert].first; - char ncount= BLI_countlist(&ss->fmap[vert]); - MFace *f; + int i, j, ok, total=0; + IndexNode *node= ss->pmap[vert].first; + char ncount= BLI_countlist(&ss->pmap[vert]); + MPoly *f; + MLoop *ml; avg[0] = avg[1] = avg[2] = 0; @@ -920,21 +921,34 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver } while(node){ - f= &ss->mface[node->index]; - - if(f->v4) { - skip= (f->v1==vert?2: - f->v2==vert?3: - f->v3==vert?0: - f->v4==vert?1:-1); - } - - for(i=0; i<(f->v4?4:3); ++i) { - if(i != skip && (ncount!=2 || BLI_countlist(&ss->fmap[(&f->v1)[i]]) <= 2)) { - if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[(&f->v1)[i]]); - else add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co); - ++total; + f= &ss->mpoly[node->index]; + + /* find the loop in the poly whic references this vertex */ + ok = FALSE; + ml = ss->mloop + f->loopstart; + for (j = 0; j < f->totloop; j++, ml++) { + if (ml->v == vert) { + ok = TRUE; + break; + } + } + + if (ok) { + /* vertex was found */ + unsigned int f_adj_v[3] = { + ME_POLY_LOOP_PREV(ss->mloop, f, j)->v, + ml->v, + ME_POLY_LOOP_NEXT(ss->mloop, f, j)->v}; + + + for (i=0; i<3; ++i) { + if (ncount!=2 || BLI_countlist(&ss->pmap[f_adj_v[i]]) <= 2) { + if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[f_adj_v[i]]); + else add_v3_v3(avg, ss->mvert[f_adj_v[i]].co); + ++total; + } } + } node= node->next; @@ -1108,7 +1122,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float if(ss->multires) { do_multires_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last); } - else if(ss->fmap) + else if(ss->pmap) do_mesh_smooth_brush(sd, ss, nodes[n], iteration != count ? 1.0f : last); } @@ -2301,7 +2315,7 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]) for (a= 0; a < me->totvert; a++, mvert++) copy_v3_v3(mvert->co, vertCos[a]); - mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL); + mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } /* apply new coords on active key block */ @@ -2534,7 +2548,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); } else if (ss->kb) sculpt_update_keyblock(ob); } @@ -2678,7 +2692,7 @@ static void sculpt_update_tex(const Scene *scene, Sculpt *sd, SculptSession *ss) } } -void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_fmap) +void sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob, int need_pmap) { DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); SculptSession *ss = ob->sculpt; @@ -2692,23 +2706,28 @@ 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->totpoly = dm->getNumPolys(dm); ss->mvert= NULL; - ss->mface= NULL; + ss->mpoly= NULL; + ss->mloop= NULL; ss->face_normals= NULL; } else { Mesh *me = get_mesh(ob); ss->totvert = me->totvert; - ss->totface = me->totface; + ss->totpoly = me->totpoly; ss->mvert = me->mvert; - ss->mface = me->mface; + ss->mpoly = me->mpoly; + ss->mloop = me->mloop; ss->face_normals = NULL; ss->multires = NULL; } + /* BMESH ONLY --- at some point we should move sculpt code to use polygons only - but for now it needs tessfaces */ + BKE_mesh_tessface_ensure(ob->data); + ss->pbvh = dm->getPBVH(ob, dm); - ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL; + ss->pmap = (need_pmap && dm->getPolyMap)? dm->getPolyMap(ob, dm): NULL; if(ss->modifiers_active) { if(!ss->orig_cos) { @@ -2920,8 +2939,8 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio if(brush->flag & BRUSH_ANCHORED) { if(ss->face_normals) { float *fn = ss->face_normals; - cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totface, "Sculpt face norms"); - for(i = 0; i < ss->totface; ++i, fn += 3) + cache->face_norms= MEM_mallocN(sizeof(float) * 3 * ss->totpoly, "Sculpt face norms"); + for(i = 0; i < ss->totpoly; ++i, fn += 3) copy_v3_v3(cache->face_norms[i], fn); } @@ -3331,7 +3350,7 @@ static void sculpt_restore_mesh(Sculpt *sd, SculptSession *ss) if(ss->face_normals) { float *fn = ss->face_normals; - for(i = 0; i < ss->totface; ++i, fn += 3) + for(i = 0; i < ss->totpoly; ++i, fn += 3) copy_v3_v3(fn, cache->face_norms[i]); } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index a69d5b2ee56..94ec0d17bb9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -62,7 +62,7 @@ struct Brush *sculptmode_brush(void); void sculpt(Sculpt *sd); int sculpt_poll(struct bContext *C); -void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_fmap); +void sculpt_update_mesh_elements(struct Scene *scene, struct Sculpt *sd, struct Object *ob, int need_pmap); /* Deformed mesh sculpt */ void free_sculptsession_deformMats(struct SculptSession *ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 4c54a5891b1..b1f009522fa 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_mapping(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL); free_sculptsession_deformMats(ss); tag_update|= 1; diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index bf8cb58a2f5..ce07beae674 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -50,6 +50,7 @@ #include "BKE_depsgraph.h" #include "BKE_mesh.h" #include "BKE_customdata.h" +#include "BKE_tessmesh.h" #include "ED_screen.h" #include "ED_image.h" @@ -155,7 +156,7 @@ typedef struct Temp_UvData{ -void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){ +void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){ Temp_UVData *tmp_uvdata; float diff[2]; int i; @@ -208,11 +209,15 @@ void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mo sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*(tmp_uvdata[i].p[1] - 0.5f*(tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1]/tmp_uvdata[i].ncounter)); for(element = sculptdata->uv[i].element; element; element = element->next){ - MTFace *mt; + MLoopUV *luv; + BMLoop *l; + if(element->separate && element != sculptdata->uv[i].element) break; - mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE); - copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv); + + l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); } } } @@ -222,7 +227,7 @@ void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mo return; } -static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio) +static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio) { Temp_UVData *tmp_uvdata; float diff[2]; @@ -268,11 +273,15 @@ static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculpt sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*tmp_uvdata[i].p[1]; for(element = sculptdata->uv[i].element; element; element = element->next){ - MTFace *mt; + MLoopUV *luv; + BMLoop *l; + if(element->separate && element != sculptdata->uv[i].element) break; - mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE); - copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv); + + l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); } } } @@ -288,7 +297,7 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, float co[2], radius, radius_root; Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; unsigned int tool; UvSculptData *sculptdata = (UvSculptData *)op->customdata; SpaceImage *sima; @@ -340,11 +349,15 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, sculptdata->uv[i].uv[1] -= strength*diff[1]*0.001; for(element = sculptdata->uv[i].element; element; element = element->next){ - MTFace *mt; + MLoopUV *luv; + BMLoop *l; + if(element->separate && element != sculptdata->uv[i].element) break; - mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE); - copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv); + + l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[i].uv); } } } @@ -378,16 +391,18 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength*diff[1]; for(element = sculptdata->uv[uvindex].element; element; element = element->next){ - MTFace *mt; + MLoopUV *luv; + BMLoop *l; + if(element->separate && element != sculptdata->uv[uvindex].element) break; - mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE); - copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[uvindex].uv); + + l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, sculptdata->uv[uvindex].uv); } } } - - BKE_mesh_end_editmesh(obedit->data, em); } @@ -399,7 +414,7 @@ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op) } if(data->elementMap) { - EM_free_uv_element_map(data->elementMap); + EDBM_free_uv_element_map(data->elementMap); } if(data->uv){ MEM_freeN(data->uv); @@ -418,7 +433,7 @@ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op) op->customdata = NULL; } -static int get_uv_element_offset_from_face(UvElementMap *map, EditFace *efa, int index, int island_index, int doIslands){ +static int get_uv_element_offset_from_face(UvElementMap *map, BMFace *efa, int index, int island_index, int doIslands){ UvElement *element = ED_get_uv_element(map, efa, index); if(!element || (doIslands && element->island != island_index)){ return -1; @@ -451,7 +466,8 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent Object *obedit = CTX_data_edit_object(C); ToolSettings *ts = scene->toolsettings; UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data"); - EditMesh *em = BKE_mesh_get_editmesh(obedit->data); + BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh; + BMesh *bm = em->bm; op->customdata = data; @@ -459,11 +475,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent int counter = 0, i; ARegion *ar= CTX_wm_region(C); float co[2]; - EditFace *efa; + BMFace *efa; + MLoopUV *luv; + BMLoop *l; + BMIter iter, liter; + UvEdge *edges; GHash *edgeHash; GHashIterator* ghi; - MTFace *mt; + int do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS); int island_index = 0; /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/ @@ -476,15 +496,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent if(do_island_optimization){ /* We will need island information */ if(ts->uv_flag & UV_SYNC_SELECTION){ - data->elementMap = EM_make_uv_element_map(em, 0, 1); + data->elementMap = EDBM_make_uv_element_map(em, 0, 1); }else{ - data->elementMap = EM_make_uv_element_map(em, 1, 1); + data->elementMap = EDBM_make_uv_element_map(em, 1, 1); } }else { if(ts->uv_flag & UV_SYNC_SELECTION){ - data->elementMap = EM_make_uv_element_map(em, 0, 0); + data->elementMap = EDBM_make_uv_element_map(em, 0, 0); }else{ - data->elementMap = EM_make_uv_element_map(em, 1, 0); + data->elementMap = EDBM_make_uv_element_map(em, 1, 0); } } @@ -503,7 +523,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent Image *ima= CTX_data_edit_image(C); uv_find_nearest_vert(scene, ima, em, co, NULL, &hit); - element = ED_get_uv_element(data->elementMap, hit.efa, hit.uv); + element = ED_get_uv_element(data->elementMap, hit.efa, hit.lindex); island_index = element->island; } @@ -540,7 +560,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent /* So that we can use this as index for the UvElements */ counter = -1; /* initialize the unique UVs */ - for(i = 0; i < em->totvert; i++){ + for(i = 0; i < bm->totvert; i++){ UvElement *element = data->elementMap->vert[i]; for(; element; element = element->next){ if(element->separate){ @@ -550,23 +570,28 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent ; continue; } + efa = element->face; - mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + l = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); counter++; data->uv[counter].element = element; data->uv[counter].flag = 0; - data->uv[counter].uv = mt->uv[element->tfindex]; + data->uv[counter].uv = luv->uv; } /* pointer arithmetic to the rescue, as always :)*/ uniqueUv[element - data->elementMap->buf] = counter; } } + /* Now, on to generate our uv connectivity data */ - for(efa = em->faces.first, counter = 0; efa; efa = efa->next){ - int nverts = efa->v4 ? 4 : 3; - for(i = 0; i < nverts; i++){ + counter = 0; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int nverts = efa->len; + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { int offset1, itmp1 = get_uv_element_offset_from_face(data->elementMap, efa, i, island_index, do_island_optimization); int offset2, itmp2 = get_uv_element_offset_from_face(data->elementMap, efa, (i+1)%nverts, island_index, do_island_optimization); @@ -598,8 +623,10 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag); } counter++; + i++; } } + MEM_freeN(uniqueUv); /* Allocate connectivity data, we allocate edges once */ @@ -639,7 +666,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent } /* Allocate initial selection for grab tool */ - if(data->tool){ + if(data->tool == UV_SCULPT_TOOL_GRAB){ float radius, radius_root; UvSculptData *sculptdata = (UvSculptData *)op->customdata; SpaceImage *sima; diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index 6f2a0385231..611322fc1ab 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -23,6 +23,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_buttons/SConscript b/source/blender/editors/space_buttons/SConscript index 740353bc1f0..7bc588c627c 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 ../../blenfont ../../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_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 5d0f294b06a..a77e6dccbb8 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -879,6 +879,7 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog IMB_anim_index_rebuild(clip->anim, tc_flag, size_flag, quality, stop, do_update, progress); if(!build_undistort_count) { + BKE_movieclip_reload(clip); return; } else { @@ -905,6 +906,8 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog if(distortion) BKE_tracking_distortion_destroy(distortion); + + BKE_movieclip_reload(clip); } static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt index 15c90fb701e..3975a5f56f3 100644 --- a/source/blender/editors/space_image/CMakeLists.txt +++ b/source/blender/editors/space_image/CMakeLists.txt @@ -25,6 +25,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 8063dc6c902..dd988c94dc9 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -52,6 +52,7 @@ #include "BKE_mesh.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "IMB_imbuf_types.h" @@ -275,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; } @@ -294,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; } @@ -587,12 +586,12 @@ 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); + struct BMEditMesh *em= me->edit_btmesh; int sloppy= 1; /* partially selected face is ok */ if(scene_use_new_shading_nodes(scene)) { /* new shading system, get image from material */ - EditFace *efa= EM_get_actFace(em, sloppy); + BMFace *efa = BM_active_face_get(em->bm, sloppy); if(efa) { Image *node_ima; @@ -604,12 +603,12 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa)) } else { /* old shading system, we set texface */ - MTFace *tf; + MTexPoly *tf; - if(em && EM_texFaceCheck(em)) { + if(em && EDBM_texFaceCheck(em)) { sima->image= NULL; - tf = EM_get_active_mtface(em, NULL, NULL, sloppy); + tf = EDBM_get_active_mtexpoly(em, NULL, TRUE); /* partially selected face is ok */ if(tf) { /* don't need to check for pin here, see above */ @@ -620,8 +619,6 @@ static void image_refresh(const bContext *C, ScrArea *UNUSED(sa)) } } } - - 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 4c1c13c1092..7cf5b1fc3fb 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -25,6 +25,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 52e6a8808ae..38d99c084b3 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" @@ -78,7 +79,7 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats) if(dm) { totvert = dm->getNumVerts(dm); totedge = dm->getNumEdges(dm); - totface = dm->getNumFaces(dm); + totface = dm->getNumPolys(dm); stats->totvert += totvert*totob; stats->totedge += totedge*totob; @@ -139,26 +140,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 6b72fd066e0..ec4ed971a76 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'] == 'linux': 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 f1ef35936fa..e78bad62ba5 100644 --- a/source/blender/editors/space_view3d/CMakeLists.txt +++ b/source/blender/editors/space_view3d/CMakeLists.txt @@ -24,6 +24,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 62c12500aa8..09a4a9eb749 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -32,6 +32,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_utildefines.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_edgehash.h" @@ -46,6 +47,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" +#include "DNA_windowmanager_types.h" #include "BKE_DerivedMesh.h" #include "BKE_effect.h" @@ -53,6 +55,7 @@ #include "BKE_material.h" #include "BKE_paint.h" #include "BKE_property.h" +#include "BKE_tessmesh.h" #include "BKE_scene.h" #include "BIF_gl.h" @@ -77,7 +80,7 @@ typedef struct drawMeshFaceSelect_userData { } drawMeshFaceSelect_userData; typedef struct drawEMTFMapped_userData { - EditMesh *em; + BMEditMesh *em; short has_mcol; short has_mtface; MFace *mf; @@ -112,25 +115,23 @@ static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flag static EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me) { EdgeHash *eh = BLI_edgehash_new(); - MFace *mf; - int i; + MPoly *mp; + MLoop *ml; + MLoop *ml_next; + int i, j; - for(i=0; i<me->totface; i++) { - mf = &me->mface[i]; + for(i=0; i<me->totpoly; i++) { + mp = &me->mpoly[i]; - if(!(mf->flag & ME_HIDE)) { + if (!(mp->flag & ME_HIDE)) { unsigned int flags = eEdge_Visible; - if(mf->flag & ME_FACE_SEL) flags |= eEdge_Select; - - get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags); - get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags); + if (mp->flag & ME_FACE_SEL) flags |= eEdge_Select; - if(mf->v4) { - get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags); - get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags); + ml = me->mloop + mp->loopstart; + for (j=0; j<mp->totloop; j++, ml++) { + ml_next = ME_POLY_LOOP_NEXT(me->mloop, mp, j); + get_marked_edge_info__orFlags(eh, ml->v, ml_next->v, flags); } - else - get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags); } } @@ -169,7 +170,7 @@ static int draw_mesh_face_select__drawFaceOptsInv(void *userData, int index) { Mesh *me = (Mesh*)userData; - MFace *mface = &me->mface[index]; + MPoly *mface = &me->mpoly[index]; if(!(mface->flag&ME_HIDE) && !(mface->flag&ME_FACE_SEL)) return 2; /* Don't set color */ else @@ -443,16 +444,16 @@ static int draw_tface__set_draw(MTFace *tface, int has_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); + MTFace *tface = DM_get_poly_data_layer(dm, CD_MTFACE); + 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++) { Material *ma= give_current_material(Gtexdraw.ob, mface[i].mat_nr+1); if (ma && (ma->game.flag&GEMAT_INVISIBLE)) { @@ -514,42 +515,62 @@ static void add_tface_color_layer(DerivedMesh *dm) } } } - CustomData_add_layer( &dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numFaceData ); + CustomData_add_layer( &dm->faceData, CD_TEXTURE_MCOL, CD_ASSIGN, finalCol, dm->numTessFaceData ); } 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]; - const int matnr = mface->mat_nr; - if (mface->flag & ME_HIDE) return 0; - return draw_tface__set_draw(tface, (me->mcol != NULL), matnr); + Mesh *me = (Mesh *)userData; + + /* array checked for NULL before calling */ + MPoly *mpoly = &me->mpoly[index]; + + BLI_assert(index >= 0 && index < me->totpoly); + + if (mpoly->flag & ME_HIDE) { + return 0; + } + else { + MTexPoly *tpoly = (me->mtpoly) ? &me->mtpoly[index] : NULL; + MTFace mtf= {{{0}}}; + int matnr = mpoly->mat_nr; + + if (tpoly) { + ME_MTEXFACE_CPY(&mtf, tpoly); + } + + return draw_tface__set_draw(&mtf, (me->mloopcol != NULL), matnr); + } } static int draw_em_tf_mapped__set_draw(void *userData, int index) { drawEMTFMapped_userData *data = userData; - EditMesh *em = data->em; - EditFace *efa= EM_get_face_for_index(index); - MTFace *tface; - int matnr; + BMEditMesh *em = data->em; + BMFace *efa= EDBM_get_face_for_index(em, index); - if (efa->h) + if (efa==NULL || BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { return 0; + } + else { + MTFace mtf= {{{0}}}; + int matnr = efa->mat_nr; - tface = data->has_mtface ? CustomData_em_get(&em->fdata, efa->data, CD_MTFACE) : NULL; - matnr = efa->mat_nr; + if (data->has_mtface) { + MTexPoly *tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); + ME_MTEXFACE_CPY(&mtf, tpoly); + } - return draw_tface__set_draw_legacy(tface, data->has_mcol, matnr); + return draw_tface__set_draw_legacy(&mtf, data->has_mcol, matnr); + } } static int wpaint__setSolidDrawOptions_material(void *userData, int index, int *drawSmooth_r) { Mesh *me = (Mesh*)userData; - if (me->mat && me->mface) { - Material *ma= me->mat[me->mface[index].mat_nr]; + if (me->mat && me->mpoly) { + Material *ma= me->mat[me->mpoly[index].mat_nr]; if (ma && (ma->game.flag & GEMAT_INVISIBLE)) { return 0; } @@ -563,8 +584,8 @@ static int wpaint__setSolidDrawOptions_material(void *userData, int index, int * static int wpaint__setSolidDrawOptions_facemask(void *userData, int index, int *drawSmooth_r) { Mesh *me = (Mesh*)userData; - MFace *mface = &me->mface[index]; - if (mface->flag & ME_HIDE) return 0; + MPoly *mp = &me->mpoly[index]; + if (mp->flag & ME_HIDE) return 0; *drawSmooth_r = 1; return 1; } @@ -573,15 +594,24 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) { Mesh *me = ob->data; DerivedMesh *ddm; - MFace *mf, *mface= me->mface; - MTFace *tface= me->mtface; - MCol *mcol= me->mcol; /* why does mcol exist? */ + MPoly *mp, *mface = me->mpoly; + MTexPoly *mtpoly = me->mtpoly; + MLoopUV *mloopuv = me->mloopuv; + MLoopUV *luv; + MLoopCol *mloopcol = me->mloopcol; /* why does mcol exist? */ + MLoopCol *lcol; + bProperty *prop = get_ob_property(ob, "Text"); GPUVertexAttribs gattribs; - int a, totface= me->totface; + int a, totpoly = me->totpoly; + + /* fake values to pass to GPU_render_text() */ + MCol tmp_mcol[4] = {{0}}; + MCol *tmp_mcol_pt = mloopcol ? tmp_mcol : NULL; + MTFace tmp_tf = {{{0}}}; /* don't draw without tfaces */ - if(!tface) + if(!mtpoly || !mloopuv) return; /* don't draw when editing */ @@ -593,17 +623,23 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) ddm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH); - for(a=0, mf=mface; a<totface; a++, tface++, mf++) { - short matnr= mf->mat_nr; - int mf_smooth= mf->flag & ME_SMOOTH; + for(a=0, mp=mface; a<totpoly ; a++, mtpoly++, mp++) { + short matnr= mp->mat_nr; + int mf_smooth= mp->flag & ME_SMOOTH; Material *mat = me->mat[matnr]; int mode= mat->game.flag; - if (!(mode&GEMAT_INVISIBLE) && (mode&GEMAT_TEXT)) { + if (!(mode&GEMAT_INVISIBLE) && (mode&GEMAT_TEXT) && mp->totloop >= 3) { + /* get the polygon as a tri/quad */ + int mp_vi[4]; float v1[3], v2[3], v3[3], v4[3]; char string[MAX_PROPSTRING]; int characters, i, glattrib= -1, badtex= 0; + + /* TEXFACE */ + ME_MTEXFACE_CPY(&tmp_tf, mtpoly); + if(glsl) { GPU_enable_material(matnr+1, &gattribs); @@ -615,17 +651,49 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) } } else { - badtex = set_draw_settings_cached(0, tface, mat, Gtexdraw); + badtex = set_draw_settings_cached(0, &tmp_tf, mat, Gtexdraw); if (badtex) { - if (mcol) mcol+=4; continue; } } - ddm->getVertCo(ddm, mf->v1, v1); - ddm->getVertCo(ddm, mf->v2, v2); - ddm->getVertCo(ddm, mf->v3, v3); - if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4); + mp_vi[0] = me->mloop[mp->loopstart + 0].v; + mp_vi[1] = me->mloop[mp->loopstart + 1].v; + mp_vi[2] = me->mloop[mp->loopstart + 2].v; + mp_vi[3] = (mp->totloop >= 4) ? me->mloop[mp->loopstart + 3].v : 0; + + /* UV */ + luv = &mloopuv[mp->loopstart]; + copy_v2_v2(tmp_tf.uv[0], luv->uv); luv++; + copy_v2_v2(tmp_tf.uv[1], luv->uv); luv++; + copy_v2_v2(tmp_tf.uv[2], luv->uv); luv++; + if (mp->totloop >= 4) { + copy_v2_v2(tmp_tf.uv[3], luv->uv); + } + + /* COLOR */ + if (mloopcol) { + unsigned int totloop_clamp = MIN2(4, mp->totloop); + unsigned int j; + lcol = &mloopcol[mp->loopstart]; + + for (j = 0; j <= totloop_clamp; j++, lcol++) { + tmp_mcol[j].a = lcol->a; + tmp_mcol[j].r = lcol->r; + tmp_mcol[j].g = lcol->g; + tmp_mcol[j].b = lcol->b; + } + } + + /* LOCATION */ + ddm->getVertCo(ddm, mp_vi[0], v1); + ddm->getVertCo(ddm, mp_vi[1], v2); + ddm->getVertCo(ddm, mp_vi[2], v3);; + if (mp->totloop >= 4) { + ddm->getVertCo(ddm, mp_vi[3], v4); + } + + // The BM_FONT handling is in the gpu module, shared with the // game engine, was duplicated previously @@ -633,7 +701,7 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) set_property_valstr(prop, string); characters = strlen(string); - if(!BKE_image_get_ibuf(tface->tpage, NULL)) + if(!BKE_image_get_ibuf(mtpoly->tpage, NULL)) characters = 0; if (!mf_smooth) { @@ -644,11 +712,8 @@ static void draw_mesh_text(Scene *scene, Object *ob, int glsl) glNormal3fv(nor); } - GPU_render_text(tface, mode, string, characters, - (unsigned int*)mcol, v1, v2, v3, (mf->v4? v4: NULL), glattrib); - } - if (mcol) { - mcol+=4; + GPU_render_text(&tmp_tf, mode, string, characters, + (unsigned int*)tmp_mcol_pt, v1, v2, v3, (mp->totloop >= 4 ? v4: NULL), glattrib); } } @@ -697,11 +762,11 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec if(ob->mode & OB_MODE_EDIT) { drawEMTFMapped_userData data; - data.em= me->edit_mesh; - data.has_mcol= CustomData_has_layer(&me->edit_mesh->fdata, CD_MCOL); - data.has_mtface= CustomData_has_layer(&me->edit_mesh->fdata, CD_MTFACE); - data.mf= DM_get_face_data_layer(dm, CD_MFACE); - data.tf= DM_get_face_data_layer(dm, CD_MTFACE); + data.em= me->edit_btmesh; + data.has_mcol= CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL); + data.has_mtface= CustomData_has_layer(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY); + data.mf= DM_get_tessface_data_layer(dm, CD_MFACE); + data.tf= DM_get_tessface_data_layer(dm, CD_MTFACE); dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data); } @@ -709,7 +774,7 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec if(ob->mode & OB_MODE_WEIGHT_PAINT) dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions_facemask, GPU_enable_material, NULL, me, 1); else - dm->drawMappedFacesTex(dm, me->mface ? draw_tface_mapped__set_draw : NULL, NULL, me); + dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, NULL, me); } else { if(GPU_buffer_legacy(dm)) { @@ -724,8 +789,8 @@ void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec if(!CustomData_has_layer(&dm->faceData,CD_TEXTURE_MCOL)) add_tface_color_layer(dm); - userData.mf = DM_get_face_data_layer(dm, CD_MFACE); - userData.tf = DM_get_face_data_layer(dm, CD_MTFACE); + userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE); + userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE); dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData); } @@ -834,17 +899,19 @@ static int tex_mat_set_face_mesh_cb(void *userData, int index) /* faceselect mode face hiding */ TexMatCallback *data= (TexMatCallback*)userData; Mesh *me = (Mesh*)data->me; - MFace *mface = &me->mface[index]; + MPoly *mp = &me->mpoly[index]; - return !(mface->flag & ME_HIDE); + return !(mp->flag & ME_HIDE); } -static int tex_mat_set_face_editmesh_cb(void *UNUSED(userData), int index) +static int tex_mat_set_face_editmesh_cb(void *userData, int index) { /* editmode face hiding */ - EditFace *efa= EM_get_face_for_index(index); + TexMatCallback *data= (TexMatCallback*)userData; + Mesh *me = (Mesh*)data->me; + BMFace *efa= EDBM_get_face_for_index(me->edit_btmesh, index); - return !(efa->h); + return !BM_elem_flag_test(efa, BM_ELEM_HIDDEN); } void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int draw_flags) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 8fc2f17fae4..7ce88ee9b48 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -47,6 +47,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" @@ -79,6 +80,8 @@ #include "BKE_movieclip.h" #include "BKE_tracking.h" +#include "BKE_tessmesh.h" + #include "smoke_API.h" #include "IMB_imbuf.h" @@ -119,42 +122,51 @@ typedef enum eWireDrawMode { /* user data structures for derived mesh callbacks */ typedef struct foreachScreenVert_userData { - void (*func)(void *userData, EditVert *eve, int x, int y, int index); + void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; eV3DClipTest clipVerts; } foreachScreenVert_userData; typedef struct foreachScreenEdge_userData { - void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); + void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; eV3DClipTest clipVerts; } foreachScreenEdge_userData; typedef struct foreachScreenFace_userData { - void (*func)(void *userData, EditFace *efa, int x, int y, int index); + void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; } foreachScreenFace_userData; typedef struct drawDMVerts_userData { + BMEditMesh *em; /* BMESH BRANCH ONLY */ + int sel; - EditVert *eve_act; + BMVert *eve_act; } drawDMVerts_userData; typedef struct drawDMEdgesSel_userData { + BMEditMesh *em; /* BMESH BRANCH ONLY */ + unsigned char *baseCol, *selCol, *actCol; - EditEdge *eed_act; + BMEdge *eed_act; } drawDMEdgesSel_userData; typedef struct drawDMFacesSel_userData { unsigned char *cols[4]; - EditFace *efa_act; + + DerivedMesh *dm; /* BMESH BRANCH ONLY */ + BMEditMesh *em; /* BMESH BRANCH ONLY */ + + BMFace *efa_act; int *orig_index; } drawDMFacesSel_userData; typedef struct drawDMNormal_userData { + BMEditMesh *em; float normalsize; } drawDMNormal_userData; @@ -228,8 +240,10 @@ static void view3d_project_short_clip(ARegion *ar, const float vec[3], short adr } } +/* BMESH NOTE: this function is unused in bmesh only */ + /* only use while object drawing */ -static void view3d_project_short_noclip(ARegion *ar, const float vec[3], short adr[2]) +static void UNUSED_FUNCTION(view3d_project_short_noclip)(ARegion *ar, const float vec[3], short adr[2]) { RegionView3D *rv3d= ar->regiondata; float fx, fy, vec4[4]; @@ -1990,15 +2004,17 @@ static void drawlattice(Scene *scene, View3D *v3d, Object *ob) static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s)) { foreachScreenVert_userData *data = userData; - EditVert *eve = EM_get_vert_for_index(index); + BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index); - if (eve->h==0) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { short s[2]= {IS_CLIPPED, 0}; if (data->clipVerts != V3D_CLIP_TEST_OFF) { view3d_project_short_clip(data->vc.ar, co, s, 1); } else { - view3d_project_short_noclip(data->vc.ar, co, s); + float co2[2]; + mul_v3_m4v3(co2, data->vc.obedit->obmat, co); + project_short_noclip(data->vc.ar, co2, s); } if (s[0]!=IS_CLIPPED) @@ -2008,11 +2024,11 @@ 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 (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, eV3DClipTest clipVerts) { foreachScreenVert_userData data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; @@ -2022,9 +2038,9 @@ void mesh_foreachScreenVert( if(clipVerts != V3D_CLIP_TEST_OFF) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 1, 0, 0); + EDBM_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); } @@ -2066,17 +2082,23 @@ static int is_co_in_region(ARegion *ar, const short co[2]) static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co) { foreachScreenEdge_userData *data = userData; - EditEdge *eed = EM_get_edge_for_index(index); - short s[2][2]; + BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index); + + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + short s[2][2]; - if (eed->h==0) { if (data->clipVerts == V3D_CLIP_TEST_RV3D_CLIPPING) { 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]); + float v1_co[3], v2_co[3]; + + mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co); + mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co); + + project_short_noclip(data->vc.ar, v1_co, s[0]); + project_short_noclip(data->vc.ar, v2_co, s[1]); if (data->clipVerts == V3D_CLIP_TEST_REGION) { if ( !is_co_in_region(data->vc.ar, s[0]) && @@ -2093,11 +2115,11 @@ 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 (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, eV3DClipTest clipVerts) { foreachScreenEdge_userData data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; @@ -2107,9 +2129,9 @@ void mesh_foreachScreenEdge( if(clipVerts != V3D_CLIP_TEST_OFF) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 0, 1, 0); + EDBM_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); } @@ -2117,11 +2139,14 @@ void mesh_foreachScreenEdge( static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no)) { foreachScreenFace_userData *data = userData; - EditFace *efa = EM_get_face_for_index(index); - short s[2]; + BMFace *efa = EDBM_get_face_for_index(data->vc.em, index); + + if (efa && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + float cent2[3]; + short s[2]; - if (efa && efa->h==0 && efa->fgonf!=EM_FGON) { - view3d_project_short_clip(data->vc.ar, cent, s, 1); + mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent); + project_short(data->vc.ar, cent2, s); if (s[0] != IS_CLIPPED) { data->func(data->userData, efa, s[0], s[1], index); @@ -2131,11 +2156,11 @@ static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *ce void mesh_foreachScreenFace( ViewContext *vc, - void (*func)(void *userData, EditFace *efa, int x, int y, int index), + void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData) { foreachScreenFace_userData data; - DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); + DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH); data.vc= *vc; data.func = func; @@ -2144,9 +2169,9 @@ void mesh_foreachScreenFace( //if(clipVerts) ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */ - EM_init_index_arrays(vc->em, 0, 0, 1); + EDBM_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); } @@ -2217,19 +2242,20 @@ void nurbs_foreachScreenVert( static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no) { drawDMNormal_userData *data = userData; - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(data->em, index); - if (efa->h==0 && efa->fgonf!=EM_FGON) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { glVertex3fv(cent); glVertex3f(cent[0] + no[0] * data->normalsize, cent[1] + no[1] * data->normalsize, cent[2] + no[2] * data->normalsize); } } -static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) +static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) { drawDMNormal_userData data; + data.em = em; data.normalsize = scene->toolsettings->normalsize; glBegin(GL_LINES); @@ -2239,26 +2265,28 @@ static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_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) { drawDMNormal_userData *data = userData; - EditVert *eve = EM_get_vert_for_index(index); + BMVert *eve = EDBM_get_vert_for_index(data->em, index); - if (eve->h==0) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { glVertex3fv(co); if (no_f) { @@ -2273,10 +2301,11 @@ 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) { drawDMNormal_userData data; + data.em = em; data.normalsize = scene->toolsettings->normalsize; glBegin(GL_LINES); @@ -2284,13 +2313,13 @@ static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm) 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)) { drawDMVerts_userData * data = userData; - EditVert *eve = EM_get_vert_for_index(index); + BMVert *eve = EDBM_get_vert_for_index(data->em, index); - if (eve->h==0 && (eve->f&SELECT)==data->sel) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_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); @@ -2312,11 +2341,12 @@ 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) { drawDMVerts_userData data; data.sel = sel; data.eve_act = eve_act; + data.em = em; bglBegin(GL_POINTS); dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data); @@ -2326,16 +2356,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; drawDMEdgesSel_userData * data = userData; unsigned char *col; - if (eed->h==0) { + eed = EDBM_get_edge_for_index(data->em, index); + + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { if (eed==data->eed_act) { glColor4ubv(data->actCol); } else { - if (eed->f&SELECT) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { col = data->selCol; } else { col = data->baseCol; @@ -2350,38 +2382,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) { drawDMEdgesSel_userData 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_elem_flag_test(EDBM_get_edge_for_index(userData, index), BM_ELEM_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_elem_flag_test(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_ELEM_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_elem_flag_test(eed->v1, BM_ELEM_SELECT))?2:1]; + unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))?2:1]; glColor4ub( col0[0] + (col1[0]-col0[0])*t, col0[1] + (col1[1]-col0[1])*t, @@ -2389,48 +2423,48 @@ 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_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_HIDDEN) && !BM_elem_flag_test(eed, BM_ELEM_SMOOTH); } -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); } /* Draw only Freestyle feature edges */ -static int draw_dm_edges_freestyle__setDrawOptions(void *UNUSED(userData), int index) +static int draw_dm_edges_freestyle__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->freestyle); + return !BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_FREESTYLE); } -static void draw_dm_edges_freestyle(DerivedMesh *dm) +static void draw_dm_edges_freestyle(BMEditMesh *em, DerivedMesh *dm) { - dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, NULL); + dm->drawMappedEdges(dm, draw_dm_edges_freestyle__setDrawOptions, em); } /* Draw faces with color set based on selection @@ -2438,15 +2472,18 @@ static void draw_dm_edges_freestyle(DerivedMesh *dm) static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r)) { drawDMFacesSel_userData * data = userData; - EditFace *efa = EM_get_face_for_index(index); + BMFace *efa = EDBM_get_face_for_index(data->em, index); unsigned char *col; - if (efa->h==0) { + if (!efa) + return 0; + + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { if (efa == data->efa_act) { glColor4ubv(data->cols[3]); return 2; /* stipple */ } else { - col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0]; + col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)?2:0]; if (col[3]==0) return 0; glColor4ubv(col); return 1; @@ -2457,16 +2494,18 @@ static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNU static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index) { + drawDMFacesSel_userData *data = userData; - EditFace *efa; - EditFace *next_efa; + BMFace *efa; + BMFace *next_efa; + unsigned char *col, *next_col; if(!data->orig_index) return 0; - efa= EM_get_face_for_index(data->orig_index[index]); - next_efa= EM_get_face_for_index(data->orig_index[next_index]); + efa= EDBM_get_face_for_index(data->em, data->orig_index[index]); + next_efa= EDBM_get_face_for_index(data->em, data->orig_index[next_index]); if(efa == next_efa) return 1; @@ -2474,8 +2513,8 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int if(efa == data->efa_act || next_efa == data->efa_act) return 0; - col = data->cols[(efa->f & SELECT) ? 1 : (efa->flag & ME_FREESTYLE_FACE) ? 2 : 0]; - next_col = data->cols[(next_efa->f & SELECT) ? 1 : (next_efa->flag & ME_FREESTYLE_FACE) ? 2 : 0]; + col = data->cols[BM_elem_flag_test(efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(efa, BM_ELEM_FREESTYLE)?2:0]; + next_col = data->cols[BM_elem_flag_test(next_efa, BM_ELEM_SELECT)?1:BM_elem_flag_test(next_efa, BM_ELEM_FREESTYLE)?2:0]; if(col[3]==0 || next_col[3]==0) return 0; @@ -2484,70 +2523,88 @@ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int } /* also draws the active face */ -static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, EditFace *efa_act) +static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, + unsigned char *selCol, unsigned char *markCol, unsigned char *actCol, BMFace *efa_act) { drawDMFacesSel_userData data; + data.dm= dm; data.cols[0] = baseCol; + data.em = em; data.cols[1] = selCol; data.cols[2] = markCol; data.cols[3] = actCol; data.efa_act = efa_act; - data.orig_index = DM_get_face_data_layer(dm, CD_ORIGINDEX); + data.orig_index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX); dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0); } -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 ? (float *)CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE) : NULL; + + if (!crease) + return 0; + + if (!BM_elem_flag_test(eed, BM_ELEM_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 = (float *)CustomData_bmesh_get(&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_elem_flag_test(eed, BM_ELEM_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 = (float *)CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_BWEIGHT); + + if (!bweight) + return; + + if (!BM_elem_flag_test(eve, BM_ELEM_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); } } @@ -2561,8 +2618,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; @@ -2599,13 +2656,13 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, 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) { @@ -2619,9 +2676,9 @@ static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, glPointSize(1.0); } -static void draw_em_fancy_edges(Scene *scene, View3D *v3d, +static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, - EditEdge *eed_act) + BMEdge *eed_act) { ToolSettings *ts= scene->toolsettings; int pass; @@ -2654,21 +2711,21 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, } 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); } } @@ -2679,13 +2736,10 @@ static void draw_em_fancy_edges(Scene *scene, View3D *v3d, } } -static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSettings *unit) +static void draw_em_measure_stats(View3D *v3d, 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 numstr[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 */ @@ -2695,6 +2749,9 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet 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"; @@ -2704,11 +2761,16 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet else conv_float= "%.2g"; 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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for(; eed; eed=BM_iter_step(&iter)) { + /* draw selected edges, or edges next to selected verts while draging */ + if(BM_elem_flag_test(eed, BM_ELEM_SELECT) || + (do_moving && (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || BM_elem_flag_test(eed->v2, BM_ELEM_SELECT) ))) { + copy_v3_v3(v1, eed->v1->co); copy_v3_v3(v2, eed->v2->co); @@ -2733,96 +2795,92 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet } 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_calc, but that is for 2d faces + so instead add up tessalation triangle areas */ + BMFace *f; + int n; + +#define DRAW_EM_MEASURE_STATS_FACEAREA() \ + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { \ + mul_v3_fl(vmid, 1.0/n); \ + if(unit->system) \ + bUnit_AsString(numstr, sizeof(numstr), area*unit->scale_length, \ + 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); \ + else \ + BLI_snprintf(numstr, sizeof(numstr), conv_float, area); \ + view3d_cached_text_draw_add(vmid, numstr, 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) { - // XXX should be B_UNIT_AREA - bUnit_AsString(numstr, sizeof(numstr), area * unit->scale_length, 3, - unit->system, B_UNIT_LENGTH, do_split, FALSE); - } - else { - sprintf(numstr, conv_float, area); - } - - view3d_cached_text_draw_add(efa->cent, numstr, 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; + } + + 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); } + 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) { - EditEdge *e1, *e2, *e3, *e4; + BMFace *efa; + 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); - } - 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(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2))); - interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f); - view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col); - } - if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) { - /* Vec 2 */ - sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3))); - interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f); - view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col); - } - if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) { - /* Vec 3 */ - if(efa->v4) - sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4))); - else - sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1))); - interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f); - view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col); - } - /* Vec 4 */ - if(efa->v4) { - if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) { - sprintf(numstr,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1))); - interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f); + + + for(efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + efa; efa=BM_iter_step(&iter)) { + BMIter liter; + BMLoop *loop; + + BM_face_center_bounds_calc(em->bm, efa, vmid); + + for(loop = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa); + loop; loop = BM_iter_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_elem_flag_test(efa, BM_ELEM_SELECT)) || + (do_moving && BM_elem_flag_test(loop->v, BM_ELEM_SELECT))) + { + BLI_snprintf(numstr, sizeof(numstr), "%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3))); + interp_v3_v3v3(fvec, vmid, v2, 0.8f); view3d_cached_text_draw_add(fvec, numstr, 0, V3D_CACHE_TEXT_ASCII, col); } } @@ -2830,55 +2888,64 @@ static void draw_em_measure_stats(View3D *v3d, Object *ob, EditMesh *em, UnitSet } } -static void draw_em_indices(EditMesh *em) +static void draw_em_indices(BMEditMesh *em) { - EditEdge *e; - EditFace *f; - EditVert *v; + BMEdge *e; + BMFace *f; + BMVert *v; int i; char numstr[32]; float pos[3]; unsigned char col[4]; - /* For now, reuse appropriate theme colors from stats text colors */ + BMIter iter; + BMesh *bm= em->bm; + /* For now, reuse appropriate theme colors from stats text colors */ + i= 0; if (em->selectmode & SCE_SELECT_VERTEX) { UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col); - for (v = em->verts.first, i = 0; v; v = v->next, i++) { - if (v->f & SELECT) { + BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { sprintf(numstr, "%d", i); view3d_cached_text_draw_add(v->co, numstr, 0, V3D_CACHE_TEXT_ASCII, col); } + i++; } } if (em->selectmode & SCE_SELECT_EDGE) { + i= 0; UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col); - for (e = em->edges.first, i = 0; e; e = e->next, i++) { - if (e->f & SELECT) { + BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { sprintf(numstr, "%d", i); mid_v3_v3v3(pos, e->v1->co, e->v2->co); view3d_cached_text_draw_add(pos, numstr, 0, V3D_CACHE_TEXT_ASCII, col); } + i++; } } if (em->selectmode & SCE_SELECT_FACE) { + i= 0; UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col); - for (f = em->faces.first, i = 0; f; f = f->next, i++) { - if (f->f & SELECT) { + BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) { + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + BM_face_center_mean_calc(bm, f, pos); sprintf(numstr, "%d", i); - view3d_cached_text_draw_add(f->cent, numstr, 0, V3D_CACHE_TEXT_ASCII, col); + view3d_cached_text_draw_add(pos, numstr, 0, V3D_CACHE_TEXT_ASCII, col); } + i++; } } } -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_elem_flag_test(efa, BM_ELEM_HIDDEN)) { GPU_enable_material(efa->mat_nr+1, NULL); return 1; } @@ -2886,34 +2953,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_elem_flag_test(efa, BM_ELEM_HIDDEN); } static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, - Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt) + 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 = BM_active_face_get(em->bm, FALSE); /* 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; - } else if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + /*if (ese->type == BM_FACE ) { + efa_act = (BMFace *)ese->data; + } else */ if ( ese->htype == BM_EDGE ) { + eed_act = (BMEdge *)ese->data; + } else if ( ese->htype == BM_VERT ) { + 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)) { @@ -2937,7 +3005,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, glEnable(GL_LIGHTING); glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); - finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, NULL, 0); + finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0); glFrontFace(GL_CCW); glDisable(GL_LIGHTING); @@ -2975,7 +3043,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, if (!(me->drawflag & ME_DRAW_FREESTYLE_FACE)) col3[3] = 0; - draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -2990,7 +3058,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, glEnable(GL_BLEND); glDepthMask(0); // disable write in zbuffer, needed for nice transp - draw_dm_faces_sel(cageDM, col1, col2, col3, col4, efa_act); + draw_dm_faces_sel(em, cageDM, col1, col2, col3, col4, efa_act); glDisable(GL_BLEND); glDepthMask(1); // restore write in zbuffer @@ -3002,14 +3070,14 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, /* 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); @@ -3019,7 +3087,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, UI_ThemeColor(TH_EDGE_SHARP); glLineWidth(2); - draw_dm_edges_sharp(cageDM); + draw_dm_edges_sharp(em, cageDM); glColor3ub(0,0,0); glLineWidth(1); @@ -3029,31 +3097,31 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, UI_ThemeColor(TH_FREESTYLE_EDGE_MARK); glLineWidth(2); - draw_dm_edges_freestyle(cageDM); + draw_dm_edges_freestyle(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) { - 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)) && @@ -3074,7 +3142,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, GPU_disable_material(); } - EM_free_index_arrays(); + EDBM_free_index_arrays(em); } /* Mesh drawing routines */ @@ -3126,7 +3194,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* Check to draw dynamic paint colors (or weights from WeightVG modifiers). * Note: Last "preview-active" modifier in stack will win! */ - if(DM_get_face_data_layer(dm, CD_WEIGHT_MCOL) && modifiers_isPreview(ob)) + if(DM_get_tessface_data_layer(dm, CD_WEIGHT_MCOL) && modifiers_isPreview(ob)) draw_flags |= DRAW_MODIFIERS_PREVIEW; /* Unwanted combination */ @@ -3139,7 +3207,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? */ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); @@ -3197,7 +3265,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D /* weight paint in solid mode, special case. focus on making the weights clear * rather than the shading, this is also forced in wire view */ GPU_enable_material(0, NULL); - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mface, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mpoly, 1); bglPolygonOffset(rv3d->dist, 1.0); glDepthMask(0); // disable write in zbuffer, selected edge wires show better @@ -3322,14 +3390,14 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); - dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mface, 1); + dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me->mpoly, 1); glDisable(GL_COLOR_MATERIAL); glDisable(GL_LIGHTING); GPU_disable_material(); } else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) { - if(me->mcol) + if(me->mloopcol) dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, NULL, 1); else { glColor3f(1.0f, 1.0f, 1.0f); @@ -3416,7 +3484,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_after= 0, drawlinked= 0, retval= 0, glsl, check_alpha, i; /* If we are drawing shadows and any of the materials don't cast a shadow, @@ -3440,9 +3508,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) { @@ -3460,7 +3528,7 @@ static int draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D } else { /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */ - if(me->totface<=4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) { + if(me->totpoly <= 4 || ED_view3d_boundbox_clip(rv3d, ob->obmat, (ob->bb)? ob->bb: me->bb)) { glsl = draw_glsl_material(scene, ob, v3d, dt); check_alpha = check_alpha_pass(base); @@ -3729,7 +3797,7 @@ static int drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, B return 1; } - if(dt>OB_WIRE && dm->getNumFaces(dm)) { + if(dt>OB_WIRE && dm->getNumTessFaces(dm)) { int glsl = draw_glsl_material(scene, ob, v3d, dt); GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl, NULL); @@ -6073,7 +6141,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base) int hasfaces= 0; if (dm) { - hasfaces= dm->getNumFaces(dm); + hasfaces= dm->getNumTessFaces(dm); } else { hasfaces= displist_has_faces(&ob->disp); } @@ -7004,44 +7072,51 @@ static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset) 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_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_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_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + if (((void**)userData)[1]) { WM_set_framebuffer_index_color(index+1); } return 1; @@ -7050,11 +7125,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_elem_flag_test(efa, BM_ELEM_HIDDEN)) { WM_set_framebuffer_index_color(index+1); bglVertex3fv(cent); @@ -7062,24 +7137,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, +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, GPU_enable_material, NULL, (void*)(intptr_t) 1, 0); + ptrs[1] = (void*)(intptr_t) 1; + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0); 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, GPU_enable_material, NULL, (void*) 0, 0); + dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0); } } @@ -7093,7 +7170,7 @@ static int bbs_mesh_solid_hide__setDrawOpts(void *userData, int index, int *UNUS { Mesh *me = userData; - if (!(me->mface[index].flag&ME_HIDE)) { + if (!(me->mpoly[index].flag&ME_HIDE)) { WM_set_framebuffer_index_color(index+1); return 1; } else { @@ -7106,7 +7183,7 @@ static int bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index, int *UNU { Mesh *me = userData; - if (!(me->mface[index].flag & ME_HIDE)) { + if (!(me->mpoly[index].flag & ME_HIDE)) { return 1; } else { return 0; @@ -7140,36 +7217,36 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec case OB_MESH: 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 { Mesh *me= ob->data; @@ -7184,7 +7261,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec bbs_obmode_mesh_verts(ob, dm, 1); - em_vertoffs = me->totvert+1; + bm_vertoffs = me->totvert+1; dm->release(dm); } else { @@ -7213,7 +7290,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 1ed8e44a26b..61b4260450b 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -38,12 +38,12 @@ #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" #include "BLI_edgehash.h" #include "BLI_rand.h" -#include "BLI_utildefines.h" #include "BKE_curve.h" #include "BKE_constraint.h" // for the get_constraint_target function diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 5238fd30ae6..98301e63705 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -58,6 +58,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" #include "BKE_deform.h" #include "BKE_object.h" @@ -153,32 +154,36 @@ 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_elem_flag_test(eve, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT)) { + float *f; + totedge++; - median[3]+= eed->crease; - median[6]+= eed->bweight; + f = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE); + median[3]+= f ? *f : 0.0f; + + f = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT); + median[6]+= 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(&bm->vdata, evedef->head.data, CD_MDEFORMVERT); if(tot==1 && dvert && dvert->totweight) { bDeformGroup *dg; int i, max=1, init=1; @@ -202,8 +207,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; @@ -409,31 +412,35 @@ 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; + BMesh *bm = em->bm; + 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, bm, BM_VERTS_OF_MESH, NULL) { + if(BM_elem_flag_test(eve, BM_ELEM_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, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE); + if (!crease) break; + + *crease= fixed_crease; } } } @@ -450,10 +457,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, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE); + + if (!crease) break; + + *crease *= sca; + CLAMP(*crease, 0.0f, 1.0f); } } } @@ -461,33 +472,39 @@ 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, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + float *crease = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_CREASE); + if (!crease) break; + + *crease = 1.0f - ((1.0f - *crease) * sca); + CLAMP(*crease, 0.0f, 1.0f); } } } } } - if (median[6] != 0.0f) { - EditEdge *eed; - const float fixed_bweight= (ve_median[6] <= 0.0f ? 0.0f : (ve_median[6] >= 1.0f ? 1.0f : FLT_MAX)); + if(median[6] != 0.0f) { + BMEdge *eed; + const float fixed_bweight = (ve_median[6] <= 0.0f ? 0.0f : (ve_median[6] >= 1.0f ? 1.0f : FLT_MAX)); if(fixed_bweight != FLT_MAX) { /* simple case */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->bweight= fixed_bweight; + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT); + if(!bweight) break; + + *bweight = fixed_bweight; } } } else { /* scale crease to target median */ - float median_new= ve_median[6]; - float median_orig= ve_median[6] - median[6]; /* previous median value */ + float median_new = ve_median[6]; + float median_orig = ve_median[6] - median[6]; /* previous median value */ /* incase of floating point error */ CLAMP(median_orig, 0.0f, 1.0f); @@ -495,29 +512,35 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float if(median_new < median_orig) { /* scale down */ - const float sca= median_new / median_orig; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f & SELECT) { - eed->bweight *= sca; - CLAMP(eed->bweight, 0.0f, 1.0f); + const float sca = median_new / median_orig; + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT); + if(!bweight) break; + + *bweight *= sca; + CLAMP(*bweight, 0.0f, 1.0f); } } } else { /* scale up */ - const float sca= (1.0f - median_new) / (1.0f - median_orig); + 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->bweight = 1.0f - ((1.0f - eed->bweight) * sca); - CLAMP(eed->bweight, 0.0f, 1.0f); + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + float *bweight = (float *)CustomData_bmesh_get(&bm->edata, eed->head.data, CD_BWEIGHT); + if(!bweight) break; + + *bweight = 1.0f - ((1.0f - *bweight) * sca); + CLAMP(*bweight, 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; @@ -594,37 +617,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->htype == 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 */ @@ -646,7 +667,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); @@ -659,7 +680,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); @@ -669,14 +690,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_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) { + dvert= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); if(dvert) { defvert_copy(dvert, dvert_act); @@ -685,13 +707,15 @@ static void vgroup_copy_active_to_sel(Object *ob) } } + + index++; } } } static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) { - EditVert *eve_act; + BMVert *eve_act; MDeformVert *dv_act; act_vert_def(ob, &eve_act, &dv_act); @@ -701,8 +725,9 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const 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 *dv; MDeformWeight *dw; float weight_act; @@ -712,26 +737,25 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const int def_nr) if(dw == NULL) return; - + weight_act= dw->weight; - for (eve= em->verts.first; eve; eve= eve->next, index++) { - if (eve->f & SELECT && eve != eve_act) { - dv= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT); - if(dv) { - dw= defvert_find_index(dv, def_nr); - if (dw) { - dw->weight= weight_act; + eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for (index=0; eve; eve=BM_iter_step(&iter), index++) { + if(BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve != eve_act) { + dv= CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MDEFORMVERT); + dw= defvert_find_index(dv, def_nr); + if (dw) { + dw->weight= weight_act; - if (me->editflag & ME_EDIT_MIRROR_X) { - editvert_mirror_update(ob, eve, -1, index); - } + if (me->editflag & ME_EDIT_MIRROR_X) { + editvert_mirror_update(ob, eve, -1, index); } } } } - if (me->editflag & ME_EDIT_MIRROR_X) { + if(me->editflag & ME_EDIT_MIRROR_X) { editvert_mirror_update(ob, eve_act, -1, -1); } } @@ -739,7 +763,7 @@ static void vgroup_copy_active_to_sel_single(Object *ob, const 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); @@ -787,7 +811,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); @@ -802,7 +826,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 *dv; act_vert_def(ob, &eve, &dv); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 4f46a746b9e..c73d8e14f05 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1584,7 +1584,7 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) /* calc window coord */ initgrabz(rv3d, 0.0, 0.0, 0.0); ED_view3d_win_to_delta(ar, mval_f, vec); - fac= MAX3( fabs(vec[0]), fabs(vec[1]), fabs(vec[1]) ); + fac= maxf(fabsf(vec[0]), maxf(fabsf(vec[1]), fabsf(vec[2]))); /* largest abs axis */ fac= 1.0f/fac; asp= ( (float)ibuf->y)/(float)ibuf->x; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 1df0b3a8a4e..0a942a42540 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" @@ -336,12 +337,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 */ @@ -362,7 +363,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"); } @@ -371,12 +372,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"); } @@ -384,14 +385,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"); } @@ -424,9 +424,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 */ @@ -451,7 +448,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); @@ -459,8 +456,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); } } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index f98149d2485..ec6d1bdbe87 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -61,6 +61,7 @@ #include "BKE_context.h" #include "BKE_paint.h" #include "BKE_armature.h" +#include "BKE_tessmesh.h" #include "BKE_movieclip.h" #include "BKE_object.h" #include "BKE_tracking.h" @@ -164,43 +165,49 @@ void view3d_get_transformation(const ARegion *ar, RegionView3D *rv3d, Object *ob /* 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 = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL); + for ( ; eve; eve=BM_iter_step(&iter), index++) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_vert_select_set(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 = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL); + for ( ; eed; eed=BM_iter_step(&iter), index++) { + if(!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_edge_select_set(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 = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for ( ; efa; efa=BM_iter_step(&iter), index++) { + if(!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + if(EDBM_check_backbuf(index)) { + BM_face_select_set(em->bm, efa, select); } } } @@ -208,14 +215,14 @@ static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select) /* object mode, EM_ prefix is confusing here, rename? */ -static void EM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select) +static void EDBM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select) { MVert *mv = me->mvert; int a; if (mv) { for(a=1; a<=me->totvert; a++, mv++) { - if(EM_check_backbuf(a)) { + if(EDBM_check_backbuf(a)) { if(!(mv->flag & ME_HIDE)) { mv->flag = select?(mv->flag|SELECT):(mv->flag&~SELECT); } @@ -224,15 +231,16 @@ static void EM_backbuf_checkAndSelectVerts_obmode(Mesh *me, int select) } } /* object mode, EM_ prefix is confusing here, rename? */ -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); } } } @@ -460,39 +468,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)) { LassoSelectUserData *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_elem_select_set(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) { LassoSelectUserData *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_elem_select_set(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_elem_select_set(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)) { LassoSelectUserData *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_elem_select_set(data->vc->em->bm, efa, data->select); } } @@ -506,7 +514,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 = ▭ @@ -517,17 +525,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_flag_disable_all(vc->em, BM_ELEM_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, V3D_CLIP_TEST_RV3D_CLIPPING); @@ -546,15 +554,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 @@ -832,14 +840,14 @@ static void do_lasso_select_paintvert(ViewContext *vc, int mcords[][2], short mo if(extend==0 && select) paintvert_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */ - em_vertoffs= me->totvert+1; /* max index array */ + bm_vertoffs= me->totvert+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_checkAndSelectVerts_obmode(me, select); + EDBM_backbuf_checkAndSelectVerts_obmode(me, select); - EM_free_backbuf(); + EDBM_free_backbuf(); paintvert_flush_flags(ob); } @@ -849,20 +857,20 @@ static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short mo Mesh *me= ob?ob->data:NULL; rcti rect; - if(me==NULL || me->totface==0) + if(me==NULL || me->totpoly==0) return; 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); } @@ -1728,37 +1736,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)) { BoxSelectUserData *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - eve->f = data->select?(eve->f|1):(eve->f&~1); + BM_elem_select_set(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) { BoxSelectUserData *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_elem_select_set(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_elem_select_set(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)) { BoxSelectUserData *data = userData; if (BLI_in_rcti(data->rect, x, y)) { - EM_select_face_fgon(data->vc->em, efa, data->select); + BM_elem_select_set(data->vc->em->bm, efa, data->select); } } static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend) @@ -1774,17 +1782,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_flag_disable_all(vc->em, BM_ELEM_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, V3D_CLIP_TEST_RV3D_CLIPPING); } @@ -1803,15 +1811,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; } @@ -2045,7 +2053,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) { @@ -2269,32 +2277,32 @@ typedef struct CircleSelectUserData { float radius; } CircleSelectUserData; -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)) { CircleSelectUserData *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_elem_select_set(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)) { CircleSelectUserData *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_elem_select_set(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)) { CircleSelectUserData *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_elem_select_set(data->vc->em->bm, efa, data->select); } } @@ -2304,10 +2312,10 @@ static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], f int bbsel; CircleSelectUserData 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; @@ -2317,7 +2325,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, V3D_CLIP_TEST_RV3D_CLIPPING); } @@ -2325,7 +2333,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, V3D_CLIP_TEST_OFF); } @@ -2333,14 +2341,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) @@ -2350,11 +2358,11 @@ static void paint_facesel_circle_select(ViewContext *vc, int select, const int m /* int bbsel; */ /* UNUSED */ if (me) { - em_vertoffs= me->totface+1; /* max index array */ + bm_vertoffs= me->totpoly+1; /* max index array */ - /* bbsel= */ /* UNUSED */ EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); - EM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE); - EM_free_backbuf(); + /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0)); + EDBM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE); + EDBM_free_backbuf(); } } @@ -2366,11 +2374,11 @@ static void paint_vertsel_circle_select(ViewContext *vc, int select, const int m /* int bbsel; */ /* UNUSED */ /* CircleSelectUserData data = {NULL}; */ /* UNUSED */ if (me) { - em_vertoffs= me->totvert+1; /* max index array */ + bm_vertoffs= me->totvert+1; /* max index array */ - /* bbsel= */ /* UNUSED */ EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); - EM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE); - EM_free_backbuf(); + /* bbsel= */ /* UNUSED */ EDBM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); + EDBM_backbuf_checkAndSelectVerts_obmode(me, select==LEFTMOUSE); + EDBM_free_backbuf(); paintvert_flush_flags(ob); } diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index 3665b0b13c3..087ed8380d6 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -55,6 +55,8 @@ #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_tessmesh.h" +#include "BKE_DerivedMesh.h" #include "BKE_scene.h" #include "BKE_tracking.h" @@ -80,12 +82,15 @@ 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; } TransVert; + /* SELECT == (1 << 0) */ +#define TX_VERT_USE_MAPLOC (1 << 1) + static TransVert *transvmain=NULL; static int tottrans= 0; @@ -97,7 +102,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_mesh_normals_update(me->edit_btmesh->bm); // does face centers too } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { Curve *cu= obedit->data; @@ -188,6 +193,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_elem_index_get(eve) != -1 && !(tv[BM_elem_index_get(eve)].flag & TX_VERT_USE_MAPLOC)) { + copy_v3_v3(tv[BM_elem_index_get(eve)].maploc, co); + tv[BM_elem_index_get(eve)].flag |= TX_VERT_USE_MAPLOC; + } +} + /* 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) */ @@ -199,7 +217,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; @@ -211,53 +229,91 @@ 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*/ + /* abuses vertex index all over, set, just set dirty here, + * perhaps this could use its own array instead? - campbell */ + // 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; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_elem_index_set(eve, 1); /* set_dirty! */ tottrans++; } - else eve->f1= 0; + else BM_elem_index_set(eve, 0); /* set_dirty! */ } } 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; + BMEdge *eed; + + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) + BM_elem_index_set(eve, 0); /* set_dirty! */ + + BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { + if(!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_elem_index_set(eed->v1, 1); /* set_dirty! */ + BM_elem_index_set(eed->v2, 1); /* set_dirty! */ + } } - 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_elem_index_get(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_elem_index_set(eve, 0); /* set_dirty! */ + + BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL) { + if(!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BMIter liter; + BMLoop *l; + + BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) { + BM_elem_index_set(l->v, 1); /* set_dirty! */ + } } } - 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_elem_index_get(eve)) tottrans++; } + /* for any of the 3 loops above which all dirty the indicies */ + bm->elem_index_dirty |= BM_VERT; /* 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_elem_index_get(eve)) { + BM_elem_index_set(eve, a); /* set_dirty! */ copy_v3_v3(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_elem_index_get(eve) & SELECT; tv++; - } + a++; + } else BM_elem_index_set(eve, -1); /* set_dirty! */ } + /* set dirty already, above */ + + 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 (obedit->type==OB_ARMATURE){ @@ -927,10 +983,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); @@ -1013,7 +1069,7 @@ int minmax_verts(Object *obedit, float *min, float *max) tv= transvmain; for(a=0; a<tottrans; a++, tv++) { - copy_v3_v3(vec, tv->loc); + copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc); mul_m3_v3(bmat, vec); add_v3_v3(vec, obedit->obmat[3]); add_v3_v3(centroid, vec); @@ -1025,4 +1081,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 0705d066f26..86a2abe7a74 100644 --- a/source/blender/editors/space_view3d/view3d_toolbar.c +++ b/source/blender/editors/space_view3d/view3d_toolbar.c @@ -268,3 +268,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 1a2e8932411..c05f9de691b 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -756,7 +756,6 @@ void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][ mult_m4_m4m4(pmat, rv3d->winmat, vmat); } -#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) @@ -769,7 +768,6 @@ void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, out[1] = uy; out[2] = uz; } -#endif /* use view3d_get_object_project_mat to get projecting mat */ void ED_view3d_project_float(const ARegion *ar, const float vec[3], float adr[2], float mat[4][4]) diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt index a659afbbada..98461918151 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 f2d5baecfb3..0cf3875aa2e 100644 --- a/source/blender/editors/transform/SConscript +++ b/source/blender/editors/transform/SConscript @@ -6,6 +6,6 @@ sources = env.Glob('*.c') incs = '../include ../../blenfont ../../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 15bd14ce94c..862b68ea7e1 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> + static void drawTransformApply(const struct bContext *C, struct ARegion *ar, void *arg); static int doEdgeSlide(TransInfo *t, float perc); @@ -3489,7 +3493,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); } @@ -4283,506 +4288,467 @@ 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_elem_flag_test(e2, BM_ELEM_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_face_other_loop(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_edge_other_vert(olde, v)->co, v->co); + sub_v3_v3v3(f2, BM_edge_other_vert(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); + } + + copy_v3_v3(vec, a); + return l; + } else { + sub_v3_v3v3(n, BM_edge_other_vert(l->e, v)->co, v->co); + add_v3_v3v3(a, a, n); + i += 1; + } + + if (BM_face_other_loop(l->e, l->f, v)->e == nexte) { + if (i) + mul_v3_fl(a, 1.0f / (float)i); + + copy_v3_v3(vec, a); + return BM_face_other_loop(l->e, l->f, v); + } + + l = l->radial_next; + } while (l != firstl); + + if (i) + mul_v3_fl(a, 1.0f / (float)i); + + copy_v3_v3(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; - int i, j, numsel, numadded=0, timesthrough = 0, vertsel=0; - /* UV correction vars */ - GHash **uvarray= NULL; + BMBVHTree *btree = BMBVH_NewBVH(em, 0, NULL, NULL); + SmallHash table; SlideData *sld = MEM_callocN(sizeof(*sld), "sld"); - const int uvlay_tot= (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) ? CustomData_number_of_layers(&em->fdata, CD_MTFACE) : 0; - 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_elem_flag_test(v, BM_ELEM_SELECT)) { + numsel = 0; + BM_ITER(e, &iter2, em->bm, BM_EDGES_OF_VERT, v) { + if (BM_elem_flag_test(e, BM_ELEM_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 == 0 || 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_elem_flag_test(e, BM_ELEM_SELECT)) { + if (BM_edge_face_count(e) != 2) + return 0; //can only handle exactly 2 faces around each 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_elem_flag_test(v, BM_ELEM_SELECT)) { + BM_elem_flag_enable(v, BM_ELEM_TAG); + BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j)); + j += 1; + } + else { + BM_elem_flag_disable(v, BM_ELEM_TAG); + } } - // 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_elem_flag_test(v, BM_ELEM_TAG)) + 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; + + if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) + break; - // make sure the UPs and DOWNs are 'faceloops' - // Also find the nearest slidevert to the cursor + v = BM_edge_other_vert(e, v); + } while (e != first->e); - look = vertlist; - nearest = NULL; - while(look) { - tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link); + BM_elem_flag_disable(v, BM_ELEM_TAG); - 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; - } + l1 = l2 = l = NULL; + l1 = e->l; + l2 = e->l->radial_next; - 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; - } - } + l = BM_face_other_loop(l1->e, l1->f, v); + sub_v3_v3v3(vec, BM_edge_other_vert(l->e, v)->co, v->co); - if(look->next != NULL) { - TransDataSlideVert *sv; - - ev = (EditVert*)look->next->link; - sv = BLI_ghash_lookup(vertgh, ev); + if (l2 != l1) { + l = BM_face_other_loop(l2->e, l2->f, v); + sub_v3_v3v3(vec2, BM_edge_other_vert(l->e, v)->co, v->co); + } else { + l2 = NULL; + } - if(sv) { - float co[3], co2[3], tvec[3]; + /*iterate over the loop*/ + first = v; + do { + TransDataSlideVert *sv = tempsv + j; - ev = (EditVert*)look->link; + sv->v = v; + sv->origvert = *v; + copy_v3_v3(sv->upvec, vec); + if (l2) + copy_v3_v3(sv->downvec, vec2); - 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); - } + l = BM_face_other_loop(l1->e, l1->f, v); + sv->up = BM_edge_other_vert(l->e, v); - if (ev == tempsv->up->v1) { - sub_v3_v3v3(tvec, co, co2); - } else { - sub_v3_v3v3(tvec, co2, co); - } + if (l2) { + l = BM_face_other_loop(l2->e, l2->f, v); + sv->down = BM_edge_other_vert(l->e, v); + } - add_v3_v3(start, tvec); + v2=v, v = BM_edge_other_vert(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); - } + e1 = e; + e = get_other_edge(bm, v, e); + if (!e) { + //v2=v, v = BM_edge_other_vert(l1->e, v); - if (ev == tempsv->down->v1) { - sub_v3_v3v3(tvec, co2, co); - } else { - sub_v3_v3v3(tvec, co, co2); + sv = tempsv + j + 1; + sv->v = v; + sv->origvert = *v; + + l = BM_face_other_loop(l1->e, l1->f, v); + sv->up = BM_edge_other_vert(l->e, v); + sub_v3_v3v3(sv->upvec, BM_edge_other_vert(l->e, v)->co, v->co); + + if (l2) { + l = BM_face_other_loop(l2->e, l2->f, v); + sv->down = BM_edge_other_vert(l->e, v); + sub_v3_v3v3(sv->downvec, BM_edge_other_vert(l->e, v)->co, v->co); } - add_v3_v3(end, tvec); - - totvec += 1.0f; - nearest = (EditVert*)look->link; + BM_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_flag_disable(v2, BM_ELEM_TAG); + + 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_elem_flag_disable(v, BM_ELEM_TAG); + BM_elem_flag_disable(v2, BM_ELEM_TAG); + } while (e != first->e && l1); } - add_v3_v3(start, end); - mul_v3_fl(start, 0.5f*(1.0f/totvec)); - copy_v3_v3(vec, start); - start[0] = t->mval[0]; - start[1] = t->mval[1]; - add_v3_v3v3(end, start, vec); + //EDBM_flag_disable_all(em, BM_ELEM_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_elem_flag_test(e, BM_ELEM_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_elem_flag_test(e2, BM_ELEM_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 each other */ - 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, BMO_OP_FLAG_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_face_copy(em->bm, f, 1, 1); + + BM_elem_select_set(em->bm, copyf, FALSE); + BM_elem_flag_enable(copyf, BM_ELEM_HIDDEN); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, copyf) { + BM_elem_select_set(em->bm, l->v, FALSE); + BM_elem_flag_enable(l->v, BM_ELEM_HIDDEN); + BM_elem_select_set(em->bm, l->e, FALSE); + BM_elem_flag_enable(l->e, BM_ELEM_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]; + BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf); + } + } + + BLI_smallhash_insert(&sld->vhash, (uintptr_t)tempsv->v, tempsv); + } + + sld->em = em; - if (uvlay_tot) { - int maxnum = 0; + /*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]; - 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; + 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; +} - for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) { +void projectSVData(TransInfo *t, int final) +{ + SlideData *sld = t->customData; + TransDataSlideVert *tempsv; + BMEditMesh *em = sld->em; + SmallHash visit; + int i; + + if (!em) + return; + + /* BMESH_TODO, (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) + * currently all vertex data is interpolated which is nice mostly + * except for shape keys where you dont want to modify UVs for eg. + * current BMesh code doesnt make it easy to pick which data we interpolate + * - campbell */ - uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "createSlideVerts2 gh"); + 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, hide, 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 + and hidden state*/ + sel = BM_elem_flag_test(f, BM_ELEM_SELECT); + hide = BM_elem_flag_test(f, BM_ELEM_HIDDEN); + + 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_elem_flag_test(l2->e, BM_ELEM_SELECT) || BM_elem_flag_test(l2->prev->e, BM_ELEM_SELECT)) { + BMLoop *l3 = l2; + + do_vdata = 1; + + if (!BM_elem_flag_test(l2->e, BM_ELEM_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); + } + if (!copyf) + continue; /* shouldn't happen, but protection */ + } + + BM_loop_interp_from_face(em->bm, l2, copyf, do_vdata, FALSE); - 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 (fabsf(suv->origuv[0]-uv_new[0]) > 0.0001f || fabsf(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 map 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_elem_attrs_copy(em->bm, em->bm, copyf2, f); + + /*restore selection and hidden flags*/ + BM_elem_select_set(em->bm, f, sel); + BM_elem_hide_set(em->bm, f, hide); + } + } + + 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; @@ -4796,31 +4762,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_face_verts_kill(sld->em->bm, copyf); + } + + sld->em->bm->ob = t->obedit; + bmesh_end_edit(sld->em->bm, BMO_OP_FLAG_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) @@ -4860,108 +4833,28 @@ void initEdgeSlide(TransInfo *t) static int doEdgeSlide(TransInfo *t, float perc) { 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; - const int uvlay_tot= sld->uvlay_tot; - 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) { - 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) { - copy_v2_v2(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } + TransDataSlideVert *svlist = sld->sv, *sv; + float vec[3]; + int i; - look = look->next; + sld->perc = perc; + + sv = svlist; + for (i=0; i<sld->totsv; i++, sv++) { + if (perc > 0.0f) { + copy_v3_v3(vec, sv->upvec); + mul_v3_fl(vec, perc); + add_v3_v3v3(sv->v->co, sv->origvert.co, vec); } - } - 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) { - /* 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) { - copy_v2_v2(((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) { - /* 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) { - copy_v2_v2(((float *)fuv_link->link), uv_tmp); - fuv_link = fuv_link->next; - } - } - } - } - } - look = look->next; + else { + copy_v3_v3(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 4c4c2f67d82..13f7d279da9 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -39,6 +39,8 @@ #include "DNA_listBase.h" #include "BLI_editVert.h" +#include "BLI_smallhash.h" +#include "BKE_tessmesh.h" /* ************************** Types ***************************** */ @@ -64,6 +66,7 @@ struct wmEvent; struct wmTimer; struct ARegion; struct ReportList; +struct SmallHash; typedef struct TransSnapPoint { struct TransSnapPoint *next,*prev; @@ -182,25 +185,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 fe244fbdafa..5158f2beada 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -73,6 +73,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" #include "BKE_tracking.h" @@ -103,13 +104,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 @@ -298,16 +302,17 @@ static void createTransTexspace(TransInfo *t) 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++; + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) countsel++; if (propmode) count++; } } @@ -327,14 +332,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_elem_flag_test(eed, BM_ELEM_HIDDEN) && (BM_elem_flag_test(eed, BM_ELEM_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_elem_flag_test(eed, BM_ELEM_SELECT)) td->flag= TD_SELECTED; else td->flag= 0; @@ -345,12 +353,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++; @@ -409,7 +417,7 @@ static short apply_targetless_ik(Object *ob) } for(;segcount;segcount--) { Bone *bone; - float rmat[4][4], tmat[4][4], imat[4][4]; + float rmat[4][4]/*, tmat[4][4], imat[4][4]*/; /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */ /* we put in channel the entire result of rmat= (channel * constraint * IK) */ @@ -420,6 +428,8 @@ static short apply_targetless_ik(Object *ob) bone= parchan->bone; bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */ + /* XXX Old code. Will remove it later. */ +#if 0 if(parchan->parent) { Bone *parbone= parchan->parent->bone; float offs_bone[4][4]; @@ -462,6 +472,8 @@ static short apply_targetless_ik(Object *ob) } /* result matrix */ mult_m4_m4m4(rmat, imat, parchan->pose_mat); +#endif + armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat); /* apply and decompose, doesn't work for constraints or non-uniform scale well */ { @@ -1854,126 +1866,123 @@ void flushTransParticles(TransInfo *t) /* proportional distance based on connectivity */ #define THRESHOLDFACTOR (1.0f-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 < THRESHOLDFACTOR * v1->tmp.fp) { - v1->tmp.fp = v2->tmp.fp + edge_len; - done = 1; - } else if (v1->tmp.fp + edge_len < THRESHOLDFACTOR * 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; - } + fill_vn_fl(dists, em->bm->totvert, FLT_MAX); - return done; -} + BM_mesh_elem_index_ensure(em->bm, BM_VERT); -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; - } - } - } + BLI_smallhash_init(visit); + BM_ITER(v, &viter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(v, BM_ELEM_SELECT)==0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + continue; + + + BLI_smallhash_insert(visit, (uintptr_t)v, NULL); + BLI_array_append(queue, v); + BLI_array_append(dqueue, 0.0f); + dists[BM_elem_index_get(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_edge_other_vert(e, v2); + + if (BM_elem_flag_test(v3, BM_ELEM_SELECT) || BM_elem_flag_test(v3, BM_ELEM_HIDDEN)) + continue; + + sub_v3_v3v3(vec, v2->co, v3->co); + mul_m3_v3(mtx, vec); + + d2 = d + len_v3(vec); + + if (dists[BM_elem_index_get(v3)] != FLT_MAX) + dists[BM_elem_index_get(v3)] = MIN2(d2, dists[BM_elem_index_get(v3)]); + else + dists[BM_elem_index_get(v3)] = d2; + + tots[BM_elem_index_get(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 cent_r[3], BMesh *bm, BMVert *eve) + { - EditFace *efa; + BMFace *efa; + BMIter iter; - 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) { - copy_v3_v3(cent, efa->cent); + BM_ITER(efa, &iter, bm, BM_FACES_OF_VERT, eve) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_face_center_mean_calc(bm, efa, cent_r); + break; + } } } -static void get_edge_center(float *cent, EditMesh *em, EditVert *eve) +static void get_edge_center(float cent_r[3], BMesh *bm, BMVert *eve) { - EditEdge *eed; + BMEdge *eed; + BMIter iter; - for(eed= em->edges.first; eed; eed= eed->next) - if(eed->f & SELECT) - if(eed->v1==eve || eed->v2==eve) - break; - if(eed) { - mid_v3_v3v3(cent, eed->v1->co, eed->v2->co); + BM_ITER(eed, &iter, bm, BM_EDGES_OF_VERT, eve) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + mid_v3_v3v3(cent_r, eed->v1->co, eed->v2->co); + break; + } } } /* 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) +static void VertsToTransData(TransInfo *t, TransData *td, BMEditMesh *em, BMVert *eve, float *bweight) { td->flag = 0; //if(key) @@ -1982,11 +1991,12 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert td->loc = eve->co; copy_v3_v3(td->center, td->loc); + if(t->around==V3D_LOCAL) { if(em->selectmode & SCE_SELECT_FACE) - get_face_center(td->center, em, eve); + get_face_center(td->center, em->bm, eve); else if(em->selectmode & SCE_SELECT_EDGE) - get_edge_center(td->center, em, eve); + get_edge_center(td->center, em->bm, eve); } copy_v3_v3(td->iloc, td->loc); @@ -2003,8 +2013,8 @@ static void VertsToTransData(TransInfo *t, TransData *td, EditMesh *em, EditVert td->val = NULL; td->extra = NULL; if (t->mode == TFM_BWEIGHT) { - td->val = &(eve->bweight); - td->ival = eve->bweight; + td->val = bweight; + td->ival = bweight ? *(bweight) : 1.0f; } } @@ -2012,18 +2022,23 @@ 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; + float *dists=NULL; int count=0, countsel=0, a, totleft; int propmode = (t->flag & T_PROP_EDIT) ? (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) : 0; int mirror = 0; + char *selstate = NULL; short selectmode = ts->selectmode; if (t->flag & T_MIRROR) { + EDBM_CacheMirrorVerts(em, TRUE); mirror = 1; } @@ -2032,55 +2047,89 @@ static void createTransEditVerts(bContext *C, TransInfo *t) selectmode = SCE_SELECT_EDGE; } + /* BMESH_TODO, writing into the index values is BAD!, means we cant + * use the values for vertex mirror - campbell */ + // 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; - else - eve->f1= 0; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_elem_flag_enable(eve, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(eve, BM_ELEM_TAG); + } } } 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BM_iter_step(&iter)) BM_elem_flag_disable(eve, BM_ELEM_TAG); + + eed = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); + for( ; eed; eed=BM_iter_step(&iter)) { + if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_elem_flag_enable(eed->v1, BM_ELEM_TAG); + BM_elem_flag_enable(eed->v2, BM_ELEM_TAG); + } } } 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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for( ; eve; eve=BM_iter_step(&iter)) BM_elem_flag_disable(eve, BM_ELEM_TAG); + + efa = BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL); + for( ; efa; efa=BM_iter_step(&iter)) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BMIter liter; + BMLoop *l; + + l = BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, efa); + for (; l; l=BM_iter_step(&liter)) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } } - /* 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*/ + selstate = MEM_callocN(sizeof(*selstate) * bm->totvert, __func__); + eve = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BM_iter_step(&iter), a++) { + if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if (BM_elem_flag_test(eve, BM_ELEM_TAG)) { + selstate[a] = 1; + countsel++; + } if(propmode) count++; } } - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; + /* note: in prop mode we need at least 1 selected */ + if (countsel == 0) { + goto cleanup; + } /* check active */ - if (em->selected.last) { - EditSelection *ese = em->selected.last; - if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; + if (em->bm->selected.last) { + BMEditSelection *ese = em->bm->selected.last; + if (ese->htype == BM_VERT) { + 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)"); @@ -2089,7 +2138,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) invert_m3_m3(smtx, mtx); if(propmode & T_PROP_CONNECTED) { - editmesh_set_connectivity_distance(em, mtx); + editmesh_set_connectivity_distance(em, mtx, dists); } /* detect CrazySpace [tm] */ @@ -2097,7 +2146,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) 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 @@ -2105,7 +2154,7 @@ static void createTransEditVerts(bContext *C, TransInfo *t) if(totleft > 0) { mappedcos= crazyspace_get_mapped_editverts(t->scene, t->obedit); quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats"); - crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats); + crazyspace_set_quats_editmesh(em, (float*)defcos, mappedcos, quats); /* BMESH_TODO, abuses vertex index, should use an int array */ if(mappedcos) MEM_freeN(mappedcos); } @@ -2117,8 +2166,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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BM_iter_step(&iter), a++) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN) && selstate[a] && eve->co[0]!=0.0f) { if(eve->co[0]<0.0f) { t->mirror = -1; @@ -2129,34 +2179,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 = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); + for(a=0; eve; eve=BM_iter_step(&iter), a++) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if(propmode || selstate[a]) { + float *bweight = CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_BWEIGHT); + + VertsToTransData(t, tob, em, 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_elem_index_get(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_elem_index_get(eve) != -1) { + quat_to_mat3(qmat, quats + 4*BM_elem_index_get(eve)); if(defmats) mul_serie_m3(mat, mtx, qmat, defmats[a], @@ -2179,8 +2231,8 @@ static void createTransEditVerts(bContext *C, TransInfo *t) /* Mirror? */ 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; } } @@ -2200,12 +2252,22 @@ static void createTransEditVerts(bContext *C, TransInfo *t) } } } - + +cleanup: /* crazy space free */ if(quats) MEM_freeN(quats); if(defmats) MEM_freeN(defmats); + if (dists) + MEM_freeN(dists); + + MEM_freeN(selstate); + + if (t->flag & T_MIRROR) { + EDBM_EndMirrorCache(em); + mirror = 1; + } } /* *** NODE EDITOR *** */ @@ -2383,30 +2445,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_elem_flag_disable(efa, BM_ELEM_TAG); + continue; + } + + BM_elem_flag_enable(efa, BM_ELEM_TAG); + 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++; } } @@ -2425,20 +2490,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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)); } } @@ -4817,7 +4879,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); } } } @@ -5067,7 +5129,7 @@ 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'); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 3c019c1680f..4073081ffc2 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -71,6 +71,7 @@ #include "BKE_mesh.h" #include "BKE_nla.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BKE_tracking.h" #include "ED_anim_api.h" @@ -236,10 +237,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++) { @@ -374,7 +375,6 @@ static void recalcData_actedit(TransInfo *t) BLI_freelistN(&anim_data); } } - /* helper for recalcData() - for Graph Editor transforms */ static void recalcData_graphedit(TransInfo *t) { @@ -714,7 +714,7 @@ static void recalcData_view3d(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] */ @@ -722,11 +722,12 @@ static void recalcData_view3d(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; @@ -1537,12 +1538,12 @@ void calculateCenter(TransInfo *t) /* EDIT MODE ACTIVE EDITMODE ELEMENT */ if (t->obedit) { - if(t->obedit->type == OB_MESH) { - EditSelection ese; - EditMesh *em = BKE_mesh_get_editmesh(t->obedit->data); + if (t->obedit && t->obedit->type == OB_MESH) { + BMEditSelection ese; + BMEditMesh *em = ((Mesh*)t->obedit->data)->edit_btmesh; - if (EM_get_actSelection(em, &ese)) { - EM_editselection_center(t->center, &ese); + if (EDBM_get_actSelection(em, &ese)) { + EDBM_editselection_center(em, t->center, &ese); calculateCenter2D(t); break; } diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 5578ea754df..f95856b2373 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -60,6 +60,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" @@ -298,72 +299,63 @@ 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; + BMEditSelection ese; 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 { + } + else { + BMesh *bm = em->bm; + BMVert *eve; + + BMIter iter; + /* 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 */ if(ts->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->f & SELECT) { - totsel++; - calc_tw_center(scene, eve->co); + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + if(BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + totsel++; + calc_tw_center(scene, eve->co); + } } } } else if(ts->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)) { - if(!eed->v1->f1) { - eed->v1->f1= 1; - totsel++; - calc_tw_center(scene, eed->v1->co); - } - if(!eed->v2->f1) { - eed->v2->f1= 1; - totsel++; - calc_tw_center(scene, eed->v2->co); + BMIter itersub; + BMEdge *eed; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + /* check the vertex has a selected edge, only add it once */ + BM_ITER(eed, &itersub, bm, BM_EDGES_OF_VERT, eve) { + if(BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + totsel++; + calc_tw_center(scene, eve->co); + break; + } } } } } 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)) { - if(!efa->v1->f1) { - efa->v1->f1= 1; - totsel++; - calc_tw_center(scene, efa->v1->co); - } - if(!efa->v2->f1) { - efa->v2->f1= 1; - totsel++; - calc_tw_center(scene, efa->v2->co); - } - if(!efa->v3->f1) { - efa->v3->f1= 1; - totsel++; - calc_tw_center(scene, efa->v3->co); - } - if(efa->v4 && !efa->v4->f1) { - efa->v4->f1= 1; - totsel++; - calc_tw_center(scene, efa->v4->co); + BMIter itersub; + BMFace *efa; + BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL) { + if(!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { + /* check the vertex has a selected face, only add it once */ + BM_ITER(efa, &itersub, bm, BM_FACES_OF_VERT, eve) { + if(BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + totsel++; + calc_tw_center(scene, eve->co); + break; + } } } } diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 8a9249f78e5..19dbf8b713e 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -41,6 +41,7 @@ #include "BKE_armature.h" #include "BKE_curve.h" #include "BKE_context.h" +#include "BKE_tessmesh.h" #include "BKE_report.h" #include "BLI_math.h" @@ -583,56 +584,57 @@ 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) + switch (ese.htype) { - 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) - { - add_v3_v3(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_elem_flag_test(efa, BM_ELEM_SELECT)) { + add_v3_v3(normal, efa->no); + sub_v3_v3v3(vec, + BM_FACE_FIRST_LOOP(efa)->v->co, + BM_FACE_FIRST_LOOP(efa)->next->v->co); add_v3_v3(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_elem_flag_test(eve, BM_ELEM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -651,12 +653,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_elem_flag_test(eed, BM_ELEM_SELECT)) { sub_v3_v3v3(plane, eed->v2->co, eed->v1->co); break; } @@ -665,12 +668,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_elem_flag_test(eed, BM_ELEM_SELECT)) { /* use average vert normals as plane and edge vector as normal */ copy_v3_v3(plane, eed->v1->no); add_v3_v3(plane, eed->v2->no); @@ -680,13 +684,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_elem_flag_test(eve, BM_ELEM_SELECT)) { if (v1 == NULL) { v1 = eve; } @@ -702,24 +706,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_elem_flag_test(eve, BM_ELEM_SELECT)) { copy_v3_v3(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_elem_flag_test(eve, BM_ELEM_SELECT)) { add_v3_v3(normal, eve->no); } } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index d079bd41c10..183ade56cf0 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -68,6 +68,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" @@ -1352,13 +1354,13 @@ 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], +static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[][4], const float ray_start[3], const float ray_normal[3], const float mval[2], float r_loc[3], float r_no[3], int *r_dist, float *r_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]; @@ -1426,19 +1428,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 */ @@ -1460,11 +1462,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_elem_flag_test(efa, BM_ELEM_HIDDEN)) { test = 0; + } else if (efa) { + BMIter iter; + BMLoop *l; + + l = BM_iter_new(&iter, em->bm, BM_LOOPS_OF_FACE, efa); + for ( ; l; l=BM_iter_step(&iter)) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) { + test = 0; + break; + } + } } } } @@ -1492,7 +1505,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; @@ -1507,11 +1520,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 */ @@ -1533,9 +1546,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_elem_flag_test(eve, BM_ELEM_HIDDEN) || BM_elem_flag_test(eve, BM_ELEM_SELECT))) { test = 0; } @@ -1551,7 +1564,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; } @@ -1567,11 +1580,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 */ @@ -1593,9 +1606,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_elem_flag_test(eed, BM_ELEM_HIDDEN) || + BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) || + BM_elem_flag_test(eed->v2, BM_ELEM_SELECT))) { test = 0; } @@ -1611,7 +1626,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; } @@ -1630,14 +1645,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 { @@ -1793,7 +1808,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], { 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]; @@ -1823,7 +1838,7 @@ static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], 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++) { @@ -1919,6 +1934,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; @@ -1940,6 +1956,7 @@ static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, L retval = retval || val; dm->release(dm); +#endif } } @@ -1947,7 +1964,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; @@ -1959,8 +1976,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 7a6ccdff08f..eb0286716f3 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -23,6 +23,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 cfbc735eb5c..16501c59551 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','player'], priority=[330,210] ) diff --git a/source/blender/editors/util/crazyspace.c b/source/blender/editors/util/crazyspace.c index 9ee4a875e24..ae4f99414bd 100644 --- a/source/blender/editors/util/crazyspace.c +++ b/source/blender/editors/util/crazyspace.c @@ -41,6 +41,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" @@ -106,18 +107,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"); @@ -136,10 +137,59 @@ 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_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + if (!BM_elem_flag_test(v, BM_ELEM_SELECT) || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + continue; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, v) { + BMLoop *l2 = BM_face_other_loop(l->e, l->f, v); + + /* retrieve mapped coordinates */ + v1= mappedcos + 3*BM_elem_index_get(l->v); + v2= mappedcos + 3*BM_elem_index_get(BM_edge_other_vert(l2->e, l->v)); + v3= mappedcos + 3*BM_elem_index_get(BM_edge_other_vert(l->e, l->v)); + + co1= (origcos)? origcos + 3*BM_elem_index_get(l->v) : l->v->co; + co2= (origcos)? origcos + 3*BM_elem_index_get(BM_edge_other_vert(l2->e, l->v)) : BM_edge_other_vert(l2->e, l->v)->co; + co3= (origcos)? origcos + 3*BM_elem_index_get(BM_edge_other_vert(l->e, l->v)) : BM_edge_other_vert(l->e, l->v)->co; + + set_crazy_vertex_quat(quats, v1, v2, v3, co1, co2, co3); + quats+= 4; + + vert_table[BM_elem_index_get(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_elem_index_set(v, vert_table[index]-1); /* set_dirty! */ + else + BM_elem_index_set(v, -1); /* set_dirty! */ + + index++; + } + em->bm->elem_index_dirty |= BM_VERT; + + 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; @@ -204,9 +254,11 @@ 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 } +/* BMESH_TODO - use MPolys over MFace's */ + void crazyspace_set_quats_mesh(Mesh *me, float *origcos, float *mappedcos, float *quats) { int i; @@ -267,7 +319,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; @@ -286,13 +339,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++) @@ -307,7 +360,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 a40c6cfa42f..7f301123ab8 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -108,10 +108,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) { diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c index 34dffc11d94..4776cf0af53 100644 --- a/source/blender/editors/util/editmode_undo.c +++ b/source/blender/editors/util/editmode_undo.c @@ -96,8 +96,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; @@ -107,10 +107,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); } } @@ -118,8 +118,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; @@ -168,7 +168,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; @@ -248,7 +248,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) { @@ -256,7 +256,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 { @@ -264,7 +264,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); } @@ -272,7 +272,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(C); } DAG_id_tag_update(&obedit->id, OB_RECALC_DATA); diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 4fb9f916df7..56a835beeb8 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -48,6 +48,8 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_tessmesh.h" /* BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND */ + #include "ED_armature.h" #include "ED_particle.h" @@ -86,6 +88,19 @@ void ED_undo_push(bContext *C, const char *str) printf("undo push %s\n", str); if(obedit) { + +#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND + /* undo is causing tessface recalc, so without we need to do explicitly */ + + if (U.undosteps == 0) { + if (obedit->type == OB_MESH) { + Mesh *me= obedit->data; + BMEdit_RecalcTesselation(me->edit_btmesh); + } + } + +#endif /* BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND */ + if (U.undosteps == 0) return; if(obedit->type==OB_MESH) diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index a747c2ac6bd..1c69e569aa6 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -23,6 +23,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 a6712bf8efa..9759ab447f6 100644 --- a/source/blender/editors/uvedit/uvedit_buttons.c +++ b/source/blender/editors/uvedit/uvedit_buttons.c @@ -47,6 +47,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" @@ -61,32 +62,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++; } } @@ -100,23 +89,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); + } } } } @@ -131,13 +116,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); @@ -161,8 +146,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) @@ -171,14 +154,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); @@ -194,8 +177,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 6ced91f0d01..ca8f1e4fb97 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -31,7 +31,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" @@ -44,7 +48,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" @@ -121,34 +127,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; @@ -157,13 +162,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) { @@ -171,21 +182,36 @@ 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); + BLI_array_growitems(tf_uv, efa->len); + BLI_array_growitems(tf_uvorig, efa->len); + + 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); + + copy_v2_v2(tf_uvorig[i], luv->uv); + + i++; + } - totarea += EM_face_area(efa); + poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len); + + totarea += BM_face_area_calc(em->bm, 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_elem_flag_enable(efa, BM_ELEM_TAG); } else { if(tf == activetf) activetf= NULL; - efa->tmp.p = NULL; + BM_elem_flag_disable(efa, BM_ELEM_TAG); } } @@ -193,24 +219,40 @@ 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_elem_flag_test(efa, BM_ELEM_TAG)) { + 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_elem_flag_test(efa, BM_ELEM_TAG)) { + area = BM_face_area_calc(em->bm, efa) / totarea; + + BLI_array_empty(tf_uv); + BLI_array_empty(tf_uvorig); + BLI_array_growitems(tf_uv, efa->len); + BLI_array_growitems(tf_uvorig, efa->len); + + 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); + + copy_v2_v2(tf_uvorig[i], luv->uv); + + 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; @@ -222,11 +264,11 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac weight_to_rgb(col, areadiff); 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(); } } @@ -235,6 +277,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 */ @@ -245,7 +288,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; @@ -376,6 +419,8 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac glShadeModel(GL_FLAT); break; + +#endif } } } @@ -397,17 +442,19 @@ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage) 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(); } } @@ -427,17 +474,19 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob) glColor3ub(112, 112, 112); 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(); } } @@ -449,19 +498,23 @@ 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; Image *ima= sima->image; - StitchPreviewer *stitch_preview = uv_get_stitch_previewer(); - em= BKE_mesh_get_editmesh(me); - activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */ + StitchPreviewer *stitch_preview = uv_get_stitch_previewer(); + em= me->edit_btmesh; + activetf= EDBM_get_active_mtexpoly(em, &efa_act, FALSE); /* will be set to NULL if hidden */ + activef = BM_active_face_get(em->bm, FALSE); ts= scene->toolsettings; drawfaces= draw_uvs_face_check(scene); @@ -483,7 +536,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 */ @@ -508,45 +561,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_elem_flag_enable(efa, BM_ELEM_TAG); + 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_elem_flag_disable(efa, BM_ELEM_TAG); } } 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_elem_flag_enable(efa, BM_ELEM_TAG); } else { if(tf == activetf) activetf= NULL; - efa->tmp.p = NULL; + BM_elem_flag_disable(efa, BM_ELEM_TAG); } } @@ -554,7 +608,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); @@ -562,11 +616,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); @@ -583,39 +637,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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); } } @@ -625,34 +678,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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 */ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + 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(); } glLineWidth(1); @@ -660,89 +711,62 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glColor4ubv((unsigned char *)col2); if(me->drawflag & ME_DRAWEDGES) { - int lastsel= 0, sel; + int sel, lastsel = -1; UI_GetThemeColor4ubv(TH_VERTEX_SELECT, col1); if(interpedges) { glShadeModel(GL_SMOOTH); - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - 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; - 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(); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + glBegin(GL_LINE_LOOP); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + sel = (uvedit_uv_selected(em, scene, l)? 1 : 0); + glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); + + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + glVertex2fv(luv->uv); } + glEnd(); } glShadeModel(GL_FLAT); } else { - for(efa= em->faces.first; efa; efa= efa->next) { - tf= (MTFace *)efa->tmp.p; /* visible faces cached */ - - 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; - 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]); + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + glBegin(GL_LINES); + 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[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); } + 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_elem_flag_test(efa, BM_ELEM_TAG)) + 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(); } } @@ -766,11 +790,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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); } } @@ -780,11 +805,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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); } } @@ -800,18 +826,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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(); @@ -822,18 +844,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_elem_flag_test(efa, BM_ELEM_TAG)) + 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(); @@ -843,18 +862,15 @@ 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_elem_flag_test(efa, BM_ELEM_TAG)) + 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(); @@ -872,9 +888,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris); glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris*3); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_quads); - glDrawArrays(GL_QUADS, 0, stitch_preview->num_static_quads*4); - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_tris); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); UI_ThemeColor4(TH_STITCH_PREVIEW_FACE); @@ -885,18 +898,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); /*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);*/ - - glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_quads); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - UI_ThemeColor4(TH_STITCH_PREVIEW_FACE); - glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4); - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE); - glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4); - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - /*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT); - glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);*/ - glDisable(GL_BLEND); /* draw vert preview */ @@ -914,7 +915,6 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit) } glPointSize(1.0); - BKE_mesh_end_editmesh(obedit->data, em); } void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact) diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index a5b4173cc67..6566a79e467 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -34,6 +34,7 @@ struct EditFace; struct EditMesh; +struct MTexPoly; struct Image; struct MTFace; struct Object; @@ -41,59 +42,65 @@ struct Scene; struct SpaceImage; struct UvElementMap; 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]); + /* find nearest */ typedef struct NearestHit { - struct EditFace *efa; - struct MTFace *tf; - - int vert, uv; - int edge, vert2; + struct BMFace *efa; + struct MTexPoly *tf; + struct BMLoop *l, *nextl; + struct MLoopUV *luv, *nextluv; + int lindex; //index of loop within face + int vert1, vert2; //index in mesh of edge vertices } NearestHit; -void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], float penalty[2], struct NearestHit *hit); -void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], struct NearestHit *hit); +void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], float penalty[2], struct NearestHit *hit); +void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], struct NearestHit *hit); /* utility tool functions */ -struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct EditFace *efa, int index); +struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct BMFace *efa, int index); void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); /* smart stitch */ /* object that stores display data for previewing before accepting stitching */ typedef struct StitchPreviewer { - /* OpenGL requires different calls for Triangles and Quads. - * here we'll store the quads of the mesh */ - float *preview_quads; - /* ...and here we'll store the triangles*/ + /* here we'll store the preview triangles of the mesh */ float *preview_tris; /* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */ float *preview_stitchable; float *preview_unstitchable; /* here we'll store the number of triangles and quads to be drawn */ unsigned int num_tris; - unsigned int num_quads; unsigned int num_stitchable; unsigned int num_unstitchable; - /* store static island Quads */ - float *static_quads; /* ...and here we'll store the triangles*/ float *static_tris; unsigned int num_static_tris; - unsigned int num_static_quads; } StitchPreviewer; StitchPreviewer *uv_get_stitch_previewer(void); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 5f836ec4ca7..0df2a70302a 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -33,6 +33,7 @@ #include <stdlib.h> #include <string.h> #include <math.h> +#include <string.h> #include "MEM_guardedalloc.h" @@ -40,11 +41,14 @@ #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_node_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" @@ -58,6 +62,7 @@ #include "BKE_node.h" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_tessmesh.h" #include "ED_image.h" #include "ED_mesh.h" @@ -77,19 +82,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; } @@ -157,9 +166,10 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i void ED_uvedit_assign_image(Main *bmain, 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... */ @@ -170,16 +180,15 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im 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; } if(scene_use_new_shading_nodes(scene)) { /* new shading system, assign image in material */ int sloppy= 1; - EditFace *efa= EM_get_actFace(em, sloppy); + BMFace *efa= BM_active_face_get(em->bm, sloppy); if(efa) ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima); @@ -188,14 +197,15 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im /* old shading system, assign image to selected faces */ /* ensure we have a uv map */ - 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_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY); + BM_data_layer_add(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) { @@ -204,8 +214,9 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im if(ima->id.us==0) id_us_plus(&ima->id); else id_lib_extern(&ima->id); } - else + else { tf->tpage= NULL; + } update = 1; } @@ -216,16 +227,16 @@ void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *im 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)) @@ -238,17 +249,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_elem_flag_test(efa, BM_ELEM_HIDDEN) && BM_elem_flag_test(efa, BM_ELEM_SELECT)) tf->tile= curtile; /* set tile index */ } DAG_id_tag_update(obedit->data, 0); - BKE_mesh_end_editmesh(obedit->data, em); return 1; } @@ -273,18 +283,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_elem_flag_test(efa, BM_ELEM_HIDDEN)==0); else - return (efa->h==0 && (efa->f & SELECT)); + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)==0 && BM_elem_flag_test(efa, BM_ELEM_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) @@ -293,131 +302,199 @@ 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_elem_flag_test(efa, BM_ELEM_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_elem_select_set(em->bm, efa, TRUE); + 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); + if(ts->uv_flag & UV_SYNC_SELECTION) { + BM_elem_select_set(em->bm, efa, FALSE); + } + 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)); + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test(l->f, BM_ELEM_SELECT); + } + else if (ts->selectmode == SCE_SELECT_EDGE) { + return BM_elem_flag_test(l->e, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && + BM_elem_flag_test(l->next->v, BM_ELEM_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_elem_select_set(em->bm, l->f, TRUE); else if(ts->selectmode & SCE_SELECT_EDGE) - EM_select_edge((*(&efa->e1 + i)), 1); + BM_elem_select_set(em->bm, l->e, TRUE); else { - (efa->v1 + i)->f |= SELECT; - (efa->v1 + (i+1)%nvert)->f |= SELECT; + BM_elem_select_set(em->bm, l->e->v1, TRUE); + BM_elem_select_set(em->bm, l->e->v2, TRUE); } } - 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_elem_select_set(em->bm, l->f, FALSE); else if(ts->selectmode & SCE_SELECT_EDGE) - EM_select_edge((*(&efa->e1 + i)), 0); + BM_elem_select_set(em->bm, l->e, FALSE); else { - (efa->v1 + i)->f &= ~SELECT; - (efa->v1 + (i+1)%nvert)->f &= ~SELECT; + BM_elem_select_set(em->bm, l->e->v1, FALSE); + BM_elem_select_set(em->bm, l->e->v2, FALSE); } } - 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_elem_flag_test(l->f, BM_ELEM_SELECT); else - return (*(&efa->v1 + i))->f & SELECT; + return BM_elem_flag_test(l->v, BM_ELEM_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_elem_select_set(em->bm, l->f, TRUE); else - (*(&efa->v1 + i))->f |= SELECT; + BM_elem_select_set(em->bm, l->v, TRUE); + } + 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_elem_select_set(em->bm, l->f, FALSE); else - (*(&efa->v1 + i))->f &= ~SELECT; + BM_elem_select_set(em->bm, l->v, FALSE); + } + 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 ***********************/ @@ -432,6 +509,22 @@ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit) } /*********************** geometric utilities ***********************/ +void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2]) +{ + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + zero_v2(cent); + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + add_v2_v2(cent, luv->uv); + } + + mul_v2_fl(cent, 1.0f / (float)f->len); +} + void uv_center(float uv[][2], float cent[2], int quad) { @@ -453,6 +546,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; @@ -470,56 +585,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; @@ -539,99 +664,133 @@ 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 ****************************/ -void uv_find_nearest_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit) +void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit) { - MTFace *tf; - EditFace *efa; - EditVert *eve; + MTexPoly *tf; + BMFace *efa; + BMLoop *l; + 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; + BM_mesh_elem_index_ensure(em->bm, BM_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)) { - 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 = l->next; + hit->luv = luv; + hit->nextluv = nextluv; + hit->lindex = i; + hit->vert1 = BM_elem_index_get(hit->l->v); + hit->vert2 = BM_elem_index_get(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*/ + uv_find_nearest_edge(scene, ima, em, co, hit); + hit->l = hit->nextl = NULL; + hit->luv = hit->nextluv = NULL; - for(i=0; i<nverts; i++) { - add_v2_v2(cent, tf->uv[i]); - } + 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]); + add_v2_v2(cent, luv->uv); + } - 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]; @@ -647,86 +806,99 @@ static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float return (c1*c2 >= 0.0f); } -void uv_find_nearest_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit) +void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em, + float co[2], float penalty[2], NearestHit *hit) { - EditFace *efa; - EditVert *eve; - MTFace *tf; + BMFace *efa; + 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*/ + uv_find_nearest_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); + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - if(uvedit_face_visible(scene, ima, efa, tf)) { - nverts= efa->v4? 4: 3; - - 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 = 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_elem_index_get(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; } @@ -748,25 +920,34 @@ 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 = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, a); + first= EDBM_get_uv_map_vert(vmap, BM_elem_index_get(l->v)); for(iterv=first; iterv; iterv=iterv->next) { if(iterv->separate) first= iterv; - if(iterv->f == efa->tmp.l) + if(iterv->f == BM_elem_index_get(efa)) return first; } return NULL; } -UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index) +/* BMESH_TODO - in some cases we already know the loop so looking up the index isnt needed */ + +UvElement *ED_get_uv_element(UvElementMap *map, BMFace *efa, int index) { - UvElement *element = map->vert[(*(&efa->v1 + index))->tmp.l]; + BMLoop *l; + UvElement *element; + + l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, efa, index); + + element = map->vert[BM_elem_index_get(l->v)]; for(; element; element = element->next) if(element->face == efa) @@ -775,10 +956,10 @@ UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index) 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 */ @@ -792,8 +973,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_elem_flag_test(em->bm, efa, EFA_F1_FLAG)) return 0; tot++; @@ -817,8 +998,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_elem_flag_enable(em->bm, efa, EFA_F1_FLAG); break; } } @@ -827,41 +1008,45 @@ 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; + 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; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - 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); } + + BMO_elem_flag_disable(em->bm, efa, EFA_F1_FLAG); - efa->tmp.l= count; - efa->f1= 0; + BM_elem_index_set(efa, count); /* set_inline */ + + count++; } - + em->bm->elem_index_dirty &= ~BM_FACE; + /* 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; @@ -872,21 +1057,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_elem_flag_test(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_elem_flag_enable(em->bm, efa, EFA_F1_FLAG); uv_vertex_loop_flag(iterv1); uv_vertex_loop_flag(iterv2); @@ -899,16 +1088,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)) + if(uvedit_uv_selected(em, scene, hit->l)) select= 0; else select= 1; @@ -916,83 +1103,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_elem_index_get(l->v)); startv= vlist; @@ -1012,50 +1225,108 @@ 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); +} + +/* WATCH IT: this returns first selected UV, + * not ideal in many cases since there could be multiple */ +static float *uv_sel_co_from_eve(Scene *scene, Image *ima, BMEditMesh *em, BMVert *eve) +{ + BMIter liter; + BMLoop *l; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) { + MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY); + + if (!uvedit_face_visible(scene, ima, l->f, tf)) + continue; + + if (uvedit_uv_selected(em, scene, l)) { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + return luv->uv; + } + } + + return NULL; } /* ******************** align operator **************** */ @@ -1066,32 +1337,35 @@ static void weld_align_uv(bContext *C, int tool) Scene *scene; Object *obedit; Image *ima; - EditMesh *em; - EditFace *efa; - MTFace *tf; + BMEditMesh *em; + 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); + BMFace *efa; + BMLoop *l; - 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) + 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) + } } } @@ -1101,170 +1375,173 @@ 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]; + BMFace *efa; + BMLoop *l; + + 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]; + BMFace *efa; + BMLoop *l; + + 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]; + } + } } } if(tool == 's' || tool == 't' || tool == 'u') { - /* pass 1&2 variables */ - int i, j; - int starttmpl= -1, connectedtostarttmpl= -1, startcorner; - int endtmpl= -1, connectedtoendtmpl= -1, endcorner; - MTFace *startface, *endface; - int itmpl, jtmpl; - EditVert *eve; - int pass; /* first 2 passes find endpoints, 3rd pass moves middle points, 4th pass is fail-on-face-selected */ - EditFace *startefa, *endefa= NULL; /* endefa shouldnt need to be initialized but just incase */ - - /* pass 3 variables */ - float startx, starty, firstm, firstb, midx, midy; - float endx, endy, secondm, secondb, midmovedx, midmovedy; - float IsVertical_check= -1; - float IsHorizontal_check= -1; - - for(i= 0, eve= em->verts.first; eve; eve= eve->next, i++) /* give each point a unique name */ - eve->tmp.l= i; - for(pass= 1; pass <= 3; pass++) { /* do this for each endpoint */ - if(pass == 3){ /* calculate */ - startx= startface->uv[startcorner][0]; - starty= startface->uv[startcorner][1]; - endx= endface->uv[endcorner][0]; - endy= endface->uv[endcorner][1]; - firstm= (endy-starty)/(endx-startx); - firstb= starty-(firstm*startx); - secondm= -1.0f/firstm; - if(startx == endx) IsVertical_check= startx; - if(starty == endy) IsHorizontal_check= starty; - } - for(efa= em->faces.first; efa; efa= efa->next) { /* for each face */ - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); /* get face */ - if(uvedit_face_visible(scene, ima, efa, tf)) { /* if you can see it */ - if(uvedit_face_selected(scene, efa, tf)) { /* if the face is selected, get out now! */ - pass= 4; - break; - } - for(i= 0; (i < 3 || (i == 3 && efa->v4)); i++) { /* for each point of the face */ - itmpl= (*(&efa->v1 + i))->tmp.l; /* get unique name for points */ - if(pass == 3) { /* move */ - if(uvedit_uv_selected(scene, efa, tf, i)) { - if(!(itmpl == starttmpl || itmpl == endtmpl)) { - if(IsVertical_check != -1) tf->uv[i][0]= IsVertical_check; - if(IsHorizontal_check != -1) tf->uv[i][1]= IsHorizontal_check; - if((IsVertical_check == -1) && (IsHorizontal_check == -1)) { - midx= tf->uv[i][0]; - midy= tf->uv[i][1]; - if(tool == 's') { - secondb= midy-(secondm*midx); - midmovedx= (secondb-firstb)/(firstm-secondm); - midmovedy= (secondm*midmovedx)+secondb; - tf->uv[i][0]= midmovedx; - tf->uv[i][1]= midmovedy; - } - else if(tool == 't') { - tf->uv[i][0]= (midy-firstb)/firstm; /* midmovedx */ - } - else if(tool == 'u') { - tf->uv[i][1]= (firstm*midx)+firstb; /* midmovedy */ - } - } - } - } + BMEdge *eed; + BMLoop *l; + BMVert *eve; + BMVert *eve_start; + BMIter iter, liter, eiter; + + /* clear tag */ + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_elem_flag_disable(eve, BM_ELEM_TAG); + } + + /* tag verts with a selected UV */ + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve) { + tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY); + + if (!uvedit_face_visible(scene, ima, l->f, tf)) + continue; + + if (uvedit_uv_selected(em, scene, l)) { + BM_elem_flag_enable(eve, BM_ELEM_TAG); + break; + } + } + } + + /* flush vertex tags to edges */ + BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) { + if (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) && BM_elem_flag_test(eed->v2, BM_ELEM_TAG)) { + BM_elem_flag_enable(eed, BM_ELEM_TAG); + } + else { + BM_elem_flag_disable(eed, BM_ELEM_TAG); + } + } + + /* find a vertex with only one tagged edge */ + eve_start = NULL; + BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) { + int tot_eed_tag = 0; + BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + tot_eed_tag++; + } + } + + if (tot_eed_tag == 1) { + eve_start = eve; + break; + } + } + + if (eve_start) { + BMVert **eve_line = NULL; + BMVert *eve_next = NULL; + BLI_array_declare(eve_line); + int i; + + eve = eve_start; + + /* walk over edges, building an array of verts in a line */ + while (eve) { + BLI_array_append(eve_line, eve); + /* dont touch again */ + BM_elem_flag_disable(eve, BM_ELEM_TAG); + + eve_next = NULL; + + /* find next eve */ + BM_ITER(eed, &eiter, em->bm, BM_EDGES_OF_VERT, eve) { + if (BM_elem_flag_test(eed, BM_ELEM_TAG)) { + BMVert *eve_other = BM_edge_other_vert(eed, eve); + if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) { + /* this is a tagged vert we didnt walk over yet, step onto it */ + eve_next = eve_other; + break; } - else { - for(j= 0; (j < 3 || (j == 3 && efa->v4)); j++) { /* also for each point on the face */ - jtmpl= (*(&efa->v1 + j))->tmp.l; - if(i != j && (!efa->v4 || ABS(i-j) != 2)) { /* if the points are connected */ - /* quad (0,1,2,3) 0,1 0,3 1,0 1,2 2,1 2,3 3,0 3,2 - * triangle (0,1,2) 0,1 0,2 1,0 1,2 2,0 2,1 */ - if(uvedit_uv_selected(scene, efa, tf, i) && uvedit_uv_selected(scene, efa, tf, j)) { - /* if the edge is selected */ - if(pass == 1) { /* if finding first endpoint */ - if(starttmpl == -1) { /* if the first endpoint isn't found yet */ - starttmpl= itmpl; /* set unique name for endpoint */ - connectedtostarttmpl= jtmpl; - /* get point that endpoint is connected to */ - startface= tf; /* get face it's on */ - startcorner= i; /* what corner of the face? */ - startefa= efa; - efa= em->faces.first; - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - i= -1; - break; - } - if(starttmpl == itmpl && jtmpl != connectedtostarttmpl) { - starttmpl= -1; /* not an endpoint */ - efa= startefa; - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - i= startcorner; - break; - } - } - else if(pass == 2) { /* if finding second endpoint */ - if(endtmpl == -1 && itmpl != starttmpl) { - endtmpl= itmpl; - connectedtoendtmpl= jtmpl; - endface= tf; - endcorner= i; - endefa= efa; - efa= em->faces.first; - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - i= -1; - break; - } - if(endtmpl == itmpl && jtmpl != connectedtoendtmpl) { - endtmpl= -1; - efa= endefa; - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - i= endcorner; - break; - } - } - } - } - } + } + } + + eve = eve_next; + } + + /* now we have all verts, make into a line */ + if (BLI_array_count(eve_line) > 2) { + + /* we know the returns from these must be valid */ + float *uv_start = uv_sel_co_from_eve(scene, ima, em, eve_line[0]); + float *uv_end = uv_sel_co_from_eve(scene, ima, em, eve_line[BLI_array_count(eve_line) - 1]); + + if (tool == 't') { + uv_start[0] = uv_end[0] = (uv_start[0] + uv_end[0]) * 0.5f; + } + else if (tool == 'u') { + uv_start[1] = uv_end[1] = (uv_start[1] + uv_end[1]) * 0.5f; + } + + /* go over all verts except for endpoints */ + for (i = 0; i < BLI_array_count(eve_line); i++) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_VERT, eve_line[i]) { + tf = CustomData_bmesh_get(&em->bm->pdata, l->f->head.data, CD_MTEXPOLY); + + if (!uvedit_face_visible(scene, ima, l->f, tf)) + continue; + + if (uvedit_uv_selected(em, scene, l)) { + MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end); } } } } - if(pass == 2 && (starttmpl == -1 || endtmpl == -1)) { - /* if endpoints aren't found */ - pass=4; + else { + /* error - not a line, needs 3+ points */ } + + if (eve_line) { + MEM_freeN(eve_line); + } + } + else { + /* error - cant find an endpoint */ } } + 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) @@ -1321,6 +1598,7 @@ static void UV_OT_weld(wmOperatorType *ot) ot->poll= ED_operator_uvedit; } + /* ******************** (de)select all operator **************** */ static void select_all_perform(bContext *C, int action) @@ -1328,43 +1606,50 @@ static void select_all_perform(bContext *C, int action) 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; 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_flag_enable_all(em, BM_ELEM_SELECT); break; case SEL_DESELECT: - EM_deselect_all(em); + EDBM_flag_disable_all(em, BM_ELEM_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; } @@ -1372,21 +1657,25 @@ static void select_all_perform(bContext *C, int action) } } - 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; } } @@ -1397,14 +1686,12 @@ static void select_all_perform(bContext *C, int action) 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"); select_all_perform(C, action); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); - BKE_mesh_end_editmesh(obedit->data, em); return OPERATOR_FINISHED; } @@ -1425,7 +1712,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; @@ -1434,7 +1721,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]) @@ -1455,13 +1742,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 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. @@ -1496,76 +1789,100 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop) /* find edge */ uv_find_nearest_edge(scene, ima, em, co, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } + + hitlen = 0; } else if(selectmode == UV_SELECT_VERTEX) { /* find vertex */ uv_find_nearest_vert(scene, ima, em, co, penalty, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } /* mark 1 vertex as being hit */ - for(i=0; i<4; i++) + BLI_array_growitems(hitv, hit.efa->len); + BLI_array_growitems(hituv, hit.efa->len); + for(i=0; i<hit.efa->len; i++) { 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 */ uv_find_nearest_edge(scene, ima, em, co, &hit); if(hit.efa == NULL) { - BKE_mesh_end_editmesh(obedit->data, em); + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } /* mark 2 edge vertices as being hit */ - for(i=0; i<4; i++) + BLI_array_growitems(hitv, hit.efa->len); + BLI_array_growitems(hituv, hit.efa->len); + for (i=0; i < hit.efa->len; i++) { 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); + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } /* make active */ - EM_set_actFace(em, hit.efa); + BM_active_face_set(em->bm, hit.efa); /* mark all face vertices as being hit */ - for(i=0; i<4; i++) - hituv[i]= hit.tf->uv[i]; - hitv[0]= hit.efa->v1->tmp.l; - hitv[1]= hit.efa->v2->tmp.l; - hitv[2]= hit.efa->v3->tmp.l; + BLI_array_growitems(hitv, hit.efa->len); + BLI_array_growitems(hituv, hit.efa->len); + 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); + hituv[i]= luv->uv; + hitv[i] = BM_elem_index_get(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) { uv_find_nearest_vert(scene, ima, em, co, NULL, &hit); if(hit.efa==NULL) { - BKE_mesh_end_editmesh(obedit->data, em); + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } + + hitlen = 0; } else { - BKE_mesh_end_editmesh(obedit->data, em); + hitlen = 0; + BLI_array_free(hitv); + BLI_array_free(hituv); return OPERATOR_CANCELLED; } @@ -1579,36 +1896,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; @@ -1616,109 +1933,101 @@ 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; - + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + /* 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_elem_index_get(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_elem_index_get(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_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) + uvedit_uv_select(em, scene, l); flush= 1; } } } } - + +#if 0 /* BM_elem_select_set API handles all of this? */ + 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); + else if(flush==-1) EDBM_deselect_flush(em); } } - - DAG_id_tag_update(obedit->data, 0); + +#endif + + 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); + + BLI_array_free(hitv); + BLI_array_free(hituv); + return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED; } @@ -1819,7 +2128,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; @@ -1827,7 +2136,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; } @@ -1858,7 +2166,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; } @@ -1923,31 +2230,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; - 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; + 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 (!(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; } @@ -1982,78 +2303,78 @@ 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_elem_flag_disable(eve, BM_ELEM_TAG); + } - 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_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } } } /* 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); */ /* UNUSED */ + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + 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; */ /* UNUSED */ 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 = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL); + for (efa_index=0; efa; efa=BM_iter_step(&iter), efa_index++) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ + + 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_elem_index_get(l->v)); while (vlist_iter) { if(vlist_iter->separate) @@ -2072,35 +2393,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); */ /* UNUSED */ if(select) - uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex); + uvedit_uv_select(em, scene, BM_iter_at_index(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, BM_iter_at_index(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_elem_flag_test(efa, BM_ELEM_TAG)) { 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) @@ -2111,9 +2430,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, extend; @@ -2147,14 +2469,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_elem_flag_disable(efa, BM_ELEM_TAG); + + 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_elem_flag_enable(efa, BM_ELEM_TAG); + change = 1; } } } @@ -2166,51 +2490,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, luv->uv[0], luv->uv[1])) { + if(select) uvedit_uv_select(em, scene, l); + else uvedit_uv_deselect(em, scene, l); } - 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((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); } } } @@ -2219,20 +2518,20 @@ static int border_select_exec(bContext *C, wmOperator *op) if(change) { /* make sure newly selected vert selection is updated*/ +#if 0 /* BM_elem_select_set 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); + if(select) EDBM_select_flush(em); + else EDBM_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; } @@ -2261,20 +2560,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); } } @@ -2283,10 +2584,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"); @@ -2308,21 +2611,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_elem_select_set 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; } @@ -2422,97 +2723,93 @@ 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)) copy_v2_v2(tface->uv[0], sima->cursor); - if(uvedit_uv_selected(scene, efa, tface, 1)) copy_v2_v2(tface->uv[1], sima->cursor); - if(uvedit_uv_selected(scene, efa, tface, 2)) copy_v2_v2(tface->uv[2], sima->cursor); - if(efa->v4) - if(uvedit_uv_selected(scene, efa, tface, 3)) copy_v2_v2(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); + copy_v2_v2(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; - + + /* BMESH_TODO - stop setting the index, bad juju + * not totally simple because 3 states and because the count is not + * based on the global vertex index :S - campbell */ + /* 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_elem_index_set(eve, -1); /* set_dirty! */ + em->bm->elem_index_dirty |= BM_VERT; /* 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_elem_flag_disable(efa, BM_ELEM_TAG); + continue; + } else { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + } + + change = 1; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (uvedit_uv_selected(em, scene, l) && BM_elem_index_get(l->v) == -1) { + BM_elem_index_set(l->v, count); /* set_dirty! */ + count++; + } } - else - efa->tmp.p = NULL; } + em->bm->elem_index_dirty |= BM_VERT; /* set above but include for completeness since they are made dirty again */ 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_elem_flag_test(efa, BM_ELEM_TAG)) + 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_elem_index_get(l->v) >= 0 && + (!uvedit_uv_selected(em, scene, l))) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + add_v2_v2(&coords[BM_elem_index_get(l->v) * 2], luv->uv); + change = 1; } } } @@ -2521,46 +2818,23 @@ 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_elem_flag_test(efa, BM_ELEM_TAG)) + 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_elem_index_get(l->v) >= 0 + && (users = usercount[BM_elem_index_get(l->v)])) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + copy_v2_v2(luv->uv, &coords[BM_elem_index_get(l->v) * 2]); } } } @@ -2568,43 +2842,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; } @@ -2667,35 +2939,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; } @@ -2722,26 +2993,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; } @@ -2765,122 +3038,76 @@ 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; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int hide = 0; - tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); - } + 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*/ + luv = 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 (!(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_elem_select_set(em->bm, efa, FALSE); + 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_elem_select_set(em->bm, efa, FALSE); + } + 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_elem_select_set(em->bm, l->v, FALSE); + 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; } @@ -2907,114 +3134,97 @@ 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; + BMIter iter, liter; + MLoopUV *luv; int facemode= sima ? sima->flag & SI_SELACTFACE : 0; int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1; - + /* 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_elem_select_set(em->bm, efa, TRUE); + 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + int totsel=0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + totsel += BM_elem_flag_test(l->v, BM_ELEM_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_elem_select_set(em->bm, efa, TRUE); } } } - } - 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)==0) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + } + + BM_elem_select_set(em->bm, efa, TRUE); } } } - - /* 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_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_elem_select_set(em->bm, efa, TRUE); } } - - /* 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_elem_flag_test(efa, BM_ELEM_HIDDEN) && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)==0) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + luv->flag |= MLOOPUV_VERTSEL; + } + } + + BM_elem_select_set(em->bm, efa, TRUE); } } - - /* 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; } @@ -3152,24 +3362,27 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op) UvVertMap *vmap; Object *ob = CTX_data_edit_object(C); Mesh *me= (Mesh*)ob->data; - EditMesh *em; - EditEdge *editedge; + BMEditMesh *em; + BMEdge *editedge; float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; char mark_seams = RNA_boolean_get(op->ptr, "mark_seams"); char mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp"); - em = BKE_mesh_get_editmesh(me); + BMesh *bm; + BMIter iter; - if(!EM_texFaceCheck(em)) { - BKE_mesh_end_editmesh(ob->data, em); + em = me->edit_btmesh; + bm = em->bm; + + if(!EDBM_texFaceCheck(em)) { return OPERATOR_CANCELLED; } /* This code sets editvert->tmp.l to the index. This will be useful later on. */ - 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(editedge = em->edges.first; editedge; editedge = editedge->next) { + BM_ITER(editedge, &iter, bm, BM_EDGES_OF_MESH, NULL) { /* flags to determine if we uv is separated from first editface match */ char separated1 = 0, separated2; /* set to denote edge must be flagged as seam */ @@ -3179,30 +3392,30 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op) /* For use with v1coincident. v1coincident will change only if we've had commonFaces */ int commonFaces = 0; - EditFace *efa1, *efa2; + BMFace *efa1, *efa2; UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter; /* mv2cache stores the first of the list of coincident uv's for later comparison * mv2sep holds the last separator and is copied to mv2cache when a hit is first found */ UvMapVert *mv2cache = NULL, *mv2sep = NULL; - mvinit1 = vmap->vert[editedge->v1->tmp.l]; + mvinit1 = vmap->vert[BM_elem_index_get(editedge->v1)]; if(mark_seams) - editedge->seam = 0; + BM_elem_flag_disable(editedge, BM_ELEM_SEAM); for(mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) { if(mv1->separate && commonFaces) v1coincident = 0; separated2 = 0; - efa1 = EM_get_face_for_index(mv1->f); - mvinit2 = vmap->vert[editedge->v2->tmp.l]; + efa1 = EDBM_get_face_for_index(em, mv1->f); + mvinit2 = vmap->vert[BM_elem_index_get(editedge->v2)]; for(mv2 = mvinit2; mv2; mv2 = mv2->next) { if(mv2->separate) mv2sep = mv2; - efa2 = EM_get_face_for_index(mv2->f); + efa2 = EDBM_get_face_for_index(em, mv2->f); if(efa1 == efa2) { /* if v1 is not coincident no point in comparing */ if(v1coincident) { @@ -3237,17 +3450,16 @@ static int seams_from_islands_exec(bContext *C, wmOperator *op) if(faces_separated) { if(mark_seams) - editedge->seam = 1; + BM_elem_flag_enable(editedge, BM_ELEM_SEAM); if(mark_sharp) - editedge->sharp = 1; + BM_elem_flag_disable(editedge, BM_ELEM_SMOOTH); } } me->drawflag |= ME_DRAWSEAMS; - EM_free_uv_vert_map(vmap); - EM_free_index_arrays(); - BKE_mesh_end_editmesh(me, em); + EDBM_free_uv_vert_map(vmap); + EDBM_free_index_arrays(em); DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); @@ -3279,16 +3491,19 @@ static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_edit_object(C); Scene *scene = CTX_data_scene(C); Mesh *me= (Mesh*)ob->data; - EditMesh *em= BKE_mesh_get_editmesh(me); - EditFace *efa; + BMEditMesh *em= me->edit_btmesh; + BMesh *bm = em->bm; + BMFace *efa; + BMLoop *loop; - for(efa = em->faces.first; efa; efa = efa->next) { - MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - int i, nverts = efa->v4? 4 : 3; + BMIter iter, liter; - for(i = 0; i < nverts; i++) - if(uvedit_edge_selected(scene, efa, mt, i)) - (*(&efa->e1 + i))->seam = 1; + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + BM_ITER(loop, &liter, bm, BM_LOOPS_OF_FACE, efa) { + if(uvedit_edge_selected(em, scene, loop)) { + BM_elem_flag_enable(loop, BM_ELEM_SEAM); + } + } } me->drawflag |= ME_DRAWSEAMS; @@ -3296,8 +3511,6 @@ static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op)) if(scene->toolsettings->edge_mode_live_unwrap) ED_unwrap_lscm(scene, ob, FALSE); - BKE_mesh_end_editmesh(me, em); - DAG_id_tag_update(&me->id, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, me); @@ -3338,7 +3551,9 @@ void ED_operatortypes_uvedit(void) WM_operatortype_append(UV_OT_snap_selected); WM_operatortype_append(UV_OT_align); + WM_operatortype_append(UV_OT_stitch); + WM_operatortype_append(UV_OT_seams_from_islands); WM_operatortype_append(UV_OT_mark_seam); WM_operatortype_append(UV_OT_weld); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index d651a17b624..68c8669ccc7 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -743,8 +743,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 2cb4759c5ae..5adb3074314 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_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index c012a23c175..70971e43409 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -50,6 +50,7 @@ #include "BKE_customdata.h" #include "BKE_depsgraph.h" #include "BKE_mesh.h" +#include "BKE_tessmesh.h" #include "ED_mesh.h" #include "ED_uvedit.h" @@ -116,7 +117,7 @@ typedef struct StitchState { /* stich at midpoints or at islands */ char midpoints; /* editmesh, cached for use in modal handler */ - EditMesh *em; + BMEditMesh *em; /* element map for getting info about uv connectivity */ UvElementMap *element_map; /* edge container */ @@ -162,21 +163,17 @@ static StitchPreviewer *_stitch_preview; static StitchPreviewer * stitch_preview_init(void) { _stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer"); - _stitch_preview->preview_quads = NULL; _stitch_preview->preview_tris = NULL; _stitch_preview->preview_stitchable = NULL; _stitch_preview->preview_unstitchable = NULL; - _stitch_preview->num_quads = 0; _stitch_preview->num_tris = 0; _stitch_preview->num_stitchable = 0; _stitch_preview->num_unstitchable = 0; - _stitch_preview->static_quads = NULL; _stitch_preview->static_tris = NULL; _stitch_preview->num_static_tris = 0; - _stitch_preview->num_static_quads = 0; return _stitch_preview; } @@ -186,10 +183,6 @@ static void stitch_preview_delete(void) { if(_stitch_preview) { - if(_stitch_preview->preview_quads){ - MEM_freeN(_stitch_preview->preview_quads); - _stitch_preview->preview_quads = NULL; - } if(_stitch_preview->preview_tris){ MEM_freeN(_stitch_preview->preview_tris); _stitch_preview->preview_tris = NULL; @@ -202,10 +195,6 @@ static void stitch_preview_delete(void) MEM_freeN(_stitch_preview->preview_unstitchable); _stitch_preview->preview_unstitchable = NULL; } - if(_stitch_preview->static_quads){ - MEM_freeN(_stitch_preview->static_quads); - _stitch_preview->static_quads = NULL; - } if(_stitch_preview->static_tris){ MEM_freeN(_stitch_preview->static_tris); _stitch_preview->static_tris = NULL; @@ -276,11 +265,17 @@ static int stitch_check_uvs_stitchable(UvElement *element, UvElement *element_it do_limit = state->use_limit; if(do_limit){ - MTFace *mtface_orig = CustomData_em_get(&state->em->fdata, element->face->data, CD_MTFACE); - MTFace *mtface_iter = CustomData_em_get(&state->em->fdata, element_iter->face->data, CD_MTFACE); + MLoopUV *luv_orig, *luv_iter; + BMLoop *l_orig, *l_iter; + + + l_orig = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv_orig = CustomData_bmesh_get(&state->em->bm->ldata, l_orig->head.data, CD_MLOOPUV); + l_iter = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element_iter->tfindex); + luv_iter = CustomData_bmesh_get(&state->em->bm->ldata, l_iter->head.data, CD_MLOOPUV); - if(fabs(mtface_orig->uv[element->tfindex][0] - mtface_iter->uv[element_iter->tfindex][0]) < limit - && fabs(mtface_orig->uv[element->tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < limit){ + if(fabs(luv_orig->uv[0] - luv_iter->uv[0]) < limit + && fabs(luv_orig->uv[1] - luv_iter->uv[1]) < limit){ return 1; }else return 0; @@ -301,8 +296,7 @@ static int stitch_check_uvs_state_stitchable(UvElement *element, UvElement *elem /* calculate snapping for islands */ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final){ int i; - EditFace *efa; - MTFace *mt; + BMFace *efa; UvElement *element; for(i = 0; i < state->element_map->totalIslands; i++){ @@ -322,15 +316,22 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer for(j = 0; j < numOfIslandUVs; j++, element++){ /* stitchable uvs have already been processed, don't process */ if(!(element->flag & STITCH_PROCESSED)){ + MLoopUV *luv; + BMLoop *l; + + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); + efa = element->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + if(final){ - stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, mt->uv[element->tfindex]); + stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, luv->uv); - mt->uv[element->tfindex][0] += island_stitch_data[i].translation[0]; - mt->uv[element->tfindex][1] += island_stitch_data[i].translation[1]; + luv->uv[0] += island_stitch_data[i].translation[0]; + luv->uv[1] += island_stitch_data[i].translation[1]; } + /* BMESH_TODO preview else if(efa->tmp.l != STITCH_NO_PREVIEW){ if(efa->v4){ @@ -346,7 +347,8 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer preview->preview_tris[efa->tmp.l + 2*element->tfindex] += island_stitch_data[i].translation[0]; preview->preview_tris[efa->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1]; } - } + }*/ + (void)preview; } /* cleanup */ element->flag &= STITCH_SELECTED; @@ -360,30 +362,28 @@ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map, IslandStitchData *island_stitch_data) { UvElement *element1, *element2; - EditFace *efa1; - EditFace *efa2; - MTFace *mt1; - MTFace *mt2; float uv1[2], uv2[2]; float edgecos, edgesin; int index1, index2; float rotation; + MLoopUV *luv1, *luv2; + BMLoop *l1, *l2; element1 = state->uvs[edge->uv1]; element2 = state->uvs[edge->uv2]; - efa1 = element1->face; - mt1 = CustomData_em_get(&state->em->fdata, efa1->data, CD_MTFACE); - efa2 = element2->face; - mt2 = CustomData_em_get(&state->em->fdata, efa2->data, CD_MTFACE); + l1 = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element1->face, element1->tfindex); + luv1 = CustomData_bmesh_get(&state->em->bm->ldata, l1->head.data, CD_MLOOPUV); + l2 = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element2->face, element2->tfindex); + luv2 = CustomData_bmesh_get(&state->em->bm->ldata, l2->head.data, CD_MLOOPUV); index1 = uvfinal_map[element1 - state->element_map->buf]; index2 = uvfinal_map[element2 - state->element_map->buf]; /* the idea here is to take the directions of the edges and find the rotation between final and initial * direction. This, using inner and outer vector products, gives the angle. Directions are differences so... */ - uv1[0] = mt2->uv[element2->tfindex][0] - mt1->uv[element1->tfindex][0]; - uv1[1] = mt2->uv[element2->tfindex][1] - mt1->uv[element1->tfindex][1]; + uv1[0] = luv2->uv[0] - luv1->uv[0]; + uv1[1] = luv2->uv[1] - luv1->uv[1]; uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0]; uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1]; @@ -407,11 +407,14 @@ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchStat int index; UvElement *element_iter; float rotation = 0; + BMLoop *l; if(element->island == state->static_island && !state->midpoints) return; - index = (*(&element->face->v1 + element->tfindex))->tmp.l; + l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex); + + index = BM_elem_index_get(l->v); element_iter = state->element_map->vert[index]; @@ -444,7 +447,7 @@ static void stitch_state_delete(StitchState *stitch_state) { if(stitch_state){ if(stitch_state->element_map){ - EM_free_uv_element_map(stitch_state->element_map); + EDBM_free_uv_element_map(stitch_state->element_map); } if(stitch_state->uvs){ MEM_freeN(stitch_state->uvs); @@ -477,8 +480,11 @@ static void stitch_state_delete(StitchState *stitch_state) static void determine_uv_stitchability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){ int vert_index; UvElement *element_iter; + BMLoop *l; + + l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex); - vert_index = (*(&element->face->v1 + element->tfindex))->tmp.l; + vert_index = BM_elem_index_get(l->v); element_iter = state->element_map->vert[vert_index]; for(; element_iter; element_iter = element_iter->next){ @@ -497,24 +503,23 @@ static void determine_uv_stitchability(UvElement *element, StitchState *state, I /* set preview buffer position of UV face in editface->tmp.l */ -static void stitch_set_face_preview_buffer_position(EditFace *efa, StitchPreviewer *preview) +static void stitch_set_face_preview_buffer_position(BMFace *efa, StitchPreviewer *preview, unsigned int *preview_position) { - if(efa->tmp.l == STITCH_NO_PREVIEW) + int index = BM_elem_index_get(efa); + + if(preview_position[index] == STITCH_NO_PREVIEW) { - if(efa->v4) - { - efa->tmp.l = preview->num_quads*8; - preview->num_quads++; - } else { - efa->tmp.l = preview->num_tris*6; - preview->num_tris++; - } + preview_position[index] = preview->num_tris*6; + + /* BMESH_TODO, count per face triangles */ + //preview->num_tris += 4; } } /* setup face preview for all coincident uvs and their faces */ -static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){ +static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data, + unsigned int *preview_position){ StitchPreviewer *preview = uv_get_stitch_previewer(); /* static island does not change so returning immediately */ @@ -526,19 +531,26 @@ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchSta } do{ - stitch_set_face_preview_buffer_position(element->face, preview); + stitch_set_face_preview_buffer_position(element->face, preview, preview_position); element = element->next; }while(element && !element->separate); } /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */ -static void stitch_validate_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){ +static void stitch_validate_stichability (UvElement *element, StitchState *state, IslandStitchData *island_stitch_data, + unsigned int *preview_position){ UvElement *element_iter; StitchPreviewer *preview; + int vert_index; + BMLoop *l; + + l = BM_iter_at_index(NULL, BM_LOOPS_OF_FACE, element->face, element->tfindex); + + vert_index = BM_elem_index_get(l->v); preview = uv_get_stitch_previewer(); - element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l]; + element_iter = state->element_map->vert[vert_index]; for(; element_iter; element_iter = element_iter->next){ if(element_iter->separate){ @@ -548,7 +560,7 @@ static void stitch_validate_stichability(UvElement *element, StitchState *state, if((element_iter->island == state->static_island) || (element->island == state->static_island)){ element->flag |= STITCH_STITCHABLE; preview->num_stitchable++; - stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data); + stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data, preview_position); return; } } @@ -568,21 +580,25 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) StitchPreviewer *preview; IslandStitchData *island_stitch_data = NULL; int previous_island = state->static_island; - EditFace *efa; - EditVert *ev; + BMFace *efa; + BMIter iter; UVVertAverage *final_position; char stitch_midpoints = state->midpoints; /* used to map uv indices to uvaverage indices for selection */ unsigned int *uvfinal_map; + /* per face preview position in preview buffer */ + unsigned int *preview_position; /* cleanup previous preview */ stitch_preview_delete(); preview = stitch_preview_init(); if(preview == NULL) return 0; + + preview_position = MEM_mallocN(state->em->bm->totface*sizeof(*preview_position), "stitch_face_preview_position"); /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */ - for(efa = state->em->faces.first; efa; efa = efa->next){ - efa->tmp.l = STITCH_NO_PREVIEW; + for(i = 0; i < state->em->bm->totface; i++){ + preview_position[i] = STITCH_NO_PREVIEW; } island_stitch_data = MEM_callocN(sizeof(*island_stitch_data)*state->element_map->totalIslands, "stitch_island_data"); @@ -590,10 +606,8 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) return 0; } - /* store indices to editVerts. */ - for(ev = state->em->verts.first, i = 0; ev; ev = ev->next, i++){ - ev->tmp.l = i; - } + /* store indices to editVerts and Faces. May be unneeded but ensuring anyway */ + BM_mesh_elem_index_ensure(state->em->bm, BM_VERT | BM_FACE); /***************************************** * First determine stitchability of uvs * @@ -618,7 +632,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) UvElement *element = state->selection_stack[i]; if(element->flag & STITCH_STITCHABLE_CANDIDATE){ element->flag &= ~STITCH_STITCHABLE_CANDIDATE; - stitch_validate_stichability(element, state, island_stitch_data); + stitch_validate_stichability(element, state, island_stitch_data, preview_position); }else{ /* add to preview for unstitchable */ preview->num_unstitchable++; @@ -636,7 +650,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); element = &state->element_map->buf[state->element_map->islandIndices[i]]; for(j = 0; j < numOfIslandUVs; j++, element++){ - stitch_set_face_preview_buffer_position(element->face, preview); + stitch_set_face_preview_buffer_position(element->face, preview, preview_position); } } } @@ -646,47 +660,42 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) * Setup the preview buffers and fill them with the appropriate data * *********************************************************************/ if(!final){ - unsigned int tricount = 0, quadcount = 0; + BMLoop *l; + MLoopUV *luv; + unsigned int tricount = 0; int stitchBufferIndex = 0, unstitchBufferIndex = 0; /* initialize the preview buffers */ - preview->preview_quads = (float *)MEM_mallocN(preview->num_quads*sizeof(float)*8, "quad_uv_stitch_prev"); preview->preview_tris = (float *)MEM_mallocN(preview->num_tris*sizeof(float)*6, "tri_uv_stitch_prev"); preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable*sizeof(float)*2, "stitch_preview_stichable_data"); preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable*sizeof(float)*2, "stitch_preview_unstichable_data"); - preview->static_quads = (float *)MEM_mallocN(state->quads_per_island[state->static_island]*sizeof(float)*8, "static_island_preview_quads"); preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island]*sizeof(float)*6, "static_island_preview_tris"); - preview->num_static_quads = state->quads_per_island[state->static_island]; preview->num_static_tris = state->tris_per_island[state->static_island]; /* will cause cancel and freeing of all data structures so OK */ - if(!preview->preview_quads || !preview->preview_tris || !preview->preview_stitchable || !preview->preview_unstitchable){ + if(!preview->preview_tris || !preview->preview_stitchable || !preview->preview_unstitchable){ return 0; } /* copy data from MTFaces to the preview display buffers */ - for(efa = state->em->faces.first; efa; efa = efa->next){ - MTFace *mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + BM_ITER(efa, &iter, state->em->bm, BM_FACES_OF_MESH, NULL) { + /* just to test if face was added for processing. uvs of inselected vertices will return NULL */ UvElement *element = ED_get_uv_element(state->element_map, efa, 0); if(element){ - if(efa->tmp.l != STITCH_NO_PREVIEW){ - if(efa->v4) { - memcpy(preview->preview_quads+efa->tmp.l, &mt->uv[0][0], 8*sizeof(float)); - } else { - memcpy(preview->preview_tris+efa->tmp.l, &mt->uv[0][0], 6*sizeof(float)); - } + int index = BM_elem_index_get(efa); + + if(preview_position[index] != STITCH_NO_PREVIEW){ + /* BMESH_TODO preview */ + //memcpy(preview->preview_tris+efa->tmp.l, &mt->uv[0][0], 6*sizeof(float)); } if(element->island == state->static_island){ - if(efa->v4) { - memcpy(preview->static_quads + quadcount*8, &mt->uv[0][0], 8*sizeof(float)); - quadcount++; - } else { - memcpy(preview->static_tris + tricount*6, &mt->uv[0][0], 6*sizeof(float)); - tricount++; - } + /* BMESH_TODO preview */ + //memcpy(preview->static_tris + tricount*6, &mt->uv[0][0], 6*sizeof(float)); + //tricount++; + (void)tricount; } } } @@ -695,21 +704,18 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) for(i = 0; i < state->total_separate_uvs; i++){ UvElement *element = (UvElement *)state->uvs[i]; if(element->flag & STITCH_STITCHABLE){ - MTFace *mt; - efa = element->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); + + copy_v2_v2(&preview->preview_stitchable[stitchBufferIndex*2], luv->uv); - preview->preview_stitchable[stitchBufferIndex*2] = mt->uv[element->tfindex][0]; - preview->preview_stitchable[stitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1]; stitchBufferIndex++; } else if(element->flag & STITCH_SELECTED){ - MTFace *mt; - efa = element->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); - preview->preview_unstitchable[unstitchBufferIndex*2] = mt->uv[element->tfindex][0]; - preview->preview_unstitchable[unstitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1]; + copy_v2_v2(&preview->preview_unstitchable[unstitchBufferIndex*2], luv->uv); unstitchBufferIndex++; } } @@ -726,39 +732,37 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) for(i = 0; i < state->selection_size; i++){ UvElement *element = state->selection_stack[i]; if(element->flag & STITCH_STITCHABLE){ - MTFace *mt; - + BMLoop *l; + MLoopUV *luv; UvElement *element_iter; - uvfinal_map[element - state->element_map->buf] = i; + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); + - efa = element->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + uvfinal_map[element - state->element_map->buf] = i; - final_position[i].uv[0] = mt->uv[element->tfindex][0]; - final_position[i].uv[1] = mt->uv[element->tfindex][1]; + copy_v2_v2(final_position[i].uv, luv->uv); final_position[i].count = 1; if(state->snap_islands && element->island == state->static_island && !stitch_midpoints) continue; - element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l]; + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; for(;element_iter; element_iter = element_iter->next){ if(element_iter->separate){ if(stitch_check_uvs_state_stitchable(element, element_iter, state)){ - efa = element_iter->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element_iter->face, element_iter->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); if(stitch_midpoints){ - final_position[i].uv[0] += mt->uv[element_iter->tfindex][0]; - final_position[i].uv[1] += mt->uv[element_iter->tfindex][1]; + add_v2_v2(final_position[i].uv, luv->uv); final_position[i].count++; }else if(element_iter->island == state->static_island){ /* if multiple uvs on the static island exist, * last checked remains. to disambiguate we need to limit or use * edge stitch */ - final_position[i].uv[0] = mt->uv[element_iter->tfindex][0]; - final_position[i].uv[1] = mt->uv[element_iter->tfindex][1]; + copy_v2_v2(final_position[i].uv, luv->uv); } } } @@ -775,16 +779,18 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) for(i = 0; i < state->selection_size; i++){ UvElement *element = state->selection_stack[i]; if(element->flag & STITCH_STITCHABLE){ - MTFace *mt; - efa = element->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + BMLoop *l; + MLoopUV *luv; + + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); /* accumulate each islands' translation from stitchable elements. it is important to do here * because in final pass MTFaces get modified and result is zero. */ - island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - mt->uv[element->tfindex][0]; - island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - mt->uv[element->tfindex][1]; - island_stitch_data[element->island].medianPoint[0] += mt->uv[element->tfindex][0]; - island_stitch_data[element->island].medianPoint[1] += mt->uv[element->tfindex][1]; + island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - luv->uv[0]; + island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - luv->uv[1]; + island_stitch_data[element->island].medianPoint[0] += luv->uv[0]; + island_stitch_data[element->island].medianPoint[1] += luv->uv[1]; island_stitch_data[element->island].numOfElements++; } } @@ -816,26 +822,23 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) UvElement *element_iter = element; /* propagate to coincident uvs */ do{ - MTFace *mt; + BMLoop *l; + MLoopUV *luv; - efa = element_iter->face; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element_iter->face, element_iter->tfindex); + luv = CustomData_bmesh_get(&state->em->bm->ldata, l->head.data, CD_MLOOPUV); element_iter->flag |= STITCH_PROCESSED; /* either flush to preview or to the MTFace, if final */ if(final){ - mt->uv[element_iter->tfindex][0] = final_position[i].uv[0]; - mt->uv[element_iter->tfindex][1] = final_position[i].uv[1]; - - uvedit_uv_select(scene, efa, mt, element_iter->tfindex); - }else if(efa->tmp.l != STITCH_NO_PREVIEW){ - if(efa->v4){ - *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0]; - *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1]; - }else{ - *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0]; - *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1]; - } + copy_v2_v2(luv->uv, final_position[i].uv); + + uvedit_uv_select(state->em, scene, l); + }else if(preview_position[BM_elem_index_get(element_iter->face)] != STITCH_NO_PREVIEW){ + /* BMESH_TODO: preview for stitch + *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0]; + *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1]; + */ } /* end of calculations, keep only the selection flag */ @@ -856,6 +859,7 @@ static int stitch_process_data(StitchState *state, Scene *scene, int final) MEM_freeN(final_position); MEM_freeN(uvfinal_map); MEM_freeN(island_stitch_data); + MEM_freeN(preview_position); return 1; } @@ -880,13 +884,15 @@ static int uv_edge_compare(const void *a, const void *b){ /* Select all common uvs */ -static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int always_select) +static void stitch_select_uv(UvElement *element, StitchState *state, int always_select) { - /* This works due to setting of tmp in find nearest uv vert */ + BMLoop *l; UvElement *element_iter; - UvElement **selection_stack = stitch_state->selection_stack; + UvElement **selection_stack = state->selection_stack; + + l = BM_iter_at_index(state->em->bm, BM_LOOPS_OF_FACE, element->face, element->tfindex); - element_iter = stitch_state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l]; + element_iter = state->element_map->vert[BM_elem_index_get(l->v)]; /* first deselect all common uvs */ for(; element_iter; element_iter = element_iter->next){ if(element_iter->separate){ @@ -897,26 +903,29 @@ static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int continue; element_iter->flag &= ~STITCH_SELECTED; - for(i = 0; i < stitch_state->selection_size; i++){ + for(i = 0; i < state->selection_size; i++){ if(selection_stack[i] == element_iter){ - (stitch_state->selection_size)--; - selection_stack[i] = selection_stack[stitch_state->selection_size]; + (state->selection_size)--; + selection_stack[i] = selection_stack[state->selection_size]; break; } } }else{ element_iter->flag |= STITCH_SELECTED; - selection_stack[(stitch_state->selection_size)++] = element_iter; + selection_stack[state->selection_size++] = element_iter; } } } } -static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *normal) +static void stitch_calculate_edge_normal(BMEditMesh *em, UvEdge *edge, float *normal) { + /* BMESH_TODO need a way to disambiguate between normals for bmesh. */ +#if 0 UvElement *element = edge->element; - EditFace *efa = element->face; + BMFace *efa = element->face; MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); + int nverts = efa->v4?4 : 3; int index = (element->tfindex + 2)%nverts; float tangent[2], internal[2]; @@ -924,17 +933,20 @@ static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *norm sub_v2_v2v2(tangent, mt->uv[(element->tfindex + 1)%nverts], mt->uv[element->tfindex]); sub_v2_v2v2(internal, mt->uv[index], mt->uv[element->tfindex]); - /* choose one of the normals */ normal[0] = tangent[1]; normal[1] = -tangent[0]; - /* if normal points inside the face, invert */ if(dot_v2v2(normal, internal) > 0){ normal[0] = -tangent[1]; normal[1] = tangent[0]; } normalize_v2(normal); +#else + (void)em; + (void)edge; + (void)normal; +#endif } static int stitch_init(bContext *C, wmOperator *op) @@ -947,8 +959,10 @@ static int stitch_init(bContext *C, wmOperator *op) /* maps uvelements to their first coincident uv */ int *map; int counter = 0, i; - EditFace *efa; - EditMesh *em; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + BMEditMesh *em; GHashIterator* ghi; UvEdge *all_edges; StitchState *state = MEM_mallocN(sizeof(StitchState), "stitch state"); @@ -965,15 +979,15 @@ static int stitch_init(bContext *C, wmOperator *op) /* initialize state */ state->use_limit = RNA_boolean_get(op->ptr, "use_limit"); state->limit_dist = RNA_float_get(op->ptr, "limit"); - state->em = em = BKE_mesh_get_editmesh((Mesh*)obedit->data); + state->em = em = ((Mesh *)obedit->data)->edit_btmesh; state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands"); state->static_island = RNA_int_get(op->ptr, "static_island"); state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap"); /* in uv synch selection, all uv's are visible */ if(ts->uv_flag & UV_SYNC_SELECTION){ - state->element_map = EM_make_uv_element_map(state->em, 0, 1); + state->element_map = EDBM_make_uv_element_map(state->em, 0, 1); }else{ - state->element_map = EM_make_uv_element_map(state->em, 1, 1); + state->element_map = EDBM_make_uv_element_map(state->em, 1, 1); } if(!state->element_map){ stitch_state_delete(state); @@ -1013,7 +1027,7 @@ static int stitch_init(bContext *C, wmOperator *op) /* So that we can use this as index for the UvElements */ counter = -1; /* initialize the unique UVs and map */ - for(i = 0; i < state->em->totvert; i++){ + for(i = 0; i < em->bm->totvert; i++){ UvElement *element = state->element_map->vert[i]; for(; element; element = element->next){ if(element->separate){ @@ -1025,42 +1039,48 @@ static int stitch_init(bContext *C, wmOperator *op) } } + counter = 0; /* Now, on to generate our uv connectivity data */ - for(efa = state->em->faces.first, counter = 0; efa; efa = efa->next){ - if((ts->uv_flag & UV_SYNC_SELECTION) || (!efa->h && efa->f & SELECT)){ - int nverts = efa->v4 ? 4 : 3; - - for(i = 0; i < nverts; i++){ - UvElement *element = ED_get_uv_element(state->element_map, efa, i); - int offset1, itmp1 = element - state->element_map->buf; - int offset2, itmp2 = ED_get_uv_element(state->element_map, efa, (i+1)%nverts) - state->element_map->buf; - - offset1 = map[itmp1]; - offset2 = map[itmp2]; - - all_edges[counter].flag = 0; - all_edges[counter].element = element; - /* using an order policy, sort uvs according to address space. This avoids - * Having two different UvEdges with the same uvs on different positions */ - if(offset1 < offset2){ - all_edges[counter].uv1 = offset1; - all_edges[counter].uv2 = offset2; - } - else{ - all_edges[counter].uv1 = offset2; - all_edges[counter].uv2 = offset1; - } + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + int nverts; + + if (!(ts->uv_flag & UV_SYNC_SELECTION) && ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !BM_elem_flag_test(efa, BM_ELEM_SELECT))) + continue; + + nverts = efa->len; + i = 0; + + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + UvElement *element = ED_get_uv_element(state->element_map, efa, i); + int offset1, itmp1 = element - state->element_map->buf; + int offset2, itmp2 = ED_get_uv_element(state->element_map, efa, (i+1)%nverts) - state->element_map->buf; + + offset1 = map[itmp1]; + offset2 = map[itmp2]; + + all_edges[counter].flag = 0; + all_edges[counter].element = element; + /* using an order policy, sort uvs according to address space. This avoids + * Having two different UvEdges with the same uvs on different positions */ + if(offset1 < offset2){ + all_edges[counter].uv1 = offset1; + all_edges[counter].uv2 = offset2; + } + else{ + all_edges[counter].uv1 = offset2; + all_edges[counter].uv2 = offset1; + } - if(BLI_ghash_haskey(edgeHash, &all_edges[counter])){ - char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]); - *flag = 0; - } - else{ - BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag)); - all_edges[counter].flag = STITCH_BOUNDARY; - } - counter++; + if(BLI_ghash_haskey(edgeHash, &all_edges[counter])){ + char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]); + *flag = 0; } + else{ + BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag)); + all_edges[counter].flag = STITCH_BOUNDARY; + } + counter++; + i++; } } @@ -1126,34 +1146,30 @@ static int stitch_init(bContext *C, wmOperator *op) int faceIndex, elementIndex; UvElement *element; - EM_init_index_arrays(em, 0, 0, 1); - + EDBM_init_index_arrays(em, 0, 0, 1); - RNA_BEGIN(op->ptr, itemptr, "selection") { - faceIndex = RNA_int_get(&itemptr, "face_index"); - elementIndex = RNA_int_get(&itemptr, "element_index"); - efa = EM_get_face_for_index(faceIndex); - element = ED_get_uv_element(state->element_map, efa, elementIndex); - stitch_select_uv(element, state, 1); - } - RNA_END; + RNA_BEGIN(op->ptr, itemptr, "selection") { + faceIndex = RNA_int_get(&itemptr, "face_index"); + elementIndex = RNA_int_get(&itemptr, "element_index"); + efa = EDBM_get_face_for_index(em, faceIndex); + element = ED_get_uv_element(state->element_map, efa, elementIndex); + stitch_select_uv(element, state, 1); + } + RNA_END; - EM_free_index_arrays(); + EDBM_free_index_arrays(em); /* Clear the selection */ RNA_collection_clear(op->ptr, "selection"); } else { - for(efa = state->em->faces.first ; efa; efa = efa->next){ - int numOfVerts; - MTFace *mt; - mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE); - numOfVerts = efa->v4 ? 4 : 3; - - for(i = 0; i < numOfVerts; i++){ - if(uvedit_uv_selected(scene, efa, mt, i)){ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { + i = 0; + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if(uvedit_uv_selected(em, scene, l)){ UvElement *element = ED_get_uv_element(state->element_map, efa, i); stitch_select_uv(element, state, 1); } + i++; } } } @@ -1169,16 +1185,12 @@ static int stitch_init(bContext *C, wmOperator *op) state->tris_per_island[i] = 0; } - for(efa = state->em->faces.first; efa; efa = efa->next){ + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { UvElement *element = ED_get_uv_element(state->element_map, efa, 0); if(element){ - if(efa->v4){ - state->quads_per_island[element->island]++; - } - else { - state->tris_per_island[element->island]++; - } + /* BMESH_TODO preview active island */ + //state->tris_per_island[element->island]++; } } @@ -1217,7 +1229,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished) stitch_state = (StitchState *)op->customdata; if(finished){ - EditFace *efa; int i; RNA_float_set(op->ptr, "limit", stitch_state->limit_dist); @@ -1226,10 +1237,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished) RNA_int_set(op->ptr, "static_island", stitch_state->static_island); RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoints); - for(i = 0, efa = stitch_state->em->faces.first; efa; efa = efa->next, i++){ - efa->tmp.l = i; - } - /* Store selection for re-execution of stitch */ for(i = 0; i < stitch_state->selection_size; i++){ PointerRNA itemptr; @@ -1237,7 +1244,7 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished) RNA_collection_add(op->ptr, "selection", &itemptr); - RNA_int_set(&itemptr, "face_index", element->face->tmp.l); + RNA_int_set(&itemptr, "face_index", BM_elem_index_get(element->face)); RNA_int_set(&itemptr, "element_index", element->tfindex); } @@ -1250,7 +1257,6 @@ static void stitch_exit(bContext *C, wmOperator *op, int finished) DAG_id_tag_update(obedit->data, 0); WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); - BKE_mesh_end_editmesh(obedit->data, stitch_state->em); stitch_state_delete(stitch_state); op->customdata = NULL; @@ -1297,7 +1303,7 @@ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */ /* This works due to setting of tmp in find nearest uv vert */ - UvElement *element = ED_get_uv_element(stitch_state->element_map, hit.efa, hit.uv); + UvElement *element = ED_get_uv_element(stitch_state->element_map, hit.efa, hit.lindex); stitch_select_uv(element, stitch_state, 0); } @@ -1467,5 +1473,3 @@ void UV_OT_stitch(wmOperatorType *ot) /* Selection should not be editable or viewed in toolbar */ RNA_def_property_flag(prop, PROP_HIDDEN); } - - diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index f3569639454..6d15d023fbe 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -42,11 +42,13 @@ #include "DNA_scene_types.h" #include "DNA_modifier_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 "BLI_string.h" #include "BKE_cdderivedmesh.h" @@ -58,6 +60,14 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_report.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" @@ -80,9 +90,9 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) { Main *bmain= CTX_data_main(C); - 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; @@ -90,15 +100,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_data_layer_add(em->bm, &em->bm->pdata, CD_MTEXPOLY); + BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV); + } + if(!ED_uvedit_test(obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return 0; } @@ -128,70 +138,69 @@ static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit) ED_uvedit_assign_image(bmain, 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) { - EditFace *efa; - MTFace *tf; - + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + /* verify if we have any selected uv's before unwrapping, so we can cancel the operator early */ - for(efa= em->faces.first; efa; efa= efa->next) { + BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) { if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - if(efa->h) + if(BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) continue; } - else if((efa->h) || ((efa->f & SELECT)==0)) + else if(BM_elem_flag_test(efa, BM_ELEM_HIDDEN) || !BM_elem_flag_test(efa, BM_ELEM_SELECT)) continue; - - tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - if(!tf) - return 1; /* default selected if doesn't exists */ + + 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) + return 1; + + if (uvedit_uv_selected(em, scene, l)) + break; + } - 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)) ) - ) { + if (implicit && !l) continue; - } - + return 1; } return 0; } -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; - int a; + BMFace *efa; + BMLoop *l; + BMEdge *eed; + BMIter iter, liter; + MTexPoly *tf; handle = param_construct_begin(); if(correct_aspect) { - efa = EM_get_actFace(em, 1); + efa = BM_active_face_get(em->bm, TRUE); if(efa) { float aspx, aspy; - 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); @@ -201,71 +210,108 @@ 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; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); - 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; - - if((efa->h) || (sel && (efa->f & SELECT)==0)) - continue; + int lsel; - tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - - 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)) ) - ) { + if((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT)==0)) continue; + + /* tf= (MTexPoly *)CustomData_em_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */ + 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; + 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; + + /*scanfill time!*/ + BLI_begin_edgefill(); + + 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; + } + + 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_elem_index_get(ls[0]->v); + vkeys[1] = (ParamKey)BM_elem_index_get(ls[1]->v); + vkeys[2] = (ParamKey)BM_elem_index_get(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_elem_flag_test(eed, BM_ELEM_SEAM)) { ParamKey vkeys[2]; - vkeys[0] = (ParamKey)eed->v1->tmp.l; - vkeys[1] = (ParamKey)eed->v2->tmp.l; + vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1); + vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2); param_edge_set_seam(handle, vkeys); } } @@ -277,9 +323,11 @@ static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short imp } -static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene) +static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene, BMEditMesh *em) { - int i, nverts = (editFace->v4)? 4: 3; + BMLoop *l; + BMIter liter; + MLoopUV *luv; *uv = NULL; *pin = 0; @@ -288,29 +336,28 @@ static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int if(index == ORIGINDEX_NONE) return; - for(i = 0; i < nverts; i++) { - if((*(&editFace->v1 + i))->tmp.t == index) { - *uv = texFace->uv[i]; - *pin = ((texFace->unwrap & TF_PIN_MASK(i)) != 0); - *select = (uvedit_uv_selected(scene, editFace, texFace, i) != 0); + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) { + if(BM_elem_index_get(l->v) == index) { + luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV); + *uv = luv->uv; + *pin = (luv->flag & MLOOPUV_PINNED)? 1 : 0; + *select = (uvedit_uv_selected(em, scene, l) != 0); } } } -/* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above) +/* unwrap handle initialisation for subsurf aware-unwrapper. The many modifications required to make the original function(see above) * work justified the existence of a new function. */ -static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short fill, short sel, short correct_aspect) +static ParamHandle *construct_param_handle_subsurfed(Scene *scene, BMEditMesh *em, short fill, short sel, short correct_aspect) { ParamHandle *handle; /* index pointers */ MFace *face; MEdge *edge; - EditVert *editVert; - EditFace *editFace, **editFaceTmp; - EditEdge *editEdge, **editEdgeTmp; + BMFace *editFace; int i; - /* modifier initialization data, will control what type of subdivision will happen*/ + /* modifier initialisation data, will control what type of subdivision will happen*/ SubsurfModifierData smd = {{0}}; /* Used to hold subsurfed Mesh */ DerivedMesh *derivedMesh, *initialDerived; @@ -320,29 +367,26 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi MVert *subsurfedVerts; MEdge *subsurfedEdges; MFace *subsurfedFaces; - /* MTFace *subsurfedTexfaces; */ /* UNUSED */ /* number of vertices and faces for subsurfed mesh*/ int numOfEdges, numOfFaces; /* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */ - EditFace **faceMap; - /* Mini container to hold all EditFaces so that they may be indexed easily and fast. */ - EditFace **editFaceArray; + BMFace **faceMap; /* similar to the above, we need a way to map edges to their original ones */ - EditEdge **edgeMap; - EditEdge **editEdgeArray; + BMEdge **edgeMap; handle = param_construct_begin(); if(correct_aspect) { - EditFace *eface = EM_get_actFace(editMesh, 1); + editFace = BM_active_face_get(em->bm, TRUE); - if(eface) { + if(editFace) { + MTexPoly *tf; float aspx, aspy; - MTFace *texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE); + tf= CustomData_bmesh_get(&em->bm->pdata, editFace->head.data, CD_MTEXPOLY); + + ED_image_uv_aspect(tf->tpage, &aspx, &aspy); - ED_image_uv_aspect(texface->tpage, &aspx, &aspy); - if(aspx!=aspy) param_aspect_ratio(handle, aspx, aspy); } @@ -352,7 +396,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi smd.levels = scene->toolsettings->uv_subsurf_level; smd.subdivType = ME_CC_SUBSURF; - initialDerived = CDDM_from_editmesh(editMesh, NULL); + initialDerived = CDDM_from_BMEditMesh(em, NULL, 0, 0); derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, 0, NULL, 0, 0, 1); @@ -361,49 +405,34 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi /* get the derived data */ subsurfedVerts = derivedMesh->getVertArray(derivedMesh); subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh); - subsurfedFaces = derivedMesh->getFaceArray(derivedMesh); + subsurfedFaces = derivedMesh->getTessFaceArray(derivedMesh); origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX); origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX); - origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX); - - /* subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE); */ /* UNUSED */ + origFaceIndices = derivedMesh->getTessFaceDataArray(derivedMesh, CD_ORIGINDEX); numOfEdges = derivedMesh->getNumEdges(derivedMesh); - numOfFaces = derivedMesh->getNumFaces(derivedMesh); + numOfFaces = derivedMesh->getNumTessFaces(derivedMesh); faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map"); - editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray"); - /* fill edit face array with edit faces */ - for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++) - *editFaceTmp = editFace; + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + EDBM_init_index_arrays(em, 0, 1, 1); /* map subsurfed faces to original editFaces */ for(i = 0; i < numOfFaces; i++) - faceMap[i] = editFaceArray[origFaceIndices[i]]; - - MEM_freeN(editFaceArray); + faceMap[i] = EDBM_get_face_for_index(em, origFaceIndices[i]); edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map"); - editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray"); - - /* fill edit edge array with edit edges */ - for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++) - *editEdgeTmp = editEdge; /* map subsurfed edges to original editEdges */ for(i = 0; i < numOfEdges; i++) { /* not all edges correspond to an old edge */ edgeMap[i] = (origEdgeIndices[i] != -1)? - editEdgeArray[origEdgeIndices[i]] : NULL; + EDBM_get_edge_for_index(em, origEdgeIndices[i]) : NULL; } - MEM_freeN(editEdgeArray); - - /* we need the editvert indices too */ - for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++) - editVert->tmp.t = i; + EDBM_free_index_arrays(em); /* Prepare and feed faces to the solver */ for(i = 0; i < numOfFaces; i++) { @@ -411,23 +440,19 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi ParamBool pin[4], select[4]; float *co[4]; float *uv[4]; - EditFace *origFace = faceMap[i]; - MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE); + BMFace *origFace = faceMap[i]; face = subsurfedFaces+i; if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) { - if(origFace->h) + if(BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) continue; } else { - if((origFace->h) || (sel && (origFace->f & SELECT)==0)) + if(BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) || (sel && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) continue; } - /* Now we feed the rest of the data from the subsurfed faces */ - /* texface= subsurfedTexfaces+i; */ /* UNUSED */ - /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */ key = (ParamKey)face; vkeys[0] = (ParamKey)face->v1; @@ -442,17 +467,17 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus * flushing the solution to the edit mesh. */ - texface_from_original_index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene); - texface_from_original_index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene); - texface_from_original_index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene); - texface_from_original_index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene); + texface_from_original_index(origFace, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene, em); + texface_from_original_index(origFace, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene, em); + texface_from_original_index(origFace, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene, em); + texface_from_original_index(origFace, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene, em); param_face_add(handle, key, 4, vkeys, co, uv, pin, select); } /* these are calculated from original mesh too */ for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) { - if((edgeMap[i] != NULL) && edgeMap[i]->seam) { + if((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) { ParamKey vkeys[2]; vkeys[0] = (ParamKey)edge->v1; vkeys[1] = (ParamKey)edge->v2; @@ -475,7 +500,7 @@ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *edi typedef struct MinStretch { Scene *scene; Object *obedit; - EditMesh *em; + BMEditMesh *em; ParamHandle *handle; float blend; double lasttime; @@ -487,13 +512,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; } @@ -674,12 +698,9 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) ot->poll= ED_operator_uvedit; /* properties */ - RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", - "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry"); - RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", - "Blend factor between stretch minimized and original", 0.0f, 1.0f); - RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", - "Number of iterations to run, 0 is unlimited when run interactively", 0, 100); + RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry"); + RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f); + RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100); } /* ******************** Pack Islands operator **************** */ @@ -688,12 +709,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; } @@ -712,7 +732,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; } @@ -728,8 +747,7 @@ void UV_OT_pack_islands(wmOperatorType *ot) ot->poll= ED_operator_uvedit; /* properties */ - RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", - "Space between islands", 0.0f, 1.0f); + RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } /* ******************** Average Islands Scale operator **************** */ @@ -738,12 +756,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; } @@ -755,7 +772,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; } @@ -777,13 +793,12 @@ 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; short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF; if(!ED_uvedit_test(obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); return; } @@ -793,7 +808,6 @@ void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit) liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1); param_lscm_begin(liveHandle, PARAM_TRUE, abf); - BKE_mesh_end_editmesh(obedit->data, em); } void ED_uvedit_live_unwrap_re_solve(void) @@ -824,9 +838,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; @@ -836,13 +853,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_elem_flag_test(efa, BM_ELEM_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); @@ -917,7 +933,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 */ @@ -944,7 +960,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) @@ -970,14 +985,17 @@ static void uv_transform_properties(wmOperatorType *ot, int 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= BM_active_face_get(em->bm, TRUE); + 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); } @@ -987,30 +1005,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_elem_flag_test(efa, BM_ELEM_SELECT) || BM_elem_flag_test(efa, BM_ELEM_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_elem_flag_test(efa, BM_ELEM_SELECT)||BM_elem_flag_test(efa, BM_ELEM_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; } } } @@ -1028,12 +1044,13 @@ static void uv_map_clip_correct_properties(wmOperatorType *ot) "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"); @@ -1045,16 +1062,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_elem_flag_test(efa, BM_ELEM_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); } } @@ -1067,31 +1081,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_elem_flag_test(efa, BM_ELEM_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_elem_flag_test(efa, BM_ELEM_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); } } } @@ -1102,9 +1113,9 @@ static void uv_map_clip_correct(EditMesh *em, wmOperator *op) /* assumes UV Map is checked, doesn't run update funcs */ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel) { + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; ParamHandle *handle; - EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data); const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES; const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT); const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF; @@ -1123,15 +1134,13 @@ 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"); @@ -1141,11 +1150,8 @@ static int unwrap_exec(bContext *C, wmOperator *op) short implicit= 0; if(!uvedit_have_selection(scene, em, implicit)) { - BKE_mesh_end_editmesh(obedit->data, em); - return 0; + return OPERATOR_CANCELLED; } - - BKE_mesh_end_editmesh(obedit->data, em); /* add uvs if they don't exist yet */ if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { @@ -1215,17 +1221,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; } @@ -1235,17 +1242,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_elem_flag_test(efa, BM_ELEM_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); } } } @@ -1253,15 +1258,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_elem_flag_test(efa, BM_ELEM_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); } } @@ -1271,15 +1274,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_elem_flag_test(efa, BM_ELEM_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); } } } @@ -1289,7 +1290,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; } @@ -1325,38 +1325,20 @@ 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; + Mesh *me = (Mesh*)obedit->data; /* add uvs if they don't exist yet */ - if(!ED_uvedit_ensure_uvs(C, scene, obedit)) { - BKE_mesh_end_editmesh(obedit->data, em); + if (!ED_uvedit_ensure_uvs(C, scene, obedit)) { 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); - - tf->uv[0][0]= 0.0f; - tf->uv[0][1]= 0.0f; - - tf->uv[1][0]= 1.0f; - tf->uv[1][1]= 0.0f; - - tf->uv[2][0]= 1.0f; - tf->uv[2][1]= 1.0f; - - tf->uv[3][0]= 0.0f; - tf->uv[3][1]= 1.0f; - } + if (!ED_mesh_uv_loop_reset(C, me)) { + return OPERATOR_CANCELLED; } 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; } @@ -1388,55 +1370,69 @@ 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; + float **uvs = NULL; + BLI_array_fixedstack_declare(uvs, BM_NGON_STACK_SIZE, efa->len, __func__); 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); + 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_fixedstack_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_elem_flag_test(efa, BM_ELEM_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); @@ -1444,7 +1440,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; } @@ -1484,31 +1479,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_elem_flag_test(efa, BM_ELEM_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); @@ -1516,7 +1513,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; } @@ -1542,15 +1538,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; - float no[3], cube_size, *loc, dx, dy; + BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + /* MTexPoly *tf; */ /* UNUSED */ + MLoopUV *luv; + float 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; } @@ -1560,34 +1558,31 @@ 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); - - axis_dominant_v3(&cox, &coy, no); - - 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; + 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); */ /* UNUSED */ + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) + continue; + + axis_dominant_v3(&cox, &coy, efa->no); + + 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]); + + if (first) { + dx = floor(luv->uv[0]); + dy = floor(luv->uv[1]); + first = 0; } + + + luv->uv[0] -= dx; + luv->uv[1] -= dy; } } @@ -1596,7 +1591,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; } @@ -1612,7 +1606,6 @@ void UV_OT_cube_project(wmOperatorType *ot) ot->poll= ED_operator_uvmap; /* properties */ - RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", - "Size of the cube to project on", 0.001f, 100.0f); + RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on", 0.001f, 100.0f); uv_map_clip_correct_properties(ot); } |