Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt23
-rw-r--r--source/blender/editors/mesh/SConscript1
-rw-r--r--source/blender/editors/mesh/bmesh_select.c2440
-rw-r--r--source/blender/editors/mesh/bmesh_selecthistory.c126
-rw-r--r--source/blender/editors/mesh/bmesh_tools.c5118
-rw-r--r--source/blender/editors/mesh/bmeshutils.c898
-rw-r--r--source/blender/editors/mesh/editbmesh_add.c619
-rw-r--r--source/blender/editors/mesh/editbmesh_bvh.c725
-rw-r--r--source/blender/editors/mesh/editbmesh_bvh.h31
-rw-r--r--source/blender/editors/mesh/editface.c490
-rw-r--r--source/blender/editors/mesh/editmesh.c1961
-rw-r--r--source/blender/editors/mesh/editmesh_add.c1772
-rw-r--r--source/blender/editors/mesh/editmesh_lib.c2848
-rw-r--r--source/blender/editors/mesh/editmesh_loop.c736
-rw-r--r--source/blender/editors/mesh/editmesh_mods.c4500
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c7605
-rwxr-xr-xsource/blender/editors/mesh/knifetool.c1863
-rw-r--r--source/blender/editors/mesh/loopcut.c363
-rw-r--r--source/blender/editors/mesh/mesh_data.c169
-rw-r--r--source/blender/editors/mesh/mesh_intern.h115
-rw-r--r--source/blender/editors/mesh/mesh_ops.c45
-rw-r--r--source/blender/editors/mesh/meshtools.c225
22 files changed, 12657 insertions, 20016 deletions
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index a03bf173425..1581c91ab04 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -21,9 +21,11 @@
set(INC
../include
+ ../uvedit
../../blenkernel
../../blenloader
../../blenlib
+ ../../bmesh
../../imbuf
../../makesdna
../../makesrna
@@ -34,19 +36,20 @@ set(INC
)
set(SRC
- editface.c
- editmesh.c
- editmesh_add.c
- editmesh_lib.c
- editmesh_loop.c
- editmesh_mods.c
- editmesh_tools.c
+ meshtools.c
loopcut.c
- mesh_data.c
mesh_ops.c
- meshtools.c
-
+ editbmesh_bvh.c
+ editbmesh_bvh.h
+ editbmesh_add.c
+ bmeshutils.c
mesh_intern.h
+ bmesh_selecthistory.c
+ bmesh_select.c
+ mesh_data.c
+ bmesh_tools.c
+ knifetool.c
+ editface.c
)
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}")
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 34936c025bc..dc352e07fec 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -7,6 +7,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../gpu ../../blenloader'
incs += ' ../../makesrna ../../render/extern/include #/intern/elbeem/extern'
+incs += ' ../../bmesh ../uvedit '
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'
diff --git a/source/blender/editors/mesh/bmesh_select.c b/source/blender/editors/mesh/bmesh_select.c
new file mode 100644
index 00000000000..e0c0215bc2b
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_select.c
@@ -0,0 +1,2440 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+
+BMEditMesh_mods.c, UI level access, no geometry changes
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+#include "BKE_paint.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "UI_resources.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/* ****************************** MIRROR **************** */
+
+void EDBM_select_mirrored(Object *obedit, BMEditMesh *em)
+{
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BMVert *eve, *v1;
+ BMIter iter;
+ int i;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ v1= editbmesh_get_x_mirror_vert(obedit, em, eve, eve->co, i);
+ if(v1) {
+ BM_Select(em->bm, eve, 0);
+ BM_Select(em->bm, v1, 1);
+ }
+ }
+ i++;
+ }
+ }
+}
+
+void EDBM_automerge(Scene *scene, Object *obedit, int update)
+{
+ BMEditMesh *em;
+
+ if ((scene->toolsettings->automerge) &&
+ (obedit && obedit->type==OB_MESH) &&
+ (((Mesh*)obedit->data)->mr==NULL))
+ {
+ em = ((Mesh*)obedit->data)->edit_btmesh;
+ if (!em)
+ return;
+
+ BMO_CallOpf(em->bm, "automerge verts=%hv dist=%f", BM_SELECT, scene->toolsettings->doublimit);
+ if (update) {
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ }
+ }
+}
+
+/* ****************************** SELECTION ROUTINES **************** */
+
+unsigned int bm_solidoffs=0, bm_wireoffs=0, bm_vertoffs=0; /* set in drawobject.c ... for colorindices */
+
+/* facilities for border select and circle select */
+static char *selbuf= NULL;
+
+/* opengl doesn't support concave... */
+static void draw_triangulated(short 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, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
+{
+ unsigned int *dr, *drm;
+ struct ImBuf *buf, *bufmask;
+ int a;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(paint_facesel_test(vc->obact));
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+ if(bm_vertoffs==0) return 0;
+
+ dr = buf->rect;
+
+ /* draw the mask */
+ glDisable(GL_DEPTH_TEST);
+
+ glColor3ub(0, 0, 0);
+
+ /* yah, opengl doesn't do concave... tsk! */
+ ED_region_pixelspace(vc->ar);
+ draw_triangulated(mcords, tot);
+
+ glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
+ for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
+ glEnd();
+
+ glFinish(); /* to be sure readpixels sees mask */
+
+ /* grab mask */
+ bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ drm = bufmask->rect;
+ if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=bm_vertoffs && *drm==0) selbuf[*dr]= 1;
+ dr++; drm++;
+ }
+ IMB_freeImBuf(buf);
+ IMB_freeImBuf(bufmask);
+ return 1;
+
+}
+
+/* circle shaped sample area */
+int EDBM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ short xmin, ymin, xmax, ymax, xc, yc;
+ int radsq;
+
+ /* method in use for face selecting too */
+ if(vc->obedit==NULL) {
+ if(paint_facesel_test(vc->obact));
+ else return 0;
+ }
+ else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ xmin= xs-rads; xmax= xs+rads;
+ ymin= ys-rads; ymax= ys+rads;
+ buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+ if(bm_vertoffs==0) return 0;
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(bm_vertoffs+1, "selbuf");
+ radsq= rads*rads;
+ for(yc= -rads; yc<=rads; yc++) {
+ for(xc= -rads; xc<=rads; xc++, dr++) {
+ if(xc*xc + yc*yc < radsq) {
+ if(*dr>0 && *dr<=bm_vertoffs) selbuf[*dr]= 1;
+ }
+ }
+ }
+
+ IMB_freeImBuf(buf);
+ return 1;
+
+}
+
+static void findnearestvert__doClosest(void *userData, BMVert *eve, int x, int y, int index)
+{
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
+ if (BM_TestHFlag(eve, BM_SELECT) == data->select) {
+ if (data->strict == 1)
+ return;
+ else
+ temp += 5;
+ }
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = eve;
+ data->closestIndex = index;
+ }
+ }
+}
+
+
+
+
+static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
+{
+ BMEditMesh *em= (BMEditMesh *)handle;
+ BMVert *eve = BMIter_AtIndex(em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && BM_TestHFlag(eve, BM_SELECT)) return 0;
+ return 1;
+}
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+BMVert *EDBM_findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
+{
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)){
+ int distance;
+ unsigned int index;
+ BMVert *eve;
+
+ if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest);
+ else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL);
+
+ eve = BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, index-1);
+
+ if(eve && distance < *dist) {
+ *dist = distance;
+ return eve;
+ } else {
+ return NULL;
+ }
+
+ }
+ else {
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; BMVert *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMVert *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_VERTS_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.select = sel;
+ data.dist = *dist;
+ data.strict = strict;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* returns labda for closest distance v1 to line-piece v2-v3 */
+float labda_PdistVL2Dfl( 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, BMEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
+{
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } *data = userData;
+ float v1[2], v2[2];
+ int distance;
+
+ v1[0] = x0;
+ v1[1] = y0;
+ v2[0] = x1;
+ v2[1] = y1;
+
+ distance= dist_to_line_segment_v2(data->mval, v1, v2);
+
+ if(BM_TestHFlag(eed, BM_SELECT)) distance+=5;
+ if(distance < data->dist) {
+ if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
+ float vec[3];
+
+ vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
+ vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
+ vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
+ mul_m4_v3(data->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+ else {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+}
+BMEdge *EDBM_findnearestedge(ViewContext *vc, int *dist)
+{
+
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ int distance;
+ unsigned int index;
+ BMEdge *eed;
+
+ view3d_validate_backbuf(vc);
+
+ index = view3d_sample_backbuf_rect(vc, vc->mval, 50, bm_solidoffs, bm_wireoffs, &distance,0, NULL, NULL);
+ eed = BMIter_AtIndex(vc->em->bm, BM_EDGES_OF_MESH, NULL, index-1);
+
+ if (eed && distance<*dist) {
+ *dist = distance;
+ return eed;
+ } else {
+ return NULL;
+ }
+ }
+ else {
+ struct { ViewContext vc; float mval[2]; int dist; BMEdge *closest; } data;
+
+ data.vc= *vc;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
+
+ *dist = data.dist;
+ return data.closest;
+ }
+}
+
+static void findnearestface__getDistance(void *userData, BMFace *efa, int x, int y, int UNUSED(index))
+{
+ struct { short mval[2]; int dist; BMFace *toFace; } *data = userData;
+
+ if (efa==data->toFace) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist)
+ data->dist = temp;
+ }
+}
+static void findnearestface__doClosest(void *userData, BMFace *efa, int x, int y, int index)
+{
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = efa;
+ data->closestIndex = index;
+ }
+ }
+}
+
+BMFace *EDBM_findnearestface(ViewContext *vc, int *dist)
+{
+
+ if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
+ unsigned int index;
+ BMFace *efa;
+
+ view3d_validate_backbuf(vc);
+
+ index = view3d_sample_backbuf(vc, vc->mval[0], vc->mval[1]);
+ efa = BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, index-1);
+
+ if (efa) {
+ struct { short mval[2]; int dist; BMFace *toFace; } data;
+
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = 0x7FFF; /* largest short */
+ data.toFace = efa;
+
+ mesh_foreachScreenFace(vc, findnearestface__getDistance, &data);
+
+ if(vc->em->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
+ *dist= data.dist;
+ return efa;
+ }
+ }
+
+ return NULL;
+ }
+ else {
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; BMFace *closest; } data;
+ static int lastSelectedIndex=0;
+ static BMFace *lastSelected=NULL;
+
+ if (lastSelected && BMIter_AtIndex(vc->em->bm, BM_FACES_OF_MESH, NULL, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = vc->mval[0];
+ data.mval[1] = vc->mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ data.closestIndex = 0;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+
+ data.pass = 0;
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
+ mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* best distance based on screen coords.
+ use em->selectmode to define how to use
+ selected vertices and edges get disadvantage
+ return 1 if found one
+*/
+static int unified_findnearest(ViewContext *vc, BMVert **eve, BMEdge **eed, BMFace **efa)
+{
+ BMEditMesh *em= vc->em;
+ int dist= 75;
+
+ *eve= NULL;
+ *eed= NULL;
+ *efa= NULL;
+
+ /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
+ view3d_validate_backbuf(vc);
+
+ if(em->selectmode & SCE_SELECT_VERTEX)
+ *eve= EDBM_findnearestvert(vc, &dist, BM_SELECT, 0);
+ if(em->selectmode & SCE_SELECT_FACE)
+ *efa= EDBM_findnearestface(vc, &dist);
+
+ dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
+ if(em->selectmode & SCE_SELECT_EDGE)
+ *eed= EDBM_findnearestedge(vc, &dist);
+
+ /* return only one of 3 pointers, for frontbuffer redraws */
+ if(*eed) {
+ *efa= NULL; *eve= NULL;
+ }
+ else if(*efa) {
+ *eve= NULL;
+ }
+
+ return (*eve || *eed || *efa);
+}
+
+/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
+
+static EnumPropertyItem prop_similar_types[] = {
+ {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
+ {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
+
+ {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
+ {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
+ {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
+ {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
+ {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
+ {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
+ {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+
+ {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
+ {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
+ {SIMFACE_AREA, "AREA", 0, "Area", ""},
+ {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
+ {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
+ {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* selects new faces/edges/verts based on the existing selection */
+
+static int similar_face_select_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similarfaces faces=%hf type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+/* ***************************************************** */
+
+/* EDGE GROUP */
+
+/* wrap the above function but do selection flushing edge to face */
+static int similar_edge_select_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similaredges edges=%he type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_ALL);
+ EDBM_selectmode_flush(em);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+/* ********************************* */
+
+/*
+VERT GROUP
+ mode 1: same normal
+ mode 2: same number of face users
+ mode 3: same vertex groups
+*/
+
+
+static int similar_vert_select_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+ float thresh = CTX_data_tool_settings(C)->select_thresh;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "similarverts verts=%hv type=%d thresh=%f", BM_SELECT, type, thresh);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* clear the existing selection */
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ EDBM_selectmode_flush(em);
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int select_similar_exec(bContext *C, wmOperator *op)
+{
+ int type= RNA_enum_get(op->ptr, "type");
+
+ if(type < 100)
+ return similar_vert_select_exec(C, op);
+ else if(type < 200)
+ return similar_edge_select_exec(C, op);
+ else
+ return similar_face_select_exec(C, op);
+}
+
+static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ EnumPropertyItem *item= NULL;
+ int a, totitem= 0;
+
+ if(obedit && obedit->type == OB_MESH) {
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ for (a=SIMVERT_NORMAL; a<SIMEDGE_LENGTH; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ } else if(em->selectmode & SCE_SELECT_EDGE) {
+ for (a=SIMEDGE_LENGTH; a<SIMFACE_MATERIAL; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ } else if(em->selectmode & SCE_SELECT_FACE) {
+ for (a=SIMFACE_MATERIAL; a<=SIMFACE_COPLANAR; a++) {
+ RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
+ }
+ }
+ RNA_enum_item_end(&item, &totitem);
+
+ *free= 1;
+
+ return item;
+ }
+
+ return NULL;
+}
+
+void MESH_OT_select_similar(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name= "Select Similar";
+ ot->idname= "MESH_OT_select_similar";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= select_similar_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select similar vertices, edges or faces by property types.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ prop= ot->prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
+ RNA_def_enum_funcs(prop, select_similar_type_itemf);
+}
+
+/* ***************************************************** */
+
+/* **************** LOOP SELECTS *************** */
+/*faceloop_select, edgeloop_select, and edgering_select, are left
+ here for reference purposes temporarily, but have all been replaced
+ by uses of walker_select.*/
+
+static void walker_select(BMEditMesh *em, int walkercode, void *start, int select)
+{
+ BMesh *bm = em->bm;
+ BMHeader *h;
+ BMWalker walker;
+
+ BMW_Init(&walker, bm, walkercode, 0, 0);
+ h = BMW_Begin(&walker, start);
+ for (; h; h=BMW_Step(&walker)) {
+ BM_Select(bm, h, select);
+ }
+ BMW_End(&walker);
+}
+
+static int loop_multiselect(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0 //BMESH_TODO
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= EM_GetBMEditMesh(((Mesh *)obedit->data));
+ BMEdge *eed;
+ BMEdge **edarray;
+ int edindex, edfirstcount;
+ int looptype= RNA_boolean_get(op->ptr, "ring");
+
+ /* sets em->totedgesel */
+ EM_nedges_selected(em);
+
+ edarray = MEM_mallocN(sizeof(BMEdge*)*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);
+
+ EM_EndBMEditMesh(obedit->data, em);
+#endif
+ 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, short mval[2], short extend, short ring)
+{
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int select= 1;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */
+ view3d_validate_backbuf(&vc);
+
+ eed= EDBM_findnearestedge(&vc, &dist);
+ if(eed) {
+ if(extend==0) EDBM_clear_flag_all(em, BM_SELECT);
+
+ if(BM_TestHFlag(em, BM_SELECT)==0) select=1;
+ else if(extend) select=0;
+
+ if(em->selectmode & SCE_SELECT_FACE) {
+ walker_select(em, BMW_FACELOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if(ring)
+ walker_select(em, BMW_EDGERING, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+ else if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(ring)
+ walker_select(em, BMW_EDGERING, eed, select);
+ else
+ walker_select(em, BMW_LOOP, eed, select);
+ }
+
+ EDBM_selectmode_flush(em);
+// if (EM_texFaceCheck())
+
+ /* sets as active, useful for other tools */
+ if(select && em->selectmode & SCE_SELECT_EDGE) {
+ EDBM_store_selection(em, eed);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
+ }
+}
+
+static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
+ RNA_boolean_get(op->ptr, "ring"));
+
+ /* cannot do tweaks for as long this keymap is after transform map */
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Loop Select";
+ ot->idname= "MESH_OT_loop_select";
+
+ /* api callbacks */
+ ot->invoke= mesh_select_loop_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select a loop of connected edges.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+ RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
+}
+
+/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
+
+/* since you want to create paths with multiple selects, it doesn't have extend option */
+static void mouse_mesh_shortest_path(bContext *UNUSED(C), short UNUSED(mval[2]))
+{
+#if 0 //BMESH_TODO
+ ViewContext vc;
+ BMEditMesh *em;
+ BMEdge *eed;
+ int dist= 50;
+
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+ em= vc.em;
+
+ eed= findnearestedge(&vc, &dist);
+ if(eed) {
+ Mesh *me= vc.obedit->data;
+ int path = 0;
+
+ if (em->bm->selected.last) {
+ EditSelection *ese = em->bm->selected.last;
+
+ if(ese && ese->type == BMEdge) {
+ BMEdge *eed_act;
+ eed_act = (BMEdge*)ese->data;
+ if (eed_act != eed) {
+ if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
+ EM_remove_selection(em, eed_act, BMEdge);
+ path = 1;
+ }
+ }
+ }
+ }
+ if (path==0) {
+ int act = (edgetag_context_check(vc.scene, eed)==0);
+ edgetag_context_set(em, vc.scene, eed, act); /* switch the edge option */
+ }
+
+ EM_selectmode_flush(em);
+
+ /* even if this is selected it may not be in the selection list */
+ if(edgetag_context_check(vc.scene, eed)==0)
+ EDBM_remove_selection(em, eed);
+ else
+ EDBM_store_selection(em, eed);
+
+ /* force drawmode for mesh */
+ switch (CTX_data_tool_settings(C)->edge_mode) {
+
+ case EDGE_MODE_TAG_SEAM:
+ me->drawflag |= ME_DRAWSEAMS;
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ me->drawflag |= ME_DRAWSHARP;
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ me->drawflag |= ME_DRAWCREASES;
+ break;
+ case EDGE_MODE_TAG_BEVEL:
+ me->drawflag |= ME_DRAWBWEIGHTS;
+ break;
+ }
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
+ }
+#endif
+}
+
+
+static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
+{
+
+ view3d_operator_needs_opengl(C);
+
+ mouse_mesh_shortest_path(C, event->mval);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_shortest_path(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shortest Path Select";
+ ot->idname= "MESH_OT_select_shortest_path";
+
+ /* api callbacks */
+ ot->invoke= mesh_shortest_path_select_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select shortest path between two selections.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+}
+
+/* ************************************************** */
+/* here actual select happens */
+/* gets called via generic mouse select operator */
+int mouse_mesh(bContext *C, const short mval[2], short extend)
+{
+ ViewContext vc;
+ BMVert *eve = NULL;
+ BMEdge *eed = NULL;
+ BMFace *efa = NULL;
+
+ /* setup view context for argument to callbacks */
+ em_setup_viewcontext(C, &vc);
+ vc.mval[0]= mval[0];
+ vc.mval[1]= mval[1];
+
+ if(unified_findnearest(&vc, &eve, &eed, &efa)) {
+
+ if(extend==0) EDBM_clear_flag_all(vc.em, BM_SELECT);
+
+ if(efa) {
+ /* set the last selected face */
+ EDBM_set_actFace(vc.em, efa);
+
+ if(!BM_TestHFlag(efa, BM_SELECT)) {
+ EDBM_store_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, efa);
+ BM_Select(vc.em->bm, efa, 0);
+ }
+ }
+ else if(eed) {
+ if(!BM_TestHFlag(eed, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 1);
+ }
+ else if(extend) {
+ EDBM_remove_selection(vc.em, eed);
+ BM_Select(vc.em->bm, eed, 0);
+ }
+ }
+ else if(eve) {
+ if(!BM_TestHFlag(eve, BM_SELECT)) {
+ EDBM_store_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 1);
+ }
+ else if(extend){
+ EDBM_remove_selection(vc.em, eve);
+ BM_Select(vc.em->bm, eve, 0);
+ }
+ }
+
+ EDBM_selectmode_flush(vc.em);
+
+// if (EM_texFaceCheck()) {
+
+ if (efa && efa->mat_nr != vc.obedit->actcol-1) {
+ vc.obedit->actcol= efa->mat_nr+1;
+ vc.em->mat_nr= efa->mat_nr;
+// BIF_preview_changed(ID_MA);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void EDBM_strip_selections(BMEditMesh *em)
+{
+ BMEditSelection *ese, *nextese;
+
+ if(!(em->selectmode & SCE_SELECT_VERTEX)){
+ ese = em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_VERT) BLI_freelinkN(&(em->bm->selected),ese);
+ ese = nextese;
+ }
+ }
+ if(!(em->selectmode & SCE_SELECT_EDGE)){
+ ese=em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_EDGE) BLI_freelinkN(&(em->bm->selected), ese);
+ ese = nextese;
+ }
+ }
+ if(!(em->selectmode & SCE_SELECT_FACE)){
+ ese=em->bm->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == BM_FACE) BLI_freelinkN(&(em->bm->selected), ese);
+ ese = nextese;
+ }
+ }
+}
+
+/* when switching select mode, makes sure selection is consistant for editing */
+/* also for paranoia checks to make sure edge or face mode works */
+void EDBM_selectmode_set(BMEditMesh *em)
+{
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ em->bm->selectmode = em->selectmode;
+
+ EDBM_strip_selections(em); /*strip BMEditSelections from em->selected that are not relevant to new mode*/
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ /*BMIter iter;
+
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) BM_Select(em->bm, efa, 0);*/
+
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ /* deselect vertices, and select again based on edge select */
+ eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; eve; eve=BMIter_Step(&iter)) BM_Select(em->bm, eve, 0);
+
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, BM_SELECT))
+ BM_Select(em->bm, eed, 1);
+ }
+
+ /* selects faces based on edge status */
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_FACE) {
+ /* deselect eges, and select again based on face select */
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) BM_Select(em->bm, eed, 0);
+
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ BM_Select(em->bm, efa, 1);
+ }
+ }
+}
+
+void EDBM_convertsel(BMEditMesh *em, short oldmode, short selectmode)
+{
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+
+ /*have to find out what the selectionmode was previously*/
+ if(oldmode == SCE_SELECT_VERTEX) {
+ if(selectmode == SCE_SELECT_EDGE) {
+ /*select all edges associated with every selected vertex*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ else if(BM_TestHFlag(eed->v2, BM_SELECT)) BM_Select(em->bm, eed, 1);
+ }
+ }
+ else if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(oldmode == SCE_SELECT_EDGE){
+ if(selectmode == SCE_SELECT_FACE) {
+ BMIter liter;
+ BMLoop *l;
+
+ /*select all faces associated with every selected vertex*/
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ l = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
+ for (; l; l=BMIter_Step(&liter)) {
+ if (BM_TestHFlag(l->v, BM_SELECT)) {
+ BM_Select(em->bm, efa, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void EDBM_select_swap(BMEditMesh *em) /* exported for UV */
+{
+ BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+
+ if(em->bm->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, eve, !BM_TestHFlag(eve, BM_SELECT));
+ }
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, eed, !BM_TestHFlag(eed, BM_SELECT));
+ }
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(efa, BM_HIDDEN))
+ continue;
+ BM_Select(em->bm, efa, !BM_TestHFlag(efa, BM_SELECT));
+ }
+
+ }
+// if (EM_texFaceCheck())
+}
+
+static int select_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ EDBM_select_swap(em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_inverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Inverse";
+ ot->idname= "MESH_OT_select_inverse";
+ ot->description= "Select inverse of (un)selected vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= select_inverse_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ ViewContext vc;
+ BMWalker walker;
+ BMEditMesh *em;
+ BMVert *eve;
+ BMEdge *e, *eed;
+ BMFace *efa;
+ int sel= !RNA_boolean_get(op->ptr, "deselect");
+
+ /* unified_finednearest needs ogl */
+ view3d_operator_needs_opengl(C);
+
+ /* setup view context for argument to callbacks */
+ em_setup_viewcontext(C, &vc);
+ em = vc.em;
+
+ if(vc.em->bm->totedge==0)
+ return OPERATOR_CANCELLED;
+
+ vc.mval[0]= event->mval[0];
+ vc.mval[1]= event->mval[1];
+
+ /* return warning! */
+
+ /*if(limit) {
+ int retval= select_linked_limited_invoke(&vc, 0, sel);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return retval;
+ }*/
+
+ if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_CANCELLED;
+ }
+
+ if (efa) {
+ eed = bm_firstfaceloop(efa)->e;
+ } else if (!eed) {
+ if (!eve || !eve->e)
+ return OPERATOR_CANCELLED;
+
+ eed = eve->e;
+ }
+
+ BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
+ e = BMW_Begin(&walker, eed->v1);
+ for (; e; e=BMW_Step(&walker)) {
+ BM_Select(em->bm, e->v1, sel);
+ BM_Select(em->bm, e->v2, sel);
+ }
+ BMW_End(&walker);
+ EDBM_select_flush(em, SCE_SELECT_VERTEX);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_linked_pick(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked";
+ ot->idname= "MESH_OT_select_linked_pick";
+
+ /* api callbacks */
+ ot->invoke= select_linked_pick_invoke;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "select/deselect all vertices linked to the edge under the mouse cursor.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+ RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+}
+
+
+static int select_linked_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ BLI_array_declare(verts);
+ BMVert **verts = NULL;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ BMWalker walker;
+ int i, tot;
+
+ tot = 0;
+ BM_ITER_SELECT(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
+ if (BM_TestHFlag(v, BM_SELECT)) {
+ BLI_array_growone(verts);
+ verts[tot++] = v;
+ }
+ }
+
+ BMW_Init(&walker, em->bm, BMW_SHELL, 0, 0);
+ for (i=0; i<tot; i++) {
+ e = BMW_Begin(&walker, verts[i]);
+ for (; e; e=BMW_Step(&walker)) {
+ BM_Select(em->bm, e->v1, 1);
+ BM_Select(em->bm, e->v2, 1);
+ }
+ }
+ BMW_End(&walker);
+ EDBM_select_flush(em, SCE_SELECT_VERTEX);
+
+ BLI_array_free(verts);
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_linked(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked All";
+ ot->idname= "MESH_OT_select_linked";
+
+ /* api callbacks */
+ ot->exec= select_linked_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Select all vertices linked to the active mesh.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+}
+
+/* ******************** **************** */
+
+static int select_more(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_more(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select More";
+ ot->idname= "MESH_OT_select_more";
+ ot->description= "Select more vertices, edges or faces connected to initial selection.";
+
+ /* api callbacks */
+ ot->exec= select_more;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int select_less(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ EDBM_InitOpf(em, &bmop, op, "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 1, usefaces);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_less(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Less";
+ ot->idname= "MESH_OT_select_less";
+ ot->description= "Deselect vertices, edges or faces at the boundary of each selection region.";
+
+ /* api callbacks */
+ ot->exec= select_less;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_select_nth_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+// BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+// int nth = RNA_int_get(op->ptr, "nth");
+
+#if 0 //BMESH_TODO
+ if(EM_deselect_nth(em, nth) == 0) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face.");
+ return OPERATOR_CANCELLED;
+ }
+#else
+ BKE_report(op->reports, RPT_ERROR, "Unimplemented");
+#endif
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_select_nth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Nth";
+ ot->description= "";
+ ot->idname= "MESH_OT_select_nth";
+
+ /* api callbacks */
+ ot->exec= mesh_select_nth_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
+}
+
+#if 0 //BMESH_TODO, select nth tool
+/* not that optimal!, should be nicer with bmesh */
+static void tag_face_edges(EditFace *efa)
+{
+ if(efa->v4)
+ efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;
+ else
+ efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
+}
+static int tag_face_edges_test(EditFace *efa)
+{
+ if(efa->v4)
+ return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0;
+ else
+ return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0;
+}
+
+void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act)
+{
+ EditFace *efa;
+ EditEdge *eed;
+ int ok= 1;
+
+ if(efa_act==NULL) {
+ return;
+ }
+
+ /* to detect loose edges, we put f2 flag on 1 */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.l= 0;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.l = 0;
+ }
+
+ efa_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l==1) { /* initialize */
+ tag_face_edges(efa);
+ }
+
+ if(efa->tmp.l)
+ efa->tmp.l++;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l==0 && tag_face_edges_test(efa)) {
+ efa->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->tmp.l > 0 && efa->tmp.l % nth) {
+ EM_select_face(efa, 0);
+ }
+ }
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ EM_select_face(efa, 1);
+ }
+ }
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+}
+
+/* not that optimal!, should be nicer with bmesh */
+static void tag_edge_verts(EditEdge *eed)
+{
+ eed->v1->tmp.l= eed->v2->tmp.l= 1;
+}
+static int tag_edge_verts_test(EditEdge *eed)
+{
+ return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0;
+}
+
+void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act)
+{
+ EditEdge *eed;
+ EditVert *eve;
+ int ok= 1;
+
+ if(eed_act==NULL) {
+ return;
+ }
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ eve->tmp.l= 0;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.l = 0;
+ }
+
+ eed_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l==1) { /* initialize */
+ tag_edge_verts(eed);
+ }
+
+ if(eed->tmp.l)
+ eed->tmp.l++;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l==0 && tag_edge_verts_test(eed)) {
+ eed->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->tmp.l > 0 && eed->tmp.l % nth) {
+ EM_select_edge(eed, 0);
+ }
+ }
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ EM_select_edge(eed, 1);
+ }
+ }
+
+ {
+ /* grr, should be a function */
+ EditFace *efa;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4) {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ else {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ }
+ }
+
+ EM_nvertices_selected(em);
+ EM_nedges_selected(em);
+ EM_nfaces_selected(em);
+}
+
+void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ int ok= 1;
+
+ if(eve_act==NULL) {
+ return;
+ }
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ eve->tmp.l = 0;
+ }
+
+ eve_act->tmp.l = 1;
+
+ while(ok) {
+ ok = 0;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->tmp.l)
+ eve->tmp.l++;
+ }
+
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */
+ eed->v2->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */
+ eed->v1->tmp.l= 1;
+ ok = 1; /* keep looping */
+ }
+ }
+ }
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->tmp.l > 0 && eve->tmp.l % nth) {
+ eve->f &= ~SELECT;
+ }
+ }
+
+ EM_deselect_flush(em);
+
+ EM_nvertices_selected(em);
+ // EM_nedges_selected(em); // flush does these
+ // EM_nfaces_selected(em); // flush does these
+}
+#endif
+
+int EM_deselect_nth(BMEditMesh *em, int nth)
+{
+#if 0 //BMESH_TODO
+ EditSelection *ese;
+ ese = ((EditSelection*)em->selected.last);
+ if(ese) {
+ if(ese->type == EDITVERT) {
+ em_deselect_nth_vert(em, nth, (EditVert*)ese->data);
+ return 1;
+ }
+
+ if(ese->type == EDITEDGE) {
+ em_deselect_nth_edge(em, nth, (EditEdge*)ese->data);
+ return 1;
+ }
+ }
+ else {
+ EditFace *efa_act = EM_get_actFace(em, 0);
+ if(efa_act) {
+ em_deselect_nth_face(em, nth, efa_act);
+ return 1;
+ }
+ }
+
+ return 0;
+#endif
+ return 1;
+}
+
+void em_setup_viewcontext(bContext *C, ViewContext *vc)
+{
+ view3d_set_viewcontext(C, vc);
+
+ if(vc->obedit) {
+ Mesh *me= vc->obedit->data;
+ vc->em= me->edit_btmesh;
+ }
+}
+
+/* poll call for mesh operators requiring a view3d context */
+int EM_view3d_poll(bContext *C)
+{
+ if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
+ return 1;
+ return 0;
+}
+
+
+static int select_sharp_edges_exec(bContext *C, wmOperator *op)
+{
+ /* Find edges that have exactly two neighboring faces,
+ * check the angle between those faces, and if angle is
+ * small enough, select the edge
+ */
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMIter iter;
+ BMEdge *e;
+ BMLoop *l1, *l2;
+ float sharp = RNA_float_get(op->ptr, "sharpness"), angle;
+
+ sharp = (sharp * M_PI) / 180.0;
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_HIDDEN) || !e->l)
+ continue;
+
+ l1 = e->l;
+ l2 = l1->radial_next;
+
+ if (l1 == l2)
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = saacos(l1->f->no[0]*l2->f->no[0]+l1->f->no[1]*l2->f->no[1]+l1->f->no[2]*l2->f->no[2]);
+
+ if (fabs(angle) < sharp) {
+ BM_Select(em->bm, e, 1);
+ }
+
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edges_select_sharp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Sharp Edges";
+ ot->description= "Marked selected edges as sharp.";
+ ot->idname= "MESH_OT_edges_select_sharp";
+
+ /* api callbacks */
+ ot->exec= select_sharp_edges_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
+}
+
+static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMIter iter, liter, liter2;
+ BMFace *f, **stack = NULL;
+ BLI_array_declare(stack);
+ BMLoop *l, *l2;
+ float sharp = RNA_float_get(op->ptr, "sharpness");
+ int i;
+
+ sharp = (sharp * M_PI) / 180.0;
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(f, BM_HIDDEN) || !BM_TestHFlag(f, BM_SELECT) || BMINDEX_GET(f))
+ continue;
+
+ BLI_array_empty(stack);
+ i = 1;
+
+ BLI_array_growone(stack);
+ stack[i-1] = f;
+
+ while (i) {
+ f = stack[i-1];
+ i--;
+
+ BM_Select(em->bm, f, 1);
+
+ BMINDEX_SET(f, 1);
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_LOOP, l) {
+ float angle;
+
+ if (BMINDEX_GET(l2->f) || BM_TestHFlag(l2->f, BM_HIDDEN))
+ continue;
+
+ /* edge has exactly two neighboring faces, check angle */
+ angle = saacos(f->no[0]*l2->f->no[0]+f->no[1]*l2->f->no[1]+f->no[2]*l2->f->no[2]);
+
+ /* invalidate: edge too sharp */
+ if (fabs(angle) < sharp) {
+ BLI_array_growone(stack);
+ stack[i] = l2->f;
+ i++;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_array_free(stack);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Linked Flat Faces";
+ ot->description= "Select linked faces by angle.";
+ ot->idname= "MESH_OT_faces_select_linked_flat";
+
+ /* api callbacks */
+ ot->exec= select_linked_flat_faces_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "sharpness", 1.0f, 0.01f, FLT_MAX, "sharpness", "", 1.0f, 180.0f);
+}
+
+static int select_non_manifold_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMVert *v;
+ BMEdge *e;
+ BMIter iter;
+
+ /* Selects isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+ if(em->selectmode==SCE_SELECT_FACE) {
+ BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
+ return OPERATOR_CANCELLED;
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Vert(em->bm, v))
+ BM_Select(em->bm, v, 1);
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(em->bm, BM_HIDDEN) && BM_Nonmanifold_Edge(em->bm, e))
+ BM_Select(em->bm, e, 1);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_non_manifold(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Non Manifold";
+ ot->description= "Select all non-manifold vertices or edges.";
+ ot->idname= "MESH_OT_select_non_manifold";
+
+ /* api callbacks */
+ ot->exec= select_non_manifold_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_select_random_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMVert *eve;
+ BMEdge *eed;
+ BMFace *efa;
+ BMIter iter;
+ float randfac = RNA_float_get(op->ptr, "percent")/100.0f;
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ if(!RNA_boolean_get(op->ptr, "extend"))
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, eve, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eed, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, eed, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+ else {
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(efa, BM_HIDDEN) && BLI_frand() < randfac)
+ BM_Select(em->bm, efa, 1);
+ }
+ EDBM_selectmode_flush(em);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_random(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Random";
+ ot->description= "Randomly select vertices.";
+ ot->idname= "MESH_OT_select_random";
+
+ /* api callbacks */
+ ot->exec= mesh_select_random_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly.", 0.f, 100.0f);
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend Selection", "Extend selection instead of deselecting everything first.");
+}
+
+static int select_next_loop(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMFace *f;
+ BMVert *v;
+ BMIter iter;
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, 0);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l;
+ BMIter liter;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ if (BM_TestHFlag(l->v, BM_SELECT) && !BM_TestHFlag(l->v, BM_HIDDEN)) {
+ BMINDEX_SET(l->next->v, 1);
+ BM_Select(em->bm, l->v, 0);
+ }
+ }
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BMINDEX_GET(v)) {
+ BM_Select(em->bm, v, 1);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_next_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Next Loop";
+ ot->idname= "MESH_OT_select_next_loop";
+ ot->description= "";
+
+ /* api callbacks */
+ ot->exec= select_next_loop;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+ BMFace *f;
+ BMEdge *e;
+ BMIter iter;
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ BMINDEX_SET(e, 0);
+ }
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l1, *l2;
+ BMIter liter1, liter2;
+
+ BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
+ int tot=0, totsel=0;
+
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
+ tot++;
+ totsel += BM_TestHFlag(l2->f, BM_SELECT) != 0;
+ }
+
+ if ((tot != totsel && totsel > 0) || (totsel == 1 && tot == 1))
+ BMINDEX_SET(l1->e, 1);
+ }
+ }
+
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BMINDEX_GET(e) && !BM_TestHFlag(e, BM_HIDDEN))
+ BM_Select_Edge(em->bm, e, 1);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_region_to_loop(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Boundary Loop";
+ ot->idname= "MESH_OT_region_to_loop";
+
+ /* api callbacks */
+ ot->exec= region_to_loop;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int loop_find_region(BMEditMesh *em, BMLoop *l, int flag,
+ SmallHash *fhash, BMFace ***region_out)
+{
+ BLI_array_declare(region);
+ BLI_array_declare(stack);
+ BMFace **region = NULL, *f;
+ BMFace **stack = NULL;
+
+ BLI_array_append(stack, l->f);
+ BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
+
+ while (BLI_array_count(stack) > 0) {
+ BMIter liter1, liter2;
+ BMLoop *l1, *l2;
+
+ f = BLI_array_pop(stack);
+ BLI_array_append(region, f);
+
+ BM_ITER(l1, &liter1, em->bm, BM_LOOPS_OF_FACE, f) {
+ if (BM_TestHFlag(l1->e, flag))
+ continue;
+
+ BM_ITER(l2, &liter2, em->bm, BM_LOOPS_OF_EDGE, l1->e) {
+ if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
+ continue;
+
+ BLI_array_append(stack, l2->f);
+ BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
+ }
+ }
+ }
+
+ BLI_array_free(stack);
+
+ *region_out = region;
+ return BLI_array_count(region);
+}
+
+int verg_radial(const void *va, const void *vb)
+{
+ BMEdge *e1 = *((void**)va);
+ BMEdge *e2 = *((void**)vb);
+ int a, b;
+
+ a = BM_Edge_FaceCount(e1);
+ b = BM_Edge_FaceCount(e2);
+
+ if (a > b) return -1;
+ if (a == b) return 0;
+ if (a < b) return 1;
+
+ return -1;
+}
+
+static int loop_find_regions(BMEditMesh *em, int selbigger)
+{
+ SmallHash visithash;
+ BMIter iter;
+ BMEdge *e, **edges=NULL;
+ BLI_array_declare(edges);
+ BMFace *f;
+ int count = 0, i;
+
+ BLI_smallhash_init(&visithash);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, 0);
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT)) {
+ BLI_array_append(edges, e);
+ BMINDEX_SET(e, 1);
+ } else {
+ BMINDEX_SET(e, 0);
+ }
+ }
+
+ /*sort edges by radial cycle length*/
+ qsort(edges, BLI_array_count(edges), sizeof(void*), verg_radial);
+
+ for (i=0; i<BLI_array_count(edges); i++) {
+ BMIter liter;
+ BMLoop *l;
+ BMFace **region=NULL, **r;
+ int c, tot=0;
+
+ e = edges[i];
+
+ if (!BMINDEX_GET(e))
+ continue;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_EDGE, e) {
+ if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
+ continue;
+
+ c = loop_find_region(em, l, BM_SELECT, &visithash, &r);
+
+ if (!region || (selbigger ? c >= tot : c < tot)) {
+ tot = c;
+ if (region)
+ MEM_freeN(region);
+ region = r;
+ }
+ }
+
+ if (region) {
+ int j;
+
+ for (j=0; j<tot; j++) {
+ BMINDEX_SET(region[j], 1);
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, region[j]) {
+ BMINDEX_SET(l->e, 0);
+ }
+ }
+
+ count += tot;
+
+ MEM_freeN(region);
+ }
+ }
+
+ BLI_array_free(edges);
+ BLI_smallhash_release(&visithash);
+
+ return count;
+}
+
+static int loop_to_region(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+ BMIter iter;
+ BMFace *f;
+ int selbigger = RNA_boolean_get(op->ptr, "select_bigger");
+ int a, b;
+
+ /*find the set of regions with smallest number of total faces*/
+ a = loop_find_regions(em, selbigger);
+ b = loop_find_regions(em, !selbigger);
+
+ if ((a <= b) ^ selbigger) {
+ loop_find_regions(em, selbigger);
+ }
+
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BMINDEX_GET(f) && !BM_TestHFlag(f, BM_HIDDEN)) {
+ BM_Select_Face(em->bm, f, 1);
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_to_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Loop Inner-Region";
+ ot->idname= "MESH_OT_loop_to_region";
+
+ /* api callbacks */
+ ot->exec= loop_to_region;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "select_bigger", 0, "Select Bigger", "Select bigger regions instead of smaller ones");
+}
diff --git a/source/blender/editors/mesh/bmesh_selecthistory.c b/source/blender/editors/mesh/bmesh_selecthistory.c
new file mode 100644
index 00000000000..3b7fade9c05
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_selecthistory.c
@@ -0,0 +1,126 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* ********* Selection History ************ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "mesh_intern.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+/*these wrap equivilent bmesh functions. I'm in two minds of it we should
+ just use the bm functions directly; on the one hand, there's no real
+ need (at the moment) to wrap them, but on the other hand having these
+ wrapped avoids a confusing mess of mixing BM_ and EDBM_ namespaces.*/
+
+void EDBM_editselection_center(BMEditMesh *em, float *center, BMEditSelection *ese)
+{
+ BM_editselection_center(em->bm, center, ese);
+}
+
+void EDBM_editselection_normal(float *normal, BMEditSelection *ese)
+{
+ BM_editselection_normal(normal, ese);
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void EDBM_editselection_plane(BMEditMesh *em, float *plane, BMEditSelection *ese)
+{
+ BM_editselection_plane(em->bm, plane, ese);
+}
+
+void EDBM_remove_selection(BMEditMesh *em, void *data)
+{
+ BM_remove_selection(em->bm, data);
+}
+
+void EDBM_store_selection(BMEditMesh *em, void *data)
+{
+ BM_store_selection(em->bm, data);
+}
+
+void EDBM_validate_selections(BMEditMesh *em)
+{
+ BM_validate_selections(em->bm);
+}
diff --git a/source/blender/editors/mesh/bmesh_tools.c b/source/blender/editors/mesh/bmesh_tools.c
new file mode 100644
index 00000000000..ca6f61e24fd
--- /dev/null
+++ b/source/blender/editors/mesh/bmesh_tools.c
@@ -0,0 +1,5118 @@
+ /* $Id: bmesh_tools.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
+
+#include "BKE_material.h"
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+#include "BKE_texture.h"
+#include "BKE_main.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "RE_render_ext.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+static void add_normal_aligned(float *nor, float *add)
+{
+ if( INPR(nor, add) < -0.9999f)
+ sub_v3_v3v3(nor, nor, add);
+ else
+ add_v3_v3v3(nor, nor, add);
+}
+
+
+static int subdivide_exec(bContext *C, wmOperator *op)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int cuts= RNA_int_get(op->ptr,"number_cuts");
+ float fractal= RNA_float_get(op->ptr, "fractal")/2.5;
+ int flag= 0;
+
+ if(fractal != 0.0f)
+ flag |= B_FRACTAL;
+
+ if (RNA_boolean_get(op->ptr, "quadtri") &&
+ RNA_enum_get(op->ptr, "quadcorner") == SUBD_STRAIGHT_CUT)
+ {
+ RNA_enum_set(op->ptr, "quadcorner", SUBD_INNERVERT);
+ }
+
+ BM_esubdivideflag(obedit, em->bm, BM_SELECT,
+ 0.0f, fractal,
+ ts->editbutflag|flag,
+ cuts, 0, RNA_enum_get(op->ptr, "quadcorner"),
+ RNA_boolean_get(op->ptr, "quadtri"),
+ 1, RNA_int_get(op->ptr, "seed"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Note, these values must match delete_mesh() event values */
+static EnumPropertyItem prop_mesh_cornervert_types[] = {
+ {SUBD_INNERVERT, "INNERVERT", 0, "Inner Vert", ""},
+ {SUBD_PATH, "PATH", 0, "Path", ""},
+ {SUBD_STRAIGHT_CUT, "STRAIGHT_CUT", 0, "Straight Cut", ""},
+ {SUBD_FAN, "FAN", 0, "Fan", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void MESH_OT_subdivide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Subdivide";
+ ot->description= "Subdivide selected edges.";
+ ot->idname= "MESH_OT_subdivide";
+
+ /* api callbacks */
+ ot->exec= subdivide_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_int(ot->srna, "number_cuts", 1, 1, 50, "Number of Cuts", "", 1, INT_MAX);
+
+ RNA_def_boolean(ot->srna, "quadtri", 0, "Quad/Tri Mode", "Tries to prevent ngons");
+ RNA_def_enum(ot->srna, "quadcorner", prop_mesh_cornervert_types, SUBD_STRAIGHT_CUT, "Quad Corner Type", "How to subdivide quad corners (anything other then Straight Cut will prevent ngons)");
+
+ RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
+ RNA_def_int(ot->srna, "seed", 0, 0, 10000, "Random Seed", "Seed for the random number generator", 0, 50);
+}
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor))
+{
+ BMOIter siter;
+ BMIter liter;
+ BMFace *f;
+ BMLoop *l;
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_face_indiv faces=%hf", flag);
+
+ /*deselect original verts*/
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ BMO_ITER(f, &siter, em->bm, &bmop, "faceout", BM_FACE) {
+ BM_Select(em->bm, f, 1);
+
+ /*set face vertex normals to face normal*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ VECCOPY(l->v->no, f->no);
+ }
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 's'; // s is shrink/fatten
+}
+
+#if 0
+short EDBM_Extrude_face_indiv(BMEditMesh *em, wmOperator *op, short flag, float *nor)
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed;
+ EditFace *efa, *nextfa;
+
+ if(em==NULL) return 0;
+
+ /* selected edges with 1 or more selected face become faces */
+ /* selected faces each makes new faces */
+ /* always remove old faces, keeps volumes manifold */
+ /* select the new extrusion, deselect old */
+
+ /* step 1; init, count faces in edges */
+ recalc_editnormals(em);
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f2= 0; // amount of unselected faces
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT);
+ else {
+ efa->e1->f2++;
+ efa->e2->f2++;
+ efa->e3->f2++;
+ if(efa->e4) efa->e4->f2++;
+ }
+ }
+
+ /* step 2: make new faces from faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ v1= addvertlist(em, efa->v1->co, efa->v1);
+ v2= addvertlist(em, efa->v2->co, efa->v2);
+ v3= addvertlist(em, efa->v3->co, efa->v3);
+
+ v1->f1= v2->f1= v3->f1= 1;
+ VECCOPY(v1->no, efa->n);
+ VECCOPY(v2->no, efa->n);
+ VECCOPY(v3->no, efa->n);
+ if(efa->v4) {
+ v4= addvertlist(em, efa->v4->co, efa->v4);
+ v4->f1= 1;
+ VECCOPY(v4->no, efa->n);
+ }
+ else v4= NULL;
+
+ /* side faces, clockwise */
+ addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
+ addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
+ if(efa->v4) {
+ addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
+ addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
+ }
+ else {
+ addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
+ }
+ /* top face */
+ addfacelist(em, v1, v2, v3, v4, efa, NULL);
+ }
+ }
+
+ /* step 3: remove old faces */
+ efa= em->faces.first;
+ while(efa) {
+ nextfa= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(em, efa);
+ }
+ efa= nextfa;
+ }
+
+ /* step 4: redo selection */
+ EM_clear_flag_all(em, SELECT);
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1) eve->f |= SELECT;
+ }
+
+ EM_select_flush(em);
+
+ return 'n';
+}
+#endif
+
+/* extrudes individual edges */
+short EDBM_Extrude_edges_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor))
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_edge_only edges=%he", flag);
+
+ /*deselect original verts*/
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_VERT|BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 'n'; // n is normal grab
+}
+
+#if 0
+/* nor is filled with constraint vector */
+short EDBM_Extrude_edges_indiv(BMEditMesh *em, short flag, float *nor)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.f = NULL;
+ eed->f2= ((eed->f & flag)!=0);
+ }
+
+ set_edge_directions_f2(em, 2);
+
+ /* sample for next loop */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->tmp.f = efa;
+ efa->e2->tmp.f = efa;
+ efa->e3->tmp.f = efa;
+ if(efa->e4) efa->e4->tmp.f = efa;
+ }
+ /* make the faces */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & flag) {
+ if(eed->v1->tmp.v == NULL)
+ eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
+ if(eed->v2->tmp.v == NULL)
+ eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
+
+ if(eed->dir==1)
+ addfacelist(em, eed->v1, eed->v2,
+ eed->v2->tmp.v, eed->v1->tmp.v,
+ eed->tmp.f, NULL);
+ else
+ addfacelist(em, eed->v2, eed->v1,
+ eed->v1->tmp.v, eed->v2->tmp.v,
+ eed->tmp.f, NULL);
+
+ /* for transform */
+ if(eed->tmp.f) {
+ efa = eed->tmp.f;
+ if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
+ }
+ }
+ }
+ normalize_v3(nor);
+
+ /* set correct selection */
+ EM_clear_flag_all(em, SELECT);
+ for(eve= em->verts.last; eve; eve= eve->prev) {
+ if(eve->tmp.v) {
+ eve->tmp.v->f |= flag;
+ }
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
+ }
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
+ return 'n'; // n is for normal constraint
+}
+#endif
+
+/* extrudes individual vertices */
+short EDBM_Extrude_verts_indiv(BMEditMesh *em, wmOperator *op, short flag, float *UNUSED(nor))
+{
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "extrude_vert_indiv verts=%hv", flag);
+
+ /*deselect original verts*/
+ BMO_UnHeaderFlag_Buffer(em->bm, &bmop, "verts", BM_SELECT, BM_VERT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_VERT);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) return 0;
+
+ return 'g'; // g is grab
+}
+
+short EDBM_Extrude_edge(Object *obedit, BMEditMesh *em, int flag, float *nor)
+{
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMOIter siter;
+ BMOperator extop;
+ BMVert *vert;
+ BMEdge *edge;
+ BMFace *f;
+ ModifierData *md;
+ BMHeader *el;
+
+ BMO_Init_Op(&extop, "extrudefaceregion");
+ BMO_HeaderFlag_To_Slot(bm, &extop, "edgefacein",
+ flag, BM_VERT|BM_EDGE|BM_FACE);
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ md = obedit->modifiers.first;
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ invert_m4_m4(imtx, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, obedit->obmat, imtx);
+ }
+
+ for (edge=BMIter_New(&iter,bm,BM_EDGES_OF_MESH,NULL);
+ edge; edge=BMIter_Step(&iter))
+ {
+ if(edge->head.flag & flag) {
+ float co1[3], co2[3];
+
+ copy_v3_v3(co1, edge->v1->co);
+ copy_v3_v3(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ mul_v3_m4v3(co1, mtx, co1);
+ mul_v3_m4v3(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(co1[0]) < mmd->tolerance) &&
+ (fabs(co2[0]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(co1[1]) < mmd->tolerance) &&
+ (fabs(co2[1]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(co1[2]) < mmd->tolerance) &&
+ (fabs(co2[2]) < mmd->tolerance) )
+ BMO_Insert_MapPointer(bm, &extop, "exclude", edge, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ BM_ITER(vert, &iter, bm, BM_VERTS_OF_MESH, NULL) {
+ BM_Select(bm, vert, 0);
+ }
+
+ BM_ITER(edge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+ BM_Select(bm, edge, 0);
+ }
+
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BM_Select(bm, f, 0);
+ }
+
+ BMO_Exec_Op(bm, &extop);
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ BMO_ITER(el, &siter, bm, &extop, "geomout", BM_ALL) {
+ BM_Select(bm, el, 1);
+
+ if (el->type == BM_FACE) {
+ f = (BMFace*)el;
+ add_normal_aligned(nor, f->no);
+ };
+ }
+
+ normalize_v3(nor);
+
+ BMO_Finish_Op(bm, &extop);
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+ return 'n'; // normal constraint
+
+}
+short EDBM_Extrude_vert(Object *obedit, BMEditMesh *em, short flag, float *nor)
+{
+ BMIter iter;
+ BMEdge *eed;
+
+ /*ensure vert flags are consistent for edge selections*/
+ eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; eed; eed=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(eed, flag)) {
+ if (flag != BM_SELECT) {
+ BM_SetHFlag(eed->v1, flag);
+ BM_SetHFlag(eed->v2, flag);
+ } else {
+ BM_Select(em->bm, eed->v1, 1);
+ BM_Select(em->bm, eed->v2, 1);
+ }
+ } else {
+ if (BM_TestHFlag(eed->v1, flag) && BM_TestHFlag(eed->v2, flag)) {
+ if (flag != BM_SELECT)
+ BM_SetHFlag(eed, flag);
+ else BM_Select(em->bm, eed, 1);
+ }
+ }
+ }
+
+ return EDBM_Extrude_edge(obedit, em, flag, nor);
+
+}
+
+static int extrude_repeat_mesh(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+
+ int steps = RNA_int_get(op->ptr,"steps");
+
+ float offs = RNA_float_get(op->ptr,"offset");
+ float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a;
+
+ /* dvec */
+ dvec[0]= rv3d->persinv[2][0];
+ dvec[1]= rv3d->persinv[2][1];
+ dvec[2]= rv3d->persinv[2][2];
+ normalize_v3(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ copy_m3_m4(bmat, obedit->obmat);
+ invert_m3_m3(tmat, bmat);
+ mul_m3_v3(tmat, dvec);
+
+ for(a=0; a<steps; a++) {
+ EDBM_Extrude_edge(obedit, em, BM_SELECT, nor);
+ //BMO_CallOpf(em->bm, "extrudefaceregion edgefacein=%hef", BM_SELECT);
+ BMO_CallOpf(em->bm, "translate vec=%v verts=%hv", (float*)dvec, BM_SELECT);
+ //extrudeflag(obedit, em, SELECT, nor);
+ //translateflag(em, SELECT, dvec);
+ }
+
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_repeat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Repeat Mesh";
+ ot->description= "Extrude selected vertices, edges or faces repeatedly.";
+ ot->idname= "MESH_OT_extrude_repeat";
+
+ /* api callbacks */
+ ot->exec= extrude_repeat_mesh;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, FLT_MAX);
+ RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, INT_MAX);
+}
+
+/* generic extern called extruder */
+int EDBM_Extrude_Mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOperator *op, float *norin)
+{
+ short nr, transmode= 0;
+ float stacknor[3] = {0.0f, 0.0f, 0.0f};
+ float *nor = norin ? norin : stacknor;
+
+ nor[0] = nor[1] = nor[2] = 0.0f;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(em->bm->totvertsel==0) nr= 0;
+ else if(em->bm->totvertsel==1) nr= 4;
+ else if(em->bm->totedgesel==0) nr= 4;
+ else if(em->bm->totfacesel==0)
+ nr= 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(em->bm->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(em->selectmode & SCE_SELECT_EDGE) {
+ if (em->bm->totedgesel==0) nr = 0;
+
+ nr = 1;
+ /*else if (em->totedgesel==1) nr = 3;
+ else if(em->totfacesel==0) nr = 3;
+ else if(em->totfacesel==1)
+ nr= 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ */
+ }
+ else {
+ if (em->bm->totfacesel == 0) nr = 0;
+ else if (em->bm->totfacesel == 1) nr = 1;
+ else
+ nr= 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return 'g';
+
+ if(nr==1 && em->selectmode & SCE_SELECT_VERTEX)
+ transmode= EDBM_Extrude_vert(obedit, em, SELECT, nor);
+ else if (nr == 1) transmode= EDBM_Extrude_edge(obedit, em, SELECT, nor);
+ else if(nr==4) transmode= EDBM_Extrude_verts_indiv(em, op, SELECT, nor);
+ else if(nr==3) transmode= EDBM_Extrude_edges_indiv(em, op, SELECT, nor);
+ else transmode= EDBM_Extrude_face_indiv(em, op, SELECT, nor);
+
+ if(transmode==0) {
+ BKE_report(op->reports, RPT_ERROR, "Not a valid selection for extrude");
+ }
+ else {
+
+ /* We need to force immediate calculation here because
+ * transform may use derived objects (which are now stale).
+ *
+ * This shouldn't be necessary, derived queries should be
+ * automatically building this data if invalid. Or something.
+ */
+// DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+ object_handle_update(scene, obedit);
+
+ /* individual faces? */
+// BIF_TransformSetUndo("Extrude");
+ if(nr==2) {
+// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
+// Transform();
+ }
+ else {
+// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
+ if(transmode=='n') {
+ mul_m4_v3(obedit->obmat, nor);
+ sub_v3_v3v3(nor, nor, obedit->obmat[3]);
+// BIF_setSingleAxisConstraint(nor, "along normal");
+ }
+// Transform();
+ }
+ }
+
+ return transmode;
+}
+
+/* extrude without transform */
+static int mesh_extrude_region_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ EDBM_Extrude_Mesh(scene, obedit, em, op, NULL);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Region";
+ ot->idname= "MESH_OT_extrude_region";
+
+ /* api callbacks */
+ //ot->invoke= mesh_extrude_region_invoke;
+ ot->exec= mesh_extrude_region_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_verts_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_verts_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_verts_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Only Vertices";
+ ot->idname= "MESH_OT_extrude_verts_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_verts_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_edges_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_edges_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_edges_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Only Edges";
+ ot->idname= "MESH_OT_extrude_edges_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_edges_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+static int mesh_extrude_faces_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+ float nor[3];
+
+ EDBM_Extrude_face_indiv(em, op, BM_SELECT, nor);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_extrude_faces_indiv(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Extrude Individual Faces";
+ ot->idname= "MESH_OT_extrude_faces_indiv";
+
+ /* api callbacks */
+ ot->exec= mesh_extrude_faces_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+/* ******************** (de)select all operator **************** */
+
+void EDBM_toggle_select_all(BMEditMesh *em) /* exported for UV */
+{
+ if(em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel)
+ EDBM_clear_flag_all(em, SELECT);
+ else
+ EDBM_set_flag_all(em, SELECT);
+}
+
+static int toggle_select_all_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ EDBM_toggle_select_all(em);
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select/Deselect All";
+ ot->idname= "MESH_OT_select_all";
+ ot->description= "(de)select all vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= toggle_select_all_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/* *************** add-click-mesh (extrude) operator ************** */
+
+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;
+
+ em_setup_viewcontext(C, &vc);
+
+ INIT_MINMAX(min, max);
+
+ BM_ITER_SELECT(v1, &iter, vc.em->bm, BM_VERTS_OF_MESH, NULL)
+ DO_MINMAX(v1->co, min, max);
+ done= 1;
+ }
+
+ /* call extrude? */
+ if(done) {
+ BMEdge *eed;
+ float vec[3], cent[3], mat[3][3];
+ float nor[3]= {0.0, 0.0, 0.0};
+
+ /* check for edges that are half selected, use for rotation */
+ done= 0;
+ BM_ITER(eed, &iter, vc.em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(eed->v1, BM_SELECT) ^ BM_TestHFlag(eed->v2, BM_SELECT)) {
+ if(BM_TestHFlag(eed->v1, BM_SELECT))
+ sub_v3_v3v3(vec, eed->v1->co, eed->v2->co);
+ else
+ sub_v3_v3v3(vec, eed->v2->co, eed->v1->co);
+ add_v3_v3v3(nor, nor, vec);
+ done= 1;
+ }
+ }
+ if(done) normalize_v3(nor);
+
+ /* center */
+ add_v3_v3v3(cent, min, max);
+ mul_v3_fl(cent, 0.5f);
+ VECCOPY(min, cent);
+
+ mul_m4_v3(vc.obedit->obmat, min); // view space
+ 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
+
+ sub_v3_v3v3(min, min, cent);
+
+ /* calculate rotation */
+ unit_m3(mat);
+ if(done) {
+ float dot;
+
+ VECCOPY(vec, min);
+ normalize_v3(vec);
+ dot= INPR(vec, nor);
+
+ if( fabs(dot)<0.999) {
+ float cross[3], si, q1[4];
+
+ cross_v3_v3v3(cross, nor, vec);
+ normalize_v3(cross);
+ dot= 0.5f*saacos(dot);
+ 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);
+ }
+ }
+
+
+ EDBM_Extrude_edge(vc.obedit, vc.em, SELECT, nor);
+ EDBM_CallOpf(vc.em, op, "rotate verts=%hv cent=%v mat=%m3",
+ BM_SELECT, cent, mat);
+ EDBM_CallOpf(vc.em, op, "translate verts=%hv vec=%v",
+ BM_SELECT, min);
+ }
+ else {
+ float *curs= give_cursor(vc.scene, vc.v3d);
+ BMOperator bmop;
+ BMOIter oiter;
+
+ VECCOPY(min, curs);
+
+ view3d_get_view_aligned_coordinate(&vc, min, event->mval, 0);
+ invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
+ mul_m4_v3(vc.obedit->imat, min); // back in object space
+
+ EDBM_InitOpf(vc.em, &bmop, op, "makevert co=%v", min);
+ BMO_Exec_Op(vc.em->bm, &bmop);
+
+ BMO_ITER(v1, &oiter, vc.em->bm, &bmop, "newvertout", BM_VERT) {
+ BM_Select(vc.em->bm, v1, 1);
+ }
+
+ if (!EDBM_FinishOp(vc.em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+ }
+
+ //retopo_do_all();
+ 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;
+}
+
+static int delete_mesh(bContext *C, Object *obedit, wmOperator *op, int event, Scene *UNUSED(scene))
+{
+ BMEditMesh *bem = ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(event<1) return OPERATOR_CANCELLED;
+
+ if(event==10 ) {
+ //"Erase Vertices";
+
+ if (!EDBM_CallOpf(bem, op, "del geom=%hv context=%i", BM_SELECT, DEL_VERTS))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==11) {
+ //"Edge Loop"
+ if (!EDBM_CallOpf(bem, op, "dissolveedgeloop edges=%he", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==7) {
+ //"Dissolve"
+ if (bem->selectmode & SCE_SELECT_FACE) {
+ if (!EDBM_CallOpf(bem, op, "dissolvefaces faces=%hf",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_EDGE) {
+ if (!EDBM_CallOpf(bem, op, "dissolveedges edges=%he",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ } else if (bem->selectmode & SCE_SELECT_VERTEX) {
+ if (!EDBM_CallOpf(bem, op, "dissolveverts verts=%hv",BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+ }
+ else if(event==4) {
+ //Edges and Faces
+ if (!EDBM_CallOpf(bem, op, "del geom=%hef context=%i", BM_SELECT, DEL_EDGESFACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==1) {
+ //"Erase Edges"
+ if (!EDBM_CallOpf(bem, op, "del geom=%he context=%i", BM_SELECT, DEL_EDGES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==2) {
+ //"Erase Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%i", BM_SELECT, DEL_FACES))
+ return OPERATOR_CANCELLED;
+ }
+ else if(event==5) {
+ //"Erase Only Faces";
+ if (!EDBM_CallOpf(bem, op, "del geom=%hf context=%d",
+ BM_SELECT, DEL_ONLYFACES))
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Note, these values must match delete_mesh() event values */
+static EnumPropertyItem prop_mesh_delete_types[] = {
+ {7, "DISSOLVE", 0, "Dissolve", ""},
+ {12, "COLLAPSE", 0, "Collapse", ""},
+ {10,"VERT", 0, "Vertices", ""},
+ {1, "EDGE", 0, "Edges", ""},
+ {2, "FACE", 0, "Faces", ""},
+ {11, "EDGE_LOOP", 0, "Edge Loop", ""},
+ {4, "EDGE_FACE", 0, "Edges & Faces", ""},
+ {5, "ONLY_FACE", 0, "Only Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int delete_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+ Scene *scene = CTX_data_scene(C);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (type != 12) {
+ delete_mesh(C, obedit, op, type, scene);
+ } else {
+ if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+
+
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Delete";
+ ot->description= "Delete selected vertices, edges or faces.";
+ ot->idname= "MESH_OT_delete";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= delete_mesh_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /*props */
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
+}
+
+
+static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
+{
+ BMOperator bmop;
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "contextual_create geom=%hfev", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "faceout", BM_SELECT, BM_FACE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_face_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Edge/Face";
+ ot->description= "Add an edge or face to selected.";
+ ot->idname= "MESH_OT_edge_face_add";
+
+ /* api callbacks */
+ ot->exec= addedgeface_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+}
+
+static EnumPropertyItem prop_mesh_edit_types[] = {
+ {1, "VERT", 0, "Vertices", ""},
+ {2, "EDGE", 0, "Edges", ""},
+ {3, "FACE", 0, "Faces", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int mesh_selection_type_exec(bContext *C, wmOperator *op)
+{
+
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int type = RNA_enum_get(op->ptr,"type");
+
+ switch (type) {
+ case 1:
+ em->selectmode = SCE_SELECT_VERTEX;
+ break;
+ case 2:
+ em->selectmode = SCE_SELECT_EDGE;
+ break;
+ case 3:
+ em->selectmode = SCE_SELECT_FACE;
+ break;
+ }
+
+ EDBM_selectmode_set(em);
+ CTX_data_tool_settings(C)->selectmode = em->selectmode;
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_selection_type(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Selection Mode";
+ ot->description= "Set the selection mode type.";
+ ot->idname= "MESH_OT_selection_type";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= mesh_selection_type_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
+ RNA_def_boolean(ot->srna, "inclusive", 0, "Inclusive", "Selects geometry around selected geometry, occording to selection mode");
+}
+
+/* ************************* SEAMS AND EDGES **************** */
+
+static int editbmesh_mark_seam(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= ((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ /* auto-enable seams drawing */
+ if(clear==0) {
+ me->drawflag |= ME_DRAWSEAMS;
+ }
+
+ if(clear) {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_ClearHFlag(eed, BM_SEAM);
+ }
+ }
+ else {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_SetHFlag(eed, BM_SEAM);
+ }
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_seam(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Seam";
+ ot->idname= "MESH_OT_mark_seam";
+ ot->description= "(un)mark selected edges as a seam.";
+
+ /* api callbacks */
+ ot->exec= editbmesh_mark_seam;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+static int editbmesh_mark_sharp(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= ((Mesh *)obedit->data);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMEdge *eed;
+ BMIter iter;
+ int clear = RNA_boolean_get(op->ptr, "clear");
+
+ /* auto-enable sharp edge drawing */
+ if(clear == 0) {
+ me->drawflag |= ME_DRAWSHARP;
+ }
+
+ if(!clear) {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_SetHFlag(eed, BM_SHARP);
+ }
+ } else {
+ BM_ITER_SELECT(eed, &iter, bm, BM_EDGES_OF_MESH, NULL)
+ BM_ClearHFlag(eed, BM_SHARP);
+ }
+ }
+
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_sharp(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Mark Sharp";
+ ot->idname= "MESH_OT_mark_sharp";
+ ot->description= "(un)mark selected edges as sharp.";
+
+ /* api callbacks */
+ ot->exec= editbmesh_mark_sharp;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
+}
+
+
+static int editbmesh_vert_connect(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ int len = 0;
+
+ BMO_InitOpf(bm, &bmop, "connectverts verts=%hv", BM_SELECT);
+ BMO_Exec_Op(bm, &bmop);
+ len = BMO_GetSlot(&bmop, "edgeout")->len;
+ BMO_Finish_Op(bm, &bmop);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void MESH_OT_vert_connect(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Connect";
+ ot->idname= "MESH_OT_vert_connect";
+
+ /* api callbacks */
+ ot->exec= editbmesh_vert_connect;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int editbmesh_edge_split(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ int len = 0;
+
+ BMO_InitOpf(bm, &bmop, "edgesplit edges=%he numcuts=%d", BM_SELECT, RNA_int_get(op->ptr,"number_cuts"));
+ BMO_Exec_Op(bm, &bmop);
+ len = BMO_GetSlot(&bmop, "outsplit")->len;
+ BMO_Finish_Op(bm, &bmop);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return len ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
+
+void MESH_OT_edge_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Edge Split";
+ ot->idname= "MESH_OT_edge_split";
+
+ /* api callbacks */
+ ot->exec= editbmesh_edge_split;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "number_cuts", 1, 1, 10, "Number of Cuts", "", 1, INT_MAX);
+}
+
+/****************** add duplicate operator ***************/
+
+static int mesh_duplicate_exec(bContext *C, wmOperator *op)
+{
+ Object *ob= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ EDBM_InitOpf(em, &bmop, op, "dupe geom=%hvef", BM_SELECT);
+
+ BMO_Exec_Op(em->bm, &bmop);
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "newout", BM_SELECT, BM_ALL);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+ WM_cursor_wait(1);
+ mesh_duplicate_exec(C, op);
+ WM_cursor_wait(0);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_duplicate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Duplicate";
+ ot->description= "Duplicate selected vertices, edges or faces.";
+ ot->idname= "MESH_OT_duplicate";
+
+ /* api callbacks */
+ ot->invoke= mesh_duplicate_invoke;
+ ot->exec= mesh_duplicate_exec;
+
+ ot->poll= ED_operator_editmesh;
+
+ /* to give to transform */
+ RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
+}
+
+static int flip_normals(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "reversefaces faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_flip_normals(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Flip Normals";
+ ot->description= "Flip the direction of selected face's vertex and face normals";
+ ot->idname= "MESH_OT_flip_normals";
+
+ /* api callbacks */
+ ot->exec= flip_normals;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+float *bm_get_cd_float(CustomData *cdata, void *data, int type)
+{
+ float *f = CustomData_bmesh_get(cdata, data, type);
+
+ return f;
+}
+
+static const EnumPropertyItem direction_items[]= {
+ {DIRECTION_CW, "CW", 0, "Clockwise", ""},
+ {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+/* only accepts 1 selected edge, or 2 selected faces */
+static int edge_rotate_selected(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ BMEdge *eed;
+ BMIter iter;
+ int ccw = RNA_int_get(op->ptr, "direction") == 1; // direction == 2 when clockwise and ==1 for counter CW.
+
+ if (!(em->bm->totfacesel == 2 || em->bm->totedgesel == 1)) {
+ BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+ return OPERATOR_CANCELLED;
+ }
+
+ /*first see if we have two adjacent faces*/
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_Edge_FaceCount(eed) == 2) {
+ if ((BM_TestHFlag(eed->l->f, BM_SELECT) && BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_SELECT))
+ && !(BM_TestHFlag(eed->l->f, BM_HIDDEN) || BM_TestHFlag(((BMLoop*)eed->l->radial_next)->f, BM_HIDDEN)))
+ {
+ break;
+ }
+ }
+ }
+
+ /*ok, we don't have two adjacent faces, but we do have two selected ones.
+ that's an error condition.*/
+ if (!eed && em->bm->totfacesel == 2) {
+ BKE_report(op->reports, RPT_ERROR, "Select one edge or two adjacent faces");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!eed) {
+ BM_ITER_SELECT(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL)
+ if (BM_TestHFlag(eed, BM_SELECT))
+ break;
+ }
+ }
+
+ /*this should never happen*/
+ if (!eed)
+ return OPERATOR_CANCELLED;
+
+ EDBM_InitOpf(em, &bmop, op, "edgerotate edges=%e ccw=%d", eed, ccw);
+ BMO_Exec_Op(em->bm, &bmop);
+
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "edgeout", BM_SELECT, BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate Selected Edge";
+ ot->description= "Rotate selected edge or adjoining faces.";
+ ot->idname= "MESH_OT_edge_rotate";
+
+ /* api callbacks */
+ ot->exec= edge_rotate_selected;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "direction", "direction to rotate edge around.");
+}
+
+/* pinning code */
+
+/* swap is 0 or 1, if 1 it pins not selected */
+void EDBM_pin_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *h;
+ int itermode;
+
+ if(em==NULL) return;
+
+ if (em->selectmode & SCE_SELECT_VERTEX)
+ itermode = BM_VERTS_OF_MESH;
+ else if (em->selectmode & SCE_SELECT_EDGE)
+ itermode = BM_EDGES_OF_MESH;
+ else
+ itermode = BM_FACES_OF_MESH;
+
+ BM_ITER(h, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(h, BM_SELECT) ^ swap)
+ BM_Pin(em->bm, h, 1);
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int pin_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ Mesh *me= ((Mesh *)obedit->data);
+
+ me->drawflag |= ME_DRAW_PINS;
+
+ EDBM_pin_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_pin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Pin Selection";
+ ot->idname= "MESH_OT_pin";
+
+ /* api callbacks */
+ ot->exec= pin_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Pin (un)selected vertices, edges or faces.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Pin unselected rather than selected.");
+}
+
+/* swap is 0 or 1, if 1 it unhides not selected */
+void EDBM_unpin_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *ele;
+ 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(ele, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(ele, BM_SELECT) ^ swap)
+ BM_Pin(em->bm, ele, 0);
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int unpin_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_unpin_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_unpin(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Unpin Selection";
+ ot->idname= "MESH_OT_unpin";
+ ot->description= "Unpin (un)selected vertices, edges or faces.";
+
+ /* api callbacks */
+ ot->exec= unpin_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unpin unselected rather than selected.");
+}
+
+
+/* swap is 0 or 1, if 1 it hides not selected */
+void EDBM_hide_mesh(BMEditMesh *em, int swap)
+{
+ BMIter iter;
+ BMHeader *h;
+ int itermode;
+
+ if(em==NULL) return;
+
+ if (em->selectmode & SCE_SELECT_VERTEX)
+ itermode = BM_VERTS_OF_MESH;
+ else if (em->selectmode & SCE_SELECT_EDGE)
+ itermode = BM_EDGES_OF_MESH;
+ else
+ itermode = BM_FACES_OF_MESH;
+
+ BM_ITER(h, &iter, em->bm, itermode, NULL) {
+ if (BM_TestHFlag(h, BM_SELECT) ^ swap)
+ BM_Hide(em->bm, h, 1);
+ }
+
+ /*original hide flushing comment (OUTDATED):
+ hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
+ /* - vertex hidden, always means edge is hidden too
+ - edge hidden, always means face is hidden too
+ - face hidden, only set face hide
+ - then only flush back down what's absolute hidden
+ */
+
+}
+
+static int hide_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_hide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Hide Selection";
+ ot->idname= "MESH_OT_hide";
+
+ /* api callbacks */
+ ot->exec= hide_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+ ot->description= "Hide (un)selected vertices, edges or faces.";
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
+}
+
+
+void EDBM_reveal_mesh(BMEditMesh *em)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int sels[3] = {1, !(em->selectmode & SCE_SELECT_VERTEX), !(em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE))};
+
+ for (i=0; i<3; i++) {
+ BM_ITER(ele, &iter, em->bm, types[i], NULL) {
+ if (BM_TestHFlag(ele, BM_HIDDEN)) {
+ BM_Hide(em->bm, ele, 0);
+
+ if (sels[i])
+ BM_Select(em->bm, ele, 1);
+ }
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+}
+
+static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+
+ EDBM_reveal_mesh(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_reveal(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reveal Hidden";
+ ot->idname= "MESH_OT_reveal";
+ ot->description= "Reveal all hidden vertices, edges and faces.";
+
+ /* api callbacks */
+ ot->exec= reveal_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int normals_make_consistent_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ /*doflip has to do with bmesh_rationalize_normals, it's an internal
+ thing*/
+ if (!EDBM_CallOpf(em, op, "righthandfaces faces=%hf doflip=%d", BM_SELECT, 1))
+ return OPERATOR_CANCELLED;
+
+ if (RNA_boolean_get(op->ptr, "inside"))
+ EDBM_CallOpf(em, op, "reversefaces faces=%hf doflip=%d", BM_SELECT, 1);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_normals_make_consistent(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Make Normals Consistent";
+ ot->description= "Make face and vertex normals point either outside or inside the mesh";
+ ot->idname= "MESH_OT_normals_make_consistent";
+
+ /* api callbacks */
+ ot->exec= normals_make_consistent_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+}
+
+
+
+static int do_smooth_vertex(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ ModifierData *md;
+ int mirrx=0, mirry=0, mirrz=0;
+ int i, repeat;
+
+ /* if there is a mirror modifier with clipping, flag the verts that
+ * are within tolerance of the plane(s) of reflection
+ */
+ for(md=obedit->modifiers.first; md; md=md->next) {
+ if(md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ mirrx = 1;
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ mirry = 1;
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ mirrz = 1;
+ }
+ }
+ }
+
+ repeat = RNA_int_get(op->ptr,"repeat");
+ if (!repeat)
+ repeat = 1;
+
+ for (i=0; i<repeat; i++) {
+ if (!EDBM_CallOpf(em, op, "vertexsmooth verts=%hv mirror_clip_x=%d mirror_clip_y=%d mirror_clip_z=%d",
+ BM_SELECT, mirrx, mirry, mirrz))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ //BMESH_TODO: need to handle the x-axis editing option here properly.
+ //should probably make a helper function for that? I dunno.
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Smooth Vertex";
+ ot->description= "Flatten angles of selected vertices.";
+ ot->idname= "MESH_OT_vertices_smooth";
+
+ /* api callbacks */
+ ot->exec= do_smooth_vertex;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
+}
+
+
+static int bm_test_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMIter iter;
+ BMEdge *e;
+
+ /*hide all back edges*/
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (!BM_TestHFlag(e, BM_SELECT))
+ continue;
+
+ if (!BMBVH_EdgeVisible(tree, e, ar, v3d, obedit))
+ BM_Select(em->bm, e, 0);
+ }
+
+ BMBVH_FreeBVH(tree);
+
+#if 0 //uv island walker test
+ BMIter iter, liter;
+ BMFace *f;
+ BMLoop *l, *l2;
+ MLoopUV *luv;
+ BMWalker walker;
+ int i=0;
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ }
+ }
+
+ BMW_Init(&walker, em->bm, BMW_UVISLAND, 0);
+
+ BM_ITER(f, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if (luv->flag & MLOOPUV_VERTSEL) {
+ l2 = BMW_Begin(&walker, l);
+ for (; l2; l2=BMW_Step(&walker)) {
+ luv = CustomData_bmesh_get(&em->bm->ldata, l2->head.data, CD_MLOOPUV);
+ luv->flag |= MLOOPUV_VERTSEL;
+ }
+ }
+ }
+ }
+
+ BMW_End(&walker);
+#endif
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_bm_test(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "BMesh Test Operator";
+ ot->idname= "MESH_OT_bm_test";
+
+ /* api callbacks */
+ ot->exec= bm_test_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ //RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
+}
+
+/********************** Smooth/Solid Operators *************************/
+
+void mesh_set_smooth_faces(BMEditMesh *em, short smooth)
+{
+ BMIter iter;
+ BMFace *efa;
+
+ if(em==NULL) return;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if (BM_TestHFlag(efa, BM_SELECT)) {
+ if (smooth)
+ BM_SetHFlag(efa, BM_SMOOTH);
+ else
+ BM_ClearHFlag(efa, BM_SMOOTH);
+ }
+ }
+}
+
+static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ mesh_set_smooth_faces(em, 1);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shade Smooth";
+ ot->description= "Display faces smooth (using vertex normals).";
+ ot->idname= "MESH_OT_faces_shade_smooth";
+
+ /* api callbacks */
+ ot->exec= mesh_faces_shade_smooth_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ mesh_set_smooth_faces(em, 0);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_faces_shade_flat(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shade Flat";
+ ot->description= "Display faces flat.";
+ ot->idname= "MESH_OT_faces_shade_flat";
+
+ /* api callbacks */
+ ot->exec= mesh_faces_shade_flat_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+/********************** UV/Color Operators *************************/
+
+
+static const EnumPropertyItem axis_items[]= {
+ {OPUVC_AXIS_X, "X", 0, "X", ""},
+ {OPUVC_AXIS_Y, "Y", 0, "Y", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+static int mesh_rotate_uvs(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the direction from RNA */
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshrotateuvs faces=%hf dir=%d", BM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_reverse_uvs(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshreverseuvs faces=%hf", BM_SELECT);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+static int mesh_rotate_colors(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* get the direction from RNA */
+ int dir = RNA_enum_get(op->ptr, "direction");
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+
+ /* dependencies graph and notification stuff */
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
+*/
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+}
+
+
+static int mesh_reverse_colors(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+#if 0
+ Scene *scene= CTX_data_scene(C);
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ EditFace *efa;
+ short change = 0;
+ MCol tmpcol, *mcol;
+ int axis= RNA_enum_get(op->ptr, "axis");
+
+ if (!EM_vertColorCheck(em)) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ if (axis == AXIS_Y) {
+ tmpcol= mcol[1];
+ mcol[1]= mcol[2];
+ mcol[2]= tmpcol;
+
+ if(efa->v4) {
+ tmpcol= mcol[0];
+ mcol[0]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ } else {
+ tmpcol= mcol[0];
+ mcol[0]= mcol[1];
+ mcol[1]= tmpcol;
+
+ if(efa->v4) {
+ tmpcol= mcol[2];
+ mcol[2]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ }
+ change = 1;
+ }
+ }
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ if(!change)
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_uvs_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate UVs";
+ ot->idname= "MESH_OT_uvs_rotate";
+
+ /* api callbacks */
+ ot->exec= mesh_rotate_uvs;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
+}
+
+//void MESH_OT_uvs_mirror(wmOperatorType *ot)
+void MESH_OT_uvs_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reverse UVs";
+ ot->idname= "MESH_OT_uvs_reverse";
+
+ /* api callbacks */
+ ot->exec= mesh_reverse_uvs;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
+}
+
+void MESH_OT_colors_rotate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rotate Colors";
+ ot->idname= "MESH_OT_colors_rotate";
+
+ /* api callbacks */
+ ot->exec= mesh_rotate_colors;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
+}
+
+void MESH_OT_colors_reverse(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Reverse Colors";
+ ot->idname= "MESH_OT_colors_reverse";
+
+ /* api callbacks */
+ ot->exec= mesh_reverse_colors;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ //RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
+}
+
+
+static int merge_firstlast(BMEditMesh *em, int first, int uvmerge, wmOperator *wmop)
+{
+ BMVert *mergevert;
+ BMEditSelection *ese;
+
+ /* do sanity check in mergemenu in edit.c ?*/
+ if(first == 0){
+ ese = em->bm->selected.last;
+ mergevert= (BMVert*)ese->data;
+ }
+ else{
+ ese = em->bm->selected.first;
+ mergevert = (BMVert*)ese->data;
+ }
+
+ if (!BM_TestHFlag(mergevert, BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ if (uvmerge) {
+ if (!EDBM_CallOpf(em, wmop, "pointmerge_facedata verts=%hv snapv=%e", BM_SELECT, mergevert))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, mergevert->co))
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
+}
+
+static int merge_target(BMEditMesh *em, Scene *scene, View3D *v3d, Object *ob,
+ int target, int uvmerge, wmOperator *wmop)
+{
+ BMIter iter;
+ BMVert *v;
+ float *vco=NULL, co[3], cent[3] = {0.0f, 0.0f, 0.0f}, fac;
+ int i;
+
+ if (target) {
+ vco = give_cursor(scene, v3d);
+ VECCOPY(co, vco);
+ mul_m4_v3(ob->imat, co);
+ } else {
+ i = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(v, BM_SELECT))
+ continue;
+ VECADD(cent, cent, v->co);
+ i++;
+ }
+
+ if (!i)
+ return OPERATOR_CANCELLED;
+
+ fac = 1.0f / (float)i;
+ mul_v3_fl(cent, fac);
+ copy_v3_v3(co, cent);
+ vco = co;
+ }
+
+ if (!vco)
+ return OPERATOR_CANCELLED;
+
+ if (uvmerge) {
+ if (!EDBM_CallOpf(em, wmop, "vert_average_facedata verts=%hv", BM_SELECT))
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_CallOpf(em, wmop, "pointmerge verts=%hv mergeco=%v", BM_SELECT, co))
+ return OPERATOR_CANCELLED;
+
+ return OPERATOR_FINISHED;
+}
+
+static int merge_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene= CTX_data_scene(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int status= 0, uvs= RNA_boolean_get(op->ptr, "uvs");
+
+ switch(RNA_enum_get(op->ptr, "type")) {
+ case 3:
+ status = merge_target(em, scene, v3d, obedit, 0, uvs, op);
+ break;
+ case 4:
+ status = merge_target(em, scene, v3d, obedit, 1, uvs, op);
+ break;
+ case 1:
+ status = merge_firstlast(em, 0, uvs, op);
+ break;
+ case 6:
+ status = merge_firstlast(em, 1, uvs, op);
+ break;
+ case 5:
+ status = 1;
+ if (!EDBM_CallOpf(em, op, "collapse edges=%he", BM_SELECT))
+ status = 0;
+ break;
+ }
+
+ if(!status)
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem merge_type_items[]= {
+ {6, "FIRST", 0, "At First", ""},
+ {1, "LAST", 0, "At Last", ""},
+ {3, "CENTER", 0, "At Center", ""},
+ {4, "CURSOR", 0, "At Cursor", ""},
+ {5, "COLLAPSE", 0, "Collapse", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+static EnumPropertyItem *merge_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
+{
+ Object *obedit;
+ EnumPropertyItem *item= NULL;
+ int totitem= 0;
+
+ if(!C) /* needed for docs */
+ return merge_type_items;
+
+ obedit= CTX_data_edit_object(C);
+ if(obedit && obedit->type == OB_MESH) {
+ BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
+
+ if(em->selectmode & SCE_SELECT_VERTEX) {
+ if(em->bm->selected.first && em->bm->selected.last &&
+ ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT) {
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ }
+ else if(em->bm->selected.first && ((BMEditSelection*)em->bm->selected.first)->type == BM_VERT)
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
+ else if(em->bm->selected.last && ((BMEditSelection*)em->bm->selected.last)->type == BM_VERT)
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
+ }
+
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
+ RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
+ RNA_enum_item_end(&item, &totitem);
+
+ *free= 1;
+
+ return item;
+ }
+
+ return NULL;
+}
+
+void MESH_OT_merge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Merge";
+ ot->idname= "MESH_OT_merge";
+
+ /* api callbacks */
+ ot->exec= merge_exec;
+ ot->invoke= WM_menu_invoke;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
+ RNA_def_enum_funcs(ot->prop, merge_type_itemf);
+ RNA_def_boolean(ot->srna, "uvs", 1, "UVs", "Move UVs according to merge.");
+}
+
+
+static int removedoublesflag_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ int count;
+
+ EDBM_InitOpf(em, &bmop, op, "finddoubles verts=%hv dist=%f",
+ BM_SELECT, RNA_float_get(op->ptr, "mergedist"));
+ BMO_Exec_Op(em->bm, &bmop);
+
+ count = BMO_CountSlotMap(em->bm, &bmop, "targetmapout");
+
+ if (!EDBM_CallOpf(em, op, "weldverts targetmap=%s", &bmop, "targetmapout")) {
+ BMO_Finish_Op(em->bm, &bmop);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ /*we need a better way of reporting this, since this doesn't work
+ with the last operator panel correctly.
+ if(count)
+ {
+ sprintf(msg, "Removed %d vertices", count);
+ BKE_report(op->reports, RPT_INFO, msg);
+ }
+ */
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_remove_doubles(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Remove Doubles";
+ ot->idname= "MESH_OT_remove_doubles";
+
+ /* api callbacks */
+ ot->exec= removedoublesflag_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "mergedist", 0.0001f, 0.000001f, 50.0f,
+ "Merge Distance",
+ "Minimum distance between elements to merge.", 0.00001, 10.0);
+}
+
+/************************ Vertex Path Operator *************************/
+
+typedef struct PathNode {
+ int u;
+ int visited;
+ ListBase edges;
+} PathNode;
+
+typedef struct PathEdge {
+ struct PathEdge *next, *prev;
+ int v;
+ float w;
+} PathEdge;
+
+
+
+int select_vertex_path_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_edit_object(C);
+ BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
+ BMOperator bmop;
+ BMEditSelection *sv, *ev;
+
+ /* get the type from RNA */
+ int type = RNA_enum_get(op->ptr, "type");
+
+ sv = em->bm->selected.last;
+ if( sv != NULL )
+ ev = sv->prev;
+ else return OPERATOR_CANCELLED;
+ if( ev == NULL )
+ return OPERATOR_CANCELLED;
+
+ if( sv->type != BM_VERT || ev->type != BM_VERT )
+ return OPERATOR_CANCELLED;
+
+ /* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
+ EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type);
+
+ /* execute the operator */
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /* DO NOT clear the existing selection */
+ /* EDBM_clear_flag_all(em, BM_SELECT); */
+
+ /* select the output */
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
+
+ /* finish the operator */
+ if( !EDBM_FinishOp(em, &bmop, op, 1) )
+ return OPERATOR_CANCELLED;
+
+ EDBM_selectmode_flush(em);
+
+ /* dependencies graph and notification stuff */
+/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
+*/
+ DAG_id_tag_update(ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
+
+
+ /* we succeeded */
+ return OPERATOR_FINISHED;
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+ EditVert *eve, *s, *t;
+ EditEdge *eed;
+ EditSelection *ese;
+ PathEdge *newpe, *currpe;
+ PathNode *currpn;
+ PathNode *Q;
+ int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
+ int unbalanced, totnodes;
+ short physical;
+ float *cost;
+ Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
+
+ s = t = NULL;
+
+ ese = ((EditSelection*)em->selected.last);
+ if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
+ physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
+
+ t = (EditVert*)ese->data;
+ s = (EditVert*)ese->prev->data;
+
+ /*need to find out if t is actually reachable by s....*/
+ for(eve=em->verts.first; eve; eve=eve->next){
+ eve->f1 = 0;
+ }
+
+ s->f1 = 1;
+
+ unbalanced = 1;
+ totnodes = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1 && !eed->v2->f1){
+ eed->v2->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ else if(eed->v2->f1 && !eed->v1->f1){
+ eed->v1->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ }
+ }
+ }
+
+ if(s->f1 && t->f1){ /* t can be reached by s */
+ Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
+ totnodes = 0;
+ for(eve=em->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ Q[totnodes].u = totnodes;
+ Q[totnodes].edges.first = 0;
+ Q[totnodes].edges.last = 0;
+ Q[totnodes].visited = 0;
+ eve->tmp.p = &(Q[totnodes]);
+ totnodes++;
+ }
+ else eve->tmp.p = NULL;
+ }
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1){
+ currpn = ((PathNode*)eed->v1->tmp.p);
+
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
+ if(physical){
+ newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ if(eed->v2->f1){
+ currpn = ((PathNode*)eed->v2->tmp.p);
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
+ if(physical){
+ newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ }
+ }
+
+ heap = BLI_heap_new();
+ cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
+ previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
+
+ for(v=0; v < totnodes; v++){
+ cost[v] = 1000000;
+ previous[v] = -1; /*array of indices*/
+ }
+
+ pnindex = ((PathNode*)s->tmp.p)->u;
+ cost[pnindex] = 0;
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
+
+ while( !BLI_heap_empty(heap) ){
+
+ pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
+ currpn = &(Q[pnindex]);
+
+ if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
+ break;
+
+ for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
+ if(!Q[currpe->v].visited){
+ if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
+ cost[currpe->v] = cost[currpn->u] + currpe->w;
+ previous[currpe->v] = currpn->u;
+ Q[currpe->v].visited = 1;
+ BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
+ }
+ }
+ }
+ }
+
+ pathvert = ((PathNode*)t->tmp.p)->u;
+ while(pathvert != -1){
+ for(eve=em->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
+ }
+ }
+ pathvert = previous[pathvert];
+ }
+
+ for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
+ MEM_freeN(Q);
+ MEM_freeN(cost);
+ MEM_freeN(previous);
+ BLI_heap_free(heap, NULL);
+ EM_select_flush(em);
+ }
+ }
+ else {
+ BKE_mesh_end_editmesh(obedit->data, em);
+ BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+}
+
+void MESH_OT_select_vertex_path(wmOperatorType *ot)
+{
+ static const EnumPropertyItem type_items[] = {
+ {VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
+ {VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Select Vertex Path";
+ ot->idname= "MESH_OT_select_vertex_path";
+
+ /* api callbacks */
+ ot->exec= select_vertex_path_exec;
+ ot->invoke= WM_menu_invoke;
+ 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 *************************/
+
+#if 0
+/* 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);
+
+}
+#endif
+
+/* helper to find edge for edge_rip */
+static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, short *mval)
+{
+ float vec1[3], vec2[3], mvalf[2];
+
+ view3d_project_float(ar, co1, vec1, mat);
+ view3d_project_float(ar, co2, vec2, mat);
+ mvalf[0]= (float)mval[0];
+ mvalf[1]= (float)mval[1];
+
+ return dist_to_line_segment_v2(mvalf, vec1, vec2);
+}
+
+/* based on mouse cursor position, it defines how is being ripped */
+static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ ARegion *ar= CTX_wm_region(C);
+ View3D *v3d = CTX_wm_view3d(C);
+ RegionView3D *rv3d= CTX_wm_region_view3d(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+ BMBVHTree *bvhtree;
+ BMOIter siter;
+ BMIter iter, eiter, liter;
+ BMLoop *l;
+ BMEdge *e, *e2, *closest = NULL;
+ BMVert *v;
+ int side = 0, i, singlesel = 0;
+ float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1], 0.0f};
+ float dist = FLT_MAX, d;
+
+ view3d_get_object_project_mat(rv3d, obedit, projectMat);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT))
+ BMINDEX_SET(e, 1);
+ else BMINDEX_SET(e, 0);
+ }
+
+ /*handle case of one vert selected. we identify
+ the closest edge around that vert to the mouse cursor,
+ then rip the two adjacent edges in the vert fan.*/
+ if (em->bm->totvertsel == 1 && em->bm->totedgesel == 0 && em->bm->totfacesel == 0) {
+ singlesel = 1;
+
+ /*find selected vert*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_SELECT))
+ break;
+ }
+
+ /*this should be impossible, but sanity checks are a good thing*/
+ if (!v)
+ return OPERATOR_CANCELLED;
+
+ /*find closest edge to mouse cursor*/
+ e2 = NULL;
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_VERT, v) {
+ d = mesh_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, event->mval);
+ if (d < dist) {
+ dist = d;
+ e2 = e;
+ }
+ }
+
+ if (!e2)
+ return OPERATOR_CANCELLED;
+
+ /*rip two adjacent edges*/
+ if (BM_Edge_FaceCount(e2) == 1) {
+ l = e2->l;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+ } else if (BM_Edge_FaceCount(e2) == 2) {
+ l = e2->l;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+
+ l = e2->l->radial_next;
+ e = BM_OtherFaceLoop(e2, l->f, v)->e;
+ BMINDEX_SET(e, 1);
+ BM_SetHFlag(e, BM_SELECT);
+ }
+
+ dist = FLT_MAX;
+ } else {
+ /*expand edge selection*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BMINDEX_GET(e)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1 && e2->l) {
+ l = BM_OtherFaceLoop(e2, e2->l->f, v);
+ l = (BMLoop*)l->radial_next;
+ l = BM_OtherFaceLoop(l->e, l->f, v);
+
+ if (l)
+ BM_Select(em->bm, l->e, 1);
+ }
+ }
+ }
+
+ if (!EDBM_InitOpf(em, &bmop, op, "edgesplit edges=%he", BM_SELECT)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /*build bvh tree for edge visibility tests*/
+ bvhtree = BMBVH_NewBVH(em);
+
+ for (i=0; i<2; i++) {
+ BMO_ITER(e, &siter, em->bm, &bmop, i ? "edgeout2":"edgeout1", BM_EDGE) {
+ float cent[3] = {0, 0, 0}, mid[4], vec[3];
+
+ if (!BMBVH_EdgeVisible(bvhtree, e, ar, v3d, obedit) || !e->l)
+ continue;
+
+ /*method for calculating distance:
+
+ for each edge: calculate face center, then made a vector
+ from edge midpoint to face center. offset edge midpoint
+ by a small amount along this vector.*/
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, e->l->f) {
+ add_v3_v3v3(cent, cent, l->v->co);
+ }
+ mul_v3_fl(cent, 1.0f/(float)e->l->f->len);
+
+ add_v3_v3v3(mid, e->v1->co, e->v2->co);
+ mul_v3_fl(mid, 0.5f);
+ sub_v3_v3v3(vec, cent, mid);
+ normalize_v3(vec);
+ mul_v3_fl(vec, 0.01f);
+ add_v3_v3v3(mid, mid, vec);
+
+ /*yay we have our comparison point, now project it*/
+ view3d_project_float(ar, mid, mid, projectMat);
+
+ vec[0] = fmval[0] - mid[0];
+ vec[1] = fmval[1] - mid[1];
+ d = vec[0]*vec[0] + vec[1]*vec[1];
+
+ if (d < dist) {
+ side = i;
+ closest = e;
+ dist = d;
+ }
+ }
+ }
+
+ EDBM_clear_flag_all(em, BM_SELECT);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, side?"edgeout2":"edgeout1", BM_SELECT, BM_EDGE);
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_SELECT))
+ BMINDEX_SET(e, 1);
+ else BMINDEX_SET(e, 0);
+ }
+
+ /*constrict edge selection again*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ e2 = NULL;
+ i = 0;
+ BM_ITER(e, &eiter, em->bm, BM_EDGES_OF_VERT, v) {
+ if (BMINDEX_GET(e)) {
+ e2 = e;
+ i++;
+ }
+ }
+
+ if (i == 1) {
+ if (singlesel)
+ BM_Select(em->bm, v, 0);
+ else
+ BM_Select(em->bm, e2, 0);
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1)) {
+ BMBVH_FreeBVH(bvhtree);
+ return OPERATOR_CANCELLED;
+ }
+
+ BMBVH_FreeBVH(bvhtree);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+#if 0 //BMESH_TODO
+ 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, *mval= event->mval;
+
+ /* select flush... vertices are important */
+ EM_selectmode_set(em);
+
+ view3d_get_object_project_mat(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;
+ 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_ERROR, "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_ERROR, "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_ERROR, "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, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+// RNA_enum_set(op->ptr, "proportional", 0);
+// RNA_boolean_set(op->ptr, "mirror", 0);
+// WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
+#endif
+}
+
+void MESH_OT_rip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Rip";
+ ot->idname= "MESH_OT_rip";
+
+ /* api callbacks */
+ ot->invoke= mesh_rip_invoke;
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL);
+ RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
+}
+
+/************************ Shape Operators *************************/
+
+/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
+static void shape_propagate(Object *obedit, BMEditMesh *em, wmOperator *op)
+{
+ BMIter iter;
+ BMVert *eve = NULL;
+ float *co;
+ int i, totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
+
+ if (!CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
+ BKE_report(op->reports, RPT_ERROR, "Mesh does not have shape keys");
+ return;
+ }
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+
+ for (i=0; i<totshape; i++) {
+ co = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, i);
+ VECCOPY(co, eve->co);
+ }
+ }
+
+#if 0
+ //TAG Mesh Objects that share this data
+ for(base = scene->base.first; base; base = base->next){
+ if(base->object && base->object->data == me){
+ base->object->recalc = OB_RECALC_DATA;
+ }
+ }
+#endif
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+}
+
+
+static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= obedit->data;
+ BMEditMesh *em= me->edit_btmesh;
+
+ shape_propagate(obedit, em, op);
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Shape Propagate";
+ ot->description= "Apply selected vertex locations to all other shape keys.";
+ ot->idname= "MESH_OT_shape_propagate_to_all";
+
+ /* api callbacks */
+ ot->exec= shape_propagate_to_all_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/*BMESH_TODO this should be properly encapsulated in a bmop. but later.*/
+static int blend_from_shape_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= obedit->data;
+ BMEditMesh *em= me->edit_btmesh;
+ BMVert *eve;
+ BMIter iter;
+ float co[3], *sco;
+ float blend= RNA_float_get(op->ptr, "blend");
+ int shape= RNA_enum_get(op->ptr, "shape");
+ int add= RNA_int_get(op->ptr, "add");
+ int totshape;
+
+ /*sanity check*/
+ totshape = CustomData_number_of_layers(&em->bm->vdata, CD_SHAPEKEY);
+ if (totshape == 0 || shape < 0 || shape >= totshape)
+ return OPERATOR_CANCELLED;
+
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(eve, BM_SELECT) || BM_TestHFlag(eve, BM_HIDDEN))
+ continue;
+
+ sco = CustomData_bmesh_get_n(&em->bm->vdata, eve->head.data, CD_SHAPEKEY, shape);
+ VECCOPY(co, sco);
+
+
+ if(add) {
+ mul_v3_fl(co, blend);
+ add_v3_v3v3(eve->co, eve->co, co);
+ }
+ else
+ interp_v3_v3v3(eve->co, eve->co, co, blend);
+
+ VECCOPY(sco, co);
+ }
+
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+}
+
+static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ Mesh *me= (obedit) ? obedit->data : NULL;
+ BMEditMesh *em = me->edit_btmesh;
+ EnumPropertyItem tmp= {0, "", 0, "", ""}, *item= NULL;
+ int totitem= 0, a;
+
+ if(obedit && obedit->type == OB_MESH && CustomData_has_layer(&em->bm->vdata, CD_SHAPEKEY)) {
+ for (a=0; a<em->bm->vdata.totlayer; a++) {
+ if (em->bm->vdata.layers[a].type != CD_SHAPEKEY)
+ continue;
+
+ tmp.value= totitem;
+ tmp.identifier= em->bm->vdata.layers[a].name;
+ tmp.name= em->bm->vdata.layers[a].name;
+ RNA_enum_item_add(&item, &totitem, &tmp);
+
+ totitem++;
+ }
+ }
+
+ RNA_enum_item_end(&item, &totitem);
+ *free= 1;
+
+ return item;
+}
+
+void MESH_OT_blend_from_shape(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static EnumPropertyItem shape_items[]= {{0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Blend From Shape";
+ ot->description= "Blend in shape from a shape key.";
+ ot->idname= "MESH_OT_blend_from_shape";
+
+ /* api callbacks */
+ ot->exec= blend_from_shape_exec;
+ ot->invoke= WM_operator_props_popup;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ prop= RNA_def_enum(ot->srna, "shape", shape_items, 0, "Shape", "Shape key to use for blending.");
+ RNA_def_enum_funcs(prop, shape_itemf);
+ RNA_def_float(ot->srna, "blend", 1.0f, -FLT_MAX, FLT_MAX, "Blend", "Blending factor.", -2.0f, 2.0f);
+ RNA_def_boolean(ot->srna, "add", 1, "Add", "Add rather then blend between shapes.");
+}
+
+/* TODO - some way to select on an arbitrary axis */
+static int select_axis_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMEditSelection *ese = em->bm->selected.last;
+ int axis= RNA_int_get(op->ptr, "axis");
+ int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
+
+ if(ese==NULL)
+ return OPERATOR_CANCELLED;
+
+ if(ese->type==BM_VERT) {
+ BMVert *ev, *act_vert= (BMVert*)ese->data;
+ BMIter iter;
+ float value= act_vert->co[axis];
+ float limit= CTX_data_tool_settings(C)->doublimit; // XXX
+
+ if(mode==0)
+ value -= limit;
+ else if (mode==1)
+ value += limit;
+
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(!BM_TestHFlag(ev, BM_HIDDEN)) {
+ switch(mode) {
+ case -1: /* aligned */
+ if(fabs(ev->co[axis] - value) < limit)
+ BM_Select(em->bm, ev, 1);
+ break;
+ case 0: /* neg */
+ if(ev->co[axis] > value)
+ BM_Select(em->bm, ev, 1);
+ break;
+ case 1: /* pos */
+ if(ev->co[axis] < value)
+ BM_Select(em->bm, ev, 1);
+ break;
+ }
+ }
+ }
+ }
+
+ EDBM_selectmode_flush(em);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_axis(wmOperatorType *ot)
+{
+ static EnumPropertyItem axis_mode_items[] = {
+ {0, "POSITIVE", 0, "Positive Axis", ""},
+ {1, "NEGATIVE", 0, "Negative Axis", ""},
+ {-1, "ALIGNED", 0, "Aligned Axis", ""},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Select Axis";
+ ot->description= "Select all data in the mesh on a single axis.";
+ ot->idname= "MESH_OT_select_axis";
+
+ /* api callbacks */
+ ot->exec= select_axis_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
+ RNA_def_int(ot->srna, "axis", 0, 0, 2, "Axis", "Select the axis to compare each vertex on", 0, 2);
+}
+
+static int solidify_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+ float nor[3] = {0,0,1};
+
+ float thickness= RNA_float_get(op->ptr, "thickness");
+
+ extrudeflag(obedit, em, SELECT, nor, 1);
+ EM_make_hq_normals(em);
+ EM_solidify(em, thickness);
+
+
+ /* update vertex normals too */
+ recalc_editnormals(em);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+
+void MESH_OT_solidify(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ /* identifiers */
+ ot->name= "Solidify";
+ ot->description= "Create a solid skin by extruding, compensating for sharp angles.";
+ ot->idname= "MESH_OT_solidify";
+
+ /* api callbacks */
+ ot->exec= solidify_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "thickness", "", -10.0f, 10.0f);
+ RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
+}
+
+#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
+#define TRAIL_FREEHAND 2
+#define TRAIL_MIXED 3 /* (1|2) */
+#define TRAIL_AUTO 4
+#define TRAIL_MIDPOINTS 8
+
+typedef struct CutCurve {
+ float x;
+ float y;
+} CutCurve;
+
+/* ******************************************************************** */
+/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
+ drawn by user.
+
+ Currently mapped to KKey when in MeshEdit mode.
+ Usage:
+ Hit Shift K, Select Centers or Exact
+ Hold LMB down to draw path, hit RETKEY.
+ ESC cancels as expected.
+
+ Contributed by Robert Wenzlaff (Det. Thorn).
+
+ 2.5 revamp:
+ - non modal (no menu before cutting)
+ - exit on mouse release
+ - polygon/segment drawing can become handled by WM cb later
+
+ bmesh port version
+*/
+
+#define KNIFE_EXACT 1
+#define KNIFE_MIDPOINT 2
+#define KNIFE_MULTICUT 3
+
+static EnumPropertyItem knife_items[]= {
+ {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
+ {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
+ {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
+
+static float bm_seg_intersect(BMEdge *e, CutCurve *c, int len, char mode,
+ struct GHash *gh, int *isected)
+{
+#define MAXSLOPE 100000
+ float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
+ float y2min, dist, lastdist=0, xdiff2, xdiff1;
+ float m1, b1, m2, b2, x21, x22, y21, y22, xi;
+ float yi, x1min, x1max, y1max, y1min, perc=0;
+ float *scr;
+ float threshold = 0.0;
+ int i;
+
+ //threshold = 0.000001; /*tolerance for vertex intersection*/
+ // XXX threshold = scene->toolsettings->select_thresh / 100;
+
+ /* Get screen coords of verts */
+ scr = BLI_ghash_lookup(gh, e->v1);
+ x21=scr[0];
+ y21=scr[1];
+
+ scr = BLI_ghash_lookup(gh, e->v2);
+ x22=scr[0];
+ y22=scr[1];
+
+ xdiff2=(x22-x21);
+ if (xdiff2) {
+ m2=(y22-y21)/xdiff2;
+ b2= ((x22*y21)-(x21*y22))/xdiff2;
+ }
+ else {
+ m2=MAXSLOPE; /* Verticle slope */
+ b2=x22;
+ }
+
+ *isected = 0;
+
+ /*check for *exact* vertex intersection first*/
+ if(mode!=KNIFE_MULTICUT){
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /*test e->v1*/
+ if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
+ perc = 0;
+ *isected = 1;
+ return(perc);
+ }
+ /*test e->v2*/
+ else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
+ perc = 0;
+ *isected = 2;
+ return(perc);
+ }
+ }
+ }
+
+ /*now check for edge interesect (may produce vertex intersection as well)*/
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /* Perp. Distance from point to line */
+ if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
+ /* change in sign. Skip extra math */
+ else dist=x22-x12;
+
+ if (i==0) lastdist=dist;
+
+ /* if dist changes sign, and intersect point in edge's Bound Box*/
+ if ((lastdist*dist)<=0){
+ xdiff1=(x12-x11); /* Equation of line between last 2 points */
+ if (xdiff1){
+ m1=(y12-y11)/xdiff1;
+ b1= ((x12*y11)-(x11*y12))/xdiff1;
+ }
+ else{
+ m1=MAXSLOPE;
+ b1=x12;
+ }
+ x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
+ x2min=MIN2(x21,x22)-0.001; /* due to round off error */
+ y2max=MAX2(y21,y22)+0.001;
+ y2min=MIN2(y21,y22)-0.001;
+
+ /* Found an intersect, calc intersect point */
+ if (m1==m2){ /* co-incident lines */
+ /* cut at 50% of overlap area*/
+ x1max=MAX2(x11, x12);
+ x1min=MIN2(x11, x12);
+ xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
+
+ y1max=MAX2(y11, y12);
+ y1min=MIN2(y11, y12);
+ yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
+ }
+ else if (m2==MAXSLOPE){
+ xi=x22;
+ yi=m1*x22+b1;
+ }
+ else if (m1==MAXSLOPE){
+ xi=x12;
+ yi=m2*x12+b2;
+ }
+ else {
+ xi=(b1-b2)/(m2-m1);
+ yi=(b1*m2-m1*b2)/(m2-m1);
+ }
+
+ /* Intersect inside bounding box of edge?*/
+ if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
+ /*test for vertex intersect that may be 'close enough'*/
+ if(mode!=KNIFE_MULTICUT){
+ if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
+ if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
+ *isected = 1;
+ perc = 0;
+ break;
+ }
+ }
+ if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
+ if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
+ *isected = 2;
+ perc = 0;
+ break;
+ }
+ }
+ }
+ if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
+ else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
+ //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
+
+ break;
+ }
+ }
+ lastdist=dist;
+ }
+ return(perc);
+}
+
+#define MAX_CUTS 2048
+
+static int knife_cut_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMesh *bm = em->bm;
+ ARegion *ar= CTX_wm_region(C);
+ BMVert *bv;
+ BMIter iter;
+ BMEdge *be;
+ BMOperator bmop;
+ CutCurve curve[MAX_CUTS];
+ struct GHash *gh;
+ float isect=0.0;
+ float *scr, co[4];
+ int len=0, isected, i;
+ short numcuts=1, mode= RNA_int_get(op->ptr, "type");
+
+ /* edit-object needed for matrix, and ar->regiondata for projections to work */
+ if (ELEM3(NULL, obedit, ar, ar->regiondata))
+ return OPERATOR_CANCELLED;
+
+ if (bm->totvertsel < 2) {
+ //error("No edges are selected to operate on");
+ return OPERATOR_CANCELLED;;
+ }
+
+ /* get the cut curve */
+ RNA_BEGIN(op->ptr, itemptr, "path") {
+
+ RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
+ len++;
+ if(len>= MAX_CUTS) break;
+ }
+ RNA_END;
+
+ if(len<2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife cut exec");
+ for(bv=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);bv;bv=BMIter_Step(&iter)){
+ scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
+ VECCOPY(co, bv->co);
+ co[3]= 1.0;
+ mul_m4_v4(obedit->obmat, co);
+ project_float(ar, co, scr);
+ BLI_ghash_insert(gh, bv, scr);
+ }
+
+ BMO_Init_Op(&bmop, "esubd");
+
+ i = 0;
+ /*store percentage of edge cut for KNIFE_EXACT here.*/
+ for (be=BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be=BMIter_Step(&iter)) {
+ if( BM_Selected(bm, be) ) {
+ isect= bm_seg_intersect(be, curve, len, mode, gh, &isected);
+
+ if (isect != 0.0f) {
+ if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) {
+ BMO_Insert_MapFloat(bm, &bmop,
+ "edgepercents",
+ be, isect);
+
+ }
+ BMO_SetFlag(bm, be, 1);
+ } else BMO_ClearFlag(bm, be, 1);
+ } else BMO_ClearFlag(bm, be, 1);
+ }
+
+ BMO_Flag_To_Slot(bm, &bmop, "edges", 1, BM_EDGE);
+
+ if (mode == KNIFE_MIDPOINT) numcuts = 1;
+ BMO_Set_Int(&bmop, "numcuts", numcuts);
+
+ BMO_Set_Int(&bmop, "flag", B_KNIFE);
+ BMO_Set_Int(&bmop, "quadcornertype", SUBD_STRAIGHT_CUT);
+ BMO_Set_Int(&bmop, "singleedge", 0);
+ BMO_Set_Int(&bmop, "gridfill", 0);
+
+ BMO_Set_Float(&bmop, "radius", 0);
+
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Finish_Op(bm, &bmop);
+
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)WMEM_freeN);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_knife_cut(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ ot->name= "Knife Cut";
+ ot->description= "Cut selected edges and faces into parts.";
+ ot->idname= "MESH_OT_knife_cut";
+
+ ot->invoke= WM_gesture_lines_invoke;
+ ot->modal= WM_gesture_lines_modal;
+ ot->exec= knife_cut_exec;
+
+ ot->poll= EM_view3d_poll;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
+ prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
+
+ /* internal */
+ RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
+}
+
+static int mesh_separate_selected(Main *bmain, Scene *scene, Base *editbase, wmOperator *wmop)
+{
+ Base *basenew;
+ BMIter iter;
+ BMVert *v;
+ BMEdge *e;
+ Object *obedit = editbase->object;
+ Mesh *me = obedit->data;
+ BMEditMesh *em = me->edit_btmesh;
+ BMesh *bmnew;
+ int allocsize[] = {512, 512, 2048, 512};
+
+ if (!em)
+ return OPERATOR_CANCELLED;
+
+ bmnew = BM_Make_Mesh(obedit, allocsize);
+ CustomData_copy(&em->bm->vdata, &bmnew->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->edata, &bmnew->edata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->ldata, &bmnew->ldata, CD_MASK_BMESH, CD_CALLOC, 0);
+ CustomData_copy(&em->bm->pdata, &bmnew->pdata, CD_MASK_BMESH, CD_CALLOC, 0);
+
+ CustomData_bmesh_init_pool(&bmnew->vdata, allocsize[0]);
+ CustomData_bmesh_init_pool(&bmnew->edata, allocsize[1]);
+ CustomData_bmesh_init_pool(&bmnew->ldata, allocsize[2]);
+ CustomData_bmesh_init_pool(&bmnew->pdata, allocsize[3]);
+
+ basenew= ED_object_add_duplicate(bmain, scene, editbase, USER_DUP_MESH); /* 0 = fully linked */
+ assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
+
+ ED_base_object_select(basenew, BA_DESELECT);
+
+ EDBM_CallOpf(em, wmop, "dupe geom=%hvef dest=%p", BM_SELECT, bmnew);
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_FACES);
+
+ /*clean up any loose edges*/
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (BM_TestHFlag(e, BM_HIDDEN))
+ continue;
+
+ if (BM_Edge_FaceCount(e) != 0)
+ BM_Select(em->bm, e, 0); /*deselect*/
+ }
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_EDGES);
+
+ /*clean up any loose verts*/
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(v, BM_HIDDEN))
+ continue;
+
+ if (BM_Vert_EdgeCount(v) != 0)
+ BM_Select(em->bm, v, 0); /*deselect*/
+ }
+
+ EDBM_CallOpf(em, wmop, "del geom=%hvef context=%i", BM_SELECT, DEL_VERTS);
+
+ BM_Compute_Normals(bmnew);
+ BMO_CallOpf(bmnew, "bmesh_to_mesh mesh=%p object=%p", basenew->object->data, basenew->object);
+
+ BM_Free_Mesh(bmnew);
+ ((Mesh*)basenew->object->data)->edit_btmesh = NULL;
+
+ return 1;
+}
+
+//BMESH_TODO
+static int mesh_separate_material(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop))
+{
+ return 0;
+}
+
+//BMESH_TODO
+static int mesh_separate_loose(Main *UNUSED(bmain), Scene *UNUSED(scene), Base *UNUSED(editbase), wmOperator *UNUSED(wmop))
+{
+ return 0;
+}
+
+static int mesh_separate_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene= CTX_data_scene(C);
+ Base *base= CTX_data_active_base(C);
+ int retval= 0, type= RNA_enum_get(op->ptr, "type");
+
+ if(type == 0)
+ retval= mesh_separate_selected(bmain, scene, base, op);
+ else if(type == 1)
+ retval= mesh_separate_material (bmain, scene, base, op);
+ else if(type == 2)
+ retval= mesh_separate_loose(bmain, scene, base, op);
+
+ if(retval) {
+ DAG_id_tag_update(base->object->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+/* *************** Operator: separate parts *************/
+
+static EnumPropertyItem prop_separate_types[] = {
+ {0, "SELECTED", 0, "Selection", ""},
+ {1, "MATERIAL", 0, "By Material", ""},
+ {2, "LOOSE", 0, "By loose parts", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+void MESH_OT_separate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Separate";
+ ot->description= "Separate selected geometry into a new mesh.";
+ ot->idname= "MESH_OT_separate";
+
+ /* api callbacks */
+ ot->invoke= WM_menu_invoke;
+ ot->exec= mesh_separate_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
+}
+
+
+static int fill_mesh_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMOperator bmop;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "triangle_fill edges=%he", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ BMO_Exec_Op(em->bm, &bmop);
+
+ /*select new geometry*/
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_FACE|BM_EDGE);
+
+ if (!EDBM_FinishOp(em, &bmop, op, 1))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+
+}
+
+void MESH_OT_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Fill";
+ ot->idname= "MESH_OT_fill";
+
+ /* api callbacks */
+ ot->exec= fill_mesh_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int beautify_fill_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "beautify_fill faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_beautify_fill(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Beautify Fill";
+ ot->idname= "MESH_OT_beautify_fill";
+
+ /* api callbacks */
+ ot->exec= beautify_fill_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+/********************** Quad/Tri Operators *************************/
+
+static int quads_convert_to_tris_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+
+ if (!EDBM_CallOpf(em, op, "triangulate faces=%hf", BM_SELECT))
+ return OPERATOR_CANCELLED;
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Quads to Tris";
+ ot->idname= "MESH_OT_quads_convert_to_tris";
+
+ /* api callbacks */
+ ot->exec= quads_convert_to_tris_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+static int tris_convert_to_quads_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ int dosharp, douvs, dovcols, domaterials;
+ float limit = RNA_float_get(op->ptr, "limit");
+
+ dosharp = RNA_boolean_get(op->ptr, "sharp");
+ douvs = RNA_boolean_get(op->ptr, "uvs");
+ dovcols = RNA_boolean_get(op->ptr, "vcols");
+ domaterials = RNA_boolean_get(op->ptr, "materials");
+
+ if (!EDBM_CallOpf(em, op,
+ "join_triangles faces=%hf limit=%f compare_sharp=%i compare_uvs=%i compare_vcols=%i compare_materials=%i",
+ BM_SELECT, limit, dosharp, douvs, dovcols, domaterials))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Tris to Quads";
+ ot->idname= "MESH_OT_tris_convert_to_quads";
+
+ /* api callbacks */
+ ot->exec= tris_convert_to_quads_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "limit", 40.0f, -180.0f, 180.0f, "Max Angle", "Angle Limit in Degrees", -180, 180.0f);
+
+ RNA_def_boolean(ot->srna, "uvs", 0, "Compare UVs", "");
+ RNA_def_boolean(ot->srna, "vcols", 0, "Compare VCols", "");
+ RNA_def_boolean(ot->srna, "sharp", 0, "Compare Sharp", "");
+ RNA_def_boolean(ot->srna, "materials", 0, "Compare Materials", "");
+
+}
+
+static int edge_flip_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ edge_flip(em);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_edge_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Edge Flip";
+ ot->idname= "MESH_OT_edge_flip";
+
+ /* api callbacks */
+ ot->exec= edge_flip_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+//BMESH_TODO
+static int split_mesh(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
+
+ WM_cursor_wait(1);
+
+ /* make duplicate first */
+ adduplicateflag(em, SELECT);
+ /* old faces have flag 128 set, delete them */
+ delfaceflag(em, 128);
+ recalc_editnormals(em);
+
+ WM_cursor_wait(0);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_split(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Split";
+ ot->idname= "MESH_OT_split";
+
+ /* api callbacks */
+ ot->exec= split_mesh;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+
+static int spin_mesh(bContext *UNUSED(C), wmOperator *UNUSED(op), float *UNUSED(dvec), int UNUSED(steps), float UNUSED(degr), int UNUSED(dupli) )
+{
+#if 0
+ 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*M_PI/360.0;
+ phi/= steps;
+ if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
+
+ RNA_float_get_array(op->ptr, "axis", n);
+ normalize_v3(n);
+
+ q[0]= (float)cos(phi);
+ si= (float)sin(phi);
+ q[1]= n[0]*si;
+ q[2]= n[1]*si;
+ q[3]= n[2]*si;
+ quat_to_mat3( cmat,q);
+
+ mul_m3_m3m3(tmat,cmat,bmat);
+ mul_m3_m3m3(bmat,imat,tmat);
+
+ 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, OB_RECALC_DATA);
+ }
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return ok;
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+static int spin_mesh_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0
+ Object *obedit= CTX_data_edit_object(C);
+ int ok;
+
+ ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
+ if(ok==0) {
+ BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+#endif
+ return OPERATOR_FINISHED;
+}
+
+/* get center and axis, in global coords */
+static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+#if 0
+ 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]);
+
+#endif
+ 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 *UNUSED(C), wmOperator *UNUSED(op))
+{
+#if 0
+ 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_ERROR, "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.000) {
+ dvec[0]= -dvec[0];
+ dvec[1]= -dvec[1];
+ dvec[2]= -dvec[2];
+ }
+
+ if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No valid vertices are selected");
+ BKE_mesh_end_editmesh(obedit->data, em);
+ return OPERATOR_CANCELLED;
+ }
+#endif
+ return OPERATOR_CANCELLED;
+}
+
+/* get center and axis, in global coords */
+static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+#if 0
+ 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]);
+#endif
+ 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);
+}
+
+int select_by_number_vertices_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));
+ 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_ERROR, "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) );
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+#endif
+ 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, "Triangles", 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->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
+}
+
+
+#define MIRROR_THRESH 1.0f
+
+int select_mirror_exec(bContext *C, wmOperator *op)
+{
+
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMVert *v1, *v2;
+ BMIter iter;
+ int extend= RNA_boolean_get(op->ptr, "extend");
+ float mirror_co[3];
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BM_TestHFlag(v1, BM_SELECT) || BM_TestHFlag(v1, BM_HIDDEN))
+ BMINDEX_SET(v1, 0);
+ else BMINDEX_SET(v1, 1);
+ }
+
+ if (!extend)
+ EDBM_clear_flag_all(em, BM_SELECT);
+
+ BM_ITER(v1, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (!BMINDEX_GET(v1) || BM_TestHFlag(v1, BM_HIDDEN))
+ continue;
+
+ VECCOPY(mirror_co, v1->co);
+ mirror_co[0] *= -1.0f;
+
+ v2 = BMBVH_FindClosestVertTopo(tree, mirror_co, MIRROR_THRESH, v1);
+ if (v2 && !BM_TestHFlag(v2, BM_HIDDEN))
+ BM_Select(em->bm, v2, 1);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_mirror(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Select Mirror";
+ ot->description= "Select mesh items at mirrored locations.";
+ ot->idname= "MESH_OT_select_mirror";
+
+ /* api callbacks */
+ ot->exec= select_mirror_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
+}
+
+/********* qsort routines. not sure how to make these
+ work, since we aren't using linked lists for
+ geometry anymore. might need a sortof "swap"
+ function for bmesh elements. *********/
+
+typedef struct xvertsort {
+ float x;
+ BMVert *v1;
+} xvertsort;
+
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ uintptr_t x;
+ struct EditFace *efa;
+};
+
+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;
+}
+
+// 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 *UNUSED(C), int UNUSED(flag))
+{
+#if 0 //hrm, geometry isn't in linked lists anymore. . .
+ ViewContext vc;
+ BMEditMesh *em;
+ BMVert *eve;
+ BMIter iter;
+ xvertsort *sortblock;
+ ListBase tbase;
+ int i, amount;
+
+ em_setup_viewcontext(C, &vc);
+ em = vc.em;
+
+ amount = em->bm->totvert;
+ sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if(BM_TestHFlag(eve, BM_SELECT))
+ sortblock[i].v1 = eve;
+ }
+
+ ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
+ mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0);
+
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ for (i=0; i<amount; i++) {
+ eve = sortblock[i].v1;
+
+ if (eve) {
+ BLI_remlink(&vc.em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ }
+ }
+
+ BLI_movelisttolist(&vc.em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+#endif
+
+}
+
+static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ xsortvert_flag(C, SELECT);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_sort(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Vertex Sort";
+ ot->description= "Sort vertex order";
+ ot->idname= "MESH_OT_vertices_sort";
+
+ /* api callbacks */
+ ot->exec= mesh_vertices_sort_exec;
+
+ ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+#if 0
+/* called from buttons */
+static void hashvert_flag(EditMesh *em, int flag)
+{
+ /* switch vertex order using hash table */
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb, onth, *newsort;
+ ListBase tbase;
+ int amount, a, b;
+
+ /* count */
+ eve= em->verts.first;
+ amount= 0;
+ while(eve) {
+ if(eve->f & flag) amount++;
+ eve= eve->next;
+ }
+ if(amount==0) return;
+
+ /* allocate memory */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+
+ BLI_srand(1);
+
+ sb= sortblock;
+ for(a=0; a<amount; a++, sb++) {
+ b= (int)(amount*BLI_drand());
+ if(b>=0 && b<amount) {
+ newsort= sortblock+b;
+ onth= *sb;
+ *sb= *newsort;
+ *newsort= onth;
+ }
+ }
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ sb= sortblock;
+ while(amount--) {
+ eve= sb->v1;
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ sb++;
+ }
+
+ BLI_movelisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+
+}
+#endif
+
+static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= ((Mesh *)obedit->data)->edit_btmesh;
+ //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;
+}
+
+/******end of qsort stuff ****/
+
+
+static int mesh_noise_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ Material *ma;
+ Tex *tex;
+ BMVert *eve;
+ BMIter iter;
+ float fac= RNA_float_get(op->ptr, "factor");
+
+ if(em==NULL) return OPERATOR_FINISHED;
+
+ ma= give_current_material(obedit, obedit->actcol);
+ if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
+ BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned.");
+ return OPERATOR_FINISHED;
+ }
+ tex= give_current_material_texture(ma);
+
+ if(tex->type==TEX_STUCCI) {
+ float b2, vec[3];
+ float ofs= tex->turbul/200.0;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
+ if(tex->stype) ofs*=(b2*b2);
+ vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
+ vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
+ vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
+
+ add_v3_v3(eve->co, vec);
+ }
+ }
+ }
+ else {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ if (BM_TestHFlag(eve, BM_SELECT) && !BM_TestHFlag(eve, BM_HIDDEN)) {
+ float tin, dum;
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
+ eve->co[2]+= fac*tin;
+ }
+ }
+ }
+
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_noise(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Noise";
+ ot->description= "Use vertex coordinate as texture coordinate";
+ ot->idname= "MESH_OT_noise";
+
+ /* api callbacks */
+ ot->exec= mesh_noise_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
+}
+
+/*bevel! yay!!*/
+static int mesh_bevel_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ BMEditMesh *em= (((Mesh *)obedit->data))->edit_btmesh;
+ BMIter iter;
+ BMEdge *eed;
+ BMOperator bmop;
+ float factor= RNA_float_get(op->ptr, "percent"), fac=factor, dfac, df, s;
+ /*float p2 = RNA_float_get(op->ptr, "param2");
+ float p3 = RNA_float_get(op->ptr, "param3");
+ float p4 = RNA_float_get(op->ptr, "param4");
+ float p5 = RNA_float_get(op->ptr, "param5");*/
+ int i, recursion = RNA_int_get(op->ptr, "recursion");
+ float *w = NULL, ftot;
+ int li;
+ BLI_array_declare(w);
+
+ BM_add_data_layer(em->bm, &em->bm->edata, CD_PROP_FLT);
+ li = CustomData_number_of_layers(&em->bm->edata, CD_PROP_FLT)-1;
+
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ float d = len_v3v3(eed->v1->co, eed->v2->co);
+ float *dv = CustomData_bmesh_get_n(&em->bm->edata, eed->head.data, CD_PROP_FLT, li);
+
+ *dv = d;
+ }
+
+ if(em==NULL) return OPERATOR_CANCELLED;
+
+ /*ugh, stupid math depends somewhat on angles!*/
+ dfac = 1.0/(float)(recursion+1);
+ df = 1.0;
+ for (i=0, ftot=0.0f; i<recursion; i++) {
+ s = pow(df, 1.25);
+
+ BLI_array_append(w, s);
+ ftot += s;
+
+ df *= 2.0;
+ }
+
+ for (i=0; i<BLI_array_count(w); i++) {
+ w[i] /= ftot;
+ }
+
+ fac = factor;
+ for (i=0; i<BLI_array_count(w); i++) {
+ fac = w[BLI_array_count(w)-i-1]*factor;
+
+ if (!EDBM_InitOpf(em, &bmop, op, "bevel geom=%hev percent=%f lengthlayer=%i uselengths=%i", BM_SELECT, fac, li, 1))
+ return OPERATOR_CANCELLED;
+
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_Finish_Op(em->bm, &bmop);
+ }
+
+ BM_free_data_layer_n(em->bm, &em->bm->edata, CD_MASK_PROP_FLT, li);
+
+ BLI_array_free(w);
+ EDBM_RecalcNormals(em);
+
+ DAG_id_tag_update(obedit->data, 0);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_bevel(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Bevel";
+ ot->description= "Edge/Vertex Bevel";
+ ot->idname= "MESH_OT_bevel";
+
+ /* api callbacks */
+ ot->exec= mesh_bevel_exec;
+ ot->poll= ED_operator_editmesh;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ RNA_def_float(ot->srna, "percent", 0.5f, -FLT_MAX, FLT_MAX, "Percentage", "", 0.0f, 1.0f);
+ RNA_def_int(ot->srna, "recursion", 1, 1, 50, "Recursion Level", "Recursion Level", 1, 8);
+ //RNA_def_float(ot->srna, "param2", 1.0f, -FLT_MAX, FLT_MAX, "Parameter 2", "", -1000.0f, 1000.0f);
+ //RNA_def_float(ot->srna, "param3", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 3", "", -1000.0f, 1000.0f);
+ //RNA_def_float(ot->srna, "param4", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 4", "", -1000.0f, 1000.0f);
+ //RNA_def_float(ot->srna, "param5", 0.5f, -FLT_MAX, FLT_MAX, "Parameter 5", "", -1000.0f, 1000.0f);
+}
+
+static int mesh_export_obj_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ DerivedMesh *dm;
+ Scene *scene = CTX_data_scene(C);
+ Mesh *me;
+ Main *bmain = CTX_data_main(C);
+ MVert *mvert, *mv;
+ MLoop *mloop, *ml;
+ MPoly *mpoly, *mp;
+ MTexPoly *mtexpoly;
+ MLoopUV *luv, *mloopuv;
+ MLoopCol *mloopcol;
+ FILE *file, *matfile;
+ int *face_mat_group;
+ struct {Material *mat; MTexPoly poly; int end;} **matlists;
+ char str[FILE_MAX], str2[FILE_MAX];
+ int i, j, c, free;
+
+ if (ob->type != OB_MESH) {
+ BKE_report(op->reports, RPT_OPERATOR, "Only meshes can be exported");
+ return OPERATOR_CANCELLED;
+ }
+
+ RNA_string_get(op->ptr, "filepath", str);
+
+ sprintf(str2, "%s_materials.mtl", str);
+ file = fopen(str, "wb");
+ matfile = fopen(str2, "wb");
+
+ if (!file) {
+ BKE_report(op->reports, RPT_OPERATOR, "Could not open file");
+
+ if (matfile)
+ fclose(matfile);
+ return OPERATOR_CANCELLED;
+ }
+
+ if (!matfile) {
+ BKE_report(op->reports, RPT_OPERATOR, "Could not open material file");
+
+ if (file)
+ fclose(file);
+ return OPERATOR_CANCELLED;
+ }
+
+ me = ob->data;
+ if (me->edit_btmesh) {
+ EDBM_LoadEditBMesh(scene, ob);
+ }
+
+ if (!RNA_boolean_get(op->ptr, "apply_modifiers")) {
+ dm = CDDM_from_mesh(me, ob);
+ free = 1;
+ } else {
+ dm = mesh_get_derived_final(scene, ob, CD_MASK_DERIVEDMESH);
+ if (!CDDM_Check(dm)) {
+ dm = CDDM_copy(dm, 0);
+ free = 1;
+ } else {
+ free = 0;
+ }
+ }
+
+ face_mat_group = MEM_callocN(sizeof(int)*dm->numPolyData, "face_mat_group");
+
+ if (MAX2(ob->totcol, me->totcol))
+ matlists = MEM_callocN(sizeof(*matlists)*MAX2(me->totcol, ob->totcol), "matlists");
+ else matlists = NULL;
+
+ for (i=0; i<MAX2(ob->totcol, me->totcol); i++) {
+ matlists[i] = MEM_callocN(sizeof(**matlists), "matlists[i]");
+ matlists[i][0].end = 1;
+ }
+
+
+ mvert = CDDM_get_verts(dm);
+ mloop = CDDM_get_loops(dm);
+ mpoly = CDDM_get_polys(dm);
+ mtexpoly = CustomData_get_layer(&dm->polyData, CD_MTEXPOLY);
+ mloopuv = CustomData_get_layer(&dm->loopData, CD_MLOOPUV);
+ mloopcol = CustomData_get_layer(&dm->loopData, CD_MLOOPCOL);
+
+ /*build material list*/
+ mp = mpoly;
+ for (i=0; i<dm->numPolyData; i++, (mtexpoly ? mtexpoly++ : NULL), mp++) {
+ int found = 0;
+
+ j = 0;
+ while (!matlists[mp->mat_nr][j].end) {
+ Material *mat = ob->matbits[mp->mat_nr] ? ob->mat[mp->mat_nr] : me->mat[mp->mat_nr];
+
+ if (matlists[mp->mat_nr][j].mat == mat) {
+ if (mtexpoly) {
+ if (matlists[mp->mat_nr][j].poly.tpage == mtexpoly->tpage) {
+ found = 1;
+ break;
+ }
+ } else {
+ found = 1;
+ break;
+ }
+ }
+ j++;
+ }
+
+ if (!found) {
+ matlists[mp->mat_nr] = MEM_reallocN(matlists[mp->mat_nr], sizeof(**matlists)*(j+2));
+
+ /*add sentinal*/
+ matlists[mp->mat_nr][j+1].end = 1;
+ matlists[mp->mat_nr][j].end = 0;
+
+ if (ob->matbits && ob->matbits[mp->mat_nr]) {
+ matlists[mp->mat_nr][j].mat = ob->mat[mp->mat_nr];
+ } else {
+ matlists[mp->mat_nr][j].mat = me->mat[mp->mat_nr];
+ }
+
+ if (mtexpoly)
+ matlists[mp->mat_nr][j].poly = *mtexpoly;
+ }
+
+ face_mat_group[i] = j;
+ }
+
+ /*write material references*/
+ fprintf(file, "mtllib %s_materials.mtl\n", str);
+ fprintf(file, "o %s\n", (ob->id.name+2));
+
+ for (mv=mvert, i=0; i<dm->numVertData; i++, mv++) {
+ fprintf(file, "v %.8f\t%.8f\t%.8f\n", mv->co[0], mv->co[1], mv->co[2]);
+ fprintf(file, "vn %.5f\t%.5f\t%.5f\n", (float)mv->no[0]/65535.0f, (float)mv->no[1]/65535.0f, (float)mv->no[2]/65535.0f);
+ }
+
+ /*write texture coordinates*/
+ if (mloopuv) {
+ fprintf(file, "\n");
+ for (mp=mpoly, i=0; i<dm->numPolyData; i++, mp++) {
+ luv = mloopuv + mp->loopstart;
+ for (j=0; j<mp->totloop; j++, luv++) {
+ fprintf(file, "vt %.8f\t%.8f\n", luv->uv[0], luv->uv[1]);
+ }
+ }
+ }
+
+ fprintf(file, "\n");
+ c = 0;
+ for (mp=mpoly, i=0; i<dm->numPolyData; i++, mp++) {
+ char matname[256];
+
+ if (mp->flag & ME_SMOOTH) {
+ fprintf(file, "s 1\n");
+ } else {
+ fprintf(file, "s off\n");
+ }
+
+ if (matlists[mp->mat_nr][face_mat_group[i]].mat && matlists[mp->mat_nr][face_mat_group[i]].poly.tpage) {
+ sprintf(matname, "%s__%s", matlists[mp->mat_nr][face_mat_group[i]].mat->id.name+2,
+ matlists[mp->mat_nr][face_mat_group[i]].poly.tpage->id.name+2);
+ } else if (matlists[mp->mat_nr][face_mat_group[i]].mat) {
+ sprintf(matname, "%s", matlists[mp->mat_nr][face_mat_group[i]].mat->id.name+2);
+ } else if (matlists[mp->mat_nr][face_mat_group[i]].poly.tpage != NULL) {
+ sprintf(matname, "texture_%s", matlists[mp->mat_nr][face_mat_group[i]].poly.tpage->id.name+2);
+ } else {
+ sprintf(matname, "__null_material_%d_%d", mp->mat_nr, face_mat_group[mp->mat_nr]);
+ }
+
+ fprintf(file, "usemtl %s\n", matname);
+ fprintf(file, "f ");
+
+ ml = mloop + mp->loopstart;
+ luv = mloopuv ? mloopuv + mp->loopstart : NULL;
+ for (j=0; j<mp->totloop; j++, ml++, (luv ? luv++ : NULL), c++) {
+ if (luv) {
+ fprintf(file, "%d/%d ", ml->v+1, c+1);
+ } else {
+ fprintf(file, "%d ", ml->v+1);
+ }
+ }
+ fprintf(file, "\n");
+ }
+
+ fclose(file);
+
+ /*write material library*/
+ fprintf(matfile, "#Blender MTL File\n\n");
+ for (i=0; i<MAX2(ob->totcol, me->totcol); i++) {
+ Material *mat;
+ char basedir[FILE_MAX], filename[FILE_MAX], str3[FILE_MAX];
+
+ j = 0;
+ while (!matlists[i][j].end) {
+ mat = matlists[i][j].mat;
+
+ if (mat && matlists[i][j].poly.tpage) {
+ fprintf(matfile, "newmtl %s__%s\n", mat->id.name+2,
+ matlists[i][j].poly.tpage->id.name+2);
+ } else if (mat) {
+ fprintf(matfile, "newmtl %s\n", mat->id.name+2);
+ } else if (matlists[i][j].poly.tpage != NULL) {
+ fprintf(matfile, "newmtl texture_%s\n", matlists[i][j].poly.tpage->id.name+2);
+ } else {
+ fprintf(matfile, "newmtl __null_material_%d_%d\n", i, j);
+ }
+
+ if (mat) {
+ fprintf(matfile, "Kd %.6f %.6f %.6f\n", mat->r, mat->g, mat->b);
+ fprintf(matfile, "Ks %.6f %.6f %.6f\n", mat->specr, mat->specg, mat->specb);
+ fprintf(matfile, "Ns %.6f\n", mat->spec*1000.0f);
+ } else {
+ fprintf(matfile, "Kd %.6f %.6f %.6f\n", 0.45f, 0.45f, 0.45f);
+ fprintf(matfile, "Ks %.6f %.6f %.6f\n", 1.0f, 0.4f, 0.1f);
+ fprintf(matfile, "Ns %.6f\n", 300.0f);
+ }
+
+ fprintf(matfile, "illum 2\n");
+
+ if (matlists[i][j].poly.tpage) {
+ BLI_strncpy(str2, matlists[i][j].poly.tpage->name, FILE_MAX);
+ BLI_strncpy(basedir, bmain->name, FILE_MAX);
+
+ BLI_splitdirstring(basedir, filename);
+ BLI_cleanup_file(basedir, str2); /* fix any /foo/../foo/ */
+
+ if (BLI_exists(str2)) {
+ char rel[3] = {0};
+
+ BLI_strncpy(str3, str2, FILE_MAX);
+ if (RNA_boolean_get(op->ptr, "relpaths")) {
+ BLI_path_rel(str3, str);
+
+ if (str3[2] != '.' && str3[2] != '/' && str3[2] != '\\') {
+ rel[0] = '.';
+ rel[1] = '/';
+ }
+ }
+
+ fprintf(matfile, "map_Ka %s%s\n", rel, (str3+2*RNA_boolean_get(op->ptr, "relpaths")));
+ fprintf(matfile, "map_Kd %s%s\n", rel, (str3+2*RNA_boolean_get(op->ptr, "relpaths")));
+ }
+ }
+
+ fprintf(matfile, "\n");
+ j++;
+ }
+ }
+
+ fclose(matfile);
+
+ for (i=0; i<MAX2(ob->totcol, me->totcol); i++) {
+ MEM_freeN(matlists[i]);
+ }
+
+ if (matlists)
+ MEM_freeN(matlists);
+
+ if (face_mat_group)
+ MEM_freeN(face_mat_group);
+
+ if (free) {
+ dm->needsFree = 1;
+ dm->release(dm);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void export_obj_filesel(bContext *C, wmOperator *op, const char *path)
+{
+ RNA_string_set(op->ptr, "filepath", path);
+ WM_event_add_fileselect(C, op);
+}
+
+
+static int export_obj_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+{
+ char filename[FILE_MAX];
+
+ BLI_strncpy(filename, "//untitled.obj", FILE_MAX);
+
+ if(RNA_property_is_set(op->ptr, "filepath"))
+ return mesh_export_obj_exec(C, op);
+
+ export_obj_filesel(C, op, filename);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+void EXPORT_MESH_OT_wavefront(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Export Wavefront OBJ";
+ ot->description= "Export Wavefront (obj)";
+ ot->idname= "EXPORT_MESH_OT_wavefront";
+
+ /* api callbacks */
+ ot->exec= mesh_export_obj_exec;
+ ot->invoke= export_obj_invoke;
+ ot->poll= ED_operator_object_active;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_filesel(ot, FOLDERFILE|TEXTFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH);
+
+ RNA_def_boolean(ot->srna, "apply_modifiers", 0, "Apply Modifiers", "Apply Modifiers");
+ RNA_def_boolean(ot->srna, "relpaths", 0, "Relative Paths", "Use relative paths for textures");
+}
diff --git a/source/blender/editors/mesh/bmeshutils.c b/source/blender/editors/mesh/bmeshutils.c
new file mode 100644
index 00000000000..06ebf1e9df0
--- /dev/null
+++ b/source/blender/editors/mesh/bmeshutils.c
@@ -0,0 +1,898 @@
+ /* $Id: bmeshutils.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "bmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "editbmesh_bvh.h"
+#include "mesh_intern.h"
+
+void EDBM_RecalcNormals(BMEditMesh *em)
+{
+ BM_Compute_Normals(em->bm);
+}
+
+void EDBM_stats_update(BMEditMesh *em)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
+ int *tots[3];
+ int i;
+
+ tots[0] = &em->bm->totvertsel;
+ tots[1] = &em->bm->totedgesel;
+ tots[2] = &em->bm->totfacesel;
+
+ em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
+
+ for (i=0; i<3; i++) {
+ ele = BMIter_New(&iter, em->bm, types[i], NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(ele, BM_SELECT)) {
+ *tots[i]++;
+ }
+ }
+ }
+}
+
+int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ va_end(list);
+
+ return 1;
+}
+
+
+/*returns 0 on error, 1 on success. executes and finishes a bmesh operator*/
+int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report) {
+ const char *errmsg;
+
+ BMO_Finish_Op(em->bm, bmop);
+
+ if (BMO_GetError(em->bm, &errmsg, NULL)) {
+ BMEditMesh *emcopy = em->emcopy;
+
+ if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
+
+ BMEdit_Free(em);
+ *em = *emcopy;
+
+ MEM_freeN(emcopy);
+ em->emcopyusers = 0;
+ em->emcopy = NULL;
+ return 0;
+ } else {
+ em->emcopyusers--;
+ if (em->emcopyusers < 0) {
+ printf("warning: em->emcopyusers was less then zero.\n");
+ }
+
+ if (em->emcopyusers <= 0) {
+ BMEdit_Free(em->emcopy);
+ MEM_freeN(em->emcopy);
+ em->emcopy = NULL;
+ }
+ }
+
+ return 1;
+}
+
+int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, 1);
+}
+
+int EDBM_CallAndSelectOpf(BMEditMesh *em, wmOperator *op, const char *selectslot, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ BKE_report(op->reports, RPT_ERROR,
+ "Parse error in EDBM_CallOpf");
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, selectslot, BM_SELECT, BM_ALL);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, op, 1);
+}
+
+int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...)
+{
+ BMesh *bm = em->bm;
+ BMOperator bmop;
+ va_list list;
+
+ va_start(list, fmt);
+
+ if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
+ va_end(list);
+ return 0;
+ }
+
+ if (!em->emcopy)
+ em->emcopy = BMEdit_Copy(em);
+ em->emcopyusers++;
+
+ BMO_Exec_Op(bm, &bmop);
+
+ va_end(list);
+ return EDBM_FinishOp(em, &bmop, NULL, 0);
+}
+
+void EDBM_selectmode_to_scene(Scene *scene, Object *obedit)
+{
+ BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
+
+ if (!em)
+ return;
+
+ scene->toolsettings->selectmode = em->selectmode;
+}
+
+void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob)
+{
+ Mesh *me = ob->data;
+ BMesh *bm;
+
+ if (!me->mpoly && me->totface) {
+ printf("yeek!! bmesh conversion issue! may lose lots of geometry!\n");
+
+ /*BMESH_TODO need to write smarter code here*/
+ bm = BKE_mesh_to_bmesh(me, ob);
+ } else {
+ bm = BKE_mesh_to_bmesh(me, ob);
+ }
+
+ me->edit_btmesh = BMEdit_Create(bm);
+ me->edit_btmesh->selectmode = ts->selectmode;
+ me->edit_btmesh->me = me;
+ me->edit_btmesh->ob = ob;
+}
+
+void EDBM_LoadEditBMesh(Scene *scene, Object *ob)
+{
+ Mesh *me = ob->data;
+ BMesh *bm = me->edit_btmesh->bm;
+
+ BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob);
+}
+
+void EDBM_FreeEditBMesh(BMEditMesh *tm)
+{
+ BMEdit_Free(tm);
+}
+
+void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface)
+{
+ EDBM_free_index_arrays(tm);
+
+ if (forvert) {
+ BMIter iter;
+ BMVert *ele;
+ int i=0;
+
+ tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->vert_index[i++] = ele;
+ }
+ }
+
+ if (foredge) {
+ BMIter iter;
+ BMEdge *ele;
+ int i=0;
+
+ tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->edge_index[i++] = ele;
+ }
+ }
+
+ if (forface) {
+ BMIter iter;
+ BMFace *ele;
+ int i=0;
+
+ tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index");
+
+ ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ tm->face_index[i++] = ele;
+ }
+ }
+}
+
+void EDBM_free_index_arrays(BMEditMesh *tm)
+{
+ if (tm->vert_index) {
+ MEM_freeN(tm->vert_index);
+ tm->vert_index = NULL;
+ }
+
+ if (tm->edge_index) {
+ MEM_freeN(tm->edge_index);
+ tm->edge_index = NULL;
+ }
+
+ if (tm->face_index) {
+ MEM_freeN(tm->face_index);
+ tm->face_index = NULL;
+ }
+}
+
+BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index)
+{
+ return tm->vert_index && index < tm->bm->totvert ?tm->vert_index[index]:NULL;
+}
+
+BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
+{
+ return tm->edge_index && index < tm->bm->totedge ?tm->edge_index[index]:NULL;
+}
+
+BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index)
+{
+ return (tm->face_index && index<tm->bm->totface && index>=0) ? tm->face_index[index] : NULL;
+}
+
+/* this replaces the active flag used in uv/face mode */
+void EDBM_set_actFace(BMEditMesh *em, BMFace *efa)
+{
+ em->bm->act_face = efa;
+}
+
+BMFace *EDBM_get_actFace(BMEditMesh *em, int sloppy)
+{
+ if (em->bm->act_face) {
+ return em->bm->act_face;
+ } else if (sloppy) {
+ BMFace *efa= NULL;
+ BMEditSelection *ese;
+
+ ese = em->bm->selected.last;
+ for (; ese; ese=ese->prev){
+ if(ese->type == BM_FACE) {
+ efa = (BMFace *)ese->data;
+
+ if (BM_TestHFlag(efa, BM_HIDDEN)) efa= NULL;
+ else break;
+ }
+ }
+ if (efa==NULL) {
+ BMIter iter;
+ efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
+ for ( ; efa; efa=BMIter_Step(&iter)) {
+ if (BM_TestHFlag(efa, BM_SELECT))
+ break;
+ }
+ }
+ return efa; /* can still be null */
+ }
+ return NULL;
+
+}
+
+void EDBM_select_flush(BMEditMesh *em, int selectmode)
+{
+ em->bm->selectmode = selectmode;
+ BM_SelectMode_Flush(em->bm);
+ em->bm->selectmode = em->selectmode;
+}
+
+/*BMESH_TODO*/
+void EDBM_deselect_flush(BMEditMesh *UNUSED(em))
+{
+}
+
+
+void EDBM_selectmode_flush(BMEditMesh *em)
+{
+ em->bm->selectmode = em->selectmode;
+ BM_SelectMode_Flush(em->bm);
+}
+
+/*EDBM_select_[more/less] are api functions, I think the uv editor
+ uses them? though the select more/less ops themselves do not.*/
+void EDBM_select_more(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_InitOpf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+ BMO_Finish_Op(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+void EDBM_select_less(BMEditMesh *em)
+{
+ BMOperator bmop;
+ int usefaces = em->selectmode > SCE_SELECT_EDGE;
+
+ BMO_InitOpf(em->bm, &bmop,
+ "regionextend geom=%hvef constrict=%d usefaces=%d",
+ BM_SELECT, 0, usefaces);
+ BMO_Exec_Op(em->bm, &bmop);
+ BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
+ BMO_Finish_Op(em->bm, &bmop);
+
+ EDBM_selectmode_flush(em);
+}
+
+int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
+{
+ BMEditSelection *ese_last = em->bm->selected.last;
+ BMFace *efa = EDBM_get_actFace(em, 0);
+
+ ese->next = ese->prev = NULL;
+
+ if (ese_last) {
+ if (ese_last->type == BM_FACE) { /* if there is an active face, use it over the last selected face */
+ if (efa) {
+ ese->data = (void *)efa;
+ } else {
+ ese->data = ese_last->data;
+ }
+ ese->type = BM_FACE;
+ } else {
+ ese->data = ese_last->data;
+ ese->type = ese_last->type;
+ }
+ } else if (efa) { /* no */
+ ese->data = (void *)efa;
+ ese->type = BM_FACE;
+ } else {
+ ese->data = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+void EDBM_clear_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ if (flag & BM_SELECT)
+ BM_clear_selection_history(em->bm);
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+
+ BM_ITER(ele, &iter, em->bm, type, NULL) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 0);
+ BM_ClearHFlag(ele, flag);
+ }
+ }
+}
+
+void EDBM_set_flag_all(BMEditMesh *em, int flag)
+{
+ BMIter iter;
+ BMHeader *ele;
+ int i, type;
+
+ for (i=0; i<3; i++) {
+ switch (i) {
+ case 0:
+ type = BM_VERTS_OF_MESH;
+ break;
+ case 1:
+ type = BM_EDGES_OF_MESH;
+ break;
+ case 2:
+ type = BM_FACES_OF_MESH;
+ break;
+ }
+
+ ele = BMIter_New(&iter, em->bm, type, NULL);
+ for ( ; ele; ele=BMIter_Step(&iter)) {
+ if (flag & BM_SELECT) BM_Select(em->bm, ele, 1);
+ BM_SetHFlag(ele, flag);
+ }
+ }
+}
+
+/**************-------------- Undo ------------*****************/
+
+/* for callbacks */
+
+static void *getEditMesh(bContext *C)
+{
+ Object *obedit= CTX_data_edit_object(C);
+ if(obedit && obedit->type==OB_MESH) {
+ Mesh *me= obedit->data;
+ return me->edit_btmesh;
+ }
+ return NULL;
+}
+
+typedef struct undomesh {
+ Mesh me;
+ int selectmode;
+ char obname[64];
+} undomesh;
+
+/*undo simply makes copies of a bmesh*/
+static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
+{
+ BMEditMesh *em = emv;
+ Mesh *obme = obdata;
+
+ undomesh *me = MEM_callocN(sizeof(undomesh), "undo Mesh");
+ strcpy(me->obname, em->bm->ob->id.name+2);
+
+ /*make sure shape keys work*/
+ me->me.key = obme->key ? copy_key_nolib(obme->key) : NULL;
+
+ /*we recalc the tesselation here, to avoid seeding calls to
+ BMEdit_RecalcTesselation throughout the code.*/
+ BMEdit_RecalcTesselation(em);
+
+ BMO_CallOpf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", me, 1);
+ me->selectmode = em->selectmode;
+
+ return me;
+}
+
+static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata))
+{
+ BMEditMesh *em = emv, *em2;
+ Object *ob;
+ undomesh *me = umv;
+ BMesh *bm;
+ int allocsize[4] = {512, 512, 2048, 512};
+
+ ob = (Object*)find_id("OB", me->obname);
+ ob->shapenr = em->bm->shapenr;
+
+ BMEdit_Free(em);
+
+ bm = BM_Make_Mesh(ob, allocsize);
+ BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 0);
+
+ em2 = BMEdit_Create(bm);
+ *em = *em2;
+
+ em->selectmode = me->selectmode;
+
+ MEM_freeN(em2);
+}
+
+
+static void free_undo(void *umv)
+{
+ free_mesh(umv, 0);
+ MEM_freeN(umv);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(bContext *C, const char *name)
+{
+ undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+}
+
+/*write comment here*/
+UvVertMap *EDBM_make_uv_vert_map(BMEditMesh *em, int selected, int do_face_idx_array, float *limit)
+{
+ BMVert *ev;
+ BMFace *efa;
+ BMLoop *l;
+ BMIter iter, liter;
+ /* vars from original func */
+ UvVertMap *vmap;
+ UvMapVert *buf;
+ MTexPoly *tf;
+ MLoopUV *luv;
+ unsigned int a;
+ int totverts, i, totuv;
+
+ if (do_face_idx_array)
+ EDBM_init_index_arrays(em, 0, 0, 1);
+
+ /* we need the vert */
+ totverts=0;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, totverts);
+ totverts++;
+ }
+
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT)))
+ totuv += efa->len;
+ }
+
+ if(totuv==0) {
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+ vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
+ if (!vmap) {
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+
+ vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
+ buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
+
+ if (!vmap->vert || !vmap->buf) {
+ free_uv_vert_map(vmap);
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+ return NULL;
+ }
+
+ a = 0;
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) {
+ i = 0;
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ buf->tfindex= i;
+ buf->f= a;
+ buf->separate = 0;
+
+ buf->next= vmap->vert[BMINDEX_GET(l->v)];
+ vmap->vert[BMINDEX_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);
+
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uv = luv->uv;
+
+ lastv= NULL;
+ iterv= vlist;
+
+ while(iterv) {
+ next= iterv->next;
+ efa = EDBM_get_face_for_index(em, iterv->f);
+ tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+
+ l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
+ luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ uv2 = luv->uv;
+
+ sub_v2_v2v2(uvdiff, uv2, uv);
+
+ if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
+ if(lastv) lastv->next= next;
+ else vlist= next;
+ iterv->next= newvlist;
+ newvlist= iterv;
+ }
+ else
+ lastv=iterv;
+
+ iterv= next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ vmap->vert[a]= newvlist;
+ a++;
+ }
+
+ if (do_face_idx_array)
+ EDBM_free_index_arrays(em);
+
+ return vmap;
+}
+
+
+UvMapVert *EDBM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
+{
+ return vmap->vert[v];
+}
+
+void EDBM_free_uv_vert_map(UvVertMap *vmap)
+{
+ if (vmap) {
+ if (vmap->vert) MEM_freeN(vmap->vert);
+ if (vmap->buf) MEM_freeN(vmap->buf);
+ MEM_freeN(vmap);
+ }
+}
+
+
+/* last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
+MTexPoly *EDBM_get_active_mtexpoly(BMEditMesh *em, BMFace **act_efa, int sloppy)
+{
+ BMFace *efa = NULL;
+
+ if(!EDBM_texFaceCheck(em))
+ return NULL;
+
+ efa = EDBM_get_actFace(em, sloppy);
+
+ if (efa) {
+ if (act_efa) *act_efa = efa;
+ return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
+ }
+
+ if (act_efa) *act_efa= NULL;
+ return NULL;
+}
+
+/* can we edit UV's for this mesh?*/
+int EDBM_texFaceCheck(BMEditMesh *em)
+{
+ /* some of these checks could be a touch overkill */
+ return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
+ CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
+}
+
+int EDBM_vertColorCheck(BMEditMesh *em)
+{
+ /* some of these checks could be a touch overkill */
+ return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
+}
+
+
+void EDBM_CacheMirrorVerts(BMEditMesh *em)
+{
+ BMBVHTree *tree = BMBVH_NewBVH(em);
+ BMIter iter;
+ BMVert *v;
+ float invmat[4][4];
+ int li, i;
+
+ if (!em->vert_index) {
+ EDBM_init_index_arrays(em, 1, 0, 0);
+ em->mirr_free_arrays = 1;
+ }
+
+ if (!CustomData_get_layer_named(&em->bm->vdata, CD_PROP_INT, (char*)"__mirror_index")) {
+ BM_add_data_layer_named(em->bm, &em->bm->vdata, CD_PROP_INT, (char*)"__mirror_index");
+ }
+
+ li = CustomData_get_named_layer_index(&em->bm->vdata, CD_PROP_INT, "__mirror_index");
+ em->bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
+
+ /*multiply verts by object matrix, temporarily*/
+
+ i = 0;
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+
+ if (em->ob)
+ mul_m4_v3(em->ob->obmat, v->co);
+ }
+
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMVert *mirr;
+ int *idx = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, li);
+ float co[3] = {-v->co[0], v->co[1], v->co[2]};
+
+ //temporary for testing, check for selection
+ if (!BM_TestHFlag(v, BM_SELECT))
+ continue;
+
+ mirr = BMBVH_FindClosestVertTopo(tree, co, BM_SEARCH_MAXDIST, v);
+ if (mirr && mirr != v) {
+ *idx = BMINDEX_GET(mirr);
+ idx = CustomData_bmesh_get_layer_n(&em->bm->vdata,mirr->head.data, li);
+ *idx = BMINDEX_GET(v);
+ } else *idx = -1;
+ }
+
+ /*unmultiply by object matrix*/
+ if (em->ob) {
+ i = 0;
+ invert_m4_m4(invmat, em->ob->obmat);
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(v, i);
+ i++;
+
+ mul_m4_v3(invmat, v->co);
+ }
+
+ BMBVH_FreeBVH(tree);
+ }
+}
+
+BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
+{
+ int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
+
+ if (mirr && *mirr >=0 && *mirr < em->bm->totvert) {
+ if (!em->vert_index) {
+ printf("err: should only be called between "
+ "EDBM_CacheMirrorVerts and EDBM_EndMirrorCache");
+ return NULL;
+ }
+
+ return em->vert_index[*mirr];
+ }
+
+ return NULL;
+}
+
+void EDBM_EndMirrorCache(BMEditMesh *em)
+{
+ if (em->mirr_free_arrays) {
+ MEM_freeN(em->vert_index);
+ em->vert_index = NULL;
+ }
+}
diff --git a/source/blender/editors/mesh/editbmesh_add.c b/source/blender/editors/mesh/editbmesh_add.c
new file mode 100644
index 00000000000..dfb242d7144
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_add.c
@@ -0,0 +1,619 @@
+ /* $Id: bmesh_tools.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_object.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+
+/* uses context to figure out transform for primitive */
+/* returns standard diameter */
+static float new_primitive_matrix(bContext *C, float *loc, float *rot, float primmat[][4])
+{
+ Object *obedit= CTX_data_edit_object(C);
+ View3D *v3d =CTX_wm_view3d(C);
+ float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3];
+
+ unit_m4(primmat);
+
+ eul_to_mat3(rmat, rot);
+ invert_m3(rmat);
+
+ /* inverse transform for initial rotation and object */
+ copy_m3_m4(mat, obedit->obmat);
+ mul_m3_m3m3(cmat, rmat, mat);
+ invert_m3_m3(imat, cmat);
+ copy_m4_m3(primmat, imat);
+
+ /* center */
+ VECCOPY(primmat[3], loc);
+ VECSUB(primmat[3], primmat[3], obedit->obmat[3]);
+ invert_m3_m3(imat, mat);
+ mul_m3_v3(imat, primmat[3]);
+
+ if(v3d) return v3d->grid;
+ return 1.0f;
+}
+
+/* ********* add primitive operators ************* */
+
+static void make_prim_init(bContext *C, float *dia, float mat[][4],
+ int *state, float *loc, float *rot, unsigned int layer)
+{
+ Object *obedit= CTX_data_edit_object(C);
+
+ *state = 0;
+ if(obedit==NULL || obedit->type!=OB_MESH) {
+ obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer);
+
+ /* create editmode */
+ ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
+ *state = 1;
+ }
+ else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+
+ *dia *= new_primitive_matrix(C, loc, rot, mat);
+}
+
+static void make_prim_finish(bContext *C, int *state, int enter_editmode)
+{
+ Object *obedit = CTX_data_edit_object(C);
+
+ DAG_id_tag_update(obedit->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+ /* userdef */
+ if (*state && !enter_editmode) {
+ ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
+ }
+ WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
+
+}
+static int add_primitive_plane_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_grid xsegments=%i ysegments=%i size=%f mat=%m4", 1, 1, sqrt(2.0), mat))
+ return OPERATOR_CANCELLED;
+
+ /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_plane_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Plane";
+ ot->description= "Construct a filled planar mesh with 4 vertices.";
+ ot->idname= "MESH_OT_primitive_plane_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_plane_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cube_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit= CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_cube mat=%m4 size=%f", mat, 2.0f))
+ return OPERATOR_CANCELLED;
+
+ /* BMESH_TODO make plane side this: sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cube_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Cube";
+ ot->description= "Construct a cube mesh.";
+ ot->idname= "MESH_OT_primitive_cube_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cube_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static const EnumPropertyItem fill_type_items[]= {
+ {0, "NOTHING", 0, "Nothing", "Don't fill at all"},
+ {1, "NGON", 0, "Ngon", "Use ngons"},
+ {2, "TRIFAN", 0, "Triangle Fan", "Use triangle fans"},
+ {0, NULL, 0, NULL, NULL}};
+
+static int add_primitive_circle_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state, cap_end, cap_tri;
+ unsigned int layer;
+
+ cap_end = RNA_enum_get(op->ptr, "fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_circle segments=%i diameter=%f cap_ends=%i cap_tris=%i mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ cap_end, cap_tri, mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_circle_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Circle";
+ ot->description= "Construct a circle mesh.";
+ ot->idname= "MESH_OT_primitive_circle_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_circle_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ RNA_def_enum(ot->srna, "fill_type", fill_type_items, 0, "Fill Type", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state, cap_end, cap_tri;
+ unsigned int layer;
+
+ cap_end = RNA_enum_get(op->ptr, "end_fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i cap_tris=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius"),
+ RNA_float_get(op->ptr, "radius"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Tube";
+ ot->description= "Construct a tube mesh.";
+ ot->idname= "MESH_OT_primitive_cylinder_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cylinder_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
+ RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
+ RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Cap Fill Type", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_cone_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state, cap_end, cap_tri;
+ unsigned int layer;
+
+ cap_end = RNA_enum_get(op->ptr, "end_fill_type");
+ cap_tri = cap_end==2;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%i cap_tris=%i depth=%f mat=%m4",
+ RNA_int_get(op->ptr, "vertices"), RNA_float_get(op->ptr, "radius1"),
+ RNA_float_get(op->ptr, "radius2"), cap_end, cap_tri, RNA_float_get(op->ptr, "depth"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_cone_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Cone";
+ ot->description= "Construct a conic mesh (ends filled).";
+ ot->idname= "MESH_OT_primitive_cone_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_cone_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
+ RNA_def_float(ot->srna, "radius1", 1.0f, 0.0, FLT_MAX, "Radius 1", "", 0.001, 100.00);
+ RNA_def_float(ot->srna, "radius2", 0.0f, 0.0, FLT_MAX, "Radius 2", "", 0.001, 100.00);
+ RNA_def_float(ot->srna, "depth", 1.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
+ RNA_def_enum(ot->srna, "end_fill_type", fill_type_items, 1, "Base Fill Type", "");
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_grid_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_grid xsegments=%i ysegments=%i size=%f mat=%m4",
+ RNA_int_get(op->ptr, "x_subdivisions"),
+ RNA_int_get(op->ptr, "y_subdivisions"),
+ RNA_float_get(op->ptr, "size"), mat))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_grid_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Grid";
+ ot->description= "Construct a grid mesh.";
+ ot->idname= "MESH_OT_primitive_grid_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_grid_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000);
+ RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state, view_aligned;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, &view_aligned);
+ if (!view_aligned)
+ rot[0] += M_PI/2.0f;
+
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout", "create_monkey mat=%m4", mat)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Monkey";
+ ot->description= "Construct a Suzanne mesh.";
+ ot->idname= "MESH_OT_primitive_monkey_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_monkey_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+
+static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_uvsphere segments=%i revolutions=%i diameter=%f mat=%m4",
+ RNA_int_get(op->ptr, "rings"), RNA_int_get(op->ptr, "segments"),
+ RNA_float_get(op->ptr,"size"), mat))
+ return OPERATOR_CANCELLED;
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add UV Sphere";
+ ot->description= "Construct a UV sphere mesh.";
+ ot->idname= "MESH_OT_primitive_uv_sphere_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_uvsphere_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500);
+ RNA_def_int(ot->srna, "rings", 24, INT_MIN, INT_MAX, "Rings", "", 3, 500);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
+
+static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit;
+ Mesh *me;
+ BMEditMesh *em;
+ float loc[3], rot[3], mat[4][4], dia;
+ int enter_editmode;
+ int state;
+ unsigned int layer;
+
+ ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer, NULL);
+ make_prim_init(C, &dia, mat, &state, loc, rot, layer);
+
+ obedit = CTX_data_edit_object(C);
+ me = obedit->data;
+ em = me->edit_btmesh;
+
+ if (!EDBM_CallAndSelectOpf(em, op, "vertout",
+ "create_icosphere subdivisions=%i diameter=%f mat=%m4",
+ RNA_int_get(op->ptr, "subdivisions"),
+ RNA_float_get(op->ptr, "size"), mat)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ make_prim_finish(C, &state, enter_editmode);
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Add Ico Sphere";
+ ot->description= "Construct an Icosphere mesh.";
+ ot->idname= "MESH_OT_primitive_ico_sphere_add";
+
+ /* api callbacks */
+ ot->invoke= ED_object_add_generic_invoke;
+ ot->exec= add_primitive_icosphere_exec;
+ ot->poll= ED_operator_scene_editable;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* props */
+ RNA_def_int(ot->srna, "subdivisions", 2, 0, 6, "Subdivisions", "", 0, 8);
+ RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
+
+ ED_object_add_generic_props(ot, TRUE);
+}
diff --git a/source/blender/editors/mesh/editbmesh_bvh.c b/source/blender/editors/mesh/editbmesh_bvh.c
new file mode 100644
index 00000000000..d7ab294d877
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_bvh.c
@@ -0,0 +1,725 @@
+ /* $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2010 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#define IN_EDITMESHBVH
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLO_sys_types.h" // for intptr_t support
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_types.h"
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+#include "BLI_array.h"
+#include "BLI_kdopbvh.h"
+
+#include "BKE_context.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bmesh.h"
+#include "BKE_report.h"
+#include "BKE_tessmesh.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_view3d.h"
+#include "ED_util.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+
+#include "UI_interface.h"
+
+#include "mesh_intern.h"
+#include "bmesh.h"
+
+#include "editbmesh_bvh.h"
+
+typedef struct BMBVHTree {
+ BMEditMesh *em;
+ BMesh *bm;
+ BVHTree *tree;
+ float epsilon;
+ float maxdist; //for nearest point search
+
+ /*stuff for topological vert search*/
+ BMVert *v, *curv;
+ GHash *gh;
+ float curw, curd;
+ float co[3];
+ int curtag;
+} BMBVHTree;
+
+BMBVHTree *BMBVH_NewBVH(BMEditMesh *em)
+{
+ BMBVHTree *tree = MEM_callocN(sizeof(*tree), "BMBVHTree");
+ float cos[3][3];
+ int i;
+
+ BMEdit_RecalcTesselation(em);
+
+ tree->em = em;
+ tree->bm = em->bm;
+ tree->epsilon = FLT_EPSILON*2.0f;
+
+ tree->tree = BLI_bvhtree_new(em->tottri, tree->epsilon, 8, 8);
+
+ for (i=0; i<em->tottri; i++) {
+ VECCOPY(cos[0], em->looptris[i][0]->v->co);
+ VECCOPY(cos[1], em->looptris[i][1]->v->co);
+ VECCOPY(cos[2], em->looptris[i][2]->v->co);
+
+ BLI_bvhtree_insert(tree->tree, i, (float*)cos, 3);
+ }
+
+ BLI_bvhtree_balance(tree->tree);
+
+ return tree;
+}
+
+void BMBVH_FreeBVH(BMBVHTree *tree)
+{
+ BLI_bvhtree_free(tree->tree);
+ MEM_freeN(tree);
+}
+
+/*taken from bvhutils.c*/
+static float ray_tri_intersection(const BVHTreeRay *ray, const float UNUSED(m_dist), float *v0,
+ float *v1, float *v2, float *uv, float UNUSED(e))
+{
+ float dist;
+#if 0
+ float vv1[3], vv2[3], vv3[3], cent[3];
+
+ /*expand triangle by an epsilon. this is probably a really stupid
+ way of doing it, but I'm too tired to do better work.*/
+ VECCOPY(vv1, v0);
+ VECCOPY(vv2, v1);
+ VECCOPY(vv3, v2);
+
+ add_v3_v3v3(cent, vv1, vv2);
+ add_v3_v3v3(cent, cent, vv3);
+ mul_v3_fl(cent, 1.0f/3.0f);
+
+ sub_v3_v3v3(vv1, vv1, cent);
+ sub_v3_v3v3(vv2, vv2, cent);
+ sub_v3_v3v3(vv3, vv3, cent);
+
+ mul_v3_fl(vv1, 1.0f + e);
+ mul_v3_fl(vv2, 1.0f + e);
+ mul_v3_fl(vv3, 1.0f + e);
+
+ add_v3_v3v3(vv1, vv1, cent);
+ add_v3_v3v3(vv2, vv2, cent);
+ add_v3_v3v3(vv3, vv3, cent);
+
+ if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, vv1, vv2, vv3, &dist, uv))
+ return dist;
+#else
+ if(isect_ray_tri_v3((float*)ray->origin, (float*)ray->direction, v0, v1, v2, &dist, uv))
+ return dist;
+#endif
+
+ return FLT_MAX;
+}
+
+static void raycallback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ float dist, uv[2];
+
+ if (!ls[0] || !ls[1] || !ls[2])
+ return;
+
+ dist = ray_tri_intersection(ray, hit->dist, ls[0]->v->co, ls[1]->v->co,
+ ls[2]->v->co, uv, tree->epsilon);
+ if (dist < hit->dist) {
+ hit->dist = dist;
+ hit->index = index;
+
+ VECCOPY(hit->no, ls[0]->v->no);
+
+ copy_v3_v3(hit->co, ray->direction);
+ normalize_v3(hit->co);
+ mul_v3_fl(hit->co, dist);
+ add_v3_v3(hit->co, ray->origin);
+ }
+}
+
+BMFace *BMBVH_RayCast(BMBVHTree *tree, float *co, float *dir, float *hitout)
+{
+ BVHTreeRayHit hit;
+
+ hit.dist = FLT_MAX;
+ hit.index = -1;
+
+ BLI_bvhtree_ray_cast(tree->tree, co, dir, 0.0f, &hit, raycallback, tree);
+ if (hit.dist != FLT_MAX && hit.index != -1) {
+ if (hitout) {
+ VECCOPY(hitout, hit.co);
+ }
+
+ return tree->em->looptris[hit.index][0]->f;
+ }
+
+ return NULL;
+}
+
+BVHTree *BMBVH_BVHTree(BMBVHTree *tree)
+{
+ return tree->tree;
+}
+
+static void vertsearchcallback(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *hit)
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ float dist, maxdist, v[3];
+ int i;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ sub_v3_v3v3(v, hit->co, ls[i]->v->co);
+
+ dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ if (dist < hit->dist && dist < maxdist) {
+ VECCOPY(hit->co, ls[i]->v->co);
+ VECCOPY(hit->no, ls[i]->v->no);
+ hit->dist = dist;
+ }
+ }
+}
+
+BMVert *BMBVH_FindClosestVert(BMBVHTree *tree, float *co, float maxdist)
+{
+ BVHTreeNearest hit;
+
+ VECCOPY(hit.co, co);
+ hit.dist = maxdist*5;
+ hit.index = -1;
+
+ tree->maxdist = maxdist;
+
+ BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback, tree);
+ if (hit.dist != FLT_MAX && hit.index != -1) {
+ BMLoop **ls = tree->em->looptris[hit.index];
+ float dist, curdist = tree->maxdist, v[3];
+ int cur=0, i;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ sub_v3_v3v3(v, hit.co, ls[i]->v->co);
+
+ dist = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+ if (dist < curdist) {
+ cur = i;
+ curdist = dist;
+ }
+ }
+
+ return ls[i]->v;
+ }
+
+ return NULL;
+}
+
+typedef struct walklist {
+ BMVert *v;
+ int valence;
+ int depth;
+ float w, r;
+ int totwalked;
+
+ /*state data*/
+ BMVert *lastv;
+ BMLoop *curl, *firstl;
+ BMEdge *cure;
+} walklist;
+
+
+static short winding(float *v1, float *v2, float *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ double inp;
+
+ //inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy]) +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+ inp= (v2[0]-v1[0])*(v1[1]-v3[1]) +(v1[1]-v2[1])*(v1[0]-v3[0]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[0]==v3[0] && v1[1]==v3[1]) return 0;
+ if(v2[0]==v3[0] && v2[1]==v3[1]) return 0;
+ }
+ return 1;
+}
+
+static float topo_compare(BMesh *bm, BMVert *v1, BMVert *v2)
+{
+ BMIter iter1, iter2;
+ BMEdge *e1, *e2, *cure1 = NULL, *cure2 = NULL;
+ BMLoop *l1, *l2;
+ BMVert *lastv1, *lastv2;
+ GHash *gh;
+ walklist *stack1=NULL, *stack2=NULL;
+ BLI_array_declare(stack1);
+ BLI_array_declare(stack2);
+ float vec1[3], vec2[3], minangle=FLT_MAX, w;
+ int lvl=1;
+ static int maxlevel = 3;
+
+ /*ok. see how similar v is to v2, based on topological similaritys in the local
+ topological neighborhood*/
+
+ /*step 1: find two edges, one that contains v and one that contains v2, with the
+ smallest angle between the two edges*/
+
+ BM_ITER(e1, &iter1, bm, BM_EDGES_OF_VERT, v1) {
+ BM_ITER(e2, &iter2, bm, BM_EDGES_OF_VERT, v2) {
+ float angle;
+
+ if (e1->v1 == e2->v1 || e1->v2 == e2->v2 || e1->v1 == e2->v2 || e1->v2 == e2->v1)
+ continue;
+
+ sub_v3_v3v3(vec1, BM_OtherEdgeVert(e1, v1)->co, v1->co);
+ sub_v3_v3v3(vec2, BM_OtherEdgeVert(e2, v2)->co, v2->co);
+
+ angle = fabs(angle_v3v3(vec1, vec2));
+
+ if (angle < minangle) {
+ minangle = angle;
+ cure1 = e1;
+ cure2 = e2;
+ }
+ }
+ }
+
+ if (!cure1 || !cure1->l || !cure2->l) {
+ /*just return 1.0 in this case*/
+ return 1.0f;
+ }
+
+ /*assumtions
+
+ we assume a 2-manifold mesh here. if at any time this isn't the case,
+ e.g. a hole or an edge with more then 2 faces around it, we um ignore
+ that edge I guess, and try to make the algorithm go around as necassary.*/
+
+ l1 = cure1->l;
+ l2 = cure2->l;
+
+ lastv1 = l1->v == v1 ? ((BMLoop*)l1->next)->v : ((BMLoop*)l1->prev)->v;
+ lastv2 = l2->v == v2 ? ((BMLoop*)l2->next)->v : ((BMLoop*)l2->prev)->v;
+
+ /*we can only provide meaningful comparisons if v1 and v2 have the same valence*/
+ if (BM_Vert_EdgeCount(v1) != BM_Vert_EdgeCount(v2))
+ return 1.0f; /*full mismatch*/
+
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
+
+#define SPUSH(s, d, vt, lv, e)\
+ if (BLI_array_count(s) <= lvl) BLI_array_growone(s);\
+ memset((s+lvl), 0, sizeof(*s));\
+ s[lvl].depth = d;\
+ s[lvl].v = vt;\
+ s[lvl].cure = e;\
+ s[lvl].lastv = lv;\
+ s[lvl].valence = BM_Vert_EdgeCount(vt);\
+
+ lvl = 0;
+
+ SPUSH(stack1, 0, v1, lastv1, cure1);
+ SPUSH(stack2, 0, v2, lastv2, cure2);
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ lvl = 1;
+ while (lvl) {
+ int term = 0;
+ walklist *s1 = stack1 + lvl - 1, *s2 = stack2 + lvl - 1;
+
+ /*pop from the stack*/
+ lvl--;
+
+ if (s1->curl && s1->curl->e == s1->cure)
+ term = 1;
+ if (s2->curl && s2->curl->e == s2->cure)
+ term = 1;
+
+ /*find next case to do*/
+ if (!s1->curl)
+ s1->curl = s1->cure->l;
+ if (!s2->curl) {
+ float no1[3], no2[3], angle;
+ int wind1, wind2;
+
+ s2->curl = s2->cure->l;
+
+ /*find which of two possible faces to use*/
+ l1 = BM_OtherFaceLoop(s1->curl->e, s1->curl->f, s1->lastv);
+ l2 = BM_OtherFaceLoop(s2->curl->e, s2->curl->f, s2->lastv);
+
+ if (l1->v == s2->lastv) {
+ l1 = (BMLoop*) l1->next;
+ if (l1->v == s2->v)
+ l1 = (BMLoop*) l1->prev->prev;
+ } else if (l1->v == s2->v) {
+ l1 = (BMLoop*) l1->next;
+ if (l1->v == s2->lastv)
+ l1 = (BMLoop*) l1->prev->prev;
+ }
+
+ if (l2->v == s2->lastv) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->v)
+ l2 = (BMLoop*) l2->prev->prev;
+ } else if (l2->v == s2->v) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->lastv)
+ l2 = (BMLoop*) l2->prev->prev;
+ }
+
+ wind1 = winding(s1->v->co, s1->lastv->co, l1->v->co);
+
+ wind2 = winding(s2->v->co, s2->lastv->co, l2->v->co);
+
+ /*if angle between the two adjacent faces is greater then 90 degrees,
+ we need to flip wind2*/
+ l1 = l2;
+ l2 = s2->curl->radial_next;
+ l2 = BM_OtherFaceLoop(l2->e, l2->f, s2->lastv);
+
+ if (l2->v == s2->lastv) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->v)
+ l2 = (BMLoop*) l2->prev->prev;
+ } else if (l2->v == s2->v) {
+ l2 = (BMLoop*) l2->next;
+ if (l2->v == s2->lastv)
+ l2 = (BMLoop*) l2->prev->prev;
+ }
+
+ normal_tri_v3(no1, s2->v->co, s2->lastv->co, l1->v->co);
+ normal_tri_v3(no2, s2->v->co, s2->lastv->co, l2->v->co);
+
+ /*enforce identical winding as no1*/
+ mul_v3_fl(no2, -1.0);
+
+ angle = angle_v3v3(no1, no2);
+ if (angle > M_PI/2 - FLT_EPSILON*2)
+ wind2 = !wind2;
+
+ if (wind1 == wind2)
+ s2->curl = s2->curl->radial_next;
+ }
+
+ /*handle termination cases of having already looped through all child
+ nodes, or the valence mismatching between v1 and v2, or we hit max
+ recursion depth*/
+ term |= s1->valence != s2->valence || lvl+1 > maxlevel;
+ term |= s1->curl->radial_next == (BMLoop*)l1;
+ term |= s2->curl->radial_next == (BMLoop*)l2;
+
+ if (!term) {
+ lastv1 = s1->v;
+ lastv2 = s2->v;
+ v1 = BM_OtherEdgeVert(s1->curl->e, lastv1);
+ v2 = BM_OtherEdgeVert(s2->curl->e, lastv2);
+
+ e1 = s1->curl->e;
+ e2 = s2->curl->e;
+
+ if (!BLI_ghash_haskey(gh, v1) && !BLI_ghash_haskey(gh, v2)) {
+ /*repush the current stack item*/
+ lvl++;
+
+ //if (maxlevel % 2 == 0) {
+ BLI_ghash_insert(gh, v1, NULL);
+ BLI_ghash_insert(gh, v2, NULL);
+ //}
+
+ /*now push the child node*/
+ SPUSH(stack1, lvl, v1, lastv1, e1);
+ SPUSH(stack2, lvl, v2, lastv2, e2);
+
+ lvl++;
+
+ s1 = stack1 + lvl - 2;
+ s2 = stack2 + lvl - 2;
+ }
+
+ s1->curl = s1->curl->v == s1->v ? (BMLoop*) s1->curl->prev : (BMLoop*) s1->curl->next;
+ s2->curl = s2->curl->v == s2->v ? (BMLoop*) s2->curl->prev : (BMLoop*) s2->curl->next;
+
+ s1->curl = (BMLoop*) s1->curl->radial_next;
+ s2->curl = (BMLoop*) s2->curl->radial_next;
+ }
+
+#define WADD(stack, s)\
+ if (lvl) {/*silly attempt to make this non-commutative: randomize\
+ how much this particular weight adds to the total*/\
+ stack[lvl-1].r += r;\
+ s->w *= r;\
+ stack[lvl-1].totwalked++;\
+ stack[lvl-1].w += s->w;\
+ }
+
+ /*if no next case to do, update parent weight*/
+ if (term) {
+ float r = 0.8f + BLI_frand()*0.2f - FLT_EPSILON;
+
+ if (s1->totwalked) {
+ s1->w /= s1->r;
+ } else
+ s1->w = s1->valence == s2->valence ? 1.0f : 0.0f;
+
+ WADD(stack1, s1);
+
+ if (s2->totwalked) {
+ s2->w /= s2->r;
+ } else
+ s2->w = s1->valence == s2->valence ? 1.0f : 0.0f;
+
+ WADD(stack2, s2);
+
+ /*apply additional penalty to weight mismatch*/
+ if (s2->w != s1->w)
+ s2->w *= 0.8f;
+ }
+ }
+
+ w = (stack1[0].w + stack2[0].w)*0.5f;
+
+ BLI_array_free(stack1);
+ BLI_array_free(stack2);
+
+ BLI_ghash_free(gh, NULL, NULL);
+
+ return 1.0f - w;
+}
+
+static void vertsearchcallback_topo(void *userdata, int index, const float *UNUSED(co), BVHTreeNearest *UNUSED(hit))
+{
+ BMBVHTree *tree = userdata;
+ BMLoop **ls = tree->em->looptris[index];
+ int i;
+ float maxdist, vec[3], w;
+
+ maxdist = tree->maxdist;
+
+ for (i=0; i<3; i++) {
+ float dis;
+
+ if (BLI_ghash_haskey(tree->gh, ls[i]->v))
+ continue;
+
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ dis = dot_v3v3(vec, vec);
+
+ w = topo_compare(tree->em->bm, tree->v, ls[i]->v);
+ tree->curtag++;
+
+ if (w < tree->curw-FLT_EPSILON*4) {
+ tree->curw = w;
+ tree->curv = ls[i]->v;
+
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ tree->curd = dot_v3v3(vec, vec);
+
+ /*we deliberately check for equality using (smallest possible float)*4
+ comparison factor, to always prefer distance in cases of verts really
+ close to each other*/
+ } else if (fabs(tree->curw - w) < FLT_EPSILON*4) {
+ /*if w is equal to hitex->curw, sort by distance*/
+ sub_v3_v3v3(vec, tree->co, ls[i]->v->co);
+ dis = dot_v3v3(vec, vec);
+
+ if (dis < tree->curd) {
+ tree->curd = dis;
+ tree->curv = ls[i]->v;
+ }
+ }
+
+ BLI_ghash_insert(tree->gh, ls[i]->v, NULL);
+ }
+}
+
+BMVert *BMBVH_FindClosestVertTopo(BMBVHTree *tree, float *co, float maxdist, BMVert *sourcev)
+{
+ BVHTreeNearest hit;
+
+ memset(&hit, 0, sizeof(hit));
+
+ VECCOPY(hit.co, co);
+ VECCOPY(tree->co, co);
+ hit.index = -1;
+ hit.dist = maxdist;
+
+ tree->curw = FLT_MAX;
+ tree->curd = FLT_MAX;
+ tree->curv = NULL;
+ tree->curtag = 1;
+
+ tree->gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh bvh");
+
+ tree->maxdist = maxdist;
+ tree->v = sourcev;
+
+ BLI_bvhtree_find_nearest(tree->tree, co, &hit, vertsearchcallback_topo, tree);
+
+ BLI_ghash_free(tree->gh, NULL, NULL);
+ tree->gh = NULL;
+
+ return tree->curv;
+}
+
+
+#if 0 //BMESH_TODO: not implemented yet
+int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d)
+{
+
+}
+#endif
+
+static BMFace *edge_ray_cast(BMBVHTree *tree, float *co, float *dir, float *hitout, BMEdge *e)
+{
+ BMFace *f = BMBVH_RayCast(tree, co, dir, hitout);
+
+ if (f && BM_Edge_In_Face(f, e))
+ return NULL;
+
+ return f;
+}
+
+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 m[2], end[3];
+
+ if (!ar) {
+ printf("error in BMBVH_EdgeVisible!\n");
+ return 0;
+ }
+
+ m[0] = ar->winx/2.0;
+ m[1] = ar->winy/2.0;
+ viewline(ar, v3d, m, origin, end);
+
+ invert_m4_m4(invmat, obedit->obmat);
+ mul_m4_v3(invmat, origin);
+
+ VECCOPY(co1, e->v1->co);
+ add_v3_v3v3(co2, e->v1->co, e->v2->co);
+ mul_v3_fl(co2, 0.5f);
+ VECCOPY(co3, e->v2->co);
+
+ scale_point(co1, co2, 0.99);
+ scale_point(co3, co2, 0.99);
+
+ /*ok, idea is to generate rays going from the camera origin to the
+ three points on the edge (v1, mid, v2)*/
+ sub_v3_v3v3(dir1, origin, co1);
+ sub_v3_v3v3(dir2, origin, co2);
+ sub_v3_v3v3(dir3, origin, co3);
+
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dir3);
+
+ mul_v3_fl(dir1, epsilon);
+ mul_v3_fl(dir2, epsilon);
+ mul_v3_fl(dir3, epsilon);
+
+ /*offset coordinates slightly along view vectors, to avoid
+ hitting the faces that own the edge.*/
+ add_v3_v3v3(co1, co1, dir1);
+ add_v3_v3v3(co2, co2, dir2);
+ add_v3_v3v3(co3, co3, dir3);
+
+ normalize_v3(dir1);
+ normalize_v3(dir2);
+ normalize_v3(dir3);
+
+ /*do three samplings: left, middle, right*/
+ f = edge_ray_cast(tree, co1, dir1, NULL, e);
+ if (f && !edge_ray_cast(tree, co2, dir2, NULL, e))
+ return 1;
+ else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e))
+ return 1;
+ else if (!f)
+ return 1;
+
+ return 0;
+}
diff --git a/source/blender/editors/mesh/editbmesh_bvh.h b/source/blender/editors/mesh/editbmesh_bvh.h
new file mode 100644
index 00000000000..c8decd24f38
--- /dev/null
+++ b/source/blender/editors/mesh/editbmesh_bvh.h
@@ -0,0 +1,31 @@
+#ifndef _EDITBMESH_BVH
+#define _EDITBMESH_BVH
+
+struct BMEditMesh;
+struct BMFace;
+struct BMEdge;
+struct BMVert;
+struct RegionView3D;
+struct BMBVHTree;
+struct BVHTree;
+
+#ifndef IN_EDITMESHBVH
+typedef struct BMBVHTree BMBVHTree;
+#endif
+
+struct BMBVHTree *BMBVH_NewBVH(struct BMEditMesh *em);
+void BMBVH_FreeBVH(struct BMBVHTree *tree);
+struct BVHTree *BMBVH_BVHTree(struct BMBVHTree *tree);
+
+struct BMFace *BMBVH_RayCast(struct BMBVHTree *tree, float *co, float *dir, float *hitout);
+
+int BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
+ struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
+
+#define BM_SEARCH_MAXDIST 0.4f
+
+/*find a vert closest to co in a sphere of radius maxdist*/
+struct BMVert *BMBVH_FindClosestVert(struct BMBVHTree *tree, float *co, float maxdist);
+struct BMVert *BMBVH_FindClosestVertTopo(struct BMBVHTree *tree, float *co,
+ float maxdist, struct BMVert *sourcev);
+#endif /* _EDITBMESH_H */
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 9cec034af28..06eb1f1ead4 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
@@ -54,6 +54,7 @@
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_context.h"
+#include "BKE_tessmesh.h"
#include "BIF_gl.h"
@@ -73,40 +74,53 @@ void paintface_flush_flags(Object *ob)
{
Mesh *me= get_mesh(ob);
DerivedMesh *dm= ob->derivedFinal;
- MFace *faces, *mf, *mf_orig;
- int *index_array = NULL;
+ MPoly *mf_orig;
+ DMFaceIter *fiter;
+ int *index = NULL;
int totface;
int i;
if(me==NULL || dm==NULL)
return;
- index_array = dm->getFaceDataArray(dm, CD_ORIGINDEX);
-
- if(!index_array)
- return;
-
- faces = dm->getFaceArray(dm);
+ fiter = dm->newFaceIter(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;
+
+ for (i=0; !fiter->done; fiter->step(fiter), i++) {
+ index = fiter->getCDData(fiter, CD_ORIGINDEX, -1);
+ if (!index) {
+ fiter->free(fiter);
+ return;
+ }
+
+ mf_orig = me->mpoly + *index;
+ fiter->flags = mf_orig->flag;
}
+
+ fiter->free(fiter);
}
/* returns 0 if not found, otherwise 1 */
-static int facesel_face_pick(struct bContext *C, Mesh *me, const short mval[2], unsigned int *index, short rect)
+static int facesel_face_pick(struct bContext *C, Mesh *me, Object *ob, const short mval[2], unsigned int *index, short rect)
{
+ Scene *scene = CTX_data_scene(C);
ViewContext vc;
view3d_set_viewcontext(C, &vc);
- if (!me || me->totface==0)
+ if (!me || me->totpoly==0)
return 0;
-// XXX if (v3d->flag & V3D_INVALID_BACKBUF) {
+ /*we can't assume mfaces have a correct origindex layer that indices to mpolys.
+ so instead we have to regenerate the tesselation faces altogether.
+
+ the final 0, 0 paramters causes it to use the index of each mpoly, instead
+ of reading from the origindex layer.*/
+ me->totface = mesh_recalcTesselation(&me->fdata, &me->ldata, &me->pdata,
+ me->mvert, me->totface, me->totloop, me->totpoly, 0, 0);
+ mesh_update_customdata_pointers(me);
+ makeDerivedMesh(scene, ob, NULL, CD_MASK_BAREMESH, 0);
+
+ // XXX if (v3d->flag & V3D_INVALID_BACKBUF) {
// XXX drawview.c! check_backbuf();
// XXX persp(PERSP_VIEW);
// XXX }
@@ -123,7 +137,7 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const short mval[2],
*index = view3d_sample_backbuf(&vc, mval[0], mval[1]);
}
- if ((*index)<=0 || (*index)>(unsigned int)me->totface)
+ if ((*index)<=0 || (*index)>(unsigned int)me->totpoly)
return 0;
(*index)--;
@@ -133,41 +147,35 @@ static int facesel_face_pick(struct bContext *C, Mesh *me, const short mval[2],
/* 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)
+MTexPoly *EDBM_get_active_mtface(BMEditMesh *em, BMFace **act_efa, int sloppy)
{
- EditFace *efa = NULL;
+ BMFace *efa = NULL;
- if(!EM_texFaceCheck(em))
+ if(!EDBM_texFaceCheck(em))
return NULL;
- efa = EM_get_actFace(em, sloppy);
+ efa = EDBM_get_actFace(em, sloppy);
if (efa) {
- if (mcol) {
- if (CustomData_has_layer(&em->fdata, CD_MCOL))
- *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- else
- *mcol = NULL;
- }
if (act_efa) *act_efa = efa;
- return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
}
+
if (act_efa) *act_efa= NULL;
- if(mcol) *mcol = NULL;
return NULL;
}
void paintface_hide(Object *ob, const int unselected)
{
Mesh *me;
- MFace *mface;
+ MPoly *mface;
int a;
me= get_mesh(ob);
- if(me==NULL || me->totface==0) return;
+ if(me==NULL || me->totpoly==0) return;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0) {
if(unselected) {
@@ -189,14 +197,14 @@ void paintface_hide(Object *ob, const int unselected)
void paintface_reveal(Object *ob)
{
Mesh *me;
- MFace *mface;
+ MPoly *mface;
int a;
me= get_mesh(ob);
- if(me==NULL || me->totface==0) return;
+ if(me==NULL || me->totpoly==0) return;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if(mface->flag & ME_HIDE) {
mface->flag |= ME_FACE_SEL;
@@ -210,30 +218,30 @@ void paintface_reveal(Object *ob)
/* Set tface seams based on edge data, uses hash table to find seam edges. */
-static void hash_add_face(EdgeHash *ehash, MFace *mf)
+static void hash_add_face(EdgeHash *ehash, MPoly *mf, MLoop *mloop)
{
- BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
- BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
- if(mf->v4) {
- BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
- BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
- }
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+ MLoop *ml, *ml2;
+ int i;
+
+ for (i=0, ml=mloop; i<mf->totloop; i++, ml++) {
+ ml2 = mloop + (i+1) % mf->totloop;
+ BLI_edgehash_insert(ehash, ml->v, ml2->v, NULL);
+ }
}
static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
{
- MFace *mf;
- int a, doit=1, mark=0;
- char *linkflag;
EdgeHash *ehash, *seamhash;
+ MPoly *mf;
+ MLoop *ml;
MEdge *med;
+ char *linkflag;
+ int a, b, doit=1, mark=0;
ehash= BLI_edgehash_new();
seamhash = BLI_edgehash_new();
- linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
+ linkflag= MEM_callocN(sizeof(char)*me->totpoly, "linkflaguv");
for(med=me->medge, a=0; a < me->totedge; a++, med++)
if(med->flag & ME_SEAM)
@@ -241,17 +249,17 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
if (mode==0 || mode==1) {
/* only put face under cursor in array */
- mf= ((MFace*)me->mface) + index;
- hash_add_face(ehash, mf);
+ mf= ((MPoly*)me->mpoly) + index;
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
linkflag[index]= 1;
}
else {
/* fill array by selection */
- mf= me->mface;
- for(a=0; a<me->totface; a++, mf++) {
+ mf= me->mpoly;
+ for(a=0; a<me->totpoly; a++, mf++) {
if(mf->flag & ME_HIDE);
else if(mf->flag & ME_FACE_SEL) {
- hash_add_face(ehash, mf);
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
linkflag[a]= 1;
}
}
@@ -261,35 +269,26 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
doit= 0;
/* expand selection */
- mf= me->mface;
- for(a=0; a<me->totface; a++, mf++) {
+ mf= me->mpoly;
+ for(a=0; a<me->totpoly; a++, mf++) {
if(mf->flag & ME_HIDE)
continue;
if(!linkflag[a]) {
+ MLoop *mnextl;
mark= 0;
- if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
- if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
- mark= 1;
- if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
- if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
- mark= 1;
- if(mf->v4) {
- if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
- if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
- mark= 1;
- if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
- if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
- mark= 1;
+ ml = me->mloop + mf->loopstart;
+ for (b=0; b<mf->totloop; b++, ml++) {
+ mnextl = b < mf->totloop-1 ? ml - 1 : me->mloop + mf->loopstart;
+ if (!BLI_edgehash_haskey(seamhash, ml->v, mnextl->v))
+ if (!BLI_edgehash_haskey(ehash, ml->v, mnextl->v))
+ mark = 1;
}
- else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1))
- if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
- mark = 1;
if(mark) {
linkflag[a]= 1;
- hash_add_face(ehash, mf);
+ hash_add_face(ehash, mf, me->mloop + mf->loopstart);
doit= 1;
}
}
@@ -301,24 +300,24 @@ static void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int ind
BLI_edgehash_free(seamhash, NULL);
if(mode==0 || mode==2) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag |= ME_FACE_SEL;
else
mf->flag &= ~ME_FACE_SEL;
}
else if(mode==1) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a] && (mf->flag & ME_FACE_SEL))
break;
- if (a<me->totface) {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if (a<me->totpoly) {
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag &= ~ME_FACE_SEL;
}
else {
- for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for(a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if(linkflag[a])
mf->flag |= ME_FACE_SEL;
}
@@ -333,7 +332,7 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[
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
@@ -352,28 +351,27 @@ void paintface_select_linked(bContext *UNUSED(C), Object *ob, short UNUSED(mval[
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;
}
mface++;
}
- }
- else {
+ } else {
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
- mface= me->mface;
- a= me->totface;
+ mface= me->mpoly;
+ a= me->totpoly;
while(a--) {
if((mface->flag & ME_HIDE) == 0 && mface->flag & ME_FACE_SEL) {
action = SEL_DESELECT;
@@ -382,55 +380,65 @@ void paintface_deselect_all_visible(Object *ob, int action, short flush_flags)
mface++;
}
}
-
- mface= me->mface;
- a= me->totface;
- while(a--) {
- if((mface->flag & ME_HIDE) == 0) {
- switch (action) {
- case SEL_SELECT:
- mface->flag |= ME_FACE_SEL;
- break;
- case SEL_DESELECT:
- mface->flag &= ~ME_FACE_SEL;
- break;
- case SEL_INVERT:
- mface->flag ^= ME_FACE_SEL;
- break;
- }
- }
- mface++;
- }
}
- if(flush_flags) {
- paintface_flush_flags(ob);
+ //BMESH_TODO object_facesel_flush_dm(ob);
+// XXX notifier! object_tface_flags_changed(OBACT, 0);
+}
+
+void selectswap_tface(Scene *scene)
+{
+ Mesh *me;
+ MPoly *mface;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0) return;
+
+ mface= me->mpoly;
+ a= me->totpoly;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
+ else mface->flag |= ME_FACE_SEL;
+ }
}
}
int paintface_minmax(Object *ob, float *min, float *max)
{
- Mesh *me= get_mesh(ob);
- MFace *mf;
+ Mesh *me;
+ MPoly *mf;
+ MTexPoly *tf;
+ MLoop *ml;
MVert *mv;
- int a, ok=0;
- float vec[3];
+ int a, b, ok=0;
+ float vec[3], bmat[3][3];
- if(me==NULL)
- return ok;
+ me= get_mesh(ob);
+ if(!me || !me->mtpoly) return ok;
+
+ copy_m3_m4(bmat, ob->obmat);
mv= me->mvert;
- mf= me->mface;
- for (a=me->totface; a>0; a--, mf++) {
- if ((mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL)) == 0) {
- int i= mf->v4 ? 3:2;
- do {
- mul_v3_m4v3(vec, ob->obmat, (mv + (*(&mf->v1 + i)))->co);
- DO_MINMAX(vec, min, max);
- } while (i--);
- ok= 1;
+ mf= me->mpoly;
+ tf= me->mtpoly;
+ for (a=me->totpoly; a>0; a--, mf++, tf++) {
+ if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
+ continue;
+
+ ml = me->mloop + mf->totloop;
+ for (b=0; b<mf->totloop; b++, ml++) {
+ VECCOPY(vec, (mv+ml->v)->co);
+ mul_m3_v3(bmat, vec);
+ add_v3_v3v3(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
}
+
+ ok= 1;
}
+
return ok;
}
@@ -438,12 +446,12 @@ int paintface_minmax(Object *ob, float *min, float *max)
#define ME_SEAM_DONE 2 /* reuse this flag */
-static float edgetag_cut_cost(int e1, int e2, int vert)
+static float edgetag_cut_cost(BMEditMesh *em, int e1, int e2, int vert)
{
- EditVert *v = EM_get_vert_for_index(vert);
- EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
- EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
- EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
+ BMVert *v = EDBM_get_vert_for_index(em, vert);
+ BMEdge *eed1 = EDBM_get_edge_for_index(em, e1), *eed2 = EDBM_get_edge_for_index(em, e2);
+ BMVert *v1 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed1->v1) == vert)? BMINDEX_GET(eed1->v2): BMINDEX_GET(eed1->v1) );
+ BMVert *v2 = EDBM_get_vert_for_index(em, (BMINDEX_GET(eed2->v1) == vert)? BMINDEX_GET(eed2->v2): BMINDEX_GET(eed2->v1) );
float cost, d1[3], d2[3];
cost = len_v3v3(v1->co, v->co);
@@ -457,19 +465,20 @@ static float edgetag_cut_cost(int e1, int e2, int vert)
return cost;
}
-static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
+static void edgetag_add_adjacent(BMEditMesh *em, Heap *heap, int mednum, int vertnum,
+ int *nedges, int *edges, int *prevedge, float *cost)
{
int startadj, endadj = nedges[vertnum+1];
for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
int adjnum = edges[startadj];
- EditEdge *eedadj = EM_get_edge_for_index(adjnum);
+ BMEdge *eedadj = EDBM_get_edge_for_index(em, adjnum);
float newcost;
- if (eedadj->f2 & ME_SEAM_DONE)
+ if (eedadj->head.flags[0].f & ME_SEAM_DONE)
continue;
- newcost = cost[mednum] + edgetag_cut_cost(mednum, adjnum, vertnum);
+ newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum);
if (cost[adjnum] > newcost) {
cost[adjnum] = newcost;
@@ -479,72 +488,94 @@ static void edgetag_add_adjacent(Heap *heap, int mednum, int vertnum, int *nedge
}
}
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
+void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val)
{
switch (scene->toolsettings->edge_mode) {
case EDGE_MODE_SELECT:
- EM_select_edge(eed, val);
+ BM_Select(em->bm, eed, val);
break;
case EDGE_MODE_TAG_SEAM:
- if (val) {eed->seam = 255;}
- else {eed->seam = 0;}
+ if (val) {BM_SetHFlag(eed, BM_SEAM);}
+ else {BM_ClearHFlag(eed, BM_SEAM);}
break;
case EDGE_MODE_TAG_SHARP:
- if (val) {eed->sharp = 1;}
- else {eed->sharp = 0;}
+ if (val) {BM_SetHFlag(eed, BM_SEAM);}
+ else {BM_ClearHFlag(eed, BM_SEAM);}
break;
- case EDGE_MODE_TAG_CREASE:
- if (val) {eed->crease = 1.0f;}
- else {eed->crease = 0.0f;}
+ case EDGE_MODE_TAG_CREASE:
+ {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_CREASE);
+
+ if (val) {*crease = 1.0f;}
+ else {*crease = 0.0f;}
break;
+ }
case EDGE_MODE_TAG_BEVEL:
- if (val) {eed->bweight = 1.0f;}
- else {eed->bweight = 0.0f;}
+ {
+ float *bweight = CustomData_bmesh_get(&em->bm->edata, eed->head.data, CD_BWEIGHT);
+
+ if (val) {*bweight = 1.0f;}
+ else {*bweight = 0.0f;}
break;
+ }
}
}
-int edgetag_context_check(Scene *scene, EditEdge *eed)
+static float bm_cdata_get_single_float(BMesh *UNUSED(bm), CustomData *cdata, void *element, int type)
+{
+ BMHeader *ele = element;
+ float *f;
+
+ if (!CustomData_has_layer(cdata, type))
+ return 0.0f;
+
+ f = CustomData_bmesh_get(cdata, ele->data, type);
+
+ return *f;
+}
+
+int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed)
{
switch (scene->toolsettings->edge_mode) {
case EDGE_MODE_SELECT:
- return (eed->f & SELECT) ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SELECT) ? 1 : 0;
case EDGE_MODE_TAG_SEAM:
- return eed->seam ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SEAM);
case EDGE_MODE_TAG_SHARP:
- return eed->sharp ? 1 : 0;
+ return BM_TestHFlag(eed, BM_SHARP);
case EDGE_MODE_TAG_CREASE:
- return eed->crease ? 1 : 0;
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_CREASE) ? 1 : 0;
case EDGE_MODE_TAG_BEVEL:
- return eed->bweight ? 1 : 0;
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, eed, CD_BWEIGHT) ? 1 : 0;
}
return 0;
}
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
+int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
{
- EditEdge *eed;
- EditVert *ev;
-
+ BMEdge *eed;
+ BMVert *ev;
+ BMIter iter;
Heap *heap;
float *cost;
int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
/* we need the vert */
- for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
- ev->tmp.l = totvert;
+ BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(ev, totvert);
totvert++;
}
- for (eed= em->edges.first; eed; eed = eed->next) {
- eed->f2 = 0;
- if (eed->h) {
- eed->f2 |= ME_SEAM_DONE;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ eed->head.flags[0].f = 0;
+ if (BM_TestHFlag(eed, BM_SELECT)) {
+ eed->head.flags[0].f |= ME_SEAM_DONE;
}
- eed->tmp.l = totedge;
+
+ BMINDEX_SET(eed, totedge);
totedge++;
}
@@ -555,9 +586,9 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
/* count edges, compute adjacent edges offsets and fill adjacent edges */
- for (eed= em->edges.first; eed; eed = eed->next) {
- nedges[eed->v1->tmp.l+1]++;
- nedges[eed->v2->tmp.l+1]++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ nedges[BMINDEX_GET(eed->v1)+1]++;
+ nedges[BMINDEX_GET(eed->v2)+1]++;
}
for (a=1; a<totvert; a++) {
@@ -567,107 +598,108 @@ int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge
}
nedges[0] = nedges[1] = 0;
- for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
- edges[nedges[eed->v1->tmp.l+1]++] = a;
- edges[nedges[eed->v2->tmp.l+1]++] = a;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ edges[nedges[BMINDEX_GET(eed->v1)+1]++] = a;
+ edges[nedges[BMINDEX_GET(eed->v2)+1]++] = a;
cost[a] = 1e20f;
prevedge[a] = -1;
+ a++;
}
/* regular dijkstra shortest path, but over edges instead of vertices */
heap = BLI_heap_new();
- BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
- cost[source->tmp.l] = 0.0f;
-
- EM_init_index_arrays(em, 1, 1, 0);
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BMINDEX_GET(source)));
+ cost[BMINDEX_GET(source)] = 0.0f;
+ EDBM_init_index_arrays(em, 1, 1, 0);
while (!BLI_heap_empty(heap)) {
mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
- eed = EM_get_edge_for_index( mednum );
+ eed = EDBM_get_edge_for_index(em, mednum);
- if (mednum == target->tmp.l)
+ if (mednum == BMINDEX_GET(target))
break;
- if (eed->f2 & ME_SEAM_DONE)
+ if (eed->head.flags[0].f & ME_SEAM_DONE)
continue;
- eed->f2 |= ME_SEAM_DONE;
+ eed->head.flags[0].f |= ME_SEAM_DONE;
- edgetag_add_adjacent(heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
- edgetag_add_adjacent(heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v1), nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, heap, mednum, BMINDEX_GET(eed->v2), nedges, edges, prevedge, cost);
}
-
MEM_freeN(nedges);
MEM_freeN(edges);
MEM_freeN(cost);
BLI_heap_free(heap, NULL);
- for (eed= em->edges.first; eed; eed = eed->next) {
- eed->f2 &= ~ME_SEAM_DONE;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ eed->head.flags[0].f &= ~ME_SEAM_DONE;
}
- if (mednum != target->tmp.l) {
+ if (mednum != BMINDEX_GET(target)) {
MEM_freeN(prevedge);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
return 0;
}
/* follow path back to source and mark as seam */
- if (mednum == target->tmp.l) {
+ if (mednum == BMINDEX_GET(target)) {
short allseams = 1;
- mednum = target->tmp.l;
+ mednum = BMINDEX_GET(target);
do {
- eed = EM_get_edge_for_index( mednum );
- if (!edgetag_context_check(scene, eed)) {
+ eed = EDBM_get_edge_for_index(em, mednum);
+ if (!edgetag_context_check(scene, em, eed)) {
allseams = 0;
break;
}
mednum = prevedge[mednum];
- } while (mednum != source->tmp.l);
+ } while (mednum != BMINDEX_GET(source));
- mednum = target->tmp.l;
+ mednum = BMINDEX_GET(target);
do {
- eed = EM_get_edge_for_index( mednum );
+ eed = EDBM_get_edge_for_index(em, mednum);
if (allseams)
- edgetag_context_set(scene, eed, 0);
+ edgetag_context_set(em, scene, eed, 0);
else
- edgetag_context_set(scene, eed, 1);
+ edgetag_context_set(em, scene, eed, 1);
mednum = prevedge[mednum];
} while (mednum != -1);
}
MEM_freeN(prevedge);
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
return 1;
}
/* *************************************** */
#if 0
-static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
+static void seam_edgehash_insert_face(EdgeHash *ehash, MPoly *mf, MLoop *loopstart)
{
- BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
- BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
- if (mf->v4) {
- BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
- BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
- }
- else
- BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+ MLoop *ml1, *ml2;
+ int a;
+
+ for (a=0; a<mf->totloop; a++) {
+ ml1 = loopstart + a;
+ ml2 = loopstart + (a+1) % mf->totloop;
+
+ BLI_edgehash_insert(ehash, ml1->v, ml2->v, NULL);
+ }
}
void seam_mark_clear_tface(Scene *scene, short mode)
{
Mesh *me;
- MFace *mf;
+ MPoly *mf;
+ MLoop *ml1, *ml2;
MEdge *med;
- int a;
+ int a, b;
me= get_mesh(OBACT);
- if(me==0 || me->totface==0) return;
+ if(me==0 || me->totpoly==0) return;
if (mode == 0)
mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
@@ -678,9 +710,9 @@ void seam_mark_clear_tface(Scene *scene, short mode)
if (mode == 2) {
EdgeHash *ehash = BLI_edgehash_new();
- for (a=0, mf=me->mface; a<me->totface; a++, mf++)
+ for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++)
if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
- seam_edgehash_insert_face(ehash, mf);
+ seam_edgehash_insert_face(ehash, mf, me->mloop + mf->loopstart);
for (a=0, med=me->medge; a<me->totedge; a++, med++)
if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
@@ -693,11 +725,11 @@ void seam_mark_clear_tface(Scene *scene, short mode)
EdgeHash *ehash1 = BLI_edgehash_new();
EdgeHash *ehash2 = BLI_edgehash_new();
- for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+ for (a=0, mf=me->mpoly; a<me->totpoly; a++, mf++) {
if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
- seam_edgehash_insert_face(ehash1, mf);
+ seam_edgehash_insert_face(ehash1, mf, me->mloop + mf->loopstart);
else
- seam_edgehash_insert_face(ehash2, mf);
+ seam_edgehash_insert_face(ehash2, mf, me->mloop + mf->loopstart);
}
for (a=0, med=me->medge; a<me->totedge; a++, med++)
@@ -719,21 +751,24 @@ void seam_mark_clear_tface(Scene *scene, short mode)
int paintface_mouse_select(struct bContext *C, Object *ob, const short mval[2], int extend)
{
Mesh *me;
- MFace *mface, *msel;
+ MPoly *mface, *msel;
unsigned int a, index;
/* Get the face under the cursor */
me = get_mesh(ob);
- if (!facesel_face_pick(C, me, mval, &index, 1))
+ if (!facesel_face_pick(C, me, ob, mval, &index, 1))
return 0;
- msel= (((MFace*)me->mface)+index);
+ if (index >= me->totpoly || index < 0)
+ return 0;
+
+ msel= me->mpoly + index;
if (msel->flag & ME_HIDE) return 0;
/* clear flags */
- mface = me->mface;
- a = me->totface;
+ mface = me->mpoly;
+ a = me->totpoly;
if (!extend) {
while (a--) {
mface->flag &= ~ME_FACE_SEL;
@@ -761,25 +796,36 @@ int paintface_mouse_select(struct bContext *C, Object *ob, const short mval[2],
int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
{
+ Object *ob = vc->obact;
Mesh *me;
- MFace *mface;
+ MPoly *mface;
struct ImBuf *ibuf;
unsigned int *rt;
- int a, index;
char *selar;
+ int a, index;
int sx= rect->xmax-rect->xmin+1;
int sy= rect->ymax-rect->ymin+1;
-
- me= get_mesh(vc->obact);
+
+ me= get_mesh(ob);
+ if(me==0) return 0;
+ if(me->totpoly==0) return 0;
if(me==NULL || me->totface==0 || sx*sy <= 0)
return OPERATOR_CANCELLED;
- selar= MEM_callocN(me->totface+1, "selar");
+ selar= MEM_callocN(me->totpoly+1, "selar");
if (extend == 0 && select)
paintface_deselect_all_visible(vc->obact, SEL_DESELECT, FALSE);
+ if (extend == 0 && select) {
+ mface= me->mpoly;
+ for(a=1; a<=me->totpoly; a++, mface++) {
+ if((mface->flag & ME_HIDE) == 0)
+ mface->flag &= ~ME_FACE_SEL;
+ }
+ }
+
view3d_validate_backbuf(vc);
ibuf = IMB_allocImBuf(sx,sy,32,IB_rect);
@@ -796,8 +842,8 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
rt++;
}
- mface= me->mface;
- for(a=1; a<=me->totface; a++, mface++) {
+ mface= me->mpoly;
+ for(a=1; a<=me->totpoly; a++, mface++) {
if(selar[a]) {
if(mface->flag & ME_HIDE);
else {
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
deleted file mode 100644
index ec08bfccda3..00000000000
--- a/source/blender/editors/mesh/editmesh.c
+++ /dev/null
@@ -1,1961 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
- * All rights reserved.
- *
- * Contributor(s): Blender Foundation, full recode 2002-2008
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh.c
- * \ingroup edmesh
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_key_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_dynstr.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_DerivedMesh.h"
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_key.h"
-#include "BKE_main.h"
-#include "BKE_material.h"
-#include "BKE_mesh.h"
-#include "BKE_paint.h"
-#include "BKE_report.h"
-#include "BKE_multires.h"
-
-#include "ED_mesh.h"
-#include "ED_object.h"
-#include "ED_screen.h"
-#include "ED_util.h"
-#include "ED_view3d.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-/* own include */
-#include "mesh_intern.h"
-
-/*
-editmesh.c:
- - add/alloc/free data
- - hashtables
- - enter/exit editmode
-*/
-
-/* XXX */
-static void BIF_undo_push(const char *UNUSED(arg)) {}
-static void error(const char *UNUSED(arg)) {}
-
-
-/* ***************** HASH ********************* */
-
-
-#define EDHASHSIZE (512*512)
-#define EDHASH(a, b) (a % EDHASHSIZE)
-
-
-/* ************ ADD / REMOVE / FIND ****************** */
-
-static void *calloc_em(EditMesh *UNUSED(em), size_t size, size_t nr)
-{
- return calloc(size, nr);
-}
-
-/* used to bypass normal calloc with fast one */
-static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em;
-static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em;
-static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em;
-
-EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example)
-{
- EditVert *eve;
- static int hashnr= 0;
-
- eve= callocvert(em, sizeof(EditVert), 1);
- BLI_addtail(&em->verts, eve);
- em->totvert++;
-
- if(vec) VECCOPY(eve->co, vec);
-
- eve->hash= hashnr++;
- if( hashnr>=EDHASHSIZE) hashnr= 0;
-
- /* new verts get keyindex of -1 since they did not
- * have a pre-editmode vertex order
- */
- eve->keyindex = -1;
-
- if(example) {
- CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
- eve->bweight = example->bweight;
- }
- else {
- CustomData_em_set_default(&em->vdata, &eve->data);
- }
-
- return eve;
-}
-
-void free_editvert (EditMesh *em, EditVert *eve)
-{
-
- EM_remove_selection(em, eve, EDITVERT);
- CustomData_em_free_block(&em->vdata, &eve->data);
- if(eve->fast==0)
- free(eve);
-
- em->totvert--;
-}
-
-
-EditEdge *findedgelist(EditMesh *em, EditVert *v1, EditVert *v2)
-{
- EditVert *v3;
- struct HashEdge *he;
-
- /* swap ? */
- if( v1 > v2) {
- v3= v2;
- v2= v1;
- v1= v3;
- }
-
- if(em->hashedgetab==NULL)
- em->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab");
-
- he= em->hashedgetab + EDHASH(v1->hash, v2->hash);
-
- while(he) {
-
- if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed;
-
- he= he->next;
- }
- return 0;
-}
-
-static void insert_hashedge(EditMesh *em, EditEdge *eed)
-{
- /* assuming that eed is not in the list yet, and that a find has been done before */
-
- struct HashEdge *first, *he;
-
- first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
-
- if( first->eed==0 ) {
- first->eed= eed;
- }
- else {
- he= &eed->hash;
- he->eed= eed;
- he->next= first->next;
- first->next= he;
- }
-}
-
-static void remove_hashedge(EditMesh *em, EditEdge *eed)
-{
- /* assuming eed is in the list */
-
- struct HashEdge *first, *he, *prev=NULL;
-
- he=first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
-
- while(he) {
- if(he->eed == eed) {
- /* remove from list */
- if(he==first) {
- if(first->next) {
- he= first->next;
- first->eed= he->eed;
- first->next= he->next;
- }
- else he->eed= 0;
- }
- else {
- prev->next= he->next;
- }
- return;
- }
- prev= he;
- he= he->next;
- }
-}
-
-EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *example)
-{
- EditVert *v3;
- EditEdge *eed;
- int swap= 0;
-
- if(v1==v2) return NULL;
- if(v1==NULL || v2==NULL) return NULL;
-
- /* swap ? */
- if(v1>v2) {
- v3= v2;
- v2= v1;
- v1= v3;
- swap= 1;
- }
-
- /* find in hashlist */
- eed= findedgelist(em, v1, v2);
-
- if(eed==NULL) {
-
- eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1);
- eed->v1= v1;
- eed->v2= v2;
- BLI_addtail(&em->edges, eed);
- eed->dir= swap;
- insert_hashedge(em, eed);
- em->totedge++;
-
- /* copy edge data:
- rule is to do this with addedgelist call, before addfacelist */
- if(example) {
- eed->crease= example->crease;
- eed->bweight= example->bweight;
- eed->sharp = example->sharp;
- eed->seam = example->seam;
- eed->h |= (example->h & EM_FGON);
- }
- }
-
- return eed;
-}
-
-void remedge(EditMesh *em, EditEdge *eed)
-{
- BLI_remlink(&em->edges, eed);
- remove_hashedge(em, eed);
-
- em->totedge--;
-}
-
-void free_editedge(EditMesh *em, EditEdge *eed)
-{
- EM_remove_selection(em, eed, EDITEDGE);
- if(eed->fast==0){
- free(eed);
- }
-}
-
-void free_editface(EditMesh *em, EditFace *efa)
-{
- EM_remove_selection(em, efa, EDITFACE);
-
- if (em->act_face==efa) {
- EM_set_actFace(em, em->faces.first == efa ? NULL : em->faces.first);
- }
-
- CustomData_em_free_block(&em->fdata, &efa->data);
- if(efa->fast==0)
- free(efa);
-
- em->totface--;
-}
-
-void free_vertlist(EditMesh *em, ListBase *edve)
-{
- EditVert *eve, *next;
-
- if (!edve) return;
-
- eve= edve->first;
- while(eve) {
- next= eve->next;
- free_editvert(em, eve);
- eve= next;
- }
- edve->first= edve->last= NULL;
- em->totvert= em->totvertsel= 0;
-}
-
-void free_edgelist(EditMesh *em, ListBase *lb)
-{
- EditEdge *eed, *next;
-
- eed= lb->first;
- while(eed) {
- next= eed->next;
- free_editedge(em, eed);
- eed= next;
- }
- lb->first= lb->last= NULL;
- em->totedge= em->totedgesel= 0;
-}
-
-void free_facelist(EditMesh *em, ListBase *lb)
-{
- EditFace *efa, *next;
-
- efa= lb->first;
- while(efa) {
- next= efa->next;
- free_editface(em, efa);
- efa= next;
- }
- lb->first= lb->last= NULL;
- em->totface= em->totfacesel= 0;
-}
-
-EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges)
-{
- EditFace *efa;
- EditEdge *e1, *e2=0, *e3=0, *e4=0;
-
- /* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */
- if(v1==v4 || v2==v4 || v3==v4) v4= NULL;
-
- /* add face to list and do the edges */
- if(exampleEdges) {
- e1= addedgelist(em, v1, v2, exampleEdges->e1);
- e2= addedgelist(em, v2, v3, exampleEdges->e2);
- if(v4) e3= addedgelist(em, v3, v4, exampleEdges->e3);
- else e3= addedgelist(em, v3, v1, exampleEdges->e3);
- if(v4) e4= addedgelist(em, v4, v1, exampleEdges->e4);
- }
- else {
- e1= addedgelist(em, v1, v2, NULL);
- e2= addedgelist(em, v2, v3, NULL);
- if(v4) e3= addedgelist(em, v3, v4, NULL);
- else e3= addedgelist(em, v3, v1, NULL);
- if(v4) e4= addedgelist(em, v4, v1, NULL);
- }
-
- if(v1==v2 || v2==v3 || v1==v3) return NULL;
- if(e2==0) return NULL;
-
- efa= (EditFace *)callocface(em, sizeof(EditFace), 1);
- efa->v1= v1;
- efa->v2= v2;
- efa->v3= v3;
- efa->v4= v4;
-
- efa->e1= e1;
- efa->e2= e2;
- efa->e3= e3;
- efa->e4= e4;
-
- if(example) {
- efa->mat_nr= example->mat_nr;
- efa->flag= example->flag;
- CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
- CustomData_em_validate_data(&em->fdata, efa->data, efa->v4 ? 4 : 3);
- }
- else {
- efa->mat_nr= em->mat_nr;
-
- CustomData_em_set_default(&em->fdata, &efa->data);
- }
-
- BLI_addtail(&em->faces, efa);
- em->totface++;
-
- if(efa->v4) {
- normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- }
- else {
- normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
- cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
- }
-
- return efa;
-}
-
-/* ************************ end add/new/find ************ */
-
-/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */
-
-/* some nice utility functions */
-
-EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve)
-{
- if (eve==eed->v1) {
- return eed->v2;
- } else if (eve==eed->v2) {
- return eed->v1;
- } else {
- return NULL;
- }
-}
-
-EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2)
-{
- if (eed->v1==eed2->v1 || eed->v1==eed2->v2) {
- return eed->v1;
- } else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) {
- return eed->v2;
- } else {
- return NULL;
- }
-}
-
-int editedge_containsVert(EditEdge *eed, EditVert *eve)
-{
- return (eed->v1==eve || eed->v2==eve);
-}
-
-int editface_containsVert(EditFace *efa, EditVert *eve)
-{
- return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve));
-}
-
-int editface_containsEdge(EditFace *efa, EditEdge *eed)
-{
- return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed));
-}
-
-
-/* ************************ stuct EditMesh manipulation ***************************** */
-
-/* fake callocs for fastmalloc below */
-static void *calloc_fastvert(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditVert *eve= em->curvert++;
- eve->fast= 1;
- return eve;
-}
-static void *calloc_fastedge(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditEdge *eed= em->curedge++;
- eed->fast= 1;
- return eed;
-}
-static void *calloc_fastface(EditMesh *em, size_t UNUSED(size), size_t UNUSED(nr))
-{
- EditFace *efa= em->curface++;
- efa->fast= 1;
- return efa;
-}
-
-/* allocate 1 chunk for all vertices, edges, faces. These get tagged to
- prevent it from being freed
-*/
-static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface)
-{
- if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts");
- else em->allverts= NULL;
- em->curvert= em->allverts;
-
- if(totedge==0) totedge= 4*totface; // max possible
-
- if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges");
- else em->alledges= NULL;
- em->curedge= em->alledges;
-
- if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces");
- else em->allfaces= NULL;
- em->curface= em->allfaces;
-
- callocvert= calloc_fastvert;
- callocedge= calloc_fastedge;
- callocface= calloc_fastface;
-}
-
-static void end_editmesh_fastmalloc(void)
-{
- callocvert= calloc_em;
- callocedge= calloc_em;
- callocface= calloc_em;
-}
-
-/* do not free editmesh itself here */
-void free_editMesh(EditMesh *em)
-{
- if(em==NULL) return;
-
- if(em->verts.first) free_vertlist(em, &em->verts);
- if(em->edges.first) free_edgelist(em, &em->edges);
- if(em->faces.first) free_facelist(em, &em->faces);
- if(em->selected.first) BLI_freelistN(&(em->selected));
-
- CustomData_free(&em->vdata, 0);
- CustomData_free(&em->fdata, 0);
-
- if(em->derivedFinal) {
- if (em->derivedFinal!=em->derivedCage) {
- em->derivedFinal->needsFree= 1;
- em->derivedFinal->release(em->derivedFinal);
- }
- em->derivedFinal= NULL;
- }
- if(em->derivedCage) {
- em->derivedCage->needsFree= 1;
- em->derivedCage->release(em->derivedCage);
- em->derivedCage= NULL;
- }
-
- /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */
-#if 0
- if(em->hashedgetab) {
- HashEdge *he, *hen;
- int a, used=0, max=0, nr;
- he= em->hashedgetab;
- for(a=0; a<EDHASHSIZE; a++, he++) {
- if(he->eed) used++;
- hen= he->next;
- nr= 0;
- while(hen) {
- nr++;
- hen= hen->next;
- }
- if(max<nr) max= nr;
- }
- printf("hastab used %d max %d\n", used, max);
- }
-#endif
- if(em->hashedgetab) MEM_freeN(em->hashedgetab);
- em->hashedgetab= NULL;
-
- if(em->allverts) MEM_freeN(em->allverts);
- if(em->alledges) MEM_freeN(em->alledges);
- if(em->allfaces) MEM_freeN(em->allfaces);
-
- em->allverts= em->curvert= NULL;
- em->alledges= em->curedge= NULL;
- em->allfaces= em->curface= NULL;
-
- mesh_octree_table(NULL, NULL, NULL, 'e');
- mesh_mirrtopo_table(NULL, 'e');
-
- em->totvert= em->totedge= em->totface= 0;
-
-// XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
- em->retopo_paint_data= NULL;
- em->act_face = NULL;
-}
-
-static void editMesh_set_hash(EditMesh *em)
-{
- EditEdge *eed;
-
- if(em->hashedgetab) MEM_freeN(em->hashedgetab);
- em->hashedgetab= NULL;
-
- for(eed=em->edges.first; eed; eed= eed->next) {
- if( findedgelist(em, eed->v1, eed->v2)==NULL )
- insert_hashedge(em, eed);
- }
-
-}
-
-
-/* ************************ IN & OUT EDITMODE ***************************** */
-
-
-static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
-{
- EditFace *efa2;
- float cent1[3], cent2[3];
- float inp;
-
- efa2 = eed->tmp.f;
- if(efa1==efa2) return;
-
- inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
- if(inp<0.999f && inp >-0.999f) eed->f2= 1;
-
- if(efa1->v4) cent_quad_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
- else cent_tri_v3(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
- if(efa2->v4) cent_quad_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
- else cent_tri_v3(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
-
- sub_v3_v3v3(cent1, cent2, cent1);
- normalize_v3(cent1);
- inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2];
-
- if(inp < -0.001f) eed->f1= 1;
-}
-
-#if 0
-typedef struct {
- EditEdge *eed;
- float noLen,no[3];
- int adjCount;
-} EdgeDrawFlagInfo;
-
-static int edgeDrawFlagInfo_cmp(const void *av, const void *bv)
-{
- const EdgeDrawFlagInfo *a = av;
- const EdgeDrawFlagInfo *b = bv;
-
- if (a->noLen<b->noLen) return -1;
- else if (a->noLen>b->noLen) return 1;
- else return 0;
-}
-#endif
-
-static void edge_drawflags(Mesh *me, EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed, *e1, *e2, *e3, *e4;
- EditFace *efa;
-
- /* - count number of times edges are used in faces: 0 en 1 time means draw edge
- * - edges more than 1 time used: in *tmp.f is pointer to first face
- * - check all faces, when normal differs to much: draw (flag becomes 1)
- */
-
- /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old
- game engine (2.04)
- */
-
- recalc_editnormals(em);
-
- /* init */
- eve= em->verts.first;
- while(eve) {
- eve->f1= 1; /* during test it's set at zero */
- eve= eve->next;
- }
- eed= em->edges.first;
- while(eed) {
- eed->f2= eed->f1= 0;
- eed->tmp.f = 0;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
- if(e1->f2<4) e1->f2+= 1;
- if(e2->f2<4) e2->f2+= 1;
- if(e3->f2<4) e3->f2+= 1;
- if(e4 && e4->f2<4) e4->f2+= 1;
-
- if(e1->tmp.f == 0) e1->tmp.f = (void *) efa;
- if(e2->tmp.f == 0) e2->tmp.f = (void *) efa;
- if(e3->tmp.f ==0) e3->tmp.f = (void *) efa;
- if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa;
-
- efa= efa->next;
- }
-
- if(me->drawflag & ME_ALLEDGES) {
- efa= em->faces.first;
- while(efa) {
- if(efa->e1->f2>=2) efa->e1->f2= 1;
- if(efa->e2->f2>=2) efa->e2->f2= 1;
- if(efa->e3->f2>=2) efa->e3->f2= 1;
- if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1;
-
- efa= efa->next;
- }
- }
- else {
-
- /* handle single-edges for 'test cylinder flag' (old engine) */
-
- eed= em->edges.first;
- while(eed) {
- if(eed->f2==1) eed->f1= 1;
- eed= eed->next;
- }
-
- /* all faces, all edges with flag==2: compare normal */
- efa= em->faces.first;
- while(efa) {
- if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa);
- else efa->e1->f2= 1;
- if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa);
- else efa->e2->f2= 1;
- if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa);
- else efa->e3->f2= 1;
- if(efa->e4) {
- if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa);
- else efa->e4->f2= 1;
- }
- efa= efa->next;
- }
-
- /* sphere collision flag */
-
- eed= em->edges.first;
- while(eed) {
- if(eed->f1!=1) {
- eed->v1->f1= eed->v2->f1= 0;
- }
- eed= eed->next;
- }
-
- }
-}
-
-/* turns Mesh into editmesh */
-void make_editMesh(Scene *scene, Object *ob)
-{
- Mesh *me= ob->data;
- MFace *mface;
- MVert *mvert;
- MSelect *mselect;
- KeyBlock *actkey;
- EditMesh *em;
- EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
- EditFace *efa, *efa_last_sel= NULL;
- EditEdge *eed;
- EditSelection *ese;
- float *co, (*keyco)[3]= NULL;
- int tot, a, eekadoodle= 0;
- const short is_paint_sel= paint_facesel_test(ob);
-
- if(me->edit_mesh==NULL)
- me->edit_mesh= MEM_callocN(sizeof(EditMesh), "editmesh");
- else
- /* because of reload */
- free_editMesh(me->edit_mesh);
-
- em= me->edit_mesh;
-
- em->selectmode= scene->toolsettings->selectmode; // warning needs to be synced
- em->act_face = NULL;
- em->totvert= tot= me->totvert;
- em->totedge= me->totedge;
- em->totface= me->totface;
-
- if(tot==0) {
- return;
- }
-
- if(ob->actcol > 0)
- em->mat_nr= ob->actcol-1;
-
- /* initialize fastmalloc for editmesh */
- init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
-
- actkey = ob_get_keyblock(ob);
- if(actkey) {
- /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
- undo_editmode_clear();
- keyco= actkey->data;
- em->shapenr= ob->shapenr;
- }
-
- /* make editverts */
- CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- mvert= me->mvert;
-
- evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
- for(a=0; a<tot; a++, mvert++) {
-
- co= mvert->co;
-
- /* edit the shape key coordinate if available */
- if(keyco && a < actkey->totelem)
- co= keyco[a];
-
- eve= addvertlist(em, co, NULL);
- evlist[a]= eve;
-
- /* face select sets selection in next loop */
- if(!is_paint_sel)
- eve->f |= (mvert->flag & 1);
-
- if (mvert->flag & ME_HIDE) eve->h= 1;
- normal_short_to_float_v3(eve->no, mvert->no);
-
- eve->bweight= ((float)mvert->bweight)/255.0f;
-
- /* lets overwrite the keyindex of the editvert
- * with the order it used to be in before
- * editmode
- */
- eve->keyindex = a;
-
- CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data);
- }
-
- if(actkey && actkey->totelem!=me->totvert);
- else {
- MEdge *medge= me->medge;
-
- CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- /* make edges */
- for(a=0; a<me->totedge; a++, medge++) {
- eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL);
- /* eed can be zero when v1 and v2 are identical, dxf import does this... */
- if(eed) {
- eed->crease= ((float)medge->crease)/255.0f;
- eed->bweight= ((float)medge->bweight)/255.0f;
-
- if(medge->flag & ME_SEAM) eed->seam= 1;
- if(medge->flag & ME_SHARP) eed->sharp = 1;
- if(medge->flag & SELECT) eed->f |= SELECT;
- if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
- if(medge->flag & ME_HIDE) eed->h |= 1;
- if(em->selectmode==SCE_SELECT_EDGE)
- EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ...
- CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
- }
- }
-
- CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
-
- /* make faces */
- mface= me->mface;
-
- for(a=0; a<me->totface; a++, mface++) {
- eve1= evlist[mface->v1];
- eve2= evlist[mface->v2];
- if(!mface->v3) eekadoodle= 1;
- eve3= evlist[mface->v3];
- if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL;
-
- efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
-
- if(efa) {
- CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data);
-
- efa->mat_nr= mface->mat_nr;
- efa->flag= mface->flag & ~ME_HIDE;
-
- /* select and hide face flag */
- if(mface->flag & ME_HIDE) {
- efa->h= 1;
- } else {
- if (a==me->act_face) {
- EM_set_actFace(em, efa);
- }
-
- /* dont allow hidden and selected */
- if(mface->flag & ME_FACE_SEL) {
- efa->f |= SELECT;
-
- if(is_paint_sel) {
- EM_select_face(efa, 1); /* flush down */
- }
-
- efa_last_sel= efa;
- }
- }
- }
- }
- }
-
- if(EM_get_actFace(em, 0)==NULL && efa_last_sel) {
- EM_set_actFace(em, efa_last_sel);
- }
-
- if(eekadoodle)
- error("This Mesh has old style edgecodes, please put it in the bugtracker!");
-
- MEM_freeN(evlist);
-
- end_editmesh_fastmalloc(); // resets global function pointers
-
- if(me->mselect){
- //restore editselections
- EM_init_index_arrays(em, 1,1,1);
- mselect = me->mselect;
-
- for(a=0; a<me->totselect; a++, mselect++){
- /*check if recorded selection is still valid, if so copy into editmesh*/
- if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){
- ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
- ese->type = mselect->type;
- if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else
- if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else
- if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index);
- BLI_addtail(&(em->selected),ese);
- }
- }
- EM_free_index_arrays();
- }
- /* this creates coherent selections. also needed for older files */
- EM_selectmode_set(em);
- /* paranoia check to enforce hide rules */
- EM_hide_reset(em);
- /* sets helper flags which arent saved */
- EM_fgon_flags(em);
-
- if (EM_get_actFace(em, 0)==NULL) {
- EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */
- }
-}
-
-/* makes Mesh out of editmesh */
-void load_editMesh(Scene *scene, Object *obedit)
-{
- Mesh *me= obedit->data;
- MVert *mvert, *oldverts;
- MEdge *medge;
- MFace *mface;
- MSelect *mselect;
- EditMesh *em= me->edit_mesh;
- EditVert *eve;
- EditFace *efa, *efa_act;
- EditEdge *eed;
- EditSelection *ese;
- float *fp, *newkey, *oldkey;
- int i, a, ototvert;
-
- /* this one also tests of edges are not in faces: */
- /* eed->f2==0: not in face, f2==1: draw it */
- /* eed->f1 : flag for dynaface (cylindertest, old engine) */
- /* eve->f1 : flag for dynaface (sphere test, old engine) */
- /* eve->f2 : being used in vertexnormals */
- edge_drawflags(me, em);
-
- EM_stats_update(em);
-
- /* new Vertex block */
- if(em->totvert==0) mvert= NULL;
- else mvert= MEM_callocN(em->totvert*sizeof(MVert), "loadeditMesh vert");
-
- /* new Edge block */
- if(em->totedge==0) medge= NULL;
- else medge= MEM_callocN(em->totedge*sizeof(MEdge), "loadeditMesh edge");
-
- /* new Face block */
- if(em->totface==0) mface= NULL;
- else mface= MEM_callocN(em->totface*sizeof(MFace), "loadeditMesh face");
-
- /* lets save the old verts just in case we are actually working on
- * a key ... we now do processing of the keys at the end */
- oldverts= me->mvert;
- ototvert= me->totvert;
-
- /* don't free this yet */
- CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
-
- /* free custom data */
- CustomData_free(&me->vdata, me->totvert);
- CustomData_free(&me->edata, me->totedge);
- CustomData_free(&me->fdata, me->totface);
-
- /* add new custom data */
- me->totvert= em->totvert;
- me->totedge= em->totedge;
- me->totface= em->totface;
-
- CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
- CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
- CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
-
- CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
- CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
- CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
- mesh_update_customdata_pointers(me);
-
- /* the vertices, use ->tmp.l as counter */
- eve= em->verts.first;
- a= 0;
-
- while(eve) {
- VECCOPY(mvert->co, eve->co);
-
- /* vertex normal */
- normal_float_to_short_v3(mvert->no, eve->no);
-
- /* note: it used to remove me->dvert when it was not in use, cancelled
- that... annoying when you have a fresh vgroup */
- CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a);
-
- eve->tmp.l = a++; /* counter */
-
- mvert->flag= 0;
- mvert->flag |= (eve->f & SELECT);
- if (eve->h) mvert->flag |= ME_HIDE;
-
- mvert->bweight= (char)(255.0f*eve->bweight);
-
- eve= eve->next;
- mvert++;
- }
-
- /* the edges */
- a= 0;
- eed= em->edges.first;
- while(eed) {
- medge->v1= (unsigned int) eed->v1->tmp.l;
- medge->v2= (unsigned int) eed->v2->tmp.l;
-
- medge->flag= (eed->f & SELECT) | ME_EDGERENDER;
- if(eed->f2<2) medge->flag |= ME_EDGEDRAW;
- if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
- if(eed->sharp) medge->flag |= ME_SHARP;
- if(eed->seam) medge->flag |= ME_SEAM;
- if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
- if(eed->h & 1) medge->flag |= ME_HIDE;
-
- medge->crease= (char)(255.0f*eed->crease);
- medge->bweight= (char)(255.0f*eed->bweight);
- CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);
-
- eed->tmp.l = a++;
-
- medge++;
- eed= eed->next;
- }
-
- /* the faces */
- a = 0;
- efa= em->faces.first;
- efa_act= EM_get_actFace(em, 0);
- i = 0;
- me->act_face = -1;
- while(efa) {
- mface= &((MFace *) me->mface)[i];
-
- mface->v1= (unsigned int) efa->v1->tmp.l;
- mface->v2= (unsigned int) efa->v2->tmp.l;
- mface->v3= (unsigned int) efa->v3->tmp.l;
- if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l;
-
- mface->mat_nr= efa->mat_nr;
-
- mface->flag= efa->flag;
- /* bit 0 of flag is already taken for smooth... */
-
- if(efa->h) {
- mface->flag |= ME_HIDE;
- mface->flag &= ~ME_FACE_SEL;
- } else {
- if(efa->f & 1) mface->flag |= ME_FACE_SEL;
- else mface->flag &= ~ME_FACE_SEL;
- }
-
- /* watch: efa->e1->f2==0 means loose edge */
-
- if(efa->e1->f2==1) {
- efa->e1->f2= 2;
- }
- if(efa->e2->f2==1) {
- efa->e2->f2= 2;
- }
- if(efa->e3->f2==1) {
- efa->e3->f2= 2;
- }
- if(efa->e4 && efa->e4->f2==1) {
- efa->e4->f2= 2;
- }
-
- CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i);
-
- /* no index '0' at location 3 or 4 */
- test_index_face(mface, &me->fdata, i, efa->v4?4:3);
-
- if (efa_act == efa)
- me->act_face = a;
-
- efa->tmp.l = a++;
- i++;
- efa= efa->next;
- }
-
- /* patch hook indices and vertex parents */
- {
- Object *ob;
- ModifierData *md;
- EditVert **vertMap = NULL;
- int j;
-
- for (ob=G.main->object.first; ob; ob=ob->id.next) {
- if (ob->parent==ob && ELEM(ob->partype, PARVERT1,PARVERT3)) {
-
- /* duplicate code from below, make it function later...? */
- if (!vertMap) {
- vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->keyindex!=-1)
- vertMap[eve->keyindex] = eve;
- }
- }
- if(ob->par1 < ototvert) {
- eve = vertMap[ob->par1];
- if(eve) ob->par1= eve->tmp.l;
- }
- if(ob->par2 < ototvert) {
- eve = vertMap[ob->par2];
- if(eve) ob->par2= eve->tmp.l;
- }
- if(ob->par3 < ototvert) {
- eve = vertMap[ob->par3];
- if(eve) ob->par3= eve->tmp.l;
- }
-
- }
- if (ob->data==me) {
- for (md=ob->modifiers.first; md; md=md->next) {
- if (md->type==eModifierType_Hook) {
- HookModifierData *hmd = (HookModifierData*) md;
-
- if (!vertMap) {
- vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
-
- for (eve=em->verts.first; eve; eve=eve->next) {
- if (eve->keyindex!=-1)
- vertMap[eve->keyindex] = eve;
- }
- }
-
- for (i=j=0; i<hmd->totindex; i++) {
- if(hmd->indexar[i] < ototvert) {
- eve = vertMap[hmd->indexar[i]];
-
- if (eve) {
- hmd->indexar[j++] = eve->tmp.l;
- }
- }
- else j++;
- }
-
- hmd->totindex = j;
- }
- }
- }
- }
-
- if (vertMap) MEM_freeN(vertMap);
- }
-
- /* are there keys? */
- if(me->key) {
- KeyBlock *currkey;
- KeyBlock *actkey= BLI_findlink(&me->key->block, em->shapenr-1);
-
- float (*ofs)[3] = NULL;
-
- /* editing the base key should update others */
- if(me->key->type==KEY_RELATIVE && oldverts) {
- int act_is_basis = 0;
- /* find if this key is a basis for any others */
- for(currkey = me->key->block.first; currkey; currkey= currkey->next) {
- if(em->shapenr-1 == currkey->relative) {
- act_is_basis = 1;
- break;
- }
- }
-
- if(act_is_basis) { /* active key is a base */
- float (*fp)[3]= actkey->data;
- i=0;
- ofs= MEM_callocN(sizeof(float) * 3 * em->totvert, "currkey->data");
- eve= em->verts.first;
- mvert = me->mvert;
- while(eve) {
- if(eve->keyindex>=0)
- VECSUB(ofs[i], mvert->co, fp[eve->keyindex]);
-
- eve= eve->next;
- i++;
- mvert++;
- }
- }
- }
-
-
- /* Lets reorder the key data so that things line up roughly
- * with the way things were before editmode */
- currkey = me->key->block.first;
- while(currkey) {
- int apply_offset = (ofs && (currkey != actkey) && (em->shapenr-1 == currkey->relative));
-
- fp= newkey= MEM_callocN(me->key->elemsize*em->totvert, "currkey->data");
- oldkey = currkey->data;
-
- eve= em->verts.first;
-
- i = 0;
- mvert = me->mvert;
- while(eve) {
- if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
- if(currkey == actkey) {
- if(actkey == me->key->refkey) {
- VECCOPY(fp, mvert->co);
- }
- else {
- VECCOPY(fp, mvert->co);
- if(oldverts) {
- VECCOPY(mvert->co, oldverts[eve->keyindex].co);
- }
- }
- }
- else {
- if(oldkey) {
- VECCOPY(fp, oldkey + 3 * eve->keyindex);
- }
- }
- }
- else {
- VECCOPY(fp, mvert->co);
- }
-
- /* propagate edited basis offsets to other shapes */
- if(apply_offset) {
- VECADD(fp, fp, ofs[i]);
- }
-
- fp+= 3;
- ++i;
- ++mvert;
- eve= eve->next;
- }
- currkey->totelem= em->totvert;
- if(currkey->data) MEM_freeN(currkey->data);
- currkey->data = newkey;
-
- currkey= currkey->next;
- }
-
- if(ofs) MEM_freeN(ofs);
- }
-
- if(oldverts) MEM_freeN(oldverts);
-
- i = 0;
- for(ese=em->selected.first; ese; ese=ese->next) i++;
- me->totselect = i;
- if(i==0) mselect= NULL;
- else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections");
-
- if(me->mselect) MEM_freeN(me->mselect);
- me->mselect= mselect;
-
- for(ese=em->selected.first; ese; ese=ese->next){
- mselect->type = ese->type;
- if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l;
- else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l;
- else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l;
- mselect++;
- }
-
- /* to be sure: clear ->tmp.l pointers */
- eve= em->verts.first;
- while(eve) {
- eve->tmp.l = 0;
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- eed->tmp.l = 0;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- efa->tmp.l = 0;
- efa= efa->next;
- }
-
- /* remake softbody of all users */
- if(me->id.us>1) {
- Base *base;
- for(base= scene->base.first; base; base= base->next)
- if(base->object->data==me)
- base->object->recalc |= OB_RECALC_DATA;
- }
-
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
-
- /* topology could be changed, ensure mdisps are ok */
- multires_topology_changed(scene, obedit);
-}
-
-void remake_editMesh(Scene *scene, Object *ob)
-{
- make_editMesh(scene, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
- BIF_undo_push("Undo all changes");
-}
-
-/* *************** Operator: separate parts *************/
-
-static EnumPropertyItem prop_separate_types[] = {
- {0, "SELECTED", 0, "Selection", ""},
- {1, "MATERIAL", 0, "By Material", ""},
- {2, "LOOSE", 0, "By loose parts", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* return 1: success */
-static int mesh_separate_selected(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- EditMesh *em, *emnew;
- EditVert *eve, *v1;
- EditEdge *eed, *e1;
- EditFace *efa, *f1;
- Object *obedit;
- Mesh *me, *menew;
- Base *basenew;
-
- if(editbase==NULL) return 0;
-
- obedit= editbase->object;
- me= obedit->data;
- em= BKE_mesh_get_editmesh(me);
- if(me->key) {
- BKE_report(op->reports, RPT_WARNING, "Can't separate mesh with shape keys.");
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- if(em->selected.first)
- BLI_freelistN(&(em->selected)); /* clear the selection order */
-
- EM_selectmode_set(em); // enforce full consistent selection flags
-
- EM_stats_update(em);
-
- if(em->totvertsel==0) {
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- /* we are going to work as follows:
- * 1. add a linked duplicate object: this will be the new one, we remember old pointer
- * 2. give new object empty mesh and put in editmode
- * 3: do a split if needed on current editmesh.
- * 4. copy over: all NOT selected verts, edges, faces
- * 5. call load_editMesh() on the new object
- */
-
- /* 1 */
- basenew= ED_object_add_duplicate(bmain, scene, editbase, 0); /* 0 = fully linked */
- ED_base_object_select(basenew, BA_DESELECT);
-
- /* 2 */
- basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */
- assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */
- me->id.us--;
- make_editMesh(scene, basenew->object);
- emnew= menew->edit_mesh;
- CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
- CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
- CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0);
-
- /* 3 */
- /* SPLIT: first make duplicate */
- adduplicateflag(em, SELECT);
- /* SPLIT: old faces have 3x flag 128 set, delete these ones */
- delfaceflag(em, 128);
- /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
- EM_selectmode_set(em);
-
- /* 4 */
- /* move over: everything that is selected */
- for(eve= em->verts.first; eve; eve= v1) {
- v1= eve->next;
- if(eve->f & SELECT) {
- BLI_remlink(&em->verts, eve);
- BLI_addtail(&emnew->verts, eve);
- }
- }
-
- for(eed= em->edges.first; eed; eed= e1) {
- e1= eed->next;
- if(eed->f & SELECT) {
- BLI_remlink(&em->edges, eed);
- BLI_addtail(&emnew->edges, eed);
- }
- }
-
- for(efa= em->faces.first; efa; efa= f1) {
- f1= efa->next;
- if (efa == em->act_face && (efa->f & SELECT)) {
- EM_set_actFace(em, NULL);
- }
-
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&emnew->faces, efa);
- }
- }
-
- /* 5 */
- load_editMesh(scene, basenew->object);
- free_editMesh(emnew);
- MEM_freeN(menew->edit_mesh);
- menew->edit_mesh= NULL;
-
- /* copy settings */
- menew->texflag= me->texflag;
- menew->drawflag= me->drawflag;
- menew->flag= me->flag;
- menew->editflag= me->editflag;
- menew->smoothresh= me->smoothresh;
-
- /* hashedges are invalid now, make new! */
- editMesh_set_hash(em);
-
- DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
- DAG_id_tag_update(&basenew->object->id, OB_RECALC_DATA);
-
- BKE_mesh_end_editmesh(me, em);
-
- return 1;
-}
-
-/* return 1: success */
-static int mesh_separate_material(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- Mesh *me= editbase->object->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- unsigned char curr_mat;
-
- for (curr_mat = 1; curr_mat < editbase->object->totcol; ++curr_mat) {
- /* clear selection, we're going to use that to select material group */
- EM_clear_flag_all(em, SELECT);
- /* select the material */
- EM_select_by_material(em, curr_mat);
- /* and now separate */
- if(0==mesh_separate_selected(op, bmain, scene, editbase)) {
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
- }
-
- BKE_mesh_end_editmesh(me, em);
- return 1;
-}
-
-/* return 1: success */
-static int mesh_separate_loose(wmOperator *op, Main *bmain, Scene *scene, Base *editbase)
-{
- Mesh *me;
- EditMesh *em;
- int doit= 1;
-
- me= editbase->object->data;
- em= BKE_mesh_get_editmesh(me);
-
- if(me->key) {
- error("Can't separate with vertex keys");
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- EM_clear_flag_all(em, SELECT);
-
- while(doit) {
- /* Select a random vert to start with */
- EditVert *eve;
- int tot;
-
- /* check if all verts that are visible have been done */
- for(eve=em->verts.first; eve; eve= eve->next)
- if(!eve->h) break;
- if(eve==NULL) break; /* only hidden verts left, quit early */
-
- /* first non hidden vert */
- eve->f |= SELECT;
-
- selectconnected_mesh_all(em);
-
- /* don't separate the very last part */
- for(eve=em->verts.first; eve; eve= eve->next)
- if((eve->f & SELECT)==0) break;
- if(eve==NULL) break;
-
- tot= BLI_countlist(&em->verts);
-
- /* and now separate */
- doit= mesh_separate_selected(op, bmain, scene, editbase);
-
- /* with hidden verts this can happen */
- if(tot == BLI_countlist(&em->verts))
- break;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return 1;
-}
-
-
-static int mesh_separate_exec(bContext *C, wmOperator *op)
-{
- Main *bmain= CTX_data_main(C);
- Scene *scene= CTX_data_scene(C);
- Base *base= CTX_data_active_base(C);
- int retval= 0, type= RNA_enum_get(op->ptr, "type");
-
- if(type == 0)
- retval= mesh_separate_selected(op, bmain, scene, base);
- else if(type == 1)
- retval= mesh_separate_material(op, bmain, scene, base);
- else if(type == 2)
- retval= mesh_separate_loose(op, bmain, scene, base);
-
- if(retval) {
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data);
-
- // XXX: new object was created, but selection wasn't actually changed
- // need this for outliner update without adding new ND. nazgul.
- WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
-
- return OPERATOR_FINISHED;
- }
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_separate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Separate";
- ot->description= "Separate selected geometry into a new mesh";
- ot->idname= "MESH_OT_separate";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= mesh_separate_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ot->prop= RNA_def_enum(ot->srna, "type", prop_separate_types, 0, "Type", "");
-}
-
-
-/* ******************************************** */
-
-/* *************** UNDO ***************************** */
-/* new mesh undo, based on pushing editmesh data itself */
-/* reuses same code as for global and curve undo... unify that (ton) */
-
-/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
-
-/* a compressed version of editmesh data */
-
-typedef struct EditVertC
-{
- float no[3];
- float co[3];
- unsigned char f, h;
- short bweight;
- int keyindex;
-} EditVertC;
-
-typedef struct EditEdgeC
-{
- int v1, v2;
- unsigned char f, h, seam, sharp, pad;
- short crease, bweight, fgoni;
-} EditEdgeC;
-
-typedef struct EditFaceC
-{
- int v1, v2, v3, v4;
- unsigned char flag, f, h, fgonf, pad1;
- short mat_nr;
-} EditFaceC;
-
-typedef struct EditSelectionC{
- short type;
- int index;
-}EditSelectionC;
-
-typedef struct UndoMesh {
- EditVertC *verts;
- EditEdgeC *edges;
- EditFaceC *faces;
- EditSelectionC *selected;
- int totvert, totedge, totface, totsel;
- int selectmode, shapenr;
- char retopo_mode;
- CustomData vdata, edata, fdata;
-} UndoMesh;
-
-/* for callbacks */
-
-static void free_undoMesh(void *umv)
-{
- UndoMesh *um= umv;
-
- if(um->verts) MEM_freeN(um->verts);
- if(um->edges) MEM_freeN(um->edges);
- if(um->faces) MEM_freeN(um->faces);
- if(um->selected) MEM_freeN(um->selected);
-// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
- CustomData_free(&um->vdata, um->totvert);
- CustomData_free(&um->edata, um->totedge);
- CustomData_free(&um->fdata, um->totface);
- MEM_freeN(um);
-}
-
-static void *editMesh_to_undoMesh(void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um;
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec=NULL;
- EditEdgeC *eedc=NULL;
- EditFaceC *efac=NULL;
- EditSelectionC *esec=NULL;
- int a;
-
- um= MEM_callocN(sizeof(UndoMesh), "undomesh");
-
- um->selectmode = em->selectmode;
- um->shapenr = em->shapenr;
-
- for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
- for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
- for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
- for(ese=em->selected.first; ese; ese=ese->next) um->totsel++;
- /* malloc blocks */
-
- if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
- if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
- if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
- if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
-
- if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
- if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
- if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
-
- /* now copy vertices */
- a = 0;
- for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
- VECCOPY(evec->co, eve->co);
- VECCOPY(evec->no, eve->no);
-
- evec->f= eve->f;
- evec->h= eve->h;
- evec->keyindex= eve->keyindex;
- eve->tmp.l = a; /*store index*/
- evec->bweight= (short)(eve->bweight*255.0f);
-
- CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
- }
-
- /* copy edges */
- a = 0;
- for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) {
- eedc->v1= (int)eed->v1->tmp.l;
- eedc->v2= (int)eed->v2->tmp.l;
- eedc->f= eed->f;
- eedc->h= eed->h;
- eedc->seam= eed->seam;
- eedc->sharp= eed->sharp;
- eedc->crease= (short)(eed->crease*255.0f);
- eedc->bweight= (short)(eed->bweight*255.0f);
- eedc->fgoni= eed->fgoni;
- eed->tmp.l = a; /*store index*/
- CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
-
- }
-
- /* copy faces */
- a = 0;
- for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
- efac->v1= (int)efa->v1->tmp.l;
- efac->v2= (int)efa->v2->tmp.l;
- efac->v3= (int)efa->v3->tmp.l;
- if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
- else efac->v4= -1;
-
- efac->mat_nr= efa->mat_nr;
- efac->flag= efa->flag;
- efac->f= efa->f;
- efac->h= efa->h;
- efac->fgonf= efa->fgonf;
-
- efa->tmp.l = a; /*store index*/
-
- CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
- }
-
- a = 0;
- for(ese=em->selected.first; ese; ese=ese->next, esec++){
- esec->type = ese->type;
- if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l;
- else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l;
- else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
- }
-
-// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
-// um->retopo_mode= scene->toolsettings->retopo_mode;
-
- return um;
-}
-
-static void undoMesh_to_editMesh(void *umv, void *emv)
-{
- EditMesh *em= (EditMesh *)emv;
- UndoMesh *um= (UndoMesh *)umv;
- EditVert *eve, **evar=NULL;
- EditEdge *eed;
- EditFace *efa;
- EditSelection *ese;
- EditVertC *evec;
- EditEdgeC *eedc;
- EditFaceC *efac;
- EditSelectionC *esec;
- int a=0;
-
- free_editMesh(em);
-
- /* malloc blocks */
- memset(em, 0, sizeof(EditMesh));
-
- em->selectmode = um->selectmode;
- em->shapenr = um->shapenr;
-
- init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
-
- CustomData_free(&em->vdata, 0);
- CustomData_free(&em->edata, 0);
- CustomData_free(&em->fdata, 0);
-
- CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
- CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
-
- /* now copy vertices */
-
- if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
- for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
- eve= addvertlist(em, evec->co, NULL);
- evar[a]= eve;
-
- VECCOPY(eve->no, evec->no);
- eve->f= evec->f;
- eve->h= evec->h;
- eve->keyindex= evec->keyindex;
- eve->bweight= ((float)evec->bweight)/255.0f;
-
- CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
- }
-
- /* copy edges */
- for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
- eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL);
-
- eed->f= eedc->f;
- eed->h= eedc->h;
- eed->seam= eedc->seam;
- eed->sharp= eedc->sharp;
- eed->fgoni= eedc->fgoni;
- eed->crease= ((float)eedc->crease)/255.0f;
- eed->bweight= ((float)eedc->bweight)/255.0f;
- CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
- }
-
- /* copy faces */
- for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
- if(efac->v4 != -1)
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
- else
- efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
-
- efa->mat_nr= efac->mat_nr;
- efa->flag= efac->flag;
- efa->f= efac->f;
- efa->h= efac->h;
- efa->fgonf= efac->fgonf;
-
- CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
- }
-
- end_editmesh_fastmalloc();
- if(evar) MEM_freeN(evar);
-
- em->totvert = um->totvert;
- em->totedge = um->totedge;
- em->totface = um->totface;
- /*restore stored editselections*/
- if(um->totsel){
- EM_init_index_arrays(em, 1,1,1);
- for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
- ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
- ese->type = esec->type;
- if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
- if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
- if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
- BLI_addtail(&(em->selected),ese);
- }
- EM_free_index_arrays();
- }
-
- /* restore total selections */
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-
-// XXX retopo_free_paint();
-// em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
-// scene->toolsettings->retopo_mode= um->retopo_mode;
-// if(scene->toolsettings->retopo_mode) {
-// XXX if(G.vd->depths) G.vd->depths->damaged= 1;
-// retopo_queue_updates(G.vd);
-// retopo_paint_view_update(G.vd);
-// }
-
-}
-
-static void *getEditMesh(bContext *C)
-{
- Object *obedit= CTX_data_edit_object(C);
- if(obedit && obedit->type==OB_MESH) {
- Mesh *me= obedit->data;
- return me->edit_mesh;
- }
- return NULL;
-}
-
-/* and this is all the undo system needs to know */
-void undo_push_mesh(bContext *C, const char *name)
-{
- undo_editmode_push(C, name, getEditMesh, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
-}
-
-
-
-/* *************** END UNDO *************/
-
-static EditVert **g_em_vert_array = NULL;
-static EditEdge **g_em_edge_array = NULL;
-static EditFace **g_em_face_array = NULL;
-
-void EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int i;
-
- if (forVert) {
- em->totvert= BLI_countlist(&em->verts);
-
- if(em->totvert) {
- g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*em->totvert, "em_v_arr");
-
- for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
- g_em_vert_array[i] = eve;
- }
- }
-
- if (forEdge) {
- em->totedge= BLI_countlist(&em->edges);
-
- if(em->totedge) {
- g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*em->totedge, "em_e_arr");
-
- for (i=0,eed=em->edges.first; eed; i++,eed=eed->next)
- g_em_edge_array[i] = eed;
- }
- }
-
- if (forFace) {
- em->totface= BLI_countlist(&em->faces);
-
- if(em->totface) {
- g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*em->totface, "em_f_arr");
-
- for (i=0,efa=em->faces.first; efa; i++,efa=efa->next)
- g_em_face_array[i] = efa;
- }
- }
-}
-
-void EM_free_index_arrays(void)
-{
- if (g_em_vert_array) MEM_freeN(g_em_vert_array);
- if (g_em_edge_array) MEM_freeN(g_em_edge_array);
- if (g_em_face_array) MEM_freeN(g_em_face_array);
- g_em_vert_array = NULL;
- g_em_edge_array = NULL;
- g_em_face_array = NULL;
-}
-
-EditVert *EM_get_vert_for_index(int index)
-{
- return g_em_vert_array?g_em_vert_array[index]:NULL;
-}
-
-EditEdge *EM_get_edge_for_index(int index)
-{
- return g_em_edge_array?g_em_edge_array[index]:NULL;
-}
-
-EditFace *EM_get_face_for_index(int index)
-{
- return g_em_face_array?g_em_face_array[index]:NULL;
-}
-
-/* can we edit UV's for this mesh?*/
-int EM_texFaceCheck(EditMesh *em)
-{
- /* some of these checks could be a touch overkill */
- if ( (em) &&
- (em->faces.first) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE)))
- return 1;
- return 0;
-}
-
-/* can we edit colors for this mesh?*/
-int EM_vertColorCheck(EditMesh *em)
-{
- /* some of these checks could be a touch overkill */
- if ( (em) &&
- (em->faces.first) &&
- (CustomData_has_layer(&em->fdata, CD_MCOL)))
- return 1;
- return 0;
-}
-
-
-void em_setup_viewcontext(bContext *C, ViewContext *vc)
-{
- view3d_set_viewcontext(C, vc);
-
- if(vc->obedit) {
- Mesh *me= vc->obedit->data;
- vc->em= me->edit_mesh;
- }
-}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
deleted file mode 100644
index fa3619883f4..00000000000
--- a/source/blender/editors/mesh/editmesh_add.c
+++ /dev/null
@@ -1,1772 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_add.c
- * \ingroup edmesh
- */
-
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-#include "RNA_enum_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_library.h"
-#include "BKE_mesh.h"
-#include "BKE_report.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_transform.h"
-#include "ED_view3d.h"
-#include "ED_object.h"
-
-#include "mesh_intern.h"
-
-/* bpymenu removed XXX */
-
-/* XXX */
-#define add_numbut(a, b, c, d, e, f, g) {}
-/* XXX */
-
-static float icovert[12][3] = {
- {0.0f,0.0f,-200.0f},
- {144.72f, -105.144f,-89.443f},
- {-55.277f, -170.128,-89.443f},
- {-178.885f,0.0f,-89.443f},
- {-55.277f,170.128f,-89.443f},
- {144.72f,105.144f,-89.443f},
- {55.277f,-170.128f,89.443f},
- {-144.72f,-105.144f,89.443f},
- {-144.72f,105.144f,89.443f},
- {55.277f,170.128f,89.443f},
- {178.885f,0.0f,89.443f},
- {0.0f,0.0f,200.0f}
-};
-static short icoface[20][3] = {
- {2,0,1},
- {1,0,5},
- {3,0,2},
- {4,0,3},
- {5,0,4},
- {1,5,10},
- {2,1,6},
- {3,2,7},
- {4,3,8},
- {5,4,9},
- {6,1,10},
- {7,2,6},
- {8,3,7},
- {9,4,8},
- {10,5,9},
- {6,10,11},
- {7,6,11},
- {8,7,11},
- {9,8,11},
- {10,9,11}
-};
-
-/* *************** add-click-mesh (extrude) operator ************** */
-
-static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
-{
- ViewContext vc;
- EditVert *eve;
- float min[3], max[3];
- int done= 0;
- short use_proj;
-
- em_setup_viewcontext(C, &vc);
-
- use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE);
-
- invert_m4_m4(vc.obedit->imat, vc.obedit->obmat);
-
- INIT_MINMAX(min, max);
-
- for(eve= vc.em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- DO_MINMAX(eve->co, min, max);
- done= 1;
- }
- }
-
- /* call extrude? */
- if(done) {
- const short rot_src= RNA_boolean_get(op->ptr, "rotate_source");
- EditEdge *eed;
- float vec[3], cent[3], mat[3][3];
- float nor[3]= {0.0, 0.0, 0.0};
-
- /* 2D normal calc */
- float mval_f[2];
-
- mval_f[0]= (float)event->mval[0];
- mval_f[1]= (float)event->mval[1];
-
- done= 0;
-
- /* calculate the normal for selected edges */
- for(eed= vc.em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- float co1[3], co2[3];
- mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
- mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
- project_float_noclip(vc.ar, co1, co1);
- project_float_noclip(vc.ar, co2, co2);
-
- /* 2D rotate by 90d while adding.
- * (x, y) = (y, -x)
- *
- * accumulate the screenspace normal in 2D,
- * with screenspace edge length weighting the result. */
- if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
- nor[0] += (co1[1] - co2[1]);
- nor[1] += -(co1[0] - co2[0]);
- }
- else {
- nor[0] += (co2[1] - co1[1]);
- nor[1] += -(co2[0] - co1[0]);
- }
- done= 1;
- }
- }
-
- if(done) {
- float view_vec[3], cross[3];
-
- /* convert the 2D nomal into 3D */
- mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
- mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
-
- /* correct the normal to be aligned on the view plane */
- copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
- mul_mat3_m4_v3(vc.obedit->imat, view_vec);
- cross_v3_v3v3(cross, nor, view_vec);
- cross_v3_v3v3(nor, view_vec, cross);
- normalize_v3(nor);
- }
-
- /* center */
- mid_v3_v3v3(cent, min, max);
- copy_v3_v3(min, cent);
-
- mul_m4_v3(vc.obedit->obmat, min); // view space
- view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
- mul_m4_v3(vc.obedit->imat, min); // back in object space
-
- sub_v3_v3(min, cent);
-
- /* calculate rotation */
- unit_m3(mat);
- if(done) {
- float dot;
-
- copy_v3_v3(vec, min);
- normalize_v3(vec);
- dot= INPR(vec, nor);
-
- if( fabs(dot)<0.999) {
- float cross[3], si, q1[4];
-
- cross_v3_v3v3(cross, nor, vec);
- normalize_v3(cross);
- dot= 0.5f*saacos(dot);
-
- /* halve the rotation if its applied twice */
- if(rot_src) dot *= 0.5f;
-
- si= (float)sin(dot);
- q1[0]= (float)cos(dot);
- q1[1]= cross[0]*si;
- q1[2]= cross[1]*si;
- q1[3]= cross[2]*si;
- quat_to_mat3( mat,q1);
- }
- }
-
- if(rot_src) {
- rotateflag(vc.em, SELECT, cent, mat);
- /* also project the source, for retopo workflow */
- if(use_proj)
- EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
- }
-
- extrudeflag(vc.obedit, vc.em, SELECT, nor, 0);
- rotateflag(vc.em, SELECT, cent, mat);
- translateflag(vc.em, SELECT, min);
-
- recalc_editnormals(vc.em);
- }
- else if(vc.em->selectmode & SCE_SELECT_VERTEX) {
-
- float imat[4][4];
- const float *curs= give_cursor(vc.scene, vc.v3d);
-
- copy_v3_v3(min, curs);
- view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
-
- eve= addvertlist(vc.em, 0, NULL);
-
- invert_m4_m4(imat, vc.obedit->obmat);
- mul_v3_m4v3(eve->co, imat, min);
-
- eve->f= SELECT;
- }
-
- if(use_proj)
- EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data);
- DAG_id_tag_update(vc.obedit->data, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Duplicate or Extrude at 3D Cursor";
- ot->description= "Duplicate and extrude selected vertices, edges or faces towards 3D Cursor";
- ot->idname= "MESH_OT_dupli_extrude_cursor";
-
- /* api callbacks */
- ot->invoke= dupli_extrude_cursor;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "rotate_source", 1, "Rotate Source", "Rotate initial selection giving better shape");
-}
-
-
-/* ********************** */
-
-/* selected faces get hidden edges */
-static int make_fgon(EditMesh *em, wmOperator *op, int make)
-{
- EditFace *efa;
- EditEdge *eed;
- EditVert *eve;
- float *nor=NULL; // reference
- int done=0;
-
- if(make==0) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- efa->fgonf= 0;
- efa->e1->h &= ~EM_FGON;
- efa->e2->h &= ~EM_FGON;
- efa->e3->h &= ~EM_FGON;
- if(efa->e4) efa->e4->h &= ~EM_FGON;
- done= 1;
- }
- }
- EM_fgon_flags(em); // redo flags and indices for fgons
-
- return done;
- }
-
- /* tagging edges. rule is:
- - edge used by exactly 2 selected faces
- - no vertices allowed with only tagged edges (return)
- - face normals are allowed to difffer
-
- */
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0; // amount of selected
- eed->f2= 0; // amount of unselected
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(nor==NULL) nor= efa->n;
- if(efa->e1->f1 < 3) efa->e1->f1++;
- if(efa->e2->f1 < 3) efa->e2->f1++;
- if(efa->e3->f1 < 3) efa->e3->f1++;
- if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++;
- }
- else {
- if(efa->e1->f2 < 3) efa->e1->f2++;
- if(efa->e2->f2 < 3) efa->e2->f2++;
- if(efa->e3->f2 < 3) efa->e3->f2++;
- if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++;
- }
- }
- // now eed->f1 becomes tagged edge
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2 && eed->f2==0) eed->f1= 1;
- else eed->f1= 0;
- }
-
- // no vertices allowed with only tagged edges
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1) {
- eed->v1->f1 |= 1;
- eed->v2->f1 |= 1;
- }
- else {
- eed->v1->f1 |= 2;
- eed->v2->f1 |= 2;
- }
- }
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1==1) break;
- }
- if(eve) {
- BKE_report(op->reports, RPT_WARNING, "Cannot make a polygon with interior vertices");
- return 0;
- }
-
- // check for faces
- if(nor==NULL) {
- BKE_report(op->reports, RPT_WARNING, "No faces were selected to make FGon");
- return 0;
- }
-
- // and there we go
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1) {
- eed->h |= EM_FGON;
- done= 1;
- }
- }
-
- if(done)
- EM_fgon_flags(em); // redo flags and indices for fgons
- return done;
-}
-
-static int make_fgon_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if( make_fgon(em, op, 1) ) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_fgon_make(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make F-gon";
- ot->description= "Make fgon from selected faces";
- ot->idname= "MESH_OT_fgon_make";
-
- /* api callbacks */
- ot->exec= make_fgon_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int clear_fgon_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if( make_fgon(em, op, 0) ) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
-}
-
-void MESH_OT_fgon_clear(struct wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Clear F-gon";
- ot->description= "Clear fgon from selected face";
- ot->idname= "MESH_OT_fgon_clear";
-
- /* api callbacks */
- ot->exec= clear_fgon_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* precondition; 4 vertices selected, check for 4 edges and create face */
-static EditFace *addface_from_edges(EditMesh *em)
-{
- EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL};
- EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
- int a;
-
- /* find the 4 edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if( (eed->f & SELECT) || (eed->v1->f & eed->v2->f & SELECT) ) {
- if(eedar[0]==NULL) eedar[0]= eed;
- else if(eedar[1]==NULL) eedar[1]= eed;
- else if(eedar[2]==NULL) eedar[2]= eed;
- else eedar[3]= eed;
-
- }
- }
-
-
- if(eedar[3]) {
- /* first 2 points */
- v1= eedar[0]->v1;
- v2= eedar[0]->v2;
-
- /* find the 2 edges connected to first edge */
- for(a=1; a<4; a++) {
- if( eedar[a]->v1 == v2) v3= eedar[a]->v2;
- else if(eedar[a]->v2 == v2) v3= eedar[a]->v1;
- else if( eedar[a]->v1 == v1) v4= eedar[a]->v2;
- else if(eedar[a]->v2 == v1) v4= eedar[a]->v1;
- }
-
- /* verify if last edge exists */
- if(v3 && v4) {
- for(a=1; a<4; a++) {
- if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break;
- if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break;
- }
- if(a!=4) {
- return addfacelist(em, v1, v2, v3, v4, NULL, NULL);
- }
- }
- }
- return NULL;
-}
-
-/* ******************************* */
-
-/* this also allows to prevent triangles being made in quads */
-static int compareface_overlaps(EditFace *vl1, EditFace *vl2)
-{
- EditVert *v1, *v2, *v3, *v4;
- int equal= 0;
-
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
- v4= vl2->v4;
-
- if(vl1==vl2) return 0;
-
- if(v4==NULL && vl1->v4==NULL) {
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++;
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++;
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++;
- }
- else {
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++;
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++;
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++;
- if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++;
- }
-
- if(v4 && vl1->v4) {
- if(equal==4) return 1;
- }
- else
- if(equal>=3) return 1;
-
- return 0;
-}
-
-/* checks for existence, and for tria overlapping inside quad */
-static EditFace *exist_face_overlaps(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
-{
- EditFace *efa, efatest;
-
- efatest.v1= v1;
- efatest.v2= v2;
- efatest.v3= v3;
- efatest.v4= v4;
-
- efa= em->faces.first;
- while(efa) {
- if(compareface_overlaps(&efatest, efa)) return efa;
- efa= efa->next;
- }
- return NULL;
-}
-
-/* will be new face smooth or solid? depends on smoothness of face neighbours
- * of new face, if function return 1, then new face will be smooth, when functio
- * will return zero, then new face will be solid */
-static void fix_new_face(EditMesh *em, EditFace *eface)
-{
- struct EditFace *efa;
- struct EditEdge *eed=NULL;
- struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4;
- struct EditVert *ev1=NULL, *ev2=NULL;
- short smooth=0; /* "total smoothnes" of faces in neighbourhood */
- short coef; /* "weight" of smoothness */
- short count=0; /* number of edges with same direction as eface */
- short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */
-
- efa = em->faces.first;
-
- while(efa) {
-
- if(efa==eface) {
- efa = efa->next;
- continue;
- }
-
- coef = 0;
- ev1 = ev2 = NULL;
- eed = NULL;
-
- if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) {
- ev1 = v1;
- coef++;
- }
- if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) {
- if(ev1) ev2 = v2;
- else ev1 = v2;
- coef++;
- }
- if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) {
- if(coef<2) {
- if(ev1) ev2 = v3;
- else ev1 = v3;
- }
- coef++;
- }
- if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) {
- if(ev1 && coef<2) ev2 = v4;
- coef++;
- }
-
- /* "democracy" of smoothness */
- if(efa->flag & ME_SMOOTH)
- smooth += coef;
- else
- smooth -= coef;
-
- /* try to find edge using vertexes ev1 and ev2 */
- if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(em, ev1, ev2);
-
- /* has bordering edge of efa same direction as edge of eface ? */
- if(eed) {
- if(eed->v1==v1) vi00 = 1;
- else if(eed->v1==v2) vi00 = 2;
- else if(eed->v1==v3) vi00 = 3;
- else if(v4 && eed->v1==v4) vi00 = 4;
-
- if(eed->v2==v1) vi01 = 1;
- else if(eed->v2==v2) vi01 = 2;
- else if(eed->v2==v3) vi01 = 3;
- else if(v4 && eed->v2==v4) vi01 = 4;
-
- if(v4) {
- if(vi01==1 && vi00==4) vi00 = 0;
- if(vi01==4 && vi00==1) vi01 = 0;
- }
- else {
- if(vi01==1 && vi00==3) vi00 = 0;
- if(vi01==3 && vi00==1) vi01 = 0;
- }
-
- if(eed->v1==efa->v1) vi10 = 1;
- else if(eed->v1==efa->v2) vi10 = 2;
- else if(eed->v1==efa->v3) vi10 = 3;
- else if(efa->v4 && eed->v1==efa->v4) vi10 = 4;
-
- if(eed->v2==efa->v1) vi11 = 1;
- else if(eed->v2==efa->v2) vi11 = 2;
- else if(eed->v2==efa->v3) vi11 = 3;
- else if(efa->v4 && eed->v2==efa->v4) vi11 = 4;
-
- if(efa->v4) {
- if(vi11==1 && vi10==4) vi10 = 0;
- if(vi11==4 && vi10==1) vi11 = 0;
- }
- else {
- if(vi11==1 && vi10==3) vi10 = 0;
- if(vi11==3 && vi10==1) vi11 = 0;
- }
-
- if(((vi00>vi01) && (vi10>vi11)) ||
- ((vi00<vi01) && (vi10<vi11)))
- count++;
- else
- count--;
- }
-
- efa = efa->next;
- }
-
- /* set up smoothness according voting of face in neighbourhood */
- if(smooth >= 0)
- eface->flag |= ME_SMOOTH;
- else
- eface->flag &= ~ME_SMOOTH;
-
- /* flip face, when too much "face normals" in neighbourhood is different */
- if(count > 0) {
- flipface(em, eface);
- }
-}
-
-/* only adds quads or trias when there's edges already */
-static void addfaces_from_edgenet(EditMesh *em)
-{
- EditVert *eve1, *eve2, *eve3, *eve4;
-
- for(eve1= em->verts.first; eve1; eve1= eve1->next) {
- for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
- if(findedgelist(em, eve1,eve2)) {
- for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) {
- if((eve2!=eve3 && (eve3->f & 1) && findedgelist(em, eve1,eve3))) {
- EditEdge *sh_edge= NULL;
- EditVert *sh_vert= NULL;
-
- sh_edge= findedgelist(em, eve2,eve3);
-
- if(sh_edge) { /* Add a triangle */
- if(!exist_face_overlaps(em, eve1,eve2,eve3,NULL))
- fix_new_face(em, addfacelist(em, eve1,eve2,eve3,NULL,NULL,NULL));
- }
- else { /* Check for a shared vertex */
- for(eve4= em->verts.first; eve4; eve4= eve4->next) {
- if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) &&
- !findedgelist(em, eve1,eve4) && findedgelist(em, eve2,eve4) &&
- findedgelist(em, eve3,eve4)) {
- sh_vert= eve4;
- break;
- }
- }
-
- if(sh_vert) {
- if(sh_vert) {
- if(!exist_face_overlaps(em, eve1,eve2,eve4,eve3))
- fix_new_face(em, addfacelist(em, eve1,eve2,eve4,eve3,NULL,NULL));
- }
- }
- }
- }
- }
- }
- }
- }
-
- EM_select_flush(em);
-
-// XXX DAG_id_tag_update(obedit->data, 0);
-}
-
-static void addedgeface_mesh(EditMesh *em, wmOperator *op)
-{
- EditVert *eve, *neweve[4];
- EditEdge *eed;
- EditFace *efa;
- short amount=0;
-
- /* how many selected ? */
- if(em->selectmode & SCE_SELECT_EDGE) {
- /* in edge mode finding selected vertices means flushing down edge codes... */
- /* can't make face with only edge selection info... */
- EM_selectmode_set(em);
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- amount++;
- if(amount>4) break;
- neweve[amount-1]= eve;
- }
- }
-
- if(amount==2) {
- eed= addedgelist(em, neweve[0], neweve[1], NULL);
- EM_select_edge(eed, 1);
-
- // XXX DAG_id_tag_update(obedit->data, 0);
- return;
- }
- else if(amount > 4) {
- addfaces_from_edgenet(em);
- return;
- }
- else if(amount<2) {
- BKE_report(op->reports, RPT_WARNING, "More vertices are needed to make an edge/face");
- return;
- }
-
- efa= NULL; // check later
-
- if(amount==3) {
-
- if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL);
- EM_select_face(efa, 1);
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
- else if(amount==4) {
- /* this test survives when theres 2 triangles */
- if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- int tria= 0;
-
- /* remove trias if they exist, 4 cases.... */
- if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++;
- if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++;
- if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++;
- if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++;
-
- if(tria==2) join_triangles(em);
- else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
- /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */
- EditEdge *eedcheck;
- int count;
- count = 0;
- for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) {
- if(eedcheck->f & SELECT) {
- count++;
- }
- }
-
- if(count++ > 4){
- addfaces_from_edgenet(em);
- return;
- } else {
- /* if 4 edges exist, we just create the face, convex or not */
- efa= addface_from_edges(em);
- if(efa==NULL) {
-
- /* the order of vertices can be anything, 6 cases to check */
- if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL);
- }
- else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) {
- efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL);
- }
- else BKE_report(op->reports, RPT_WARNING, "cannot find nice quad from concave set of vertices");
-
- }
- }
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
- else BKE_report(op->reports, RPT_WARNING, "The selected vertices already form a face");
- }
-
- if(efa) {
- EM_select_face(efa, 1);
-
- fix_new_face(em, efa);
-
- recalc_editnormals(em);
- }
- }
-
-static int addedgeface_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- addedgeface_mesh(em, op);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edge_face_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make Edge/Face";
- ot->description= "Add an edge or face to selected";
- ot->idname= "MESH_OT_edge_face_add";
-
- /* api callbacks */
- ot->exec= addedgeface_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
-}
-
-
-
-/* ************************ primitives ******************* */
-
-// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
-// this hack is only used so that scons+mingw + split-sources hack works
- // ------------------------------- start copied code
-/* these are not the monkeys you are looking for */
-static int monkeyo= 4;
-static int monkeynv= 271;
-static int monkeynf= 250;
-static signed char monkeyv[271][3]= {
-{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
-{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
-{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
-{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
-{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
-{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
-{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
-{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
-{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
-{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
-{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
-{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
-{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
-{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
-{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
-{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
-{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
-{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
-{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
-{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
-{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
-{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
-{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
-{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
-{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
-{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
-{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
-{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
-{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
-{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
-{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
-{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
-{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
-{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
-{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
-{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
-{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
-{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
-{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
-{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
-{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
-{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
-{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
-{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
-{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
-{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
-{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
-{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
-{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
-{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
-{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
-{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
-{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
-{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
-{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
-{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
-{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
-{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
-{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
-{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
-{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
-{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
-{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
-{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
-{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
-{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
-{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
-{-26,-16,-42},{-17,49,-49},
-};
-
-static signed char monkeyf[250][4]= {
-{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4},
-{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6},
-{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8},
-{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12},
-{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12},
-{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4},
-{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4},
-{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23},
-{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15},
-{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
-{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
-{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44},
-{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19},
-{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38},
-{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39},
-{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42},
-{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16},
-{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32},
-{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35},
-{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21},
-{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11},
-{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38},
-{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39},
-{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34},
-{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34},
-{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36},
-{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27},
-{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42},
-{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34},
-{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26},
-{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35},
-{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35},
-{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58},
-{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52},
-{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49},
-{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24},
-{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100},
-{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24},
-{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110},
-{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48},
-{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43},
-{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6},
-{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30},
-{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5},
-{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13},
-{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30},
-{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31},
-{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35},
-{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27},
-{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23},
-{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35},
-{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4},
-{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35},
-{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33},
-{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35},
-{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36},
-{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39},
-{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17},
-{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19},
-{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30},
-{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30},
-{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66},
-{-68,-67,24,-33},
-};
- // ------------------------------- end copied code
-
-
-#define PRIM_PLANE 0
-#define PRIM_CUBE 1
-#define PRIM_CIRCLE 4
-#define PRIM_CYLINDER 5
-#define PRIM_CONE 7
-#define PRIM_GRID 10
-#define PRIM_UVSPHERE 11
-#define PRIM_ICOSPHERE 12
-#define PRIM_MONKEY 13
-
-static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg,
- int subdiv, float dia, float depth, int ext, int fill)
-{
- /*
- * type - for the type of shape
- * dia - the radius for cone,sphere cylinder etc.
- * depth -
- * ext - extrude
- * fill - end capping, and option to fill in circle
- * cent[3] - center of the data.
- * */
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
- float phi, phid, vec[3];
- float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
- short a, b;
-
- EM_clear_flag_all(em, SELECT);
-
- phid= 2.0f*(float)M_PI/tot;
- phi= .25f*(float)M_PI;
-
- switch(type) {
- case PRIM_GRID: /* grid */
- /* clear flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
-
- /* one segment first: the X axis */
- phi = (2*dia)/(float)(tot-1);
- phid = (2*dia)/(float)(seg-1);
- for(a=tot-1;a>=0;a--) {
- vec[0] = (phi*a) - dia;
- vec[1]= - dia;
- vec[2]= 0.0f;
- eve= addvertlist(em, vec, NULL);
- eve->f= 1+2+4;
- if(a < tot -1) addedgelist(em, eve->prev, eve, NULL);
- }
- /* extrude and translate */
- vec[0]= vec[2]= 0.0;
- vec[1]= phid;
-
- for(a=0;a<seg-1;a++) {
- extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
- translateflag(em, 2, vec);
- }
-
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
- recalc_editnormals(em);
- break;
-
- case PRIM_UVSPHERE: /* UVsphere */
-
- /* clear all flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
-
- /* one segment first */
- phi= 0;
- phid/=2;
- for(a=0; a<=tot; a++) {
- vec[0]= dia*sinf(phi);
- vec[1]= 0.0;
- vec[2]= dia*cosf(phi);
- eve= addvertlist(em, vec, NULL);
- eve->f= 1+2+4;
- if(a==0) v1= eve;
- else addedgelist(em, eve, eve->prev, NULL);
- phi+= phid;
- }
-
- /* extrude and rotate */
- phi= M_PI/seg;
- q[0]= cos(phi);
- q[3]= sin(phi);
- q[1]=q[2]= 0;
- quat_to_mat3( cmat,q);
-
- for(a=0; a<seg; a++) {
- extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
- rotateflag(em, 2, v1->co, cmat);
- }
-
- removedoublesflag(em, 4, 0, 0.0001);
-
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
- recalc_editnormals(em);
- break;
- case PRIM_ICOSPHERE: /* Icosphere */
- {
- EditVert *eva[12];
- EditEdge *eed;
-
- /* clear all flags */
- eve= em->verts.first;
- while(eve) {
- eve->f= 0;
- eve= eve->next;
- }
- dia/=200;
- for(a=0;a<12;a++) {
- vec[0]= dia*icovert[a][0];
- vec[1]= dia*icovert[a][1];
- vec[2]= dia*icovert[a][2];
- eva[a]= addvertlist(em, vec, NULL);
- eva[a]->f= 1+2;
- }
- for(a=0;a<20;a++) {
- EditFace *evtemp;
- v1= eva[ icoface[a][0] ];
- v2= eva[ icoface[a][1] ];
- v3= eva[ icoface[a][2] ];
- evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL);
- evtemp->e1->f = 1+2;
- evtemp->e2->f = 1+2;
- evtemp->e3->f = 1+2;
- }
-
- dia*=200;
- for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0);
- /* and now do imat */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & 2) {
- mul_m4_v3(mat,eve->co);
- }
- eve= eve->next;
- }
-
- // Clear the flag 2 from the edges
- for(eed=em->edges.first;eed;eed=eed->next){
- if(eed->f & 2){
- eed->f &= !2;
- }
- }
- }
- break;
- case PRIM_MONKEY: /* Monkey */
- {
- //extern int monkeyo, monkeynv, monkeynf;
- //extern signed char monkeyf[][4];
- //extern signed char monkeyv[][3];
- EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
- int i;
-
- for (i=0; i<monkeynv; i++) {
- float v[3];
- v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
- tv[i]= addvertlist(em, v, NULL);
- tv[i]->f |= SELECT;
- tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL);
- tv[monkeynv+i]->f |= SELECT;
- }
- for (i=0; i<monkeynf; i++) {
- addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
- addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
- }
-
- MEM_freeN(tv);
-
- /* and now do imat */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- mul_m4_v3(mat,eve->co);
- }
- }
- recalc_editnormals(em);
- }
- break;
- default: /* all types except grid, sphere... */
- if(type==PRIM_CONE);
- else if(ext==0)
- depth= 0.0f;
-
- /* first vertex at 0° for circular objects */
- if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) )
- phi = 0.0f;
-
- vtop= vdown= v1= v2= 0;
- for(b=0; b<=ext; b++) {
- for(a=0; a<tot; a++) {
-
- vec[0]= dia*sinf(phi);
- vec[1]= dia*cosf(phi);
- vec[2]= b?depth:-depth;
-
- mul_m4_v3(mat, vec);
- eve= addvertlist(em, vec, NULL);
- eve->f= SELECT;
- if(a==0) {
- if(b==0) v1= eve;
- else v2= eve;
- }
- phi+=phid;
- }
- }
-
- /* center vertices */
- /* type PRIM_CONE can only have 1 one side filled
- * if the cone has no capping, dont add vtop */
- if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) {
- vec[0]= vec[1]= 0.0f;
- vec[2]= type==PRIM_CONE ? depth : -depth;
- mul_m4_v3(mat, vec);
- vdown= addvertlist(em, vec, NULL);
- if((ext || type==PRIM_CONE) && fill) {
- vec[0]= vec[1]= 0.0f;
- vec[2]= type==PRIM_CONE ? -depth : depth;
- mul_m4_v3(mat,vec);
- vtop= addvertlist(em, vec, NULL);
- }
- } else {
- vdown= v1;
- vtop= v2;
- }
- if(vtop) vtop->f= SELECT;
- if(vdown) vdown->f= SELECT;
-
- /* top and bottom face */
- if(fill || type==PRIM_CONE) {
- if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
- v3= v1->next->next;
- if(ext) v4= v2->next->next;
-
- addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL);
- if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL);
-
- }
- else {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL);
- v3= v3->next;
- if(ext && fill) {
- addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL);
- v4= v4->next;
- }
- }
- if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
- addfacelist(em, vdown, v3, v1, 0, NULL, NULL);
- if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL);
- }
- }
- }
- else if(type==PRIM_CIRCLE) { /* we need edges for a circle */
- v3= v1;
- for(a=1;a<tot;a++) {
- addedgelist(em, v3, v3->next, NULL);
- v3= v3->next;
- }
- addedgelist(em, v3, v1, NULL);
- }
- /* side faces */
- if(ext) {
- v3= v1;
- v4= v2;
- for(a=1; a<tot; a++) {
- addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL);
- v3= v3->next;
- v4= v4->next;
- }
- addfacelist(em, v3, v1, v2, v4, NULL, NULL);
- }
- else if(fill && type==PRIM_CONE) {
- /* add the bottom flat area of the cone
- * if capping is disabled dont bother */
- v3= v1;
- for(a=1; a<tot; a++) {
- addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL);
- v3= v3->next;
- }
- addfacelist(em, vtop, v1, v3, 0, NULL, NULL);
- }
- }
-
- EM_stats_update(em);
- /* simple selection flush OK, based on fact it's a single model */
- EM_select_flush(em); /* flushes vertex -> edge -> face selection */
-
- if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY))
- EM_recalc_normal_direction(em, FALSE, TRUE); /* otherwise monkey has eyes in wrong direction */
-
- BKE_mesh_end_editmesh(obedit->data, em);
-}
-
-/* ********* add primitive operators ************* */
-
-static const char *get_mesh_defname(int type)
-{
- switch (type) {
- case PRIM_PLANE: return "Plane";
- case PRIM_CUBE: return "Cube";
- case PRIM_CIRCLE: return "Circle";
- case PRIM_CYLINDER: return "Cylinder";
- case PRIM_CONE: return "Cone";
- case PRIM_GRID: return "Grid";
- case PRIM_UVSPHERE: return "Sphere";
- case PRIM_ICOSPHERE: return "Icosphere";
- case PRIM_MONKEY: return "Monkey";
- default:
- return "Mesh";
- }
-}
-
-static void make_prim_ext(bContext *C, float *loc, float *rot, int enter_editmode, unsigned int layer,
- int type, int tot, int seg,
- int subdiv, float dia, float depth, int ext, int fill)
-{
- Object *obedit= CTX_data_edit_object(C);
- int newob = 0;
- float mat[4][4];
- float scale;
-
- if(obedit==NULL || obedit->type!=OB_MESH) {
- obedit= ED_object_add_type(C, OB_MESH, loc, rot, FALSE, layer);
-
- rename_id((ID *)obedit, get_mesh_defname(type));
- rename_id((ID *)obedit->data, get_mesh_defname(type));
-
- /* create editmode */
- ED_object_enter_editmode(C, EM_DO_UNDO|EM_IGNORE_LAYER); /* rare cases the active layer is messed up */
- newob = 1;
- }
- else DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
-
- scale= ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
-
- dia *= scale;
- depth *= scale * 0.5f;
-
- make_prim(obedit, type, mat, tot, seg, subdiv, dia, depth, ext, fill);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
-
- /* userdef */
- if (newob && !enter_editmode) {
- ED_object_exit_editmode(C, EM_FREEDATA); /* adding EM_DO_UNDO messes up operator redo */
- }
- WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, obedit);
-}
-
-static int add_primitive_plane_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_PLANE, 4, 0, 0, sqrt(2.0f), 0.0f, 0, 1);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_plane_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Plane";
- ot->description= "Construct a filled planar mesh with 4 vertices";
- ot->idname= "MESH_OT_primitive_plane_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_plane_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cube_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- /* sqrt(2.0f) - plane (diameter of 1.41 makes it unit size) */
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CUBE, 4, 0, 0, sqrt(2.0f), 2.0f, 1, 1);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cube_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cube";
- ot->description= "Construct a cube mesh";
- ot->idname= "MESH_OT_primitive_cube_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cube_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_circle_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CIRCLE, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"), 0.0f, 0,
- RNA_boolean_get(op->ptr, "fill"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_circle_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Circle";
- ot->description= "Construct a circle mesh";
- ot->idname= "MESH_OT_primitive_circle_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_circle_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 3, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "fill", 0, "Fill", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CYLINDER, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"),
- RNA_float_get(op->ptr, "depth"), 1,
- RNA_boolean_get(op->ptr, "cap_ends"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cylinder_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cylinder";
- ot->description= "Construct a cylinder mesh";
- ot->idname= "MESH_OT_primitive_cylinder_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cylinder_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "cap_ends", 1, "Cap Ends", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_cone_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_CONE, RNA_int_get(op->ptr, "vertices"), 0, 0,
- RNA_float_get(op->ptr,"radius"), RNA_float_get(op->ptr, "depth"),
- 0, RNA_boolean_get(op->ptr, "cap_end"));
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_cone_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Cone";
- ot->description= "Construct a conic mesh (ends filled)";
- ot->idname= "MESH_OT_primitive_cone_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_cone_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "vertices", 32, INT_MIN, INT_MAX, "Vertices", "", 2, 500);
- RNA_def_float(ot->srna, "radius", 1.0f, 0.0, FLT_MAX, "Radius", "", 0.001, 100.00);
- RNA_def_float(ot->srna, "depth", 2.0f, 0.0, FLT_MAX, "Depth", "", 0.001, 100.00);
- RNA_def_boolean(ot->srna, "cap_end", 1, "Cap End", "");
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_grid_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_GRID, RNA_int_get(op->ptr, "x_subdivisions"),
- RNA_int_get(op->ptr, "y_subdivisions"), 0,
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 1);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_grid_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Grid";
- ot->description= "Construct a grid mesh";
- ot->idname= "MESH_OT_primitive_grid_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_grid_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "x_subdivisions", 10, INT_MIN, INT_MAX, "X Subdivisions", "", 3, 1000);
- RNA_def_int(ot->srna, "y_subdivisions", 10, INT_MIN, INT_MAX, "Y Subdivisions", "", 3, 1000);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, FLT_MAX);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_MONKEY, 0, 0, 2, 0.0f, 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_monkey_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Monkey";
- ot->description= "Construct a Suzanne mesh";
- ot->idname= "MESH_OT_primitive_monkey_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_monkey_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_UVSPHERE, RNA_int_get(op->ptr, "ring_count"),
- RNA_int_get(op->ptr, "segments"), 0,
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_uv_sphere_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add UV Sphere";
- ot->description= "Construct a UV sphere mesh";
- ot->idname= "MESH_OT_primitive_uv_sphere_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_uvsphere_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "segments", 32, INT_MIN, INT_MAX, "Segments", "", 3, 500);
- RNA_def_int(ot->srna, "ring_count", 16, INT_MIN, INT_MAX, "Rings", "", 3, 500);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0, FLT_MAX, "Size", "", 0.001, 100.00);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
-{
- int enter_editmode;
- unsigned int layer;
- float loc[3], rot[3];
-
- if(!ED_object_add_generic_get_opts(C, op, loc, rot, &enter_editmode, &layer))
- return OPERATOR_CANCELLED;
-
- make_prim_ext(C, loc, rot, enter_editmode, layer,
- PRIM_ICOSPHERE, 0, 0, RNA_int_get(op->ptr, "subdivisions"),
- RNA_float_get(op->ptr,"size"), 0.0f, 0, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_primitive_ico_sphere_add(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Add Ico Sphere";
- ot->description= "Construct an Icosphere mesh";
- ot->idname= "MESH_OT_primitive_ico_sphere_add";
-
- /* api callbacks */
- ot->invoke= ED_object_add_generic_invoke;
- ot->exec= add_primitive_icosphere_exec;
- ot->poll= ED_operator_scene_editable;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "subdivisions", 2, 0, INT_MAX, "Subdivisions", "", 0, 8);
- RNA_def_float(ot->srna, "size", 1.0f, 0.0f, FLT_MAX, "Size", "", 0.001f, 100.00);
-
- ED_object_add_generic_props(ot, TRUE);
-}
-
-/****************** add duplicate operator ***************/
-
-static int mesh_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *ob= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(ob->data);
-
- adduplicateflag(em, SELECT);
-
- BKE_mesh_end_editmesh(ob->data, em);
-
- DAG_id_tag_update(ob->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- WM_cursor_wait(1);
- mesh_duplicate_exec(C, op);
- WM_cursor_wait(0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_duplicate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Duplicate Mesh";
- ot->description= "Duplicate selected vertices, edges or faces";
- ot->idname= "MESH_OT_duplicate";
-
- /* api callbacks */
- ot->invoke= mesh_duplicate_invoke;
- ot->exec= mesh_duplicate_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* to give to transform */
- RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
-}
-
diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c
deleted file mode 100644
index b7ed6ec14ca..00000000000
--- a/source/blender/editors/mesh/editmesh_lib.c
+++ /dev/null
@@ -1,2848 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_lib.c
- * \ingroup edmesh
- */
-
-
-/*
-
-editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_edgehash.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_customdata.h"
-#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_mesh.h"
-
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-#include "ED_transform.h"
-
-#include "mesh_intern.h"
-
-/* Helpers for EM_set_flag_all_selectmode */
-#define SET_EVE_FLAG(eve, flag) \
- if (eve->h==0) { \
- if (flag & SELECT && !(eve->f & SELECT)) { \
- ++selvert; \
- } \
- eve->f |= flag; \
- }
-
-#define SET_EED_FLAG(eed, flag) \
- if (eed->h==0) { \
- if (flag & SELECT && !(eed->f & SELECT)) { \
- ++seledge; \
- } \
- eed->f |= flag; \
- SET_EVE_FLAG(eed->v1, flag); \
- SET_EVE_FLAG(eed->v2, flag); \
- }
-
-
-/* ****************** stats *************** */
-
-int EM_nfaces_selected(EditMesh *em)
-{
- EditFace *efa;
- int count= 0;
-
- for (efa= em->faces.first; efa; efa= efa->next)
- if (efa->f & SELECT)
- count++;
-
- em->totfacesel= count;
-
- return count;
-}
-
-int EM_nedges_selected(EditMesh *em)
-{
- EditEdge *eed;
- int count= 0;
-
- for (eed= em->edges.first; eed; eed= eed->next)
- if(eed->f & SELECT)
- count++;
-
- em->totedgesel= count;
-
- return count;
-}
-
-int EM_nvertices_selected(EditMesh *em)
-{
- EditVert *eve;
- int count= 0;
-
- for (eve= em->verts.first; eve; eve= eve->next)
- if (eve->f & SELECT)
- count++;
-
- em->totvertsel= count;
-
- return count;
-}
-
-void EM_stats_update(EditMesh *em)
-{
-
- em->totvert= BLI_countlist(&em->verts);
- em->totedge= BLI_countlist(&em->edges);
- em->totface= BLI_countlist(&em->faces);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* ************************************** */
-
-/* this replaces the active flag used in uv/face mode */
-void EM_set_actFace(EditMesh *em, EditFace *efa)
-{
- em->act_face = efa;
-}
-
-EditFace *EM_get_actFace(EditMesh *em, int sloppy)
-{
- if (em->act_face) {
- return em->act_face;
- } else if (sloppy) {
- EditFace *efa= NULL;
- EditSelection *ese;
-
- ese = em->selected.last;
- for (; ese; ese=ese->prev){
- if(ese->type == EDITFACE) {
- efa = (EditFace *)ese->data;
-
- if (efa->h) efa= NULL;
- else break;
- }
- }
- if (efa==NULL) {
- for (efa= em->faces.first; efa; efa= efa->next) {
- if (efa->f & SELECT)
- break;
- }
- }
- return efa; /* can still be null */
- }
- return NULL;
-}
-
-int EM_get_actSelection(EditMesh *em, EditSelection *ese)
-{
- EditSelection *ese_last = em->selected.last;
- EditFace *efa = EM_get_actFace(em, 0);
-
- ese->next = ese->prev = NULL;
-
- if (ese_last) {
- if (ese_last->type == EDITFACE) { /* if there is an active face, use it over the last selected face */
- if (efa) {
- ese->data = (void *)efa;
- } else {
- ese->data = ese_last->data;
- }
- ese->type = EDITFACE;
- } else {
- ese->data = ese_last->data;
- ese->type = ese_last->type;
- }
- } else if (efa) { /* no */
- ese->data = (void *)efa;
- ese->type = EDITFACE;
- } else {
- ese->data = NULL;
- return 0;
- }
- return 1;
-}
-
-/* ********* Selection History ************ */
-static int EM_check_selection(EditMesh *em, void *data)
-{
- EditSelection *ese;
-
- for(ese = em->selected.first; ese; ese = ese->next){
- if(ese->data == data) return 1;
- }
-
- return 0;
-}
-
-void EM_remove_selection(EditMesh *em, void *data, int UNUSED(type))
-{
- EditSelection *ese;
- for(ese=em->selected.first; ese; ese = ese->next){
- if(ese->data == data){
- BLI_freelinkN(&(em->selected),ese);
- break;
- }
- }
-}
-
-void EM_store_selection(EditMesh *em, void *data, int type)
-{
- EditSelection *ese;
- if(!EM_check_selection(em, data)){
- ese = (EditSelection*) MEM_callocN( sizeof(EditSelection), "Edit Selection");
- ese->type = type;
- ese->data = data;
- BLI_addtail(&(em->selected),ese);
- }
-}
-
-void EM_validate_selections(EditMesh *em)
-{
- EditSelection *ese, *nextese;
-
- ese = em->selected.first;
-
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITVERT && !(((EditVert*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- else if(ese->type == EDITEDGE && !(((EditEdge*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- else if(ese->type == EDITFACE && !(((EditFace*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
-}
-
-static void EM_strip_selections(EditMesh *em)
-{
- EditSelection *ese, *nextese;
- if(!(em->selectmode & SCE_SELECT_VERTEX)){
- ese = em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITVERT) BLI_freelinkN(&(em->selected),ese);
- ese = nextese;
- }
- }
- if(!(em->selectmode & SCE_SELECT_EDGE)){
- ese=em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITEDGE) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
- }
- if(!(em->selectmode & SCE_SELECT_FACE)){
- ese=em->selected.first;
- while(ese){
- nextese = ese->next;
- if(ese->type == EDITFACE) BLI_freelinkN(&(em->selected), ese);
- ese = nextese;
- }
- }
-}
-
-/* generic way to get data from an EditSelection type
-These functions were written to be used by the Modifier widget when in Rotate about active mode,
-but can be used anywhere.
-EM_editselection_center
-EM_editselection_normal
-EM_editselection_plane
-*/
-void EM_editselection_center(float *center, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- copy_v3_v3(center, eve->co);
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
- add_v3_v3v3(center, eed->v1->co, eed->v2->co);
- mul_v3_fl(center, 0.5);
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- copy_v3_v3(center, efa->cent);
- }
-}
-
-void EM_editselection_normal(float *normal, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- copy_v3_v3(normal, eve->no);
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
- float plane[3]; /* need a plane to correct the normal */
- float vec[3]; /* temp vec storage */
-
- add_v3_v3v3(normal, eed->v1->no, eed->v2->no);
- sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
-
- /* the 2 vertex normals will be close but not at rightangles to the edge
- for rotate about edge we want them to be at right angles, so we need to
- do some extra colculation to correct the vert normals,
- we need the plane for this */
- cross_v3_v3v3(vec, normal, plane);
- cross_v3_v3v3(normal, plane, vec);
- normalize_v3(normal);
-
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- copy_v3_v3(normal, efa->n);
- }
-}
-
-/* Calculate a plane that is rightangles to the edge/vert/faces normal
-also make the plane run allong an axis that is related to the geometry,
-because this is used for the manipulators Y axis.*/
-void EM_editselection_plane(float *plane, EditSelection *ese)
-{
- if (ese->type==EDITVERT) {
- EditVert *eve= ese->data;
- float vec[3]={0,0,0};
-
- if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
- EM_editselection_center(vec, ese->prev);
- sub_v3_v3v3(plane, vec, eve->co);
- } else {
- /* make a fake plane thats at rightangles to the normal
- we cant make a crossvec from a vec thats the same as the vec
- unlikely but possible, so make sure if the normal is (0,0,1)
- that vec isnt the same or in the same direction even.*/
- if (eve->no[0]<0.5f) vec[0]=1;
- else if (eve->no[1]<0.5f) vec[1]=1;
- else vec[2]=1;
- cross_v3_v3v3(plane, eve->no, vec);
- }
- } else if (ese->type==EDITEDGE) {
- EditEdge *eed= ese->data;
-
- /*the plane is simple, it runs allong the edge
- however selecting different edges can swap the direction of the y axis.
- this makes it less likely for the y axis of the manipulator
- (running along the edge).. to flip less often.
- at least its more predictable */
- if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
- sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
- else
- sub_v3_v3v3(plane, eed->v1->co, eed->v2->co);
-
- } else if (ese->type==EDITFACE) {
- EditFace *efa= ese->data;
- float vec[3];
- if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
- float vecA[3], vecB[3];
- sub_v3_v3v3(vecA, efa->v4->co, efa->v3->co);
- sub_v3_v3v3(vecB, efa->v1->co, efa->v2->co);
- add_v3_v3v3(plane, vecA, vecB);
-
- sub_v3_v3v3(vecA, efa->v1->co, efa->v4->co);
- sub_v3_v3v3(vecB, efa->v2->co, efa->v3->co);
- add_v3_v3v3(vec, vecA, vecB);
- /*use the biggest edge length*/
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
- } else {
- /*start with v1-2 */
- sub_v3_v3v3(plane, efa->v1->co, efa->v2->co);
-
- /*test the edge between v2-3, use if longer */
- sub_v3_v3v3(vec, efa->v2->co, efa->v3->co);
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
-
- /*test the edge between v1-3, use if longer */
- sub_v3_v3v3(vec, efa->v3->co, efa->v1->co);
- if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
- copy_v3_v3(plane, vec);
- }
- }
- normalize_v3(plane);
-}
-
-
-
-void EM_select_face(EditFace *efa, int sel)
-{
- if(sel) {
- efa->f |= SELECT;
- efa->e1->f |= SELECT;
- efa->e2->f |= SELECT;
- efa->e3->f |= SELECT;
- if(efa->e4) efa->e4->f |= SELECT;
- efa->v1->f |= SELECT;
- efa->v2->f |= SELECT;
- efa->v3->f |= SELECT;
- if(efa->v4) efa->v4->f |= SELECT;
- }
- else {
- efa->f &= ~SELECT;
- efa->e1->f &= ~SELECT;
- efa->e2->f &= ~SELECT;
- efa->e3->f &= ~SELECT;
- if(efa->e4) efa->e4->f &= ~SELECT;
- efa->v1->f &= ~SELECT;
- efa->v2->f &= ~SELECT;
- efa->v3->f &= ~SELECT;
- if(efa->v4) efa->v4->f &= ~SELECT;
- }
-}
-
-void EM_select_edge(EditEdge *eed, int sel)
-{
- if(sel) {
- eed->f |= SELECT;
- eed->v1->f |= SELECT;
- eed->v2->f |= SELECT;
- }
- else {
- eed->f &= ~SELECT;
- eed->v1->f &= ~SELECT;
- eed->v2->f &= ~SELECT;
- }
-}
-
-void EM_select_face_fgon(EditMesh *em, EditFace *efa, int val)
-{
- short index=0;
-
- if(efa->fgonf==0) EM_select_face(efa, val);
- else {
- if(efa->e1->fgoni) index= efa->e1->fgoni;
- if(efa->e2->fgoni) index= efa->e2->fgoni;
- if(efa->e3->fgoni) index= efa->e3->fgoni;
- if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni;
-
- if((index==0) && (G.f & G_DEBUG))printf("wrong fgon select\n");
-
- // select all ngon faces with index
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->fgonf) {
- if(efa->e1->fgoni==index || efa->e2->fgoni==index ||
- efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) {
- EM_select_face(efa, val);
- }
- }
- }
- }
-}
-
-
-/* only vertices */
-int faceselectedOR(EditFace *efa, int flag)
-{
- if ((efa->v1->f | efa->v2->f | efa->v3->f | (efa->v4?efa->v4->f:0))&flag) {
- return 1;
- } else {
- return 0;
- }
-}
-
-// replace with (efa->f & SELECT)
-int faceselectedAND(EditFace *efa, int flag)
-{
- if ((efa->v1->f & efa->v2->f & efa->v3->f & (efa->v4?efa->v4->f:flag))&flag) {
- return 1;
- } else {
- return 0;
- }
-}
-
-void EM_clear_flag_all(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for (eve= em->verts.first; eve; eve= eve->next) eve->f &= ~flag;
- for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~flag;
- for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~flag;
-
- if(flag & SELECT) {
- BLI_freelistN(&(em->selected));
- em->totvertsel= em->totedgesel= em->totfacesel= 0;
- }
-}
-
-void EM_set_flag_all(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
- for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
- for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
-
- if(flag & SELECT) {
- em->totvertsel= em->totvert;
- em->totedgesel= em->totedge;
- em->totfacesel= em->totface;
- }
-}
-
-void EM_set_flag_all_selectmode(EditMesh *em, int flag)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- int selvert= 0, seledge= 0, selface= 0;
-
- if (em->selectmode & SCE_SELECT_VERTEX) {
- /* If vertex select mode enabled all the data could be affected */
- for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
- for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
- for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
-
- if (flag & SELECT) {
- selvert= em->totvert;
- seledge= em->totedge;
- selface= em->totface;
- }
- } else if (em->selectmode & SCE_SELECT_EDGE) {
- /* If edge select mode is enabled we should affect on all edges, faces and */
- /* vertices, connected to them */
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- SET_EED_FLAG(eed, flag)
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- efa->f |= flag;
-
- if (flag & SELECT) {
- ++selface;
- }
- }
- }
- } else if (em->selectmode & SCE_SELECT_FACE) {
- /* No vertex and edge select mode, only face selection */
- /* In face select mode only edges and vertices belongs to faces should be affected */
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- efa->f |= flag;
- SET_EED_FLAG(efa->e1, flag);
- SET_EED_FLAG(efa->e2, flag);
- SET_EED_FLAG(efa->e3, flag);
-
- if (efa->e4) {
- SET_EED_FLAG(efa->e4, flag);
- }
-
- if (flag & SELECT) {
- ++selface;
- }
- }
- }
- }
-
- if(flag & SELECT) {
- em->totvertsel= selvert;
- em->totedgesel= seledge;
- em->totfacesel= selface;
- }
- }
-/* flush for changes in vertices only */
-void EM_deselect_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT);
- else eed->f &= ~SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT );
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT );
- else efa->f &= ~SELECT;
- }
- }
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-
-/* flush selection to edges & faces */
-
-/* this only based on coherent selected vertices, for example when adding new
- objects. call clear_flag_all() before you select vertices to be sure it ends OK!
-
-*/
-
-void EM_select_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ) efa->f |= SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ) efa->f |= SELECT;
- }
- }
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* when vertices or edges can be selected, also make fgon consistent */
-static void check_fgons_selection(EditMesh *em)
-{
- EditFace *efa, *efan;
- EditEdge *eed;
- ListBase *lbar;
- int sel, desel, index, totfgon= 0;
-
- /* count amount of fgons */
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->fgoni>totfgon) totfgon= eed->fgoni;
-
- if(totfgon==0) return;
-
- lbar= MEM_callocN((totfgon+1)*sizeof(ListBase), "listbase array");
-
- /* put all fgons in lbar */
- for(efa= em->faces.first; efa; efa= efan) {
- efan= efa->next;
- index= efa->e1->fgoni;
- if(index==0) index= efa->e2->fgoni;
- if(index==0) index= efa->e3->fgoni;
- if(index==0 && efa->e4) index= efa->e4->fgoni;
- if(index) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&lbar[index], efa);
- }
- }
-
- /* now check the fgons */
- for(index=1; index<=totfgon; index++) {
- /* we count on vertices/faces/edges being set OK, so we only have to set ngon itself */
- sel= desel= 0;
- for(efa= lbar[index].first; efa; efa= efa->next) {
- if(efa->e1->fgoni==0) {
- if(efa->e1->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e2->fgoni==0) {
- if(efa->e2->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e3->fgoni==0) {
- if(efa->e3->f & SELECT) sel++;
- else desel++;
- }
- if(efa->e4 && efa->e4->fgoni==0) {
- if(efa->e4->f & SELECT) sel++;
- else desel++;
- }
-
- if(sel && desel) break;
- }
-
- if(sel && desel) sel= 0;
- else if(sel) sel= 1;
- else sel= 0;
-
- /* select/deselect and put back */
- for(efa= lbar[index].first; efa; efa= efa->next) {
- if(sel) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- BLI_movelisttolist(&em->faces, &lbar[index]);
- }
-
- MEM_freeN(lbar);
-}
-
-
-/* flush to edges & faces */
-
-/* based on select mode it selects edges/faces
- assumed is that verts/edges/faces were properly selected themselves
- with the calls above
-*/
-
-void EM_selectmode_flush(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- // flush to edges & faces
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
- else eed->f &= ~SELECT;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- }
- }
- // flush to faces
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4) {
- if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT) efa->f |= SELECT;
- else efa->f &= ~SELECT;
- }
- }
- }
- // make sure selected faces have selected edges too, for extrude (hack?)
- else if(em->selectmode & SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) EM_select_face(efa, 1);
- }
- }
-
- if(!(em->selectmode & SCE_SELECT_FACE))
- check_fgons_selection(em);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-void EM_convertsel(EditMesh *em, short oldmode, short selectmode)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- /*clear flags*/
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0;
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0;
- for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0;
-
- /*have to find out what the selectionmode was previously*/
- if(oldmode == SCE_SELECT_VERTEX) {
- if(selectmode == SCE_SELECT_EDGE){
- /*select all edges associated with every selected vertex*/
- for(eed= em->edges.first; eed; eed= eed->next){
- if(eed->v1->f&SELECT) eed->f1 = 1;
- else if(eed->v2->f&SELECT) eed->f1 = 1;
- }
-
- for(eed= em->edges.first; eed; eed= eed->next){
- if(eed->f1 == 1) EM_select_edge(eed,1);
- }
- }
- else if(selectmode == SCE_SELECT_FACE){
- /*select all faces associated with every selected vertex*/
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->v1->f&SELECT) efa->f1 = 1;
- else if(efa->v2->f&SELECT) efa->f1 = 1;
- else if(efa->v3->f&SELECT) efa->f1 = 1;
- else{
- if(efa->v4){
- if(efa->v4->f&SELECT) efa->f1 =1;
- }
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->f1 == 1) EM_select_face(efa,1);
- }
- }
- }
-
- if(oldmode == SCE_SELECT_EDGE){
- if(selectmode == SCE_SELECT_FACE){
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->e1->f&SELECT) efa->f1 = 1;
- else if(efa->e2->f&SELECT) efa->f1 = 1;
- else if(efa->e3->f&SELECT) efa->f1 = 1;
- else if(efa->e4){
- if(efa->e4->f&SELECT) efa->f1 = 1;
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next){
- if(efa->f1 == 1) EM_select_face(efa,1);
- }
- }
- }
-
- check_fgons_selection(em);
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-void EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit)
-{
- scene->toolsettings->selectmode= get_mesh(obedit)->edit_mesh->selectmode;
-}
-
-/* when switching select mode, makes sure selection is consistent for editing */
-/* also for paranoia checks to make sure edge or face mode works */
-void EM_selectmode_set(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- EM_strip_selections(em); /*strip EditSelections from em->selected that are not relevant to new mode*/
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- /* vertices -> edges -> faces */
- for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~SELECT;
- for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~SELECT;
-
- EM_select_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- /* deselect vertices, and select again based on edge select */
- for(eve= em->verts.first; eve; eve= eve->next) eve->f &= ~SELECT;
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->f & SELECT) EM_select_edge(eed, 1);
- /* selects faces based on edge status */
- EM_selectmode_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_FACE) {
- /* deselect eges, and select again based on face select */
- for(eed= em->edges.first; eed; eed= eed->next) EM_select_edge(eed, 0);
-
- for(efa= em->faces.first; efa; efa= efa->next)
- if(efa->f & SELECT) EM_select_face(efa, 1);
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* paranoia check, actually only for entering editmode. rule:
-- vertex hidden, always means edge is hidden too
-- edge hidden, always means face is hidden too
-- face hidden, dont change anything
-*/
-void EM_hide_reset(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->v1->h || eed->v2->h) eed->h |= 1;
-
- for(efa= em->faces.first; efa; efa= efa->next)
- if((efa->e1->h & 1) || (efa->e2->h & 1) || (efa->e3->h & 1) || (efa->e4 && (efa->e4->h & 1)))
- efa->h= 1;
-
-}
-
-void EM_data_interp_from_verts(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *eve, float fac)
-{
- void *src[2];
- float w[2];
-
- if (v1->data && v2->data) {
- src[0]= v1->data;
- src[1]= v2->data;
- w[0] = 1.0f-fac;
- w[1] = fac;
-
- CustomData_em_interp(&em->vdata, src, w, NULL, 2, eve->data);
- }
-}
-
-void EM_data_interp_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4)
-{
- float w[2][4][4];
- void *src[2];
- int count = (efa2)? 2: 1;
-
- if (efa1->data) {
- /* set weights for copying from corners directly to other corners */
- memset(w, 0, sizeof(w));
-
- w[i1/4][0][i1%4]= 1.0f;
- w[i2/4][1][i2%4]= 1.0f;
- w[i3/4][2][i3%4]= 1.0f;
- if (i4 != -1)
- w[i4/4][3][i4%4]= 1.0f;
-
- src[0]= efa1->data;
- src[1]= (efa2)? efa2->data: NULL;
-
- CustomData_em_interp(&em->fdata, src, NULL, (float*)w, count, efan->data);
- }
-}
-
-EditFace *EM_face_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, int i1, int i2, int i3, int i4)
-{
- EditFace *efan;
- EditVert **v[2];
-
- v[0]= &efa1->v1;
- v[1]= (efa2)? &efa2->v1: NULL;
-
- efan= addfacelist(em, v[i1/4][i1%4], v[i2/4][i2%4], v[i3/4][i3%4],
- (i4 == -1)? 0: v[i4/4][i4%4], efa1, NULL);
-
- EM_data_interp_from_faces(em, efa1, efa2, efan, i1, i2, i3, i4);
-
- return efan;
-}
-
-static void update_data_blocks(EditMesh *em, CustomData *olddata, CustomData *data)
-{
- EditFace *efa;
- EditVert *eve;
- void *block;
-
- if (data == &em->vdata) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- block = NULL;
- CustomData_em_set_default(data, &block);
- CustomData_em_copy_data(olddata, data, eve->data, &block);
- CustomData_em_free_block(olddata, &eve->data);
- eve->data= block;
- }
- }
- else if (data == &em->fdata) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- block = NULL;
- CustomData_em_set_default(data, &block);
- CustomData_em_copy_data(olddata, data, efa->data, &block);
- CustomData_em_free_block(olddata, &efa->data);
- efa->data= block;
- }
- }
-}
-
-void EM_add_data_layer(EditMesh *em, CustomData *data, int type, const char *name)
-{
- CustomData olddata;
-
- olddata= *data;
- olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
- CustomData_add_layer_named(data, type, CD_CALLOC, NULL, 0, name);
-
- update_data_blocks(em, &olddata, data);
- if (olddata.layers) MEM_freeN(olddata.layers);
-}
-
-void EM_free_data_layer(EditMesh *em, CustomData *data, int type)
-{
- CustomData olddata;
-
- olddata= *data;
- olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
- CustomData_free_layer_active(data, type, 0);
-
- update_data_blocks(em, &olddata, data);
- if (olddata.layers) MEM_freeN(olddata.layers);
-}
-
-/* ******** EXTRUDE ********* */
-
-static void add_normal_aligned(float *nor, float *add)
-{
- if( INPR(nor, add) < -0.9999f)
- sub_v3_v3(nor, add);
- else
- add_v3_v3(nor, add);
-}
-
-static void set_edge_directions_f2(EditMesh *em, int val)
-{
- EditFace *efa;
- int do_all= 1;
-
- /* edge directions are used for extrude, to detect direction of edges that make new faces */
- /* we have set 'f2' flags in edges that need to get a direction set (e.g. get new face) */
- /* the val argument differs... so we need it as arg */
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- do_all= 0;
- if(efa->e1->f2<val) {
- if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
- else efa->e1->dir= 1;
- }
- if(efa->e2->f2<val) {
- if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
- else efa->e2->dir= 1;
- }
- if(efa->e3->f2<val) {
- if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
- else efa->e3->dir= 1;
- }
- if(efa->e4 && efa->e4->f2<val) {
- if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
- else efa->e4->dir= 1;
- }
- }
- }
- /* ok, no faces done... then we at least set it for exterior edges */
- if(do_all) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
- else efa->e1->dir= 1;
- if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
- else efa->e2->dir= 1;
- if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
- else efa->e3->dir= 1;
- if(efa->e4) {
- if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
- else efa->e4->dir= 1;
- }
- }
- }
-}
-
-/* individual face extrude */
-/* will use vertex normals for extrusion directions, so *nor is unaffected */
-short extrudeflag_face_indiv(EditMesh *em, short UNUSED(flag), float *UNUSED(nor))
-{
- EditVert *eve, *v1, *v2, *v3, *v4;
- EditEdge *eed;
- EditFace *efa, *nextfa;
-
- if(em==NULL) return 0;
-
- /* selected edges with 1 or more selected face become faces */
- /* selected faces each makes new faces */
- /* always remove old faces, keeps volumes manifold */
- /* select the new extrusion, deselect old */
-
- /* step 1; init, count faces in edges */
- recalc_editnormals(em);
-
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f2= 0; // amount of unselected faces
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT);
- else {
- efa->e1->f2++;
- efa->e2->f2++;
- efa->e3->f2++;
- if(efa->e4) efa->e4->f2++;
- }
- }
-
- /* step 2: make new faces from faces */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- v1= addvertlist(em, efa->v1->co, efa->v1);
- v2= addvertlist(em, efa->v2->co, efa->v2);
- v3= addvertlist(em, efa->v3->co, efa->v3);
-
- v1->f1= v2->f1= v3->f1= 1;
- VECCOPY(v1->no, efa->n);
- VECCOPY(v2->no, efa->n);
- VECCOPY(v3->no, efa->n);
- if(efa->v4) {
- v4= addvertlist(em, efa->v4->co, efa->v4);
- v4->f1= 1;
- VECCOPY(v4->no, efa->n);
- }
- else v4= NULL;
-
- /* side faces, clockwise */
- addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
- addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
- if(efa->v4) {
- addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
- addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
- }
- else {
- addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
- }
- /* top face */
- addfacelist(em, v1, v2, v3, v4, efa, NULL);
- }
- }
-
- /* step 3: remove old faces */
- efa= em->faces.first;
- while(efa) {
- nextfa= efa->next;
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextfa;
- }
-
- /* step 4: redo selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1) eve->f |= SELECT;
- }
-
- EM_select_flush(em);
-
- return 'n';
-}
-
-
-/* extrudes individual edges */
-/* nor is filled with constraint vector */
-short extrudeflag_edges_indiv(EditMesh *em, short flag, float *nor)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.f = NULL;
- eed->f2= ((eed->f & flag)!=0);
- }
-
- set_edge_directions_f2(em, 2);
-
- /* sample for next loop */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
- }
- /* make the faces */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & flag) {
- if(eed->v1->tmp.v == NULL)
- eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
- if(eed->v2->tmp.v == NULL)
- eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
-
- if(eed->dir==1)
- addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
-
- /* for transform */
- if(eed->tmp.f) {
- efa = eed->tmp.f;
- if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
- }
- }
- }
- normalize_v3(nor);
-
- /* set correct selection */
- EM_clear_flag_all(em, SELECT);
- for(eve= em->verts.last; eve; eve= eve->prev) {
- if(eve->tmp.v) {
- eve->tmp.v->f |= flag;
- }
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
- }
-
- if(is_zero_v3(nor)) return 'g'; // g is grab
- return 'n'; // n is for normal constraint
-}
-
-/* extrudes individual vertices */
-short extrudeflag_verts_indiv(EditMesh *em, short flag, float *UNUSED(nor))
-{
- EditVert *eve;
-
- /* make the edges */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & flag) {
- eve->tmp.v = addvertlist(em, eve->co, eve);
- addedgelist(em, eve, eve->tmp.v, NULL);
- }
- else eve->tmp.v = NULL;
- }
-
- /* set correct selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.last; eve; eve= eve->prev)
- if (eve->tmp.v)
- eve->tmp.v->f |= flag;
-
- return 'g'; // g is grab
-}
-
-
-/* this is actually a recode of extrudeflag(), using proper edge/face select */
-/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */
-static short extrudeflag_edge(Object *obedit, EditMesh *em, short UNUSED(flag), float *nor, int all)
-{
- /* all select edges/faces: extrude */
- /* old select is cleared, in new ones it is set */
- EditVert *eve, *nextve;
- EditEdge *eed, *nexted;
- EditFace *efa, *nextfa, *efan;
- short del_old= 0;
- ModifierData *md;
-
- if(em==NULL) return 0;
-
- md = obedit->modifiers.first;
-
- /* selected edges with 0 or 1 selected face become faces */
- /* selected faces generate new faces */
-
- /* if *one* selected face has edge with unselected face; remove old selected faces */
-
- /* if selected edge is not used anymore; remove */
- /* if selected vertex is not used anymore: remove */
-
- /* select the new extrusion, deselect old */
-
-
- /* step 1; init, count faces in edges */
- recalc_editnormals(em);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.v = NULL;
- eve->f1= 0;
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0; // amount of unselected faces
- eed->f2= 0; // amount of selected faces
- if(eed->f & SELECT) {
- eed->v1->f1= 1; // we call this 'selected vertex' now
- eed->v2->f1= 1;
- }
- eed->tmp.f = NULL; // here we tuck face pointer, as sample
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- efa->e1->f2++;
- efa->e2->f2++;
- efa->e3->f2++;
- if(efa->e4) efa->e4->f2++;
-
- // sample for next loop
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
- }
- else {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* If a mirror modifier with clipping is on, we need to adjust some
- * of the cases above to handle edges on the line of symmetry.
- */
- for (; md; md=md->next) {
- if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obedit->obmat, imtx);
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2 == 1) {
- float co1[3], co2[3];
-
- copy_v3_v3(co1, eed->v1->co);
- copy_v3_v3(co2, eed->v2->co);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, co1);
- mul_m4_v3(mtx, co2);
- }
-
- if (mmd->flag & MOD_MIR_AXIS_X)
- if ( (fabsf(co1[0]) < mmd->tolerance) &&
- (fabsf(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabsf(co1[1]) < mmd->tolerance) &&
- (fabsf(co2[1]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabsf(co1[2]) < mmd->tolerance) &&
- (fabsf(co2[2]) < mmd->tolerance) )
- ++eed->f2;
- }
- }
- }
- }
- }
-
- set_edge_directions_f2(em, 2);
-
- /* step 1.5: if *one* selected face has edge with unselected face; remove old selected faces */
- if(all == 0) {
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1 || (efa->e4 && efa->e4->f1)) {
- del_old= 1;
- break;
- }
- }
- }
- }
-
- /* step 2: make new faces from edges */
- for(eed= em->edges.last; eed; eed= eed->prev) {
- if(eed->f & SELECT) {
- if(eed->f2<2) {
- if(eed->v1->tmp.v == NULL)
- eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
- if(eed->v2->tmp.v == NULL)
- eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
-
- /* if del_old, the preferred normal direction is exact
- * opposite as for keep old faces
- */
- if(eed->dir!=del_old)
- addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
- }
- }
- }
-
- /* step 3: make new faces from faces */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & SELECT) {
- if (efa->v1->tmp.v == NULL)
- efa->v1->tmp.v = addvertlist(em, efa->v1->co, efa->v1);
- if (efa->v2->tmp.v ==NULL)
- efa->v2->tmp.v = addvertlist(em, efa->v2->co, efa->v2);
- if (efa->v3->tmp.v ==NULL)
- efa->v3->tmp.v = addvertlist(em, efa->v3->co, efa->v3);
- if (efa->v4 && (efa->v4->tmp.v == NULL))
- efa->v4->tmp.v = addvertlist(em, efa->v4->co, efa->v4);
-
- if(efa->v4)
- efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v,
- efa->v3->tmp.v, efa->v4->tmp.v, efa, efa);
- else
- efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v,
- efa->v3->tmp.v, NULL, efa, efa);
-
- /* keep old faces means flipping normal, reverse vertex order gives bad UV's & VCols etc - [#25260] */
- if(del_old==0) {
- flipface(em, efan);
- }
-
- if (em->act_face == efa) {
- em->act_face = efan;
- }
-
- /* for transform */
- add_normal_aligned(nor, efa->n);
- }
- }
-
- if(del_old) {
-
- /* step 4: remove old faces, if del_old */
- efa= em->faces.first;
- while(efa) {
- nextfa= efa->next;
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextfa;
- }
-
-
- /* step 5: remove selected unused edges */
- /* start tagging again */
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1=0;
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->f1= 1;
- efa->e2->f1= 1;
- efa->e3->f1= 1;
- if(efa->e4) efa->e4->f1= 1;
- }
- /* remove */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- if(eed->f1==0) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- }
- eed= nexted;
- }
-
- /* step 6: remove selected unused vertices */
- for(eed= em->edges.first; eed; eed= eed->next)
- eed->v1->f1= eed->v2->f1= 0;
-
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f1) {
- // hack... but we need it for step 7, redoing selection
- if(eve->tmp.v) eve->tmp.v->tmp.v= eve->tmp.v;
-
- BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
- }
-
- normalize_v3(nor); // translation normal grab
-
- /* step 7: redo selection */
- EM_clear_flag_all(em, SELECT);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->tmp.v) {
- eve->tmp.v->f |= SELECT;
- }
- }
-
- EM_select_flush(em);
-
- if(is_zero_v3(nor)) return 'g'; // grab
- return 'n'; // normal constraint
-}
-
-short extrudeflag_vert(Object *obedit, EditMesh *em, short flag, float *nor, int all)
-{
- /* all verts/edges/faces with (f & 'flag'): extrude */
- /* from old verts, 'flag' is cleared, in new ones it is set */
- EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
- EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
- EditFace *efa, *efa2, *nextvl;
- short sel=0, del_old= 0, is_face_sel=0;
- ModifierData *md;
-
- if(em==NULL) return 0;
-
- md = obedit->modifiers.first;
-
- /* clear vert flag f1, we use this to detect a loose selected vertice */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) eve->f1= 1;
- else eve->f1= 0;
- eve= eve->next;
- }
- /* clear edges counter flag, if selected we set it at 1 */
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & flag) && (eed->v2->f & flag) ) {
- eed->f2= 1;
- eed->v1->f1= 0;
- eed->v2->f1= 0;
- }
- else eed->f2= 0;
-
- eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
- eed->tmp.f = NULL; /* used as sample */
-
- eed= eed->next;
- }
-
- /* we set a flag in all selected faces, and increase the associated edge counters */
-
- efa= em->faces.first;
- while(efa) {
- efa->f1= 0;
-
- if(faceselectedAND(efa, flag)) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- if(e1->f2 < 3) e1->f2++;
- if(e2->f2 < 3) e2->f2++;
- if(e3->f2 < 3) e3->f2++;
- if(e4 && e4->f2 < 3) e4->f2++;
-
- efa->f1= 1;
- is_face_sel= 1; // for del_old
- }
- else if(faceselectedOR(efa, flag)) {
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- e4= efa->e4;
-
- if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2;
- if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2;
- if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2;
- if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2;
- }
-
- // sample for next loop
- efa->e1->tmp.f = efa;
- efa->e2->tmp.f = efa;
- efa->e3->tmp.f = efa;
- if(efa->e4) efa->e4->tmp.f = efa;
-
- efa= efa->next;
- }
-
- set_edge_directions_f2(em, 3);
-
- /* the current state now is:
- eve->f1==1: loose selected vertex
-
- eed->f2==0 : edge is not selected, no extrude
- eed->f2==1 : edge selected, is not part of a face, extrude
- eed->f2==2 : edge selected, is part of 1 face, extrude
- eed->f2==3 : edge selected, is part of more faces, no extrude
-
- eed->f1==0: new edge
- eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove
- eed->f1==2: edge selected, part of a partially selected face
-
- efa->f1==1 : duplicate this face
- */
-
- /* If a mirror modifier with clipping is on, we need to adjust some
- * of the cases above to handle edges on the line of symmetry.
- */
- for (; md; md=md->next) {
- if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, obedit->obmat, imtx);
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2 == 2) {
- float co1[3], co2[3];
-
- copy_v3_v3(co1, eed->v1->co);
- copy_v3_v3(co2, eed->v2->co);
-
- if (mmd->mirror_ob) {
- mul_m4_v3(mtx, co1);
- mul_m4_v3(mtx, co2);
- }
-
- if (mmd->flag & MOD_MIR_AXIS_X)
- if ( (fabsf(co1[0]) < mmd->tolerance) &&
- (fabsf(co2[0]) < mmd->tolerance) )
- ++eed->f2;
-
- if (mmd->flag & MOD_MIR_AXIS_Y)
- if ( (fabsf(co1[1]) < mmd->tolerance) &&
- (fabsf(co2[1]) < mmd->tolerance) )
- ++eed->f2;
- if (mmd->flag & MOD_MIR_AXIS_Z)
- if ( (fabsf(co1[2]) < mmd->tolerance) &&
- (fabsf(co2[2]) < mmd->tolerance) )
- ++eed->f2;
- }
- }
- }
- }
- }
-
- /* copy all selected vertices, */
- /* write pointer to new vert in old struct at eve->tmp.v */
- eve= em->verts.last;
- while(eve) {
- eve->f &= ~128; /* clear, for later test for loose verts */
- if(eve->f & flag) {
- sel= 1;
- v1= addvertlist(em, 0, NULL);
-
- VECCOPY(v1->co, eve->co);
- VECCOPY(v1->no, eve->no);
- v1->f= eve->f;
- eve->f &= ~flag;
- eve->tmp.v = v1;
- }
- else eve->tmp.v = NULL;
- eve= eve->prev;
- }
-
- if(sel==0) return 0;
-
- /* all edges with eed->f2==1 or eed->f2==2 become faces */
-
- /* if del_old==1 then extrude is in partial geometry, to keep it manifold.
- verts with f1==0 and (eve->f & 128)==0) are removed
- edges with eed->f2>2 are removed
- faces with efa->f1 are removed
- if del_old==0 the extrude creates a volume.
- */
-
- /* find if we delete old faces */
- if(is_face_sel && all==0) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if( (eed->f2==1 || eed->f2==2) ) {
- if(eed->f1==2) {
- del_old= 1;
- break;
- }
- }
- }
- }
-
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
- if( eed->f2<3) {
- eed->v1->f |= 128; /* = no loose vert! */
- eed->v2->f |= 128;
- }
- if( (eed->f2==1 || eed->f2==2) ) {
-
- /* if del_old, the preferred normal direction is exact opposite as for keep old faces */
- if(eed->dir != del_old)
- efa2 = addfacelist(em, eed->v1, eed->v2,
- eed->v2->tmp.v, eed->v1->tmp.v,
- eed->tmp.f, NULL);
- else
- efa2 = addfacelist(em, eed->v2, eed->v1,
- eed->v1->tmp.v, eed->v2->tmp.v,
- eed->tmp.f, NULL);
-
- /* Needs smarter adaption of existing creases.
- * If addedgelist is used, make sure seams are set to 0 on these
- * new edges, since we do not want to add any seams on extrusion.
- */
- efa2->e1->crease= eed->crease;
- efa2->e2->crease= eed->crease;
- efa2->e3->crease= eed->crease;
- if(efa2->e4) efa2->e4->crease= eed->crease;
- }
-
- eed= nexted;
- }
-
- /* duplicate faces, if necessary remove old ones */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f1 & 1) {
-
- v1 = efa->v1->tmp.v;
- v2 = efa->v2->tmp.v;
- v3 = efa->v3->tmp.v;
- if(efa->v4)
- v4 = efa->v4->tmp.v;
- else
- v4= NULL;
-
- /* hmm .. not sure about edges here */
- if(del_old==0) // if we keep old, we flip normal
- efa2= addfacelist(em, v3, v2, v1, v4, efa, efa);
- else
- efa2= addfacelist(em, v1, v2, v3, v4, efa, efa);
-
- /* for transform */
- add_normal_aligned(nor, efa->n);
-
- if(del_old) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- }
- efa= nextvl;
- }
- /* delete edges after copying edges above! */
- if(del_old) {
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f2==3 && eed->f1==1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- }
-
- normalize_v3(nor); // for grab
-
- /* for all vertices with eve->tmp.v!=0
- if eve->f1==1: make edge
- if flag!=128 : if del_old==1: remove
- */
- eve= em->verts.last;
- while(eve) {
- nextve= eve->prev;
- if(eve->tmp.v) {
- if(eve->f1==1) addedgelist(em, eve, eve->tmp.v, NULL);
- else if( (eve->f & 128)==0) {
- if(del_old) {
- BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
- eve= NULL;
- }
- }
- }
- if(eve) {
- eve->f &= ~128;
- }
- eve= nextve;
- }
- // since its vertex select mode now, it also deselects higher order
- EM_selectmode_flush(em);
-
- if(is_zero_v3(nor)) return 'g'; // g is grab, for correct undo print
- return 'n';
-}
-
-/* generic extrude */
-short extrudeflag(Object *obedit, EditMesh *em, short flag, float *nor, int all)
-{
- if(em->selectmode & SCE_SELECT_VERTEX)
- return extrudeflag_vert(obedit, em, flag, nor, all);
- else
- return extrudeflag_edge(obedit, em, flag, nor, all);
-
-}
-
-void rotateflag(EditMesh *em, short flag, float *cent, float rotmat[][3])
-{
- /* all verts with (flag & 'flag') rotate */
- EditVert *eve;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- eve->co[0]-=cent[0];
- eve->co[1]-=cent[1];
- eve->co[2]-=cent[2];
- mul_m3_v3(rotmat,eve->co);
- eve->co[0]+=cent[0];
- eve->co[1]+=cent[1];
- eve->co[2]+=cent[2];
- }
- eve= eve->next;
- }
-}
-
-void translateflag(EditMesh *em, short flag, float *vec)
-{
- /* all verts with (flag & 'flag') translate */
- EditVert *eve;
-
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- eve->co[0]+=vec[0];
- eve->co[1]+=vec[1];
- eve->co[2]+=vec[2];
- }
- eve= eve->next;
- }
-}
-
-/* helper call for below */
-static EditVert *adduplicate_vertex(EditMesh *em, EditVert *eve, int flag)
-{
- /* FIXME: copy deformation weight from eve ok here? */
- EditVert *v1= addvertlist(em, eve->co, eve);
-
- v1->f= eve->f;
- eve->f &= ~flag;
- eve->f|= 128;
-
- eve->tmp.v = v1;
-
- return v1;
-}
-
-/* old selection has flag 128 set, and flag 'flag' cleared
-new selection has flag 'flag' set */
-void adduplicateflag(EditMesh *em, int flag)
-{
- EditVert *eve, *v1, *v2, *v3, *v4;
- EditEdge *eed, *newed;
- EditFace *efa, *newfa, *act_efa = EM_get_actFace(em, 0);
-
- EM_clear_flag_all(em, 128);
- EM_selectmode_set(em); // paranoia check, selection now is consistent
-
- /* vertices first */
- for(eve= em->verts.last; eve; eve= eve->prev) {
-
- if(eve->f & flag)
- adduplicate_vertex(em, eve, flag);
- else
- eve->tmp.v = NULL;
- }
-
- /* copy edges, note that vertex selection can be independent of edge */
- for(eed= em->edges.last; eed; eed= eed->prev) {
- if( eed->f & flag ) {
- v1 = eed->v1->tmp.v;
- if(v1==NULL) v1= adduplicate_vertex(em, eed->v1, flag);
- v2 = eed->v2->tmp.v;
- if(v2==NULL) v2= adduplicate_vertex(em, eed->v2, flag);
-
- newed= addedgelist(em, v1, v2, eed);
-
- newed->f= eed->f;
- eed->f &= ~flag;
- eed->f |= 128;
- }
- }
-
- /* then duplicate faces, again create new vertices if needed */
- for(efa= em->faces.last; efa; efa= efa->prev) {
- if(efa->f & flag) {
- v1 = efa->v1->tmp.v;
- if(v1==NULL) v1= adduplicate_vertex(em, efa->v1, flag);
- v2 = efa->v2->tmp.v;
- if(v2==NULL) v2= adduplicate_vertex(em, efa->v2, flag);
- v3 = efa->v3->tmp.v;
- if(v3==NULL) v3= adduplicate_vertex(em, efa->v3, flag);
- if(efa->v4) {
- v4 = efa->v4->tmp.v;
- if(v4==NULL) v4= adduplicate_vertex(em, efa->v4, flag);
- }
- else v4= NULL;
-
- newfa= addfacelist(em, v1, v2, v3, v4, efa, efa);
-
- if (efa==act_efa) {
- EM_set_actFace(em, newfa);
- }
-
- newfa->f= efa->f;
- efa->f &= ~flag;
- efa->f |= 128;
- }
- }
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-}
-
-void delfaceflag(EditMesh *em, int flag)
-{
- /* delete all faces with 'flag', including loose edges and loose vertices */
- /* this is maybe a bit weird, but this function is used for 'split' and 'separate' */
- /* in remaining vertices/edges 'flag' is cleared */
- EditVert *eve,*nextve;
- EditEdge *eed, *nexted;
- EditFace *efa,*nextvl;
-
- /* to detect loose edges, we put f2 flag on 1 */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & flag) eed->f2= 1;
- else eed->f2= 0;
- }
-
- /* delete faces */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f & flag) {
-
- efa->e1->f2= 1;
- efa->e2->f2= 1;
- efa->e3->f2= 1;
- if(efa->e4) {
- efa->e4->f2= 1;
- }
-
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
-
- /* all remaining faces: make sure we keep the edges */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->f2= 0;
- efa->e2->f2= 0;
- efa->e3->f2= 0;
- if(efa->e4) {
- efa->e4->f2= 0;
- }
- }
-
- /* remove tagged edges, and clear remaining ones */
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- if(eed->f2==1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- else {
- eed->f &= ~flag;
- eed->v1->f &= ~flag;
- eed->v2->f &= ~flag;
- }
- eed= nexted;
- }
-
- /* vertices with 'flag' now are the loose ones, and will be removed */
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & flag) {
- BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
-
-}
-
-/* ********************* */
-#if 0
-static int check_vnormal_flip(float *n, float *vnorm)
-{
- float inp;
-
- inp= n[0]*vnorm[0]+n[1]*vnorm[1]+n[2]*vnorm[2];
-
- /* angles 90 degrees: dont flip */
- if(inp> -0.000001) return 0;
-
- return 1;
-}
-#endif
-
-
-
-/* does face centers too */
-void recalc_editnormals(EditMesh *em)
-{
- EditFace *efa;
- EditVert *eve;
-
- for(eve= em->verts.first; eve; eve=eve->next)
- zero_v3(eve->no);
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- float *n4= (efa->v4)? efa->v4->no: NULL;
- float *c4= (efa->v4)? efa->v4->co: NULL;
-
- if(efa->v4) {
- normal_quad_v3(efa->n, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- cent_quad_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- }
- else {
- normal_tri_v3(efa->n, efa->v1->co, efa->v2->co, efa->v3->co);
- cent_tri_v3(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
- }
-
- accumulate_vertex_normals(efa->v1->no, efa->v2->no, efa->v3->no, n4,
- efa->n, efa->v1->co, efa->v2->co, efa->v3->co, c4);
- }
-
- /* following Mesh convention; we use vertex coordinate itself for normal in this case */
- for(eve= em->verts.first; eve; eve=eve->next) {
- if(normalize_v3(eve->no) == 0.0f) {
- copy_v3_v3(eve->no, eve->co);
- normalize_v3(eve->no);
- }
- }
-}
-
-int compareface(EditFace *vl1, EditFace *vl2)
-{
- EditVert *v1, *v2, *v3, *v4;
-
- if(vl1->v4 && vl2->v4) {
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
- v4= vl2->v4;
-
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) {
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) {
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) {
- if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) {
- return 1;
- }
- }
- }
- }
- }
- else if(vl1->v4==0 && vl2->v4==0) {
- v1= vl2->v1;
- v2= vl2->v2;
- v3= vl2->v3;
-
- if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) {
- if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) {
- if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) {
- return 1;
- }
- }
- }
- }
-
- return 0;
-}
-
-/* checks for existence, not tria overlapping inside quad */
-EditFace *exist_face(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
-{
- EditFace *efa, efatest;
-
- efatest.v1= v1;
- efatest.v2= v2;
- efatest.v3= v3;
- efatest.v4= v4;
-
- efa= em->faces.first;
- while(efa) {
- if(compareface(&efatest, efa)) return efa;
- efa= efa->next;
- }
- return NULL;
-}
-
-/* evaluate if entire quad is a proper convex quad */
-int convex(float *v1, float *v2, float *v3, float *v4)
-{
- float nor[3], nor1[3], nor2[3], vec[4][2];
-
- /* define projection, do both trias apart, quad is undefined! */
- normal_tri_v3( nor1,v1, v2, v3);
- normal_tri_v3( nor2,v1, v3, v4);
- nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
- nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
- nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
-
- if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
- vec[0][0]= v1[0]; vec[0][1]= v1[1];
- vec[1][0]= v2[0]; vec[1][1]= v2[1];
- vec[2][0]= v3[0]; vec[2][1]= v3[1];
- vec[3][0]= v4[0]; vec[3][1]= v4[1];
- }
- else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
- vec[0][0]= v1[0]; vec[0][1]= v1[2];
- vec[1][0]= v2[0]; vec[1][1]= v2[2];
- vec[2][0]= v3[0]; vec[2][1]= v3[2];
- vec[3][0]= v4[0]; vec[3][1]= v4[2];
- }
- else {
- vec[0][0]= v1[1]; vec[0][1]= v1[2];
- vec[1][0]= v2[1]; vec[1][1]= v2[2];
- vec[2][0]= v3[1]; vec[2][1]= v3[2];
- vec[3][0]= v4[1]; vec[3][1]= v4[2];
- }
-
- /* linetests, the 2 diagonals have to instersect to be convex */
- if( isect_line_line_v2(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
- return 0;
-}
-
-
-/* ********************* Fake Polgon support (FGon) ***************** */
-
-
-/* results in:
- - faces having ->fgonf flag set (also for draw)
- - edges having ->fgoni index set (for select)
-*/
-
-float EM_face_area(EditFace *efa)
-{
- if(efa->v4) return area_quad_v3(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- else return area_tri_v3(efa->v1->co, efa->v2->co, efa->v3->co);
-}
-
-float EM_face_perimeter(EditFace *efa)
-{
- if(efa->v4) return
- len_v3v3(efa->v1->co, efa->v2->co)+
- len_v3v3(efa->v2->co, efa->v3->co)+
- len_v3v3(efa->v3->co, efa->v4->co)+
- len_v3v3(efa->v4->co, efa->v1->co);
-
- else return
- len_v3v3(efa->v1->co, efa->v2->co)+
- len_v3v3(efa->v2->co, efa->v3->co)+
- len_v3v3(efa->v3->co, efa->v1->co);
-}
-
-void EM_fgon_flags(EditMesh *em)
-{
- EditFace *efa, *efan, *efamax;
- EditEdge *eed;
- ListBase listb={NULL, NULL};
- float size, maxsize;
- short done, curindex= 1;
-
- // for each face with fgon edge AND not fgon flag set
- for(eed= em->edges.first; eed; eed= eed->next) eed->fgoni= 0; // index
- for(efa= em->faces.first; efa; efa= efa->next) efa->fgonf= 0; // flag
-
- // for speed & simplicity, put fgon face candidates in new listbase
- efa= em->faces.first;
- while(efa) {
- efan= efa->next;
- if( (efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) ||
- (efa->e3->h & EM_FGON) || (efa->e4 && (efa->e4->h & EM_FGON)) ) {
- BLI_remlink(&em->faces, efa);
- BLI_addtail(&listb, efa);
- }
- efa= efan;
- }
-
- // find an undone face with fgon edge
- for(efa= listb.first; efa; efa= efa->next) {
- if(efa->fgonf==0) {
-
- // init this face
- efa->fgonf= EM_FGON;
- if(efa->e1->h & EM_FGON) efa->e1->fgoni= curindex;
- if(efa->e2->h & EM_FGON) efa->e2->fgoni= curindex;
- if(efa->e3->h & EM_FGON) efa->e3->fgoni= curindex;
- if(efa->e4 && (efa->e4->h & EM_FGON)) efa->e4->fgoni= curindex;
-
- // we search for largest face, to give facedot drawing rights
- maxsize= EM_face_area(efa);
- efamax= efa;
-
- // now flush curendex over edges and set faceflags
- done= 1;
- while(done==1) {
- done= 0;
-
- for(efan= listb.first; efan; efan= efan->next) {
- if(efan->fgonf==0) {
- // if one if its edges has index set, do other too
- if( (efan->e1->fgoni==curindex) || (efan->e2->fgoni==curindex) ||
- (efan->e3->fgoni==curindex) || (efan->e4 && (efan->e4->fgoni==curindex)) ) {
-
- efan->fgonf= EM_FGON;
- if(efan->e1->h & EM_FGON) efan->e1->fgoni= curindex;
- if(efan->e2->h & EM_FGON) efan->e2->fgoni= curindex;
- if(efan->e3->h & EM_FGON) efan->e3->fgoni= curindex;
- if(efan->e4 && (efan->e4->h & EM_FGON)) efan->e4->fgoni= curindex;
-
- size= EM_face_area(efan);
- if(size>maxsize) {
- efamax= efan;
- maxsize= size;
- }
- done= 1;
- }
- }
- }
- }
-
- efamax->fgonf |= EM_FGON_DRAW;
- curindex++;
-
- }
- }
-
- // put fgon face candidates back in listbase
- efa= listb.first;
- while(efa) {
- efan= efa->next;
- BLI_remlink(&listb, efa);
- BLI_addtail(&em->faces, efa);
- efa= efan;
- }
-
- // remove fgon flags when edge not in fgon (anymore)
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->fgoni==0) eed->h &= ~EM_FGON;
- }
-
-}
-
-/* editmesh vertmap, copied from intern.mesh.c
- * if do_face_idx_array is 0 it means we need to run it as well as freeing
- * */
-
-UvVertMap *EM_make_uv_vert_map(EditMesh *em, int selected, int do_face_idx_array, float *limit)
-{
- EditVert *ev;
- EditFace *efa;
- int totverts;
-
- /* vars from original func */
- UvVertMap *vmap;
- UvMapVert *buf;
- MTFace *tf;
- unsigned int a;
- int i, totuv, nverts;
-
- if (do_face_idx_array)
- EM_init_index_arrays(em, 0, 0, 1);
-
- /* we need the vert */
- for (ev= em->verts.first, totverts=0; ev; ev= ev->next, totverts++) {
- ev->tmp.l = totverts;
- }
-
- totuv = 0;
-
- /* generate UvMapVert array */
- for (efa= em->faces.first; efa; efa= efa->next)
- if(!selected || ((!efa->h) && (efa->f & SELECT)))
- totuv += (efa->v4)? 4: 3;
-
- if(totuv==0) {
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
- vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
- if (!vmap) {
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
-
- vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
- buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
-
- if (!vmap->vert || !vmap->buf) {
- free_uv_vert_map(vmap);
- if (do_face_idx_array)
- EM_free_index_arrays();
- return NULL;
- }
-
- for (a=0, efa= em->faces.first; efa; a++, efa= efa->next) {
- if(!selected || ((!efa->h) && (efa->f & SELECT))) {
- nverts= (efa->v4)? 4: 3;
-
- for(i=0; i<nverts; i++) {
- buf->tfindex= i;
- buf->f= a;
- buf->separate = 0;
-
- buf->next= vmap->vert[(*(&efa->v1 + i))->tmp.l];
- vmap->vert[(*(&efa->v1 + i))->tmp.l]= buf;
-
- buf++;
- }
- }
- }
-
- /* sort individual uvs for each vert */
- for(a=0, ev=em->verts.first; ev; a++, ev= ev->next) {
- UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
- UvMapVert *iterv, *v, *lastv, *next;
- float *uv, *uv2, uvdiff[2];
-
- while(vlist) {
- v= vlist;
- vlist= vlist->next;
- v->next= newvlist;
- newvlist= v;
-
- efa = EM_get_face_for_index(v->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv = tf->uv[v->tfindex];
-
- lastv= NULL;
- iterv= vlist;
-
- while(iterv) {
- next= iterv->next;
- efa = EM_get_face_for_index(iterv->f);
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv2 = tf->uv[iterv->tfindex];
-
- sub_v2_v2v2(uvdiff, uv2, uv);
-
- if(fabsf(uv[0]-uv2[0]) < limit[0] && fabsf(uv[1]-uv2[1]) < limit[1]) {
- if(lastv) lastv->next= next;
- else vlist= next;
- iterv->next= newvlist;
- newvlist= iterv;
- }
- else
- lastv=iterv;
-
- iterv= next;
- }
-
- newvlist->separate = 1;
- }
-
- vmap->vert[a]= newvlist;
- }
-
- if (do_face_idx_array)
- EM_free_index_arrays();
-
- return vmap;
-}
-
-UvMapVert *EM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
-{
- return vmap->vert[v];
-}
-
-void EM_free_uv_vert_map(UvVertMap *vmap)
-{
- if (vmap) {
- if (vmap->vert) MEM_freeN(vmap->vert);
- if (vmap->buf) MEM_freeN(vmap->buf);
- MEM_freeN(vmap);
- }
-}
-
-/* poll call for mesh operators requiring a view3d context */
-int EM_view3d_poll(bContext *C)
-{
- if(ED_operator_editmesh(C) && ED_operator_view3d_active(C))
- return 1;
- return 0;
-}
-
-/* higher quality normals */
-
-/* NormalCalc */
-/* NormalCalc modifier: calculates higher quality normals
-*/
-
-/* each edge uses this to */
-typedef struct EdgeFaceRef {
- int f1; /* init as -1 */
- int f2;
-} EdgeFaceRef;
-
-void EM_make_hq_normals(EditMesh *em)
-{
- EditFace *efa;
- EditVert *eve;
- int i;
-
- EdgeHash *edge_hash = BLI_edgehash_new();
- EdgeHashIterator *edge_iter;
- int edge_ref_count = 0;
- int ed_v1, ed_v2; /* use when getting the key */
- EdgeFaceRef *edge_ref_array = MEM_callocN(em->totedge * sizeof(EdgeFaceRef), "Edge Connectivity");
- EdgeFaceRef *edge_ref;
- float edge_normal[3];
-
- EM_init_index_arrays(em, 1, 1, 1);
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- zero_v3(eve->no);
- eve->tmp.l= i;
- }
-
- /* This function adds an edge hash if its not there, and adds the face index */
-#define NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(EDV1, EDV2); \
- edge_ref = (EdgeFaceRef *)BLI_edgehash_lookup(edge_hash, EDV1, EDV2); \
- if (!edge_ref) { \
- edge_ref = &edge_ref_array[edge_ref_count]; edge_ref_count++; \
- edge_ref->f1=i; \
- edge_ref->f2=-1; \
- BLI_edgehash_insert(edge_hash, EDV1, EDV2, edge_ref); \
- } else { \
- edge_ref->f2=i; \
- }
-
-
- efa= em->faces.first;
- for(i = 0; i < em->totface; i++, efa= efa->next) {
- if(efa->v4) {
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v4->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v4->tmp.l, efa->v1->tmp.l);
- } else {
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v1->tmp.l, efa->v2->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v2->tmp.l, efa->v3->tmp.l);
- NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE(efa->v3->tmp.l, efa->v1->tmp.l);
- }
- }
-
-#undef NOCALC_EDGEWEIGHT_ADD_EDGEREF_FACE
-
-
- for(edge_iter = BLI_edgehashIterator_new(edge_hash); !BLI_edgehashIterator_isDone(edge_iter); BLI_edgehashIterator_step(edge_iter)) {
- /* Get the edge vert indices, and edge value (the face indices that use it)*/
- BLI_edgehashIterator_getKey(edge_iter, (int*)&ed_v1, (int*)&ed_v2);
- edge_ref = BLI_edgehashIterator_getValue(edge_iter);
-
- if (edge_ref->f2 != -1) {
- EditFace *ef1= EM_get_face_for_index(edge_ref->f1), *ef2= EM_get_face_for_index(edge_ref->f2);
- float angle= angle_normalized_v3v3(ef1->n, ef2->n);
- if(angle > 0.0f) {
- /* We have 2 faces using this edge, calculate the edges normal
- * using the angle between the 2 faces as a weighting */
- add_v3_v3v3(edge_normal, ef1->n, ef2->n);
- normalize_v3(edge_normal);
- mul_v3_fl(edge_normal, angle);
- }
- else {
- /* cant do anything useful here!
- Set the face index for a vert incase it gets a zero normal */
- EM_get_vert_for_index(ed_v1)->tmp.l=
- EM_get_vert_for_index(ed_v2)->tmp.l= -(edge_ref->f1 + 1);
- continue;
- }
- } else {
- /* only one face attached to that edge */
- /* an edge without another attached- the weight on this is
- * undefined, M_PI/2 is 90d in radians and that seems good enough */
- VECCOPY(edge_normal, EM_get_face_for_index(edge_ref->f1)->n)
- mul_v3_fl(edge_normal, M_PI/2);
- }
- add_v3_v3(EM_get_vert_for_index(ed_v1)->no, edge_normal );
- add_v3_v3(EM_get_vert_for_index(ed_v2)->no, edge_normal );
-
-
- }
- BLI_edgehashIterator_free(edge_iter);
- BLI_edgehash_free(edge_hash, NULL);
- MEM_freeN(edge_ref_array);
-
- /* normalize vertex normals and assign */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(normalize_v3(eve->no) == 0.0f && eve->tmp.l < 0) {
- /* exceptional case, totally flat */
- efa= EM_get_face_for_index(-(eve->tmp.l) - 1);
- VECCOPY(eve->no, efa->n);
- }
- }
-
- EM_free_index_arrays();
-}
-
-void EM_solidify(EditMesh *em, float dist)
-{
- EditFace *efa;
- EditVert *eve;
- float *vert_angles= MEM_callocN(sizeof(float) * em->totvert * 2, "EM_solidify"); /* 2 in 1 */
- float *vert_accum= vert_angles + em->totvert;
- float face_angles[4];
- int i, j;
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- eve->tmp.l= i;
- }
-
- efa= em->faces.first;
- for(i = 0; i < em->totface; i++, efa= efa->next) {
-
- if(!(efa->f & SELECT))
- continue;
-
- if(efa->v4) {
- angle_quad_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- j= 3;
- }
- else {
- angle_tri_v3(face_angles, efa->v1->co, efa->v2->co, efa->v3->co);
- j= 2;
- }
-
- for(; j>=0; j--) {
- eve= *(&efa->v1 + j);
- vert_accum[eve->tmp.l] += face_angles[j];
- vert_angles[eve->tmp.l]+= shell_angle_to_dist(angle_normalized_v3v3(eve->no, efa->n)) * face_angles[j];
- }
- }
-
- for(eve= em->verts.first, i=0; eve; eve= eve->next, i++) {
- if(vert_accum[i]) { /* zero if unselected */
- madd_v3_v3fl(eve->co, eve->no, dist * vert_angles[i] / vert_accum[i]);
- }
- }
-
- MEM_freeN(vert_angles);
-}
-
-/* not that optimal!, should be nicer with bmesh */
-static void tag_face_edges(EditFace *efa)
-{
- if(efa->v4)
- efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;
- else
- efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
-}
-static int tag_face_edges_test(EditFace *efa)
-{
- if(efa->v4)
- return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l || efa->e4->tmp.l) ? 1:0;
- else
- return (efa->e1->tmp.l || efa->e2->tmp.l || efa->e3->tmp.l) ? 1:0;
-}
-
-static void em_deselect_nth_face(EditMesh *em, int nth, EditFace *efa_act)
-{
- EditFace *efa;
- EditEdge *eed;
- int ok= 1;
-
- if(efa_act==NULL) {
- return;
- }
-
- /* to detect loose edges, we put f2 flag on 1 */
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.l= 0;
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.l = 0;
- }
-
- efa_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(efa->tmp.l==1) { /* initialize */
- tag_face_edges(efa);
- }
-
- if(efa->tmp.l) {
- efa->tmp.l++;
- }
- }
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- if(efa->tmp.l==0 && tag_face_edges_test(efa)) {
- efa->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->tmp.l > 0 && efa->tmp.l % nth) {
- EM_select_face(efa, 0);
- }
- }
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- EM_select_face(efa, 1);
- }
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-/* not that optimal!, should be nicer with bmesh */
-static void tag_edge_verts(EditEdge *eed)
-{
- eed->v1->tmp.l= eed->v2->tmp.l= 1;
-}
-static int tag_edge_verts_test(EditEdge *eed)
-{
- return (eed->v1->tmp.l || eed->v2->tmp.l) ? 1:0;
-}
-
-static void em_deselect_nth_edge(EditMesh *em, int nth, EditEdge *eed_act)
-{
- EditEdge *eed;
- EditVert *eve;
- int ok= 1;
-
- if(eed_act==NULL) {
- return;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.l= 0;
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- eed->tmp.l = 0;
- }
-
- eed_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->tmp.l==1) { /* initialize */
- tag_edge_verts(eed);
- }
-
- if(eed->tmp.l) {
- eed->tmp.l++;
- }
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->tmp.l==0 && tag_edge_verts_test(eed)) {
- eed->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->tmp.l > 0 && eed->tmp.l % nth) {
- EM_select_edge(eed, 0);
- }
- }
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- EM_select_edge(eed, 1);
- }
- }
-
- {
- /* grr, should be a function */
- EditFace *efa;
- for (efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4) {
- if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT );
- else efa->f &= ~SELECT;
- }
- else {
- if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT );
- else efa->f &= ~SELECT;
- }
- }
- }
-
- EM_nvertices_selected(em);
- EM_nedges_selected(em);
- EM_nfaces_selected(em);
-}
-
-static void em_deselect_nth_vert(EditMesh *em, int nth, EditVert *eve_act)
-{
- EditVert *eve;
- EditEdge *eed;
- int ok= 1;
-
- if(eve_act==NULL) {
- return;
- }
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.l = 0;
- }
-
- eve_act->tmp.l = 1;
-
- while(ok) {
- ok = 0;
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- if(eve->tmp.l)
- eve->tmp.l++;
- }
- }
-
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- if(eed->v1->tmp.l==2 && eed->v2->tmp.l==0) { /* initialize */
- eed->v2->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- else if(eed->v2->tmp.l==2 && eed->v1->tmp.l==0) { /* initialize */
- eed->v1->tmp.l= 1;
- ok = 1; /* keep looping */
- }
- }
- }
- }
-
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->tmp.l > 0 && eve->tmp.l % nth) {
- eve->f &= ~SELECT;
- }
- }
-
- EM_deselect_flush(em);
-
- EM_nvertices_selected(em);
- // EM_nedges_selected(em); // flush does these
- // EM_nfaces_selected(em); // flush does these
-}
-
-static void deselect_nth_active(EditMesh *em, EditVert **eve_p, EditEdge **eed_p, EditFace **efa_p)
-{
- EditSelection *ese;
-
- *eve_p= NULL;
- *eed_p= NULL;
- *efa_p= NULL;
-
- ese= (EditSelection*)em->selected.last;
-
- if(ese) {
- switch(ese->type) {
- case EDITVERT:
- *eve_p= (EditVert *)ese->data;
- return;
- case EDITEDGE:
- *eed_p= (EditEdge *)ese->data;
- return;
- case EDITFACE:
- *efa_p= (EditFace *)ese->data;
- return;
- }
- }
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- EditVert *eve;
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- *eve_p= eve;
- return;
- }
- }
- }
-
- if(em->selectmode & SCE_SELECT_EDGE) {
- EditEdge *eed;
- for (eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- *eed_p= eed;
- return;
- }
- }
- }
-
- if(em->selectmode & SCE_SELECT_FACE) {
- EditFace *efa= EM_get_actFace(em, 1);
- if(efa) {
- *efa_p= efa;
- return;
- }
- }
-}
-
-int EM_deselect_nth(EditMesh *em, int nth)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- deselect_nth_active(em, &eve, &eed, &efa);
-
- if(eve)
- em_deselect_nth_vert(em, nth, eve);
- else if (eed)
- em_deselect_nth_edge(em, nth, eed);
- else if (efa)
- em_deselect_nth_face(em, nth, efa);
- else
- return 0;
-
- return 1;
-}
-
-void EM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, EditMesh *em)
-{
- EditVert *eve;
- for(eve= em->verts.first;eve; eve=eve->next) {
- if(eve->f & SELECT) {
- float mval[2], vec[3], no_dummy[3];
- int dist_dummy;
- mul_v3_m4v3(vec, obedit->obmat, eve->co);
- project_float_noclip(ar, vec, mval);
- if(snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) {
- mul_v3_m4v3(eve->co, obedit->imat, vec);
- }
- }
- }
-}
diff --git a/source/blender/editors/mesh/editmesh_loop.c b/source/blender/editors/mesh/editmesh_loop.c
deleted file mode 100644
index 72e9e3b6d9e..00000000000
--- a/source/blender/editors/mesh/editmesh_loop.c
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_loop.c
- * \ingroup edmesh
- */
-
-
-/*
-
-editmesh_loop: tools with own drawing subloops, select, knife, subdiv
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-
-
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_editVert.h"
-#include "BLI_ghash.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_mesh.h"
-#include "BKE_array_mallocn.h"
-
-#include "PIL_time.h"
-
-#include "BIF_gl.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-#include "ED_view3d.h"
-
-#include "mesh_intern.h"
-
-/* **** XXX ******** */
-static void error(const char *UNUSED(arg)) {}
-/* **** XXX ******** */
-
-#if 0 /* UNUSED 2.5 */
-static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines)
-{
- EditEdge *eed;
- EditFace *efa;
- EditVert *v[2][2];
- float co[2][3];
- int looking= 1,i;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- // tag startedge OK
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
-
- // if edge tagged, select opposing edge and mark face ok
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- if(previewlines > 0 && select == 0){
-// XXX persp(PERSP_VIEW);
-// XXX glPushMatrix();
-// XXX mymultmatrix(obedit->obmat);
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4 == NULL) { continue; }
- if(efa->h == 0){
- if(efa->e1->f2 == 1){
- if(efa->e1->h == 1 || efa->e3->h == 1 )
- continue;
-
- v[0][0] = efa->v1;
- v[0][1] = efa->v2;
- v[1][0] = efa->v4;
- v[1][1] = efa->v3;
- } else if(efa->e2->f2 == 1){
- if(efa->e2->h == 1 || efa->e4->h == 1)
- continue;
- v[0][0] = efa->v2;
- v[0][1] = efa->v3;
- v[1][0] = efa->v1;
- v[1][1] = efa->v4;
- } else { continue; }
-
- for(i=1;i<=previewlines;i++){
- co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
- co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
- co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
-
- co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
- co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
- co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
- glColor3ub(255, 0, 255);
- glBegin(GL_LINES);
- glVertex3f(co[0][0],co[0][1],co[0][2]);
- glVertex3f(co[1][0],co[1][1],co[1][2]);
- glEnd();
- }
- }
- }
- glPopMatrix();
- } else {
-
- /* (de)select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
- }
-}
-
-static void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
-{
- ViewContext vc; // XXX
- EditEdge *nearest=NULL, *eed;
- float fac;
- int keys = 0, holdnum=0, selectmode, dist;
- short mvalo[2] = {0, 0}, mval[2] = {0, 0};
- short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
- short hasHidden = 0;
- char msg[128];
-
- selectmode = em->selectmode;
-
- if(em->selectmode & SCE_SELECT_FACE){
- em->selectmode = SCE_SELECT_EDGE;
- EM_selectmode_set(em);
- }
-
-
- BIF_undo_push("Loopcut Begin");
- while(choosing && !cancel){
-// XXX getmouseco_areawin(mval);
- if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
- mvalo[0] = mval[0];
- mvalo[1] = mval[1];
- dist= 50;
- nearest = findnearestedge(&vc, &dist); // returns actual distance in dist
-// scrarea_do_windraw(curarea); // after findnearestedge, backbuf!
-
- BLI_snprintf(msg, sizeof(msg),"Number of Cuts: %d (S)mooth: %s", numcuts, smooth ? "on":"off");
-
-// headerprint(msg);
- /* Need to figure preview */
- if(nearest){
- edgering_sel(em, nearest, 0, numcuts);
- }
-// XXX screen_swapbuffers();
-
- /* backbuffer refresh for non-apples (no aux) */
-#ifndef __APPLE__
-// XXX if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
-// backdrawview3d(0);
-// }
-#endif
- }
- else PIL_sleep_ms(10); // idle
-
-
- while(qtest())
- {
- val=0;
-// XXX event= extern_qread(&val);
- if(val && (event == MOUSEX || event == MOUSEY)){ ; }
- else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
- {
- if(event == MIDDLEMOUSE){
- cuthalf = 1;
- }
- if (nearest==NULL)
- cancel = 1;
- choosing=0;
- mvalo[0] = -1;
- }
- else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
- {
- choosing=0;
- cancel = 1;
- mvalo[0] = -1;
- }
- else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
- {
- numcuts++;
- mvalo[0] = -1;
- }
- else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
- {
- if(numcuts > 1){
- numcuts--;
- mvalo[0] = -1;
- }
- }
- else if(val && event==SKEY)
- {
- if(smooth){smooth=0;}
- else { smooth=1; }
- mvalo[0] = -1;
- }
-
- else if(val){
- holdnum = -1;
- switch(event){
- case PAD9:
- case NINEKEY:
- holdnum = 9; break;
- case PAD8:
- case EIGHTKEY:
- holdnum = 8;break;
- case PAD7:
- case SEVENKEY:
- holdnum = 7;break;
- case PAD6:
- case SIXKEY:
- holdnum = 6;break;
- case PAD5:
- case FIVEKEY:
- holdnum = 5;break;
- case PAD4:
- case FOURKEY:
- holdnum = 4;break;
- case PAD3:
- case THREEKEY:
- holdnum = 3; break;
- case PAD2:
- case TWOKEY:
- holdnum = 2;break;
- case PAD1:
- case ONEKEY:
- holdnum = 1; break;
- case PAD0:
- case ZEROKEY:
- holdnum = 0;break;
- case BACKSPACEKEY:
- holdnum = -2;break;
- }
- if(holdnum >= 0 && numcuts*10 < 130){
- if(keys == 0){ // first level numeric entry
- if(holdnum > 0){
- numcuts = holdnum;
- keys++;
- }
- } else if(keys > 0){//highrt level numeric entry
- numcuts *= 10;
- numcuts += holdnum;
- keys++;
- }
- } else if (holdnum == -2){// backspace
- if (keys > 1){
- numcuts /= 10;
- keys--;
- } else {
- numcuts=1;
- keys = 0;
- }
- }
- mvalo[0] = -1;
- break;
- } // End Numeric Entry
- } //End while(qtest())
- } // End Choosing
-
- if(cancel){
- return;
- }
- /* clean selection */
- for(eed=em->edges.first; eed; eed = eed->next){
- EM_select_edge(eed,0);
- }
- /* select edge ring */
- edgering_sel(em, nearest, 1, 0);
-
- /* now cut the loops */
- if(smooth){
- fac= 1.0f;
-// XXX if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
- fac= 0.292f*fac;
- esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts, SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
- } else {
- esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
- }
- /* if this was a single cut, enter edgeslide mode */
- if(numcuts == 1 && hasHidden == 0){
- if(cuthalf)
- EdgeSlide(em, op, 1,0.0);
- else {
- if(EdgeSlide(em, op, 0,0.0) == -1){
- BIF_undo();
- }
- }
- }
-
- if(em->selectmode != selectmode){
- em->selectmode = selectmode;
- EM_selectmode_set(em);
- }
-
-// DAG_id_tag_update(obedit->data, 0);
- return;
-}
-#endif
-
-/* *************** LOOP SELECT ************* */
-#if 0
-static short edgeFaces(EditMesh *em, EditEdge *e)
-{
- EditFace *search=NULL;
- short count = 0;
-
- search = em->faces.first;
- while(search){
- if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e))
- count++;
- search = search->next;
- }
- return count;
-}
-#endif
-
-
-
-/* ***************** TRAIL ************************
-
-Read a trail of mouse coords and return them as an array of CutCurve structs
-len returns number of mouse coords read before commiting with RETKEY
-It is up to the caller to free the block when done with it,
-
-XXX Is only used here, so local inside this file (ton)
- */
-
-#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
-#define TRAIL_FREEHAND 2
-#define TRAIL_MIXED 3 /* (1|2) */
-#define TRAIL_AUTO 4
-#define TRAIL_MIDPOINTS 8
-
-typedef struct CutCurve {
- float x;
- float y;
-} CutCurve;
-
-
-/* ******************************************************************** */
-/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
- drawn by user.
-
- Currently mapped to KKey when in MeshEdit mode.
- Usage:
- Hit Shift K, Select Centers or Exact
- Hold LMB down to draw path, hit RETKEY.
- ESC cancels as expected.
-
- Contributed by Robert Wenzlaff (Det. Thorn).
-
- 2.5 revamp:
- - non modal (no menu before cutting)
- - exit on mouse release
- - polygon/segment drawing can become handled by WM cb later
-
-*/
-
-#define KNIFE_EXACT 1
-#define KNIFE_MIDPOINT 2
-#define KNIFE_MULTICUT 3
-
-static EnumPropertyItem knife_items[]= {
- {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
- {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
- {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
-
-static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
-{
-#define MAXSLOPE 100000
- float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
- float y2min, dist, lastdist=0, xdiff2, xdiff1;
- float m1, b1, m2, b2, x21, x22, y21, y22, xi;
- float yi, x1min, x1max, y1max, y1min, perc=0;
- float *scr;
- float threshold;
- int i;
-
- threshold = 0.000001; /*tolerance for vertex intersection*/
- // XXX threshold = scene->toolsettings->select_thresh / 100;
-
- /* Get screen coords of verts */
- scr = BLI_ghash_lookup(gh, e->v1);
- x21=scr[0];
- y21=scr[1];
-
- scr = BLI_ghash_lookup(gh, e->v2);
- x22=scr[0];
- y22=scr[1];
-
- xdiff2=(x22-x21);
- if (xdiff2) {
- m2=(y22-y21)/xdiff2;
- b2= ((x22*y21)-(x21*y22))/xdiff2;
- }
- else {
- m2=MAXSLOPE; /* Verticle slope */
- b2=x22;
- }
-
- /*check for *exact* vertex intersection first*/
- if(mode!=KNIFE_MULTICUT){
- for (i=0; i<len; i++){
- if (i>0){
- x11=x12;
- y11=y12;
- }
- else {
- x11=c[i].x;
- y11=c[i].y;
- }
- x12=c[i].x;
- y12=c[i].y;
-
- /*test e->v1*/
- if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
- e->v1->f1 = 1;
- perc = 0;
- return(perc);
- }
- /*test e->v2*/
- else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
- e->v2->f1 = 1;
- perc = 0;
- return(perc);
- }
- }
- }
-
- /*now check for edge interesect (may produce vertex intersection as well)*/
- for (i=0; i<len; i++){
- if (i>0){
- x11=x12;
- y11=y12;
- }
- else {
- x11=c[i].x;
- y11=c[i].y;
- }
- x12=c[i].x;
- y12=c[i].y;
-
- /* Perp. Distance from point to line */
- if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
- /* change in sign. Skip extra math */
- else dist=x22-x12;
-
- if (i==0) lastdist=dist;
-
- /* if dist changes sign, and intersect point in edge's Bound Box*/
- if ((lastdist*dist)<=0){
- xdiff1=(x12-x11); /* Equation of line between last 2 points */
- if (xdiff1){
- m1=(y12-y11)/xdiff1;
- b1= ((x12*y11)-(x11*y12))/xdiff1;
- }
- else{
- m1=MAXSLOPE;
- b1=x12;
- }
- x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
- x2min=MIN2(x21,x22)-0.001; /* due to round off error */
- y2max=MAX2(y21,y22)+0.001;
- y2min=MIN2(y21,y22)-0.001;
-
- /* Found an intersect, calc intersect point */
- if (m1==m2){ /* co-incident lines */
- /* cut at 50% of overlap area*/
- x1max=MAX2(x11, x12);
- x1min=MIN2(x11, x12);
- xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
-
- y1max=MAX2(y11, y12);
- y1min=MIN2(y11, y12);
- yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
- }
- else if (m2==MAXSLOPE){
- xi=x22;
- yi=m1*x22+b1;
- }
- else if (m1==MAXSLOPE){
- xi=x12;
- yi=m2*x12+b2;
- }
- else {
- xi=(b1-b2)/(m2-m1);
- yi=(b1*m2-m1*b2)/(m2-m1);
- }
-
- /* Intersect inside bounding box of edge?*/
- if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
- /*test for vertex intersect that may be 'close enough'*/
- if(mode!=KNIFE_MULTICUT){
- if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
- if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
- e->v1->f1 = 1;
- perc = 0;
- break;
- }
- }
- if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
- if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
- e->v2->f1 = 1;
- perc = 0;
- break;
- }
- }
- }
- if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
- else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
- //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
-
- break;
- }
- }
- lastdist=dist;
- }
- return(perc);
-}
-
-
-#define MAX_CUTS 256
-
-static int knife_cut_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- ARegion *ar= CTX_wm_region(C);
- EditEdge *eed;
- EditVert *eve;
- CutCurve curve[MAX_CUTS];
- struct GHash *gh;
- float isect=0.0;
- float *scr, co[4];
- int len=0;
- short numcuts= RNA_int_get(op->ptr, "num_cuts");
- short mode= RNA_enum_get(op->ptr, "type");
-// int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
-
- /* edit-object needed for matrix, and ar->regiondata for projections to work */
- if (ELEM3(NULL, obedit, ar, ar->regiondata))
- return OPERATOR_CANCELLED;
-
- if (EM_nvertices_selected(em) < 2) {
- error("No edges are selected to operate on");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /* get the cut curve */
- RNA_BEGIN(op->ptr, itemptr, "path") {
-
- RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
- len++;
- if(len>= MAX_CUTS) break;
- }
- RNA_END;
-
- if(len<2) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /*store percentage of edge cut for KNIFE_EXACT here.*/
- for(eed=em->edges.first; eed; eed= eed->next)
- eed->tmp.fp = 0.0;
-
- /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
- gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife_cut_exec gh");
- for(eve=em->verts.first; eve; eve=eve->next){
- scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
- VECCOPY(co, eve->co);
- co[3]= 1.0;
- mul_m4_v4(obedit->obmat, co);
- project_float(ar, co, scr);
- BLI_ghash_insert(gh, eve, scr);
- eve->f1 = 0; /*store vertex intersection flag here*/
-
- }
-
- eed= em->edges.first;
- while(eed) {
- if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet
- isect= seg_intersect(eed, curve, len, mode, gh);
- if (isect!=0.0f) eed->f2= 1;
- else eed->f2=0;
- eed->tmp.fp= isect;
- }
- else {
- eed->f2=0;
- eed->f1=0;
- }
- eed= eed->next;
- }
-
- if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
- else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
- else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
-
- eed=em->edges.first;
- while(eed){
- eed->f2=0;
- eed->f1=0;
- eed=eed->next;
- }
-
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_knife_cut(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- ot->name= "Knife Cut";
- ot->description= "Cut selected edges and faces into parts";
- ot->idname= "MESH_OT_knife_cut";
-
- ot->invoke= WM_gesture_lines_invoke;
- ot->modal= WM_gesture_lines_modal;
- ot->exec= knife_cut_exec;
-
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
- prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
- RNA_def_int(ot->srna, "num_cuts", 1, 1, MAX_CUTS, "Number of Cuts", "Only for Multi-Cut", 1, MAX_CUTS);
- // doesn't work atm.. RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
-
- /* internal */
- RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
-}
-
-/* ******************************************************* */
-
diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c
deleted file mode 100644
index 8cdbe6707a3..00000000000
--- a/source/blender/editors/mesh/editmesh_mods.c
+++ /dev/null
@@ -1,4500 +0,0 @@
-/*
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_mods.c
- * \ingroup edmesh
- */
-
-
-/*
-
-editmesh_mods.c, UI level access, no geometry changes
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_material_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_editVert.h"
-#include "BLI_rand.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_context.h"
-#include "BKE_displist.h"
-#include "BKE_depsgraph.h"
-#include "BKE_mesh.h"
-#include "BKE_material.h"
-#include "BKE_paint.h"
-#include "BKE_report.h"
-#include "BKE_texture.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
-
-#include "RE_render_ext.h" /* externtex */
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-#include "ED_uvedit.h"
-
-#include "BIF_gl.h"
-
-#include "mesh_intern.h"
-
-#include "BLO_sys_types.h" // for intptr_t support
-
-/* XXX */
-static void waitcursor(int UNUSED(val)) {}
-static int pupmenu(const char *UNUSED(arg)) {return 0;}
-
-/* ****************************** MIRROR **************** */
-
-void EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em)
-{
- EditVert *eve, *eve_mirror;
- int index= 0;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.v= NULL;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next, index++) {
- if(eve->tmp.v==NULL) {
- eve_mirror = editmesh_get_x_mirror_vert(ob, em, eve, eve->co, index);
- if(eve_mirror) {
- eve->tmp.v= eve_mirror;
- eve_mirror->tmp.v = eve;
- }
- }
- }
-}
-
-static void EM_select_mirrored(Object *obedit, EditMesh *em, int extend)
-{
-
- EditVert *eve;
-
- EM_cache_x_mirror_vert(obedit, em);
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT && eve->tmp.v && (eve->tmp.v != eve->tmp.v->tmp.v)) {
- eve->tmp.v->f |= SELECT;
-
- if(extend==FALSE)
- eve->f &= ~SELECT;
-
- /* remove the interference */
- eve->tmp.v->tmp.v= NULL;
- eve->tmp.v= NULL;
- }
- }
-}
-
-void EM_automerge(Scene *scene, Object *obedit, int update)
-{
- Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */
- int len;
-
- if ((scene->toolsettings->automerge) &&
- (obedit && obedit->type==OB_MESH && (obedit->mode & OB_MODE_EDIT))
- ) {
- EditMesh *em= me->edit_mesh;
- int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
-
- len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit);
- if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
- if (update) {
- DAG_id_tag_update(&me->id, 0);
- }
- }
- }
-}
-
-/* ****************************** SELECTION ROUTINES **************** */
-
-unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
-
-/* facilities for border select and circle select */
-static char *selbuf= NULL;
-
-/* opengl doesn't support concave... */
-static void draw_triangulated(short 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, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
-{
- unsigned int *dr, *drm;
- struct ImBuf *buf, *bufmask;
- int a;
- GLboolean is_cull;
-
- /* method in use for face selecting too */
- if(vc->obedit==NULL) {
- if(paint_facesel_test(vc->obact));
- else return 0;
- }
- else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-
- buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if(buf==NULL) return 0;
- if(em_vertoffs==0) return 0;
-
- dr = buf->rect;
-
- /* draw the mask */
- glDisable(GL_DEPTH_TEST);
-
- glColor3ub(0, 0, 0);
-
- /* some opengl drivers have problems with draw direction */
- glGetBooleanv(GL_CULL_FACE, &is_cull);
- if(is_cull) glDisable(GL_CULL_FACE);
-
- /* yah, opengl doesn't do concave... tsk! */
- ED_region_pixelspace(vc->ar);
- draw_triangulated(mcords, tot);
-
- glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
- for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
- glEnd();
-
- glFinish(); /* to be sure readpixels sees mask */
-
- /* grab mask */
- bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- drm = bufmask->rect;
- if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
-
- /* build selection lookup */
- selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
-
- a= (xmax-xmin+1)*(ymax-ymin+1);
- while(a--) {
- if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
- dr++; drm++;
- }
- IMB_freeImBuf(buf);
- IMB_freeImBuf(bufmask);
-
- if(is_cull) glEnable(GL_CULL_FACE);
-
- return 1;
-
-}
-
-/* circle shaped sample area */
-int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
-{
- struct ImBuf *buf;
- unsigned int *dr;
- short xmin, ymin, xmax, ymax, xc, yc;
- int radsq;
-
- /* method in use for face selecting too */
- if(vc->obedit==NULL) {
- if(paint_facesel_test(vc->obact));
- else return 0;
- }
- else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-
- xmin= xs-rads; xmax= xs+rads;
- ymin= ys-rads; ymax= ys+rads;
- buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
- if(em_vertoffs==0) return 0;
- if(buf==NULL) return 0;
-
- dr = buf->rect;
-
- /* build selection lookup */
- selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
- radsq= rads*rads;
- for(yc= -rads; yc<=rads; yc++) {
- for(xc= -rads; xc<=rads; xc++, dr++) {
- if(xc*xc + yc*yc < radsq) {
- if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
- }
- }
- }
-
- IMB_freeImBuf(buf);
- return 1;
-
-}
-
-static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
-{
- struct { short mval[2], 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 { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
- static int lastSelectedIndex=0;
- static EditVert *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->verts, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.select = sel;
- data.dist = *dist;
- data.strict = strict;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
-
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenVert(vc, findnearestvert__doClosest, &data, 1);
- }
-
- *dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
-
- return data.closest;
- }
-}
-
-/* returns labda for closest distance v1 to line-piece v2-v3 */
-static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
-{
- float rc[2], len;
-
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
- len= rc[0]*rc[0]+ rc[1]*rc[1];
- if(len==0.0f)
- return 0.0f;
-
- return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
-}
-
-/* note; uses v3d, so needs active 3d window */
-static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index))
-{
- struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } *data = userData;
- float v1[2], v2[2];
- int distance;
-
- ED_view3d_local_clipping(data->vc.rv3d, data->vc.obedit->obmat); /* for local clipping lookups */
-
- v1[0] = x0;
- v1[1] = y0;
- v2[0] = x1;
- v2[1] = y1;
-
- distance= dist_to_line_segment_v2(data->mval, v1, v2);
-
-
- if(eed->f & SELECT) distance+=5;
- if(distance < data->dist) {
- if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
- float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
- float vec[3];
-
- vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
- vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
- vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
-
- if(view3d_test_clipping(data->vc.rv3d, vec, 1)==0) {
- data->dist = distance;
- data->closest = eed;
- }
- }
- else {
- data->dist = distance;
- data->closest = eed;
- }
- }
-}
-EditEdge *findnearestedge(ViewContext *vc, int *dist)
-{
-
- if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
- int distance;
- unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
- EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
-
- if (eed && distance<*dist) {
- *dist = distance;
- return eed;
- } else {
- return NULL;
- }
- }
- else {
- struct { ViewContext vc; float mval[2]; int dist; EditEdge *closest; } data;
-
- data.vc= *vc;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = *dist;
- data.closest = NULL;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenEdge(vc, findnearestedge__doClosest, &data, 2);
-
- *dist = data.dist;
- return data.closest;
- }
-}
-
-static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int UNUSED(index))
-{
- struct { short 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 { short mval[2], 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 { short 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 { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
- static int lastSelectedIndex=0;
- static EditFace *lastSelected=NULL;
-
- if (lastSelected && BLI_findlink(&vc->em->faces, lastSelectedIndex)!=lastSelected) {
- lastSelectedIndex = 0;
- lastSelected = NULL;
- }
-
- data.lastIndex = lastSelectedIndex;
- data.mval[0] = vc->mval[0];
- data.mval[1] = vc->mval[1];
- data.dist = *dist;
- data.closest = NULL;
- data.closestIndex = 0;
-
- data.pass = 0;
-
- ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
-
- if (data.dist>3) {
- data.pass = 1;
- mesh_foreachScreenFace(vc, findnearestface__doClosest, &data);
- }
-
- *dist = data.dist;
- lastSelected = data.closest;
- lastSelectedIndex = data.closestIndex;
-
- return data.closest;
- }
-}
-
-/* best distance based on screen coords.
- use em->selectmode to define how to use
- selected vertices and edges get disadvantage
- return 1 if found one
-*/
-static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed, EditFace **efa)
-{
- EditMesh *em= vc->em;
- int dist= 75;
-
- *eve= NULL;
- *eed= NULL;
- *efa= NULL;
-
- /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(vc);
-
- if(em->selectmode & SCE_SELECT_VERTEX)
- *eve= findnearestvert(vc, &dist, SELECT, 0);
- if(em->selectmode & SCE_SELECT_FACE)
- *efa= findnearestface(vc, &dist);
-
- dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
- if(em->selectmode & SCE_SELECT_EDGE)
- *eed= findnearestedge(vc, &dist);
-
- /* return only one of 3 pointers, for frontbuffer redraws */
- if(*eed) {
- *efa= NULL; *eve= NULL;
- }
- else if(*efa) {
- *eve= NULL;
- }
-
- return (*eve || *eed || *efa);
-}
-
-
-/* **************** SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
-
-/* selects new faces/edges/verts based on the existing selection */
-
-/* VERT GROUP */
-
-#define SIMVERT_NORMAL 0
-#define SIMVERT_FACE 1
-#define SIMVERT_VGROUP 2
-#define SIMVERT_TOT 3
-
-/* EDGE GROUP */
-
-#define SIMEDGE_LENGTH 101
-#define SIMEDGE_DIR 102
-#define SIMEDGE_FACE 103
-#define SIMEDGE_FACE_ANGLE 104
-#define SIMEDGE_CREASE 105
-#define SIMEDGE_SEAM 106
-#define SIMEDGE_SHARP 107
-#define SIMEDGE_TOT 108
-
-/* FACE GROUP */
-
-#define SIMFACE_MATERIAL 201
-#define SIMFACE_IMAGE 202
-#define SIMFACE_AREA 203
-#define SIMFACE_PERIMETER 204
-#define SIMFACE_NORMAL 205
-#define SIMFACE_COPLANAR 206
-#define SIMFACE_TOT 207
-
-static EnumPropertyItem prop_similar_types[] = {
- {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
- {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
- {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
- {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
- {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
- {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
- {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
- {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
- {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
- {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
- {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
- {SIMFACE_AREA, "AREA", 0, "Area", ""},
- {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
- {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
- {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-
-/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
-*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
-#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5f) <= b))
-
-static int similar_face_select__internal(EditMesh *em, int mode, float thresh)
-{
- EditFace *efa, *base_efa=NULL;
- unsigned int selcount=0; /*count how many new faces we select*/
-
- /*deselcount, count how many deselected faces are left, so we can bail out early
- also means that if there are no deselected faces, we can avoid a lot of looping */
- unsigned int deselcount=0;
- short ok=0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!efa->h) {
- if (efa->f & SELECT) {
- efa->f1=1;
- ok=1;
- } else {
- efa->f1=0;
- deselcount++; /* a deselected face we may select later */
- }
- }
- }
-
- if (!ok || !deselcount) /* no data selected OR no more data to select */
- return 0;
-
- if (mode==SIMFACE_AREA) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.fp= EM_face_area(efa);
- }
- } else if (mode==SIMFACE_PERIMETER) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.fp= EM_face_perimeter(efa);
- }
- }
-
- for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
- if (base_efa->f1) { /* This was one of the faces originaly selected */
- if (mode==SIMFACE_MATERIAL) { /* same material */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (
- !(efa->f & SELECT) &&
- !efa->h &&
- base_efa->mat_nr == efa->mat_nr
- ) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMFACE_IMAGE) { /* same image */
- MTFace *tf, *base_tf;
-
- base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
- CD_MTFACE);
-
- if(!base_tf)
- return selcount;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
- CD_MTFACE);
-
- if(base_tf->tpage == tf->tpage) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (
- (!(efa->f & SELECT) && !efa->h) &&
- SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
- ) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMFACE_NORMAL) {
- float angle;
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- angle= RAD2DEGF(angle_v2v2(base_efa->n, efa->n));
- if (angle/180.0f<=thresh) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMFACE_COPLANAR) { /* same planer */
- float angle, base_dot, dot;
- base_dot= dot_v3v3(base_efa->cent, base_efa->n);
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (!(efa->f & SELECT) && !efa->h) {
- angle= RAD2DEGF(angle_v2v2(base_efa->n, efa->n));
- if (angle/180.0f<=thresh) {
- dot=dot_v3v3(efa->cent, base_efa->n);
- if (fabsf(base_dot-dot) <= thresh) {
- EM_select_face(efa, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- }
- }
- }
- } /* end base_efa loop */
- return selcount;
-}
-
-static int similar_face_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- int selcount = similar_face_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
-
- if (selcount) {
- /* here was an edge-mode only select flush case, has to be generalized */
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-/* ***************************************************** */
-
-static int similar_edge_select__internal(EditMesh *em, int mode, float thresh)
-{
- EditEdge *eed, *base_eed=NULL;
- unsigned int selcount=0; /* count how many new edges we select*/
-
- /*count how many visible selected edges there are,
- so we can return when there are none left */
- unsigned int deselcount=0;
-
- short ok=0;
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!eed->h) {
- if (eed->f & SELECT) {
- eed->f1=1;
- ok=1;
- } else {
- eed->f1=0;
- deselcount++;
- }
- /* set all eed->tmp.l to 0 we use it later.
- for counting face users*/
- eed->tmp.l=0;
- eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
- }
- }
-
- if (!ok || !deselcount) /* no data selected OR no more data to select*/
- return 0;
-
- if (mode==SIMEDGE_LENGTH) { /*store length*/
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!eed->h) /* dont calc data for hidden edges*/
- eed->tmp.fp= len_v3v3(eed->v1->co, eed->v2->co);
- }
- } else if (mode==SIMEDGE_FACE) { /*store face users*/
- EditFace *efa;
- /* cound how many faces each edge uses use tmp->l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->e1->tmp.l++;
- efa->e2->tmp.l++;
- efa->e3->tmp.l++;
- if (efa->e4) efa->e4->tmp.l++;
- }
- } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
- EditFace *efa;
- int j;
- /* cound how many faces each edge uses use tmp.l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- /* here we use the edges temp data to assign a face
- if a face has already been assigned (eed->f2==1)
- we calculate the angle between the current face and
- the edges previously found face.
- store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
- but tagging eed->f2==2, so we know not to look at it again.
- This only works for edges that connect to 2 faces. but its good enough
- */
-
- /* se we can loop through face edges*/
- j=0;
- eed= efa->e1;
- while (j<4) {
- if (j==1) eed= efa->e2;
- else if (j==2) eed= efa->e3;
- else if (j==3) {
- eed= efa->e4;
- if (!eed)
- break;
- } /* done looping */
-
- if (!eed->h) { /* dont calc data for hidden edges*/
- if (eed->f2==2)
- break;
- else if (eed->f2==0) /* first access, assign the face */
- eed->tmp.f= efa;
- else if (eed->f2==1) /* second, we assign the angle*/
- eed->tmp.fp= RAD2DEGF(angle_v2v2(eed->tmp.f->n, efa->n))/180;
- eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
- }
- j++;
- }
- }
- }
-
- for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
- if (base_eed->f1) {
- if (mode==SIMEDGE_LENGTH) { /* same length */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_DIR) { /* same direction */
- float base_dir[3], dir[3], angle;
- sub_v3_v3v3(base_dir, base_eed->v1->co, base_eed->v2->co);
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (!(eed->f & SELECT) && !eed->h) {
- sub_v3_v3v3(dir, eed->v1->co, eed->v2->co);
- angle= RAD2DEGF(angle_v2v2(base_dir, dir));
-
- if (angle>90.0f) /* use the smallest angle between the edges */
- angle= fabsf(angle-180.0f);
-
- if (angle / 90.0f<=thresh) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- } else if (mode==SIMEDGE_FACE) { /* face users */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- base_eed->tmp.l==eed->tmp.l
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- eed->f2==2 &&
- (fabsf(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_CREASE) { /* edge crease */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (fabsf(base_eed->crease-eed->crease) <= thresh)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_SEAM) { /* edge seam */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (eed->seam == base_eed->seam)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (
- !(eed->f & SELECT) &&
- !eed->h &&
- (eed->sharp == base_eed->sharp)
- ) {
- EM_select_edge(eed, 1);
- selcount++;
- deselcount--;
- if (!deselcount) /*have we selected all posible faces?, if so return*/
- return selcount;
- }
- }
- }
- }
- }
- return selcount;
-}
-/* wrap the above function but do selection flushing edge to face */
-static int similar_edge_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- int selcount = similar_edge_select__internal(em, RNA_int_get(op->ptr, "type"), RNA_float_get(op->ptr, "threshold"));
-
- if (selcount) {
- /* here was an edge-mode only select flush case, has to be generalized */
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-/* ********************************* */
-
-static int similar_vert_select_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditVert *eve, *base_eve=NULL;
- unsigned int selcount=0; /* count how many new edges we select*/
-
- /*count how many visible selected edges there are,
- so we can return when there are none left */
- unsigned int deselcount=0;
- int mode= RNA_enum_get(op->ptr, "type");
- float thresh = RNA_float_get(op->ptr, "threshold");
-
- short ok=0;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (!eve->h) {
- if (eve->f & SELECT) {
- eve->f1=1;
- ok=1;
- } else {
- eve->f1=0;
- deselcount++;
- }
- /* set all eve->tmp.l to 0 we use them later.*/
- eve->tmp.l=0;
- }
-
- }
-
- if (!ok || !deselcount) { /* no data selected OR no more data to select*/
- BKE_mesh_end_editmesh(me, em);
- return 0;
- }
-
- if(mode == SIMVERT_FACE) {
- /* store face users */
- EditFace *efa;
-
- /* count how many faces each edge uses use tmp->l */
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->v1->tmp.l++;
- efa->v2->tmp.l++;
- efa->v3->tmp.l++;
- if (efa->v4) efa->v4->tmp.l++;
- }
- }
-
-
- for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
- if (base_eve->f1) {
-
- if(mode == SIMVERT_NORMAL) {
- float angle;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (!(eve->f & SELECT) && !eve->h) {
- angle= RAD2DEGF(angle_v2v2(base_eve->no, eve->no));
- if (angle/180.0f<=thresh) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) {/*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- }
- }
- }
- }
- else if(mode == SIMVERT_FACE) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if (
- !(eve->f & SELECT) &&
- !eve->h &&
- base_eve->tmp.l==eve->tmp.l
- ) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) {/*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- }
- }
- }
- else if(mode == SIMVERT_VGROUP) {
- MDeformVert *dvert, *base_dvert;
- short i, j; /* weight index */
-
- base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
- CD_MDEFORMVERT);
-
- if (!base_dvert || base_dvert->totweight == 0) {
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- dvert= CustomData_em_get(&em->vdata, eve->data,
- CD_MDEFORMVERT);
-
- if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
- /* do the extra check for selection in the following if, so were not
- checking verts that may be already selected */
- for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
- for (j=0; dvert->totweight >j; j++) {
- if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
- eve->f |= SELECT;
- selcount++;
- deselcount--;
- if (!deselcount) { /*have we selected all posible faces?, if so return*/
- BKE_mesh_end_editmesh(me, em);
- return selcount;
- }
- break;
- }
- }
- }
- }
- }
- }
- }
- } /* end basevert loop */
-
- if(selcount) {
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_FINISHED;
- }
-
- BKE_mesh_end_editmesh(me, em);
- return OPERATOR_CANCELLED;
-}
-
-static int select_similar_exec(bContext *C, wmOperator *op)
-{
- int type= RNA_enum_get(op->ptr, "type");
-
- if(type < 100)
- return similar_vert_select_exec(C, op);
- else if(type < 200)
- return similar_edge_select_exec(C, op);
- else
- return similar_face_select_exec(C, op);
-}
-
-static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- Object *obedit= CTX_data_edit_object(C);
- EnumPropertyItem *item= NULL;
- int a, totitem= 0;
-
- if (C == NULL) {
- return prop_similar_types;
- }
-
- if(obedit && obedit->type == OB_MESH) {
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(a=SIMVERT_NORMAL; a<=SIMVERT_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(a=SIMEDGE_LENGTH; a<=SIMEDGE_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- else if(em->selectmode & SCE_SELECT_FACE) {
- for(a=SIMFACE_MATERIAL; a<=SIMFACE_TOT; a++)
- RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
- }
- }
-
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
-
- return item;
-}
-
-void MESH_OT_select_similar(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Select Similar";
- ot->description= "Select similar vertices, edges or faces by property types";
- ot->idname= "MESH_OT_select_similar";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= select_similar_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
- RNA_def_enum_funcs(prop, select_similar_type_itemf);
- ot->prop= prop;
- RNA_def_float(ot->srna, "threshold", 0.01f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 100.f);
-}
-
-/* ******************************************* */
-
-
-int mesh_layers_menu_charlen(CustomData *data, int type)
-{
- int i, len = 0;
- /* see if there is a duplicate */
- for(i=0; i<data->totlayer; i++) {
- if((&data->layers[i])->type == type) {
- /* we could count the chars here but we'll just assumeme each
- * is 32 chars with some room for the menu text - 40 should be fine */
- len+=40;
- }
- }
- return len;
-}
-
-/* this function adds menu text into an existing string.
- * this string's size should be allocated with mesh_layers_menu_charlen */
-void mesh_layers_menu_concat(CustomData *data, int type, char *str)
-{
- int i, count = 0;
- char *str_pt = str;
- CustomDataLayer *layer;
-
- /* see if there is a duplicate */
- for(i=0; i<data->totlayer; i++) {
- layer = &data->layers[i];
- if(layer->type == type) {
- str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
- count++;
- }
- }
-}
-
-int mesh_layers_menu(CustomData *data, int type) {
- int ret;
- char *str_pt, *str;
-
- str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
- str[0] = '\0';
-
- str_pt += sprintf(str_pt, "Layers%%t|");
-
- mesh_layers_menu_concat(data, type, str_pt);
-
- ret = pupmenu(str);
- MEM_freeN(str);
- return ret;
-}
-
-static void EM_mesh_copy_edge(EditMesh *em, short type)
-{
- EditSelection *ese;
- short change=0;
-
- EditEdge *eed, *eed_act;
- float vec[3], vec_mid[3], eed_len, eed_len_act;
-
- if (!em) return;
-
- ese = em->selected.last;
- if (!ese) return;
-
- eed_act = (EditEdge*)ese->data;
-
- switch (type) {
- case 1: /* copy crease */
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
- eed->crease = eed_act->crease;
- change = 1;
- }
- }
- break;
- case 2: /* copy bevel weight */
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act && eed->bweight != eed_act->bweight) {
- eed->bweight = eed_act->bweight;
- change = 1;
- }
- }
- break;
-
- case 3: /* copy length */
- eed_len_act = len_v3v3(eed_act->v1->co, eed_act->v2->co);
- for(eed=em->edges.first; eed; eed=eed->next) {
- if (eed->f & SELECT && eed != eed_act) {
-
- eed_len = len_v3v3(eed->v1->co, eed->v2->co);
-
- if (eed_len == eed_len_act) continue;
- /* if this edge is zero length we cont do anything with it*/
- if (eed_len == 0.0f) continue;
- if (eed_len_act == 0.0f) {
- add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
- mul_v3_fl(vec_mid, 0.5);
- VECCOPY(eed->v1->co, vec_mid);
- VECCOPY(eed->v2->co, vec_mid);
- } else {
- /* copy the edge length */
- add_v3_v3v3(vec_mid, eed->v1->co, eed->v2->co);
- mul_v3_fl(vec_mid, 0.5);
-
- /* SCALE 1 */
- sub_v3_v3v3(vec, eed->v1->co, vec_mid);
- mul_v3_fl(vec, eed_len_act/eed_len);
- add_v3_v3v3(eed->v1->co, vec, vec_mid);
-
- /* SCALE 2 */
- sub_v3_v3v3(vec, eed->v2->co, vec_mid);
- mul_v3_fl(vec, eed_len_act/eed_len);
- add_v3_v3v3(eed->v2->co, vec, vec_mid);
- }
- change = 1;
- }
- }
-
- if (change)
- recalc_editnormals(em);
-
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-static void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
-{
- short change=0;
-
- EditFace *efa, *efa_act;
- MTFace *tf, *tf_act = NULL;
- MCol *mcol, *mcol_act = NULL;
- if (!em) return;
- efa_act = EM_get_actFace(em, 0);
-
- if (!efa_act) return;
-
- tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
- mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
-
- switch (type) {
- case 1: /* copy material */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
- efa->mat_nr = efa_act->mat_nr;
- change = 1;
- }
- }
- break;
- case 2: /* copy image */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (tf_act->tpage) {
- tf->tpage = tf_act->tpage;
- tf->mode |= TF_TEX;
- } else {
- tf->tpage = NULL;
- tf->mode &= ~TF_TEX;
- }
- tf->tile= tf_act->tile;
- change = 1;
- }
- }
- break;
-
- case 3: /* copy UV's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
- change = 1;
- }
- }
- break;
- case 4: /* mode's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->mode= tf_act->mode;
- change = 1;
- }
- }
- break;
- case 5: /* copy transp's */
- if (!tf_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- return;
- }
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- tf->transp= tf_act->transp;
- change = 1;
- }
- }
- break;
-
- case 6: /* copy vcols's */
- if (!mcol_act) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
- return;
- } else {
- /* guess the 4th color if needs be */
- float val =- 1;
-
- if (!efa_act->v4) {
- /* guess the othe vale, we may need to use it
- *
- * Modifying the 4th value of the mcol is ok here since its not seen
- * on a triangle
- * */
- val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->r = (char)val;
-
- val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->g = (char)val;
-
- val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
- (mcol_act+3)->b = (char)val;
- }
-
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT && efa != efa_act) {
- /* TODO - make copy from tri to quad guess the 4th vert */
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- memcpy(mcol, mcol_act, sizeof(MCol)*4);
- change = 1;
- }
- }
- }
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-
-void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type)
-{
- short change=0;
-
- EditFace *efa;
- MTFace *tf, *tf_from;
- MCol *mcol, *mcol_from;
-
- if (!em) return;
-
- switch(type) {
- case 7:
- case 8:
- case 9:
- if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
- BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple uv/image layers");
- return;
- } else {
- int layer_orig_idx, layer_idx;
-
- layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
- if (layer_idx<0) return;
-
- /* warning, have not updated mesh pointers however this is not needed since we swicth back */
- layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
- if (layer_idx==layer_orig_idx)
- return;
-
- /* get the tfaces */
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
- /* store the tfaces in our temp */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- }
- }
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
- }
- break;
-
- case 10: /* select vcol layers - make sure this stays in sync with above code */
- if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
- BKE_report(op->reports, RPT_WARNING, "mesh does not have multiple color layers");
- return;
- } else {
- int layer_orig_idx, layer_idx;
-
- layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
- if (layer_idx<0) return;
-
- /* warning, have not updated mesh pointers however this is not needed since we swicth back */
- layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
- if (layer_idx==layer_orig_idx)
- return;
-
- /* get the tfaces */
- CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
- /* store the tfaces in our temp */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- }
- }
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
-
- }
- break;
- }
-
- /* layer copy only - sanity checks done above */
- switch (type) {
- case 7: /* copy UV's only */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, tf_from->uv, sizeof(tf->uv));
- change = 1;
- }
- }
- break;
- case 8: /* copy image settings only */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (tf_from->tpage) {
- tf->tpage = tf_from->tpage;
- tf->mode |= TF_TEX;
- } else {
- tf->tpage = NULL;
- tf->mode &= ~TF_TEX;
- }
- tf->tile= tf_from->tile;
- change = 1;
- }
- }
- break;
- case 9: /* copy all tface info */
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf_from = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
- tf->tpage = tf_from->tpage;
- tf->mode = tf_from->mode;
- tf->transp = tf_from->transp;
- change = 1;
- }
- }
- break;
- case 10:
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- mcol_from = (MCol *)efa->tmp.p;
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- memcpy(mcol, mcol_from, sizeof(MCol)*4);
- change = 1;
- }
- }
- break;
- }
-
- if (change) {
-// DAG_id_tag_update(obedit->data, 0);
-
- }
-}
-
-
-/* ctrl+c in mesh editmode */
-static void mesh_copy_menu(EditMesh *em, wmOperator *op)
-{
- EditSelection *ese;
- int ret;
- if (!em) return;
-
- ese = em->selected.last;
-
- /* Faces can have a NULL ese, so dont return on a NULL ese here */
-
- if(ese && ese->type == EDITVERT) {
- /* EditVert *ev, *ev_act = (EditVert*)ese->data;
- ret= pupmenu(""); */
- } else if(ese && ese->type == EDITEDGE) {
- ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Bevel Weight%x2|Length%x3");
- if (ret<1) return;
-
- EM_mesh_copy_edge(em, ret);
-
- } else if(ese==NULL || ese->type == EDITFACE) {
- ret= pupmenu(
- "Copy Face Selected%t|"
- "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
- "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
-
- "TexFace UVs from layer%x7|"
- "TexFace Images from layer%x8|"
- "TexFace All from layer%x9|"
- "Vertex Colors from layer%x10");
- if (ret<1) return;
-
- if (ret<=6) {
- EM_mesh_copy_face(em, op, ret);
- } else {
- EM_mesh_copy_face_layer(em, op, ret);
- }
- }
-}
-
-/* **************** LOOP SELECTS *************** */
-
-/* selects quads in loop direction of indicated edge */
-/* only flush over edges with valence <= 2 */
-void faceloop_select(EditMesh *em, EditEdge *startedge, int select)
-{
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* tag startedge OK*/
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0 && efa->e4 && efa->f1==0) { /* not done quad */
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
-
- /* if edge tagged, select opposing edge and mark face ok */
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- /* (de)select the faces */
- if(select!=2) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f1) EM_select_face(efa, select);
- }
- }
-}
-
-
-/* helper for edgeloop_select, checks for eed->f2 tag in faces */
-static int edge_not_in_tagged_face(EditMesh *em, EditEdge *eed)
-{
- EditFace *efa;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
- if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
- return 0;
- }
- }
- }
- }
- return 1;
-}
-
-static void ensure_ed_vert_sel(EditMesh *em)
-{
- EditEdge *eed;
-
- /* EM_selectmode_flush() doesnt take into account that deselected edges
- * may be still connected to selected edges [#26885] */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- eed->v1->f |= SELECT;
- eed->v2->f |= SELECT;
- }
- }
-}
-
-/* selects or deselects edges that:
-- if edges has 2 faces:
- - has vertices with valence of 4
- - not shares face with previous edge
-- if edge has 1 face:
- - has vertices with valence 4
- - not shares face with previous edge
- - but also only 1 face
-- if edge no face:
- - has vertices with valence 2
-*/
-static void edgeloop_select(EditMesh *em, EditEdge *starteed, int select)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
- /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->f1= 0;
- eve->f2= 0;
- }
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- if((eed->h & 1)==0) { /* fgon edges add to valence too */
- eed->v1->f1++; eed->v2->f1++;
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* looped edges & vertices get tagged f2 */
- starteed->f2= 1;
- if(starteed->v1->f1<5) starteed->v1->f2= 1;
- if(starteed->v2->f1<5) starteed->v2->f2= 1;
- /* sorry, first edge isnt even ok */
- if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
-
- while(looking) {
- looking= 0;
-
- /* find correct valence edges which are not tagged yet, but connect to tagged one */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
- if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
- /* new edge is not allowed to be in face with tagged edge */
- if(edge_not_in_tagged_face(em, eed)) {
- if(eed->f1==starteed->f1) { /* same amount of faces */
- looking= 1;
- eed->f2= 1;
- if(eed->v2->f1<5) eed->v2->f2= 1;
- if(eed->v1->f1<5) eed->v1->f2= 1;
- }
- }
- }
- }
- }
- }
- /* and we do the select */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
-
- if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
- ensure_ed_vert_sel(em);
- }
-}
-
-/*
- Almostly exactly the same code as faceloop select
-*/
-static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
-{
- EditEdge *eed;
- EditFace *efa;
- int looking= 1;
-
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- /* tag startedge OK */
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
-
- /* if edge tagged, select opposing edge and mark face ok */
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
- }
- }
- }
-
- /* (de)select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
- }
-
- if(select == FALSE && !(em->selectmode & SCE_SELECT_VERTEX)) { /* only when not in vert sel [#26931] */
- ensure_ed_vert_sel(em);
- }
-}
-
-static int loop_multiselect(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditEdge *eed;
- EditEdge **edarray;
- int edindex, edfirstcount;
- int looptype= RNA_boolean_get(op->ptr, "ring");
-
- /* sets em->totedgesel */
- EM_nedges_selected(em);
-
- edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
- edindex = 0;
- edfirstcount = em->totedgesel;
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f&SELECT){
- edarray[edindex] = eed;
- edindex += 1;
- }
- }
-
- if(looptype){
- for(edindex = 0; edindex < edfirstcount; edindex +=1){
- eed = edarray[edindex];
- edgering_select(em, eed,SELECT);
- }
- EM_selectmode_flush(em);
- }
- else{
- for(edindex = 0; edindex < edfirstcount; edindex +=1){
- eed = edarray[edindex];
- edgeloop_select(em, eed,SELECT);
- }
- EM_selectmode_flush(em);
- }
- MEM_freeN(edarray);
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_multi_select(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Multi Select Loops";
- ot->description= "Select a loop of connected edges by connection type";
- ot->idname= "MESH_OT_loop_multi_select";
-
- /* api callbacks */
- ot->exec= loop_multiselect;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
-}
-
-
-/* ***************** MAIN MOUSE SELECTION ************** */
-
-
-/* ***************** loop select (non modal) ************** */
-
-static void mouse_mesh_loop(bContext *C, const short 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 short mval[2])
-{
- ViewContext vc;
- EditMesh *em;
- EditEdge *eed, *eed_act= NULL;
- int dist= 50;
-
- em_setup_viewcontext(C, &vc);
- vc.mval[0]= mval[0];
- vc.mval[1]= mval[1];
- em= vc.em;
-
- /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
- view3d_validate_backbuf(&vc);
-
- eed= findnearestedge(&vc, &dist);
- if(eed) {
- Mesh *me= vc.obedit->data;
- int path = 0;
-
- if (em->selected.last) {
- EditSelection *ese = em->selected.last;
-
- if(ese && ese->type == EDITEDGE) {
- eed_act = (EditEdge*)ese->data;
- if (eed_act != eed) {
- if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) { /* <- this is where the magic happens */
- EM_remove_selection(em, eed_act, EDITEDGE);
- path = 1;
- }
- }
- }
- }
- if (path==0) {
- int act = (edgetag_context_check(vc.scene, eed)==0);
- edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
- }
-
- /* even if this is selected it may not be in the selection list */
- if(edgetag_context_check(vc.scene, eed)==0) {
- EM_remove_selection(em, eed, EDITEDGE);
- }
- else {
- /* other modes need to keep the last edge tagged */
- if(eed_act) {
- if(vc.scene->toolsettings->edge_mode!=EDGE_MODE_SELECT) {
- /* for non-select modes, always de-select the previous active edge */
- EM_select_edge(eed_act, 0);
- }
- }
-
- /* set the new edge active */
- EM_select_edge(eed, 1);
- EM_store_selection(em, eed, EDITEDGE);
- }
-
- EM_selectmode_flush(em);
-
- /* force drawmode for mesh */
- switch (vc.scene->toolsettings->edge_mode) {
-
- case EDGE_MODE_TAG_SEAM:
- me->drawflag |= ME_DRAWSEAMS;
- break;
- case EDGE_MODE_TAG_SHARP:
- me->drawflag |= ME_DRAWSHARP;
- break;
- case EDGE_MODE_TAG_CREASE:
- me->drawflag |= ME_DRAWCREASES;
- break;
- case EDGE_MODE_TAG_BEVEL:
- me->drawflag |= ME_DRAWBWEIGHTS;
- break;
- }
-
- /* live unwrap while tagging */
- if( (vc.scene->toolsettings->edge_mode_live_unwrap) &&
- (vc.scene->toolsettings->edge_mode == EDGE_MODE_TAG_SEAM) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE))
- ) {
- ED_unwrap_lscm(vc.scene, vc.obedit, FALSE); /* unwrap all not just sel */
- }
-
- DAG_id_tag_update(vc.obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
- }
-}
-
-
-static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
-{
-
- view3d_operator_needs_opengl(C);
-
- mouse_mesh_shortest_path(C, event->mval);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_shortest_path_select_poll(bContext *C)
-{
- if(ED_operator_editmesh_region_view3d(C)) {
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
- return (em->selectmode & SCE_SELECT_EDGE);
- }
- return 0;
-}
-
-void MESH_OT_select_shortest_path(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shortest Path Select";
- ot->description= "Select shortest path between two selections";
- ot->idname= "MESH_OT_select_shortest_path";
-
- /* api callbacks */
- ot->invoke= mesh_shortest_path_select_invoke;
- ot->poll= mesh_shortest_path_select_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
-}
-
-
-/* ************************************************** */
-
-
-/* here actual select happens */
-/* gets called via generic mouse select operator */
-int mouse_mesh(bContext *C, const short 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;
-// BIF_preview_changed(ID_MA);
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data);
-
- return 1;
- }
-
- return 0;
-}
-
-/* *********** select linked ************* */
-
-/* for use with selectconnected_delimit_mesh only! */
-#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
-#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
-
-#define face_tag(efa)\
-if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
-else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
-
-/* all - 1) use all faces for extending the selection 2) only use the mouse face
-* sel - 1) select 0) deselect
-* */
-
-/* legacy warning, this function combines too much :) */
-static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
-{
- EditMesh *em= vc->em;
- EditFace *efa;
- EditEdge *eed;
- EditVert *eve;
- short done=1, change=0;
-
- if(em->faces.first==0) return OPERATOR_CANCELLED;
-
- /* flag all edges+faces as off*/
- for(eed= em->edges.first; eed; eed= eed->next)
- eed->tmp.l=0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->tmp.l = 0;
- }
-
- if (all) {
- // XXX verts?
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT)
- eed->tmp.l= 1;
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
-
- if (efa->f & SELECT) {
- face_tag(efa);
- } else {
- efa->tmp.l = 0;
- }
- }
- }
- else {
- if( unified_findnearest(vc, &eve, &eed, &efa) ) {
-
- if(efa) {
- efa->tmp.l = 1;
- face_tag(efa);
- }
- else if(eed)
- eed->tmp.l= 1;
- else {
- for(eed= em->edges.first; eed; eed= eed->next)
- if(eed->v1==eve || eed->v2==eve)
- break;
- eed->tmp.l= 1;
- }
- }
- else
- return OPERATOR_FINISHED;
- }
-
- while(done==1) {
- done= 0;
- /* simple algo - select all faces that have a selected edge
- * this intern selects the edge, repeat until nothing is left to do */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if ((efa->tmp.l == 0) && (!efa->h)) {
- if (is_face_tag(efa)) {
- face_tag(efa);
- done= 1;
- }
- }
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (efa->tmp.l) {
- if (sel) {
- if (!(efa->f & SELECT)) {
- EM_select_face(efa, 1);
- change = 1;
- }
- } else {
- if (efa->f & SELECT) {
- EM_select_face(efa, 0);
- change = 1;
- }
- }
- }
- }
-
- if (!change)
- return OPERATOR_CANCELLED;
-
- if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundaries */
- for(efa= em->faces.first; efa; efa= efa->next)
- if (efa->f & SELECT)
- EM_select_face(efa, 1);
-
- // if (EM_texFaceCheck())
-
- return OPERATOR_FINISHED;
-}
-
-#undef is_edge_delimit_ok
-#undef is_face_tag
-#undef face_tag
-
-static void linked_limit_default(bContext *C, wmOperator *op) {
- if(!RNA_property_is_set(op->ptr, "limit")) {
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
- if(em->selectmode == SCE_SELECT_FACE)
- RNA_boolean_set(op->ptr, "limit", TRUE);
- }
-}
-
-static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
-{
- Object *obedit= CTX_data_edit_object(C);
- ViewContext vc;
- EditVert *eve, *v1, *v2;
- EditEdge *eed;
- EditFace *efa;
- short done=1, toggle=0;
- int sel= !RNA_boolean_get(op->ptr, "deselect");
- int limit;
-
- linked_limit_default(C, op);
-
- limit = RNA_boolean_get(op->ptr, "limit");
-
- /* unified_finednearest needs ogl */
- view3d_operator_needs_opengl(C);
-
- /* setup view context for argument to callbacks */
- em_setup_viewcontext(C, &vc);
-
- if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
-
- vc.mval[0]= event->mval[0];
- vc.mval[1]= event->mval[1];
-
- /* return warning! */
- if(limit) {
- int retval= select_linked_limited_invoke(&vc, 0, sel);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- return retval;
- }
-
- if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_CANCELLED;
- }
-
- /* clear test flags */
- for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
-
- /* start vertex/face/edge */
- if(eve) eve->f1= 1;
- else if(eed) eed->v1->f1= eed->v2->f1= 1;
- else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
-
- /* set flag f1 if affected */
- while(done==1) {
- done= 0;
- toggle++;
-
- if(toggle & 1) eed= vc.em->edges.first;
- else eed= vc.em->edges.last;
-
- while(eed) {
- v1= eed->v1;
- v2= eed->v2;
-
- if(eed->h==0) {
- if(v1->f1 && v2->f1==0) {
- v2->f1= 1;
- done= 1;
- }
- else if(v1->f1==0 && v2->f1) {
- v1->f1= 1;
- done= 1;
- }
- }
-
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
-
- /* now use vertex f1 flag to select/deselect */
- for(eed= vc.em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f1 && eed->v2->f1)
- EM_select_edge(eed, sel);
- }
- for(efa= vc.em->faces.first; efa; efa= efa->next) {
- if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
- EM_select_face(efa, sel);
- }
- /* no flush needed, connected geometry is done */
-
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_linked_pick(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked";
- ot->description= "(un)select all vertices linked to the active mesh";
- ot->idname= "MESH_OT_select_linked_pick";
-
- /* api callbacks */
- ot->invoke= select_linked_pick_invoke;
- ot->poll= ED_operator_editmesh_region_view3d;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)");
-}
-
-
-/* ************************* */
-
-void selectconnected_mesh_all(EditMesh *em)
-{
- EditVert *v1,*v2;
- EditEdge *eed;
- short done=1, toggle=0;
-
- if(em->edges.first==0) return;
-
- while(done==1) {
- done= 0;
-
- toggle++;
- if(toggle & 1) eed= em->edges.first;
- else eed= em->edges.last;
-
- while(eed) {
- v1= eed->v1;
- v2= eed->v2;
- if(eed->h==0) {
- if(v1->f & SELECT) {
- if( (v2->f & SELECT)==0 ) {
- v2->f |= SELECT;
- done= 1;
- }
- }
- else if(v2->f & SELECT) {
- if( (v1->f & SELECT)==0 ) {
- v1->f |= SELECT;
- done= 1;
- }
- }
- }
- if(toggle & 1) eed= eed->next;
- else eed= eed->prev;
- }
- }
-
- /* now use vertex select flag to select rest */
- EM_select_flush(em);
-
- // if (EM_texFaceCheck())
-}
-
-static int select_linked_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if( RNA_boolean_get(op->ptr, "limit") ) {
- ViewContext vc;
- em_setup_viewcontext(C, &vc);
- select_linked_limited_invoke(&vc, 1, 1);
- }
- else
- selectconnected_mesh_all(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-static int select_linked_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- linked_limit_default(C, op);
- return select_linked_exec(C, op);
-}
-
-void MESH_OT_select_linked(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked All";
- ot->description= "Select all vertices linked to the active mesh";
- ot->idname= "MESH_OT_select_linked";
-
- /* api callbacks */
- ot->exec= select_linked_exec;
- ot->invoke= select_linked_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "Limit selection by seam boundaries (faces only)");
-}
-
-
-/* ************************* */
-
-/* swap is 0 or 1, if 1 it hides not selected */
-void EM_hide_mesh(EditMesh *em, int swap)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
- int a;
-
- if(em==NULL) return;
-
- /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
- /* - vertex hidden, always means edge is hidden too
- - edge hidden, always means face is hidden too
- - face hidden, only set face hide
- - then only flush back down what's absolute hidden
- */
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if((eve->f & SELECT)!=swap) {
- eve->f &= ~SELECT;
- eve->h= 1;
- }
- }
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->h || eed->v2->h) {
- eed->h |= 1;
- eed->f &= ~SELECT;
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
- efa->h= 1;
- efa->f &= ~SELECT;
- }
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if((eed->f & SELECT)!=swap) {
- eed->h |= 1;
- EM_select_edge(eed, 0);
- }
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
- efa->h= 1;
- efa->f &= ~SELECT;
- }
- }
- }
- else {
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if((efa->f & SELECT)!=swap) {
- efa->h= 1;
- EM_select_face(efa, 0);
- }
- }
- }
-
- /* flush down, only whats 100% hidden */
- for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
-
- if(em->selectmode & SCE_SELECT_FACE) {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h) a= 1; else a= 2;
- efa->e1->f1 |= a;
- efa->e2->f1 |= a;
- efa->e3->f1 |= a;
- if(efa->e4) efa->e4->f1 |= a;
- /* When edges are not delt with in their own loop, we need to explicitly re-selct select edges that are joined to unselected faces */
- if (swap && (em->selectmode == SCE_SELECT_FACE) && (efa->f & SELECT)) {
- EM_select_face(efa, 1);
- }
- }
- }
-
- if(em->selectmode >= SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==1) eed->h |= 1;
- if(eed->h & 1) a= 1; else a= 2;
- eed->v1->f1 |= a;
- eed->v2->f1 |= a;
- }
- }
-
- if(em->selectmode >= SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1==1) eve->h= 1;
- }
- }
-
- em->totedgesel= em->totfacesel= em->totvertsel= 0;
-// if(EM_texFaceCheck())
-
- // DAG_id_tag_update(obedit->data, 0);
-}
-
-static int hide_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_hide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Hide Selection";
- ot->description= "Hide (un)selected vertices, edges or faces";
- ot->idname= "MESH_OT_hide";
-
- /* api callbacks */
- ot->exec= hide_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
-}
-
-void EM_reveal_mesh(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- if(em==NULL) return;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h) {
- eve->h= 0;
- eve->f |= SELECT;
- }
- }
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h & 1) {
- eed->h &= ~1;
- if(em->selectmode & SCE_SELECT_VERTEX);
- else EM_select_edge(eed, 1);
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h) {
- efa->h= 0;
- if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
- else EM_select_face(efa, 1);
- }
- }
-
- EM_fgon_flags(em); /* redo flags and indices for fgons */
- EM_selectmode_flush(em);
-
-// if (EM_texFaceCheck())
-// DAG_id_tag_update(obedit->data, 0);
-}
-
-static int reveal_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_reveal_mesh(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_reveal(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Reveal Hidden";
- ot->description= "Reveal all hidden vertices, edges and faces";
- ot->idname= "MESH_OT_reveal";
-
- /* api callbacks */
- ot->exec= reveal_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int select_by_number_vertices_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditFace *efa;
- int numverts= RNA_enum_get(op->ptr, "type");
-
- /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
- * faces
- */
-
- /* for loose vertices/edges, we first select all, loop below will deselect */
- if(numverts==5) {
- EM_set_flag_all(em, SELECT);
- }
- else if(em->selectmode!=SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
- return OPERATOR_CANCELLED;
- }
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if (efa->e4) {
- EM_select_face(efa, (numverts==4) );
- }
- else {
- EM_select_face(efa, (numverts==3) );
- }
- }
-
- EM_selectmode_flush(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
-{
- static const EnumPropertyItem type_items[]= {
- {3, "TRIANGLES", 0, "Triangles", NULL},
- {4, "QUADS", 0, "Quads", NULL},
- {5, "OTHER", 0, "Other", NULL},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select by Number of Vertices";
- ot->description= "Select vertices or faces by vertex count";
- ot->idname= "MESH_OT_select_by_number_vertices";
-
- /* api callbacks */
- ot->exec= select_by_number_vertices_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
-}
-
-
-static int select_mirror_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- int extend= RNA_boolean_get(op->ptr, "extend");
-
- EM_select_mirrored(obedit, em, extend);
- EM_selectmode_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Mirror";
- ot->description= "Select mesh items at mirrored locations";
- ot->idname= "MESH_OT_select_mirror";
-
- /* api callbacks */
- ot->exec= select_mirror_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the existing selection");
-}
-
-static int select_sharp_edges_exec(bContext *C, wmOperator *op)
-{
- /* Find edges that have exactly two neighboring faces,
- * check the angle between those faces, and if angle is
- * small enough, select the edge
- */
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditEdge *eed;
- EditFace *efa;
- EditFace **efa1;
- EditFace **efa2;
- intptr_t edgecount = 0, i = 0;
- float sharpness, fsharpness;
-
- /* 'standard' behaviour - check if selected, then apply relevant selection */
-
- if(em->selectmode==SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- sharpness= RNA_float_get(op->ptr, "sharpness");
- fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f;
-
- /* count edges, use tmp.l */
- eed= em->edges.first;
- while(eed) {
- edgecount++;
- eed->tmp.l = i;
- eed= eed->next;
- ++i;
- }
-
- /* for each edge, we want a pointer to two adjacent faces */
- efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
- efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
-
-#define face_table_edge(eed) { \
- i = eed->tmp.l; \
- if (i != -1) { \
- if (efa1[i]) { \
- if (efa2[i]) { \
- /* invalidate, edge has more than two neighbors */ \
- eed->tmp.l = -1; \
- } \
- else { \
- efa2[i] = efa; \
- } \
- } \
- else { \
- efa1[i] = efa; \
- } \
- } \
- }
-
- /* find the adjacent faces of each edge, we want only two */
- efa= em->faces.first;
- while(efa) {
- face_table_edge(efa->e1);
- face_table_edge(efa->e2);
- face_table_edge(efa->e3);
- if (efa->e4) {
- face_table_edge(efa->e4);
- }
- efa= efa->next;
- }
-
-#undef face_table_edge
-
- eed = em->edges.first;
- while(eed) {
- i = eed->tmp.l;
- if (i != -1) {
- /* edge has two or less neighboring faces */
- if ( (efa1[i]) && (efa2[i]) ) {
- /* edge has exactly two neighboring faces, check angle */
- float angle;
- angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
- efa1[i]->n[1]*efa2[i]->n[1] +
- efa1[i]->n[2]*efa2[i]->n[2]);
- if (fabsf(angle) >= fsharpness)
- EM_select_edge(eed, 1);
- }
- }
-
- eed= eed->next;
- }
-
- MEM_freeN(efa1);
- MEM_freeN(efa2);
-
-// if (EM_texFaceCheck())
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data); //TODO is this needed ?
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edges_select_sharp(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Sharp Edges";
- ot->description= "Marked selected edges as sharp";
- ot->idname= "MESH_OT_edges_select_sharp";
-
- /* api callbacks */
- ot->exec= select_sharp_edges_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
-}
-
-
-static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
-{
- /* Find faces that are linked to selected faces that are
- * relatively flat (angle between faces is higher than
- * specified angle)
- */
- EditEdge *eed;
- EditFace *efa;
- EditFace **efa1;
- EditFace **efa2;
- intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
- float fsharpness;
-
- if(em->selectmode!=SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Only works in face selection mode");
- return;
- }
-
- fsharpness = ((180.0f - sharpness) * (float)M_PI) / 180.0f;
-
- i=0;
- /* count edges, use tmp.l */
- eed= em->edges.first;
- while(eed) {
- edgecount++;
- eed->tmp.l = i;
- eed= eed->next;
- ++i;
- }
-
- /* for each edge, we want a pointer to two adjacent faces */
- efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
- efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
- "pairs of edit face pointers");
-
-#define face_table_edge(eed) { \
- i = eed->tmp.l; \
- if (i != -1) { \
- if (efa1[i]) { \
- if (efa2[i]) { \
- /* invalidate, edge has more than two neighbors */ \
- eed->tmp.l = -1; \
- } \
- else { \
- efa2[i] = efa; \
- } \
- } \
- else { \
- efa1[i] = efa; \
- } \
- } \
- }
-
- /* find the adjacent faces of each edge, we want only two */
- efa= em->faces.first;
- while(efa) {
- face_table_edge(efa->e1);
- face_table_edge(efa->e2);
- face_table_edge(efa->e3);
- if (efa->e4) {
- face_table_edge(efa->e4);
- }
-
- /* while were at it, count the selected faces */
- if (efa->f & SELECT) ++faceselcount;
-
- efa= efa->next;
- }
-
-#undef face_table_edge
-
- eed= em->edges.first;
- while(eed) {
- i = eed->tmp.l;
- if (i != -1) {
- /* edge has two or less neighboring faces */
- if ( (efa1[i]) && (efa2[i]) ) {
- /* edge has exactly two neighboring faces, check angle */
- float angle;
- angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
- efa1[i]->n[1]*efa2[i]->n[1] +
- efa1[i]->n[2]*efa2[i]->n[2]);
- /* invalidate: edge too sharp */
- if (fabsf(angle) >= fsharpness)
- eed->tmp.l = -1;
- }
- else {
- /* invalidate: less than two neighbors */
- eed->tmp.l = -1;
- }
- }
-
- eed= eed->next;
- }
-
-#define select_flat_neighbor(eed) { \
- i = eed->tmp.l; \
- if (i!=-1) { \
- if (! (efa1[i]->f & SELECT) ) { \
- EM_select_face(efa1[i], 1); \
- ++faceselcount; \
- } \
- if (! (efa2[i]->f & SELECT) ) { \
- EM_select_face(efa2[i], 1); \
- ++faceselcount; \
- } \
- } \
- }
-
- while (faceselcount != faceselcountold) {
- faceselcountold = faceselcount;
-
- efa= em->faces.first;
- while(efa) {
- if (efa->f & SELECT) {
- select_flat_neighbor(efa->e1);
- select_flat_neighbor(efa->e2);
- select_flat_neighbor(efa->e3);
- if (efa->e4) {
- select_flat_neighbor(efa->e4);
- }
- }
- efa= efa->next;
- }
- }
-
-#undef select_flat_neighbor
-
- MEM_freeN(efa1);
- MEM_freeN(efa2);
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness"));
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Linked Flat Faces";
- ot->description= "Select linked faces by angle";
- ot->idname= "MESH_OT_faces_select_linked_flat";
-
- /* api callbacks */
- ot->exec= select_linked_flat_faces_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "sharpness", 135.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
-}
-
-static void select_non_manifold(EditMesh *em, wmOperator *op )
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- /* Selects isolated verts, and edges that do not have 2 neighboring
- * faces
- */
-
- if(em->selectmode==SCE_SELECT_FACE) {
- BKE_report(op->reports, RPT_WARNING, "Doesn't work in face selection mode");
- return;
- }
-
- eve= em->verts.first;
- while(eve) {
- /* this will count how many edges are connected
- * to this vert */
- eve->f1= 0;
- eve= eve->next;
- }
-
- eed= em->edges.first;
- while(eed) {
- /* this will count how many faces are connected to
- * this edge */
- eed->f1= 0;
- /* increase edge count for verts */
- ++eed->v1->f1;
- ++eed->v2->f1;
- eed= eed->next;
- }
-
- efa= em->faces.first;
- while(efa) {
- /* increase face count for edges */
- ++efa->e1->f1;
- ++efa->e2->f1;
- ++efa->e3->f1;
- if (efa->e4)
- ++efa->e4->f1;
- efa= efa->next;
- }
-
- /* select verts that are attached to an edge that does not
- * have 2 neighboring faces */
- eed= em->edges.first;
- while(eed) {
- if (eed->h==0 && eed->f1 != 2) {
- EM_select_edge(eed, 1);
- }
- eed= eed->next;
- }
-
- /* select isolated verts */
- if(em->selectmode & SCE_SELECT_VERTEX) {
- eve= em->verts.first;
- while(eve) {
- if (eve->f1 == 0) {
- if (!eve->h) eve->f |= SELECT;
- }
- eve= eve->next;
- }
- }
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_non_manifold_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- select_non_manifold(em, op);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_non_manifold(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Non Manifold";
- ot->description= "Select all non-manifold vertices or edges";
- ot->idname= "MESH_OT_select_non_manifold";
-
- /* api callbacks */
- ot->exec= select_non_manifold_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-void EM_select_swap(EditMesh *em) /* exported for UV */
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if(eve->f & SELECT) eve->f &= ~SELECT;
- else eve->f|= SELECT;
- }
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- EM_select_edge(eed, !(eed->f & SELECT));
- }
- }
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- EM_select_face(efa, !(efa->f & SELECT));
- }
- }
- }
-
- EM_selectmode_flush(em);
-
-// if (EM_texFaceCheck())
-
-}
-
-static int select_inverse_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_select_swap(em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_inverse(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Inverse";
- ot->description= "Select inverse of (un)selected vertices, edges or faces";
- ot->idname= "MESH_OT_select_inverse";
-
- /* api callbacks */
- ot->exec= select_inverse_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* ******************** (de)select all operator **************** */
-
-void EM_toggle_select_all(EditMesh *em) /* exported for UV */
-{
- if(EM_nvertices_selected(em))
- EM_clear_flag_all(em, SELECT);
- else
- EM_set_flag_all_selectmode(em, SELECT);
-}
-
-void EM_select_all(EditMesh *em)
-{
- EM_set_flag_all_selectmode(em, SELECT);
-}
-
-void EM_deselect_all(EditMesh *em)
-{
- EM_clear_flag_all(em, SELECT);
-}
-
-static int select_all_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- int action = RNA_enum_get(op->ptr, "action");
-
- switch (action) {
- case SEL_TOGGLE:
- EM_toggle_select_all(em);
- break;
- case SEL_SELECT:
- EM_select_all(em);
- break;
- case SEL_DESELECT:
- EM_deselect_all(em);
- break;
- case SEL_INVERT:
- EM_select_swap(em);
- break;
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select or Deselect All";
- ot->description= "Change selection of all vertices, edges or faces";
- ot->idname= "MESH_OT_select_all";
-
- /* api callbacks */
- ot->exec= select_all_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- WM_operator_properties_select_all(ot);
-}
-
-/* ******************** **************** */
-
-void EM_select_more(EditMesh *em)
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) eve->f1= 1;
- else eve->f1 = 0;
- }
-
- /* set f1 flags in vertices to select 'more' */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if (eed->v1->f & SELECT)
- eed->v2->f1 = 1;
- if (eed->v2->f & SELECT)
- eed->v1->f1 = 1;
- }
- }
-
- /* new selected edges, but not in facemode */
- if(em->selectmode <= SCE_SELECT_EDGE) {
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
- }
- }
- }
- /* new selected faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
- EM_select_face(efa, 1);
- }
- }
-}
-
-static int select_more(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ;
-
- EM_select_more(em);
-
-// if (EM_texFaceCheck(em))
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_more(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select More";
- ot->description= "Select more vertices, edges or faces connected to initial selection";
- ot->idname= "MESH_OT_select_more";
-
- /* api callbacks */
- ot->exec= select_more;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static void EM_select_less(EditMesh *em)
-{
- EditEdge *eed;
- EditFace *efa;
-
- if(em->selectmode <= SCE_SELECT_EDGE) {
- /* eed->f1 == 1: edge with a selected and deselected vert */
-
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- if(eed->h==0) {
-
- if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) )
- eed->f1= 1;
- if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) )
- eed->f1= 1;
- }
- }
-
- /* deselect edges with flag set */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if (eed->h==0 && eed->f1 == 1) {
- EM_select_edge(eed, 0);
- }
- }
- EM_deselect_flush(em);
-
- }
- else {
- /* deselect faces with 1 or more deselect edges */
- /* eed->f1 == mixed selection edge */
- for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->f & SELECT) {
- efa->e1->f1 |= 1;
- efa->e2->f1 |= 1;
- efa->e3->f1 |= 1;
- if(efa->e4) efa->e4->f1 |= 1;
- }
- else {
- efa->e1->f1 |= 2;
- efa->e2->f1 |= 2;
- efa->e3->f1 |= 2;
- if(efa->e4) efa->e4->f1 |= 2;
- }
- }
- }
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) {
- EM_select_face(efa, 0);
- }
- }
- }
- EM_selectmode_flush(em);
-
- }
-}
-
-static int select_less(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- EM_select_less(em);
-
-// if (EM_texFaceCheck(em))
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_less(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Less";
- ot->description= "Select less vertices, edges or faces connected to initial selection";
- ot->idname= "MESH_OT_select_less";
-
- /* api callbacks */
- ot->exec= select_less;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static void selectrandom_mesh(EditMesh *em, float randfac) /* randomly selects a user-set % of vertices/edges/faces */
-{
- EditVert *eve;
- EditEdge *eed;
- EditFace *efa;
-
- BLI_srand( BLI_rand() ); /* random seed */
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->h==0) {
- if (BLI_frand() < randfac)
- eve->f |= SELECT;
- }
- }
- EM_selectmode_flush(em);
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->h==0) {
- if (BLI_frand() < randfac)
- EM_select_edge(eed, 1);
- }
- }
- EM_selectmode_flush(em);
- }
- else {
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->h==0) {
- if (BLI_frand() < randfac)
- EM_select_face(efa, 1);
- }
- }
-
- EM_selectmode_flush(em);
- }
-// if (EM_texFaceCheck())
-}
-
-static int mesh_select_random_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- if(!RNA_boolean_get(op->ptr, "extend"))
- EM_deselect_all(em);
-
- selectrandom_mesh(em, RNA_float_get(op->ptr, "percent")/100.0f);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_random(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Random";
- ot->description= "Randomly select vertices";
- ot->idname= "MESH_OT_select_random";
-
- /* api callbacks */
- ot->exec= mesh_select_random_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float_percentage(ot->srna, "percent", 50.f, 0.0f, 100.0f, "Percent", "Percentage of elements to select randomly.", 0.f, 100.0f);
- RNA_def_boolean(ot->srna, "extend", FALSE, "Extend Selection", "Extend selection instead of deselecting everything first.");
-}
-
-void EM_select_by_material(EditMesh *em, int index)
-{
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- EM_select_face(efa, 1);
- }
- }
-
- EM_selectmode_flush(em);
-}
-
-void EM_deselect_by_material(EditMesh *em, int index)
-{
- EditFace *efa;
-
- for (efa=em->faces.first; efa; efa= efa->next) {
- if (efa->mat_nr==index) {
- EM_select_face(efa, 0);
- }
- }
-
- EM_selectmode_flush(em);
-}
-
-/* ************************* SEAMS AND EDGES **************** */
-
-static int editmesh_mark_seam(bContext *C, wmOperator *op)
-{
- Scene *scene= CTX_data_scene(C);
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Mesh *me= ((Mesh *)obedit->data);
- EditEdge *eed;
- int clear = RNA_boolean_get(op->ptr, "clear");
-
- /* auto-enable seams drawing */
- if(clear==0) {
- me->drawflag |= ME_DRAWSEAMS;
- }
-
- if(clear) {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->f & SELECT)) {
- eed->seam = 0;
- }
- eed= eed->next;
- }
- }
- else {
- eed= em->edges.first;
- while(eed) {
- if((eed->h==0) && (eed->f & SELECT)) {
- eed->seam = 1;
- }
- eed= eed->next;
- }
- }
-
- /* live unwrap while tagging */
- if( (scene->toolsettings->edge_mode_live_unwrap) &&
- (CustomData_has_layer(&em->fdata, CD_MTFACE))
- ) {
- ED_unwrap_lscm(scene, obedit, FALSE); /* unwrap all not just sel */
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_seam(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Seam";
- ot->description= "(un)mark selected edges as a seam";
- ot->idname= "MESH_OT_mark_seam";
-
- /* api callbacks */
- ot->exec= editmesh_mark_seam;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
-
-static int editmesh_mark_sharp(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Mesh *me= ((Mesh *)obedit->data);
- int clear = RNA_boolean_get(op->ptr, "clear");
- EditEdge *eed;
-
- /* auto-enable sharp edge drawing */
- if(clear == 0) {
- me->drawflag |= ME_DRAWSHARP;
- }
-
- if(!clear) {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
- eed = eed->next;
- }
- } else {
- eed= em->edges.first;
- while(eed) {
- if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
- eed = eed->next;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_mark_sharp(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mark Sharp";
- ot->description= "(un)mark selected edges as sharp";
- ot->idname= "MESH_OT_mark_sharp";
-
- /* api callbacks */
- ot->exec= editmesh_mark_sharp;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
-}
-
-/* **************** NORMALS ************** */
-
-void EM_recalc_normal_direction(EditMesh *em, int inside, int select) /* makes faces righthand turning */
-{
- EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
- EditFace *efa, *startvl;
- float maxx, nor[3], cent[3];
- int totsel, found, foundone, direct, turn, tria_nr;
-
- /* based at a select-connected to witness loose objects */
-
- /* count per edge the amount of faces */
-
- /* find the ultimate left, front, upper face (not manhattan dist!!) */
- /* also evaluate both triangle cases in quad, since these can be non-flat */
-
- /* put normal to the outside, and set the first direction flags in edges */
-
- /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
- /* this is in fact the 'select connected' */
-
- /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
-
- waitcursor(1);
-
- eed= em->edges.first;
- while(eed) {
- eed->f2= 0; /* edge direction */
- eed->f1= 0; /* counter */
- eed= eed->next;
- }
-
- /* count faces and edges */
- totsel= 0;
- efa= em->faces.first;
- while(efa) {
- if(select==0 || (efa->f & SELECT) ) {
- efa->f1= 1;
- totsel++;
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->v4) efa->e4->f1++;
- }
- else efa->f1= 0;
-
- efa= efa->next;
- }
-
- while(totsel>0) {
- /* from the outside to the inside */
-
- efa= em->faces.first;
- startvl= NULL;
- maxx= -1.0e10;
- tria_nr= 0;
-
- while(efa) {
- if(efa->f1) {
- cent_tri_v3(cent, efa->v1->co, efa->v2->co, efa->v3->co);
- cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
-
- if(cent[0]>maxx) {
- maxx= cent[0];
- startvl= efa;
- tria_nr= 0;
- }
- if(efa->v4) {
- cent_tri_v3(cent, efa->v1->co, efa->v3->co, efa->v4->co);
- cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
-
- if(cent[0]>maxx) {
- maxx= cent[0];
- startvl= efa;
- tria_nr= 1;
- }
- }
- }
- efa= efa->next;
- }
-
- if (startvl==NULL)
- startvl= em->faces.first;
-
- /* set first face correct: calc normal */
-
- if(tria_nr==1) {
- normal_tri_v3( nor,startvl->v1->co, startvl->v3->co, startvl->v4->co);
- cent_tri_v3(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
- } else {
- normal_tri_v3( nor,startvl->v1->co, startvl->v2->co, startvl->v3->co);
- cent_tri_v3(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
- }
- /* first normal is oriented this way or the other */
- if(inside) {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0f) flipface(em, startvl);
- }
- else {
- if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0f) flipface(em, startvl);
- }
-
- eed= startvl->e1;
- if(eed->v1==startvl->v1) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e2;
- if(eed->v1==startvl->v2) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e3;
- if(eed->v1==startvl->v3) eed->f2= 1;
- else eed->f2= 2;
-
- eed= startvl->e4;
- if(eed) {
- if(eed->v1==startvl->v4) eed->f2= 1;
- else eed->f2= 2;
- }
-
- startvl->f1= 0;
- totsel--;
-
- /* test normals */
- found= 1;
- direct= 1;
- while(found) {
- found= 0;
- if(direct) efa= em->faces.first;
- else efa= em->faces.last;
- while(efa) {
- if(efa->f1) {
- turn= 0;
- foundone= 0;
-
- ed1= efa->e1;
- ed2= efa->e2;
- ed3= efa->e3;
- ed4= efa->e4;
-
- if(ed1->f2) {
- if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
- if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed2->f2) {
- if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
- if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed3->f2) {
- if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
- if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
- foundone= 1;
- }
- else if(ed4 && ed4->f2) {
- if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
- if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
- foundone= 1;
- }
-
- if(foundone) {
- found= 1;
- totsel--;
- efa->f1= 0;
-
- if(turn) {
- if(ed1->v1==efa->v1) ed1->f2= 2;
- else ed1->f2= 1;
- if(ed2->v1==efa->v2) ed2->f2= 2;
- else ed2->f2= 1;
- if(ed3->v1==efa->v3) ed3->f2= 2;
- else ed3->f2= 1;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f2= 2;
- else ed4->f2= 1;
- }
-
- flipface(em, efa);
-
- }
- else {
- if(ed1->v1== efa->v1) ed1->f2= 1;
- else ed1->f2= 2;
- if(ed2->v1==efa->v2) ed2->f2= 1;
- else ed2->f2= 2;
- if(ed3->v1==efa->v3) ed3->f2= 1;
- else ed3->f2= 2;
- if(ed4) {
- if(ed4->v1==efa->v4) ed4->f2= 1;
- else ed4->f2= 2;
- }
- }
- }
- }
- if(direct) efa= efa->next;
- else efa= efa->prev;
- }
- direct= 1-direct;
- }
- }
-
- recalc_editnormals(em);
-
-// DAG_id_tag_update(obedit->data, 0);
-
- waitcursor(0);
-}
-
-
-static int normals_make_consistent_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
-
- /* 'standard' behaviour - check if selected, then apply relevant selection */
-
- // XXX need other args
- EM_recalc_normal_direction(em, RNA_boolean_get(op->ptr, "inside"), 1);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data); //TODO is this needed ?
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_normals_make_consistent(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Make Normals Consistent";
- ot->description= "Flip all selected vertex and face normals in a consistent direction";
- ot->idname= "MESH_OT_normals_make_consistent";
-
- /* api callbacks */
- ot->exec= normals_make_consistent_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
-}
-
-/* **************** VERTEX DEFORMS *************** */
-
-static int smooth_vertex(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditVert *eve, *eve_mir = NULL;
- EditEdge *eed;
- float *adror, *adr, fac;
- float fvec[3];
- int teller=0;
- ModifierData *md;
- int index;
-
- /* count */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) teller++;
- eve= eve->next;
- }
- if(teller==0) {
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- eve->tmp.p = (void*)adr;
- eve->f1= 0;
- eve->f2= 0;
- adr+= 3;
- }
- eve= eve->next;
- }
-
- /* if there is a mirror modifier with clipping, flag the verts that
- * are within tolerance of the plane(s) of reflection
- */
- for(md=obedit->modifiers.first; md; md=md->next) {
- if(md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- for (eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
-
- switch(mmd->axis){
- case 0:
- if (fabsf(eve->co[0]) < mmd->tolerance)
- eve->f2 |= 1;
- break;
- case 1:
- if (fabsf(eve->co[1]) < mmd->tolerance)
- eve->f2 |= 2;
- break;
- case 2:
- if (fabsf(eve->co[2]) < mmd->tolerance)
- eve->f2 |= 4;
- break;
- }
- }
- }
- }
- }
- }
-
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
- mid_v3_v3v3(fvec, eed->v1->co, eed->v2->co);
-
- if((eed->v1->f & SELECT) && eed->v1->f1<255) {
- eed->v1->f1++;
- add_v3_v3(eed->v1->tmp.p, fvec);
- }
- if((eed->v2->f & SELECT) && eed->v2->f1<255) {
- eed->v2->f1++;
- add_v3_v3(eed->v2->tmp.p, fvec);
- }
- }
- eed= eed->next;
- }
-
- index= 0;
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- if(eve->f1) {
-
- int xaxis= RNA_boolean_get(op->ptr, "xaxis");
- int yaxis= RNA_boolean_get(op->ptr, "yaxis");
- int zaxis= RNA_boolean_get(op->ptr, "zaxis");
-
- if (((Mesh *)obedit->data)->editflag & ME_EDIT_MIRROR_X) {
- eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve, eve->co, index);
- }
-
- adr = eve->tmp.p;
- fac= 0.5f/(float)eve->f1;
-
- if(xaxis)
- eve->co[0]= 0.5f*eve->co[0]+fac*adr[0];
- if(yaxis)
- eve->co[1]= 0.5f*eve->co[1]+fac*adr[1];
- if(zaxis)
- eve->co[2]= 0.5f*eve->co[2]+fac*adr[2];
-
-
- /* clip if needed by mirror modifier */
- if (eve->f2) {
- if (eve->f2 & 1) {
- eve->co[0]= 0.0f;
- }
- if (eve->f2 & 2) {
- eve->co[1]= 0.0f;
- }
- if (eve->f2 & 4) {
- eve->co[2]= 0.0f;
- }
- }
-
- if (eve_mir) {
- eve_mir->co[0]=-eve->co[0];
- eve_mir->co[1]= eve->co[1];
- eve_mir->co[2]= eve->co[2];
- }
-
- }
- eve->tmp.p= NULL;
- }
- index++;
- eve= eve->next;
- }
- MEM_freeN(adror);
-
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int smooth_vertex_exec(bContext *C, wmOperator *op)
-{
- int repeat = RNA_int_get(op->ptr, "repeat");
- int i;
-
- if (!repeat) repeat = 1;
-
- for (i=0; i<repeat; i++) {
- smooth_vertex(C, op);
- }
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Smooth Vertex";
- ot->description= "Flatten angles of selected vertices";
- ot->idname= "MESH_OT_vertices_smooth";
-
- /* api callbacks */
- ot->exec= smooth_vertex_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Smooth Iterations", "", 1, INT_MAX);
- RNA_def_boolean(ot->srna, "xaxis", 1, "X-Axis", "Smooth along the X axis.");
- RNA_def_boolean(ot->srna, "yaxis", 1, "Y-Axis", "Smooth along the Y axis.");
- RNA_def_boolean(ot->srna, "zaxis", 1, "Z-Axis", "Smooth along the Z axis.");
-}
-
-static int mesh_noise_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- Material *ma;
- Tex *tex;
- EditVert *eve;
- float fac= RNA_float_get(op->ptr, "factor");
-
- if(em==NULL) return OPERATOR_FINISHED;
-
- ma= give_current_material(obedit, obedit->actcol);
- if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no material or texture assigned.");
- return OPERATOR_FINISHED;
- }
- tex= give_current_material_texture(ma);
-
-
- if(tex->type==TEX_STUCCI) {
- float b2, vec[3];
- float ofs= tex->turbul/200.0f;
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
- if(tex->stype) ofs*=(b2*b2);
- vec[0]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
- vec[1]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
- vec[2]= fac*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
-
- add_v3_v3(eve->co, vec);
- }
- }
- }
- else {
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f & SELECT) {
- float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0);
- eve->co[2]+= fac*tin;
- }
- }
- }
-
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_noise(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Noise";
- ot->description= "Use vertex coordinate as texture coordinate";
- ot->idname= "MESH_OT_noise";
-
- /* api callbacks */
- ot->exec= mesh_noise_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_float(ot->srna, "factor", 0.1f, -FLT_MAX, FLT_MAX, "Factor", "", 0.0f, 1.0f);
-}
-
-void flipface(EditMesh *em, EditFace *efa)
-{
- if(efa->v4) {
- SWAP(EditVert *, efa->v2, efa->v4);
- SWAP(EditEdge *, efa->e1, efa->e4);
- SWAP(EditEdge *, efa->e2, efa->e3);
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1);
- }
- else {
- SWAP(EditVert *, efa->v2, efa->v3);
- SWAP(EditEdge *, efa->e1, efa->e3);
- efa->e2->dir= 1-efa->e2->dir;
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3);
- }
-
- if(efa->v4) normal_quad_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
- else normal_tri_v3( efa->n,efa->v1->co, efa->v2->co, efa->v3->co);
-}
-
-
-static int flip_normals(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- EditFace *efa;
-
- efa= em->faces.first;
- while(efa) {
- if( efa->f & SELECT ){
- flipface(em, efa);
- }
- efa= efa->next;
- }
-
- /* update vertex normals too */
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_flip_normals(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Flip Normals";
- ot->description= "Toggle the direction of selected face's vertex and face normals";
- ot->idname= "MESH_OT_flip_normals";
-
- /* api callbacks */
- ot->exec= flip_normals;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
-static int solidify_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- float nor[3] = {0,0,1};
-
- float thickness= RNA_float_get(op->ptr, "thickness");
-
- extrudeflag(obedit, em, SELECT, nor, 1);
- EM_make_hq_normals(em);
- EM_solidify(em, thickness);
-
-
- /* update vertex normals too */
- recalc_editnormals(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_solidify(wmOperatorType *ot)
-{
- PropertyRNA *prop;
- /* identifiers */
- ot->name= "Solidify";
- ot->description= "Create a solid skin by extruding, compensating for sharp angles";
- ot->idname= "MESH_OT_solidify";
-
- /* api callbacks */
- ot->exec= solidify_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- prop= RNA_def_float(ot->srna, "thickness", 0.01f, -FLT_MAX, FLT_MAX, "Thickness", "", -10.0f, 10.0f);
- RNA_def_property_ui_range(prop, -10, 10, 0.1, 4);
-}
-
-static int mesh_select_nth_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- int nth = RNA_int_get(op->ptr, "nth");
-
- EM_deselect_nth(em, nth);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_select_nth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Select Nth";
- ot->description= "";
- ot->idname= "MESH_OT_select_nth";
-
- /* api callbacks */
- ot->exec= mesh_select_nth_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- RNA_def_int(ot->srna, "nth", 2, 2, 100, "Nth Selection", "", 1, INT_MAX);
-}
-
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
deleted file mode 100644
index a78029da079..00000000000
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ /dev/null
@@ -1,7605 +0,0 @@
- /* $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2004 by Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): Johnny Matthews, Geoffrey Bantle.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/editors/mesh/editmesh_tools.c
- * \ingroup edmesh
- */
-
-
-/*
-
-editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
-
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
-
-#include "BLO_sys_types.h" // for intptr_t support
-
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_key_types.h"
-
-#include "MEM_guardedalloc.h"
-
-#include "RNA_define.h"
-#include "RNA_access.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_editVert.h"
-#include "BLI_rand.h"
-#include "BLI_ghash.h"
-#include "BLI_linklist.h"
-#include "BLI_heap.h"
-#include "BLI_scanfill.h"
-
-#include "BKE_context.h"
-#include "BKE_depsgraph.h"
-#include "BKE_global.h"
-#include "BKE_key.h"
-#include "BKE_mesh.h"
-#include "BKE_bmesh.h"
-#include "BKE_report.h"
-
-
-#include "WM_api.h"
-#include "WM_types.h"
-
-#include "ED_mesh.h"
-#include "ED_screen.h"
-#include "ED_transform.h"
-#include "ED_view3d.h"
-#include "ED_object.h"
-
-
-#include "mesh_intern.h"
-
-/* XXX */
-static void waitcursor(int UNUSED(val)) {}
-#define add_numbut(a, b, c, d, e, f, g) {}
-
-/* XXX */
-
-/* RNA corner cut enum property - used in multiple files for tools
- * that need this property for esubdivideflag() */
-EnumPropertyItem corner_type_items[] = {
- {SUBDIV_CORNER_PATH, "PATH", 0, "Path", ""},
- {SUBDIV_CORNER_INNERVERT, "INNER_VERTEX", 0, "Inner Vertex", ""},
- {SUBDIV_CORNER_FAN, "FAN", 0, "Fan", ""},
- {0, NULL, 0, NULL, NULL}};
-
-
-/* local prototypes ---------------*/
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa);
-int EdgeLoopDelete(EditMesh *em, wmOperator *op);
-
-/********* qsort routines *********/
-
-
-typedef struct xvertsort {
- float x;
- EditVert *v1;
-} xvertsort;
-
-static int vergxco(const void *v1, const void *v2)
-{
- const xvertsort *x1=v1, *x2=v2;
-
- if( x1->x > x2->x ) return 1;
- else if( x1->x < x2->x) return -1;
- return 0;
-}
-
-struct facesort {
- uintptr_t x;
- struct EditFace *efa;
-};
-
-
-static int vergface(const void *v1, const void *v2)
-{
- const struct facesort *x1=v1, *x2=v2;
-
- if( x1->x > x2->x ) return 1;
- else if( x1->x < x2->x) return -1;
- return 0;
-}
-
-
-/* *********************************** */
-
-static void convert_to_triface(EditMesh *em, int direction)
-{
- EditFace *efa, *efan, *next;
- float fac;
-
- efa= em->faces.last;
- while(efa) {
- next= efa->prev;
- if(efa->v4) {
- if(efa->f & SELECT) {
- /* choose shortest diagonal for split */
- fac= len_v3v3(efa->v1->co, efa->v3->co) - len_v3v3(efa->v2->co, efa->v4->co);
- /* this makes sure exact squares get split different in both cases */
- if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) {
- efan= EM_face_from_faces(em, efa, NULL, 0, 1, 2, -1);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, efa, NULL, 0, 2, 3, -1);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- }
- else {
- efan= EM_face_from_faces(em, efa, NULL, 0, 1, 3, -1);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- efan= EM_face_from_faces(em, efa, NULL, 1, 2, 3, -1);
- if(efa->f & SELECT) EM_select_face(efan, 1);
- }
-
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- }
- efa= next;
- }
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-
-
-}
-
-int removedoublesflag(EditMesh *em, short flag, short automerge, float limit) /* return amount */
-{
- /*
- flag - Test with vert->flags
- automerge - Alternative operation, merge unselected into selected.
- Used for "Auto Weld" mode. warning.
- limit - Quick manhattan distance between verts.
- */
-
- /* all verts with (flag & 'flag') are being evaluated */
- EditVert *eve, *v1, *nextve;
- EditEdge *eed, *e1, *nexted;
- EditFace *efa, *nextvl;
- xvertsort *sortblock, *sb, *sb1;
- struct facesort *vlsortblock, *vsb, *vsb1;
- int a, b, test, amount;
-
-
- /* flag 128 is cleared, count */
-
- /* Normal non weld operation */
- eve= em->verts.first;
- amount= 0;
- while(eve) {
- eve->f &= ~128;
- if(eve->h==0 && (automerge || (eve->f & flag))) amount++;
- eve= eve->next;
- }
- if(amount==0) return 0;
-
- /* allocate memory and qsort */
- sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->h==0 && (automerge || (eve->f & flag))) {
- sb->x= eve->co[0]+eve->co[1]+eve->co[2];
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
- qsort(sortblock, amount, sizeof(xvertsort), vergxco);
-
-
- /* test for doubles */
- sb= sortblock;
- if (automerge) {
- for(a=0; a<amount; a++, sb++) {
- eve= sb->v1;
- if( (eve->f & 128)==0 ) {
- sb1= sb+1;
- for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) {
- if(sb1->x - sb->x > limit) break;
-
- /* when automarge, only allow unselected->selected */
- v1= sb1->v1;
- if( (v1->f & 128)==0 ) {
- if ((eve->f & flag)==0 && (v1->f & flag)==1) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
- (float)fabs(v1->co[1]-eve->co[1])<=limit &&
- (float)fabs(v1->co[2]-eve->co[2])<=limit)
- { /* unique bit */
- eve->f|= 128;
- eve->tmp.v = v1;
- }
- } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
- (float)fabs(v1->co[1]-eve->co[1])<=limit &&
- (float)fabs(v1->co[2]-eve->co[2])<=limit)
- { /* unique bit */
- v1->f|= 128;
- v1->tmp.v = eve;
- }
- }
- }
- }
- }
- }
- } else {
- for(a=0; a<amount; a++, sb++) {
- eve= sb->v1;
- if( (eve->f & 128)==0 ) {
- sb1= sb+1;
- for(b=a+1; b<amount; b++, sb1++) {
- /* first test: simpel dist */
- if(sb1->x - sb->x > limit) break;
- v1= sb1->v1;
-
- /* second test: is vertex allowed */
- if( (v1->f & 128)==0 ) {
- if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
- (float)fabs(v1->co[1]-eve->co[1])<=limit &&
- (float)fabs(v1->co[2]-eve->co[2])<=limit)
- {
- v1->f|= 128;
- v1->tmp.v = eve;
- }
- }
- }
- }
- }
- }
- MEM_freeN(sortblock);
-
- if (!automerge)
- for(eve = em->verts.first; eve; eve=eve->next)
- if((eve->f & flag) && (eve->f & 128))
- EM_data_interp_from_verts(em, eve, eve->tmp.v, eve->tmp.v, 0.5f);
-
- /* test edges and insert again */
- eed= em->edges.first;
- while(eed) {
- eed->f2= 0;
- eed= eed->next;
- }
- eed= em->edges.last;
- while(eed) {
- nexted= eed->prev;
-
- if(eed->f2==0) {
- if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
- remedge(em, eed);
-
- if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v;
- if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v;
- e1= addedgelist(em, eed->v1, eed->v2, eed);
-
- if(e1) {
- e1->f2= 1;
- if(eed->f & SELECT)
- e1->f |= SELECT;
- }
- if(e1!=eed) free_editedge(em, eed);
- }
- }
- eed= nexted;
- }
-
- /* first count amount of test faces */
- efa= (struct EditFace *)em->faces.first;
- amount= 0;
- while(efa) {
- efa->f1= 0;
- if(efa->v1->f & 128) efa->f1= 1;
- else if(efa->v2->f & 128) efa->f1= 1;
- else if(efa->v3->f & 128) efa->f1= 1;
- else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1;
-
- if(efa->f1==1) amount++;
- efa= efa->next;
- }
-
- /* test faces for double vertices, and if needed remove them */
- efa= (struct EditFace *)em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f1==1) {
-
- if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v;
- if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v;
- if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v;
- if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v;
-
- test= 0;
- if(efa->v1==efa->v2) test+=1;
- if(efa->v2==efa->v3) test+=2;
- if(efa->v3==efa->v1) test+=4;
- if(efa->v4==efa->v1) test+=8;
- if(efa->v3==efa->v4) test+=16;
- if(efa->v2==efa->v4) test+=32;
-
- if(test) {
- if(efa->v4) {
- if(test==1 || test==2) {
- efa->v2= efa->v3;
- efa->v3= efa->v4;
- efa->v4= 0;
-
- EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 3, 3);
-
- test= 0;
- }
- else if(test==8 || test==16) {
- efa->v4= 0;
- test= 0;
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- amount--;
- }
- }
- else {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- amount--;
- }
- }
-
- if(test==0) {
- /* set edge pointers */
- efa->e1= findedgelist(em, efa->v1, efa->v2);
- efa->e2= findedgelist(em, efa->v2, efa->v3);
- if(efa->v4==0) {
- efa->e3= findedgelist(em, efa->v3, efa->v1);
- efa->e4= 0;
- }
- else {
- efa->e3= findedgelist(em, efa->v3, efa->v4);
- efa->e4= findedgelist(em, efa->v4, efa->v1);
- }
- }
- }
- efa= nextvl;
- }
-
- /* double faces: sort block */
- /* count again, now all selected faces */
- amount= 0;
- efa= em->faces.first;
- while(efa) {
- efa->f1= 0;
- if(faceselectedOR(efa, 1)) {
- efa->f1= 1;
- amount++;
- }
- efa= efa->next;
- }
-
- if(amount) {
- /* double faces: sort block */
- vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub");
- efa= em->faces.first;
- while(efa) {
- if(efa->f1 & 1) {
- if(efa->v4) vsb->x= (uintptr_t) MIN4( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3, (uintptr_t)efa->v4);
- else vsb->x= (uintptr_t) MIN3( (uintptr_t)efa->v1, (uintptr_t)efa->v2, (uintptr_t)efa->v3);
-
- vsb->efa= efa;
- vsb++;
- }
- efa= efa->next;
- }
-
- qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
-
- vsb= vlsortblock;
- for(a=0; a<amount; a++) {
- efa= vsb->efa;
- if( (efa->f1 & 128)==0 ) {
- vsb1= vsb+1;
-
- for(b=a+1; b<amount; b++) {
-
- /* first test: same pointer? */
- if(vsb->x != vsb1->x) break;
-
- /* second test: is test permitted? */
- efa= vsb1->efa;
- if( (efa->f1 & 128)==0 ) {
- if( compareface(efa, vsb->efa)) efa->f1 |= 128;
-
- }
- vsb1++;
- }
- }
- vsb++;
- }
-
- MEM_freeN(vlsortblock);
-
- /* remove double faces */
- efa= (struct EditFace *)em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f1 & 128) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- }
-
- /* remove double vertices */
- a= 0;
- eve= (struct EditVert *)em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(automerge || eve->f & flag) {
- if(eve->f & 128) {
- a++;
- BLI_remlink(&em->verts, eve);
- free_editvert(em, eve);
- }
- }
- eve= nextve;
- }
-
- return a; /* amount */
-}
-
-static int removedoublesflag_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
- int totvert= em->totvert, totedge= em->totedge, totface= em->totface;
-
- int count = removedoublesflag(em,1,0,RNA_float_get(op->ptr, "limit"));
-
- if (totvert != em->totvert || totedge != em->totedge || totface != em->totface) {
- recalc_editnormals(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
- }
-
- BKE_reportf(op->reports, RPT_INFO, "Removed %d vert%s.", count, (count==1)?"ex":"ices");
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_remove_doubles(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Remove Doubles";
- ot->description= "Remove duplicate vertices";
- ot->idname= "MESH_OT_remove_doubles";
-
- /* api callbacks */
- ot->exec= removedoublesflag_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- prop= RNA_def_float(ot->srna, "limit", 0.0001f, 0.000001f, 50.0f, "Merge Threshold", "Minimum distance between merged verts", 0.00001f, 2.0f);
- RNA_def_property_ui_range(prop, 0.000001f, 50.0f, 0.001, 5);
-}
-
-// XXX is this needed?
-/* called from buttons */
-static void xsortvert_flag__doSetX(void *userData, EditVert *UNUSED(eve), int x, int UNUSED(y), int index)
-{
- xvertsort *sortblock = userData;
-
- sortblock[index].x = x;
-}
-
-/* all verts with (flag & 'flag') are sorted */
-static void xsortvert_flag(bContext *C, int flag)
-{
- ViewContext vc;
- EditVert *eve;
- xvertsort *sortblock;
- ListBase tbase;
- int i, amount;
-
- em_setup_viewcontext(C, &vc);
-
- amount = BLI_countlist(&vc.em->verts);
- sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
- for (i=0,eve= vc.em->verts.first; eve; i++,eve=eve->next)
- if(eve->f & flag)
- sortblock[i].v1 = eve;
-
- ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d);
- mesh_foreachScreenVert(&vc, xsortvert_flag__doSetX, sortblock, 0);
-
- qsort(sortblock, amount, sizeof(xvertsort), vergxco);
-
- /* make temporal listbase */
- tbase.first= tbase.last= 0;
- for (i=0; i<amount; i++) {
- eve = sortblock[i].v1;
-
- if (eve) {
- BLI_remlink(&vc.em->verts, eve);
- BLI_addtail(&tbase, eve);
- }
- }
-
- BLI_movelisttolist(&vc.em->verts, &tbase);
-
- MEM_freeN(sortblock);
-
-}
-
-static int mesh_vertices_sort_exec(bContext *C, wmOperator *UNUSED(op))
-{
- xsortvert_flag(C, SELECT);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_sort(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Vertex Sort";
- ot->description= "Sort vertex order";
- ot->idname= "MESH_OT_vertices_sort";
-
- /* api callbacks */
- ot->exec= mesh_vertices_sort_exec;
-
- ot->poll= EM_view3d_poll; /* uses view relative X axis to sort verts */
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
-/* called from buttons */
-static void hashvert_flag(EditMesh *em, int flag)
-{
- /* switch vertex order using hash table */
- EditVert *eve;
- struct xvertsort *sortblock, *sb, onth, *newsort;
- ListBase tbase;
- int amount, a, b;
-
- /* count */
- eve= em->verts.first;
- amount= 0;
- while(eve) {
- if(eve->f & flag) amount++;
- eve= eve->next;
- }
- if(amount==0) return;
-
- /* allocate memory */
- sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
- eve= em->verts.first;
- while(eve) {
- if(eve->f & flag) {
- sb->v1= eve;
- sb++;
- }
- eve= eve->next;
- }
-
- BLI_srand(1);
-
- sb= sortblock;
- for(a=0; a<amount; a++, sb++) {
- b= (int)(amount*BLI_drand());
- if(b>=0 && b<amount) {
- newsort= sortblock+b;
- onth= *sb;
- *sb= *newsort;
- *newsort= onth;
- }
- }
-
- /* make temporal listbase */
- tbase.first= tbase.last= 0;
- sb= sortblock;
- while(amount--) {
- eve= sb->v1;
- BLI_remlink(&em->verts, eve);
- BLI_addtail(&tbase, eve);
- sb++;
- }
-
- BLI_movelisttolist(&em->verts, &tbase);
-
- MEM_freeN(sortblock);
-
-}
-
-static int mesh_vertices_randomize_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- hashvert_flag(em, SELECT);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_vertices_randomize(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Vertex Randomize";
- ot->description= "Randomize vertex order";
- ot->idname= "MESH_OT_vertices_randomize";
-
- /* api callbacks */
- ot->exec= mesh_vertices_randomize_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
-/* generic extern called extruder */
-static void extrude_mesh(Object *obedit, EditMesh *em, wmOperator *op, short type)
-{
- float nor[3]= {0.0, 0.0, 0.0};
- short transmode= 0;
-
- if(type<1) return;
-
- if(type==1) transmode= extrudeflag(obedit, em, SELECT, nor, 0);
- else if(type==4) transmode= extrudeflag_verts_indiv(em, SELECT, nor);
- else if(type==3) transmode= extrudeflag_edges_indiv(em, SELECT, nor);
- else transmode= extrudeflag_face_indiv(em, SELECT, nor);
-
- EM_stats_update(em);
-
- if(transmode==0) {
- BKE_report(op->reports, RPT_WARNING, "Not a valid selection for extrude");
- }
- else {
- EM_fgon_flags(em);
-
- /* We need to force immediate calculation here because
- * transform may use derived objects (which are now stale).
- *
- * This shouldn't be necessary, derived queries should be
- * automatically building this data if invalid. Or something.
- */
- DAG_id_tag_update(obedit->data, 0);
-
- /* individual faces? */
-// BIF_TransformSetUndo("Extrude");
- if(type==2) {
-// initTransform(TFM_SHRINKFATTEN, CTX_NO_PET|CTX_NO_MIRROR);
-// Transform();
- }
- else {
-// initTransform(TFM_TRANSLATION, CTX_NO_PET|CTX_NO_MIRROR);
- if(transmode=='n') {
- mul_m4_v3(obedit->obmat, nor);
- sub_v3_v3(nor, obedit->obmat[3]);
-// BIF_setSingleAxisConstraint(nor, "along normal");
- }
-// Transform();
- }
- }
-
-}
-
-// XXX should be a menu item
-static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-/* extrude without transform */
-static int mesh_extrude_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- extrude_mesh(obedit, em, op, RNA_enum_get(op->ptr, "type"));
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-static EnumPropertyItem extrude_items[] = {
- {1, "REGION", 0, "Region", ""},
- {2, "FACES", 0, "Individual Faces", ""},
- {3, "EDGES", 0, "Only Edges", ""},
- {4, "VERTS", 0, "Only Vertices", ""},
- {0, NULL, 0, NULL, NULL}};
-
-
-static EnumPropertyItem *mesh_extrude_itemf(bContext *C, PointerRNA *UNUSED(ptr), int *free)
-{
- EnumPropertyItem *item= NULL;
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em;
-
- int totitem= 0;
-
- if(obedit==NULL || obedit->type != OB_MESH)
- return extrude_items;
-
- em = BKE_mesh_get_editmesh(obedit->data);
-
- EM_stats_update(em);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- if(em->totvertsel==0) {}
- else if(em->totvertsel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
- else if(em->totedgesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[3]); }
- else if(em->totfacesel==0) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- else if(em->totfacesel==1) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[3]);
- }
- }
- else if(em->selectmode & SCE_SELECT_EDGE) {
- if (em->totedgesel==0) {}
- else if (em->totedgesel==1) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
- else if(em->totfacesel==0) { RNA_enum_item_add(&item, &totitem, &extrude_items[2]); }
- else if(em->totfacesel==1) {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[2]);
- }
- }
- else {
- if (em->totfacesel == 0) {}
- else if (em->totfacesel == 1) { RNA_enum_item_add(&item, &totitem, &extrude_items[0]); }
- else {
- RNA_enum_item_add(&item, &totitem, &extrude_items[0]);
- RNA_enum_item_add(&item, &totitem, &extrude_items[1]);
- }
- }
-
- if(item) {
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
- return item;
- }
- else {
- return NULL;
- }
-}
-
-void MESH_OT_extrude(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Extrude";
- ot->description= "Extrude selected vertices, edges or faces";
- ot->idname= "MESH_OT_extrude";
-
- /* api callbacks */
- ot->invoke= mesh_extrude_invoke;
- ot->exec= mesh_extrude_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", extrude_items, 0, "Type", "");
- RNA_def_property_flag(prop, PROP_HIDDEN);
- RNA_def_enum_funcs(prop, mesh_extrude_itemf);
- ot->prop= prop;
-}
-
-static int split_mesh(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- WM_cursor_wait(1);
-
- /* make duplicate first */
- adduplicateflag(em, SELECT);
- /* old faces have flag 128 set, delete them */
- delfaceflag(em, 128);
- recalc_editnormals(em);
-
- WM_cursor_wait(0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_split(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Split";
- ot->description= "Split selected geometry into separate disconnected mesh";
- ot->idname= "MESH_OT_split";
-
- /* api callbacks */
- ot->exec= split_mesh;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-
-static int extrude_repeat_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- int steps = RNA_int_get(op->ptr,"steps");
-
- float offs = RNA_float_get(op->ptr,"offset");
-
- float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
- short a;
-
- /* dvec */
- RNA_float_get_array(op->ptr, "direction", dvec);
- normalize_v3(dvec);
- dvec[0]*= offs;
- dvec[1]*= offs;
- dvec[2]*= offs;
-
- /* base correction */
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(tmat, bmat);
- mul_m3_v3(tmat, dvec);
-
- for(a=0; a<steps; a++) {
- extrudeflag(obedit, em, SELECT, nor, 0);
- translateflag(em, SELECT, dvec);
- }
-
- recalc_editnormals(em);
-
- EM_fgon_flags(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-/* get center and axis, in global coords */
-static int extrude_repeat_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- if(rv3d)
- RNA_float_set_array(op->ptr, "direction", rv3d->persinv[2]);
-
- return extrude_repeat_mesh_exec(C, op);
-}
-
-void MESH_OT_extrude_repeat(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Extrude Repeat Mesh";
- ot->description= "Extrude selected vertices, edges or faces repeatedly";
- ot->idname= "MESH_OT_extrude_repeat";
-
- /* api callbacks */
- ot->invoke= extrude_repeat_mesh_invoke;
- ot->exec= extrude_repeat_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_float(ot->srna, "offset", 2.0f, 0.0f, 100.0f, "Offset", "", 0.0f, 100.0f);
- RNA_def_int(ot->srna, "steps", 10, 0, 180, "Steps", "", 0, 180);
- RNA_def_float_vector(ot->srna, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "Direction", "Direction of extrude", -FLT_MAX, FLT_MAX);
-}
-
-/* ************************** spin operator ******************** */
-
-
-static int spin_mesh(bContext *C, wmOperator *op, float *dvec, int steps, float degr, int dupli )
-{
- Object *obedit= CTX_data_edit_object(C);
- ToolSettings *ts= CTX_data_tool_settings(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditVert *eve,*nextve;
- float nor[3]= {0.0f, 0.0f, 0.0f};
- float si, n[3], q[4], cmat[3][3], imat[3][3], tmat[3][3];
- float cent[3], bmat[3][3];
- float phi;
- short a, ok= 1;
-
- RNA_float_get_array(op->ptr, "center", cent);
-
- /* imat and center and size */
- copy_m3_m4(bmat, obedit->obmat);
- invert_m3_m3(imat,bmat);
-
- cent[0]-= obedit->obmat[3][0];
- cent[1]-= obedit->obmat[3][1];
- cent[2]-= obedit->obmat[3][2];
- mul_m3_v3(imat, cent);
-
- phi= degr*(float)M_PI/360.0f;
- phi/= steps;
- if(ts->editbutflag & B_CLOCKWISE) phi= -phi;
-
- RNA_float_get_array(op->ptr, "axis", n);
- normalize_v3(n);
-
- q[0]= (float)cos(phi);
- si= (float)sin(phi);
- q[1]= n[0]*si;
- q[2]= n[1]*si;
- q[3]= n[2]*si;
- quat_to_mat3( cmat,q);
-
- mul_m3_m3m3(tmat,cmat,bmat);
- mul_m3_m3m3(bmat,imat,tmat);
-
- if(dupli==0)
- if(ts->editbutflag & B_KEEPORIG)
- adduplicateflag(em, 1);
-
- for(a=0; a<steps; a++) {
- if(dupli==0) ok= extrudeflag(obedit, em, SELECT, nor, 0);
- else adduplicateflag(em, SELECT);
-
- if(ok==0)
- break;
-
- rotateflag(em, SELECT, cent, bmat);
- if(dvec) {
- mul_m3_v3(bmat,dvec);
- translateflag(em, SELECT, dvec);
- }
- }
-
- if(ok==0) {
- /* no vertices or only loose ones selected, remove duplicates */
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & SELECT) {
- BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
- }
- else {
- recalc_editnormals(em);
-
- EM_fgon_flags(em);
-
- DAG_id_tag_update(obedit->data, 0);
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return ok;
-}
-
-static int spin_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- int ok;
-
- ok= spin_mesh(C, op, NULL, RNA_int_get(op->ptr,"steps"), RNA_float_get(op->ptr,"degrees"), RNA_boolean_get(op->ptr,"dupli"));
- if(ok==0) {
- BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
- return OPERATOR_CANCELLED;
- }
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-/* get center and axis, in global coords */
-static int spin_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[2]);
-
- return spin_mesh_exec(C, op);
-}
-
-void MESH_OT_spin(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Spin";
- ot->description= "Extrude selected vertices in a circle around the cursor in indicated viewport";
- ot->idname= "MESH_OT_spin";
-
- /* api callbacks */
- ot->invoke= spin_mesh_invoke;
- ot->exec= spin_mesh_exec;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 128);
- RNA_def_boolean(ot->srna, "dupli", 0, "Dupli", "Make Duplicates");
- RNA_def_float(ot->srna, "degrees", 90.0f, -FLT_MAX, FLT_MAX, "Degrees", "Degrees", -360.0f, 360.0f);
-
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
-
-}
-
-static int screw_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditVert *eve,*v1=0,*v2=0;
- EditEdge *eed;
- float dvec[3], nor[3];
- int steps, turns;
-
- turns= RNA_int_get(op->ptr, "turns");
- steps= RNA_int_get(op->ptr, "steps");
-
- /* clear flags */
- for(eve= em->verts.first; eve; eve= eve->next)
- eve->f1= 0;
-
- /* edges set flags in verts */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->v1->f & SELECT) {
- if(eed->v2->f & SELECT) {
- /* watch: f1 is a byte */
- if(eed->v1->f1<2) eed->v1->f1++;
- if(eed->v2->f1<2) eed->v2->f1++;
- }
- }
- }
- /* find two vertices with eve->f1==1, more or less is wrong */
- for(eve= em->verts.first; eve; eve= eve->next) {
- if(eve->f1==1) {
- if(v1==NULL) v1= eve;
- else if(v2==NULL) v2= eve;
- else {
- v1= NULL;
- break;
- }
- }
- }
- if(v1==NULL || v2==NULL) {
- BKE_report(op->reports, RPT_WARNING, "You have to select a string of connected vertices too");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /* calculate dvec */
- dvec[0]= ( v1->co[0]- v2->co[0] )/steps;
- dvec[1]= ( v1->co[1]- v2->co[1] )/steps;
- dvec[2]= ( v1->co[2]- v2->co[2] )/steps;
-
- VECCOPY(nor, obedit->obmat[2]);
-
- if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.0f) {
- negate_v3(dvec);
- }
-
- if(spin_mesh(C, op, dvec, turns*steps, 360.0f*turns, 0)) {
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "No valid vertices are selected");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* get center and axis, in global coords */
-static int screw_mesh_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
-{
- Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
-
- RNA_float_set_array(op->ptr, "center", give_cursor(scene, v3d));
- RNA_float_set_array(op->ptr, "axis", rv3d->viewinv[1]);
-
- return screw_mesh_exec(C, op);
-}
-
-void MESH_OT_screw(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Screw";
- ot->description= "Extrude selected vertices in screw-shaped rotation around the cursor in indicated viewport";
- ot->idname= "MESH_OT_screw";
-
- /* api callbacks */
- ot->invoke= screw_mesh_invoke;
- ot->exec= screw_mesh_exec;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /*props */
- RNA_def_int(ot->srna, "steps", 9, 0, INT_MAX, "Steps", "Steps", 0, 256);
- RNA_def_int(ot->srna, "turns", 1, 0, INT_MAX, "Turns", "Turns", 0, 256);
-
- RNA_def_float_vector_xyz(ot->srna, "center", 3, NULL, -FLT_MAX, FLT_MAX, "Center", "Center in global view space", -FLT_MAX, FLT_MAX);
- RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -FLT_MAX, FLT_MAX);
-}
-
-static void erase_edges(EditMesh *em, ListBase *l)
-{
- EditEdge *ed, *nexted;
-
- ed = (EditEdge *) l->first;
- while(ed) {
- nexted= ed->next;
- if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
- remedge(em, ed);
- free_editedge(em, ed);
- }
- ed= nexted;
- }
-}
-
-static void erase_faces(EditMesh *em, ListBase *l)
-{
- EditFace *f, *nextf;
-
- f = (EditFace *) l->first;
-
- while(f) {
- nextf= f->next;
- if( faceselectedOR(f, SELECT) ) {
- BLI_remlink(l, f);
- free_editface(em, f);
- }
- f = nextf;
- }
-}
-
-static void erase_vertices(EditMesh *em, ListBase *l)
-{
- EditVert *v, *nextv;
-
- v = (EditVert *) l->first;
- while(v) {
- nextv= v->next;
- if(v->f & 1) {
- BLI_remlink(l, v);
- free_editvert(em, v);
- }
- v = nextv;
- }
-}
-
-static void delete_mesh(EditMesh *em, wmOperator *op, int event)
-{
- EditFace *efa, *nextvl;
- EditVert *eve,*nextve;
- EditEdge *eed,*nexted;
- int count;
- /* const char *str="Erase"; */
-
-
- if(event<1) return;
-
- if(event==10 ) {
- /* str= "Erase Vertices"; */
- erase_edges(em, &em->edges);
- erase_faces(em, &em->faces);
- erase_vertices(em, &em->verts);
- }
- else if(event==6) {
- if(!EdgeLoopDelete(em, op))
- return;
-
- /* str= "Erase Edge Loop"; */
- }
- else if(event==4) {
- /* str= "Erase Edges & Faces"; */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- /* delete only faces with 1 or more edges selected */
- count= 0;
- if(efa->e1->f & SELECT) count++;
- if(efa->e2->f & SELECT) count++;
- if(efa->e3->f & SELECT) count++;
- if(efa->e4 && (efa->e4->f & SELECT)) count++;
- if(count) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->v1->f & SELECT) event++;
- if( efa->v2->f & SELECT) event++;
- if( efa->v3->f & SELECT) event++;
- if(efa->v4 && (efa->v4->f & SELECT)) event++;
-
- if(event>1) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- }
- else if(event==1) {
- /* str= "Erase Edges"; */
- // faces first
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- event=0;
- if( efa->e1->f & SELECT) event++;
- if( efa->e2->f & SELECT) event++;
- if( efa->e3->f & SELECT) event++;
- if(efa->e4 && (efa->e4->f & SELECT)) event++;
-
- if(event) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
- if(eed->f & SELECT) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
- /* to remove loose vertices: */
- eed= em->edges.first;
- while(eed) {
- if( eed->v1->f & SELECT) eed->v1->f-=SELECT;
- if( eed->v2->f & SELECT) eed->v2->f-=SELECT;
- eed= eed->next;
- }
- eve= em->verts.first;
- while(eve) {
- nextve= eve->next;
- if(eve->f & SELECT) {
- BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
- }
- eve= nextve;
- }
-
- }
- else if(event==2) {
- /* str="Erase Faces"; */
- delfaceflag(em, SELECT);
- }
- else if(event==3) {
- /* str= "Erase All"; */
- if(em->verts.first) free_vertlist(em, &em->verts);
- if(em->edges.first) free_edgelist(em, &em->edges);
- if(em->faces.first) free_facelist(em, &em->faces);
- if(em->selected.first) BLI_freelistN(&(em->selected));
- }
- else if(event==5) {
- /* str= "Erase Only Faces"; */
- efa= em->faces.first;
- while(efa) {
- nextvl= efa->next;
- if(efa->f & SELECT) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- efa= nextvl;
- }
- }
-
- EM_fgon_flags(em); // redo flags and indices for fgons
-}
-
-/* Note, these values must match delete_mesh() event values */
-static EnumPropertyItem prop_mesh_delete_types[] = {
- {10,"VERT", 0, "Vertices", ""},
- {1, "EDGE", 0, "Edges", ""},
- {2, "FACE", 0, "Faces", ""},
- {3, "ALL", 0, "All", ""},
- {4, "EDGE_FACE",0, "Edges & Faces", ""},
- {5, "ONLY_FACE",0, "Only Faces", ""},
- {6, "EDGE_LOOP",0, "Edge Loop", ""},
- {0, NULL, 0, NULL, NULL}
-};
-
-static int delete_mesh_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- int type= RNA_enum_get(op->ptr, "type");
-
- if(type==6)
- return WM_operator_name_call(C, "MESH_OT_delete_edgeloop", WM_OP_EXEC_DEFAULT, NULL);
-
- delete_mesh(em, op, type);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_delete(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Delete";
- ot->description= "Delete selected vertices, edges or faces";
- ot->idname= "MESH_OT_delete";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= delete_mesh_exec;
-
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /*props */
- ot->prop= RNA_def_enum(ot->srna, "type", prop_mesh_delete_types, 10, "Type", "Method used for deleting mesh data");
-}
-
-
-/*GB*/
-/*-------------------------------------------------------------------------------*/
-/*--------------------------- Edge Based Subdivide ------------------------------*/
-
-#define EDGENEW 2
-#define FACENEW 2
-#define EDGEINNER 4
-#define EDGEOLD 8
-
-/*used by faceloop cut to select only edges valid for edge slide*/
-#define DOUBLEOPFILL 16
-
-/* calculates offset for co, based on fractal, sphere or smooth settings */
-static void alter_co(float *co, EditEdge *edge, float smooth, float fractal, int beauty, float perc)
-{
- float vec1[3], fac;
-
- if(beauty & B_SMOOTH) {
- /* we calculate an offset vector vec1[], to be added to *co */
- float len, fac, nor[3], nor1[3], nor2[3];
-
- sub_v3_v3v3(nor, edge->v1->co, edge->v2->co);
- len= 0.5f*normalize_v3(nor);
-
- VECCOPY(nor1, edge->v1->no);
- VECCOPY(nor2, edge->v2->no);
-
- /* cosine angle */
- fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
-
- vec1[0]= fac*nor1[0];
- vec1[1]= fac*nor1[1];
- vec1[2]= fac*nor1[2];
-
- /* cosine angle */
- fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
-
- vec1[0]+= fac*nor2[0];
- vec1[1]+= fac*nor2[1];
- vec1[2]+= fac*nor2[2];
-
- /* falloff for multi subdivide */
- smooth *= sqrtf(fabs(1.0f - 2.0f*fabsf(0.5f-perc)));
-
- vec1[0]*= smooth*len;
- vec1[1]*= smooth*len;
- vec1[2]*= smooth*len;
-
- co[0] += vec1[0];
- co[1] += vec1[1];
- co[2] += vec1[2];
- }
- else if(beauty & B_SPHERE) { /* subdivide sphere */
- normalize_v3(co);
- co[0]*= smooth;
- co[1]*= smooth;
- co[2]*= smooth;
- }
-
- if(beauty & B_FRACTAL) {
- fac= fractal*len_v3v3(edge->v1->co, edge->v2->co);
- vec1[0]= fac*(float)(0.5-BLI_drand());
- vec1[1]= fac*(float)(0.5-BLI_drand());
- vec1[2]= fac*(float)(0.5-BLI_drand());
- add_v3_v3(co, vec1);
- }
-}
-
-/* assumes in the edge is the correct interpolated vertices already */
-/* percent defines the interpolation, smooth, fractal and beauty are for special options */
-/* results in new vertex with correct coordinate, vertex normal and weight group info */
-static EditVert *subdivide_edge_addvert(EditMesh *em, EditEdge *edge, float smooth, float fractal, int beauty, float percent)
-{
- EditVert *ev;
- float co[3];
-
- co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0];
- co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1];
- co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2];
-
- /* offset for smooth or sphere or fractal */
- alter_co(co, edge, smooth, fractal, beauty, percent);
-
- /* clip if needed by mirror modifier */
- if (edge->v1->f2) {
- if ( edge->v1->f2 & edge->v2->f2 & 1) {
- co[0]= 0.0f;
- }
- if ( edge->v1->f2 & edge->v2->f2 & 2) {
- co[1]= 0.0f;
- }
- if ( edge->v1->f2 & edge->v2->f2 & 4) {
- co[2]= 0.0f;
- }
- }
-
- ev = addvertlist(em, co, NULL);
-
- /* vert data (vgroups, ..) */
- EM_data_interp_from_verts(em, edge->v1, edge->v2, ev, percent);
-
- /* normal */
- ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0];
- ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1];
- ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2];
- normalize_v3(ev->no);
-
- return ev;
-}
-
-static void flipvertarray(EditVert** arr, short size)
-{
- EditVert *hold;
- int i;
-
- for(i=0; i<size/2; i++) {
- hold = arr[i];
- arr[i] = arr[size-i-1];
- arr[size-i-1] = hold;
- }
-}
-
-static void facecopy(EditMesh *em, EditFace *source, EditFace *target)
-{
- float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
- float *v4 = source->v4? source->v4->co: NULL;
- float w[4][4];
-
- CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
-
- target->mat_nr = source->mat_nr;
- target->flag = source->flag;
- target->h = source->h;
-
- interp_weights_face_v3( w[0],v1, v2, v3, v4, target->v1->co);
- interp_weights_face_v3( w[1],v1, v2, v3, v4, target->v2->co);
- interp_weights_face_v3( w[2],v1, v2, v3, v4, target->v3->co);
- if (target->v4)
- interp_weights_face_v3( w[3],v1, v2, v3, v4, target->v4->co);
-
- CustomData_em_validate_data(&em->fdata, target->data, target->v4 ? 4 : 3);
- CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
-}
-
-static void fill_quad_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
-{
- EditEdge *cedge=NULL;
- EditVert *v[4], **verts;
- EditFace *hold;
- short start=0, end, left, right, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
- else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
- end = (start+1)%4;
- left = (start+2)%4;
- right = (start+3)%4;
-
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- |---*---*---|
- | |
- | |
- | |
- -------------
- left right
-
- where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
- and 0,1,2... are the indexes of the new verts stored in verts
-
- We will fill this case like this or this depending on even or odd cuts
-
- |---*---*---| |---*---|
- | / \ | | / \ |
- | / \ | | / \ |
- |/ \| |/ \|
- ------------- ---------
- */
-
- // Make center face
- if(vertsize % 2 == 0) {
- hold = addfacelist(em, verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- hold->e4->f2 |= EDGEINNER;
- }else{
- hold = addfacelist(em, verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
- hold->e1->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- }
- facecopy(em, efa,hold);
-
- // Make side faces
- for(i=0;i<(vertsize-1)/2;i++) {
- hold = addfacelist(em, verts[i],verts[i+1],v[right],NULL,NULL,NULL);
- facecopy(em, efa,hold);
- if(i+1 != (vertsize-1)/2) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e2->f2 |= EDGEINNER;
- }
- }
- hold = addfacelist(em, verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
- facecopy(em, efa,hold);
- if(i+1 != (vertsize-1)/2) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e3->f2 |= EDGEINNER;
- }
- }
- }
-}
-
-static void fill_tri_single(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, int seltype)
-{
- EditEdge *cedge=NULL;
- EditVert *v[3], **verts;
- EditFace *hold;
- short start=0, end, op, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
-
- if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
- end = (start+1)%3;
- op = (start+2)%3;
-
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- |---*---*---|
- \ |
- \ |
- \ |
- \ |
- \ |
- \ |
- |op
-
- where start,end,op are indexes of EditFace->v1, etc (stored in v)
- and 0,1,2... are the indexes of the new verts stored in verts
-
- We will fill this case like this or this depending on even or odd cuts
-
- 3 2 1 0
- |---*---*---|
- \ \ \ |
- \ \ \ |
- \ \ \ |
- \ \ \|
- \ \\|
- \ |
- |op
- */
-
- // Make side faces
- for(i=0;i<(vertsize-1);i++) {
- hold = addfacelist(em, verts[i],verts[i+1],v[op],NULL,NULL,NULL);
- if(i+1 != vertsize-1) {
- if(seltype == SUBDIV_SELECT_INNER) {
- hold->e2->f2 |= EDGEINNER;
- }
- }
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_op(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[2]={NULL, NULL};
- EditVert *v[4], **verts[2];
- EditFace *hold;
- short start=0, /*end,*/ left, /* right,*/ vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;}
- else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;}
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- /* end = (start+1)%4; */ /* UNUSED */
- left = (start+2)%4;
- /* right = (start+3)%4; */ /* UNUSED */
- if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- |---*---*---|
- | |
- | |
- | |
- |---*---*---|
- 0 1 2 3
- left right
-
- We will fill this case like this or this depending on even or odd cuts
-
- |---*---*---|
- | | | |
- | | | |
- | | | |
- |---*---*---|
- */
-
- // Make side faces
- for(i=0;i<vertsize-1;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL);
- if(i < vertsize-2) {
- hold->e2->f2 |= EDGEINNER;
- hold->e2->f2 |= DOUBLEOPFILL;
- }
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_adj_path(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[2]={NULL, NULL};
- EditVert *v[4], **verts[2];
- EditFace *hold;
- short start=0, start2=0, vertsize,i;
- int ctrl= 0; // XXX
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;}
- if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;}
- if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;}
- if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;}
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- end2 3|-----------|
-
- We will fill this case like this or this depending on even or odd cuts
- |---*---*---|
- | / / / |
- * / / |
- | / / |
- * / |
- | / |
- |-----------|
- */
-
- // Make outside tris
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
- /* when ctrl is depressed, only want verts on the cutline selected */
- if (ctrl)
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
- /* when ctrl is depressed, only want verts on the cutline selected */
- if (ctrl)
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e1->h |= EM_FGON;
- //}
- // Make side faces
-
- for(i=0;i<numcuts;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- //EM_fgon_flags(em);
-
-}
-
-static void fill_quad_double_adj_fan(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[2]={NULL, NULL};
- EditVert *v[4], *op=NULL, **verts[2];
- EditFace *hold;
- short start=0, start2=0, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
- if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
- if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
- if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
-
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- end2 3|-----------|op
-
- We will fill this case like this or this (warning horrible ascii art follows)
- |---*---*---|
- | \ \ \ |
- *---\ \ \ |
- | \ \ \ \|
- *---- \ \ \ |
- | --- \\\|
- |-----------|
- */
-
- for(i=0;i<=numcuts;i++) {
- hold = addfacelist(em, op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_double_adj_inner(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[2]={NULL, NULL};
- EditVert *v[4], *op=NULL, **verts[2],**inner;
- EditFace *hold;
- short start=0, start2=0, vertsize,i;
- float co[3];
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
- if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
- if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
- if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
-
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | |
- 1* |
- | |
- 2* |
- | |
- end2 3|-----------|op
-
- We will fill this case like this or this (warning horrible ascii art follows)
- |---*-----*---|
- | * / |
- * \ / |
- | * |
- | / \ |
- * \ |
- | \ |
- |-------------|
- */
-
- // Add Inner Vert(s)
- inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts");
-
- for(i=0;i<numcuts;i++) {
- co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ;
- co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ;
- co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ;
- inner[i] = addvertlist(em, co, NULL);
- inner[i]->f2 |= EDGEINNER;
-
- EM_data_interp_from_verts(em, verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
- }
-
- // Add Corner Quad
- hold = addfacelist(em, verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- // Add Bottom Quads
- hold = addfacelist(em, verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e1->h |= EM_FGON;
- //}
- // Add Fill Quads (if # cuts > 1)
-
- for(i=0;i<numcuts-1;i++) {
- hold = addfacelist(em, inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
- hold->e1->f2 |= EDGEINNER;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- hold = addfacelist(em, inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
-
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e1->h |= EM_FGON;
- //}
- }
-
- //EM_fgon_flags(em);
-
- MEM_freeN(inner);
-}
-
-static void fill_tri_double(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[2]={NULL, NULL};
- EditVert *v[3], **verts[2];
- EditFace *hold;
- short start=0, start2=0, vertsize,i;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
-
- if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;}
- if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;}
- if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;}
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- /*
- We should have something like this now
-
- end start
- 3 2 1 0
- start2 0|---*---*---|
- | /
- 1* /
- | /
- 2* /
- | /
- end2 3|
-
- We will fill this case like this or this depending on even or odd cuts
- |---*---*---|
- | / / /
- * / /
- | / /
- * /
- | /
- |
- */
-
- // Make outside tri
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- // Make side faces
-
- for(i=0;i<numcuts;i++) {
- hold = addfacelist(em, verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
-}
-
-static void fill_quad_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts)
-{
- EditEdge *cedge[3]={0};
- EditVert *v[4], **verts[3];
- EditFace *hold;
- short start=0, start2=0, start3=0, vertsize, i, repeats;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(!(efa->e1->f & SELECT)) {
- cedge[0] = efa->e2;
- cedge[1] = efa->e3;
- cedge[2] = efa->e4;
- start = 1;start2 = 2;start3 = 3;
- }
- if(!(efa->e2->f & SELECT)) {
- cedge[0] = efa->e3;
- cedge[1] = efa->e4;
- cedge[2] = efa->e1;
- start = 2;start2 = 3;start3 = 0;
- }
- if(!(efa->e3->f & SELECT)) {
- cedge[0] = efa->e4;
- cedge[1] = efa->e1;
- cedge[2] = efa->e2;
- start = 3;start2 = 0;start3 = 1;
- }
- if(!(efa->e4->f & SELECT)) {
- cedge[0] = efa->e1;
- cedge[1] = efa->e2;
- cedge[2] = efa->e3;
- start = 0;start2 = 1;start3 = 2;
- }
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, cedge[0]);
- verts[1] = BLI_ghash_lookup(gh, cedge[1]);
- verts[2] = BLI_ghash_lookup(gh, cedge[2]);
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
- if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);}
- /*
- We should have something like this now
-
- start2
- 3 2 1 0
- start3 0|---*---*---|3
- | |
- 1* *2
- | |
- 2* *1
- | |
- 3|-----------|0 start
-
- We will fill this case like this or this depending on even or odd cuts
- there are a couple of differences. For odd cuts, there is a tri in the
- middle as well as 1 quad at the bottom (not including the extra quads
- for odd cuts > 1
-
- For even cuts, there is a quad in the middle and 2 quads on the bottom
-
- they are numbered here for clarity
-
- 1 outer tris and bottom quads
- 2 inner tri or quad
- 3 repeating quads
-
- |---*---*---*---|
- |1/ / \ \ 1|
- |/ 3 / \ 3 \|
- * / 2 \ *
- | / \ |
- |/ \ |
- *---------------*
- | 3 |
- | |
- *---------------*
- | |
- | 1 |
- | |
- |---------------|
-
- |---*---*---*---*---|
- | 1/ / \ \ 1|
- | / / \ \ |
- |/ 3 / \ 3 \|
- * / \ *
- | / \ |
- | / 2 \ |
- |/ \|
- *-------------------*
- | |
- | 3 |
- | |
- *-------------------*
- | |
- | 1 |
- | |
- *-------------------*
- | |
- | 1 |
- | |
- |-------------------|
-
- */
-
- // Make outside tris
- hold = addfacelist(em, verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- // Make bottom quad
- hold = addfacelist(em, verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- //If it is even cuts, add the 2nd lower quad
- if(numcuts % 2 == 0) {
- hold = addfacelist(em, verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- // Also Make inner quad
- hold = addfacelist(em, verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
- hold->e3->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e3->h |= EM_FGON;
- //}
- facecopy(em, efa,hold);
- repeats = (numcuts / 2) -1;
- } else {
- // Make inner tri
- hold = addfacelist(em, verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- //if(scene->toolsettings->editbutflag & B_AUTOFGON) {
- // hold->e2->h |= EM_FGON;
- //}
- facecopy(em, efa,hold);
- repeats = ((numcuts+1) / 2)-1;
- }
-
- // cuts for 1 and 2 do not have the repeating quads
- if(numcuts < 3) {repeats = 0;}
- for(i=0;i<repeats;i++) {
- //Make side repeating Quads
- hold = addfacelist(em, verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- hold = addfacelist(em, verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
- hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- // Do repeating bottom quads
- for(i=0;i<repeats;i++) {
- if(numcuts % 2 == 1) {
- hold = addfacelist(em, verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
- } else {
- hold = addfacelist(em, verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
- }
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa,hold);
- }
- //EM_fgon_flags(em);
-}
-
-static void fill_quad_quadruple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
-{
- EditVert **verts[4], ***innerverts;
- EditFace *hold;
- EditEdge temp;
- short vertsize, i, j;
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, efa->e1);
- verts[1] = BLI_ghash_lookup(gh, efa->e2);
- verts[2] = BLI_ghash_lookup(gh, efa->e3);
- verts[3] = BLI_ghash_lookup(gh, efa->e4);
-
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
- if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);}
- if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
- /*
- We should have something like this now
- 1
-
- 3 2 1 0
- 0|---*---*---|0
- | |
- 1* *1
- 2 | | 4
- 2* *2
- | |
- 3|---*---*---|3
- 3 2 1 0
-
- 3
- // we will fill a 2 dim array of editvert*s to make filling easier
- // the innervert order is shown
-
- 0 0---1---2---3
- | | | |
- 1 0---1---2---3
- | | | |
- 2 0---1---2---3
- | | | |
- 3 0---1---2---3
-
- */
- innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array");
- for(i=0;i<numcuts+2;i++) {
- innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array");
- }
-
- // first row is e1 last row is e3
- for(i=0;i<numcuts+2;i++) {
- innerverts[0][i] = verts[0][(numcuts+1)-i];
- innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i];
- }
-
- for(i=1;i<=numcuts;i++) {
- /* we create a fake edge for the next loop */
- temp.v2 = innerverts[i][0] = verts[1][i];
- temp.v1 = innerverts[i][numcuts+1] = verts[3][i];
-
- for(j=1;j<=numcuts;j++) {
- float percent= (float)j/(float)(numcuts+1);
-
- innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, percent);
- }
- }
- // Fill with faces
- for(i=0;i<numcuts+1;i++) {
- for(j=0;j<numcuts+1;j++) {
- hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
- hold->e1->f2 = EDGENEW;
- hold->e2->f2 = EDGENEW;
- hold->e3->f2 = EDGENEW;
- hold->e4->f2 = EDGENEW;
-
- if(i != 0) { hold->e1->f2 |= EDGEINNER; }
- if(j != 0) { hold->e2->f2 |= EDGEINNER; }
- if(i != numcuts) { hold->e3->f2 |= EDGEINNER; }
- if(j != numcuts) { hold->e4->f2 |= EDGEINNER; }
-
- facecopy(em, efa,hold);
- }
- }
- // Clean up our dynamic multi-dim array
- for(i=0;i<numcuts+2;i++) {
- MEM_freeN(innerverts[i]);
- }
- MEM_freeN(innerverts);
-}
-
-static void fill_tri_triple(EditMesh *em, EditFace *efa, struct GHash *gh, int numcuts, float smooth, float fractal, int beauty)
-{
- EditVert **verts[3], ***innerverts;
- short vertsize, i, j;
- EditFace *hold;
- EditEdge temp;
-
- // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
- verts[0] = BLI_ghash_lookup(gh, efa->e1);
- verts[1] = BLI_ghash_lookup(gh, efa->e2);
- verts[2] = BLI_ghash_lookup(gh, efa->e3);
-
- //This is the index size of the verts array
- vertsize = numcuts+2;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
- if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
- if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);}
- /*
- We should have something like this now
- 3
-
- 3 2 1 0
- 0|---*---*---|3
- | /
- 1 1* *2
- | /
- 2* *1 2
- | /
- 3|/
- 0
-
- we will fill a 2 dim array of editvert*s to make filling easier
-
- 3
-
- 0 0---1---2---3---4
- | / | / |/ | /
- 1 0---1----2---3
- 1 | / | / | /
- 2 0----1---2 2
- | / | /
- |/ |/
- 3 0---1
- | /
- |/
- 4 0
-
- */
-
- innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array");
- for(i=0;i<numcuts+2;i++) {
- innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array");
- }
- //top row is e3 backwards
- for(i=0;i<numcuts+2;i++) {
- innerverts[0][i] = verts[2][(numcuts+1)-i];
- }
-
- for(i=1;i<=numcuts+1;i++) {
- //fake edge, first vert is from e1, last is from e2
- temp.v1= innerverts[i][0] = verts[0][i];
- temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i];
-
- for(j=1;j<(numcuts+1)-i;j++) {
- float percent= (float)j/(float)((numcuts+1)-i);
-
- innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(em, &temp, smooth, fractal, beauty, 1-percent);
- }
- }
-
- // Now fill the verts with happy little tris :)
- for(i=0;i<=numcuts+1;i++) {
- for(j=0;j<(numcuts+1)-i;j++) {
- //We always do the first tri
- hold = addfacelist(em, innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- if(i != 0) { hold->e1->f2 |= EDGEINNER; }
- if(j != 0) { hold->e2->f2 |= EDGEINNER; }
- if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;}
-
- facecopy(em, efa,hold);
- //if there are more to come, we do the 2nd
- if(j+1 <= numcuts-i) {
- hold = addfacelist(em, innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
- facecopy(em, efa,hold);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- }
- }
- }
-
- // Clean up our dynamic multi-dim array
- for(i=0;i<numcuts+2;i++) {
- MEM_freeN(innerverts[i]);
- }
- MEM_freeN(innerverts);
-}
-
-//Next two fill types are for knife exact only and are provided to allow for knifing through vertices
-//This means there is no multicut!
-static void fill_quad_doublevert(EditMesh *em, EditFace *efa, int v1, int v2)
-{
- EditFace *hold;
- /*
- Depending on which two vertices have been knifed through (v1 and v2), we
- triangulate like the patterns below.
- X-------| |-------X
- | \ | | / |
- | \ | | / |
- | \ | | / |
- --------X X--------
- */
-
- if(v1 == 1 && v2 == 3){
- hold= addfacelist(em, efa->v1, efa->v2, efa->v3, 0, efa, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
- hold= addfacelist(em, efa->v1, efa->v3, efa->v4, 0, efa, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
- else{
- hold= addfacelist(em, efa->v1, efa->v2, efa->v4, 0, efa, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e2->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
- hold= addfacelist(em, efa->v2, efa->v3, efa->v4, 0, efa, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
-}
-
-static void fill_quad_singlevert(EditMesh *em, EditFace *efa, struct GHash *gh)
-{
- EditEdge *cedge=NULL;
- EditVert *v[4], **verts;
- EditFace *hold;
- short start=0, end, left, right, vertsize;
-
- v[0] = efa->v1;
- v[1] = efa->v2;
- v[2] = efa->v3;
- v[3] = efa->v4;
-
- if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
- else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
- else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
- else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
-
- // Point verts to the array of new verts for cedge
- verts = BLI_ghash_lookup(gh, cedge);
- //This is the index size of the verts array
- vertsize = 3;
-
- // Is the original v1 the same as the first vert on the selected edge?
- // if not, the edge is running the opposite direction in this face so flip
- // the array to the correct direction
-
- if(verts[0] != v[start]) {flipvertarray(verts,3);}
- end = (start+1)%4;
- left = (start+2)%4;
- right = (start+3)%4;
-
-/*
- We should have something like this now
-
- end start
- 2 1 0
- |-----*-----|
- | |
- | |
- | |
- -------------
- left right
-
- where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
- and 0,1,2 are the indexes of the new verts stored in verts. We fill like
- this, depending on whether its vertex 'left' or vertex 'right' thats
- been knifed through...
-
- |---*---| |---*---|
- | / | | \ |
- | / | | \ |
- |/ | | \|
- X-------- --------X
-*/
-
- if(v[left]->f1){
- //triangle is composed of cutvert, end and left
- hold = addfacelist(em, verts[1],v[end],v[left],NULL, NULL,NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e3->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
-
- //quad is composed of cutvert, left, right and start
- hold = addfacelist(em, verts[1],v[left],v[right],v[start], NULL, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e4->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
- else if(v[right]->f1){
- //triangle is composed of cutvert, right and start
- hold = addfacelist(em, verts[1],v[right],v[start], NULL, NULL, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e1->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- //quad is composed of cutvert, end, left, right
- hold = addfacelist(em, verts[1],v[end], v[left], v[right], NULL, NULL);
- hold->e1->f2 |= EDGENEW;
- hold->e2->f2 |= EDGENEW;
- hold->e3->f2 |= EDGENEW;
- hold->e4->f2 |= EDGENEW;
- hold->e4->f2 |= EDGEINNER;
- facecopy(em, efa, hold);
- }
-
-}
-
-// This function takes an example edge, the current point to create and
-// the total # of points to create, then creates the point and return the
-// editvert pointer to it.
-static EditVert *subdivideedgenum(EditMesh *em, EditEdge *edge, int curpoint, int totpoint, float smooth, float fractal, int beauty)
-{
- EditVert *ev;
- float percent;
-
- if (beauty & (B_PERCENTSUBD) && totpoint == 1)
- //percent=(float)(edge->tmp.l)/32768.0f;
- percent= edge->tmp.fp;
- else
- percent= (float)curpoint/(float)(totpoint+1);
-
- ev= subdivide_edge_addvert(em, edge, smooth, fractal, beauty, percent);
- ev->f = edge->v1->f;
-
- return ev;
-}
-
-void esubdivideflag(Object *obedit, EditMesh *em, int flag, float smooth, float fractal, int beauty, int numcuts, int corner_pattern, int seltype)
-{
- EditFace *ef;
- EditEdge *eed, *cedge, *sort[4];
- EditVert *eve, **templist;
- struct GHash *gh;
- float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3];
- int i, j, edgecount, touchcount, facetype,hold;
- ModifierData *md= obedit->modifiers.first;
- int ctrl= 0; // XXX
-
- //Set faces f1 to 0 cause we need it later
- for(ef=em->faces.first;ef;ef = ef->next) ef->f1 = 0;
- for(eve=em->verts.first; eve; eve=eve->next) {
- if(!(beauty & B_KNIFE)) /* knife sets this flag for vertex cuts */
- eve->f1 = 0;
- eve->f2 = 0;
- }
-
- for (; md; md=md->next) {
- if (md->type==eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData*) md;
-
- if(mmd->flag & MOD_MIR_CLIPPING) {
- for (eve= em->verts.first; eve; eve= eve->next) {
- eve->f2= 0;
- switch(mmd->axis){
- case 0:
- if (fabsf(eve->co[0]) < mmd->tolerance)
- eve->f2 |= 1;
- break;
- case 1:
- if (fabsf(eve->co[1]) < mmd->tolerance)
- eve->f2 |= 2;
- break;
- case 2:
- if (fabsf(eve->co[2]) < mmd->tolerance)
- eve->f2 |= 4;
- break;
- }
- }
- }
- }
- }
-
- //Flush vertex flags upward to the edges
- for(eed = em->edges.first;eed;eed = eed->next) {
- //if(eed->f & flag && eed->v1->f == eed->v2->f) {
- // eed->f |= eed->v1->f;
- // }
- eed->f2 = 0;
- if(eed->f & flag) {
- eed->f2 |= EDGEOLD;
- }
- }
-
- // We store an array of verts for each edge that is subdivided,
- // we put this array as a value in a ghash which is keyed by the EditEdge*
-
- // Now for beauty subdivide deselect edges based on length
- if(beauty & B_BEAUTY) {
- for(ef = em->faces.first;ef;ef = ef->next) {
- if(!ef->v4) {
- continue;
- }
- if(ef->f & SELECT) {
- VECCOPY(v1mat, ef->v1->co);
- VECCOPY(v2mat, ef->v2->co);
- VECCOPY(v3mat, ef->v3->co);
- VECCOPY(v4mat, ef->v4->co);
- mul_mat3_m4_v3(obedit->obmat, v1mat);
- mul_mat3_m4_v3(obedit->obmat, v2mat);
- mul_mat3_m4_v3(obedit->obmat, v3mat);
- mul_mat3_m4_v3(obedit->obmat, v4mat);
-
- length[0] = len_v3v3(v1mat, v2mat);
- length[1] = len_v3v3(v2mat, v3mat);
- length[2] = len_v3v3(v3mat, v4mat);
- length[3] = len_v3v3(v4mat, v1mat);
- sort[0] = ef->e1;
- sort[1] = ef->e2;
- sort[2] = ef->e3;
- sort[3] = ef->e4;
-
-
- // Beauty Short Edges
- if(beauty & B_BEAUTY_SHORT) {
- for(j=0;j<2;j++) {
- hold = -1;
- for(i=0;i<4;i++) {
- if(length[i] < 0) {
- continue;
- } else if(hold == -1) {
- hold = i;
- } else {
- if(length[hold] < length[i]) {
- hold = i;
- }
- }
- }
- if (hold > -1) {
- sort[hold]->f &= ~SELECT;
- sort[hold]->f2 |= EDGENEW;
- length[hold] = -1;
- }
- }
- }
-
- // Beauty Long Edges
- else {
- for(j=0;j<2;j++) {
- hold = -1;
- for(i=0;i<4;i++) {
- if(length[i] < 0) {
- continue;
- } else if(hold == -1) {
- hold = i;
- } else {
- if(length[hold] > length[i]) {
- hold = i;
- }
- }
- }
- if (hold > -1) {
- sort[hold]->f &= ~SELECT;
- sort[hold]->f2 |= EDGENEW;
- length[hold] = -1;
- }
- }
- }
- }
- }
- }
-
- gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "subdivideedgenum gh");
-
- // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut
- if(beauty & B_KNIFE) {
- for(eed= em->edges.first;eed;eed=eed->next) {
- if( eed->tmp.fp == 0 ) {
- EM_select_edge(eed,0);
- }
- }
- }
- // So for each edge, if it is selected, we allocate an array of size cuts+2
- // so we can have a place for the v1, the new verts and v2
- for(eed=em->edges.first;eed;eed = eed->next) {
- if(eed->f & flag) {
- templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist");
- templist[0] = eed->v1;
- for(i=0;i<numcuts;i++) {
- // This function creates the new vert and returns it back
- // to the array
- templist[i+1] = subdivideedgenum(em, eed, i+1, numcuts, smooth, fractal, beauty);
- //while we are here, we can copy edge info from the original edge
- cedge = addedgelist(em, templist[i],templist[i+1],eed);
- // Also set the edge f2 to EDGENEW so that we can use this info later
- cedge->f2 = EDGENEW;
- }
- templist[i+1] = eed->v2;
- //Do the last edge too
- cedge = addedgelist(em, templist[i],templist[i+1],eed);
- cedge->f2 = EDGENEW;
- // Now that the edge is subdivided, we can put its verts in the ghash
- BLI_ghash_insert(gh, eed, templist);
- }
- }
-
-// DAG_id_tag_update(obedit->data, 0);
- // Now for each face in the mesh we need to figure out How many edges were cut
- // and which filling method to use for that face
- for(ef = em->faces.first;ef;ef = ef->next) {
- edgecount = 0;
- facetype = 3;
- if(ef->e1->f & flag) {edgecount++;}
- if(ef->e2->f & flag) {edgecount++;}
- if(ef->e3->f & flag) {edgecount++;}
- if(ef->v4) {
- facetype = 4;
- if(ef->e4->f & flag) {edgecount++;}
- }
- if(facetype == 4) {
- switch(edgecount) {
- case 0:
- if(beauty & B_KNIFE && numcuts == 1){
- /*Test for when knifing through two opposite verts but no edges*/
- touchcount = 0;
- if(ef->v1->f1) touchcount++;
- if(ef->v2->f1) touchcount++;
- if(ef->v3->f1) touchcount++;
- if(ef->v4->f1) touchcount++;
- if(touchcount == 2){
- if(ef->v1->f1 && ef->v3->f1){
- ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 1, 3);
- }
- else if(ef->v2->f1 && ef->v4->f1){
- ef->f1 = SELECT;
- fill_quad_doublevert(em, ef, 2, 4);
- }
- }
- }
- break;
-
- case 1:
- if(beauty & B_KNIFE && numcuts == 1){
- /*Test for when knifing through an edge and one vert*/
- touchcount = 0;
- if(ef->v1->f1) touchcount++;
- if(ef->v2->f1) touchcount++;
- if(ef->v3->f1) touchcount++;
- if(ef->v4->f1) touchcount++;
-
- if(touchcount == 1){
- if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) ||
- (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) ||
- (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) ||
- (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){
-
- ef->f1 = SELECT;
- fill_quad_singlevert(em, ef, gh);
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- }
- else{
- ef->f1 = SELECT;
- fill_quad_single(em, ef, gh, numcuts, seltype);
- }
- break;
- case 2: ef->f1 = SELECT;
- // if there are 2, we check if edge 1 and 3 are either both on or off that way
- // we can tell if the selected pair is Adjacent or Opposite of each other
- if((ef->e1->f & flag && ef->e3->f & flag) ||
- (ef->e2->f & flag && ef->e4->f & flag)) {
- fill_quad_double_op(em, ef, gh, numcuts);
- }else{
- switch(corner_pattern) {
- case 0: fill_quad_double_adj_path(em, ef, gh, numcuts); break;
- case 1: fill_quad_double_adj_inner(em, ef, gh, numcuts); break;
- case 2: fill_quad_double_adj_fan(em, ef, gh, numcuts); break;
- }
-
- }
- break;
- case 3: ef->f1 = SELECT;
- fill_quad_triple(em, ef, gh, numcuts);
- break;
- case 4: ef->f1 = SELECT;
- fill_quad_quadruple(em, ef, gh, numcuts, smooth, fractal, beauty);
- break;
- }
- } else {
- switch(edgecount) {
- case 0: break;
- case 1: ef->f1 = SELECT;
- fill_tri_single(em, ef, gh, numcuts, seltype);
- break;
- case 2: ef->f1 = SELECT;
- fill_tri_double(em, ef, gh, numcuts);
- break;
- case 3: ef->f1 = SELECT;
- fill_tri_triple(em, ef, gh, numcuts, smooth, fractal, beauty);
- break;
- }
- }
- }
-
- // Delete Old Edges and Faces
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(BLI_ghash_haskey(gh,eed)) {
- eed->f1 = SELECT;
- } else {
- eed->f1 = 0;
- }
- }
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- if(seltype == SUBDIV_SELECT_ORIG && !ctrl) {
- /* bugfix: vertex could get flagged as "not-selected"
- // solution: clear flags before, not at the same time as setting SELECT flag -dg
- */
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(!(eed->f2 & EDGENEW || eed->f2 & EDGEOLD)) {
- eed->f &= !flag;
- EM_select_edge(eed,0);
- }
- }
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) {
- eed->f |= flag;
- EM_select_edge(eed,1);
- }
- }
- } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| ctrl) {
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & EDGEINNER) {
- eed->f |= flag;
- EM_select_edge(eed,1);
- if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT;
- if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT;
- }else{
- eed->f &= !flag;
- EM_select_edge(eed,0);
- }
- }
- } else if(seltype == SUBDIV_SELECT_LOOPCUT){
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f2 & DOUBLEOPFILL){
- eed->f |= flag;
- EM_select_edge(eed,1);
- }else{
- eed->f &= !flag;
- EM_select_edge(eed,0);
- }
- }
- }
- if(em->selectmode & SCE_SELECT_VERTEX) {
- for(eed = em->edges.first;eed;eed = eed->next) {
- if(eed->f & SELECT) {
- eed->v1->f |= SELECT;
- eed->v2->f |= SELECT;
- }
- }
- }
-
- //fix hide flags for edges. First pass, hide edges of hidden faces
- for(ef=em->faces.first; ef; ef=ef->next){
- if(ef->h){
- ef->e1->h |= 1;
- ef->e2->h |= 1;
- ef->e3->h |= 1;
- if(ef->e4) ef->e4->h |= 1;
- }
- }
- //second pass: unhide edges of visible faces adjacent to hidden faces
- for(ef=em->faces.first; ef; ef=ef->next){
- if(ef->h == 0){
- ef->e1->h &= ~1;
- ef->e2->h &= ~1;
- ef->e3->h &= ~1;
- if(ef->e4) ef->e4->h &= ~1;
- }
- }
-
- //third pass: unhide edges that have both verts visible
- //(these were missed if all faces were hidden, bug #21976)
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->v1->h == 0 && eed->v2->h == 0)
- eed->h &= ~1;
- }
-
- // Free the ghash and call MEM_freeN on all the value entries to return
- // that memory
- BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
-
- EM_selectmode_flush(em);
- for(ef=em->faces.first;ef;ef = ef->next) {
- if(ef->e4) {
- if( (ef->e1->f & SELECT && ef->e2->f & SELECT) &&
- (ef->e3->f & SELECT && ef->e4->f & SELECT) ) {
- ef->f |= SELECT;
- }
- } else {
- if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
- ef->f |= SELECT;
- }
- }
- }
-
- recalc_editnormals(em);
-}
-
-static int count_selected_edges(EditEdge *ed)
-{
- int totedge = 0;
- while(ed) {
- ed->tmp.p = 0;
- if( ed->f & SELECT ) totedge++;
- ed= ed->next;
- }
- return totedge;
-}
-
-/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */
-typedef EditFace *EVPtr;
-typedef EVPtr EVPTuple[2];
-
-/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces)
- sharing one edge.
- arguments: selected edge list, face list.
- Edges will also be tagged accordingly (see eed->f2) */
-
-static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
-{
- EditEdge *e1, *e2, *e3;
- EVPtr *evp;
- int i = 0;
-
- /* run through edges, if selected, set pointer edge-> facearray */
- while(eed) {
- eed->f2= 0;
- eed->f1= 0;
- if( eed->f & SELECT ) {
- eed->tmp.p = (EditVert *) (&efaa[i]);
- i++;
- }
- else eed->tmp.p = NULL;
-
- eed= eed->next;
- }
-
-
- /* find edges pointing to 2 faces by procedure:
-
- - run through faces and their edges, increase
- face counter e->f1 for each face
- */
-
- while(efa) {
- efa->f1= 0;
- if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */
- e1= efa->e1;
- e2= efa->e2;
- e3= efa->e3;
- if(e1->f2<3 && e1->tmp.p) {
- if(e1->f2<2) {
- evp= (EVPtr *) e1->tmp.p;
- evp[(int)e1->f2] = efa;
- }
- e1->f2+= 1;
- }
- if(e2->f2<3 && e2->tmp.p) {
- if(e2->f2<2) {
- evp= (EVPtr *) e2->tmp.p;
- evp[(int)e2->f2]= efa;
- }
- e2->f2+= 1;
- }
- if(e3->f2<3 && e3->tmp.p) {
- if(e3->f2<2) {
- evp= (EVPtr *) e3->tmp.p;
- evp[(int)e3->f2]= efa;
- }
- e3->f2+= 1;
- }
- }
- else {
- /* set to 3 to make sure these are not flipped or joined */
- efa->e1->f2= 3;
- efa->e2->f2= 3;
- efa->e3->f2= 3;
- if (efa->e4) efa->e4->f2= 3;
- }
-
- efa= efa->next;
- }
- return i;
-}
-
-
-/* returns vertices of two adjacent triangles forming a quad
- - can be righthand or lefthand
-
- 4-----3
- |\ |
- | \ 2 | <- efa1
- | \ |
- efa-> | 1 \ |
- | \|
- 1-----2
-
-*/
-#define VTEST(face, num, other) \
- (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
-
-static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex)
-{
- if VTEST(efa, 1, efa1) {
- *v1= efa->v1;
- *v2= efa->v2;
- vindex[0]= 0;
- vindex[1]= 1;
- }
- else if VTEST(efa, 2, efa1) {
- *v1= efa->v2;
- *v2= efa->v3;
- vindex[0]= 1;
- vindex[1]= 2;
- }
- else if VTEST(efa, 3, efa1) {
- *v1= efa->v3;
- *v2= efa->v1;
- vindex[0]= 2;
- vindex[1]= 0;
- }
-
- if VTEST(efa1, 1, efa) {
- *v3= efa1->v1;
- *v4= (efa1->v2 == *v2)? efa1->v3: efa1->v2;
- vindex[2]= 0;
- vindex[3]= (efa1->v2 == *v2)? 2: 1;
- }
- else if VTEST(efa1, 2, efa) {
- *v3= efa1->v2;
- *v4= (efa1->v3 == *v2)? efa1->v1: efa1->v3;
- vindex[2]= 1;
- vindex[3]= (efa1->v3 == *v2)? 0: 2;
- }
- else if VTEST(efa1, 3, efa) {
- *v3= efa1->v3;
- *v4= (efa1->v1 == *v2)? efa1->v2: efa1->v1;
- vindex[2]= 2;
- vindex[3]= (efa1->v1 == *v2)? 1: 0;
- }
- else
- *v3= *v4= NULL;
-}
-
-/* Helper functions for edge/quad edit features*/
-static void untag_edges(EditFace *f)
-{
- f->e1->f1 = 0;
- f->e2->f1 = 0;
- f->e3->f1 = 0;
- if (f->e4) f->e4->f1 = 0;
-}
-
-/** remove and free list of tagged edges and faces */
-static void free_tagged_edges_faces(EditMesh *em, EditEdge *eed, EditFace *efa)
-{
- EditEdge *nexted;
- EditFace *nextvl;
-
- while(efa) {
- nextvl= efa->next;
- if(efa->f1) {
- BLI_remlink(&em->faces, efa);
- free_editface(em, efa);
- }
- else
- /* avoid deleting edges that are still in use */
- untag_edges(efa);
- efa= nextvl;
- }
-
- while(eed) {
- nexted= eed->next;
- if(eed->f1) {
- remedge(em, eed);
- free_editedge(em, eed);
- }
- eed= nexted;
- }
-}
-
-
-/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
-static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit)
-{
-
- /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
- /*Note: this is more complicated than it needs to be and should be cleaned up...*/
- float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff,
- edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff,
- minarea, maxarea, areaA, areaB;
-
- /*First Test: Normal difference*/
- normal_tri_v3( noA1,v1->co, v2->co, v3->co);
- normal_tri_v3( noA2,v1->co, v3->co, v4->co);
-
- if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
- else normalADiff = RAD2DEGF(angle_v2v2(noA1, noA2));
- //if(!normalADiff) normalADiff = 179;
- normal_tri_v3( noB1,v2->co, v3->co, v4->co);
- normal_tri_v3( noB2,v4->co, v1->co, v2->co);
-
- if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
- else normalBDiff = RAD2DEGF(angle_v2v2(noB1, noB2));
- //if(!normalBDiff) normalBDiff = 179;
-
- measure += (normalADiff/360) + (normalBDiff/360);
- if(measure > limit) return measure;
-
- /*Second test: Colinearity*/
- sub_v3_v3v3(edgeVec1, v1->co, v2->co);
- sub_v3_v3v3(edgeVec2, v2->co, v3->co);
- sub_v3_v3v3(edgeVec3, v3->co, v4->co);
- sub_v3_v3v3(edgeVec4, v4->co, v1->co);
-
- diff = 0.0;
-
- diff = (
- fabsf(RAD2DEGF(angle_v2v2(edgeVec1, edgeVec2)) - 90) +
- fabsf(RAD2DEGF(angle_v2v2(edgeVec2, edgeVec3)) - 90) +
- fabsf(RAD2DEGF(angle_v2v2(edgeVec3, edgeVec4)) - 90) +
- fabsf(RAD2DEGF(angle_v2v2(edgeVec4, edgeVec1)) - 90)) / 360;
- if(!diff) return 0.0;
-
- measure += diff;
- if(measure > limit) return measure;
-
- /*Third test: Concavity*/
- areaA = area_tri_v3(v1->co, v2->co, v3->co) + area_tri_v3(v1->co, v3->co, v4->co);
- areaB = area_tri_v3(v2->co, v3->co, v4->co) + area_tri_v3(v4->co, v1->co, v2->co);
-
- if(areaA <= areaB) minarea = areaA;
- else minarea = areaB;
-
- if(areaA >= areaB) maxarea = areaA;
- else maxarea = areaB;
-
- if(!maxarea) measure += 1;
- else measure += (1 - (minarea / maxarea));
-
- return measure;
-}
-
-#define T2QUV_LIMIT 0.005f
-#define T2QCOL_LIMIT 3
-static int compareFaceAttribs(EditMesh *em, EditFace *f1, EditFace *f2, EditEdge *eed)
-{
- /*Test to see if the per-face attributes for the joining edge match within limit*/
- MTFace *tf1, *tf2;
- unsigned int *col1, *col2;
- short i,attrok=0, flag = 0, /* XXX scene->toolsettings->editbutflag,*/ fe1[2], fe2[2];
-
- tf1 = CustomData_em_get(&em->fdata, f1->data, CD_MTFACE);
- tf2 = CustomData_em_get(&em->fdata, f2->data, CD_MTFACE);
-
- col1 = CustomData_em_get(&em->fdata, f1->data, CD_MCOL);
- col2 = CustomData_em_get(&em->fdata, f2->data, CD_MCOL);
-
- /*store indices for faceedges*/
- f1->v1->f1 = 0;
- f1->v2->f1 = 1;
- f1->v3->f1 = 2;
-
- fe1[0] = eed->v1->f1;
- fe1[1] = eed->v2->f1;
-
- f2->v1->f1 = 0;
- f2->v2->f1 = 1;
- f2->v3->f1 = 2;
-
- fe2[0] = eed->v1->f1;
- fe2[1] = eed->v2->f1;
-
- /*compare faceedges for each face attribute. Additional per face attributes can be added later*/
- /*do UVs*/
- if(flag & B_JOINTRIA_UV){
-
- if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
- else if(tf1->tpage != tf2->tpage); /*do nothing*/
- else{
- for(i = 0; i < 2; i++){
- if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] &&
- tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV;
- }
- }
- }
-
- /*do VCOLs*/
- if(flag & B_JOINTRIA_VCOL){
- if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
- else{
- char *f1vcol, *f2vcol;
- for(i = 0; i < 2; i++){
- f1vcol = (char *)&(col1[fe1[i]]);
- f2vcol = (char *)&(col2[fe2[i]]);
-
- /*compare f1vcol with f2vcol*/
- if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] &&
- f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] &&
- f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL;
- }
- }
- }
-
- if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1;
- return 0;
-}
-
-static int fplcmp(const void *v1, const void *v2)
-{
- const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
-
- if( e1->crease > e2->crease) return 1;
- else if( e1->crease < e2->crease) return -1;
-
- return 0;
-}
-
-/*Bitflags for edges.*/
-#define T2QDELETE 1
-#define T2QCOMPLEX 2
-#define T2QJOIN 4
-void join_triangles(EditMesh *em)
-{
- EditVert *v1, *v2, *v3, *v4, *eve;
- EditEdge *eed, **edsortblock = NULL, **edb = NULL;
- EditFace *efa;
- EVPTuple *efaar = NULL;
- EVPtr *efaa = NULL;
- float *creases = NULL;
- float measure; /*Used to set tolerance*/
- float limit = 0.8f; // XXX scene->toolsettings->jointrilimit;
- int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
-
- /*if we take a long time on very dense meshes we want waitcursor to display*/
- waitcursor(1);
-
- totseledge = count_selected_edges(em->edges.first);
- if(totseledge==0) return;
-
- /*abusing crease value to store weights for edge pairs. Nasty*/
- for(eed=em->edges.first; eed; eed=eed->next) totedge++;
- if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
- for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
- creases[i] = eed->crease;
- eed->crease = 0.0;
- }
-
- /*clear temp flags*/
- for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0;
- for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0;
- for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0;
-
- /*For every selected 2 manifold edge, create pointers to its two faces.*/
- efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad");
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
- complexedges = 0;
-
- if(ok){
-
-
- /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/
- for(eed=em->edges.first; eed; eed=eed->next){
- /* eed->f2 is 2 only if this edge is part of exactly two
- triangles, and both are selected, and it has EVPTuple assigned */
- if(eed->f2 == 2){
- efaa= (EVPtr *) eed->tmp.p;
- efaa[0]->tmp.l++;
- efaa[1]->tmp.l++;
- }
- }
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f2 == 2){
- efaa= (EVPtr *) eed->tmp.p;
- v1 = v2 = v3 = v4 = NULL;
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
- if(v1 && v2 && v3 && v4){
- /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/
- if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){
- eed->f1 |= T2QJOIN;
- efaa[0]->f1 = 1; //mark for join
- efaa[1]->f1 = 1; //mark for join
- }
- else{
-
- /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved.
- Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria:
-
- 1: the two faces do not share the same material
- 2: the edge joining the two faces is marked as sharp.
- 3: the two faces UV's do not make a good match
- 4: the two faces Vertex colors do not make a good match
-
- If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function.
- This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user
- the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the
- same faces in the current pair later.
-
- This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of
- the python scripts bundled with Blender releases.
- */
-
-// XXX if(scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
-// else if(scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
-// else if(((scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
- compareFaceAttribs(em, efaa[0], efaa[1], eed); // XXX == 0); /*do nothing*/
-// else{
- measure = measure_facepair(v1, v2, v3, v4, limit);
- if(measure < limit){
- complexedges++;
- eed->f1 |= T2QCOMPLEX;
- eed->crease = measure; /*we dont mark edges for join yet*/
- }
-// }
- }
- }
- }
- }
-
- /*Quicksort the complex edges according to their weighting*/
- if(complexedges){
- edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
- for(eed = em->edges.first; eed; eed=eed->next){
- if(eed->f1 & T2QCOMPLEX){
- *edb = eed;
- edb++;
- }
- }
- qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp);
- /*now go through and mark the edges who get the highest weighting*/
- for(edb=edsortblock, i=0; i < complexedges; edb++, i++){
- efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/
- if( !efaa[0]->f1 && !efaa[1]->f1){
- efaa[0]->f1 = 1; //mark for join
- efaa[1]->f1 = 1; //mark for join
- (*edb)->f1 |= T2QJOIN;
- }
- }
- }
-
- /*finally go through all edges marked for join (simple and complex) and create new faces*/
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f1 & T2QJOIN){
- efaa= (EVPtr *)eed->tmp.p;
- v1 = v2 = v3 = v4 = NULL;
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
- if((v1 && v2 && v3 && v4) && (exist_face(em, v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be addressed.*/
- /*flag for delete*/
- eed->f1 |= T2QDELETE;
- /*create new quad and select*/
- efa = EM_face_from_faces(em, efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
- EM_select_face(efa,1);
- }
- else{
- efaa[0]->f1 = 0;
- efaa[1]->f1 = 0;
- }
- }
- }
- }
-
- /*free data and cleanup*/
- if(creases){
- for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
- MEM_freeN(creases);
- }
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f1 & T2QDELETE) eed->f1 = 1;
- else eed->f1 = 0;
- }
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
- if(efaar) MEM_freeN(efaar);
- if(edsortblock) MEM_freeN(edsortblock);
-
- EM_selectmode_flush(em);
-
-}
-/* ******************** END TRIANGLE TO QUAD ************************************* */
-
-#define FACE_MARKCLEAR(f) (f->f1 = 1)
-
-/* quick hack, basically a copy of beautify_fill */
-static void edge_flip(EditMesh *em)
-{
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditFace *efa, *w;
- //void **efaar, **efaa;
- EVPTuple *efaar;
- EVPtr *efaa;
- int totedge, ok, vindex[4];
-
- /* - all selected edges with two faces
- * - find the faces: store them in edges (using datablock)
- * - per edge: - test convex
- * - test edge: flip?
- - if true: remedge, addedge, all edges at the edge get new face pointers
- */
-
- EM_selectmode_flush(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
-
- totedge = count_selected_edges(em->edges.first);
- if(totedge==0) return;
-
- /* temporary array for : edge -> face[1], face[2] */
- efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
-
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
-
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- if(eed->f2==2) { /* points to 2 faces */
-
- efaa= (EVPtr *) eed->tmp.p;
-
- /* don't do it if flagged */
-
- ok= 1;
- efa= efaa[0];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- efa= efaa[1];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
-
- if(ok) {
- /* test convex */
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
-
-/*
- 4-----3 4-----3
- |\ | | /|
- | \ 1 | | 1 / |
- | \ | -> | / |
- | 0 \ | | / 0 |
- | \| |/ |
- 1-----2 1-----2
-*/
- /* make new faces */
- if (v1 && v2 && v3) {
- if( convex(v1->co, v2->co, v3->co, v4->co) ) {
- if(exist_face(em, v1, v2, v3, v4)==0) {
- /* outch this may break seams */
- w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
- vindex[1], 4+vindex[2], -1);
-
- EM_select_face(w, 1);
-
- /* outch this may break seams */
- w= EM_face_from_faces(em, efaa[0], efaa[1], vindex[0],
- 4+vindex[2], 4+vindex[3], -1);
-
- EM_select_face(w, 1);
- }
- /* tag as to-be-removed */
- FACE_MARKCLEAR(efaa[1]);
- FACE_MARKCLEAR(efaa[0]);
- eed->f1 = 1;
-
- } /* endif test convex */
- }
- }
- }
- eed= nexted;
- }
-
- /* clear tagged edges and faces: */
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- MEM_freeN(efaar);
-}
-
-#define DIRECTION_CW 1
-#define DIRECTION_CCW 2
-
-static const EnumPropertyItem direction_items[]= {
- {DIRECTION_CW, "CW", 0, "Clockwise", ""},
- {DIRECTION_CCW, "CCW", 0, "Counter Clockwise", ""},
- {0, NULL, 0, NULL, NULL}};
-
-#define AXIS_X 1
-#define AXIS_Y 2
-
-static const EnumPropertyItem axis_items_xy[]= {
- {AXIS_X, "X", 0, "X", ""},
- {AXIS_Y, "Y", 0, "Y", ""},
- {0, NULL, 0, NULL, NULL}};
-
-static void edge_rotate(EditMesh *em, wmOperator *op, EditEdge *eed, int dir)
-{
- EditVert **verts[2];
- EditFace *face[2], *efa, *newFace[2];
- EditEdge **edges[2], **hiddenedges, *srchedge;
- int facecount, p1, p2, p3, p4, fac1, fac2, i, j;
- int numhidden, numshared, p[2][4];
-
- /* check to make sure that the edge is only part of 2 faces */
- facecount = 0;
- for(efa = em->faces.first;efa;efa = efa->next) {
- if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) {
- if(facecount >= 2) {
- /* more than two faces with this edge */
- return;
- }
- else {
- face[facecount] = efa;
- facecount++;
- }
- }
- }
-
- if(facecount < 2)
- return;
-
- /* how many edges does each face have */
- if(face[0]->e4) fac1= 4;
- else fac1= 3;
-
- if(face[1]->e4) fac2= 4;
- else fac2= 3;
-
- /* make a handy array for verts and edges */
- verts[0]= &face[0]->v1;
- edges[0]= &face[0]->e1;
- verts[1]= &face[1]->v1;
- edges[1]= &face[1]->e1;
-
- /* we don't want to rotate edges between faces that share more than one edge */
- numshared= 0;
- for(i=0; i<fac1; i++)
- for(j=0; j<fac2; j++)
- if (edges[0][i] == edges[1][j])
- numshared++;
-
- if(numshared > 1)
- return;
-
- /* we want to construct an array of vertex indicis in both faces, starting at
- the last vertex of the edge being rotated.
- - first we find the two vertices that lie on the rotating edge
- - then we make sure they are ordered according to the face vertex order
- - and then we construct the array */
- p1= p2= p3= p4= 0;
-
- for(i=0; i<4; i++) {
- if(eed->v1 == verts[0][i]) p1 = i;
- if(eed->v2 == verts[0][i]) p2 = i;
- if(eed->v1 == verts[1][i]) p3 = i;
- if(eed->v2 == verts[1][i]) p4 = i;
- }
-
- if((p1+1)%fac1 == p2)
- SWAP(int, p1, p2);
- if((p3+1)%fac2 == p4)
- SWAP(int, p3, p4);
-
- for (i = 0; i < 4; i++) {
- p[0][i]= (p1 + i)%fac1;
- p[1][i]= (p3 + i)%fac2;
- }
-
- /* create an Array of the Edges who have h set prior to rotate */
- numhidden = 0;
- for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next)
- if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT)))
- numhidden++;
-
- hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
- if(!hiddenedges) {
- BKE_report(op->reports, RPT_ERROR, "Memory allocation failed");
- return;
- }
-
- numhidden = 0;
- for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
- if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT))
- hiddenedges[numhidden++] = srchedge;
-
- /* create the 2 new faces */
- if(fac1 == 3 && fac2 == 3) {
- /* no need of reverse setup */
-
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
- }
- else if(fac1 == 4 && fac2 == 3) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
-
- verts[0][p[0][2]]->f |= SELECT;
- verts[1][p[1][1]]->f |= SELECT;
- }
- }
- else if(fac1 == 3 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
-
- verts[0][p[0][1]]->f |= SELECT;
- verts[1][p[1][2]]->f |= SELECT;
- }
-
- }
- else if(fac1 == 4 && fac2 == 4) {
- if(dir == DIRECTION_CCW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
- } else if (dir == DIRECTION_CW) {
- newFace[0]= EM_face_from_faces(em, face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
- newFace[1]= EM_face_from_faces(em, face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
-
- verts[0][p[0][2]]->f |= SELECT;
- verts[1][p[1][2]]->f |= SELECT;
- }
- }
- else
- return; /* This should never happen */
-
- if(dir == DIRECTION_CCW || (fac1 == 3 && fac2 == 3)) {
- verts[0][p[0][1]]->f |= SELECT;
- verts[1][p[1][1]]->f |= SELECT;
- }
-
- /* copy old edge's flags to new center edge*/
- for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) {
- if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) {
- srchedge->f = eed->f;
- srchedge->h = eed->h;
- srchedge->dir = eed->dir;
- srchedge->seam = eed->seam;
- srchedge->crease = eed->crease;
- srchedge->bweight = eed->bweight;
- }
- }
-
- /* resetting hidden flag */
- for(numhidden--; numhidden>=0; numhidden--)
- hiddenedges[numhidden]->h= 1;
-
- /* check for orhphan edges */
- for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
- srchedge->f1= -1;
-
- /* cleanup */
- MEM_freeN(hiddenedges);
-
- /* get rid of the old edge and faces*/
- remedge(em, eed);
- free_editedge(em, eed);
- BLI_remlink(&em->faces, face[0]);
- free_editface(em, face[0]);
- BLI_remlink(&em->faces, face[1]);
- free_editface(em, face[1]);
-}
-
-/* only accepts 1 selected edge, or 2 selected faces */
-static int edge_rotate_selected(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditEdge *eed;
- EditFace *efa;
- int dir = RNA_enum_get(op->ptr, "direction"); // dir == 2 when clockwise and ==1 for counter CW.
- short edgeCount = 0;
-
- /*clear new flag for new edges, count selected edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2 &= ~2;
- if(eed->f & SELECT) edgeCount++;
- }
-
- if(edgeCount>1) {
- /* more selected edges, check faces */
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->f & SELECT) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
- edgeCount= 0;
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2) edgeCount++;
- }
- if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f1==2) {
- edge_rotate(em, op, eed,dir);
- break;
- }
- }
- }
- else
- {
- BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
- }
- else if(edgeCount==1) {
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f & SELECT) {
- EM_select_edge(eed, 0);
- edge_rotate(em, op, eed,dir);
- break;
- }
- }
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Select one edge or two adjacent faces");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- /* flush selected vertices (again) to edges/faces */
- EM_select_flush(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edge_rotate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rotate Selected Edge";
- ot->description= "Rotate selected edge or adjoining faces";
- ot->idname= "MESH_OT_edge_rotate";
-
- /* api callbacks */
- ot->exec= edge_rotate_selected;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate the edge around.");
-}
-
-
-/******************* BEVEL CODE STARTS HERE ********************/
-
- /* XXX old bevel not ported yet */
-
-static void bevel_menu(EditMesh *em)
-{
- BME_Mesh *bm;
- BME_TransData_Head *td;
-// TransInfo *t;
- int options, res, gbm_free = 0;
-
-// t = BIF_GetTransInfo();
- if (!G.editBMesh) {
- G.editBMesh = MEM_callocN(sizeof(*(G.editBMesh)),"bevel_menu() G.editBMesh");
- gbm_free = 1;
- }
-
- G.editBMesh->options = BME_BEVEL_RUNNING | BME_BEVEL_SELECT;
- G.editBMesh->res = 1;
-
- while(G.editBMesh->options & BME_BEVEL_RUNNING) {
- options = G.editBMesh->options;
- res = G.editBMesh->res;
- bm = BME_editmesh_to_bmesh(em);
-// BIF_undo_push("Pre-Bevel");
- free_editMesh(em);
- BME_bevel(bm,0.1f,res,options,0,0,&td);
- BME_bmesh_to_editmesh(bm, td, em);
- EM_selectmode_flush(em);
- G.editBMesh->bm = bm;
- G.editBMesh->td = td;
-// initTransform(TFM_BEVEL,CTX_BMESH);
-// Transform();
- BME_free_transdata(td);
- BME_free_mesh(bm);
-// if (t->state != TRANS_CONFIRM) {
-// BIF_undo();
-// }
- if (options == G.editBMesh->options) {
- G.editBMesh->options &= ~BME_BEVEL_RUNNING;
- }
- }
-
- if (gbm_free) {
- MEM_freeN(G.editBMesh);
- G.editBMesh = NULL;
- }
-}
-
-
-/* *********** END BEVEL *********/
-
-/* this utility function checks to see if 2 edit edges share a face,
-returns 1 if they do
-returns 0 if they do not, or if the function is passed the same edge 2 times
-*/
-short sharesFace(EditMesh *em, EditEdge* e1, EditEdge* e2)
-{
- EditFace *search=NULL;
-
- search = em->faces.first;
- if (e1 == e2){
- return 0 ;
- }
- while(search){
- if(
- ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
- ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
- ) {
- return 1;
- }
- search = search->next;
- }
- return 0;
-}
-
-
-typedef struct SlideUv {
- float origuv[2];
- float *uv_up, *uv_down;
- //float *fuv[4];
- LinkNode *fuv_list;
-} SlideUv;
-
-typedef struct SlideVert {
- EditEdge *up,*down;
- EditVert origvert;
-} SlideVert;
-
-#if 0
-int EdgeSlide(EditMesh *em, wmOperator *op, short immediate, float imperc)
-{
- return 0;
-/* XXX REFACTOR - #if 0'd for now, otherwise can't make 64bit windows builds on 64bit machine */
-useless:
- goto useless // because it doesn't do anything right now
-
-// NumInput num; XXX
- Mesh *me= NULL; // XXX
- EditFace *efa;
- EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
- EditVert *ev, *nearest;
- LinkNode *edgelist = NULL, *vertlist=NULL, *look;
- GHash *vertgh;
-
- SlideVert *tempsv;
- float perc = 0, percp = 0,vertdist; // XXX, projectMat[4][4];
- float shiftlabda= 0.0f,len = 0.0f;
- int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0;
- int wasshift = 0;
-
- /* UV correction vars */
- GHash **uvarray= NULL;
- int uvlay_tot= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
- int uvlay_idx;
- SlideUv *slideuvs=NULL, *suv=NULL, *suv_last=NULL;
- float uv_tmp[2];
- LinkNode *fuv_link;
-
- short event, draw=1;
- short mval[2], mvalo[2];
- char str[128];
- float labda = 0.0f;
-
-// initNumInput(&num);
-
-// view3d_get_object_project_mat(curarea, obedit, projectMat);
-
- mvalo[0] = -1; mvalo[1] = -1;
- numsel =0;
-
- // Get number of selected edges and clear some flags
- for(eed=em->edges.first;eed;eed=eed->next) {
- eed->f1 = 0;
- eed->f2 = 0;
- if(eed->f & SELECT) numsel++;
- }
-
- for(ev=em->verts.first;ev;ev=ev->next) {
- ev->f1 = 0;
- }
-
- //Make sure each edge only has 2 faces
- // make sure loop doesn't cross face
- for(efa=em->faces.first;efa;efa=efa->next) {
- int ct = 0;
- if(efa->e1->f & SELECT) {
- ct++;
- efa->e1->f1++;
- if(efa->e1->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
- }
- }
- if(efa->e2->f & SELECT) {
- ct++;
- efa->e2->f1++;
- if(efa->e2->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
- }
- }
- if(efa->e3->f & SELECT) {
- ct++;
- efa->e3->f1++;
- if(efa->e3->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
- }
- }
- if(efa->e4 && efa->e4->f & SELECT) {
- ct++;
- efa->e4->f1++;
- if(efa->e4->f1 > 2) {
- BKE_report(op->reports, RPT_ERROR, "3+ face edge");
- return 0;
- }
- }
- // Make sure loop is not 2 edges of same face
- if(ct > 1) {
- BKE_report(op->reports, RPT_ERROR, "Loop crosses itself");
- return 0;
- }
- }
- // Get # of selected verts
- for(ev=em->verts.first;ev;ev=ev->next) {
- if(ev->f & SELECT) vertsel++;
- }
-
- // Test for multiple segments
- if(vertsel > numsel+1) {
- BKE_report(op->reports, RPT_ERROR, "Please choose a single edge loop");
- return 0;
- }
-
- // Get the edgeloop in order - mark f1 with SELECT once added
- for(eed=em->edges.first;eed;eed=eed->next) {
- if((eed->f & SELECT) && !(eed->f1 & SELECT)) {
- // If this is the first edge added, just put it in
- if(!edgelist) {
- BLI_linklist_prepend(&edgelist,eed);
- numadded++;
- first = eed;
- last = eed;
- eed->f1 = SELECT;
- } else {
- if(editedge_getSharedVert(eed, last)) {
- BLI_linklist_append(&edgelist,eed);
- eed->f1 = SELECT;
- numadded++;
- last = eed;
- } else if(editedge_getSharedVert(eed, first)) {
- BLI_linklist_prepend(&edgelist,eed);
- eed->f1 = SELECT;
- numadded++;
- first = eed;
- }
- }
- }
- if(eed->next == NULL && numadded != numsel) {
- eed=em->edges.first;
- timesthrough++;
- }
-
- // It looks like there was an unexpected case - Hopefully should not happen
- if(timesthrough >= numsel*2) {
- BLI_linklist_free(edgelist,NULL);
- BKE_report(op->reports, RPT_ERROR, "Could not order loop");
- return 0;
- }
- }
-
- // Put the verts in order in a linklist
- look = edgelist;
- while(look) {
- eed = look->link;
- if(!vertlist) {
- if(look->next) {
- temp = look->next->link;
-
- //This is the first entry takes care of extra vert
- if(eed->v1 != temp->v1 && eed->v1 != temp->v2) {
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
- } else {
- BLI_linklist_append(&vertlist,eed->v2);
- eed->v2->f1 = 1;
- }
- } else {
- //This is the case that we only have 1 edge
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
- }
- }
- // for all the entries
- if(eed->v1->f1 != 1) {
- BLI_linklist_append(&vertlist,eed->v1);
- eed->v1->f1 = 1;
- } else if(eed->v2->f1 != 1) {
- BLI_linklist_append(&vertlist,eed->v2);
- eed->v2->f1 = 1;
- }
- look = look->next;
- }
-
- // populate the SlideVerts
-
- vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlide gh");
- look = vertlist;
- while(look) {
- i=0;
- j=0;
- ev = look->link;
- tempsv = (struct SlideVert*)MEM_mallocN(sizeof(struct SlideVert),"SlideVert");
- tempsv->up = NULL;
- tempsv->down = NULL;
- tempsv->origvert.co[0] = ev->co[0];
- tempsv->origvert.co[1] = ev->co[1];
- tempsv->origvert.co[2] = ev->co[2];
- tempsv->origvert.no[0] = ev->no[0];
- tempsv->origvert.no[1] = ev->no[1];
- tempsv->origvert.no[2] = ev->no[2];
- // i is total edges that vert is on
- // j is total selected edges that vert is on
-
- for(eed=em->edges.first;eed;eed=eed->next) {
- if(eed->v1 == ev || eed->v2 == ev) {
- i++;
- if(eed->f & SELECT) {
- j++;
- }
- }
- }
- // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges
- if(i == 4 && j == 2) {
- for(eed=em->edges.first;eed;eed=eed->next) {
- if(editedge_containsVert(eed, ev)) {
- if(!(eed->f & SELECT)) {
- if(!tempsv->up) {
- tempsv->up = eed;
- } else if (!(tempsv->down)) {
- tempsv->down = eed;
- }
- }
- }
- }
- }
- // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected
- if(i >= 3 && j == 1) {
- for(eed=em->edges.first;eed;eed=eed->next) {
- if(editedge_containsVert(eed, ev) && eed->f & SELECT) {
- for(efa = em->faces.first;efa;efa=efa->next) {
- if(editface_containsEdge(efa, eed)) {
- if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e1;
- } else if (!(tempsv->down)) {
- tempsv->down = efa->e1;
- }
- }
- if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e2;
- } else if (!(tempsv->down)) {
- tempsv->down = efa->e2;
- }
- }
- if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e3;
- } else if (!(tempsv->down)) {
- tempsv->down = efa->e3;
- }
- }
- if(efa->e4) {
- if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) {
- if(!tempsv->up) {
- tempsv->up = efa->e4;
- } else if (!(tempsv->down)) {
- tempsv->down = efa->e4;
- }
- }
- }
-
- }
- }
- }
- }
- }
- if(i > 4 && j == 2) {
- BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
- return 0;
- }
- BLI_ghash_insert(vertgh,ev,tempsv);
-
- look = look->next;
- }
-
- // make sure the UPs nad DOWNs are 'faceloops'
- // Also find the nearest slidevert to the cursor
-// XXX getmouseco_areawin(mval);
- look = vertlist;
- nearest = NULL;
- vertdist = -1;
- while(look) {
- tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
-
- if(!tempsv->up || !tempsv->down) {
- BKE_report(op->reports, RPT_ERROR, "Missing rails");
- BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
- return 0;
- }
-
- if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
- if(!(tempsv->up->f & SELECT)) {
- tempsv->up->f |= SELECT;
- tempsv->up->f2 |= 16;
- } else {
- tempsv->up->f2 |= ~16;
- }
- if(!(tempsv->down->f & SELECT)) {
- tempsv->down->f |= SELECT;
- tempsv->down->f2 |= 16;
- } else {
- tempsv->down->f2 |= ~16;
- }
- }
-
- if(look->next != NULL) {
- SlideVert *sv;
-
- sv = BLI_ghash_lookup(vertgh,(EditVert*)look->next->link);
-
- if(sv) {
- float tempdist, co[2];
-
- if(!sharesFace(em, tempsv->up,sv->up)) {
- EditEdge *swap;
- swap = sv->up;
- sv->up = sv->down;
- sv->down = swap;
- }
-
-// view3d_project_float(curarea, tempsv->origvert.co, co, projectMat);
-
- tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2));
-
- if(vertdist < 0) {
- vertdist = tempdist;
- nearest = (EditVert*)look->link;
- } else if ( tempdist < vertdist ) {
- vertdist = tempdist;
- nearest = (EditVert*)look->link;
- }
- }
- }
-
-
-
- look = look->next;
- }
-
-
- if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
- int maxnum = 0;
- uvarray = MEM_callocN( uvlay_tot * sizeof(GHash *), "SlideUVs Array");
- suv_last = slideuvs = MEM_callocN( uvlay_tot * (numadded+1) * sizeof(SlideUv), "SlideUVs"); /* uvLayers * verts */
- suv = NULL;
-
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
-
- uvarray[uvlay_idx] = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "EdgeSlideUV gh");
-
- for(ev=em->verts.first;ev;ev=ev->next) {
- ev->tmp.l = 0;
- }
- look = vertlist;
- while(look) {
- float *uv_new;
- tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
-
- ev = look->link;
- suv = NULL;
- for(efa = em->faces.first;efa;efa=efa->next) {
- if (ev->tmp.l != -1) { /* test for self, in this case its invalid */
- int k=-1; /* face corner */
-
- /* Is this vert in the faces corner? */
- if (efa->v1==ev) k=0;
- else if (efa->v2==ev) k=1;
- else if (efa->v3==ev) k=2;
- else if (efa->v4 && efa->v4==ev) k=3;
-
- if (k != -1) {
- MTFace *tf = CustomData_em_get_n(&em->fdata, efa->data, CD_MTFACE, uvlay_idx);
- EditVert *ev_up, *ev_down;
-
- uv_new = tf->uv[k];
-
- if (ev->tmp.l) {
- if (fabs(suv->origuv[0]-uv_new[0]) > 0.0001 || fabs(suv->origuv[1]-uv_new[1])) {
- ev->tmp.l = -1; /* Tag as invalid */
- BLI_linklist_free(suv->fuv_list,NULL);
- suv->fuv_list = NULL;
- BLI_ghash_remove(uvarray[uvlay_idx],ev, NULL, NULL);
- suv = NULL;
- break;
- }
- } else {
- ev->tmp.l = 1;
- suv = suv_last;
-
- suv->fuv_list = NULL;
- suv->uv_up = suv->uv_down = NULL;
- suv->origuv[0] = uv_new[0];
- suv->origuv[1] = uv_new[1];
-
- BLI_linklist_prepend(&suv->fuv_list, uv_new);
- BLI_ghash_insert(uvarray[uvlay_idx],ev,suv);
-
- suv_last++; /* advance to next slide UV */
- maxnum++;
- }
-
- /* Now get the uvs along the up or down edge if we can */
- if (suv) {
- if (!suv->uv_up) {
- ev_up = editedge_getOtherVert(tempsv->up,ev);
- if (efa->v1==ev_up) suv->uv_up = tf->uv[0];
- else if (efa->v2==ev_up) suv->uv_up = tf->uv[1];
- else if (efa->v3==ev_up) suv->uv_up = tf->uv[2];
- else if (efa->v4 && efa->v4==ev_up) suv->uv_up = tf->uv[3];
- }
- if (!suv->uv_down) { /* if the first face was apart of the up edge, it cant be apart of the down edge */
- ev_down = editedge_getOtherVert(tempsv->down,ev);
- if (efa->v1==ev_down) suv->uv_down = tf->uv[0];
- else if (efa->v2==ev_down) suv->uv_down = tf->uv[1];
- else if (efa->v3==ev_down) suv->uv_down = tf->uv[2];
- else if (efa->v4 && efa->v4==ev_down) suv->uv_down = tf->uv[3];
- }
-
- /* Copy the pointers to the face UV's */
- BLI_linklist_prepend(&suv->fuv_list, uv_new);
- }
- }
- }
- }
- look = look->next;
- }
- } /* end uv layer loop */
- } /* end uvlay_tot */
-
-
-
- // we should have enough info now to slide
-
- len = 0.0f;
-
- percp = -1;
- while(draw) {
- /* For the % calculation */
- short mval[2];
- float rc[2];
- float v2[2], v3[2];
- EditVert *centerVert, *upVert, *downVert;
-
-// XXX getmouseco_areawin(mval);
-
- if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) {
- PIL_sleep_ms(10);
- } else {
- char *p = str;
- int ctrl= 0, shift= 0; // XXX
-
- mvalo[0] = mval[0];
- mvalo[1] = mval[1];
-
-
- tempsv = BLI_ghash_lookup(vertgh,nearest);
-
- centerVert = editedge_getSharedVert(tempsv->up, tempsv->down);
- upVert = editedge_getOtherVert(tempsv->up, centerVert);
- downVert = editedge_getOtherVert(tempsv->down, centerVert);
-
-// view3d_project_float(curarea, upVert->co, v2, projectMat);
-// view3d_project_float(curarea, downVert->co, v3, projectMat);
-
- /* Determine the % on which the loop should be cut */
-
- rc[0]= v3[0]-v2[0];
- rc[1]= v3[1]-v2[1];
- len= rc[0]*rc[0]+ rc[1]*rc[1];
- if (len==0) {len = 0.0001;}
-
- if (shift) {
- wasshift = 0;
- labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len;
- }
- else {
- if (wasshift==0) {
- wasshift = 1;
- shiftlabda = labda;
- }
- labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda;
- }
-
-
- if(labda<=0.0) labda=0.0;
- else if(labda>=1.0)labda=1.0;
-
- perc=((1-labda)*2)-1;
-
- if(shift == 0 && ctrl==0) {
- perc *= 100;
- perc = floor(perc);
- perc /= 100;
- } else if (ctrl) {
- perc *= 10;
- perc = floor(perc);
- perc /= 10;
- }
-
- if(prop == 0) {
- len = len_v3v3(upVert->co,downVert->co)*((perc+1)/2);
- if(flip == 1) {
- len = len_v3v3(upVert->co,downVert->co) - len;
- }
- }
-
- if (0) // XXX hasNumInput(&num))
- {
-// XXX applyNumInput(&num, &perc);
-
- if (prop)
- {
- perc = MIN2(perc, 1);
- perc = MAX2(perc, -1);
- }
- else
- {
- len = MIN2(perc, len_v3v3(upVert->co,downVert->co));
- len = MAX2(len, 0);
- }
- }
-
- //Adjust Edgeloop
- if(immediate) {
- perc = imperc;
- }
- percp = perc;
- if(prop) {
- look = vertlist;
- while(look) {
- EditVert *tempev;
- ev = look->link;
- tempsv = BLI_ghash_lookup(vertgh,ev);
-
- tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev);
- interp_v3_v3v3(ev->co, tempsv->origvert.co, tempev->co, fabs(perc));
-
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
- suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
- if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
- interp_v2_v2v2(uv_tmp, suv->origuv, (perc>=0)?suv->uv_up:suv->uv_down, fabs(perc));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- VECCOPY2D(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
-
- look = look->next;
- }
- }
- else {
- //Non prop code
- look = vertlist;
- while(look) {
- float newlen;
- ev = look->link;
- tempsv = BLI_ghash_lookup(vertgh,ev);
- newlen = (len / len_v3v3(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co));
- if(newlen > 1.0) {newlen = 1.0;}
- if(newlen < 0.0) {newlen = 0.0;}
- if(flip == 0) {
- interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
- /* dont do anything if no UVs */
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
- suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
- if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
- interp_v2_v2v2(uv_tmp, suv->uv_down, suv->uv_up, fabs(newlen));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- VECCOPY2D(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
- } else{
- interp_v3_v3v3(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
-
- if (0) { // XXX scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) {
- /* dont do anything if no UVs */
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
- suv = BLI_ghash_lookup( uvarray[uvlay_idx], ev );
- if (suv && suv->fuv_list && suv->uv_up && suv->uv_down) {
- interp_v2_v2v2(uv_tmp, suv->uv_up, suv->uv_down, fabs(newlen));
- fuv_link = suv->fuv_list;
- while (fuv_link) {
- VECCOPY2D(((float *)fuv_link->link), uv_tmp);
- fuv_link = fuv_link->next;
- }
- }
- }
- }
- }
- look = look->next;
- }
-
- }
-
- // Highlight the Control Edges
-// scrarea_do_windraw(curarea);
-// persp(PERSP_VIEW);
-// glPushMatrix();
-// mymultmatrix(obedit->obmat);
-
- glColor3ub(0, 255, 0);
- glBegin(GL_LINES);
- glVertex3fv(upVert->co);
- glVertex3fv(downVert->co);
- glEnd();
-
- if(prop == 0) {
- // draw start edge for non-prop
- glPointSize(5);
- glBegin(GL_POINTS);
- glColor3ub(255,0,255);
- if(flip) {
- glVertex3fv(upVert->co);
- } else {
- glVertex3fv(downVert->co);
- }
- glEnd();
- }
-
-
- glPopMatrix();
-
- if(prop) {
- p += sprintf(str, "(P)ercentage: ");
- } else {
- p += sprintf(str, "Non (P)rop Length: ");
- }
-
- if (0) // XXX hasNumInput(&num))
- {
- char num_str[20];
-
- // XX outputNumInput(&num, num_str);
- p += sprintf(p, "%s", num_str);
- }
- else
- {
- if (prop)
- {
- p += sprintf(p, "%f", perc);
- }
- else
- {
- p += sprintf(p, "%f", len);
- }
- }
-
-
- if (prop == 0) {
- p += sprintf(p, ", Press (F) to flip control side");
- }
-
-// headerprint(str);
-// screen_swapbuffers();
- }
- if(!immediate) {
- while(qtest()) {
- short val=0;
- event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
-
- /* val==0 on key-release event */
- if (val) {
- if(ELEM(event, ESCKEY, RIGHTMOUSE)) {
- prop = 1; // Go back to prop mode
- imperc = 0; // This is the % that gets set for immediate
- immediate = 1; //Run through eval code 1 more time
- cancel = 1; // Return -1
- mvalo[0] = -1;
- } else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) {
- draw = 0; // End looping now
- } else if(event==MIDDLEMOUSE) {
- perc = 0;
- immediate = 1;
- } else if(event==PKEY) {
-// XXX initNumInput(&num); /* reset num input */
- if (prop) {
- prop = 0;
-// XXX num.flag |= NUM_NO_NEGATIVE;
- }
- else {
- prop = 1;
- }
- mvalo[0] = -1;
- } else if(event==FKEY) {
- (flip == 1) ? (flip = 0):(flip = 1);
- mvalo[0] = -1;
- } else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges
- look = vertlist;
- while(look) {
- if(nearest == (EditVert*)look->link) {
- if(look->next == NULL) {
- nearest = (EditVert*)vertlist->link;
- } else {
- nearest = (EditVert*)look->next->link;
- }
- mvalo[0] = -1;
- break;
- }
- look = look->next;
- }
- } else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges
- look = vertlist;
- while(look) {
- if(look->next) {
- if(look->next->link == nearest) {
- nearest = (EditVert*)look->link;
- mvalo[0] = -1;
- break;
- }
- } else {
- if((EditVert*)vertlist->link == nearest) {
- nearest = look->link;
- mvalo[0] = -1;
- break;
- }
- }
- look = look->next;
- }
- }
-
-// XXX if (handleNumInput(&num, event))
- {
- mvalo[0] = -1; /* NEED A BETTER WAY TO TRIGGER REDRAW */
- }
- }
-
- }
- } else {
- draw = 0;
- }
-// DAG_id_tag_update(obedit->data, 0);
- }
-
-
- if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
- look = vertlist;
- while(look) {
- tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
- if(tempsv != NULL) {
- tempsv->up->f &= !SELECT;
- tempsv->down->f &= !SELECT;
- }
- look = look->next;
- }
- }
-
-// force_draw(0);
-
- if(!immediate)
- EM_automerge(0);
-// DAG_id_tag_update(obedit->data, 0);
-// scrarea_queue_winredraw(curarea);
-
- //BLI_ghash_free(edgesgh, freeGHash, NULL);
- BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
- BLI_linklist_free(vertlist,NULL);
- BLI_linklist_free(edgelist,NULL);
-
- if (uvlay_tot) { // XXX && (scene->toolsettings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
- for (uvlay_idx=0; uvlay_idx<uvlay_tot; uvlay_idx++) {
- BLI_ghash_free(uvarray[uvlay_idx], NULL, NULL);
- }
- MEM_freeN(uvarray);
- MEM_freeN(slideuvs);
-
- suv = suv_last-1;
- while (suv >= slideuvs) {
- if (suv->fuv_list) {
- BLI_linklist_free(suv->fuv_list,NULL);
- }
- suv--;
- }
- }
-
- if(cancel == 1) {
- return -1;
- }
-
- return 1;
-}
-#endif // END OF XXX
-
-int EdgeLoopDelete(EditMesh *UNUSED(em), wmOperator *UNUSED(op))
-{
-#if 0 //XXX won't work with new edgeslide
-
- /* temporal flag setting so we keep UVs when deleting edge loops,
- * this is a bit of a hack but it works how you would want in almost all cases */
- // short uvcalc_flag_orig = 0; // XXX scene->toolsettings->uvcalc_flag;
- // scene->toolsettings->uvcalc_flag |= UVCALC_TRANSFORM_CORRECT;
-
- if(!EdgeSlide(em, op, 1, 1)) {
- return 0;
- }
-
- /* restore uvcalc flag */
- // scene->toolsettings->uvcalc_flag = uvcalc_flag_orig;
-
- EM_select_more(em);
- removedoublesflag(em, 1,0, 0.001);
- EM_select_flush(em);
- // DAG_id_tag_update(obedit->data, 0);
- return 1;
-#endif
- return 0;
-}
-
-
-/* -------------------- More tools ------------------ */
-#if 0
-void mesh_set_face_flags(EditMesh *em, short mode)
-{
- EditFace *efa;
- MTFace *tface;
- short m_tex=0, m_shared=0,
- m_light=0, m_invis=0, m_collision=0,
- m_twoside=0, m_obcolor=0, m_halo=0,
- m_billboard=0, m_shadow=0, m_text=0,
- m_sort=0;
- short flag = 0, change = 0;
-
-// XXX if (!EM_texFaceCheck()) {
-// error("not a mesh with uv/image layers");
-// return;
-// }
-
- add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL);
- add_numbut(2, TOG|SHO, "Light", 0, 0, &m_light, NULL);
- add_numbut(3, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL);
- add_numbut(4, TOG|SHO, "Collision", 0, 0, &m_collision, NULL);
- add_numbut(5, TOG|SHO, "Shared", 0, 0, &m_shared, NULL);
- add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL);
- add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL);
- add_numbut(8, TOG|SHO, "Halo", 0, 0, &m_halo, NULL);
- add_numbut(9, TOG|SHO, "Billboard", 0, 0, &m_billboard, NULL);
- add_numbut(10, TOG|SHO, "Shadow", 0, 0, &m_shadow, NULL);
- add_numbut(11, TOG|SHO, "Text", 0, 0, &m_text, NULL);
- add_numbut(12, TOG|SHO, "Sort", 0, 0, &m_sort, NULL);
-
- if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 13, REDRAW))
- return;
-
- /* these 2 cant both be on */
- if (mode) /* are we seeting*/
- if (m_halo)
- m_billboard = 0;
-
- if (m_tex) flag |= TF_TEX;
- if (m_shared) flag |= TF_SHAREDCOL;
- if (m_light) flag |= TF_LIGHT;
- if (m_invis) flag |= TF_INVISIBLE;
- if (m_collision) flag |= TF_DYNAMIC;
- if (m_twoside) flag |= TF_TWOSIDE;
- if (m_obcolor) flag |= TF_OBCOL;
- if (m_halo) flag |= TF_BILLBOARD;
- if (m_billboard) flag |= TF_BILLBOARD2;
- if (m_shadow) flag |= TF_SHADOW;
- if (m_text) flag |= TF_BMFONT;
- if (m_sort) flag |= TF_ALPHASORT;
-
- if (flag==0)
- return;
-
- efa= em->faces.first;
- while(efa) {
- if(efa->f & SELECT) {
- tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (mode) tface->mode |= flag;
- else tface->mode &= ~flag;
- change = 1;
- }
- efa= efa->next;
- }
-
-}
-#endif
-
-/********************** Rip Operator *************************/
-
-/* helper to find edge for edge_rip */
-static float mesh_rip_edgedist(ARegion *ar, float mat[][4], float *co1, float *co2, const short mval[2])
-{
- float vec1[3], vec2[3], mvalf[2];
-
- view3d_project_float(ar, co1, vec1, mat);
- 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, *mval= event->mval;
-
- /* select flush... vertices are important */
- EM_selectmode_set(em);
-
- view3d_get_object_project_mat(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;
- view3d_project_float(ar, efa->cent, vec, projectMat);
- dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
- if(dist<mindist) {
- mindist= dist;
- sefa= efa;
- }
- }
- }
-
- if(efa) {
- BKE_report(op->reports, RPT_WARNING, "Can't perform ripping with faces selected this way");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
- if(sefa==NULL) {
- BKE_report(op->reports, RPT_WARNING, "No proper selection or faces included");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
-
- /* duplicate vertices, new vertices get selected */
- for(eve = em->verts.last; eve; eve= eve->prev) {
- eve->tmp.v = NULL;
- if(eve->f & SELECT) {
- eve->tmp.v = addvertlist(em, eve->co, eve);
- eve->f &= ~SELECT;
- eve->tmp.v->f |= SELECT;
- }
- }
-
- /* find the best candidate edge */
- /* or one of sefa edges is selected... */
- if(sefa->e1->f & SELECT) seed= sefa->e2;
- if(sefa->e2->f & SELECT) seed= sefa->e1;
- if(sefa->e3->f & SELECT) seed= sefa->e2;
- if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
-
- /* or we do the distance trick */
- if(seed==NULL) {
- mindist= 1000000.0f;
- if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
- dist = mesh_rip_edgedist(ar, projectMat,
- sefa->e1->v1->co,
- sefa->e1->v2->co, mval);
- if(dist<mindist) {
- seed= sefa->e1;
- mindist= dist;
- }
- }
- if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
- dist = mesh_rip_edgedist(ar, projectMat,
- sefa->e2->v1->co,
- sefa->e2->v2->co, mval);
- if(dist<mindist) {
- seed= sefa->e2;
- mindist= dist;
- }
- }
- if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
- dist= mesh_rip_edgedist(ar, projectMat,
- sefa->e3->v1->co,
- sefa->e3->v2->co, mval);
- if(dist<mindist) {
- seed= sefa->e3;
- mindist= dist;
- }
- }
- if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
- dist= mesh_rip_edgedist(ar, projectMat,
- sefa->e4->v1->co,
- sefa->e4->v2->co, mval);
- if(dist<mindist) {
- seed= sefa->e4;
- mindist= dist;
- }
- }
- }
-
- if(seed==NULL) { // never happens?
- BKE_report(op->reports, RPT_WARNING, "No proper edge found to start");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- faceloop_select(em, seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
-
- /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
- for(eed = em->edges.last; eed; eed= eed->prev) {
- eed->tmp.v = NULL;
- if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
- EditEdge *newed;
-
- newed= addedgelist(em, eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
- eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
- if(eed->f & SELECT) {
- EM_select_edge(eed, 0);
- EM_remove_selection(em, eed, EDITEDGE);
- EM_select_edge(newed, 1);
- }
- eed->tmp.v = (EditVert *)newed;
- }
- }
-
- /* first clear edges to help finding neighbours */
- for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
-
- /* put new vertices & edges && flag in best face */
- mesh_rip_setface(em, sefa);
-
- /* starting with neighbours of best face, we loop over the seam */
- sefa->f1= 2;
- doit= 1;
- while(doit) {
- doit= 0;
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- /* new vert in face */
- if (efa->v1->tmp.v || efa->v2->tmp.v ||
- efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
- /* face is tagged with loop */
- if(efa->f1==1) {
- mesh_rip_setface(em, efa);
- efa->f1= 2;
- doit= 1;
- }
- }
- }
- }
-
- /* remove loose edges, that were part of a ripped face */
- for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
- for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
- for(efa= em->faces.first; efa; efa=efa->next) {
- efa->e1->f1= 1;
- efa->e2->f1= 1;
- efa->e3->f1= 1;
- if(efa->e4) efa->e4->f1= 1;
- }
-
- for(eed = em->edges.last; eed; eed= seed) {
- seed= eed->prev;
- if(eed->f1==0) {
- if(eed->v1->tmp.v || eed->v2->tmp.v ||
- (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
- remedge(em, eed);
- free_editedge(em, eed);
- eed= NULL;
- }
- }
- if(eed) {
- eed->v1->f1= 1;
- eed->v2->f1= 1;
- }
- }
-
- /* and remove loose selected vertices, that got duplicated accidentally */
- for(eve = em->verts.first; eve; eve= nextve) {
- nextve= eve->next;
- if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
- BLI_remlink(&em->verts,eve);
- free_editvert(em, eve);
- }
- }
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
-// RNA_enum_set(op->ptr, "proportional", 0);
-// RNA_boolean_set(op->ptr, "mirror", 0);
-// WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_rip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rip";
- ot->description= "Rip selection from mesh (quads only)";
- ot->idname= "MESH_OT_rip";
-
- /* api callbacks */
- ot->invoke= mesh_rip_invoke;
- ot->poll= EM_view3d_poll;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* to give to transform */
- /* XXX Transform this in a macro */
- Transform_Properties(ot, P_CONSTRAINT|P_MIRROR);
-}
-
-
-/************************ Shape Operators *************************/
-
-static void shape_propagate(Object *obedit, EditMesh *em, wmOperator *op)
-{
- EditVert *ev = NULL;
- Mesh* me = (Mesh*)obedit->data;
- Key* ky = NULL;
- KeyBlock* kb = NULL;
-
-
- if(me->key){
- ky = me->key;
- } else {
- BKE_report(op->reports, RPT_WARNING, "Object Has No Key");
- return;
- }
-
- if(ky->block.first){
- for(ev = em->verts.first; ev ; ev = ev->next){
- if(ev->f & SELECT){
- for(kb=ky->block.first;kb;kb = kb->next){
- float *data;
- data = kb->data;
- VECCOPY(data+(ev->keyindex*3),ev->co);
- }
- }
- }
- } else {
- BKE_report(op->reports, RPT_WARNING, "Object Has No Blendshapes");
- return;
- }
-
-#if 0
- //TAG Mesh Objects that share this data
- for(base = scene->base.first; base; base = base->next){
- if(base->object && base->object->data == me){
- base->object->recalc = OB_RECALC_DATA;
- }
- }
-#endif
-
- DAG_id_tag_update(obedit->data, 0);
- return;
-}
-
-
-static int shape_propagate_to_all_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- EditMesh *em= BKE_mesh_get_editmesh(me);
-
- shape_propagate(obedit, em, op);
-
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
-
- return OPERATOR_FINISHED;
-}
-
-
-void MESH_OT_shape_propagate_to_all(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shape Propagate";
- ot->description= "Apply selected vertex locations to all other shape keys";
- ot->idname= "MESH_OT_shape_propagate_to_all";
-
- /* api callbacks */
- ot->exec= shape_propagate_to_all_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int blend_from_shape_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- Mesh *me= obedit->data;
- Key *key= me->key;
- EditMesh *em= BKE_mesh_get_editmesh(me);
- EditVert *eve;
- KeyBlock *kb, *refkb= NULL;
- float *data, *refdata= NULL, co[3];
- float blend= RNA_float_get(op->ptr, "blend");
- int shape= RNA_enum_get(op->ptr, "shape");
- int add= RNA_boolean_get(op->ptr, "add");
- int blended= 0;
-
- if(key && (kb= BLI_findlink(&key->block, shape))) {
- data= kb->data;
-
- if(add) {
- refkb= BLI_findlink(&key->block, kb->relative);
- if(refkb)
- refdata = refkb->data;
- }
-
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f & SELECT) {
- if(eve->keyindex >= 0 && eve->keyindex < kb->totelem) {
- copy_v3_v3(co, data + eve->keyindex*3);
-
- if(add) {
- /* in add mode, we add relative shape key offset */
- if(refdata && eve->keyindex < refkb->totelem)
- sub_v3_v3v3(co, co, refdata + eve->keyindex*3);
-
- madd_v3_v3fl(eve->co, co, blend);
- }
- else {
- /* in blend mode, we interpolate to the shape key */
- interp_v3_v3v3(eve->co, eve->co, co, blend);
- }
-
- blended= 1;
- }
- }
- }
- }
-
- BKE_mesh_end_editmesh(me, em);
-
- if(!blended)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(&me->id, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
-
- return OPERATOR_FINISHED;
-}
-
-static EnumPropertyItem *shape_itemf(bContext *C, PointerRNA *UNUSED(ptr), 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 then 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), int *free)
-{
- Object *obedit= CTX_data_edit_object(C);
- EnumPropertyItem *item= NULL;
- int totitem= 0;
-
- if (C==NULL) {
- return merge_type_items;
- }
-
- if(obedit && obedit->type == OB_MESH) {
- EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
-
- if(em->selectmode & SCE_SELECT_VERTEX) {
- if(em->selected.first && em->selected.last &&
- ((EditSelection*)em->selected.first)->type == EDITVERT && ((EditSelection*)em->selected.last)->type == EDITVERT) {
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
- }
- else if(em->selected.first && ((EditSelection*)em->selected.first)->type == EDITVERT)
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 1);
- else if(em->selected.last && ((EditSelection*)em->selected.last)->type == EDITVERT)
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 6);
- }
-
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 3);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 4);
- RNA_enum_items_add_value(&item, &totitem, merge_type_items, 5);
- }
-
- RNA_enum_item_end(&item, &totitem);
- *free= 1;
-
- return item;
-}
-
-void MESH_OT_merge(wmOperatorType *ot)
-{
- PropertyRNA *prop;
-
- /* identifiers */
- ot->name= "Merge";
- ot->description= "Merge selected vertices";
- ot->idname= "MESH_OT_merge";
-
- /* api callbacks */
- ot->exec= merge_exec;
- ot->invoke= WM_menu_invoke;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- prop= RNA_def_enum(ot->srna, "type", merge_type_items, 3, "Type", "Merge method to use.");
- RNA_def_enum_funcs(prop, merge_type_itemf);
- ot->prop= prop;
- RNA_def_boolean(ot->srna, "uvs", 0, "UVs", "Move UVs according to merge.");
-}
-
-/************************ Vertex Path Operator *************************/
-
-typedef struct PathNode {
- int u;
- int visited;
- ListBase edges;
-} PathNode;
-
-typedef struct PathEdge {
- struct PathEdge *next, *prev;
- int v;
- float w;
-} PathEdge;
-
-#define PATH_SELECT_EDGE_LENGTH 0
-#define PATH_SELECT_TOPOLOGICAL 1
-
-static int select_vertex_path_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditVert *eve, *s, *t;
- EditEdge *eed;
- PathEdge *newpe, *currpe;
- PathNode *currpn;
- PathNode *Q;
- int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
- int unbalanced, totnodes;
- float *cost;
- int type= RNA_enum_get(op->ptr, "type");
- Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
-
- s = t = NULL;
- for(eve=em->verts.first; eve; eve=eve->next) {
- if(eve->f&SELECT) {
- if(s == NULL) s= eve;
- else if(t == NULL) t= eve;
- else {
- /* more than two vertices are selected,
- show warning message and cancel operator */
- s = t = NULL;
- break;
- }
-
- }
-
- /*need to find out if t is actually reachable by s....*/
- eve->f1 = 0;
- }
-
- if(s != NULL && t != NULL) {
- s->f1 = 1;
-
- unbalanced = 1;
- totnodes = 1;
- while(unbalanced){
- unbalanced = 0;
- for(eed=em->edges.first; eed; eed=eed->next){
- if(!eed->h){
- if(eed->v1->f1 && !eed->v2->f1){
- eed->v2->f1 = 1;
- totnodes++;
- unbalanced = 1;
- }
- else if(eed->v2->f1 && !eed->v1->f1){
- eed->v1->f1 = 1;
- totnodes++;
- unbalanced = 1;
- }
- }
- }
- }
-
- if(s->f1 && t->f1){ /* t can be reached by s */
- Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
- totnodes = 0;
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f1){
- Q[totnodes].u = totnodes;
- Q[totnodes].edges.first = 0;
- Q[totnodes].edges.last = 0;
- Q[totnodes].visited = 0;
- eve->tmp.p = &(Q[totnodes]);
- totnodes++;
- }
- else eve->tmp.p = NULL;
- }
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(!eed->h){
- if(eed->v1->f1){
- currpn = ((PathNode*)eed->v1->tmp.p);
-
- newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
- newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
- if (type == PATH_SELECT_EDGE_LENGTH) {
- newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
- }
- else newpe->w = 1;
- newpe->next = 0;
- newpe->prev = 0;
- BLI_addtail(&(currpn->edges), newpe);
- }
- if(eed->v2->f1){
- currpn = ((PathNode*)eed->v2->tmp.p);
- newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
- newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
- if (type == PATH_SELECT_EDGE_LENGTH) {
- newpe->w = len_v3v3(eed->v1->co, eed->v2->co);
- }
- else newpe->w = 1;
- newpe->next = 0;
- newpe->prev = 0;
- BLI_addtail(&(currpn->edges), newpe);
- }
- }
- }
-
- heap = BLI_heap_new();
- cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
- previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
-
- for(v=0; v < totnodes; v++){
- cost[v] = 1000000;
- previous[v] = -1; /*array of indices*/
- }
-
- pnindex = ((PathNode*)s->tmp.p)->u;
- cost[pnindex] = 0;
- BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
-
- while( !BLI_heap_empty(heap) ){
-
- pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
- currpn = &(Q[pnindex]);
-
- if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
- break;
-
- for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
- if(!Q[currpe->v].visited){
- if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
- cost[currpe->v] = cost[currpn->u] + currpe->w;
- previous[currpe->v] = currpn->u;
- Q[currpe->v].visited = 1;
- BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
- }
- }
- }
- }
-
- pathvert = ((PathNode*)t->tmp.p)->u;
- while(pathvert != -1){
- for(eve=em->verts.first; eve; eve=eve->next){
- if(eve->f1){
- if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
- }
- }
- pathvert = previous[pathvert];
- }
-
- for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
- MEM_freeN(Q);
- MEM_freeN(cost);
- MEM_freeN(previous);
- BLI_heap_free(heap, NULL);
- EM_select_flush(em);
- }
- }
- else {
- BKE_mesh_end_editmesh(obedit->data, em);
- BKE_report(op->reports, RPT_WARNING, "Path Selection requires that exactly two vertices be selected");
- return OPERATOR_CANCELLED;
- }
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_vertex_path(wmOperatorType *ot)
-{
- static const EnumPropertyItem type_items[] = {
- {PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
- {PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select Vertex Path";
- ot->description= "Select shortest path between two vertices by distance type";
- ot->idname= "MESH_OT_select_vertex_path";
-
- /* api callbacks */
- ot->exec= select_vertex_path_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
-}
-
-/********************** Region/Loop Operators *************************/
-
-static int region_to_loop(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- EditEdge *eed;
- EditFace *efa;
- int selected= 0;
-
- for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = 0;
-
- for(efa=em->faces.first; efa; efa=efa->next){
- if(efa->f&SELECT){
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4)
- efa->e4->f1++;
-
- selected= 1;
- }
- }
-
- if(!selected)
- return OPERATOR_CANCELLED;
-
- EM_clear_flag_all(em, SELECT);
-
- for(eed=em->edges.first; eed; eed=eed->next){
- if(eed->f1 == 1) EM_select_edge(eed, 1);
- }
-
- em->selectmode = SCE_SELECT_EDGE;
- CTX_data_tool_settings(C)->selectmode= em->selectmode;
- EM_selectmode_set(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_region_to_loop(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Region to Loop";
- ot->description= "Select a region as a loop of connected edges";
- ot->idname= "MESH_OT_region_to_loop";
-
- /* api callbacks */
- ot->exec= region_to_loop;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int validate_loop(EditMesh *em, Collection *edgecollection)
-{
- EditEdge *eed;
- EditFace *efa;
- CollectedEdge *curredge;
-
- /*1st test*/
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- curredge->eed->v1->f1 = 0;
- curredge->eed->v2->f1 = 0;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- curredge->eed->v1->f1++;
- curredge->eed->v2->f1++;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- if(curredge->eed->v1->f1 > 2) return(0); else
- if(curredge->eed->v2->f1 > 2) return(0);
- }
-
- /*2nd test*/
- for(eed = em->edges.first; eed; eed=eed->next) eed->f1 = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
- if(curredge->eed->f1 > 2) return(0);
- }
- return(1);
-}
-
-static int loop_bisect(EditMesh *em, Collection *edgecollection){
-
- EditFace *efa, *sf1, *sf2;
- EditEdge *eed, *sed;
- CollectedEdge *curredge;
- int totsf1, totsf2, unbalanced,balancededges;
-
- for(eed=em->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
- for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = 0;
-
- for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
-
- sf1 = sf2 = NULL;
- sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
-
- for(efa=em->faces.first; efa; efa=efa->next){
- if(sf2) break;
- else if(sf1){
- if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
- }
- else{
- if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa;
- }
- }
-
- if(sf1==NULL || sf2==NULL)
- return(-1);
-
- if(!(sf1->e1->f1)) sf1->e1->f2 = 1;
- if(!(sf1->e2->f1)) sf1->e2->f2 = 1;
- if(!(sf1->e3->f1)) sf1->e3->f2 = 1;
- if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1;
- sf1->f1 = 1;
- totsf1 = 1;
-
- if(!(sf2->e1->f1)) sf2->e1->f2 = 2;
- if(!(sf2->e2->f1)) sf2->e2->f2 = 2;
- if(!(sf2->e3->f1)) sf2->e3->f2 = 2;
- if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2;
- sf2->f1 = 2;
- totsf2 = 1;
-
- /*do sf1*/
- unbalanced = 1;
- while(unbalanced){
- unbalanced = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
- balancededges = 0;
- if(efa->f1 == 0){
- if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){
- balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1;
- balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1;
- balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1;
- if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1;
- if(balancededges){
- unbalanced = 1;
- efa->f1 = 1;
- totsf1++;
- }
- }
- }
- }
- }
-
- /*do sf2*/
- unbalanced = 1;
- while(unbalanced){
- unbalanced = 0;
- for(efa=em->faces.first; efa; efa=efa->next){
- balancededges = 0;
- if(efa->f1 == 0){
- if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){
- balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2;
- balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2;
- balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2;
- if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2;
- if(balancededges){
- unbalanced = 1;
- efa->f1 = 2;
- totsf2++;
- }
- }
- }
- }
- }
-
- if(totsf1 < totsf2) return(1);
- else return(2);
-}
-
-static int loop_to_region(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
-
- EditFace *efa;
- ListBase allcollections={NULL,NULL};
- Collection *edgecollection;
- int testflag;
-
- build_edgecollection(em, &allcollections);
-
- for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
- if(validate_loop(em, edgecollection)){
- testflag = loop_bisect(em, edgecollection);
- for(efa=em->faces.first; efa; efa=efa->next){
- if(efa->f1 == testflag){
- if(efa->f&SELECT) EM_select_face(efa, 0);
- else EM_select_face(efa,1);
- }
- }
- }
- }
-
- for(efa=em->faces.first; efa; efa=efa->next){ /*fix this*/
- if(efa->f&SELECT) EM_select_face(efa,1);
- }
-
- freecollections(&allcollections);
- BKE_mesh_end_editmesh(obedit->data, em);
-
- WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_loop_to_region(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Loop to Region";
- ot->description= "Select a loop of connected edges as a region";
- ot->idname= "MESH_OT_loop_to_region";
-
- /* api callbacks */
- ot->exec= loop_to_region;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/********************** UV/Color Operators *************************/
-
-// XXX please check if these functions do what you want them to
-/* texface and vertex color editmode tools for the face menu */
-
-static int mesh_rotate_uvs(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- MTFace *tf;
- float u1, v1;
- int dir= RNA_enum_get(op->ptr, "direction");
-
- if (!EM_texFaceCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- u1= tf->uv[0][0];
- v1= tf->uv[0][1];
-
- if (dir == DIRECTION_CCW) {
- if(efa->v4) {
- tf->uv[0][0]= tf->uv[3][0];
- tf->uv[0][1]= tf->uv[3][1];
-
- tf->uv[3][0]= tf->uv[2][0];
- tf->uv[3][1]= tf->uv[2][1];
- } else {
- tf->uv[0][0]= tf->uv[2][0];
- tf->uv[0][1]= tf->uv[2][1];
- }
-
- tf->uv[2][0]= tf->uv[1][0];
- tf->uv[2][1]= tf->uv[1][1];
-
- tf->uv[1][0]= u1;
- tf->uv[1][1]= v1;
- } else {
- tf->uv[0][0]= tf->uv[1][0];
- tf->uv[0][1]= tf->uv[1][1];
-
- tf->uv[1][0]= tf->uv[2][0];
- tf->uv[1][1]= tf->uv[2][1];
-
- if(efa->v4) {
- tf->uv[2][0]= tf->uv[3][0];
- tf->uv[2][1]= tf->uv[3][1];
-
- tf->uv[3][0]= u1;
- tf->uv[3][1]= v1;
- }
- else {
- tf->uv[2][0]= u1;
- tf->uv[2][1]= v1;
- }
- }
- change = 1;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_mirror_uvs(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- MTFace *tf;
- float u1, v1;
- int axis= RNA_enum_get(op->ptr, "axis");
-
- if (!EM_texFaceCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no uv/image layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- if (axis == AXIS_Y) {
- u1= tf->uv[1][0];
- v1= tf->uv[1][1];
- if(efa->v4) {
-
- tf->uv[1][0]= tf->uv[2][0];
- tf->uv[1][1]= tf->uv[2][1];
-
- tf->uv[2][0]= u1;
- tf->uv[2][1]= v1;
-
- u1= tf->uv[3][0];
- v1= tf->uv[3][1];
-
- tf->uv[3][0]= tf->uv[0][0];
- tf->uv[3][1]= tf->uv[0][1];
-
- tf->uv[0][0]= u1;
- tf->uv[0][1]= v1;
- }
- else {
- tf->uv[1][0]= tf->uv[2][0];
- tf->uv[1][1]= tf->uv[2][1];
- tf->uv[2][0]= u1;
- tf->uv[2][1]= v1;
- }
-
- } else {
- u1= tf->uv[0][0];
- v1= tf->uv[0][1];
- if(efa->v4) {
-
- tf->uv[0][0]= tf->uv[1][0];
- tf->uv[0][1]= tf->uv[1][1];
-
- tf->uv[1][0]= u1;
- tf->uv[1][1]= v1;
-
- u1= tf->uv[3][0];
- v1= tf->uv[3][1];
-
- tf->uv[3][0]= tf->uv[2][0];
- tf->uv[3][1]= tf->uv[2][1];
-
- tf->uv[2][0]= u1;
- tf->uv[2][1]= v1;
- }
- else {
- tf->uv[0][0]= tf->uv[1][0];
- tf->uv[0][1]= tf->uv[1][1];
- tf->uv[1][0]= u1;
- tf->uv[1][1]= v1;
- }
- }
- change = 1;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-static int mesh_rotate_colors(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- MCol tmpcol, *mcol;
- int dir= RNA_enum_get(op->ptr, "direction");
-
- if (!EM_vertColorCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers.");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- tmpcol= mcol[0];
-
- if (dir == DIRECTION_CCW) {
- if(efa->v4) {
- mcol[0]= mcol[3];
- mcol[3]= mcol[2];
- } else {
- mcol[0]= mcol[2];
- }
- mcol[2]= mcol[1];
- mcol[1]= tmpcol;
- } else {
- mcol[0]= mcol[1];
- mcol[1]= mcol[2];
-
- if(efa->v4) {
- mcol[2]= mcol[3];
- mcol[3]= tmpcol;
- }
- else
- mcol[2]= tmpcol;
- }
- change = 1;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-
-static int mesh_mirror_colors(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- EditFace *efa;
- short change = 0;
- MCol tmpcol, *mcol;
- int axis= RNA_enum_get(op->ptr, "axis");
-
- if (!EM_vertColorCheck(em)) {
- BKE_report(op->reports, RPT_WARNING, "Mesh has no color layers");
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_CANCELLED;
- }
-
- for(efa=em->faces.first; efa; efa=efa->next) {
- if (efa->f & SELECT) {
- mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
- if (axis == AXIS_Y) {
- tmpcol= mcol[1];
- mcol[1]= mcol[2];
- mcol[2]= tmpcol;
-
- if(efa->v4) {
- tmpcol= mcol[0];
- mcol[0]= mcol[3];
- mcol[3]= tmpcol;
- }
- } else {
- tmpcol= mcol[0];
- mcol[0]= mcol[1];
- mcol[1]= tmpcol;
-
- if(efa->v4) {
- tmpcol= mcol[2];
- mcol[2]= mcol[3];
- mcol[3]= tmpcol;
- }
- }
- change = 1;
- }
- }
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- if(!change)
- return OPERATOR_CANCELLED;
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_uvs_rotate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rotate UVs";
- ot->description= "Rotate selected UVs";
- ot->idname= "MESH_OT_uvs_rotate";
-
- /* api callbacks */
- ot->exec= mesh_rotate_uvs;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate UVs around.");
-}
-
-void MESH_OT_uvs_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mirror UVs";
- ot->description= "Mirror selected UVs";
- ot->idname= "MESH_OT_uvs_mirror";
-
- /* api callbacks */
- ot->exec= mesh_mirror_uvs;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror UVs around.");
-}
-
-void MESH_OT_colors_rotate(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Rotate Colors";
- ot->description= "Rotate UV/image color layer";
- ot->idname= "MESH_OT_colors_rotate";
-
- /* api callbacks */
- ot->exec= mesh_rotate_colors;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
-}
-
-void MESH_OT_colors_mirror(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Mirror Colors";
- ot->description= "Mirror UV/image color layer";
- ot->idname= "MESH_OT_colors_mirror";
-
- /* api callbacks */
- ot->exec= mesh_mirror_colors;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* props */
- RNA_def_enum(ot->srna, "axis", axis_items_xy, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
-}
-
-/********************** Subdivide Operator *************************/
-
-static int subdivide_exec(bContext *C, wmOperator *op)
-{
- ToolSettings *ts= CTX_data_tool_settings(C);
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
- int cuts= RNA_int_get(op->ptr,"number_cuts");
- float smooth= 0.292f*RNA_float_get(op->ptr, "smoothness");
- float fractal= RNA_float_get(op->ptr, "fractal")/100;
- int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
- int flag= 0;
-
- if(smooth != 0.0f)
- flag |= B_SMOOTH;
- if(fractal != 0.0f)
- flag |= B_FRACTAL;
-
- esubdivideflag(obedit, em, 1, smooth, fractal, ts->editbutflag|flag, cuts, corner_cut_pattern, 0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_subdivide(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Subdivide";
- ot->description= "Subdivide selected edges";
- ot->idname= "MESH_OT_subdivide";
-
- /* api callbacks */
- ot->exec= subdivide_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_int(ot->srna, "number_cuts", 1, 1, INT_MAX, "Number of Cuts", "", 1, 10);
- RNA_def_float(ot->srna, "smoothness", 0.0f, 0.0f, FLT_MAX, "Smoothness", "Smoothness factor.", 0.0f, 1.0f);
- RNA_def_float(ot->srna, "fractal", 0.0, 0.0f, FLT_MAX, "Fractal", "Fractal randomness factor.", 0.0f, 1000.0f);
- RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
-}
-
-/********************** Fill Operators *************************/
-
-/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
-edge/face flags, with very mixed results.... */
-static void beautify_fill(EditMesh *em)
-{
- EditVert *v1, *v2, *v3, *v4;
- EditEdge *eed, *nexted;
- EditEdge dia1, dia2;
- EditFace *efa, *w;
- // void **efaar, **efaa;
- EVPTuple *efaar;
- EVPtr *efaa;
- float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
- int totedge, ok, notbeauty=8, onedone, vindex[4];
-
- /* - all selected edges with two faces
- * - find the faces: store them in edges (using datablock)
- * - per edge: - test convex
- * - test edge: flip?
- * - if true: remedge, addedge, all edges at the edge get new face pointers
- */
-
- EM_selectmode_set(em); // makes sure in selectmode 'face' the edges of selected faces are selected too
-
- totedge = count_selected_edges(em->edges.first);
- if(totedge==0) return;
-
- /* temp block with face pointers */
- efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
-
- while (notbeauty) {
- notbeauty--;
-
- ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
-
- /* there we go */
- onedone= 0;
-
- eed= em->edges.first;
- while(eed) {
- nexted= eed->next;
-
- /* f2 is set in collect_quadedges() */
- if(eed->f2==2 && eed->h==0) {
-
- efaa = (EVPtr *) eed->tmp.p;
-
- /* none of the faces should be treated before, nor be part of fgon */
- ok= 1;
- efa= efaa[0];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- if(efa->fgonf) ok= 0;
- efa= efaa[1];
- if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
- if(efa->fgonf) ok= 0;
-
- if(ok) {
- /* test convex */
- givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
- if(v1 && v2 && v3 && v4) {
- if( convex(v1->co, v2->co, v3->co, v4->co) ) {
-
- /* test edges */
- if( (v1) > (v3) ) {
- dia1.v1= v3;
- dia1.v2= v1;
- }
- else {
- dia1.v1= v1;
- dia1.v2= v3;
- }
-
- if( (v2) > (v4) ) {
- dia2.v1= v4;
- dia2.v2= v2;
- }
- else {
- dia2.v1= v2;
- dia2.v2= v4;
- }
-
- /* testing rule:
- * the area divided by the total edge lengths
- */
-
- len1= len_v3v3(v1->co, v2->co);
- len2= len_v3v3(v2->co, v3->co);
- len3= len_v3v3(v3->co, v4->co);
- len4= len_v3v3(v4->co, v1->co);
- len5= len_v3v3(v1->co, v3->co);
- len6= len_v3v3(v2->co, v4->co);
-
- opp1= area_tri_v3(v1->co, v2->co, v3->co);
- opp2= area_tri_v3(v1->co, v3->co, v4->co);
-
- fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
-
- opp1= area_tri_v3(v2->co, v3->co, v4->co);
- opp2= area_tri_v3(v2->co, v4->co, v1->co);
-
- fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
-
- ok= 0;
- if(fac1 > fac2) {
- if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
- eed->f1= 1;
- efa= efaa[0];
- efa->f1= 1;
- efa= efaa[1];
- efa->f1= 1;
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], vindex[1], 4+vindex[2], -1);
- w->f |= SELECT;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[2], 4+vindex[3], -1);
- w->f |= SELECT;
-
- onedone= 1;
- }
- }
- else if(fac1 < fac2) {
- if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
- eed->f1= 1;
- efa= efaa[0];
- efa->f1= 1;
- efa= efaa[1];
- efa->f1= 1;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[1], 4+vindex[2], 4+vindex[3], -1);
- w->f |= SELECT;
-
-
- w= EM_face_from_faces(em, efaa[0], efaa[1],
- vindex[0], 4+vindex[1], 4+vindex[3], -1);
- w->f |= SELECT;
-
- onedone= 1;
- }
- }
- }
- }
- }
-
- }
- eed= nexted;
- }
-
- free_tagged_edges_faces(em, em->edges.first, em->faces.first);
-
- if(onedone==0) break;
-
- EM_selectmode_set(em); // new edges/faces were added
- }
-
- MEM_freeN(efaar);
-
- EM_select_flush(em);
-
-}
-
-/* Got this from scanfill.c. You will need to juggle around the
-* callbacks for the scanfill.c code a bit for this to work. */
-static void fill_mesh(EditMesh *em)
-{
- EditVert *eve,*v1;
- EditEdge *eed,*e1,*nexted;
- EditFace *efa,*nextvl, *efan;
- short ok;
-
- if(em==NULL) return;
- waitcursor(1);
-
- /* copy all selected vertices */
- eve= em->verts.first;
- while(eve) {
- if(eve->f & SELECT) {
- v1= BLI_addfillvert(eve->co);
- eve->tmp.v= v1;
- v1->tmp.v= eve;
- v1->xs= 0; // used for counting edges
- }
- eve= eve->next;
- }
- /* copy all selected edges */
- eed= em->edges.first;
- while(eed) {
- if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
- e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
- e1->v1->xs++;
- e1->v2->xs++;
- }
- eed= eed->next;
- }
- /* from all selected faces: remove vertices and edges to prevent doubles */
- /* all edges add values, faces subtract,
- then remove edges with vertices ->xs<2 */
- efa= em->faces.first;
- ok= 0;
- while(efa) {
- nextvl= efa->next;
- if( faceselectedAND(efa, 1) ) {
- efa->v1->tmp.v->xs--;
- efa->v2->tmp.v->xs--;
- efa->v3->tmp.v->xs--;
- if(efa->v4) efa->v4->tmp.v->xs--;
- ok= 1;
-
- }
- efa= nextvl;
- }
- if(ok) { /* there are faces selected */
- eed= filledgebase.first;
- while(eed) {
- nexted= eed->next;
- if(eed->v1->xs<2 || eed->v2->xs<2) {
- BLI_remlink(&filledgebase,eed);
- }
- eed= nexted;
- }
- }
-
- if(BLI_edgefill(em->mat_nr)) {
- efa= fillfacebase.first;
- while(efa) {
- /* normals default pointing up */
- efan= addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v,
- efa->v1->tmp.v, 0, NULL, NULL);
- if(efan) EM_select_face(efan, 1);
- efa= efa->next;
- }
- }
-
- BLI_end_edgefill();
- beautify_fill(em);
-
- WM_cursor_wait(0);
- EM_select_flush(em);
-
-}
-
-static int fill_mesh_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- fill_mesh(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-
-}
-
-void MESH_OT_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Fill";
- ot->description= "Create a segment, edge or face";
- ot->idname= "MESH_OT_fill";
-
- /* api callbacks */
- ot->exec= fill_mesh_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int beautify_fill_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- beautify_fill(em);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_beautify_fill(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Beautify Fill";
- ot->description= "Rearrange geometry on a selected surface to avoid skinny faces";
- ot->idname= "MESH_OT_beautify_fill";
-
- /* api callbacks */
- ot->exec= beautify_fill_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* ********************** SORT FACES ******************* */
-
-static void permutate(void *list, int num, int size, int *index)
-{
- void *buf;
- int len;
- int i;
-
- len = num * size;
-
- buf = MEM_mallocN(len, "permutate");
- memcpy(buf, list, len);
-
- for (i = 0; i < num; i++) {
- memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
- }
- MEM_freeN(buf);
-}
-
-/* sort faces on view axis */
-static float *face_sort_floats;
-static int float_sort(const void *v1, const void *v2)
-{
- float x1, x2;
-
- x1 = face_sort_floats[((int *) v1)[0]];
- x2 = face_sort_floats[((int *) v2)[0]];
-
- if( x1 > x2 ) return 1;
- else if( x1 < x2 ) return -1;
- return 0;
-}
-
-
-static int sort_faces_exec(bContext *C, wmOperator *op)
-{
- RegionView3D *rv3d= ED_view3d_context_rv3d(C);
- View3D *v3d= CTX_wm_view3d(C);
- Object *ob= CTX_data_edit_object(C);
- Scene *scene= CTX_data_scene(C);
- Mesh *me;
- CustomDataLayer *layer;
- int i, *index;
- int event;
- float reverse = 1;
- // XXX int ctrl= 0;
-
- if (!v3d) return OPERATOR_CANCELLED;
-
- /* This operator work in Object Mode, not in edit mode.
- * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
- * so for now, we just exit_editmode and enter_editmode at the end of this function.
- */
- ED_object_exit_editmode(C, EM_FREEDATA);
-
- me= ob->data;
- if(me->totface==0) {
- ED_object_enter_editmode(C, 0);
- return OPERATOR_FINISHED;
- }
-
- event= RNA_enum_get(op->ptr, "type");
-
- // XXX
- //if(ctrl)
- // reverse = -1;
-
- /* create index list */
- index= (int *)MEM_mallocN(sizeof(int) * me->totface, "sort faces");
- for (i = 0; i < me->totface; i++) {
- index[i] = i;
- }
-
- face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float");
-
- /* sort index list instead of faces itself
- * and apply this permutation to all face layers
- */
- if (event == 5) {
- /* Random */
- for(i=0; i<me->totface; i++) {
- face_sort_floats[i] = BLI_frand();
- }
- qsort(index, me->totface, sizeof(int), float_sort);
- } else {
- MFace *mf;
- float vec[3];
- float mat[4][4];
- float cur[3];
-
- if (event == 1)
- mul_m4_m4m4(mat, OBACT->obmat, rv3d->viewmat); /* apply the view matrix to the object matrix */
- else if (event == 2) { /* sort from cursor */
- if( v3d && v3d->localvd ) {
- VECCOPY(cur, v3d->cursor);
- } else {
- VECCOPY(cur, scene->cursor);
- }
- invert_m4_m4(mat, OBACT->obmat);
- mul_m4_v3(mat, cur);
- }
-
- mf= me->mface;
-
- for(i=0; i<me->totface; i++, mf++) {
- if (event==3) {
- face_sort_floats[i] = ((float)mf->mat_nr)*reverse;
- } else if (event==4) {
- /*selected first*/
- if (mf->flag & ME_FACE_SEL)
- face_sort_floats[i] = 0.0;
- else
- face_sort_floats[i] = reverse;
- } else {
- /* find the faces center */
- add_v3_v3v3(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
- if (mf->v4) {
- add_v3_v3(vec, (me->mvert+mf->v3)->co);
- add_v3_v3(vec, (me->mvert+mf->v4)->co);
- mul_v3_fl(vec, 0.25f);
- } else {
- add_v3_v3(vec, (me->mvert+mf->v3)->co);
- mul_v3_fl(vec, 1.0f/3.0f);
- } /* done */
-
- if (event == 1) { /* sort on view axis */
- mul_m4_v3(mat, vec);
- face_sort_floats[i] = vec[2] * reverse;
- } else if(event == 2) { /* distance from cursor*/
- face_sort_floats[i] = len_v3v3(cur, vec) * reverse; /* back to front */
- }
- }
- }
- qsort(index, me->totface, sizeof(int), float_sort);
- }
-
- MEM_freeN(face_sort_floats);
- for(i = 0; i < me->fdata.totlayer; i++) {
- layer = &me->fdata.layers[i];
- permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index);
- }
-
- MEM_freeN(index);
- DAG_id_tag_update(ob->data, 0);
-
- /* Return to editmode. */
- ED_object_enter_editmode(C, 0);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_sort_faces(wmOperatorType *ot)
-{
- static EnumPropertyItem type_items[]= {
- { 1, "VIEW_AXIS", 0, "View Axis", "" },
- { 2, "CURSOR_DISTANCE", 0, "Cursor Distance", "" },
- { 3, "MATERIAL", 0, "Material", "" },
- { 4, "SELECTED", 0, "Selected", "" },
- { 5, "RANDOMIZE", 0, "Randomize", "" },
- { 0, NULL, 0, NULL, NULL }};
-
- /* identifiers */
- ot->name= "Sort Faces"; // XXX (Ctrl to reverse)%t|
- ot->description= "The faces of the active Mesh Object are sorted, based on the current view.";
- ot->idname= "MESH_OT_sort_faces";
-
- /* api callbacks */
- ot->invoke= WM_menu_invoke;
- ot->exec= sort_faces_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
-}
-
-/********************** Quad/Tri Operators *************************/
-
-static int quads_convert_to_tris_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- convert_to_triface(em,0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_quads_convert_to_tris(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Quads to Tris";
- ot->description= "Convert selected quads to triangles";
- ot->idname= "MESH_OT_quads_convert_to_tris";
-
- /* api callbacks */
- ot->exec= quads_convert_to_tris_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int tris_convert_to_quads_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- join_triangles(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_tris_convert_to_quads(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Tris to Quads";
- ot->description= "Convert selected triangles to quads";
- ot->idname= "MESH_OT_tris_convert_to_quads";
-
- /* api callbacks */
- ot->exec= tris_convert_to_quads_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int edge_flip_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- edge_flip(em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- BKE_mesh_end_editmesh(obedit->data, em);
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_edge_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Edge Flip";
- ot->description= "Flip selected edge or adjoining faces";
- ot->idname= "MESH_OT_edge_flip";
-
- /* api callbacks */
- ot->exec= edge_flip_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/********************** Smooth/Solid Operators *************************/
-
-static void mesh_set_smooth_faces(EditMesh *em, short smooth)
-{
- EditFace *efa;
-
- if(em==NULL) return;
-
- for(efa= em->faces.first; efa; efa=efa->next) {
- if(efa->f & SELECT) {
- if(smooth) efa->flag |= ME_SMOOTH;
- else efa->flag &= ~ME_SMOOTH;
- }
- }
-
- recalc_editnormals(em);
-}
-
-static int mesh_faces_shade_smooth_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- mesh_set_smooth_faces(em, 1);
-
- BKE_mesh_end_editmesh(obedit->data, em);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_shade_smooth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shade Smooth";
- ot->description= "Display faces 'smooth' (using vertex normals)";
- ot->idname= "MESH_OT_faces_shade_smooth";
-
- /* api callbacks */
- ot->exec= mesh_faces_shade_smooth_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-static int mesh_faces_shade_flat_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- mesh_set_smooth_faces(em, 0);
-
- DAG_id_tag_update(obedit->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_faces_shade_flat(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name= "Shade Flat";
- ot->description= "Display faces 'flat'";
- ot->idname= "MESH_OT_faces_shade_flat";
-
- /* api callbacks */
- ot->exec= mesh_faces_shade_flat_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-}
-
-/* TODO - some way to select on an arbitrary axis */
-static int select_axis_exec(bContext *C, wmOperator *op)
-{
- Object *obedit= CTX_data_edit_object(C);
- EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-
- int axis= RNA_enum_get(op->ptr, "axis");
- int mode= RNA_enum_get(op->ptr, "mode"); /* -1==aligned, 0==neg, 1==pos*/
-
- EditSelection *ese = em->selected.last;
-
-
- if(ese==NULL)
- return OPERATOR_CANCELLED;
-
- if(ese->type==EDITVERT) {
- EditVert *ev;
- EditVert *act_vert= (EditVert*)ese->data;
- float value= act_vert->co[axis];
- float limit= CTX_data_tool_settings(C)->doublimit; // XXX
-
- if(mode==0) value -= limit;
- else if (mode==1) value += limit;
-
- for(ev=em->verts.first;ev;ev=ev->next) {
- if(!ev->h) {
- switch(mode) {
- case -1: /* aligned */
- if(fabs(ev->co[axis] - value) < limit)
- ev->f |= SELECT;
- break;
- case 0: /* neg */
- if(ev->co[axis] > value)
- ev->f |= SELECT;
- break;
- case 1: /* pos */
- if(ev->co[axis] < value)
- ev->f |= SELECT;
- break;
- }
- }
- }
- }
-
- EM_select_flush(em);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
-
- return OPERATOR_FINISHED;
-}
-
-void MESH_OT_select_axis(wmOperatorType *ot)
-{
- static EnumPropertyItem axis_mode_items[] = {
- {0, "POSITIVE", 0, "Positive Axis", ""},
- {1, "NEGATIVE", 0, "Negative Axis", ""},
- {-1, "ALIGNED", 0, "Aligned Axis", ""},
- {0, NULL, 0, NULL, NULL}};
-
- static EnumPropertyItem axis_items_xyz[] = {
- {0, "X_AXIS", 0, "X Axis", ""},
- {1, "Y_AXIS", 0, "Y Axis", ""},
- {2, "Z_AXIS", 0, "Z Axis", ""},
- {0, NULL, 0, NULL, NULL}};
-
- /* identifiers */
- ot->name= "Select Axis";
- ot->description= "Select all data in the mesh on a single axis";
- ot->idname= "MESH_OT_select_axis";
-
- /* api callbacks */
- ot->exec= select_axis_exec;
- ot->poll= ED_operator_editmesh;
-
- /* flags */
- ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
-
- /* properties */
- RNA_def_enum(ot->srna, "mode", axis_mode_items, 0, "Axis Mode", "Axis side to use when selecting");
- RNA_def_enum(ot->srna, "axis", axis_items_xyz, 0, "Axis", "Select the axis to compare each vertex on");
-}
-
diff --git a/source/blender/editors/mesh/knifetool.c b/source/blender/editors/mesh/knifetool.c
new file mode 100755
index 00000000000..73bb49d7667
--- /dev/null
+++ b/source/blender/editors/mesh/knifetool.c
@@ -0,0 +1,1863 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Joseph Eagar, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <float.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_object_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h" /*for WM_operator_pystring */
+#include "BLI_editVert.h"
+#include "BLI_array.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "BLI_mempool.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_kdopbvh.h"
+#include "BLI_smallhash.h"
+#include "BLI_scanfill.h"
+
+#include "BKE_blender.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+#include "BKE_mesh.h"
+#include "BKE_tessmesh.h"
+#include "BKE_depsgraph.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h" /* for paint cursor */
+
+#include "IMB_imbuf_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+#include "ED_mesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "mesh_intern.h"
+#include "editbmesh_bvh.h"
+
+/* this code here is kindof messy. . .I might need to eventually rework it - joeedh*/
+
+#define MAXGROUP 30
+#define KMAXDIST 25 /*max mouse distance from edge before not detecting it*/
+
+/* knifetool operator */
+typedef struct KnifeVert {
+ BMVert *v; /*non-NULL if this is an original vert*/
+ ListBase edges;
+
+ float co[3], sco[3]; /*sco is screen coordinates*/
+ short flag, draw, isface, inspace;
+} KnifeVert;
+
+typedef struct Ref {
+ struct Ref *next, *prev;
+ void *ref;
+} Ref;
+
+typedef struct KnifeEdge {
+ KnifeVert *v1, *v2;
+ BMFace *basef; /*face to restrict face fill to*/
+ ListBase faces;
+ int draw;
+
+ BMEdge *e, *oe; /*non-NULL if this is an original edge*/
+} KnifeEdge;
+
+typedef struct BMEdgeHit {
+ KnifeEdge *kfe;
+ float hit[3];
+ float realhit[3]; /*used in midpoint mode*/
+ float schit[3];
+ float l; /*lambda along line*/
+ KnifeVert *v; //set if snapped to a vert
+ BMFace *f;
+} BMEdgeHit;
+
+/* struct for properties used while drawing */
+typedef struct knifetool_opdata {
+ ARegion *ar; /* region that knifetool was activated in */
+ void *draw_handle; /* for drawing preview loop */
+ ViewContext vc;
+ bContext *C;
+
+ Object *ob;
+ BMEditMesh *em;
+
+ MemArena *arena;
+
+ GHash *origvertmap;
+ GHash *origedgemap;
+
+ GHash *kedgefacemap;
+
+ BMBVHTree *bmbvh;
+
+ BLI_mempool *kverts;
+ BLI_mempool *kedges;
+
+ float vthresh;
+ float ethresh;
+
+ float vertco[3];
+ float prevco[3];
+
+ /*used for drag-cutting*/
+ BMEdgeHit *linehits;
+ int totlinehit;
+
+ /*if curedge is NULL, attach to curvert;
+ if curvert is NULL, attach to curbmface,
+ otherwise create null vert*/
+ KnifeEdge *curedge, *prevedge;
+ KnifeVert *curvert, *prevvert;
+ BMFace *curbmface, *prevbmface;
+
+ int totkedge, totkvert, cutnr;
+
+ BLI_mempool *refs;
+
+ float projmat[4][4];
+ int is_ortho;
+ float clipsta, clipend;
+
+ enum {
+ MODE_IDLE,
+ MODE_DRAGGING,
+ MODE_CONNECT,
+ MODE_PANNING,
+ } mode;
+
+ int snap_midpoints, prevmode, extend;
+ int ignore_edge_snapping, ignore_vert_snapping;
+
+ int is_space, prev_is_space; /*1 if current cut location, vertco, isn't on the mesh*/
+} knifetool_opdata;
+
+static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f);
+
+void knife_project_v3(knifetool_opdata *kcd, float co[3], float sco[3])
+{
+ if (kcd->is_ortho) {
+ mul_v3_m4v3(sco, kcd->projmat, co);
+
+ sco[0] = (float)(kcd->ar->winx/2.0f)+(kcd->ar->winx/2.0f)*sco[0];
+ sco[1] = (float)(kcd->ar->winy/2.0f)+(kcd->ar->winy/2.0f)*sco[1];
+ } else
+ view3d_project_float(kcd->ar, co, sco, kcd->projmat);
+}
+
+static KnifeEdge *new_knife_edge(knifetool_opdata *kcd)
+{
+ kcd->totkedge++;
+ return BLI_mempool_calloc(kcd->kedges);
+}
+
+static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co)
+{
+ KnifeVert *kfv = BLI_mempool_calloc(kcd->kverts);
+
+ kcd->totkvert++;
+
+ copy_v3_v3(kfv->co, co);
+ copy_v3_v3(kfv->sco, co);
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ return kfv;
+}
+
+/*get a KnifeVert wrapper for an existing BMVert*/
+static KnifeVert *get_bm_knife_vert(knifetool_opdata *kcd, BMVert *v)
+{
+ KnifeVert *kfv = BLI_ghash_lookup(kcd->origvertmap, v);
+
+ if (!kfv) {
+ kfv = new_knife_vert(kcd, v->co);
+ kfv->v = v;
+ BLI_ghash_insert(kcd->origvertmap, v, kfv);
+ }
+
+ return kfv;
+}
+
+/*get a KnifeEdge wrapper for an existing BMEdge*/
+static KnifeEdge *get_bm_knife_edge(knifetool_opdata *kcd, BMEdge *e)
+{
+ KnifeEdge *kfe = BLI_ghash_lookup(kcd->origedgemap, e);
+ if (!kfe) {
+ Ref *ref;
+ BMIter iter;
+ BMFace *f;
+
+ kfe = new_knife_edge(kcd);
+ kfe->e = e;
+ kfe->v1 = get_bm_knife_vert(kcd, e->v1);
+ kfe->v2 = get_bm_knife_vert(kcd, e->v2);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v2->edges, ref);
+
+ BLI_ghash_insert(kcd->origedgemap, e, kfe);
+
+ BM_ITER(f, &iter, kcd->em->bm, BM_FACES_OF_EDGE, e) {
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = f;
+ BLI_addtail(&kfe->faces, ref);
+
+ /*ensures the kedges lst for this f is initialized,
+ it automatically adds kfe by itself*/
+ knife_get_face_kedges(kcd, f);
+ }
+ }
+
+ return kfe;
+}
+
+static void knife_start_cut(knifetool_opdata *kcd)
+{
+ kcd->prevedge = kcd->curedge;
+ kcd->prevvert = kcd->curvert;
+ kcd->prevbmface = kcd->curbmface;
+ kcd->cutnr++;
+ kcd->prev_is_space = kcd->is_space;
+ kcd->is_space = 0;
+
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+}
+
+static Ref *find_ref(ListBase *lb, void *ref)
+{
+ Ref *ref1;
+
+ for (ref1=lb->first; ref1; ref1=ref1->next) {
+ if (ref1->ref == ref)
+ return ref1;
+ }
+
+ return NULL;
+}
+
+static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f)
+{
+ ListBase *lst = BLI_ghash_lookup(kcd->kedgefacemap, f);
+
+ if (!lst) {
+ BMIter iter;
+ BMEdge *e;
+
+ lst = BLI_memarena_alloc(kcd->arena, sizeof(ListBase));
+ lst->first = lst->last = NULL;
+
+ BM_ITER(e, &iter, kcd->em->bm, BM_EDGES_OF_FACE, f) {
+ Ref *ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = get_bm_knife_edge(kcd, e);
+ BLI_addtail(lst, ref);
+ }
+
+ BLI_ghash_insert(kcd->kedgefacemap, f, lst);
+ }
+
+ return lst;
+}
+
+/*finds the proper face to restrict face fill to*/
+void knife_find_basef(knifetool_opdata *kcd, KnifeEdge *kfe)
+{
+ if (!kfe->basef) {
+ Ref *r1, *r2, *r3, *r4;
+
+ if (kfe->v1->isface || kfe->v2->isface) {
+ if (kfe->v2->isface)
+ kfe->basef = kcd->curbmface;
+ else
+ kfe->basef = kcd->prevbmface;
+ } else {
+ for (r1=kfe->v1->edges.first; r1 && !kfe->basef; r1=r1->next) {
+ KnifeEdge *ke1 = r1->ref;
+ for (r2=ke1->faces.first; r2 && !kfe->basef; r2=r2->next) {
+ for (r3=kfe->v2->edges.first; r3 && !kfe->basef; r3=r3->next) {
+ KnifeEdge *ke2 = r3->ref;
+
+ for (r4=ke2->faces.first; r4 && !kfe->basef; r4=r4->next) {
+ if (r2->ref == r4->ref) {
+ kfe->basef = r2->ref;
+ }
+ }
+ }
+ }
+ }
+ }
+ /*ok, at this point kfe->basef should be set if any valid possibility
+ exists*/
+ }
+}
+
+static KnifeVert *knife_split_edge(knifetool_opdata *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
+{
+ KnifeEdge *newkfe = new_knife_edge(kcd);
+ ListBase *lst;
+ Ref *ref;
+
+ newkfe->v1 = kfe->v1;
+ newkfe->v2 = new_knife_vert(kcd, co);
+ newkfe->v2->draw = 1;
+ newkfe->basef = kfe->basef;
+
+ ref = find_ref(&kfe->v1->edges, kfe);
+ BLI_remlink(&kfe->v1->edges, ref);
+
+ kfe->v1 = newkfe->v2;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ for (ref=kfe->faces.first; ref; ref=ref->next) {
+ Ref *ref2 = BLI_mempool_calloc(kcd->refs);
+
+ /*add kedge ref to bm faces*/
+ lst = knife_get_face_kedges(kcd, ref->ref);
+ ref2->ref = newkfe;
+ BLI_addtail(lst, ref2);
+
+ ref2 = BLI_mempool_calloc(kcd->refs);
+ ref2->ref = ref->ref;
+ BLI_addtail(&newkfe->faces, ref2);
+ }
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = newkfe;
+ BLI_addtail(&newkfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = newkfe;
+ BLI_addtail(&newkfe->v2->edges, ref);
+
+ newkfe->draw = kfe->draw;
+ newkfe->e = kfe->e;
+
+ *newkfe_out = newkfe;
+
+ return newkfe->v2;
+}
+
+static void knife_edge_append_face(knifetool_opdata *kcd, KnifeEdge *kfe, BMFace *f)
+{
+ ListBase *lst = knife_get_face_kedges(kcd, f);
+ Ref *ref = BLI_mempool_calloc(kcd->refs);
+
+ ref->ref = kfe;
+ BLI_addtail(lst, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = f;
+ BLI_addtail(&kfe->faces, ref);
+}
+
+#if 0
+static void knife_copy_edge_facelist(knifetool_opdata *kcd, KnifeEdge *dest, KnifeEdge *source)
+{
+ Ref *ref, *ref2;
+
+ for (ref2 = source->faces.first; ref2; ref2=ref2->next) {
+ ListBase *lst = knife_get_face_kedges(kcd, ref2->ref);
+
+ /*add new edge to face knife edge list*/
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = dest;
+ BLI_addtail(lst, ref);
+
+ /*add face to new edge's face list*/
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = ref2->ref;
+ BLI_addtail(&dest->faces, ref);
+ }
+}
+#endif
+
+static void knife_add_single_cut(knifetool_opdata *kcd)
+{
+ KnifeEdge *kfe = new_knife_edge(kcd), *kfe2 = NULL, *kfe3 = NULL;
+ Ref *ref;
+
+ if (kcd->prevvert && kcd->prevvert == kcd->curvert)
+ return;
+ if (kcd->prevedge && kcd->prevedge == kcd->curedge)
+ return;
+
+ kfe->draw = 1;
+
+ if (kcd->prevvert) {
+ kfe->v1 = kcd->prevvert;
+ } else if (kcd->prevedge) {
+ kfe->v1 = knife_split_edge(kcd, kcd->prevedge, kcd->prevco, &kfe2);
+ } else {
+ kfe->v1 = new_knife_vert(kcd, kcd->prevco);
+ kfe->v1->draw = kfe->draw = !kcd->prev_is_space;
+ kfe->v1->inspace = kcd->prev_is_space;
+ kfe->draw = !kcd->prev_is_space;
+ kfe->v1->isface = 1;
+ }
+
+ if (kcd->curvert) {
+ kfe->v2 = kcd->curvert;
+ } else if (kcd->curedge) {
+ kfe->v2 = knife_split_edge(kcd, kcd->curedge, kcd->vertco, &kfe3);
+
+ kcd->curvert = kfe->v2;
+ } else {
+ kfe->v2 = new_knife_vert(kcd, kcd->vertco);
+ kfe->v2->draw = !kcd->is_space;
+ kfe->v2->isface = 1;
+ kfe->v2->inspace = kcd->is_space;
+
+ if (kcd->is_space)
+ kfe->draw = 0;
+
+ kcd->curvert = kfe->v2;
+ }
+
+ knife_find_basef(kcd, kfe);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v1->edges, ref);
+
+ ref = BLI_mempool_calloc(kcd->refs);
+ ref->ref = kfe;
+ BLI_addtail(&kfe->v2->edges, ref);
+
+ if (kfe->basef && !find_ref(&kfe->faces, kfe->basef))
+ knife_edge_append_face(kcd, kfe, kfe->basef);
+
+ /*sanity check to make sure we're in the right edge/face lists*/
+ if (kcd->curbmface) {
+ if (!find_ref(&kfe->faces, kcd->curbmface)) {
+ knife_edge_append_face(kcd, kfe, kcd->curbmface);
+ }
+
+ if (kcd->prevbmface && kcd->prevbmface != kcd->curbmface) {
+ if (!find_ref(&kfe->faces, kcd->prevbmface)) {
+ knife_edge_append_face(kcd, kfe, kcd->prevbmface);
+ }
+ }
+ }
+
+ /*set up for next cut*/
+ kcd->prevbmface = kcd->curbmface;
+ kcd->prevvert = kcd->curvert;
+ kcd->prevedge = kcd->curedge;
+ copy_v3_v3(kcd->prevco, kcd->vertco);
+ kcd->prev_is_space = kcd->is_space;
+}
+
+static int verge_linehit(const void *vlh1, const void *vlh2)
+{
+ const BMEdgeHit *lh1=vlh1, *lh2=vlh2;
+
+ if (lh1->l < lh2->l) return -1;
+ else if (lh1->l > lh2->l) return 1;
+ else return 0;
+}
+
+static void knife_add_cut(knifetool_opdata *kcd)
+{
+ BMEditMesh *em = kcd->em;
+ knifetool_opdata oldkcd = *kcd;
+
+ if (kcd->linehits) {
+ BMEdgeHit *lh, *lastlh, *firstlh;
+ int i;
+
+ qsort(kcd->linehits, kcd->totlinehit, sizeof(BMEdgeHit), verge_linehit);
+
+ lh = kcd->linehits;
+ lastlh = firstlh = NULL;
+ for (i=0; i<kcd->totlinehit; i++, (lastlh=lh), lh++) {
+ BMFace *f = lastlh ? lastlh->f : lh->f;
+
+ if (lastlh && len_v3v3(lastlh->hit, lh->hit) == 0.0f) {
+ if (!firstlh)
+ firstlh = lastlh;
+ continue;
+ } else if (lastlh && firstlh) {
+ if (firstlh->v || lastlh->v) {
+ KnifeVert *kfv = firstlh->v ? firstlh->v : lastlh->v;
+
+ kcd->prevvert = kfv;
+ copy_v3_v3(kcd->prevco, firstlh->hit);
+ kcd->prevedge = NULL;
+ kcd->prevbmface = f;
+ }
+ lastlh = firstlh = NULL;
+ }
+
+ if (len_v3v3(kcd->prevco, lh->realhit) < FLT_EPSILON*80)
+ continue;
+ if (len_v3v3(kcd->vertco, lh->realhit) < FLT_EPSILON*80)
+ continue;
+
+ if (kcd->prev_is_space || kcd->is_space) {
+ kcd->prev_is_space = kcd->is_space = 0;
+ copy_v3_v3(kcd->prevco, lh->hit);
+ kcd->prevedge = lh->kfe;
+ kcd->curbmface = lh->f;
+ continue;
+ }
+
+ kcd->is_space = 0;
+ kcd->curedge = lh->kfe;
+ kcd->curbmface = lh->f;
+ kcd->curvert = lh->v;
+ copy_v3_v3(kcd->vertco, lh->hit);
+
+ knife_add_single_cut(kcd);
+ }
+
+ kcd->curbmface = oldkcd.curbmface;
+ kcd->curvert = oldkcd.curvert;
+ kcd->curedge = oldkcd.curedge;
+ kcd->is_space = oldkcd.is_space;
+ copy_v3_v3(kcd->vertco, oldkcd.vertco);
+
+ knife_add_single_cut(kcd);
+
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+ } else {
+ knife_add_single_cut(kcd);
+ }
+}
+
+static void knife_finish_cut(knifetool_opdata *kcd)
+{
+
+}
+
+/* modal loop selection drawing callback */
+static void knifetool_draw(const bContext *C, ARegion *ar, void *arg)
+{
+ knifetool_opdata *kcd = arg;
+
+ glDisable(GL_DEPTH_TEST);
+
+ glPolygonOffset(1.0f, 1.0f);
+
+ glPushMatrix();
+ glMultMatrixf(kcd->ob->obmat);
+
+ if (kcd->mode == MODE_DRAGGING) {
+ glColor3f(0.1, 0.1, 0.1);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->prevco);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+
+ glLineWidth(1.0);
+ }
+
+ if (kcd->curedge) {
+ glColor3f(0.5, 0.3, 0.15);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINES);
+ glVertex3fv(kcd->curedge->v1->co);
+ glVertex3fv(kcd->curedge->v2->co);
+ glEnd();
+
+ glLineWidth(1.0);
+ } else if (kcd->curvert) {
+ glColor3f(0.8, 0.2, 0.1);
+ glPointSize(11);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+ }
+
+ if (kcd->curbmface) {
+ glColor3f(0.1, 0.8, 0.05);
+ glPointSize(9);
+
+ glBegin(GL_POINTS);
+ glVertex3fv(kcd->vertco);
+ glEnd();
+ }
+
+ if (kcd->totlinehit > 0) {
+ BMEdgeHit *lh;
+ int i;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /*draw any snapped verts first*/
+ glColor4f(0.8, 0.2, 0.1, 0.4);
+ glPointSize(11);
+ glBegin(GL_POINTS);
+ lh = kcd->linehits;
+ for (i=0; i<kcd->totlinehit; i++, lh++) {
+ float sv1[3], sv2[3];
+
+ knife_project_v3(kcd, lh->kfe->v1->co, sv1);
+ knife_project_v3(kcd, lh->kfe->v2->co, sv2);
+ knife_project_v3(kcd, lh->hit, lh->schit);
+
+ if (len_v2v2(lh->schit, sv1) < kcd->vthresh/4) {
+ copy_v3_v3(lh->hit, lh->kfe->v1->co);
+ glVertex3fv(lh->hit);
+ lh->v = lh->kfe->v1;
+ } else if (len_v2v2(lh->schit, sv2) < kcd->vthresh/4) {
+ copy_v3_v3(lh->hit, lh->kfe->v2->co);
+ glVertex3fv(lh->hit);
+ lh->v = lh->kfe->v2;
+ }
+ }
+ glEnd();
+
+ /*now draw the rest*/
+ glColor4f(0.1, 0.8, 0.05, 0.4);
+ glPointSize(7);
+ glBegin(GL_POINTS);
+ lh = kcd->linehits;
+ for (i=0; i<kcd->totlinehit; i++, lh++) {
+ glVertex3fv(lh->hit);
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+ }
+
+ if (kcd->totkedge > 0) {
+ BLI_mempool_iter iter;
+ KnifeEdge *kfe;
+
+ glLineWidth(1.0);
+ glBegin(GL_LINES);
+
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
+ if (!kfe->draw)
+ continue;
+
+ glColor3f(0.2, 0.2, 0.2);
+
+ glVertex3fv(kfe->v1->co);
+ glVertex3fv(kfe->v2->co);
+ }
+
+ glEnd();
+ glLineWidth(1.0);
+ }
+
+ if (kcd->totkvert > 0) {
+ BLI_mempool_iter iter;
+ KnifeVert *kfv;
+
+ glPointSize(5.0);
+
+ glBegin(GL_POINTS);
+ BLI_mempool_iternew(kcd->kverts, &iter);
+ for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
+ if (!kfv->draw)
+ continue;
+
+ glColor3f(0.6, 0.1, 0.2);
+
+ glVertex3fv(kfv->co);
+ }
+
+ glEnd();
+ }
+
+ glPopMatrix();
+ glEnable(GL_DEPTH_TEST);
+}
+
+void _print_smhash(SmallHash *hash)
+{
+ int i, linecol=79, c=0;
+
+ printf("{");
+ for (i=0; i<hash->size; i++) {
+ if (hash->table[i].val == CELL_UNUSED) {
+ printf("--u-");
+ } else if (hash->table[i].val == CELL_FREE) {
+ printf("--f-");
+ } else {
+ printf("%2x", (unsigned int)hash->table[i].key);
+ }
+
+ if (i != hash->size-1)
+ printf(", ");
+
+ c += 6;
+
+ if (c >= linecol) {
+ printf("\n ");
+ c = 0;
+ }
+ }
+
+ fflush(stdout);
+}
+
+static int kfe_vert_in_edge(KnifeEdge *e, KnifeVert *v) {
+ return e->v1 == v || e->v2 == v;
+}
+
+static int point_on_line(float p[3], float v1[3], float v2[3])
+{
+ float d = dist_to_line_segment_v3(p, v1, v2);
+ if (d < 0.01) {
+ d = len_v3v3(v1, v2);
+ if (d == 0.0)
+ return 0;
+
+ d = len_v3v3(p, v1) / d;
+
+ if (d >= -FLT_EPSILON*10 || d <= 1.0+FLT_EPSILON*10)
+ return 1;
+ }
+
+ return 0;
+}
+
+BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3],
+ float v2[3], float v3[3], SmallHash *ehash, bglMats *mats, int *count)
+{
+ BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree);
+ BMEdgeHit *edges = NULL;
+ BLI_array_declare(edges);
+ BVHTreeOverlap *results, *result;
+ BMLoop **ls;
+ float cos[9], uv[3], lambda;
+ unsigned int tot=0;
+ int i, j;
+
+ copy_v3_v3(cos, v1);
+ copy_v3_v3(cos+3, v2);
+ copy_v3_v3(cos+6, v3);
+
+ BLI_bvhtree_insert(tree2, 0, cos, 3);
+ BLI_bvhtree_balance(tree2);
+
+ result = results = BLI_bvhtree_overlap(tree, tree2, &tot);
+
+ for (i=0; i<tot; i++, result++) {
+ float p[3];
+
+ ls = (BMLoop**)kcd->em->looptris[result->indexA];
+
+ for (j=0; j<3; j++) {
+ BMLoop *l1 = ls[j];
+ BMFace *hitf;
+ ListBase *lst = knife_get_face_kedges(kcd, l1->f);
+ Ref *ref, *ref2;
+
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+
+ if (kfe == kcd->curedge || kfe== kcd->prevedge)
+ continue;
+
+ if (isect_line_tri_v3(kfe->v1->co, kfe->v2->co, v1, v2, v3, &lambda, uv)) {
+ float no[3], view[3], sp[3];
+
+ sub_v3_v3v3(p, kfe->v2->co, kfe->v1->co);
+ mul_v3_fl(p, lambda);
+ add_v3_v3(p, kfe->v1->co);
+
+ if (kcd->curedge && point_on_line(p, kcd->curedge->v1->co, kcd->curedge->v2->co))
+ continue;
+ if (kcd->prevedge && point_on_line(p, kcd->prevedge->v1->co, kcd->prevedge->v2->co))
+ continue;
+ if (kcd->curvert && len_v3v3(kcd->curvert->co, p) < FLT_EPSILON*50)
+ continue;
+ if (kcd->prevvert && len_v3v3(kcd->prevvert->co, p) < FLT_EPSILON*50)
+ continue;
+ if (len_v3v3(kcd->prevco, p) < FLT_EPSILON*50 || len_v3v3(kcd->vertco, p) < FLT_EPSILON*50)
+ continue;
+
+ knife_project_v3(kcd, p, sp);
+ view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
+ mul_m4_v3(kcd->ob->imat, view);
+
+ sub_v3_v3v3(view, p, view);
+ normalize_v3(view);;
+
+ copy_v3_v3(no, view);
+ mul_v3_fl(no, -0.0003);
+
+ /*go backwards toward view a bit*/
+ add_v3_v3(p, no);
+
+ hitf = BMBVH_RayCast(bmtree, p, no, NULL);
+ for (ref2=kfe->faces.first; ref2; ref2=ref2->next) {
+ if (ref2->ref == hitf)
+ hitf = NULL;
+ }
+
+ if (!hitf && !BLI_smallhash_haskey(ehash, (intptr_t)kfe)) {
+ BMEdgeHit hit;
+
+ if (len_v3v3(p, kcd->vertco) < FLT_EPSILON*50 || len_v3v3(p, kcd->prevco) < FLT_EPSILON*50)
+ continue;
+
+ hit.kfe = kfe;
+ hit.v = NULL;
+
+ knife_find_basef(kcd, kfe);
+ hit.f = kfe->basef;
+
+ copy_v3_v3(hit.realhit, p);
+
+ if (kcd->snap_midpoints) {
+ add_v3_v3v3(hit.hit, kfe->v1->co, kfe->v2->co);
+ mul_v3_fl(hit.hit, 0.5f);
+ } else {
+ copy_v3_v3(hit.hit, p);
+ }
+ knife_project_v3(kcd, hit.hit, hit.schit);
+
+ BLI_array_append(edges, hit);
+ BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
+ }
+ }
+ }
+ }
+ }
+
+ if (results)
+ MEM_freeN(results);
+
+ *count = BLI_array_count(edges);
+ return edges;
+}
+
+void knife_bgl_get_mats(knifetool_opdata *kcd, bglMats *mats)
+{
+ bgl_get_mats(mats);
+ //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat);
+ //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
+}
+
+/*finds (visible) edges that intersects the current screen drag line*/
+static void knife_find_line_hits(knifetool_opdata *kcd)
+{
+ bglMats mats;
+ BMEdgeHit *e1, *e2;
+ SmallHash hash, *ehash = &hash;
+ float vec[3], v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3];
+ int i, c1, c2;
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ if (kcd->linehits) {
+ MEM_freeN(kcd->linehits);
+ kcd->linehits = NULL;
+ kcd->totlinehit = 0;
+ }
+
+ copy_v3_v3(v1, kcd->prevco);
+ copy_v3_v3(v2, kcd->vertco);
+
+ /*project screen line's 3d coordinates back into 2d*/
+ knife_project_v3(kcd, v1, s1);
+ knife_project_v3(kcd, v2, s2);
+
+ if (len_v2v2(s1, s2) < 1)
+ return;
+
+ /*unproject screen line*/
+ viewline(kcd->ar, kcd->vc.v3d, s1, v1, v3);
+ viewline(kcd->ar, kcd->vc.v3d, s2, v2, v4);
+
+ /*view3d_unproject(&mats, v1, s1[0], s1[1], 0.0f);
+ view3d_unproject(&mats, v2, s2[0], s2[1], 0.0f);
+ view3d_unproject(&mats, v3, s1[0], s1[1], 1.0f-FLT_EPSILON);
+ view3d_unproject(&mats, v4, s2[0], s2[1], 1.0f-FLT_EPSILON);*/
+
+ mul_m4_v3(kcd->ob->imat, v1);
+ mul_m4_v3(kcd->ob->imat, v2);
+ mul_m4_v3(kcd->ob->imat, v3);
+ mul_m4_v3(kcd->ob->imat, v4);
+
+ sub_v3_v3v3(vec, v2, v1);
+ normalize_v3(vec);
+ mul_v3_fl(vec, 0.01);
+ add_v3_v3(v1, vec);
+ add_v3_v3(v3, vec);
+
+ sub_v3_v3v3(vec, v4, v2);
+ normalize_v3(vec);
+ mul_v3_fl(vec, 0.01);
+ add_v3_v3(v4, vec);
+ add_v3_v3(v2, vec);
+
+ sub_v3_v3v3(view, v4, v1);
+ normalize_v3(view);
+
+ BLI_smallhash_init(ehash);
+
+ /*test two triangles of sceen line's plane*/
+ e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1);
+ e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, ehash, &mats, &c2);
+ if (c1 && c2) {
+ e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2));
+ memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2);
+ MEM_freeN(e2);
+ } else if (c2) {
+ e1 = e2;
+ }
+
+ kcd->linehits = e1;
+ kcd->totlinehit = c1+c2;
+
+ /*find position along screen line, used for sorting*/
+ for (i=0; i<kcd->totlinehit; i++) {
+ BMEdgeHit *lh = e1+i;
+
+ lh->l = len_v2v2(lh->schit, s1) / len_v2v2(s2, s1);
+ }
+
+ BLI_smallhash_release(ehash);
+}
+
+static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3], int *is_space)
+{
+ BMFace *f;
+ bglMats mats;
+ float origin[3], ray[3];
+ float mval[2], imat[3][3];
+ int dist = KMAXDIST;
+
+ knife_bgl_get_mats(kcd, &mats);
+
+ mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1];
+
+ /*unproject to find view ray*/
+ view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f);
+
+ sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]);
+ normalize_v3(ray);
+
+ /*transform into object space*/
+ invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
+ copy_m3_m4(imat, kcd->ob->obmat);
+ invert_m3(imat);
+
+ mul_m4_v3(kcd->ob->imat, origin);
+ mul_m3_v3(imat, ray);
+
+ copy_v3_v3(co, origin);
+ add_v3_v3(co, ray);
+
+ f = BMBVH_RayCast(kcd->bmbvh, origin, ray, co);
+
+ if (is_space)
+ *is_space = !f;
+
+ if (!f) {
+ /*try to use backbuffer selection method if ray casting failed*/
+ f = EDBM_findnearestface(&kcd->vc, &dist);
+
+ /*cheat for now; just put in the origin instead
+ of a true coordinate on the face*/
+ copy_v3_v3(co, origin);
+ add_v3_v3(co, ray);
+ }
+
+ return f;
+}
+
+/*find the 2d screen space density of vertices within a radius. used to scale snapping
+ distance for picking edges/verts.*/
+static int knife_sample_screen_density(knifetool_opdata *kcd, float radius)
+{
+ BMFace *f;
+ int is_space;
+ float co[3], sco[3];
+
+ f = knife_find_closest_face(kcd, co, &is_space);
+
+ if (f && !is_space) {
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float dis;
+ int c = 0;
+
+ knife_project_v3(kcd, co, sco);
+
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ int i;
+
+ for (i=0; i<2; i++) {
+ KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ dis = len_v2v2(kfv->sco, sco);
+ if (dis < radius) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ copy_v3_v3(vec, kfv->co);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ c++;
+ }
+ } else {
+ c++;
+ }
+ }
+ }
+ }
+
+ return c;
+ }
+
+ return 0;
+}
+
+/*returns snapping distance for edges/verts, scaled by the density of the
+ surrounding mesh (in screen space)*/
+static float knife_snap_size(knifetool_opdata *kcd, float maxsize)
+{
+ float density = (float)knife_sample_screen_density(kcd, maxsize*2.0f);
+
+ density = MAX2(density, 1);
+
+ return MIN2(maxsize / (density*0.5f), maxsize);
+}
+
+/*p is closest point on edge to the mouse cursor*/
+static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space)
+{
+ BMFace *f;
+ float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->ethresh);
+
+ if (kcd->ignore_vert_snapping)
+ maxdist *= 0.5;
+
+ f = knife_find_closest_face(kcd, co, NULL);
+ *is_space = !f;
+
+ /*set p to co, in case we don't find anything, means a face cut*/
+ copy_v3_v3(p, co);
+ kcd->curbmface = f;
+
+ if (f) {
+ KnifeEdge *cure = NULL;
+ ListBase *lst;
+ Ref *ref;
+ float dis, curdis=FLT_MAX;
+
+ knife_project_v3(kcd, co, sco);
+
+ /*look through all edges associated with this face*/
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+
+ /*project edge vertices into screen space*/
+ knife_project_v3(kcd, kfe->v1->co, kfe->v1->sco);
+ knife_project_v3(kcd, kfe->v2->co, kfe->v2->sco);
+
+ dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
+ if (dis < curdis && dis < maxdist) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float labda_PdistVL2Dfl(float *v1, float *v2, float *v3);
+ float labda= labda_PdistVL2Dfl(sco, kfe->v1->sco, kfe->v2->sco);
+ float vec[3];
+
+ vec[0]= kfe->v1->co[0] + labda*(kfe->v2->co[0] - kfe->v1->co[0]);
+ vec[1]= kfe->v1->co[1] + labda*(kfe->v2->co[1] - kfe->v1->co[1]);
+ vec[2]= kfe->v1->co[2] + labda*(kfe->v2->co[2] - kfe->v1->co[2]);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ cure = kfe;
+ curdis = dis;
+ }
+ } else {
+ cure = kfe;
+ curdis = dis;
+ }
+ }
+ }
+
+ if (fptr)
+ *fptr = f;
+
+ if (cure && p) {
+ float d;
+
+ if (!kcd->ignore_edge_snapping || !(cure->e)) {
+
+ closest_to_line_segment_v3(p, sco, cure->v1->sco, cure->v2->sco);
+ sub_v3_v3(p, cure->v1->sco);
+
+ if (kcd->snap_midpoints) {
+ d = 0.5f;
+ } else {
+ d = len_v3v3(cure->v1->sco, cure->v2->sco);
+ if (d != 0.0) {
+ d = len_v3(p) / d;
+ }
+ }
+
+ interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
+ } else {
+ return NULL;
+ }
+ }
+
+ return cure;
+ }
+
+ if (fptr)
+ *fptr = NULL;
+
+ return NULL;
+}
+
+/*find a vertex near the mouse cursor, if it exists*/
+static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMFace **fptr, int *is_space)
+{
+ BMFace *f;
+ float co[3], sco[3], maxdist = knife_snap_size(kcd, kcd->vthresh);
+
+ if (kcd->ignore_vert_snapping)
+ maxdist *= 0.5;
+
+ f = knife_find_closest_face(kcd, co, is_space);
+
+ /*set p to co, in case we don't find anything, means a face cut*/
+ copy_v3_v3(p, co);
+ kcd->curbmface = f;
+
+ if (f) {
+ ListBase *lst;
+ Ref *ref;
+ KnifeVert *curv = NULL;
+ float dis, curdis=FLT_MAX;
+
+ knife_project_v3(kcd, co, sco);
+
+ lst = knife_get_face_kedges(kcd, f);
+ for (ref=lst->first; ref; ref=ref->next) {
+ KnifeEdge *kfe = ref->ref;
+ int i;
+
+ for (i=0; i<2; i++) {
+ KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
+
+ knife_project_v3(kcd, kfv->co, kfv->sco);
+
+ dis = len_v2v2(kfv->sco, sco);
+ if (dis < curdis && dis < maxdist) {
+ if(kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float vec[3];
+
+ copy_v3_v3(vec, kfv->co);
+ mul_m4_v3(kcd->vc.obedit->obmat, vec);
+
+ if(view3d_test_clipping(kcd->vc.rv3d, vec, 1)==0) {
+ curv = kfv;
+ curdis = dis;
+ }
+ } else {
+ curv = kfv;
+ curdis = dis;
+ }
+ }
+ }
+ }
+
+ if (!kcd->ignore_vert_snapping || !(curv && curv->v)) {
+ if (fptr)
+ *fptr = f;
+
+ if (curv && p) {
+ copy_v3_v3(p, curv->co);
+ }
+
+ return curv;
+ } else {
+ if (fptr)
+ *fptr = f;
+
+ return NULL;
+ }
+ }
+
+ if (fptr)
+ *fptr = NULL;
+
+ return NULL;
+}
+
+/*update active knife edge/vert pointers*/
+static int knife_update_active(knifetool_opdata *kcd)
+{
+ kcd->curvert = NULL; kcd->curedge = NULL; kcd->curbmface = NULL;
+
+ kcd->curvert = knife_find_closest_vert(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space);
+ if (!kcd->curvert) {
+ kcd->curedge = knife_find_closest_edge(kcd, kcd->vertco, &kcd->curbmface, &kcd->is_space);
+ }
+
+ if (kcd->mode == MODE_DRAGGING) {
+ knife_find_line_hits(kcd);
+ }
+ return 1;
+}
+
+#define MARK 4
+#define DEL 8
+#define VERT_ON_EDGE 16
+#define VERT_ORIG 32
+#define FACE_FLIP 64
+#define BOUNDARY 128
+#define FACE_NEW 256
+
+typedef struct facenet_entry {
+ struct facenet_entry *next, *prev;
+ KnifeEdge *kfe;
+} facenet_entry;
+
+static void rnd_offset_co(float co[3], float scale)
+{
+ int i;
+
+ for (i=0; i<3; i++) {
+ co[i] += (BLI_drand()-0.5)*scale;
+ }
+}
+
+static void remerge_faces(knifetool_opdata *kcd)
+{
+ BMesh *bm = kcd->em->bm;
+ SmallHash svisit, *visit=&svisit;
+ BMIter iter;
+ BMFace *f;
+ BMFace **stack = NULL;
+ BLI_array_declare(stack);
+ BMFace **faces = NULL;
+ BLI_array_declare(faces);
+ BMOperator bmop;
+ int idx;
+
+ BMO_InitOpf(bm, &bmop, "beautify_fill faces=%ff constrain_edges=%fe", FACE_NEW, BOUNDARY);
+
+ BMO_Exec_Op(bm, &bmop);
+ BMO_Flag_Buffer(bm, &bmop, "geomout", FACE_NEW, BM_FACE);
+
+ BMO_Finish_Op(bm, &bmop);
+
+ BLI_smallhash_init(visit);
+ BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
+ BMIter eiter;
+ BMEdge *e;
+ BMFace *f2;
+
+ if (!BMO_TestFlag(bm, f, FACE_NEW))
+ continue;
+
+ if (BLI_smallhash_haskey(visit, (intptr_t)f))
+ continue;
+
+ BLI_array_empty(stack);
+ BLI_array_empty(faces);
+ BLI_array_append(stack, f);
+ BLI_smallhash_insert(visit, (intptr_t)f, NULL);
+
+ do {
+ f2 = BLI_array_pop(stack);
+
+ BLI_array_append(faces, f2);
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f2) {
+ BMIter fiter;
+ BMFace *f3;
+
+ if (BMO_TestFlag(bm, e, BOUNDARY))
+ continue;
+
+ BM_ITER(f3, &fiter, bm, BM_FACES_OF_EDGE, e) {
+ if (!BMO_TestFlag(bm, f3, FACE_NEW))
+ continue;
+ if (BLI_smallhash_haskey(visit, (intptr_t)f3))
+ continue;
+
+ BLI_smallhash_insert(visit, (intptr_t)f3, NULL);
+ BLI_array_append(stack, f3);
+ }
+ }
+ } while (BLI_array_count(stack) > 0);
+
+ if (BLI_array_count(faces) > 0) {
+ idx = BMINDEX_GET(faces[0]);
+
+ f2 = BM_Join_Faces(bm, faces, BLI_array_count(faces));
+ if (f2) {
+ BMO_SetFlag(bm, f2, FACE_NEW);
+ BMINDEX_SET(f2, idx);
+ }
+ }
+ }
+}
+
+/*use edgenet to fill faces. this is a bit annoying and convoluted.*/
+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, shash2, *hash = &shash, *visited = &shash2;
+ int i, j, k=0, totface=bm->totface;
+
+ BMO_push(bm, NULL);
+ bmesh_begin_edit(bm, BMOP_UNTAN_MULTIRES);
+
+ i = 0;
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMINDEX_SET(f, i);
+ faces[i] = f;
+ i++;
+ }
+
+ BM_ITER(e, &bmiter, bm, BM_EDGES_OF_MESH, NULL) {
+ BMO_SetFlag(bm, e, BOUNDARY);
+ }
+
+ /*turn knife verts into real verts, as necassary*/
+ BLI_mempool_iternew(kcd->kverts, &iter);
+ for (kfv=BLI_mempool_iterstep(&iter); kfv; kfv=BLI_mempool_iterstep(&iter)) {
+ if (!kfv->v) {
+ kfv->v = BM_Make_Vert(bm, kfv->co, NULL);
+ kfv->flag = 1;
+ BMO_SetFlag(bm, kfv->v, DEL);
+ } else {
+ kfv->flag = 0;
+ BMO_SetFlag(bm, kfv->v, VERT_ORIG);
+ }
+
+ BMO_SetFlag(bm, kfv->v, MARK);
+ }
+
+ /*we want to only do changed faces. first, go over new edges and add to
+ face net lists.*/
+ i=0; j=0; k=0;
+ BLI_mempool_iternew(kcd->kedges, &iter);
+ for (kfe=BLI_mempool_iterstep(&iter); kfe; kfe=BLI_mempool_iterstep(&iter)) {
+ Ref *ref;
+ if (!kfe->v1 || !kfe->v2 || kfe->v1->inspace || kfe->v2->inspace)
+ continue;
+
+ i++;
+
+ if (kfe->e && kfe->v1->v == kfe->e->v1 && kfe->v2->v == kfe->e->v2) {
+ kfe->oe = kfe->e;
+ continue;
+ }
+
+ j++;
+
+ if (kfe->e) {
+ kfe->oe = kfe->e;
+
+ BMO_SetFlag(bm, kfe->e, DEL);
+ BMO_ClearFlag(bm, kfe->e, BOUNDARY);
+ kfe->e = NULL;
+ }
+
+ kfe->e = BM_Make_Edge(bm, kfe->v1->v, kfe->v2->v, NULL, 1);
+ BMO_SetFlag(bm, kfe->e, BOUNDARY);
+
+ for (ref=kfe->faces.first; ref; ref=ref->next) {
+ f = ref->ref;
+
+ entry = BLI_memarena_alloc(arena, sizeof(*entry));
+ entry->kfe = kfe;
+ BLI_addtail(face_nets+BMINDEX_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_SetFlag(bm, kfe->e, BOUNDARY);
+ kfe->oe = kfe->e;
+
+ for (ref=kfe->faces.first; ref; ref=ref->next) {
+ f = ref->ref;
+
+ if (face_nets[BMINDEX_GET(f)].first) {
+ entry = BLI_memarena_alloc(arena, sizeof(*entry));
+ entry->kfe = kfe;
+ BLI_addtail(face_nets+BMINDEX_GET(f), entry);
+ }
+ }
+ }
+
+ for (i=0; i<totface; i++) {
+ EditFace *efa;
+ EditVert *eve, *lasteve;
+ int j;
+ float rndscale = FLT_EPSILON*25;
+
+ f = faces[i];
+ BLI_smallhash_init(hash);
+
+ if (face_nets[i].first)
+ BMO_SetFlag(bm, f, DEL);
+
+ BLI_begin_edgefill();
+
+ for (entry=face_nets[i].first; entry; entry=entry->next) {
+ if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v1)) {
+ eve = BLI_addfillvert(entry->kfe->v1->v->co);
+ eve->xs = 0;
+ rnd_offset_co(eve->co, rndscale);
+ eve->tmp.p = entry->kfe->v1->v;
+ BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v1, eve);
+ }
+
+ if (!BLI_smallhash_haskey(hash, (intptr_t)entry->kfe->v2)) {
+ eve = BLI_addfillvert(entry->kfe->v2->v->co);
+ eve->xs = 0;
+ rnd_offset_co(eve->co, rndscale);
+ eve->tmp.p = entry->kfe->v2->v;
+ BLI_smallhash_insert(hash, (intptr_t)entry->kfe->v2, eve);
+ }
+ }
+
+ for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) {
+ EditEdge *eed;
+
+ lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
+ eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
+
+ eve->xs++;
+ lasteve->xs++;
+ }
+
+ for (j=0, entry=face_nets[i].first; entry; entry=entry->next, j++) {
+ lasteve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v1);
+ eve = BLI_smallhash_lookup(hash, (intptr_t)entry->kfe->v2);
+
+ if (eve->xs > 1 && lasteve->xs > 1) {
+ BLI_addfilledge(lasteve, eve);
+
+ BMO_ClearFlag(bm, entry->kfe->e->v1, DEL);
+ BMO_ClearFlag(bm, entry->kfe->e->v2, DEL);
+ } else {
+ if (lasteve->xs < 2)
+ BLI_remlink(&fillvertbase, lasteve);
+ if (eve->xs < 2)
+ BLI_remlink(&fillvertbase, eve);
+ }
+ }
+
+ BLI_edgefill(0);
+
+ for (efa=fillfacebase.first; efa; efa=efa->next) {
+ BMVert *v1=efa->v3->tmp.p, *v2=efa->v2->tmp.p, *v3=efa->v1->tmp.p;
+ BMFace *f2;
+ BMLoop *l;
+ BMVert *verts[3] = {v1, v2, v3};
+
+ if (v1 == v2 || v2 == v3 || v1 == v3)
+ continue;
+ if (BM_Face_Exists(bm, verts, 3, &f2))
+ continue;
+
+ f2 = BM_Make_QuadTri(bm, v1, v2, v3, NULL, NULL, 0);
+ BMO_SetFlag(bm, f2, FACE_NEW);
+
+ l = bm_firstfaceloop(f2);
+ do {
+ BMO_ClearFlag(bm, l->e, DEL);
+ l = l->next;
+ } while (l != bm_firstfaceloop(f2));
+
+ BMO_ClearFlag(bm, f2, DEL);
+ BMINDEX_SET(f2, i);
+
+ BM_Face_UpdateNormal(bm, f2);
+ if (dot_v3v3(f->no, f2->no) < 0.0) {
+ BM_flip_normal(bm, f2);
+ }
+ }
+
+ BLI_end_edgefill();
+ BLI_smallhash_release(hash);
+ }
+
+ /* interpolate customdata */
+ BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+ BMLoop *l1;
+ BMFace *f2;
+ BMIter liter1;
+
+ if (!BMO_TestFlag(bm, f, FACE_NEW))
+ continue;
+
+ f2 = faces[BMINDEX_GET(f)];
+ if (BMINDEX_GET(f) < 0 || BMINDEX_GET(f) >= totface) {
+ printf("eek!!\n");
+ }
+
+ BM_Copy_Attributes(bm, bm, f2, f);
+
+ BM_ITER(l1, &liter1, bm, BM_LOOPS_OF_FACE, f) {
+ BM_loop_interp_from_face(bm, l1, f2, 1, 1);
+ }
+ }
+
+ /*merge triangles back into faces*/
+ remerge_faces(kcd);
+
+ /*delete left over faces*/
+ BMO_CallOpf(bm, "del geom=%ff context=%i", DEL, DEL_ONLYFACES);
+ BMO_CallOpf(bm, "del geom=%fe context=%i", DEL, DEL_EDGES);
+ BMO_CallOpf(bm, "del geom=%fv context=%i", DEL, DEL_VERTS);
+
+ if (face_nets)
+ MEM_freeN(face_nets);
+ if (faces)
+ MEM_freeN(faces);
+ BLI_memarena_free(arena);
+ BLI_smallhash_release(hash);
+
+ BMO_ClearStack(bm); /*remerge_faces sometimes raises errors, so make sure to clear them*/
+
+ bmesh_end_edit(bm, BMOP_UNTAN_MULTIRES);
+ BMO_pop(bm);
+}
+
+/*called on tool confirmation*/
+static void knifetool_finish(bContext *C, wmOperator *op)
+{
+ knifetool_opdata *kcd= op->customdata;
+
+ knifenet_fill_faces(kcd);
+
+ DAG_id_tag_update(kcd->ob->data, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_GEOM|ND_DATA, kcd->ob->data);
+}
+
+/*copied from paint_image.c*/
+static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+{
+ int orth= get_view3d_cliprange(v3d, rv3d, clipsta, clipend);
+
+ if (orth) { /* only needed for ortho */
+ float fac = 2.0f / ((*clipend) - (*clipsta));
+ *clipsta *= fac;
+ *clipend *= fac;
+ }
+
+ return orth;
+}
+
+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);
+ view3d_get_object_project_mat(ar->regiondata, kcd->ob, kcd->projmat);
+ //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->viewmat, kcd->vc.rv3d->winmat);
+
+ kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d,
+ &kcd->clipsta, &kcd->clipend);
+}
+
+/* called when modal loop selection is done... */
+static void knifetool_exit (bContext *C, wmOperator *op)
+{
+ knifetool_opdata *kcd= op->customdata;
+
+ if (!kcd)
+ return;
+
+ /* deactivate the extra drawing stuff in 3D-View */
+ ED_region_draw_cb_exit(kcd->ar->type, kcd->draw_handle);
+
+ /* free the custom data */
+ BLI_mempool_destroy(kcd->refs);
+ BLI_mempool_destroy(kcd->kverts);
+ BLI_mempool_destroy(kcd->kedges);
+
+ BLI_ghash_free(kcd->origedgemap, NULL, NULL);
+ BLI_ghash_free(kcd->origvertmap, NULL, NULL);
+ BLI_ghash_free(kcd->kedgefacemap, NULL, NULL);
+
+ BMBVH_FreeBVH(kcd->bmbvh);
+ BLI_memarena_free(kcd->arena);
+
+ /* tag for redraw */
+ ED_region_tag_redraw(kcd->ar);
+
+ /* destroy kcd itself */
+ MEM_freeN(kcd);
+ op->customdata= NULL;
+}
+
+/* called when modal loop selection gets set up... */
+static int knifetool_init (bContext *C, wmOperator *op, int do_cut)
+{
+ knifetool_opdata *kcd;
+
+ /* alloc new customdata */
+ kcd= op->customdata= MEM_callocN(sizeof(knifetool_opdata), "knifetool Modal Op Data");
+
+ /* assign the drawing handle for drawing preview line... */
+ kcd->ar= CTX_wm_region(C);
+ kcd->C = C;
+ kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
+ em_setup_viewcontext(C, &kcd->vc);
+
+ kcd->ob = CTX_data_edit_object(C);
+ kcd->em= ((Mesh *)kcd->ob->data)->edit_btmesh;
+ kcd->bmbvh = BMBVH_NewBVH(kcd->em);
+ kcd->arena = BLI_memarena_new(1<<15, "knife");
+ kcd->vthresh = KMAXDIST-1;
+ kcd->ethresh = KMAXDIST;
+
+ knife_recalc_projmat(kcd);
+
+ ED_region_tag_redraw(kcd->ar);
+
+ kcd->refs = BLI_mempool_create(sizeof(Ref), 1, 2048, 0, 0);
+ kcd->kverts = BLI_mempool_create(sizeof(KnifeVert), 1, 512, 0, 1);
+ kcd->kedges = BLI_mempool_create(sizeof(KnifeEdge), 1, 512, 0, 1);
+
+ kcd->origedgemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origedgemap");
+ kcd->origvertmap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
+ kcd->kedgefacemap = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife origvertmap");
+
+ return 1;
+}
+
+static int knifetool_cancel (bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ knifetool_exit(C, op);
+ return OPERATOR_CANCELLED;
+}
+
+static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt)
+{
+ knifetool_opdata *kcd;
+
+ view3d_operator_needs_opengl(C);
+
+ if (!knifetool_init(C, op, 0))
+ return OPERATOR_CANCELLED;
+
+ /* add a modal handler for this operator - handles loop selection */
+ WM_event_add_modal_handler(C, op);
+
+ kcd = op->customdata;
+ kcd->vc.mval[0] = evt->mval[0];
+ kcd->vc.mval[1] = evt->mval[1];
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+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)
+ return OPERATOR_FINISHED;
+
+ view3d_operator_needs_opengl(C);
+
+ if (kcd->mode == MODE_PANNING)
+ kcd->mode = kcd->prevmode;
+
+ kcd->snap_midpoints = event->ctrl;
+ kcd->ignore_vert_snapping = kcd->ignore_edge_snapping = event->shift;
+
+ switch (event->type) {
+ case ESCKEY:
+ case RETKEY: /* confirm */ // XXX hardcoded
+ if (event->val == KM_RELEASE) {
+ if (kcd->mode == MODE_DRAGGING && event->type == ESCKEY) {
+ kcd->mode = MODE_IDLE;
+ ED_region_tag_redraw(kcd->ar);
+ } else {
+ /* finish */
+ ED_region_tag_redraw(kcd->ar);
+
+ knifetool_finish(C, op);
+ knifetool_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ ED_region_tag_redraw(kcd->ar);
+ return OPERATOR_RUNNING_MODAL;
+
+ 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 LEFTMOUSE:
+ knife_recalc_projmat(kcd);
+ if (event->val != KM_RELEASE)
+ break;
+
+ 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);
+ return OPERATOR_RUNNING_MODAL;
+
+ case EKEY:
+ kcd->extend = event->val!=KM_RELEASE;
+ return OPERATOR_RUNNING_MODAL;
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ case MOUSEMOVE: /* mouse moved somewhere to select another loop */
+ if (kcd->mode != MODE_PANNING) {
+ knife_recalc_projmat(kcd);
+ kcd->vc.mval[0] = event->mval[0];
+ kcd->vc.mval[1] = event->mval[1];
+
+ if (knife_update_active(kcd))
+ ED_region_tag_redraw(kcd->ar);
+ }
+
+ break;
+ }
+
+ /* keep going until the user confirms */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void MESH_OT_knifetool (wmOperatorType *ot)
+{
+ /* description */
+ ot->name= "Knife Topology Tool";
+ ot->idname= "MESH_OT_knifetool";
+ ot->description= "Cut new topology";
+
+ /* callbacks */
+ ot->invoke= knifetool_invoke;
+ ot->modal= knifetool_modal;
+ ot->cancel= knifetool_cancel;
+ ot->poll= ED_operator_editmesh_view3d;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
+}
diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c
index 0ec356a88ae..6c6d4e3bd4a 100644
--- a/source/blender/editors/mesh/loopcut.c
+++ b/source/blender/editors/mesh/loopcut.c
@@ -15,7 +15,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
@@ -32,6 +32,8 @@
#include <float.h>
+#define _USE_MATH_DEFINES
+#include <math.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
@@ -50,7 +52,7 @@
#include "BLI_blenlib.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
#include "BLI_editVert.h"
-#include "BLI_math.h"
+#include "BLI_array.h"
#include "BLI_utildefines.h"
#include "BKE_blender.h"
@@ -61,6 +63,8 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_array_mallocn.h"
+#include "BKE_tessmesh.h"
+#include "BKE_depsgraph.h"
#include "BIF_gl.h"
#include "BIF_glutil.h" /* for paint cursor */
@@ -95,11 +99,14 @@ typedef struct tringselOpData {
ViewContext vc;
Object *ob;
- EditMesh *em;
- EditEdge *eed;
+ BMEditMesh *em;
+ BMEdge *eed;
int extend;
int do_cut;
+
+ double leftmouse_time;
+ wmTimer *timer;
} tringselOpData;
/* modal loop selection drawing callback */
@@ -130,17 +137,62 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
}
}
+/*given two opposite edges in a face, finds the ordering of their vertices so
+ that cut preview lines won't cross each other*/
+static void edgering_find_order(BMEditMesh *em, BMEdge *lasteed, BMEdge *eed,
+ BMVert *lastv1, BMVert *v[2][2])
+{
+ BMIter liter;
+ BMLoop *l, *l2;
+ int rev;
+
+ l = eed->l;
+
+ /*find correct order for v[1]*/
+ if (!(BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))) {
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_LOOP, l) {
+ if (BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))
+ break;
+ }
+ }
+
+ /*this should never happen*/
+ if (!l) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ v[1][0] = lasteed->v1;
+ v[1][1] = lasteed->v2;
+ return;
+ }
+
+ l2 = BM_OtherFaceLoop(l->e, l->f, eed->v1);
+ rev = (l2 == (BMLoop*)l->prev);
+ while (l2->v != lasteed->v1 && l2->v != lasteed->v2) {
+ l2 = rev ? (BMLoop*)l2->prev : (BMLoop*)l2->next;
+ }
+
+ if (l2->v == lastv1) {
+ v[0][0] = eed->v1;
+ v[0][1] = eed->v2;
+ } else {
+ v[0][0] = eed->v2;
+ v[0][1] = eed->v1;
+ }
+}
+
static void edgering_sel(tringselOpData *lcd, int previewlines, int select)
{
- EditMesh *em = lcd->em;
- EditEdge *startedge = lcd->eed;
- EditEdge *eed;
- EditFace *efa;
- EditVert *v[2][2];
+ BMEditMesh *em = lcd->em;
+ BMEdge *startedge = lcd->eed;
+ BMEdge *eed, *lasteed;
+ BMVert *v[2][2], *lastv1;
+ BMWalker walker;
float (*edges)[2][3] = NULL;
- V_DYNDECLARE(edges);
+ BLI_array_declare(edges);
float co[2][3];
- int looking=1, i, tot=0;
+ int i, tot=0;
+
+ memset(v, 0, sizeof(v));
if (!startedge)
return;
@@ -152,110 +204,81 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select)
}
if (!lcd->extend) {
- EM_clear_flag_all(lcd->em, SELECT);
+ EDBM_clear_flag_all(lcd->em, BM_SELECT);
}
- /* in eed->f1 we put the valence (amount of faces in edge) */
- /* in eed->f2 we put tagged flag as correct loop */
- /* in efa->f1 we put tagged flag as correct to select */
+ if (select) {
+ BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0);
+ eed = BMW_Begin(&walker, startedge);
+ for (; eed; eed=BMW_Step(&walker)) {
+ BM_Select(em->bm, eed, 1);
+ }
+ BMW_End(&walker);
- for(eed= em->edges.first; eed; eed= eed->next) {
- eed->f1= 0;
- eed->f2= 0;
+ return;
}
- for(efa= em->faces.first; efa; efa= efa->next) {
- efa->f1= 0;
- if(efa->h==0) {
- efa->e1->f1++;
- efa->e2->f1++;
- efa->e3->f1++;
- if(efa->e4) efa->e4->f1++;
- }
- }
-
- // tag startedge OK
- startedge->f2= 1;
-
- while(looking) {
- looking= 0;
-
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
- if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
-
- // if edge tagged, select opposing edge and mark face ok
- if(efa->e1->f2) {
- efa->e3->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- else if(efa->e2->f2) {
- efa->e4->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e3->f2) {
- efa->e1->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- if(efa->e4->f2) {
- efa->e2->f2= 1;
- efa->f1= 1;
- looking= 1;
- }
- }
+ BMW_Init(&walker, em->bm, BMW_EDGERING, 0, 0);
+ eed = startedge = BMW_Begin(&walker, startedge);
+ lastv1 = NULL;
+ for (lasteed=NULL; eed; eed=BMW_Step(&walker)) {
+ if (lasteed) {
+ if (lastv1) {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
+ } else {
+ v[1][0] = lasteed->v1;
+ v[1][1] = lasteed->v2;
+ lastv1 = lasteed->v1;
+ }
+
+ edgering_find_order(em, lasteed, eed, lastv1, v);
+ lastv1 = v[0][0];
+
+ for(i=1;i<=previewlines;i++){
+ co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
+ co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
+ co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
+
+ co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
+ co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
+ co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
+
+ BLI_array_growone(edges);
+ VECCOPY(edges[tot][0], co[0]);
+ VECCOPY(edges[tot][1], co[1]);
+ tot++;
}
}
+ lasteed = eed;
}
- if(previewlines > 0 && !select){
- for(efa= em->faces.first; efa; efa= efa->next) {
- if(efa->v4 == NULL) { continue; }
- if(efa->h == 0){
- if(efa->e1->f2 == 1){
- if(efa->e1->h == 1 || efa->e3->h == 1 )
- continue;
-
- v[0][0] = efa->v1;
- v[0][1] = efa->v2;
- v[1][0] = efa->v4;
- v[1][1] = efa->v3;
- } else if(efa->e2->f2 == 1){
- if(efa->e2->h == 1 || efa->e4->h == 1)
- continue;
- v[0][0] = efa->v2;
- v[0][1] = efa->v3;
- v[1][0] = efa->v1;
- v[1][1] = efa->v4;
- } else { continue; }
-
- for(i=1;i<=previewlines;i++){
- co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
- co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
- co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
-
- co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
- co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
- co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
-
- V_GROW(edges);
- VECCOPY(edges[tot][0], co[0]);
- VECCOPY(edges[tot][1], co[1]);
- tot++;
- }
- }
- }
- } else {
- select = (startedge->f & SELECT) == 0;
+ if (BM_Edge_Share_Faces(lasteed, startedge)) {
+ v[1][0] = v[0][0];
+ v[1][1] = v[0][1];
- /* select the edges */
- for(eed= em->edges.first; eed; eed= eed->next) {
- if(eed->f2) EM_select_edge(eed, select);
+ 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];
+
+ co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
+ co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
+ co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
+
+ BLI_array_growone(edges);
+ VECCOPY(edges[tot][0], co[0]);
+ VECCOPY(edges[tot][1], co[1]);
+ tot++;
}
}
+ BMW_End(&walker);
lcd->edges = edges;
lcd->totedge = tot;
}
@@ -265,7 +288,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 +298,18 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts)
static void ringsel_finish(bContext *C, wmOperator *op)
{
tringselOpData *lcd= op->customdata;
- int cuts= (lcd->do_cut)? RNA_int_get(op->ptr,"number_cuts"): 0;
+ int cuts= RNA_int_get(op->ptr, "number_cuts");
if (lcd->eed) {
- EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data);
-
+ BMEditMesh *em = lcd->em;
+
edgering_sel(lcd, cuts, 1);
if (lcd->do_cut) {
-
- esubdivideflag(lcd->ob, em, SELECT, 0.0f, 0.0f, 0, cuts, 0, SUBDIV_SELECT_LOOPCUT);
-
+ BM_esubdivideflag(lcd->ob, em->bm, BM_SELECT, 0.0f,
+ 0.0f, 0, cuts, SUBDIV_SELECT_LOOPCUT,
+ SUBD_PATH, 0, 0, 0);
+
/* force edge slide to edge select mode in in face select mode */
if (em->selectmode & SCE_SELECT_FACE) {
if (em->selectmode == SCE_SELECT_FACE)
@@ -292,33 +317,38 @@ static void ringsel_finish(bContext *C, wmOperator *op)
else
em->selectmode &= ~SCE_SELECT_FACE;
CTX_data_tool_settings(C)->selectmode= em->selectmode;
- EM_selectmode_set(em);
+ EDBM_selectmode_set(em);
+
+ WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C));
WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C));
}
-
+
+ WM_event_add_notifier(C, NC_GEOM|ND_SELECT|ND_DATA, lcd->ob->data);
DAG_id_tag_update(lcd->ob->data, 0);
- WM_event_add_notifier(C, NC_GEOM|ND_DATA, lcd->ob->data);
}
else {
/* sets as active, useful for other tools */
if(em->selectmode & SCE_SELECT_VERTEX)
- EM_store_selection(em, lcd->eed->v1, EDITVERT);
+ EDBM_selectmode_flush(em);
if(em->selectmode & SCE_SELECT_EDGE)
- EM_store_selection(em, lcd->eed, EDITEDGE);
+ EDBM_selectmode_flush(em);
- EM_selectmode_flush(lcd->em);
+ EDBM_selectmode_flush(lcd->em);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, lcd->ob->data);
}
}
}
/* called when modal loop selection is done... */
-static void ringsel_exit(wmOperator *op)
+static void ringsel_exit(bContext *C, wmOperator *op)
{
tringselOpData *lcd= op->customdata;
-
+
+ if (lcd->timer)
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), lcd->timer);
+
/* deactivate the extra drawing stuff in 3D-View */
ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle);
@@ -344,7 +374,7 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut)
lcd->ar= CTX_wm_region(C);
lcd->draw_handle= ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW);
lcd->ob = CTX_data_edit_object(C);
- lcd->em= BKE_mesh_get_editmesh((Mesh *)lcd->ob->data);
+ lcd->em= ((Mesh *)lcd->ob->data)->edit_btmesh;
lcd->extend = do_cut ? 0 : RNA_boolean_get(op->ptr, "extend");
lcd->do_cut = do_cut;
em_setup_viewcontext(C, &lcd->vc);
@@ -354,17 +384,17 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut)
return 1;
}
-static int ringcut_cancel (bContext *UNUSED(C), wmOperator *op)
+static int ringcut_cancel (bContext *C, wmOperator *op)
{
/* this is just a wrapper around exit() */
- ringsel_exit(op);
+ ringsel_exit(C, op);
return OPERATOR_CANCELLED;
}
static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
{
tringselOpData *lcd;
- EditEdge *edge;
+ BMEdge *edge;
int dist = 75;
view3d_operator_needs_opengl(C);
@@ -375,7 +405,7 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
lcd = op->customdata;
if (lcd->em->selectmode == SCE_SELECT_FACE) {
- ringsel_exit(op);
+ ringsel_exit(C, op);
WM_operator_name_call(C, "MESH_OT_loop_select", WM_OP_INVOKE_REGION_WIN, NULL);
return OPERATOR_CANCELLED;
}
@@ -383,17 +413,13 @@ static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt)
lcd->vc.mval[0] = evt->mval[0];
lcd->vc.mval[1] = evt->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
- if(!edge) {
- ringsel_exit(op);
- return OPERATOR_CANCELLED;
- }
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
lcd->eed = edge;
+
ringsel_find_edge(lcd, 1);
-
ringsel_finish(C, op);
- ringsel_exit(op);
+ ringsel_exit(C, op);
return OPERATOR_FINISHED;
}
@@ -402,9 +428,13 @@ 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 we're in the cut-n-slide macro, set release_confirm based on user pref*/
+ if (op->opm)
+ RNA_boolean_set(op->next->ptr, "release_confirm", U.loopcut_finish_on_release);
+
if(modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit))
BKE_report(op->reports, RPT_WARNING, "Loop cut doesn't work well on deformed edit mesh display");
@@ -420,7 +450,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt)
lcd->vc.mval[0] = evt->mval[0];
lcd->vc.mval[1] = evt->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
if (edge != lcd->eed) {
lcd->eed = edge;
ringsel_find_edge(lcd, 1);
@@ -430,30 +460,49 @@ 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) {
+ if (event->val == KM_RELEASE) {
/* 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;
+ return OPERATOR_FINISHED|OPERATOR_ABORT_MACRO;
+ } else {
+ lcd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER2, 0.12);
}
ED_region_tag_redraw(lcd->ar);
break;
+ case TIMER2:
+ /* finish */
+ ED_region_tag_redraw(lcd->ar);
+
+ ringsel_finish(C, op);
+ ringsel_exit(C, op);
+
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+
+ return OPERATOR_FINISHED;
+
case RIGHTMOUSE: /* abort */ // XXX hardcoded
+ ED_region_tag_redraw(lcd->ar);
+ ringsel_exit(C, op);
+ ED_area_headerprint(CTX_wm_area(C), NULL);
+
+ return OPERATOR_FINISHED;
case ESCKEY:
if (event->val == KM_RELEASE) {
/* cancel */
@@ -465,33 +514,35 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event)
ED_region_tag_redraw(lcd->ar);
break;
- case WHEELUPMOUSE: /* change number of cuts */
case PAGEUPKEY:
- if (event->val == KM_PRESS) {
- cuts++;
- RNA_int_set(op->ptr, "number_cuts",cuts);
- ringsel_find_edge(lcd, cuts);
-
- ED_region_tag_redraw(lcd->ar);
- }
+ case WHEELUPMOUSE: /* change number of cuts */
+ if (event->val == KM_RELEASE)
+ break;
+
+ cuts++;
+ RNA_int_set(op->ptr,"number_cuts",cuts);
+ ringsel_find_edge(lcd, cuts);
+
+ ED_region_tag_redraw(lcd->ar);
break;
- case WHEELDOWNMOUSE: /* change number of cuts */
case PAGEDOWNKEY:
- if (event->val == KM_PRESS) {
- cuts=MAX2(cuts-1,1);
- RNA_int_set(op->ptr,"number_cuts",cuts);
- ringsel_find_edge(lcd, cuts);
-
- ED_region_tag_redraw(lcd->ar);
- }
+ case WHEELDOWNMOUSE: /* change number of cuts */
+ if (event->val == KM_RELEASE)
+ break;
+
+ cuts=MAX2(cuts-1,1);
+ RNA_int_set(op->ptr,"number_cuts",cuts);
+ ringsel_find_edge(lcd, cuts);
+
+ ED_region_tag_redraw(lcd->ar);
break;
case MOUSEMOVE: { /* mouse moved somewhere to select another loop */
int dist = 75;
- EditEdge *edge;
+ BMEdge *edge;
lcd->vc.mval[0] = event->mval[0];
lcd->vc.mval[1] = event->mval[1];
- edge = findnearestedge(&lcd->vc, &dist);
+ edge = EDBM_findnearestedge(&lcd->vc, &dist);
if (edge != lcd->eed) {
lcd->eed = edge;
@@ -529,11 +580,11 @@ void MESH_OT_loopcut (wmOperatorType *ot)
/* description */
ot->name= "Loop Cut";
ot->idname= "MESH_OT_loopcut";
- ot->description= "Add a new loop between existing loops";
+ ot->description= "Add a new loop between existing loops.";
/* callbacks */
ot->invoke= ringcut_invoke;
- ot->modal= ringcut_modal;
+ ot->modal= loopcut_modal;
ot->cancel= ringcut_cancel;
ot->poll= ED_operator_editmesh_region_view3d;
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index f3e26cfee36..b6c6570e27d 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -56,6 +56,7 @@
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -72,15 +73,27 @@
#include "mesh_intern.h"
+#define GET_CD_DATA(me, data) (me->edit_btmesh ? &me->edit_btmesh->bm->data : &me->data)
+
static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
{
Mesh *me = ob->data;
- CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
+ CustomData *data;
void *actlayerdata, *rndlayerdata, *clonelayerdata, *stencillayerdata, *layerdata=layer->data;
int type= layer->type;
- int index= CustomData_get_layer_index(data, type);
- int i, actindex, rndindex, cloneindex, stencilindex;
+ int index;
+ int i, actindex, rndindex, cloneindex, stencilindex, tot;
+
+ if (layer->type == CD_MLOOPCOL || layer->type == CD_MLOOPUV) {
+ data = (me->edit_btmesh)? &me->edit_btmesh->bm->ldata: &me->ldata;
+ tot = me->totloop;
+ } else {
+ data = (me->edit_btmesh)? &me->edit_btmesh->bm->pdata: &me->pdata;
+ tot = me->totpoly;
+ }
+ index = CustomData_get_layer_index(data, type);
+
/* ok, deleting a non-active layer needs to preserve the active layer indices.
to do this, we store a pointer to the .data member of both layer and the active layer,
(to detect if we're deleting the active layer or not), then use the active
@@ -94,15 +107,15 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la
stencillayerdata = data->layers[CustomData_get_stencil_layer_index(data, type)].data;
CustomData_set_layer_active(data, type, layer - &data->layers[index]);
- if(me->edit_mesh) {
- EM_free_data_layer(me->edit_mesh, data, type);
+ if(me->edit_btmesh) {
+ BM_free_data_layer(me->edit_btmesh->bm, data, type);
}
else {
- CustomData_free_layer_active(data, type, me->totface);
+ CustomData_free_layer_active(data, type, tot);
mesh_update_customdata_pointers(me);
}
- if(!CustomData_has_layer(data, type) && (type == CD_MCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
+ if(!CustomData_has_layer(data, type) && (type == CD_MLOOPCOL && (ob->mode & OB_MODE_VERTEX_PAINT)))
ED_object_toggle_modes(C, OB_MODE_VERTEX_PAINT);
/* reconstruct active layer */
@@ -176,37 +189,48 @@ static void copy_editface_active_customdata(EditMesh *em, int type, int index)
int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_set)
{
- EditMesh *em;
+ BMEditMesh *em;
int layernum;
- if(me->edit_mesh) {
- em= me->edit_mesh;
+ if(me->edit_btmesh) {
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return 0;
- EM_add_data_layer(em, &em->fdata, CD_MTFACE, name);
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
if(layernum) /* copy data from active UV */
copy_editface_active_customdata(em, CD_MTFACE, layernum);
if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
+ CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
+
+ BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
+ if(active_set || layernum==0)
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPUV, layernum);
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ layernum= CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
if(layernum >= MAX_MTFACE)
return 0;
- if(me->mtface)
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DUPLICATE, me->mtface, me->totface, name);
- else
- CustomData_add_layer_named(&me->fdata, CD_MTFACE, CD_DEFAULT, NULL, me->totface, name);
-
- if(active_set || layernum==0)
- CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
-
+ if(me->mtpoly) {
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DUPLICATE, me->mtpoly, me->totpoly, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DUPLICATE, me->mloopuv, me->totloop, name);
+ } else {
+ CustomData_add_layer_named(&me->pdata, CD_MTEXPOLY, CD_DEFAULT, NULL, me->totpoly, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPUV, CD_DEFAULT, NULL, me->totloop, name);
+ }
+
+ if(active_set || layernum==0) {
+ CustomData_set_layer_active(&me->pdata, CD_MTEXPOLY, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, layernum);
+ }
+
mesh_update_customdata_pointers(me);
}
@@ -218,63 +242,73 @@ 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);
return 1;
}
-int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me, const char *name, int active_set)
+int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mesh *me, const char *name, int active_set)
{
- EditMesh *em;
- MCol *mcol;
+ BMEditMesh *em;
+ MLoopCol *mcol;
int layernum;
- if(me->edit_mesh) {
- em= me->edit_mesh;
+ if(me->edit_btmesh) {
+ em= me->edit_btmesh;
- layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
+ layernum= CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
if(layernum >= MAX_MCOL)
return 0;
- EM_add_data_layer(em, &em->fdata, CD_MCOL, name);
+ BM_add_data_layer(em->bm, &em->bm->pdata, CD_MLOOPCOL);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
+
if(layernum) /* copy data from active vertex color layer */
copy_editface_active_customdata(em, CD_MCOL, layernum);
if(active_set || layernum==0)
- CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
+ CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
+
}
else {
- layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
- if(layernum >= MAX_MCOL)
+ layernum= CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
+ if(layernum >= CD_MLOOPCOL)
return 0;
- mcol= me->mcol;
+ mcol= me->mloopcol;
- if(me->mcol)
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DUPLICATE, me->mcol, me->totface, name);
+ if(me->mloopcol)
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DUPLICATE, me->mloopcol, me->totloop, name);
else
- CustomData_add_layer_named(&me->fdata, CD_MCOL, CD_DEFAULT, NULL, me->totface, name);
+ CustomData_add_layer_named(&me->ldata, CD_MLOOPCOL, CD_DEFAULT, NULL, me->totloop, name);
if(active_set || layernum==0)
- CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+ CustomData_set_layer_active(&me->ldata, CD_MLOOPCOL, layernum);
mesh_update_customdata_pointers(me);
+ /*BMESH_TODO
if(!mcol)
shadeMeshMCol(scene, ob, me);
+ */
}
DAG_id_tag_update(&me->id, 0);
@@ -285,12 +319,11 @@ int ED_mesh_color_add(bContext *C, Scene *scene, Object *ob, Mesh *me, const cha
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;
@@ -371,25 +404,25 @@ static int drop_named_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_CANCELLED;
}
- /* turn mesh in editmode */
- /* BKE_mesh_get/end_editmesh: ED_uvedit_assign_image also calls this */
+ /* put mesh in editmode */
obedit= base->object;
me= obedit->data;
- if(me->edit_mesh==NULL) {
- make_editMesh(scene, obedit);
+ if(me->edit_btmesh==NULL) {
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, obedit);
exitmode= 1;
}
- if(me->edit_mesh==NULL)
+
+ if(me->edit_btmesh==NULL)
return OPERATOR_CANCELLED;
ED_uvedit_assign_image(scene, obedit, ima, NULL);
if(exitmode) {
- load_editMesh(scene, obedit);
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_LoadEditBMesh(scene, obedit);
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
}
/* dummie drop support; ensure view shows a result :) */
@@ -575,7 +608,7 @@ void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges)
if(calc_edges || (mesh->totface && mesh->totedge == 0))
BKE_mesh_calc_edges(mesh, calc_edges);
- mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
+ mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL);
DAG_id_tag_update(&mesh->id, 0);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, mesh);
@@ -611,15 +644,15 @@ static void mesh_add_verts(Mesh *mesh, int len)
mesh->totvert= totvert;
}
-void ED_mesh_transform(Mesh *me, float *mat)
+void ED_mesh_transform(Mesh *mesh, float *mat)
{
int i;
- MVert *mvert= me->mvert;
+ MVert *mvert= mesh->mvert;
- for(i= 0; i < me->totvert; i++, mvert++)
+ for(i= 0; i < mesh->totvert; i++, mvert++)
mul_m4_v3((float (*)[4])mat, mvert->co);
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL);
}
static void mesh_add_edges(Mesh *mesh, int len)
@@ -685,7 +718,7 @@ static void mesh_add_faces(Mesh *mesh, int len)
/*
void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges, int faces)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add geometry in edit mode.");
return;
}
@@ -701,19 +734,18 @@ void ED_mesh_geometry_add(Mesh *mesh, ReportList *reports, int verts, int edges,
void ED_mesh_faces_add(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add faces in edit mode.");
return;
}
-
mesh_add_faces(mesh, count);
}
void ED_mesh_edges_add(Mesh *mesh, ReportList *reports, int count)
{
- if(mesh->edit_mesh) {
+ if(mesh->edit_btmesh) {
BKE_report(reports, RPT_ERROR, "Can't add edges in edit mode.");
- return;
+ return;
}
mesh_add_edges(mesh, count);
@@ -721,7 +753,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;
}
@@ -729,7 +761,8 @@ void ED_mesh_vertices_add(Mesh *mesh, ReportList *reports, int count)
mesh_add_verts(mesh, count);
}
-void ED_mesh_calc_normals(Mesh *me)
+void ED_mesh_calc_normals(Mesh *mesh)
{
- mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, NULL, 0, NULL, NULL);
}
+
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 4d620424b0a..3af641c222d 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -37,15 +37,67 @@
#ifndef MESH_INTERN_H
#define MESH_INTERN_H
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_tessmesh.h"
+
+#include "BLI_editVert.h"
+
+#include "RNA_types.h"
+
struct bContext;
struct wmOperatorType;
+struct ViewContext;
+struct BMEditMesh;
+struct BMesh;
+struct BMEdge;
+struct BMFace;
struct wmOperator;
+/* ******************** bmeshutils.c */
+
+/*
+ok: the EDBM module is for editmode bmesh stuff. in contrast, the
+ BMEdit module is for code shared with blenkernel that concerns
+ the BMEditMesh structure.
+*/
+
+/*calls a bmesh op, reporting errors to the user, etc*/
+int EDBM_CallOpf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt, ...);
+
+/*calls a bmesh op, reporting errors to the user, etc.
+
+ selects an output slot specified by selslot*/
+//int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op, char *selslot, char *fmt, ...);
+//moved to ED_mesh.h
+
+/*same as above, but doesn't report errors.*/
+int EDBM_CallOpfSilent(struct BMEditMesh *em, const char *fmt, ...);
+
+/*these next two functions are the split version of EDBM_CallOpf, so you can
+ do stuff with a bmesh operator, after initializing it but before executing
+ it.
+
+ execute the operator with BM_Exec_Op*/
+int EDBM_InitOpf(struct BMEditMesh *em, struct BMOperator *bmop,
+ struct wmOperator *op, const char *fmt, ...);
+/*cleans up after a bmesh operator*/
+int EDBM_FinishOp(struct BMEditMesh *em, struct BMOperator *bmop,
+ struct wmOperator *op, int report);
+
+void EDBM_clear_flag_all(struct BMEditMesh *em, int flag);
+void EDBM_store_selection(struct BMEditMesh *em, void *data);
+void EDBM_validate_selections(struct BMEditMesh *em);
+void EDBM_remove_selection(struct BMEditMesh *em, void *data);
+void EDBM_stats_update(struct BMEditMesh *em);
+
/* ******************** editface.c */
-int edgetag_context_check(Scene *scene, EditEdge *eed);
-void edgetag_context_set(Scene *scene, EditEdge *eed, int val);
-int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target);
+int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *eed);
+void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *eed, int val);
+int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target);
/* ******************* editmesh.c */
@@ -53,6 +105,10 @@ extern void free_editvert(EditMesh *em, EditVert *eve);
extern void free_editedge(EditMesh *em, EditEdge *eed);
extern void free_editface(EditMesh *em, EditFace *efa);
+/*frees dst mesh, then copies the contents of
+ *src (the struct) to dst. */
+void set_editMesh(EditMesh *dst, EditMesh *src);
+
extern void free_vertlist(EditMesh *em, ListBase *edve);
extern void free_edgelist(EditMesh *em, ListBase *lb);
extern void free_facelist(EditMesh *em, ListBase *lb);
@@ -64,7 +120,7 @@ extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct Ed
extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges);
extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2);
-void em_setup_viewcontext(struct bContext *C, ViewContext *vc);
+void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc);
void MESH_OT_separate(struct wmOperatorType *ot);
@@ -136,19 +192,22 @@ extern struct EditFace *EM_face_from_faces(EditMesh *em, struct EditFace *efa1,
extern int EM_view3d_poll(struct bContext *C);
-/* ******************* editmesh_loop.c */
+/* ******************* knifetool.c */
void MESH_OT_knife_cut(struct wmOperatorType *ot);
-/* ******************* editmesh_mods.c */
+/* ******************* bmesh_select.c */
void MESH_OT_loop_select(struct wmOperatorType *ot);
void MESH_OT_select_all(struct wmOperatorType *ot);
+void MESH_OT_bmesh_test(struct wmOperatorType *ot);
void MESH_OT_select_more(struct wmOperatorType *ot);
void MESH_OT_select_less(struct wmOperatorType *ot);
void MESH_OT_select_inverse(struct wmOperatorType *ot);
void MESH_OT_select_non_manifold(struct wmOperatorType *ot);
void MESH_OT_select_linked(struct wmOperatorType *ot);
void MESH_OT_select_linked_pick(struct wmOperatorType *ot);
+void MESH_OT_pin(struct wmOperatorType *ot);
+void MESH_OT_unpin(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);
@@ -167,29 +226,8 @@ void MESH_OT_noise(struct wmOperatorType *ot);
void MESH_OT_flip_normals(struct wmOperatorType *ot);
void MESH_OT_solidify(struct wmOperatorType *ot);
void MESH_OT_select_nth(struct wmOperatorType *ot);
-
-
-extern EditEdge *findnearestedge(ViewContext *vc, int *dist);
-void editmesh_select_by_material(EditMesh *em, int index);
-void EM_recalc_normal_direction(EditMesh *em, int inside, int select); /* makes faces righthand turning */
-void EM_select_more(EditMesh *em);
-void selectconnected_mesh_all(EditMesh *em);
-void faceloop_select(EditMesh *em, EditEdge *startedge, int select);
-
-/**
- * findnearestvert
- *
- * dist (in/out): minimal distance to the nearest and at the end, actual distance
- * sel: selection bias
- * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
- * if 0, unselected vertice are given the bias
- * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
- */
-extern EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict);
-
-
-/* ******************* editmesh_tools.c */
-
+void MESH_OT_select_next_loop(struct wmOperatorType *ot);
+
#define SUBDIV_SELECT_ORIG 0
#define SUBDIV_SELECT_INNER 1
#define SUBDIV_SELECT_INNER_SEL 2
@@ -232,9 +270,12 @@ void MESH_OT_region_to_loop(struct wmOperatorType *ot);
void MESH_OT_select_axis(struct wmOperatorType *ot);
void MESH_OT_uvs_rotate(struct wmOperatorType *ot);
-void MESH_OT_uvs_mirror(struct wmOperatorType *ot);
+//void MESH_OT_uvs_mirror(struct wmOperatorType *ot);
+void MESH_OT_uvs_reverse(struct wmOperatorType *ot);
void MESH_OT_colors_rotate(struct wmOperatorType *ot);
-void MESH_OT_colors_mirror(struct wmOperatorType *ot);
+//void MESH_OT_colors_mirror(struct wmOperatorType *ot);
+
+void MESH_OT_colors_reverse(struct wmOperatorType *ot);
void MESH_OT_delete(struct wmOperatorType *ot);
void MESH_OT_rip(struct wmOperatorType *ot);
@@ -253,8 +294,20 @@ void MESH_OT_sticky_add(struct wmOperatorType *ot);
void MESH_OT_sticky_remove(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
+/* ************* bmesh_tools.c ***********/
+void MESH_OT_vert_connect(struct wmOperatorType *ot);
+void MESH_OT_edge_split(struct wmOperatorType *ot);
+void MESH_OT_extrude_region(struct wmOperatorType *ot);
+void MESH_OT_extrude_verts_indiv(struct wmOperatorType *ot);
+void MESH_OT_extrude_edges_indiv(struct wmOperatorType *ot);
+void MESH_OT_extrude_faces_indiv(struct wmOperatorType *ot);
+void MESH_OT_bm_test(struct wmOperatorType *ot);
+
void MESH_OT_edgering_select(struct wmOperatorType *ot);
void MESH_OT_loopcut(struct wmOperatorType *ot);
+void MESH_OT_knifetool(struct wmOperatorType *ot);
+void MESH_OT_bevel(struct wmOperatorType *ot);
+
#endif // MESH_INTERN_H
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 282eeef906f..38e57e02339 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -59,6 +59,7 @@
/**************************** registration **********************************/
+void EXPORT_MESH_OT_wavefront(wmOperatorType *ot);
void ED_operatortypes_mesh(void)
{
WM_operatortype_append(MESH_OT_select_all);
@@ -87,16 +88,18 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_primitive_monkey_add);
WM_operatortype_append(MESH_OT_primitive_uv_sphere_add);
WM_operatortype_append(MESH_OT_primitive_ico_sphere_add);
- WM_operatortype_append(MESH_OT_fgon_clear);
- WM_operatortype_append(MESH_OT_fgon_make);
WM_operatortype_append(MESH_OT_duplicate);
WM_operatortype_append(MESH_OT_remove_doubles);
WM_operatortype_append(MESH_OT_vertices_sort);
WM_operatortype_append(MESH_OT_vertices_randomize);
- WM_operatortype_append(MESH_OT_extrude);
WM_operatortype_append(MESH_OT_spin);
WM_operatortype_append(MESH_OT_screw);
-
+
+ WM_operatortype_append(MESH_OT_extrude_region);
+ WM_operatortype_append(MESH_OT_extrude_faces_indiv);
+ WM_operatortype_append(MESH_OT_extrude_edges_indiv);
+ WM_operatortype_append(MESH_OT_extrude_verts_indiv);
+
WM_operatortype_append(MESH_OT_split);
WM_operatortype_append(MESH_OT_extrude_repeat);
WM_operatortype_append(MESH_OT_edge_rotate);
@@ -106,9 +109,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_axis);
WM_operatortype_append(MESH_OT_uvs_rotate);
- WM_operatortype_append(MESH_OT_uvs_mirror);
WM_operatortype_append(MESH_OT_colors_rotate);
- WM_operatortype_append(MESH_OT_colors_mirror);
WM_operatortype_append(MESH_OT_fill);
WM_operatortype_append(MESH_OT_beautify_fill);
@@ -117,7 +118,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_edge_flip);
WM_operatortype_append(MESH_OT_faces_shade_smooth);
WM_operatortype_append(MESH_OT_faces_shade_flat);
- WM_operatortype_append(MESH_OT_sort_faces);
+ //WM_operatortype_append(MESH_OT_sort_faces);
WM_operatortype_append(MESH_OT_delete);
@@ -133,7 +134,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_vertices_smooth);
WM_operatortype_append(MESH_OT_noise);
WM_operatortype_append(MESH_OT_flip_normals);
- WM_operatortype_append(MESH_OT_knife_cut);
+ //WM_operatortype_append(MESH_OT_knife_cut);
WM_operatortype_append(MESH_OT_rip);
WM_operatortype_append(MESH_OT_blend_from_shape);
WM_operatortype_append(MESH_OT_shape_propagate_to_all);
@@ -151,6 +152,14 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_solidify);
WM_operatortype_append(MESH_OT_select_nth);
+ WM_operatortype_append(MESH_OT_vert_connect);
+ WM_operatortype_append(MESH_OT_knifetool);
+
+ WM_operatortype_append(MESH_OT_bevel);
+
+ WM_operatortype_append(MESH_OT_select_next_loop);
+
+ WM_operatortype_append(EXPORT_MESH_OT_wavefront);
}
#if 0 /* UNUSED, remove? */
@@ -158,7 +167,7 @@ static int ED_operator_editmesh_face_select(bContext *C)
{
Object *obedit= CTX_data_edit_object(C);
if(obedit && obedit->type==OB_MESH) {
- EditMesh *em = ((Mesh *)obedit->data)->edit_mesh;
+ BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
if (em && em->selectmode & SCE_SELECT_FACE) {
return 1;
}
@@ -194,31 +203,28 @@ void ED_operatormacros_mesh(void)
ot= WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude region and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 1);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_faces_move", "Extrude Individual Faces and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude faces and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 2);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_faces_indiv");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_shrink_fatten");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_edges_move", "Extrude Only Edges and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude edges and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
- RNA_enum_set(otmacro->ptr, "type", 3);
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_edges_indiv");
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", 0);
ot= WM_operatortype_append_macro("MESH_OT_extrude_vertices_move", "Extrude Only Vertices and Move", OPTYPE_UNDO|OPTYPE_REGISTER);
ot->description = "Extrude vertices and move result";
- otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude");
+ otmacro= WM_operatortype_macro_define(ot, "MESH_OT_extrude_verts_indiv");
RNA_enum_set(otmacro->ptr, "type", 4);
otmacro= WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
RNA_enum_set(otmacro->ptr, "proportional", 0);
@@ -284,6 +290,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_fill", FKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_beautify_fill", FKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0);
+
WM_keymap_add_item(keymap, "MESH_OT_quads_convert_to_tris", TKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "MESH_OT_tris_convert_to_quads", JKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "MESH_OT_edge_flip", FKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
@@ -301,7 +308,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "INFO_MT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "MESH_OT_split", YKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_vert_connect", YKEY, KM_PRESS, 0, 0);
/* use KM_CLICK because same key is used for tweaks */
WM_keymap_add_item(keymap, "MESH_OT_dupli_extrude_cursor", ACTIONMOUSE, KM_CLICK, KM_CTRL, 0);
@@ -310,8 +317,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);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 763e82b8b53..49b9516190a 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -68,6 +68,7 @@
#include "BKE_mesh.h"
#include "BKE_material.h"
#include "BKE_report.h"
+#include "BKE_tessmesh.h"
#include "BKE_multires.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -81,14 +82,14 @@
/* own include */
#include "mesh_intern.h"
-
+#include "uvedit_intern.h"
/* * ********************** no editmode!!! *********** */
/*********************** JOIN ***************************/
/* join selected meshes into the active mesh, context sensitive
-return 0 if no join is made (error) and 1 of the join is done */
+return 0 if no join is made (error) and 1 if the join is done */
int join_mesh_exec(bContext *C, wmOperator *op)
{
@@ -100,15 +101,17 @@ int join_mesh_exec(bContext *C, wmOperator *op)
MVert *mvert, *mv;
MEdge *medge = NULL;
MFace *mface = NULL;
+ MPoly *mpoly = NULL;
+ MLoop *mloop = NULL;
Key *key, *nkey=NULL;
KeyBlock *kb, *okb, *kbn;
float imat[4][4], cmat[4][4], *fp1, *fp2, curpos;
int a, b, totcol, totmat=0, totedge=0, totvert=0, totface=0, ok=0;
- int vertofs, *matmap=NULL;
- int i, j, index, haskey=0, edgeofs, faceofs;
+ int totloop=0, totpoly=0, vertofs, *matmap=NULL;
+ int i, j, index, haskey=0, edgeofs, faceofs, loopofs, polyofs;
bDeformGroup *dg, *odg;
MDeformVert *dvert;
- CustomData vdata, edata, fdata;
+ CustomData vdata, edata, fdata, ldata, pdata;
if(scene->obedit) {
BKE_report(op->reports, RPT_WARNING, "Cant join while in editmode");
@@ -129,6 +132,8 @@ int join_mesh_exec(bContext *C, wmOperator *op)
totvert+= me->totvert;
totedge+= me->totedge;
totface+= me->totface;
+ totloop+= me->totloop;
+ totpoly+= me->totpoly;
totmat+= base->object->totcol;
if(base->object == ob)
@@ -282,14 +287,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
memset(&vdata, 0, sizeof(vdata));
memset(&edata, 0, sizeof(edata));
memset(&fdata, 0, sizeof(fdata));
+ memset(&ldata, 0, sizeof(ldata));
+ memset(&pdata, 0, sizeof(pdata));
mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
+ mloop= CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
+ mpoly= CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
vertofs= 0;
edgeofs= 0;
faceofs= 0;
+ loopofs= 0;
+ polyofs= 0;
/* inverse transform for all selected meshes in this object */
invert_m4_m4(imat, ob->obmat);
@@ -413,9 +424,6 @@ int join_mesh_exec(bContext *C, wmOperator *op)
}
}
- if(base->object!=ob)
- multiresModifier_prepare_join(scene, base->object, ob);
-
CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
@@ -442,14 +450,51 @@ int join_mesh_exec(bContext *C, wmOperator *op)
medge->v1+= vertofs;
medge->v2+= vertofs;
}
+ }
+
+ if (me->totloop) {
+ if(base->object!=ob)
+ multiresModifier_prepare_join(scene, base->object, ob);
- edgeofs += me->totedge;
+ CustomData_merge(&me->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+ CustomData_copy_data(&me->ldata, &ldata, 0, loopofs, me->totloop);
+
+ for(a=0; a<me->totloop; a++, mloop++) {
+ mloop->v += vertofs;
+ mloop->e += edgeofs;
+ }
}
- /* vertofs is used to help newly added verts be reattached to their edge/face
- * (cannot be set earlier, or else reattaching goes wrong)
+ if(me->totpoly) {
+ /* make mapping for materials */
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) {
+ matmap[a-1]= b;
+ break;
+ }
+ }
+ }
+
+ CustomData_merge(&me->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+ CustomData_copy_data(&me->pdata, &pdata, 0, polyofs, me->totpoly);
+
+ for(a=0; a<me->totpoly; a++, mpoly++) {
+ mpoly->loopstart += loopofs;
+ mpoly->mat_nr= matmap ? matmap[(int)mpoly->mat_nr] : 0;
+ }
+
+ polyofs += me->totpoly;
+ }
+
+ /* these are used for relinking (cannot be set earlier,
+ * or else reattaching goes wrong)
*/
vertofs += me->totvert;
+ edgeofs += me->totedge;
+ loopofs += me->totloop;
/* free base, now that data is merged */
if(base->object != ob)
@@ -464,14 +509,20 @@ int join_mesh_exec(bContext *C, wmOperator *op)
CustomData_free(&me->vdata, me->totvert);
CustomData_free(&me->edata, me->totedge);
CustomData_free(&me->fdata, me->totface);
+ CustomData_free(&me->ldata, me->totloop);
+ CustomData_free(&me->pdata, me->totpoly);
me->totvert= totvert;
me->totedge= totedge;
me->totface= totface;
+ me->totloop= totloop;
+ me->totpoly= totpoly;
me->vdata= vdata;
me->edata= edata;
me->fdata= fdata;
+ me->ldata= ldata;
+ me->pdata= pdata;
mesh_update_customdata_pointers(me);
@@ -530,11 +581,11 @@ int join_mesh_exec(bContext *C, wmOperator *op)
ED_object_exit_editmode(C, EM_FREEDATA|EM_WAITCURSOR|EM_DO_UNDO);
#else
/* toggle editmode using lower level functions so this can be called from python */
- make_editMesh(scene, ob);
- load_editMesh(scene, ob);
- free_editMesh(me->edit_mesh);
- MEM_freeN(me->edit_mesh);
- me->edit_mesh= NULL;
+ EDBM_MakeEditBMesh(scene->toolsettings, scene, ob);
+ EDBM_LoadEditBMesh(scene, ob);
+ EDBM_FreeEditBMesh(me->edit_btmesh);
+ MEM_freeN(me->edit_btmesh);
+ me->edit_btmesh= NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
#endif
WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE, scene);
@@ -761,7 +812,7 @@ static struct {
/* mode is 's' start, or 'e' end, or 'u' use */
/* if end, ob can be NULL */
-intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
+intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, float *co, char mode)
{
MocNode **bt;
@@ -787,10 +838,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
* we are using the undeformed coordinates*/
INIT_MINMAX(min, max);
- if(em && me->edit_mesh==em) {
- EditVert *eve;
+ if(em && me->edit_btmesh==em) {
+ BMIter iter;
+ BMVert *eve;
- for(eve= em->verts.first; eve; eve= eve->next)
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL)
DO_MINMAX(eve->co, min, max)
}
else {
@@ -822,10 +874,11 @@ intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode)
MeshOctree.table= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table");
- if(em && me->edit_mesh==em) {
- EditVert *eve;
+ if(em && me->edit_btmesh==em) {
+ BMVert *eve;
+ BMIter iter;
- for(eve= em->verts.first; eve; eve= eve->next) {
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve));
}
}
@@ -887,27 +940,23 @@ long mesh_mirrtopo_table(Object *ob, char mode)
Mesh *me= ob->data;
if( (mesh_topo_lookup==NULL) ||
(mesh_topo_lookup_mode != ob->mode) ||
- (me->edit_mesh && me->edit_mesh->totvert != mesh_topo_lookup_tot) ||
- (me->edit_mesh==NULL && me->totvert != mesh_topo_lookup_tot)
+ (me->edit_btmesh && me->edit_btmesh->bm->totvert != mesh_topo_lookup_tot) ||
+ (me->edit_btmesh==NULL && me->totvert != mesh_topo_lookup_tot)
) {
mesh_mirrtopo_table(ob, 's');
}
} else if(mode=='s') { /* start table */
Mesh *me= ob->data;
MEdge *medge;
- EditMesh *em= me->edit_mesh;
- void **eve_tmp_back= NULL; /* some of the callers are using eve->tmp so restore after */
-
-
- /* editmode*/
- EditEdge *eed;
-
- int a, last, totvert;
- int totUnique= -1, totUniqueOld= -1;
-
+ BMEditMesh *em= me->edit_btmesh;
+ BMEdge *eed;
+ BMIter iter;
MIRRHASH_TYPE *MirrTopoHash = NULL;
MIRRHASH_TYPE *MirrTopoHash_Prev = NULL;
MirrTopoPair *MirrTopoPairs;
+ int a, last, totvert;
+ int totUnique= -1, totUniqueOld= -1;
+
mesh_topo_lookup_mode= ob->mode;
/* reallocate if needed */
@@ -917,12 +966,12 @@ long mesh_mirrtopo_table(Object *ob, char mode)
}
if(em) {
- EditVert *eve;
+ BMVert *eve;
+
totvert= 0;
- eve_tmp_back= MEM_callocN( em->totvert * sizeof(void *), "TopoMirr" );
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve_tmp_back[totvert]= eve->tmp.p;
- eve->tmp.l = totvert++;
+ BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BMINDEX_SET(eve, totvert);
+ totvert++;
}
}
else {
@@ -933,9 +982,9 @@ long mesh_mirrtopo_table(Object *ob, char mode)
/* Initialize the vert-edge-user counts used to detect unique topology */
if(em) {
- for(eed=em->edges.first; eed; eed= eed->next) {
- MirrTopoHash[eed->v1->tmp.l]++;
- MirrTopoHash[eed->v2->tmp.l]++;
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ MirrTopoHash[BMINDEX_GET(eed->v1)]++;
+ MirrTopoHash[BMINDEX_GET(eed->v2)]++;
}
} else {
for(a=0, medge=me->medge; a<me->totedge; a++, medge++) {
@@ -951,9 +1000,9 @@ long mesh_mirrtopo_table(Object *ob, char mode)
/* use the number of edges per vert to give verts unique topology IDs */
if(em) {
- for(eed=em->edges.first; eed; eed= eed->next) {
- MirrTopoHash[eed->v1->tmp.l] += MirrTopoHash_Prev[eed->v2->tmp.l];
- MirrTopoHash[eed->v2->tmp.l] += MirrTopoHash_Prev[eed->v1->tmp.l];
+ BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ MirrTopoHash[BMINDEX_GET(eed->v1)] += MirrTopoHash_Prev[BMINDEX_GET(eed->v2)];
+ MirrTopoHash[BMINDEX_GET(eed->v2)] += MirrTopoHash_Prev[BMINDEX_GET(eed->v1)];
}
} else {
for(a=0, medge=me->medge; a<me->totedge; a++, medge++) {
@@ -985,19 +1034,6 @@ long mesh_mirrtopo_table(Object *ob, char mode)
memcpy(MirrTopoHash_Prev, MirrTopoHash, sizeof(MIRRHASH_TYPE) * totvert);
}
- /* restore eve->tmp.* */
- if(eve_tmp_back) {
- EditVert *eve;
- totvert= 0;
- for(eve= em->verts.first; eve; eve= eve->next) {
- eve->tmp.p= eve_tmp_back[totvert++];
- }
-
- MEM_freeN(eve_tmp_back);
- eve_tmp_back= NULL;
- }
-
-
/* Hash/Index pairs are needed for sorting to find index pairs */
MirrTopoPairs= MEM_callocN( sizeof(MirrTopoPair) * totvert, "MirrTopoPairs");
@@ -1005,7 +1041,7 @@ long mesh_mirrtopo_table(Object *ob, char mode)
mesh_topo_lookup = MEM_mallocN( totvert * sizeof(long), "mesh_topo_lookup" );
if(em) {
- EM_init_index_arrays(em,1,0,0);
+ EDBM_init_index_arrays(em,1,0,0);
}
@@ -1029,8 +1065,8 @@ long mesh_mirrtopo_table(Object *ob, char mode)
if ((a==totvert) || (MirrTopoPairs[a-1].hash != MirrTopoPairs[a].hash)) {
if (a-last==2) {
if(em) {
- mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-2].vIndex);
- mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EM_get_vert_for_index(MirrTopoPairs[a-1].vIndex);
+ mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-2].vIndex);
+ mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = (long)EDBM_get_vert_for_index(em, MirrTopoPairs[a-1].vIndex);
} else {
mesh_topo_lookup[MirrTopoPairs[a-1].vIndex] = MirrTopoPairs[a-2].vIndex;
mesh_topo_lookup[MirrTopoPairs[a-2].vIndex] = MirrTopoPairs[a-1].vIndex;
@@ -1040,7 +1076,7 @@ long mesh_mirrtopo_table(Object *ob, char mode)
}
}
if(em) {
- EM_free_index_arrays();
+ EDBM_free_index_arrays(em);
}
MEM_freeN( MirrTopoPairs );
@@ -1090,9 +1126,10 @@ int mesh_get_x_mirror_vert(Object *ob, int index)
} else {
return mesh_get_x_mirror_vert_spacial(ob, index);
}
+ return 0;
}
-static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, float *co)
+static BMVert *editbmesh_get_x_mirror_vert_spacial(Object *ob, BMEditMesh *em, float *co)
{
float vec[3];
intptr_t poinval;
@@ -1110,20 +1147,28 @@ static EditVert *editmesh_get_x_mirror_vert_spacial(Object *ob, EditMesh *em, fl
poinval= mesh_octree_table(ob, em, vec, 'u');
if(poinval != -1)
- return (EditVert *)(poinval);
+ return (BMVert *)(poinval);
return NULL;
}
-static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em, EditVert *eve, int index)
+static BMVert *editbmesh_get_x_mirror_vert_topo(Object *ob, struct BMEditMesh *em, BMVert *eve, int index)
{
long poinval;
if (mesh_mirrtopo_table(ob, 'u')==-1)
return NULL;
if (index == -1) {
- index = BLI_findindex(&em->verts, eve);
-
- if (index == -1) {
+ BMIter iter;
+ BMVert *v;
+
+ index = 0;
+ BM_ITER(v, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ if (v == eve)
+ break;
+ index++;
+ }
+
+ if (index == em->bm->totvert) {
return NULL;
}
}
@@ -1131,22 +1176,23 @@ static EditVert *editmesh_get_x_mirror_vert_topo(Object *ob, struct EditMesh *em
poinval= mesh_topo_lookup[ index ];
if(poinval != -1)
- return (EditVert *)(poinval);
+ return (BMVert *)(poinval);
return NULL;
}
-EditVert *editmesh_get_x_mirror_vert(Object *ob, struct EditMesh *em, EditVert *eve, float *co, int index)
+BMVert *editbmesh_get_x_mirror_vert(Object *ob, struct BMEditMesh *em, BMVert *eve, float *co, int index)
{
+ //BMESH_TODO use this flag, ME_EDIT_MIRROR_TOPO, at appropriate places
if (((Mesh *)ob->data)->editflag & ME_EDIT_MIRROR_TOPO) {
- return editmesh_get_x_mirror_vert_topo(ob, em, eve, index);
+ return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
} else {
- return editmesh_get_x_mirror_vert_spacial(ob, em, co);
+ return editbmesh_get_x_mirror_vert_spacial(ob, em, co);
}
}
-#if 0
-float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_cent)
+
+float *editmesh_get_mirror_uv(BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
{
float vec[2];
float cent_vec[2];
@@ -1174,26 +1220,29 @@ float *editmesh_get_mirror_uv(int axis, float *uv, float *mirrCent, float *face_
/* TODO - Optimize */
{
- EditFace *efa;
- int i, len;
- for(efa=em->faces.first; efa; efa=efa->next) {
- MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
- uv_center(tf->uv, cent, (void *)efa->v4);
-
+ BMIter iter;
+ BMFace *efa;
+
+ BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
+ poly_uv_center(em, efa, cent);
+
if ( (fabs(cent[0] - cent_vec[0]) < 0.001) && (fabs(cent[1] - cent_vec[1]) < 0.001) ) {
- len = efa->v4 ? 4 : 3;
- for (i=0; i<len; i++) {
- if ( (fabs(tf->uv[i][0] - vec[0]) < 0.001) && (fabs(tf->uv[i][1] - vec[1]) < 0.001) ) {
- return tf->uv[i];
- }
+ BMIter liter;
+ BMLoop *l;
+
+ BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
+ MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
+ if ( (fabs(luv->uv[0] - vec[0]) < 0.001) && (fabs(luv->uv[1] - vec[1]) < 0.001) ) {
+ return luv->uv;
+
}
}
}
}
+ }
return NULL;
}
-#endif
static unsigned int mirror_facehash(const void *ptr)
{
@@ -1241,7 +1290,7 @@ static int mirror_facecmp(const void *a, const void *b)
return (mirror_facerotation((MFace*)a, (MFace*)b) == -1);
}
-int *mesh_get_x_mirror_faces(Object *ob, EditMesh *em)
+int *mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em)
{
Mesh *me= ob->data;
MVert *mv, *mvert= me->mvert;